Initial work of ESM transformation
This commit is contained in:
parent
2472c9cff2
commit
b8205a63aa
303 changed files with 1959 additions and 2450 deletions
|
|
@ -1,6 +1,4 @@
|
|||
"use strict";
|
||||
|
||||
exports.Anchor = class Anchor {
|
||||
export class Anchor {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
|
@ -13,4 +11,4 @@ exports.Anchor = class Anchor {
|
|||
const y = a.x * tfm.xy + a.y * tfm.yy + tfm.y;
|
||||
return new Anchor(x, y);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
"use strict";
|
||||
|
||||
const { mix } = require("../utils");
|
||||
import { mix } from "../utils.mjs";
|
||||
|
||||
class Box {
|
||||
constructor(t, b, l, r) {
|
||||
|
|
@ -11,7 +9,6 @@ class Box {
|
|||
this.xMid = this.xMiddle = mix(l, r, 0.5);
|
||||
this.yMid = this.yMiddle = mix(b, t, 0.5);
|
||||
}
|
||||
|
||||
withTop(t) {
|
||||
return new Box(t, this.bottom, this.left, this.right);
|
||||
}
|
||||
|
|
@ -24,14 +21,12 @@ class Box {
|
|||
withRight(r) {
|
||||
return new Box(this.top, this.bottom, this.left, r);
|
||||
}
|
||||
|
||||
withXPadding(d) {
|
||||
return new Box(this.top, this.bottom, this.left + d, this.right - d);
|
||||
}
|
||||
withYPadding(d) {
|
||||
return new Box(this.top - d, this.bottom + d, this.left, this.right);
|
||||
}
|
||||
|
||||
mixX(t) {
|
||||
return mix(this.left, this.right, t);
|
||||
}
|
||||
|
|
@ -45,5 +40,4 @@ class Box {
|
|||
return mix(this.bottom, this.top, t);
|
||||
}
|
||||
}
|
||||
|
||||
exports.Box = Box;
|
||||
export { Box };
|
||||
|
|
@ -1,80 +1,21 @@
|
|||
"use strict";
|
||||
|
||||
const TypoGeom = require("typo-geom");
|
||||
const { Point } = require("./point");
|
||||
const { Transform } = require("./transform");
|
||||
|
||||
exports.SPIRO_PRECISION = 1 / 2;
|
||||
exports.OCCURRENT_PRECISION = 1 / 16;
|
||||
exports.GEOMETRY_PRECISION = 1 / 4;
|
||||
exports.BOOLE_RESOLUTION = 0x4000;
|
||||
|
||||
exports.OffsetCurve = class OffsetCurve {
|
||||
constructor(bone, offset, contrast) {
|
||||
this.bone = bone;
|
||||
this.offset = offset;
|
||||
this.contrast = contrast;
|
||||
}
|
||||
eval(t) {
|
||||
const c = this.bone.eval(t);
|
||||
const d = this.bone.derivative(t);
|
||||
const absD = Math.hypot(d.x, d.y);
|
||||
return {
|
||||
x: c.x - (d.y / absD) * this.offset * this.contrast,
|
||||
y: c.y + (d.x / absD) * this.offset
|
||||
};
|
||||
}
|
||||
derivative(t) {
|
||||
const DELTA = 1 / 0x10000;
|
||||
const forward = this.eval(t + DELTA);
|
||||
const backward = this.eval(t - DELTA);
|
||||
return {
|
||||
x: (forward.x - backward.x) / (2 * DELTA),
|
||||
y: (forward.y - backward.y) / (2 * DELTA)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
exports.ReverseCurve = class ReverseCurve {
|
||||
constructor(original) {
|
||||
this.m_original = original;
|
||||
}
|
||||
eval(t) {
|
||||
return this.m_original.eval(1 - t);
|
||||
}
|
||||
derivative(t) {
|
||||
return -this.m_original.derivative(1 - t);
|
||||
}
|
||||
};
|
||||
|
||||
exports.convertShapeToArcs = function convertShapeToArcs(shape) {
|
||||
return shape.map(convertContourToArcs);
|
||||
};
|
||||
import * as TypoGeom from "typo-geom";
|
||||
import { Point } from "./point.mjs";
|
||||
import { Transform } from "./transform.mjs";
|
||||
|
||||
function contourToRep(contour) {
|
||||
let c = [];
|
||||
for (const z of contour) c.push({ type: z.type, x: z.x, y: z.y });
|
||||
return c;
|
||||
}
|
||||
exports.shapeToRep = function (shape) {
|
||||
return shape.map(contourToRep);
|
||||
};
|
||||
|
||||
function repToContour(contourRep) {
|
||||
let c = [];
|
||||
for (const z of contourRep) c.push(Point.fromXY(z.type, z.x, z.y));
|
||||
return c;
|
||||
}
|
||||
exports.repToShape = function (shapeRep) {
|
||||
return shapeRep.map(repToContour);
|
||||
};
|
||||
|
||||
function convertContourToArcs(contour) {
|
||||
if (!contour || !contour.length) return [];
|
||||
|
||||
const newContour = [];
|
||||
let z0 = Point.from(Point.Type.Corner, contour[0]);
|
||||
|
||||
for (let j = 1; j < contour.length; j++) {
|
||||
const z = contour[j];
|
||||
switch (z.type) {
|
||||
|
|
@ -99,7 +40,6 @@ function convertContourToArcs(contour) {
|
|||
let zf = contour[j + 1] || contour[0];
|
||||
const zfIsCorner = zf.type === Point.Type.contour;
|
||||
if (!zfIsCorner) zf = Point.from(Point.Type.Corner, zc).mix(0.5, zf);
|
||||
|
||||
newContour.push(
|
||||
new TypoGeom.Arcs.Bez3(
|
||||
z0,
|
||||
|
|
@ -108,7 +48,6 @@ function convertContourToArcs(contour) {
|
|||
Point.from(Point.Type.Corner, zf)
|
||||
)
|
||||
);
|
||||
|
||||
z0 = zf;
|
||||
if (zfIsCorner) j++;
|
||||
break;
|
||||
|
|
@ -124,11 +63,58 @@ function convertContourToArcs(contour) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newContour;
|
||||
}
|
||||
|
||||
exports.BezToContoursSink = class BezToContoursSink {
|
||||
export const SPIRO_PRECISION = 1 / 2;
|
||||
export const OCCURRENT_PRECISION = 1 / 16;
|
||||
export const GEOMETRY_PRECISION = 1 / 4;
|
||||
export const BOOLE_RESOLUTION = 0x4000;
|
||||
export class OffsetCurve {
|
||||
constructor(bone, offset, contrast) {
|
||||
this.bone = bone;
|
||||
this.offset = offset;
|
||||
this.contrast = contrast;
|
||||
}
|
||||
eval(t) {
|
||||
const c = this.bone.eval(t);
|
||||
const d = this.bone.derivative(t);
|
||||
const absD = Math.hypot(d.x, d.y);
|
||||
return {
|
||||
x: c.x - (d.y / absD) * this.offset * this.contrast,
|
||||
y: c.y + (d.x / absD) * this.offset
|
||||
};
|
||||
}
|
||||
derivative(t) {
|
||||
const DELTA = 1 / 0x10000;
|
||||
const forward = this.eval(t + DELTA);
|
||||
const backward = this.eval(t - DELTA);
|
||||
return {
|
||||
x: (forward.x - backward.x) / (2 * DELTA),
|
||||
y: (forward.y - backward.y) / (2 * DELTA)
|
||||
};
|
||||
}
|
||||
}
|
||||
export class ReverseCurve {
|
||||
constructor(original) {
|
||||
this.m_original = original;
|
||||
}
|
||||
eval(t) {
|
||||
return this.m_original.eval(1 - t);
|
||||
}
|
||||
derivative(t) {
|
||||
return -this.m_original.derivative(1 - t);
|
||||
}
|
||||
}
|
||||
export function convertShapeToArcs(shape) {
|
||||
return shape.map(convertContourToArcs);
|
||||
}
|
||||
export const shapeToRep = function (shape) {
|
||||
return shape.map(contourToRep);
|
||||
};
|
||||
export const repToShape = function (shapeRep) {
|
||||
return shapeRep.map(repToContour);
|
||||
};
|
||||
export class BezToContoursSink {
|
||||
constructor(gizmo) {
|
||||
this.gizmo = gizmo || Transform.Id();
|
||||
this.contours = [];
|
||||
|
|
@ -157,4 +143,4 @@ exports.BezToContoursSink = class BezToContoursSink {
|
|||
this.lastContour.push(Point.transformedXY(this.gizmo, Point.Type.CubicEnd, x2, y2));
|
||||
this.lastContour.push(Point.transformedXY(this.gizmo, Point.Type.Corner, x, y));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
"use strict";
|
||||
|
||||
const crypto = require("crypto");
|
||||
const TypoGeom = require("typo-geom");
|
||||
const SpiroJs = require("spiro");
|
||||
|
||||
const CurveUtil = require("./curve-util");
|
||||
const Format = require("../util/formatter");
|
||||
const { Point } = require("./point");
|
||||
const { Transform } = require("./transform");
|
||||
const { SpiroExpander } = require("./spiro-expand");
|
||||
import crypto from "crypto";
|
||||
import * as TypoGeom from "typo-geom";
|
||||
import * as SpiroJs from "spiro";
|
||||
import * as CurveUtil from "./curve-util.mjs";
|
||||
import * as Format from "../util/formatter.mjs";
|
||||
import { Point } from "./point.mjs";
|
||||
import { Transform } from "./transform.mjs";
|
||||
import { SpiroExpander } from "./spiro-expand.mjs";
|
||||
|
||||
class GeometryBase {
|
||||
asContours() {
|
||||
|
|
@ -33,7 +30,6 @@ class GeometryBase {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class ContourGeometry extends GeometryBase {
|
||||
constructor(points) {
|
||||
super();
|
||||
|
|
@ -67,7 +63,6 @@ class ContourGeometry extends GeometryBase {
|
|||
return Format.struct(`ContourGeometry`, Format.list(this.m_points.map(Format.typedPoint)));
|
||||
}
|
||||
}
|
||||
|
||||
class SpiroGeometry extends GeometryBase {
|
||||
constructor(gizmo, closed, knots) {
|
||||
super();
|
||||
|
|
@ -110,28 +105,22 @@ class SpiroGeometry extends GeometryBase {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DiSpiroGeometry extends GeometryBase {
|
||||
constructor(gizmo, contrast, closed, biKnots) {
|
||||
super();
|
||||
|
||||
this.m_biKnots = [];
|
||||
for (const k of biKnots) this.m_biKnots.push(k.clone());
|
||||
|
||||
this.m_closed = closed;
|
||||
this.m_gizmo = gizmo;
|
||||
this.m_contrast = contrast;
|
||||
|
||||
this.m_cachedExpansionResults = null;
|
||||
this.m_cachedContours = null;
|
||||
}
|
||||
|
||||
asContours() {
|
||||
if (this.m_cachedContours) return this.m_cachedContours;
|
||||
const expandResult = this.expand();
|
||||
const lhs = [...expandResult.lhs];
|
||||
const rhs = [...expandResult.rhs];
|
||||
|
||||
let rawGeometry;
|
||||
if (this.m_closed) {
|
||||
rawGeometry = new CombineGeometry([
|
||||
|
|
@ -161,7 +150,6 @@ class DiSpiroGeometry extends GeometryBase {
|
|||
this.m_cachedExpansionResults = expander.expand();
|
||||
return this.m_cachedExpansionResults;
|
||||
}
|
||||
|
||||
asReferences() {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -177,7 +165,6 @@ class DiSpiroGeometry extends GeometryBase {
|
|||
}
|
||||
return this.m_biKnots.length;
|
||||
}
|
||||
|
||||
toShapeStringOrNull() {
|
||||
return Format.struct(
|
||||
"DiSpiroGeometry",
|
||||
|
|
@ -188,7 +175,6 @@ class DiSpiroGeometry extends GeometryBase {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ReferenceGeometry extends GeometryBase {
|
||||
constructor(glyph, x, y) {
|
||||
super();
|
||||
|
|
@ -231,7 +217,6 @@ class ReferenceGeometry extends GeometryBase {
|
|||
return Format.struct("ReferenceGeometry", sTarget, Format.n(this.m_x), Format.n(this.m_y));
|
||||
}
|
||||
}
|
||||
|
||||
class TaggedGeometry extends GeometryBase {
|
||||
constructor(g, tag) {
|
||||
super();
|
||||
|
|
@ -261,7 +246,6 @@ class TaggedGeometry extends GeometryBase {
|
|||
return this.m_geom.toShapeStringOrNull();
|
||||
}
|
||||
}
|
||||
|
||||
class TransformedGeometry extends GeometryBase {
|
||||
constructor(g, tfm) {
|
||||
super();
|
||||
|
|
@ -281,7 +265,6 @@ class TransformedGeometry extends GeometryBase {
|
|||
if (!Transform.isTranslate(this.m_transform)) return null;
|
||||
const rs = this.m_geom.asReferences();
|
||||
if (!rs) return null;
|
||||
|
||||
let result = [];
|
||||
for (const { glyph, x, y } of rs)
|
||||
result.push({ glyph, x: x + this.m_transform.x, y: y + this.m_transform.y });
|
||||
|
|
@ -324,7 +307,6 @@ class TransformedGeometry extends GeometryBase {
|
|||
return Format.struct("TransformedGeometry", sTarget, Format.gizmo(this.m_transform));
|
||||
}
|
||||
}
|
||||
|
||||
class CombineGeometry extends GeometryBase {
|
||||
constructor(parts) {
|
||||
super();
|
||||
|
|
@ -373,7 +355,6 @@ class CombineGeometry extends GeometryBase {
|
|||
let s = 0;
|
||||
for (const part of this.m_parts) s += part.measureComplexity();
|
||||
}
|
||||
|
||||
unlinkReferences() {
|
||||
let parts = [];
|
||||
for (const part of this.m_parts) {
|
||||
|
|
@ -396,7 +377,6 @@ class CombineGeometry extends GeometryBase {
|
|||
return Format.struct("CombineGeometry", Format.list(sParts));
|
||||
}
|
||||
}
|
||||
|
||||
class BooleanGeometry extends GeometryBase {
|
||||
constructor(operator, operands) {
|
||||
super();
|
||||
|
|
@ -411,7 +391,6 @@ class BooleanGeometry extends GeometryBase {
|
|||
}
|
||||
asContoursImpl() {
|
||||
if (this.m_operands.length === 0) return [];
|
||||
|
||||
let arcs = CurveUtil.convertShapeToArcs(this.m_operands[0].asContours());
|
||||
if (this.m_operands.length === 1) {
|
||||
arcs = TypoGeom.Boolean.removeOverlap(
|
||||
|
|
@ -456,7 +435,6 @@ class BooleanGeometry extends GeometryBase {
|
|||
unlinkReferences() {
|
||||
if (this.m_operands.length === 0) return new CombineGeometry([]);
|
||||
if (this.m_operands.length === 1) return this.m_operands[0].unlinkReferences();
|
||||
|
||||
let operands = [];
|
||||
for (const operand of this.m_operands) {
|
||||
operands.push(operand.unlinkReferences());
|
||||
|
|
@ -473,13 +451,6 @@ class BooleanGeometry extends GeometryBase {
|
|||
return Format.struct("BooleanGeometry", this.m_operator, Format.list(sParts));
|
||||
}
|
||||
}
|
||||
|
||||
exports.hashGeometry = function (geom) {
|
||||
const s = geom.toShapeStringOrNull();
|
||||
if (!s) return null;
|
||||
return crypto.createHash("sha256").update(s).digest("hex");
|
||||
};
|
||||
|
||||
function combineWith(a, b) {
|
||||
if (a instanceof CombineGeometry) {
|
||||
return a.with(b);
|
||||
|
|
@ -487,15 +458,18 @@ function combineWith(a, b) {
|
|||
return new CombineGeometry([a, b]);
|
||||
}
|
||||
}
|
||||
|
||||
exports.GeometryBase = GeometryBase;
|
||||
exports.SpiroGeometry = SpiroGeometry;
|
||||
exports.DiSpiroGeometry = DiSpiroGeometry;
|
||||
exports.ContourGeometry = ContourGeometry;
|
||||
exports.ReferenceGeometry = ReferenceGeometry;
|
||||
exports.TaggedGeometry = TaggedGeometry;
|
||||
exports.TransformedGeometry = TransformedGeometry;
|
||||
exports.CombineGeometry = CombineGeometry;
|
||||
exports.BooleanGeometry = BooleanGeometry;
|
||||
|
||||
exports.combineWith = combineWith;
|
||||
export const hashGeometry = function (geom) {
|
||||
const s = geom.toShapeStringOrNull();
|
||||
if (!s) return null;
|
||||
return crypto.createHash("sha256").update(s).digest("hex");
|
||||
};
|
||||
export { GeometryBase };
|
||||
export { SpiroGeometry };
|
||||
export { DiSpiroGeometry };
|
||||
export { ContourGeometry };
|
||||
export { ReferenceGeometry };
|
||||
export { TaggedGeometry };
|
||||
export { TransformedGeometry };
|
||||
export { CombineGeometry };
|
||||
export { BooleanGeometry };
|
||||
export { combineWith };
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
"use strict";
|
||||
|
||||
class Point {
|
||||
constructor(type, x, y) {
|
||||
this.type = type;
|
||||
|
|
@ -31,7 +29,6 @@ class Point {
|
|||
round(d) {
|
||||
return new Point(this.type, Math.round(d * this.x) / d, Math.round(d * this.y) / d);
|
||||
}
|
||||
|
||||
static from(type, z) {
|
||||
return new Point(type, z.x || 0, z.y || 0);
|
||||
}
|
||||
|
|
@ -61,12 +58,10 @@ class Point {
|
|||
return new Point(z.type, z.x + dx || 0, z.y + dy || 0);
|
||||
}
|
||||
}
|
||||
|
||||
Point.Type = {
|
||||
Corner: 0,
|
||||
CubicStart: 1,
|
||||
CubicEnd: 2,
|
||||
Quadratic: 3
|
||||
};
|
||||
|
||||
exports.Point = Point;
|
||||
export { Point };
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
const SpiroJs = require("spiro");
|
||||
|
||||
const { linreg } = require("../utils");
|
||||
const Format = require("../util/formatter");
|
||||
import * as SpiroJs from "spiro";
|
||||
import { linreg } from "../utils.mjs";
|
||||
import * as Format from "../util/formatter.mjs";
|
||||
|
||||
class BiKnot {
|
||||
constructor(type, x, y, d1, d2) {
|
||||
|
|
@ -23,7 +20,6 @@ class BiKnot {
|
|||
k1.unimportant = this.unimportant;
|
||||
return k1;
|
||||
}
|
||||
|
||||
toShapeString() {
|
||||
return Format.tuple(
|
||||
this.type,
|
||||
|
|
@ -41,17 +37,14 @@ class BiKnot {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BiKnotCollector {
|
||||
constructor(gizmo, contrast) {
|
||||
this.gizmo = gizmo;
|
||||
this.contrast = contrast;
|
||||
|
||||
this.controlKnots = [];
|
||||
this.defaultD1 = 0;
|
||||
this.defaultD2 = 0;
|
||||
}
|
||||
|
||||
pushKnot(type, x, y) {
|
||||
const tfZ = this.gizmo.applyXY(x, y);
|
||||
const k0 = this.controlKnots[this.controlKnots.length - 1];
|
||||
|
|
@ -61,7 +54,6 @@ class BiKnotCollector {
|
|||
this.controlKnots.push(new BiKnot(type, tfZ.x, tfZ.y, this.defaultD1, this.defaultD2));
|
||||
}
|
||||
}
|
||||
|
||||
setWidth(l, r) {
|
||||
const k0 = this.controlKnots[this.controlKnots.length - 1];
|
||||
if (k0) {
|
||||
|
|
@ -83,7 +75,6 @@ class BiKnotCollector {
|
|||
if (k0) k0.unimportant = 1;
|
||||
}
|
||||
}
|
||||
|
||||
class SpiroExpander {
|
||||
constructor(gizmo, contrast, closed, cks) {
|
||||
this.gizmo = gizmo;
|
||||
|
|
@ -91,12 +82,10 @@ class SpiroExpander {
|
|||
this.closed = closed;
|
||||
this.controlKnots = cks;
|
||||
}
|
||||
|
||||
initializeNormals() {
|
||||
const normalRectifier = new NormalRectifier(this.controlKnots, this.gizmo);
|
||||
SpiroJs.spiroToArcsOnContext(this.controlKnots, this.closed, normalRectifier);
|
||||
}
|
||||
|
||||
iterateNormals() {
|
||||
const centerBone = this.getPass2Knots();
|
||||
const normalRectifier = new NormalRectifier(this.controlKnots, this.gizmo);
|
||||
|
|
@ -117,7 +106,6 @@ class SpiroExpander {
|
|||
}
|
||||
return middles;
|
||||
}
|
||||
|
||||
expand() {
|
||||
const lhs = [],
|
||||
rhs = [];
|
||||
|
|
@ -137,12 +125,10 @@ class SpiroExpander {
|
|||
y: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Create important knots
|
||||
for (let j = 0; j < this.controlKnots.length; j++) {
|
||||
const knot = this.controlKnots[j];
|
||||
if (knot.unimportant) continue;
|
||||
|
||||
let dx, dy;
|
||||
if (knot.proposedNormal) {
|
||||
dx = knot.proposedNormal.x;
|
||||
|
|
@ -153,14 +139,12 @@ class SpiroExpander {
|
|||
}
|
||||
lhs[j].x = knot.x + knot.d1 * dx;
|
||||
lhs[j].y = knot.y + knot.d1 * dy;
|
||||
|
||||
rhs[j].x = knot.x - knot.d2 * dx;
|
||||
rhs[j].y = knot.y - knot.d2 * dy;
|
||||
}
|
||||
this.interpolateUnimportantKnots(lhs, rhs);
|
||||
return { lhs, rhs };
|
||||
}
|
||||
|
||||
interpolateUnimportantKnots(lhs, rhs) {
|
||||
for (let j = 0; j < this.controlKnots.length; j++) {
|
||||
const knot = this.controlKnots[j];
|
||||
|
|
@ -168,7 +152,6 @@ class SpiroExpander {
|
|||
let jBefore, jAfter;
|
||||
for (jBefore = j - 1; cyNth(this.controlKnots, jBefore).unimportant; jBefore--);
|
||||
for (jAfter = j + 1; cyNth(this.controlKnots, jAfter).unimportant; jAfter++);
|
||||
|
||||
const knotBefore = this.gizmo.unapply(cyNth(this.controlKnots, jBefore)),
|
||||
knotAfter = this.gizmo.unapply(cyNth(this.controlKnots, jAfter)),
|
||||
ref = this.gizmo.unapply(knot),
|
||||
|
|
@ -176,7 +159,6 @@ class SpiroExpander {
|
|||
lhsAfter = this.gizmo.unapply(cyNth(lhs, jAfter)),
|
||||
rhsBefore = this.gizmo.unapply(cyNth(rhs, jBefore)),
|
||||
rhsAfter = this.gizmo.unapply(cyNth(rhs, jAfter));
|
||||
|
||||
const lhsTf = this.gizmo.applyXY(
|
||||
linreg(knotBefore.x, lhsBefore.x, knotAfter.x, lhsAfter.x, ref.x),
|
||||
linreg(knotBefore.y, lhsBefore.y, knotAfter.y, lhsAfter.y, ref.y)
|
||||
|
|
@ -185,20 +167,17 @@ class SpiroExpander {
|
|||
linreg(knotBefore.x, rhsBefore.x, knotAfter.x, rhsAfter.x, ref.x),
|
||||
linreg(knotBefore.y, rhsBefore.y, knotAfter.y, rhsAfter.y, ref.y)
|
||||
);
|
||||
|
||||
(lhs[j].x = lhsTf.x), (lhs[j].y = lhsTf.y);
|
||||
(rhs[j].x = rhsTf.x), (rhs[j].y = rhsTf.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NormalRectifier {
|
||||
constructor(stage1ControlKnots, gizmo) {
|
||||
this.gizmo = gizmo;
|
||||
this.controlKnots = stage1ControlKnots;
|
||||
this.nKnotsProcessed = 0;
|
||||
}
|
||||
|
||||
beginShape() {}
|
||||
endShape() {}
|
||||
moveTo(x, y) {
|
||||
|
|
@ -224,7 +203,6 @@ class NormalRectifier {
|
|||
this.nKnotsProcessed += 1;
|
||||
}
|
||||
}
|
||||
|
||||
function isTangentValid(d) {
|
||||
return isFinite(d.x) && isFinite(d.y);
|
||||
}
|
||||
|
|
@ -240,6 +218,5 @@ function reverseKnotType(ty) {
|
|||
function cyNth(a, j) {
|
||||
return a[j % a.length];
|
||||
}
|
||||
|
||||
exports.BiKnotCollector = BiKnotCollector;
|
||||
exports.SpiroExpander = SpiroExpander;
|
||||
export { BiKnotCollector };
|
||||
export { SpiroExpander };
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
"use strict";
|
||||
|
||||
exports.Transform = class Transform {
|
||||
export class Transform {
|
||||
constructor(xx, yx, xy, yy, x, y) {
|
||||
this.xx = xx;
|
||||
this.yx = yx;
|
||||
|
|
@ -9,15 +7,12 @@ exports.Transform = class Transform {
|
|||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
static Id() {
|
||||
return new Transform(1, 0, 0, 1, 0, 0);
|
||||
}
|
||||
|
||||
static Translate(x, y) {
|
||||
return new Transform(1, 0, 0, 1, x, y);
|
||||
}
|
||||
|
||||
apply(pt) {
|
||||
return this.applyXY(pt.x, pt.y);
|
||||
}
|
||||
|
|
@ -56,11 +51,9 @@ exports.Transform = class Transform {
|
|||
-(-this.x * this.xy + this.y * this.xx) / denom
|
||||
);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `[[${this.xx} ${this.xy}] [${this.yx} ${this.yy}]] + [[${this.x}] [${this.y}]]`;
|
||||
}
|
||||
|
||||
static isTranslate(tfm) {
|
||||
return tfm.xx === 1 && tfm.yy === 1 && tfm.xy === 0 && tfm.yx === 0;
|
||||
}
|
||||
|
|
@ -85,4 +78,4 @@ exports.Transform = class Transform {
|
|||
z00.y
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue