@thi.ng/geom
Version:
Functional, polymorphic API for 2D geometry types & SVG generation
86 lines (85 loc) • 2.58 kB
JavaScript
import { DEFAULT, defmulti } from "@thi.ng/defmulti/defmulti";
import { copy } from "@thi.ng/vectors/copy";
import { Line } from "./api/line.js";
import { Line3 } from "./api/line3.js";
import { Path } from "./api/path.js";
import { Path3 } from "./api/path3.js";
import { Polyline } from "./api/polyline.js";
import { asCubic } from "./as-cubic.js";
import { asPolygon } from "./as-polygon.js";
import { asPolyline } from "./as-polyline.js";
import { __copyAttribs } from "./internal/copy.js";
import { __dispatch } from "./internal/dispatch.js";
import { pathFromCubics } from "./path-from-cubics.js";
const asPath = defmulti(
__dispatch,
{
line: "polyline",
quad: "poly",
tri: "poly"
},
{
[DEFAULT]: (src, opts) => opts?.linear ? asPath(asPolygon(src)[0], opts) : __defaultImpl(src, opts),
arc: ($, opts) => opts?.linear ? asPath(asPolyline($)[0], opts) : __defaultImpl($, opts),
complexpoly: ({ boundary, children, attribs }, opts) => {
attribs = __copyAttribs(attribs);
if (opts?.linear) {
return __linearPath(
boundary,
children.map(
(c) => __lineSegments(Line, c.points, true)
),
true
);
}
const res = pathFromCubics(asCubic(boundary, opts), attribs);
for (let child of children) {
res.addSubPaths(
pathFromCubics(asCubic(child, opts)).segments
);
}
return res;
},
poly: ($, opts) => opts?.linear ? __linearPath($, [], true) : __defaultImpl($, opts),
polyline: ($, opts) => opts?.linear ? __linearPath($, [], false) : __defaultImpl($, opts)
}
);
const __defaultImpl = (src, opts) => pathFromCubics(
asCubic(src, { attribs: false, ...opts }),
__copyAttribs(src.attribs)
);
function __lineSegments(ctor, points, closed) {
const n = points.length;
if (!n) return [];
const segments = [{ type: "m", point: copy(points[0]) }];
for (let i = 1; i < n; i++)
segments.push({
type: "l",
geo: new ctor([copy(points[i - 1]), copy(points[i])])
});
if (closed) {
segments.push(
{
type: "l",
geo: new ctor([copy(points[n - 1]), copy(points[0])])
},
{ type: "z" }
);
}
return segments;
}
const __linearPath = (shape, subPaths, closed = false) => {
const attribs = __copyAttribs(shape.attribs);
return shape.dim === 2 ? new Path(
__lineSegments(Line, shape.points, closed),
subPaths,
attribs
) : new Path3(
__lineSegments(Line3, shape.points, closed),
subPaths,
attribs
);
};
export {
asPath
};