/s and /S are reconstructed with spiros.

This commit is contained in:
be5invis 2015-08-18 11:51:34 +08:00
parent 3b7c951e76
commit be865f5ddb
7 changed files with 110 additions and 51 deletions

View file

@ -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!

View file

@ -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
}
}])
}

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -6,6 +6,7 @@ font = fontforge.open(source)
font.selection.all()
font.removeOverlap()
font.addExtrema()
font.simplify(1)
font.canonicalContours()
font.canonicalStart()

View file

@ -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 {