Ia = [max( min(X1,X2), min(X3,X4) ),
min( max(X1,X2), max(X3,X4) )]
Теперь нам нужно проверить, что этот интервал Ia существует:
if (max(X1,X2) < min(X3,X4)):
returnFalse# There is no mutual abcisses
Итак, у нас есть двухстрочная формула и взаимный интервал. Формулы вашей линии:
f1(x) = A1*x + b1 = y
f2(x) = A2*x + b2 = y
Поскольку мы получили две точки по сегментам, мы можем определить A1, A2, b1 и 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
Если отрезки параллельны, то A1 == A2:
if (A1 == A2):
returnFalse# Parallel segments
Точка (Xa, Ya), стоящая на обеих линиях, должна проверять обе формулы f1 и 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
Последнее, что нужно сделать, это проверить, включен ли Xa в 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
В дополнение к этому вы можете проверить при запуске, что две из четырех предоставленных точек не равны, чтобы избежать всего этого тестирования.
Сегменты, это сегменты, извините. Не могли бы вы обновить свой ответ по сегментам?
aneuryzm 01
13
Это не так уж сложно, я написал много (несущественных?) Промежуточных шагов для понимания. Основные моменты для орудий: проверьте наличие взаимного интервала, вычислите A1, A2, b1, b2 и Xa, а затем убедитесь, что Xa входит во взаимный интервал. Вот и все :)
OMG_peanuts
2
A1 - A2 никогда не будет равно нулю, потому что if (A1 == A2) в этом случае вернется до этого вычисления.
inkredibl
3
если A1 == A2 и b1 == b2, сегменты находятся друг над другом и имеют бесконечное количество пересечений
lynxoid
5
Формула A1 * x + b1 = y не обрабатывает вертикальные линии, поэтому вертикальные сегменты следует обрабатывать отдельно с помощью этого метода.
дмитрий
77
Пользователь @ i_4_got указывает на эту страницу с очень эффективным решением на Python. Я воспроизвожу его здесь для удобства (так как я был бы счастлив иметь его здесь):
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)
Люблю это решение. Очень просто и коротко! Я создал программу wxPython, которая рисует линию и проверяет, пересекается ли она с другой линией. Я не мог разместить его здесь, поэтому он находится где-то под этим комментарием.
user1766438
33
Вам не нужно точно вычислять, где пересекаются сегменты, нужно только понимать , пересекаются ли они вообще. Это упростит решение.
Идея состоит в том, чтобы рассматривать один сегмент как «якорь» и разделять второй сегмент на 2 точки.
Теперь вам нужно будет найти относительное положение каждой точки относительно «привязанного» сегмента (OnLeft, OnRight или Collinear).
Сделав это для обеих точек, убедитесь, что одна из точек - OnLeft, а другая - OnRight (или, возможно, укажите коллинеарное положение, если вы также хотите включить неправильные пересечения).
Затем вы должны повторить процесс с ролями якоря и отдельных сегментов.
Пересечение существует тогда и только тогда, когда одна из точек - OnLeft, а другая - OnRight. См. Эту ссылку для более подробного объяснения с примерами изображений для каждого возможного случая.
Реализовать такой метод будет намного проще, чем на самом деле реализовать метод, который находит точку пересечения (учитывая множество угловых случаев, с которыми вам также придется справиться).
Обновить
Следующие функции должны иллюстрировать идею (источник: Computational Geometry in C ). Примечание. В этом примере предполагается использование целых чисел. Если вместо этого вы используете представление с плавающей запятой (что, очевидно, может усложнить ситуацию), тогда вам следует определить какое-то значение epsilon для обозначения «равенства» (в основном для IsCollinearоценки).
// 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);
}
Конечно, при использовании этих функций необходимо помнить, что каждый сегмент находится «между» другим сегментом (поскольку это конечные сегменты, а не бесконечные линии).
Кроме того, с помощью этих функций вы можете понять, есть ли у вас правильный или неправильный перекресток.
Правильно : коллинеарных точек нет. Сегменты пересекают друг друга «из стороны в сторону».
Неправильно : один сегмент только "касается" другого (по крайней мере, одна из точек коллинеарна закрепленному сегменту).
+1 Во многом моя идея. Если вы просто думаете о том, где находятся точки относительно друг друга, вы можете решить, должны ли их сегменты пересекаться или нет, ничего не вычисляя.
Йохен Ритцель, 01
и @ THC4k Эм, вообще-то непонятно. Для примера проверьте изображение, которое я добавил к вопросу: две точки - «OnLeft» и «OnRight», но эти 2 сегмента не пересекаются.
аневризм 02
@ Патрик, на самом деле нет. В зависимости от того, какой из сегментов является «якорем», тогда обе точки в этом случае либо OnLeft, либо OnRight. (См. Мой обновленный ответ).
Лиран
1
+1 Я видел десятки ответов на эту проблему, но это, безусловно, самый ясный, простой и эффективный из всех, что я видел. :)
Мигель
16
Предположим, у двух сегментов есть конечные точки A, B и C, D. Числовой надежный способ определить пересечение - это проверить знак четырех определителей:
Для пересечения каждый определитель слева должен иметь знак, противоположный знаку справа, но между двумя линиями не должно быть никакой связи. Вы в основном сравниваете каждую точку сегмента с другим сегментом, чтобы убедиться, что они лежат на противоположных сторонах линии, определяемой другим сегментом.
работает ли это для неправильных пересечений, т.е. когда точка пересечения лежит на одном отрезке линии?
Саям Кази,
@SayamQazi Похоже, что пересечение не удается, если вы проходите конечную точку отрезка линии, по крайней мере. Поскольку, если вы находитесь в сегменте: я предполагаю, что это будет сравнение 0 против 1 / -1, поэтому оно не обнаружит пересечения.
Warty
1
Кстати, чтобы объяснить это: каждый детерминант вычисляет перекрестное произведение конечных точек векторов двух отрезков линии. В верхнем левом углу, например, CA x CB против верхнего правого DA x DB. По сути, это проверяет, на какой стороне находится вершина (тактность). Все еще пытаюсь понять, как это работает для отрезков линии, которые не растягиваются бесконечно.
Warty
7
Проверить, пересекаются ли линейные сегменты, очень просто с помощью библиотеки Shapely, используя intersectsметод:
from shapely.geometry import LineString
line = LineString([(0, 0), (1, 1)])
other = LineString([(0, 1), (1, 0)])
print(line.intersects(other))
# True
line = LineString([(0, 0), (1, 1)])
other = LineString([(0, 1), (1, 2)])
print(line.intersects(other))
# False
На основании Liran в и Grumdrig в отличные ответы здесь полный код Python , чтобы проверить , если закрытые сегменты пересекаются. Работает для коллинеарных сегментов, сегментов, параллельных оси Y, вырожденных сегментов (черт в деталях). Предполагает целочисленные координаты. Координаты с плавающей запятой требуют модификации проверки равенства точек.
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 Закрытый сегмент содержит свои конечные точки. Например, замкнутый сегмент точек из R будет [0, 1] (0 <= x <= 1) в отличие от, скажем,] 0, 1] (0 <x <= 1)
dmitri
5
Вот решение с использованием точечных произведений:
# 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)
Это круто, и я забыл про Desmos - он идеально подходит для этой задачи! Благодарность!
ponadto
Люблю ваше решение, но кажется, что оно не работает, если два отрезка находятся на одной линии
Х. Папа
Очень хорошо. Для всех, кто переносит это на другой язык, обязательно используйте float или int64, поскольку int32 будет довольно быстро переполняться на числах меньше 1280x720
этот другой парень
4
У вас есть два отрезка линии. Определите один сегмент конечными точками A и B, а второй сегмент - конечными точками C и D. Есть хороший трюк, чтобы показать, что они должны пересекаться ВНУТРИ границ сегментов. (Обратите внимание, что сами линии могут пересекаться за пределами сегментов, поэтому будьте осторожны. Хороший код также будет следить за параллельными линиями.)
Уловка состоит в том, чтобы проверить, что точки A и B должны располагаться на противоположных сторонах линии CD, И что точки C и D должны лежать на противоположных сторонах линии AB.
Поскольку это домашнее задание, я не буду давать вам точного решения. Но простой тест, чтобы увидеть, на какую сторону линии падает точка, - это использовать скалярное произведение. Таким образом, для данной линии CD вычислите вектор нормали к этой линии (я назову ее N_C.) Теперь просто проверьте признаки этих двух результатов:
dot(A-C,N_C)
а также
dot(B-C,N_C)
Если эти результаты имеют противоположные знаки, то A и B являются противоположными сторонами линии CD. Теперь проделайте тот же тест для другой линии, AB. Имеет нормальный вектор N_A. Сравните признаки
dot(C-A,N_A)
а также
dot(D-A,N_A)
Я предоставлю вам решить, как вычислить вектор нормали. (В 2-d это тривиально, но будет ли ваш код беспокоиться о том, являются ли A и B разными точками? Аналогично, различны ли C и D?)
Вам все еще нужно беспокоиться о линейных сегментах, которые лежат на одной и той же бесконечной линии, или о том, что одна точка фактически попадает на сам другой линейный сегмент. Хороший код решит все возможные проблемы.
Вот код C, чтобы проверить, находятся ли две точки на противоположных сторонах отрезка линии. Используя этот код, вы также можете проверить, пересекаются ли два сегмента.
// 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
Ниже приведена функция тестирования, чтобы убедиться, что она работает.
closed_segment_intersect()из тестового кода не определяется.
hhquark
1
@hhquark Спасибо. Я удалил эти строки. Я включил эти строки во время тестирования, чтобы убедиться, что моя реализация согласуется с реализацией из другого ответа ( я думаю, stackoverflow.com/a/18524383/7474256 ).
Фабиан Инь
1
для отрезков AB и CD найти наклон отрезка CD
slope=(Dy-Cy)/(Dx-Cx)
протяните CD над A и B и пройдите расстояние до CD, идя прямо вверх
Вы уверены в формулах? Поскольку координаты B не используются, как же найти пересечение AB и CD, не рассматривая все 4 вершины?
mac13k
1
Думаю, должно быть: dist2 = slope * (Dx-Bx) + By-Dy
mac13k
1
Поскольку вы не упоминаете, что хотите найти точку пересечения линии, проблема становится проще. Если вам нужна точка пересечения, то ответ OMG_peanuts - более быстрый подход. Однако, если вы просто хотите определить, пересекаются ли линии или нет, вы можете сделать это с помощью линейного уравнения (ax + by + c = 0). Подход следующий:
Начнем с двух отрезков линии: отрезка 1 и отрезка 2.
Убедитесь, что два линейных сегмента являются линией ненулевой длины и отдельными сегментами.
С этого момента я предполагаю, что эти два сегмента имеют отличную от нуля длину и различны. Для каждого сегмента линии вычислите наклон линии, а затем получите уравнение линии в виде ax + by + c = 0. Теперь вычислите значение f = ax + by + c для двух точек отрезка. другой сегмент линии (повторите то же самое для другого сегмента линии).
Теперь все, что осталось, - это разные случаи. Если f = 0 для любой точки, то две линии касаются точки. Если f1_1 и f1_2 равны или f2_1 и f2_2 равны, то прямые не пересекаются. Если f1_1 и f1_2 не равны, а f2_1 и f2_2 не равны, то отрезки пересекаются. В зависимости от того, хотите ли вы рассматривать соприкасающиеся линии как «пересекающиеся» или нет, вы можете адаптировать свои условия.
Этот код не рассчитывает a1и не работает для ортогональных линий.
Björn Lindqvist
1
Мы также можем решить эту проблему, используя векторы.
Определим сегменты как [start, end]. Учитывая два таких сегментов [A, B]и [C, D]что оба они имеют ненулевую длину, мы можем выбрать один из конечных точек , которые будут использоваться в качестве опорной точки , так что мы получаем три вектора:
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]]
Отсюда мы можем найти пересечение, вычислив t и u in p + t*r = u*q. Немного поиграв с уравнением, мы получаем:
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]
Таким образом, функция такая:
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
Если определитель равен 0,0, то отрезки параллельны. Это может означать, что они перекрываются. Если они перекрываются только в конечных точках, тогда существует одно решение пересечения. В противном случае решений будет бесконечное количество. Что является вашей точкой пересечения с бесконечным множеством решений? Так что это интересный частный случай. Если вы заранее знаете, что линии не могут перекрываться, вы можете просто проверить, det == 0.0если да, просто скажите, что они не пересекаются, и готово. В противном случае, давайте продолжим
Теперь, если det, det1 и det2 равны нулю, тогда ваши линии коллинеарны и могут перекрываться. Если det равен нулю, но det1 или det2 нет, то они не коллинеарны, а параллельны, поэтому пересечения нет. Итак, что остается, если det равен нулю, это проблема 1D, а не 2D. Нам нужно будет проверить один из двух способов, в зависимости от того, равен ли dx1 нулю (чтобы избежать деления на ноль). Если dx1 равен нулю, просто проделайте ту же логику со значениями y, а не x ниже.
s = X3 / dx1
t = X4 / dx1
Это вычисляет два масштабатора, так что если мы масштабируем вектор (dx1, dy1) по s, мы получаем точку (x3, y3), а по t мы получаем (x4, y4). Итак, если s или t находится между 0,0 и 1,0, то точка 3 или 4 находится на нашей первой строке. Отрицательное значение будет означать, что точка находится за началом нашего вектора, а> 1.0 означает, что она находится впереди конца нашего вектора. 0.0 означает, что он находится в (x1, y1), а 1.0 означает, что он находится в (x2, y2). Если и s, и t <0,0 или оба> 1,0, то они не пересекаются. И это касается особого случая параллельных линий.
Теперь, если det != 0.0тогда
s = det1 / det
t = det2 / det
if (s < 0.0 || s > 1.0 || t < 0.0 || t > 1.0)
return false // no intersect
На самом деле это похоже на то, что мы делали выше. Теперь, если мы пройдем вышеуказанный тест, наши отрезки линии пересекаются, и мы можем довольно легко вычислить пересечение следующим образом:
Ix = X1 + t * dx1
Iy = Y1 + t * dy1
Если вы хотите глубже понять, что делает математика, изучите правило Крамера.
Опечатка: «dx2 = X4 - X4» должно быть «dx2 = X4 - X3»
geowar
1
Ответ Георгия , безусловно, наиболее понятен. Пришлось разобраться с этим, так как пример brycboe, хотя и простой, имел проблемы с колинеарностью.
Код для тестирования:
#!/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))
если ваши данные определяют линию, вам просто нужно доказать, что они не параллельны. Для этого вы можете вычислить
alpha = float(y2 - y1) / (x2 - x1).
Если этот коэффициент равен как для Line1, так и для Line2, это означает, что прямые параллельны. Если нет, значит, они пересекутся.
Если они параллельны, вы должны доказать, что они не совпадают. Для этого вы вычисляете
beta = y1 - alpha*x1
Если бета одинакова для Line1 и Line2, это означает, что ваши линии пересекаются, поскольку они равны
Если они сегментные, вам все равно придется вычислять альфа и бета, как описано выше для каждой строки. Затем вы должны проверить, что (beta1 - beta2) / (alpha1 - alpha2) больше Min (x1_line1, x2_line1) и меньше Max (x1_line1, x2_line1)
Вычислите точку пересечения линий, лежащих на ваших сегментах (это в основном означает решение системы линейных уравнений), затем проверьте, находится ли она между начальной и конечной точками ваших сегментов.
Реализовано на JAVA. Однако кажется, что это не работает для коллинеарных линий (то есть сегментов, которые существуют друг в друге 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
}
Одно из вышеперечисленных решений сработало так хорошо, что я решил написать полную демонстрационную программу с использованием wxPython. Вы должны иметь возможность запускать эту программу так: python " ваше имя файла "
# 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()
Используя решение OMG_Peanuts , я перевел на SQL. (Скалярная функция HANA)
Спасибо OMG_Peanuts, отлично работает. Я использую круглую землю, но расстояния небольшие, поэтому я считаю, что это нормально.
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;
Ответы:
Уравнение линии:
Для сегмента это то же самое, за исключением того, что x входит в интервал I.
Если у вас есть два сегмента, которые определены следующим образом:
Абсис Xa потенциальной точки пересечения (Xa, Ya) должен содержаться как в интервале I1, так и в I2, определяемых следующим образом:
И можно сказать, что Ха входит в:
Теперь нам нужно проверить, что этот интервал Ia существует:
if (max(X1,X2) < min(X3,X4)): return False # There is no mutual abcisses
Итак, у нас есть двухстрочная формула и взаимный интервал. Формулы вашей линии:
Поскольку мы получили две точки по сегментам, мы можем определить A1, A2, b1 и 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
Если отрезки параллельны, то A1 == A2:
if (A1 == A2): return False # Parallel segments
Точка (Xa, Ya), стоящая на обеих линиях, должна проверять обе формулы f1 и 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
Последнее, что нужно сделать, это проверить, включен ли Xa в 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
В дополнение к этому вы можете проверить при запуске, что две из четырех предоставленных точек не равны, чтобы избежать всего этого тестирования.
источник
Пользователь @ i_4_got указывает на эту страницу с очень эффективным решением на Python. Я воспроизвожу его здесь для удобства (так как я был бы счастлив иметь его здесь):
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)
источник
Вам не нужно точно вычислять, где пересекаются сегменты, нужно только понимать , пересекаются ли они вообще. Это упростит решение.
Идея состоит в том, чтобы рассматривать один сегмент как «якорь» и разделять второй сегмент на 2 точки.
Теперь вам нужно будет найти относительное положение каждой точки относительно «привязанного» сегмента (OnLeft, OnRight или Collinear).
Сделав это для обеих точек, убедитесь, что одна из точек - OnLeft, а другая - OnRight (или, возможно, укажите коллинеарное положение, если вы также хотите включить неправильные пересечения).
Затем вы должны повторить процесс с ролями якоря и отдельных сегментов.
Пересечение существует тогда и только тогда, когда одна из точек - OnLeft, а другая - OnRight. См. Эту ссылку для более подробного объяснения с примерами изображений для каждого возможного случая.
Реализовать такой метод будет намного проще, чем на самом деле реализовать метод, который находит точку пересечения (учитывая множество угловых случаев, с которыми вам также придется справиться).
Обновить
Следующие функции должны иллюстрировать идею (источник: Computational Geometry in C ).
Примечание. В этом примере предполагается использование целых чисел. Если вместо этого вы используете представление с плавающей запятой (что, очевидно, может усложнить ситуацию), тогда вам следует определить какое-то значение epsilon для обозначения «равенства» (в основном для
IsCollinear
оценки).// points "a" and "b" forms the anchored segment. // point "c" is the evaluated point bool IsOnLeft(Point a, Point b, Point c) { return Area2(a, b, c) > 0; } bool IsOnRight(Point a, Point b, Point c) { return Area2(a, b, c) < 0; } bool IsCollinear(Point a, Point b, Point c) { return Area2(a, b, c) == 0; } // calculates the triangle's size (formed by the "anchor" segment and additional point) int Area2(Point a, Point b, Point c) { return (b.X - a.X) * (c.Y - a.Y) - (c.X - a.X) * (b.Y - a.Y); }
Конечно, при использовании этих функций необходимо помнить, что каждый сегмент находится «между» другим сегментом (поскольку это конечные сегменты, а не бесконечные линии).
Кроме того, с помощью этих функций вы можете понять, есть ли у вас правильный или неправильный перекресток.
источник
Предположим, у двух сегментов есть конечные точки A, B и C, D. Числовой надежный способ определить пересечение - это проверить знак четырех определителей:
Для пересечения каждый определитель слева должен иметь знак, противоположный знаку справа, но между двумя линиями не должно быть никакой связи. Вы в основном сравниваете каждую точку сегмента с другим сегментом, чтобы убедиться, что они лежат на противоположных сторонах линии, определяемой другим сегментом.
Смотрите здесь: http://www.cs.cmu.edu/~quake/robust.html
источник
Проверить, пересекаются ли линейные сегменты, очень просто с помощью библиотеки Shapely, используя
intersects
метод:from shapely.geometry import LineString line = LineString([(0, 0), (1, 1)]) other = LineString([(0, 1), (1, 0)]) print(line.intersects(other)) # True
line = LineString([(0, 0), (1, 1)]) other = LineString([(0, 1), (1, 2)]) print(line.intersects(other)) # False
источник
На основании Liran в и Grumdrig в отличные ответы здесь полный код Python , чтобы проверить , если закрытые сегменты пересекаются. Работает для коллинеарных сегментов, сегментов, параллельных оси Y, вырожденных сегментов (черт в деталях). Предполагает целочисленные координаты. Координаты с плавающей запятой требуют модификации проверки равенства точек.
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
источник
Вот решение с использованием точечных произведений:
# 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)
Вот визуализация в Desmos: Пересечение отрезка линии
источник
У вас есть два отрезка линии. Определите один сегмент конечными точками A и B, а второй сегмент - конечными точками C и D. Есть хороший трюк, чтобы показать, что они должны пересекаться ВНУТРИ границ сегментов. (Обратите внимание, что сами линии могут пересекаться за пределами сегментов, поэтому будьте осторожны. Хороший код также будет следить за параллельными линиями.)
Уловка состоит в том, чтобы проверить, что точки A и B должны располагаться на противоположных сторонах линии CD, И что точки C и D должны лежать на противоположных сторонах линии AB.
Поскольку это домашнее задание, я не буду давать вам точного решения. Но простой тест, чтобы увидеть, на какую сторону линии падает точка, - это использовать скалярное произведение. Таким образом, для данной линии CD вычислите вектор нормали к этой линии (я назову ее N_C.) Теперь просто проверьте признаки этих двух результатов:
а также
Если эти результаты имеют противоположные знаки, то A и B являются противоположными сторонами линии CD. Теперь проделайте тот же тест для другой линии, AB. Имеет нормальный вектор N_A. Сравните признаки
а также
Я предоставлю вам решить, как вычислить вектор нормали. (В 2-d это тривиально, но будет ли ваш код беспокоиться о том, являются ли A и B разными точками? Аналогично, различны ли C и D?)
Вам все еще нужно беспокоиться о линейных сегментах, которые лежат на одной и той же бесконечной линии, или о том, что одна точка фактически попадает на сам другой линейный сегмент. Хороший код решит все возможные проблемы.
источник
Вот код C, чтобы проверить, находятся ли две точки на противоположных сторонах отрезка линии. Используя этот код, вы также можете проверить, пересекаются ли два сегмента.
// 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));
}
источник
Вот еще один код на Python, чтобы проверить, пересекаются ли закрытые сегменты. Это переписанная версия кода C ++ в http://www.cdn.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ . Эта реализация охватывает все особые случаи (например, все точки коллинеарны).
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
Ниже приведена функция тестирования, чтобы убедиться, что она работает.
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))
источник
closed_segment_intersect()
из тестового кода не определяется.для отрезков AB и CD найти наклон отрезка CD
протяните CD над A и B и пройдите расстояние до CD, идя прямо вверх
проверьте, находятся ли они на противоположных сторонах
return dist1*dist2<0
источник
Поскольку вы не упоминаете, что хотите найти точку пересечения линии, проблема становится проще. Если вам нужна точка пересечения, то ответ OMG_peanuts - более быстрый подход. Однако, если вы просто хотите определить, пересекаются ли линии или нет, вы можете сделать это с помощью линейного уравнения (ax + by + c = 0). Подход следующий:
Начнем с двух отрезков линии: отрезка 1 и отрезка 2.
Убедитесь, что два линейных сегмента являются линией ненулевой длины и отдельными сегментами.
С этого момента я предполагаю, что эти два сегмента имеют отличную от нуля длину и различны. Для каждого сегмента линии вычислите наклон линии, а затем получите уравнение линии в виде ax + by + c = 0. Теперь вычислите значение f = ax + by + c для двух точек отрезка. другой сегмент линии (повторите то же самое для другого сегмента линии).
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);
Теперь все, что осталось, - это разные случаи. Если f = 0 для любой точки, то две линии касаются точки. Если f1_1 и f1_2 равны или f2_1 и f2_2 равны, то прямые не пересекаются. Если f1_1 и f1_2 не равны, а f2_1 и f2_2 не равны, то отрезки пересекаются. В зависимости от того, хотите ли вы рассматривать соприкасающиеся линии как «пересекающиеся» или нет, вы можете адаптировать свои условия.
источник
a1
и не работает для ортогональных линий.Мы также можем решить эту проблему, используя векторы.
Определим сегменты как
[start, end]
. Учитывая два таких сегментов[A, B]
и[C, D]
что оба они имеют ненулевую длину, мы можем выбрать один из конечных точек , которые будут использоваться в качестве опорной точки , так что мы получаем три вектора: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]]
Отсюда мы можем найти пересечение, вычислив t и u in
p + t*r = u*q
. Немного поиграв с уравнением, мы получаем:Таким образом, функция такая:
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
источник
Это мой способ проверки пересечения линии и места пересечения. Давайте использовать от x1 до x4 и от y1 до y4
Затем нам нужны векторы для их представления
Теперь посмотрим на определитель
Если определитель равен 0,0, то отрезки параллельны. Это может означать, что они перекрываются. Если они перекрываются только в конечных точках, тогда существует одно решение пересечения. В противном случае решений будет бесконечное количество. Что является вашей точкой пересечения с бесконечным множеством решений? Так что это интересный частный случай. Если вы заранее знаете, что линии не могут перекрываться, вы можете просто проверить,
det == 0.0
если да, просто скажите, что они не пересекаются, и готово. В противном случае, давайте продолжимТеперь, если det, det1 и det2 равны нулю, тогда ваши линии коллинеарны и могут перекрываться. Если det равен нулю, но det1 или det2 нет, то они не коллинеарны, а параллельны, поэтому пересечения нет. Итак, что остается, если det равен нулю, это проблема 1D, а не 2D. Нам нужно будет проверить один из двух способов, в зависимости от того, равен ли dx1 нулю (чтобы избежать деления на ноль). Если dx1 равен нулю, просто проделайте ту же логику со значениями y, а не x ниже.
Это вычисляет два масштабатора, так что если мы масштабируем вектор (dx1, dy1) по s, мы получаем точку (x3, y3), а по t мы получаем (x4, y4). Итак, если s или t находится между 0,0 и 1,0, то точка 3 или 4 находится на нашей первой строке. Отрицательное значение будет означать, что точка находится за началом нашего вектора, а> 1.0 означает, что она находится впереди конца нашего вектора. 0.0 означает, что он находится в (x1, y1), а 1.0 означает, что он находится в (x2, y2). Если и s, и t <0,0 или оба> 1,0, то они не пересекаются. И это касается особого случая параллельных линий.
Теперь, если
det != 0.0
тогдаs = det1 / det t = det2 / det if (s < 0.0 || s > 1.0 || t < 0.0 || t > 1.0) return false // no intersect
На самом деле это похоже на то, что мы делали выше. Теперь, если мы пройдем вышеуказанный тест, наши отрезки линии пересекаются, и мы можем довольно легко вычислить пересечение следующим образом:
Если вы хотите глубже понять, что делает математика, изучите правило Крамера.
источник
Ответ Георгия , безусловно, наиболее понятен. Пришлось разобраться с этим, так как пример brycboe, хотя и простой, имел проблемы с колинеарностью.
Код для тестирования:
#!/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))
источник
если ваши данные определяют линию, вам просто нужно доказать, что они не параллельны. Для этого вы можете вычислить
Если этот коэффициент равен как для Line1, так и для Line2, это означает, что прямые параллельны. Если нет, значит, они пересекутся.
Если они параллельны, вы должны доказать, что они не совпадают. Для этого вы вычисляете
Если бета одинакова для Line1 и Line2, это означает, что ваши линии пересекаются, поскольку они равны
Если они сегментные, вам все равно придется вычислять альфа и бета, как описано выше для каждой строки. Затем вы должны проверить, что (beta1 - beta2) / (alpha1 - alpha2) больше Min (x1_line1, x2_line1) и меньше Max (x1_line1, x2_line1)
источник
Вычислите точку пересечения линий, лежащих на ваших сегментах (это в основном означает решение системы линейных уравнений), затем проверьте, находится ли она между начальной и конечной точками ваших сегментов.
источник
Это то, что у меня есть для AS3, я мало знаю о python, но концепция есть
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(); }
источник
Реализовано на JAVA. Однако кажется, что это не работает для коллинеарных линий (то есть сегментов, которые существуют друг в друге 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; } }
На данный момент результат
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
источник
Я думал, что внесу хорошее решение 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 }
источник
Одно из вышеперечисленных решений сработало так хорошо, что я решил написать полную демонстрационную программу с использованием wxPython. Вы должны иметь возможность запускать эту программу так: python " ваше имя файла "
# 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()
источник
Используя решение OMG_Peanuts , я перевел на SQL. (Скалярная функция HANA)
Спасибо OMG_Peanuts, отлично работает. Я использую круглую землю, но расстояния небольшие, поэтому я считаю, что это нормально.
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;
источник
Решено, но почему бы и не использовать 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
Этот:
print islineintersect([(15, 20), (100, 200)], [(210, 5), (23, 119)])
Выход:
True
И это:
print islineintersect([(15, 20), (100, 200)], [(-1, -5), (-5, -5)])
Выход:
False
источник