From 3fd1ebfec336e134aba59e25caa4470d1bcf381c Mon Sep 17 00:00:00 2001 From: be5invis Date: Mon, 1 Feb 2021 19:25:55 -0800 Subject: [PATCH] Refactor geometry system --- font-src/gen/finalize/glyphs.js | 45 +++-- font-src/gen/otd-conv/glyphs.js | 60 +++--- font-src/gen/otd-conv/layout.js | 24 +-- font-src/glyphs/index.ptl | 9 +- font-src/glyphs/marks/index.ptl | 2 +- font-src/glyphs/symbol/geometric/plain.ptl | 2 +- font-src/glyphs/symbol/math/apl.ptl | 2 +- font-src/kits/boole-kit.ptl | 2 +- font-src/kits/spiro-kit.ptl | 4 +- font-src/meta/macros.ptl | 2 +- font-src/support/glyph.js | 215 +++++++++++++-------- 11 files changed, 208 insertions(+), 159 deletions(-) diff --git a/font-src/gen/finalize/glyphs.js b/font-src/gen/finalize/glyphs.js index 295b529bc..e583be233 100644 --- a/font-src/gen/finalize/glyphs.js +++ b/font-src/gen/finalize/glyphs.js @@ -16,14 +16,7 @@ function finalizeGlyphs(para, glyphStore) { function suppressNaN(glyphStore) { for (const g of glyphStore.glyphs()) { - if (!g.contours) continue; - for (let k = 0; k < g.contours.length; k++) { - let contour = g.contours[k]; - for (let z of contour) { - if (!isFinite(z.x)) z.x = 0; - if (!isFinite(z.y)) z.y = 0; - } - } + if (g.geometry) g.geometry.suppressNaN(); } } @@ -31,32 +24,38 @@ function suppressNaN(glyphStore) { function regulateGlyphStore(skew, glyphStore) { for (const g of glyphStore.glyphs()) { - if (!g.semanticInclusions || !g.contours) continue; - if (g.isPureComposite()) regulateCompositeGlyph(glyphStore, g); + if (g.geometry.isEmpty()) continue; + if (!regulateCompositeGlyph(glyphStore, g)) { + const cs = g.geometry.asContours(); + g.clearGeometry(); + for (const c of cs) g.geometry.addContour(c); + } + } + for (const g of glyphStore.glyphs()) { + if (!g.geometry.asReferences()) regulateSimpleGlyph(g, skew); } - for (const g of glyphStore.glyphs()) regulateSimpleGlyph(g, skew); } /////////////////////////////////////////////////////////////////////////////////////////////////// function regulateCompositeGlyph(glyphStore, g) { - const references = []; - for (const sr of g.semanticInclusions) { + const refs = g.geometry.asReferences(); + if (!refs) return false; + for (const sr of refs) { const gn = glyphStore.queryNameOf(sr.glyph); - if (!gn || sr.glyph.autoRefPriority < 0) return; - references.push({ glyph: gn, x: sr.x, y: sr.y }); + if (!gn || sr.glyph.autoRefPriority < 0) return false; } - - g.semanticInclusions = []; - g.contours = []; - g.references = references; + return true; } function regulateSimpleGlyph(g, skew) { - if (!g.contours || !g.contours.length) return; - for (const contour of g.contours) for (const z of contour) z.x -= z.y * skew; - g.contours = simplifyContours(g.contours); - for (const contour of g.contours) for (const z of contour) z.x += z.y * skew; + let cs = g.geometry.asContours(); + for (const contour of cs) for (const z of contour) z.x -= z.y * skew; + cs = simplifyContours(cs); + for (const contour of cs) for (const z of contour) z.x += z.y * skew; + + g.clearGeometry(); + for (const c of cs) g.geometry.addContour(c); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/font-src/gen/otd-conv/glyphs.js b/font-src/gen/otd-conv/glyphs.js index bfb52eeca..7b0085e34 100644 --- a/font-src/gen/otd-conv/glyphs.js +++ b/font-src/gen/otd-conv/glyphs.js @@ -1,48 +1,58 @@ const { Ot } = require("ot-builder"); const Point = require("../../support/point"); -class NamedGlyphStore { +class MappedGlyphStore { constructor() { + this.m_nameMapping = new Map(); this.m_mapping = new Map(); } - declare(name) { + declare(name, source) { const g = new Ot.Glyph(); g.name = name; - this.m_mapping.set(name, g); + this.m_nameMapping.set(name, g); + this.m_mapping.set(source, g); } - query(name) { - return this.m_mapping.get(name); + queryBySourceGlyph(source) { + return this.m_mapping.get(source); + } + queryByName(name) { + return this.m_nameMapping.get(name); } decideOrder() { const gs = Ot.ListGlyphStoreFactory.createStoreFromList([...this.m_mapping.values()]); return gs.decideOrder(); } - fill(name, data) { - const g = this.query(name); - if (!g) return; + fill(name, source) { + const g = this.queryBySourceGlyph(source); + if (!g) throw new Error("Unreachable"); - g.horizontal = { start: 0, end: data.advanceWidth }; - if (data.references && data.references.length) { - this.fillReferences(g, data); - } else if (data.contours && data.contours.length) { - this.fillContours(g, data); + // Fill metrics + g.horizontal = { start: 0, end: source.advanceWidth }; + + // Fill Geometry + if (source.geometry.isEmpty()) return; + const rs = source.geometry.asReferences(); + if (rs) { + this.fillReferences(g, rs); + } else { + this.fillContours(g, source.geometry.asContours()); } } - fillReferences(g, data) { + fillReferences(g, rs) { const gl = new Ot.Glyph.GeometryList(); - for (const ref of data.references) { - const target = this.query(ref.glyph); - if (!target) continue; + for (const ref of rs) { + const target = this.queryBySourceGlyph(ref.glyph); + if (!target) throw new Error("Unreachable"); const tfm = Ot.Glyph.Transform2X3.Translate(ref.x, ref.y); gl.items.push(new Ot.Glyph.TtReference(target, tfm)); } g.geometry = gl; } - fillContours(g, data) { + fillContours(g, contours) { const cs = new Ot.Glyph.ContourSet(); - for (const c of data.contours) { + for (const c of contours) { const c1 = []; for (const z of c) { c1.push( @@ -67,21 +77,21 @@ function convertGlyphs(gsOrig) { .map(([j, gn, g]) => [j, gn, queryOrderingUnicode(gsOrig, g), g]) .sort(byRank); - const gs = new NamedGlyphStore(); + const gs = new MappedGlyphStore(); const cmap = new Ot.Cmap.Table(); - for (const [origIndex, name, uOrd, g] of sortedEntries) { - gs.declare(name); - const us = gsOrig.queryUnicodeOf(g); + for (const [origIndex, name, uOrd, gSrc] of sortedEntries) { + gs.declare(name, gSrc); + const us = gsOrig.queryUnicodeOf(gSrc); if (us) { for (const u of us) { if (isFinite(u - 0) && u) { - cmap.unicode.set(u, gs.query(name)); + cmap.unicode.set(u, gs.queryBySourceGlyph(gSrc)); } } } } - for (const [origIndex, name, uOrd, g] of sortedEntries) gs.fill(name, g); + for (const [origIndex, name, uOrd, gSrc] of sortedEntries) gs.fill(name, gSrc); return { glyphs: gs, cmap }; } diff --git a/font-src/gen/otd-conv/layout.js b/font-src/gen/otd-conv/layout.js index b2a13637a..62d404768 100644 --- a/font-src/gen/otd-conv/layout.js +++ b/font-src/gen/otd-conv/layout.js @@ -35,8 +35,8 @@ const GsubSingleHandler = { fill(dst, src, store) { const st = src.substitutions; for (const k in st) { - const from = store.glyphs.query(k); - const to = store.glyphs.query(st[k]); + const from = store.glyphs.queryByName(k); + const to = store.glyphs.queryByName(st[k]); if (from && to) dst.mapping.set(from, to); } } @@ -48,7 +48,7 @@ const GsubMultipleHandler = { fill(dst, src, store) { const st = src.substitutions; for (const k in st) { - const from = store.glyphs.query(k); + const from = store.glyphs.queryByName(k); const to = mapGlyphListAll(st[k], store); if (!from || !to) continue; dst.mapping.set(from, to); @@ -68,7 +68,7 @@ const GsubLigatureHandler = { fill(dst, src, store) { const st = src.substitutions; for (const { from: _from, to: _to } of st) { - const to = store.glyphs.query(_to); + const to = store.glyphs.queryByName(_to); const from = mapGlyphListAll(_from, store); if (!from || !to) continue; dst.mapping.push({ from, to }); @@ -114,7 +114,7 @@ const GsubReverseHandler = { { const m1 = new Set(); for (let k = 0; k < st.match[j].length; k++) { - const gFrom = store.glyphs.query(st.match[j][k]); + const gFrom = store.glyphs.queryByName(st.match[j][k]); if (gFrom) m1.add(gFrom); } if (!m1.size) continue out; @@ -123,8 +123,8 @@ const GsubReverseHandler = { if (j === doSubAt) { for (let k = 0; k < st.match[j].length; k++) { - const gFrom = store.glyphs.query(st.match[j][k]); - const gTo = store.glyphs.query(st.to[k]); + const gFrom = store.glyphs.queryByName(st.match[j][k]); + const gTo = store.glyphs.queryByName(st.to[k]); if (!gFrom) continue; if (gTo) { replacement.set(gFrom, gTo); @@ -142,7 +142,7 @@ const GsubReverseHandler = { function mapGlyphListAll(gl, store) { const out = []; for (const item of gl) { - const fg = store.glyphs.query(item); + const fg = store.glyphs.queryByName(item); if (!fg) return null; out.push(fg); } @@ -151,7 +151,7 @@ function mapGlyphListAll(gl, store) { function mapGlyphListSome(gl, store) { const out = []; for (const item of gl) { - const fg = store.glyphs.query(item); + const fg = store.glyphs.queryByName(item); if (!fg) continue; out.push(fg); } @@ -204,7 +204,7 @@ function convertMarkRecords(marks, mm, store) { const out = new Map(); for (const gn in marks) { const mark = marks[gn]; - const g = store.glyphs.query(gn); + const g = store.glyphs.queryByName(gn); if (!g) continue; let markAnchors = []; markAnchors[mm.get(mark.class)] = { x: mark.x, y: mark.y }; @@ -216,7 +216,7 @@ function convertBaseRecords(bases, mm, store) { const out = new Map(); for (const gn in bases) { const baseObj = bases[gn]; - const g = store.glyphs.query(gn); + const g = store.glyphs.queryByName(gn); if (!g) continue; const baseArray = []; for (const bkStr in baseObj) { @@ -319,7 +319,7 @@ function convertGdef(otdGdef, glyphs) { const gdef = new Ot.Gdef.Table(); gdef.glyphClassDef = new Map(); for (const gn in otdGdef.glyphClassDef) { - const g = glyphs.query(gn); + const g = glyphs.queryByName(gn); if (g) gdef.glyphClassDef.set(g, otdGdef.glyphClassDef[gn]); } return gdef; diff --git a/font-src/glyphs/index.ptl b/font-src/glyphs/index.ptl index b14523640..3b5cf7faf 100644 --- a/font-src/glyphs/index.ptl +++ b/font-src/glyphs/index.ptl @@ -89,14 +89,9 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin define [warnAboutBrokenGlyph g ensuredGlyphName saveGlyphName] : begin local complexity 0 - local broken false - if g.contours : begin - foreach [c : items-of g.contours] : foreach [z : items-of c] : begin - inc complexity - if [not : isFinite z.x] : set broken true - if [not : isFinite z.y] : set broken true + if g.geometry : set complexity : g.geometry.suppressNaN - if ([not recursive] && (broken || complexity > 4096)) : begin + if ([not recursive] && complexity > 4096) : begin console.log 'Possible broken shape found in' ensuredGlyphName 'Complexity' complexity console.log 'Family' para.naming.family para.naming.weight para.naming.width para.naming.slope if saveGlyphName : throw : new Error "Overcomplicated \(saveGlyphName)" diff --git a/font-src/glyphs/marks/index.ptl b/font-src/glyphs/marks/index.ptl index a2af1200f..eef8c97fc 100644 --- a/font-src/glyphs/marks/index.ptl +++ b/font-src/glyphs/marks/index.ptl @@ -221,7 +221,7 @@ glyph-block Marks : begin define cs : new BezToContoursSink ShapeConv.transferGenericShapeAsBezier {{inner outer}} cs GEOMETRY_PRECISION - currentGlyph.includeGeometry cs 0 0 + currentGlyph.includeContours cs.contours 0 0 create-glyph 'tildeAbove' 0x303 : glyph-proc set-width 0 diff --git a/font-src/glyphs/symbol/geometric/plain.ptl b/font-src/glyphs/symbol/geometric/plain.ptl index 4d318ac08..d166dcf70 100644 --- a/font-src/glyphs/symbol/geometric/plain.ptl +++ b/font-src/glyphs/symbol/geometric/plain.ptl @@ -47,7 +47,7 @@ glyph-block Symbol-Geometric-Plain : for-width-kinds WideWidth1 begin 0 local outlines : glyph-proc : begin set this.gizmo : Translate 0 0 - foreach c [items-of sh.contours] : foreach j [range 0 c.length] : begin + foreach c [items-of : sh.geometry.asContours] : foreach j [range 0 c.length] : begin local a c.[if j (j - 1) (c.length - 1)] local b c.(j) include : dispiro diff --git a/font-src/glyphs/symbol/math/apl.ptl b/font-src/glyphs/symbol/math/apl.ptl index c4e18da4c..b6d33c66a 100644 --- a/font-src/glyphs/symbol/math/apl.ptl +++ b/font-src/glyphs/symbol/math/apl.ptl @@ -21,7 +21,7 @@ glyph-block Symbol-Math-APL : begin local corners : new-glyph : glyph-proc set this.gizmo : Translate 0 0 - foreach [c : items-of overlay.contours] : foreach [z : items-of c] : do + foreach [c : items-of : overlay.geometry.asContours] : foreach [z : items-of c] : do if (z.type === Point.Type.Corner) : begin define x z.x define y z.y diff --git a/font-src/kits/boole-kit.ptl b/font-src/kits/boole-kit.ptl index 39c7e35ae..f0db02467 100644 --- a/font-src/kits/boole-kit.ptl +++ b/font-src/kits/boole-kit.ptl @@ -29,7 +29,7 @@ export : define [SetupBuilders args] : begin local g1 : new Glyph set g1.gizmo : g.gizmo || GlobalTransform g1.include p - return : CurveUtil.convertShapeToArcs g1.contours + return : CurveUtil.convertShapeToArcs : g1.geometry.asContours define union : Boole TypoGeom.Boolean.ClipType.ctUnion define intersection : Boole TypoGeom.Boolean.ClipType.ctIntersection diff --git a/font-src/kits/spiro-kit.ptl b/font-src/kits/spiro-kit.ptl index bd2788d59..022742013 100644 --- a/font-src/kits/spiro-kit.ptl +++ b/font-src/kits/spiro-kit.ptl @@ -206,14 +206,14 @@ export : define [SetupBuilders args] : begin set g.knots knots set g.lhsKnots lhs set g.rhsKnots rhs - this.includeGeometry g 0 0 + this.includeContours g.contours 0 0 return g define [spiro-outline] : let [k : {}.slice.call arguments 0] : lambda [] : begin local g : new CurveUtil.BezToContoursSink (this.gizmo || GlobalTransform) local { .knots knots .closed closed } : prepareSpiroKnots k g convertSpiroToBezier knots closed g - this.includeGeometry g 0 0 + this.includeContours g.contours 0 0 return g return [object diff --git a/font-src/meta/macros.ptl b/font-src/meta/macros.ptl index 8ea3db0ab..83db1cec3 100644 --- a/font-src/meta/macros.ptl +++ b/font-src/meta/macros.ptl @@ -70,7 +70,7 @@ define-macro set-mark-anchor : syntax-rules define-macro set-base-anchor : syntax-rules `[set-base-anchor @::args] {'.syntactic-closure' `[currentGlyph.setBaseAnchor @::args] env} define-macro eject-contour : syntax-rules - `[eject-contour @::args] {'.syntactic-closure' `[currentGlyph.ejectContour @::args] env} + `[eject-contour @::args] {'.syntactic-closure' `[currentGlyph.geometry.ejectContour @::args] env} ###### Canvas-based mechanism define-macro new-glyph : syntax-rules diff --git a/font-src/support/glyph.js b/font-src/support/glyph.js index 4ce057ba8..8fffa5c22 100644 --- a/font-src/support/glyph.js +++ b/font-src/support/glyph.js @@ -4,19 +4,122 @@ const Transform = require("./transform"); const Point = require("./point"); const Anchor = require("./anchor"); +class GeometryStore { + constructor() { + this.m_contours = []; + this.m_references = []; + } + + addContour(c) { + this.m_contours.push(c); + } + addReference(glyph, x, y) { + this.m_references.push({ glyph, x, y }); + } + asContours() { + let result = []; + for (const c of this.m_contours) { + const c1 = [...c]; + if (c.tag) c1.tag = c.tag; + 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; + } + asReferences() { + if (this.m_contours && this.m_contours.length) return null; + if (!this.m_references.length) return null; + return this.m_references; + } + + applyTranslate(shiftX, shiftY) { + for (const c of this.m_contours) { + for (let k = 0; k < c.length; k++) { + c[k] = Point.translated(c[k], shiftX, shiftY); + } + } + for (const r of this.m_references) { + r.x += shiftX; + r.y += shiftY; + } + } + applyTransform(tfm) { + const cs = this.asContours(); + 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() { + return !this.m_contours.length && !this.m_references.length; + } +} + module.exports = class Glyph { constructor(_identifier) { this._m_identifier = _identifier; - this.contours = []; + this.geometry = new GeometryStore(); this.advanceWidth = 500; this.autoRefPriority = 0; this.markAnchors = {}; this.baseAnchors = {}; this.gizmo = Transform.Id(); - this.semanticInclusions = []; this.dependencies = []; this.defaultTag = null; } + + get contours() { + throw new TypeError("Glyph::contours has been deprecated"); + } + get semanticInclusions() { + throw new TypeError("Glyph::semanticInclusions has been deprecated"); + } + get name() { throw new TypeError("Glyph::name has been deprecated"); } @@ -40,20 +143,6 @@ module.exports = class Glyph { if (glyph._m_identifier) this.dependencies.push(glyph._m_identifier); if (glyph.dependencies) for (const dep of glyph.dependencies) this.dependencies.push(dep); } - // Contour Tagging - reTagContour(oldTag, newTag) { - for (const c of this.contours) if (c.tag === oldTag) c.tag = newTag; - } - ejectContour(tag) { - let i = 0, - j = 0; - for (; i < this.contours.length; i++) { - if (!this.contours[i].tag || this.contours[i].tag !== tag) - this.contours[j++] = this.contours[i]; - } - this.contours.length = j; - this.semanticInclusions = []; - } // Inclusion include(component, copyAnchors, copyWidth) { if (!component) { @@ -105,56 +194,26 @@ module.exports = class Glyph { this.avoidBeingComposite = g.avoidBeingComposite; } - isPureComposite() { - if (!this.semanticInclusions || !this.semanticInclusions.length) return false; - const origContourSet = new Set(this.contours); - let handledContours = new Set(); - for (const sr of this.semanticInclusions) { - for (const c of sr.contours) { - if (!origContourSet.has(c) || handledContours.has(c)) return false; - handledContours.add(c); - } - } - for (const c of this.contours) if (!handledContours.has(c)) return false; - return true; - } - includeGlyphImpl(g, shiftX, shiftY) { if (g._m_identifier) { - this.includeGlyphComponentImpl(g, shiftX, shiftY); - } else if (!g._m_identifier && g.isPureComposite()) { - for (const sr of g.semanticInclusions) - this.includeGlyphComponentImpl(sr.glyph, sr.x + shiftX, sr.y + shiftY); + if (!g.geometry.isEmpty()) this.geometry.addReference(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 { - this.includeGeometry(g, shiftX, shiftY); - } - } - includeGlyphComponentImpl(g, shiftX, shiftY) { - const newContours = this.includeGeometry(g, shiftX, shiftY); - if (newContours && newContours.length) { - this.semanticInclusions.push({ - glyph: g, - x: shiftX, - y: shiftY, - contours: newContours - }); + this.includeContours(g.geometry.asContours(), shiftX, shiftY); } } - includeGeometry(geom, shiftX, shiftY) { - if (!geom || !geom.contours || !geom.contours.length) return null; - return this.includeContours(geom.contours, shiftX, shiftY); - } - includeContours(contours, shiftX, shiftY) { - let newContours = []; - for (const contour of contours) { + includeContours(cs, shiftX, shiftY) { + for (const contour of cs) { let c = []; - c.tag = contour.tag || contours.tag || this.defaultTag; + c.tag = contour.tag || cs.tag || this.defaultTag; for (const z of contour) c.push(Point.translated(z, shiftX, shiftY)); - this.contours.push(c); - newContours.push(c); + this.geometry.addContour(c); } - return newContours; } combineAnchor(shift, baseThis, markThat, basesThat) { @@ -175,19 +234,10 @@ module.exports = class Glyph { if (g.baseAnchors) for (const k in g.baseAnchors) this.baseAnchors[k] = g.baseAnchors[k]; } applyTransform(tfm, alsoAnchors) { - for (const c of this.contours) { - for (let k = 0; k < c.length; k++) { - c[k] = Point.transformed(tfm, c[k]); - } - } if (Transform.isTranslate(tfm)) { - for (const sr of this.semanticInclusions) { - sr.x += tfm.x; - sr.y += tfm.y; - } + this.geometry.applyTranslate(tfm.x, tfm.y); } else { - // Applying a non-trivial inclusion will unlink all the SIs - this.semanticInclusions = []; + this.geometry.applyTransform(tfm); } if (alsoAnchors) { for (const k in this.baseAnchors) @@ -199,34 +249,29 @@ module.exports = class Glyph { tryBecomeMirrorOf(dst, rankSet) { if (rankSet.has(this) || rankSet.has(dst)) return; - if (this.contours.length !== dst.contours.length) return; - for (let j = 0; j < this.contours.length; j++) { - const c1 = this.contours[j], - c2 = dst.contours[j]; + const csThis = this.geometry.asContours(); + const csDst = dst.geometry.asContours(); + if (csThis.length !== csDst.length) return; + for (let j = 0; j < csThis.length; j++) { + const c1 = csThis[j], + c2 = csDst[j]; if (c1.length !== c2.length) return; } - for (let j = 0; j < this.contours.length; j++) { - const c1 = this.contours[j], - c2 = dst.contours[j]; + for (let j = 0; j < csThis.length; j++) { + const c1 = csThis[j], + c2 = csDst[j]; for (let k = 0; k < c1.length; k++) { const z1 = c1[k], z2 = c2[k]; if (z1.x !== z2.x || z1.y !== z2.y || z1.type !== z2.type) return; } } - this.semanticInclusions = [ - { - glyph: dst, - x: 0, - y: 0, - contours: [...this.contours] - } - ]; + this.geometry = new GeometryStore(); + this.geometry.addReference(dst, 0, 0); rankSet.add(this); } clearGeometry() { - this.contours = []; - this.semanticInclusions = []; + this.geometry = new GeometryStore(); } // Anchors