Reputation: 176
I have the following working code to project a single point to every segment in an array. But I want every point in an array of points to be projected to every segment.
import numpy as np
#find closest segment to single point
#line segment
l1 = np.array([[2,3,0],[7,5,0]])
l2 = np.array([[5,1,0],[8,6,0]])
#point that gets projected
p = np.array([[6,5,0]]) #only single point
#set to origin
line = l2-l1
pv = p-l1
#length of line squared
len_sq = np.sum(line**2, axis = 1) #len_sq = numpy.einsum("ij,ij->i", line, line)
#dot product of 3D vectors with einsum
dot = np.einsum('ij,ij->i',line,pv) #np.sum(line*pv,axis=1)
#percentage of line the pv vector travels in
param = np.array([dot/len_sq])
#param<0 projected point=l1, param>1 pp=l2
clamped_param = np.clip(param,0,1)
#add line fraction to l1 to get projected point
pp = l1+(clamped_param.T*line)
For Example, make
p = np.array([[6,5,0],[3,2,0]]) #multiple points
and return np.array() of 4 projected points.
Upvotes: 1
Views: 373
Reputation: 4171
Maybe you can try something like the following. If project is a function that can do the operation for a single point, then by using apply along axis, you can get it to work on all points in an array of points. The output is yielded as separate generators for each point, which have to be converted back to a single array using a stacking operation.
l1 = np.array([[2,3,0],[7,5,0]])
l2 = np.array([[5,1,0],[8,6,0]])
line = l2-l1
len_sq = np.sum(line**2, axis = 1)
def project(p):
pv = p-l1
dot = np.einsum('ij,ij->i',line,pv)
param = np.array([dot/len_sq])
clamped_param = np.clip(param,0,1)
yield l1+(clamped_param.T*line)
pts = np.array([[6,5,0],
[3,2,0]])
gen = np.apply_along_axis(project, 1, pts)
out = np.hstack([list(G) for G in gen])[0]
Upvotes: 1