如何使用numpy计算两个线段之间的交点?
在代码中我有segment1 =((x1,y1),(x2,y2))和segment2 =((x1,y1),(x2,y2))。注意段1不等于segment2。所以在我的代码中我也一直在计算斜率和y轴截距,如果可以避免这样做会很好但是我不知道怎么做。
我一直在使用Cramer的规则和我在Python中编写的函数,但我想找到一种更快的方法。
答案 0 :(得分:31)
直接从http://www.cs.mun.ca/~rod/2500/notes/numpy-arrays/numpy-arrays.html
被盗#
# 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)
答案 1 :(得分:13)
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
和def nest_level(L):
'''Return the maximum "nesting level" of nested list L, that is, how many
levels of sub-lists are in L, at the "deepest" point within L. For example,
nest level([1, [[], [[2]]], ’three’]) should return 4 because element 2 is
in a list ([2]) within a list ([[2]]) within a list ([[], [[2]]])
within the original list.
'''
if type(L) != list:
count = 0
elif L == []:
count = 1
else:
if type(L[0]) == list:
count = 1
count = count + nest_level(L[0])
else:
count = 0
count = count + nest_level(L[1:])
return count
的交点。
有趣的是,我们可以通过取两行的交叉积来找到交叉点。
答案 2 :(得分:9)
这可能是一个迟到的回应,但这是我用谷歌搜索过的“numpy line intersection”时的第一个响应。在我的情况下,我在一个平面上有两条线,我想快速得到它们之间的任何交叉点,而Hamish的解决方案会很慢 - 需要在所有线段上嵌套for循环。
以下是没有for循环的方法(它很快):
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)]
然后使用它,提供两行作为参数,其中arg是一个2列矩阵,每行对应一个(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)
玩得开心
答案 3 :(得分:4)
这是@Hamish Grubijan的答案版本,该答案也适用于每个输入参数中的多个点,即a1
,a2
,b1
,b2
可以是2D点的Nx2行数组。 perp
函数替换为点积。
T = np.array([[0, -1], [1, 0]])
def line_intersect(a1, a2, b1, b2):
da = np.atleast_2d(a2 - a1)
db = np.atleast_2d(b2 - b1)
dp = np.atleast_2d(a1 - b1)
dap = np.dot(da, T)
denom = np.sum(dap * db, axis=1)
num = np.sum(dap * dp, axis=1)
return np.atleast_2d(num / denom).T * db + b1
答案 4 :(得分:1)
这是一个(位强制)单行:
import numpy as np
from scipy.interpolate import interp1d
interp1d(segment1-segment2,np.arange(segment1.shape[0]))(0)
插值差值(默认为线性),并找到倒数的0。
干杯!
答案 5 :(得分:1)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
'''
finding intersect point of line AB and CD
where A is the first point of line AB
and B is the second point of line AB
and C is the first point of line CD
and D is the second point of line CD
'''
def get_intersect(A, B, C, D):
# a1x + b1y = c1
a1 = B.y - A.y
b1 = A.x - B.x
c1 = a1 * (A.x) + b1 * (A.y)
# a2x + b2y = c2
a2 = D.y - C.y
b2 = C.x - D.x
c2 = a2 * (C.x) + b2 * (C.y)
# determinant
det = a1 * b2 - a2 * b1
# parallel line
if det == 0:
return (float('inf'), float('inf'))
# intersect point(x,y)
x = ((b2 * c1) - (b1 * c2)) / det
y = ((a1 * c2) - (a2 * c1)) / det
return (x, y)
答案 6 :(得分:0)
这是我用来查找线交叉的,它可以有每条线的2个点,或者只是一个点和它的斜率。我基本上解决了线性方程组。
def line_intersect(p0, p1, m0=None, m1=None, q0=None, q1=None):
''' intersect 2 lines given 2 points and (either associated slopes or one extra point)
Inputs:
p0 - first point of first line [x,y]
p1 - fist point of second line [x,y]
m0 - slope of first line
m1 - slope of second line
q0 - second point of first line [x,y]
q1 - second point of second line [x,y]
'''
if m0 is None:
if q0 is None:
raise ValueError('either m0 or q0 is needed')
dy = q0[1] - p0[1]
dx = q0[0] - p0[0]
lhs0 = [-dy, dx]
rhs0 = p0[1] * dx - dy * p0[0]
else:
lhs0 = [-m0, 1]
rhs0 = p0[1] - m0 * p0[0]
if m1 is None:
if q1 is None:
raise ValueError('either m1 or q1 is needed')
dy = q1[1] - p1[1]
dx = q1[0] - p1[0]
lhs1 = [-dy, dx]
rhs1 = p1[1] * dx - dy * p1[0]
else:
lhs1 = [-m1, 1]
rhs1 = p1[1] - m1 * p1[0]
a = np.array([lhs0,
lhs1])
b = np.array([rhs0,
rhs1])
try:
px = np.linalg.solve(a, b)
except:
px = np.array([np.nan, np.nan])
return px