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)):
returnFalse# There is no mutual abcisses
Donc, nous avons 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 obtenu deux points par segment, nous sommes en mesure de 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):
returnFalse# Parallel segments
Un point (Xa, Ya) 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) )) or
(Xa > min( max(X1,X2), max(X3,X4) )) ):
returnFalse# intersection is out of boundelse:
returnTrue
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.
Des segments, ce sont des segments, désolé. Pourriez-vous mettre à jour votre réponse en fonction des segments?
aneuryzm
13
Ce n'est pas si compliqué, j'ai écrit un tas d'étapes intermédiaires (non essentielles?) Dans un but de compréhension. Les principaux points à implémenter sont les suivants: Vérifier l'existence d'intervalle mutuel, calculer A1, A2, b1, b2 et Xa, puis vérifier que Xa est inclus dans l'intervalle mutuel. C'est tout :)
OMG_peanuts
2
A1 - A2 ne sera jamais nul car if (A1 == A2) serait retourné avant ce calcul dans ce cas.
inkredibl
3
si A1 == A2 et b1 == b2, les segments sont les uns sur les autres et ont une infinité d'intersections
lynxoïde
5
La formule A1 * x + b1 = y ne gère pas les lignes verticales, donc les segments verticaux doivent être traités séparément avec cette méthode.
dmitri
77
L'utilisateur @ i_4_got pointe vers cette page avec une solution très efficace en Python. Je le reproduis ici pour plus de commodité (car cela m'aurait fait plaisir de l'avoir ici):
defccw(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 intersectdefintersect(A,B,C,D):return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)
J'adore cette solution. Très simple et court! J'ai créé un programme wxPython qui trace une ligne et voit si elle croise une autre ligne. Je n'ai pas pu le placer ici, donc c'est quelque part en dessous de ce commentaire.
user1766438 le
32
Il n'est pas nécessaire de calculer exactement où les segments se croisent, mais seulement de comprendre s'ils se croisent. Cela simplifiera la solution.
L'idée est de traiter un segment comme "l'ancre" et de séparer le deuxième segment en 2 points.
Maintenant, vous devrez trouver la position relative de chaque point par rapport au segment "ancré" (OnLeft, OnRight ou Collinear).
Après avoir fait cela pour les deux points, vérifiez que l'un des points est OnLeft et l'autre OnRight (ou peut-être inclure la position colinéaire, si vous souhaitez également inclure des intersections incorrectes ).
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 images d'exemple pour chaque cas possible.
Implémenter une telle méthode sera beaucoup plus facile que d'implémenter réellement une méthode qui trouve le point d'intersection (étant donné les nombreux cas d'angle que vous devrez également gérer).
Mise à jour
Les fonctions suivantes devraient illustrer l'idée (source: Computational Geometry in C ). Remarque: cet exemple suppose l'utilisation d'entiers. Si vous utilisez plutôt une représentation en virgule flottante (ce qui pourrait évidemment compliquer les choses), alors vous devriez déterminer une valeur epsilon pour indiquer "l'égalité" (principalement pour l' IsCollinearévaluation).
// points "a" and "b" forms the anchored segment.// point "c" is the evaluated pointboolIsOnLeft(Point a, Point b, Point c){
return Area2(a, b, c) > 0;
}
boolIsOnRight(Point a, Point b, Point c){
return Area2(a, b, c) < 0;
}
boolIsCollinear(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)intArea2(Point a, Point b, Point c){
return (b.X - a.X) * (c.Y - a.Y) -
(c.X - a.X) * (b.Y - a.Y);
}
Bien entendu, lors de l'utilisation de ces fonctions, il faut se rappeler de vérifier que chaque segment se trouve "entre" l'autre segment (puisque ce sont des segments finis, et non des lignes infinies).
En outre, en utilisant ces fonctions, vous pouvez comprendre si vous avez un intersection correcte ou incorrecte .
Bon : il n'y a pas de points colinéaires. Les segments se croisent "d'un côté à l'autre".
Mauvais : un segment "touche" seulement l'autre (au moins un des points est colinéaire au segment ancré).
+1 À peu près aussi mon idée. Si vous pensez simplement à l'emplacement des points les uns par rapport aux autres, vous pouvez décider si leurs segments doivent se croiser ou non, sans rien calculer.
Jochen Ritzel
et @ THC4k Uhm, ce n'est en fait pas clair. Par exemple, vérifiez l'image que j'ai ajoutée à la question: les 2 points sont "OnLeft" et "OnRight" mais les 2 segments ne se croisent pas.
aneuryzm
@Patrick, en fait non. Selon lequel des segments est "l'ancre", alors les deux points sont soit OnLeft soit OnRight dans ce cas. (Voir ma réponse mise à jour).
Liran
+1 J'ai vu des dizaines de réponses à ce problème, mais c'est de loin la plus claire, la plus simple et la plus efficace que j'ai vue. :)
Miguel
16
Supposons que les deux segments aient des extrémités A, B et C, D. La manière numériquement robuste de déterminer l'intersection est de vérifier le signe des quatre déterminants:
Pour l'intersection, chaque déterminant de gauche doit avoir le signe opposé de celui de droite, mais il n'y a pas besoin de relation entre les deux lignes. Vous vérifiez essentiellement chaque point d'un segment par rapport à l'autre segment pour vous assurer qu'ils se trouvent sur les côtés opposés de la ligne définie par l'autre segment.
fonctionne-t-il pour les intersections incorrectes, c'est-à-dire lorsque le point d'intersection se trouve sur un segment de ligne?
Sayam Qazi
@SayamQazi Il semble que l'intersection échoue si vous passez au moins l'extrémité d'un segment de ligne. Car si vous êtes sur le segment: je suppose que ce serait une comparaison 0 vs 1 / -1, donc il ne détecterait aucune intersection.
Warty
1
D'ailleurs, pour expliquer ceci: chaque déterminant calcule le produit croisé des points d'extrémité des vecteurs de deux segments de ligne. Le coin supérieur gauche est CA x CB vs DA x DB en haut à droite, par exemple. Cela teste essentiellement de quel côté se trouve un sommet (horloge). J'essaie toujours de comprendre comment cela fonctionne pour les segments de ligne qui ne s'étendent pas indéfiniment.
Warty
7
Vérifier si les segments de ligne se croisent est très facile avec la bibliothèque Shapely en utilisant la intersectsméthode:
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
Basé sur les excellentes réponses de Liran et Grumdrig, voici un code Python complet pour vérifier si les segments fermés se croisent. 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 à virgule flottante nécessitent une modification du test d'égalité des points.
defside(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])
return1if d > 0else (-1if d < 0else0)
defis_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]
#defclosed_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 collinearif s1 == 0and 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 sideif s1 and s1 == s2:
returnFalse
s1 = side(c,d,a)
s2 = side(c,d,b)
# No touching and on the same sideif s1 and s1 == s2:
returnFalsereturnTrue
Le segment @Sam Closed contient ses extrémités. Par exemple, un segment fermé de points de R serait [0, 1] (0 <= x <= 1) par opposition à] 0, 1] (0 <x <= 1)
dmitri
5
Voici une solution utilisant des produits dot:
# assumes line segments are stored in the format [(x0,y0),(x1,y1)]defintersects(s0,s1):
dx0 = s0[1][0]-s0[0][0]
dx1 = s1[1][0]-s1[0][0]
dy0 = s0[1][1]-s0[0][1]
dy1 = s1[1][1]-s1[0][1]
p0 = dy1*(s1[1][0]-s0[0][0]) - dx1*(s1[1][1]-s0[0][1])
p1 = dy1*(s1[1][0]-s0[1][0]) - dx1*(s1[1][1]-s0[1][1])
p2 = dy0*(s0[1][0]-s1[0][0]) - dx0*(s0[1][1]-s1[0][1])
p3 = dy0*(s0[1][0]-s1[1][0]) - dx0*(s0[1][1]-s1[1][1])
return (p0*p1<=0) & (p2*p3<=0)
C'est génial, et j'ai oublié Desmos - c'est parfait pour ce problème! Merci!
ponadto
J'adore votre solution, mais il semble qu'elle échoue si les deux segments de ligne sont alignés
H. Pope
Très agréable. Pour quiconque porte ceci dans une autre langue, assurez-vous d'utiliser float ou int64 car un int32 débordera assez rapidement sur les nombres inférieurs à 1280x720
cet autre gars
4
Vous avez deux segments de ligne. Définissez un segment par les points d'extrémité A et B et le deuxième segment par les points d'extrémité C et D. Il y a 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 faire attention. Un bon code surveillera également les lignes parallèles.)
L'astuce consiste à tester que les points A et B doivent être alignés sur les côtés opposés de la ligne CD, ET que les points C et D doivent se trouver sur les côtés opposés de la ligne AB.
Puisque ce sont des devoirs, je ne vous donnerai pas de solution explicite. Mais un test simple pour voir de quel côté d'une ligne tombe un point consiste à utiliser un produit scalaire. Ainsi, pour une ligne CD donnée, calculez le vecteur normal de 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. Faites maintenant le même test pour l'autre ligne, AB. Il a le 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 déterminer comment calculer un vecteur normal. (En 2D, c'est trivial, mais votre code se souciera-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 soucier des segments de ligne qui se trouvent le long de la 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.
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 vérifier si deux segments se croisent également.
// 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));
defon_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])):
returnTruereturnFalsedeforientation(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:
return0# colinearelif val > 0:
return1# clockwiseelse:
return2# counter-clockwisedefdo_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 caseif (o1 != o2 and o3 != o4):
returnTrue# Special Cases# p1, q1 and p2 are colinear and p2 lies on segment p1q1if (o1 == 0and on_segment(p1, p2, q1)):
returnTrue# p1, q1 and p2 are colinear and q2 lies on segment p1q1if (o2 == 0and on_segment(p1, q2, q1)):
returnTrue# p2, q2 and p1 are colinear and p1 lies on segment p2q2if (o3 == 0and on_segment(p2, p1, q2)):
returnTrue# p2, q2 and q1 are colinear and q1 lies on segment p2q2if (o4 == 0and on_segment(p2, q1, q2)):
returnTruereturnFalse# Doesn't fall in any of the above cases
Voici une fonction de test pour vérifier qu'elle fonctionne.
closed_segment_intersect()à partir du code de test n'est pas défini.
hhquark
1
@hhquark Merci. J'ai maintenant supprimé ces lignes. J'ai inclus ces lignes lors des tests pour vérifier que mon implémentation est conforme à l'implémentation d'une autre réponse ( stackoverflow.com/a/18524383/7474256 , je pense).
Fabian Ying
1
pour les segments AB et CD, trouvez la pente de CD
slope=(Dy-Cy)/(Dx-Cx)
étendre le CD sur A et B et prendre la distance jusqu'au CD en montant
Êtes-vous sûr des formules? Comme les coordonnées de B ne sont pas utilisées, comment pouvez-vous trouver l'intersection de AB et CD sans considérer les 4 sommets?
mac13k
1
Je pense qu'il devrait y avoir: dist2 = pente * (Dx-Bx) + By-Dy
mac13k
1
Puisque vous ne mentionnez pas que vous souhaitez 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 OMG_peanuts est une approche plus rapide. Cependant, si vous souhaitez simplement savoir si les lignes se croisent ou non, vous pouvez le faire en utilisant l'équation de ligne (ax + by + c = 0). L'approche est la suivante:
Commençons par deux segments de ligne: le segment 1 et le segment 2.
Vérifiez si les deux segments de ligne sont des lignes de longueur différente de zéro 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, calculez la pente de la droite puis obtenez l'équation d'une droite sous la forme de ax + by + c = 0. Maintenant, calculez la valeur de f = ax + by + c pour les deux points du autre segment de ligne (répétez ceci également pour l'autre segment de ligne).
Maintenant, il ne reste plus que les différents cas. Si f = 0 pour n'importe quel point, alors les deux lignes se touchent en un point. Si f1_1 et f1_2 sont égaux ou f2_1 et f2_2 sont égaux, alors les lignes ne se coupent pas. Si f1_1 et f1_2 sont inégaux et f2_1 et f2_2 sont inégaux, alors les segments de ligne se croisent. Selon que vous souhaitez considérer les lignes qui se touchent comme "se croisant" ou non, vous pouvez adapter vos conditions.
Ce code ne calcule pas a1et ne fonctionne pas pour les lignes orthogonales.
Björn Lindqvist
1
Nous pouvons également résoudre ce problème en utilisant des vecteurs.
Définissons les segments comme [start, end]. Étant donné deux de ces segments [A, B]et [C, D]que les deux ont une longueur non nulle, nous pouvons choisir l'un des points d'extrémité à 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]]
De là, nous pouvons rechercher une intersection en calculant t et u in 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:
defintersects(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 >= 0and t <= 1and u >= 0and u <= 1
Si le déterminant est 0,0, les segments de ligne 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, que dites-vous de votre point d'intersection? C'est donc un cas spécial intéressant. Si vous savez à l'avance que les lignes ne peuvent pas se chevaucher, vous pouvez simplement vérifier si det == 0.0et si c'est le cas, dites simplement qu'elles ne se croisent pas et que c'est terminé. Sinon, continuons sur
Maintenant, si det, det1 et det2 sont tous nuls, alors vos lignes sont colinéaires et peuvent se chevaucher. Si det est nul mais que det1 ou det2 ne le sont pas, alors ils ne sont pas colinéaires, mais parallèles, il n'y a donc 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 façons, selon que dx1 est égal à zéro ou non (nous pouvons donc éviter la division par zéro). Si dx1 est égal à zéro, faites simplement la même logique avec les valeurs y plutôt que x ci-dessous.
s = X3 / dx1
t = X4 / dx1
Cela calcule deux scalers, de sorte que si nous mettons à l'échelle 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 derrière 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 tous les deux <0,0 ou les deux sont> 1,0, ils ne se croisent pas. Et cela gère le cas particulier des lignes parallèles.
Maintenant, si det != 0.0alors
s = det1 / det
t = det2 / det
if (s < 0.0 || s > 1.0 || t < 0.0 || t > 1.0)
return false // no intersect
C'est vraiment similaire à ce que nous faisions ci-dessus. Maintenant, si nous réussissons le test ci-dessus, nos segments de ligne se croisent et nous pouvons calculer l'intersection assez facilement comme ceci:
Ix = X1 + t * dx1
Iy = Y1 + t * dy1
Si vous voulez approfondir ce que font les mathématiques, examinez la règle de Cramer.
La réponse de Georgy est de loin la plus propre à mettre en œuvre. J'ai dû chasser cela, car l'exemple du brycboe, bien que simple également, avait des problèmes de colinéarité.
Code de test:
#!/usr/bin/python## Notes on intersection:## https://bryceboe.com/2006/10/23/line-segment-intersection-algorithm/## /programming/3838329/how-can-i-check-if-two-segments-intersectfrom shapely.geometry import LineString
classPoint:def__init__(self,x,y):
self.x = x
self.y = y
defccw(A,B,C):return (C.y-A.y)*(B.x-A.x) > (B.y-A.y)*(C.x-A.x)
defintersect(A,B,C,D):return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)
defShapelyIntersect(A,B,C,D):return LineString([(A.x,A.y),(B.x,B.y)]).intersects(LineString([(C.x,C.y),(D.x,D.y)]))
a = Point(0,0)
b = Point(0,1)
c = Point(1,1)
d = Point(1,0)
'''
Test points:
b(0,1) c(1,1)
a(0,0) d(1,0)
'''# F
print(intersect(a,b,c,d))
# T
print(intersect(a,c,b,d))
print(intersect(b,d,a,c))
print(intersect(d,b,a,c))
# F
print(intersect(a,d,b,c))
# same end point cases:
print("same end points")
# F - not intersected
print(intersect(a,b,a,d))
# T - This shows as intersected
print(intersect(b,a,a,d))
# F - this does not
print(intersect(b,a,d,a))
# F - this does not
print(intersect(a,b,d,a))
print("same end points, using shapely")
# T
print(ShapelyIntersect(a,b,a,d))
# T
print(ShapelyIntersect(b,a,a,d))
# T
print(ShapelyIntersect(b,a,d,a))
# T
print(ShapelyIntersect(a,b,d,a))
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 pour Line1 et Line2, cela signifie que la ligne est parallèle. Sinon, cela signifie qu'ils se croiseront.
S'ils sont parallèles, vous devez prouver qu'ils ne sont pas identiques. Pour cela, vous calculez
beta = y1 - alpha*x1
Si la version bêta est la même pour Line1 et Line2, cela signifie que votre ligne se coupe car elles sont égales
S'ils sont segment, 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érieur à Min (x1_line1, x2_line1) et inférieur à Max (x1_line1, x2_line1)
Calculez le point d'intersection des lignes posées sur vos segments (cela signifie essentiellement résoudre un système d'équations linéaires), puis vérifiez s'il se trouve entre les points de départ et d'arrivée de vos segments.
Implémenté en JAVA. Cependant, il semble que cela ne fonctionne pas pour les lignes colinéaires (alias segments de ligne qui existent les uns dans les autres L1 (0,0) (10,10) L2 (1,1) (2,2)
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
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
}
L'une des solutions ci-dessus fonctionnait si bien que j'ai décidé d'écrire un programme de démonstration complet en utilisant wxPython. Vous devriez pouvoir exécuter ce programme comme ceci: python " votre nom de fichier "
# Click on the window to draw a line.# The program will tell you if this and the other line intersect.import wx
classPoint:def__init__(self, newX, newY):
self.x = newX
self.y = newY
app = wx.App()
frame = wx.Frame(None, wx.ID_ANY, "Main")
p1 = Point(90,200)
p2 = Point(150,80)
mp = Point(0,0) # mouse point
highestX = 0defccw(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 intersectdefintersect(A,B,C,D):return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)
defis_intersection(p1, p2, p3, p4):return intersect(p1, p2, p3, p4)
defdrawIntersection(pc):
mp2 = Point(highestX, mp.y)
if is_intersection(p1, p2, mp, mp2):
pc.DrawText("intersection", 10, 10)
else:
pc.DrawText("no intersection", 10, 10)
defdo_paint(evt):
pc = wx.PaintDC(frame)
pc.DrawLine(p1.x, p1.y, p2.x, p2.y)
pc.DrawLine(mp.x, mp.y, highestX, mp.y)
drawIntersection(pc)
defdo_left_mouse(evt):global mp, highestX
point = evt.GetPosition()
mp = Point(point[0], point[1])
highestX = frame.Size[0]
frame.Refresh()
frame.Bind(wx.EVT_PAINT, do_paint)
frame.Bind(wx.EVT_LEFT_DOWN, do_left_mouse)
frame.Show()
app.MainLoop()
Utilisation d' OMG_Peanuts solution , j'ai traduit en SQL. (Fonction scalaire HANA)
Merci OMG_Peanuts, cela fonctionne très bien. J'utilise de la terre ronde, mais les distances sont petites, donc je pense que ça va.
FUNCTION GA_INTERSECT" ( IN LAT_A1 DOUBLE,
IN LONG_A1 DOUBLE,
IN LAT_A2 DOUBLE,
IN LONG_A2 DOUBLE,
IN LAT_B1 DOUBLE,
IN LONG_B1 DOUBLE,
IN LAT_B2 DOUBLE,
IN LONG_B2 DOUBLE)
RETURNS RET_DOESINTERSECT DOUBLE
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER AS
BEGIN
DECLARE MA DOUBLE;
DECLARE MB DOUBLE;
DECLARE BA DOUBLE;
DECLARE BB DOUBLE;
DECLARE XA DOUBLE;
DECLARE MAX_MIN_X DOUBLE;
DECLARE MIN_MAX_X DOUBLE;
DECLARE DOESINTERSECT INTEGER;
SELECT 1 INTO DOESINTERSECT FROM DUMMY;
IF LAT_A2-LAT_A1 != 0 AND LAT_B2-LAT_B1 != 0 THEN
SELECT (LONG_A2 - LONG_A1)/(LAT_A2 - LAT_A1) INTO MA FROM DUMMY;
SELECT (LONG_B2 - LONG_B1)/(LAT_B2 - LAT_B1) INTO MB FROM DUMMY;
IF MA = MB THEN
SELECT 0 INTO DOESINTERSECT FROM DUMMY;
END IF;
END IF;
SELECT LONG_A1-MA*LAT_A1 INTO BA FROM DUMMY;
SELECT LONG_B1-MB*LAT_B1 INTO BB FROM DUMMY;
SELECT (BB - BA) / (MA - MB) INTO XA FROM DUMMY;
-- Max of Mins
IF LAT_A1 < LAT_A2 THEN -- MIN(LAT_A1, LAT_A2) = LAT_A1
IF LAT_B1 < LAT_B2 THEN -- MIN(LAT_B1, LAT_B2) = LAT_B1
IF LAT_A1 > LAT_B1 THEN -- MAX(LAT_A1, LAT_B1) = LAT_A1
SELECT LAT_A1 INTO MAX_MIN_X FROM DUMMY;
ELSE -- MAX(LAT_A1, LAT_B1) = LAT_B1
SELECT LAT_B1 INTO MAX_MIN_X FROM DUMMY;
END IF;
ELSEIF LAT_B2 < LAT_B1 THEN -- MIN(LAT_B1, LAT_B2) = LAT_B2
IF LAT_A1 > LAT_B2 THEN -- MAX(LAT_A1, LAT_B2) = LAT_A1
SELECT LAT_A1 INTO MAX_MIN_X FROM DUMMY;
ELSE -- MAX(LAT_A1, LAT_B2) = LAT_B2
SELECT LAT_B2 INTO MAX_MIN_X FROM DUMMY;
END IF;
END IF;
ELSEIF LAT_A2 < LAT_A1 THEN -- MIN(LAT_A1, LAT_A2) = LAT_A2
IF LAT_B1 < LAT_B2 THEN -- MIN(LAT_B1, LAT_B2) = LAT_B1
IF LAT_A2 > LAT_B1 THEN -- MAX(LAT_A2, LAT_B1) = LAT_A2
SELECT LAT_A2 INTO MAX_MIN_X FROM DUMMY;
ELSE -- MAX(LAT_A2, LAT_B1) = LAT_B1
SELECT LAT_B1 INTO MAX_MIN_X FROM DUMMY;
END IF;
ELSEIF LAT_B2 < LAT_B1 THEN -- MIN(LAT_B1, LAT_B2) = LAT_B2
IF LAT_A2 > LAT_B2 THEN -- MAX(LAT_A2, LAT_B2) = LAT_A2
SELECT LAT_A2 INTO MAX_MIN_X FROM DUMMY;
ELSE -- MAX(LAT_A2, LAT_B2) = LAT_B2
SELECT LAT_B2 INTO MAX_MIN_X FROM DUMMY;
END IF;
END IF;
END IF;
-- Min of Max
IF LAT_A1 > LAT_A2 THEN -- MAX(LAT_A1, LAT_A2) = LAT_A1
IF LAT_B1 > LAT_B2 THEN -- MAX(LAT_B1, LAT_B2) = LAT_B1
IF LAT_A1 < LAT_B1 THEN -- MIN(LAT_A1, LAT_B1) = LAT_A1
SELECT LAT_A1 INTO MIN_MAX_X FROM DUMMY;
ELSE -- MIN(LAT_A1, LAT_B1) = LAT_B1
SELECT LAT_B1 INTO MIN_MAX_X FROM DUMMY;
END IF;
ELSEIF LAT_B2 > LAT_B1 THEN -- MAX(LAT_B1, LAT_B2) = LAT_B2
IF LAT_A1 < LAT_B2 THEN -- MIN(LAT_A1, LAT_B2) = LAT_A1
SELECT LAT_A1 INTO MIN_MAX_X FROM DUMMY;
ELSE -- MIN(LAT_A1, LAT_B2) = LAT_B2
SELECT LAT_B2 INTO MIN_MAX_X FROM DUMMY;
END IF;
END IF;
ELSEIF LAT_A2 > LAT_A1 THEN -- MAX(LAT_A1, LAT_A2) = LAT_A2
IF LAT_B1 > LAT_B2 THEN -- MAX(LAT_B1, LAT_B2) = LAT_B1
IF LAT_A2 < LAT_B1 THEN -- MIN(LAT_A2, LAT_B1) = LAT_A2
SELECT LAT_A2 INTO MIN_MAX_X FROM DUMMY;
ELSE -- MIN(LAT_A2, LAT_B1) = LAT_B1
SELECT LAT_B1 INTO MIN_MAX_X FROM DUMMY;
END IF;
ELSEIF LAT_B2 > LAT_B1 THEN -- MAX(LAT_B1, LAT_B2) = LAT_B2
IF LAT_A2 < LAT_B2 THEN -- MIN(LAT_A2, LAT_B2) = LAT_A2
SELECT LAT_A2 INTO MIN_MAX_X FROM DUMMY;
ELSE -- MIN(LAT_A2, LAT_B2) = LAT_B2
SELECT LAT_B2 INTO MIN_MAX_X FROM DUMMY;
END IF;
END IF;
END IF;
IF XA < MAX_MIN_X OR
XA > MIN_MAX_X THEN
SELECT 0 INTO DOESINTERSECT FROM DUMMY;
END IF;
RET_DOESINTERSECT := :DOESINTERSECT;
END;
Réponses:
L'équation d'une ligne est:
Pour un segment, c'est exactement la même chose, sauf que x est inclus sur un intervalle I.
Si vous avez deux segments, définis comme suit:
L'abcisse Xa du point d'intersection potentiel (Xa, Ya) doit être contenue à la fois dans les intervalles I1 et I2, définis comme suit:
Et nous pourrions dire que Xa est inclus dans:
Maintenant, nous devons vérifier que cet intervalle Ia existe:
if (max(X1,X2) < min(X3,X4)): return False # There is no mutual abcisses
Donc, nous avons une formule à deux lignes et un intervalle mutuel. Vos formules de ligne sont:
Comme nous avons obtenu deux points par segment, nous sommes en mesure de 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) 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) )) or (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.
la source
L'utilisateur @ i_4_got pointe vers cette page avec une solution très efficace en Python. Je le reproduis ici pour plus 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)
la source
Il n'est pas nécessaire de calculer exactement où les segments se croisent, mais seulement de comprendre s'ils se croisent. Cela simplifiera la solution.
L'idée est de traiter un segment comme "l'ancre" et de séparer le deuxième segment en 2 points.
Maintenant, vous devrez trouver la position relative de chaque point par rapport au segment "ancré" (OnLeft, OnRight ou Collinear).
Après avoir fait cela pour les deux points, vérifiez que l'un des points est OnLeft et l'autre OnRight (ou peut-être inclure la position colinéaire, si vous souhaitez également inclure des intersections incorrectes ).
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 images d'exemple pour chaque cas possible.
Implémenter une telle méthode sera beaucoup plus facile que d'implémenter réellement une méthode qui trouve le point d'intersection (étant donné les nombreux cas d'angle que vous devrez également gérer).
Mise à jour
Les fonctions suivantes devraient illustrer l'idée (source: Computational Geometry in C ).
Remarque: cet exemple suppose l'utilisation d'entiers. Si vous utilisez plutôt une représentation en virgule flottante (ce qui pourrait évidemment compliquer les choses), alors vous devriez déterminer une valeur epsilon pour indiquer "l'égalité" (principalement pour l'
IsCollinear
évaluation).// 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 entendu, lors de l'utilisation de ces fonctions, il faut se rappeler de vérifier que chaque segment se trouve "entre" l'autre segment (puisque ce sont des segments finis, et non des lignes infinies).
En outre, en utilisant ces fonctions, vous pouvez comprendre si vous avez un intersection correcte ou incorrecte .
la source
Supposons que les deux segments aient des extrémités A, B et C, D. La manière numériquement robuste de déterminer l'intersection est de vérifier le signe des quatre déterminants:
Pour l'intersection, chaque déterminant de gauche doit avoir le signe opposé de celui de droite, mais il n'y a pas besoin de relation entre les deux lignes. Vous vérifiez essentiellement chaque point d'un segment par rapport à l'autre segment pour vous assurer qu'ils se trouvent sur les côtés opposés de la ligne définie par l'autre segment.
Voir ici: http://www.cs.cmu.edu/~quake/robust.html
la source
Vérifier si les segments de ligne se croisent est très facile avec la bibliothèque Shapely en utilisant la
intersects
méthode: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
la source
Basé sur les excellentes réponses de Liran et Grumdrig, voici un code Python complet pour vérifier si les segments fermés se croisent. 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 à 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
la source
Voici une solution utilisant des produits dot:
# assumes line segments are stored in the format [(x0,y0),(x1,y1)] def intersects(s0,s1): dx0 = s0[1][0]-s0[0][0] dx1 = s1[1][0]-s1[0][0] dy0 = s0[1][1]-s0[0][1] dy1 = s1[1][1]-s1[0][1] p0 = dy1*(s1[1][0]-s0[0][0]) - dx1*(s1[1][1]-s0[0][1]) p1 = dy1*(s1[1][0]-s0[1][0]) - dx1*(s1[1][1]-s0[1][1]) p2 = dy0*(s0[1][0]-s1[0][0]) - dx0*(s0[1][1]-s1[0][1]) p3 = dy0*(s0[1][0]-s1[1][0]) - dx0*(s0[1][1]-s1[1][1]) return (p0*p1<=0) & (p2*p3<=0)
Voici une visualisation dans Desmos: Intersection de segment de ligne
la source
Vous avez deux segments de ligne. Définissez un segment par les points d'extrémité A et B et le deuxième segment par les points d'extrémité C et D. Il y a 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 faire attention. Un bon code surveillera également les lignes parallèles.)
L'astuce consiste à tester que les points A et B doivent être alignés sur les côtés opposés de la ligne CD, ET que les points C et D doivent se trouver sur les côtés opposés de la ligne AB.
Puisque ce sont des devoirs, je ne vous donnerai pas de solution explicite. Mais un test simple pour voir de quel côté d'une ligne tombe un point consiste à utiliser un produit scalaire. Ainsi, pour une ligne CD donnée, calculez le vecteur normal de cette ligne (je l'appellerai N_C.) Maintenant, testez simplement les signes de ces deux résultats:
et
Si ces résultats ont des signes opposés, alors A et B sont des côtés opposés de la ligne CD. Faites maintenant le même test pour l'autre ligne, AB. Il a le vecteur normal N_A. Comparez les signes de
et
Je vous laisse le soin de déterminer comment calculer un vecteur normal. (En 2D, c'est trivial, mais votre code se souciera-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 soucier des segments de ligne qui se trouvent le long de la 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.
la source
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 vérifier si deux segments se croisent également.
// 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));
}
la source
Voici un autre code python pour vérifier si les segments fermés se croisent. Il s'agit de la version réécrite du code C ++ dans http://www.cdn.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ . Cette implémentation 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
Voici une fonction de test pour vérifier qu'elle 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))
la source
closed_segment_intersect()
à partir du code de test n'est pas défini.pour les segments AB et CD, trouvez la pente de CD
étendre le CD sur A et B et prendre la distance jusqu'au CD en montant
vérifier s'ils sont sur les côtés opposés
return dist1*dist2<0
la source
Puisque vous ne mentionnez pas que vous souhaitez 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 OMG_peanuts est une approche plus rapide. Cependant, si vous souhaitez simplement savoir si les lignes se croisent ou non, vous pouvez le faire en utilisant l'équation de ligne (ax + by + c = 0). L'approche est la suivante:
Commençons par deux segments de ligne: le segment 1 et le segment 2.
Vérifiez si les deux segments de ligne sont des lignes de longueur différente de zéro 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, calculez la pente de la droite puis obtenez l'équation d'une droite sous la forme de ax + by + c = 0. Maintenant, calculez la valeur de f = ax + by + c pour les deux points du autre segment de ligne (répétez ceci également pour l'autre segment de ligne).
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);
Maintenant, il ne reste plus que les différents cas. Si f = 0 pour n'importe quel point, alors les deux lignes se touchent en un point. Si f1_1 et f1_2 sont égaux ou f2_1 et f2_2 sont égaux, alors les lignes ne se coupent pas. Si f1_1 et f1_2 sont inégaux et f2_1 et f2_2 sont inégaux, alors les segments de ligne se croisent. Selon que vous souhaitez considérer les lignes qui se touchent comme "se croisant" ou non, vous pouvez adapter vos conditions.
la source
a1
et ne fonctionne pas pour les lignes orthogonales.Nous pouvons également résoudre ce problème en utilisant des vecteurs.
Définissons les segments comme
[start, end]
. Étant donné deux de ces segments[A, B]
et[C, D]
que les deux ont une longueur non nulle, nous pouvons choisir l'un des points d'extrémité à 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]]
De là, nous pouvons rechercher une intersection en calculant t et u in
p + t*r = u*q
. Après avoir joué un peu avec l'équation, nous obtenons: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
la source
C'est ma façon de vérifier le franchissement de ligne et où se produit l'intersection. Permet d'utiliser x1 à x4 et y1 à y4
Ensuite, nous avons besoin de quelques vecteurs pour les représenter
Maintenant, nous regardons le déterminant
Si le déterminant est 0,0, les segments de ligne 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, que dites-vous de votre point d'intersection? C'est donc un cas spécial 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 c'est terminé. Sinon, continuons surMaintenant, si det, det1 et det2 sont tous nuls, alors vos lignes sont colinéaires et peuvent se chevaucher. Si det est nul mais que det1 ou det2 ne le sont pas, alors ils ne sont pas colinéaires, mais parallèles, il n'y a donc 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 façons, selon que dx1 est égal à zéro ou non (nous pouvons donc éviter la division par zéro). Si dx1 est égal à zéro, faites simplement la même logique avec les valeurs y plutôt que x ci-dessous.
Cela calcule deux scalers, de sorte que si nous mettons à l'échelle 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 derrière 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 tous les deux <0,0 ou les deux sont> 1,0, ils ne se croisent pas. Et cela gère le cas particulier des lignes parallèles.
Maintenant, si
det != 0.0
alorss = det1 / det t = det2 / det if (s < 0.0 || s > 1.0 || t < 0.0 || t > 1.0) return false // no intersect
C'est vraiment similaire à ce que nous faisions ci-dessus. Maintenant, si nous réussissons le test ci-dessus, nos segments de ligne se croisent et nous pouvons calculer l'intersection assez facilement comme ceci:
Si vous voulez approfondir ce que font les mathématiques, examinez la règle de Cramer.
la source
La réponse de Georgy est de loin la plus propre à mettre en œuvre. J'ai dû chasser cela, car l'exemple du brycboe, bien que simple également, avait des problèmes de colinéarité.
Code de test:
#!/usr/bin/python # # Notes on intersection: # # https://bryceboe.com/2006/10/23/line-segment-intersection-algorithm/ # # /programming/3838329/how-can-i-check-if-two-segments-intersect from shapely.geometry import LineString class Point: def __init__(self,x,y): self.x = x self.y = y def ccw(A,B,C): return (C.y-A.y)*(B.x-A.x) > (B.y-A.y)*(C.x-A.x) def intersect(A,B,C,D): return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D) def ShapelyIntersect(A,B,C,D): return LineString([(A.x,A.y),(B.x,B.y)]).intersects(LineString([(C.x,C.y),(D.x,D.y)])) a = Point(0,0) b = Point(0,1) c = Point(1,1) d = Point(1,0) ''' Test points: b(0,1) c(1,1) a(0,0) d(1,0) ''' # F print(intersect(a,b,c,d)) # T print(intersect(a,c,b,d)) print(intersect(b,d,a,c)) print(intersect(d,b,a,c)) # F print(intersect(a,d,b,c)) # same end point cases: print("same end points") # F - not intersected print(intersect(a,b,a,d)) # T - This shows as intersected print(intersect(b,a,a,d)) # F - this does not print(intersect(b,a,d,a)) # F - this does not print(intersect(a,b,d,a)) print("same end points, using shapely") # T print(ShapelyIntersect(a,b,a,d)) # T print(ShapelyIntersect(b,a,a,d)) # T print(ShapelyIntersect(b,a,d,a)) # T print(ShapelyIntersect(a,b,d,a))
la source
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
Si ce coefficient est égal pour Line1 et Line2, cela signifie que la ligne est parallèle. Sinon, cela signifie qu'ils se croiseront.
S'ils sont parallèles, vous devez prouver qu'ils ne sont pas identiques. Pour cela, vous calculez
Si la version bêta est la même pour Line1 et Line2, cela signifie que votre ligne se coupe car elles sont égales
S'ils sont segment, 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érieur à Min (x1_line1, x2_line1) et inférieur à Max (x1_line1, x2_line1)
la source
Calculez le point d'intersection des lignes posées sur vos segments (cela signifie essentiellement résoudre un système d'équations linéaires), puis vérifiez s'il se trouve entre les points de départ et d'arrivée de vos segments.
la source
C'est ce que j'ai pour AS3, je ne sais pas grand-chose sur 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(); }
la source
Implémenté en JAVA. Cependant, il semble que cela ne fonctionne pas pour les lignes colinéaires (alias segments de ligne qui existent les uns dans les autres L1 (0,0) (10,10) L2 (1,1) (2,2)
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; } }
Jusqu'à présent, la sortie 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
la source
J'ai pensé apporter une belle solution 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 }
la source
L'une des solutions ci-dessus fonctionnait si bien que j'ai décidé d'écrire un programme de démonstration complet en utilisant wxPython. Vous devriez pouvoir exécuter ce programme comme ceci: python " votre nom de fichier "
# Click on the window to draw a line. # The program will tell you if this and the other line intersect. import wx class Point: def __init__(self, newX, newY): self.x = newX self.y = newY app = wx.App() frame = wx.Frame(None, wx.ID_ANY, "Main") p1 = Point(90,200) p2 = Point(150,80) mp = Point(0,0) # mouse point highestX = 0 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) def is_intersection(p1, p2, p3, p4): return intersect(p1, p2, p3, p4) def drawIntersection(pc): mp2 = Point(highestX, mp.y) if is_intersection(p1, p2, mp, mp2): pc.DrawText("intersection", 10, 10) else: pc.DrawText("no intersection", 10, 10) def do_paint(evt): pc = wx.PaintDC(frame) pc.DrawLine(p1.x, p1.y, p2.x, p2.y) pc.DrawLine(mp.x, mp.y, highestX, mp.y) drawIntersection(pc) def do_left_mouse(evt): global mp, highestX point = evt.GetPosition() mp = Point(point[0], point[1]) highestX = frame.Size[0] frame.Refresh() frame.Bind(wx.EVT_PAINT, do_paint) frame.Bind(wx.EVT_LEFT_DOWN, do_left_mouse) frame.Show() app.MainLoop()
la source
Utilisation d' OMG_Peanuts solution , j'ai traduit en SQL. (Fonction scalaire HANA)
Merci OMG_Peanuts, cela fonctionne très bien. J'utilise de la terre ronde, mais les distances sont petites, donc je pense que ça va.
FUNCTION GA_INTERSECT" ( IN LAT_A1 DOUBLE, IN LONG_A1 DOUBLE, IN LAT_A2 DOUBLE, IN LONG_A2 DOUBLE, IN LAT_B1 DOUBLE, IN LONG_B1 DOUBLE, IN LAT_B2 DOUBLE, IN LONG_B2 DOUBLE) RETURNS RET_DOESINTERSECT DOUBLE LANGUAGE SQLSCRIPT SQL SECURITY INVOKER AS BEGIN DECLARE MA DOUBLE; DECLARE MB DOUBLE; DECLARE BA DOUBLE; DECLARE BB DOUBLE; DECLARE XA DOUBLE; DECLARE MAX_MIN_X DOUBLE; DECLARE MIN_MAX_X DOUBLE; DECLARE DOESINTERSECT INTEGER; SELECT 1 INTO DOESINTERSECT FROM DUMMY; IF LAT_A2-LAT_A1 != 0 AND LAT_B2-LAT_B1 != 0 THEN SELECT (LONG_A2 - LONG_A1)/(LAT_A2 - LAT_A1) INTO MA FROM DUMMY; SELECT (LONG_B2 - LONG_B1)/(LAT_B2 - LAT_B1) INTO MB FROM DUMMY; IF MA = MB THEN SELECT 0 INTO DOESINTERSECT FROM DUMMY; END IF; END IF; SELECT LONG_A1-MA*LAT_A1 INTO BA FROM DUMMY; SELECT LONG_B1-MB*LAT_B1 INTO BB FROM DUMMY; SELECT (BB - BA) / (MA - MB) INTO XA FROM DUMMY; -- Max of Mins IF LAT_A1 < LAT_A2 THEN -- MIN(LAT_A1, LAT_A2) = LAT_A1 IF LAT_B1 < LAT_B2 THEN -- MIN(LAT_B1, LAT_B2) = LAT_B1 IF LAT_A1 > LAT_B1 THEN -- MAX(LAT_A1, LAT_B1) = LAT_A1 SELECT LAT_A1 INTO MAX_MIN_X FROM DUMMY; ELSE -- MAX(LAT_A1, LAT_B1) = LAT_B1 SELECT LAT_B1 INTO MAX_MIN_X FROM DUMMY; END IF; ELSEIF LAT_B2 < LAT_B1 THEN -- MIN(LAT_B1, LAT_B2) = LAT_B2 IF LAT_A1 > LAT_B2 THEN -- MAX(LAT_A1, LAT_B2) = LAT_A1 SELECT LAT_A1 INTO MAX_MIN_X FROM DUMMY; ELSE -- MAX(LAT_A1, LAT_B2) = LAT_B2 SELECT LAT_B2 INTO MAX_MIN_X FROM DUMMY; END IF; END IF; ELSEIF LAT_A2 < LAT_A1 THEN -- MIN(LAT_A1, LAT_A2) = LAT_A2 IF LAT_B1 < LAT_B2 THEN -- MIN(LAT_B1, LAT_B2) = LAT_B1 IF LAT_A2 > LAT_B1 THEN -- MAX(LAT_A2, LAT_B1) = LAT_A2 SELECT LAT_A2 INTO MAX_MIN_X FROM DUMMY; ELSE -- MAX(LAT_A2, LAT_B1) = LAT_B1 SELECT LAT_B1 INTO MAX_MIN_X FROM DUMMY; END IF; ELSEIF LAT_B2 < LAT_B1 THEN -- MIN(LAT_B1, LAT_B2) = LAT_B2 IF LAT_A2 > LAT_B2 THEN -- MAX(LAT_A2, LAT_B2) = LAT_A2 SELECT LAT_A2 INTO MAX_MIN_X FROM DUMMY; ELSE -- MAX(LAT_A2, LAT_B2) = LAT_B2 SELECT LAT_B2 INTO MAX_MIN_X FROM DUMMY; END IF; END IF; END IF; -- Min of Max IF LAT_A1 > LAT_A2 THEN -- MAX(LAT_A1, LAT_A2) = LAT_A1 IF LAT_B1 > LAT_B2 THEN -- MAX(LAT_B1, LAT_B2) = LAT_B1 IF LAT_A1 < LAT_B1 THEN -- MIN(LAT_A1, LAT_B1) = LAT_A1 SELECT LAT_A1 INTO MIN_MAX_X FROM DUMMY; ELSE -- MIN(LAT_A1, LAT_B1) = LAT_B1 SELECT LAT_B1 INTO MIN_MAX_X FROM DUMMY; END IF; ELSEIF LAT_B2 > LAT_B1 THEN -- MAX(LAT_B1, LAT_B2) = LAT_B2 IF LAT_A1 < LAT_B2 THEN -- MIN(LAT_A1, LAT_B2) = LAT_A1 SELECT LAT_A1 INTO MIN_MAX_X FROM DUMMY; ELSE -- MIN(LAT_A1, LAT_B2) = LAT_B2 SELECT LAT_B2 INTO MIN_MAX_X FROM DUMMY; END IF; END IF; ELSEIF LAT_A2 > LAT_A1 THEN -- MAX(LAT_A1, LAT_A2) = LAT_A2 IF LAT_B1 > LAT_B2 THEN -- MAX(LAT_B1, LAT_B2) = LAT_B1 IF LAT_A2 < LAT_B1 THEN -- MIN(LAT_A2, LAT_B1) = LAT_A2 SELECT LAT_A2 INTO MIN_MAX_X FROM DUMMY; ELSE -- MIN(LAT_A2, LAT_B1) = LAT_B1 SELECT LAT_B1 INTO MIN_MAX_X FROM DUMMY; END IF; ELSEIF LAT_B2 > LAT_B1 THEN -- MAX(LAT_B1, LAT_B2) = LAT_B2 IF LAT_A2 < LAT_B2 THEN -- MIN(LAT_A2, LAT_B2) = LAT_A2 SELECT LAT_A2 INTO MIN_MAX_X FROM DUMMY; ELSE -- MIN(LAT_A2, LAT_B2) = LAT_B2 SELECT LAT_B2 INTO MIN_MAX_X FROM DUMMY; END IF; END IF; END IF; IF XA < MAX_MIN_X OR XA > MIN_MAX_X THEN SELECT 0 INTO DOESINTERSECT FROM DUMMY; END IF; RET_DOESINTERSECT := :DOESINTERSECT; END;
la source
Résolu mais toujours pourquoi pas avec python ... :)
def islineintersect(line1, line2): i1 = [min(line1[0][0], line1[1][0]), max(line1[0][0], line1[1][0])] i2 = [min(line2[0][0], line2[1][0]), max(line2[0][0], line2[1][0])] ia = [max(i1[0], i2[0]), min(i1[1], i2[1])] if max(line1[0][0], line1[1][0]) < min(line2[0][0], line2[1][0]): return False m1 = (line1[1][1] - line1[0][1]) * 1. / (line1[1][0] - line1[0][0]) * 1. m2 = (line2[1][1] - line2[0][1]) * 1. / (line2[1][0] - line2[0][0]) * 1. if m1 == m2: return False b1 = line1[0][1] - m1 * line1[0][0] b2 = line2[0][1] - m2 * line2[0][0] x1 = (b2 - b1) / (m1 - m2) if (x1 < max(i1[0], i2[0])) or (x1 > min(i1[1], i2[1])): return False return True
Ce:
print islineintersect([(15, 20), (100, 200)], [(210, 5), (23, 119)])
Production:
True
Et ça:
print islineintersect([(15, 20), (100, 200)], [(-1, -5), (-5, -5)])
Production:
False
la source