Elegant batch segment intersection calculation with numpy - python

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!?

Related

How to pick a random point from one of the sides of a pentagon?

In my program, I have 5 coordinates. In Python, I want to connect the 5 points together to form a pentagon, and know which points were connected to form each side. My goal is to then pick a random point from one of the sides of the pentagon. Does anyone know how I could write this in Python? I tried reading about convex hull but wasn't able to achieve anything, and I'm not sure if that is necessary for this problem. Thanks!
You can use the following to generate a point on a line segment:
x0 = x1 + a * (x2 - x1)
y0 = y1 + a * (y2 - y1)
, where (x1, y1) and (x2, y2) are start and end points of the segment and a is a number between 0 and 1.
Now, to solve your problem, you need two random numbers. First an integer to select a random side of the pentagon, and then a float between 0 and 1 to generate a random point on that side:
import random as rnd
i = rnd.randrange(5)
j = (i+1) % 5
t = rnd.uniform(0, 1)
x = [0, 1, 2, 3, 4]
y = [4, 3, 2, 1, 0]
x0 = x[i] + t * (x[j] - x[i])
y0 = y[i] + t * (y[j] - y[i])
print(i, j, t, x0, y0)

Mathematical calculation in python abs function

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!

Radius of three points out of a points list for python or R

For the purpose of a mathematical model of riding along an arbitrary path, I need to know the radius of each segment. My path is defined by points with the distance /dx in 3d space and listed in a text file (x;y;z).
To calculate the radius I need at least three points.
Therefore, I'm looking for a script (python or R) that takes the first three points, calculate the radius and stores the value to the middle point. For the next iteration it should take the second point as start and the following two points -> r(P1,P2,P3) -> P1(x,y,z) = n; P2(x,y,z) = n + 1; P3(x,y,z) = n + 2;
Thanks for any advise and your support!
# distance between 2 points
eucl.dist <- function(x1, x2) sqrt(sum((x1 - x2) ^ 2))
# area of triangle
area <- function(x1,x2,x3) {
v1 = x1 - x2
v2 = x1 - x3
0.5* sqrt( (v1[2]*v2[3] - v1[3]*v2[2])**2 +
(v1[3]*v2[1] - v1[1]*v2[3])**2 +
(v1[1]*v2[2] - v1[2]*v2[1])**2)
}
# function to calculate curvature (optional for this problem)
curvature <- function(x1, x2, x3){
4 * area(x1, x2, x3) / (eucl.dist(x1,x2)*eucl.dist(x2,x3)*eucl.dist(x3,x1))
}
# function to calculate radius
radius <- function(x1, x2, x3){
0.25 * (eucl.dist(x1,x2)*eucl.dist(x2,x3)*eucl.dist(x3,x1)) / area(x1, x2, x3)
}
# Test on some simple 2D case
path2D <- cbind( c(0, 1, 2, 2, 3, 4, 4, 4),
c(0, 1, 0,-1,-1, 0, 1, 3),
rep(0,8) )
names(path2D) <- x("x","y","z")
#plot the path
plot( path2D[,1], path2D[,2], type="b",
lwd=2, col="slateblue",
xlim=c(-1,5), ylim=c(-2,4),
xlab="x", ylab="y")
# calculate vector with radii
rads <- sapply( 1 : (nrow(path2D) - 2), FUN=function(i){ radius(x1 = path2D[i,], x2 = path2D[i+1,], x3 = path2D[i+2,] )} )
# [1] 1.0000000 1.5811388 0.7071068 1.5811388 1.5811388 Inf
# Add text to the plot
text(path2D[2,1],path2D[2,2], round(rads[1],2), pos=3, cex=.8)
text(path2D[3,1],path2D[3,2], round(rads[2],2), pos=4, cex=.8)
text(path2D[4,1],path2D[4,2], round(rads[3],2), pos=2, cex=.8)
text(path2D[5,1],path2D[5,2], round(rads[4],2), pos=1, cex=.8)
text(path2D[6,1],path2D[6,2], round(rads[5],2), pos=4, cex=.8)
text(path2D[7,1],path2D[7,2], round(rads[6],2), pos=4, cex=.8)
Many thanks to Katia, she've done the work!
To calculate the radius for a given points list in 3d space, I use the following code:
rm(list=ls())
setwd("...")
## ask Katia # stackoverflow
# distance between 2 points
eucl.dist <- function(x1, x2) sqrt(sum((x1 - x2) ^ 2))
# area of triangle
area <- function(x1,x2,x3) {
v1 = x1 - x2
v2 = x1 - x3
0.5* sqrt( (v1[2]*v2[3] - v1[3]*v2[2])**2 +
(v1[3]*v2[1] - v1[1]*v2[3])**2 +
(v1[1]*v2[2] - v1[2]*v2[1])**2)
}
# function to calculate curvature (optional for this problem)
curvature <- function(x1, x2, x3){
4 * area(x1, x2, x3) / (eucl.dist(x1,x2)*eucl.dist(x2,x3)*eucl.dist(x3,x1))
}
# function to calculate radius
radius <- function(x1, x2, x3){
0.25 * (eucl.dist(x1,x2)*eucl.dist(x2,x3)*eucl.dist(x3,x1)) / area(x1, x2, x3)
}
# reading data
path3D <- read.table("...txt", dec=".", sep=";", header=TRUE)
colnames(path3D) <- c("x","y","z")
# calculate vector with radii
rads <- sapply( 1 : (nrow(path3D) - 2), FUN=function(i){ radius(x1 = path3D[i,], x2 = path3D[i+1,], x3 = path3D[i+2,] )} )
rads <- data.frame(rads)
#add header
colnames(rads) <- c("radius")
#considering, that for the first value no radius could be calculated
rads <- rbind( Inf, rads)
#...also for the last one
rads <- rbind(rads, Inf)
#merge the data
path3D <- cbind(path3D, data.frame(rads))
#write to file
write.table(path3D, "....txt", sep=";",row.names=FALSE)
Thank you again! Well coded!

Numpy and line intersections

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.

Plane equation for 3D vectors

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

Categories