@thi.ng/geom 6.1.9 → 7.0.1
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 +114 -1
- package/README.md +34 -29
- package/api/arc.js +1 -1
- package/api/complex-polygon.d.ts +14 -0
- package/api/complex-polygon.js +44 -0
- package/api/path.d.ts +11 -3
- package/api/path.js +45 -29
- package/apply-transforms.js +5 -10
- package/arc-length.d.ts +1 -0
- package/arc-length.js +12 -0
- package/arc.d.ts +51 -1
- package/arc.js +12 -1
- package/area.d.ts +1 -0
- package/area.js +4 -1
- package/as-cubic.d.ts +2 -0
- package/as-cubic.js +10 -2
- package/as-path.d.ts +19 -3
- package/as-path.js +54 -1
- package/as-polygon.d.ts +7 -5
- package/as-polygon.js +14 -1
- package/as-polyline.d.ts +6 -4
- package/as-polyline.js +19 -5
- package/bounds.js +14 -7
- package/centroid.d.ts +3 -2
- package/centroid.js +10 -1
- package/classify-point.d.ts +5 -2
- package/clip-convex.d.ts +22 -3
- package/clip-convex.js +39 -12
- package/closest-point.d.ts +2 -0
- package/closest-point.js +34 -0
- package/complex-polygon-from-path.d.ts +14 -0
- package/complex-polygon-from-path.js +9 -0
- package/complex-polygon.d.ts +23 -0
- package/complex-polygon.js +6 -0
- package/convex-hull.d.ts +1 -0
- package/convex-hull.js +2 -0
- package/edges.d.ts +2 -0
- package/edges.js +7 -3
- package/fit-into-bounds.js +5 -10
- package/flip.d.ts +1 -0
- package/flip.js +5 -0
- package/index.d.ts +5 -0
- package/index.js +5 -0
- package/internal/bounds.js +3 -6
- package/internal/copy.d.ts +3 -1
- package/internal/copy.js +9 -3
- package/internal/transform.d.ts +20 -7
- package/internal/transform.js +10 -0
- package/intersects.js +3 -6
- package/package.json +48 -33
- package/path-builder.d.ts +21 -1
- package/path-builder.js +31 -14
- package/path-from-svg.d.ts +13 -1
- package/path-from-svg.js +10 -14
- package/path.d.ts +59 -2
- package/path.js +44 -19
- package/point-inside.d.ts +12 -9
- package/point-inside.js +3 -0
- package/proximity.d.ts +11 -0
- package/proximity.js +9 -0
- package/resample.d.ts +1 -0
- package/resample.js +7 -1
- package/rotate.d.ts +1 -0
- package/rotate.js +13 -10
- package/scale-with-center.d.ts +20 -0
- package/scale-with-center.js +7 -0
- package/scale.d.ts +1 -0
- package/scale.js +12 -9
- package/scatter.js +1 -2
- package/simplify.d.ts +4 -3
- package/simplify.js +39 -27
- package/split-arclength.d.ts +1 -1
- package/split-arclength.js +4 -6
- package/subdiv-curve.d.ts +5 -1
- package/subdiv-curve.js +10 -8
- package/transform-vertices.d.ts +1 -0
- package/transform-vertices.js +19 -19
- package/transform.d.ts +1 -0
- package/transform.js +17 -16
- package/translate.d.ts +1 -0
- package/translate.js +17 -12
- package/vertices.d.ts +18 -17
- package/vertices.js +22 -11
- package/with-attribs.d.ts +1 -1
- package/with-attribs.js +1 -1
package/area.js
CHANGED
|
@@ -14,9 +14,12 @@ const area = defmulti(
|
|
|
14
14
|
($) => 0.5 * Math.abs($.start - $.end) * $.r[0] * $.r[1]
|
|
15
15
|
),
|
|
16
16
|
circle: ($) => PI * $.r ** 2,
|
|
17
|
+
complexpoly: ($, signed) => area($.boundary, signed) - $.children.reduce((acc, c) => acc + area(c, signed), 0),
|
|
17
18
|
ellipse: ($) => PI * $.r[0] * $.r[1],
|
|
18
19
|
group: ({ children }) => children.reduce((sum, $) => sum + area($, false), 0),
|
|
19
|
-
path: (
|
|
20
|
+
path: ($, signed) => {
|
|
21
|
+
return $.closed ? asPolygon($).reduce((acc, p) => acc + area(p, signed), 0) : 0;
|
|
22
|
+
},
|
|
20
23
|
plane: () => Infinity,
|
|
21
24
|
poly: ($, signed) => {
|
|
22
25
|
const area2 = polyArea2($.points);
|
package/as-cubic.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { Cubic } from "./api/cubic.js";
|
|
|
10
10
|
*
|
|
11
11
|
* - {@link Arc}
|
|
12
12
|
* - {@link Circle}
|
|
13
|
+
* - {@link ComplexPolygon}
|
|
13
14
|
* - {@link Cubic}
|
|
14
15
|
* - {@link Ellipse}
|
|
15
16
|
* - {@link Group}
|
|
@@ -27,6 +28,7 @@ import { Cubic } from "./api/cubic.js";
|
|
|
27
28
|
* for more details):
|
|
28
29
|
*
|
|
29
30
|
* - {@link Group} (only used for eligible children)
|
|
31
|
+
* - {@link ComplexPolygon}
|
|
30
32
|
* - {@link Polygon}
|
|
31
33
|
* - {@link Polyline}
|
|
32
34
|
* - {@link Quad}
|
package/as-cubic.js
CHANGED
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
openCubicFromControlPoints
|
|
9
9
|
} from "@thi.ng/geom-splines/cubic-from-controlpoints";
|
|
10
10
|
import { TAU } from "@thi.ng/math/api";
|
|
11
|
+
import { concat } from "@thi.ng/transducers/concat";
|
|
12
|
+
import { flatten1 } from "@thi.ng/transducers/flatten1";
|
|
11
13
|
import { mapcat } from "@thi.ng/transducers/mapcat";
|
|
12
14
|
import { Cubic } from "./api/cubic.js";
|
|
13
15
|
import { arc } from "./arc.js";
|
|
@@ -25,6 +27,9 @@ const asCubic = defmulti(
|
|
|
25
27
|
{
|
|
26
28
|
arc: cubicFromArc,
|
|
27
29
|
circle: ($) => asCubic(arc($.pos, $.r, 0, 0, TAU, true, true)),
|
|
30
|
+
complexpoly: ($, opts = {}) => [
|
|
31
|
+
...mapcat((x) => asCubic(x, opts), [$.boundary, ...$.children])
|
|
32
|
+
],
|
|
28
33
|
cubic: ($) => [$],
|
|
29
34
|
group: ($, opts) => [
|
|
30
35
|
...mapcat((x) => asCubic(x, opts), $.children)
|
|
@@ -33,7 +38,10 @@ const asCubic = defmulti(
|
|
|
33
38
|
cubicFromLine(points[0], points[1], { ...attribs })
|
|
34
39
|
],
|
|
35
40
|
path: ($) => [
|
|
36
|
-
...mapcat(
|
|
41
|
+
...mapcat(
|
|
42
|
+
(segment) => segment.geo ? asCubic(segment.geo) : null,
|
|
43
|
+
concat($.segments, flatten1($.subPaths))
|
|
44
|
+
)
|
|
37
45
|
],
|
|
38
46
|
poly: ($, opts = {}) => __polyCubic(
|
|
39
47
|
$,
|
|
@@ -50,7 +58,7 @@ const asCubic = defmulti(
|
|
|
50
58
|
quadratic: ({ attribs, points }) => [
|
|
51
59
|
cubicFromQuadratic(points[0], points[1], points[2], { ...attribs })
|
|
52
60
|
],
|
|
53
|
-
rect: ($, opts) => asCubic(asPolygon($), opts)
|
|
61
|
+
rect: ($, opts) => asCubic(asPolygon($)[0], opts)
|
|
54
62
|
}
|
|
55
63
|
);
|
|
56
64
|
const __polyCubic = ($, opts, breakPoints, controlPoints) => {
|
package/as-path.d.ts
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Maybe } from "@thi.ng/api";
|
|
2
|
+
import type { MultiFn2O } from "@thi.ng/defmulti";
|
|
3
|
+
import type { Attribs, CubicOpts, IShape } from "@thi.ng/geom-api";
|
|
4
|
+
import { Path } from "./api/path.js";
|
|
5
|
+
export interface AsPathOpts extends CubicOpts {
|
|
6
|
+
/**
|
|
7
|
+
* If true (default: false), creates path consisting of linear segments
|
|
8
|
+
* only.
|
|
9
|
+
*/
|
|
10
|
+
linear: boolean;
|
|
11
|
+
}
|
|
2
12
|
/**
|
|
3
|
-
* Converts given shape into a {@link Path} (via {@link asCubic} and
|
|
13
|
+
* Converts given shape into a {@link Path} (by default via {@link asCubic} and
|
|
4
14
|
* {@link pathFromCubics}).
|
|
5
15
|
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* If {@link AsPathOpts.linear} is enabled the shape will be converted into a
|
|
18
|
+
* path consisting only of linear segments (NOT cubic beziers). As an interim
|
|
19
|
+
* step this will involve a conversion via {@link asPolygon} or
|
|
20
|
+
* {@link asPolyline} with default opts.
|
|
21
|
+
*
|
|
6
22
|
* @param src
|
|
7
23
|
* @param attribs
|
|
8
24
|
*/
|
|
9
|
-
export declare const asPath: (
|
|
25
|
+
export declare const asPath: ((shape: IShape, opts?: Partial<AsPathOpts>, attribs?: Attribs) => Path) & MultiFn2O<IShape, Maybe<Partial<AsPathOpts>>, Attribs, Path>;
|
|
10
26
|
//# sourceMappingURL=as-path.d.ts.map
|
package/as-path.js
CHANGED
|
@@ -1,7 +1,60 @@
|
|
|
1
|
+
import { DEFAULT, defmulti } from "@thi.ng/defmulti/defmulti";
|
|
2
|
+
import { copy } from "@thi.ng/vectors/copy";
|
|
3
|
+
import { Line } from "./api/line.js";
|
|
4
|
+
import { Path } from "./api/path.js";
|
|
1
5
|
import { asCubic } from "./as-cubic.js";
|
|
6
|
+
import { asPolygon } from "./as-polygon.js";
|
|
7
|
+
import { asPolyline } from "./as-polyline.js";
|
|
2
8
|
import { __copyAttribs } from "./internal/copy.js";
|
|
9
|
+
import { __dispatch } from "./internal/dispatch.js";
|
|
3
10
|
import { pathFromCubics } from "./path.js";
|
|
4
|
-
const asPath = (
|
|
11
|
+
const asPath = defmulti(
|
|
12
|
+
__dispatch,
|
|
13
|
+
{
|
|
14
|
+
line: "polyline",
|
|
15
|
+
quad: "poly",
|
|
16
|
+
tri: "poly"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
[DEFAULT]: (src, opts, attribs) => opts?.linear ? asPath(asPolygon(src)[0], opts, attribs || __copyAttribs(src)) : __defaultImpl(src, opts, attribs),
|
|
20
|
+
arc: ($, opts, attribs) => opts?.linear ? asPath(asPolyline($)[0], opts, attribs || __copyAttribs($)) : __defaultImpl($, opts, attribs),
|
|
21
|
+
complexpoly: ($, opts, attribs) => {
|
|
22
|
+
attribs = attribs || __copyAttribs($);
|
|
23
|
+
if (opts?.linear) {
|
|
24
|
+
return __linearPath(
|
|
25
|
+
$.boundary,
|
|
26
|
+
$.children.map((c) => __lineSegments(c.points, true)),
|
|
27
|
+
attribs,
|
|
28
|
+
true
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
const res = pathFromCubics(asCubic($.boundary, opts), attribs);
|
|
32
|
+
for (let child of $.children) {
|
|
33
|
+
res.addSubPaths(pathFromCubics(asCubic(child, opts)).segments);
|
|
34
|
+
}
|
|
35
|
+
return res;
|
|
36
|
+
},
|
|
37
|
+
poly: ($, opts, attribs) => opts?.linear ? __linearPath($, [], attribs, true) : __defaultImpl($, opts, attribs),
|
|
38
|
+
polyline: ($, opts, attribs) => opts?.linear ? __linearPath($, [], attribs, false) : __defaultImpl($, opts, attribs)
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
const __defaultImpl = (src, opts, attribs) => pathFromCubics(asCubic(src, opts), attribs || __copyAttribs(src));
|
|
42
|
+
const __lineSegments = (points, closed) => {
|
|
43
|
+
if (!points.length) return [];
|
|
44
|
+
const segments = [{ type: "m", point: copy(points[0]) }];
|
|
45
|
+
for (let i = 1, n = points.length; i < n; i++)
|
|
46
|
+
segments.push({
|
|
47
|
+
type: "l",
|
|
48
|
+
geo: new Line([copy(points[i - 1]), copy(points[i])])
|
|
49
|
+
});
|
|
50
|
+
if (closed) segments.push({ type: "z" });
|
|
51
|
+
return segments;
|
|
52
|
+
};
|
|
53
|
+
const __linearPath = (shape, subPaths, attribs, closed = false) => new Path(
|
|
54
|
+
__lineSegments(shape.points, closed),
|
|
55
|
+
subPaths,
|
|
56
|
+
attribs || __copyAttribs(shape)
|
|
57
|
+
);
|
|
5
58
|
export {
|
|
6
59
|
asPath
|
|
7
60
|
};
|
package/as-polygon.d.ts
CHANGED
|
@@ -2,19 +2,21 @@ import type { MultiFn1O } from "@thi.ng/defmulti";
|
|
|
2
2
|
import type { IShape, SamplingOpts } from "@thi.ng/geom-api";
|
|
3
3
|
import { Polygon } from "./api/polygon.js";
|
|
4
4
|
/**
|
|
5
|
-
* Converts given shape into
|
|
5
|
+
* Converts given shape into an array of {@link Polygon}s, optionally using
|
|
6
|
+
* provided
|
|
6
7
|
* [`SamplingOpts`](https://docs.thi.ng/umbrella/geom-api/interfaces/SamplingOpts.html)
|
|
7
8
|
* or number of target vertices.
|
|
8
9
|
*
|
|
9
10
|
* @remarks
|
|
10
|
-
* If the shape has a `__samples` attribute, it will be removed in the
|
|
11
|
-
* avoid recursive application.
|
|
11
|
+
* If the input shape has a `__samples` attribute, it will be removed in the
|
|
12
|
+
* results polys to avoid recursive application.
|
|
12
13
|
*
|
|
13
14
|
* Currently implemented for:
|
|
14
15
|
*
|
|
15
16
|
* - {@link Circle}
|
|
17
|
+
* - {@link ComplexPolygon}
|
|
16
18
|
* - {@link Ellipse}
|
|
17
|
-
* - {@link Line}
|
|
19
|
+
* - {@link Line} (will be closed)
|
|
18
20
|
* - {@link Path}
|
|
19
21
|
* - {@link Polygon}
|
|
20
22
|
* - {@link Polyline} (will be closed)
|
|
@@ -25,5 +27,5 @@ import { Polygon } from "./api/polygon.js";
|
|
|
25
27
|
* @param shape
|
|
26
28
|
* @param opts
|
|
27
29
|
*/
|
|
28
|
-
export declare const asPolygon: MultiFn1O<IShape, number | Partial<SamplingOpts>, Polygon>;
|
|
30
|
+
export declare const asPolygon: MultiFn1O<IShape, number | Partial<SamplingOpts>, Polygon[]>;
|
|
29
31
|
//# sourceMappingURL=as-polygon.d.ts.map
|
package/as-polygon.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defmulti } from "@thi.ng/defmulti/defmulti";
|
|
2
|
+
import { Path } from "./api/path.js";
|
|
2
3
|
import { Polygon } from "./api/polygon.js";
|
|
3
4
|
import { __copyAttribsNoSamples as __attribs } from "./internal/copy.js";
|
|
4
5
|
import { __dispatch } from "./internal/dispatch.js";
|
|
@@ -17,7 +18,19 @@ const asPolygon = defmulti(
|
|
|
17
18
|
tri: "points"
|
|
18
19
|
},
|
|
19
20
|
{
|
|
20
|
-
|
|
21
|
+
complexpoly: ($, opts) => [$.boundary, ...$.children].map(
|
|
22
|
+
(x) => new Polygon(vertices(x, opts), __attribs($))
|
|
23
|
+
),
|
|
24
|
+
path: ($, opts) => {
|
|
25
|
+
const tmp = new Path();
|
|
26
|
+
return [$.segments, ...$.subPaths].map((segments) => {
|
|
27
|
+
tmp.segments = segments;
|
|
28
|
+
return new Polygon(vertices(tmp, opts), __attribs($));
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
points: ($, opts) => [
|
|
32
|
+
new Polygon(vertices($, opts), __attribs($))
|
|
33
|
+
]
|
|
21
34
|
}
|
|
22
35
|
);
|
|
23
36
|
export {
|
package/as-polyline.d.ts
CHANGED
|
@@ -2,18 +2,20 @@ import type { MultiFn1O } from "@thi.ng/defmulti";
|
|
|
2
2
|
import type { IShape, SamplingOpts } from "@thi.ng/geom-api";
|
|
3
3
|
import { Polyline } from "./api/polyline.js";
|
|
4
4
|
/**
|
|
5
|
-
* Converts given shape into
|
|
5
|
+
* Converts given shape into an array of {@link Polyline}s, optionally using
|
|
6
|
+
* provided
|
|
6
7
|
* [`SamplingOpts`](https://docs.thi.ng/umbrella/geom-api/interfaces/SamplingOpts.html)
|
|
7
8
|
* or number of target vertices.
|
|
8
9
|
*
|
|
9
10
|
* @remarks
|
|
10
|
-
* If the shape has a `__samples` attribute, it will be removed in the
|
|
11
|
-
* avoid recursive application.
|
|
11
|
+
* If the shape has a `__samples` attribute, it will be removed in the results
|
|
12
|
+
* to avoid recursive application.
|
|
12
13
|
*
|
|
13
14
|
* Currently implemented for:
|
|
14
15
|
*
|
|
15
16
|
* - {@link Arc}
|
|
16
17
|
* - {@link Circle}
|
|
18
|
+
* - {@link ComplexPolygon}
|
|
17
19
|
* - {@link Cubic}
|
|
18
20
|
* - {@link Ellipse}
|
|
19
21
|
* - {@link Line}
|
|
@@ -28,5 +30,5 @@ import { Polyline } from "./api/polyline.js";
|
|
|
28
30
|
* @param shape
|
|
29
31
|
* @param opts
|
|
30
32
|
*/
|
|
31
|
-
export declare const asPolyline: MultiFn1O<IShape, number | Partial<SamplingOpts>, Polyline>;
|
|
33
|
+
export declare const asPolyline: MultiFn1O<IShape, number | Partial<SamplingOpts>, Polyline[]>;
|
|
32
34
|
//# sourceMappingURL=as-polyline.d.ts.map
|
package/as-polyline.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { peek } from "@thi.ng/arrays/peek";
|
|
1
2
|
import { defmulti } from "@thi.ng/defmulti/defmulti";
|
|
3
|
+
import { mapcat } from "@thi.ng/transducers/mapcat";
|
|
2
4
|
import { set } from "@thi.ng/vectors/set";
|
|
5
|
+
import { Path } from "./api/path.js";
|
|
3
6
|
import { Polyline } from "./api/polyline.js";
|
|
4
7
|
import { __copyAttribsNoSamples as __attribs } from "./internal/copy.js";
|
|
5
8
|
import { __dispatch } from "./internal/dispatch.js";
|
|
@@ -19,16 +22,27 @@ const asPolyline = defmulti(
|
|
|
19
22
|
tri: "poly"
|
|
20
23
|
},
|
|
21
24
|
{
|
|
22
|
-
|
|
25
|
+
complexpoly: ($, opts) => [
|
|
26
|
+
...asPolyline($.boundary, opts),
|
|
27
|
+
...mapcat((child) => asPolyline(child, opts), $.children)
|
|
28
|
+
],
|
|
29
|
+
group: ($, opts) => [
|
|
30
|
+
...mapcat((child) => asPolyline(child, opts), $.children)
|
|
31
|
+
],
|
|
32
|
+
points: ($, opts) => [new Polyline(vertices($, opts), __attribs($))],
|
|
23
33
|
path: ($, opts) => {
|
|
24
|
-
const
|
|
25
|
-
$.
|
|
26
|
-
|
|
34
|
+
const tmp = new Path();
|
|
35
|
+
return [$.segments, ...$.subPaths].map((segments) => {
|
|
36
|
+
tmp.segments = segments;
|
|
37
|
+
const pts = vertices(tmp, opts);
|
|
38
|
+
peek(segments).type === "z" && pts.push(set([], pts[0]));
|
|
39
|
+
return new Polyline(pts, __attribs($));
|
|
40
|
+
});
|
|
27
41
|
},
|
|
28
42
|
poly: ($, opts) => {
|
|
29
43
|
const pts = vertices($, opts);
|
|
30
44
|
pts.push(set([], pts[0]));
|
|
31
|
-
return new Polyline(pts, __attribs($));
|
|
45
|
+
return [new Polyline(pts, __attribs($))];
|
|
32
46
|
}
|
|
33
47
|
}
|
|
34
48
|
);
|
package/bounds.js
CHANGED
|
@@ -7,6 +7,7 @@ import { comp } from "@thi.ng/transducers/comp";
|
|
|
7
7
|
import { filter } from "@thi.ng/transducers/filter";
|
|
8
8
|
import { iterator1 } from "@thi.ng/transducers/iterator";
|
|
9
9
|
import { map } from "@thi.ng/transducers/map";
|
|
10
|
+
import { mapcat } from "@thi.ng/transducers/mapcat";
|
|
10
11
|
import { addN2 } from "@thi.ng/vectors/addn";
|
|
11
12
|
import { max } from "@thi.ng/vectors/max";
|
|
12
13
|
import { min } from "@thi.ng/vectors/min";
|
|
@@ -38,6 +39,10 @@ const bounds = defmulti(
|
|
|
38
39
|
subN2([], $.pos, $.r + margin),
|
|
39
40
|
mulN2(null, [2, 2], $.r + margin)
|
|
40
41
|
),
|
|
42
|
+
complexpoly: ($, margin = 0) => {
|
|
43
|
+
const res = __collBounds([$.boundary, ...$.children], bounds);
|
|
44
|
+
return res ? new Rect(...res).offset(margin) : void 0;
|
|
45
|
+
},
|
|
41
46
|
cubic: ({ points }, margin = 0) => rectFromMinMaxWithMargin(
|
|
42
47
|
...cubicBounds(points[0], points[1], points[2], points[3]),
|
|
43
48
|
margin
|
|
@@ -52,15 +57,17 @@ const bounds = defmulti(
|
|
|
52
57
|
},
|
|
53
58
|
line: ({ points: [a, b] }, margin = 0) => rectFromMinMaxWithMargin(min([], a, b), max([], a, b), margin),
|
|
54
59
|
path: (path, margin = 0) => {
|
|
60
|
+
const $segmentGeo = (segments) => iterator1(
|
|
61
|
+
comp(
|
|
62
|
+
map((s) => s.geo),
|
|
63
|
+
filter((s) => !!s)
|
|
64
|
+
),
|
|
65
|
+
segments
|
|
66
|
+
);
|
|
55
67
|
const b = __collBounds(
|
|
56
68
|
[
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
map((s) => s.geo),
|
|
60
|
-
filter((s) => !!s)
|
|
61
|
-
),
|
|
62
|
-
path.segments
|
|
63
|
-
)
|
|
69
|
+
...$segmentGeo(path.segments),
|
|
70
|
+
...mapcat($segmentGeo, path.subPaths)
|
|
64
71
|
],
|
|
65
72
|
bounds
|
|
66
73
|
);
|
package/centroid.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { MultiFn1O } from "@thi.ng/defmulti";
|
|
|
3
3
|
import type { IShape } from "@thi.ng/geom-api";
|
|
4
4
|
import type { Vec } from "@thi.ng/vectors";
|
|
5
5
|
/**
|
|
6
|
-
* Computes centroid of given shape, writes result in
|
|
7
|
-
* vector (or creates new one if omitted).
|
|
6
|
+
* Computes (possibly weighted) centroid of given shape, writes result in
|
|
7
|
+
* optionally provided output vector (or creates new one if omitted).
|
|
8
8
|
*
|
|
9
9
|
* @remarks
|
|
10
10
|
* Currently implemented for:
|
|
@@ -13,6 +13,7 @@ import type { Vec } from "@thi.ng/vectors";
|
|
|
13
13
|
* - {@link Arc}
|
|
14
14
|
* - {@link BPatch}
|
|
15
15
|
* - {@link Circle}
|
|
16
|
+
* - {@link ComplexPolygon}
|
|
16
17
|
* - {@link Cubic}
|
|
17
18
|
* - {@link Ellipse}
|
|
18
19
|
* - {@link Group}
|
package/centroid.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { defmulti } from "@thi.ng/defmulti/defmulti";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
centerOfWeight2,
|
|
4
|
+
complexCenterOfWeight2
|
|
5
|
+
} from "@thi.ng/geom-poly-utils/center-of-weight";
|
|
3
6
|
import { centroid as _centroid } from "@thi.ng/geom-poly-utils/centroid";
|
|
4
7
|
import { add } from "@thi.ng/vectors/add";
|
|
5
8
|
import { addmN } from "@thi.ng/vectors/addmn";
|
|
@@ -17,6 +20,7 @@ const centroid = defmulti(
|
|
|
17
20
|
bpatch: "points",
|
|
18
21
|
ellipse: "circle",
|
|
19
22
|
line3: "line",
|
|
23
|
+
path: "group",
|
|
20
24
|
points3: "points",
|
|
21
25
|
polyline: "points",
|
|
22
26
|
quad: "poly",
|
|
@@ -26,6 +30,11 @@ const centroid = defmulti(
|
|
|
26
30
|
},
|
|
27
31
|
{
|
|
28
32
|
circle: ($, out) => set(out || [], $.pos),
|
|
33
|
+
complexpoly: ($, out) => complexCenterOfWeight2(
|
|
34
|
+
$.boundary.points,
|
|
35
|
+
$.children.map((c) => c.points),
|
|
36
|
+
out
|
|
37
|
+
),
|
|
29
38
|
group: ($, out) => {
|
|
30
39
|
const b = bounds($);
|
|
31
40
|
return b ? centroid(b, out) : void 0;
|
package/classify-point.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { ReadonlyVec } from "@thi.ng/vectors";
|
|
|
10
10
|
* Currently only implemented for:
|
|
11
11
|
*
|
|
12
12
|
* - {@link Circle}
|
|
13
|
-
* - {@link Plane}
|
|
13
|
+
* - {@link Plane} (-1 = below, +1 = above)
|
|
14
14
|
* - {@link Sphere}
|
|
15
15
|
* - {@link Triangle}
|
|
16
16
|
*
|
|
@@ -18,7 +18,10 @@ import type { ReadonlyVec } from "@thi.ng/vectors";
|
|
|
18
18
|
* more comprehensive feature set (incl. support for more shapes) to perform
|
|
19
19
|
* similar checks as this function.
|
|
20
20
|
*
|
|
21
|
-
* Also see
|
|
21
|
+
* Also see:
|
|
22
|
+
* - {@link closestPoint}
|
|
23
|
+
* - {@link pointInside}
|
|
24
|
+
* - {@link proximity}
|
|
22
25
|
*
|
|
23
26
|
* @param shape
|
|
24
27
|
* @param p
|
package/clip-convex.d.ts
CHANGED
|
@@ -3,9 +3,10 @@ import type { MultiFn2 } from "@thi.ng/defmulti";
|
|
|
3
3
|
import type { IShape } from "@thi.ng/geom-api";
|
|
4
4
|
import type { ReadonlyVec } from "@thi.ng/vectors";
|
|
5
5
|
/**
|
|
6
|
-
* Takes a shape and a boundary (both convex)
|
|
7
|
-
* algorithm to compute a clipped version of the
|
|
8
|
-
*
|
|
6
|
+
* Takes a shape and a boundary (both convex), then uses the Sutherland-Hodgeman
|
|
7
|
+
* algorithm to compute a clipped version of the shape (against the boundary)
|
|
8
|
+
* and returns resulting clipped shape or `undefined` if there're no remaining
|
|
9
|
+
* result vertices (i.e. if the original shape was clipped entirely).
|
|
9
10
|
*
|
|
10
11
|
* @remarks
|
|
11
12
|
* Internally uses
|
|
@@ -13,6 +14,24 @@ import type { ReadonlyVec } from "@thi.ng/vectors";
|
|
|
13
14
|
* For groups, calls itself for each child shape individually and returns a new
|
|
14
15
|
* group of results (if any).
|
|
15
16
|
*
|
|
17
|
+
* For {@link ComplexPolygon}s, children are only processed if the main boundary
|
|
18
|
+
* hasn't been completely clipped. Similarly for paths, where sub-paths are only
|
|
19
|
+
* processed if the main path has remaining vertices. Paths are
|
|
20
|
+
* sampled/converted to polygons and are only processed if the main path is
|
|
21
|
+
* {@link Path.closed}.
|
|
22
|
+
*
|
|
23
|
+
* Currently implemented for:
|
|
24
|
+
*
|
|
25
|
+
* - {@link Circle}
|
|
26
|
+
* - {@link ComplexPolygon}
|
|
27
|
+
* - {@link Ellipse}
|
|
28
|
+
* - {@link Group}
|
|
29
|
+
* - {@link Line}
|
|
30
|
+
* - {@link Path}
|
|
31
|
+
* - {@link Polygon}
|
|
32
|
+
* - {@link Quad}
|
|
33
|
+
* - {@link Triangle}
|
|
34
|
+
*
|
|
16
35
|
* @param shape
|
|
17
36
|
* @param boundary
|
|
18
37
|
*/
|
package/clip-convex.js
CHANGED
|
@@ -2,29 +2,46 @@ import { defmulti } from "@thi.ng/defmulti/defmulti";
|
|
|
2
2
|
import { clipLineSegmentPoly } from "@thi.ng/geom-clip-line/clip-poly";
|
|
3
3
|
import { sutherlandHodgeman } from "@thi.ng/geom-clip-poly";
|
|
4
4
|
import { centroid } from "@thi.ng/geom-poly-utils/centroid";
|
|
5
|
+
import { ComplexPolygon } from "./api/complex-polygon.js";
|
|
5
6
|
import { Group } from "./api/group.js";
|
|
6
7
|
import { Line } from "./api/line.js";
|
|
8
|
+
import { Path } from "./api/path.js";
|
|
7
9
|
import { Polygon } from "./api/polygon.js";
|
|
8
10
|
import { __copyAttribs } from "./internal/copy.js";
|
|
9
11
|
import { __dispatch } from "./internal/dispatch.js";
|
|
10
12
|
import { ensureVertices, vertices } from "./vertices.js";
|
|
13
|
+
const __clipVertices = ($, boundary) => {
|
|
14
|
+
boundary = ensureVertices(boundary);
|
|
15
|
+
const pts = sutherlandHodgeman(vertices($), boundary, centroid(boundary));
|
|
16
|
+
return pts.length ? new Polygon(pts, __copyAttribs($)) : void 0;
|
|
17
|
+
};
|
|
11
18
|
const clipConvex = defmulti(
|
|
12
19
|
__dispatch,
|
|
13
20
|
{
|
|
14
21
|
circle: "rect",
|
|
15
22
|
ellipse: "rect",
|
|
16
|
-
path: "rect",
|
|
17
23
|
quad: "poly",
|
|
18
24
|
tri: "poly"
|
|
19
25
|
},
|
|
20
26
|
{
|
|
27
|
+
complexpoly: ($, boundary) => {
|
|
28
|
+
boundary = ensureVertices(boundary);
|
|
29
|
+
const c = centroid(boundary);
|
|
30
|
+
let clipped = sutherlandHodgeman($.boundary.points, boundary, c);
|
|
31
|
+
if (!clipped.length) return void 0;
|
|
32
|
+
const res = [new Polygon(clipped)];
|
|
33
|
+
for (let child of $.children) {
|
|
34
|
+
clipped = sutherlandHodgeman(child.points, boundary, c);
|
|
35
|
+
if (clipped.length) res.push(new Polygon(clipped));
|
|
36
|
+
}
|
|
37
|
+
return new ComplexPolygon(res[0], res.slice(1), __copyAttribs($));
|
|
38
|
+
},
|
|
21
39
|
group: ({ children, attribs }, boundary) => {
|
|
22
40
|
boundary = ensureVertices(boundary);
|
|
23
41
|
const clipped = [];
|
|
24
42
|
for (let c of children) {
|
|
25
43
|
const res = clipConvex(c, boundary);
|
|
26
|
-
if (res)
|
|
27
|
-
clipped.push(res);
|
|
44
|
+
if (res) clipped.push(res);
|
|
28
45
|
}
|
|
29
46
|
return clipped.length ? new Group({ ...attribs }, clipped) : void 0;
|
|
30
47
|
},
|
|
@@ -36,6 +53,24 @@ const clipConvex = defmulti(
|
|
|
36
53
|
);
|
|
37
54
|
return segments && segments.length ? new Line(segments[0], __copyAttribs($)) : void 0;
|
|
38
55
|
},
|
|
56
|
+
path: ($, boundary) => {
|
|
57
|
+
if ($.closed) return void 0;
|
|
58
|
+
boundary = ensureVertices(boundary);
|
|
59
|
+
let clipped = __clipVertices($, boundary);
|
|
60
|
+
if (!clipped) return void 0;
|
|
61
|
+
const res = new ComplexPolygon(clipped, [], __copyAttribs($));
|
|
62
|
+
for (let sub of $.subPaths) {
|
|
63
|
+
clipped = __clipVertices(
|
|
64
|
+
new Path(sub, [], __copyAttribs($)),
|
|
65
|
+
boundary
|
|
66
|
+
);
|
|
67
|
+
if (clipped) {
|
|
68
|
+
clipped.attribs = void 0;
|
|
69
|
+
res.addChild(clipped);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return res;
|
|
73
|
+
},
|
|
39
74
|
poly: ($, boundary) => {
|
|
40
75
|
boundary = ensureVertices(boundary);
|
|
41
76
|
const pts = sutherlandHodgeman(
|
|
@@ -45,15 +80,7 @@ const clipConvex = defmulti(
|
|
|
45
80
|
);
|
|
46
81
|
return pts.length ? new Polygon(pts, __copyAttribs($)) : void 0;
|
|
47
82
|
},
|
|
48
|
-
rect:
|
|
49
|
-
boundary = ensureVertices(boundary);
|
|
50
|
-
const pts = sutherlandHodgeman(
|
|
51
|
-
vertices($),
|
|
52
|
-
boundary,
|
|
53
|
-
centroid(boundary)
|
|
54
|
-
);
|
|
55
|
-
return pts.length ? new Polygon(pts, __copyAttribs($)) : void 0;
|
|
56
|
-
}
|
|
83
|
+
rect: __clipVertices
|
|
57
84
|
}
|
|
58
85
|
);
|
|
59
86
|
export {
|
package/closest-point.d.ts
CHANGED
|
@@ -12,8 +12,10 @@ import type { ReadonlyVec, Vec } from "@thi.ng/vectors";
|
|
|
12
12
|
* - {@link AABB}
|
|
13
13
|
* - {@link Arc}
|
|
14
14
|
* - {@link Circle}
|
|
15
|
+
* - {@link ComplexPolygon}
|
|
15
16
|
* - {@link Cubic}
|
|
16
17
|
* - {@link Line}
|
|
18
|
+
* - {@link Path}
|
|
17
19
|
* - {@link Plane}
|
|
18
20
|
* - {@link Points}
|
|
19
21
|
* - {@link Points3}
|
package/closest-point.js
CHANGED
|
@@ -14,6 +14,8 @@ import { closestPointArray } from "@thi.ng/geom-closest-point/points";
|
|
|
14
14
|
import { closestPointCubic } from "@thi.ng/geom-splines/cubic-closest-point";
|
|
15
15
|
import { closestPointQuadratic } from "@thi.ng/geom-splines/quadratic-closest-point";
|
|
16
16
|
import { add2, add3 } from "@thi.ng/vectors/add";
|
|
17
|
+
import { distSq2 } from "@thi.ng/vectors/distsq";
|
|
18
|
+
import { set2 } from "@thi.ng/vectors/set";
|
|
17
19
|
import { __dispatch } from "./internal/dispatch.js";
|
|
18
20
|
const closestPoint = defmulti(
|
|
19
21
|
__dispatch,
|
|
@@ -27,6 +29,20 @@ const closestPoint = defmulti(
|
|
|
27
29
|
aabb: ($, p, out) => closestPointAABB(p, $.pos, add3([], $.pos, $.size), out),
|
|
28
30
|
arc: ($, p, out) => closestPointArc(p, $.pos, $.r, $.axis, $.start, $.end, out),
|
|
29
31
|
circle: ($, p, out) => closestPointCircle(p, $.pos, $.r, out),
|
|
32
|
+
complexpoly: ($, p, out) => {
|
|
33
|
+
out = closestPointPolyline(p, $.boundary.points, true, out);
|
|
34
|
+
let minD = distSq2(p, out);
|
|
35
|
+
let tmp = [];
|
|
36
|
+
for (let child of $.children) {
|
|
37
|
+
closestPointPolyline(p, child.points, true, tmp);
|
|
38
|
+
const d = distSq2(p, tmp);
|
|
39
|
+
if (d < minD) {
|
|
40
|
+
minD = d;
|
|
41
|
+
set2(out, tmp);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
},
|
|
30
46
|
cubic: ({ points }, p, out) => closestPointCubic(
|
|
31
47
|
p,
|
|
32
48
|
points[0],
|
|
@@ -36,6 +52,24 @@ const closestPoint = defmulti(
|
|
|
36
52
|
out
|
|
37
53
|
),
|
|
38
54
|
line: ({ points }, p, out) => closestPointSegment(p, points[0], points[1], out),
|
|
55
|
+
path: ($, p, out) => {
|
|
56
|
+
let minD = Infinity;
|
|
57
|
+
const $closestPSegment = (segments) => {
|
|
58
|
+
for (let s of segments) {
|
|
59
|
+
if (!s.geo) continue;
|
|
60
|
+
const q = closestPoint(s.geo, p);
|
|
61
|
+
if (!q) continue;
|
|
62
|
+
const d = distSq2(p, q);
|
|
63
|
+
if (d < minD) {
|
|
64
|
+
minD = d;
|
|
65
|
+
out = set2(out || [], q);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
$closestPSegment($.segments);
|
|
70
|
+
for (let sub of $.subPaths) $closestPSegment(sub);
|
|
71
|
+
return out;
|
|
72
|
+
},
|
|
39
73
|
plane: ($, p, out) => closestPointPlane(p, $.normal, $.w, out),
|
|
40
74
|
points: ($, p, out) => closestPointArray(p, $.points, out),
|
|
41
75
|
poly: ($, p, out) => closestPointPolyline(p, $.points, true, out),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Attribs, SamplingOpts } from "@thi.ng/geom-api";
|
|
2
|
+
import { ComplexPolygon } from "./api/complex-polygon.js";
|
|
3
|
+
import type { Path } from "./api/path.js";
|
|
4
|
+
/**
|
|
5
|
+
* Converts given path into a {@link ComplexPolygon}, using `opts` to control
|
|
6
|
+
* the conversion (via {@link asPolygon}). If no new `attribs` are given, those
|
|
7
|
+
* of the path will be used (shallow copy).
|
|
8
|
+
*
|
|
9
|
+
* @param path
|
|
10
|
+
* @param opts
|
|
11
|
+
* @param attribs
|
|
12
|
+
*/
|
|
13
|
+
export declare const complexPolygonFromPath: (path: Path, opts?: number | Partial<SamplingOpts>, attribs?: Attribs) => ComplexPolygon;
|
|
14
|
+
//# sourceMappingURL=complex-polygon-from-path.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ComplexPolygon } from "./api/complex-polygon.js";
|
|
2
|
+
import { asPolygon } from "./as-polygon.js";
|
|
3
|
+
const complexPolygonFromPath = (path, opts, attribs) => {
|
|
4
|
+
const [boundary, ...children] = asPolygon(path, opts);
|
|
5
|
+
return new ComplexPolygon(boundary, children, attribs || boundary.attribs);
|
|
6
|
+
};
|
|
7
|
+
export {
|
|
8
|
+
complexPolygonFromPath
|
|
9
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Attribs } from "@thi.ng/geom-api";
|
|
2
|
+
import { ComplexPolygon } from "./api/complex-polygon.js";
|
|
3
|
+
import { Polygon } from "./api/polygon.js";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a {@link ComplexPolygon} instance from given `boundary` and `child`
|
|
6
|
+
* polygons (the latter are assumed non-overlapping holes and will be
|
|
7
|
+
* interpreted as such).
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Child polygons are considered holes and fully enclosed by the boundary poly.
|
|
11
|
+
* Depending on usage, holes should also have the opposite vertex order (e.g.
|
|
12
|
+
* via {@link flip}) than the boundary. This is not enforced automatically and
|
|
13
|
+
* the user's responsibility.
|
|
14
|
+
*
|
|
15
|
+
* Any attribs on `boundary` or `children` will be ignored, only those given as
|
|
16
|
+
* `attribs` will be used.
|
|
17
|
+
*
|
|
18
|
+
* @param boundary
|
|
19
|
+
* @param children
|
|
20
|
+
* @param attribs
|
|
21
|
+
*/
|
|
22
|
+
export declare const complexPolygon: (boundary?: Polygon, children?: Iterable<Polygon>, attribs?: Attribs) => ComplexPolygon;
|
|
23
|
+
//# sourceMappingURL=complex-polygon.d.ts.map
|