Как найти точку пересечения прямых python

If your lines are multiple points instead, you can use this version.

enter image description here

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

Stolen directly from https://web.archive.org/web/20111108065352/https://www.cs.mun.ca/~rod/2500/notes/numpy-arrays/numpy-arrays.html

#
# line segment intersection using vectors
# see Computer Graphics by F.S. Hill
#
from numpy import *
def perp( a ) :
    b = empty_like(a)
    b[0] = -a[1]
    b[1] = a[0]
    return b

# line segment a given by endpoints a1, a2
# line segment b given by endpoints b1, b2
# return 
def seg_intersect(a1,a2, b1,b2) :
    da = a2-a1
    db = b2-b1
    dp = a1-b1
    dap = perp(da)
    denom = dot( dap, db)
    num = dot( dap, dp )
    return (num / denom.astype(float))*db + b1

p1 = array( [0.0, 0.0] )
p2 = array( [1.0, 0.0] )

p3 = array( [4.0, -5.0] )
p4 = array( [4.0, 2.0] )

print seg_intersect( p1,p2, p3,p4)

p1 = array( [2.0, 2.0] )
p2 = array( [4.0, 3.0] )

p3 = array( [6.0, 0.0] )
p4 = array( [6.0, 3.0] )

print seg_intersect( p1,p2, p3,p4)

Trenton McKinney's user avatar

answered Jul 15, 2010 at 3:13

Hamish Grubijan's user avatar

Hamish GrubijanHamish Grubijan

10.5k23 gold badges97 silver badges147 bronze badges

6

import numpy as np

def get_intersect(a1, a2, b1, b2):
    """ 
    Returns the point of intersection of the lines passing through a2,a1 and b2,b1.
    a1: [x, y] a point on the first line
    a2: [x, y] another point on the first line
    b1: [x, y] a point on the second line
    b2: [x, y] another point on the second line
    """
    s = np.vstack([a1,a2,b1,b2])        # s for stacked
    h = np.hstack((s, np.ones((4, 1)))) # h for homogeneous
    l1 = np.cross(h[0], h[1])           # get first line
    l2 = np.cross(h[2], h[3])           # get second line
    x, y, z = np.cross(l1, l2)          # point of intersection
    if z == 0:                          # lines are parallel
        return (float('inf'), float('inf'))
    return (x/z, y/z)

if __name__ == "__main__":
    print get_intersect((0, 1), (0, 2), (1, 10), (1, 9))  # parallel  lines
    print get_intersect((0, 1), (0, 2), (1, 10), (2, 10)) # vertical and horizontal lines
    print get_intersect((0, 1), (1, 2), (0, 10), (1, 9))  # another line for fun

Explanation

Note that the equation of a line is ax+by+c=0. So if a point is on this line, then it is a solution to (a,b,c).(x,y,1)=0 (. is the dot product)

let l1=(a1,b1,c1), l2=(a2,b2,c2) be two lines and p1=(x1,y1,1), p2=(x2,y2,1) be two points.

Finding the line passing through two points:

let t=p1xp2 (the cross product of two points) be a vector representing a line.

We know that p1 is on the line t because t.p1 = (p1xp2).p1=0.
We also know that p2 is on t because t.p2 = (p1xp2).p2=0. So t must be the line passing through p1 and p2.

This means that we can get the vector representation of a line by taking the cross product of two points on that line.

Finding the point of intersection:

Now let r=l1xl2 (the cross product of two lines) be a vector representing a point

We know r lies on l1 because r.l1=(l1xl2).l1=0. We also know r lies on l2 because r.l2=(l1xl2).l2=0. So r must be the point of intersection of the lines l1 and l2.

Interestingly, we can find the point of intersection by taking the cross product of two lines.

answered Mar 10, 2017 at 20:56

Norbu Tsering's user avatar

10

This is is a late response, perhaps, but it was the first hit when I Googled ‘numpy line intersections’. In my case, I have two lines in a plane, and I wanted to quickly get any intersections between them, and Hamish’s solution would be slow — requiring a nested for loop over all line segments.

Here’s how to do it without a for loop (it’s quite fast):

from numpy import where, dstack, diff, meshgrid

def find_intersections(A, B):

    # min, max and all for arrays
    amin = lambda x1, x2: where(x1<x2, x1, x2)
    amax = lambda x1, x2: where(x1>x2, x1, x2)
    aall = lambda abools: dstack(abools).all(axis=2)
    slope = lambda line: (lambda d: d[:,1]/d[:,0])(diff(line, axis=0))

    x11, x21 = meshgrid(A[:-1, 0], B[:-1, 0])
    x12, x22 = meshgrid(A[1:, 0], B[1:, 0])
    y11, y21 = meshgrid(A[:-1, 1], B[:-1, 1])
    y12, y22 = meshgrid(A[1:, 1], B[1:, 1])

    m1, m2 = meshgrid(slope(A), slope(B))
    m1inv, m2inv = 1/m1, 1/m2

    yi = (m1*(x21-x11-m2inv*y21) + y11)/(1 - m1*m2inv)
    xi = (yi - y21)*m2inv + x21

    xconds = (amin(x11, x12) < xi, xi <= amax(x11, x12), 
              amin(x21, x22) < xi, xi <= amax(x21, x22) )
    yconds = (amin(y11, y12) < yi, yi <= amax(y11, y12),
              amin(y21, y22) < yi, yi <= amax(y21, y22) )

    return xi[aall(xconds)], yi[aall(yconds)]

Then to use it, provide two lines as arguments, where is arg is a 2 column matrix, each row corresponding to an (x, y) point:

# example from matplotlib contour plots
Acs = contour(...)
Bsc = contour(...)

# A and B are the two lines, each is a 
# two column matrix
A = Acs.collections[0].get_paths()[0].vertices
B = Bcs.collections[0].get_paths()[0].vertices

# do it
x, y = find_intersections(A, B)

have fun

Eric's user avatar

Eric

94.7k52 gold badges239 silver badges370 bronze badges

answered Feb 2, 2012 at 10:44

marmaduke's user avatar

marmadukemarmaduke

1011 silver badge2 bronze badges

2

This is a version of @Hamish Grubijan’s answer that also works for multiple points in each of the input arguments, i.e., a1, a2, b1, b2 can be Nx2 row arrays of 2D points. The perp function is replaced by a dot product.

T = np.array([[0, -1], [1, 0]])
def line_intersect(a1, a2, b1, b2):
    da = np.atleast_2d(a2 - a1)
    db = np.atleast_2d(b2 - b1)
    dp = np.atleast_2d(a1 - b1)
    dap = np.dot(da, T)
    denom = np.sum(dap * db, axis=1)
    num = np.sum(dap * dp, axis=1)
    return np.atleast_2d(num / denom).T * db + b1

answered Nov 16, 2016 at 16:55

user1248490's user avatar

user1248490user1248490

9539 silver badges16 bronze badges

I would like to add something small here. The original question is about line segments. I arrived here, because I was looking for line segment intersection, which in my case meant that I need to filter those cases, where no intersection of the line segments exists. Here is some code which does that:

def line_intersection(x1, y1, x2, y2, x3, y3, x4, y4):
    """find the intersection of line segments A=(x1,y1)/(x2,y2) and
    B=(x3,y3)/(x4,y4). Returns a point or None"""
    denom = ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
    if denom==0: return None
    px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denom
    py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denom
    if (px - x1) * (px - x2) < 0 and (py - y1) * (py - y2) < 0 
      and (px - x3) * (px - x4) < 0 and (py - y3) * (py - y4) < 0:
        return [px, py]
    else:
        return None

answered Aug 25, 2021 at 14:32

user16751456's user avatar

1

In case you are looking for a vectorized version where we can rule out vertical line segments.

def intersect(a):
    # a numpy array with dimension [n, 2, 2, 2]
    # axis 0: line-pair, axis 1: two lines, axis 2: line delimiters axis 3: x and y coords
    # for each of the n line pairs a boolean is returned stating of the two lines intersect
    # Note: the edge case of a vertical line is not handled.
    m = (a[:, :, 1, 1] - a[:, :, 0, 1]) / (a[:, :, 1, 0] - a[:, :, 0, 0])
    t = a[:, :, 0, 1] - m[:, :] * a[:, :, 0, 0]
    x = (t[:, 0] - t[:, 1]) / (m[:, 1] - m[:, 0])
    y = m[:, 0] * x + t[:, 0]
    r = a.min(axis=2).max(axis=1), a.max(axis=2).min(axis=1)
    return (x >= r[0][:, 0]) & (x <= r[1][:, 0]) & (y >= r[0][:, 1]) & (y <= r[1][:, 1])

A sample invocation would be:

intersect(np.array([
    [[[1, 2], [2, 2]],
     [[1, 2], [1, 1]]], # I
    [[[3, 4], [4, 4]],
     [[4, 4], [5, 6]]], # II
    [[[2, 0], [3, 1]],
     [[3, 0], [4, 1]]], # III
    [[[0, 5], [2, 5]],
     [[2, 4], [1, 3]]], # IV
]))
# returns [False, True, False, False]

Visualization (I need more reputation to post images here).

answered Jan 9, 2022 at 16:30

Florian Leicher's user avatar

Here’s a (bit forced) one-liner:

import numpy as np
from scipy.interpolate import interp1d

x = np.array([0, 1])
segment1 = np.array([0, 1])
segment2 = np.array([-1, 2])

x_intersection = interp1d(segment1 - segment2, x)(0)
# if you need it:
y_intersection = interp1d(x, segment1)(x_intersection)

Interpolate the difference (default is linear), and find a 0 of the inverse.

Cheers!

answered Mar 31, 2017 at 17:36

Andy Reagan's user avatar

Andy ReaganAndy Reagan

5797 silver badges16 bronze badges

3

This is what I use to find line intersection, it works having either 2 points of each line, or just a point and its slope. I basically solve the system of linear equations.

def line_intersect(p0, p1, m0=None, m1=None, q0=None, q1=None):
    ''' intersect 2 lines given 2 points and (either associated slopes or one extra point)
    Inputs:
        p0 - first point of first line [x,y]
        p1 - fist point of second line [x,y]
        m0 - slope of first line
        m1 - slope of second line
        q0 - second point of first line [x,y]
        q1 - second point of second line [x,y]
    '''
    if m0 is  None:
        if q0 is None:
            raise ValueError('either m0 or q0 is needed')
        dy = q0[1] - p0[1]
        dx = q0[0] - p0[0]
        lhs0 = [-dy, dx]
        rhs0 = p0[1] * dx - dy * p0[0]
    else:
        lhs0 = [-m0, 1]
        rhs0 = p0[1] - m0 * p0[0]

    if m1 is  None:
        if q1 is None:
            raise ValueError('either m1 or q1 is needed')
        dy = q1[1] - p1[1]
        dx = q1[0] - p1[0]
        lhs1 = [-dy, dx]
        rhs1 = p1[1] * dx - dy * p1[0]
    else:
        lhs1 = [-m1, 1]
        rhs1 = p1[1] - m1 * p1[0]

    a = np.array([lhs0, 
                  lhs1])

    b = np.array([rhs0, 
                  rhs1])
    try:
        px = np.linalg.solve(a, b)
    except:
        px = np.array([np.nan, np.nan])

    return px

answered Oct 17, 2014 at 1:01

dashesy's user avatar

dashesydashesy

2,5593 gold badges44 silver badges61 bronze badges

We can solve this 2D line intersection problem using determinant.

To solve this, we have to convert our lines to the following form: ax+by=c. where

 a = y1 - y2
 b = x1 - x2
 c = ax1 + by1 

If we apply this equation for each line, we will got two line equation. a1x+b1y=c1 and a2x+b2y=c2.

Now when we got the expression for both lines.
First of all we have to check if the lines are parallel or not. To examine this we want to find the determinant. The lines are parallel if the determinant is equal to zero.
We find the determinant by solving the following expression:

det = a1 * b2 - a2 * b1

If the determinant is equal to zero, then the lines are parallel and will never intersect. If the lines are not parallel, they must intersect at some point.
The point of the lines intersects are found using the following formula:

equation for finding line intersection using determinant

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y


'''
finding intersect point of line AB and CD 
where A is the first point of line AB
and B is the second point of line AB
and C is the first point of line CD
and D is the second point of line CD
'''



def get_intersect(A, B, C, D):
    # a1x + b1y = c1
    a1 = B.y - A.y
    b1 = A.x - B.x
    c1 = a1 * (A.x) + b1 * (A.y)

    # a2x + b2y = c2
    a2 = D.y - C.y
    b2 = C.x - D.x
    c2 = a2 * (C.x) + b2 * (C.y)

    # determinant
    det = a1 * b2 - a2 * b1

    # parallel line
    if det == 0:
        return (float('inf'), float('inf'))

    # intersect point(x,y)
    x = ((b2 * c1) - (b1 * c2)) / det
    y = ((a1 * c2) - (a2 * c1)) / det
    return (x, y)

answered Sep 6, 2019 at 11:32

Sadekujjaman's user avatar

2

I wrote a module for line to compute this and some other simple line operations. It is implemented in c++, so it works very fast. You can install FastLine via pip and then use it in this way:

from FastLine import Line
# define a line by two points
l1 = Line(p1=(0,0), p2=(10,10))
# or define a line by slope and intercept
l2 = Line(m=0.5, b=-1)

# compute intersection
p = l1.intersection(l2)
# returns (-2.0, -2.0)

answered Jan 22, 2022 at 17:13

M.Ali Zarrinzade's user avatar

0

The reason you would want to use numpy code is because it’s faster and it’s only really faster when you can broadcast it. The way you make numpy code fast is by doing everything in a series of of numpy operations without loops. If you’re not going to do this, don’t use numpy.

    def line_intersect(x1, y1, x2, y2, x3, y3, x4, y4):
        denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
        if denom == 0:
            return None  # Parallel.
        ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom
        ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom
        if 0.0 <= ua <= 1.0 and 0.0 <= ub <= 1.0:
            return (x1 + ua * (x2 - x1)), (y1 + ua * (y2 - y1))
        return None

However, let’s do use numpy:

It’s a bit easier to deal with points as complex numbers (x=real, y=imag). That trick is used elsewhere. And rather than a 2d set of elements we use a numpy 1d complex array for the 2d points.

import numpy as np

def find_intersections(a, b):
    old_np_seterr = np.seterr(divide="ignore", invalid="ignore")
    try:
        ax1, bx1 = np.meshgrid(np.real(a[:-1]), np.real(b[:-1]))
        ax2, bx2 = np.meshgrid(np.real(a[1:]), np.real(b[1:]))
        ay1, by1 = np.meshgrid(np.imag(a[:-1]), np.imag(b[:-1]))
        ay2, by2 = np.meshgrid(np.imag(a[1:]), np.imag(b[1:]))

        # Note if denom is zero these are parallel lines.
        denom = (by2 - by1) * (ax2 - ax1) - (bx2 - bx1) * (ay2 - ay1)

        ua = ((bx2 - bx1) * (ay1 - by1) - (by2 - by1) * (ax1 - bx1)) / denom
        ub = ((ax2 - ax1) * (ay1 - by1) - (ay2 - ay1) * (ax1 - bx1)) / denom
        hit = np.dstack((0.0 <= ua, ua <= 1.0, 0.0 <= ub, ub <= 1.0)).all(axis=2)
        ax1 = ax1[hit]
        ay1 = ay1[hit]
        x_vals = ax1 + ua[hit] * (ax2[hit] - ax1)
        y_vals = ay1 + ua[hit] * (ay2[hit] - ay1)
        return x_vals + y_vals * 1j
    finally:
        np.seterr(**old_np_seterr)

Invoking code:

import svgelements as svge
from random import random
import numpy as np

j = svge.Path(svge.Circle(cx=random() * 5, cy=random() * 5, r=random() * 5)).npoint(
    np.arange(0, 1, 0.001)
)
k = svge.Path(svge.Circle(cx=random() * 5, cy=random() * 5, r=random() * 5)).npoint(
    np.arange(0, 1, 0.001)
)
j = j[:, 0] + j[:, 1] * 1j
k = k[:, 0] + k[:, 1] * 1j

intersects = find_intersections(j, k)
print(intersects)
# Random circles will intersect in 0 or 2 points.

In our code, a and b are segment lists. These expect to be a series of connected points and we mesh them to find any segment n -> n+1 segment that intersects with any or all the other segments.

We return all intersections between the polyline a and the polyline b.

Two tricks (for adaptations):

  1. We mesh all the segments. We check every segment in the polyline a list and every segment in the polyline b list. It’s pretty easy to see how you’d arrange this if you wanted other inputs.

  2. Many code examples will check if denom is zero but that’s not allowed in pure array code since there’s a mesh of different points to check, so conditionals need to be in-lined. We turn off the seterr for dividing by 0 and infinity because we expect to do that if we have parallel lines. Which gets rid of the check for denom being zero. If denom is zero then the lines are parallel which means they either meet at 0 points or infinite many points. The typical conditional checking for the values of ua and ub is done in an array stack of each of the checks which then sees if all of these are true for any elements, and then just returns true for those elements.


If you need the value t or the segments within the lists that intersected this should be readily determined from the ua ub and hit.

answered Dec 6, 2022 at 5:33

Tatarize's user avatar

TatarizeTatarize

10.1k4 gold badges57 silver badges64 bronze badges

import numpy as np

data = np.array([
    #  segment1               segment2
    # [[x1, y1], [x2, y2]],  [[x1, y1], [x2, y2]]
    [[0, 0], [1, 1], [0, 1], [1, 0]],
    [[0, 0], [1, 1], [1, 0], [1, 1]],
    [(0, 1), (0, 2), (1, 10), (2, 10)],
    [(0, 1), (1, 2), (0, 10), (1, 9)],
    [[0, 0], [0, 1], [0, 2], [1, 3]],
    [[0, 1], [2, 3], [4, 5], [6, 7]],  
    [[1, 2], [3, 4], [5, 6], [7, 8]]
])

def intersect(data):
    L = len(data)
    x1, y1, x2, y2 = data.reshape(L * 2, -1).T
    R = np.full([L, 2], np.nan)
    X = np.concatenate([
        (y2 - y1).reshape(L * 2, -1), 
        (x1 - x2).reshape(L * 2, -1)], 
        axis=1
    ).reshape(L, 2, 2)
    B = (x1 * y2 - x2 * y1).reshape(L, 2)
    I = np.isfinite(np.linalg.cond(X))
    R[I] = np.matmul(np.linalg.inv(X[I]), B[I][:,:,None]).squeeze(-1)
    return R

intersect(data)

array([[ 0.5,  0.5],
       [ 1. ,  1. ],
       [ 0. , 10. ],
       [ 4.5,  5.5],
       [ 0. ,  2. ],
       [ nan,  nan],
       [ nan,  nan]])

answered Mar 10 at 12:59

xmduhan's user avatar

xmduhanxmduhan

94712 silver badges14 bronze badges



У меня есть две линии, которые пересекаются в одной точке. Я знаю конечные точки этих двух линий. Как вычислить точку пересечения в 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]


4688  


6  

6 ответов:

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

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]) #Typo was here

    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)

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

Итак, мы имеем линейную систему:

A1 * x + B1 * y = C1
А2 * x + B2 * y = C2

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

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

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

A1 B1
А2 B2

И D x и D y можно найти из matricies:

C1 B1
С2 B2

И

A1 С1
А2 С2

(обратите внимание, что столбец C соответственно заменяет coef. столбцы x и y )

Итак, теперь python, для ясности для нас, чтобы не испортить вещи, давайте сделаем отображение между math и python. Мы будем использовать массив L для хранения наших coefs A, B, C линейных уравнений и intestead pretty 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 – производит coefs 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"

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

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

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

Наклон = подъем = ду / ДХ = высота / расстояние

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)

Используя формулу из:
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]

1. Чтобы найти пересечение двух прямых, вы можете использовать одновременные уравнения. Формула выглядит следующим образом:

Вычислите код пересечения двух прямых:

# Рассчитать пересечение двух прямых
#y = a1*x + b1
#y = a2*x + b2
# Если пересечения нет, выбросить исключение и вернуть None
def cal_intersection(a1,b1,a2,b2):
    try:
        x = (b2-b1)/(a1-a2)
        y = a1*(b2-b1)/(a1-a2) + b1
        return (x,y)
    except Exception as e:
        print(str(e))
        return None

2. Найдите крайнюю точку параболы, вычислите значение x, когда производная равна 0, а затем введите формулу, чтобы найти y, формула выглядит следующим образом:

Код для расчета параболических экстремумов:

# Парабола: y = a * x ** 2 + b * x + c 
# Если a равно 0, выбросить исключение и вернуть None
def getExtremePoint(a,b,c):
    try:
        x = -(b/2/a)
        y = (4*a*c - b**2)/4/a
        return (x,y)
    except Exception as e:
        print(str(e))
        return None

Проверить код для поиска пересечения прямых:

import numpy as np  
import matplotlib.pyplot as plt  

a1,b1,a2,b2 = np.random.rand(4)
input_x = np.arange(-5,5,0.1) 

y_predict2 = a1 * input_x + b1
y_predict1 = a2 * input_x + b2

#    
intersection = cal_intersection(a1,b1,a2,b2)

#Рисунок
plt.plot(input_x,y_predict1,color='r',linestyle='-',marker='.',label=u"predict") 
plt.plot(input_x,y_predict2,color='g',linestyle='-',marker='.',label=u"predict") 
plt.scatter(intersection[0],intersection[1],color='b',linestyle='-',marker='.',label=u"intersection",linewidth=11) 
plt.legend(loc='upper left')
plt.show()

Проверить код крайней точки параболы:

import numpy as np  
import matplotlib.pyplot as plt  

a,b,c = (-1) ** np.random.randint(0,2)*np.random.rand(3)
input_x = np.arange(-5,5,0.1) 

y_predict = a * input_x **2 + b * input_x + c

# Найти крайние точки
extreme = getExtremePoint(a,b,c)

#Рисунок
plt.plot(input_x,y_predict,color='r',linestyle='-',marker='.',label=u"predict") 
plt.scatter(extreme[0],extreme[1],color='b',linestyle='-',marker='.',label=u"extreme",linewidth=11) 
plt.legend(loc='upper left')
plt.show()

Вычислительная геометрия

Теоретический материал: обширный и подробный и краткий.

Полезно помнить про документацию на модуль math (ужатая версия на русском).
Там есть очень полезные функции, например, atan2.

Для тех, кто допускает, что его жизнь будет так или иначе связана с программированием, рекомендуется
создавать классы для базовых примитивов (точка, вектор, прямая, луч, окружность и т.п.) и определять соответствующие операции с ними.
Например, разность двух точек может давать вектор, вектора можно скалярно и векторно перемножать.
Сами вектора можно умножать на числа, складывать и вычитать.
Прямую можно собрать по двум точкам, по точке и вектору, которому прямая должна быть параллельна или перпендикулярна.
Функция “Пересечение” может выдавать список точек (возможно, пустой)
И т.п. Здесь хороший простор для продумывания удобной архитектуры решения.

Русско-английский тематический словарик

точка point
вектор vector
прямая line
луч ray
отрезок segment
угол angle
окружность circle
треугольник triangle
прямоугольник rectangle
квадрат square
многоугольник polygon
окружность circle
медиана median
биссектриса bisector
высота altitude
пересечение intersection
длина length
периметр perimeter
площадь area
касательная tangent
скалярное произведение dot product
векторное произведение cross product
вектор нормали normal vector
ограничивающий прямоугольник bounding box

0: Класс «Точка»

Реализуйте класс Pt, поддерживающих следующие операции:

  • Создание из пары чисел или из строки;
  • Сложение и вычитание точек;
  • Умножение и деление на число (целое и действительное);
  • Скалярное и косое произведения;
  • Вычисление длины при помощи abs;
  • Проверка на равенство.

print(Pt())
print(Pt(1, 2))
print(Pt(‘2 3’))
print(Pt(1, 2) + Pt(-1, 2))
print(Pt(1, 2) – Pt(-1, 2))
print(3 * Pt(1, 2))
print(Pt(4, 6) / 2)
print(Pt(1, 2).dot(Pt(2, 1)))
print(Pt(1, 2).cross(Pt(2, 1)))
print(abs(Pt(3, 4)))
print(Pt(1, 2) == Pt(1, 2))

(0, 0)
(1, 2)
(2, 3)
(0, 4)
(2, 0)
(3, 6)
(2.0, 3.0)
4
-3
5.0
True

Могущество скалярного и косого (векторного) произведения

Рассмотрим какой-нибудь ненулевой вектор $overrightarrow{v}$ на плоскости.
Для каждого вектора $overrightarrow{w}$ посчитаем скалярное и векторные произведения.
И в зависимости от знаков и равенства нулю покрасим области разным цветом.
В результате плоскость будет разбита на 4 четвертушки, 4 луча и точку.
Это позволяет очень быстро и эффективно определять взаимное расположение точек и векторов.

Упражнения на векторные и скалярные произведения

A: Расстояние между двумя точками

Даны координаты двух точек. Найдите расстояние между ними.

Для решения используйте math.hypot.

0 0
1 1

1.4142135623730951

B: Полярный угол точки

Даны два числа – координаты точки, не совпадающей с началом координат.

Выведите ее полярный угол (величину от 0 до $2pi$).

Для решения используйте math.atan2.

C: Угол между векторами

Даны четыре числа: координаты двух невырожденных векторов.

Выведите величину неориентированного угла между ними.

Для решения используйте math.atan2.

D: Площадь треугольника

Даны шесть чисел:
координаты трех вершин треугольника.

Выведите значение площади треугольника.

В решении разрешается использовать только скалярное и косое произведения.
Никаких корней и тригонометрии.

E: Классификация векторов

Даны четыре числа: координаты двух ненулевых векторов.
Если эти вектора коллинеарны, выведите 1. Если эти вектора
перпендикулярны, выведите 2. Иначе выведите 0.

В решении разрешается использовать только скалярное и косое произведения.
Никаких корней и тригонометрии.

F: Три точки

Программа получает на вход шесть чисел: координаты трех точек.

Программа должна вывести YES, если эти точки лежат на одной прямой, или
NO в противном случае.

В решении разрешается использовать только скалярное и косое произведения.
Никаких корней и тригонометрии.

G: Принадлежность точки лучу

Программа получает на вход шесть чисел: координаты точки
и координаты начала и конца вектора. Проверьте, принадлежит ли данная точка
лучу, задаваемому данным вектором.

Программа должна вывести YES, если точка принадлежит лучу, или
NO в противном случае.

В решении разрешается использовать только скалярное и косое произведения.
Никаких корней и тригонометрии.

H: Принадлежность точки отрезку

Программа получает на вход шесть чисел: координаты точки
и координаты концов отрезка. Проверьте, принадлежит ли данная точка
данному отрезку.

Программа должна вывести YES, если точка принадлежит отрезку, или
NO в противном случае.

В решении разрешается использовать только скалярное и косое произведения.
Никаких корней и тригонометрии.

I: Расстояние от точки до луча

Дано шесть чисел: координаты точки, координаты начала и конца вектора.

Программа должна вывести единственное число: расстояние от точки до луча,
заданного вектором.

В решении разрешается использовать только скалярное и косое произведения.
Никакой тригонометрии.

J: Расстояние от точки до отрезка

Дано шесть чисел: координаты точки и координаты двух концов отрезка.

Программа должна вывести единственное число:
расстояние от данной точки до данного отрезка.

В решении разрешается использовать только скалярное и косое произведения.
Никакой тригонометрии.

K: Принадлежит ли точка углу

Дан угол AOB (O — вершина угла, A и B — точки на сторонах) и точка P.
Определите, принадлежит ли точка P углу AOB (включая его стороны: лучи OA и OB).

Программа получает на вход координаты точек A, O, B, P.
Все координаты — целые, не превосходят 100 по модулю. Точки A, O, B не лежат на одной прямой.

Программа должна вывести слово YES или NO.

В решении разрешается использовать только скалярное и косое произведения.
Никаких корней и тригонометрии.

L: Пересекаются ли два луча

Даны два луча: AB и CD (A и C — вершины лучей, B и D лежат на лучах).
Проверьте, пересекаются ли они.

Программа получает на вход координаты точек A, B, C, D.
Все координаты — целые, не превосходят 100 по модулю.

Программа должна вывести слово YES или NO.

В решении разрешается использовать только скалярное и косое произведения.
Никаких корней и тригонометрии.

M: Пересекаются ли два отрезка

Даны два отрезка AB и CD.
Проверьте, пересекаются ли они.

Программа получает на вход координаты точек A, B, C, D.
Все координаты — целые, не превосходят 100 по модулю.

Программа должна вывести слово YES или NO.

Для решения пригодится bounding box — параллельный осям ограничивающий прямоугольник.
В решении разрешается использовать только скалярное и косое произведения.
Никаких корней и тригонометрии.

Упражнения на уравнение прямой

N: Уравнение прямой

Прямая задана двумя точками. Выведите коэффициенты A, B, C нормального уравнения прямой.

O: Перпендикулярная прямая

Дано уравнение прямой и координаты точки. Выведите коэффициенты уравнения прямой, перпендикулярной данной прямой и проходящей через данную точку.

P: Принадлежность точки прямой

Даны координаты точки и уравнение прямой. Определите, принадлежит ли точка прямой, выведите
YES или NO.

Q: Взаимное расположение двух точек

Даны две точки и уравнение прямой, точки не лежат на прямой. Выведите YES, если точки лежат по одну сторону от прямой
и NO в противном случае.

R: Классификация прямых

Программа получает на вход шесть чисел: коэффициенты уравнений двух прямых.

Программа должна вывести 1, если эти прямые совпадают, 2 – если параллельны, 3 – если перпендикулярны и 0 во всех остальных случаях.

В решении разрешается использовать только скалярное и косое произведения.
Никаких корней и тригонометрии.

S: Расстояние от точки до прямой

Даны пять чисел: координаты точки и коэффициенты нормального уравнения прямой.

Программа должна вывести одно число: расстояние от данной точки до данной прямой.

T: Параллельная прямая

Даны четыре числа: коэффициенты нормального уравнения прямой и величина d.

Программа должна вывести три числа: коэффициенты нормального уравнения любой из прямых, паралелльных данной, и лежащих от нее на расстоянии d.

U: Основание перпендикуляра

Дано пять чисел: координаты точки и коэффициенты нормального уравнения прямой.

Программа должна вывести два числа: координаты основания перпендикуляра, опущенного из данной точки на данную прямую

V: Пересечение двух прямых — 1

Дано шесть чисел: коэффициенты нормальных уравнений двух непараллельных прямых.

Программа должна вывести два числа: координаты точки пересечения данных прямых.

Если уравнения прямых — это $a_1x + b_1y + c_1=0$ и $a_2x + b_2y + c_2=0$,
то оказывается, что для нахождения ответа очень помогают числа
$$Delta=[overrightarrow{(a_1;b_1)}, overrightarrow{(a_2;b_2)}], quad
Delta_x=[overrightarrow{(c_1;b_1)}, overrightarrow{(c_2;b_2)}], quad
Delta_y=[overrightarrow{(a_1;c_1)}, overrightarrow{(a_2;c_2)}].$$
Соответствующие формулы называются формулами Крамера.
Обычно эти формулы записывают при помощи определителей:
$$Delta=begin{vmatrix} a_1 & b_1 \ a_2 & b_2 end{vmatrix}, quad
Delta_x=begin{vmatrix} c_1 & b_1 \ c_2 & b_2 end{vmatrix}, quad
Delta_y=begin{vmatrix} a_1 & c_1 \ a_2 & c_2 end{vmatrix}.$$

W: Пересечение двух прямых — 2

На плоскости даны две прямые. Каждая прямая задается парой точек, через которые она проходит. Требуется установить, пересекаются ли эти прямые, и найти координаты точки пересечения.

Вводятся сначала координаты двух различных точек, через которые проходит первая прямая, а затем — координаты еще двух различных (но, быть может, совпадающих с первыми двумя) точек, через которые проходит вторая прямая. Координаты каждой точки — целые числа, по модулю не превышающие 1000.

Если прямые не пересекаются, выведите одно число 0. Если прямые совпадают, выведите 2. Если прямые пересекаются ровно в одной точке, то выведите сначала число 1, а затем два вещественных числа — координаты точки пересечения.

0 0
1 1
1 0
-1 2

1 0.5 0.5

Добавить комментарий