Ia = [max( min(X1,X2), min(X3,X4) ),
min( max(X1,X2), max(X3,X4) )]
Agora, precisamos verificar se este intervalo Ia existe:
if (max(X1,X2) < min(X3,X4)):
returnFalse# There is no mutual abcisses
Portanto, temos a fórmula de duas linhas e um intervalo mútuo. Suas fórmulas de linha são:
f1(x) = A1*x + b1 = y
f2(x) = A2*x + b2 = y
Como obtivemos dois pontos por segmento, podemos determinar A1, A2, b1 e 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
Se os segmentos forem paralelos, A1 == A2:
if (A1 == A2):
returnFalse# Parallel segments
Um ponto (Xa, Ya) em ambas as linhas deve verificar ambas as fórmulas f1 e 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
A última coisa a fazer é verificar se Xa está incluído em 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
Além disso, você pode verificar na inicialização se dois dos quatro pontos fornecidos não são iguais para evitar todos os testes.
Segmentos, são segmentos, desculpe. Você poderia atualizar sua resposta a determinados segmentos?
aneuryzm
13
Isso não é tão complicado, eu escrevi muitos passos intermediários (não essenciais?) Em um propósito de compreensão. Os principais pontos para implementos são apenas: Verifique a existência de intervalo mútuo, calcule A1, A2, b1, b2 e Xa e verifique se Xa está incluído no intervalo mútuo. Isso é tudo :)
OMG_peanuts
3
A1 - A2 nunca será zero porque se (A1 == A2) teria retornado antes deste cálculo nesse caso.
inkredibl de
3
se A1 == A2 e b1 == b2, os segmentos estão um em cima do outro e têm infinitas interseções
lincóide
6
A fórmula A1 * x + b1 = y não trata de linhas verticais, portanto, segmentos verticais devem ser tratados separadamente com este método.
dmitri
78
O usuário @ i_4_got aponta para esta página com uma solução muito eficiente em Python. Eu reproduzo aqui por conveniência (já que ficaria feliz em tê-lo aqui):
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)
Adoro esta solução. Muito simples e curto! Eu fiz um programa wxPython que desenha uma linha e vê se ela se cruza com outra linha. Não consegui colocá-lo aqui, por isso está em algum lugar abaixo deste comentário.
user1766438
33
Você não precisa calcular exatamente onde os segmentos se cruzam, mas apenas entender se eles se cruzam. Isso simplificará a solução.
A ideia é tratar um segmento como a "âncora" e separar o segundo segmento em 2 pontos.
Agora, você terá que encontrar a posição relativa de cada ponto ao segmento "ancorado" (OnLeft, OnRight ou Collinear).
Depois de fazer isso para ambos os pontos, verifique se um dos pontos está OnLeft e o outro está OnRight (ou talvez inclua a posição Collinear, se desejar incluir interseções inadequadas também).
Você deve então repetir o processo com as funções de âncora e segmentos separados.
Existe uma interseção se, e somente se, um dos pontos for OnLeft e o outro for OnRight. Veja este link para uma explicação mais detalhada com imagens de exemplo para cada caso possível.
Implementar tal método será muito mais fácil do que implementar um método que encontre o ponto de interseção (dados os muitos casos de canto que você também terá que lidar).
Atualizar
As funções a seguir devem ilustrar a ideia (fonte: Geometria Computacional em C ). Observação: Este exemplo pressupõe o uso de inteiros. Se você estiver usando alguma representação de ponto flutuante (o que poderia obviamente complicar as coisas), então você deve determinar algum valor épsilon para indicar "igualdade" (principalmente para a IsCollinearavaliação).
// 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);
}
Claro, ao usar essas funções, deve-se lembrar de verificar se cada segmento está "entre" o outro segmento (uma vez que esses são segmentos finitos, e não linhas infinitas).
Além disso, usando essas funções, você pode entender se tem um cruzamento adequado ou impróprio .
Própria : Não há pontos colineares. Os segmentos se cruzam "de lado a lado".
Impróprio : um segmento apenas "toca" o outro (pelo menos um dos pontos é colinear ao segmento ancorado).
1 Quase ideia minha também. Se você apenas pensar em onde os pontos estão em relação uns aos outros, você pode decidir se seus segmentos devem se cruzar ou não, sem calcular nada.
Jochen Ritzel
e @ THC4k Uhm, na verdade não está claro. Por exemplo, verifique a imagem que adicionei à pergunta: os 2 pontos são "OnLeft" e "OnRight", mas os 2 segmentos não estão se cruzando.
aneuryzm,
@Patrick, na verdade não. Dependendo de qual dos segmentos é a "âncora", os dois pontos são OnLeft ou OnRight neste caso. (Veja minha resposta atualizada).
Liran,
1
+1 Já vi dezenas de respostas para esse problema, mas essa é de longe a mais clara, mais simples e mais eficiente que já vi. :)
Miguel de
16
Suponha que os dois segmentos tenham pontos finais A, B e C, D. A maneira numericamente robusta de determinar a interseção é verificar o sinal dos quatro determinantes:
Para a interseção, cada determinante da esquerda deve ter o sinal oposto ao da direita, mas não precisa haver nenhuma relação entre as duas linhas. Basicamente, você verifica cada ponto de um segmento em relação ao outro segmento para ter certeza de que estão em lados opostos da linha definida pelo outro segmento.
funciona para interseções impróprias, ou seja, quando o ponto de interseção está em um segmento de linha?
Sayam Qazi
@SayamQazi Parece falhar a interseção se você estiver passando pelo ponto final de um segmento de linha, pelo menos. Pois, se você estiver no segmento: Suponho que seria uma comparação 0 vs 1 / -1, portanto, não detectaria nenhuma interseção.
Warty de
1
A propósito, para explicar isso: cada determinante está computando o produto cruzado dos pontos finais dos vetores de dois segmentos de linha. A parte superior esquerda é CA x CB vs parte superior direita DA x DB, por exemplo. Isso testa essencialmente em que lado está o vértice (clockness). Ainda estou tentando descobrir como funciona para segmentos de linha que não se estendem infinitamente.
Warty
8
Verificar se os segmentos de linha se cruzam é muito fácil com a biblioteca Shapely usando o intersectsmétodo:
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
Com base nas excelentes respostas de Liran e Grumdrig, aqui está um código Python completo para verificar se segmentos fechados se cruzam. Funciona para segmentos colineares, segmentos paralelos ao eixo Y, segmentos degenerados (o diabo está nos detalhes). Assume coordenadas inteiras. As coordenadas de ponto flutuante requerem uma modificação no teste de igualdade de pontos.
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
@Sam O segmento fechado contém seus pontos finais. Por exemplo, um segmento fechado de pontos de R seria [0, 1] (0 <= x <= 1) em oposição a dizer] 0, 1] (0 <x <= 1)
dmitri
6
Aqui está uma solução usando produtos escalares:
# 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)
Isso é incrível, e esqueci o Desmos - é perfeito para esse problema! Obrigado!
Ponadto de
Adorei sua solução, mas parece que ela falha se os dois segmentos de linha estiverem alinhados
H. Pope
Muito agradável. Para qualquer outro portando isso para um idioma diferente, certifique-se de usar float ou int64, pois um int32 irá transbordar rapidamente em números menores que 1280x720
aquele outro cara
4
Você tem dois segmentos de linha. Defina um segmento pelos pontos finais A e B e o segundo segmento pelos pontos finais C e D. Há um bom truque para mostrar que eles devem se cruzar, DENTRO dos limites dos segmentos. (Observe que as próprias linhas podem se cruzar além dos limites dos segmentos, então você deve ter cuidado. Um bom código também observará as linhas paralelas.)
O truque é testar se os pontos A e B devem se alinhar em lados opostos da linha CD, E se os pontos C e D devem estar em lados opostos da linha AB.
Já que isso é dever de casa, não vou dar uma solução explícita. Mas um teste simples para ver em que lado de uma linha um ponto cai é usar um produto escalar. Assim, para uma determinada linha CD, calcule o vetor normal para essa linha (vou chamá-lo de N_C.) Agora, simplesmente teste os sinais desses dois resultados:
dot(A-C,N_C)
e
dot(B-C,N_C)
Se esses resultados tiverem sinais opostos, A e B são lados opostos da linha CD. Agora faça o mesmo teste para a outra linha, AB. Possui vetor normal N_A. Compare os sinais de
dot(C-A,N_A)
e
dot(D-A,N_A)
Vou deixar para você descobrir como calcular um vetor normal. (Em 2-d, isso é trivial, mas seu código se preocupará se A e B são pontos distintos? Da mesma forma, C e D são distintos?)
Você ainda precisa se preocupar com os segmentos de linha que estão ao longo da mesma linha infinita ou se um ponto realmente cai no próprio segmento de linha. Um bom código atenderá a todos os problemas possíveis.
Aqui está o código C para verificar se dois pontos estão nos lados opostos do segmento de linha. Usando este código, você pode verificar se dois segmentos se cruzam também.
// 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
Abaixo está uma função de teste para verificar se funciona.
closed_segment_intersect()do código de teste não está definido.
hhquark de
1
@hhquark Obrigado. Agora removi essas linhas. Incluí essas linhas durante o teste para verificar se minha implementação está de acordo com a implementação de outra resposta ( stackoverflow.com/a/18524383/7474256 , eu acho).
Fabian Ying
1
para os segmentos AB e CD, encontre a inclinação de CD
slope=(Dy-Cy)/(Dx-Cx)
estenda o CD sobre A e B, e tome a distância até o CD subindo
Tem certeza sobre as fórmulas? Como as coordenadas de B não são usadas, como você pode encontrar a interseção de AB e CD sem considerar todos os 4 vértices?
Como você não mencionou que deseja encontrar o ponto de interseção da linha, o problema se torna mais simples de resolver. Se você precisa do ponto de interseção, a resposta OMG_peanuts é uma abordagem mais rápida. No entanto, se você deseja apenas descobrir se as linhas se cruzam ou não, você pode fazer isso usando a equação da linha (ax + by + c = 0). A abordagem é a seguinte:
Vamos começar com dois segmentos de linha: segmento 1 e segmento 2.
Verifique se os dois segmentos de linha são linhas de comprimento diferente de zero e segmentos distintos.
Daqui em diante, presumo que os dois segmentos têm comprimento diferente de zero e são distintos. Para cada segmento de linha, calcule a inclinação da linha e, em seguida, obtenha a equação de uma linha na forma de ax + by + c = 0. Agora, calcule o valor de f = ax + by + c para os dois pontos do outro segmento de linha (repita isso para o outro segmento de linha também).
Agora tudo o que resta são os diferentes casos. Se f = 0 para qualquer ponto, as duas linhas se tocam em um ponto. Se f1_1 e f1_2 forem iguais ou f2_1 e f2_2 forem iguais, então as linhas não se cruzam. Se f1_1 e f1_2 forem desiguais e f2_1 e f2_2 forem desiguais, os segmentos de linha se cruzam. Dependendo se você deseja considerar as linhas que se tocam como "intersecção" ou não, você pode adaptar suas condições.
Este código não calcula a1e não funciona para linhas ortogonais.
Björn Lindqvist
1
Também podemos resolver isso utilizando vetores.
Vamos definir os segmentos como [start, end]. Dados dois desses segmentos [A, B]e [C, D]que ambos têm comprimento diferente de zero, podemos escolher um dos pontos finais a ser usado como ponto de referência para obtermos três vetores:
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]]
A partir daí, podemos procurar uma interseção calculando t e u em p + t*r = u*q. Depois de brincar um pouco com a equação, obtemos:
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]
Assim, a função é:
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
Se o determinante for 0,0, os segmentos de linha são paralelos. Isso pode significar que eles se sobrepõem. Se eles se sobrepõem apenas nos pontos finais, então há uma solução de interseção. Caso contrário, haverá soluções infinitas. Com infinitas soluções, qual é o seu ponto de intersecção? Portanto, é um caso especial interessante. Se você sabe com antecedência que as linhas não podem se sobrepor, você pode apenas verificar det == 0.0se sim, apenas dizer que elas não se cruzam e pronto. Caso contrário, vamos continuar
Agora, se det, det1 e det2 são todos zero, então suas linhas são colineares e podem se sobrepor. Se det for zero, mas det1 ou det2 não forem, eles não serão colineares, mas paralelos, portanto, não há interseção. Então, o que resta agora se det for zero é um problema 1D em vez de 2D. Precisaremos verificar uma de duas maneiras, dependendo se dx1 é zero ou não (para que possamos evitar a divisão por zero). Se dx1 for zero, faça a mesma lógica com os valores de y em vez de x abaixo.
s = X3 / dx1
t = X4 / dx1
Isso calcula dois escalonadores, de modo que, se escalarmos o vetor (dx1, dy1) em s, obteremos o ponto (x3, y3), e em t obteremos (x4, y4). Portanto, se s ou t estiver entre 0,0 e 1,0, o ponto 3 ou 4 estará em nossa primeira linha. Negativo significa que o ponto está atrás do início do nosso vetor, enquanto> 1.0 significa que está mais à frente do final do nosso vetor. 0,0 significa que está em (x1, y1) e 1,0 significa que está em (x2, y2). Se s e t forem <0,0 ou ambos forem> 1,0, eles não se cruzam. E isso trata do caso especial das linhas paralelas.
Agora se det != 0.0então
s = det1 / det
t = det2 / det
if (s < 0.0 || s > 1.0 || t < 0.0 || t > 1.0)
return false // no intersect
Isso é realmente semelhante ao que estávamos fazendo acima. Agora, se passarmos no teste acima, nossos segmentos de linha se cruzam e podemos calcular a interseção facilmente, assim:
Ix = X1 + t * dx1
Iy = Y1 + t * dy1
Se você quiser se aprofundar no que a matemática está fazendo, dê uma olhada na Regra de Cramer.
A resposta de Georgy é a mais limpa de implementar, de longe. Tive que perseguir isso, já que o exemplo do brycboe, embora simples também, tinha problemas com colinearidade.
Código para teste:
#!/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))
se seus dados definem linha, você só precisa provar que eles não são paralelos. Para fazer isso, você pode calcular
alpha = float(y2 - y1) / (x2 - x1).
Se este coeficiente for igual para Linha1 e Linha2, significa que as linhas são paralelas. Caso contrário, significa que eles se cruzarão.
Se eles forem paralelos, você terá que provar que não são iguais. Para isso, você calcula
beta = y1 - alpha*x1
Se beta é o mesmo para Linha1 e Linha2, significa que sua linha se cruza, pois são iguais
Se eles forem um segmento, você ainda terá que calcular alfa e beta conforme descrito acima para cada linha. Então você tem que verificar se (beta1 - beta2) / (alpha1 - alpha2) é maior que Min (x1_line1, x2_line1) e menor que Max (x1_line1, x2_line1)
Calcule o ponto de interseção das linhas que colocam em seus segmentos (significa basicamente resolver um sistema de equações lineares), depois verifique se está entre os pontos inicial e final de seus segmentos.
Implementado em JAVA. No entanto, parece que não funciona para linhas colineares (também conhecidas como segmentos de linha que existem entre si 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
}
Uma das soluções acima funcionou tão bem que decidi escrever um programa de demonstração completo usando wxPython. Você deve ser capaz de executar este programa assim: python " seu nome de arquivo "
# 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()
Usando a solução OMG_Peanuts , traduzi para SQL. (Função escalar HANA)
Obrigado OMG_Peanuts, funciona muito bem. Estou usando a Terra redonda, mas as distâncias são pequenas, então acho que está tudo bem.
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;
Respostas:
A equação de uma linha é:
Para um segmento, é exatamente o mesmo, exceto que x está incluído em um intervalo I.
Se você tiver dois segmentos, definidos como segue:
O abcisse Xa do ponto potencial de interseção (Xa, Ya) deve estar contido em ambos os intervalos I1 e I2, definidos como segue:
I1 = [min(X1,X2), max(X1,X2)] I2 = [min(X3,X4), max(X3,X4)]
E poderíamos dizer que Xa está incluído em:
Ia = [max( min(X1,X2), min(X3,X4) ), min( max(X1,X2), max(X3,X4) )]
Agora, precisamos verificar se este intervalo Ia existe:
if (max(X1,X2) < min(X3,X4)): return False # There is no mutual abcisses
Portanto, temos a fórmula de duas linhas e um intervalo mútuo. Suas fórmulas de linha são:
Como obtivemos dois pontos por segmento, podemos determinar A1, A2, b1 e 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
Se os segmentos forem paralelos, A1 == A2:
if (A1 == A2): return False # Parallel segments
Um ponto (Xa, Ya) em ambas as linhas deve verificar ambas as fórmulas f1 e 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
A última coisa a fazer é verificar se Xa está incluído em 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
Além disso, você pode verificar na inicialização se dois dos quatro pontos fornecidos não são iguais para evitar todos os testes.
fonte
O usuário @ i_4_got aponta para esta página com uma solução muito eficiente em Python. Eu reproduzo aqui por conveniência (já que ficaria feliz em tê-lo aqui):
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)
fonte
Você não precisa calcular exatamente onde os segmentos se cruzam, mas apenas entender se eles se cruzam. Isso simplificará a solução.
A ideia é tratar um segmento como a "âncora" e separar o segundo segmento em 2 pontos.
Agora, você terá que encontrar a posição relativa de cada ponto ao segmento "ancorado" (OnLeft, OnRight ou Collinear).
Depois de fazer isso para ambos os pontos, verifique se um dos pontos está OnLeft e o outro está OnRight (ou talvez inclua a posição Collinear, se desejar incluir interseções inadequadas também).
Você deve então repetir o processo com as funções de âncora e segmentos separados.
Existe uma interseção se, e somente se, um dos pontos for OnLeft e o outro for OnRight. Veja este link para uma explicação mais detalhada com imagens de exemplo para cada caso possível.
Implementar tal método será muito mais fácil do que implementar um método que encontre o ponto de interseção (dados os muitos casos de canto que você também terá que lidar).
Atualizar
As funções a seguir devem ilustrar a ideia (fonte: Geometria Computacional em C ).
Observação: Este exemplo pressupõe o uso de inteiros. Se você estiver usando alguma representação de ponto flutuante (o que poderia obviamente complicar as coisas), então você deve determinar algum valor épsilon para indicar "igualdade" (principalmente para a
IsCollinear
avaliação).// 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); }
Claro, ao usar essas funções, deve-se lembrar de verificar se cada segmento está "entre" o outro segmento (uma vez que esses são segmentos finitos, e não linhas infinitas).
Além disso, usando essas funções, você pode entender se tem um cruzamento adequado ou impróprio .
fonte
Suponha que os dois segmentos tenham pontos finais A, B e C, D. A maneira numericamente robusta de determinar a interseção é verificar o sinal dos quatro determinantes:
Para a interseção, cada determinante da esquerda deve ter o sinal oposto ao da direita, mas não precisa haver nenhuma relação entre as duas linhas. Basicamente, você verifica cada ponto de um segmento em relação ao outro segmento para ter certeza de que estão em lados opostos da linha definida pelo outro segmento.
Veja aqui: http://www.cs.cmu.edu/~quake/robust.html
fonte
Verificar se os segmentos de linha se cruzam é muito fácil com a biblioteca Shapely usando o
intersects
método: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
fonte
Com base nas excelentes respostas de Liran e Grumdrig, aqui está um código Python completo para verificar se segmentos fechados se cruzam. Funciona para segmentos colineares, segmentos paralelos ao eixo Y, segmentos degenerados (o diabo está nos detalhes). Assume coordenadas inteiras. As coordenadas de ponto flutuante requerem uma modificação no teste de igualdade de pontos.
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
fonte
Aqui está uma solução usando produtos escalares:
# 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)
Aqui está uma visualização no Desmos: Intersecção de segmento de linha
fonte
Você tem dois segmentos de linha. Defina um segmento pelos pontos finais A e B e o segundo segmento pelos pontos finais C e D. Há um bom truque para mostrar que eles devem se cruzar, DENTRO dos limites dos segmentos. (Observe que as próprias linhas podem se cruzar além dos limites dos segmentos, então você deve ter cuidado. Um bom código também observará as linhas paralelas.)
O truque é testar se os pontos A e B devem se alinhar em lados opostos da linha CD, E se os pontos C e D devem estar em lados opostos da linha AB.
Já que isso é dever de casa, não vou dar uma solução explícita. Mas um teste simples para ver em que lado de uma linha um ponto cai é usar um produto escalar. Assim, para uma determinada linha CD, calcule o vetor normal para essa linha (vou chamá-lo de N_C.) Agora, simplesmente teste os sinais desses dois resultados:
e
Se esses resultados tiverem sinais opostos, A e B são lados opostos da linha CD. Agora faça o mesmo teste para a outra linha, AB. Possui vetor normal N_A. Compare os sinais de
e
Vou deixar para você descobrir como calcular um vetor normal. (Em 2-d, isso é trivial, mas seu código se preocupará se A e B são pontos distintos? Da mesma forma, C e D são distintos?)
Você ainda precisa se preocupar com os segmentos de linha que estão ao longo da mesma linha infinita ou se um ponto realmente cai no próprio segmento de linha. Um bom código atenderá a todos os problemas possíveis.
fonte
Aqui está o código C para verificar se dois pontos estão nos lados opostos do segmento de linha. Usando este código, você pode verificar se dois segmentos se cruzam também.
// 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));
}
fonte
Aqui está outro código Python para verificar se os segmentos fechados se cruzam. É a versão reescrita do código C ++ em http://www.cdn.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ . Esta implementação cobre todos os casos especiais (por exemplo, todos os pontos colineares).
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
Abaixo está uma função de teste para verificar se funciona.
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))
fonte
closed_segment_intersect()
do código de teste não está definido.para os segmentos AB e CD, encontre a inclinação de CD
estenda o CD sobre A e B, e tome a distância até o CD subindo
verifique se eles estão em lados opostos
return dist1*dist2<0
fonte
Como você não mencionou que deseja encontrar o ponto de interseção da linha, o problema se torna mais simples de resolver. Se você precisa do ponto de interseção, a resposta OMG_peanuts é uma abordagem mais rápida. No entanto, se você deseja apenas descobrir se as linhas se cruzam ou não, você pode fazer isso usando a equação da linha (ax + by + c = 0). A abordagem é a seguinte:
Vamos começar com dois segmentos de linha: segmento 1 e segmento 2.
Verifique se os dois segmentos de linha são linhas de comprimento diferente de zero e segmentos distintos.
Daqui em diante, presumo que os dois segmentos têm comprimento diferente de zero e são distintos. Para cada segmento de linha, calcule a inclinação da linha e, em seguida, obtenha a equação de uma linha na forma de ax + by + c = 0. Agora, calcule o valor de f = ax + by + c para os dois pontos do outro segmento de linha (repita isso para o outro segmento de linha também).
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);
Agora tudo o que resta são os diferentes casos. Se f = 0 para qualquer ponto, as duas linhas se tocam em um ponto. Se f1_1 e f1_2 forem iguais ou f2_1 e f2_2 forem iguais, então as linhas não se cruzam. Se f1_1 e f1_2 forem desiguais e f2_1 e f2_2 forem desiguais, os segmentos de linha se cruzam. Dependendo se você deseja considerar as linhas que se tocam como "intersecção" ou não, você pode adaptar suas condições.
fonte
a1
e não funciona para linhas ortogonais.Também podemos resolver isso utilizando vetores.
Vamos definir os segmentos como
[start, end]
. Dados dois desses segmentos[A, B]
e[C, D]
que ambos têm comprimento diferente de zero, podemos escolher um dos pontos finais a ser usado como ponto de referência para obtermos três vetores: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]]
A partir daí, podemos procurar uma interseção calculando t e u em
p + t*r = u*q
. Depois de brincar um pouco com a equação, obtemos:Assim, a função é:
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
fonte
Esta é a minha maneira de verificar o cruzamento da linha e onde ocorre a interseção. Vamos usar x1 a x4 e y1 a y4
Então, precisamos de alguns vetores para representá-los
Agora olhamos para o determinante
Se o determinante for 0,0, os segmentos de linha são paralelos. Isso pode significar que eles se sobrepõem. Se eles se sobrepõem apenas nos pontos finais, então há uma solução de interseção. Caso contrário, haverá soluções infinitas. Com infinitas soluções, qual é o seu ponto de intersecção? Portanto, é um caso especial interessante. Se você sabe com antecedência que as linhas não podem se sobrepor, você pode apenas verificar
det == 0.0
se sim, apenas dizer que elas não se cruzam e pronto. Caso contrário, vamos continuarAgora, se det, det1 e det2 são todos zero, então suas linhas são colineares e podem se sobrepor. Se det for zero, mas det1 ou det2 não forem, eles não serão colineares, mas paralelos, portanto, não há interseção. Então, o que resta agora se det for zero é um problema 1D em vez de 2D. Precisaremos verificar uma de duas maneiras, dependendo se dx1 é zero ou não (para que possamos evitar a divisão por zero). Se dx1 for zero, faça a mesma lógica com os valores de y em vez de x abaixo.
Isso calcula dois escalonadores, de modo que, se escalarmos o vetor (dx1, dy1) em s, obteremos o ponto (x3, y3), e em t obteremos (x4, y4). Portanto, se s ou t estiver entre 0,0 e 1,0, o ponto 3 ou 4 estará em nossa primeira linha. Negativo significa que o ponto está atrás do início do nosso vetor, enquanto> 1.0 significa que está mais à frente do final do nosso vetor. 0,0 significa que está em (x1, y1) e 1,0 significa que está em (x2, y2). Se s e t forem <0,0 ou ambos forem> 1,0, eles não se cruzam. E isso trata do caso especial das linhas paralelas.
Agora se
det != 0.0
entãos = det1 / det t = det2 / det if (s < 0.0 || s > 1.0 || t < 0.0 || t > 1.0) return false // no intersect
Isso é realmente semelhante ao que estávamos fazendo acima. Agora, se passarmos no teste acima, nossos segmentos de linha se cruzam e podemos calcular a interseção facilmente, assim:
Se você quiser se aprofundar no que a matemática está fazendo, dê uma olhada na Regra de Cramer.
fonte
A resposta de Georgy é a mais limpa de implementar, de longe. Tive que perseguir isso, já que o exemplo do brycboe, embora simples também, tinha problemas com colinearidade.
Código para teste:
#!/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))
fonte
se seus dados definem linha, você só precisa provar que eles não são paralelos. Para fazer isso, você pode calcular
alpha = float(y2 - y1) / (x2 - x1).
Se este coeficiente for igual para Linha1 e Linha2, significa que as linhas são paralelas. Caso contrário, significa que eles se cruzarão.
Se eles forem paralelos, você terá que provar que não são iguais. Para isso, você calcula
Se beta é o mesmo para Linha1 e Linha2, significa que sua linha se cruza, pois são iguais
Se eles forem um segmento, você ainda terá que calcular alfa e beta conforme descrito acima para cada linha. Então você tem que verificar se (beta1 - beta2) / (alpha1 - alpha2) é maior que Min (x1_line1, x2_line1) e menor que Max (x1_line1, x2_line1)
fonte
Calcule o ponto de interseção das linhas que colocam em seus segmentos (significa basicamente resolver um sistema de equações lineares), depois verifique se está entre os pontos inicial e final de seus segmentos.
fonte
Isso é o que eu tenho para AS3, não sei muito sobre python, mas o conceito 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(); }
fonte
Implementado em JAVA. No entanto, parece que não funciona para linhas colineares (também conhecidas como segmentos de linha que existem entre si 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; } }
A produção até agora é
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
fonte
Pensei em contribuir com uma boa solução 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 }
fonte
Uma das soluções acima funcionou tão bem que decidi escrever um programa de demonstração completo usando wxPython. Você deve ser capaz de executar este programa assim: python " seu nome de arquivo "
# 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()
fonte
Usando a solução OMG_Peanuts , traduzi para SQL. (Função escalar HANA)
Obrigado OMG_Peanuts, funciona muito bem. Estou usando a Terra redonda, mas as distâncias são pequenas, então acho que está tudo bem.
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;
fonte
Resolvido, mas por que não com 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
Este:
print islineintersect([(15, 20), (100, 200)], [(210, 5), (23, 119)])
Resultado:
True
E isto:
print islineintersect([(15, 20), (100, 200)], [(-1, -5), (-5, -5)])
Resultado:
False
fonte