Comment pourrais-je utiliser numpy pour calculer l'intersection entre deux segments de ligne?
Dans le code, j'ai segment1 = ((x1, y1), (x2, y2)) et segment2 = ((x1, y1), (x2, y2)). Remarque le segment 1 n'est pas égal au segment2. Donc, dans mon code, j'ai également calculé la pente et l'ordonnée à l'origine, ce serait bien si cela pouvait être évité, mais je ne sais pas comment.
J'utilise la règle de Cramer avec une fonction que j'ai écrite en Python, mais j'aimerais trouver un moyen plus rapide de le faire.
Volé directement à 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)
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 __== "__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
Notez que l'équation d'une ligne est ax+by+c=0
. Donc si un point est sur cette ligne, alors c'est une solution pour (a,b,c).(x,y,1)=0
(.
est le produit scalaire)
soit l1=(a1,b1,c1)
, l2=(a2,b2,c2)
deux lignes et p1=(x1,y1,1)
, p2=(x2,y2,1)
deux points.
soit t=p1xp2
(le produit croisé de deux points) un vecteur représentant une ligne.
Nous savons que p1
est sur la ligne t
parce que t.p1 = (p1xp2).p1=0
. Nous savons également que p2
est sur t
car t.p2 = (p1xp2).p2=0
. Donc, t
doit être la ligne passant par p1
et p2
.
Cela signifie que nous pouvons obtenir la représentation vectorielle d'une ligne en prenant le produit croisé de deux points sur cette ligne .
Soit maintenant r=l1xl2
(le produit croisé de deux lignes) un vecteur représentant un point.
Nous savons que r
se trouve sur l1
car r.l1=(l1xl2).l1=0
. Nous savons également que r
se trouve sur l2
car r.l2=(l1xl2).l2=0
. Donc, r
doit être le point d'intersection des lignes l1
et l2
.
Fait intéressant, nous pouvons trouver le point d'intersection en prenant le produit croisé de deux lignes .
C’est une réponse tardive, peut-être, mais c’est le premier résultat lorsque j’ai cherché Google 'intersections de lignes numpy'. Dans mon cas, il y a deux lignes dans un avion et je voulais obtenir rapidement toutes les intersections entre elles. La solution de Hamish serait lente - nécessitant une boucle imbriquée sur tous les segments de ligne.
Voici comment le faire sans une boucle for (c'est assez rapide):
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)]
Ensuite, pour l'utiliser, spécifiez deux lignes en tant qu'arguments, où arg est une matrice à 2 colonnes, chaque ligne correspondant à un point (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)
s'amuser
Ceci est une version de la réponse de @Hamish Grubijan qui fonctionne également pour plusieurs points dans chacun des arguments d'entrée, c.-à-d., a1
, a2
, b1
, b2
, peuvent être des tableaux de rangées 2D de points Nx2. La fonction perp
est remplacée par un produit scalaire.
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
Voici un one-liner (un peu forcé):
import numpy as np
from scipy.interpolate import interp1d
interp1d(segment1-segment2,np.arange(segment1.shape[0]))(0)
Interpoler la différence (par défaut, linéaire) et trouver un 0 de l'inverse.
À votre santé!
C’est ce que j’utilise pour trouver une intersection de ligne, cela fonctionne en ayant 2 points de chaque ligne ou juste un point et sa pente. Je résous fondamentalement le système d'équations linéaires.
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