More optimizations
This commit is contained in:
parent
2a9be6e815
commit
7a65490b5f
5 changed files with 72 additions and 47 deletions
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue