Introduced libspiro-js into Iosevka.
This commit is contained in:
parent
0ffc4f58cf
commit
14acdd1f1e
7 changed files with 284 additions and 107 deletions
|
@ -2,6 +2,45 @@ 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 unspiro : let [s2b [require 'libspiro-js'].spiroToBezierOnContext] : function [c closed pts] [s2b pts closed c]
|
||||||
|
|
||||||
|
### Spiro functions
|
||||||
|
define [PREPARE f] (.type 'prepare' .af f)
|
||||||
|
define [CLOSE f] (.type 'close' .af f)
|
||||||
|
define [SETWIDTH l r] : function [] : this.set-width l r
|
||||||
|
define [HEADS d] : function [] : this.heads-to d
|
||||||
|
define [WIDTHHEADS l r d] : function [] : begin [this.set-width l r] [this.heads-to d]
|
||||||
|
define [SAMPLES n] : lambda [] : this.set-samples n
|
||||||
|
define [VIRTUAL] : this.points.[this.points.length - 1].subdivided = true
|
||||||
|
define [reverse a] : a.reverse
|
||||||
|
|
||||||
|
define [flatpts pts] : begin {
|
||||||
|
local ans ()
|
||||||
|
foreach p [items-of pts] : piecewise {
|
||||||
|
[p <@ Array] : set ans : ans.concat [flatpts p]
|
||||||
|
true : ans.push p
|
||||||
|
}
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
define [spiro pts] : begin {
|
||||||
|
local s : new Stroke
|
||||||
|
local points : ().slice.call arguments 0
|
||||||
|
local closed false
|
||||||
|
local lastaf null
|
||||||
|
if [points.0 && points.0.type === 'prepare'] : begin {
|
||||||
|
points.0.af.call s
|
||||||
|
set points : points.slice 1
|
||||||
|
}
|
||||||
|
if [points.[points.length - 1] && points.[points.length - 1].type === 'close'] : begin {
|
||||||
|
set lastaf points.[points.length - 1].af
|
||||||
|
set points : points.slice 0 [-1]
|
||||||
|
set closed true
|
||||||
|
}
|
||||||
|
unspiro s closed [flatpts points]
|
||||||
|
if lastaf : lastaf.call s
|
||||||
|
s.set-samples 2
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
### COMMON FUNCTIONS
|
### COMMON FUNCTIONS
|
||||||
|
|
||||||
|
@ -77,6 +116,43 @@ define [buildFont para recursive] : begin {
|
||||||
define globalTransform : Italify para.italicAngle
|
define globalTransform : Italify para.italicAngle
|
||||||
define ITALICCOR : 1 / [Math.sqrt [1 - globalTransform.yx * globalTransform.yx]]
|
define ITALICCOR : 1 / [Math.sqrt [1 - globalTransform.yx * globalTransform.yx]]
|
||||||
|
|
||||||
|
define [G4 _x _y f] : begin {
|
||||||
|
local (.x x .y y) : tp globalTransform (.x _x .y _y)
|
||||||
|
return (.x x .y y .type 'g4' .af f)
|
||||||
|
}
|
||||||
|
define [G2 _x _y f] : begin {
|
||||||
|
local (.x x .y y) : tp globalTransform (.x _x .y _y)
|
||||||
|
return (.x x .y y .type 'g2' .af f)
|
||||||
|
}
|
||||||
|
define [LEFT _x _y f] : begin {
|
||||||
|
local (.x x .y y) : tp globalTransform (.x _x .y _y)
|
||||||
|
return (.x x .y y .type 'left' .af f)
|
||||||
|
}
|
||||||
|
define [RIGHT _x _y f] : begin {
|
||||||
|
local (.x x .y y) : tp globalTransform (.x _x .y _y)
|
||||||
|
return (.x x .y y .type 'right' .af f)
|
||||||
|
}
|
||||||
|
define [CAP_RTL x y _radius f] : begin {
|
||||||
|
local radius : fallback _radius [RIGHTSB - SB - STROKE]
|
||||||
|
local shift : radius * [1 - [Math.cos : Math.asin [0.25 / radius]]]
|
||||||
|
return : list {
|
||||||
|
G4 [x + 0.25] [y - shift] VIRTUAL
|
||||||
|
G4 x y f
|
||||||
|
G4 [x - 0.25] [y - shift] VIRTUAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
define [CAP_LTR x y r f] : [CAP_RTL x y r f].reverse
|
||||||
|
define [CUP_RTL x y _radius f] : begin {
|
||||||
|
local radius : fallback _radius [RIGHTSB - SB - STROKE]
|
||||||
|
local shift : radius * [1 - [Math.cos : Math.asin [0.25 / radius]]]
|
||||||
|
return : list {
|
||||||
|
G4 [x + 0.25] [y + shift] VIRTUAL
|
||||||
|
G4 x y f
|
||||||
|
G4 [x - 0.25] [y + shift] VIRTUAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
define [CUP_LTR x y r f] : [CUP_RTL x y r f].reverse
|
||||||
|
|
||||||
define UPWARD (.x [-ITALICCOR] .y 0)
|
define UPWARD (.x [-ITALICCOR] .y 0)
|
||||||
define DOWNWARD (.x ITALICCOR .y 0)
|
define DOWNWARD (.x ITALICCOR .y 0)
|
||||||
define RIGHTWARD (.x globalTransform.yx .y 1)
|
define RIGHTWARD (.x globalTransform.yx .y 1)
|
||||||
|
@ -264,7 +340,7 @@ define [buildFont para recursive] : begin {
|
||||||
define [create-glyph name actions] : piecewise {
|
define [create-glyph name actions] : piecewise {
|
||||||
[name && actions] : begin {
|
[name && actions] : begin {
|
||||||
if [pickHash && [not pickHash.(name)]] : return nothing
|
if [pickHash && [not pickHash.(name)]] : return nothing
|
||||||
process.stderr.write : "Building /" + name + [if recursive " (recursive)" ""] + " for " + para.family + ' ' + para.style + "\n"
|
# process.stderr.write : "Building /" + name + [if recursive " (recursive)" ""] + " for " + para.family + ' ' + para.style + "\n"
|
||||||
set dependencyProfile`name ()
|
set dependencyProfile`name ()
|
||||||
define glyphObject [new Glyph name]
|
define glyphObject [new Glyph name]
|
||||||
glyphObject.set-width WIDTH
|
glyphObject.set-width WIDTH
|
||||||
|
|
|
@ -213,6 +213,36 @@ define [EHookLower bottom smooth hook _middle _stroke _o] : XSHookLower bottom [
|
||||||
define [CHookLower bottom smooth hook _middle _stroke _o] : XSHookLower bottom [RIGHTSB + TAILADJX * globalTransform.yx] _middle [SB + [fallback _o O]] smooth [hook - TAILADJY * globalTransform.yx] _stroke
|
define [CHookLower bottom smooth hook _middle _stroke _o] : XSHookLower bottom [RIGHTSB + TAILADJX * globalTransform.yx] _middle [SB + [fallback _o O]] smooth [hook - TAILADJY * globalTransform.yx] _stroke
|
||||||
define [RevEHookLower bottom smooth hook _middle _stroke _o] : XSHookLower bottom SB _middle [RIGHTSB - [fallback _o O]] smooth hook _stroke
|
define [RevEHookLower bottom smooth hook _middle _stroke _o] : XSHookLower bottom SB _middle [RIGHTSB - [fallback _o O]] smooth hook _stroke
|
||||||
|
|
||||||
|
define [SpiroGeneralHookUpper conn free smooth y hook connectType fconn ffree tension refsmooth] : begin {
|
||||||
|
set tension : fallback tension 0
|
||||||
|
set refsmooth : fallback refsmooth smooth
|
||||||
|
local dist : free - conn
|
||||||
|
local radius : dist * dist / [[2.6 + tension] * refsmooth]
|
||||||
|
return : flatpts : list {
|
||||||
|
G4 free [y - hook] ffree
|
||||||
|
[if [free > conn] CAP_RTL CAP_LTR] [[mix conn free SBALANCE] - OMIDCOR_S] y radius
|
||||||
|
[fallback connectType G4] conn [y - smooth] fconn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
define [SpiroGeneralHookLower conn free smooth y hook connectType fconn ffree tension refsmooth] : begin {
|
||||||
|
set tension : fallback tension 0
|
||||||
|
set refsmooth : fallback refsmooth smooth
|
||||||
|
local dist : free - conn
|
||||||
|
local radius : dist * dist / [[2.6 + tension] * refsmooth]
|
||||||
|
return : flatpts : list {
|
||||||
|
G4 free [y + hook] ffree
|
||||||
|
[if [free > conn] CUP_RTL CUP_LTR] [[mix conn free SBALANCE] - OMIDCOR_S] y radius
|
||||||
|
[fallback connectType G4] conn [y + smooth] fconn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define [SpiroCHookUpper l r y connectType s] : begin {
|
||||||
|
return : SpiroGeneralHookUpper [l + O] r SMALLSMOOTHA [y - O] HOOK connectType nothing nothing 0 SMALLSMOOTH
|
||||||
|
}
|
||||||
|
define [SpiroCHookLower l r y connectType s] : list {
|
||||||
|
return : reverse : SpiroGeneralHookLower [l + O] r SMALLSMOOTHB [y + O] HOOK connectType nothing nothing 0 SMALLSMOOTH
|
||||||
|
}
|
||||||
|
|
||||||
define [smallo u d l r _width _sma _smb] : glyph-construction {
|
define [smallo u d l r _width _sma _smb] : glyph-construction {
|
||||||
local middle : [l + r] / 2
|
local middle : [l + r] / 2
|
||||||
local width : fallback _width STROKE
|
local width : fallback _width STROKE
|
||||||
|
@ -221,31 +251,50 @@ define [smallo u d l r _width _sma _smb] : glyph-construction {
|
||||||
local mc : OMIDCOR * width
|
local mc : OMIDCOR * width
|
||||||
if [u - d > sma + smb] {
|
if [u - d > sma + smb] {
|
||||||
then : begin {
|
then : begin {
|
||||||
include : create-stroke
|
include : spiro {
|
||||||
:.set-transform globalTransform
|
G4 [middle - mc] [u - O] [SETWIDTH width 0]
|
||||||
:.start-from [middle - mc] [u - O]
|
LEFT [l + O] [u - sma]
|
||||||
:.set-width width 0
|
RIGHT [l + O] [d + smb]
|
||||||
:.arc-hv-to [l + O] [u - sma]
|
G4 [middle + mc] [d + O]
|
||||||
:.line-to [l + O] [d + smb]
|
LEFT [r - O] [d + sma]
|
||||||
:.arc-vh-to [middle + mc] [d + O]
|
RIGHT [r - O] [u - smb]
|
||||||
:.arc-hv-to [r - O] [d + sma]
|
CLOSE [SAMPLES 2]
|
||||||
:.line-to [r - O] [u - smb]
|
}
|
||||||
:.arc-vh-to [middle - mc] [u - O]
|
|
||||||
}
|
}
|
||||||
else : begin {
|
else : begin {
|
||||||
local ymiddlea : mix d u [smb / [sma + smb]]
|
local ymiddlea : mix d u [smb / [sma + smb]]
|
||||||
local ymiddleb : mix d u [sma / [sma + smb]]
|
local ymiddleb : mix d u [sma / [sma + smb]]
|
||||||
include : create-stroke
|
include : spiro {
|
||||||
:.set-transform globalTransform
|
G4 [middle - mc] [u - O] [SETWIDTH width 0]
|
||||||
:.start-from [middle - mc] [u - O]
|
G4 [l + O] ymiddlea
|
||||||
:.set-width width 0
|
G4 [middle + mc] [d + O]
|
||||||
:.arc-hv-to [l + O] ymiddlea
|
G4 [r - O] ymiddleb
|
||||||
:.arc-vh-to [middle + mc] [d + O]
|
CLOSE [SAMPLES 2]
|
||||||
:.arc-hv-to [r - O] ymiddleb
|
|
||||||
:.arc-vh-to [middle - mc] [u - O]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
define [SmalloAlt u d l r _width _sma _smb] : glyph-construction {
|
||||||
|
local middle : [l + r] / 2
|
||||||
|
local width : fallback _width STROKE
|
||||||
|
local sma : fallback _sma SMALLSMOOTHA
|
||||||
|
local smb : fallback _smb SMALLSMOOTHB
|
||||||
|
local mc : OMIDCOR * width
|
||||||
|
local rho 0.77
|
||||||
|
local ymiddlea : mix d u [smb / [sma + smb]]
|
||||||
|
local ymiddleb : mix d u [sma / [sma + smb]]
|
||||||
|
include : spiro {
|
||||||
|
G4 [middle - mc] [u - O] [SETWIDTH width 0]
|
||||||
|
G4 [mix middle l rho] [mix ymiddlea u rho]
|
||||||
|
G4 [l + O] ymiddlea
|
||||||
|
G4 [mix middle l rho] [mix ymiddlea d rho]
|
||||||
|
G4 [middle + mc] [d + O]
|
||||||
|
G4 [mix middle r rho] [mix ymiddleb d rho]
|
||||||
|
G4 [r - O] ymiddleb
|
||||||
|
G4 [mix middle r rho] [mix ymiddleb u rho]
|
||||||
|
CLOSE [SAMPLES 2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
define [HBar xleft xright y _fine] : glyph-construction {
|
define [HBar xleft xright y _fine] : glyph-construction {
|
||||||
local fine : [fallback _fine STROKE] / 2
|
local fine : [fallback _fine STROKE] / 2
|
||||||
|
|
|
@ -77,7 +77,7 @@ create-glyph 'g' : glyph-construction {
|
||||||
assign-unicode 'g'
|
assign-unicode 'g'
|
||||||
include pMarks
|
include pMarks
|
||||||
|
|
||||||
include : smallo XH [XH * GBARPOS - O] SB [RIGHTSB - 0.3 * SB]
|
include : SmalloAlt XH [XH * GBARPOS] SB [RIGHTSB - 0.3 * SB]
|
||||||
|
|
||||||
local gleftx [SB * 0.8 + O]
|
local gleftx [SB * 0.8 + O]
|
||||||
local grightx [RIGHTSB + SB * 0.1 - O]
|
local grightx [RIGHTSB + SB * 0.1 - O]
|
||||||
|
@ -106,27 +106,29 @@ create-glyph 'c' : glyph-construction {
|
||||||
set-width WIDTH
|
set-width WIDTH
|
||||||
assign-unicode 'c'
|
assign-unicode 'c'
|
||||||
include eMarks
|
include eMarks
|
||||||
|
include : spiro {
|
||||||
include : CHookLower 0 SMALLSMOOTHB HOOK
|
PREPARE [SETWIDTH STROKE 0]
|
||||||
include : CHookUpper XH SMALLSMOOTHA HOOK
|
SpiroCHookUpper SB RIGHTSB XH LEFT
|
||||||
include : create-stroke
|
SpiroCHookLower SB RIGHTSB 0 RIGHT
|
||||||
:.start-from [SB + O] [XH - SMALLSMOOTHA] :.set-width STROKE 0
|
}
|
||||||
:.line-to [SB + O] SMALLSMOOTHB
|
# include : CHookLower 0 SMALLSMOOTHB HOOK
|
||||||
|
# include : CHookUpper XH SMALLSMOOTHA HOOK
|
||||||
|
# include : create-stroke
|
||||||
|
# :.start-from [SB + O] [XH - SMALLSMOOTHA] :.set-width STROKE 0
|
||||||
|
# :.line-to [SB + O] SMALLSMOOTHB
|
||||||
}
|
}
|
||||||
define [SmallEShape top stroke barpos] : glyph-construction {
|
define [SmallEShape top stroke barpos] : glyph-construction {
|
||||||
local barbottom [top * [fallback barpos EBARPOS]]
|
local barbottom [top * [fallback barpos EBARPOS]]
|
||||||
local hookx [RIGHTSB - OXHOOK + TAILADJX * globalTransform.yx]
|
local hookx [RIGHTSB - OXHOOK + TAILADJX * globalTransform.yx]
|
||||||
local hookmiddle : [mix [SB + O] hookx 0.55] + OMIDCOR_S
|
local hookmiddle : [mix [SB + O] hookx 0.55] + OMIDCOR_S
|
||||||
|
|
||||||
include : create-stroke
|
include : spiro {
|
||||||
:.start-from [RIGHTSB - O] barbottom
|
LEFT [RIGHTSB - O] barbottom [WIDTHHEADS stroke 0 UPWARD]
|
||||||
:.heads-to UPWARD
|
RIGHT [RIGHTSB - O] [top - SMALLSMOOTHB]
|
||||||
:.set-width stroke 0
|
G4 [MIDDLE - OMIDCOR_S] [top - O]
|
||||||
:.line-to [RIGHTSB - O] [top - SMALLSMOOTHB]
|
LEFT [SB + O] [top - SMALLSMOOTHA]
|
||||||
:.arc-vh-to MIDDLE [top - O]
|
SpiroCHookLower SB RIGHTSB 0 RIGHT
|
||||||
:.arc-hv-to [SB + O] [top - SMALLSMOOTHA]
|
}
|
||||||
:.line-to [SB + O] SMALLSMOOTHB
|
|
||||||
include : EHookLower 0 SMALLSMOOTHB SHOOK [mix SB RIGHTSB SBALANCE] stroke
|
|
||||||
include : create-stroke
|
include : create-stroke
|
||||||
:.start-from [SB + [stroke / 2]] barbottom
|
:.start-from [SB + [stroke / 2]] barbottom
|
||||||
:.set-width stroke 0
|
:.set-width stroke 0
|
||||||
|
@ -171,14 +173,14 @@ define [SmallTShape top bot] : glyph-construction {
|
||||||
local hookx [center + [WIDTH - SB * 2] * 0.78 - OXHOOK + TAILADJX * globalTransform.yx]
|
local hookx [center + [WIDTH - SB * 2] * 0.78 - OXHOOK + TAILADJX * globalTransform.yx]
|
||||||
local turn : mix center hookx [0.5 + globalTransform.yx * 0.5]
|
local turn : mix center hookx [0.5 + globalTransform.yx * 0.5]
|
||||||
local smb : [turn - center] * 1.1
|
local smb : [turn - center] * 1.1
|
||||||
|
local rho 0.77
|
||||||
|
|
||||||
include : create-stroke
|
include : spiro {
|
||||||
:.start-from center top
|
LEFT center top [WIDTHHEADS STROKE 0 DOWNWARD]
|
||||||
:.set-width STROKE 0
|
RIGHT center [bot + smb]
|
||||||
:.heads-to DOWNWARD
|
CUP_LTR turn [bot + O] [[hookx - center] * 0.6]
|
||||||
:.line-to center [bot + smb]
|
G2 hookx [bot + HOOK - TAILADJY * globalTransform.yx]
|
||||||
:.arc-vh-to turn [bot + O]
|
}
|
||||||
:.curve-to [turn + [KAPPA_HOOK + TAILADJKAPPA * globalTransform.yx + 0.1] * [hookx - turn]] [bot + O] hookx [bot + HOOK - TAILADJY * globalTransform.yx]
|
|
||||||
|
|
||||||
include : HBarTop [center + HALFSTROKE - LONGJUT + TBALANCE2] [center + HALFSTROKE + LONGJUT + TBALANCE2] [top * XH / CAP]
|
include : HBarTop [center + HALFSTROKE - LONGJUT + TBALANCE2] [center + HALFSTROKE + LONGJUT + TBALANCE2] [top * XH / CAP]
|
||||||
}
|
}
|
||||||
|
@ -283,22 +285,24 @@ create-glyph 'm' : glyph-construction {
|
||||||
local m2 : m1 + [MIDDLE - sw / 2 - SB]
|
local m2 : m1 + [MIDDLE - sw / 2 - SB]
|
||||||
include : create-stroke
|
include : create-stroke
|
||||||
:.start-from [MIDDLE - sw / 2] 0
|
:.start-from [MIDDLE - sw / 2] 0
|
||||||
:.set-width 0 sw :.heads-to UPWARD
|
:.set-width 0 sw
|
||||||
|
:.heads-to UPWARD
|
||||||
:.line-to [MIDDLE - sw / 2] [XH - SMALLSMOOTHA]
|
:.line-to [MIDDLE - sw / 2] [XH - SMALLSMOOTHA]
|
||||||
:.arc-vh-to m1 [XO - STROKE]
|
:.arc-vh-to m1 [XO - STROKE]
|
||||||
:.set-width 0 STROKE
|
:.set-width 0 STROKE
|
||||||
:.heads-to LEFTWARD
|
:.heads-to LEFTWARD
|
||||||
:.arc-hv-to [SB + sw * 0.75] [XH - SMALLSMOOTHA]
|
:.arc-hv-to [SB + sw * 0.75 * ITALICCOR] [XH - SMALLSMOOTHA]
|
||||||
:.heads-to DOWNWARD
|
:.heads-to DOWNWARD
|
||||||
:.set-width 0 [sw * 0.4]
|
:.set-width 0 [sw * 0.4]
|
||||||
include : create-stroke
|
include : create-stroke
|
||||||
:.start-from [RIGHTSB - sw - O] 0
|
:.start-from [RIGHTSB - sw - O] 0
|
||||||
:.set-width 0 sw :.heads-to UPWARD
|
:.set-width 0 sw
|
||||||
|
:.heads-to UPWARD
|
||||||
:.line-to [RIGHTSB - sw - O] [XH - SMALLSMOOTHA]
|
:.line-to [RIGHTSB - sw - O] [XH - SMALLSMOOTHA]
|
||||||
:.arc-vh-to m2 [XO - STROKE]
|
:.arc-vh-to m2 [XO - STROKE]
|
||||||
:.set-width 0 STROKE
|
:.set-width 0 STROKE
|
||||||
:.heads-to LEFTWARD
|
:.heads-to LEFTWARD
|
||||||
:.arc-hv-to [MIDDLE + sw * 0.25] [XH - SMALLSMOOTHA]
|
:.arc-hv-to [MIDDLE + sw * 0.25 * ITALICCOR] [XH - SMALLSMOOTHA]
|
||||||
:.heads-to DOWNWARD
|
:.heads-to DOWNWARD
|
||||||
:.set-width 0 [sw * 0.4]
|
:.set-width 0 [sw * 0.4]
|
||||||
include : create-stroke
|
include : create-stroke
|
||||||
|
|
|
@ -21,6 +21,7 @@ font.removeOverlap()
|
||||||
font.addExtrema()
|
font.addExtrema()
|
||||||
font.simplify(2)
|
font.simplify(2)
|
||||||
font.layers["Fore"].is_quadratic = False
|
font.layers["Fore"].is_quadratic = False
|
||||||
|
font.addExtrema()
|
||||||
font.simplify(6, ("smoothcurves", "removesingletonpoints", "setstarttoextremum"), 0.2)
|
font.simplify(6, ("smoothcurves", "removesingletonpoints", "setstarttoextremum"), 0.2)
|
||||||
font.canonicalContours()
|
font.canonicalContours()
|
||||||
font.canonicalStart()
|
font.canonicalStart()
|
||||||
|
|
|
@ -7,7 +7,8 @@ font = fontforge.open(source)
|
||||||
font.selection.all()
|
font.selection.all()
|
||||||
font.removeOverlap()
|
font.removeOverlap()
|
||||||
font.em = 1000
|
font.em = 1000
|
||||||
font.simplify(1)
|
font.addExtrema()
|
||||||
|
font.simplify(0.1)
|
||||||
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"))
|
|
@ -6,11 +6,7 @@ define utp [require './transform'].untransform
|
||||||
|
|
||||||
define [fallback] : for [local j 0] [j < arguments.length] [inc j] : if [arguments`j !== nothing] : return arguments`j
|
define [fallback] : for [local j 0] [j < arguments.length] [inc j] : if [arguments`j !== nothing] : return arguments`j
|
||||||
|
|
||||||
define [xs-array low high] : begin {
|
define [xs-array a] ([a.0 - 1] :: [a.concat ([a`[a.length - 1] + 1])])
|
||||||
local a ()
|
|
||||||
for [local j [low - 1]] [j <= high] [inc j] : a.push j
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
define [ys-array a] (a.0 :: [a.concat (a`[a.length - 1])])
|
define [ys-array a] (a.0 :: [a.concat (a`[a.length - 1])])
|
||||||
|
|
||||||
define SAMPLES 3
|
define SAMPLES 3
|
||||||
|
@ -33,6 +29,8 @@ define [Stroke] : begin {
|
||||||
.x 0
|
.x 0
|
||||||
.y 0
|
.y 0
|
||||||
)
|
)
|
||||||
|
this.defaultD1 = 0
|
||||||
|
this.defaultD2 = 0
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
define Stroke.is : object {
|
define Stroke.is : object {
|
||||||
|
@ -51,8 +49,16 @@ define [Stroke.bindParameters para] : begin {
|
||||||
}
|
}
|
||||||
define [Stroke.prototype.set-width d1 d2] : begin {
|
define [Stroke.prototype.set-width d1 d2] : begin {
|
||||||
local point this.points`[this.points.length - 1]
|
local point this.points`[this.points.length - 1]
|
||||||
|
if point {
|
||||||
|
then {
|
||||||
point.d1 = d1
|
point.d1 = d1
|
||||||
point.d2 = d2
|
point.d2 = d2
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.defaultD1 = d1
|
||||||
|
this.defaultD2 = d2
|
||||||
|
}
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
define [Stroke.prototype.heads-to x y] : begin {
|
define [Stroke.prototype.heads-to x y] : begin {
|
||||||
|
@ -69,18 +75,28 @@ define [Stroke.prototype.start-from x y] : begin {
|
||||||
this.points = ([tp this.gizmo (.x x .y y .onCurve true)])
|
this.points = ([tp this.gizmo (.x x .y y .onCurve true)])
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
define [Stroke.prototype.line-to x y] : begin {
|
define Stroke.prototype.moveTo Stroke.prototype.start-from
|
||||||
this.points.push [tp this.gizmo (.x x .y y .onCurve true)]
|
define [Stroke.prototype.line-to x y subdivided] : begin {
|
||||||
|
this.points.push [tp this.gizmo (.x x .y y .onCurve true .subdivided subdivided)]
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
define [Stroke.prototype.curve-to xc yc x y] : begin {
|
define Stroke.prototype.lineTo Stroke.prototype.line-to
|
||||||
this.points.push [tp this.gizmo (.x xc .y yc .onCurve false)] [tp this.gizmo (.x x .y y .onCurve true)]
|
define [Stroke.prototype.curve-to xc yc x y subdivided] : begin {
|
||||||
|
this.points.push {
|
||||||
|
tp this.gizmo (.x xc .y yc .onCurve false)
|
||||||
|
tp this.gizmo (.x x .y y .onCurve true .subdivided subdivided)
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
define [Stroke.prototype.cubic-to x1 y1 x2 y2 x y] : begin {
|
define [Stroke.prototype.cubic-to x1 y1 x2 y2 x y subdivided] : begin {
|
||||||
this.points.push [tp this.gizmo (.x x1 .y y1 .onCurve false .cubic true)] [tp this.gizmo (.x x2 .y y2 .onCurve false .cubic true)] [tp this.gizmo (.x x .y y .onCurve true)]
|
this.points.push {
|
||||||
|
tp this.gizmo (.x x1 .y y1 .onCurve false .cubic true)
|
||||||
|
tp this.gizmo (.x x2 .y y2 .onCurve false .cubic true)
|
||||||
|
tp this.gizmo (.x x .y y .onCurve true .subdivided subdivided)
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
define Stroke.prototype.cubicTo Stroke.prototype.cubic-to
|
||||||
define [Stroke.prototype.arc-vh-to x y _kappah _kappav] : begin {
|
define [Stroke.prototype.arc-vh-to x y _kappah _kappav] : begin {
|
||||||
local kappah : fallback _kappah BKAPPA
|
local kappah : fallback _kappah BKAPPA
|
||||||
local kappav : fallback _kappav _kappah CKAPPA
|
local kappav : fallback _kappav _kappah CKAPPA
|
||||||
|
@ -120,55 +136,74 @@ define [near a b c] : begin {
|
||||||
local dist : Math.max [Math.abs [a.y - c.y]] [Math.abs [a.x - c.x]]
|
local dist : Math.max [Math.abs [a.y - c.y]] [Math.abs [a.x - c.x]]
|
||||||
return : [Math.abs [b.y - my]] < dist && [Math.abs [b.x - mx]] < dist
|
return : [Math.abs [b.y - my]] < dist && [Math.abs [b.x - mx]] < dist
|
||||||
}
|
}
|
||||||
define [computeOffsetPoint curve t j foffset fpdx fpdy] : begin {
|
define [computeOffsetPoint curve t j sl foffset fpdx fpdy] : begin {
|
||||||
local onpoint : curve.compute [t - j]
|
local onpoint : curve.compute [[t - j] / sl]
|
||||||
local normal : curve.normal [t - j]
|
local normal : curve.normal [[t - j] / sl]
|
||||||
return (.x onpoint.x + [foffset t] * [normal.x + [fpdx t]] .y onpoint.y + [foffset t] * [normal.y + [fpdy t]])
|
return (.x onpoint.x + [foffset t] * [normal.x + [fpdx t]] .y onpoint.y + [foffset t] * [normal.y + [fpdy t]])
|
||||||
}
|
}
|
||||||
|
|
||||||
define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
local d1s ([set d1 [if [this.points.0.d1 >= 0] this.points.0.d1 d1]])
|
|
||||||
local d2s ([set d2 [if [this.points.0.d2 >= 0] this.points.0.d2 d2]])
|
local ts (0)
|
||||||
|
local d1s ([set d1 [if [this.points.0.d1 >= 0] this.points.0.d1 this.defaultD1]])
|
||||||
|
local d2s ([set d2 [if [this.points.0.d2 >= 0] [-this.points.0.d2] this.defaultD2]])
|
||||||
local pdxs (0)
|
local pdxs (0)
|
||||||
local pdys (0)
|
local pdys (0)
|
||||||
|
local notSubdivideds ()
|
||||||
|
|
||||||
local samples : fallback _samples this.samples SAMPLES
|
local samples : fallback _samples this.samples SAMPLES
|
||||||
local shapes ()
|
local shapes ()
|
||||||
local subSegments ()
|
local subSegments ()
|
||||||
|
|
||||||
local p0 this.points.0
|
local p0 this.points.0
|
||||||
|
local arclengthSofar 0
|
||||||
for [local j 1] [j < this.points.length] [inc j] : begin {
|
for [local j 1] [j < this.points.length] [inc j] : begin {
|
||||||
local p1 this.points`j
|
local p1 this.points`j
|
||||||
piecewise {
|
piecewise {
|
||||||
p1.onCurve : begin {
|
p1.onCurve : begin {
|
||||||
subSegments.push : local seg : new Bezier p0.x p0.y [[p0.x + p1.x] / 2] [[p0.y + p1.y] / 2] p1.x p1.y
|
subSegments.push : local seg : new Bezier p0.x p0.y [[p0.x + p1.x] / 2] [[p0.y + p1.y] / 2] p1.x p1.y
|
||||||
|
arclengthSofar = arclengthSofar + [seg.length]
|
||||||
|
if [not p1.subdivided] : begin {
|
||||||
|
ts.push arclengthSofar
|
||||||
d1s.push : set d1 [if [p1.d1 >= 0] p1.d1 d1]
|
d1s.push : set d1 [if [p1.d1 >= 0] p1.d1 d1]
|
||||||
d2s.push : set d2 [if [p1.d2 >= 0] p1.d2 d2]
|
d2s.push : set d2 [if [p1.d2 >= 0] [-p1.d2] d2]
|
||||||
local normalpt : seg.normal 1
|
local normalpt : seg.normal 1
|
||||||
pdxs.push : if [p1.pdx !== nothing] [p1.pdx - normalpt.x] 0
|
pdxs.push : if [p1.pdx !== nothing] [p1.pdx - normalpt.x] 0
|
||||||
pdys.push : if [p1.pdy !== nothing] [p1.pdy - normalpt.y] 0
|
pdys.push : if [p1.pdy !== nothing] [p1.pdy - normalpt.y] 0
|
||||||
|
set notSubdivideds.[subSegments.length - 1] true
|
||||||
|
}
|
||||||
p0 = p1
|
p0 = p1
|
||||||
}
|
}
|
||||||
p1.cubic : begin {
|
p1.cubic : begin {
|
||||||
local p2 this.points`[j + 1]
|
local p2 this.points`[j + 1]
|
||||||
local p3 this.points`[j + 2]
|
local p3 this.points`[j + 2]
|
||||||
subSegments.push : local seg : new Bezier p0.x p0.y p1.x p1.y p2.x p2.y p3.x p3.y
|
subSegments.push : local seg : new Bezier p0.x p0.y p1.x p1.y p2.x p2.y p3.x p3.y
|
||||||
|
arclengthSofar = arclengthSofar + [seg.length]
|
||||||
|
if [not p3.subdivided] : begin {
|
||||||
|
ts.push arclengthSofar
|
||||||
d1s.push : set d1 [if [p3.d1 >= 0] p3.d1 d1]
|
d1s.push : set d1 [if [p3.d1 >= 0] p3.d1 d1]
|
||||||
d2s.push : set d2 [if [p3.d2 >= 0] p3.d2 d2]
|
d2s.push : set d2 [if [p3.d2 >= 0] [-p3.d2] d2]
|
||||||
local normalpt : seg.normal 1
|
local normalpt : seg.normal 1
|
||||||
pdxs.push : if [p3.pdx !== nothing] [p3.pdx - normalpt.x] 0
|
pdxs.push : if [p3.pdx !== nothing] [p3.pdx - normalpt.x] 0
|
||||||
pdys.push : if [p3.pdy !== nothing] [p3.pdy - normalpt.y] 0
|
pdys.push : if [p3.pdy !== nothing] [p3.pdy - normalpt.y] 0
|
||||||
|
set notSubdivideds.[subSegments.length - 1] true
|
||||||
|
}
|
||||||
p0 = p3
|
p0 = p3
|
||||||
j = j + 2
|
j = j + 2
|
||||||
}
|
}
|
||||||
true : begin {
|
true : begin {
|
||||||
local p2 this.points`[j + 1]
|
local p2 this.points`[j + 1]
|
||||||
subSegments.push : local seg : new Bezier p0.x p0.y p1.x p1.y p2.x p2.y
|
subSegments.push : local seg : new Bezier p0.x p0.y p1.x p1.y p2.x p2.y
|
||||||
|
arclengthSofar = arclengthSofar + [seg.length]
|
||||||
|
if [not p2.subdivided] : begin {
|
||||||
|
ts.push arclengthSofar
|
||||||
d1s.push : set d1 [if [p2.d1 >= 0] p2.d1 d1]
|
d1s.push : set d1 [if [p2.d1 >= 0] p2.d1 d1]
|
||||||
d2s.push : set d2 [if [p2.d2 >= 0] p2.d2 d2]
|
d2s.push : set d2 [if [p2.d2 >= 0] [-p2.d2] d2]
|
||||||
local normalpt : seg.normal 1
|
local normalpt : seg.normal 1
|
||||||
pdxs.push : if [p2.pdx !== nothing] [p2.pdx - normalpt.x] 0
|
pdxs.push : if [p2.pdx !== nothing] [p2.pdx - normalpt.x] 0
|
||||||
pdys.push : if [p2.pdy !== nothing] [p2.pdy - normalpt.y] 0
|
pdys.push : if [p2.pdy !== nothing] [p2.pdy - normalpt.y] 0
|
||||||
|
set notSubdivideds.[subSegments.length - 1] true
|
||||||
|
}
|
||||||
p0 = p2
|
p0 = p2
|
||||||
j = j + 1
|
j = j + 1
|
||||||
}
|
}
|
||||||
|
@ -177,43 +212,44 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
if [this.points.0.pdx !== nothing] : set pdxs.0 [this.points.0.pdx - [subSegments.0.normal 0].x]
|
if [this.points.0.pdx !== nothing] : set pdxs.0 [this.points.0.pdx - [subSegments.0.normal 0].x]
|
||||||
if [this.points.0.pdy !== nothing] : set pdys.0 [this.points.0.pdy - [subSegments.0.normal 0].y]
|
if [this.points.0.pdy !== nothing] : set pdys.0 [this.points.0.pdy - [subSegments.0.normal 0].y]
|
||||||
|
|
||||||
local f1 : smooth [xs-array 0 d1s.length] [ys-array d1s]
|
local f1 : smooth [xs-array ts] [ys-array d1s]
|
||||||
local f2 : smooth [xs-array 0 d2s.length] [ys-array [d2s.map [[x] -> [-x]]]]
|
local f2 : smooth [xs-array ts] [ys-array d2s]
|
||||||
local fpdx : smooth [xs-array 0 d1s.length] [ys-array pdxs]
|
local fpdx : smooth [xs-array ts] [ys-array pdxs]
|
||||||
local fpdy : smooth [xs-array 0 d2s.length] [ys-array pdys]
|
local fpdy : smooth [xs-array ts] [ys-array pdys]
|
||||||
|
|
||||||
local left ()
|
local left ()
|
||||||
local right ()
|
local right ()
|
||||||
|
set arclengthSofar 0
|
||||||
for [local j 0] [j < subSegments.length] [inc j] : begin {
|
for [local j 0] [j < subSegments.length] [inc j] : begin {
|
||||||
local curve subSegments`j
|
local curve subSegments`j
|
||||||
local arcLength : curve.length
|
local segLength : curve.length
|
||||||
local segLengths (0)
|
local segLengths (0)
|
||||||
foreach sample [range 1 till samples] : begin {
|
foreach sample [range 1 till samples] : begin {
|
||||||
segLengths.push : curve.split 0 [sample / samples] :.length
|
segLengths.push : curve.split 0 [sample / samples] :.length
|
||||||
}
|
}
|
||||||
left.push [begin [local last [computeOffsetPoint curve j j f1 fpdx fpdy]] (.x last.x .y last.y .onCurve true)]
|
left.push [begin [local last [computeOffsetPoint curve arclengthSofar arclengthSofar segLength f1 fpdx fpdy]] (.x last.x .y last.y .onCurve true)]
|
||||||
right.push [begin [local last [computeOffsetPoint curve j j f2 fpdx fpdy]] (.x last.x .y last.y .onCurve true)]
|
right.push [begin [local last [computeOffsetPoint curve arclengthSofar arclengthSofar segLength f2 fpdx fpdy]] (.x last.x .y last.y .onCurve true)]
|
||||||
|
|
||||||
foreach sample [range 0 samples] : begin {
|
foreach sample [range 0 samples] : begin {
|
||||||
local t : j + segLengths.(sample) / arcLength
|
local t : arclengthSofar + segLengths.(sample)
|
||||||
local tn : j + segLengths.[sample + 1] / arcLength
|
local tn : arclengthSofar + segLengths.[sample + 1]
|
||||||
|
|
||||||
local lthis : computeOffsetPoint curve t j f1 fpdx fpdy
|
local lthis : computeOffsetPoint curve t arclengthSofar segLength f1 fpdx fpdy
|
||||||
local rthis : computeOffsetPoint curve t j f2 fpdx fpdy
|
local rthis : computeOffsetPoint curve t arclengthSofar segLength f2 fpdx fpdy
|
||||||
local lnext : computeOffsetPoint curve tn j f1 fpdx fpdy
|
local lnext : computeOffsetPoint curve tn arclengthSofar segLength f1 fpdx fpdy
|
||||||
local rnext : computeOffsetPoint curve tn j f2 fpdx fpdy
|
local rnext : computeOffsetPoint curve tn arclengthSofar segLength f2 fpdx fpdy
|
||||||
local lnthis1 : computeOffsetPoint curve [t + TINY] j f1 fpdx fpdy
|
local lnthis1 : computeOffsetPoint curve [t + TINY] arclengthSofar segLength f1 fpdx fpdy
|
||||||
local rnthis1 : computeOffsetPoint curve [t + TINY] j f2 fpdx fpdy
|
local rnthis1 : computeOffsetPoint curve [t + TINY] arclengthSofar segLength f2 fpdx fpdy
|
||||||
local lnnext1 : computeOffsetPoint curve [tn - TINY] j f1 fpdx fpdy
|
local lnnext1 : computeOffsetPoint curve [tn - TINY] arclengthSofar segLength f1 fpdx fpdy
|
||||||
local rnnext1 : computeOffsetPoint curve [tn - TINY] j f2 fpdx fpdy
|
local rnnext1 : computeOffsetPoint curve [tn - TINY] arclengthSofar segLength f2 fpdx fpdy
|
||||||
local lnthis2 : computeOffsetPoint curve [t + 2 * TINY] j f1 fpdx fpdy
|
local lnthis2 : computeOffsetPoint curve [t + 2 * TINY] arclengthSofar segLength f1 fpdx fpdy
|
||||||
local rnthis2 : computeOffsetPoint curve [t + 2 * TINY] j f2 fpdx fpdy
|
local rnthis2 : computeOffsetPoint curve [t + 2 * TINY] arclengthSofar segLength f2 fpdx fpdy
|
||||||
local lnnext2 : computeOffsetPoint curve [tn - 2 * TINY] j f1 fpdx fpdy
|
local lnnext2 : computeOffsetPoint curve [tn - 2 * TINY] arclengthSofar segLength f1 fpdx fpdy
|
||||||
local rnnext2 : computeOffsetPoint curve [tn - 2 * TINY] j f2 fpdx fpdy
|
local rnnext2 : computeOffsetPoint curve [tn - 2 * TINY] arclengthSofar segLength f2 fpdx fpdy
|
||||||
local lnthis3 : computeOffsetPoint curve [t + 3 * TINY] j f1 fpdx fpdy
|
local lnthis3 : computeOffsetPoint curve [t + 3 * TINY] arclengthSofar segLength f1 fpdx fpdy
|
||||||
local rnthis3 : computeOffsetPoint curve [t + 3 * TINY] j f2 fpdx fpdy
|
local rnthis3 : computeOffsetPoint curve [t + 3 * TINY] arclengthSofar segLength f2 fpdx fpdy
|
||||||
local lnnext3 : computeOffsetPoint curve [tn - 3 * TINY] j f1 fpdx fpdy
|
local lnnext3 : computeOffsetPoint curve [tn - 3 * TINY] arclengthSofar segLength f1 fpdx fpdy
|
||||||
local rnnext3 : computeOffsetPoint curve [tn - 3 * TINY] j f2 fpdx fpdy
|
local rnnext3 : computeOffsetPoint curve [tn - 3 * TINY] arclengthSofar segLength f2 fpdx fpdy
|
||||||
|
|
||||||
local dlthis [dforward lthis lnthis1 lnthis2 lnthis3]
|
local dlthis [dforward lthis lnthis1 lnthis2 lnthis3]
|
||||||
local drthis [dforward rthis rnthis1 rnthis2 rnthis3]
|
local drthis [dforward rthis rnthis1 rnthis2 rnthis3]
|
||||||
|
@ -234,6 +270,14 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
right.push (.x rnext.x .y rnext.y .onCurve true)
|
right.push (.x rnext.x .y rnext.y .onCurve true)
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
arclengthSofar = arclengthSofar + segLength
|
||||||
|
if notSubdivideds.(j) : begin {
|
||||||
|
shapes.push : left.concat [right.reverse]
|
||||||
|
set left ()
|
||||||
|
set right ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if [left.length + right.length > 2] : begin {
|
||||||
shapes.push : left.concat [right.reverse]
|
shapes.push : left.concat [right.reverse]
|
||||||
set left ()
|
set left ()
|
||||||
set right ()
|
set right ()
|
||||||
|
|
|
@ -3,7 +3,8 @@ exports.transformPoint = function(tfm, pt){
|
||||||
x : pt.x * tfm.xx + pt.y * tfm.yx + tfm.x,
|
x : pt.x * tfm.xx + pt.y * tfm.yx + tfm.x,
|
||||||
y : pt.x * tfm.xy + pt.y * tfm.yy + tfm.y,
|
y : pt.x * tfm.xy + pt.y * tfm.yy + tfm.y,
|
||||||
onCurve: pt.onCurve,
|
onCurve: pt.onCurve,
|
||||||
cubic: pt.cubic
|
cubic: pt.cubic,
|
||||||
|
subdivided: pt.subdivided
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.inverse = function(tfm){
|
exports.inverse = function(tfm){
|
||||||
|
@ -25,6 +26,7 @@ exports.untransform = function(tfm, pt){
|
||||||
x : (xx * tfm.yy - yy * tfm.yx) / denom,
|
x : (xx * tfm.yy - yy * tfm.yx) / denom,
|
||||||
y : (yy * tfm.xx - xx * tfm.xy) / denom,
|
y : (yy * tfm.xx - xx * tfm.xy) / denom,
|
||||||
onCurve: pt.onCurve,
|
onCurve: pt.onCurve,
|
||||||
cubic: pt.cubic
|
cubic: pt.cubic,
|
||||||
|
subdivided: pt.subdivided
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue