Как я могу проверить, пересекаются ли два сегмента?

90

Как я могу проверить, пересекаются ли 2 сегмента?

Имеются следующие данные:

Segment1 [ {x1,y1}, {x2,y2} ]
Segment2 [ {x1,y1}, {x2,y2} ] 

Мне нужно написать небольшой алгоритм на Python, чтобы определить, пересекаются ли 2 линии.


альтернативный текст

аневризм
источник

Ответы:

62

Уравнение линии:

f(x) = A*x + b = y

Для сегмента это то же самое, за исключением того, что x входит в интервал I.

Если у вас есть два сегмента, которые определены следующим образом:

Segment1 = {(X1, Y1), (X2, Y2)}
Segment2 = {(X3, Y3), (X4, Y4)}

Абсис Xa потенциальной точки пересечения (Xa, Ya) должен содержаться как в интервале I1, так и в I2, определяемых следующим образом:

I1 = [min(X1,X2), max(X1,X2)]
I2 = [min(X3,X4), max(X3,X4)]

И можно сказать, что Ха входит в:

Ia = [max( min(X1,X2), min(X3,X4) ),
      min( max(X1,X2), max(X3,X4) )]

Теперь нам нужно проверить, что этот интервал Ia существует:

if (max(X1,X2) < min(X3,X4)):
    return False  # 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):
    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

В дополнение к этому вы можете проверить при запуске, что две из четырех предоставленных точек не равны, чтобы избежать всего этого тестирования.

OMG_peanuts
источник
1
Сегменты, это сегменты, извините. Не могли бы вы обновить свой ответ по сегментам?
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. Я воспроизвожу его здесь для удобства (так как я был бы счастлив иметь его здесь):

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)
Грумдриг
источник
8
Очень простой и элегантный, но он плохо справляется с коллинеарностью, и, следовательно, для этой цели требуется больше кода.
charles
7
Решение, которое также обрабатывает коллинеарность, можно найти на geeksforgeeks.org/check-if-two-given-line-segments-intersect
Zsolt Safrany
Люблю это решение. Очень просто и коротко! Я создал программу 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 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);
}

Конечно, при использовании этих функций необходимо помнить, что каждый сегмент находится «между» другим сегментом (поскольку это конечные сегменты, а не бесконечные линии).

Кроме того, с помощью этих функций вы можете понять, есть ли у вас правильный или неправильный перекресток.

  • Правильно : коллинеарных точек нет. Сегменты пересекают друг друга «из стороны в сторону».
  • Неправильно : один сегмент только "касается" другого (по крайней мере, одна из точек коллинеарна закрепленному сегменту).
Лиран
источник
+1 Во многом моя идея. Если вы просто думаете о том, где находятся точки относительно друг друга, вы можете решить, должны ли их сегменты пересекаться или нет, ничего не вычисляя.
Йохен Ритцель, 01
и @ THC4k Эм, вообще-то непонятно. Для примера проверьте изображение, которое я добавил к вопросу: две точки - «OnLeft» и «OnRight», но эти 2 сегмента не пересекаются.
аневризм 02
@ Патрик, на самом деле нет. В зависимости от того, какой из сегментов является «якорем», тогда обе точки в этом случае либо OnLeft, либо OnRight. (См. Мой обновленный ответ).
Лиран
1
+1 Я видел десятки ответов на эту проблему, но это, безусловно, самый ясный, простой и эффективный из всех, что я видел. :)
Мигель
16

Предположим, у двух сегментов есть конечные точки A, B и C, D. Числовой надежный способ определить пересечение - это проверить знак четырех определителей:

| Ax-Cx  Bx-Cx |    | Ax-Dx  Bx-Dx |
| Ay-Cy  By-Cy |    | Ay-Dy  By-Dy |

| Cx-Ax  Dx-Ax |    | Cx-Bx  Dx-Bx |
| Cy-Ay  Dy-Ay |    | Cy-By  Dy-By |

Для пересечения каждый определитель слева должен иметь знак, противоположный знаку справа, но между двумя линиями не должно быть никакой связи. Вы в основном сравниваете каждую точку сегмента с другим сегментом, чтобы убедиться, что они лежат на противоположных сторонах линии, определяемой другим сегментом.

Смотрите здесь: http://www.cs.cmu.edu/~quake/robust.html

Виктор Лю
источник
работает ли это для неправильных пересечений, т.е. когда точка пересечения лежит на одном отрезке линии?
Саям Кази,
@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

введите описание изображения здесь

Георгий
источник
6

На основании 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
дмитрий
источник
Что именно означает «закрытые сегменты»?
Сэм
@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)]
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: Пересечение отрезка линии

BenMan95
источник
Это круто, и я забыл про 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?)

Вам все еще нужно беспокоиться о линейных сегментах, которые лежат на одной и той же бесконечной линии, или о том, что одна точка фактически попадает на сам другой линейный сегмент. Хороший код решит все возможные проблемы.


источник
3

Вот код 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));

}

Влад
источник
3

Вот еще один код на 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))
Фабиан Инь
источник
1
closed_segment_intersect()из тестового кода не определяется.
hhquark
1
@hhquark Спасибо. Я удалил эти строки. Я включил эти строки во время тестирования, чтобы убедиться, что моя реализация согласуется с реализацией из другого ответа ( я думаю, stackoverflow.com/a/18524383/7474256 ).
Фабиан Инь
1

для отрезков AB и CD найти наклон отрезка CD

slope=(Dy-Cy)/(Dx-Cx)

протяните CD над A и B и пройдите расстояние до CD, идя прямо вверх

dist1=slope*(Cx-Ax)+Ay-Cy
dist2=slope*(Dx-Ax)+Ay-Dy

проверьте, находятся ли они на противоположных сторонах

return dist1*dist2<0
Анонимный
источник
Вы уверены в формулах? Поскольку координаты B не используются, как же найти пересечение AB и CD, не рассматривая все 4 вершины?
mac13k
1
Думаю, должно быть: dist2 = slope * (Dx-Bx) + By-Dy
mac13k
1

Поскольку вы не упоминаете, что хотите найти точку пересечения линии, проблема становится проще. Если вам нужна точка пересечения, то ответ OMG_peanuts - более быстрый подход. Однако, если вы просто хотите определить, пересекаются ли линии или нет, вы можете сделать это с помощью линейного уравнения (ax + by + c = 0). Подход следующий:

  1. Начнем с двух отрезков линии: отрезка 1 и отрезка 2.

    segment1 = [[x1,y1], [x2,y2]]
    segment2 = [[x3,y3], [x4,y4]]
    
  2. Убедитесь, что два линейных сегмента являются линией ненулевой длины и отдельными сегментами.

  3. С этого момента я предполагаю, что эти два сегмента имеют отличную от нуля длину и различны. Для каждого сегмента линии вычислите наклон линии, а затем получите уравнение линии в виде 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);
    
  4. Теперь все, что осталось, - это разные случаи. Если f = 0 для любой точки, то две линии касаются точки. Если f1_1 и f1_2 равны или f2_1 и f2_2 равны, то прямые не пересекаются. Если f1_1 и f1_2 не равны, а f2_1 и f2_2 не равны, то отрезки пересекаются. В зависимости от того, хотите ли вы рассматривать соприкасающиеся линии как «пересекающиеся» или нет, вы можете адаптировать свои условия.

Ahyuthan_jr
источник
Этот код не рассчитывает 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]

Таким образом, функция такая:

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

источник
1

Это мой способ проверки пересечения линии и места пересечения. Давайте использовать от x1 до x4 и от y1 до y4

Segment1 = {(X1, Y1), (X2, Y2)}
Segment2 = {(X3, Y3), (X4, Y4)}

Затем нам нужны векторы для их представления

dx1 = X2 - X1
dx2 = X4 - X4
dy1 = Y2 - Y1
dy2 = Y4 - Y3

Теперь посмотрим на определитель

det = dx1 * dy2 - dx2 * dy1

Если определитель равен 0,0, то отрезки параллельны. Это может означать, что они перекрываются. Если они перекрываются только в конечных точках, тогда существует одно решение пересечения. В противном случае решений будет бесконечное количество. Что является вашей точкой пересечения с бесконечным множеством решений? Так что это интересный частный случай. Если вы заранее знаете, что линии не могут перекрываться, вы можете просто проверить, det == 0.0если да, просто скажите, что они не пересекаются, и готово. В противном случае, давайте продолжим

dx3 = X3 - X1
dy3 = Y3 - Y1

det1 = dx1 * dy3 - dx3 * dy1
det2 = dx2 * dy3 - dx3 * dy2

Теперь, если 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

Если вы хотите глубже понять, что делает математика, изучите правило Крамера.

Джейсон Хоффосс
источник
1
Опечатка: «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-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))
убежище
источник
0

если ваши данные определяют линию, вам просто нужно доказать, что они не параллельны. Для этого вы можете вычислить

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)

PierrOz
источник
0

Вычислите точку пересечения линий, лежащих на ваших сегментах (это в основном означает решение системы линейных уравнений), затем проверьте, находится ли она между начальной и конечной точками ваших сегментов.

Косии
источник
0

Это то, что у меня есть для 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();
    }
Даниэль
источник
0

Реализовано на 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
Странник
источник
0

Я думал, что внесу хорошее решение 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

}
Матей Укмар
источник
0

Одно из вышеперечисленных решений сработало так хорошо, что я решил написать полную демонстрационную программу с использованием 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()
user1766438
источник
0

Используя решение 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;
Нью-Йорк Рино
источник
-2

Решено, но почему бы и не использовать 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
Любовь Шарма
источник