|
6 | 6 | import numpy.linalg as linalg |
7 | 7 |
|
8 | 8 |
|
9 | | -def _line2d_seg_dist(p1, p2, p0): |
| 9 | +def _line2d_seg_dist(p, s0, s1): |
10 | 10 | """ |
11 | | - Return the distance(s) from line defined by p1 - p2 to point(s) p0. |
| 11 | + Return the distance(s) from point(s) *p* to segment(s) (*s0*, *s1*). |
12 | 12 |
|
13 | | - p0[0] = x(s) |
14 | | - p0[1] = y(s) |
15 | | -
|
16 | | - intersection point p = p1 + u*(p2-p1) |
17 | | - and intersection point lies within segment if u is between 0 and 1. |
18 | | -
|
19 | | - If p1 and p2 are identical, the distance between them and p0 is returned. |
20 | | - """ |
21 | | - |
22 | | - x01 = np.asarray(p0[0]) - p1[0] |
23 | | - y01 = np.asarray(p0[1]) - p1[1] |
24 | | - if np.all(p1[0:2] == p2[0:2]): |
25 | | - return np.hypot(x01, y01) |
26 | | - |
27 | | - x21 = p2[0] - p1[0] |
28 | | - y21 = p2[1] - p1[1] |
29 | | - u = (x01*x21 + y01*y21) / (x21**2 + y21**2) |
30 | | - u = np.clip(u, 0, 1) |
31 | | - d = np.hypot(x01 - u*x21, y01 - u*y21) |
32 | | - |
33 | | - return d |
| 13 | + Parameters |
| 14 | + ---------- |
| 15 | + p : (ndim,) or (N, ndim) array-like |
| 16 | + The points from which the distances are computed. |
| 17 | + s0, s1 : (ndim,) or (N, ndim) array-like |
| 18 | + The xy(z...) coordinates of the segment endpoints. |
| 19 | + """ |
| 20 | + s0 = np.asarray(s0) |
| 21 | + s01 = s1 - s0 # shape (ndim,) or (N, ndim) |
| 22 | + s0p = p - s0 # shape (ndim,) or (N, ndim) |
| 23 | + l2 = s01 @ s01 # squared segment length |
| 24 | + # Avoid div. by zero for degenerate segments (for them, s01 = (0, 0, ...) |
| 25 | + # so the value of l2 doesn't matter; this just replaces 0/0 by 0/1). |
| 26 | + l2 = np.where(l2, l2, 1) |
| 27 | + # Project onto segment, without going past segment ends. |
| 28 | + p1 = s0 + np.multiply.outer(np.clip(s0p @ s01 / l2, 0, 1), s01) |
| 29 | + return ((p - p1) ** 2).sum(axis=-1) ** (1/2) |
34 | 30 |
|
35 | 31 |
|
36 | 32 | def world_transformation(xmin, xmax, |
|
0 commit comments