Fix rounding errors found in certain Extended glyphs (#1100).

This commit is contained in:
be5invis 2021-05-30 16:00:03 -07:00
parent a16554a244
commit b7e7752109
3 changed files with 23 additions and 5 deletions

View file

@ -1,2 +1,3 @@
* Fix Aile's long-S at Italic (#1098). * Fix Aile's long-S at Italic (#1098).
* Fix assignment of capital Gamma in `ss14` (#1099). * Fix assignment of capital Gamma in `ss14` (#1099).
* Fix rounding errors found in certain Extended glyphs (#1100).

View file

@ -4,7 +4,7 @@ const fs = require("fs-extra");
const zlib = require("zlib"); const zlib = require("zlib");
const { encode, decode } = require("@msgpack/msgpack"); const { encode, decode } = require("@msgpack/msgpack");
const Edition = 4; const Edition = 5;
const MAX_AGE = 5; const MAX_AGE = 5;
class GfEntry { class GfEntry {

View file

@ -121,11 +121,13 @@ class SimplifyGeometry extends Geom.GeometryBase {
class FairizedShapeSink { class FairizedShapeSink {
constructor() { constructor() {
this.lastReferenceZ = null;
this.contours = []; this.contours = [];
this.lastContour = []; this.lastContour = [];
} }
beginShape() {} beginShape() {}
endShape() { endShape() {
this.lastReferenceZ = null;
if (this.lastContour.length > 2) { if (this.lastContour.length > 2) {
// TT use CW for outline, being different from Clipper // TT use CW for outline, being different from Clipper
const c = this.lastContour.reverse(); const c = this.lastContour.reverse();
@ -136,20 +138,32 @@ class FairizedShapeSink {
} }
this.lastContour = []; this.lastContour = [];
} }
tryAlignWithPreviousKnot(z) {
if (!this.lastReferenceZ) return z;
let x1 = z.x,
y1 = z.y;
if (geometryPrecisionEqual(x1, this.lastReferenceZ.x)) x1 = this.lastReferenceZ.x;
if (geometryPrecisionEqual(y1, this.lastReferenceZ.y)) y1 = this.lastReferenceZ.y;
return Point.fromXY(z.type, x1, y1).round(CurveUtil.GEOMETRY_PRECISION);
}
moveTo(x, y) { moveTo(x, y) {
this.endShape(); this.endShape();
this.lineTo(x, y); this.lineTo(x, y);
} }
lineTo(x, y) { lineTo(x, y) {
const z = Point.fromXY(Point.Type.Corner, x, y).round(1); const z0 = Point.fromXY(Point.Type.Corner, x, y);
const z = this.tryAlignWithPreviousKnot(z0);
this.popOccurrentKnots(z); this.popOccurrentKnots(z);
this.popColinearKnots(z); this.popColinearKnots(z);
this.lastContour.push(z); this.lastContour.push(z);
this.lastReferenceZ = z0;
} }
arcTo(arc, x, y) { arcTo(arc, x, y) {
const offPoints = TypoGeom.Quadify.auto(arc, 1, 8); const offPoints = TypoGeom.Quadify.auto(arc, 1, 8);
for (const z of offPoints) { for (const z of offPoints) {
this.lastContour.push(Point.from(Point.Type.Quadratic, z).round(1)); this.lastContour.push(
this.tryAlignWithPreviousKnot(Point.from(Point.Type.Quadratic, z))
);
} }
this.lineTo(x, y); this.lineTo(x, y);
} }
@ -195,7 +209,10 @@ function isOccurrent(zFirst, zLast) {
); );
} }
function geometryPrecisionEqual(a, b) { function geometryPrecisionEqual(a, b) {
return Math.round(a) === Math.round(b); return (
Math.round(a * CurveUtil.RECIP_GEOMETRY_PRECISION) ===
Math.round(b * CurveUtil.RECIP_GEOMETRY_PRECISION)
);
} }
function aligned(a, b, c) { function aligned(a, b, c) {
return geometryPrecisionEqual(a, b) && geometryPrecisionEqual(b, c); return geometryPrecisionEqual(a, b) && geometryPrecisionEqual(b, c);