Как вычислить точку пересечения двух линий?

У меня есть две линии, которые пересекаются в одной точке. Я знаю конечные точки двух линий. Как вычислить точку пересечения в Python?

# Given these endpoints
#line 1
A = [X, Y]
B = [X, Y]

#line 2
C = [X, Y]
D = [X, Y]

# Compute this:
point_of_intersection = [X, Y]

person bolt19    schedule 19.12.2013    source источник
comment
Это отрезки или линии?   -  person user2357112 supports Monica    schedule 19.12.2013
comment
Эта проблема в основном сводится к математике. Вы можете использовать алгебраические манипуляции, чтобы найти выражение для координат пересечения, а затем вставить это выражение в свою программу. Однако не забудьте сначала проверить наличие параллельных линий.   -  person user2357112 supports Monica    schedule 19.12.2013
comment
Выполните поиск в stackoverflow, прежде чем задать вопрос: [ответ] [1] [1]: stackoverflow.com/questions/3252194/   -  person Cao Manh Dat    schedule 19.12.2013
comment
«Я знаю, как это сделать на бумаге» - Тогда в чем именно ваша проблема? Здесь вам нужно применить чистую математику. А Python - ваш калькулятор. Что ты пробовал?   -  person poke    schedule 19.12.2013
comment
возможный дубликат Как я могу проверить, пересекаются ли два сегмента?   -  person Jerry Coffin    schedule 19.12.2013


Ответы (8)


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

def line_intersection(line1, line2):
    xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
    ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])

    def det(a, b):
        return a[0] * b[1] - a[1] * b[0]

    div = det(xdiff, ydiff)
    if div == 0:
       raise Exception('lines do not intersect')

    d = (det(*line1), det(*line2))
    x = det(d, xdiff) / div
    y = det(d, ydiff) / div
    return x, y

print line_intersection((A, B), (C, D))

И, к вашему сведению, я бы использовал кортежи вместо списков для ваших баллов. Например.

A = (X, Y)

РЕДАКТИРОВАТЬ: Изначально была опечатка. Это было исправлено в сентябре 2014 г. благодаря @zidik.

Это просто транслитерация Python следующей формулы, где строки (a1, a2) и (b1, b2 < / strong>), а пересечение - p. (Если знаменатель равен нулю, линии не имеют единственного пересечения.)

person Paul Draper    schedule 19.12.2013
comment
Это решение дает (1.0, 2.0) для пересечения line_intersection(((0.5, 0.5), (1.5, 0.5)), ((1, 0), (1, 2))), которое должно быть (1, 0.5). - person xtofl; 11.08.2014
comment
Я должен согласиться с @xtofl - это не работает. Я получаю ложные срабатывания и отрицания. - person rbaleksandar; 08.09.2016
comment
Î также не использовал бы здесь исключения. Подойдет простой False, и это не так дорого, как обработка исключения. - person rbaleksandar; 08.09.2016
comment
Это решение не работает для точек, которые пересекаются в (0., 0.) - person Lee; 23.02.2017
comment
Ха! @Pithikos собирался сказать, что ... Изобретать колесо полезно только для обучения / понимания и никогда для реализации - person user32882; 17.03.2019
comment
Я бы никогда не реализовал код, который уже запрограммирован в библиотеке: это пустая трата времени, и вы рискуете сделать код с ошибками. Как сказал @ user32882, единственный смысл самореализации - это учиться, но вопрос не в этом. Я рекомендую этот ответ для математического форума. ;) - person loved.by.Jesus; 29.09.2020
comment
@ love.by.Jesus Я согласен. Если у вас есть хороший способ установки, аудита, развертывания и обновления вашей библиотеки. - person Paul Draper; 29.09.2020
comment
использование других библиотек плохо что ?? но numpy широко используется, и реализация намного приятнее stackoverflow.com/a/42727584/2580835 - person iperov; 13.03.2021

Не могу оставаться в стороне,

Итак, у нас есть линейная система:

A 1 * x + B 1 * y = C 1
A 2 * x + B < sub> 2 * y = C 2

давайте сделаем это с помощью правила Крамера, поэтому решение можно найти в детерминантах:

x = D x / D
y = D y / D

где D - главный детерминант системы:

A 1 B 1
A 2 B 2

и D x и D y можно найти из матриц:

C 1 B 1
C 2 B 2

а также

A 1 C 1
A 2 C 2

(обратите внимание, поскольку столбец C последовательно заменяет столбцы коэффициентов x и y)

Итак, теперь питон, для ясности, чтобы не напортачить, давайте сделаем сопоставление между математикой и питоном. Мы будем использовать массив L для хранения наших коэффициентов A, B, C линейных уравнений и вместо красивых x, y у нас будет [0], [1], но все равно. Таким образом, то, что я написал выше, в дальнейшем будет иметь следующий вид:

для D

L1[0] L1[1]
L2[0] L2[1]

для D x

L1[2] L1[1]
L2[2] L2[1]

для D y

L1[0] L1[2]
L2[0] L2[2]

Теперь займемся кодированием:

line - создает коэффициенты A, B, C линейного уравнения по двум указанным точкам,
intersection - находит точку пересечения (если есть) двух строк, предоставленных coefs.

from __future__ import division 

def line(p1, p2):
    A = (p1[1] - p2[1])
    B = (p2[0] - p1[0])
    C = (p1[0]*p2[1] - p2[0]*p1[1])
    return A, B, -C

def intersection(L1, L2):
    D  = L1[0] * L2[1] - L1[1] * L2[0]
    Dx = L1[2] * L2[1] - L1[1] * L2[2]
    Dy = L1[0] * L2[2] - L1[2] * L2[0]
    if D != 0:
        x = Dx / D
        y = Dy / D
        return x,y
    else:
        return False

Пример использования:

L1 = line([0,1], [2,3])
L2 = line([2,3], [0,4])

R = intersection(L1, L2)
if R:
    print "Intersection detected:", R
else:
    print "No single intersection point detected"
person rook    schedule 19.12.2013
comment
Работает хорошо, очень шустро - person Alex Black; 20.06.2016
comment
Это решение сообщает о пересечении, где линии МОГУТ пересекаться, учитывая их бесконечную длину. - person firelynx; 26.09.2016
comment
@firelynx Я думаю, вы путаете термин линия с сегментом линии. OP запрашивает пересечение линий (намеренно или из-за непонимания разницы). При проверке линий на пересечение необходимо учитывать тот факт, что линии бесконечны, то есть лучи, начинающиеся из его средней точки (определяемой заданными координатами двух точек, которые определяют ее) в обоих направлениях. В случае пересечения отрезков линии только часть линии между заданными точками проверяется на пересечение, а ее бесконечное продолжение игнорируется. - person rbaleksandar; 16.10.2016
comment
Кстати, как насчет совпадения линий? Используя приведенный выше алгоритм, он возвращает true для двух совпадающих линий, которые, очевидно, не могут возвращать единственную точку пересечения (поскольку математически в этом случае существует бесконечное количество точек пересечения). Я думаю, что алгоритмы должны обрабатывать это в отдельном случае, поскольку просто пересекающиеся и совпадающие линии - это два очень разных случая. - person rbaleksandar; 08.11.2016
comment
Да @rbaleksandar, с этим методом - когда R равно true (D != 0), мы можем говорить только о пересекающихся линиях. Все остальные случаи для R (когда D == 0) могут означать что угодно, кроме пересекающихся (совпадающих или параллельных) линий. - person rook; 10.11.2016
comment
извините за копание, но я не могу понять, как определяются значения для A, B и C, как и в первом методе. кто-нибудь может уточнить? Спасибо! - person Applecow; 09.01.2018
comment
@Applecow: C - определитель строки. См. Ответ Пола Дрейпера (stackoverflow.com/a/20677983/501134) - person mrdaliri; 14.12.2019

Вот решение с использованием библиотеки Shapely. Shapely часто используется для работы с ГИС, но создан для использования в вычислительной геометрии. Я изменил ваши входные данные со списков на кортежи.

Проблема

# Given these endpoints
#line 1
A = (X, Y)
B = (X, Y)

#line 2
C = (X, Y)
D = (X, Y)

# Compute this:
point_of_intersection = (X, Y)

Решение

import shapely
from shapely.geometry import LineString, Point

line1 = LineString([A, B])
line2 = LineString([C, D])

int_pt = line1.intersection(line2)
point_of_intersection = int_pt.x, int_pt.y

print(point_of_intersection)
person user11708734    schedule 27.06.2019
comment
Важно знать, что это решение работает только в том случае, если пересечение находится между заданными конечными точками, поскольку shapely находит только пересечение сегментов линии, а не соответствующих бесконечных линий. - person jarlemag; 07.12.2020

Используя формулу из: https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection

 def findIntersection(x1,y1,x2,y2,x3,y3,x4,y4):
        px= ( (x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4) ) / ( (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4) ) 
        py= ( (x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4) ) / ( (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4) )
        return [px, py]
person Gabriel Eng    schedule 01.07.2018
comment
Я использую этот фрагмент кода с большим успехом. Однако я борюсь с тем, как построить механизм, который бы сказал мне, действительно ли точка пересекается с конечным отрезком прямой, а не с воображаемой бесконечной линией. Поэтому мне нужно найти, находится ли точка x, y где-нибудь в пространстве (x1, y1, x2, y2). Любые идеи? - person Mars; 19.11.2020

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

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

import numpy as np
import matplotlib.pyplot as plt
"""
Sukhbinder
5 April 2017
Based on:    
"""

def _rect_inter_inner(x1,x2):
    n1=x1.shape[0]-1
    n2=x2.shape[0]-1
    X1=np.c_[x1[:-1],x1[1:]]
    X2=np.c_[x2[:-1],x2[1:]]    
    S1=np.tile(X1.min(axis=1),(n2,1)).T
    S2=np.tile(X2.max(axis=1),(n1,1))
    S3=np.tile(X1.max(axis=1),(n2,1)).T
    S4=np.tile(X2.min(axis=1),(n1,1))
    return S1,S2,S3,S4

def _rectangle_intersection_(x1,y1,x2,y2):
    S1,S2,S3,S4=_rect_inter_inner(x1,x2)
    S5,S6,S7,S8=_rect_inter_inner(y1,y2)

    C1=np.less_equal(S1,S2)
    C2=np.greater_equal(S3,S4)
    C3=np.less_equal(S5,S6)
    C4=np.greater_equal(S7,S8)

    ii,jj=np.nonzero(C1 & C2 & C3 & C4)
    return ii,jj

def intersection(x1,y1,x2,y2):
    """
INTERSECTIONS Intersections of curves.
   Computes the (x,y) locations where two curves intersect.  The curves
   can be broken with NaNs or have vertical segments.
usage:
x,y=intersection(x1,y1,x2,y2)
    Example:
    a, b = 1, 2
    phi = np.linspace(3, 10, 100)
    x1 = a*phi - b*np.sin(phi)
    y1 = a - b*np.cos(phi)
    x2=phi    
    y2=np.sin(phi)+2
    x,y=intersection(x1,y1,x2,y2)
    plt.plot(x1,y1,c='r')
    plt.plot(x2,y2,c='g')
    plt.plot(x,y,'*k')
    plt.show()
    """
    ii,jj=_rectangle_intersection_(x1,y1,x2,y2)
    n=len(ii)

    dxy1=np.diff(np.c_[x1,y1],axis=0)
    dxy2=np.diff(np.c_[x2,y2],axis=0)

    T=np.zeros((4,n))
    AA=np.zeros((4,4,n))
    AA[0:2,2,:]=-1
    AA[2:4,3,:]=-1
    AA[0::2,0,:]=dxy1[ii,:].T
    AA[1::2,1,:]=dxy2[jj,:].T

    BB=np.zeros((4,n))
    BB[0,:]=-x1[ii].ravel()
    BB[1,:]=-x2[jj].ravel()
    BB[2,:]=-y1[ii].ravel()
    BB[3,:]=-y2[jj].ravel()

    for i in range(n):
        try:
            T[:,i]=np.linalg.solve(AA[:,:,i],BB[:,i])
        except:
            T[:,i]=np.NaN


    in_range= (T[0,:] >=0) & (T[1,:] >=0) & (T[0,:] <=1) & (T[1,:] <=1)

    xy0=T[2:,in_range]
    xy0=xy0.T
    return xy0[:,0],xy0[:,1]


if __name__ == '__main__':

    # a piece of a prolate cycloid, and am going to find
    a, b = 1, 2
    phi = np.linspace(3, 10, 100)
    x1 = a*phi - b*np.sin(phi)
    y1 = a - b*np.cos(phi)

    x2=phi
    y2=np.sin(phi)+2
    x,y=intersection(x1,y1,x2,y2)
    plt.plot(x1,y1,c='r')
    plt.plot(x2,y2,c='g')
    plt.plot(x,y,'*k')
    plt.show()
person Paul Chen    schedule 11.02.2019
comment
обязательно иметь list или nd.array? - person Mir.Emad; 08.07.2020

Я не нашел интуитивного объяснения в сети, так что теперь, когда я его понял, вот мое решение. Это для бесконечных линий (что мне было нужно), а не для сегментов.

Некоторые термины, которые вы можете запомнить:

Линия определяется как y = mx + b OR y = slope * x + y-intercept

Уклон = подъем через пробег = dy / dx = высота / расстояние

Y-пересечение - это место, где линия пересекает ось Y, где X = 0

С учетом этих определений, вот некоторые функции:

def slope(P1, P2):
    # dy/dx
    # (y2 - y1) / (x2 - x1)
    return(P2[1] - P1[1]) / (P2[0] - P1[0])

def y_intercept(P1, slope):
    # y = mx + b
    # b = y - mx
    # b = P1[1] - slope * P1[0]
    return P1[1] - slope * P1[0]

def line_intersect(m1, b1, m2, b2):
    if m1 == m2:
        print ("These lines are parallel!!!")
        return None
    # y = mx + b
    # Set both lines equal to find the intersection point in the x direction
    # m1 * x + b1 = m2 * x + b2
    # m1 * x - m2 * x = b2 - b1
    # x * (m1 - m2) = b2 - b1
    # x = (b2 - b1) / (m1 - m2)
    x = (b2 - b1) / (m1 - m2)
    # Now solve for y -- use either line, because they are equal here
    # y = mx + b
    y = m1 * x + b1
    return x,y

Вот простой тест между двумя (бесконечными) строками:

A1 = [1,1]
A2 = [3,3]
B1 = [1,3]
B2 = [3,1]
slope_A = slope(A1, A2)
slope_B = slope(B1, B2)
y_int_A = y_intercept(A1, slope_A)
y_int_B = y_intercept(B1, slope_B)
print(line_intersect(slope_A, y_int_A, slope_B, y_int_B))

Выход:

(2.0, 2.0)
person Kiki Jewell    schedule 18.09.2017
comment
Вы можете попробовать это со следующими точками: A1 = [1,1] A2 = [1,3] B1 = [1,3] B2 = [3,1] - person Charlie Burns; 22.11.2017
comment
Все, что представляет собой линию с y = ax + b, выйдет из строя с вертикальными линиями - person Mehdi; 26.02.2019

Самое краткое решение, которое я нашел, использует Sympy: https://www.geeksforgeeks.org/python-sympy-line-intersection-method/

# import sympy and Point, Line 
from sympy import Point, Line 
  
p1, p2, p3 = Point(0, 0), Point(1, 1), Point(7, 7) 
l1 = Line(p1, p2) 
  
# using intersection() method 
showIntersection = l1.intersection(p3) 
  
print(showIntersection) 
person jarlemag    schedule 07.12.2020

img И вы можете использовать этот код

class Nokta:
def __init__(self,x,y):
    self.x=x
    self.y=y             
class Dogru:
def __init__(self,a,b):
    self.a=a
    self.b=b        

def Kesisim(self,Dogru_b):
    x1= self.a.x
    x2=self.b.x
    x3=Dogru_b.a.x
    x4=Dogru_b.b.x
    y1= self.a.y
    y2=self.b.y
    y3=Dogru_b.a.y
    y4=Dogru_b.b.y                          
    #Notlardaki denklemleri kullandım
    pay1=((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3))      
    pay2=((x2-x1) * (y1 - y3) - (y2 - y1) * (x1 - x3))
    payda=((y4 - y3) *(x2-x1)-(x4 - x3)*(y2 - y1))        

    if pay1==0 and pay2==0 and payda==0:
        print("DOĞRULAR BİRBİRİNE ÇAKIŞIKTIR")

    elif payda==0:               
        print("DOĞRULAR BİRBİRNE PARALELDİR")        
    else:                               
        ua=pay1/payda if payda else 0                   
        ub=pay2/payda  if payda else 0  
        #x ve y buldum 
        x=x1+ua*(x2-x1) 
        y=y1+ua*(y2-y1)
        print("DOĞRULAR {},{} NOKTASINDA KESİŞTİ".format(x,y))
person Abdurrhman Sefer    schedule 08.05.2020