Reduce closures
This commit is contained in:
parent
1f0be761a2
commit
f8a104d550
4 changed files with 148 additions and 108 deletions
|
@ -3,32 +3,44 @@
|
|||
const TypoGeom = require("typo-geom");
|
||||
const { BooleanGeometry, TransformedGeometry } = require("../support/geometry/index");
|
||||
|
||||
exports.SetupBuilders = function ({ Glyph, GlobalTransform }) {
|
||||
function impl(operator, operands) {
|
||||
return function () {
|
||||
const operandGeometries = [];
|
||||
const forwardGizmo = this.gizmo || GlobalTransform;
|
||||
const backwardGizmo = forwardGizmo.inverse();
|
||||
for (const operand of operands) {
|
||||
const g1 = new Glyph();
|
||||
g1.gizmo = forwardGizmo;
|
||||
g1.include(operand);
|
||||
operandGeometries.push(new TransformedGeometry(g1.geometry, backwardGizmo));
|
||||
}
|
||||
return this.includeGeometry(
|
||||
new TransformedGeometry(
|
||||
new BooleanGeometry(operator, operandGeometries),
|
||||
forwardGizmo
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
const union = (...operands) => impl(TypoGeom.Boolean.ClipType.ctUnion, operands);
|
||||
const intersection = (...operands) => impl(TypoGeom.Boolean.ClipType.ctIntersection, operands);
|
||||
const difference = (...operands) => impl(TypoGeom.Boolean.ClipType.ctDifference, operands);
|
||||
exports.SetupBuilders = function (bindings) {
|
||||
const union = (...operands) =>
|
||||
new BooleImpl(bindings, TypoGeom.Boolean.ClipType.ctUnion, operands);
|
||||
const intersection = (...operands) =>
|
||||
new BooleImpl(bindings, TypoGeom.Boolean.ClipType.ctIntersection, operands);
|
||||
const difference = (...operands) =>
|
||||
new BooleImpl(bindings, TypoGeom.Boolean.ClipType.ctDifference, operands);
|
||||
return {
|
||||
union: union,
|
||||
intersection: intersection,
|
||||
difference: difference
|
||||
};
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BooleImpl {
|
||||
constructor(bindings, operator, operands) {
|
||||
this.bindings = bindings;
|
||||
this.operator = operator;
|
||||
this.operands = operands;
|
||||
}
|
||||
|
||||
applyToGlyph(glyph) {
|
||||
const operandGeometries = [];
|
||||
const forwardGizmo = glyph.gizmo || this.bindings.GlobalTransform;
|
||||
const backwardGizmo = forwardGizmo.inverse();
|
||||
for (const operand of this.operands) {
|
||||
const g1 = new this.bindings.Glyph();
|
||||
g1.gizmo = forwardGizmo;
|
||||
g1.include(operand);
|
||||
operandGeometries.push(new TransformedGeometry(g1.geometry, backwardGizmo));
|
||||
}
|
||||
return glyph.includeGeometry(
|
||||
new TransformedGeometry(
|
||||
new BooleanGeometry(this.operator, operandGeometries),
|
||||
forwardGizmo
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -222,95 +222,15 @@ exports.SetupBuilders = function (bindings) {
|
|||
arcvh.superness = function (s) {
|
||||
return arcvh(DEFAULT_STEPS, s);
|
||||
};
|
||||
function flattenImpl(sink, knots) {
|
||||
for (const p of knots) {
|
||||
if (p instanceof Array) flattenImpl(sink, p);
|
||||
else sink.push(p);
|
||||
}
|
||||
}
|
||||
function nCyclic(p, n) {
|
||||
return (p + n + n) % n;
|
||||
}
|
||||
function flatten(s, knots0) {
|
||||
let knots = [];
|
||||
flattenImpl(knots, knots0);
|
||||
let unwrapped = false;
|
||||
for (let j = 0; j < knots.length; j = j + 1)
|
||||
if (knots[j] && knots[j].type === "interpolate") {
|
||||
const kBefore = knots[nCyclic(j - 1, knots.length)];
|
||||
const kAfter = knots[nCyclic(j + 1, knots.length)];
|
||||
knots[j] = knots[j].blender(kBefore, kAfter, knots[j]);
|
||||
unwrapped = true;
|
||||
}
|
||||
if (unwrapped) return flatten(s, knots);
|
||||
return knots;
|
||||
}
|
||||
function dropTailKnot(knots) {
|
||||
let last = knots[knots.length - 1];
|
||||
if (last && (last.type === "close" || last.type === "end")) {
|
||||
knots.length = knots.length - 1;
|
||||
return last.type === "close";
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function prepareSpiroKnots(_knots, s) {
|
||||
let knots = [..._knots];
|
||||
while (knots[0] && knots[0] instanceof Function) {
|
||||
knots[0].call(s);
|
||||
knots.splice(0, 1);
|
||||
}
|
||||
const closed = dropTailKnot(knots);
|
||||
knots = flatten(s, knots);
|
||||
return { knots, closed };
|
||||
}
|
||||
|
||||
class DiSpiroProxy {
|
||||
constructor(closed, collector, origKnots) {
|
||||
this.geometry = new DiSpiroGeometry(
|
||||
collector.gizmo,
|
||||
collector.contrast,
|
||||
closed,
|
||||
collector.controlKnots
|
||||
);
|
||||
this.m_origKnots = origKnots;
|
||||
}
|
||||
|
||||
get knots() {
|
||||
return this.m_origKnots;
|
||||
}
|
||||
get lhsKnots() {
|
||||
return this.geometry.expand().lhs;
|
||||
}
|
||||
get rhsKnots() {
|
||||
return this.geometry.expand().rhs;
|
||||
}
|
||||
}
|
||||
|
||||
function dispiro(...args) {
|
||||
return function () {
|
||||
const gizmo = this.gizmo || GlobalTransform;
|
||||
const collector = new BiKnotCollector(gizmo, Contrast);
|
||||
const { knots, closed } = prepareSpiroKnots(args, collector);
|
||||
for (const knot of knots) {
|
||||
collector.pushKnot(knot.type, knot.x, knot.y);
|
||||
if (knot.af) knot.af.call(collector);
|
||||
}
|
||||
|
||||
const dsp = new DiSpiroProxy(closed, collector, knots);
|
||||
this.includeGeometry(dsp.geometry);
|
||||
return dsp;
|
||||
};
|
||||
return new DispiroImpl(bindings, args);
|
||||
}
|
||||
|
||||
function spiroOutline(...args) {
|
||||
return function () {
|
||||
const gizmo = this.gizmo || GlobalTransform;
|
||||
const g = new CurveUtil.BezToContoursSink(gizmo);
|
||||
const { knots, closed } = prepareSpiroKnots(args, g);
|
||||
return this.includeGeometry(new SpiroGeometry(gizmo, closed, knots));
|
||||
};
|
||||
return new SpiroOutlineImpl(bindings, args);
|
||||
}
|
||||
|
||||
return {
|
||||
g4,
|
||||
g2,
|
||||
|
@ -335,3 +255,108 @@ exports.SetupBuilders = function (bindings) {
|
|||
"spiro-outline": spiroOutline
|
||||
};
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class DispiroImpl {
|
||||
constructor(bindings, args) {
|
||||
this.bindings = bindings;
|
||||
this.args = args;
|
||||
}
|
||||
applyToGlyph(glyph) {
|
||||
const gizmo = glyph.gizmo || this.bindings.GlobalTransform;
|
||||
const collector = new BiKnotCollector(gizmo, this.bindings.Contrast);
|
||||
const { knots, closed } = prepareSpiroKnots(this.args, collector);
|
||||
for (const knot of knots) {
|
||||
collector.pushKnot(knot.type, knot.x, knot.y);
|
||||
if (knot.af) knot.af.call(collector);
|
||||
}
|
||||
|
||||
const dsp = new DiSpiroProxy(closed, collector, knots);
|
||||
glyph.includeGeometry(dsp.geometry);
|
||||
return dsp;
|
||||
}
|
||||
}
|
||||
|
||||
class SpiroOutlineImpl {
|
||||
constructor(bindings, args) {
|
||||
this.bindings = bindings;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
applyToGlyph(glyph) {
|
||||
const gizmo = glyph.gizmo || this.bindings.GlobalTransform;
|
||||
const g = new CurveUtil.BezToContoursSink(gizmo);
|
||||
const { knots, closed } = prepareSpiroKnots(this.args, g);
|
||||
return glyph.includeGeometry(new SpiroGeometry(gizmo, closed, knots));
|
||||
}
|
||||
}
|
||||
|
||||
class DiSpiroProxy {
|
||||
constructor(closed, collector, origKnots) {
|
||||
this.geometry = new DiSpiroGeometry(
|
||||
collector.gizmo,
|
||||
collector.contrast,
|
||||
closed,
|
||||
collector.controlKnots
|
||||
);
|
||||
this.m_origKnots = origKnots;
|
||||
}
|
||||
|
||||
get knots() {
|
||||
return this.m_origKnots;
|
||||
}
|
||||
get lhsKnots() {
|
||||
return this.geometry.expand().lhs;
|
||||
}
|
||||
get rhsKnots() {
|
||||
return this.geometry.expand().rhs;
|
||||
}
|
||||
}
|
||||
|
||||
function prepareSpiroKnots(_knots, s) {
|
||||
let knots = [..._knots];
|
||||
while (knots[0] && knots[0] instanceof Function) {
|
||||
knots[0].call(s);
|
||||
knots.splice(0, 1);
|
||||
}
|
||||
const closed = dropTailKnot(knots);
|
||||
knots = flatten(s, knots);
|
||||
return { knots, closed };
|
||||
}
|
||||
|
||||
function dropTailKnot(knots) {
|
||||
let last = knots[knots.length - 1];
|
||||
if (last && (last.type === "close" || last.type === "end")) {
|
||||
knots.length = knots.length - 1;
|
||||
return last.type === "close";
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function flatten(s, knots0) {
|
||||
let knots = [];
|
||||
flattenImpl(knots, knots0);
|
||||
let unwrapped = false;
|
||||
for (let j = 0; j < knots.length; j = j + 1)
|
||||
if (knots[j] && knots[j].type === "interpolate") {
|
||||
const kBefore = knots[nCyclic(j - 1, knots.length)];
|
||||
const kAfter = knots[nCyclic(j + 1, knots.length)];
|
||||
knots[j] = knots[j].blender(kBefore, kAfter, knots[j]);
|
||||
unwrapped = true;
|
||||
}
|
||||
if (unwrapped) return flatten(s, knots);
|
||||
return knots;
|
||||
}
|
||||
|
||||
function flattenImpl(sink, knots) {
|
||||
for (const p of knots) {
|
||||
if (p instanceof Array) flattenImpl(sink, p);
|
||||
else sink.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
function nCyclic(p, n) {
|
||||
return (p + n + n) % n;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ exports.GlyphStore = class GlyphStore {
|
|||
this.encodingBackward = new Map();
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this.nameForward.size;
|
||||
}
|
||||
glyphs() {
|
||||
return this.nameForward.values();
|
||||
}
|
||||
|
|
|
@ -63,10 +63,10 @@ exports.Glyph = class Glyph {
|
|||
include(component, copyAnchors, copyWidth) {
|
||||
if (!component) {
|
||||
throw new Error("Unreachable: Attempt to include a Null or Undefined");
|
||||
} else if (component instanceof Function) {
|
||||
return component.call(this, copyAnchors, copyWidth);
|
||||
} else if (component.applyToGlyph instanceof Function) {
|
||||
return component.applyToGlyph(this, copyAnchors, copyWidth);
|
||||
} else if (component instanceof Function) {
|
||||
return component.call(this, copyAnchors, copyWidth);
|
||||
} else if (component instanceof Transform) {
|
||||
return this.applyTransform(component, copyAnchors);
|
||||
} else if (component instanceof Glyph) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue