Numpy与线交点计算
我想知道怎么用numpy来计算两条线段的交点。
在我的代码里,我有 segment1 = ((x1,y1),(x2,y2))
和 segment2 = ((x1,y1),(x2,y2))
。注意,segment1
和 segment2
是不一样的。所以在我的代码中,我还在计算斜率和y轴截距,如果能省略这些计算就好了,但我不知道怎么做。
我一直在用克拉默法则,写了一个Python函数来实现,但我想找一个更快的方法。
12 个回答
这可能是个晚来的回复,但当我在网上搜索“numpy 线交点”时,它是第一个出现的结果。在我的情况中,我有两条线在一个平面上,我想快速找到它们的交点,而Hamish的解决方案会比较慢,因为需要对所有线段使用嵌套的循环。
下面是如何在不使用循环的情况下做到这一点(速度很快):
from numpy import where, dstack, diff, meshgrid
def find_intersections(A, B):
# min, max and all for arrays
amin = lambda x1, x2: where(x1<x2, x1, x2)
amax = lambda x1, x2: where(x1>x2, x1, x2)
aall = lambda abools: dstack(abools).all(axis=2)
slope = lambda line: (lambda d: d[:,1]/d[:,0])(diff(line, axis=0))
x11, x21 = meshgrid(A[:-1, 0], B[:-1, 0])
x12, x22 = meshgrid(A[1:, 0], B[1:, 0])
y11, y21 = meshgrid(A[:-1, 1], B[:-1, 1])
y12, y22 = meshgrid(A[1:, 1], B[1:, 1])
m1, m2 = meshgrid(slope(A), slope(B))
m1inv, m2inv = 1/m1, 1/m2
yi = (m1*(x21-x11-m2inv*y21) + y11)/(1 - m1*m2inv)
xi = (yi - y21)*m2inv + x21
xconds = (amin(x11, x12) < xi, xi <= amax(x11, x12),
amin(x21, x22) < xi, xi <= amax(x21, x22) )
yconds = (amin(y11, y12) < yi, yi <= amax(y11, y12),
amin(y21, y22) < yi, yi <= amax(y21, y22) )
return xi[aall(xconds)], yi[aall(yconds)]
然后使用时,提供两条线作为参数,其中每个参数是一个有两列的矩阵,每一行对应一个 (x, y) 点:
# example from matplotlib contour plots
Acs = contour(...)
Bsc = contour(...)
# A and B are the two lines, each is a
# two column matrix
A = Acs.collections[0].get_paths()[0].vertices
B = Bcs.collections[0].get_paths()[0].vertices
# do it
x, y = find_intersections(A, B)
祝你玩得开心
解释
import numpy as np
def get_intersect(a1, a2, b1, b2):
"""
Returns the point of intersection of the lines passing through a2,a1 and b2,b1.
a1: [x, y] a point on the first line
a2: [x, y] another point on the first line
b1: [x, y] a point on the second line
b2: [x, y] another point on the second line
"""
s = np.vstack([a1,a2,b1,b2]) # s for stacked
h = np.hstack((s, np.ones((4, 1)))) # h for homogeneous
l1 = np.cross(h[0], h[1]) # get first line
l2 = np.cross(h[2], h[3]) # get second line
x, y, z = np.cross(l1, l2) # point of intersection
if z == 0: # lines are parallel
return (float('inf'), float('inf'))
return (x/z, y/z)
if __name__ == "__main__":
print get_intersect((0, 1), (0, 2), (1, 10), (1, 9)) # parallel lines
print get_intersect((0, 1), (0, 2), (1, 10), (2, 10)) # vertical and horizontal lines
print get_intersect((0, 1), (1, 2), (0, 10), (1, 9)) # another line for fun
注意,直线的方程是 ax+by+c=0
。所以如果一个点在这条直线上,那么它就是 (a,b,c).(x,y,1)=0
的解(这里的 .
是点积运算)。
设 l1=(a1,b1,c1)
和 l2=(a2,b2,c2)
是两条直线,p1=(x1,y1,1)
和 p2=(x2,y2,1)
是两个点。
找到经过两个点的直线:
设 t=p1xp2
(两个点的叉积)是一个表示直线的向量。
我们知道 p1
在直线 t
上,因为 t.p1 = (p1xp2).p1=0
。我们也知道 p2
在 t
上,因为 t.p2 = (p1xp2).p2=0
。所以 t
一定是经过 p1
和 p2
的直线。
这意味着 我们可以通过对这条直线上的两个点进行叉积来得到直线的向量表示。
找到交点:
现在设 r=l1xl2
(两条直线的叉积)是一个表示交点的向量。
我们知道 r
在 l1
上,因为 r.l1=(l1xl2).l1=0
。我们也知道 r
在 l2
上,因为 r.l2=(l1xl2).l2=0
。所以 r
一定是直线 l1
和 l2
的交点。
有趣的是,我们可以通过对两条直线进行叉积来找到交点。
#
# line segment intersection using vectors
# see Computer Graphics by F.S. Hill
#
from numpy import *
def perp( a ) :
b = empty_like(a)
b[0] = -a[1]
b[1] = a[0]
return b
# line segment a given by endpoints a1, a2
# line segment b given by endpoints b1, b2
# return
def seg_intersect(a1,a2, b1,b2) :
da = a2-a1
db = b2-b1
dp = a1-b1
dap = perp(da)
denom = dot( dap, db)
num = dot( dap, dp )
return (num / denom.astype(float))*db + b1
p1 = array( [0.0, 0.0] )
p2 = array( [1.0, 0.0] )
p3 = array( [4.0, -5.0] )
p4 = array( [4.0, 2.0] )
print seg_intersect( p1,p2, p3,p4)
p1 = array( [2.0, 2.0] )
p2 = array( [4.0, 3.0] )
p3 = array( [6.0, 0.0] )
p4 = array( [6.0, 3.0] )
print seg_intersect( p1,p2, p3,p4)