Skip to content

Commit ef0ebdf

Browse files
feat(geom): update asPath(), add AsPathOpts
BREAKING CHANGE: update asPath() args, add AsPathOpts as 2nd arg - add option for using only linear path segments (no cubics) - update impls for complexpoly & other polygon types
1 parent e3c9f20 commit ef0ebdf

File tree

1 file changed

+92
-52
lines changed

1 file changed

+92
-52
lines changed

packages/geom/src/as-path.ts

Lines changed: 92 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,121 @@
1-
import type { MultiFn1O } from "@thi.ng/defmulti";
1+
import type { MultiFn2O } from "@thi.ng/defmulti";
22
import { DEFAULT, defmulti } from "@thi.ng/defmulti/defmulti";
3-
import type { Attribs, IShape, PathSegment } from "@thi.ng/geom-api";
3+
import type { Attribs, CubicOpts, IShape, PathSegment } from "@thi.ng/geom-api";
44
import type { ReadonlyVec } from "@thi.ng/vectors";
55
import { copy } from "@thi.ng/vectors/copy";
6+
import type { Arc } from "./api/arc.js";
67
import type { ComplexPolygon } from "./api/complex-polygon.js";
78
import { Line } from "./api/line.js";
89
import { Path } from "./api/path.js";
910
import type { Polygon } from "./api/polygon.js";
1011
import type { Polyline } from "./api/polyline.js";
11-
import type { Rect } from "./api/rect.js";
1212
import { asCubic } from "./as-cubic.js";
13+
import { asPolygon } from "./as-polygon.js";
14+
import { asPolyline } from "./as-polyline.js";
1315
import { __copyAttribs } from "./internal/copy.js";
1416
import { __dispatch } from "./internal/dispatch.js";
1517
import { pathFromCubics } from "./path.js";
1618

19+
export interface AsPathOpts extends CubicOpts {
20+
/**
21+
* If true (default: false), creates path consisting of linear segments
22+
* only.
23+
*/
24+
linear: boolean;
25+
}
26+
1727
/**
1828
* Converts given shape into a {@link Path} (by default via {@link asCubic} and
1929
* {@link pathFromCubics}).
2030
*
2131
* @remarks
22-
* The following shape types will be converted into paths consisting only of linear segments (NOT cubic beziers):
23-
*
24-
* - {@link ComplexPolygon}
25-
* - {@link Polygon}
26-
* - {@link Polyline}
27-
* - {@link Quad}
28-
* - {@link Rect}
29-
* - {@link Triangle}
32+
* If {@link AsPathOpts.linear} is enabled the shape will be converted into a
33+
* path consisting only of linear segments (NOT cubic beziers). As an interim
34+
* step this will involve a conversion via {@link asPolygon} or
35+
* {@link asPolyline} with default opts.
3036
*
3137
* @param src
3238
* @param attribs
3339
*/
34-
export const asPath: MultiFn1O<IShape, Attribs, IShape> = defmulti<
35-
any,
36-
Attribs | undefined,
37-
IShape
38-
>(
39-
__dispatch,
40-
{ quad: "poly", tri: "poly" },
41-
{
42-
[DEFAULT]: (src: IShape, attribs?: Attribs) =>
43-
pathFromCubics(asCubic(src), attribs || __copyAttribs(src)),
40+
export const asPath: ((
41+
shape: IShape,
42+
opts?: Partial<AsPathOpts>,
43+
attribs?: Attribs
44+
) => Path) &
45+
MultiFn2O<IShape, Partial<AsPathOpts> | undefined, Attribs, Path> =
46+
defmulti<any, Partial<AsPathOpts> | undefined, Attribs | undefined, Path>(
47+
__dispatch,
48+
{
49+
line: "polyline",
50+
quad: "poly",
51+
tri: "poly",
52+
},
53+
{
54+
[DEFAULT]: (
55+
src: IShape,
56+
opts?: Partial<AsPathOpts>,
57+
attribs?: Attribs
58+
) =>
59+
opts?.linear
60+
? asPath(
61+
asPolygon(src)[0],
62+
opts,
63+
attribs || __copyAttribs(src)
64+
)
65+
: __defaultImpl(src, opts, attribs),
4466

45-
complexpoly: ($: ComplexPolygon, attribs) =>
46-
new Path(
47-
__lineSegments($.boundary.points, true),
48-
$.children.map((c) => __lineSegments(c.points, true)),
49-
attribs || __copyAttribs($)
50-
),
67+
arc: ($: Arc, opts, attribs) =>
68+
opts?.linear
69+
? asPath(
70+
asPolyline($)[0],
71+
opts,
72+
attribs || __copyAttribs($)
73+
)
74+
: __defaultImpl($, opts, attribs),
5175

52-
poly: ($: Polygon, attribs) =>
53-
new Path(
54-
__lineSegments($.points, true),
55-
[],
56-
attribs || __copyAttribs($)
57-
),
76+
complexpoly: ($: ComplexPolygon, opts, attribs) => {
77+
attribs = attribs || __copyAttribs($);
78+
if (opts?.linear) {
79+
return new Path(
80+
__lineSegments($.boundary.points, true),
81+
$.children.map((c) => __lineSegments(c.points, true)),
82+
attribs
83+
);
84+
}
85+
const res = pathFromCubics(asCubic($.boundary, opts), attribs);
86+
for (let child of $.children) {
87+
res.addSubPaths(
88+
pathFromCubics(asCubic(child, opts)).segments
89+
);
90+
}
91+
return res;
92+
},
5893

59-
polyline: ($: Polyline, attribs) =>
60-
new Path(
61-
__lineSegments($.points, false),
62-
[],
63-
attribs || __copyAttribs($)
64-
),
94+
poly: ($: Polygon, opts, attribs) =>
95+
opts?.linear
96+
? new Path(
97+
__lineSegments($.points, true),
98+
[],
99+
attribs || __copyAttribs($)
100+
)
101+
: __defaultImpl($, opts, attribs),
65102

66-
rect: ($: Rect, attribs) => {
67-
const max = $.max();
68-
return new Path(
69-
__lineSegments(
70-
[$.pos, [max[0], $.pos[1]], max, [$.pos[0], max[1]]],
71-
false
72-
),
73-
[],
74-
attribs || __copyAttribs($)
75-
);
76-
},
77-
}
78-
);
103+
polyline: ($: Polyline, opts, attribs) =>
104+
opts?.linear
105+
? new Path(
106+
__lineSegments($.points, false),
107+
[],
108+
attribs || __copyAttribs($)
109+
)
110+
: __defaultImpl($, opts, attribs),
111+
}
112+
);
113+
114+
const __defaultImpl = (
115+
src: IShape,
116+
opts?: Partial<CubicOpts>,
117+
attribs?: Attribs
118+
) => pathFromCubics(asCubic(src, opts), attribs || __copyAttribs(src));
79119

80120
const __lineSegments = (points: ReadonlyVec[], closed: boolean) => {
81121
if (!points.length) return [];

0 commit comments

Comments
 (0)