Skip to content

Commit

Permalink
feat(geom): add asCubic() impls for circle, group, rect
Browse files Browse the repository at this point in the history
- re-use arc impl from geom-splines
  • Loading branch information
postspectacular committed Jul 12, 2019
1 parent 3e386f7 commit 5ca4166
Showing 1 changed file with 21 additions and 57 deletions.
78 changes: 21 additions & 57 deletions packages/geom/src/ops/as-cubic.ts
@@ -1,80 +1,42 @@
import { IObjectOf } from "@thi.ng/api";
import { defmulti, Implementation1, MultiFn1O } from "@thi.ng/defmulti";
import { CubicOpts, IShape, Type } from "@thi.ng/geom-api";
import { closedCubicFromBreakPoints, closedCubicFromControlPoints } from "@thi.ng/geom-splines";
import {
EPS,
HALF_PI,
roundEps,
sincos
} from "@thi.ng/math";
import { closedCubicFromBreakPoints, closedCubicFromControlPoints, cubicFromArc } from "@thi.ng/geom-splines";
import { TAU } from "@thi.ng/math";
import { mapcat } from "@thi.ng/transducers";
import { add2, magSq2 } from "@thi.ng/vectors";
import {
Arc,
Circle,
Cubic,
Group,
Line,
Path,
Polygon,
Quadratic
Quadratic,
Rect
} from "../api";
import { cubic, cubicFromLine, cubicFromQuadratic } from "../ctors/cubic";
import { arc } from "../ctors/arc";
import { cubicFromLine, cubicFromQuadratic } from "../ctors/cubic";
import { dispatch } from "../internal/dispatch";
import { asPolygon } from "./as-polygon";

export const asCubic: MultiFn1O<IShape, Partial<CubicOpts>, Cubic[]> = defmulti(
dispatch
);

asCubic.addAll(<IObjectOf<Implementation1<unknown, Cubic[]>>>{
[Type.ARC]: ($: Arc) => {
const p = $.pointAtTheta($.start);
const q = $.pointAtTheta($.end);
const [rx, ry] = $.r;
const [sphi, cphi] = sincos($.axis);
const dx = (cphi * (p[0] - q[0])) / 2 + (sphi * (p[1] - q[1])) / 2;
const dy = (-sphi * (p[0] - q[0])) / 2 + (cphi * (p[1] - q[1])) / 2;
if ((dx === 0 && dy === 0) || magSq2($.r) < EPS) {
return [cubicFromLine(p, q, { ...$.attribs })];
}

const mapP = (x: number, y: number) => {
x *= rx;
y *= ry;
return add2(
null,
[cphi * x - sphi * y, sphi * x + cphi * y],
$.pos
);
};
[Type.ARC]: ($: Arc) =>
cubicFromArc($.pos, $.r, $.axis, $.start, $.end).map(
(c) => new Cubic(c, $.attribs)
),

const res: Cubic[] = [];
const delta = $.end - $.start;
const n = Math.max(roundEps(Math.abs(delta) / HALF_PI, 1e-3), 1);
// https://github.com/chromium/chromium/blob/master/third_party/blink/renderer/core/svg/svg_path_parser.cc#L253
const d = delta / n;
const t = (8 / 6) * Math.tan(0.25 * d);
if (!isFinite(t)) {
return [cubicFromLine(p, q)];
}
for (let i = n, theta = $.start; i > 0; i--, theta += d) {
const [s1, c1] = sincos(theta);
const [s2, c2] = sincos(theta + d);
const curve = new Cubic(
[
mapP(c1, s1),
mapP(c1 - s1 * t, s1 + c1 * t),
mapP(c2 + s2 * t, s2 - c2 * t),
mapP(c2, s2)
],
{ ...$.attribs }
);
res.push(curve);
}
return res;
},
[Type.CIRCLE]: ($: Circle) =>
asCubic(arc($.pos, $.r, 0, 0, TAU, true, true)),

[Type.CUBIC]: ($: Cubic) => [$],

[Type.GROUP]: ($: Group) => [...mapcat(asCubic, $.children)],

[Type.LINE]: ({ attribs, points }: Line) => [
cubicFromLine(points[0], points[1], { ...attribs })
],
Expand All @@ -88,10 +50,12 @@ asCubic.addAll(<IObjectOf<Implementation1<unknown, Cubic[]>>>{
return (opts.breakPoints
? closedCubicFromBreakPoints($.points, opts.scale, opts.uniform)
: closedCubicFromControlPoints($.points, opts.scale, opts.uniform)
).map((pts) => cubic(pts, { ...$.attribs }));
).map((pts) => new Cubic(pts, { ...$.attribs }));
},

[Type.QUADRATIC]: ({ attribs, points }: Quadratic) => [
cubicFromQuadratic(points[0], points[1], points[2], { ...attribs })
]
],

[Type.RECT]: ($: Rect, opts?) => asCubic(asPolygon($), opts)
});

0 comments on commit 5ca4166

Please sign in to comment.