diff --git a/gen/build-glyphs.ptl b/gen/build-glyphs.ptl index 085cf0bdb..e6f3a57c4 100644 --- a/gen/build-glyphs.ptl +++ b/gen/build-glyphs.ptl @@ -2,7 +2,6 @@ import '../support/glyph' as Glyph import '../support/point' as Point import '../support/spiro-kit' as spirokit import '../support/boole-kit' as BooleKit -import '../support/transform' as : Transform && [object [transformPoint tp] [unTransform utp] inverse] import '../support/anchor' as Anchor import '../support/monotonic-interpolate' as smoothreg diff --git a/glyphs/common-shapes.ptl b/glyphs/common-shapes.ptl index 554f63221..444535cf1 100644 --- a/glyphs/common-shapes.ptl +++ b/glyphs/common-shapes.ptl @@ -1,6 +1,6 @@ $$include '../meta/macros.ptl' -import '../support/transform' as : Transform && [object [transformPoint tp] [unTransform utp] inverse] +import '../support/transform' as Transform import [mix linreg clamp fallback] from '../support/utils' import [Cv AnyDerivingCv] from '../support/gr' @@ -124,7 +124,7 @@ glyph-block CommonShapes : begin corner r d close [lambda : begin [set this.angles 4] [set this.fairGizmo currentGlyph.gizmo]] if transformShiftOnly : begin - local {.x mx1 .y my1} [tp globalTransform {.x mx .y my}] + local {.x mx1 .y my1} : globalTransform.apply {.x mx .y my} apply-transform : Translate (mx1 - mx) (my1 - my) define [Ring u d l r transformShiftOnly] : create-glyph : glyph-construction @@ -143,7 +143,7 @@ glyph-block CommonShapes : begin arcvh close [lambda : begin [set this.angles 4] [set this.fairGizmo currentGlyph.gizmo]] if transformShiftOnly : begin - local {.x mx1 .y my1} [tp globalTransform {.x mx .y my}] + local {.x mx1 .y my1} : globalTransform.apply {.x mx .y my} apply-transform : Translate (mx1 - mx) (my1 - my) define [RingAt x y r] : Ring (y + r) (y - r) (x - r) (x + r) define [DotAt x y r] : Ring (y + r) (y - r) (x - r) (x + r) true @@ -165,7 +165,7 @@ glyph-block CommonShapes : begin arcvh close [lambda : begin [set this.angles 4] [set this.fairGizmo currentGlyph.gizmo]] if transformShiftOnly : begin - local {.x mx1 .y my1} [tp globalTransform {.x mx .y my}] + local {.x mx1 .y my1} : globalTransform.apply {.x mx .y my} apply-transform : Translate (mx1 - mx) (my1 - my) define [RingStrokeAt x y r s] : RingStroke (y + r) (y - r) (x - r) (x + r) s define [DotStrokeAt x y r s] : RingStroke (y + r) (y - r) (x - r) (x + r) s true @@ -182,7 +182,7 @@ glyph-block CommonShapes : begin g4 r my close [lambda : begin [set this.angles 4] [set this.fairGizmo currentGlyph.gizmo]] if transformShiftOnly : begin - local {.x mx1 .y my1} [tp globalTransform {.x mx .y my}] + local {.x mx1 .y my1} : globalTransform.apply {.x mx .y my} apply-transform : Translate (mx1 - mx) (my1 - my) define [CircleRingAt x y r] : CircleRing (y + r) (y - r) (x - r) (x + r) define [CircleDotAt x y r] : CircleRing (y + r) (y - r) (x - r) (x + r) true @@ -786,8 +786,8 @@ glyph-block CommonShapes : begin local giz this.gizmo local g : create-glyph : glyph-construction set this.gizmo : Translate 0 0 - local {.x xo .y yo} : tp [Transform.Id] {.x x1 .y y1} - local {.x xt .y yt} : tp [Transform.Id] {.x x2 .y y2} + local {.x xo .y yo} : [Transform.Id].apply {.x x1 .y y1} + local {.x xt .y yt} : [Transform.Id].apply {.x x2 .y y2} local mag : Math.hypot (yo - yt) (xo - xt) include [G mag] apply-transform : Rotate : Math.atan2 (yo - yt) (xo - xt) diff --git a/glyphs/letter-latin.ptl b/glyphs/letter-latin.ptl index d7dbf6530..4d4eb5169 100644 --- a/glyphs/letter-latin.ptl +++ b/glyphs/letter-latin.ptl @@ -4,7 +4,6 @@ $$include '../meta/macros.ptl' -import '../support/transform' as : Transform && [object [transformPoint tp] [unTransform utp] inverse] import [mix linreg clamp fallback] from '../support/utils' import [designParameters] from '../meta/aesthetics' import [Dotless DoNotDeriveVariants] from "../support/gr" @@ -4706,7 +4705,7 @@ glyph-block Letter-Latin-Lower-T : begin sketch # tltail include MarkSet.if include : refer-glyph 't.standard' - local attach : utp currentGlyph.gizmo [query-glyph 't.standard'].baseAnchors.bottomright + local attach : currentGlyph.gizmo.unapply [query-glyph 't.standard'].baseAnchors.bottomright include : VBarRight attach.x 0 attach.y include : VerticalHook (attach.x - HalfStroke * HVContrast) 0 (-HookX) Hook save 'tltail' 0x1AB @@ -4856,7 +4855,7 @@ glyph-block Letter-Latin-S : begin sketch # srtail include MarkSet.p local stroke : [sStroke].call currentGlyph - local start : utp currentGlyph.gizmo stroke.lhsKnots.(stroke.lhsKnots.length - 1) + local start : currentGlyph.gizmo.unapply stroke.lhsKnots.(stroke.lhsKnots.length - 1) include : create-glyph : glyph-construction local sw : adviceBlackness2 2.875 2 XH @@ -4873,7 +4872,7 @@ glyph-block Letter-Latin-S : begin include MarkSet.if local stroke : [SStroke].call currentGlyph - local start : utp currentGlyph.gizmo stroke.lhsKnots.(stroke.lhsKnots.length - 1) + local start : currentGlyph.gizmo.unapply stroke.lhsKnots.(stroke.lhsKnots.length - 1) local sw : adviceBlackness2 2.875 2 CAP include : dispiro @@ -4889,7 +4888,7 @@ glyph-block Letter-Latin-S : begin include MarkSet.p local stroke : [sStroke].call currentGlyph - local start : utp currentGlyph.gizmo stroke.lhsKnots.(stroke.lhsKnots.length - 1) + local start : currentGlyph.gizmo.unapply stroke.lhsKnots.(stroke.lhsKnots.length - 1) local sw : adviceBlackness2 2.875 2 XH include : dispiro diff --git a/glyphs/numbers.ptl b/glyphs/numbers.ptl index 6ecc89849..dd0b2a79f 100644 --- a/glyphs/numbers.ptl +++ b/glyphs/numbers.ptl @@ -1,6 +1,5 @@ $$include '../meta/macros.ptl' -import '../support/transform' as : Transform && [object [transformPoint tp] [unTransform utp] inverse] import [mix linreg clamp fallback] from '../support/utils' import [designParameters] from '../meta/aesthetics' import [AnyCv getGrMesh] from "../support/gr" @@ -343,7 +342,7 @@ glyph-block Numbers : begin hookend O g4 SB (Hook * top / CAP) local fiveStroke : FiveStroke.call currentGlyph - local firstKnot : utp currentGlyph.gizmo fiveStroke.rhsKnots.(fiveStroke.rhsKnots.length - 1) + local firstKnot : currentGlyph.gizmo.unapply fiveStroke.rhsKnots.(fiveStroke.rhsKnots.length - 1) include : VBarRight firstKnot.x firstKnot.y top include : HBarTop xleft xright top if SLAB : begin diff --git a/glyphs/overmarks.ptl b/glyphs/overmarks.ptl index ed220ff23..03f02716a 100644 --- a/glyphs/overmarks.ptl +++ b/glyphs/overmarks.ptl @@ -1,6 +1,5 @@ $$include '../meta/macros.ptl' -import '../support/transform' as : Transform && [object [transformPoint tp]] import [curveToContour OffsetCurve] from '../support/curve-util' import [mix linreg clamp fallback] from '../support/utils' import [designParameters] from '../meta/aesthetics' @@ -221,10 +220,10 @@ glyph-block Overmarks : begin local tildeWave : [linreg hsvhThin 2.925 hsvhHeav 2.375 hsvh] * [linreg defaultHvc 1 4.35 1.1 hvc] local tildeWaveX 0.51 - define z1 : tp currentGlyph.gizmo : object [x leftEnd] [y tbot] - define z2 : tp currentGlyph.gizmo : object [x : mix leftEnd rightEnd tildeWaveX] [y : mix tbot ttop tildeWave] - define z3 : tp currentGlyph.gizmo : object [x : mix leftEnd rightEnd (1 - tildeWaveX)] [y : mix tbot ttop (1 - tildeWave)] - define z4 : tp currentGlyph.gizmo : object [x rightEnd] [y ttop] + define z1 : currentGlyph.gizmo.apply : object [x leftEnd] [y tbot] + define z2 : currentGlyph.gizmo.apply : object [x : mix leftEnd rightEnd tildeWaveX] [y : mix tbot ttop tildeWave] + define z3 : currentGlyph.gizmo.apply : object [x : mix leftEnd rightEnd (1 - tildeWaveX)] [y : mix tbot ttop (1 - tildeWave)] + define z4 : currentGlyph.gizmo.apply : object [x rightEnd] [y ttop] define bone : new Arcs.Bez3 z1 z2 z3 z4 define inner : curveToContour [new OffsetCurve bone (+hs) HVContrast] 32 diff --git a/glyphs/symbol-arrow.ptl b/glyphs/symbol-arrow.ptl index 790e3db60..ca47b634a 100644 --- a/glyphs/symbol-arrow.ptl +++ b/glyphs/symbol-arrow.ptl @@ -1,7 +1,7 @@ ###### GEOMETRIC SHAPES $$include '../meta/macros.ptl' -import '../support/transform' as : Transform && [object [transformPoint tp] [unTransform utp] inverse] +import '../support/transform' as Transform import [mix linreg clamp fallback] from '../support/utils' import [designParameters] from '../meta/aesthetics' diff --git a/glyphs/symbol-geometric.ptl b/glyphs/symbol-geometric.ptl index 2f288d051..bcd0db559 100644 --- a/glyphs/symbol-geometric.ptl +++ b/glyphs/symbol-geometric.ptl @@ -1,7 +1,6 @@ ###### GEOMETRIC SHAPES $$include '../meta/macros.ptl' -import '../support/transform' as : Transform && [object [transformPoint tp] [unTransform utp] inverse] import [mix linreg clamp fallback] from '../support/utils' import [designParameters] from '../meta/aesthetics' diff --git a/meta/aesthetics.ptl b/meta/aesthetics.ptl index ba9642ddb..c32ef79a6 100644 --- a/meta/aesthetics.ptl +++ b/meta/aesthetics.ptl @@ -1,5 +1,5 @@ import '../support/point' as Point -import '../support/transform' as : Transform && [object [transformPoint tp] [unTransform utp] inverse] +import '../support/transform' as Transform import [mix linreg clamp fallback] from '../support/utils' import '../support/anchor' as Anchor diff --git a/support/anchor.js b/support/anchor.js new file mode 100644 index 000000000..98011ee7c --- /dev/null +++ b/support/anchor.js @@ -0,0 +1,16 @@ +"use strict"; + +module.exports = class Anchor { + constructor(x, y) { + this.x = x; + this.y = y; + } + transform(tfm) { + return Anchor.transform(tfm, this); + } + static transform(tfm, a) { + const x = a.x * tfm.xx + a.y * tfm.yx + tfm.x; + const y = a.x * tfm.xy + a.y * tfm.yy + tfm.y; + return new Anchor(x, y); + } +}; diff --git a/support/anchor.ptl b/support/anchor.ptl deleted file mode 100644 index 13f3a4b77..000000000 --- a/support/anchor.ptl +++ /dev/null @@ -1,11 +0,0 @@ -export all : class Anchor - public [new x y ] : begin - set this.x x - set this.y y - - static [transform tfm a] : begin - local x : a.x * tfm.xx + a.y * tfm.yx + tfm.x - local y : a.x * tfm.xy + a.y * tfm.yy + tfm.y - return : new Anchor x y - - public [transform tfm] : Anchor.transform tfm this \ No newline at end of file diff --git a/support/point.js b/support/point.js new file mode 100644 index 000000000..db921186c --- /dev/null +++ b/support/point.js @@ -0,0 +1,73 @@ +"use strict"; + +const { z } = require("typo-geom"); + +module.exports = class Point { + constructor(x, y, on, cubic) { + this.x = x; + this.y = y; + this.on = on; + this.cubic = cubic; + } + add(z2) { + return this.addScale(1, z2); + } + addScale(scale, z2) { + return new Point(this.x + scale * z2.x, this.y + scale * z2.y, this.on, this.cubic); + } + mix(scale, z2) { + return new Point( + this.x + scale * (z2.x - this.x), + this.y + scale * (z2.y - this.y), + this.on, + this.cubic + ); + } + scale(t) { + return new Point(t * this.x, t * this.y, this.on, this.cubic); + } + round(d) { + return new Point( + Math.round(d * this.x) / d, + Math.round(d * this.y) / d, + this.on, + this.cubic + ); + } + + static from(z, on, cubic) { + return new Point(z.x || 0, z.y || 0, on, cubic); + } + static cornerFrom(z) { + return new Point(z.x || 0, z.y || 0, true, false); + } + static offFrom(z) { + return new Point(z.x || 0, z.y || 0, false, false); + } + static cubicOffFrom(z) { + return new Point(z.x || 0, z.y || 0, false, true); + } + static cornerFromXY(x, y) { + return new Point(x || 0, y || 0, true, false); + } + static offFromXY(x, y) { + return new Point(x || 0, y || 0, false, false); + } + static cubicOffFromXY(x, y) { + return new Point(x || 0, y || 0, false, true); + } + static transformed(tfm, z) { + return Point.transformedXY(tfm, z.x, z.y, z.on, z.cubic); + } + static transformedXY(tfm, x, y, on, cubic) { + return new Point( + x * tfm.xx + y * tfm.yx + tfm.x || 0, + x * tfm.xy + y * tfm.yy + tfm.y || 0, + on, + cubic + ); + } + static translated(z, dx, dy) { + return new Point(z.x + dx || 0, z.y + dy || 0, z.on, z.cubic); + } +}; diff --git a/support/point.ptl b/support/point.ptl deleted file mode 100644 index 490d9d3eb..000000000 --- a/support/point.ptl +++ /dev/null @@ -1,71 +0,0 @@ -export all : class Point - public [new x y on cubic subdivided] : begin - this.x = x - this.y = y - this.on = on || false - this.cubic = cubic || false - this.subdivided = subdivided || false - - public [add z2] : new Point - this.x + z2.x - this.y + z2.y - * this.on - * this.cubic - * this.subdivided - - public [addScale scale z2] : new Point - this.x + scale * z2.x - this.y + scale * z2.y - * this.on - * this.cubic - * this.subdivided - - public [mix scale z2] : new Point - this.x + scale * (z2.x - this.x) - this.y + scale * (z2.y - this.y) - * this.on - * this.cubic - * this.subdivided - - public [scale t] : new Point - t * this.x - t * this.y - * this.on - * this.cubic - * this.subdivided - - public [round d] : new Point - [Math.round (this.x * d)] / d - [Math.round (this.y * d)] / d - * this.on - * this.cubic - * this.subdivided - - static [from z on cubic subdivided] : new Point - * z.x - * z.y - * on - * cubic - * subdivided - - static [cornerFrom z] : new Point (z.x || 0) (z.y || 0) true false false - static [offFrom z] : new Point (z.x || 0) (z.y || 0) false false false - static [cubicOffFrom z] : new Point (z.x || 0) (z.y || 0) false true false - static [cornerFromXY x y] : new Point (x || 0) (y || 0) true false false - static [offFromXY x y] : new Point (x || 0) (y || 0) false false false - static [cubicOffFromXY x y] : new Point (x || 0) (y || 0) false true false - - static [transformed tfm z] : new Point - * z.x * tfm.xx + z.y * tfm.yx + tfm.x - * z.x * tfm.xy + z.y * tfm.yy + tfm.y - * z.on - * z.cubic - * z.subdivided - static [transformedXY tfm x y on cubic subdivided] : new Point - * x * tfm.xx + y * tfm.yx + tfm.x - * x * tfm.xy + y * tfm.yy + tfm.y - * on - * cubic - * subdivided - - static [translated z dx dy] : new Point ((z.x || 0) + dx) ((z.y || 0) + dy) z.on z.cubic z.subdivided \ No newline at end of file diff --git a/support/spiroexpand.ptl b/support/spiroexpand.ptl index ec3a462a8..484cf044a 100644 --- a/support/spiroexpand.ptl +++ b/support/spiroexpand.ptl @@ -1,5 +1,5 @@ import './monotonic-interpolate' as smooth -import './transform' as : Transform && [object [transformPoint tp] [unTransform utp] inverse] +import './transform' as Transform import './point' as Point define [fallback] : for [local j 0] (j < arguments.length) [inc j] : if (arguments.(j) !== nothing) : return arguments.(j) @@ -125,18 +125,18 @@ class SpiroExpansionContext local jAfter (j + 1) while this.controlKnots.(jAfter).unimportant : inc jAfter - local knotBefore : utp this.gizmo this.controlKnots.(jBefore) - local knotAfter : utp this.gizmo this.controlKnots.(jAfter) - local ref : utp this.gizmo knot - local lhsBefore : utp this.gizmo lhs.(jBefore) - local lhsAfter : utp this.gizmo lhs.(jAfter) - local rhsBefore : utp this.gizmo rhs.(jBefore) - local rhsAfter : utp this.gizmo rhs.(jAfter) + local knotBefore : this.gizmo.unapply this.controlKnots.(jBefore) + local knotAfter : this.gizmo.unapply this.controlKnots.(jAfter) + local ref : this.gizmo.unapply knot + local lhsBefore : this.gizmo.unapply lhs.(jBefore) + local lhsAfter : this.gizmo.unapply lhs.(jAfter) + local rhsBefore : this.gizmo.unapply rhs.(jBefore) + local rhsAfter : this.gizmo.unapply rhs.(jAfter) - local kLHS : tp this.gizmo : object + local kLHS : this.gizmo.apply : object x : linreg knotBefore.x lhsBefore.x knotAfter.x lhsAfter.x ref.x y : linreg knotBefore.y lhsBefore.y knotAfter.y lhsAfter.y ref.y - local kRHS : tp this.gizmo : object + local kRHS : this.gizmo.apply : object x : linreg knotBefore.x rhsBefore.x knotAfter.x rhsAfter.x ref.x y : linreg knotBefore.y rhsBefore.y knotAfter.y rhsAfter.y ref.y diff --git a/support/transform.js b/support/transform.js new file mode 100644 index 000000000..7eb61a2f1 --- /dev/null +++ b/support/transform.js @@ -0,0 +1,43 @@ +"use strict"; + +module.exports = class Transform { + constructor(xx, yx, xy, yy, x, y) { + this.xx = xx; + this.yx = yx; + this.xy = xy; + this.yy = yy; + this.x = x; + this.y = y; + } + + static Id() { + return new Transform(1, 0, 0, 1, 0, 0); + } + + apply(pt) { + return { + x: pt.x * this.xx + pt.y * this.yx + this.x, + y: pt.x * this.xy + pt.y * this.yy + this.y + }; + } + unapply(pt) { + const xx = pt.x - this.x; + const yy = pt.y - this.y; + const denom = this.xx * this.yy - this.xy * this.yx; + return { + x: (xx * this.yy - yy * this.yx) / denom, + y: (yy * this.xx - xx * this.xy) / denom + }; + } + inverse() { + const denom = this.xx * this.yy - this.xy * this.yx; + return new Transform( + this.yy / denom, + -this.yx / denom, + -this.xy / denom, + this.xx / denom, + -(this.x * this.yy - this.y * this.yx) / denom, + -(-this.x * this.xy + this.y * this.xx) / denom + ); + } +}; diff --git a/support/transform.ptl b/support/transform.ptl deleted file mode 100644 index bde5e4da2..000000000 --- a/support/transform.ptl +++ /dev/null @@ -1,36 +0,0 @@ -import './point' as Point - -export all : class Transform - public [new xx yx xy yy x y] : begin - this.xx = xx - this.yx = yx - this.xy = xy - this.yy = yy - this.x = x - this.y = y - public [inverse] : Transform.inverse this - - static [Id] : new Transform 1 0 0 1 0 0 - static [transformPoint tfm pt] : new Point - * pt.x * tfm.xx + pt.y * tfm.yx + tfm.x - * pt.x * tfm.xy + pt.y * tfm.yy + tfm.y - * pt.on - * pt.cubic - * pt.subdivided - static [inverse tfm] : begin - local denom : tfm.xx * tfm.yy - tfm.xy * tfm.yx - return : new Transform - * tfm.yy / denom; * -tfm.yx / denom - * -tfm.xy / denom; * tfm.xx / denom - * -(tfm.x * tfm.yy - tfm.y * tfm.yx) / denom - * -(-tfm.x * tfm.xy + tfm.y * tfm.xx) / denom - static [unTransform tfm pt] : begin - local xx : pt.x - tfm.x - local yy : pt.y - tfm.y - local denom : tfm.xx * tfm.yy - tfm.xy * tfm.yx - return : new Point - * (xx * tfm.yy - yy * tfm.yx) / denom - * (yy * tfm.xx - xx * tfm.xy) / denom - * pt.on - * pt.cubic - * pt.subdivided \ No newline at end of file diff --git a/support/utils.ptl b/support/utils.ptl index 833712df9..d221d8246 100644 --- a/support/utils.ptl +++ b/support/utils.ptl @@ -1,5 +1,4 @@ import './anchor' as Anchor -import './transform' as : Transform && [object [transformPoint tp] [unTransform utp] inverse] export : define [mix a b p] : a + (b - a) * p export : define [ratio l r m] : if [l === r] 0 ((m - l) / (r - l))