/s and /S are reconstructed with spiros.
This commit is contained in:
parent
3b7c951e76
commit
be865f5ddb
7 changed files with 110 additions and 51 deletions
|
@ -9,6 +9,13 @@ define libspiro : require 'libspiro-js'
|
|||
|
||||
define [mix a b p] : a + [b - a] * p
|
||||
define [linreg x0 y0 x1 y1 x] : y0 + [x - x0] * [y1 - y0] / [x1 - x0]
|
||||
define [bilinear x0 x1 y0 y1 z00 z01 z10 z11 x y] : linreg {
|
||||
* y0
|
||||
linreg x0 z00 x1 z10 x
|
||||
* y1
|
||||
linreg x0 z01 x1 z11 x
|
||||
* y
|
||||
}
|
||||
define [fallback] : for [local j 0] [j < arguments.length] [inc j] : if [arguments`j !== nothing] : return arguments`j
|
||||
|
||||
define emptyFontStr : JSON.stringify [require './empty.json']
|
||||
|
@ -79,10 +86,15 @@ define [buildFont para recursive] : begin {
|
|||
define globalTransform : Italify para.italicAngle
|
||||
define ITALICCOR : 1 / [Math.sqrt [1 - globalTransform.yx * globalTransform.yx]]
|
||||
|
||||
# Orient parameters
|
||||
define UPWARD (.x [-ITALICCOR] .y 0)
|
||||
define DOWNWARD (.x ITALICCOR .y 0)
|
||||
define RIGHTWARD (.x globalTransform.yx .y 1)
|
||||
define LEFTWARD (.x [- globalTransform.yx] .y [-1])
|
||||
define [normalize a] : begin {
|
||||
local m : Math.hypot a.x a.y
|
||||
return (.x [a.x / m] .y [a.y / m])
|
||||
}
|
||||
|
||||
# derived metrics
|
||||
define XO : XH - O
|
||||
|
@ -322,11 +334,11 @@ define [buildFont para recursive] : begin {
|
|||
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 [afInterpolate before after args] : g4 [mix before.x after.x args.rx] [mix before.y after.y args.ry] unimportant
|
||||
define [afInterpolate before after args] : g2 [mix before.x after.x args.rx] [mix before.y after.y args.ry] 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 [afInterpolateThem before after args] : begin {
|
||||
local knots ()
|
||||
foreach (rx ry) [items-of args.rs] : knots.push : g4 [mix before.x after.x rx] [mix before.y after.y ry] unimportant
|
||||
foreach (rx ry) [items-of args.rs] : knots.push : g2 [mix before.x after.x rx] [mix before.y after.y ry] unimportant
|
||||
return knots
|
||||
}
|
||||
|
||||
|
@ -398,13 +410,13 @@ define [buildFont para recursive] : begin {
|
|||
s.set-samples 1
|
||||
local (.knots knots .closed closed .lastafs lastafs) : prepareSpiroKnots [().slice.call arguments 0] s
|
||||
libspiro.spiroToBezierOnContext knots closed s
|
||||
foreach af : [items-of lastafs] : if af : af.call s
|
||||
foreach af [items-of lastafs] : if af : af.call s
|
||||
return s
|
||||
}
|
||||
define [spiro-outline] : let [k : ().slice.call arguments 0] : glyph-construction {
|
||||
local (.knots knots .closed closed .lastafs lastafs) : prepareSpiroKnots k this
|
||||
libspiro.spiroToBezierOnContext knots closed this
|
||||
foreach af : [items-of lastafs] : if af : af.call this
|
||||
foreach af [items-of lastafs] : if af : af.call this
|
||||
}
|
||||
|
||||
###### HERE WE GO!
|
||||
|
|
|
@ -101,8 +101,8 @@ define [xsStrand _xleft yleft _xright yright _halfstroke0 _halfstroke1 _ess _exp
|
|||
:.line-to _xleft [yleft - 1000]
|
||||
:.max-samples 1
|
||||
:.to-outline].0.map : [p] -> [tp upright p]
|
||||
local xItalicCorrection : -[outline.3.x - outline.0.x] / [2 * halfstroke0]
|
||||
local yItalicCorrection : [outline.3.y - outline.0.y] / [2 * halfstroke0]
|
||||
local xItalicCorrection : -[outline.5.x - outline.0.x] / [2 * halfstroke0]
|
||||
local yItalicCorrection : [outline.5.y - outline.0.y] / [2 * halfstroke0]
|
||||
|
||||
local roundsize : [_roundp || SMOOTHA * 0.4] * [if [yleft < yright] [-1] 1]
|
||||
local roundleft [yleft - roundsize]
|
||||
|
@ -323,6 +323,55 @@ define [LegShape xt xb xs top bottom _fine] : glyph-construction {
|
|||
:.curve-to [linreg top xt [bottom + LONGJUT] xb [bottom + fine]] [bottom + fine] xs [bottom + fine]
|
||||
:.heads-to LEFTWARD
|
||||
}
|
||||
# Spiro shapes
|
||||
define [sband sw rtl _tension _tangle _compression] : return (.type 'interpolate' .af [lambda [before after] : begin {
|
||||
local tension : fallback _tension 0.7
|
||||
local compression : fallback _compression 1
|
||||
local tensionw 0
|
||||
local minangle : -para.italicangle / 180 * Math.PI
|
||||
local maxangle : Math.atan2 [after.x - before.x] [[mix after.y before.y tension] - [mix before.y after.y tension]]
|
||||
set maxangle : Math.atan2 [[Math.sin maxangle] * compression] [Math.cos maxangle]
|
||||
local p : fallback _tangle 0.25
|
||||
local pts ()
|
||||
local samples 32
|
||||
foreach j [range 1 samples] : begin {
|
||||
local t : j / samples
|
||||
local angle : mix minangle maxangle [bez3 0 p 1 1 : if [t < 1/2] [2 * t] [2 * [1 - t]]]
|
||||
local k : bez3 0 tensionw [1 - tensionw] 1 t
|
||||
if rtl : k = 1 - k
|
||||
pts.push : g2 [mix before.x after.x [bez3 0 0 1 1 t]] [mix before.y after.y [bez3 0 tension [1 - tension] 1 t]] [widths.heading [[1 - k] * STROKE] [k * STROKE] (.x [Math.cos angle] .y [Math.sin angle])]
|
||||
}
|
||||
# throw 'w'
|
||||
return pts
|
||||
}])
|
||||
define [hookstart y p f] : return (.type 'interpolate' .af [lambda [before after] : begin {
|
||||
local atBottom : after.y > y
|
||||
local ltr : after.x > before.x
|
||||
before.x = before.x - OXHOOK * [if ltr [-1] 1]
|
||||
local hv : archv
|
||||
local mixr : fallback p : linreg 1 0.5 [SMALLSMOOTH / HOOK] 0.53 [[after.y - y] / [before.y - y]]
|
||||
local mx [[mix after.x before.x mixr] + [if atBottom 1 [-1]] * OMIDCOR_S]
|
||||
return : list {
|
||||
g4 mx y f
|
||||
hv.af.call this (.x mx .y y) after hv
|
||||
}
|
||||
}])
|
||||
define [hookend y p f dontextend] : return (.type 'interpolate' .af [lambda [before after] : begin {
|
||||
local atBottom : before.y > y
|
||||
local ltr : after.x > before.x
|
||||
after.x = after.x + OXHOOK * [if ltr [-1] 1]
|
||||
local vh : arcvh
|
||||
local mixr : fallback p : linreg 1 0.5 [SMALLSMOOTH / HOOK] 0.53 [[before.y - y] / [after.y - y]]
|
||||
local mx [[mix before.x after.x mixr] + [if atBottom 1 [-1]] * OMIDCOR_S]
|
||||
if [!dontextend && atBottom && ltr] : begin {
|
||||
after.x = after.x + TAILADJX * globalTransform.yx
|
||||
after.y = after.y - TAILADJY * globalTransform.yx
|
||||
}
|
||||
return : list {
|
||||
vh.af.call this before (.x mx .y y) vh
|
||||
g4 mx y f
|
||||
}
|
||||
}])
|
||||
|
||||
# Derived subfonts
|
||||
define [Miniature glyphs fold scale] : begin {
|
||||
|
@ -370,32 +419,4 @@ define [vdual newid unicode id spacing] : create-glyph [fallback newid : 'double
|
|||
}
|
||||
apply-transform : Translate 0 [spacing / 2]
|
||||
apply-transform : Italify
|
||||
}
|
||||
define [hookstart y p f] (.type 'interpolate' .af [lambda [before after] : begin {
|
||||
local atBottom : after.y > y
|
||||
local ltr : after.x > before.x
|
||||
before.x = before.x - OXHOOK * [if ltr [-1] 1]
|
||||
local hv : archv
|
||||
local mixr : fallback p : linreg 1 0.5 [SMALLSMOOTH / HOOK] 0.53 [[after.y - y] / [before.y - y]]
|
||||
local mx [[mix after.x before.x mixr] + [if atBottom 1 [-1]] * OMIDCOR_S]
|
||||
return : list {
|
||||
g4 mx y f
|
||||
hv.af.call this (.x mx .y y) after hv
|
||||
}
|
||||
}])
|
||||
define [hookend y p f dontextend] (.type 'interpolate' .af [lambda [before after] : begin {
|
||||
local atBottom : before.y > y
|
||||
local ltr : after.x > before.x
|
||||
after.x = after.x + OXHOOK * [if ltr [-1] 1]
|
||||
local vh : arcvh
|
||||
local mixr : fallback p : linreg 1 0.5 [SMALLSMOOTH / HOOK] 0.53 [[before.y - y] / [after.y - y]]
|
||||
local mx [[mix before.x after.x mixr] + [if atBottom 1 [-1]] * OMIDCOR_S]
|
||||
if [!dontextend && atBottom && ltr] : begin {
|
||||
after.x = after.x + TAILADJX * globalTransform.yx
|
||||
after.y = after.y - TAILADJY * globalTransform.yx
|
||||
}
|
||||
return : list {
|
||||
vh.af.call this before (.x mx .y y) vh
|
||||
g4 mx y f
|
||||
}
|
||||
}])
|
||||
}
|
|
@ -594,8 +594,17 @@ create-glyph 'S' : glyph-construction {
|
|||
set-width WIDTH
|
||||
assign-unicode 'S'
|
||||
include capitalMarks
|
||||
|
||||
include : sHookUpper CAP SMOOTHA HOOK
|
||||
include : sHookLower 0 SMOOTHA HOOK
|
||||
include : sStrand [CAP - SMOOTHA] SMOOTHA
|
||||
include : spiro {
|
||||
widths.lhs
|
||||
g4 RIGHTSB [CAP - HOOK]
|
||||
hookstart CAPO
|
||||
g4 SB [CAP - SMOOTHA]
|
||||
sband
|
||||
g4 RIGHTSB SMOOTHA [widths 0 STROKE]
|
||||
hookend O
|
||||
g4 SB HOOK
|
||||
}
|
||||
# include : sHookUpper CAP SMOOTHA HOOK
|
||||
# include : sHookLower 0 SMOOTHA HOOK
|
||||
# include : sStrand [CAP - SMOOTHA] SMOOTHA
|
||||
}
|
|
@ -127,9 +127,9 @@ define [SmallEShape top stroke barpos] : glyph-construction {
|
|||
flat [RIGHTSB - O] barbottom [heading UPWARD]
|
||||
curl [RIGHTSB - O] [top - SMALLSMOOTHB]
|
||||
arcvh
|
||||
g4 [MIDDLE - OMIDCOR_S] [XH - O]
|
||||
g4 [MIDDLE - OMIDCOR_S] [top - O]
|
||||
archv
|
||||
flat [SB + O] [XH - SMALLSMOOTHA]
|
||||
flat [SB + O] [top - SMALLSMOOTHA]
|
||||
curl [SB + O] [0 + SMALLSMOOTHB]
|
||||
hookend O
|
||||
g4 [RIGHTSB - O] HOOK
|
||||
|
@ -623,10 +623,16 @@ create-glyph 's' : glyph-construction {
|
|||
assign-unicode 's'
|
||||
include eMarks
|
||||
|
||||
include : sHookUpper XH [SMOOTHA * 0.87] SHOOK
|
||||
include : sHookLower 0 [SMOOTHA * 0.87] SHOOK
|
||||
|
||||
include : sStrand [XH - [SMOOTHA * 0.87]] [SMOOTHA * 0.87] 0.2 0.45
|
||||
include : spiro {
|
||||
widths.lhs
|
||||
g4 RIGHTSB [XH - SHOOK]
|
||||
hookstart XO SBALANCE
|
||||
g4 SB [XH - SMOOTHA * 0.85]
|
||||
sband STROKE false 1 0.75 [linreg 75 1 120 0.5 STROKE]
|
||||
g4 RIGHTSB [SMOOTHA * 0.85] [widths 0 STROKE]
|
||||
hookend O SBALANCE
|
||||
g4 SB SHOOK
|
||||
}
|
||||
}
|
||||
|
||||
### r
|
||||
|
|
|
@ -236,9 +236,15 @@ create-glyph 'semicolon' : glyph-construction {
|
|||
create-glyph 'question' : glyph-construction {
|
||||
set-width WIDTH
|
||||
assign-unicode '?'
|
||||
include : xsStrand [MIDDLE - HALFSTROKE * ITALICCOR] [mix [DOTSIZE + STROKE] [XH / 2] 0.5] RIGHTSB [CAP - SMOOTHB]
|
||||
include : twoHookUpper CAP SMOOTHB HOOK
|
||||
include : list : Ring [DOTSIZE - O] O [MIDDLE - DOTRADIUS + O] [MIDDLE + DOTRADIUS - O] true
|
||||
include : spiro {
|
||||
widths.rhs
|
||||
g4 SB [CAP - HOOK]
|
||||
hookstart CAPO
|
||||
g4 RIGHTSB [CAP - SMOOTHB * 0.85]
|
||||
flat [MIDDLE + HALFSTROKE * ITALICCOR] [mix [DOTSIZE + STROKE] [XH / 2] 0.5]
|
||||
curl [MIDDLE + HALFSTROKE * ITALICCOR] [[mix [DOTSIZE + STROKE] [XH / 2] 0.5] - 1]
|
||||
}
|
||||
}
|
||||
create-glyph 'exclam' : glyph-construction {
|
||||
set-width WIDTH
|
||||
|
|
|
@ -6,6 +6,7 @@ font = fontforge.open(source)
|
|||
|
||||
font.selection.all()
|
||||
font.removeOverlap()
|
||||
font.addExtrema()
|
||||
font.simplify(1)
|
||||
font.canonicalContours()
|
||||
font.canonicalStart()
|
||||
|
|
|
@ -5,7 +5,7 @@ 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 [mix a b p] : a + [b - a] * p
|
||||
define [xs-array a] ([a.0 - 1] :: [a.concat ([a`[a.length - 1] + 1])])
|
||||
define [ys-array a] (a.0 :: [a.concat (a`[a.length - 1])])
|
||||
|
||||
|
@ -161,6 +161,7 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
|
||||
local p0 this.points.0
|
||||
local arcLengthSofar 0
|
||||
local unjoinedSeglength 0
|
||||
for [local j 1] [j < this.points.length] [inc j] : begin {
|
||||
local p1 this.points`j
|
||||
piecewise {
|
||||
|
@ -242,9 +243,11 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
for [local j 0] [j < subSegments.length] [inc j] : begin {
|
||||
local curve subSegments`j
|
||||
local segLength : curve.length
|
||||
set unjoinedSeglength : unjoinedSeglength + segLength
|
||||
local segLengths (0)
|
||||
|
||||
local samples : Math.min maxSamples : Math.max minSamples : Math.ceil : segLength / 100
|
||||
if [segLength <= 5] : samples = 1
|
||||
|
||||
foreach sample [range 1 till samples] : begin {
|
||||
segLengths.push : curve.split 0 [sample / samples] :.length
|
||||
|
@ -281,21 +284,22 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
if [[not straight] && [nonlinear lthis lnext dlthis] && [nonlinear lthis lnext dlnext] && [il.x != null] && [il.y != null] && [nonlinear lthis il lnext] && [near lthis il lnext]] [then {
|
||||
left.push (.x il.x .y il.y .onCurve false) (.x lnext.x .y lnext.y .onCurve true)
|
||||
}] [else {
|
||||
left.push (.x lnext.x .y lnext.y .onCurve true)
|
||||
left.push (.x [mix lthis.x lnext.x 0.5] .y [mix lthis.y lnext.y 0.5]) (.x lnext.x .y lnext.y .onCurve true)
|
||||
}]
|
||||
|
||||
local ir : intersection rthis.x rthis.y drthis.x drthis.y rnext.x rnext.y drnext.x drnext.y
|
||||
if [[not straight] && [nonlinear rthis rnext drthis] && [nonlinear rthis rnext drnext] && [ir.x != null] && [ir.y != null] && [nonlinear rthis ir rnext] && [near rthis ir rnext]] [then {
|
||||
right.push (.x ir.x .y ir.y .onCurve false) (.x rnext.x .y rnext.y .onCurve true)
|
||||
}] [else {
|
||||
right.push (.x rnext.x .y rnext.y .onCurve true)
|
||||
right.push (.x [mix rthis.x rnext.x 0.5] .y [mix rthis.y rnext.y 0.5]) (.x rnext.x .y rnext.y .onCurve true)
|
||||
}]
|
||||
}
|
||||
arcLengthSofar = arcLengthSofar + segLength
|
||||
if brk.(j) : begin {
|
||||
if [brk.(j) && unjoinedSeglength >= 100] : begin {
|
||||
shapes.push : left.concat [right.reverse]
|
||||
set left ()
|
||||
set right ()
|
||||
set unjoinedSeglength 0
|
||||
}
|
||||
}
|
||||
if [left.length + right.length > 2] : begin {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue