Unify the precision management of geometries

This commit is contained in:
be5invis 2020-07-01 03:49:27 -07:00
parent 15c7381673
commit 84a8cb809c
6 changed files with 45 additions and 39 deletions

View file

@ -98,19 +98,16 @@ function simplifyContours(source) {
TypoGeom.Boolean.removeOverlap( TypoGeom.Boolean.removeOverlap(
CurveUtil.convertShapeToArcs(source), CurveUtil.convertShapeToArcs(source),
TypoGeom.Boolean.PolyFillType.pftNonZero, TypoGeom.Boolean.PolyFillType.pftNonZero,
1 << 17 CurveUtil.BOOLE_RESOLUTION
) )
), ),
sink, sink,
FINAL_SIMPLIFY_TOLERANCE CurveUtil.GEOMETRY_PRECISION
); );
return sink.contours; return sink.contours;
} }
const FINAL_SIMPLIFY_RESOLUTION = 16;
const FINAL_SIMPLIFY_TOLERANCE = 2 / FINAL_SIMPLIFY_RESOLUTION;
class FairizedShapeSink { class FairizedShapeSink {
constructor() { constructor() {
this.contours = []; this.contours = [];
@ -133,7 +130,7 @@ class FairizedShapeSink {
this.lineTo(x, y); this.lineTo(x, y);
} }
lineTo(x, y) { lineTo(x, y) {
const z = Point.cornerFromXY(x, y).round(FINAL_SIMPLIFY_RESOLUTION); const z = Point.cornerFromXY(x, y).round(CurveUtil.RECIP_GEOMETRY_PRECISION);
while (this.lastContour.length >= 2) { while (this.lastContour.length >= 2) {
const a = this.lastContour[this.lastContour.length - 2], const a = this.lastContour[this.lastContour.length - 2],
b = this.lastContour[this.lastContour.length - 1]; b = this.lastContour[this.lastContour.length - 1];
@ -146,10 +143,10 @@ class FairizedShapeSink {
this.lastContour.push(z); this.lastContour.push(z);
} }
arcTo(arc, x, y) { arcTo(arc, x, y) {
const offPoints = TypoGeom.Quadify.auto(arc, FINAL_SIMPLIFY_TOLERANCE); const offPoints = TypoGeom.Quadify.auto(arc, CurveUtil.GEOMETRY_PRECISION);
if (offPoints) { if (offPoints) {
for (const z of offPoints) for (const z of offPoints)
this.lastContour.push(Point.offFrom(z).round(FINAL_SIMPLIFY_RESOLUTION)); this.lastContour.push(Point.offFrom(z).round(CurveUtil.RECIP_GEOMETRY_PRECISION));
} }
this.lineTo(x, y); this.lineTo(x, y);
} }
@ -162,8 +159,14 @@ function isLineExtend(a, b, c) {
(aligned(a.y, b.y, c.y) && between(a.x, b.x, c.x))) (aligned(a.y, b.y, c.y) && between(a.x, b.x, c.x)))
); );
} }
function geometryPrecisionEqual(a, 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 Math.round(a) === Math.round(b) && Math.round(b) === Math.round(c); return geometryPrecisionEqual(a, b) && geometryPrecisionEqual(b, c);
} }
function between(a, b, c) { function between(a, b, c) {
return (a <= b && b <= c) || (a >= b && b >= c); return (a <= b && b <= c) || (a >= b && b >= c);

View file

@ -15,7 +15,12 @@ export : define [SetupBuilders args] : begin
set g1.gizmo : this.gizmo || globalTransform set g1.gizmo : this.gizmo || globalTransform
g1.include item g1.include item
set g1.contours : g1.contours.map CurveUtil.convertContourToCubic set g1.contours : g1.contours.map CurveUtil.convertContourToCubic
local c1 : TypoGeom.Boolean.combine operator [CurveUtil.convertShapeToArcs g.contours] [CurveUtil.convertShapeToArcs g1.contours] TypoGeom.Boolean.PolyFillType.pftNonZero TypoGeom.Boolean.PolyFillType.pftNonZero 16384 local c1 : TypoGeom.Boolean.combine operator
CurveUtil.convertShapeToArcs g.contours
CurveUtil.convertShapeToArcs g1.contours
begin TypoGeom.Boolean.PolyFillType.pftNonZero
begin TypoGeom.Boolean.PolyFillType.pftNonZero
begin CurveUtil.BOOLE_RESOLUTION
local ctx : new CurveUtil.BezToContoursSink local ctx : new CurveUtil.BezToContoursSink
TypoGeom.transferBezArcShape c1 ctx TypoGeom.transferBezArcShape c1 ctx
set g.contours ctx.contours set g.contours ctx.contours
@ -26,4 +31,4 @@ export : define [SetupBuilders args] : begin
define intersection : Boole TypoGeom.Boolean.ClipType.ctIntersection define intersection : Boole TypoGeom.Boolean.ClipType.ctIntersection
define difference : Boole TypoGeom.Boolean.ClipType.ctDifference define difference : Boole TypoGeom.Boolean.ClipType.ctDifference
return [object union intersection difference] return [object union intersection difference]

View file

@ -151,9 +151,12 @@ export : define [SetupBuilders args] : begin
if closed : knots.pop if closed : knots.pop
return {.knots [flatten knots] .closed closed .lastafs lastafs} return {.knots [flatten knots] .closed closed .lastafs lastafs}
define QUAD false define [convertSpiroToBezier knots closed ctx] : begin
define PRECISION 0.5 define CUBIC false
return : SpiroJs.spiroToBezierOnContext knots closed ctx CUBIC CurveUtil.GEOMETRY_PRECISION
define [dispiro] : let [args : {}.slice.call arguments 0] : lambda [dontinc] : begin define [dispiro] : let [args : {}.slice.call arguments 0] : lambda [dontinc] : begin
define CLOSED true
local s : new SpiroExpansionContext local s : new SpiroExpansionContext
set s.gizmo : this.gizmo || globalTransform set s.gizmo : this.gizmo || globalTransform
local {.knots knots .closed closed .lastafs lastafs} : prepareSpiroKnots [{}.slice.call args 0] s local {.knots knots .closed closed .lastafs lastafs} : prepareSpiroKnots [{}.slice.call args 0] s
@ -167,16 +170,16 @@ export : define [SetupBuilders args] : begin
local {.lhs lhs .rhs rhs} : s.expand [fallback s.contrast Contrast] local {.lhs lhs .rhs rhs} : s.expand [fallback s.contrast Contrast]
if closed : then if closed : then
local g : new CurveUtil.BezToContoursSink local g : new CurveUtil.BezToContoursSink
SpiroJs.spiroToBezierOnContext [lhs.slice 0 (-1)] true g QUAD PRECISION # CurveUtil.BezToContoursSink::beginShape won't clear the contours
local lhsContour g.contours.0 # We will get two contours at last
set g.contours {} convertSpiroToBezier [lhs.slice 0 (-1)] CLOSED g
SpiroJs.spiroToBezierOnContext [rhs.reverse :.slice 0 (-1)] true g QUAD PRECISION convertSpiroToBezier [rhs.reverse :.slice 0 (-1)] CLOSED g
local rhsContour g.contours.0 set g.contours { [g.contours.0.concat g.contours.1] }
set g.contours {[lhsContour.concat rhsContour]}
: else : begin : else : begin
local g : new CurveUtil.BezToContoursSink local g : new CurveUtil.BezToContoursSink
lhs.0.type = rhs.0.type = lhs.(lhs.length - 1).type = rhs.(rhs.length - 1).type = 'corner' lhs.0.type = lhs.(lhs.length - 1).type = 'corner'
SpiroJs.spiroToBezierOnContext [lhs.concat : rhs.reverse] true g QUAD PRECISION rhs.0.type = rhs.(rhs.length - 1).type = 'corner'
convertSpiroToBezier [lhs.concat : rhs.reverse] CLOSED g
set g.knots knots set g.knots knots
set g.lhsKnots lhs set g.lhsKnots lhs
@ -187,7 +190,7 @@ export : define [SetupBuilders args] : begin
define [spiro-outline] : let [k : {}.slice.call arguments 0] : lambda [dontinc] : begin define [spiro-outline] : let [k : {}.slice.call arguments 0] : lambda [dontinc] : begin
local g : new CurveUtil.BezToContoursSink (this.gizmo || globalTransform) local g : new CurveUtil.BezToContoursSink (this.gizmo || globalTransform)
local {.knots knots .closed closed .lastafs lastafs} : prepareSpiroKnots k g local {.knots knots .closed closed .lastafs lastafs} : prepareSpiroKnots k g
SpiroJs.spiroToBezierOnContext knots closed g QUAD PRECISION convertSpiroToBezier knots closed g
foreach af [items-of lastafs] : if af : af.call g foreach af [items-of lastafs] : if af : af.call g
this.includeGeometry g 0 0 this.includeGeometry g 0 0
return g return g

View file

@ -1,6 +1,6 @@
$$include '../meta/macros.ptl' $$include '../meta/macros.ptl'
import [OffsetCurve BezToContoursSink] from '../support/curve-util' import [OffsetCurve BezToContoursSink GEOMETRY_PRECISION] from '../support/curve-util'
import [mix linreg clamp fallback] from '../support/utils' import [mix linreg clamp fallback] from '../support/utils'
import [designParameters] from '../meta/aesthetics' import [designParameters] from '../meta/aesthetics'
import [Arcs Quadify transferGenericShapeAsBezier] from "typo-geom" import [Arcs Quadify transferGenericShapeAsBezier] from "typo-geom"
@ -230,7 +230,7 @@ glyph-block Overmarks : begin
define outer : new Arcs.Reverted : new OffsetCurve bone (-hs) HVContrast define outer : new Arcs.Reverted : new OffsetCurve bone (-hs) HVContrast
define cs : new BezToContoursSink define cs : new BezToContoursSink
transferGenericShapeAsBezier {{inner outer}} cs (1 / 4) transferGenericShapeAsBezier {{inner outer}} cs GEOMETRY_PRECISION
include cs include cs
sketch # tildeAbove sketch # tildeAbove

View file

@ -2,9 +2,12 @@
const TypoGeom = require("typo-geom"); const TypoGeom = require("typo-geom");
const Point = require("./point"); const Point = require("./point");
const { mix } = require("./utils");
const Transform = require("./transform"); const Transform = require("./transform");
exports.GEOMETRY_PRECISION = 1 / 4;
exports.RECIP_GEOMETRY_PRECISION = 4;
exports.BOOLE_RESOLUTION = 0x4000;
exports.OffsetCurve = class OffsetCurve { exports.OffsetCurve = class OffsetCurve {
constructor(bone, offset, contrast) { constructor(bone, offset, contrast) {
this.bone = bone; this.bone = bone;
@ -31,7 +34,7 @@ exports.OffsetCurve = class OffsetCurve {
} }
}; };
function convertContourToCubic(contour) { exports.convertContourToCubic = function convertContourToCubic(contour) {
if (!contour || !contour.length) return []; if (!contour || !contour.length) return [];
const newContour = []; const newContour = [];
@ -70,7 +73,11 @@ function convertContourToCubic(contour) {
} }
return newContour; return newContour;
} };
exports.convertShapeToArcs = function convertShapeToArcs(shape) {
return shape.map(convertContourToArcs);
};
function convertContourToArcs(contour) { function convertContourToArcs(contour) {
if (!contour || !contour.length) return []; if (!contour || !contour.length) return [];
@ -124,13 +131,6 @@ function convertContourToArcs(contour) {
return newContour; return newContour;
} }
function convertShapeToArcs(shape) {
return shape.map(convertContourToArcs);
}
exports.convertContourToCubic = convertContourToCubic;
exports.convertShapeToArcs = convertShapeToArcs;
exports.BezToContoursSink = class BezToContoursSink { exports.BezToContoursSink = class BezToContoursSink {
constructor(gizmo) { constructor(gizmo) {
this.gizmo = gizmo || Transform.Id(); this.gizmo = gizmo || Transform.Id();

View file

@ -116,11 +116,6 @@ module.exports = class SpiroExpansionContext {
} }
} }
}; };
function zeroes(n) {
let a = new Array(n);
for (let i = 0; i < n; ++i) a[i] = 0;
return a;
}
function normalX(angle, contrast) { function normalX(angle, contrast) {
return Math.cos(angle) * contrast; return Math.cos(angle) * contrast;
} }