Як я можу перевірити, чи перетинаються два сегменти?


90

Як я можу перевірити, чи перетинаються 2 сегменти?

У мене є такі дані:

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

Мені потрібно написати невеликий алгоритм на Python, щоб виявити, чи перетинаються 2 рядки.


текст заміщення


Відповіді:


62

Рівняння прямої:

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

Для відрізка це точно те саме, за винятком того, що х включено на інтервалі 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

На додаток до цього, ви можете перевірити під час запуску, що два з чотирьох наданих пунктів не рівні, щоб уникнути всіх цих тестувань.


1
Сегменти, вони сегменти, вибачте. Не могли б ви оновити свою відповідь із урахуванням сегментів?
aneuryzm

13
Це не так вже й складно, я написав багато (необов’язкових?) Проміжних кроків у цілях розуміння. Основними пунктами приладів є лише: Перевірити існування взаємного інтервалу, обчислити A1, A2, b1, b2 та Xa, а потім перевірити, чи Xa включено у взаємний інтервал. Це все :)
OMG_peanuts

2
A1 - A2 ніколи не буде дорівнювати нулю, оскільки якби (A1 == A2) повернувся б до цього обчислення в такому випадку.
inkredibl

3
якщо A1 == A2 і b1 == b2, сегменти знаходяться один на одному і мають нескінченно багато перетинів
lynxoid

5
Формула A1 * x + b1 = y не обробляє вертикальні лінії, отже, вертикальні відрізки слід обробляти окремо за допомогою цього методу.
dmitri

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. Дивіться це посилання для більш детального пояснення та прикладів зображень для кожного можливого випадку.

Реалізація такого методу буде набагато простішою, ніж насправді реалізація методу, який знаходить точку перетину (враховуючи безліч кутових випадків, з якими вам також доведеться обробляти).

Оновлення

Наступні функції повинні ілюструвати ідею (джерело: Обчислювальна геометрія на С ).
Примітка: Цей зразок передбачає використання цілих чисел. Якщо ви використовуєте замість цього подання з плаваючою крапкою (що, очевидно, може ускладнити ситуацію), тоді слід визначити якесь значення 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 Майже моя ідея. Якщо ви просто думаєте про те, де точки розташовані по відношенню один до одного, ви можете вирішити, чи повинні їх відрізки перетинатися чи ні, не обчислюючи нічого.
Jochen Ritzel

та @ THC4k Um, насправді незрозуміло. Для прикладу перевірте зображення, яке я додав до запитання: 2 точки - "OnLeft" і "OnRight", але 2 сегменти не перетинаються.
aneuryzm

@Patrick, насправді ні. Залежно від того, який із сегментів є "якорем", тоді обидві точки в цьому випадку є або 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

На основі чудових відповідей Лірана та Грумдріга, тут є повний код 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), на відміну від
вимови

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: Перетин відрізка лінії


Це чудово, і я забув про 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-х д. Це тривіально, але чи буде ваш код турбуватися про те, чи є A і B різними точками? Так само, C і D відрізняються?)

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


3

Ось код С, щоб перевірити, чи знаходяться дві точки на протилежних сторонах відрізка. За допомогою цього коду ви можете перевірити, чи перетинаються два сегменти.

// 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, щоб перевірити, чи перетинаються закриті сегменти. Це переписана версія коду С ++ у 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)

простягніть компакт-диск над 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 + на + c = 0. Тепер обчисліть значення f = ax + на + 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 нерівні, то відрізки лінії перетинаються. Залежно від того, чи хочете ви розглядати лінії, що торкаються, "перетинаються" чи ні, ви можете адаптувати свої умови.


Цей код не обчислює a1і не працює для ортогональних ліній.
Бьорн Ліндквіст,

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 в 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"
геовойна

1

Відповідь Георгія на сьогоднішній день є найчистішою у реалізації. Довелося переслідувати це, оскільки приклад брикбо, хоч і простий, мав проблеми з колінеарністю.

Код для тестування:

#!/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)


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()

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.