If your lines are multiple points instead, you can use this version.
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)
answered Jul 15, 2010 at 3:13
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
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
94.7k52 gold badges239 silver badges370 bronze badges
answered Feb 2, 2012 at 10:44
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
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
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
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 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
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:
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
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
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):
-
We mesh all the segments. We check every segment in the
polyline a
list and every segment in thepolyline b
list. It’s pretty easy to see how you’d arrange this if you wanted other inputs. -
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
andub
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
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
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 prettyx
,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_intersectiondef 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