Add frakturs in the Letterlike Symbols (#2438)
* * Add characters: - BLACK-LETTER CAPITAL I (`U+2111`). - BLACK-LETTER CAPITAL R (`U+211C`). * Complete frakturs in Letterlike Symbols block * Update geom cache version
This commit is contained in:
parent
61ad3c365c
commit
bff9e0b1c5
11 changed files with 496 additions and 8 deletions
6
changes/31.0.1.md
Normal file
6
changes/31.0.1.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
* Add characters:
|
||||||
|
- BLACK-LETTER CAPITAL H (`U+210C`).
|
||||||
|
- BLACK-LETTER CAPITAL I (`U+2111`).
|
||||||
|
- BLACK-LETTER CAPITAL R (`U+211C`).
|
||||||
|
- BLACK-LETTER CAPITAL Z (`U+2128`).
|
||||||
|
- BLACK-LETTER CAPITAL C (`U+212D`).
|
|
@ -1,16 +1,14 @@
|
||||||
{
|
{
|
||||||
"name": "@iosevka/monorepo",
|
"name": "@iosevka/monorepo",
|
||||||
"version": "31.0.0",
|
"version": "31.0.0",
|
||||||
"workspaces": [
|
"workspaces": ["packages/*", "tools/*"],
|
||||||
"packages/*",
|
|
||||||
"tools/*"
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "verda -f verdafile.mjs",
|
"build": "verda -f verdafile.mjs",
|
||||||
"bump-ver": "node tools/misc/src/update-package-json-version.mjs && npm install && node tools/misc/src/generate-ttfa-ranges.mjs",
|
"bump-ver": "node tools/misc/src/update-package-json-version.mjs && npm install && node tools/misc/src/generate-ttfa-ranges.mjs",
|
||||||
"clean": "verda -f verdafile.mjs clean",
|
"clean": "verda -f verdafile.mjs clean",
|
||||||
"lint": "eslint",
|
"lint": "eslint",
|
||||||
"lint:fix": "eslint --fix",
|
"lint:fix": "eslint --fix",
|
||||||
|
"copy-char-name-to-markdown": "node tools/misc/src/copy-char-name-to-markdown.mjs",
|
||||||
"generate-release-sha-file": "node tools/misc/src/generate-release-sha-file.mjs release-archives/*.zip release-archives/SHA-256.txt"
|
"generate-release-sha-file": "node tools/misc/src/generate-release-sha-file.mjs release-archives/*.zip release-archives/SHA-256.txt"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -120,6 +120,7 @@ export : define [buildGlyphs para recursive] : begin
|
||||||
|
|
||||||
# Letter-likes
|
# Letter-likes
|
||||||
run-glyph-module "./letter-like/cursive.mjs"
|
run-glyph-module "./letter-like/cursive.mjs"
|
||||||
|
run-glyph-module "./letter-like/fraktur.mjs"
|
||||||
|
|
||||||
# Symbols
|
# Symbols
|
||||||
run-glyph-module "./symbol/shared.mjs"
|
run-glyph-module "./symbol/shared.mjs"
|
||||||
|
|
295
packages/font-glyphs/src/letter-like/fraktur.ptl
Normal file
295
packages/font-glyphs/src/letter-like/fraktur.ptl
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
###### Fraktur letterforms
|
||||||
|
###
|
||||||
|
### This file is used to define the letterforms of the Fraktur style.
|
||||||
|
### For simplicity, the letters here will *NOT* support any variants.
|
||||||
|
###
|
||||||
|
|
||||||
|
$$include '../meta/macros.ptl'
|
||||||
|
|
||||||
|
import [mix fallback] from "@iosevka/util"
|
||||||
|
import [SpiroPenGeometry] from "@iosevka/geometry"
|
||||||
|
import [Vec2] from "@iosevka/geometry/point"
|
||||||
|
|
||||||
|
glyph-module
|
||||||
|
|
||||||
|
glyph-block LetterLike-Fraktur-Shared : begin
|
||||||
|
|
||||||
|
# [fraktur-stroke profile ...] will construct a Fraktur stroke from a pen profile and a list
|
||||||
|
# of control knots. The knots will form a (usually open) spiro path, then the result will be
|
||||||
|
# the area that the pen tip covers when moving along the path.
|
||||||
|
glyph-block-export fraktur-stroke
|
||||||
|
define [fraktur-stroke profile __knots] : begin
|
||||||
|
local knots : {}.slice.call arguments 1
|
||||||
|
return : new FrakturImpl profile knots
|
||||||
|
|
||||||
|
class FrakturImpl
|
||||||
|
public [new profile knots] : begin
|
||||||
|
this.profile = profile
|
||||||
|
this.knots = knots
|
||||||
|
|
||||||
|
public [applyToGlyph glyph] : begin
|
||||||
|
local c : spiro-collect glyph this.knots
|
||||||
|
local geom : new SpiroPenGeometry
|
||||||
|
begin c.gizmo
|
||||||
|
begin c.collector.closed
|
||||||
|
this.profile.getPenShape c.gizmo
|
||||||
|
c.collector.controls.map : function [k] [k.toMono]
|
||||||
|
return : glyph.includeGeometry geom
|
||||||
|
|
||||||
|
|
||||||
|
# A pen profile describes a virtual flat-tip pen. We use a 45-degree arrangement to
|
||||||
|
# simplify the math.
|
||||||
|
class FrakturProfile
|
||||||
|
public [new thick thin] : begin
|
||||||
|
# .thick is the half length of the flat tip, projected to the X/Y axis
|
||||||
|
this.thick = 0.25 * [Math.sqrt 2] * thick
|
||||||
|
# .thin is the half width of the thin tip, projected to the X/Y axis
|
||||||
|
this.thin = 0.25 * [Math.sqrt 2] * thin
|
||||||
|
|
||||||
|
public [getPenShape gizmo] : begin
|
||||||
|
local thickTf : gizmo.applyOffsetXY this.thick this.thick
|
||||||
|
list
|
||||||
|
new Vec2 (thickTf.x - this.thin) (thickTf.y + this.thin)
|
||||||
|
new Vec2 (thickTf.x + this.thin) (thickTf.y + this.thin)
|
||||||
|
new Vec2 (thickTf.x + this.thin) (thickTf.y - this.thin)
|
||||||
|
new Vec2 (-thickTf.x + this.thin) (-thickTf.y - this.thin)
|
||||||
|
new Vec2 (-thickTf.x - this.thin) (-thickTf.y - this.thin)
|
||||||
|
new Vec2 (-thickTf.x - this.thin) (-thickTf.y + this.thin)
|
||||||
|
|
||||||
|
public [xl x] : x + this.thick
|
||||||
|
public [xr x] : x - this.thick
|
||||||
|
public [xp l r p] : mix [this.xl l] [this.xr r] p
|
||||||
|
|
||||||
|
public [yb y] : y + this.thick
|
||||||
|
public [yt y] : y - this.thick
|
||||||
|
public [yp b t p] : mix [this.yb b] [this.yt t] p
|
||||||
|
|
||||||
|
# Connection to another profile's pen tip position
|
||||||
|
public [connL otherProfile x] : x - otherProfile.thick + this.thick
|
||||||
|
public [connR otherProfile x] : x + otherProfile.thick - this.thick
|
||||||
|
public [connB otherProfile y] : y - otherProfile.thick + this.thick
|
||||||
|
public [connT otherProfile y] : y + otherProfile.thick - this.thick
|
||||||
|
|
||||||
|
# Stroke widths
|
||||||
|
define frakThin : 1.0 * [AdviceStroke 8]
|
||||||
|
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)
|
||||||
|
|
||||||
|
glyph-block-export F
|
||||||
|
define F : new FrakturProfile frakFine (0.5 * frakThin)
|
||||||
|
|
||||||
|
glyph-block-export T
|
||||||
|
define T : new FrakturProfile frakThin (0.5 * frakThin)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
create-glyph "frak/C" 0x212D : glyph-proc
|
||||||
|
include : MarkSet.capital
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# Left and bottom stroke
|
||||||
|
include : fraktur-stroke S
|
||||||
|
g4.ld.start [S.xp SB RightSB 0.1] ([S.yt CAP] - 0.1 * ArchDepthA)
|
||||||
|
flat [S.xl SB] ([S.yt CAP] - 0.6 * ArchDepthA)
|
||||||
|
curl [S.xl SB] ([S.yb 0] + ArchDepthB)
|
||||||
|
~~~ [hookend [S.yb 0] (sw -- S.thick)]
|
||||||
|
g2 [S.xr RightSB] ([S.yb 0] + SHook)
|
||||||
|
|
||||||
|
# A thin connection between the two strokes
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
create-glyph "frak/H" 0x210C : glyph-proc
|
||||||
|
include : MarkSet.capDesc
|
||||||
|
|
||||||
|
local xExt : mix 0 SB 0.25
|
||||||
|
local xLeftStem : Math.max (xExt + 1.5 * DecoSizeX) [mix SB RightSB 0]
|
||||||
|
local ada : 0.6 * ArchDepthA
|
||||||
|
local adb : 0.6 * ArchDepthB
|
||||||
|
|
||||||
|
# Top and left stroke
|
||||||
|
include : fraktur-stroke S
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 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.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]
|
||||||
|
|
||||||
|
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)]
|
||||||
|
|
||||||
|
# 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]
|
||||||
|
~~~ [hookend [S.yb 0] (sw -- S.thick)]
|
||||||
|
g2 [S.xl SB] [S.yb SHook]
|
||||||
|
|
||||||
|
create-glyph "frak/R" 0x211C : glyph-proc
|
||||||
|
include : MarkSet.capital
|
||||||
|
|
||||||
|
local xExt : mix 0 SB 0.25
|
||||||
|
local xLeftStem : Math.max (xExt + 1.5 * DecoSizeX) [mix SB RightSB 0.166]
|
||||||
|
local ltHook : 0.25 * Hook
|
||||||
|
local ada : 0.6 * ArchDepthA
|
||||||
|
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)]
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# Left stroke
|
||||||
|
include : fraktur-stroke S
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
local xLegStart : mix xMidStrokeL xMidStrokeR 0.75
|
||||||
|
local yLegStart : mix yMidStrokeL yMidStrokeR 0.75
|
||||||
|
local xLegEnd RightSB
|
||||||
|
local yLegEnd : S.yb 0
|
||||||
|
|
||||||
|
# Leg
|
||||||
|
include : fraktur-stroke S
|
||||||
|
g2 xLegStart yLegStart
|
||||||
|
g2 [mix xLegStart xMidStrokeR 0.001] [mix yLegStart yMidStrokeR 0.001]
|
||||||
|
flat [mix xLegStart xLegEnd 0.75] (yLegStart - adb)
|
||||||
|
curl [mix xLegStart xLegEnd 0.75] (yLegEnd + ada)
|
||||||
|
corner xLegEnd yLegEnd
|
||||||
|
corner (xLegEnd + DecoSizeX) (yLegEnd + DecoSizeY)
|
||||||
|
|
||||||
|
create-glyph "frak/Z" 0x2128 : 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]
|
||||||
|
|
||||||
|
# Bottom Stroke
|
||||||
|
include : fraktur-stroke S
|
||||||
|
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]
|
|
@ -279,9 +279,9 @@ define-macro glyph-block : syntax-rules
|
||||||
AdviceGlottalStopArchDepth StrokeWidthBlend ArchDepthAOf ArchDepthBOf SmoothAdjust
|
AdviceGlottalStopArchDepth StrokeWidthBlend ArchDepthAOf ArchDepthBOf SmoothAdjust
|
||||||
MidJutSide MidJutCenter compositeBaseAnchors YSmoothMidR YSmoothMidL HSwToV
|
MidJutSide MidJutCenter compositeBaseAnchors YSmoothMidR YSmoothMidL HSwToV
|
||||||
NarrowUnicodeT WideUnicodeT VERY-FAR TINY]
|
NarrowUnicodeT WideUnicodeT VERY-FAR TINY]
|
||||||
define spiroFnImports `[g4 g2 corner flat curl close end straight widths
|
define spiroFnImports `[g4 g2 corner flat curl close end straight g2c cg2 flatc ccurl widths
|
||||||
disable-contrast heading unimportant important alsoThru alsoThruThem bezControls
|
disable-contrast heading unimportant important alsoThru alsoThruThem bezControls
|
||||||
quadControls archv arcvh dispiro spiro-outline]
|
quadControls archv arcvh dispiro spiro-outline spiro-collect]
|
||||||
define booleFnImports `[union intersection difference]
|
define booleFnImports `[union intersection difference]
|
||||||
|
|
||||||
dirty `[$GlyphBlocks$.push : lambda [$Capture_Ext$] : begin \\
|
dirty `[$GlyphBlocks$.push : lambda [$Capture_Ext$] : begin \\
|
||||||
|
|
|
@ -89,13 +89,23 @@ export function SetupBuilders(bindings) {
|
||||||
const curl = KnotType("right");
|
const curl = KnotType("right");
|
||||||
const close = f => new TerminateInstruction("close", f);
|
const close = f => new TerminateInstruction("close", f);
|
||||||
const end = f => new TerminateInstruction("end", f);
|
const end = f => new TerminateInstruction("end", f);
|
||||||
|
|
||||||
const straight = { l: flat, r: curl };
|
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 };
|
||||||
|
|
||||||
{
|
{
|
||||||
let directions = [
|
let directions = [
|
||||||
{ name: "up", x: 0, y: 1 },
|
{ name: "up", x: 0, y: 1 },
|
||||||
{ name: "down", x: 0, y: -1 },
|
{ name: "down", x: 0, y: -1 },
|
||||||
{ name: "left", x: -1, y: 0 },
|
{ name: "left", x: -1, y: 0 },
|
||||||
{ name: "right", 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 = [
|
let adhesions = [
|
||||||
{ name: "start", l: 0, r: TINY },
|
{ name: "start", l: 0, r: TINY },
|
||||||
|
@ -107,6 +117,10 @@ export function SetupBuilders(bindings) {
|
||||||
[g2, g2, g2],
|
[g2, g2, g2],
|
||||||
[corner, corner, corner],
|
[corner, corner, corner],
|
||||||
[straight, flat, curl],
|
[straight, flat, curl],
|
||||||
|
[g2c, g2, corner],
|
||||||
|
[cg2, corner, g2],
|
||||||
|
[flatc, flat, corner],
|
||||||
|
[ccurl, corner, curl],
|
||||||
];
|
];
|
||||||
for (const [sink, kl, kr] of knotTypes) {
|
for (const [sink, kl, kr] of knotTypes) {
|
||||||
for (const d of directions) {
|
for (const d of directions) {
|
||||||
|
@ -368,6 +382,10 @@ export function SetupBuilders(bindings) {
|
||||||
function spiroOutline(...args) {
|
function spiroOutline(...args) {
|
||||||
return new SpiroOutlineImpl(bindings, args);
|
return new SpiroOutlineImpl(bindings, args);
|
||||||
}
|
}
|
||||||
|
function spiroCollect(glyph, ...args) {
|
||||||
|
const spb = new SpiroImplBase(bindings, args);
|
||||||
|
return spb.createCollector(glyph);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
g4,
|
g4,
|
||||||
|
@ -378,6 +396,10 @@ export function SetupBuilders(bindings) {
|
||||||
close,
|
close,
|
||||||
end,
|
end,
|
||||||
straight,
|
straight,
|
||||||
|
g2c,
|
||||||
|
cg2,
|
||||||
|
flatc,
|
||||||
|
ccurl,
|
||||||
widths,
|
widths,
|
||||||
heading,
|
heading,
|
||||||
"disable-contrast": disableContrast,
|
"disable-contrast": disableContrast,
|
||||||
|
@ -391,5 +413,6 @@ export function SetupBuilders(bindings) {
|
||||||
arcvh,
|
arcvh,
|
||||||
dispiro,
|
dispiro,
|
||||||
"spiro-outline": spiroOutline,
|
"spiro-outline": spiroOutline,
|
||||||
|
"spiro-collect": spiroCollect,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import zlib from "zlib";
|
||||||
import * as CurveUtil from "@iosevka/geometry/curve-util";
|
import * as CurveUtil from "@iosevka/geometry/curve-util";
|
||||||
import { encode, decode } from "@msgpack/msgpack";
|
import { encode, decode } from "@msgpack/msgpack";
|
||||||
|
|
||||||
const Edition = 43;
|
const Edition = 44;
|
||||||
const MAX_AGE = 16;
|
const MAX_AGE = 16;
|
||||||
class GfEntry {
|
class GfEntry {
|
||||||
constructor(age, value) {
|
constructor(age, value) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import * as CurveUtil from "./curve-util.mjs";
|
||||||
import { Point } from "./point.mjs";
|
import { Point } from "./point.mjs";
|
||||||
import { QuadifySink } from "./quadify.mjs";
|
import { QuadifySink } from "./quadify.mjs";
|
||||||
import { SpiroExpander } from "./spiro-expand.mjs";
|
import { SpiroExpander } from "./spiro-expand.mjs";
|
||||||
|
import { createSpiroPenGeometry } from "./spiro-pen-expander.mjs";
|
||||||
import { spiroToOutlineWithSimplification } from "./spiro-to-outline.mjs";
|
import { spiroToOutlineWithSimplification } from "./spiro-to-outline.mjs";
|
||||||
import { strokeArcs } from "./stroke.mjs";
|
import { strokeArcs } from "./stroke.mjs";
|
||||||
import { Transform } from "./transform.mjs";
|
import { Transform } from "./transform.mjs";
|
||||||
|
@ -139,6 +140,83 @@ export class SpiroGeometry extends CachedGeometry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SpiroPenGeometry extends CachedGeometry {
|
||||||
|
constructor(gizmo, closed, pen, knots) {
|
||||||
|
super();
|
||||||
|
this.m_gizmo = gizmo;
|
||||||
|
this.m_closed = closed;
|
||||||
|
this.m_knots = knots;
|
||||||
|
this.m_pen = pen;
|
||||||
|
}
|
||||||
|
|
||||||
|
toContoursImpl() {
|
||||||
|
let contours = createSpiroPenGeometry(
|
||||||
|
this.m_gizmo,
|
||||||
|
this.m_closed,
|
||||||
|
this.m_knots,
|
||||||
|
this.m_pen,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!contours.length) return [];
|
||||||
|
|
||||||
|
let stack = [];
|
||||||
|
for (const [i, c] of contours.entries()) {
|
||||||
|
stack.push({
|
||||||
|
type: "operand",
|
||||||
|
fillType: TypoGeom.Boolean.PolyFillType.pftNonZero,
|
||||||
|
shape: CurveUtil.convertShapeToArcs([c]),
|
||||||
|
});
|
||||||
|
if (i > 0) {
|
||||||
|
stack.push({ type: "operator", operator: TypoGeom.Boolean.ClipType.ctUnion });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const arcs = TypoGeom.Boolean.combineStack(stack, CurveUtil.BOOLE_RESOLUTION);
|
||||||
|
const ctx = new CurveUtil.BezToContoursSink();
|
||||||
|
TypoGeom.ShapeConv.transferBezArcShape(arcs, ctx);
|
||||||
|
return ctx.contours;
|
||||||
|
}
|
||||||
|
|
||||||
|
toReferences() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
getDependencies() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
filterTag(fn) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
measureComplexity() {
|
||||||
|
let cplx = CPLX_NON_EMPTY | CPLX_NON_SIMPLE;
|
||||||
|
for (const z of this.m_pen) {
|
||||||
|
if (!isFinite(z.x) || !isFinite(z.y)) cplx |= CPLX_BROKEN;
|
||||||
|
}
|
||||||
|
for (const z of this.m_knots) {
|
||||||
|
if (!isFinite(z.x) || !isFinite(z.y)) cplx |= CPLX_BROKEN;
|
||||||
|
}
|
||||||
|
return cplx;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash(h) {
|
||||||
|
h.beginStruct("SpiroPenGeometry");
|
||||||
|
h.gizmo(this.m_gizmo);
|
||||||
|
h.bool(this.m_closed);
|
||||||
|
|
||||||
|
// Serialize the pen
|
||||||
|
h.beginArray(this.m_pen.length);
|
||||||
|
for (const z of this.m_pen) h.point(z);
|
||||||
|
h.endArray();
|
||||||
|
|
||||||
|
// Serialize the knots
|
||||||
|
h.beginArray(this.m_knots.length);
|
||||||
|
for (const knot of this.m_knots) h.embed(knot);
|
||||||
|
h.endArray();
|
||||||
|
|
||||||
|
h.endStruct();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class DiSpiroGeometry extends CachedGeometry {
|
export class DiSpiroGeometry extends CachedGeometry {
|
||||||
constructor(gizmo, contrast, closed, biKnots) {
|
constructor(gizmo, contrast, closed, biKnots) {
|
||||||
super();
|
super();
|
||||||
|
|
81
packages/geometry/src/spiro-pen-expander.mjs
Normal file
81
packages/geometry/src/spiro-pen-expander.mjs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import * as SpiroJs from "spiro";
|
||||||
|
import * as CurveUtil from "./curve-util.mjs";
|
||||||
|
|
||||||
|
import { Point } from "./point.mjs";
|
||||||
|
|
||||||
|
export function createSpiroPenGeometry(gizmo, closed, knots, pen) {
|
||||||
|
const collector = new ArcCollector(gizmo, pen);
|
||||||
|
SpiroJs.spiroToBezierOnContext(knots, closed, collector, CurveUtil.GEOMETRY_PRECISION);
|
||||||
|
return collector.contoursCollected;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArcCollector {
|
||||||
|
constructor(gizmo, pen) {
|
||||||
|
this.gizmo = gizmo;
|
||||||
|
this.lastX = 0;
|
||||||
|
this.lastY = 0;
|
||||||
|
this.m_pen = pen;
|
||||||
|
this.contoursCollected = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
beginShape() {}
|
||||||
|
endShape() {}
|
||||||
|
|
||||||
|
moveTo(x, y) {
|
||||||
|
const lastTf = this.gizmo.applyXY(x, y);
|
||||||
|
this.lastX = lastTf.x;
|
||||||
|
this.lastY = lastTf.y;
|
||||||
|
this.addPenProfileAt(this.lastX, this.lastY);
|
||||||
|
}
|
||||||
|
|
||||||
|
lineTo(x1, y1) {
|
||||||
|
const z1 = this.gizmo.applyXY(x1, y1);
|
||||||
|
for (let i = 0; i < this.m_pen.length; i++) {
|
||||||
|
let penPrev = this.m_pen[i];
|
||||||
|
let penNext = this.m_pen[(i + 1) % this.m_pen.length];
|
||||||
|
|
||||||
|
const l1 = new Point(Point.Type.Corner, this.lastX + penPrev.x, this.lastY + penPrev.y);
|
||||||
|
const l2 = new Point(Point.Type.Corner, z1.x + penPrev.x, z1.y + penPrev.y);
|
||||||
|
const r2 = new Point(Point.Type.Corner, z1.x + penNext.x, z1.y + penNext.y);
|
||||||
|
const r1 = new Point(Point.Type.Corner, this.lastX + penNext.x, this.lastY + penNext.y);
|
||||||
|
|
||||||
|
this.contoursCollected.push([l1, l2, r2, r1]);
|
||||||
|
}
|
||||||
|
this.lastX = z1.x;
|
||||||
|
this.lastY = z1.y;
|
||||||
|
this.addPenProfileAt(this.lastX, this.lastY);
|
||||||
|
}
|
||||||
|
|
||||||
|
cubicTo(x2, y2, x3, y3, x4, y4) {
|
||||||
|
const z2 = this.gizmo.applyXY(x2, y2);
|
||||||
|
const z3 = this.gizmo.applyXY(x3, y3);
|
||||||
|
const z4 = this.gizmo.applyXY(x4, y4);
|
||||||
|
for (let i = 0; i < this.m_pen.length; i++) {
|
||||||
|
let penPrev = this.m_pen[i];
|
||||||
|
let penNext = this.m_pen[(i + 1) % this.m_pen.length];
|
||||||
|
|
||||||
|
const l1 = new Point(Point.Type.Corner, this.lastX + penPrev.x, this.lastY + penPrev.y);
|
||||||
|
const l2 = new Point(Point.Type.CubicStart, z2.x + penPrev.x, z2.y + penPrev.y);
|
||||||
|
const l3 = new Point(Point.Type.CubicEnd, z3.x + penPrev.x, z3.y + penPrev.y);
|
||||||
|
const l4 = new Point(Point.Type.Corner, z4.x + penPrev.x, z4.y + penPrev.y);
|
||||||
|
const r4 = new Point(Point.Type.Corner, z4.x + penNext.x, z4.y + penNext.y);
|
||||||
|
const r3 = new Point(Point.Type.CubicStart, z3.x + penNext.x, z3.y + penNext.y);
|
||||||
|
const r2 = new Point(Point.Type.CubicEnd, z2.x + penNext.x, z2.y + penNext.y);
|
||||||
|
const r1 = new Point(Point.Type.Corner, this.lastX + penNext.x, this.lastY + penNext.y);
|
||||||
|
|
||||||
|
this.contoursCollected.push([l1, l2, l3, l4, r4, r3, r2, r1]);
|
||||||
|
}
|
||||||
|
this.lastX = z4.x;
|
||||||
|
this.lastY = z4.y;
|
||||||
|
this.addPenProfileAt(this.lastX, this.lastY);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPenProfileAt(x, y) {
|
||||||
|
let c = [];
|
||||||
|
for (let i = 0; i < this.m_pen.length; i++) {
|
||||||
|
let pen = this.m_pen[i];
|
||||||
|
c.push(new Point(Point.Type.Corner, x + pen.x, y + pen.y));
|
||||||
|
}
|
||||||
|
this.contoursCollected.push(c);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ import * as SpiroJs from "spiro";
|
||||||
import * as TypoGeom from "typo-geom";
|
import * as TypoGeom from "typo-geom";
|
||||||
|
|
||||||
import * as CurveUtil from "./curve-util.mjs";
|
import * as CurveUtil from "./curve-util.mjs";
|
||||||
import { Vec2 } from "./point.mjs";
|
|
||||||
|
|
||||||
export function spiroToOutline(knots, fClosed, gizmo) {
|
export function spiroToOutline(knots, fClosed, gizmo) {
|
||||||
const s = new CurveUtil.BezToContoursSink(gizmo);
|
const s = new CurveUtil.BezToContoursSink(gizmo);
|
||||||
|
|
|
@ -13,6 +13,7 @@ const TAG_END_STRUCT_TYPE = 0x12340008;
|
||||||
const TAG_TYPED_POINT = 0x12340010;
|
const TAG_TYPED_POINT = 0x12340010;
|
||||||
const TAG_GIZMO = 0x12340011;
|
const TAG_GIZMO = 0x12340011;
|
||||||
const TAG_LIST_LENGTH = 0x12340012;
|
const TAG_LIST_LENGTH = 0x12340012;
|
||||||
|
const POINT = 0x12340013;
|
||||||
|
|
||||||
const TAG_EMBED_BEGIN = 0x12340020;
|
const TAG_EMBED_BEGIN = 0x12340020;
|
||||||
const TAG_EMBED_END = 0x12340021;
|
const TAG_EMBED_END = 0x12340021;
|
||||||
|
@ -88,6 +89,12 @@ export class Hasher {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
point(z) {
|
||||||
|
this.u32(TAG_TYPED_POINT);
|
||||||
|
this.f64(z.x);
|
||||||
|
this.f64(z.y);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
typedPoint(z) {
|
typedPoint(z) {
|
||||||
this.u32(TAG_TYPED_POINT);
|
this.u32(TAG_TYPED_POINT);
|
||||||
this.u32(z.type);
|
this.u32(z.type);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue