diff --git a/changes/31.0.1.md b/changes/31.0.1.md index f392fd9d2..0dd19b5e2 100644 --- a/changes/31.0.1.md +++ b/changes/31.0.1.md @@ -5,3 +5,4 @@ - BLACK-LETTER CAPITAL R (`U+211C`) (#714). - BLACK-LETTER CAPITAL Z (`U+2128`) (#714). - BLACK-LETTER CAPITAL C (`U+212D`) (#714). + - MATHEMATICAL FRAKTUR CAPITAL J (`U+1D50D`) (#444). diff --git a/packages/font-glyphs/src/common/shapes.ptl b/packages/font-glyphs/src/common/shapes.ptl index ef92c5017..2f20c6d17 100644 --- a/packages/font-glyphs/src/common/shapes.ptl +++ b/packages/font-glyphs/src/common/shapes.ptl @@ -55,30 +55,42 @@ glyph-block CommonShapes : begin define [MaskLeft x] : Rect VERY-FAR (-VERY-FAR) (-VERY-FAR) x glyph-block-export MaskRight define [MaskRight x] : Rect VERY-FAR (-VERY-FAR) x VERY-FAR + glyph-block-export MaskAboveLine - define [MaskAboveLine x1 y1 x2 y2] : spiro-outline - corner x1 (+VERY-FAR) - corner x1 y1 - corner x2 y2 - corner x2 (+VERY-FAR) + define [MaskAboveLine x1 y1 x2 y2 _ext] : begin + local ext : fallback _ext 0 + return : spiro-outline + corner [mix x1 x2 (-ext)] (+VERY-FAR) + corner [mix x1 x2 (-ext)] [mix y1 y2 (-ext)] + corner [mix x1 x2 (1 + ext)] [mix y1 y2 (1 + ext)] + corner [mix x1 x2 (1 + ext)] (+VERY-FAR) + glyph-block-export MaskBelowLine - define [MaskBelowLine x1 y1 x2 y2] : spiro-outline - corner x1 (-VERY-FAR) - corner x1 y1 - corner x2 y2 - corner x2 (-VERY-FAR) + define [MaskBelowLine x1 y1 x2 y2 _ext] : begin + local ext : fallback _ext 0 + return : spiro-outline + corner [mix x1 x2 (-ext)] (-VERY-FAR) + corner [mix x1 x2 (-ext)] [mix y1 y2 (-ext)] + corner [mix x1 x2 (1 + ext)] [mix y1 y2 (1 + ext)] + corner [mix x1 x2 (1 + ext)] (-VERY-FAR) + glyph-block-export MaskLeftLine - define [MaskLeftLine x1 y1 x2 y2] : spiro-outline - corner (-VERY-FAR) y1 - corner x1 y1 - corner x2 y2 - corner (-VERY-FAR) y2 + define [MaskLeftLine x1 y1 x2 y2 _ext] : begin + local ext : fallback _ext 0 + spiro-outline + corner (-VERY-FAR) [mix y1 y2 (-ext)] + corner [mix x1 x2 (-ext)] [mix y1 y2 (-ext)] + corner [mix x2 x2 (1 + ext)] [mix y1 y2 (1 + ext)] + corner (-VERY-FAR) [mix y1 y2 (1 + ext)] + glyph-block-export MaskRightLine - define [MaskRightLine x1 y1 x2 y2] : spiro-outline - corner (+VERY-FAR) y1 - corner x1 y1 - corner x2 y2 - corner (+VERY-FAR) y2 + define [MaskRightLine x1 y1 x2 y2 _ext] : begin + local ext : fallback _ext 0 + spiro-outline + corner (+VERY-FAR) [mix y1 y2 (-ext)] + corner [mix x1 x2 (-ext)] [mix y1 y2 (-ext)] + corner [mix x2 x2 (1 + ext)] [mix y1 y2 (1 + ext)] + corner (+VERY-FAR) [mix y1 y2 (1 + ext)] glyph-block-export HalfRectTriangle define [HalfRectTriangle x1 y1 x2 y2] : spiro-outline diff --git a/packages/font-glyphs/src/letter-like/fraktur.ptl b/packages/font-glyphs/src/letter-like/fraktur.ptl index a05e8067f..5925e2aeb 100644 --- a/packages/font-glyphs/src/letter-like/fraktur.ptl +++ b/packages/font-glyphs/src/letter-like/fraktur.ptl @@ -9,6 +9,7 @@ $$include '../meta/macros.ptl' import [mix fallback] from "@iosevka/util" import [SpiroPenGeometry] from "@iosevka/geometry" import [Vec2] from "@iosevka/geometry/point" +import [Interpolator] from "@iosevka/geometry/spiro-control" glyph-module @@ -71,86 +72,66 @@ glyph-block LetterLike-Fraktur-Shared : begin public [connT otherProfile y] : y + otherProfile.thick - this.thick # Stroke widths - define frakThin : 1.0 * [AdviceStroke 8] + define frakThin : 1.0 * [AdviceStroke 12] define frakThick : 1.0 * Stroke define frakFine : 1.0 * [AdviceStroke 4] # For decoration glyph-block-export S - define S : new FrakturProfile frakThick (0.5 * frakThin) + define S : new FrakturProfile frakThick (0.875 * frakThin) glyph-block-export F - define F : new FrakturProfile frakFine (0.5 * frakThin) + define F : new FrakturProfile frakFine (0.875 * frakThin) glyph-block-export T - define T : new FrakturProfile frakThin (0.5 * frakThin) + define T : new FrakturProfile frakThin (0.875 * frakThin) + + # Key metrics + glyph-block-export DecoSizeX DecoSizeY FHook Wave.DepthY Wave.DepthX LbFootRise + define DecoSizeX : 0.15 * (RightSB - SB) + define DecoSizeY : 0.08 * (RightSB - SB) + define FHook : 0.4 * SHook - 0.25 * S.thick + define LbFootRise : 0.375 * SHook + 0.375 * S.thick + + glyph-block-export SlopeA SlopeB + define SlopeA : DecoSizeY / DecoSizeX + define SlopeB 1.0 + + # Wave blenders + glyph-block-export Wave + define Wave : namespace + export : define DepthY : 0.4 * SHook - 0.25 * S.thick + export : define DepthX : 0.375 * SHook + 0.125 * S.thick + + export : define [vc waveDepth] : Interpolator vcWaveBlender [object waveDepth] + define [vcWaveBlender before after args] : begin + local [object waveDepth] args + return : list + g2 (before.x + 0.5 * waveDepth) [mix before.y after.y 0.375] + g2 (after.x - 0.5 * waveDepth) [mix before.y after.y 0.625] + + export : define [h] : Interpolator hWaveBlender [object h] + define [hWaveBlender before after] : begin + return : list + g2 [mix before.x after.x 0.375] after.y + g2 [mix before.x after.x 0.625] before.y glyph-block LetterLike-Fraktur : begin glyph-block-import CommonShapes glyph-block-import LetterLike-Fraktur-Shared : S F T fraktur-stroke - - define DecoSizeX : 0.15 * (RightSB - SB) - define DecoSizeY : 0.08 * (RightSB - SB) - define FHook : 0.4 * SHook - 0.25 * S.thick - define WaveDepth : 0.4 * SHook - 0.25 * S.thick - define WaveDepthX : 0.375 * SHook + 0.5 * S.thick - define LbFootRise : 0.375 * SHook + 0.375 * S.thick - - define flex-params [HWave] : begin - local-parameter pen - local-parameter w - local-parameter l - local-parameter r - local-parameter b - local-parameter t - - return : fraktur-stroke pen - g2 l b - g2 (l + TINY) (b + TINY) - g2 [mix l r 0.375] [if w (b + w) t] - g2 [mix l r 0.625] [if w (t - w) b] - g2 (r - TINY) (t - TINY) - g2 r t - - define flex-params [VWave] : begin - local-parameter pen - local-parameter w - local-parameter l - local-parameter r - local-parameter b - local-parameter t - - return : fraktur-stroke pen - g2 r t - g2 (r - TINY) (t - TINY) - g2 [if w (r - w) l] [mix b t 0.625] - g2 [if w (l + w) r] [mix b t 0.375] - g2 (l + TINY) (b + TINY) - g2 l b - - define flex-params [VCWave] : begin - local-parameter pen - local-parameter w - local-parameter x - local-parameter b - local-parameter t - - return : fraktur-stroke pen - g2 x t - g2 (x - TINY) (t - TINY) - g2 [pen.xl (x - 0.5 * w)] [mix b t 0.625] - g2 [pen.xr (x + 0.5 * w)] [mix b t 0.375] - g2 (x + TINY) (b + TINY) - g2 x b + glyph-block-import LetterLike-Fraktur-Shared : DecoSizeX DecoSizeY SlopeA SlopeB + glyph-block-import LetterLike-Fraktur-Shared : Wave LbFootRise FHook create-glyph "frak/C" 0x212D : glyph-proc include : MarkSet.capital + local xCenter : [mix SB RightSB 0.5] + 0.75 * F.thick + # Top-right stroke include : fraktur-stroke S - g2 [S.xr RightSB] [S.yt CAP] - g2.left.mid ([S.xp SB RightSB 0.75] + 0.5 * DecoSizeX) ([S.yt CAP] - 0.5 * FHook) - corner ([S.xp SB RightSB 0.5] + DecoSizeX) [S.yt CAP] - corner [S.xp SB RightSB 0.5] ([S.yt CAP] - DecoSizeX) + g2 [S.xr RightSB] [S.yt CAP] + g2.left.mid [mix (xCenter + DecoSizeX) [S.xr RightSB] 0.5] ([S.yt CAP] - 0.5 * FHook) + corner (xCenter + DecoSizeX) [S.yt CAP] + corner xCenter ([S.yt CAP] - DecoSizeX) # Left and bottom stroke include : fraktur-stroke S @@ -164,13 +145,13 @@ glyph-block LetterLike-Fraktur : begin include : fraktur-stroke T g4.ru.start [T.connR S : S.xp SB RightSB 0.1] [T.connT S : [S.yt CAP] - 0.1 * ArchDepthA] ~~~ [arch.lhs [T.yt CAP] 0.6 (sw -- T.thick) (blendPre -- null) (blendPost -- null)] - g4.ld.end [S.xp SB RightSB 0.5] ([S.yt CAP] - DecoSizeX) + g4.ld.end [T.connL S xCenter] [T.connB S : [S.yt CAP] - DecoSizeX] # Inner decoration - include : VCWave F (WaveDepthX + 0.625 * S.thick) - x -- [F.connL S : S.xp SB RightSB 0.5] - t -- [F.connB S : [S.yt CAP] - DecoSizeX] - b -- (CAP * 0.375) + include : fraktur-stroke F + g2.ld.start [F.connL S xCenter] [F.connB S : [S.yt CAP] - DecoSizeX] + ~~~ [Wave.vc (-Wave.DepthX)] + g2.ld.end [F.connL S xCenter] (CAP * 0.375) create-glyph "frak/H" 0x210C : glyph-proc include : MarkSet.capDesc @@ -180,49 +161,66 @@ glyph-block LetterLike-Fraktur : begin local ada : 0.6 * ArchDepthA local adb : 0.6 * ArchDepthB + local xMidStrokeTop : S.xp xLeftStem RightSB 0.625 + local yMidStrokeTop : S.yt (XH - FHook) + local xMidStrokeStart : S.xl xLeftStem + local yMidStrokeStart : yMidStrokeTop - SlopeA * (xMidStrokeTop - xMidStrokeStart) + # Top and left stroke include : fraktur-stroke S - g2 [S.xr RightSB] ([S.yt CAP] - FHook) + g2 [S.xr RightSB] ([S.yt CAP] - FHook) ~~~ [arch.rhs [S.yt CAP] (sw -- S.thick) (blendPre -- null) (blendPost -- null)] - corner [S.xl xLeftStem] ([S.yt CAP] - adb) - curl [S.xl xLeftStem] [Math.min [S.yt (XH - FHook)] [S.yp 0 CAP 0.5]] - corner [S.xl xExt] ([S.yb 0] + LbFootRise) - g2c.right.end (Middle - DecoSizeX) [S.yb 0] - corner Middle ([S.yb 0] + DecoSizeY) + corner [S.xl xLeftStem] ([S.yt CAP] - adb) + curl [S.xl xLeftStem] [Math.min [S.yt (XH - FHook)] [S.yp 0 CAP 0.5]] + corner [S.xl xExt] [Math.min yMidStrokeStart ([S.yb 0] + LbFootRise)] + g2c.right.end (Middle - DecoSizeX) [S.yb 0] + corner Middle ([S.yb 0] + DecoSizeY) # Middle and right stroke include : fraktur-stroke S - g2 [S.xl xLeftStem] ([S.yt (XH - FHook)] - FHook) - corner [S.xp xLeftStem RightSB 0.625] [S.yt (XH - FHook)] + g2 xMidStrokeStart yMidStrokeStart + corner xMidStrokeTop yMidStrokeTop g2.down.mid [S.xr RightSB] [S.yp Descender(XH - FHook) 0.75] ~~~ [alsoThru.g2 0.5 0.5] g2.down.mid [S.xp xLeftStem RightSB 0.75] [S.yp Descender(XH - FHook) 0.25] g2 [S.xr RightSB] [S.yb Descender] + define [IJTopStroke] : glyph-proc + include : fraktur-stroke S + g2.ld.start [S.xr RightSB] [S.yt CAP] + ~~~ [Wave.h] + g2.ld.mid [S.xl SB] [S.yt (CAP - Wave.DepthY)] + include : fraktur-stroke F + g2.ld.start [F.connL S : S.xl SB] [F.connB S : S.yt (CAP - Wave.DepthY)] + ~~~ [Wave.vc (-Wave.DepthX)] + g2.ld.end [F.connL S : S.xl SB] (CAP * 0.625 - 2 * S.thick) + create-glyph "frak/I" 0x2111 : glyph-proc include : MarkSet.capital - - # Top Stroke - include : HWave S - l -- [S.xl SB] - r -- [S.xr RightSB] - b -- [S.yt (CAP - WaveDepth)] - t -- [S.yt CAP] - - # Deocration at top-left - include : VCWave F WaveDepthX - x -- [F.connL S : S.xl SB] - b -- (CAP * 0.625) - t -- [F.connB S : S.yt (CAP - WaveDepth)] - + include : IJTopStroke # Main stroke include : fraktur-stroke S g2.ld.start [S.xr RightSB] [S.yt CAP] g4 [S.xp SB RightSB 0.75] [S.yp ArchDepthA CAP 0.625] - g2 [S.xr RightSB] [S.yb ArchDepthA] + g4 [S.xr RightSB] [S.yb ArchDepthA] ~~~ [hookend [S.yb 0] (sw -- S.thick)] g2 [S.xl SB] [S.yb SHook] + create-glyph "frak/J" 0x1D50D : glyph-proc + include : MarkSet.capDesc + + include : IJTopStroke + + # Main stroke + local mainStrokeTop : S.yt (CAP - 1.5 * Wave.DepthY - 2 * S.thick) + include : fraktur-stroke S + g4 [S.xr RightSB] (mainStrokeTop - FHook) + ~~~ [hookstart mainStrokeTop (sw -- S.thick)] + g4 [S.xr : mix SB RightSB 0.6] (mainStrokeTop - 0.6 * ArchDepthA) + g4 [S.xr RightSB] [S.yb (Descender + ArchDepthA)] + ~~~ [hookend [S.yb Descender] (sw -- S.thick)] + g2 [S.xl SB] [S.yb (Descender + SHook)] + create-glyph "frak/R" 0x211C : glyph-proc include : MarkSet.capital @@ -233,33 +231,38 @@ glyph-block LetterLike-Fraktur : begin local adb : 0.6 * ArchDepthB # Deocration at top-left - include : VCWave F WaveDepthX - x -- [F.connL S : S.xl xExt] - b -- (CAP * 0.625) - t -- [F.connB S : S.yt (CAP - ltHook)] + include : fraktur-stroke F + g2.ld.start [F.connL S : S.xl xExt] [F.connB S : S.yt (CAP - ltHook)] + ~~~ [Wave.vc (-Wave.DepthX)] + g2.ld.end [F.connL S : S.xl xExt] (CAP * 0.625 - 2 * S.thick) local xMidStrokeL : S.xl xLeftStem local xMidStrokeR : S.xp xLeftStem RightSB 0.625 - local yMidStrokeL : S.yp 0 CAP 0.48 local yMidStrokeR : S.yp 0 CAP 0.55 + local yMidStrokeL : yMidStrokeR - SlopeA * (xMidStrokeR - xMidStrokeL) + + local xArchStart xMidStrokeL + local xArchTop xMidStrokeR + local yArchTop : S.yt CAP + local yArchStart : yArchTop - SlopeA * (xArchTop - xArchStart) # Left stroke include : fraktur-stroke S - g2.ru.start [S.xl xExt] [S.yt (CAP - ltHook)] + g2.ru.start [S.xl xExt] [S.yt (CAP - ltHook)] ~~~ [arch.rhs [S.yt CAP] 0.6 (blendPre -- null)] - flat [S.xl xLeftStem] ([S.yb CAP] - adb) - curl [S.xl xLeftStem] yMidStrokeL - corner [S.xl xExt] ([S.yb 0] + LbFootRise) - g2c.right.end (Middle - DecoSizeX) [S.yb 0] - corner Middle ([S.yb 0] + DecoSizeY) + flat [S.xl xLeftStem] [Math.max ([S.yb CAP] - ada) yArchStart] + curl [S.xl xLeftStem] yMidStrokeL + corner [S.xl xExt] ([S.yb 0] + LbFootRise) + g2c.right.end (Middle - DecoSizeX) [S.yb 0] + corner Middle ([S.yb 0] + DecoSizeY) # Top-right arch include : fraktur-stroke S - flat [S.xl xLeftStem] ([S.yb CAP] - adb) - corner [S.xp xLeftStem RightSB 0.75] [S.yt CAP] - g2.down.mid [S.xr RightSB] [mix yMidStrokeR [S.yt CAP] 0.5] - flat xMidStrokeR yMidStrokeR - curl xMidStrokeL yMidStrokeL + flat xArchStart yArchStart + corner xArchTop yArchTop + g2.down.mid [S.xr RightSB] [mix yMidStrokeR yArchTop 0.5] + flat xMidStrokeR yMidStrokeR + curl xMidStrokeL yMidStrokeL local xLegStart : mix xMidStrokeL xMidStrokeR 0.75 local yLegStart : mix yMidStrokeL yMidStrokeR 0.75 @@ -269,7 +272,7 @@ glyph-block LetterLike-Fraktur : begin # Leg include : fraktur-stroke S g2 xLegStart yLegStart - g2 [mix xLegStart xMidStrokeR 0.001] [mix yLegStart yMidStrokeR 0.001] + g2 (xLegStart + TINY) (yLegStart + SlopeA * TINY) flat [mix xLegStart xLegEnd 0.75] (yLegStart - adb) curl [mix xLegStart xLegEnd 0.75] (yLegEnd + ada) corner xLegEnd yLegEnd @@ -279,17 +282,21 @@ glyph-block LetterLike-Fraktur : begin include : MarkSet.capital # Top Stroke - include : HWave S - l -- [S.xl SB] - r -- [S.xr RightSB] - b -- [S.yt (CAP - WaveDepth)] - t -- [S.yt CAP] + include : fraktur-stroke S + g2.ld.start [S.xr RightSB] [S.yt CAP] + ~~~ [Wave.h] + g2.ld.mid [S.xl SB] [S.yt (CAP - Wave.DepthY)] # Bottom Stroke - include : fraktur-stroke S + local diag : list corner [S.xr RightSB] [S.yt CAP] - cg2.ru.start [S.xp SB RightSB 0.166] [S.yp 0 CAP 0.5] - ~~~ [arch.rhs [S.yp 0 CAP 0.55] 0.375 (sw -- S.thick)] - g2.down.mid [S.xr RightSB] [S.yb ArchDepthA] - ~~~ [hookend [S.yb 0] (sw -- S.thick)] - g2 [S.xl SB] [S.yb SHook] + corner [S.xp SB RightSB 0.166] [S.yp 0 CAP 0.5] + include : fraktur-stroke S diag + include : difference + fraktur-stroke S + g2.ru.start [S.xp SB RightSB 0.166] [S.yp 0 CAP 0.5] + ~~~ [arch.rhs [S.yp 0 CAP 0.55] 0.375 (sw -- S.thick)] + g2.down.mid [S.xr RightSB] [S.yb ArchDepthA] + ~~~ [hookend [S.yb 0] (sw -- S.thick)] + g2 [S.xl SB] [S.yb SHook] + MaskAboveLine diag.0.x diag.0.y diag.1.x diag.1.y 4 diff --git a/packages/font-glyphs/src/meta/macros.ptl b/packages/font-glyphs/src/meta/macros.ptl index 913a74190..90badbb51 100644 --- a/packages/font-glyphs/src/meta/macros.ptl +++ b/packages/font-glyphs/src/meta/macros.ptl @@ -281,7 +281,8 @@ define-macro glyph-block : syntax-rules NarrowUnicodeT WideUnicodeT VERY-FAR TINY] define spiroFnImports `[g4 g2 corner flat curl close end straight g2c cg2 flatc ccurl widths disable-contrast heading unimportant important alsoThru alsoThruThem bezControls - quadControls archv arcvh dispiro spiro-outline spiro-collect] + quadControls archv arcvh dispiro spiro-outline spiro-collect same-x same-y same-x-post + same-y-post] define booleFnImports `[union intersection difference] dirty `[$GlyphBlocks$.push : lambda [$Capture_Ext$] : begin \\ diff --git a/packages/font-glyphs/src/number/0.ptl b/packages/font-glyphs/src/number/0.ptl index 4e47f75d2..3a0e0b022 100644 --- a/packages/font-glyphs/src/number/0.ptl +++ b/packages/font-glyphs/src/number/0.ptl @@ -49,23 +49,23 @@ glyph-block Digits-Zero : begin local pcy 0.1 return : sink - g2.right.mid.r mxb (b + O) [widths.lhs fine] - alsoThru.g2 pcx pcy - flat [mix mxb r p1] [mix b myr p2] [widths.lhs sw1] - curl [mix mxb r (1 - p4)] [mix b myr (1 - p3)] [widths.lhs sw2] - g2.up.mid (r - OX) myr [widths.lhs body] - flat [mix r mxt p4] [mix myr t p3] [widths.lhs sw2] - curl [mix r mxt (1 - p1)] [mix myr t (1 - p2)] [widths.lhs sw1] - alsoThru.g2 (1 - pcx) (1 - pcy) - g2.left.mid mxt (t - O) [widths.lhs fine] - alsoThru.g2 pcx pcy - flat [mix mxt l p1] [mix t myl p2] [widths.lhs sw1] - curl [mix mxt l (1 - p4)] [mix t myl (1 - p3)] [widths.lhs sw2] - g2.down.mid (l + OX) myl [widths.lhs body] - flat [mix l mxb p4] [mix myl b p3] [widths.lhs sw2] - curl [mix l mxb (1 - p1)] [mix myl b (1 - p2)] [widths.lhs sw1] - alsoThru.g2 (1 - pcx) (1 - pcy) - g2.right.mid.l mxb (b + O) [widths.lhs fine] + g2.right.mid.post mxb (b + O) [widths.lhs fine] + alsoThru.g2 pcx pcy + flat [mix mxb r p1] [mix b myr p2] [widths.lhs sw1] + curl [mix mxb r (1 - p4)] [mix b myr (1 - p3)] [widths.lhs sw2] + g2.up.mid (r - OX) myr [widths.lhs body] + flat [mix r mxt p4] [mix myr t p3] [widths.lhs sw2] + curl [mix r mxt (1 - p1)] [mix myr t (1 - p2)] [widths.lhs sw1] + alsoThru.g2 (1 - pcx) (1 - pcy) + g2.left.mid mxt (t - O) [widths.lhs fine] + alsoThru.g2 pcx pcy + flat [mix mxt l p1] [mix t myl p2] [widths.lhs sw1] + curl [mix mxt l (1 - p4)] [mix t myl (1 - p3)] [widths.lhs sw2] + g2.down.mid (l + OX) myl [widths.lhs body] + flat [mix l mxb p4] [mix myl b p3] [widths.lhs sw2] + curl [mix l mxb (1 - p1)] [mix myl b (1 - p2)] [widths.lhs sw1] + alsoThru.g2 (1 - pcx) (1 - pcy) + g2.right.mid.pre mxb (b + O) [widths.lhs fine] close define [ZeroShapeBase shapeT] : namespace diff --git a/packages/font-kits/src/spiro-kit.mjs b/packages/font-kits/src/spiro-kit.mjs index ece5de0d4..79f25cd9a 100644 --- a/packages/font-kits/src/spiro-kit.mjs +++ b/packages/font-kits/src/spiro-kit.mjs @@ -1,9 +1,9 @@ import { DiSpiroGeometry, SpiroGeometry } from "@iosevka/geometry"; import { BiKnotCollector, - UserControlKnot, Interpolator, TerminateInstruction, + UserControlKnot, } from "@iosevka/geometry/spiro-control"; import { bez3, fallback, mix } from "@iosevka/util"; @@ -73,15 +73,37 @@ class DiSpiroProxy { } } -export function SetupBuilders(bindings) { - const { Stroke, Superness, Contrast, CorrectionOMidX, TINY } = bindings; - function KnotType(type) { - return (x, y, f) => { - if (!isFinite(x)) throw new TypeError("NaN detected for X"); - if (!isFinite(y)) throw new TypeError("NaN detected for Y"); - return new UserControlKnot(type, x, y, f); - }; +/// The builder for directed knot pairs +class DirectedKnotPairBuilder { + constructor(bindings, prevKnotType, nextKnotType, deltaX, deltaY) { + const { TINY } = bindings; + this.start = DirPairImpl(prevKnotType, nextKnotType, deltaX, deltaY, 0, TINY); + this.mid = DirPairImpl(prevKnotType, nextKnotType, deltaX, deltaY, -0.5 * TINY, 0.5 * TINY); + this.end = DirPairImpl(prevKnotType, nextKnotType, deltaX, deltaY, -TINY, 0); } +} + +function DirPairImpl(prevKnotType, nextKnotType, dirX, dirY, distPre, distPost) { + const fnPre = (x, y, af) => prevKnotType(x + dirX * distPre, y + dirY * distPre, af); + const fnPost = (x, y, af) => nextKnotType(x + dirX * distPost, y + dirY * distPost, af); + let buildFn = (x, y, af) => [fnPre(x, y, af), fnPost(x, y, af)]; + buildFn.pre = fnPre; + buildFn.post = fnPost; + return buildFn; +} + +function KnotType(type) { + return (x, y, f) => { + if (!isFinite(x)) throw new TypeError("NaN detected for X"); + if (!isFinite(y)) throw new TypeError("NaN detected for Y"); + return new UserControlKnot(type, x, y, f); + }; +} + +export function SetupBuilders(bindings) { + const { Stroke, Superness } = bindings; + + // Simple knot types const g4 = KnotType("g4"); const g2 = KnotType("g2"); const corner = KnotType("corner"); @@ -90,28 +112,15 @@ export function SetupBuilders(bindings) { const close = f => new TerminateInstruction("close", f); const end = f => new TerminateInstruction("end", f); + // Pair knots const straight = { l: flat, r: curl }; const g2c = { l: g2, r: corner }; const cg2 = { l: corner, r: g2 }; const flatc = { l: flat, r: corner }; const ccurl = { l: corner, r: curl }; + // Add the directed/heading knot builders { - let directions = [ - { name: "up", x: 0, y: 1 }, - { name: "down", x: 0, y: -1 }, - { name: "left", x: -1, y: 0 }, - { name: "right", x: 1, y: 0 }, - { name: "ru", x: 1, y: 1 }, - { name: "rd", x: 1, y: -1 }, - { name: "lu", x: -1, y: 1 }, - { name: "ld", x: -1, y: -1 }, - ]; - let adhesions = [ - { name: "start", l: 0, r: TINY }, - { name: "mid", l: -0.5 * TINY, r: 0.5 * TINY }, - { name: "end", l: -TINY, r: 0 }, - ]; let knotTypes = [ [g4, g4, g4], [g2, g2, g2], @@ -122,17 +131,29 @@ export function SetupBuilders(bindings) { [flatc, flat, corner], [ccurl, corner, curl], ]; + let directions = [ + // Straights + { name: "up", x: 0, y: 1 }, + { name: "down", x: 0, y: -1 }, + { name: "left", x: -1, y: 0 }, + { name: "right", x: 1, y: 0 }, + { name: "u", x: 0, y: 1 }, + { name: "d", x: 0, y: -1 }, + { name: "l", x: -1, y: 0 }, + { name: "r", x: 1, y: 0 }, + + // Diagonals + { name: "ru", x: 1, y: 1 }, + { name: "rd", x: 1, y: -1 }, + { name: "lu", x: -1, y: 1 }, + { name: "ld", x: -1, y: -1 }, + ]; for (const [sink, kl, kr] of knotTypes) { + sink.sl = s => new DirectedKnotPairBuilder(bindings, kl, kr, -1, s); + sink.sr = s => new DirectedKnotPairBuilder(bindings, kl, kr, 1, s); + sink.dir = (dx, dy) => new DirectedKnotPairBuilder(bindings, kl, kr, dx, dy); for (const d of directions) { - sink[d.name] = {}; - for (const a of adhesions) { - sink[d.name][a.name] = (x, y, af) => [ - kl(x + d.x * a.l, y + d.y * a.l, af), - kr(x + d.x * a.r, y + d.y * a.r, af), - ]; - sink[d.name][a.name].l = (x, y, af) => kl(x + d.x * a.l, y + d.y * a.l, af); - sink[d.name][a.name].r = (x, y, af) => kr(x + d.x * a.r, y + d.y * a.r, af); - } + sink[d.name] = new DirectedKnotPairBuilder(bindings, kl, kr, d.x, d.y); } } } diff --git a/packages/geometry/src/spiro-control.mjs b/packages/geometry/src/spiro-control.mjs index bd45b7371..bdb6265ba 100644 --- a/packages/geometry/src/spiro-control.mjs +++ b/packages/geometry/src/spiro-control.mjs @@ -1,7 +1,3 @@ -import * as Format from "@iosevka/util/formatter"; - -/////////////////////////////////////////////////////////////////////////////////////////////////// - export class BiKnotCollector { constructor(contrast) { this.contrast = contrast; // stroke contrast @@ -206,6 +202,7 @@ export class UserControlKnot { if (this.af) this.af.call(ctx); } } + export class TerminateInstruction { constructor(type, af) { this.type = type; @@ -216,6 +213,9 @@ export class TerminateInstruction { // if (this.af) this.af.call(ctx); } } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + export class InterpolatorBase { constructor(blender) { this.type = "interpolate";