How would I use numpy to calculate the intersection between two line segments?
In the code I have segment1 = ((x1,y1),(x2,y2)) and segment2 = ((x1,y1),(x2,y2)). Note segment1 does not equal segment2. So in my code I've also been calculating the slope and y-intercept, it would be nice if that could be avoided but I don't know of a way how.
I've been using Cramer's rule with a function I wrote up in Python but I'd like to find a faster way of doing this.
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)
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.
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
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
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
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).
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!
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
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)
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)
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 the polyline 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 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.
Related
I have a real life problem. I have a segment representing a road that is defined by its geographic coordinates (let's call them p1_road_test and p2_road_test) and want to test whether it intersects with another set of segments (I gave all segments different coordinates to keep it simple) :
p1_road_test = np.array([1, 1]) # x, y value of point 1 of the road segment
p2_road_test = np.array([2, 4]) # x, y value of point 2 of the road segment
The other segments are defined by an original point (p_origin_test) and another point (p_moved_test) that describes to which position the original point has moved within a year:
p_origin_test = np.matrix([(3, 5, 6), (1, 1, 2)])
p_moved_test = np.matrix([(1,3, 3), (3, 3, 2)])
# basically, the original point (3, 1) moved to position (1, 3) and spans the segment accordingly. (5, 1) moves to (3, 3) etc.
p_origin_test
Out[46]:
matrix([[3, 5, 6],
[1, 1, 2]])
p_moved_test Out[47]:
matrix([[1, 3, 3],
[3, 3, 2]])
I chose a numpy matrix to store the data to speed up the calculation, since I have 30000+ segments I need to test against the street segment. In the end I would like to know if the second segment will ever intersect with the street segment when it continues to move at this "velocity" (the p_moved was surveyed after a month).
I followed this post to calculate if two segments intersect and derive their s and t value. So far so good.
X1, Y1 = p1_road_test[0], p1_road_test[1]
X2, Y2 = p2_road_test[0], p2_road_test[1]
#count = 0
Segment1 = ((X1, Y1), (X2, Y2))
for i in range(0, np.shape(p_origin_test)[1]):
X3, Y3 = p_origin_test[0, i], p_origin_test[1, i]
X4, Y4 = p_moved_test[0, i], p_moved_test[1, i]
Segment2 = ((X3, Y3), (X4, Y4))
dx1 = X2 - X1
dx2 = X4 - X3
dy1 = Y2 - Y1
dy2 = Y4 - Y3
det = dx1 * dy2 - dx2 * dy1
dx3 = X1 - X3
dy3 = Y1 - Y3
det1 = dx1 * dy3 - dx3 * dy1
det2 = dx2 * dy3 - dx3 * dy2
s = 3 / dx1
t = 1 / dx1
s = det1 / det
t = det2 / det
if s < 0.0 or s > 1.0 or t < 0.0 or t > 1.0:
print('false', s, t) # no intersect
else:
print(s, t)
which results in the anticipated output:
0.75 0.5
false 1.5 1.0
false 1.5555555555555556 0.3333333333333333
However, I would rather like to have another matrix as output with the same dimension as my input dataset (2, 30000) containing the s and t value since I will be needing it to further derive the "change per time unit". Also I know there is a more elegant way of doing this calculation than looping through the columns, but I can't figure it out.
I would really appreciate your input on this one.
I am working with Python 3.6.9 in Spyder3 on a Linux Mint 19.3.
I created two lists now,
s_list = []
t_list = []
stored the s and t value in it
[...]
if s < 0.0 or s > 1.0 or t < 0.0 or t > 1.0:
print('false', s, t) # no intersect
else:
print(s, t)
s_list.append(s)
t_list.append(t)
and created a matrix out of this.
st_values = np.matrix([s_list, t_list])
Still, I am certain there is a better solution!?
I am trying to create the equation in python.
Sorry in advance if this has already been asked! If so, I couldn't find it, so please share the post!
I run into the problem that I don't know how to code the part in the red square (see equation ).
As I understand it the "|u1|" stands for the absolute value of u1. However, if I code it like the equation is written i.e. abs(u1)abs(u2) I get a syntax error (which I kind of expected).
My problem is the line of code:
angle = np.arccos((Mu1*Mu2)/(abs(Mu1)abs(Mu2)))
My complete code is:
import numpy as np
from math import sqrt
#first direction vector
#punt 1, PQ
# [x,y]
P = (1,1)
Q = (5,3)
#punt 2, RS
R = (2,3)
S = (4,1)
#direction vector = arctan(yq-yp/xq-xp)
#create function to calc direction vector of line
def dirvec(coord1, coord2):
#pull coordinates into x and y variables
x1 , y1 = coord1[0], coord1[1]
x2 , y2 = coord2[0], coord2[1]
#calc vector see article
v = np.arctan((y2-y1)/(x2-x1))
#outputs in radians, not degrees
v = np.degrees(v)
return v
print(dirvec(P,Q))
print(dirvec(R,S))
Mu1 = dirvec(P,Q)
Mu2 = dirvec(R,S)
angle = np.arccos((Mu1*Mu2)/(abs(Mu1)abs(Mu2)))
print(angle)
Thins I tried:
multiply the two abs, but then I'll get the same number (pi) every time:
np.arccos((Mu1*Mu2)/(abs(Mu1)*abs(Mu2)))
+ and - but I cannot imagine these are correct:
np.arccos((Mu1Mu2)/(abs(Mu1)+abs(Mu2))) np.arccos((Mu1Mu2)/(abs(Mu1)-abs(Mu2)))
In the formula, the numerator is the dot product of two vectors, and the denominator is the product of the norms of the two vectors.
Here is a simple way to write your formula:
import math
def dot_product(u, v):
(x1, y1) = u
(x2, y2) = v
return x1 * x2 + y1 * y2
def norm(u):
(x, y) = u
return math.sqrt(x * x + y * y)
def get_angle(u, v):
return math.acos( dot_product(u,v) / (norm(u) * norm(v)) )
def make_vector(p, q):
(x1, y1) = p
(x2, y2) = q
return (x2 - x1, y2 - y1)
#first direction vector
#punt 1, PQ
# [x,y]
P = (1,1)
Q = (5,3)
#punt 2, RS
R = (2,3)
S = (4,1)
angle = get_angle(make_vector(p,q), make_vector(r,s))
print(angle)
From what I see, the result of your code would always be pi or 0. It will be pi if one of the mu1 or mu2 is negative and when both are negative or positive it will be zero.
If I remember vectors properly :
Given two vectors P and Q, with say P = (x, y) and Q = (a, b)
Then abs(P) = sqrt(x^2 + y^2) and P. Q = xa+yb. So that cos# = P. Q/(abs(P) *abs(Q)). If am not clear you can give an example of what you intend to do
Okay so apparently I made a mistake in my interpretation.
I want to thank everyone for your solutions!
After some puzzling it appears that:
import math
import numpy as np
#punt 1, PQ
# [x,y]
P = (1,1)
Q = (5,3)
x1 = P[0]
x2 = Q[0]
y1 = P[1]
y2 = Q[1]
#punt 2, RS
R = (0,2)
S = (4,1)
x3 = R[0]
x4 = S[0]
y3 = R[1]
y4 = S[1]
angle = np.arccos(((x2 - x1) * (x4 - x3) + (y2 - y1) * (y4 - y3)) / (math.sqrt((x2 - x1)**2 + (y2 - y1)**2) * math.sqrt((x4 - x3)**2 + (y4 - y3)**2)))
print(angle)
Is the correct way to calculate the angle between two vectors.
This is obviously not pretty code, but it is the essence of how it works!
Again I want to thank you all for you reaction and solutions!
I have two lines that intersect at a point. I know the endpoints of the two lines. How do I compute the intersection point in 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]
Unlike other suggestions, this is short and doesn't use external libraries like numpy. (Not that using other libraries is bad...it's nice not need to, especially for such a simple problem.)
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))
And FYI, I would use tuples instead of lists for your points. E.g.
A = (X, Y)
EDIT: Initially there was a typo. That was fixed Sept 2014 thanks to #zidik.
This is simply the Python transliteration of the following formula, where the lines are (a1, a2) and (b1, b2) and the intersection is p. (If the denominator is zero, the lines have no unique intersection.)
Can't stand aside,
So we have linear system:
A1 * x + B1 * y = C1
A2 * x + B2 * y = C2
let's do it with Cramer's rule, so solution can be found in determinants:
x = Dx/D
y = Dy/D
where D is main determinant of the system:
A1 B1
A2 B2
and Dx and Dy can be found from matricies:
C1 B1
C2 B2
and
A1 C1
A2 C2
(notice, as C column consequently substitues the coef. columns of x and y)
So now the python, for clarity for us, to not mess things up let's do mapping between math and python. We will use array L for storing our coefs A, B, C of the line equations and intestead of pretty x, y we'll have [0], [1], but anyway. Thus, what I wrote above will have the following form further in the code:
for D
L1[0] L1[1]
L2[0] L2[1]
for Dx
L1[2] L1[1]
L2[2] L2[1]
for Dy
L1[0] L1[2]
L2[0] L2[2]
Now go for coding:
line - produces coefs A, B, C of line equation by two points provided,
intersection - finds intersection point (if any) of two lines provided by 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
Usage example:
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"
Here is a solution using the Shapely library. Shapely is often used for GIS work, but is built to be useful for computational geometry. I changed your inputs from lists to tuples.
Problem
# 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)
Solution
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)
Using formula from:
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]
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()
I didn't find an intuitive explanation on the web, so now that I worked it out, here's my solution. This is for infinite lines (what I needed), not segments.
Some terms you might remember:
A line is defined as y = mx + b OR y = slope * x + y-intercept
Slope = rise over run = dy / dx = height / distance
Y-intercept is where the line crosses the Y axis, where X = 0
Given those definitions, here are some functions:
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
Here's a simple test between two (infinite) lines:
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))
Output:
(2.0, 2.0)
The most concise solution I have found uses 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)
With the scikit-spatial library you can easily do it in the following way:
import matplotlib.pyplot as plt
from skspatial.objects import Line
# Define the two lines.
line_1 = Line.from_points([3, -2], [5, 4])
line_2 = Line.from_points([-1, 0], [3, 2])
# Compute the intersection point
intersection_point = line_1.intersect_line(line_2)
# Plot
_, ax = plt.subplots()
line_1.plot_2d(ax, t_1=-2, t_2=3, c="k")
line_2.plot_2d(ax, t_1=-2, t_2=3, c="k")
intersection_point.plot_2d(ax, c="r", s=100)
grid = ax.grid()
there is already an answer that uses formula from Wikipedia but that doesn't have any check point to check if line segments actually intersect so here you go
def line_intersection(a, b, c, d):
t = ((a[0] - c[0]) * (c[1] - d[1]) - (a[1] - c[1]) * (c[0] - d[0])) / ((a[0] - b[0]) * (c[1] - d[1]) - (a[1] - b[1]) * (c[0] - d[0]))
u = ((a[0] - c[0]) * (a[1] - b[1]) - (a[1] - c[1]) * (a[0] - b[0])) / ((a[0] - b[0]) * (c[1] - d[1]) - (a[1] - b[1]) * (c[0] - d[0]))
# check if line actually intersect
if (0 <= t and t <= 1 and 0 <= u and u <= 1):
return [a[0] + t * (b[0] - a[0]), a[1] + t * (b[1] - a[1])]
else:
return False
#usage
print(line_intersection([0,0], [10, 10], [0, 10], [10,0]))
#result [5.0, 5.0]
img And You can use this kode
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))
I have written a Python script to calculate the distance between two points in 3D space while accounting for periodic boundary conditions. The problem is that I need to do this calculation for many, many points and the calculation is quite slow. Here is my function.
def PBCdist(coord1,coord2,UC):
dx = coord1[0] - coord2[0]
if (abs(dx) > UC[0]*0.5):
dx = UC[0] - dx
dy = coord1[1] - coord2[1]
if (abs(dy) > UC[1]*0.5):
dy = UC[1] - dy
dz = coord1[2] - coord2[2]
if (abs(dz) > UC[2]*0.5):
dz = UC[2] - dz
dist = np.sqrt(dx**2 + dy**2 + dz**2)
return dist
I then call the function as so
for i, coord2 in enumerate(coordlist):
if (PBCdist(coord1,coord2,UC) < radius):
do something with i
Recently I read that I can greatly increase performance by using list comprehension. The following works for the non-PBC case, but not for the PBC case
coord_indices = [i for i, y in enumerate([np.sqrt(np.sum((coord2-coord1)**2)) for coord2 in coordlist]) if y < radius]
for i in coord_indices:
do something
Is there some way to do the equivalent of this for the PBC case? Is there an alternative that would work better?
You should write your distance() function in a way that you can vectorise the loop over the 5711 points. The following implementation accepts an array of points as either the x0 or x1 parameter:
def distance(x0, x1, dimensions):
delta = numpy.abs(x0 - x1)
delta = numpy.where(delta > 0.5 * dimensions, delta - dimensions, delta)
return numpy.sqrt((delta ** 2).sum(axis=-1))
Example:
>>> dimensions = numpy.array([3.0, 4.0, 5.0])
>>> points = numpy.array([[2.7, 1.5, 4.3], [1.2, 0.3, 4.2]])
>>> distance(points, [1.5, 2.0, 2.5], dimensions)
array([ 2.22036033, 2.42280829])
The result is the array of distances between the points passed as second parameter to distance() and each point in points.
import numpy as np
bounds = np.array([10, 10, 10])
a = np.array([[0, 3, 9], [1, 1, 1]])
b = np.array([[2, 9, 1], [5, 6, 7]])
min_dists = np.min(np.dstack(((a - b) % bounds, (b - a) % bounds)), axis = 2)
dists = np.sqrt(np.sum(min_dists ** 2, axis = 1))
Here a and b are lists of vectors you wish to calculate the distance between and bounds are the boundaries of the space (so here all three dimensions go from 0 to 10 and then wrap). It calculates the distances between a[0] and b[0], a[1] and b[1], and so on.
I'm sure numpy experts could do better, but this will probably be an order of magnitude faster than what you're doing, since most of the work is now done in C.
I have found that meshgrid is very useful for generating distances. For example:
import numpy as np
row_diff, col_diff = np.meshgrid(range(7), range(8))
radius_squared = (row_diff - x_coord)**2 + (col_diff - y_coord)**2
I now have an array (radius_squared) where every entry specifies the square of the distance from the array position [x_coord, y_coord].
To circularize the array, I can do the following:
row_diff, col_diff = np.meshgrid(range(7), range(8))
row_diff = np.abs(row_diff - x_coord)
row_circ_idx = np.where(row_diff > row_diff.shape[1] / 2)
row_diff[row_circ_idx] = (row_diff[row_circ_idx] -
2 * (row_circ_idx + x_coord) +
row_diff.shape[1])
row_diff = np.abs(row_diff)
col_diff = np.abs(col_diff - y_coord)
col_circ_idx = np.where(col_diff > col_diff.shape[0] / 2)
col_diff[row_circ_idx] = (row_diff[col_circ_idx] -
2 * (col_circ_idx + y_coord) +
col_diff.shape[0])
col_diff = np.abs(row_diff)
circular_radius_squared = (row_diff - x_coord)**2 + (col_diff - y_coord)**2
I now have all the array distances circularized with vector math.
I want to find a 3D plane equation given 3 points. I have got the normal calculated after applying the cross product. But the equation of a plane is known to be the normal multiply by another vector which what I am taught to be as P.OP. I substitute my main reference point as OP and i want P to be in (x, y, z) form. So that I can get something like e.g,
OP = (1, 2, 3)
I want to get something like that:
(x-1)
(y-2)
(z-3)
May I know how?
Below is my reference code.(Note: plane_point_1_x(), plane_point_1_y(), plane_point_1_z() are all functions asking for the user input of the respective points)
"""
I used Point P as my reference point so I will make use of it in this section
"""
vector_pop_x = int('x') - int(plane_point_1_x())
vector_pop_y = int('y') - int(plane_point_1_y())
vector_pop_z = int('z') - int(plane_point_1_z())
print vector_pop_x, vector_pop_y, vector_pop_z
All the above is what i did, but for some reason it did not work. I think the problem lies in the x, y , z part.
Say you have three known points, each with (x, y, z). For example:
p1 = (1, 2, 3)
p2 = (4, 6, 9)
p3 = (12, 11, 9)
Make them into symbols that are easier to look at for further processing:
x1, y1, z1 = p1
x2, y2, z2 = p2
x3, y3, z3 = p3
Determine two vectors from the points:
v1 = [x3 - x1, y3 - y1, z3 - z1]
v2 = [x2 - x1, y2 - y1, z2 - z1]
Determine the cross product of the two vectors:
cp = [v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0]]
A plane can be described using a simple equation ax + by + cz = d. The three coefficients from the cross product are a, b and c, and d can be solved by substituting a known point, for example the first:
a, b, c = cp
d = a * x1 + b * y1 + c * z1
Now do something useful, like determine the z value at x=4, y=5. Re-arrange the simple equation, and solve for z:
x = 4
y = 5
z = (d - a * x - b * y) / float(c) # z = 6.176470588235294
If I am not mistaken, one good solution here contains mistypes
vector1 = [x2 - x1, y2 - y1, z2 - z1]
vector2 = [x3 - x1, y3 - y1, z3 - z1]
cross_product = [vector1[1] * vector2[2] - vector1[2] * vector2[1], -1 * (vector1[0] * vector2[2] - vector1[2] * vector2[0]), vector1[0] * vector2[1] - vector1[1] * vector2[0]]
a = cross_product[0]
b = cross_product[1]
c = cross_product[2]
d = - (cross_product[0] * x1 + cross_product[1] * y1 + cross_product[2] * z1)
Tried previous (author's) version, but had to check it. With couple more minuses in formulas seems correct now.
One good way is:
| x1 y1 z2 1 |
| x2 y2 z2 1 |
| x3 y3 z3 1 | = 0
| x y z 1 |
Where the vertical pipes mean the determinant of the matrix, and (x1 y1 z1), (x2 y2 z2), and (x3 y3 z3) are your given points.
Plane implicit Eqn:
All points P = (x, y, z) satisfying
<n, QP> = 0
where
n is the plane normal vector,
Q is some point on the plane (any will do)
QP is the vector from Q to P
<a, b> is the scalar (dot) product operator.
(Remember that QP can be computed as P - Q)
I wish this answer already existed. Coded from http://www.had2know.com/academics/equation-plane-through-3-points.html
Supposing 3 points p1, p2, p3 - consisting of [x1, y1, z1], etc.
vector1 = [x2 - x1, y2 - y1, z2 - z1]
vector2 = [x3 - x1, y3 - y1, z3 - z1]
cross_product = [vector1[1] * vector2[2] - vector1[2] * vector2[1], -1 * vector1[0] * v2[2] - vector1[2] * vector2[0], vector1[0] * vector2[1] - vector1[1] * vector2[0]]
d = cross_product[0] * x1 - cross_product[1] * y1 + cross_product[2] * z1
a = cross_product[0]
b = cross_product[1]
c = cross_product[2]
d = d