Move boolean composition out of kits.
This commit is contained in:
parent
4cf5faf93c
commit
3ef9aaa2e2
7 changed files with 103 additions and 42 deletions
|
@ -4,6 +4,7 @@ const TypoGeom = require("typo-geom");
|
|||
const Point = require("./point");
|
||||
const Transform = require("./transform");
|
||||
|
||||
exports.SPIRO_PRECISION = 1 / 2;
|
||||
exports.GEOMETRY_PRECISION = 1 / 4;
|
||||
exports.RECIP_GEOMETRY_PRECISION = 4;
|
||||
exports.BOOLE_RESOLUTION = 0x4000;
|
||||
|
@ -34,6 +35,18 @@ exports.OffsetCurve = class OffsetCurve {
|
|||
}
|
||||
};
|
||||
|
||||
exports.ReverseCurve = class ReverseCurve {
|
||||
constructor(original) {
|
||||
this.m_original = original;
|
||||
}
|
||||
eval(t) {
|
||||
return this.m_original.eval(1 - t);
|
||||
}
|
||||
derivative(t) {
|
||||
return -this.m_original.derivative(1 - t);
|
||||
}
|
||||
};
|
||||
|
||||
exports.convertShapeToArcs = function convertShapeToArcs(shape) {
|
||||
return shape.map(convertContourToArcs);
|
||||
};
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
const Point = require("./point");
|
||||
const Transform = require("./transform");
|
||||
const CurveUtil = require("./curve-util");
|
||||
const TypoGeom = require("typo-geom");
|
||||
|
||||
class GeometryBase {
|
||||
asContours() {
|
||||
|
@ -132,7 +134,9 @@ class TransformedGeometry extends GeometryBase {
|
|||
return result;
|
||||
}
|
||||
filterTag(fn) {
|
||||
return new TransformedGeometry(this.m_geom.filterTag(fn), this.m_transform);
|
||||
const e = this.m_geom.filterTag(fn);
|
||||
if (!e) return null;
|
||||
return new TransformedGeometry(e, this.m_transform);
|
||||
}
|
||||
isEmpty() {
|
||||
return this.m_geom.isEmpty();
|
||||
|
@ -192,6 +196,62 @@ class CombineGeometry extends GeometryBase {
|
|||
}
|
||||
}
|
||||
|
||||
class BooleanGeometry extends GeometryBase {
|
||||
constructor(operator, operands) {
|
||||
super();
|
||||
this.m_operator = operator;
|
||||
this.m_operands = operands;
|
||||
this.m_resolved = null;
|
||||
}
|
||||
asContours() {
|
||||
if (this.m_resolved) return this.m_resolved;
|
||||
this.m_resolved = this.asContoursImpl();
|
||||
return this.m_resolved;
|
||||
}
|
||||
asContoursImpl() {
|
||||
let arcs = CurveUtil.convertShapeToArcs(this.m_operands[0].asContours());
|
||||
if (this.m_operands.length < 2) {
|
||||
arcs = TypoGeom.Boolean.removeOverlap(
|
||||
arcs,
|
||||
TypoGeom.Boolean.PolyFillType.pftNonZero,
|
||||
CurveUtil.BOOLE_RESOLUTION
|
||||
);
|
||||
}
|
||||
for (let j = 1; j < this.m_operands.length; j++) {
|
||||
arcs = TypoGeom.Boolean.combine(
|
||||
this.m_operator,
|
||||
arcs,
|
||||
CurveUtil.convertShapeToArcs(this.m_operands[j].asContours()),
|
||||
TypoGeom.Boolean.PolyFillType.pftNonZero,
|
||||
TypoGeom.Boolean.PolyFillType.pftNonZero,
|
||||
CurveUtil.BOOLE_RESOLUTION
|
||||
);
|
||||
}
|
||||
const ctx = new CurveUtil.BezToContoursSink();
|
||||
TypoGeom.ShapeConv.transferBezArcShape(arcs, ctx);
|
||||
return ctx.contours;
|
||||
}
|
||||
asReferences() {
|
||||
return null;
|
||||
}
|
||||
filterTag(fn) {
|
||||
let filtered = [];
|
||||
for (const operand of this.m_operands) {
|
||||
const fp = operand.filterTag(fn);
|
||||
if (fp) filtered.push(fp);
|
||||
}
|
||||
return new BooleanGeometry(this.m_operator, filtered);
|
||||
}
|
||||
isEmpty() {
|
||||
for (const operand of this.m_operands) if (!operand.isEmpty()) return false;
|
||||
return true;
|
||||
}
|
||||
measureComplexity() {
|
||||
let s = 0;
|
||||
for (const operand of this.m_operands) s += operand.measureComplexity();
|
||||
}
|
||||
}
|
||||
|
||||
function combineWith(a, b) {
|
||||
if (a instanceof CombineGeometry) {
|
||||
return a.with(b);
|
||||
|
@ -206,5 +266,6 @@ exports.ReferenceGeometry = ReferenceGeometry;
|
|||
exports.TaggedGeometry = TaggedGeometry;
|
||||
exports.TransformedGeometry = TransformedGeometry;
|
||||
exports.CombineGeometry = CombineGeometry;
|
||||
exports.BooleanGeometry = BooleanGeometry;
|
||||
|
||||
exports.combineWith = combineWith;
|
||||
|
|
|
@ -95,15 +95,15 @@ module.exports = class Glyph {
|
|||
this.avoidBeingComposite = g.avoidBeingComposite;
|
||||
}
|
||||
|
||||
combineGeometryImpl(g) {
|
||||
includeGeometry(g) {
|
||||
if (this.ctxTag) g = new Geom.TaggedGeometry(g, this.ctxTag);
|
||||
this.geometry = Geom.combineWith(this.geometry, g);
|
||||
}
|
||||
includeGlyphImpl(g, shiftX, shiftY) {
|
||||
if (g._m_identifier) {
|
||||
this.combineGeometryImpl(new Geom.ReferenceGeometry(g, shiftX, shiftY));
|
||||
this.includeGeometry(new Geom.ReferenceGeometry(g, shiftX, shiftY));
|
||||
} else {
|
||||
this.combineGeometryImpl(
|
||||
this.includeGeometry(
|
||||
new Geom.TransformedGeometry(g.geometry, Transform.Translate(shiftX, shiftY))
|
||||
);
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ module.exports = class Glyph {
|
|||
for (const z of contour) c.push(Point.translated(z, shiftX, shiftY));
|
||||
parts.push(new Geom.ContourGeometry(c));
|
||||
}
|
||||
this.combineGeometryImpl(new Geom.CombineGeometry(parts));
|
||||
this.includeGeometry(new Geom.CombineGeometry(parts));
|
||||
}
|
||||
|
||||
applyTransform(tfm, alsoAnchors) {
|
||||
|
|
|
@ -53,6 +53,10 @@ module.exports = class SpiroExpansionContext {
|
|||
const k0 = this.controlKnots[this.controlKnots.length - 1];
|
||||
if (k0) k0.type = type;
|
||||
}
|
||||
setUnimportant() {
|
||||
const k0 = this.controlKnots[this.controlKnots.length - 1];
|
||||
if (k0) k0.unimportant = true;
|
||||
}
|
||||
expand(contrast) {
|
||||
if (contrast == null) contrast = 1 / 0.9;
|
||||
const lhs = [],
|
||||
|
@ -100,6 +104,7 @@ module.exports = class SpiroExpansionContext {
|
|||
rhsAfter = this.gizmo.unapply(rhs[jAfter]);
|
||||
|
||||
lhs[j] = {
|
||||
unimportant: true,
|
||||
type: knot.type,
|
||||
...this.gizmo.apply({
|
||||
x: linreg(knotBefore.x, lhsBefore.x, knotAfter.x, lhsAfter.x, ref.x),
|
||||
|
@ -107,6 +112,7 @@ module.exports = class SpiroExpansionContext {
|
|||
})
|
||||
};
|
||||
rhs[j] = {
|
||||
unimportant: true,
|
||||
type: reverseKnotType(knot.type),
|
||||
...this.gizmo.apply({
|
||||
x: linreg(knotBefore.x, rhsBefore.x, knotAfter.x, rhsAfter.x, ref.x),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue