Migrate kits to JS
This commit is contained in:
parent
774f2a457f
commit
dad21a56ee
32 changed files with 455 additions and 319 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -43,7 +43,6 @@ release-archives/
|
|||
testdrive/iosevka*
|
||||
|
||||
# Generated scripts
|
||||
font-src/kits/**/*.js
|
||||
font-src/meta/**/*.js
|
||||
font-src/otl/**/*.js
|
||||
font-src/glyphs/**/*.js
|
||||
|
|
|
@ -4,7 +4,7 @@ const fs = require("fs-extra");
|
|||
const zlib = require("zlib");
|
||||
const { encode, decode } = require("@msgpack/msgpack");
|
||||
|
||||
const Edition = 9;
|
||||
const Edition = 10;
|
||||
const MAX_AGE = 5;
|
||||
|
||||
class GfEntry {
|
||||
|
|
|
@ -4,7 +4,7 @@ import '../support/glyph-block' as GlyphBlock
|
|||
import '../support/point' as Point
|
||||
import '../support/anchor' as Anchor
|
||||
import '../support/gr' as Gr
|
||||
import '../kits/spiro-kit' as spirokit
|
||||
import '../kits/spiro-kit' as SpiroKit
|
||||
import '../kits/boole-kit' as BooleKit
|
||||
import [ DesignParameters ] from "../meta/aesthetics"
|
||||
|
||||
|
@ -105,8 +105,8 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin
|
|||
|
||||
### Spiro constructions
|
||||
# Basic knots
|
||||
define spirofns : spirokit.SetupBuilders : object GlobalTransform Contrast Stroke Glyph para [superness DesignParameters.superness]
|
||||
define booleFns : BooleKit.SetupBuilders : object GlobalTransform Glyph
|
||||
define SpiroFns : SpiroKit.SetupBuilders : object GlobalTransform Contrast Stroke [Superness DesignParameters.superness]
|
||||
define BooleFns : BooleKit.SetupBuilders : object GlobalTransform Glyph
|
||||
|
||||
# Meta
|
||||
define [tagged tag component] : function [ca cw] : begin
|
||||
|
@ -117,7 +117,7 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin
|
|||
return ret
|
||||
|
||||
# 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$
|
||||
|
||||
### HERE WE GO
|
||||
run-glyph-module './common/shapes.js'
|
||||
|
|
|
@ -60,5 +60,5 @@ glyph-block Letter-Cyrillic-De : begin
|
|||
archv
|
||||
flat (RightSB - OX) SmallSmoothA
|
||||
curl (RightSB - OX) (XH - SmallSmoothB)
|
||||
quadcontrols 0 0.8
|
||||
quadControls 0 0.8
|
||||
g4 (SB + Stroke * 1.1) CAP
|
||||
|
|
|
@ -23,14 +23,14 @@ glyph-block Letter-Greek-Lower-Alpha : begin
|
|||
include : dispiro
|
||||
widths.rhs fine
|
||||
g4 (RightSB - OX * 1.75) XH [heading Downward]
|
||||
bezcontrols k1 k2 k3 1 6
|
||||
bezControls k1 k2 k3 1 6
|
||||
g4.left.mid (middle + CorrectionOMidS) O [widths 0 Stroke]
|
||||
archv
|
||||
flat (SB + OX * 2) SmallSmoothB
|
||||
curl (SB + OX * 2) (XH - SmallSmoothA)
|
||||
arcvh
|
||||
g4.right.mid (middle - CorrectionOMidS) (XH - O) [widths 0 Stroke]
|
||||
bezcontrols (1 - k3) 0 (1 - k1) (1 - k2) 6
|
||||
bezControls (1 - k3) 0 (1 - k1) (1 - k2) 6
|
||||
g4 (RightSB - OX * 2) 0 [widths.heading 0 fine Downward]
|
||||
|
||||
set-base-anchor 'overlay' (middle - OX) (XH * OverlayPos)
|
||||
|
|
|
@ -18,7 +18,7 @@ glyph-block Letter-Greek-Lower-Gamma : begin
|
|||
local xStart : SB + 0.4 * Stroke * HVContrast
|
||||
include : dispiro
|
||||
g4 xStart (XH - O) [widths.rhs]
|
||||
bezcontrols 0.33 0.17 1 0.62 6 important
|
||||
bezControls 0.33 0.17 1 0.62 6 important
|
||||
flat xMid 0
|
||||
curl xMid Descender [heading Downward]
|
||||
|
||||
|
@ -26,7 +26,7 @@ glyph-block Letter-Greek-Lower-Gamma : begin
|
|||
widths.rhs
|
||||
flat RightSB XH [heading Downward]
|
||||
curl RightSB (XH * 0.9) [heading Downward]
|
||||
quadcontrols 0 0.3 6
|
||||
quadControls 0 0.3 6
|
||||
g4 xMid 0 [widths.rhs : Stroke * 0.9]
|
||||
|
||||
create-glyph 'mathbb/grek/gamma' 0x213D : glyph-proc
|
||||
|
@ -42,7 +42,7 @@ glyph-block Letter-Greek-Lower-Gamma : begin
|
|||
|
||||
foreach {ob ot} [items-of {{ 0 (cor - 1) } { (-1) (-1) }}] : include : dispiro
|
||||
g4 (xStart + ot * BBD) XH [widths.rhs.heading BBS Downward]
|
||||
bezcontrols 0.33 0.17 1 0.62 6 important
|
||||
bezControls 0.33 0.17 1 0.62 6 important
|
||||
flat (xMid + ob * BBD) 0
|
||||
curl (xMid + ob * BBD) Descender [heading Downward]
|
||||
|
||||
|
@ -50,5 +50,5 @@ glyph-block Letter-Greek-Lower-Gamma : begin
|
|||
widths.rhs BBS
|
||||
flat RightSB XH [heading Downward]
|
||||
curl RightSB (XH * 0.9) [heading Downward]
|
||||
quadcontrols 0 0.3 6
|
||||
quadControls 0 0.3 6
|
||||
g4 xMid 0 [widths.rhs : BBS * 0.9]
|
|
@ -14,11 +14,11 @@ glyph-block Letter-Greek-Lower-Nu : begin
|
|||
local xmid : Middle + HalfStroke * 0.75
|
||||
include : dispiro
|
||||
g4 (SB + 0.4 * Stroke * HVContrast) (XH - O) [widths.rhs]
|
||||
bezcontrols 0.33 0.2 1 0.76 6 important
|
||||
bezControls 0.33 0.2 1 0.76 6 important
|
||||
g4.down.end xmid 0 [heading Downward]
|
||||
include : dispiro
|
||||
widths.rhs
|
||||
flat RightSB XH [heading Downward]
|
||||
curl RightSB (XH * 0.9) [heading Downward]
|
||||
quadcontrols 0 0.3 6
|
||||
quadControls 0 0.3 6
|
||||
g4 xmid 0
|
||||
|
|
|
@ -14,7 +14,7 @@ glyph-block Letter-Greek-Lower-Zeta : begin
|
|||
include : HBar SB (RightSB + O) (CAP - HalfStroke)
|
||||
include : dispiro
|
||||
g4 (RightSB + O) (CAP - Stroke) [widths.rhs]
|
||||
bezcontrols 0.7 0.35 1 0.64 12
|
||||
bezControls 0.7 0.35 1 0.64 12
|
||||
g4.down.mid (SB + Stroke * HVContrast) [mix 0 CAP (0.54 * SmallSmoothB / (SmallSmoothA + SmallSmoothB))]
|
||||
arcvh 16
|
||||
g2 [mix SB RightSB 0.55] Stroke [heading Rightward]
|
||||
|
|
|
@ -18,7 +18,7 @@ glyph-block Letter-Latin-Eth : begin
|
|||
include : dispiro
|
||||
widths.lhs
|
||||
g4.up.start (RightSB - OX) ymiddlea
|
||||
quadcontrols 0 0.8
|
||||
quadControls 0 0.8
|
||||
g4 (SB + Stroke * 1.1) CAP
|
||||
|
||||
include : dispiro
|
||||
|
|
|
@ -17,13 +17,13 @@ glyph-block Letter-Latin-Rams-Horn : begin
|
|||
include : dispiro
|
||||
widths.center
|
||||
g4 (SB + HalfStroke * HVContrast + O) top [heading Downward]
|
||||
quadcontrols 1 0.7 16
|
||||
quadControls 1 0.7 16
|
||||
g4 (Middle + d - hf) (bottom + d * (1 - TanSlope * 0.5)) [widths hf hf]
|
||||
arcvh
|
||||
g4 (Middle + CorrectionOMidX * hf * 2) (bottom + hf)
|
||||
archv
|
||||
g4 (Middle - d + hf) (bottom + d * (1 + TanSlope * 0.5))
|
||||
quadcontrols 0 0.3 16
|
||||
quadControls 0 0.3 16
|
||||
g4 (RightSB - HalfStroke * HVContrast - O) top [widths.heading HalfStroke HalfStroke Upward]
|
||||
|
||||
create-glyph 'latingamma' 0x263 : glyph-proc
|
||||
|
|
|
@ -29,7 +29,7 @@ glyph-block Letter-Latin-Upper-AE-OE : begin
|
|||
widths.rhs sw
|
||||
flat df.leftSB 0 [heading Upward]
|
||||
curl df.leftSB (top * 0.1) [heading Upward]
|
||||
quadcontrols 0 0.3 6 unimportant
|
||||
quadControls 0 0.3 6 unimportant
|
||||
g4 (eleft - HalfStroke) top [widths.rhs fine]
|
||||
|
||||
include : spiro-outline
|
||||
|
@ -40,7 +40,7 @@ glyph-block Letter-Latin-Upper-AE-OE : begin
|
|||
WithTransform [Translate (-O) 0] : spiro-outline
|
||||
corner df.leftSB 0 [heading Upward]
|
||||
curl df.leftSB (top * 0.1) [heading Upward]
|
||||
quadcontrols 0 0.3 6 unimportant
|
||||
quadControls 0 0.3 6 unimportant
|
||||
corner (eleft - HalfStroke) top [widths.rhs fine]
|
||||
corner eleft top
|
||||
corner eleft 0
|
||||
|
|
|
@ -138,23 +138,23 @@ glyph-block Letter-Latin-K : begin
|
|||
if fHookTop
|
||||
dispiro
|
||||
straight.left.start (kshRight + [if [maskBit slab 1] SideJut 0] - TanSlope * stroke) (top - stroke) [widths.rhs stroke]
|
||||
bezcontrols 0.5 0 0.5 0.65 8 : object : blend
|
||||
bezControls 0.5 0 0.5 0.65 8 : object : blend
|
||||
function [t] : widths.rhs : mix stroke fine t
|
||||
g4 xAttach1 yAttach1 [widths.rhs fine]
|
||||
dispiro
|
||||
g4.down.start (kshRight) top [widths.rhs.heading (stroke * kDiag) Downward]
|
||||
bezcontrols 0 0.2 0.5 0.65 8
|
||||
bezControls 0 0.2 0.5 0.65 8
|
||||
g4 xAttach1 yAttach1 [widths.rhs fine]
|
||||
include : difference
|
||||
dispiro
|
||||
widths.center
|
||||
g4.up.start (kshRight - O - stroke / 2 * HVContrast) 0 [heading Upward]
|
||||
quadcontrols 0 0.25 8
|
||||
quadControls 0 0.25 8
|
||||
g4 xAttach2 yAttach2 [widths.center fine]
|
||||
if fHookTop
|
||||
spiro-outline
|
||||
straight.left.start (kshRight + [if [maskBit slab 1] SideJut 0] - TanSlope * stroke) (top - stroke + 0.1)
|
||||
bezcontrols 0.5 0 0.5 0.65 8
|
||||
bezControls 0.5 0 0.5 0.65 8
|
||||
corner (xAttach1 - 0.1) yAttach1
|
||||
corner (-Width) yAttach1
|
||||
corner (-Width) (top * 2)
|
||||
|
@ -162,7 +162,7 @@ glyph-block Letter-Latin-K : begin
|
|||
corner (2 * Width) (top - stroke + 0.1)
|
||||
spiro-outline
|
||||
corner.down.start (kshRight - 1) top
|
||||
bezcontrols 0 0.2 0.5 0.65 8
|
||||
bezControls 0 0.2 0.5 0.65 8
|
||||
corner (kshLeft + stroke) (yAttach1 + 1)
|
||||
corner kshLeft 0
|
||||
corner kshLeft top
|
||||
|
|
|
@ -60,7 +60,7 @@ glyph-block Letter-Latin-Lower-Y : begin
|
|||
: else : return : list
|
||||
flat x top [widths.heading hl hr Downward]
|
||||
curl x (top - ds) [widths.heading hl hr Downward]
|
||||
quadcontrols 0 dpy1 16
|
||||
quadControls 0 dpy1 16
|
||||
|
||||
define [yBaseKnots top bottom shrink hooktop] : begin
|
||||
local {ds ds2} : CalcDS top bottom
|
||||
|
@ -86,7 +86,7 @@ glyph-block Letter-Latin-Lower-Y : begin
|
|||
curl [Math.min (yrstrokel - slabysize - 0.1) (yrstrokel - Stroke - yBottomJut)] bottom
|
||||
true : list
|
||||
ConnectZ 1
|
||||
quadcontrols 1 (1 - dpy2) 16
|
||||
quadControls 1 (1 - dpy2) 16
|
||||
flat yrstrokel (bottom + ds2) [widths.heading 0 Stroke Downward]
|
||||
curl yrstrokel bottom [widths.heading 0 Stroke Downward]
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ glyph-block Letter-Latin-Upper-R : begin
|
|||
dispiro
|
||||
widths.center sw
|
||||
g4.up.start xRightBottom bottom [heading Upward]
|
||||
quadcontrols 0 0.4 8
|
||||
quadControls 0 0.4 8
|
||||
g4 left top
|
||||
if slab : begin
|
||||
include : RightwardBottomSerif right bottom (SideJut + Jut / 8)
|
||||
|
@ -85,7 +85,7 @@ glyph-block Letter-Latin-Upper-R : begin
|
|||
dispiro
|
||||
widths.center sw
|
||||
g4.up.start xLeftBottom bottom [heading Upward]
|
||||
quadcontrols 0 0.4 8
|
||||
quadControls 0 0.4 8
|
||||
g4 right top
|
||||
if slab : begin
|
||||
include : LeftwardBottomSerif left bottom (SideJut + Jut / 8)
|
||||
|
|
|
@ -52,7 +52,7 @@ glyph-block Letter-Latin-Upper-Y : begin
|
|||
widths.rhs
|
||||
straight.left.start (RightSB + HookX / 3) (CAP - Stroke)
|
||||
g4 (RightSB - HookX / 3) (CAP - Hook)
|
||||
quadcontrols 0.55 0.7 32 unimportant
|
||||
quadControls 0.55 0.7 32 unimportant
|
||||
g4 (Middle + Stroke / 2 * HVContrast) cross
|
||||
|
||||
|
||||
|
|
|
@ -51,10 +51,10 @@ glyph-block Letter-Latin-V : begin
|
|||
include : spiro-outline
|
||||
flat vxStartL top
|
||||
curl vxStartL [VShapeTopFlat top]
|
||||
quadcontrols 0 VCurviness 9 unimportant
|
||||
quadControls 0 VCurviness 9 unimportant
|
||||
corner vxEndL 0
|
||||
corner vxEndR 0
|
||||
quadcontrols 1 (1 - VCurviness) 9 unimportant
|
||||
quadControls 1 (1 - VCurviness) 9 unimportant
|
||||
flat vxStartR [VShapeTopFlat top]
|
||||
curl vxStartR top
|
||||
|
||||
|
@ -90,13 +90,13 @@ glyph-block Letter-Latin-V : begin
|
|||
widths.lhs sw
|
||||
flat df.leftSB top [heading Downward]
|
||||
curl df.leftSB [VShapeTopFlat top] [heading Downward]
|
||||
quadcontrols 0 VCurviness 9 unimportant
|
||||
quadControls 0 VCurviness 9 unimportant
|
||||
g4 (df.middle - cornerHW) 0 [widths.lhs fine]
|
||||
include : tagged 'strokeUp' : dispiro
|
||||
widths.rhs sw
|
||||
flat df.rightSB top [heading Downward]
|
||||
curl df.rightSB [VShapeTopFlat top] [heading Downward]
|
||||
quadcontrols 0 VCurviness 9 unimportant
|
||||
quadControls 0 VCurviness 9 unimportant
|
||||
g4 (df.middle + cornerHW) 0 [widths.rhs fine]
|
||||
|
||||
#bottom cap
|
||||
|
@ -128,7 +128,7 @@ glyph-block Letter-Latin-V : begin
|
|||
widths.rhs
|
||||
straight.left.start (RightSB + HookX / 3) (top - Stroke)
|
||||
g4 (RightSB - HookX / 3) (top - HalfStroke - Hook)
|
||||
quadcontrols 0.4 0.75 64 unimportant
|
||||
quadControls 0.4 0.75 64 unimportant
|
||||
g4 (Middle + VCornerHalfWidth) 0 [widths.rhs VShapeFine]
|
||||
|
||||
define [VSerifs top] : let [sf : SerifFrame top 0 SB RightSB] : begin
|
||||
|
|
|
@ -136,7 +136,7 @@ glyph-block Letter-Latin-W : begin
|
|||
widths.lhs dim.strokeOuter
|
||||
flat df.leftSB top [heading Downward]
|
||||
curl df.leftSB (top * (1 - dim.curlyStraightSegLength)) [heading Downward]
|
||||
quadcontrols 0 0.3 6 unimportant
|
||||
quadControls 0 0.3 6 unimportant
|
||||
g4 (dim.xBot1 - 0.5 * HVContrast * dim.wCoCr) 0 [widths.lhs.heading dim.fineOuterCr Downward]
|
||||
|
||||
local kTopShift : match bodyType
|
||||
|
@ -174,7 +174,7 @@ glyph-block Letter-Latin-W : begin
|
|||
widths.rhs dim.strokeOuter
|
||||
flat df.rightSB top [heading Downward]
|
||||
curl df.rightSB (top * (1 - dim.curlyStraightSegLength)) [heading Downward]
|
||||
quadcontrols 0 0.3 6 unimportant
|
||||
quadControls 0 0.3 6 unimportant
|
||||
g4 (dim.xBot2 + 0.5 * HVContrast * dim.wCoCr) 0 [widths.rhs.heading dim.fineOuterCr Downward]
|
||||
|
||||
local oSlabPos : if bodyType (O * 2) 0
|
||||
|
@ -201,7 +201,7 @@ glyph-block Letter-Latin-W : begin
|
|||
include : dispiro
|
||||
widths.rhs dim.strokeOuter
|
||||
straight.down.start df.rightSB (top - Hook) [heading Downward]
|
||||
quadcontrols 0 0.3 6 unimportant
|
||||
quadControls 0 0.3 6 unimportant
|
||||
g4 (dim.xBot2 + 0.5 * HVContrast * dim.wCoCr) 0 [widths.rhs.heading dim.fineOuterCr Downward]
|
||||
|
||||
include : VerticalHook (df.rightSB - 0.5 * dim.strokeOuter * HVContrast) (top - Hook) (HookX * 0.65) (-Hook + 0.5 * dim.strokeOuter) dim.strokeOuter
|
||||
|
|
|
@ -37,7 +37,7 @@ glyph-block Letter-Latin-X : begin
|
|||
widths.center
|
||||
flat leftx lefty [heading [if (lefty < righty) Upward Downward]]
|
||||
curl leftx turnyleft [heading [if (lefty < righty) Upward Downward]]
|
||||
quadcontrols 0 ((cyleft - turnyleft) / (straightyleft - turnyleft)) 24
|
||||
quadControls 0 ((cyleft - turnyleft) / (straightyleft - turnyleft)) 24
|
||||
flat straightxleft straightyleft
|
||||
curl rightx righty
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ glyph-block Letter-Shared-Shapes : begin
|
|||
g4 right (wide + rinner - O / 2) [widths.heading 0 fine {.x (-HVContrast) .y ((wide - fine) / (wide + rinner * 2 - O))}]
|
||||
arcvh 8
|
||||
g4.left.mid mid (wide + rinner * 2 - O) [heading Leftward]
|
||||
quadcontrols ((x1 - mid) / (x2 - mid)) 0 8
|
||||
quadControls ((x1 - mid) / (x2 - mid)) 0 8
|
||||
g4 x2 y2
|
||||
|
||||
glyph-block-export ShoulderMidKnotLhs
|
||||
|
|
|
@ -475,7 +475,7 @@ glyph-block Marks : begin
|
|||
include : dispiro
|
||||
widths.rhs : Math.min radius (markFine * [linreg 16 2 90 1.75 (markHalfStroke * 2)])
|
||||
straight.down.start (markMiddle + radius) (aboveMarkTop - radius + commaOvershoot)
|
||||
quadcontrols 0 0.6
|
||||
quadControls 0 0.6
|
||||
g4 [mix markMiddle (markMiddle - radius) 0.2] (aboveMarkBot - radius - commaOvershoot2)
|
||||
include : ApparentTranslate 0 (DotRadius * 0.3)
|
||||
|
||||
|
@ -503,7 +503,7 @@ glyph-block Marks : begin
|
|||
include : dispiro
|
||||
widths.lhs : Math.min radius (markFine * [linreg 16 2 90 1.75 (markHalfStroke * 2)])
|
||||
straight.down.start (markMiddle - radius) (aboveMarkTop - radius + commaOvershoot)
|
||||
quadcontrols 0 0.6
|
||||
quadControls 0 0.6
|
||||
g4 [mix markMiddle (markMiddle + radius) 0.2] (aboveMarkBot - radius - commaOvershoot2)
|
||||
include : ApparentTranslate 0 (DotRadius * 0.3)
|
||||
|
||||
|
@ -1170,7 +1170,7 @@ glyph-block Marks : begin
|
|||
g4 (startX - radius) (startY + radius) [widths.rhs (hornFine / 2)]
|
||||
archv
|
||||
g4 startX startY [widths.rhs hornFine]
|
||||
quadcontrols 0 0.75 16 : object : blend : lambda [t]
|
||||
quadControls 0 0.75 16 : object : blend : lambda [t]
|
||||
widths.rhs [mix hornFine hornStroke t]
|
||||
g4 (attX - overshootX - HalfStroke * HVContrast) (attY - overshootY - Stroke) [widths.rhs hornStroke]
|
||||
|
||||
|
@ -1353,9 +1353,9 @@ glyph-block Marks : begin
|
|||
include : dispiro
|
||||
widths.center (markHalfStroke * 2)
|
||||
g4 tieLeft aboveTieBottom
|
||||
quadcontrols 0.5 1
|
||||
quadControls 0.5 1
|
||||
g4.right.mid 0 aboveTieTop [heading Rightward]
|
||||
quadcontrols 0.5 0
|
||||
quadControls 0.5 0
|
||||
g4 tieRight aboveTieBottom
|
||||
|
||||
create-glyph 'turnTieAbove' 0x35D : glyph-proc
|
||||
|
@ -1365,9 +1365,9 @@ glyph-block Marks : begin
|
|||
include : dispiro
|
||||
widths.center (markHalfStroke * 2)
|
||||
g4 tieLeft aboveTieTop
|
||||
quadcontrols 0.5 1
|
||||
quadControls 0.5 1
|
||||
g4.right.mid 0 aboveTieBottom [heading Rightward]
|
||||
quadcontrols 0.5 0
|
||||
quadControls 0.5 0
|
||||
g4 tieRight aboveTieTop
|
||||
|
||||
create-glyph 'tieBelow' 0x35C : glyph-proc
|
||||
|
|
|
@ -31,7 +31,7 @@ glyph-block Digits-Six : begin
|
|||
g4.left.mid (Middle + CorrectionOMidS) (O)
|
||||
archv
|
||||
g4.up.mid (SB + OX) (ymiddlea + Stroke * 0.3) [widths.rhs coFine]
|
||||
quadcontrols 0 0.85
|
||||
quadControls 0 0.85
|
||||
g4 ([mix SB RightSB 0.85] - 0.25 * Stroke * HVContrast) (charTop - O) [widths.rhs]
|
||||
|
||||
glyph-block-export ClosedContourNineShape
|
||||
|
|
|
@ -95,7 +95,7 @@ glyph-block Symbol-Letter : begin
|
|||
include : dispiro
|
||||
widths.center fine
|
||||
g2 left [mix 0 CAP 0.33]
|
||||
quadcontrols 1 0.6
|
||||
quadControls 1 0.6
|
||||
g2 right [mix 0 CAP 0.8]
|
||||
arcvh
|
||||
g2 [mix middle right 0.5] (CAP - O - fine / 2)
|
||||
|
|
|
@ -17,7 +17,7 @@ glyph-block Symbol-Pictograph-Heart : begin
|
|||
local y3 : heart.mixY 0.75
|
||||
return : spiro-outline
|
||||
corner heart.xMid (heart.bottom + sw * tip)
|
||||
quadcontrols 1 (2 / 3)
|
||||
quadControls 1 (2 / 3)
|
||||
g4 (heart.right - O - sw) y2
|
||||
arcvh
|
||||
g4 [heart.mixXMidRight 0.5] (heart.top - sw * tip / 1.75)
|
||||
|
@ -31,7 +31,7 @@ glyph-block Symbol-Pictograph-Heart : begin
|
|||
g4 [heart.mixXMidLeft 0.5] (heart.top - sw * tip / 1.75)
|
||||
archv
|
||||
g4 (heart.left + O + sw) y2
|
||||
quadcontrols 0 (1 / 3)
|
||||
quadControls 0 (1 / 3)
|
||||
close
|
||||
|
||||
for-width-kinds WideWidth1 : begin
|
||||
|
|
|
@ -25,15 +25,15 @@ glyph-block Symbol-Punctuation-Brackets : begin
|
|||
define [ParenShape] : params [sw [dp DesignParameters]] : let [dim : ParenDim 0 dp] : dispiro
|
||||
widths.lhs sw
|
||||
g4 dim.inside dim.top
|
||||
quadcontrols 1 (1 - dp.parenCurliness)
|
||||
quadControls 1 (1 - dp.parenCurliness)
|
||||
g4 dim.outside dim.mid
|
||||
quadcontrols 0 dp.parenCurliness
|
||||
quadControls 0 dp.parenCurliness
|
||||
g4 dim.inside dim.bottom
|
||||
|
||||
define [ParenUpperShape sw] : let [dim : ParenDim 0] : dispiro
|
||||
widths.lhs sw
|
||||
g4 dim.inside dim.top
|
||||
quadcontrols 1 (1 - DesignParameters.parenCurliness)
|
||||
quadControls 1 (1 - DesignParameters.parenCurliness)
|
||||
g4.down.end dim.outside MosaicBottom [heading Downward]
|
||||
|
||||
define [ParenExtensionShape sw] : let [dim : ParenDim 0] : dispiro
|
||||
|
@ -44,14 +44,14 @@ glyph-block Symbol-Punctuation-Brackets : begin
|
|||
define [ParenLowerShape sw] : let [dim : ParenDim 0] : dispiro
|
||||
widths.lhs sw
|
||||
g4.down.start dim.outside MosaicTop [heading Downward]
|
||||
quadcontrols 0 DesignParameters.parenCurliness
|
||||
quadControls 0 DesignParameters.parenCurliness
|
||||
g4 dim.inside dim.bottom
|
||||
|
||||
define [ParenShapeMask delta] : let [dim : ParenDim delta] : spiro-outline
|
||||
corner dim.inside dim.top
|
||||
quadcontrols 1 (1 - DesignParameters.parenCurliness)
|
||||
quadControls 1 (1 - DesignParameters.parenCurliness)
|
||||
g4 dim.outside dim.mid
|
||||
quadcontrols 0 DesignParameters.parenCurliness
|
||||
quadControls 0 DesignParameters.parenCurliness
|
||||
corner dim.inside dim.bottom
|
||||
|
||||
create-glyph'parenLeft.normal' : glyph-proc
|
||||
|
|
|
@ -21,13 +21,13 @@ glyph-block Symbol-Punctuation-Guillemet : begin
|
|||
include : dispiro
|
||||
widths.center sw
|
||||
g4 [mix Middle RightSB extension] top
|
||||
quadcontrols 0.4 0.75
|
||||
quadControls 0.4 0.75
|
||||
g4 [mix Middle SB extension] [mix top bot 0.5] [widths.center.heading (cor * sw) Leftward]
|
||||
|
||||
include : dispiro
|
||||
widths.center (sw * cor)
|
||||
g4 [mix Middle SB extension] [mix top bot 0.5] [heading Rightward]
|
||||
quadcontrols (1 - 0.4) (1 - 0.75)
|
||||
quadControls (1 - 0.4) (1 - 0.75)
|
||||
g4 [mix Middle RightSB extension] bot [widths.center sw]
|
||||
|
||||
include : Translate (-(RightSB - SB) * 0.05) 0
|
||||
|
|
|
@ -60,7 +60,7 @@ glyph-block Symbol-Punctuation-Small : begin
|
|||
g4 0 (r + ro)
|
||||
archv
|
||||
g4 ro r [widths.rhs sw]
|
||||
quadcontrols (0 + TanSlope / 2) (0.5 - TanSlope * r / Descender) 12
|
||||
quadControls (0 + TanSlope / 2) (0.5 - TanSlope * r / Descender) 12
|
||||
g4 (-commaOverflow + Descender * TanSlope) Descender [widths.rhs swEnd]
|
||||
|
||||
create-glyph 'comma.square' : glyph-proc
|
||||
|
@ -76,7 +76,7 @@ glyph-block Symbol-Punctuation-Small : begin
|
|||
SquareAt 0 r r
|
||||
dispiro
|
||||
straight.down.mid r 0 [widths.rhs sw]
|
||||
quadcontrols (0 + TanSlope / 2) (0.5 - TanSlope * r / Descender) 12
|
||||
quadControls (0 + TanSlope / 2) (0.5 - TanSlope * r / Descender) 12
|
||||
g4 (-commaOverflow + Descender * TanSlope) Descender [widths.rhs swEnd]
|
||||
|
||||
|
||||
|
@ -111,7 +111,7 @@ glyph-block Symbol-Punctuation-Small : begin
|
|||
g4 0 (r + ro)
|
||||
archv
|
||||
g4 (-ro) r [widths.lhs sw]
|
||||
quadcontrols (0 - TanSlope / 2) (0.5 - TanSlope * r / Descender) 12
|
||||
quadControls (0 - TanSlope / 2) (0.5 - TanSlope * r / Descender) 12
|
||||
g4 (commaOverflow + Descender * TanSlope) Descender [widths.lhs swEnd]
|
||||
|
||||
create-glyph 'invertComma.square' : glyph-proc
|
||||
|
@ -127,7 +127,7 @@ glyph-block Symbol-Punctuation-Small : begin
|
|||
SquareAt 0 r r
|
||||
dispiro
|
||||
straight.down.mid (-r) 0 [widths.lhs sw]
|
||||
quadcontrols (0 - TanSlope / 2) (0.5 - TanSlope * r / Descender) 12
|
||||
quadControls (0 - TanSlope / 2) (0.5 - TanSlope * r / Descender) 12
|
||||
g4 (commaOverflow + Descender * TanSlope) Descender [widths.lhs swEnd]
|
||||
|
||||
select-variant 'comma' ',' (follow -- 'punctuationDot')
|
||||
|
|
|
@ -13,9 +13,9 @@ glyph-block Symbol-Punctuation-Ties : begin
|
|||
define [TieShape y k] : dispiro
|
||||
widths.[if (k>0) 'rhs' 'lhs'] OperatorStroke
|
||||
g4 (SB + OX) y
|
||||
quadcontrols 0.5 1
|
||||
quadControls 0.5 1
|
||||
g4.right.mid Middle (y - k * Descender / 3) [heading Rightward]
|
||||
quadcontrols 0.5 0
|
||||
quadControls 0.5 0
|
||||
g4 (RightSB - OX) y
|
||||
|
||||
create-glyph "overTie" 0x2040 : TieShape CAP 1
|
||||
|
|
34
font-src/kits/boole-kit.js
Normal file
34
font-src/kits/boole-kit.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
"use strict";
|
||||
|
||||
const TypoGeom = require("typo-geom");
|
||||
const { BooleanGeometry, TransformedGeometry } = require("../support/geometry");
|
||||
|
||||
exports.SetupBuilders = function ({ Glyph, GlobalTransform }) {
|
||||
function impl(operator, operands) {
|
||||
return function () {
|
||||
const operandGeometries = [];
|
||||
const forwardGizmo = this.gizmo || GlobalTransform;
|
||||
const backwardGizmo = forwardGizmo.inverse();
|
||||
for (const operand of operands) {
|
||||
const g1 = new Glyph();
|
||||
g1.gizmo = forwardGizmo;
|
||||
g1.include(operand);
|
||||
operandGeometries.push(new TransformedGeometry(g1.geometry, backwardGizmo));
|
||||
}
|
||||
return this.includeGeometry(
|
||||
new TransformedGeometry(
|
||||
new BooleanGeometry(operator, operandGeometries),
|
||||
forwardGizmo
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
const union = (...operands) => impl(TypoGeom.Boolean.ClipType.ctUnion, operands);
|
||||
const intersection = (...operands) => impl(TypoGeom.Boolean.ClipType.ctIntersection, operands);
|
||||
const difference = (...operands) => impl(TypoGeom.Boolean.ClipType.ctDifference, operands);
|
||||
return {
|
||||
union: union,
|
||||
intersection: intersection,
|
||||
difference: difference
|
||||
};
|
||||
};
|
|
@ -1,25 +0,0 @@
|
|||
import 'typo-geom' as TypoGeom
|
||||
import '../support/curve-util' as CurveUtil
|
||||
import '../support/geometry' as [object BooleanGeometry TransformedGeometry]
|
||||
|
||||
export : define [SetupBuilders args] : begin
|
||||
define [object Glyph GlobalTransform] args
|
||||
define [impl operator operands] : begin
|
||||
return : function [] : begin
|
||||
local operandGeometries {}
|
||||
local forwardGizmo : this.gizmo || GlobalTransform
|
||||
local backwardGizmo : forwardGizmo.inverse
|
||||
foreach operand [items-of operands] : begin
|
||||
local g1 : new Glyph
|
||||
set g1.gizmo forwardGizmo
|
||||
g1.include operand
|
||||
operandGeometries.push : new TransformedGeometry g1.geometry backwardGizmo
|
||||
|
||||
define geomPureBoolian : new BooleanGeometry operator operandGeometries
|
||||
this.includeGeometry : new TransformedGeometry geomPureBoolian forwardGizmo
|
||||
|
||||
define [union] : impl TypoGeom.Boolean.ClipType.ctUnion [{}.slice.call arguments 0]
|
||||
define [intersection] : impl TypoGeom.Boolean.ClipType.ctIntersection [{}.slice.call arguments 0]
|
||||
define [difference] : impl TypoGeom.Boolean.ClipType.ctDifference [{}.slice.call arguments 0]
|
||||
|
||||
return [object union intersection difference]
|
354
font-src/kits/spiro-kit.js
Normal file
354
font-src/kits/spiro-kit.js
Normal file
|
@ -0,0 +1,354 @@
|
|||
"use strict";
|
||||
|
||||
const SpiroJs = require("spiro");
|
||||
const CurveUtil = require("../support/curve-util");
|
||||
const Transform = require("../support/transform");
|
||||
const { SpiroExpansionContext1, SpiroExpansionContext2 } = require("../support/spiro-expand");
|
||||
const { fallback, mix, bez2, bez3 } = require("../support/utils");
|
||||
const { SpiroGeometry, CombineGeometry } = require("../support/geometry");
|
||||
|
||||
exports.SetupBuilders = function (bindings) {
|
||||
const { Contrast, GlobalTransform, Stroke, Superness } = bindings;
|
||||
const g4 = (x, y, f) => ({ x, y, type: "g4", af: f });
|
||||
const g2 = (x, y, f) => ({ x, y, type: "g2", af: f });
|
||||
const corner = (x, y, f) => ({ x, y, type: "corner", af: f });
|
||||
const flat = (x, y, f) => ({ x, y, type: "left", af: f });
|
||||
const curl = (x, y, f) => ({ x, y, type: "right", af: f });
|
||||
const close = f => ({ type: "close", af: f });
|
||||
const end = f => ({ type: "end", af: f });
|
||||
|
||||
const straight = { l: flat, r: curl };
|
||||
{
|
||||
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 }
|
||||
];
|
||||
let adhesions = [
|
||||
{ name: "start", l: 0, r: 0.01 },
|
||||
{ name: "mid", l: -0.005, r: 0.005 },
|
||||
{ name: "end", l: -0.01, r: 0 }
|
||||
];
|
||||
let knotTypes = [
|
||||
[g4, g4, g4],
|
||||
[g2, g2, g2],
|
||||
[corner, corner, corner],
|
||||
[straight, flat, curl]
|
||||
];
|
||||
for (const [sink, kl, kr] of knotTypes) {
|
||||
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)
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function widths(l, r) {
|
||||
return function () {
|
||||
return this.setWidth ? this.setWidth(l, r) : void 0;
|
||||
};
|
||||
}
|
||||
widths.lhs = function (w) {
|
||||
return widths(fallback(w, Stroke), 0);
|
||||
};
|
||||
widths.rhs = function (w) {
|
||||
return widths(0, fallback(w, Stroke));
|
||||
};
|
||||
widths.center = function (w) {
|
||||
return widths(fallback(w, Stroke) / 2, fallback(w, Stroke) / 2);
|
||||
};
|
||||
|
||||
function heading(d) {
|
||||
return function () {
|
||||
return this.headsTo ? this.headsTo(d) : void 0;
|
||||
};
|
||||
}
|
||||
widths.heading = function (l, r, d) {
|
||||
return function () {
|
||||
if (this.setWidth) this.setWidth(l, r);
|
||||
return this.headsTo ? this.headsTo(d) : void 0;
|
||||
};
|
||||
};
|
||||
widths.lhs.heading = function (w, d) {
|
||||
return function () {
|
||||
if (this.setWidth) this.setWidth(fallback(w, Stroke), 0);
|
||||
return this.headsTo ? this.headsTo(d) : void 0;
|
||||
};
|
||||
};
|
||||
widths.rhs.heading = function (w, d) {
|
||||
return function () {
|
||||
if (this.setWidth) this.setWidth(0, fallback(w, Stroke));
|
||||
return this.headsTo ? this.headsTo(d) : void 0;
|
||||
};
|
||||
};
|
||||
widths.center.heading = function (w, d) {
|
||||
return function () {
|
||||
if (this.setWidth) this.setWidth(fallback(w, Stroke) / 2, fallback(w, Stroke) / 2);
|
||||
return this.headsTo ? this.headsTo(d) : void 0;
|
||||
};
|
||||
};
|
||||
|
||||
function disableContrast() {
|
||||
return function () {
|
||||
return (this.contrast = 1);
|
||||
};
|
||||
}
|
||||
function unimportant() {
|
||||
return this.setUnimportant ? this.setUnimportant() : void 0;
|
||||
}
|
||||
function important() {
|
||||
return void 0;
|
||||
}
|
||||
function afInterpolate(before, after, args) {
|
||||
return g4(
|
||||
mix(before.x, after.x, args.rx),
|
||||
mix(before.y, after.y, args.ry),
|
||||
fallback(args.raf, unimportant)
|
||||
);
|
||||
}
|
||||
function afInterpolateG2(before, after, args) {
|
||||
return g2(
|
||||
mix(before.x, after.x, args.rx),
|
||||
mix(before.y, after.y, args.ry),
|
||||
fallback(args.raf, unimportant)
|
||||
);
|
||||
}
|
||||
function afInterpolateThem(before, after, args) {
|
||||
let innerKnots = [];
|
||||
for (const [rx, ry, rt] of args.rs) {
|
||||
innerKnots.push(
|
||||
fallback(args.ty, g2)(
|
||||
mix(before.x, after.x, rx),
|
||||
mix(before.y, after.y, ry),
|
||||
args.raf && args.raf.blend && rt !== void 0
|
||||
? args.raf.blend(rt)
|
||||
: args.raf
|
||||
? args.raf
|
||||
: unimportant
|
||||
)
|
||||
);
|
||||
}
|
||||
return innerKnots;
|
||||
}
|
||||
function afInterpolateSNeck(before, after, args) {
|
||||
return [
|
||||
g2(
|
||||
mix(before.x, after.x, 1 / 2 - args.px / 6),
|
||||
mix(before.y, after.y, 1 / 2 - args.py / 6),
|
||||
widths(args.sw * args.ps, args.sw * (1 - args.ps))
|
||||
),
|
||||
g2(
|
||||
mix(before.x, after.x, 1 / 2 + args.px / 6),
|
||||
mix(before.y, after.y, 1 / 2 + args.py / 6),
|
||||
widths(args.sw * (1 - args.ps), args.sw * args.ps)
|
||||
)
|
||||
];
|
||||
}
|
||||
function alsoThru(rx, ry, raf) {
|
||||
return { type: "interpolate", rx, ry, raf, af: afInterpolate };
|
||||
}
|
||||
alsoThru.g2 = function (rx, ry, raf) {
|
||||
return { type: "interpolate", rx, ry, raf, af: afInterpolateG2 };
|
||||
};
|
||||
alsoThru.sNeck = function (px, py, sw, ps) {
|
||||
return { type: "interpolate", px, py, sw, ps, af: afInterpolateSNeck };
|
||||
};
|
||||
function alsoThruThem(es, raf, ty) {
|
||||
return { type: "interpolate", rs: es, raf, ty, af: afInterpolateThem };
|
||||
}
|
||||
function bezControlsImpl(x1, y1, x2, y2, samples, raf, ty) {
|
||||
let rs = [];
|
||||
for (let j = 1; j < samples; j = j + 1)
|
||||
rs.push([
|
||||
bez3(0, x1, x2, 1, j / samples),
|
||||
bez3(0, y1, y2, 1, j / samples),
|
||||
j / samples
|
||||
]);
|
||||
return alsoThruThem(rs, raf);
|
||||
}
|
||||
function bezControls(x1, y1, x2, y2, _samples, raf) {
|
||||
return bezControlsImpl(x1, y1, x2, y2, fallback(_samples, 3), raf);
|
||||
}
|
||||
function quadControls(x1, y1, _samples, raf) {
|
||||
return bezControlsImpl(
|
||||
(x1 * 2) / 3,
|
||||
(y1 * 2) / 3,
|
||||
mix(1, x1, 2 / 3),
|
||||
mix(1, y1, 2 / 3),
|
||||
fallback(_samples, 3),
|
||||
raf
|
||||
);
|
||||
}
|
||||
|
||||
let DEFAULT_STEPS = 6;
|
||||
|
||||
let [buildHV, buildVH] = (function (cache) {
|
||||
function build(samples, _superness) {
|
||||
const superness = fallback(_superness, Superness);
|
||||
let hv = [];
|
||||
let vh = [];
|
||||
for (let j = 1; j < samples; j = j + 1) {
|
||||
const theta = (((j + 1) / (samples + 2)) * Math.PI) / 2;
|
||||
const c = Math.pow(Math.cos(theta), 2 / superness);
|
||||
const s = Math.pow(Math.sin(theta), 2 / superness);
|
||||
hv.push([s, 1 - c]);
|
||||
vh.push([1 - c, s]);
|
||||
}
|
||||
return { hv, vh: vh };
|
||||
}
|
||||
function buildHVImpl(samples, _superness) {
|
||||
if (_superness) return build(samples, _superness).hv;
|
||||
if (!cache[samples]) cache[samples] = build(samples, _superness);
|
||||
return cache[samples].hv;
|
||||
}
|
||||
function buildVHImpl(samples, _superness) {
|
||||
if (_superness) return build(samples, _superness).vh;
|
||||
if (!cache[samples]) cache[samples] = build(samples, _superness);
|
||||
return cache[samples].vh;
|
||||
}
|
||||
return [buildHVImpl, buildVHImpl];
|
||||
})([]);
|
||||
|
||||
function archv(samples, superness) {
|
||||
return alsoThruThem(buildHV(fallback(samples, DEFAULT_STEPS), superness));
|
||||
}
|
||||
archv.superness = function (s) {
|
||||
return archv(DEFAULT_STEPS, s);
|
||||
};
|
||||
function arcvh(samples, superness) {
|
||||
return alsoThruThem(buildVH(fallback(samples, DEFAULT_STEPS), superness));
|
||||
}
|
||||
arcvh.superness = function (s) {
|
||||
return arcvh(DEFAULT_STEPS, s);
|
||||
};
|
||||
function complexThru(...a) {
|
||||
return {
|
||||
type: "interpolate",
|
||||
af: function (before, after, args) {
|
||||
let ks = [];
|
||||
for (const knot of a) ks.push(knot.af.call(this, before, after, knot));
|
||||
return ks;
|
||||
}
|
||||
};
|
||||
}
|
||||
function flattenImpl(sink, knots) {
|
||||
for (const p of knots) {
|
||||
if (p instanceof Array) flattenImpl(sink, p);
|
||||
else sink.push(p);
|
||||
}
|
||||
}
|
||||
function nCyclic(p, n) {
|
||||
return (p + n + n) % n;
|
||||
}
|
||||
function flatten(s, knots0) {
|
||||
let knots = [];
|
||||
flattenImpl(knots, knots0);
|
||||
let unwrapped = false;
|
||||
for (let j = 0; j < knots.length; j = j + 1)
|
||||
if (knots[j] && knots[j].type === "interpolate") {
|
||||
const kBefore = knots[nCyclic(j - 1, knots.length)];
|
||||
const kAfter = knots[nCyclic(j + 1, knots.length)];
|
||||
knots[j] = knots[j].af.call(s, kBefore, kAfter, knots[j]);
|
||||
unwrapped = true;
|
||||
}
|
||||
if (unwrapped) return flatten(s, knots);
|
||||
return knots;
|
||||
}
|
||||
function dropTailKnot(knots) {
|
||||
let last = knots[knots.length - 1];
|
||||
if (last && (last.type === "close" || last.type === "end")) {
|
||||
knots.length = knots.length - 1;
|
||||
return last.type === "close";
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function prepareSpiroKnots(_knots, s) {
|
||||
let knots = _knots;
|
||||
while (knots[0] && knots[0] instanceof Function) {
|
||||
knots[0].call(s);
|
||||
knots.splice(0, 1);
|
||||
}
|
||||
const closed = dropTailKnot(knots);
|
||||
knots = flatten(s, knots);
|
||||
return { knots, closed };
|
||||
}
|
||||
function iterateNormals(s, closed) {
|
||||
let knotsP2 = s.getPass2Knots(closed, fallback(s.contrast, Contrast));
|
||||
let s2 = new SpiroExpansionContext2(s.controlKnots, s.gizmo);
|
||||
return SpiroJs.spiroToArcsOnContext(knotsP2, closed, s2);
|
||||
}
|
||||
function dispiro(...args) {
|
||||
return function () {
|
||||
let s = new SpiroExpansionContext1(this.gizmo || GlobalTransform);
|
||||
let { knots, closed } = prepareSpiroKnots([].slice.call(args, 0), s);
|
||||
for (const knot of knots) {
|
||||
const ty = knot.type;
|
||||
const af = knot.af;
|
||||
knot.af = function () {
|
||||
this.setType(ty);
|
||||
return af ? af.apply(this, args) : void 0;
|
||||
};
|
||||
}
|
||||
|
||||
SpiroJs.spiroToArcsOnContext(knots, closed, s);
|
||||
iterateNormals(s, closed);
|
||||
iterateNormals(s, closed);
|
||||
const { lhs, rhs } = s.expand(fallback(s.contrast, Contrast));
|
||||
|
||||
if (closed) {
|
||||
this.includeGeometry(
|
||||
new CombineGeometry([
|
||||
new SpiroGeometry(lhs.slice(0, -1), closed, Transform.Id()),
|
||||
new SpiroGeometry(rhs.reverse().slice(0, -1), closed, Transform.Id())
|
||||
])
|
||||
);
|
||||
} else {
|
||||
lhs[0].type = lhs[lhs.length - 1].type = "corner";
|
||||
rhs[0].type = rhs[rhs.length - 1].type = "corner";
|
||||
const allKnots = lhs.concat(rhs.reverse());
|
||||
this.includeGeometry(new SpiroGeometry(allKnots, true, Transform.Id()));
|
||||
}
|
||||
return { knots, lhsKnots: lhs, rhsKnots: rhs };
|
||||
};
|
||||
}
|
||||
|
||||
function spiroOutline(...args) {
|
||||
return function () {
|
||||
const gizmo = this.gizmo || GlobalTransform;
|
||||
const g = new CurveUtil.BezToContoursSink(gizmo);
|
||||
const { knots, closed } = prepareSpiroKnots(args, g);
|
||||
return this.includeGeometry(new SpiroGeometry(knots, closed, gizmo));
|
||||
};
|
||||
}
|
||||
return {
|
||||
g4,
|
||||
g2,
|
||||
corner,
|
||||
flat,
|
||||
curl,
|
||||
close,
|
||||
end,
|
||||
straight,
|
||||
widths,
|
||||
heading,
|
||||
"disable-contrast": disableContrast,
|
||||
unimportant,
|
||||
important,
|
||||
alsoThru,
|
||||
alsoThruThem,
|
||||
bezControls,
|
||||
quadControls,
|
||||
archv,
|
||||
arcvh,
|
||||
complexThru,
|
||||
dispiro,
|
||||
"spiro-outline": spiroOutline
|
||||
};
|
||||
};
|
|
@ -1,226 +0,0 @@
|
|||
import 'spiro' as SpiroJs
|
||||
import '../support/curve-util' as CurveUtil
|
||||
import '../support/transform' as Transform
|
||||
import [SpiroExpansionContext1 SpiroExpansionContext2] from '../support/spiro-expand'
|
||||
import [fallback mix bez2 bez3] from '../support/utils'
|
||||
import [SpiroGeometry CombineGeometry] from "../support/geometry"
|
||||
|
||||
export : define [SetupBuilders args] : begin
|
||||
define [object para Glyph Contrast GlobalTransform Stroke] args
|
||||
|
||||
define [g4 x y f] {.x x .y y .type 'g4' .af f}
|
||||
define [g2 x y f] {.x x .y y .type 'g2' .af f}
|
||||
define [corner x y f] {.x x .y y .type 'corner' .af f}
|
||||
define [flat x y f] {.x x .y y .type 'left' .af f}
|
||||
define [curl x y f] {.x x .y y .type 'right' .af f}
|
||||
define [close f] {.type 'close' .af f}
|
||||
define [end f] {.type 'end' .af f}
|
||||
|
||||
define straight {.l flat .r curl}
|
||||
|
||||
#directional bi-knots
|
||||
let
|
||||
directions : list
|
||||
* {.name 'up' .x 0 .y 1}
|
||||
* {.name 'down' .x 0 .y (-1)}
|
||||
* {.name 'left' .x (-1) .y 0}
|
||||
* {.name 'right' .x 1 .y 0}
|
||||
adhensions : list
|
||||
* {.name 'start' .l 0 .r 0.01}
|
||||
* {.name 'mid' .l (-0.005) .r 0.005}
|
||||
* {.name 'end' .l (-0.01) .r 0}
|
||||
knotTypes : list
|
||||
* {g4 g4 g4}
|
||||
* {g2 g2 g2}
|
||||
* {corner corner corner}
|
||||
* {straight flat curl}
|
||||
foreach [_kt : items-of knotTypes] : let [{ sink kl kr } _kt] : begin
|
||||
foreach [_d : items-of directions] : let [d _d] : begin
|
||||
set sink.(d.name) {.}
|
||||
foreach [adh : items-of adhensions] : let [a adh] : begin
|
||||
set sink.(d.name).(a.name) : lambda [x y af] : list
|
||||
kl (x + d.x * a.l) (y + d.y * a.l) af
|
||||
kr (x + d.x * a.r) (y + d.y * a.r) af
|
||||
|
||||
# Aux functions
|
||||
define [widths l r] : lambda [] : if this.setWidth : this.setWidth l r
|
||||
define [widths.lhs w] : widths [fallback w Stroke] 0
|
||||
define [widths.rhs w] : widths 0 [fallback w Stroke]
|
||||
define [widths.center w] : widths ([fallback w Stroke] / 2) ([fallback w Stroke] / 2)
|
||||
|
||||
# Gizmo handler
|
||||
define [disable-contrast] : lambda [] : set this.contrast 1
|
||||
|
||||
define [heading d] : lambda [] : if (this.headsTo) : this.headsTo d
|
||||
define [widths.heading l r d] : lambda [] : begin
|
||||
if this.setWidth : this.setWidth l r
|
||||
if this.headsTo : this.headsTo d
|
||||
define [widths.lhs.heading w d] : lambda [] : begin
|
||||
if this.setWidth : this.setWidth [fallback w Stroke] 0
|
||||
if this.headsTo : this.headsTo d
|
||||
define [widths.rhs.heading w d] : lambda [] : begin
|
||||
if this.setWidth : this.setWidth 0 [fallback w Stroke]
|
||||
if this.headsTo : this.headsTo d
|
||||
define [widths.center.heading w d] : lambda [] : begin
|
||||
if this.setWidth : this.setWidth ([fallback w Stroke] / 2) ([fallback w Stroke] / 2)
|
||||
if this.headsTo : this.headsTo d
|
||||
define [unimportant] : if this.setUnimportant : this.setUnimportant
|
||||
define [important] nothing
|
||||
|
||||
# Interpolation pesudoknots
|
||||
define [afInterpolate before after args] : g4
|
||||
mix before.x after.x args.rx
|
||||
mix before.y after.y args.ry
|
||||
fallback args.raf unimportant
|
||||
define [afInterpolateG2 before after args] : g2
|
||||
mix before.x after.x args.rx
|
||||
mix before.y after.y args.ry
|
||||
fallback args.raf unimportant
|
||||
define [afInterpolateThem before after args] : begin
|
||||
local innerKnots {}
|
||||
foreach {rx ry rt} [items-of args.rs] : innerKnots.push : [fallback args.ty g2]
|
||||
mix before.x after.x rx
|
||||
mix before.y after.y ry
|
||||
piecewise
|
||||
(args.raf && args.raf.blend && (rt != nothing)) [args.raf.blend rt]
|
||||
args.raf args.raf
|
||||
true unimportant
|
||||
return innerKnots
|
||||
define [afInterpolateSNeck before after args] : list
|
||||
g2
|
||||
mix before.x after.x (1 / 2 - args.px / 6)
|
||||
mix before.y after.y (1 / 2 - args.py / 6)
|
||||
widths (args.sw * args.ps) (args.sw * (1 - args.ps))
|
||||
g2
|
||||
mix before.x after.x (1 / 2 + args.px / 6)
|
||||
mix before.y after.y (1 / 2 + args.py / 6)
|
||||
widths (args.sw * (1 - args.ps)) (args.sw * args.ps)
|
||||
|
||||
define [alsoThru rx ry raf] {.type 'interpolate' .rx rx .ry ry .raf raf .af afInterpolate}
|
||||
set alsoThru.g2 : lambda [rx ry raf] {.type 'interpolate' .rx rx .ry ry .raf raf .af afInterpolateG2}
|
||||
set alsoThru.sNeck : lambda [px py sw ps] {.type 'interpolate' .px px .py py .sw sw .ps ps .af afInterpolateSNeck}
|
||||
define [alsoThruThem rs raf ty] {.type 'interpolate' .rs rs .raf raf .ty ty .af afInterpolateThem}
|
||||
define [bezControlsImpl x1 y1 x2 y2 samples raf ty] : begin
|
||||
local rs {}
|
||||
foreach j [range 1 samples] : rs.push : list
|
||||
bez3 0 x1 x2 1 (j / samples)
|
||||
bez3 0 y1 y2 1 (j / samples)
|
||||
j / samples
|
||||
alsoThruThem rs raf
|
||||
define [bezcontrols x1 y1 x2 y2 _samples raf]
|
||||
bezControlsImpl x1 y1 x2 y2 [fallback _samples 3] raf
|
||||
define [quadcontrols x1 y1 _samples raf]
|
||||
bezControlsImpl (x1 * 2 / 3) (y1 * 2 / 3) [mix 1 x1 (2 / 3)] [mix 1 y1 (2 / 3)] [fallback _samples 3] raf
|
||||
|
||||
define DEFAULT_STEPS 6
|
||||
define {jhv, jvh} : let [cache {}] : begin
|
||||
local [build samples _superness] : begin
|
||||
local superness : fallback _superness args.superness
|
||||
local hv {}
|
||||
local vh {}
|
||||
foreach [j : range 1 samples] : begin
|
||||
local theta : (j + 1) / (samples + 2) * Math.PI / 2
|
||||
local c : Math.pow [Math.cos theta] (2 / superness)
|
||||
local s : Math.pow [Math.sin theta] (2 / superness)
|
||||
hv.push { s (1 - c) }
|
||||
vh.push { (1 - c) s }
|
||||
return {.hv hv .vh vh}
|
||||
local [hv samples _superness] : begin
|
||||
if (_superness) : return [build samples _superness].hv
|
||||
if (!cache.(samples)) : set cache.(samples) : build samples _superness
|
||||
return cache.(samples).hv
|
||||
local [vh samples _superness] : begin
|
||||
if (_superness) : return [build samples _superness].vh
|
||||
if (!cache.(samples)) : set cache.(samples) : build samples _superness
|
||||
return cache.(samples).vh
|
||||
list hv vh
|
||||
define [archv samples superness] : alsoThruThem [jhv [fallback samples DEFAULT_STEPS] superness]
|
||||
set archv.superness : lambda [s] : archv DEFAULT_STEPS s
|
||||
define [arcvh samples superness] : alsoThruThem [jvh [fallback samples DEFAULT_STEPS] superness]
|
||||
set arcvh.superness : lambda [s] : arcvh DEFAULT_STEPS s
|
||||
|
||||
define [complexThru] : begin
|
||||
local a : {}.slice.call arguments
|
||||
return {.type 'interpolate' .af [lambda [before after args] : begin \\
|
||||
local ks {}
|
||||
foreach knot [items-of a] : ks.push [knot.af.call this before after knot]
|
||||
return ks
|
||||
]}
|
||||
|
||||
|
||||
define [flattenImpl sink knots] : begin
|
||||
foreach p [items-of knots] : piecewise
|
||||
(p <@ Array) : flattenImpl sink p
|
||||
true : sink.push p
|
||||
define [nCyclic p n] : (p + n + n) % n
|
||||
define [flatten s knots0] : begin
|
||||
local knots : list
|
||||
flattenImpl knots knots0
|
||||
|
||||
# Unwrap interpolation knots
|
||||
local unwrapped false
|
||||
foreach j [range 0 knots.length] : if (knots.(j) && knots.(j).type === 'interpolate') : begin
|
||||
local kBefore knots.[nCyclic (j - 1) knots.length]
|
||||
local kAfter knots.[nCyclic (j + 1) knots.length]
|
||||
set knots.(j) : knots.(j).af.call s kBefore kAfter knots.(j)
|
||||
set unwrapped true
|
||||
|
||||
if unwrapped : return : flatten s knots
|
||||
return knots
|
||||
|
||||
define [dropTailKnot knots] : begin
|
||||
define last knots.(knots.length - 1)
|
||||
if (last && (last.type === 'close' || last.type === 'end')) : begin
|
||||
set knots.length : knots.length - 1
|
||||
return : last.type === 'close'
|
||||
|
||||
define [prepareSpiroKnots _knots s] : begin
|
||||
local knots _knots
|
||||
while (knots.0 && knots.0 <@ Function) : begin [knots.0.call s] [knots.splice 0 1]
|
||||
define closed : dropTailKnot knots
|
||||
set knots : flatten s knots
|
||||
return { .knots knots .closed closed }
|
||||
|
||||
define [iterateNormals s closed] : begin
|
||||
local knotsP2 : s.getPass2Knots closed [fallback s.contrast Contrast]
|
||||
local s2 : new SpiroExpansionContext2 s.controlKnots s.gizmo
|
||||
SpiroJs.spiroToArcsOnContext knotsP2 closed s2
|
||||
|
||||
define [dispiro] : let [args : {}.slice.call arguments 0] : lambda [] : begin
|
||||
define CLOSED true
|
||||
local s : new SpiroExpansionContext1 (this.gizmo || GlobalTransform)
|
||||
local { .knots knots .closed closed } : prepareSpiroKnots [{}.slice.call args 0] s
|
||||
foreach knot [items-of knots] : let [ty knot.type] [af knot.af] : begin
|
||||
set knot.af : lambda [] : begin
|
||||
this.setType ty
|
||||
if af : af.apply this args
|
||||
|
||||
SpiroJs.spiroToArcsOnContext knots closed s
|
||||
iterateNormals s closed
|
||||
iterateNormals s closed
|
||||
local {.lhs lhs .rhs rhs} : s.expand [fallback s.contrast Contrast]
|
||||
|
||||
if closed : then
|
||||
this.includeGeometry : new CombineGeometry : list
|
||||
new SpiroGeometry [lhs.slice 0 (-1)] closed [Transform.Id]
|
||||
new SpiroGeometry [rhs.reverse :.slice 0 (-1)] closed [Transform.Id]
|
||||
|
||||
: else : begin
|
||||
lhs.0.type = lhs.(lhs.length - 1).type = 'corner'
|
||||
rhs.0.type = rhs.(rhs.length - 1).type = 'corner'
|
||||
define allKnots : lhs.concat : rhs.reverse
|
||||
this.includeGeometry : new SpiroGeometry allKnots CLOSED [Transform.Id]
|
||||
|
||||
return { .knots knots .lhsKnots lhs .rhsKnots rhs }
|
||||
|
||||
define [spiro-outline] : let [k : {}.slice.call arguments 0] : lambda [] : begin
|
||||
local gizmo : this.gizmo || GlobalTransform
|
||||
local g : new CurveUtil.BezToContoursSink gizmo
|
||||
local { .knots knots .closed closed } : prepareSpiroKnots k g
|
||||
this.includeGeometry : new SpiroGeometry knots closed gizmo
|
||||
|
||||
return [object
|
||||
g4 g2 corner flat curl close end straight
|
||||
widths disable-contrast heading unimportant important
|
||||
alsoThru alsoThruThem bezcontrols quadcontrols archv arcvh complexThru
|
||||
dispiro spiro-outline]
|
|
@ -221,8 +221,8 @@ define-macro glyph-block : syntax-rules
|
|||
adviceGlottalStopSmooth shoulderMidSlope StrokeWidthBlend SmoothAOf SmoothBOf
|
||||
SmoothAdjust MidJutSide MidJutCenter compositeBaseAnchors YSmoothMidR YSmoothMidL]
|
||||
define spiroFnImports `[g4 g2 corner flat curl close end straight widths
|
||||
disable-contrast heading unimportant important alsoThru alsoThruThem bezcontrols
|
||||
quadcontrols archv arcvh complexThru dispiro spiro-outline]
|
||||
disable-contrast heading unimportant important alsoThru alsoThruThem bezControls
|
||||
quadControls archv arcvh complexThru dispiro spiro-outline]
|
||||
define booleFnImports `[union intersection difference]
|
||||
|
||||
dirty `[$GlyphBlocks$.push : lambda [$Capture_Ext$] : begin \\
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue