Refactor into geometry tree
This commit is contained in:
parent
f17710b0a4
commit
a81c477fab
6 changed files with 207 additions and 121 deletions
|
@ -3,6 +3,7 @@
|
||||||
const TypoGeom = require("typo-geom");
|
const TypoGeom = require("typo-geom");
|
||||||
const Point = require("../../support/point");
|
const Point = require("../../support/point");
|
||||||
const CurveUtil = require("../../support/curve-util");
|
const CurveUtil = require("../../support/curve-util");
|
||||||
|
const util = require("util");
|
||||||
|
|
||||||
module.exports = finalizeGlyphs;
|
module.exports = finalizeGlyphs;
|
||||||
function finalizeGlyphs(para, glyphStore) {
|
function finalizeGlyphs(para, glyphStore) {
|
||||||
|
@ -16,7 +17,7 @@ function finalizeGlyphs(para, glyphStore) {
|
||||||
|
|
||||||
function suppressNaN(glyphStore) {
|
function suppressNaN(glyphStore) {
|
||||||
for (const g of glyphStore.glyphs()) {
|
for (const g of glyphStore.glyphs()) {
|
||||||
if (g.geometry) g.geometry.suppressNaN();
|
// if (g.geometry) g.geometry.suppressNaN();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ function regulateGlyphStore(skew, glyphStore) {
|
||||||
if (!regulateCompositeGlyph(glyphStore, g)) {
|
if (!regulateCompositeGlyph(glyphStore, g)) {
|
||||||
const cs = g.geometry.asContours();
|
const cs = g.geometry.asContours();
|
||||||
g.clearGeometry();
|
g.clearGeometry();
|
||||||
for (const c of cs) g.geometry.addContour(c);
|
g.includeContours(cs, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const g of glyphStore.glyphs()) {
|
for (const g of glyphStore.glyphs()) {
|
||||||
|
@ -55,7 +56,7 @@ function regulateSimpleGlyph(g, skew) {
|
||||||
for (const contour of cs) for (const z of contour) z.x += z.y * skew;
|
for (const contour of cs) for (const z of contour) z.x += z.y * skew;
|
||||||
|
|
||||||
g.clearGeometry();
|
g.clearGeometry();
|
||||||
for (const c of cs) g.geometry.addContour(c);
|
g.includeContours(cs, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -21,11 +21,6 @@ define [$NamedParameterPair$ l r] : begin
|
||||||
|
|
||||||
define [$donothing$] nothing
|
define [$donothing$] nothing
|
||||||
|
|
||||||
# contour tagging
|
|
||||||
define [tagged tag component] : begin
|
|
||||||
set component.tag tag
|
|
||||||
return component
|
|
||||||
|
|
||||||
export all : define [buildGlyphs para recursive recursiveCodes] : begin
|
export all : define [buildGlyphs para recursive recursiveCodes] : begin
|
||||||
local glyphStore : new GlyphStore
|
local glyphStore : new GlyphStore
|
||||||
|
|
||||||
|
@ -89,7 +84,7 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin
|
||||||
|
|
||||||
define [warnAboutBrokenGlyph g ensuredGlyphName saveGlyphName] : begin
|
define [warnAboutBrokenGlyph g ensuredGlyphName saveGlyphName] : begin
|
||||||
local complexity 0
|
local complexity 0
|
||||||
if g.geometry : set complexity : g.geometry.suppressNaN
|
# if g.geometry : set complexity : g.geometry.suppressNaN
|
||||||
|
|
||||||
if ([not recursive] && complexity > 4096) : begin
|
if ([not recursive] && complexity > 4096) : begin
|
||||||
console.log 'Possible broken shape found in' ensuredGlyphName 'Complexity' complexity
|
console.log 'Possible broken shape found in' ensuredGlyphName 'Complexity' complexity
|
||||||
|
@ -113,6 +108,14 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin
|
||||||
define spirofns : spirokit.SetupBuilders : object GlobalTransform Contrast Stroke Glyph para [superness DesignParameters.superness]
|
define spirofns : spirokit.SetupBuilders : object GlobalTransform Contrast Stroke Glyph para [superness DesignParameters.superness]
|
||||||
define booleFns : BooleKit.SetupBuilders : object GlobalTransform Glyph
|
define booleFns : BooleKit.SetupBuilders : object GlobalTransform Glyph
|
||||||
|
|
||||||
|
# Meta
|
||||||
|
define [tagged tag component] : function [ca cw] : begin
|
||||||
|
define t this.ctxTag
|
||||||
|
set this.ctxTag tag
|
||||||
|
define ret : this.include component ca cw
|
||||||
|
set this.ctxTag t
|
||||||
|
return ret
|
||||||
|
|
||||||
# IDKY, but wrapping "metrics" prevents Node.js on Arch modifying it.
|
# IDKY, but wrapping "metrics" prevents Node.js on Arch modifying it.
|
||||||
define $$Capture$$ : object [metrics : Object.create metrics] $NamedParameterPair$ $donothing$ para recursive recursiveCodes glyphStore $createAndSaveGlyphImpl$ spirofns booleFns MarkSet AS_BASE ALSO_METRICS pickHash buildGlyphs tagged DivFrame fontMetrics $assignUnicodeImpl$ $defineGlyphBlockImpl$
|
define $$Capture$$ : object [metrics : Object.create metrics] $NamedParameterPair$ $donothing$ para recursive recursiveCodes glyphStore $createAndSaveGlyphImpl$ spirofns booleFns MarkSet AS_BASE ALSO_METRICS pickHash buildGlyphs tagged DivFrame fontMetrics $assignUnicodeImpl$ $defineGlyphBlockImpl$
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ define-macro set-mark-anchor : syntax-rules
|
||||||
define-macro set-base-anchor : syntax-rules
|
define-macro set-base-anchor : syntax-rules
|
||||||
`[set-base-anchor @::args] {'.syntactic-closure' `[currentGlyph.setBaseAnchor @::args] env}
|
`[set-base-anchor @::args] {'.syntactic-closure' `[currentGlyph.setBaseAnchor @::args] env}
|
||||||
define-macro eject-contour : syntax-rules
|
define-macro eject-contour : syntax-rules
|
||||||
`[eject-contour @::args] {'.syntactic-closure' `[currentGlyph.geometry.ejectContour @::args] env}
|
`[eject-contour @::args] {'.syntactic-closure' `[currentGlyph.ejectTagged @::args] env}
|
||||||
|
|
||||||
###### Canvas-based mechanism
|
###### Canvas-based mechanism
|
||||||
define-macro new-glyph : syntax-rules
|
define-macro new-glyph : syntax-rules
|
||||||
|
|
|
@ -1,107 +1,188 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const Transform = require("./transform");
|
|
||||||
const Point = require("./point");
|
const Point = require("./point");
|
||||||
const Anchor = require("./anchor");
|
const Transform = require("./transform");
|
||||||
|
|
||||||
module.exports = class GeometryStore {
|
class GeometryBase {
|
||||||
constructor() {
|
asContours() {
|
||||||
this.m_contours = [];
|
throw new Error("Unimplemented");
|
||||||
this.m_references = [];
|
|
||||||
}
|
}
|
||||||
|
asReferences() {
|
||||||
|
throw new Error("Unimplemented");
|
||||||
|
}
|
||||||
|
filterTag(fn) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
isEmpty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addContour(c, tag) {
|
class ContourGeometry extends GeometryBase {
|
||||||
if (tag) {
|
constructor(points) {
|
||||||
const zs = [...c];
|
super();
|
||||||
zs.tag = tag;
|
this.m_points = points;
|
||||||
this.m_contours.push(zs);
|
|
||||||
} else {
|
|
||||||
this.m_contours.push(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
addReference(glyph, x, y) {
|
asContours() {
|
||||||
this.m_references.push({ glyph, x, y });
|
if (this.isEmpty()) return [];
|
||||||
|
else return [this.m_points];
|
||||||
|
}
|
||||||
|
asReferences() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
filterTag(fn) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
isEmpty() {
|
||||||
|
return !this.m_points.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReferenceGeometry extends GeometryBase {
|
||||||
|
constructor(glyph, x, y) {
|
||||||
|
super();
|
||||||
|
if (!glyph || !glyph.geometry) throw new TypeError("Invalid glyph");
|
||||||
|
this.m_glyph = glyph;
|
||||||
|
this.m_x = x;
|
||||||
|
this.m_y = y;
|
||||||
|
}
|
||||||
|
unwrap() {
|
||||||
|
return new TransformedGeometry(
|
||||||
|
this.m_glyph.geometry,
|
||||||
|
Transform.Translate(this.m_x, this.m_y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
asContours() {
|
||||||
|
if (this.isEmpty()) return [];
|
||||||
|
return this.unwrap().asContours();
|
||||||
|
}
|
||||||
|
asReferences() {
|
||||||
|
if (this.isEmpty()) return [];
|
||||||
|
return [{ glyph: this.m_glyph, x: this.m_x, y: this.m_y }];
|
||||||
|
}
|
||||||
|
filterTag(fn) {
|
||||||
|
if (this.isEmpty()) return null;
|
||||||
|
return this.unwrap().filterTag(fn);
|
||||||
|
}
|
||||||
|
isEmpty() {
|
||||||
|
if (!this.m_glyph || !this.m_glyph.geometry) return true;
|
||||||
|
return this.m_glyph.geometry.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TaggedGeometry extends GeometryBase {
|
||||||
|
constructor(g, tag) {
|
||||||
|
super();
|
||||||
|
this.m_geom = g;
|
||||||
|
this.m_tag = tag;
|
||||||
|
}
|
||||||
|
asContours() {
|
||||||
|
return this.m_geom.asContours();
|
||||||
|
}
|
||||||
|
asReferences() {
|
||||||
|
return this.m_geom.asReferences();
|
||||||
|
}
|
||||||
|
filterTag(fn) {
|
||||||
|
if (!fn(this.m_tag)) return null;
|
||||||
|
else return new TaggedGeometry(this.m_geom.filterTag(fn), this.m_tag);
|
||||||
|
}
|
||||||
|
isEmpty() {
|
||||||
|
return this.m_geom.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransformedGeometry extends GeometryBase {
|
||||||
|
constructor(g, tfm) {
|
||||||
|
super();
|
||||||
|
this.m_geom = g;
|
||||||
|
this.m_transform = tfm;
|
||||||
}
|
}
|
||||||
asContours() {
|
asContours() {
|
||||||
let result = [];
|
let result = [];
|
||||||
for (const c of this.m_contours) {
|
for (const c of this.m_geom.asContours()) {
|
||||||
const c1 = [...c];
|
let c1 = [];
|
||||||
if (c.tag) c1.tag = c.tag;
|
for (const z of c) c1.push(Point.transformed(this.m_transform, z));
|
||||||
result.push(c1);
|
result.push(c1);
|
||||||
}
|
}
|
||||||
for (const r of this.m_references) {
|
|
||||||
for (const c of r.glyph.geometry.asContours()) {
|
|
||||||
let c1 = [];
|
|
||||||
for (const z of c) c1.push(Point.fromXY(z.type, z.x + r.x, z.y + r.y));
|
|
||||||
if (c.tag) c1.tag = c.tag;
|
|
||||||
result.push(c1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
asReferences() {
|
asReferences() {
|
||||||
if (this.m_contours && this.m_contours.length) return null;
|
if (!Transform.isTranslate(this.m_transform)) return null;
|
||||||
if (!this.m_references.length) return null;
|
const rs = this.m_geom.asReferences();
|
||||||
return this.m_references;
|
if (!rs) return null;
|
||||||
}
|
|
||||||
|
|
||||||
applyTranslate(shiftX, shiftY) {
|
let result = [];
|
||||||
for (const c of this.m_contours) {
|
for (const { glyph, x, y } of rs)
|
||||||
for (let k = 0; k < c.length; k++) {
|
result.push({ glyph, x: x + this.m_transform.x, y: y + this.m_transform.y });
|
||||||
c[k] = Point.translated(c[k], shiftX, shiftY);
|
return result;
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const r of this.m_references) {
|
|
||||||
r.x += shiftX;
|
|
||||||
r.y += shiftY;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
applyTransform(tfm) {
|
filterTag(fn) {
|
||||||
const cs = this.asContours();
|
return new TransformedGeometry(this.m_geom.filterTag(fn), this.m_transform);
|
||||||
for (const c of cs) {
|
|
||||||
for (let k = 0; k < c.length; k++) {
|
|
||||||
c[k] = Point.transformed(tfm, c[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.m_contours = cs;
|
|
||||||
this.m_references.length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reTagContour(oldTag, newTag) {
|
|
||||||
for (const c of this.m_contours) {
|
|
||||||
if (c.tag === oldTag) c.tag = newTag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ejectContour(tag) {
|
|
||||||
const cs = this.asContours();
|
|
||||||
let i = 0,
|
|
||||||
j = 0;
|
|
||||||
for (; i < cs.length; i++) if (!cs[i].tag || cs[i].tag !== tag) cs[j++] = cs[i];
|
|
||||||
cs.length = j;
|
|
||||||
this.m_contours = cs;
|
|
||||||
this.m_references = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
suppressNaN() {
|
|
||||||
let broken = false,
|
|
||||||
complexity = 0;
|
|
||||||
for (const c of this.m_contours) {
|
|
||||||
for (const z of c) {
|
|
||||||
complexity++;
|
|
||||||
if (!isFinite(z.x)) {
|
|
||||||
broken = true;
|
|
||||||
z.x = 0;
|
|
||||||
}
|
|
||||||
if (!isFinite(z.y)) {
|
|
||||||
broken = true;
|
|
||||||
z.y = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return broken ? 0xffff : complexity;
|
|
||||||
}
|
|
||||||
|
|
||||||
isEmpty() {
|
isEmpty() {
|
||||||
return !this.m_contours.length && !this.m_references.length;
|
return this.m_geom.isEmpty();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
class CombineGeometry extends GeometryBase {
|
||||||
|
constructor(parts) {
|
||||||
|
super();
|
||||||
|
this.m_parts = parts || [];
|
||||||
|
}
|
||||||
|
with(g) {
|
||||||
|
if (g instanceof CombineGeometry) {
|
||||||
|
return new CombineGeometry([...this.m_parts, ...g.m_parts]);
|
||||||
|
} else {
|
||||||
|
return new CombineGeometry([...this.m_parts, g]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
asContours() {
|
||||||
|
let results = [];
|
||||||
|
for (const part of this.m_parts) {
|
||||||
|
for (const c of part.asContours()) {
|
||||||
|
results.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
asReferences() {
|
||||||
|
let results = [];
|
||||||
|
for (const part of this.m_parts) {
|
||||||
|
const rs = part.asReferences();
|
||||||
|
if (!rs) return null;
|
||||||
|
for (const c of rs) {
|
||||||
|
results.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
filterTag(fn) {
|
||||||
|
let filtered = [];
|
||||||
|
for (const part of this.m_parts) {
|
||||||
|
const fp = part.filterTag(fn);
|
||||||
|
if (fp) filtered.push(fp);
|
||||||
|
}
|
||||||
|
return new CombineGeometry(filtered);
|
||||||
|
}
|
||||||
|
isEmpty() {
|
||||||
|
for (const part of this.m_parts) if (!part.isEmpty()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function combineWith(a, b) {
|
||||||
|
if (a instanceof CombineGeometry) {
|
||||||
|
return a.with(b);
|
||||||
|
} else {
|
||||||
|
return new CombineGeometry([a, b]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.GeometryBase = GeometryBase;
|
||||||
|
exports.ContourGeometry = ContourGeometry;
|
||||||
|
exports.ReferenceGeometry = ReferenceGeometry;
|
||||||
|
exports.TaggedGeometry = TaggedGeometry;
|
||||||
|
exports.TransformedGeometry = TransformedGeometry;
|
||||||
|
exports.CombineGeometry = CombineGeometry;
|
||||||
|
|
||||||
|
exports.combineWith = combineWith;
|
||||||
|
|
|
@ -3,19 +3,19 @@
|
||||||
const Transform = require("./transform");
|
const Transform = require("./transform");
|
||||||
const Point = require("./point");
|
const Point = require("./point");
|
||||||
const Anchor = require("./anchor");
|
const Anchor = require("./anchor");
|
||||||
const GeometryStore = require("./geometry");
|
const Geom = require("./geometry");
|
||||||
|
|
||||||
module.exports = class Glyph {
|
module.exports = class Glyph {
|
||||||
constructor(_identifier) {
|
constructor(_identifier) {
|
||||||
this._m_identifier = _identifier;
|
this._m_identifier = _identifier;
|
||||||
this.geometry = new GeometryStore();
|
this.geometry = new Geom.CombineGeometry();
|
||||||
this.advanceWidth = 500;
|
this.advanceWidth = 500;
|
||||||
this.autoRefPriority = 0;
|
this.autoRefPriority = 0;
|
||||||
this.markAnchors = {};
|
this.markAnchors = {};
|
||||||
this.baseAnchors = {};
|
this.baseAnchors = {};
|
||||||
this.gizmo = Transform.Id();
|
this.gizmo = Transform.Id();
|
||||||
this.dependencies = [];
|
this.dependencies = [];
|
||||||
this.defaultTag = null;
|
this.ctxTag = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get contours() {
|
get contours() {
|
||||||
|
@ -53,11 +53,7 @@ module.exports = class Glyph {
|
||||||
if (!component) {
|
if (!component) {
|
||||||
throw new Error("Unreachable: Attempt to include a Null or Undefined");
|
throw new Error("Unreachable: Attempt to include a Null or Undefined");
|
||||||
} else if (component instanceof Function) {
|
} else if (component instanceof Function) {
|
||||||
const t = this.defaultTag;
|
return component.call(this, copyAnchors, copyWidth);
|
||||||
if (component.tag) this.defaultTag = component.tag;
|
|
||||||
let ret = component.call(this, copyAnchors, copyWidth);
|
|
||||||
this.defaultTag = t;
|
|
||||||
return ret;
|
|
||||||
} else if (component instanceof Transform) {
|
} else if (component instanceof Transform) {
|
||||||
return this.applyTransform(component, copyAnchors);
|
return this.applyTransform(component, copyAnchors);
|
||||||
} else if (component.isMarkSet) {
|
} else if (component.isMarkSet) {
|
||||||
|
@ -99,33 +95,32 @@ module.exports = class Glyph {
|
||||||
this.avoidBeingComposite = g.avoidBeingComposite;
|
this.avoidBeingComposite = g.avoidBeingComposite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
combineGeometryImpl(g) {
|
||||||
|
if (this.ctxTag) g = new Geom.TaggedGeometry(g, this.ctxTag);
|
||||||
|
this.geometry = Geom.combineWith(this.geometry, g);
|
||||||
|
}
|
||||||
includeGlyphImpl(g, shiftX, shiftY) {
|
includeGlyphImpl(g, shiftX, shiftY) {
|
||||||
if (g._m_identifier) {
|
if (g._m_identifier) {
|
||||||
if (!g.geometry.isEmpty()) this.geometry.addReference(g, shiftX, shiftY);
|
this.combineGeometryImpl(new Geom.ReferenceGeometry(g, shiftX, shiftY));
|
||||||
} else if (!g._m_identifier && g.geometry.asReferences()) {
|
|
||||||
for (const sr of g.geometry.asReferences()) {
|
|
||||||
if (!sr.glyph.geometry.isEmpty())
|
|
||||||
this.geometry.addReference(sr.glyph, sr.x + shiftX, sr.y + shiftY);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.includeContours(g.geometry.asContours(), shiftX, shiftY);
|
this.combineGeometryImpl(
|
||||||
|
new Geom.TransformedGeometry(g.geometry, Transform.Translate(shiftX, shiftY))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
includeContours(cs, shiftX, shiftY) {
|
includeContours(cs, shiftX, shiftY) {
|
||||||
|
let parts = [];
|
||||||
for (const contour of cs) {
|
for (const contour of cs) {
|
||||||
let c = [];
|
let c = [];
|
||||||
for (const z of contour) c.push(Point.translated(z, shiftX, shiftY));
|
for (const z of contour) c.push(Point.translated(z, shiftX, shiftY));
|
||||||
this.geometry.addContour(c, contour.tag || cs.tag || this.defaultTag);
|
parts.push(new Geom.ContourGeometry(c));
|
||||||
}
|
}
|
||||||
|
this.combineGeometryImpl(new Geom.CombineGeometry(parts));
|
||||||
}
|
}
|
||||||
|
|
||||||
applyTransform(tfm, alsoAnchors) {
|
applyTransform(tfm, alsoAnchors) {
|
||||||
if (Transform.isTranslate(tfm)) {
|
this.geometry = new Geom.TransformedGeometry(this.geometry, tfm);
|
||||||
this.geometry.applyTranslate(tfm.x, tfm.y);
|
|
||||||
} else {
|
|
||||||
this.geometry.applyTransform(tfm);
|
|
||||||
}
|
|
||||||
if (alsoAnchors) {
|
if (alsoAnchors) {
|
||||||
for (const k in this.baseAnchors)
|
for (const k in this.baseAnchors)
|
||||||
this.baseAnchors[k] = Anchor.transform(tfm, this.baseAnchors[k]);
|
this.baseAnchors[k] = Anchor.transform(tfm, this.baseAnchors[k]);
|
||||||
|
@ -153,12 +148,14 @@ module.exports = class Glyph {
|
||||||
if (z1.x !== z2.x || z1.y !== z2.y || z1.type !== z2.type) return;
|
if (z1.x !== z2.x || z1.y !== z2.y || z1.type !== z2.type) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.geometry = new GeometryStore();
|
this.geometry = new Geom.CombineGeometry([new Geom.ReferenceGeometry(dst, 0, 0)]);
|
||||||
this.geometry.addReference(dst, 0, 0);
|
|
||||||
rankSet.add(this);
|
rankSet.add(this);
|
||||||
}
|
}
|
||||||
clearGeometry() {
|
clearGeometry() {
|
||||||
this.geometry = new GeometryStore();
|
this.geometry = new Geom.CombineGeometry();
|
||||||
|
}
|
||||||
|
ejectTagged(tag) {
|
||||||
|
this.geometry = this.geometry.filterTag(t => tag !== t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anchors
|
// Anchors
|
||||||
|
|
|
@ -14,6 +14,10 @@ module.exports = class Transform {
|
||||||
return new Transform(1, 0, 0, 1, 0, 0);
|
return new Transform(1, 0, 0, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Translate(x, y) {
|
||||||
|
return new Transform(1, 0, 0, 1, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
apply(pt) {
|
apply(pt) {
|
||||||
return {
|
return {
|
||||||
x: pt.x * this.xx + pt.y * this.yx + this.x,
|
x: pt.x * this.xx + pt.y * this.yx + this.x,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue