Added a new stroke expansion mechanism, spiroexpand. How we finally have a 'S' looking good.
This commit is contained in:
parent
be865f5ddb
commit
6fa6a8ce85
12 changed files with 271 additions and 34 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -44,5 +44,6 @@ buildglyphs.js
|
||||||
parameters.js
|
parameters.js
|
||||||
support/glyph.js
|
support/glyph.js
|
||||||
support/stroke.js
|
support/stroke.js
|
||||||
|
support/spiroexpand.js
|
||||||
testdrive/*.ttf
|
testdrive/*.ttf
|
||||||
testdrive/*.charmap
|
testdrive/*.charmap
|
|
@ -2,9 +2,8 @@ define Glyph [require './support/glyph'].Glyph
|
||||||
define Stroke [require './support/stroke'].Stroke
|
define Stroke [require './support/stroke'].Stroke
|
||||||
define tp [require './support/transform'].transformPoint
|
define tp [require './support/transform'].transformPoint
|
||||||
define inverse [require './support/transform'].inverse
|
define inverse [require './support/transform'].inverse
|
||||||
|
|
||||||
define libspiro : require 'libspiro-js'
|
define libspiro : require 'libspiro-js'
|
||||||
|
define SpiroExpansionContext [require './support/spiroexpand'].SpiroExpansionContext
|
||||||
### COMMON FUNCTIONS
|
### COMMON FUNCTIONS
|
||||||
|
|
||||||
define [mix a b p] : a + [b - a] * p
|
define [mix a b p] : a + [b - a] * p
|
||||||
|
@ -333,12 +332,23 @@ define [buildFont para recursive] : begin {
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
define [unimportant] : if [this.points && this.points.length && this.points.[this.points.length - 1]] : this.points.[this.points.length - 1].subdivided = true
|
define [unimportant] : begin {
|
||||||
define [afInterpolate before after args] : g2 [mix before.x after.x args.rx] [mix before.y after.y args.ry] unimportant
|
if [this.points && this.points.length && this.points.[this.points.length - 1]] : this.points.[this.points.length - 1].subdivided = true
|
||||||
|
if [this.controlKnots && this.controlKnots.length && this.controlKnots.[this.controlKnots.length - 1]] : this.controlKnots.[this.controlKnots.length - 1].unimportant = true
|
||||||
|
}
|
||||||
|
define [afInterpolate before after args] : g2 {
|
||||||
|
mix before.x after.x args.rx
|
||||||
|
mix before.y after.y args.ry
|
||||||
|
fallback args.raf unimportant
|
||||||
|
}
|
||||||
define [bez3 a b c d t] : [1 - t] * [1 - t] * [1 - t] * a + 3 * [1 - t] * [1 - t] * t * b +3 * t * t * [1 - t] * c + t * t * t * d
|
define [bez3 a b c d t] : [1 - t] * [1 - t] * [1 - t] * a + 3 * [1 - t] * [1 - t] * t * b +3 * t * t * [1 - t] * c + t * t * t * d
|
||||||
define [afInterpolateThem before after args] : begin {
|
define [afInterpolateThem before after args] : begin {
|
||||||
local knots ()
|
local knots ()
|
||||||
foreach (rx ry) [items-of args.rs] : knots.push : g2 [mix before.x after.x rx] [mix before.y after.y ry] unimportant
|
foreach (rx ry preserve) [items-of args.rs] : knots.push : g2 [mix before.x after.x rx] [mix before.y after.y ry] : match preserve {
|
||||||
|
1 before.af
|
||||||
|
2 after.af
|
||||||
|
otherwise unimportant
|
||||||
|
}
|
||||||
return knots
|
return knots
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,18 +368,18 @@ define [buildFont para recursive] : begin {
|
||||||
define [widths.heading l r d] : lambda [] : begin { this.set-width l r; this.heads-to d }
|
define [widths.heading l r d] : lambda [] : begin { this.set-width l r; this.heads-to d }
|
||||||
define [heading d] : lambda [] : this.heads-to d
|
define [heading d] : lambda [] : this.heads-to d
|
||||||
|
|
||||||
define [alsothru rx ry] (.type 'interpolate' .rx rx .ry ry .af afInterpolate)
|
define [alsothru rx ry raf] (.type 'interpolate' .rx rx .ry ry .raf raf .af afInterpolate)
|
||||||
define [alsothruthem rs] (.type 'interpolate' .rs rs .af afInterpolateThem)
|
define [alsothruthem rs] (.type 'interpolate' .rs rs .af afInterpolateThem)
|
||||||
define [bezcontrols x1 y1 x2 y2 _samples notiny] : begin {
|
define [bezcontrols x1 y1 x2 y2 _samples notiny] : begin {
|
||||||
local samples : fallback _samples 2
|
local samples : fallback _samples 5
|
||||||
local tiny 0.005
|
local tiny 0.005
|
||||||
local rs ()
|
local rs ()
|
||||||
if [not notiny] : rs.push ([bez3 0 x1 x2 1 tiny] [bez3 0 y1 y2 1 tiny])
|
# if [not notiny] : rs.push ([bez3 0 x1 x2 1 tiny] [bez3 0 y1 y2 1 tiny] 1)
|
||||||
foreach j [range 1 samples] : rs.push : list {
|
foreach j [range 1 samples] : rs.push : list {
|
||||||
bez3 0 x1 x2 1 [mix tiny [1 - tiny] [j / samples]]
|
bez3 0 x1 x2 1 [mix tiny [1 - tiny] [j / samples]]
|
||||||
bez3 0 y1 y2 1 [mix tiny [1 - tiny] [j / samples]]
|
bez3 0 y1 y2 1 [mix tiny [1 - tiny] [j / samples]]
|
||||||
}
|
}
|
||||||
if [not notiny] : rs.push ([bez3 0 x1 x2 1 [1 - tiny]] [bez3 0 y1 y2 1 [1 - tiny]])
|
# if [not notiny] : rs.push ([bez3 0 x1 x2 1 [1 - tiny]] [bez3 0 y1 y2 1 [1 - tiny]] 2)
|
||||||
alsothruthem rs
|
alsothruthem rs
|
||||||
}
|
}
|
||||||
define [quadcontrols x1 y1 samples] : bezcontrols [x1 * 2 / 3] [y1 * 2 / 3] [mix 1 x1 [2 / 3]] [mix 1 y1 [2 / 3]] samples
|
define [quadcontrols x1 y1 samples] : bezcontrols [x1 * 2 / 3] [y1 * 2 / 3] [mix 1 x1 [2 / 3]] [mix 1 y1 [2 / 3]] samples
|
||||||
|
@ -404,7 +414,7 @@ define [buildFont para recursive] : begin {
|
||||||
if closed : knots.pop
|
if closed : knots.pop
|
||||||
return (.knots [flatten knots] .closed closed .lastafs lastafs)
|
return (.knots [flatten knots] .closed closed .lastafs lastafs)
|
||||||
}
|
}
|
||||||
define [spiro] : begin {
|
define [spiro-stroke] : begin {
|
||||||
local s : new Stroke
|
local s : new Stroke
|
||||||
s.set-transform globalTransform
|
s.set-transform globalTransform
|
||||||
s.set-samples 1
|
s.set-samples 1
|
||||||
|
@ -413,6 +423,24 @@ define [buildFont para recursive] : begin {
|
||||||
foreach af [items-of lastafs] : if af : af.call s
|
foreach af [items-of lastafs] : if af : af.call s
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
define [spiro] : begin {
|
||||||
|
local s : new SpiroExpansionContext
|
||||||
|
set s.gizmo globalTransform
|
||||||
|
local (.knots knots .closed closed .lastafs lastafs) : prepareSpiroKnots [().slice.call arguments 0] s
|
||||||
|
foreach knot [items-of knots] : let [ty knot.type] [af knot.af] : begin {
|
||||||
|
set knot.af : lambda [] : begin {
|
||||||
|
this.set-type ty
|
||||||
|
if af : af.apply this arguments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libspiro.spiroToBezierOnContext knots closed s
|
||||||
|
foreach af [items-of lastafs] : if af : af.call s
|
||||||
|
local outlineKnots : s.expand
|
||||||
|
local g : new Glyph
|
||||||
|
libspiro.spiroToBezierOnContext outlineKnots true g
|
||||||
|
# g.cleanup
|
||||||
|
return g.contours
|
||||||
|
}
|
||||||
define [spiro-outline] : let [k : ().slice.call arguments 0] : glyph-construction {
|
define [spiro-outline] : let [k : ().slice.call arguments 0] : glyph-construction {
|
||||||
local (.knots knots .closed closed .lastafs lastafs) : prepareSpiroKnots k this
|
local (.knots knots .closed closed .lastafs lastafs) : prepareSpiroKnots k this
|
||||||
libspiro.spiroToBezierOnContext knots closed this
|
libspiro.spiroToBezierOnContext knots closed this
|
||||||
|
|
|
@ -171,12 +171,15 @@ define [nShoulder left middle right fine _top _bottom _sma _smb _wide] : glyph-c
|
||||||
flat right bottom [heading UPWARD]
|
flat right bottom [heading UPWARD]
|
||||||
curl right [top - smb]
|
curl right [top - smb]
|
||||||
arcvh
|
arcvh
|
||||||
g4 middle [top - O] [heading LEFTWARD]
|
g4 middle [top - O] [heading LEFTWARD]
|
||||||
|
archv
|
||||||
|
flat left [top - sma] [widths 0 fine]
|
||||||
|
curl left [top - sma - 2]
|
||||||
}
|
}
|
||||||
start-from middle [top - O - stroke]
|
# start-from middle [top - O - stroke]
|
||||||
arc-hv-to left [top - sma]
|
# arc-hv-to left [top - sma]
|
||||||
line-to [left - fine] [top - sma]
|
# line-to [left - fine] [top - sma]
|
||||||
arc-vh-to middle [top - O]
|
# arc-vh-to middle [top - O]
|
||||||
}
|
}
|
||||||
|
|
||||||
define [mShoulderSpiro left right top bottom width fine] : glyph-construction {
|
define [mShoulderSpiro left right top bottom width fine] : glyph-construction {
|
||||||
|
|
|
@ -223,6 +223,7 @@ create-glyph 'B' : glyph-construction {
|
||||||
assign-unicode 'B'
|
assign-unicode 'B'
|
||||||
include capitalMarks
|
include capitalMarks
|
||||||
include : BShape CAP
|
include : BShape CAP
|
||||||
|
#throw 'www'
|
||||||
}
|
}
|
||||||
|
|
||||||
create-glyph 'D' : glyph-construction {
|
create-glyph 'D' : glyph-construction {
|
||||||
|
@ -369,7 +370,6 @@ create-glyph 'U' : glyph-construction {
|
||||||
set-width WIDTH
|
set-width WIDTH
|
||||||
assign-unicode 'U'
|
assign-unicode 'U'
|
||||||
include capitalMarks
|
include capitalMarks
|
||||||
|
|
||||||
include : UShape CAP 0
|
include : UShape CAP 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,7 +599,7 @@ create-glyph 'S' : glyph-construction {
|
||||||
g4 RIGHTSB [CAP - HOOK]
|
g4 RIGHTSB [CAP - HOOK]
|
||||||
hookstart CAPO
|
hookstart CAPO
|
||||||
g4 SB [CAP - SMOOTHA]
|
g4 SB [CAP - SMOOTHA]
|
||||||
sband
|
alsothru 0.5 0.5 [widths HALFSTROKE HALFSTROKE]
|
||||||
g4 RIGHTSB SMOOTHA [widths 0 STROKE]
|
g4 RIGHTSB SMOOTHA [widths 0 STROKE]
|
||||||
hookend O
|
hookend O
|
||||||
g4 SB HOOK
|
g4 SB HOOK
|
||||||
|
|
|
@ -9,11 +9,20 @@ create-glyph 'o' : glyph-construction {
|
||||||
include : smallo XH 0 SB RIGHTSB
|
include : smallo XH 0 SB RIGHTSB
|
||||||
}
|
}
|
||||||
define [oLeft] : glyph-construction {
|
define [oLeft] : glyph-construction {
|
||||||
include : list {
|
include : spiro {
|
||||||
ORing XO O [SB + HALFSTROKE] [RIGHTSB - O] SMALLSMOOTHA SMALLSMOOTHB 0
|
widths.lhs
|
||||||
ORing [XO - STROKE] [O + STROKE] [SB + STROKE * ITALICCOR] [RIGHTSB - STROKE * ITALICCOR - O] [SMALLSMOOTHA - STROKE] [SMALLSMOOTHB - STROKE] 0
|
g4 [MIDDLE - OMIDCOR_S + HALFSTROKE / 4] XO
|
||||||
|
archv
|
||||||
|
flat [SB + HALFSTROKE * ITALICCOR] [XH - SMALLSMOOTHA] [widths HALFSTROKE 0]
|
||||||
|
curl [SB + HALFSTROKE * ITALICCOR] [0 + SMALLSMOOTHB] [widths HALFSTROKE 0]
|
||||||
|
arcvh
|
||||||
|
g4 [MIDDLE + OMIDCOR_S + HALFSTROKE / 4] O [widths STROKE 0]
|
||||||
|
archv
|
||||||
|
flat [RIGHTSB - O] [0 + SMALLSMOOTHA]
|
||||||
|
curl [RIGHTSB - O] [XH - SMALLSMOOTHB]
|
||||||
|
arcvh
|
||||||
|
close
|
||||||
}
|
}
|
||||||
reverse-last
|
|
||||||
}
|
}
|
||||||
define [oRight] : glyph-construction {
|
define [oRight] : glyph-construction {
|
||||||
include : create-glyph [oLeft]
|
include : create-glyph [oLeft]
|
||||||
|
@ -153,7 +162,7 @@ create-glyph 'e.italic' : glyph-construction {
|
||||||
|
|
||||||
local barbottom [XH * EBARPOS]
|
local barbottom [XH * EBARPOS]
|
||||||
|
|
||||||
include : spiro {
|
include : spiro-stroke {
|
||||||
widths.lhs
|
widths.lhs
|
||||||
g4 [SB + O + STROKE] barbottom
|
g4 [SB + O + STROKE] barbottom
|
||||||
archv 8
|
archv 8
|
||||||
|
@ -628,11 +637,13 @@ create-glyph 's' : glyph-construction {
|
||||||
g4 RIGHTSB [XH - SHOOK]
|
g4 RIGHTSB [XH - SHOOK]
|
||||||
hookstart XO SBALANCE
|
hookstart XO SBALANCE
|
||||||
g4 SB [XH - SMOOTHA * 0.85]
|
g4 SB [XH - SMOOTHA * 0.85]
|
||||||
sband STROKE false 1 0.75 [linreg 75 1 120 0.5 STROKE]
|
alsothru 0.5 0.5 [widths HALFSTROKE HALFSTROKE]
|
||||||
|
#sband STROKE false 1 0.75 [linreg 75 1 120 0.55 STROKE]
|
||||||
g4 RIGHTSB [SMOOTHA * 0.85] [widths 0 STROKE]
|
g4 RIGHTSB [SMOOTHA * 0.85] [widths 0 STROKE]
|
||||||
hookend O SBALANCE
|
hookend O SBALANCE
|
||||||
g4 SB SHOOK
|
g4 SB SHOOK
|
||||||
}
|
}
|
||||||
|
# throw 'w'
|
||||||
}
|
}
|
||||||
|
|
||||||
### r
|
### r
|
||||||
|
@ -648,7 +659,7 @@ create-glyph 'r' : glyph-construction {
|
||||||
widths.rhs
|
widths.rhs
|
||||||
g4 rhookx [XH - RHOOK - STROKE * 0.5]
|
g4 rhookx [XH - RHOOK - STROKE * 0.5]
|
||||||
g4 [mix barright rhookx 0.52] [XO - STROKE] [heading LEFTWARD]
|
g4 [mix barright rhookx 0.52] [XO - STROKE] [heading LEFTWARD]
|
||||||
archv
|
archv 8 'notiny'
|
||||||
flat barright [XH - SMALLSMOOTHA] [widths 0 [STROKE * 0.3]]
|
flat barright [XH - SMALLSMOOTHA] [widths 0 [STROKE * 0.3]]
|
||||||
curl barright [XH - SMALLSMOOTHA - 1]
|
curl barright [XH - SMALLSMOOTHA - 1]
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,13 +57,13 @@ create-glyph 'two' : glyph-construction {
|
||||||
g4 [[mix RIGHTSB SB SBALANCE] - OMIDCOR_S] CAPO
|
g4 [[mix RIGHTSB SB SBALANCE] - OMIDCOR_S] CAPO
|
||||||
archv 4
|
archv 4
|
||||||
g4 RIGHTSB [CAP - smb]
|
g4 RIGHTSB [CAP - smb]
|
||||||
alsothruthem : list (0.5 [0.475 + 0.4 * HALFSTROKE / [CAP - smb - STROKE]])
|
alsothru 0.5 0.45 [widths HALFSTROKE HALFSTROKE]
|
||||||
flat [SB + STROKE * ITALICCOR] STROKE
|
flat SB 1 [widths.heading STROKE 0 DOWNWARD]
|
||||||
curl [SB + STROKE * ITALICCOR] HALFSTROKE
|
curl SB 0 [heading DOWNWARD]
|
||||||
}
|
}
|
||||||
|
|
||||||
include : create-stroke
|
include : create-stroke
|
||||||
:.start-from SB 0
|
:.start-from [SB + HALFSTROKE] 0
|
||||||
:.set-width STROKE 0
|
:.set-width STROKE 0
|
||||||
:.heads-to RIGHTWARD
|
:.heads-to RIGHTWARD
|
||||||
:.line-to RIGHTSB 0
|
:.line-to RIGHTSB 0
|
||||||
|
@ -83,16 +83,18 @@ create-glyph 'three' : glyph-construction {
|
||||||
g4 SB [CAP - HOOK]
|
g4 SB [CAP - HOOK]
|
||||||
hookstart CAPO
|
hookstart CAPO
|
||||||
g4 RIGHTSB [CAP - [SMOOTHB * [CAP - barcenter] / CAPMIDDLE]]
|
g4 RIGHTSB [CAP - [SMOOTHB * [CAP - barcenter] / CAPMIDDLE]]
|
||||||
arcvh
|
# arcvh
|
||||||
flat [RIGHTSB - threeRadius] [barcenter - HALFSTROKE] [heading LEFTWARD]
|
flat [RIGHTSB - threeRadius] [barcenter - HALFSTROKE] [heading LEFTWARD]
|
||||||
|
curl [RIGHTSB - threeRadius - 1] [barcenter - HALFSTROKE] [heading LEFTWARD]
|
||||||
}
|
}
|
||||||
include : spiro {
|
include : spiro {
|
||||||
widths.lhs
|
widths.lhs
|
||||||
g4 SB HOOK
|
g4 SB HOOK
|
||||||
hookstart O
|
hookstart O
|
||||||
g4 RIGHTSB [SMOOTHA * barcenter / CAPMIDDLE]
|
g4 RIGHTSB [SMOOTHA * barcenter / CAPMIDDLE]
|
||||||
arcvh
|
# arcvh
|
||||||
flat [RIGHTSB - threeRadius] [barcenter + HALFSTROKE] [heading LEFTWARD]
|
flat [RIGHTSB - threeRadius] [barcenter + HALFSTROKE] [heading LEFTWARD]
|
||||||
|
curl [RIGHTSB - threeRadius - 1] [barcenter + HALFSTROKE] [heading LEFTWARD]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,11 +193,13 @@ create-glyph 'eight' : glyph-construction {
|
||||||
g4 [MIDDLE - OMIDCOR_S + ITALICCORS] [CAP - O - STROKE]
|
g4 [MIDDLE - OMIDCOR_S + ITALICCORS] [CAP - O - STROKE]
|
||||||
archv 1
|
archv 1
|
||||||
g4 [[mix SB RIGHTSB p] - STROKE] [CAP - smb * p]
|
g4 [[mix SB RIGHTSB p] - STROKE] [CAP - smb * p]
|
||||||
|
alsothru 0.5 0.5 [widths HALFSTROKE HALFSTROKE]
|
||||||
g4 [SB + STROKE] smb [widths 0 STROKE]
|
g4 [SB + STROKE] smb [widths 0 STROKE]
|
||||||
arcvh 1
|
arcvh 1
|
||||||
g4 [MIDDLE + OMIDCOR_S - ITALICCORS] [O + STROKE]
|
g4 [MIDDLE + OMIDCOR_S - ITALICCORS] [O + STROKE]
|
||||||
archv 1
|
archv 1
|
||||||
g4 [RIGHTSB - STROKE] sma [widths 0 STROKE]
|
g4 [RIGHTSB - STROKE] sma [widths 0 STROKE]
|
||||||
|
alsothru 0.5 0.5 [widths HALFSTROKE HALFSTROKE]
|
||||||
g4 [[mix RIGHTSB SB p] + STROKE] [CAP - sma * p] [widths STROKE 0]
|
g4 [[mix RIGHTSB SB p] + STROKE] [CAP - sma * p] [widths STROKE 0]
|
||||||
arcvh 1
|
arcvh 1
|
||||||
close
|
close
|
||||||
|
|
|
@ -36,11 +36,13 @@ create-glyph 'ampersand' : glyph-construction {
|
||||||
g4 MIDDLE [O + fine] [widths fine 0]
|
g4 MIDDLE [O + fine] [widths fine 0]
|
||||||
archv
|
archv
|
||||||
g4 [SB + O + fine * ITALICCOR] [SMOOTHB - ITALICCOR * ITALICCORS]
|
g4 [SB + O + fine * ITALICCOR] [SMOOTHB - ITALICCOR * ITALICCORS]
|
||||||
|
alsothru 0.5 0.5 [widths [fine / 2] [fine / 2]]
|
||||||
g4 [[mix SB RIGHTSB p] - fine * ITALICCOR] [CAP - SMOOTHB * pr + ITALICCOR * ITALICCORS * [fine / STROKE]] [widths 0 fine]
|
g4 [[mix SB RIGHTSB p] - fine * ITALICCOR] [CAP - SMOOTHB * pr + ITALICCOR * ITALICCORS * [fine / STROKE]] [widths 0 fine]
|
||||||
arcvh
|
arcvh
|
||||||
g4 [[mix SB RIGHTSB [mix p l 0.5]] - OMIDCOR_S + ITALICCORS] [CAPO - fine]
|
g4 [[mix SB RIGHTSB [mix p l 0.5]] - OMIDCOR_S + ITALICCORS] [CAPO - fine]
|
||||||
archv
|
archv
|
||||||
g4 [[mix SB RIGHTSB l] + fine * ITALICCOR] [CAP - SMOOTHA * pr - ITALICCOR * ITALICCORS * [fine / STROKE]]
|
g4 [[mix SB RIGHTSB l] + fine * ITALICCOR] [CAP - SMOOTHA * pr - ITALICCOR * ITALICCORS * [fine / STROKE]]
|
||||||
|
alsothru 0.5 0.45 [lambda]
|
||||||
flat [mix SB RIGHTSB r] [SMOOTHA * s]
|
flat [mix SB RIGHTSB r] [SMOOTHA * s]
|
||||||
curl [mix SB RIGHTSB r] [[SMOOTHA * s] - 1]
|
curl [mix SB RIGHTSB r] [[SMOOTHA * s] - 1]
|
||||||
}
|
}
|
||||||
|
|
3
makefile
3
makefile
|
@ -1,4 +1,4 @@
|
||||||
SUPPORT_FILES = support/glyph.js support/stroke.js parameters.js generate.js empty.json
|
SUPPORT_FILES = support/glyph.js support/stroke.js support/spiroexpand.js parameters.js generate.js empty.json
|
||||||
GLYPH_SEGMENTS = glyphs/common-shapes.patel glyphs/overmarks.patel glyphs/latin-basic-capital.patel glyphs/latin-basic-lower.patel glyphs/greek.patel glyphs/cyrillic-basic.patel glyphs/latin-extend-basis.patel glyphs/latin-extend-decorated.patel glyphs/cyrillic-extended.patel glyphs/numbers.patel glyphs/symbol-ascii.patel glyphs/symbol-punctuation.patel glyphs/symbol-math.patel glyphs/symbol-geometric.patel glyphs/symbol-other.patel glyphs/symbol-letter.patel glyphs/autobuilds.patel
|
GLYPH_SEGMENTS = glyphs/common-shapes.patel glyphs/overmarks.patel glyphs/latin-basic-capital.patel glyphs/latin-basic-lower.patel glyphs/greek.patel glyphs/cyrillic-basic.patel glyphs/latin-extend-basis.patel glyphs/latin-extend-decorated.patel glyphs/cyrillic-extended.patel glyphs/numbers.patel glyphs/symbol-ascii.patel glyphs/symbol-punctuation.patel glyphs/symbol-math.patel glyphs/symbol-geometric.patel glyphs/symbol-other.patel glyphs/symbol-letter.patel glyphs/autobuilds.patel
|
||||||
OBJDIR = build
|
OBJDIR = build
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ buildglyphs.js : buildglyphs.patel $(GLYPH_SEGMENTS)
|
||||||
patel-c --strict $< -o $@
|
patel-c --strict $< -o $@
|
||||||
support/glyph.js : support/glyph.patel
|
support/glyph.js : support/glyph.patel
|
||||||
support/stroke.js : support/stroke.patel
|
support/stroke.js : support/stroke.patel
|
||||||
|
support/spiroexpand.js : support/spiroexpand.patel
|
||||||
parameters.js : parameters.patel
|
parameters.js : parameters.patel
|
||||||
|
|
||||||
$(OBJDIR) :
|
$(OBJDIR) :
|
||||||
|
|
|
@ -22,7 +22,7 @@ define regular (
|
||||||
.hookx 170
|
.hookx 170
|
||||||
|
|
||||||
.smooth 195
|
.smooth 195
|
||||||
.smallsmooth 242
|
.smallsmooth 230
|
||||||
.smoothadjust 180
|
.smoothadjust 180
|
||||||
|
|
||||||
.o [-8]
|
.o [-8]
|
||||||
|
|
|
@ -6,8 +6,9 @@ font = fontforge.open(source)
|
||||||
|
|
||||||
font.selection.all()
|
font.selection.all()
|
||||||
font.removeOverlap()
|
font.removeOverlap()
|
||||||
font.addExtrema()
|
|
||||||
font.simplify(1)
|
font.simplify(1)
|
||||||
|
font.em = 1000
|
||||||
|
font.addExtrema()
|
||||||
font.canonicalContours()
|
font.canonicalContours()
|
||||||
font.canonicalStart()
|
font.canonicalStart()
|
||||||
font.generate(sys.argv[2], flags = ("short-post", "opentype"))
|
font.generate(sys.argv[2], flags = ("short-post", "opentype"))
|
|
@ -188,5 +188,24 @@ define [Glyph.prototype.set-anchor id type x y mbx mby] : begin {
|
||||||
local markbasepoint : if [mbx !== nothing && mby !== nothing] [tp this.gizmo (.x mbx .y mby)] (.x nothing .y nothing)
|
local markbasepoint : if [mbx !== nothing && mby !== nothing] [tp this.gizmo (.x mbx .y mby)] (.x nothing .y nothing)
|
||||||
this.anchors`id = (.x anchorpoint.x .y anchorpoint.y .type type .mbx markbasepoint.x .mby markbasepoint.y)
|
this.anchors`id = (.x anchorpoint.x .y anchorpoint.y .type type .mbx markbasepoint.x .mby markbasepoint.y)
|
||||||
}
|
}
|
||||||
|
define [oncurveRemovable a b c] : begin {
|
||||||
|
local xm : [a.x + c.x] / 2
|
||||||
|
local ym : [a.y + c.y] / 2
|
||||||
|
return : [not a.onCurve] && b.onCurve && [not c.onCurve] && [a.x <= b.x && b.x <= c.x || a.x >= b.x && b.x >= c.x] && [a.y <= b.y && b.y <= c.y || a.y >= b.y && b.y >= c.y] && [Math.abs [b.x - xm]] <= 0.5 && [Math.abs [b.y - ym]] <= 0.5
|
||||||
|
}
|
||||||
|
define [Glyph.prototype.cleanup] : begin {
|
||||||
|
foreach c [range 0 this.contours.length] : begin {
|
||||||
|
local contour this.contours.(c)
|
||||||
|
local cleanedContour ()
|
||||||
|
foreach j [range 1 : contour.length - 1] : begin {
|
||||||
|
local p0 contour.[j - 1]
|
||||||
|
local p1 contour.(j)
|
||||||
|
local p2 contour.[j + 1]
|
||||||
|
if [oncurveRemovable p0 p1 p2] : set p1.unimportant true
|
||||||
|
}
|
||||||
|
foreach point [items-of contour] : if [not point.unimportant] : cleanedContour.push point
|
||||||
|
this.contours.(c) = cleanedContour
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
exports.Glyph = Glyph
|
exports.Glyph = Glyph
|
167
support/spiroexpand.patel
Normal file
167
support/spiroexpand.patel
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
define smooth [require './monotonic-interpolate'].createInterpolant
|
||||||
|
define tp [require './transform'].transformPoint
|
||||||
|
define utp [require './transform'].untransform
|
||||||
|
|
||||||
|
define [fallback] : for [local j 0] [j < arguments.length] [inc j] : if [arguments`j !== nothing] : return arguments`j
|
||||||
|
define [linreg x0 y0 x1 y1 x] : y0 + [x - x0] * [y1 - y0] / [x1 - x0]
|
||||||
|
|
||||||
|
define [SpiroExpansionContext] : begin {
|
||||||
|
set this.gizmo (.xx 1 .yy 1 .xy 0 .yy 0 .x 0 .y 0)
|
||||||
|
set this.controlKnots ()
|
||||||
|
set this.defaultd1 0
|
||||||
|
set this.defaultd2 0
|
||||||
|
return nothing
|
||||||
|
}
|
||||||
|
define [SpiroExpansionContext.prototype.moveTo x y unimportant] : begin {
|
||||||
|
if unimportant : return nothing
|
||||||
|
# Transform incoming knots using gizmo
|
||||||
|
set (.x x .y y) : tp this.gizmo (.x x .y y)
|
||||||
|
this.controlKnots.push (.x x .y y .type 'g4' .d1 this.defaultd1 .d2 this.defaultd2)
|
||||||
|
}
|
||||||
|
define [SpiroExpansionContext.prototype.lineTo x y unimportant] : begin {
|
||||||
|
local lastKnot this.controlKnots.[this.controlKnots.length - 1]
|
||||||
|
set (.x x .y y) : tp this.gizmo (.x x .y y)
|
||||||
|
local thisKnot (.x x .y y .type 'g4' .d1 lastKnot.d1 .d2 lastKnot.d2)
|
||||||
|
if lastKnot : begin {
|
||||||
|
local normalAngle : Math.PI / 2 + [Math.atan2 [y - lastKnot.y] [x - lastKnot.x]]
|
||||||
|
set thisKnot.normalAngle normalAngle
|
||||||
|
if [lastKnot.normalAngle === nothing] : set lastKnot.normalAngle normalAngle
|
||||||
|
}
|
||||||
|
if [not unimportant] : this.controlKnots.push thisKnot
|
||||||
|
}
|
||||||
|
define [SpiroExpansionContext.prototype.cubicTo x1 y1 x2 y2 x y unimportant] : begin {
|
||||||
|
local lastKnot this.controlKnots.[this.controlKnots.length - 1]
|
||||||
|
set (.x x1 .y y1) : tp this.gizmo (.x x1 .y y1)
|
||||||
|
set (.x x2 .y y2) : tp this.gizmo (.x x2 .y y2)
|
||||||
|
set (.x x .y y) : tp this.gizmo (.x x .y y)
|
||||||
|
local thisKnot (.x x .y y .type 'g4' .d1 lastKnot.d1 .d2 lastKnot.d2)
|
||||||
|
if [lastKnot && lastKnot.normalAngle === nothing] : begin {
|
||||||
|
local normalAngle : Math.PI / 2 + [Math.atan2 [y1 - lastKnot.y] [x1 - lastKnot.x]]
|
||||||
|
if [lastKnot.normalAngle === nothing] : set lastKnot.normalAngle normalAngle
|
||||||
|
}
|
||||||
|
if [not unimportant] : begin {
|
||||||
|
local normalAngle : Math.PI / 2 + [Math.atan2 [y - y2] [x - x2]]
|
||||||
|
set thisKnot.normalAngle normalAngle
|
||||||
|
this.controlKnots.push thisKnot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
define [SpiroExpansionContext.prototype.set-width l r] : begin {
|
||||||
|
local lastKnot this.controlKnots.[this.controlKnots.length - 1]
|
||||||
|
if lastKnot {
|
||||||
|
then { lastKnot.d1 = l; lastKnot.d2 = r }
|
||||||
|
else { this.defaultd1 = l; this.defaultd2 = r}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
define [SpiroExpansionContext.prototype.heads-to direction] : begin {
|
||||||
|
local lastKnot this.controlKnots.[this.controlKnots.length - 1]
|
||||||
|
if lastKnot : begin {
|
||||||
|
lastKnot.proposedNormal = direction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
define [SpiroExpansionContext.prototype.set-type type] : begin {
|
||||||
|
local lastKnot this.controlKnots.[this.controlKnots.length - 1]
|
||||||
|
if lastKnot : begin {
|
||||||
|
lastKnot.type = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define [shortestAngle end start] : begin {
|
||||||
|
local a : [end - start] % [Math.PI * 2]
|
||||||
|
if [a > Math.PI / 2] : a = a - Math.PI
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
define [SpiroExpansionContext.prototype.expand] : begin {
|
||||||
|
local lhs ()
|
||||||
|
local rhs ()
|
||||||
|
|
||||||
|
local d1s ()
|
||||||
|
local d2s ()
|
||||||
|
local dxs ()
|
||||||
|
local dys ()
|
||||||
|
local js ()
|
||||||
|
foreach j [range 0 this.controlKnots.length] : if [not this.controlKnots.(j).unimportant] : begin {
|
||||||
|
local knot this.controlKnots.(j)
|
||||||
|
js.push j
|
||||||
|
d1s.push knot.d1
|
||||||
|
d2s.push knot.d2
|
||||||
|
if knot.proposedNormal {
|
||||||
|
then {
|
||||||
|
dxs.push : knot.proposedNormal.x - [Math.cos knot.normalAngle]
|
||||||
|
dys.push : knot.proposedNormal.y - [Math.sin knot.normalAngle]
|
||||||
|
}
|
||||||
|
else { dxs.push 0; dys.push 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local fd1 : smooth js d1s
|
||||||
|
local fd2 : smooth js d2s
|
||||||
|
local fdx : smooth js dxs
|
||||||
|
local fdy : smooth js dys
|
||||||
|
# console.log deltaAngles
|
||||||
|
|
||||||
|
# interpolate important knots
|
||||||
|
foreach j [range 0 this.controlKnots.length] : begin {
|
||||||
|
local knot this.controlKnots.(j)
|
||||||
|
if [not knot.unimportant] : begin {
|
||||||
|
set lhs.(j) : object {
|
||||||
|
x : knot.x + [[fdx j] + [Math.cos knot.normalAngle]] * [fd1 j]
|
||||||
|
y : knot.y + [[fdy j] + [Math.sin knot.normalAngle]] * [fd1 j]
|
||||||
|
type knot.type
|
||||||
|
}
|
||||||
|
set rhs.(j) : object {
|
||||||
|
x : knot.x - [[fdx j] + [Math.cos knot.normalAngle]] * [fd2 j]
|
||||||
|
y : knot.y - [[fdy j] + [Math.sin knot.normalAngle]] * [fd2 j]
|
||||||
|
type : match knot.type {
|
||||||
|
"left" "right"
|
||||||
|
"right" "left"
|
||||||
|
type type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# interpolate unimportant knots referencing their original position relationship
|
||||||
|
foreach j [range 0 this.controlKnots.length] : begin {
|
||||||
|
local knot this.controlKnots.(j)
|
||||||
|
if knot.unimportant : begin {
|
||||||
|
local jBefore [j - 1]
|
||||||
|
while this.controlKnots.(jBefore).unimportant : dec jBefore
|
||||||
|
local jAfter [j + 1]
|
||||||
|
while this.controlKnots.(jAfter).unimportant : inc jAfter
|
||||||
|
|
||||||
|
local knotBefore : utp this.gizmo this.controlKnots.(jBefore)
|
||||||
|
local knotAfter : utp this.gizmo this.controlKnots.(jAfter)
|
||||||
|
local ref : utp this.gizmo knot
|
||||||
|
local lhsBefore : utp this.gizmo lhs.(jBefore)
|
||||||
|
local lhsAfter : utp this.gizmo lhs.(jAfter)
|
||||||
|
local rhsBefore : utp this.gizmo rhs.(jBefore)
|
||||||
|
local rhsAfter : utp this.gizmo rhs.(jAfter)
|
||||||
|
|
||||||
|
local kLHS : tp this.gizmo : object {
|
||||||
|
x : linreg knotBefore.x lhsBefore.x knotAfter.x lhsAfter.x ref.x
|
||||||
|
y : linreg knotBefore.y lhsBefore.y knotAfter.y lhsAfter.y ref.y
|
||||||
|
}
|
||||||
|
local kRHS : tp this.gizmo : object {
|
||||||
|
x : linreg knotBefore.x rhsBefore.x knotAfter.x rhsAfter.x ref.x
|
||||||
|
y : linreg knotBefore.y rhsBefore.y knotAfter.y rhsAfter.y ref.y
|
||||||
|
}
|
||||||
|
|
||||||
|
set lhs.(j) : object {
|
||||||
|
x kLHS.x
|
||||||
|
y kLHS.y
|
||||||
|
type knot.type
|
||||||
|
}
|
||||||
|
set rhs.(j) : object {
|
||||||
|
x kRHS.x
|
||||||
|
y kRHS.y
|
||||||
|
type : match knot.type {
|
||||||
|
"left" "right"
|
||||||
|
"right" "left"
|
||||||
|
type type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lhs.0.type = rhs.0.type = lhs.[lhs.length - 1].type = rhs.[rhs.length - 1].type = 'corner'
|
||||||
|
return : lhs.concat [rhs.reverse]
|
||||||
|
}
|
||||||
|
exports.SpiroExpansionContext = SpiroExpansionContext
|
Loading…
Add table
Add a link
Reference in a new issue