如何将点np.array投影到线段np.array?需改造单点投影代码
Sure thing! Let's modify your existing code to handle projecting an array of points onto all your segments. The trick here is to use numpy's broadcasting to compute all projections in one go without messy loops. Here's how to do it:
Step-by-Step Breakdown
Align dimensions for broadcasting: We need to shape our inputs so numpy can calculate every point-segment combination automatically.
- Segments are stored as start points (
l1, shape(M,3)) and end points (l2, shape(M,3)), where M is the number of segments. - Points (
p) get reshaped to(N,1,3)(N = number of points) to broadcast across all segments.
- Segments are stored as start points (
Calculate core vectors:
lineis the direction vector for each segment (l2 - l1), reshaped to(1,M,3)to match the points' broadcast shape.pvis the vector from each segment's start to each point, resulting in a(N,M,3)array.
Compute projection parameters:
len_sqis the squared length of each segment (avoids square roots for efficiency).dotgives the dot product oflineandpvfor every point-segment pair.paramtells us where along the segment the projection lies; we clamp it between 0 and 1 to ensure the projection stays on the segment (not beyond the endpoints).
Generate all projection points: Multiply the clamped parameter by the direction vector and add it to the segment start. The result is a
(N,M,3)array, which we can flatten to(N*M,3)if you want a single list of all projections.
Full Working Code
import numpy as np # Define your segments: l1 = start points, l2 = end points (2 segments here) l1 = np.array([[2,3,0],[7,5,0]]) # Shape (2, 3) l2 = np.array([[5,1,0],[8,6,0]]) # Shape (2, 3) # Define your array of points (2 points here) p = np.array([[6,5,0],[3,2,0]]) # Shape (2, 3) # Reshape points to enable broadcasting across segments p_reshaped = p[:, np.newaxis, :] # Shape (2, 1, 3) # Segment direction vectors, reshaped for broadcasting line = l2 - l1 line_reshaped = line[np.newaxis, :, :] # Shape (1, 2, 3) # Squared length of each segment (avoids sqrt for efficiency) len_sq = np.sum(line**2, axis=1, keepdims=True) # Shape (2,1) -> becomes (1,2) when broadcast # Vector from segment start to each point pv = p_reshaped - l1[np.newaxis, :, :] # Shape (2, 2, 3) # Dot product for every point-segment pair dot = np.einsum('nmk,nmk->nm', line_reshaped, pv) # Shape (2,2) # Alternative (same result): dot = np.sum(line_reshaped * pv, axis=2) # Calculate and clamp projection parameter param = dot / len_sq clamped_param = np.clip(param, 0, 1) # Shape (2,2) # Compute all projection points pp = l1[np.newaxis, :, :] + clamped_param[..., np.newaxis] * line_reshaped # Shape (2,2,3) # Optional: Flatten to a single array of all projections (4 points total) pp_flat = pp.reshape(-1, 3) # Print results print("Projected points (point x segment):") print(pp) print("\nFlattened projected points:") print(pp_flat)
Example Output
For your input points, the flattened output will be exactly the 4 projection points you're expecting:
[[4.4 2.2 0. ] [7.5 5.5 0. ] [2. 3. 0. ] [7. 5. 0. ]]
This approach is efficient because it uses numpy's vectorization instead of explicit loops, making it much faster for large numbers of points or segments.
内容的提问来源于stack exchange,提问作者Tortenrandband

