More optimizations

This commit is contained in:
be5invis 2024-02-20 00:41:42 -08:00
parent 2a9be6e815
commit 7a65490b5f
5 changed files with 72 additions and 47 deletions

View file

@ -8,8 +8,8 @@ import * as CurveUtil from "./curve-util.mjs";
import { Point } from "./point.mjs";
import { QuadifySink } from "./quadify.mjs";
import { SpiroExpander } from "./spiro-expand.mjs";
import { Transform } from "./transform.mjs";
import { strokeArcs } from "./stroke.mjs";
import { Transform } from "./transform.mjs";
export const CPLX_NON_EMPTY = 0x01; // A geometry tree that is not empty
export const CPLX_NON_SIMPLE = 0x02; // A geometry tree that contains non-simple contours
@ -79,10 +79,7 @@ export class ContourSetGeometry extends GeometryBase {
export class SpiroGeometry extends GeometryBase {
constructor(gizmo, closed, knots) {
super();
this.m_knots = [];
for (const k of knots) {
this.m_knots.push({ type: k.type, x: k.x, y: k.y });
}
this.m_knots = knots;
this.m_closed = closed;
this.m_gizmo = gizmo;
this.m_cachedContours = null;
@ -120,7 +117,7 @@ export class SpiroGeometry extends GeometryBase {
"SpiroGeometry",
Format.gizmo(this.m_gizmo),
this.m_closed,
Format.list(this.m_knots.map(Format.typedPoint))
Format.list(this.m_knots.map(k => k.toShapeString()))
);
}
}
@ -140,17 +137,20 @@ export class DiSpiroGeometry extends GeometryBase {
const expandResult = this.expand();
const lhs = [...expandResult.lhsUntransformed];
const rhs = [...expandResult.rhsUntransformed];
// Reverse the RHS
for (const k of rhs) k.reverseType();
rhs.reverse();
let rawGeometry;
if (this.m_closed) {
rawGeometry = new CombineGeometry([
new SpiroGeometry(this.m_gizmo, true, lhs),
new SpiroGeometry(this.m_gizmo, true, rhs.reverse())
new SpiroGeometry(this.m_gizmo, true, rhs)
]);
} else {
lhs[0].type = lhs[lhs.length - 1].type = "corner";
rhs[0].type = rhs[rhs.length - 1].type = "corner";
const allKnots = lhs.concat(rhs.reverse());
const allKnots = lhs.concat(rhs);
rawGeometry = new SpiroGeometry(this.m_gizmo, true, allKnots);
}
this.m_cachedContours = rawGeometry.asContours();

View file

@ -20,7 +20,7 @@ export class BiKnotCollector {
c.call(this);
} else if (Array.isArray(c)) {
for (const item of c) this.add(item);
} else if (c instanceof ControlKnot) {
} else if (c instanceof UserControlKnot) {
this.afterPreFunction = true;
this.pushKnot(c);
} else if (c instanceof TerminateInstruction) {
@ -102,6 +102,33 @@ export class BiKnotCollector {
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
export class MonoKnot {
constructor(type, unimportant, x, y) {
this.type = type;
this.x = x;
this.y = y;
this.unimportant = unimportant;
}
clone() {
const k1 = new MonoKnot(this.type, this.x, this.y, this.unimportant);
return k1;
}
toShapeString() {
return Format.tuple(this.type, this.unimportant, Format.n(this.x), Format.n(this.y));
}
reverseType() {
if (this.type === "left") {
this.type = "right";
} else if (this.type === "right") {
this.type = "left";
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
class BiKnot {
constructor(type, x, y, d1, d2) {
this.type = type;
@ -144,6 +171,9 @@ class BiKnot {
: ""
);
}
toMono() {
return new MonoKnot(this.type, this.unimportant, this.x, this.y);
}
}
function nCyclic(p, n) {
@ -152,7 +182,7 @@ function nCyclic(p, n) {
///////////////////////////////////////////////////////////////////////////////////////////////////
export class ControlKnot {
export class UserControlKnot {
constructor(type, x, y, af) {
this.type = type;
this.x = x;
@ -185,10 +215,3 @@ export function Interpolator(blender, restParameters) {
for (const prop in restParameters) interpolator[prop] = restParameters[prop];
return interpolator;
}
export class ImportanceControlKnot extends ControlKnot {
constructor(type, x, y, unimportant) {
super(type, x, y, null);
this.unimportant = unimportant;
}
}

View file

@ -2,7 +2,7 @@ import { linreg, mix } from "@iosevka/util";
import * as SpiroJs from "spiro";
import { Vec2 } from "./point.mjs";
import { ControlKnot } from "./spiro-control.mjs";
import { MonoKnot } from "./spiro-control.mjs";
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -30,8 +30,9 @@ export class SpiroExpander {
for (let j = 0; j < this.m_biKnotsT.length; j++) {
const lhs = expanded.lhs[j];
const rhs = expanded.rhs[j];
middles[j] = new ControlKnot(
middles[j] = new MonoKnot(
this.m_biKnotsT[j].type,
this.m_biKnotsT[j].unimportant,
mix(lhs.x, rhs.x, 0.5),
mix(lhs.y, rhs.y, 0.5)
);
@ -39,17 +40,17 @@ export class SpiroExpander {
return middles;
}
expand() {
const lhs = [],
rhs = [],
lhsUntransformed = [],
rhsUntransformed = [];
const lhsT = [], // transformed LHS
rhsT = [], // transformed RHS
lhsU = [], // untransformed LHS
rhsU = []; // untransformed RHS
for (let j = 0; j < this.m_biKnotsT.length; j++) {
const knot = this.m_biKnotsT[j];
lhs[j] = new ControlKnot(knot.type, 0, 0);
rhs[j] = new ControlKnot(reverseKnotType(knot.type), 0, 0);
lhsUntransformed[j] = new ControlKnot(knot.type, 0, 0);
rhsUntransformed[j] = new ControlKnot(reverseKnotType(knot.type), 0, 0);
const bk = this.m_biKnotsT[j];
lhsT[j] = new MonoKnot(bk.type, bk.unimportant, 0, 0);
rhsT[j] = new MonoKnot(bk.type, bk.unimportant, 0, 0);
lhsU[j] = new MonoKnot(bk.type, bk.unimportant, 0, 0);
rhsU[j] = new MonoKnot(bk.type, bk.unimportant, 0, 0);
}
for (let j = 0; j < this.m_biKnotsT.length; j++) {
@ -63,17 +64,17 @@ export class SpiroExpander {
dx = normalX(knotT.origTangent, this.m_contrast);
dy = normalY(knotT.origTangent, this.m_contrast);
}
lhs[j].x = knotT.x + knotT.d1 * dx;
lhs[j].y = knotT.y + knotT.d1 * dy;
rhs[j].x = knotT.x - knotT.d2 * dx;
rhs[j].y = knotT.y - knotT.d2 * dy;
lhsT[j].x = knotT.x + knotT.d1 * dx;
lhsT[j].y = knotT.y + knotT.d1 * dy;
rhsT[j].x = knotT.x - knotT.d2 * dx;
rhsT[j].y = knotT.y - knotT.d2 * dy;
this.m_gizmo.unapplyToSink(lhs[j], lhsUntransformed[j]);
this.m_gizmo.unapplyToSink(rhs[j], rhsUntransformed[j]);
this.m_gizmo.unapplyToSink(lhsT[j], lhsU[j]);
this.m_gizmo.unapplyToSink(rhsT[j], rhsU[j]);
}
this.interpolateUnimportantKnots(lhs, rhs, lhsUntransformed, rhsUntransformed);
return { lhs, rhs, lhsUntransformed, rhsUntransformed };
this.interpolateUnimportantKnots(lhsT, rhsT, lhsU, rhsU);
return { lhs: lhsT, rhs: rhsT, lhsUntransformed: lhsU, rhsUntransformed: rhsU };
}
interpolateUnimportantKnots(lhsT, rhsT, lhsU, rhsU) {
for (let j = 0; j < this.m_biKnotsU.length; j++) {
@ -143,9 +144,6 @@ function normalY(tangent) {
return tangent.x / Math.hypot(tangent.x, tangent.y);
}
function reverseKnotType(ty) {
return ty === "left" ? "right" : ty === "right" ? "left" : ty;
}
function cyNth(a, j) {
return a[j % a.length];
}