Reduce closures

This commit is contained in:
be5invis 2022-03-27 12:36:01 -07:00
parent 1f0be761a2
commit f8a104d550
4 changed files with 148 additions and 108 deletions

View file

@ -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
)
);
}
}

View file

@ -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;
}

View file

@ -8,6 +8,9 @@ exports.GlyphStore = class GlyphStore {
this.encodingBackward = new Map();
}
get size() {
return this.nameForward.size;
}
glyphs() {
return this.nameForward.values();
}

View file

@ -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) {