Comment puis-je vérifier si 2 segments se croisent?
J'ai les données suivantes:
Segment1 [ {x1,y1}, {x2,y2} ]
Segment2 [ {x1,y1}, {x2,y2} ]
J'ai besoin d'écrire un petit algorithme en python pour détecter si les 2 lignes se croisent.
Mettre à jour:
L'équation d'une ligne est la suivante:
f(x) = A*x + b = y
Pour un segment, c'est exactement la même chose, sauf que x est inclus dans un intervalle I.
Si vous avez deux segments, définis comme suit:
Segment1 = {(X1, Y1), (X2, Y2)}
Segment2 = {(X3, Y3), (X4, Y4)}
Les abcisse Xa du point d'intersection potentiel (Xa, Ya) doivent être contenues dans les intervalles I1 et I2, définis comme suit:
I1 = [min(X1,X2), max(X1,X2)]
I2 = [min(X3,X4), max(X3,X4)]
Et on pourrait dire que Xa est inclus dans:
Ia = [max( min(X1,X2), min(X3,X4) ),
min( max(X1,X2), max(X3,X4) )]
Maintenant, nous devons vérifier que cet intervalle Ia existe:
if (max(X1,X2) < min(X3,X4))
return false; // There is no mutual abcisses
Nous avons donc une formule à deux lignes et un intervalle mutuel. Vos formules de ligne sont:
f1(x) = A1*x + b1 = y
f2(x) = A2*x + b2 = y
Comme nous avons deux points par segment, nous pouvons déterminer A1, A2, b1 et b2:
A1 = (Y1-Y2)/(X1-X2) // Pay attention to not dividing by zero
A2 = (Y3-Y4)/(X3-X4) // Pay attention to not dividing by zero
b1 = Y1-A1*X1 = Y2-A1*X2
b2 = Y3-A2*X3 = Y4-A2*X4
Si les segments sont parallèles, alors A1 == A2:
if (A1 == A2)
return false; // Parallel segments
Un point (Xa, Ya) situé sur les deux lignes doit vérifier les deux formules f1 et f2:
Ya = A1 * Xa + b1
Ya = A2 * Xa + b2
A1 * Xa + b1 = A2 * Xa + b2
Xa = (b2 - b1) / (A1 - A2) // Once again, pay attention to not dividing by zero
La dernière chose à faire est de vérifier que Xa est inclus dans Ia:
if ( (Xa < max( min(X1,X2), min(X3,X4) )) ||
(Xa > min( max(X1,X2), max(X3,X4) )) )
return false; // intersection is out of bound
else
return true;
En plus de cela, vous pouvez vérifier au démarrage que deux des quatre points fournis ne sont pas égaux pour éviter tous ces tests.
L'utilisateur @ i_4_got pointe vers cette page avec une solution très efficace en Python. Je le reproduis ici par souci de commodité (car cela m'aurait fait plaisir de l'avoir ici):
def ccw(A,B,C):
return (C.y-A.y) * (B.x-A.x) > (B.y-A.y) * (C.x-A.x)
# Return true if line segments AB and CD intersect
def intersect(A,B,C,D):
return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)
Vous n'avez pas à calculer exactement où les segments se croisent, mais seulement à comprendre s'ils se croisent. Cela simplifiera la solution.
L'idée est de traiter un segment comme "ancre" et de séparer le second segment en 2 points.
Maintenant, vous devrez trouver la position relative de chaque point par rapport au segment "ancré" (OnLeft, OnRight ou Colinéaire).
Après avoir fait cela pour les deux points, vérifiez que l'un des points est OnLeft et l'autre est OnRight (ou peut-être inclure la position Colinéaire, si vous souhaitez également inclure impropre intersections).
Vous devez ensuite répéter le processus avec les rôles d'ancre et de segments séparés.
Une intersection existe si, et seulement si, l’un des points est OnLeft et l’autre est OnRight. Voir ce lien pour une explication plus détaillée avec des exemples d’images pour chaque cas possible.
La mise en œuvre d'une telle méthode sera beaucoup plus facile que la mise en œuvre d'une méthode qui trouve le point d'intersection (compte tenu des nombreux cas d'angle que vous devrez également gérer).
Mettre à jour
Les fonctions suivantes devraient illustrer l'idée (source: Géométrie algorithmique en C ).
Remarque: Cet exemple suppose l’utilisation d’entiers. Si vous utilisez plutôt une représentation en virgule flottante (ce qui peut évidemment compliquer les choses), vous devez alors déterminer une valeur epsilon pour indiquer "l'égalité" (principalement pour l'évaluation IsCollinear
).
// points "a" and "b" forms the anchored segment.
// point "c" is the evaluated point
bool IsOnLeft(Point a, Point b, Point c)
{
return Area2(a, b, c) > 0;
}
bool IsOnRight(Point a, Point b, Point c)
{
return Area2(a, b, c) < 0;
}
bool IsCollinear(Point a, Point b, Point c)
{
return Area2(a, b, c) == 0;
}
// calculates the triangle's size (formed by the "anchor" segment and additional point)
int Area2(Point a, Point b, Point c)
{
return (b.X - a.X) * (c.Y - a.Y) -
(c.X - a.X) * (b.Y - a.Y);
}
Bien sûr, lorsque vous utilisez ces fonctions, vous devez vous rappeler de vérifier que chaque segment se situe "entre" l'autre segment (puisqu'il s'agit de segments finis et non de lignes infinies).
En outre, en utilisant ces fonctions, vous pouvez comprendre si vous avez une intersection correcte ou impropre.
Supposons que les deux segments ont des extrémités A, B et C, D. La méthode numériquement robuste pour déterminer une intersection consiste à vérifier le signe des quatre déterminants:
| Ax-Cx Bx-Cx | | Ax-Dx Bx-Dx |
| Ay-Cy By-Cy | | Ay-Dy By-Dy |
| Cx-Ax Dx-Ax | | Cx-Bx Dx-Bx |
| Cy-Ay Dy-Ay | | Cy-By Dy-By |
Pour l'intersection, chaque déterminant de gauche doit avoir le signe opposé de celui de droite, mais aucune relation entre les deux lignes ne doit exister. En gros, vous vérifiez chaque point d'un segment par rapport à l'autre segment pour vous assurer qu'ils se trouvent de part et d'autre de la ligne définie par l'autre segment.
Voir ici: http://www.cs.cmu.edu/~quake/robust.html
Sur la base des réponses de de Liran et de Grumdrig , voici un code Python complet permettant de vérifier si les segments closed se coupent. Fonctionne pour les segments colinéaires, les segments parallèles à l’axe Y, les segments dégénérés (le diable est dans les détails). Suppose des coordonnées entières. Les coordonnées en virgule flottante nécessitent une modification du test d’égalité des points.
def side(a,b,c):
""" Returns a position of the point c relative to the line going through a and b
Points a, b are expected to be different
"""
d = (c[1]-a[1])*(b[0]-a[0]) - (b[1]-a[1])*(c[0]-a[0])
return 1 if d > 0 else (-1 if d < 0 else 0)
def is_point_in_closed_segment(a, b, c):
""" Returns True if c is inside closed segment, False otherwise.
a, b, c are expected to be collinear
"""
if a[0] < b[0]:
return a[0] <= c[0] and c[0] <= b[0]
if b[0] < a[0]:
return b[0] <= c[0] and c[0] <= a[0]
if a[1] < b[1]:
return a[1] <= c[1] and c[1] <= b[1]
if b[1] < a[1]:
return b[1] <= c[1] and c[1] <= a[1]
return a[0] == c[0] and a[1] == c[1]
#
def closed_segment_intersect(a,b,c,d):
""" Verifies if closed segments a, b, c, d do intersect.
"""
if a == b:
return a == c or a == d
if c == d:
return c == a or c == b
s1 = side(a,b,c)
s2 = side(a,b,d)
# All points are collinear
if s1 == 0 and s2 == 0:
return \
is_point_in_closed_segment(a, b, c) or is_point_in_closed_segment(a, b, d) or \
is_point_in_closed_segment(c, d, a) or is_point_in_closed_segment(c, d, b)
# No touching and on the same side
if s1 and s1 == s2:
return False
s1 = side(c,d,a)
s2 = side(c,d,b)
# No touching and on the same side
if s1 and s1 == s2:
return False
return True
Voici le code C pour vérifier si deux points sont sur les côtés opposés du segment de ligne. En utilisant ce code, vous pouvez également vérifier si deux segments se croisent.
// true if points p1, p2 lie on the opposite sides of segment s1--s2
bool oppositeSide (Point2f s1, Point2f s2, Point2f p1, Point2f p2) {
//calculate normal to the segment
Point2f vec = s1-s2;
Point2f normal(vec.y, -vec.x); // no need to normalize
// vectors to the points
Point2f v1 = p1-s1;
Point2f v2 = p2-s1;
// compare signs of the projections of v1, v2 onto the normal
float proj1 = v1.dot(normal);
float proj2 = v2.dot(normal);
if (proj1==0 || proj2==0)
cout<<"collinear points"<<endl;
return(SIGN(proj1) != SIGN(proj2));
}
Voici un autre code python pour vérifier si les segments fermés se croisent. C'est la version réécrite du code C++ dans http://www.cdn.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ . Cette mise en œuvre couvre tous les cas particuliers (par exemple tous les points colinéaires).
def on_segment(p, q, r):
'''Given three colinear points p, q, r, the function checks if
point q lies on line segment "pr"
'''
if (q[0] <= max(p[0], r[0]) and q[0] >= min(p[0], r[0]) and
q[1] <= max(p[1], r[1]) and q[1] >= min(p[1], r[1])):
return True
return False
def orientation(p, q, r):
'''Find orientation of ordered triplet (p, q, r).
The function returns following values
0 --> p, q and r are colinear
1 --> Clockwise
2 --> Counterclockwise
'''
val = ((q[1] - p[1]) * (r[0] - q[0]) -
(q[0] - p[0]) * (r[1] - q[1]))
if val == 0:
return 0 # colinear
Elif val > 0:
return 1 # clockwise
else:
return 2 # counter-clockwise
def do_intersect(p1, q1, p2, q2):
'''Main function to check whether the closed line segments p1 - q1 and p2
- q2 intersect'''
o1 = orientation(p1, q1, p2)
o2 = orientation(p1, q1, q2)
o3 = orientation(p2, q2, p1)
o4 = orientation(p2, q2, q1)
# General case
if (o1 != o2 and o3 != o4):
return True
# Special Cases
# p1, q1 and p2 are colinear and p2 lies on segment p1q1
if (o1 == 0 and on_segment(p1, p2, q1)):
return True
# p1, q1 and p2 are colinear and q2 lies on segment p1q1
if (o2 == 0 and on_segment(p1, q2, q1)):
return True
# p2, q2 and p1 are colinear and p1 lies on segment p2q2
if (o3 == 0 and on_segment(p2, p1, q2)):
return True
# p2, q2 and q1 are colinear and q1 lies on segment p2q2
if (o4 == 0 and on_segment(p2, q1, q2)):
return True
return False # Doesn't fall in any of the above cases
Vous trouverez ci-dessous une fonction de test pour vérifier que cela fonctionne.
import matplotlib.pyplot as plt
def test_intersect_func():
p1 = (1, 1)
q1 = (10, 1)
p2 = (1, 2)
q2 = (10, 2)
fig, ax = plt.subplots()
ax.plot([p1[0], q1[0]], [p1[1], q1[1]], 'x-')
ax.plot([p2[0], q2[0]], [p2[1], q2[1]], 'x-')
print(do_intersect(p1, q1, p2, q2))
p1 = (10, 0)
q1 = (0, 10)
p2 = (0, 0)
q2 = (10, 10)
fig, ax = plt.subplots()
ax.plot([p1[0], q1[0]], [p1[1], q1[1]], 'x-')
ax.plot([p2[0], q2[0]], [p2[1], q2[1]], 'x-')
print(do_intersect(p1, q1, p2, q2))
p1 = (-5, -5)
q1 = (0, 0)
p2 = (1, 1)
q2 = (10, 10)
fig, ax = plt.subplots()
ax.plot([p1[0], q1[0]], [p1[1], q1[1]], 'x-')
ax.plot([p2[0], q2[0]], [p2[1], q2[1]], 'x-')
print(do_intersect(p1, q1, p2, q2))
p1 = (0, 0)
q1 = (1, 1)
p2 = (1, 1)
q2 = (10, 10)
fig, ax = plt.subplots()
ax.plot([p1[0], q1[0]], [p1[1], q1[1]], 'x-')
ax.plot([p2[0], q2[0]], [p2[1], q2[1]], 'x-')
print(do_intersect(p1, q1, p2, q2))
Vous avez deux segments de ligne. Définissez un segment par les points d'extrémité A et B et le second segment par les points d'extrémité C et D. Il existe une astuce intéressante pour montrer qu'ils doivent se croiser, DANS les limites des segments. (Notez que les lignes elles-mêmes peuvent se croiser au-delà des limites des segments, vous devez donc être prudent. Un bon code surveillera également les lignes parallèles.)
L'astuce consiste à vérifier que les points A et B doivent être alignés de part et d'autre de la ligne CD ET que les points C et D doivent se trouver de part et d'autre de la ligne AB.
Comme il s’agit d’un devoir, je ne vous donnerai pas de solution explicite. Mais un simple test pour voir de quel côté d'une ligne un point tombe est d'utiliser un produit scalaire. Ainsi, pour un CD de ligne donné, calculez le vecteur normal à cette ligne (je l'appellerai N_C.) Maintenant, testez simplement les signes de ces deux résultats:
dot(A-C,N_C)
et
dot(B-C,N_C)
Si ces résultats ont des signes opposés, alors A et B sont des côtés opposés de la ligne CD. Maintenant, faites le même test pour l'autre ligne, AB. Il a un vecteur normal N_A. Comparez les signes de
dot(C-A,N_A)
et
dot(D-A,N_A)
Je vous laisse le soin de comprendre comment calculer un vecteur normal. (En 2D, c'est trivial, mais votre code s'inquiètera-t-il de savoir si A et B sont des points distincts? De même, C et D sont-ils distincts?)
Vous devez toujours vous préoccuper des segments de ligne situés le long d'une même ligne infinie, ou si un point tombe réellement sur l'autre segment de ligne lui-même. Un bon code répondra à tous les problèmes possibles.
Il est très facile de vérifier si les segments de ligne se croisent avec la bibliothèque Shapely à l'aide de la méthode intersects
:
from shapely.geometry import LineString
line = LineString([(0, 0), (1, 1)])
other = LineString([(0, 1), (1, 0)])
print(line.intersects(other))
# True
line = LineString([(0, 0), (1, 1)])
other = LineString([(0, 1), (1, 2)])
print(line.intersects(other))
# False
Nous pouvons également résoudre ce problème en utilisant des vecteurs.
Définissons les segments comme [start, end]
. Étant donné que deux de ces segments [A, B]
et [C, D]
ont tous deux une longueur non nulle, nous pouvons choisir l'un des extrémités à utiliser comme point de référence afin d'obtenir trois vecteurs:
x = 0
y = 1
p = A-C = [C[x]-A[x], C[y]-A[y]]
q = B-A = [B[x]-A[x], B[y]-A[y]]
r = D-C = [D[x]-C[x], D[y]-C[y]]
À partir de là, on peut rechercher une intersection en calculant t et u dans p + t*r = u*q
. Après avoir joué un peu avec l'équation, nous obtenons:
t = (q[y]*p[x] - q[x]*p[y])/(q[x]*r[y] - q[y]*r[x])
u = (p[x] + t*r[x])/q[x]
Ainsi, la fonction est:
def intersects(a, b):
p = [b[0][0]-a[0][0], b[0][1]-a[0][1]]
q = [a[1][0]-a[0][0], a[1][1]-a[0][1]]
r = [b[1][0]-b[0][0], b[1][1]-b[0][1]]
t = (q[1]*p[0] - q[0]*p[1])/(q[0]*r[1] - q[1]*r[0]) \
if (q[0]*r[1] - q[1]*r[0]) != 0 \
else (q[1]*p[0] - q[0]*p[1])
u = (p[0] + t*r[0])/q[0] \
if q[0] != 0 \
else (p[1] + t*r[1])/q[1]
return t >= 0 and t <= 1 and u >= 0 and u <= 1
Puisque vous ne dites pas que vous voulez trouver le point d'intersection de la ligne, le problème devient plus simple à résoudre. Si vous avez besoin du point d'intersection, la réponse par OMG_peanuts est une approche plus rapide. Toutefois, si vous voulez simplement savoir si les lignes se croisent ou non, vous pouvez le faire en utilisant l’équation de ligne (ax + de + c = 0). La démarche est la suivante:
Commençons par deux segments: le segment 1 et le segment 2.
segment1 = [[x1,y1], [x2,y2]]
segment2 = [[x3,y3], [x4,y4]]
Vérifiez si les deux segments de ligne sont des lignes de longueur non nulle et des segments distincts.
À partir de là, je suppose que les deux segments sont de longueur non nulle et distincts. Pour chaque segment de droite, calcule la pente de la droite puis obtient l’équation d’une droite sous la forme: ax + de + c = 0. Maintenant, calcule la valeur de f = ax + de + c pour les deux points de la autre segment de ligne (répétez ceci pour l’autre segment de ligne également).
a2 = (y3-y4)/(x3-x4);
b1 = -1;
b2 = -1;
c1 = y1 - a1*x1;
c2 = y3 - a2*x3;
// using the sign function from numpy
f1_1 = sign(a1*x3 + b1*y3 + c1);
f1_2 = sign(a1*x4 + b1*y4 + c1);
f2_1 = sign(a2*x1 + b2*y1 + c2);
f2_2 = sign(a2*x2 + b2*y2 + c2);
Il ne reste plus que les différents cas. Si f = 0 pour un point quelconque, les deux lignes se touchent en un point. Si f1_1 et f1_2 sont égaux ou si f2_1 et f2_2 sont égaux, les lignes ne se croisent pas. Si f1_1 et f1_2 sont inégaux et que f2_1 et f2_2 sont inégaux, les segments de ligne se coupent. Selon que vous souhaitez ou non considérer les lignes qui se touchent comme "intersectées", vous pouvez adapter vos conditions.
pour les segments AB et CD, trouver la pente du CD
slope=(Dy-Cy)/(Dx-Cx)
étendre CD sur A et B et prendre la distance qui le sépare de CD
dist1=slope*(Cx-Ax)+Ay-Cy
dist2=slope*(Dx-Ax)+Ay-Dy
vérifier si elles sont sur les côtés opposés
return dist1*dist2<0
Calculez le point d'intersection des lignes posées sur vos segments (cela signifie essentiellement de résoudre un système d'équation linéaire), puis vérifiez s'il se situe entre les points de départ et d'arrivée de vos segments.
Je pensais apporter une solution Nice Swift:
struct Pt {
var x: Double
var y: Double
}
struct LineSegment {
var p1: Pt
var p2: Pt
}
func doLineSegmentsIntersect(ls1: LineSegment, ls2: LineSegment) -> Bool {
if (ls1.p2.x-ls1.p1.x == 0) { //handle vertical segment1
if (ls2.p2.x-ls2.p1.x == 0) {
//both lines are vertical and parallel
return false
}
let x = ls1.p1.x
let slope2 = (ls2.p2.y-ls2.p1.y)/(ls2.p2.x-ls2.p1.x)
let c2 = ls2.p1.y-slope2*ls2.p1.x
let y = x*slope2+c2 // y intersection point
return (y > ls1.p1.y && x < ls1.p2.y) || (y > ls1.p2.y && y < ls1.p1.y) // check if y is between y1,y2 in segment1
}
if (ls2.p2.x-ls2.p1.x == 0) { //handle vertical segment2
let x = ls2.p1.x
let slope1 = (ls1.p2.y-ls1.p1.y)/(ls1.p2.x-ls1.p1.x)
let c1 = ls1.p1.y-slope1*ls1.p1.x
let y = x*slope1+c1 // y intersection point
return (y > ls2.p1.y && x < ls2.p2.y) || (y > ls2.p2.y && y < ls2.p1.y) // validate that y is between y1,y2 in segment2
}
let slope1 = (ls1.p2.y-ls1.p1.y)/(ls1.p2.x-ls1.p1.x)
let slope2 = (ls2.p2.y-ls2.p1.y)/(ls2.p2.x-ls2.p1.x)
if (slope1 == slope2) { //segments are parallel
return false
}
let c1 = ls1.p1.y-slope1*ls1.p1.x
let c2 = ls2.p1.y-slope2*ls2.p1.x
let x = (c2-c1)/(slope1-slope2)
return (((x > ls1.p1.x && x < ls1.p2.x) || (x > ls1.p2.x && x < ls1.p1.x)) &&
((x > ls2.p1.x && x < ls2.p2.x) || (x > ls2.p2.x && x < ls2.p1.x)))
//validate that x is between x1,x2 in both segments
}
C'est ma façon de vérifier le croisement de lignes et l'endroit où l'intersection a lieu. Permet d'utiliser x1 à x4 et y1 à y4
Segment1 = {(X1, Y1), (X2, Y2)}
Segment2 = {(X3, Y3), (X4, Y4)}
Ensuite, nous avons besoin de vecteurs pour les représenter
dx1 = X2 - X1
dx2 = X4 - X4
dy1 = Y2 - Y1
dy2 = Y4 - Y3
Maintenant, regardons le déterminant
det = dx1 * dy2 - dx2 * dy1
Si le déterminant est 0,0, les segments de droite sont parallèles. Cela pourrait signifier qu'ils se chevauchent. S'ils se chevauchent uniquement aux extrémités, il existe une solution d'intersection. Sinon, il y aura des solutions infinies. Avec une infinité de solutions, quel est votre point d'intersection? C'est donc un cas particulier intéressant. Si vous savez à l'avance que les lignes ne peuvent pas se chevaucher, vous pouvez simplement vérifier si det == 0.0
et si c'est le cas, dites simplement qu'elles ne se croisent pas et que cela est fait. Sinon, permet de continuer
dx3 = X3 - X1
dy3 = Y3 - Y1
det1 = dx1 * dy3 - dx3 * dy1
det2 = dx2 * dy3 - dx3 * dy2
Maintenant, si det, det1 et det2 sont tous égaux à zéro, vos lignes sont colinéaires et peuvent se chevaucher. Si det est nul mais que det1 ou det2 ne le sont pas, ils ne sont pas colinéaires, mais parallèles, de sorte qu'il n'y a pas d'intersection. Donc ce qui reste maintenant si det est zéro est un problème 1D au lieu de 2D. Nous devrons vérifier l'une des deux manières, selon que dx1 est égal à zéro ou non (pour éviter la division par zéro). Si dx1 est égal à zéro, procédez de la même façon avec les valeurs y plutôt que x ci-dessous.
s = X3 / dx1
t = X4 / dx1
Ceci calcule deux scalers, tels que si nous redimensionnons le vecteur (dx1, dy1) par s nous obtenons le point (x3, y3), et par t nous obtenons (x4, y4). Donc, si s ou t est compris entre 0.0 et 1.0, le point 3 ou 4 se trouve sur notre première ligne. Négatif signifierait que le point est en retard sur le début de notre vecteur, tandis que> 1,0 signifie qu'il est plus en avance sur la fin de notre vecteur. 0.0 signifie qu'il est à (x1, y1) et 1.0 signifie qu'il est à (x2, y2). Si s et t sont <0.0 ou tous les deux> 1.0, ils ne se croisent pas. Et cela gère le cas particulier des lignes parallèles.
Maintenant, si det != 0.0
alors
s = det1 / det
t = det2 / det
if (s < 0.0 || s > 1.0 || t < 0.0 || t > 1.0)
return false // no intersect
Ceci est similaire à ce que nous faisions ci-dessus vraiment. Maintenant, si nous réussissons le test ci-dessus, nos segments de droite se croisent et nous pouvons calculer l'intersection assez facilement, comme ceci:
Ix = X1 + t * dx1
Iy = Y1 + t * dy1
Si vous voulez aller plus loin dans les calculs, examinez la règle de Cramer.
si vos données définissent une ligne, il vous suffit de prouver qu'elles ne sont pas parallèles. Pour ce faire, vous pouvez calculer
alpha = float(y2 - y1) / (x2 - x1).
Si ce coefficient est égal à la fois pour Ligne1 et Ligne2, cela signifie que la ligne est parallèle. Sinon, cela signifie qu'ils vont se croiser.
S'ils sont parallèles, vous devez alors prouver qu'ils ne sont pas identiques. Pour cela, vous calculez
beta = y1 - alpha*x1
Si beta est identique pour Line1 et Line2, cela signifie que vos lignes se croisent car elles sont égales.
S'ils sont des segments, vous devez toujours calculer alpha et bêta comme décrit ci-dessus pour chaque ligne. Ensuite, vous devez vérifier que (beta1 - beta2)/(alpha1 - alpha2) est supérieure à Min (x1_line1, x2_line1) et inférieure à Max (x1_line1, x2_line1)
Implémenté en Java. Cependant, il semble que cela ne fonctionne pas pour les lignes co-linéaires (ou segments de ligne qui existent les uns dans les autres)
public class TestCode
{
public class Point
{
public double x = 0;
public double y = 0;
public Point(){}
}
public class Line
{
public Point p1, p2;
public Line( double x1, double y1, double x2, double y2)
{
p1 = new Point();
p2 = new Point();
p1.x = x1;
p1.y = y1;
p2.x = x2;
p2.y = y2;
}
}
//line segments
private static Line s1;
private static Line s2;
public TestCode()
{
s1 = new Line(0,0,0,10);
s2 = new Line(-1,0,0,10);
}
public TestCode(double x1, double y1,
double x2, double y2,
double x3, double y3,
double x4, double y4)
{
s1 = new Line(x1,y1, x2,y2);
s2 = new Line(x3,y3, x4,y4);
}
public static void main(String args[])
{
TestCode code = null;
////////////////////////////
code = new TestCode(0,0,0,10,
0,1,0,5);
if( intersect(code) )
{ System.out.println( "OK COLINEAR: INTERSECTS" ); }
else
{ System.out.println( "ERROR COLINEAR: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,0,0,10,
0,1,0,10);
if( intersect(code) )
{ System.out.println( "OK COLINEAR: INTERSECTS" ); }
else
{ System.out.println( "ERROR COLINEAR: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,0,10,0,
5,0,15,0);
if( intersect(code) )
{ System.out.println( "OK COLINEAR: INTERSECTS" ); }
else
{ System.out.println( "ERROR COLINEAR: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,0,10,0,
0,0,15,0);
if( intersect(code) )
{ System.out.println( "OK COLINEAR: INTERSECTS" ); }
else
{ System.out.println( "ERROR COLINEAR: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,0,10,10,
1,1,5,5);
if( intersect(code) )
{ System.out.println( "OK COLINEAR: INTERSECTS" ); }
else
{ System.out.println( "ERROR COLINEAR: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,0,0,10,
-1,-1,0,10);
if( intersect(code) )
{ System.out.println( "OK SLOPE END: INTERSECTS" ); }
else
{ System.out.println( "ERROR SLOPE END: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(-10,-10,10,10,
-10,10,10,-10);
if( intersect(code) )
{ System.out.println( "OK SLOPE Intersect(0,0): INTERSECTS" ); }
else
{ System.out.println( "ERROR SLOPE Intersect(0,0): DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(-10,-10,10,10,
-3,-2,50,-2);
if( intersect(code) )
{ System.out.println( "OK SLOPE Line2 VERTIAL: INTERSECTS" ); }
else
{ System.out.println( "ERROR SLOPE Line2 VERTICAL: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(-10,-10,10,10,
50,-2,-3,-2);
if( intersect(code) )
{ System.out.println( "OK SLOPE Line2 (reversed) VERTIAL: INTERSECTS" ); }
else
{ System.out.println( "ERROR SLOPE Line2 (reversed) VERTICAL: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,0,0,10,
1,0,1,10);
if( intersect(code) )
{ System.out.println( "ERROR PARALLEL VERTICAL: INTERSECTS" ); }
else
{ System.out.println( "OK PARALLEL VERTICAL: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,2,10,2,
0,10,10,10);
if( intersect(code) )
{ System.out.println( "ERROR PARALLEL HORIZONTAL: INTERSECTS" ); }
else
{ System.out.println( "OK PARALLEL HORIZONTAL: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,10,5,13.75,
0,18.75,10,15);
if( intersect(code) )
{ System.out.println( "ERROR PARALLEL SLOPE=.75: INTERSECTS" ); }
else
{ System.out.println( "OK PARALLEL SLOPE=.75: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,0,1,1,
2,-1,2,10);
if( intersect(code) )
{ System.out.println( "ERROR SEPERATE SEGMENTS: INTERSECTS" ); }
else
{ System.out.println( "OK SEPERATE SEGMENTS: DO NOT INTERSECT" ); }
////////////////////////////
code = new TestCode(0,0,1,1,
-1,-10,-5,10);
if( intersect(code) )
{ System.out.println( "ERROR SEPERATE SEGMENTS 2: INTERSECTS" ); }
else
{ System.out.println( "OK SEPERATE SEGMENTS 2: DO NOT INTERSECT" ); }
}
public static boolean intersect( TestCode code )
{
return intersect( code.s1, code.s2);
}
public static boolean intersect( Line line1, Line line2 )
{
double i1min = Math.min(line1.p1.x, line1.p2.x);
double i1max = Math.max(line1.p1.x, line1.p2.x);
double i2min = Math.min(line2.p1.x, line2.p2.x);
double i2max = Math.max(line2.p1.x, line2.p2.x);
double iamax = Math.max(i1min, i2min);
double iamin = Math.min(i1max, i2max);
if( Math.max(line1.p1.x, line1.p2.x) < Math.min(line2.p1.x, line2.p2.x) )
return false;
double m1 = (line1.p2.y - line1.p1.y) / (line1.p2.x - line1.p1.x );
double m2 = (line2.p2.y - line2.p1.y) / (line2.p2.x - line2.p1.x );
if( m1 == m2 )
return false;
//b1 = line1[0][1] - m1 * line1[0][0]
//b2 = line2[0][1] - m2 * line2[0][0]
double b1 = line1.p1.y - m1 * line1.p1.x;
double b2 = line2.p1.y - m2 * line2.p1.x;
double x1 = (b2 - b1) / (m1 - m2);
if( (x1 < Math.max(i1min, i2min)) || (x1 > Math.min(i1max, i2max)) )
return false;
return true;
}
}
La sortie jusqu'à présent est
ERROR COLINEAR: DO NOT INTERSECT
ERROR COLINEAR: DO NOT INTERSECT
ERROR COLINEAR: DO NOT INTERSECT
ERROR COLINEAR: DO NOT INTERSECT
ERROR COLINEAR: DO NOT INTERSECT
OK SLOPE END: INTERSECTS
OK SLOPE Intersect(0,0): INTERSECTS
OK SLOPE Line2 VERTIAL: INTERSECTS
OK SLOPE Line2 (reversed) VERTIAL: INTERSECTS
OK PARALLEL VERTICAL: DO NOT INTERSECT
OK PARALLEL HORIZONTAL: DO NOT INTERSECT
OK PARALLEL SLOPE=.75: DO NOT INTERSECT
OK SEPERATE SEGMENTS: DO NOT INTERSECT
OK SEPERATE SEGMENTS 2: DO NOT INTERSECT
C’est ce que j’ai pour AS3, je ne connais pas grand chose à Python mais le concept est là
public function getIntersectingPointF($A:Point, $B:Point, $C:Point, $D:Point):Number {
var A:Point = $A.clone();
var B:Point = $B.clone();
var C:Point = $C.clone();
var D:Point = $D.clone();
var f_ab:Number = (D.x - C.x) * (A.y - C.y) - (D.y - C.y) * (A.x - C.x);
// are lines parallel
if (f_ab == 0) { return Infinity };
var f_cd:Number = (B.x - A.x) * (A.y - C.y) - (B.y - A.y) * (A.x - C.x);
var f_d:Number = (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y);
var f1:Number = f_ab/f_d
var f2:Number = f_cd / f_d
if (f1 == Infinity || f1 <= 0 || f1 >= 1) { return Infinity };
if (f2 == Infinity || f2 <= 0 || f2 >= 1) { return Infinity };
return f1;
}
public function getIntersectingPoint($A:Point, $B:Point, $C:Point, $D:Point):Point
{
var f:Number = getIntersectingPointF($A, $B, $C, $D);
if (f == Infinity || f <= 0 || f >= 1) { return null };
var retPoint:Point = Point.interpolate($A, $B, 1 - f);
return retPoint.clone();
}