@thi.ng/geom-closest-point 2.1.87 → 2.1.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/box.js +38 -25
- package/circle.js +6 -13
- package/ellipse.js +23 -35
- package/line.js +56 -134
- package/package.json +9 -6
- package/plane.js +6 -23
- package/points.js +13 -20
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
package/box.js
CHANGED
|
@@ -1,32 +1,45 @@
|
|
|
1
1
|
import { clamp } from "@thi.ng/math/interval";
|
|
2
2
|
import { setC2, setC3 } from "@thi.ng/vectors/setc";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
? setC2(out, minW, clamp(p[1], bmin[1], bmax[1]))
|
|
7
|
-
: setC2(out, clamp(p[0], bmin[0], bmax[0]), minW);
|
|
3
|
+
const closestPointRect = (p, bmin, bmax, out = []) => {
|
|
4
|
+
const [minID, minW] = closestBoxEdge(p, bmin, bmax, 4);
|
|
5
|
+
return minID === 0 ? setC2(out, minW, clamp(p[1], bmin[1], bmax[1])) : setC2(out, clamp(p[0], bmin[0], bmax[0]), minW);
|
|
8
6
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
const closestPointAABB = (p, bmin, bmax, out = []) => {
|
|
8
|
+
const [minID, minW] = closestBoxEdge(p, bmin, bmax, 6);
|
|
9
|
+
return minID === 0 ? setC3(
|
|
10
|
+
out,
|
|
11
|
+
minW,
|
|
12
|
+
clamp(p[1], bmin[1], bmax[1]),
|
|
13
|
+
clamp(p[2], bmin[2], bmax[2])
|
|
14
|
+
) : minID === 1 ? setC3(
|
|
15
|
+
out,
|
|
16
|
+
clamp(p[0], bmin[0], bmax[0]),
|
|
17
|
+
minW,
|
|
18
|
+
clamp(p[2], bmin[2], bmax[2])
|
|
19
|
+
) : setC3(
|
|
20
|
+
out,
|
|
21
|
+
clamp(p[0], bmin[0], bmax[0]),
|
|
22
|
+
clamp(p[1], bmin[1], bmax[1]),
|
|
23
|
+
minW
|
|
24
|
+
);
|
|
16
25
|
};
|
|
17
26
|
const closestBoxEdge = (p, bmin, bmax, n) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
27
|
+
let minD = Infinity;
|
|
28
|
+
let minID;
|
|
29
|
+
let minW;
|
|
30
|
+
for (let i = 0; i < n; i++) {
|
|
31
|
+
const j = i >> 1;
|
|
32
|
+
const w = (i & 1 ? bmax : bmin)[j];
|
|
33
|
+
const d = Math.abs(p[j] - w);
|
|
34
|
+
if (d < minD) {
|
|
35
|
+
minD = d;
|
|
36
|
+
minID = j;
|
|
37
|
+
minW = w;
|
|
30
38
|
}
|
|
31
|
-
|
|
39
|
+
}
|
|
40
|
+
return [minID, minW];
|
|
41
|
+
};
|
|
42
|
+
export {
|
|
43
|
+
closestPointAABB,
|
|
44
|
+
closestPointRect
|
|
32
45
|
};
|
package/circle.js
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
import { add } from "@thi.ng/vectors/add";
|
|
2
2
|
import { direction } from "@thi.ng/vectors/direction";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* @param out -
|
|
10
|
-
*/
|
|
11
|
-
export const closestPointCircle = (p, c, r, out = []) => add(out, c, direction(out, c, p, r));
|
|
12
|
-
/**
|
|
13
|
-
* Same as {@link closestPointCircle}.
|
|
14
|
-
*/
|
|
15
|
-
export const closestPointSphere = closestPointCircle;
|
|
3
|
+
const closestPointCircle = (p, c, r, out = []) => add(out, c, direction(out, c, p, r));
|
|
4
|
+
const closestPointSphere = closestPointCircle;
|
|
5
|
+
export {
|
|
6
|
+
closestPointCircle,
|
|
7
|
+
closestPointSphere
|
|
8
|
+
};
|
package/ellipse.js
CHANGED
|
@@ -1,38 +1,26 @@
|
|
|
1
1
|
import { SQRT2_2 } from "@thi.ng/math/api";
|
|
2
2
|
import { clamp01 } from "@thi.ng/math/interval";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const _ex = ab * tx * tx * tx;
|
|
27
|
-
const _ey = ba * ty * ty * ty;
|
|
28
|
-
const qx = apx - _ex;
|
|
29
|
-
const qy = apy - _ey;
|
|
30
|
-
const q = Math.hypot(rx * tx - _ex, ry * ty - _ey) / Math.hypot(qx, qy);
|
|
31
|
-
tx = clamp01((qx * q + _ex) / rx);
|
|
32
|
-
ty = clamp01((qy * q + _ey) / ry);
|
|
33
|
-
const t = Math.hypot(tx, ty);
|
|
34
|
-
tx /= t;
|
|
35
|
-
ty /= t;
|
|
36
|
-
}
|
|
37
|
-
return [rx * (px < ex ? -tx : tx) + ex, ry * (py < ey ? -ty : ty) + ey];
|
|
3
|
+
const closestPointEllipse = ([px, py], [ex, ey], [rx, ry], n = 3) => {
|
|
4
|
+
const apx = Math.abs(px - ex);
|
|
5
|
+
const apy = Math.abs(py - ey);
|
|
6
|
+
const ab = (rx * rx - ry * ry) / rx;
|
|
7
|
+
const ba = (ry * ry - rx * rx) / ry;
|
|
8
|
+
let tx = SQRT2_2;
|
|
9
|
+
let ty = tx;
|
|
10
|
+
for (; n-- > 0; ) {
|
|
11
|
+
const _ex = ab * tx * tx * tx;
|
|
12
|
+
const _ey = ba * ty * ty * ty;
|
|
13
|
+
const qx = apx - _ex;
|
|
14
|
+
const qy = apy - _ey;
|
|
15
|
+
const q = Math.hypot(rx * tx - _ex, ry * ty - _ey) / Math.hypot(qx, qy);
|
|
16
|
+
tx = clamp01((qx * q + _ex) / rx);
|
|
17
|
+
ty = clamp01((qy * q + _ey) / ry);
|
|
18
|
+
const t = Math.hypot(tx, ty);
|
|
19
|
+
tx /= t;
|
|
20
|
+
ty /= t;
|
|
21
|
+
}
|
|
22
|
+
return [rx * (px < ex ? -tx : tx) + ex, ry * (py < ey ? -ty : ty) + ey];
|
|
23
|
+
};
|
|
24
|
+
export {
|
|
25
|
+
closestPointEllipse
|
|
38
26
|
};
|
package/line.js
CHANGED
|
@@ -6,143 +6,65 @@ import { magSq } from "@thi.ng/vectors/magsq";
|
|
|
6
6
|
import { mixN } from "@thi.ng/vectors/mixn";
|
|
7
7
|
import { set } from "@thi.ng/vectors/set";
|
|
8
8
|
import { sub } from "@thi.ng/vectors/sub";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* mixN([], a, b, closestT(p, a, b))
|
|
17
|
-
* ```
|
|
18
|
-
*
|
|
19
|
-
* If the return value is outside the closed [0,1] interval, the
|
|
20
|
-
* projected point lies outside the line segment. Returns `undefined` if
|
|
21
|
-
* `a` and `b` are coincident.
|
|
22
|
-
*
|
|
23
|
-
* - {@link closestPointLine}
|
|
24
|
-
* - {@link closestPointSegment}
|
|
25
|
-
*
|
|
26
|
-
* @param p - query point
|
|
27
|
-
* @param a - line point A
|
|
28
|
-
* @param b - line point B
|
|
29
|
-
*/
|
|
30
|
-
export const closestT = (p, a, b) => {
|
|
31
|
-
const d = sub([], b, a);
|
|
32
|
-
const l = magSq(d);
|
|
33
|
-
return l > 1e-6 ? dot(sub([], p, a), d) / l : undefined;
|
|
9
|
+
const closestT = (p, a, b) => {
|
|
10
|
+
const d = sub([], b, a);
|
|
11
|
+
const l = magSq(d);
|
|
12
|
+
return l > 1e-6 ? dot(sub([], p, a), d) / l : void 0;
|
|
34
13
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
* @param a - line point A
|
|
44
|
-
* @param b - line point B
|
|
45
|
-
*/
|
|
46
|
-
export const closestPointLine = (p, a, b) => mixN([], a, b, closestT(p, a, b) || 0);
|
|
47
|
-
/**
|
|
48
|
-
* Returns distance from `p` to closest point to infinite line `a` ->
|
|
49
|
-
* `b`. Use {@link distToSegment} to only consider the actual line segment
|
|
50
|
-
* between these two points.
|
|
51
|
-
*
|
|
52
|
-
* {@link distToSegment}
|
|
53
|
-
*
|
|
54
|
-
* @param p - query point
|
|
55
|
-
* @param a - line point A
|
|
56
|
-
* @param b - line point B
|
|
57
|
-
*/
|
|
58
|
-
export const distToLine = (p, a, b) => dist(p, closestPointLine(p, a, b) || a);
|
|
59
|
-
/**
|
|
60
|
-
* Returns closest point to `p` on line segment `a` -> `b`. By default,
|
|
61
|
-
* if the result point lies outside the segment, returns a copy of the
|
|
62
|
-
* closest end point. The result is written to the optional `out` vector
|
|
63
|
-
* (or if omitted, a new one is created).
|
|
64
|
-
*
|
|
65
|
-
* If `insideOnly` is true, only returns the closest point iff it
|
|
66
|
-
* actually is inside the segment. The behavior of this configurable via
|
|
67
|
-
* the optional `eps` arg and by default includes both end points. This
|
|
68
|
-
* function uses {@link closestT} to compute the parametric position of the
|
|
69
|
-
* result point and determine if it lies within the line segment. If
|
|
70
|
-
* `eps > 0`, the end points `a` and `b` will be excluded from the
|
|
71
|
-
* match, effectively shortening the valid line segment from both ends,
|
|
72
|
-
* i.e. the valid interval of the parametric position will be
|
|
73
|
-
* [eps,1-eps]. If the result lies outside this interval, the function
|
|
74
|
-
* returns `undefined`. Likewise, if `a` and `b` are coincident.
|
|
75
|
-
*
|
|
76
|
-
* @param p - query point
|
|
77
|
-
* @param a - line point A
|
|
78
|
-
* @param b - line point B
|
|
79
|
-
* @param out - result
|
|
80
|
-
* @param eps - epsilon value
|
|
81
|
-
*/
|
|
82
|
-
export const closestPointSegment = (p, a, b, out, insideOnly = false, eps = 0) => {
|
|
83
|
-
const t = closestT(p, a, b);
|
|
84
|
-
if (t !== undefined && (!insideOnly || (t >= eps && t <= 1 - eps))) {
|
|
85
|
-
out = out || empty(p);
|
|
86
|
-
return t <= 0 ? set(out, a) : t >= 1 ? set(out, b) : mixN(out, a, b, t);
|
|
87
|
-
}
|
|
14
|
+
const closestPointLine = (p, a, b) => mixN([], a, b, closestT(p, a, b) || 0);
|
|
15
|
+
const distToLine = (p, a, b) => dist(p, closestPointLine(p, a, b) || a);
|
|
16
|
+
const closestPointSegment = (p, a, b, out, insideOnly = false, eps = 0) => {
|
|
17
|
+
const t = closestT(p, a, b);
|
|
18
|
+
if (t !== void 0 && (!insideOnly || t >= eps && t <= 1 - eps)) {
|
|
19
|
+
out = out || empty(p);
|
|
20
|
+
return t <= 0 ? set(out, a) : t >= 1 ? set(out, b) : mixN(out, a, b, t);
|
|
21
|
+
}
|
|
88
22
|
};
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
j = 1;
|
|
23
|
+
const distToSegment = (p, a, b) => dist(p, closestPointSegment(p, a, b) || a);
|
|
24
|
+
const closestPointPolyline = (p, pts, closed = false, out = []) => {
|
|
25
|
+
if (!pts.length)
|
|
26
|
+
return;
|
|
27
|
+
const tmp = [];
|
|
28
|
+
const n = pts.length - 1;
|
|
29
|
+
let minD = Infinity, i, j;
|
|
30
|
+
if (closed) {
|
|
31
|
+
i = n;
|
|
32
|
+
j = 0;
|
|
33
|
+
} else {
|
|
34
|
+
i = 0;
|
|
35
|
+
j = 1;
|
|
36
|
+
}
|
|
37
|
+
for (; j <= n; i = j, j++) {
|
|
38
|
+
if (closestPointSegment(p, pts[i], pts[j], tmp)) {
|
|
39
|
+
const d = distSq(p, tmp);
|
|
40
|
+
if (d < minD) {
|
|
41
|
+
minD = d;
|
|
42
|
+
set(out, tmp);
|
|
43
|
+
}
|
|
111
44
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const d = distSq(p, tmp);
|
|
115
|
-
if (d < minD) {
|
|
116
|
-
minD = d;
|
|
117
|
-
set(out, tmp);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return minD < Infinity ? out : undefined;
|
|
45
|
+
}
|
|
46
|
+
return minD < Infinity ? out : void 0;
|
|
122
47
|
};
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
* @param to - end search index
|
|
134
|
-
*/
|
|
135
|
-
export const farthestPointSegment = (a, b, points, from = 0, to = points.length) => {
|
|
136
|
-
let maxD = -1;
|
|
137
|
-
let maxIdx = -1;
|
|
138
|
-
const tmp = empty(a);
|
|
139
|
-
for (let i = from; i < to; i++) {
|
|
140
|
-
const p = points[i];
|
|
141
|
-
const d = distSq(p, closestPointSegment(p, a, b, tmp) || a);
|
|
142
|
-
if (d > maxD) {
|
|
143
|
-
maxD = d;
|
|
144
|
-
maxIdx = i;
|
|
145
|
-
}
|
|
48
|
+
const farthestPointSegment = (a, b, points, from = 0, to = points.length) => {
|
|
49
|
+
let maxD = -1;
|
|
50
|
+
let maxIdx = -1;
|
|
51
|
+
const tmp = empty(a);
|
|
52
|
+
for (let i = from; i < to; i++) {
|
|
53
|
+
const p = points[i];
|
|
54
|
+
const d = distSq(p, closestPointSegment(p, a, b, tmp) || a);
|
|
55
|
+
if (d > maxD) {
|
|
56
|
+
maxD = d;
|
|
57
|
+
maxIdx = i;
|
|
146
58
|
}
|
|
147
|
-
|
|
59
|
+
}
|
|
60
|
+
return [maxIdx, Math.sqrt(maxD)];
|
|
61
|
+
};
|
|
62
|
+
export {
|
|
63
|
+
closestPointLine,
|
|
64
|
+
closestPointPolyline,
|
|
65
|
+
closestPointSegment,
|
|
66
|
+
closestT,
|
|
67
|
+
distToLine,
|
|
68
|
+
distToSegment,
|
|
69
|
+
farthestPointSegment
|
|
148
70
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/geom-closest-point",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.89",
|
|
4
4
|
"description": "2D / 3D closest point / proximity helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"author": "Karsten Schmidt (https://thi.ng)",
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "yarn
|
|
27
|
+
"build": "yarn build:esbuild && yarn build:decl",
|
|
28
|
+
"build:decl": "tsc --declaration --emitDeclarationOnly",
|
|
29
|
+
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
|
|
28
30
|
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
|
|
29
31
|
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
|
|
30
32
|
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
|
|
@@ -33,12 +35,13 @@
|
|
|
33
35
|
"test": "bun test"
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
|
-
"@thi.ng/api": "^8.9.
|
|
37
|
-
"@thi.ng/math": "^5.7.
|
|
38
|
-
"@thi.ng/vectors": "^7.8.
|
|
38
|
+
"@thi.ng/api": "^8.9.12",
|
|
39
|
+
"@thi.ng/math": "^5.7.7",
|
|
40
|
+
"@thi.ng/vectors": "^7.8.10"
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@microsoft/api-extractor": "^7.38.3",
|
|
44
|
+
"esbuild": "^0.19.8",
|
|
42
45
|
"rimraf": "^5.0.5",
|
|
43
46
|
"tools": "^0.0.1",
|
|
44
47
|
"typedoc": "^0.25.4",
|
|
@@ -101,5 +104,5 @@
|
|
|
101
104
|
],
|
|
102
105
|
"year": 2018
|
|
103
106
|
},
|
|
104
|
-
"gitHead": "
|
|
107
|
+
"gitHead": "22e36fa838e5431d40165384918b395603bbd92f\n"
|
|
105
108
|
}
|
package/plane.js
CHANGED
|
@@ -1,26 +1,9 @@
|
|
|
1
1
|
import { dot } from "@thi.ng/vectors/dot";
|
|
2
2
|
import { normalize } from "@thi.ng/vectors/normalize";
|
|
3
3
|
import { sub } from "@thi.ng/vectors/sub";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* if zero on the plane.
|
|
11
|
-
*
|
|
12
|
-
* @param p -
|
|
13
|
-
* @param n -
|
|
14
|
-
* @param w -
|
|
15
|
-
*/
|
|
16
|
-
export const distToPlane = (p, n, w) => dot(n, p) - w;
|
|
17
|
-
/**
|
|
18
|
-
* Returns closest point to `p` on the plane defined by normal `n` and `w`. In
|
|
19
|
-
* 2D this also works for lines.
|
|
20
|
-
*
|
|
21
|
-
* @param p -
|
|
22
|
-
* @param normal -
|
|
23
|
-
* @param w -
|
|
24
|
-
* @param out -
|
|
25
|
-
*/
|
|
26
|
-
export const closestPointPlane = (p, normal, w, out = []) => sub(out, p, normalize(out, normal, distToPlane(p, normal, w)));
|
|
4
|
+
const distToPlane = (p, n, w) => dot(n, p) - w;
|
|
5
|
+
const closestPointPlane = (p, normal, w, out = []) => sub(out, p, normalize(out, normal, distToPlane(p, normal, w)));
|
|
6
|
+
export {
|
|
7
|
+
closestPointPlane,
|
|
8
|
+
distToPlane
|
|
9
|
+
};
|
package/points.js
CHANGED
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
import { distSq } from "@thi.ng/vectors/distsq";
|
|
2
2
|
import { set } from "@thi.ng/vectors/set";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* @param dist -
|
|
12
|
-
*/
|
|
13
|
-
export const closestPointArray = (p, pts, out = [], dist = distSq) => {
|
|
14
|
-
let minD = Infinity;
|
|
15
|
-
let closest;
|
|
16
|
-
for (let i = pts.length; i-- > 0;) {
|
|
17
|
-
const d = dist(pts[i], p);
|
|
18
|
-
if (d < minD) {
|
|
19
|
-
minD = d;
|
|
20
|
-
closest = pts[i];
|
|
21
|
-
}
|
|
3
|
+
const closestPointArray = (p, pts, out = [], dist = distSq) => {
|
|
4
|
+
let minD = Infinity;
|
|
5
|
+
let closest;
|
|
6
|
+
for (let i = pts.length; i-- > 0; ) {
|
|
7
|
+
const d = dist(pts[i], p);
|
|
8
|
+
if (d < minD) {
|
|
9
|
+
minD = d;
|
|
10
|
+
closest = pts[i];
|
|
22
11
|
}
|
|
23
|
-
|
|
12
|
+
}
|
|
13
|
+
return closest ? set(out, closest) : void 0;
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
closestPointArray
|
|
24
17
|
};
|