Add frakturs in the Letterlike Symbols (#2438)

* * Add characters:
  - BLACK-LETTER CAPITAL I (`U+2111`).
  - BLACK-LETTER CAPITAL R (`U+211C`).

* Complete frakturs in Letterlike Symbols block

* Update geom cache version
This commit is contained in:
Belleve 2024-07-28 03:30:59 -10:00 committed by GitHub
parent 61ad3c365c
commit bff9e0b1c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 496 additions and 8 deletions

View file

@ -5,6 +5,7 @@ import * as CurveUtil from "./curve-util.mjs";
import { Point } from "./point.mjs";
import { QuadifySink } from "./quadify.mjs";
import { SpiroExpander } from "./spiro-expand.mjs";
import { createSpiroPenGeometry } from "./spiro-pen-expander.mjs";
import { spiroToOutlineWithSimplification } from "./spiro-to-outline.mjs";
import { strokeArcs } from "./stroke.mjs";
import { Transform } from "./transform.mjs";
@ -139,6 +140,83 @@ export class SpiroGeometry extends CachedGeometry {
}
}
export class SpiroPenGeometry extends CachedGeometry {
constructor(gizmo, closed, pen, knots) {
super();
this.m_gizmo = gizmo;
this.m_closed = closed;
this.m_knots = knots;
this.m_pen = pen;
}
toContoursImpl() {
let contours = createSpiroPenGeometry(
this.m_gizmo,
this.m_closed,
this.m_knots,
this.m_pen,
);
if (!contours.length) return [];
let stack = [];
for (const [i, c] of contours.entries()) {
stack.push({
type: "operand",
fillType: TypoGeom.Boolean.PolyFillType.pftNonZero,
shape: CurveUtil.convertShapeToArcs([c]),
});
if (i > 0) {
stack.push({ type: "operator", operator: TypoGeom.Boolean.ClipType.ctUnion });
}
}
const arcs = TypoGeom.Boolean.combineStack(stack, CurveUtil.BOOLE_RESOLUTION);
const ctx = new CurveUtil.BezToContoursSink();
TypoGeom.ShapeConv.transferBezArcShape(arcs, ctx);
return ctx.contours;
}
toReferences() {
return null;
}
getDependencies() {
return null;
}
filterTag(fn) {
return this;
}
measureComplexity() {
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
for (const z of this.m_pen) {
if (!isFinite(z.x) || !isFinite(z.y)) cplx |= CPLX_BROKEN;
}
for (const z of this.m_knots) {
if (!isFinite(z.x) || !isFinite(z.y)) cplx |= CPLX_BROKEN;
}
return cplx;
}
hash(h) {
h.beginStruct("SpiroPenGeometry");
h.gizmo(this.m_gizmo);
h.bool(this.m_closed);
// Serialize the pen
h.beginArray(this.m_pen.length);
for (const z of this.m_pen) h.point(z);
h.endArray();
// Serialize the knots
h.beginArray(this.m_knots.length);
for (const knot of this.m_knots) h.embed(knot);
h.endArray();
h.endStruct();
}
}
export class DiSpiroGeometry extends CachedGeometry {
constructor(gizmo, contrast, closed, biKnots) {
super();

View file

@ -0,0 +1,81 @@
import * as SpiroJs from "spiro";
import * as CurveUtil from "./curve-util.mjs";
import { Point } from "./point.mjs";
export function createSpiroPenGeometry(gizmo, closed, knots, pen) {
const collector = new ArcCollector(gizmo, pen);
SpiroJs.spiroToBezierOnContext(knots, closed, collector, CurveUtil.GEOMETRY_PRECISION);
return collector.contoursCollected;
}
class ArcCollector {
constructor(gizmo, pen) {
this.gizmo = gizmo;
this.lastX = 0;
this.lastY = 0;
this.m_pen = pen;
this.contoursCollected = [];
}
beginShape() {}
endShape() {}
moveTo(x, y) {
const lastTf = this.gizmo.applyXY(x, y);
this.lastX = lastTf.x;
this.lastY = lastTf.y;
this.addPenProfileAt(this.lastX, this.lastY);
}
lineTo(x1, y1) {
const z1 = this.gizmo.applyXY(x1, y1);
for (let i = 0; i < this.m_pen.length; i++) {
let penPrev = this.m_pen[i];
let penNext = this.m_pen[(i + 1) % this.m_pen.length];
const l1 = new Point(Point.Type.Corner, this.lastX + penPrev.x, this.lastY + penPrev.y);
const l2 = new Point(Point.Type.Corner, z1.x + penPrev.x, z1.y + penPrev.y);
const r2 = new Point(Point.Type.Corner, z1.x + penNext.x, z1.y + penNext.y);
const r1 = new Point(Point.Type.Corner, this.lastX + penNext.x, this.lastY + penNext.y);
this.contoursCollected.push([l1, l2, r2, r1]);
}
this.lastX = z1.x;
this.lastY = z1.y;
this.addPenProfileAt(this.lastX, this.lastY);
}
cubicTo(x2, y2, x3, y3, x4, y4) {
const z2 = this.gizmo.applyXY(x2, y2);
const z3 = this.gizmo.applyXY(x3, y3);
const z4 = this.gizmo.applyXY(x4, y4);
for (let i = 0; i < this.m_pen.length; i++) {
let penPrev = this.m_pen[i];
let penNext = this.m_pen[(i + 1) % this.m_pen.length];
const l1 = new Point(Point.Type.Corner, this.lastX + penPrev.x, this.lastY + penPrev.y);
const l2 = new Point(Point.Type.CubicStart, z2.x + penPrev.x, z2.y + penPrev.y);
const l3 = new Point(Point.Type.CubicEnd, z3.x + penPrev.x, z3.y + penPrev.y);
const l4 = new Point(Point.Type.Corner, z4.x + penPrev.x, z4.y + penPrev.y);
const r4 = new Point(Point.Type.Corner, z4.x + penNext.x, z4.y + penNext.y);
const r3 = new Point(Point.Type.CubicStart, z3.x + penNext.x, z3.y + penNext.y);
const r2 = new Point(Point.Type.CubicEnd, z2.x + penNext.x, z2.y + penNext.y);
const r1 = new Point(Point.Type.Corner, this.lastX + penNext.x, this.lastY + penNext.y);
this.contoursCollected.push([l1, l2, l3, l4, r4, r3, r2, r1]);
}
this.lastX = z4.x;
this.lastY = z4.y;
this.addPenProfileAt(this.lastX, this.lastY);
}
addPenProfileAt(x, y) {
let c = [];
for (let i = 0; i < this.m_pen.length; i++) {
let pen = this.m_pen[i];
c.push(new Point(Point.Type.Corner, x + pen.x, y + pen.y));
}
this.contoursCollected.push(c);
}
}

View file

@ -2,7 +2,6 @@ import * as SpiroJs from "spiro";
import * as TypoGeom from "typo-geom";
import * as CurveUtil from "./curve-util.mjs";
import { Vec2 } from "./point.mjs";
export function spiroToOutline(knots, fClosed, gizmo) {
const s = new CurveUtil.BezToContoursSink(gizmo);