first commit
This commit is contained in:
commit
075cd395d1
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directory
|
||||||
|
# Deployed apps should consider commenting this line out:
|
||||||
|
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Special
|
||||||
|
*.ttf
|
||||||
|
*.7z
|
||||||
|
test/
|
||||||
|
preview/
|
||||||
|
build/
|
||||||
|
ref/
|
16
empty.json
Normal file
16
empty.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"version":1,
|
||||||
|
"numTables":12,
|
||||||
|
"searchRenge":128,
|
||||||
|
"entrySelector":3,
|
||||||
|
"rengeShift":64,
|
||||||
|
"head":{"version":1,"fontRevision":1,"checkSumAdjustment":369537602,"magickNumber":1594834165,"flags":11,"unitsPerEm":1000,"created":"2014-12-06T22:05:19.000Z","modified":"2014-12-06T22:20:03.000Z","xMin":34,"yMin":0,"xMax":306,"yMax":682,"macStyle":0,"lowestRecPPEM":8,"fontDirectionHint":2,"indexToLocFormat":0,"glyphDataFormat":0},
|
||||||
|
"glyf":[
|
||||||
|
{"contours":[[{"x":34,"y":0,"onCurve":true},{"x":34,"y":682,"onCurve":true},{"x":306,"y":682,"onCurve":true},{"x":306,"y":0,"onCurve":true}],[{"x":68,"y":34,"onCurve":true},{"x":272,"y":34,"onCurve":true},{"x":272,"y":648,"onCurve":true},{"x":68,"y":648,"onCurve":true}]],"advanceWidth":500,"name":".notdef"}
|
||||||
|
],
|
||||||
|
"cmap":{},
|
||||||
|
"name":{"fontFamily":"fonteditor","fontSubFamily":"Medium","uniqueSubFamily":"FontEditor 1.0 : fonteditor : 6-10-2014","fullName":"fonteditor","version":"Version 1.0","postScriptName":"fonteditor"},
|
||||||
|
"hhea":{"version":1,"ascent":812,"descent":-212,"lineGap":92,"advanceWidthMax":374,"minLeftSideBearing":34,"minRightSideBearing":68,"xMaxExtent":306,"caretSlopeRise":1,"caretSlopeRun":0,"caretOffset":0,"reserved0":0,"reserved1":0,"reserved2":0,"reserved3":0,"metricDataFormat":0,"numOfLongHorMetrics":1},
|
||||||
|
"post":{"italicAngle":0,"postoints":65411,"underlinePosition":50,"underlineThickness":0,"isFixedPitch":0,"minMemType42":0,"maxMemType42":0,"minMemType1":0,"maxMemType1":1,"format":2},
|
||||||
|
"OS/2":{"version":4,"xAvgCharWidth":1031,"usWeightClass":400,"usWidthClass":5,"fsType":0,"ySubscriptXSize":665,"ySubscriptYSize":716,"ySubscriptXOffset":0,"ySubscriptYOffset":143,"ySuperscriptXSize":665,"ySuperscriptYSize":716,"ySuperscriptXOffset":0,"ySuperscriptYOffset":491,"yStrikeoutSize":51,"yStrikeoutPosition":265,"sFamilyClass":0,"bFamilyType":2,"bSerifStyle":0,"bWeight":6,"bProportion":3,"bContrast":0,"bStrokeVariation":0,"bArmStyle":0,"bLetterform":0,"bMidline":0,"bXHeight":0,"ulUnicodeRange1":1,"ulUnicodeRange2":268435456,"ulUnicodeRange3":0,"ulUnicodeRange4":0,"achVendID":"PfEd","fsSelection":192,"usFirstCharIndex":0,"usLastCharIndex":0,"sTypoAscender":812,"sTypoDescender":-212,"sTypoLineGap":92,"usWinAscent":812,"usWinDescent":212,"ulCodePageRange1":1,"ulCodePageRange2":0,"sxHeight":792,"sCapHeight":0,"usDefaultChar":0,"usBreakChar":32,"usMaxContext":1}
|
||||||
|
}
|
650
font.patel
Normal file
650
font.patel
Normal file
|
@ -0,0 +1,650 @@
|
||||||
|
define font [require './empty.json']
|
||||||
|
define bezierCubic2Q2 [require 'node-sfnt/lib/math/bezierCubic2Q2']
|
||||||
|
define glyphList font.glyf
|
||||||
|
define glyphs (.'.notdef' glyphList.0)
|
||||||
|
define Bezier [require 'bezier-js']
|
||||||
|
define Smooth [require './smooth.js'].Smooth
|
||||||
|
define intersection [require './intersection.js'].intersection
|
||||||
|
|
||||||
|
define para (
|
||||||
|
.width 500
|
||||||
|
.stroke 85
|
||||||
|
.sb 50
|
||||||
|
.cap 771
|
||||||
|
.xheight 572
|
||||||
|
.hook 135
|
||||||
|
.smooth 192
|
||||||
|
.smallsmooth 242
|
||||||
|
.o [-8]
|
||||||
|
.descender [-178]
|
||||||
|
)
|
||||||
|
|
||||||
|
define TINY 0.0001
|
||||||
|
define LITTLE 0.01
|
||||||
|
|
||||||
|
define DESCENDER para.descender
|
||||||
|
define O para.o
|
||||||
|
define WIDTH para.width
|
||||||
|
define STROKE para.stroke
|
||||||
|
define HALFSTROKE : STROKE / 2
|
||||||
|
define SB para.sb
|
||||||
|
define CAP para.cap
|
||||||
|
define XH para.xheight
|
||||||
|
define XO : XH - O
|
||||||
|
define HOOK para.hook
|
||||||
|
define SMOOTH para.smooth
|
||||||
|
define SMALLSMOOTH para.smallsmooth
|
||||||
|
define RIGHTSB : WIDTH - SB
|
||||||
|
define CAP_SMOOTH : CAP - SMOOTH
|
||||||
|
define MIDDLE : WIDTH / 2
|
||||||
|
define KAPPA 0.51
|
||||||
|
define COKAPPA : 1 - KAPPA
|
||||||
|
define COBKAPPA : COKAPPA - 0.1
|
||||||
|
define BKAPPA : KAPPA + 0.1
|
||||||
|
define CAPMIDDLE : CAP / 2
|
||||||
|
define CAPO : CAP - O
|
||||||
|
define ESS : STROKE * 0.5
|
||||||
|
define SAMPLES 4
|
||||||
|
define KAPPA_HOOK 0.7
|
||||||
|
|
||||||
|
define [Glyph name] : begin {
|
||||||
|
set this.name name
|
||||||
|
set this.unicode ()
|
||||||
|
set this.contours ()
|
||||||
|
set this.advanceWidth 500
|
||||||
|
return nothing
|
||||||
|
}
|
||||||
|
define [Glyph.prototype.set-width w] : begin {
|
||||||
|
this.advanceWidth = w
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Glyph.prototype.assign-unicode u] : begin {
|
||||||
|
this.unicode.push [u.charCodeAt 0]
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
define [Glyph.prototype.start-from x y] : begin {
|
||||||
|
this.contours.push ((.x x .y y .onCurve true))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Glyph.prototype.line-to x y] : begin {
|
||||||
|
this.contours`[this.contours.length - 1].push (.x x .y y .onCurve true)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Glyph.prototype.curve-to xc yc x y] : begin {
|
||||||
|
this.contours`[this.contours.length - 1].push (.x xc .y yc .onCurve false) (.x x .y y .onCurve true)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Glyph.prototype.cubic-to x1 y1 x2 y2 x y] : begin {
|
||||||
|
local lastContour this.contours`[this.contours.length - 1]
|
||||||
|
local lastPoint lastContour`[lastContour.length - 1]
|
||||||
|
local segments [bezierCubic2Q2 lastPoint (.x x1 .y y1) (.x x2 .y y2) (.x x .y y)]
|
||||||
|
foreach (p0 (.x xc .y yc) (.x xf .y yf)) [items-of segments] : this.curve-to xc yc xf yf
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Glyph.prototype.reverse-last] : begin {
|
||||||
|
this.contours.[this.contours.length - 1] = [this.contours.[this.contours.length - 1].reverse]
|
||||||
|
}
|
||||||
|
define [Glyph.prototype.put-shapes contours] : begin {
|
||||||
|
foreach contour [items-of contours] : begin {
|
||||||
|
this.start-from contour.0.x contour.0.y
|
||||||
|
for [local j 1] [j < contour.length] [inc j] : begin {
|
||||||
|
local point contour`j
|
||||||
|
if point.cubic [begin {
|
||||||
|
local p2 contour`[j + 1]
|
||||||
|
local p3 contour`[j + 2]
|
||||||
|
this.cubic-to point.x point.y p2.x p2.y p3.x p3.y
|
||||||
|
j = j + 2
|
||||||
|
}] [if point.onCurve [this.line-to point.x point.y] [begin {
|
||||||
|
local p2 contour`[j + 1]
|
||||||
|
this.curve-to point.x point.y p2.x p2.y
|
||||||
|
j = j + 1
|
||||||
|
}]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
define [Stroke] : begin {
|
||||||
|
this.points = ()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Stroke.prototype.set-width d1 d2] : begin {
|
||||||
|
local point this.points`[this.points.length - 1]
|
||||||
|
point.d1 = d1
|
||||||
|
point.d2 = d2
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Stroke.prototype.start-from x y] : begin {
|
||||||
|
this.points = ((.x x .y y .onCurve true))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Stroke.prototype.line-to x y] : begin {
|
||||||
|
this.points.push (.x x .y y .onCurve true)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Stroke.prototype.curve-to xc yc x y] : begin {
|
||||||
|
this.points.push (.x xc .y yc .onCurve false) (.x x .y y .onCurve true)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Stroke.prototype.cubic-to x1 y1 x2 y2 x y] : begin {
|
||||||
|
this.points.push (.x x1 .y y1 .onCurve false .cubic true) (.x x2 .y y2 .onCurve false .cubic true) (.x x .y y .onCurve true)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Stroke.prototype.arc-vh-to x y] : begin {
|
||||||
|
local last this.points`[this.points.length - 1]
|
||||||
|
this.cubic-to last.x [last.y + BKAPPA * [y - last.y]] [x + BKAPPA * [last.x - x]] y x y
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [Stroke.prototype.arc-hv-to x y] : begin {
|
||||||
|
local last this.points`[this.points.length - 1]
|
||||||
|
this.cubic-to [last.x + BKAPPA * [x - last.x]] last.y x [y + BKAPPA * [last.y - y]] x y
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
define [dforward p0 p1 p2 p3] (
|
||||||
|
.x [p0.x + [[-11] / 6 * p0.x + 3 * p1.x - 3 / 2 * p2.x + p3.x / 3] / TINY * LITTLE]
|
||||||
|
.y [p0.y + [[-11] / 6 * p0.y + 3 * p1.y - 3 / 2 * p2.y + p3.y / 3] / TINY * LITTLE]
|
||||||
|
)
|
||||||
|
define [dbackward p0 p1 p2 p3] (
|
||||||
|
.x [p0.x + [11 / 6 * p0.x - 3 * p1.x + 3 / 2 * p2.x - p3.x / 3] / TINY * LITTLE]
|
||||||
|
.y [p0.y + [11 / 6 * p0.y - 3 * p1.y + 3 / 2 * p2.y - p3.y / 3] / TINY * LITTLE]
|
||||||
|
)
|
||||||
|
define [nonlinear a b c] : [Math.abs [[c.y - a.y] * [b.x - a.x] - [c.x - a.x] * [b.y - a.y]]] > TINY
|
||||||
|
|
||||||
|
define [Stroke.prototype.form-stroke d1 d2] : 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 subSegments ()
|
||||||
|
local p0 this.points.0
|
||||||
|
for [local j 1] [j < this.points.length] [inc j] : begin {
|
||||||
|
local p1 this.points`j
|
||||||
|
piecewise {
|
||||||
|
p1.onCurve : begin {
|
||||||
|
subSegments.push (p0 (.x [[p0.x + p1.x] / 2] .y [[p0.y + p1.y] / 2]) p1)
|
||||||
|
d1s.push : set d1 [if [p1.d1 >= 0] p1.d1 d1]
|
||||||
|
d2s.push : set d2 [if [p1.d2 >= 0] p1.d2 d2]
|
||||||
|
p0 = p1
|
||||||
|
}
|
||||||
|
p1.cubic : begin {
|
||||||
|
local p2 this.points`[j + 1]
|
||||||
|
local p3 this.points`[j + 2]
|
||||||
|
d1s.push : set d1 [if [p3.d1 >= 0] p3.d1 d1]
|
||||||
|
d2s.push : set d2 [if [p3.d2 >= 0] p3.d2 d2]
|
||||||
|
subSegments.push (p0 p1 p2 p3)
|
||||||
|
p0 = p3
|
||||||
|
j = j + 2
|
||||||
|
}
|
||||||
|
true : begin {
|
||||||
|
local p2 this.points`[j + 1]
|
||||||
|
d1s.push : set d1 [if [p2.d1 >= 0] p2.d1 d1]
|
||||||
|
d2s.push : set d2 [if [p2.d2 >= 0] p2.d2 d2]
|
||||||
|
subSegments.push (p0 p1 p2)
|
||||||
|
p0 = p2
|
||||||
|
j = j + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local f1 : Smooth d1s (.method 'cubic')
|
||||||
|
local f2 : Smooth d2s (.method 'cubic')
|
||||||
|
local left ()
|
||||||
|
local right ()
|
||||||
|
for [local j 0] [j < subSegments.length] [inc j] : begin {
|
||||||
|
local seg subSegments`j
|
||||||
|
local curve : if [seg.length > 3] [new Bezier seg.0.x seg.0.y seg.1.x seg.1.y seg.2.x seg.2.y seg.3.x seg.3.y] [new Bezier seg.0.x seg.0.y seg.1.x seg.1.y seg.2.x seg.2.y]
|
||||||
|
foreach sample [range 0 SAMPLES] : begin {
|
||||||
|
local t : j + sample / SAMPLES
|
||||||
|
local tn : j + [sample + 1] / SAMPLES
|
||||||
|
|
||||||
|
local lthis : curve.offset [sample / SAMPLES] [f1 t]
|
||||||
|
local rthis : curve.offset [sample / SAMPLES] [-[f2 t]]
|
||||||
|
|
||||||
|
local lnext : curve.offset [[sample + 1] / SAMPLES] [f1 tn]
|
||||||
|
local rnext : curve.offset [[sample + 1] / SAMPLES] [-[f2 tn]]
|
||||||
|
|
||||||
|
local lnthis1 : curve.offset [sample / SAMPLES + TINY] [f1 [t + TINY]]
|
||||||
|
local rnthis1 : curve.offset [sample / SAMPLES + TINY] [-[f2 [t + TINY]]]
|
||||||
|
local lnnext1 : curve.offset [[sample + 1] / SAMPLES - TINY] [f1 [tn - TINY]]
|
||||||
|
local rnnext1 : curve.offset [[sample + 1] / SAMPLES - TINY] [-[f2 [tn - TINY]]]
|
||||||
|
local lnthis2 : curve.offset [sample / SAMPLES + [TINY * 2]] [f1 [t + [TINY * 2]]]
|
||||||
|
local rnthis2 : curve.offset [sample / SAMPLES + [TINY * 2]] [-[f2 [t + [TINY * 2]]]]
|
||||||
|
local lnnext2 : curve.offset [[sample + 1] / SAMPLES - [TINY * 2]] [f1 [tn - [TINY * 2]]]
|
||||||
|
local rnnext2 : curve.offset [[sample + 1] / SAMPLES - [TINY * 2]] [-[f2 [tn - [TINY * 2]]]]
|
||||||
|
local lnthis3 : curve.offset [sample / SAMPLES + [TINY * 3]] [f1 [t + [TINY * 3]]]
|
||||||
|
local rnthis3 : curve.offset [sample / SAMPLES + [TINY * 3]] [-[f2 [t + [TINY * 3]]]]
|
||||||
|
local lnnext3 : curve.offset [[sample + 1] / SAMPLES - [TINY * 3]] [f1 [tn - [TINY * 3]]]
|
||||||
|
local rnnext3 : curve.offset [[sample + 1] / SAMPLES - [TINY * 3]] [-[f2 [tn - [TINY * 3]]]]
|
||||||
|
|
||||||
|
local dlthis [dforward lthis lnthis1 lnthis2 lnthis3]
|
||||||
|
local drthis [dforward rthis rnthis1 rnthis2 rnthis3]
|
||||||
|
local dlnext [dbackward lnext lnnext1 lnnext2 lnnext3]
|
||||||
|
local drnext [dbackward rnext rnnext2 rnnext2 rnnext3]
|
||||||
|
|
||||||
|
local il : intersection lthis.x lthis.y dlthis.x dlthis.y lnext.x lnext.y dlnext.x dlnext.y
|
||||||
|
local ir : intersection rthis.x rthis.y drthis.x drthis.y rnext.x rnext.y drnext.x drnext.y
|
||||||
|
|
||||||
|
if [[il.x != null] && [il.y != null] && [nonlinear lthis il lnext]] [then {
|
||||||
|
left.push (.x lthis.x .y lthis.y .onCurve true) (.x il.x .y il.y .onCurve false)
|
||||||
|
}] [else {
|
||||||
|
left.push (.x lthis.x .y lthis.y .onCurve true)
|
||||||
|
}]
|
||||||
|
|
||||||
|
if [[ir.x != null] && [ir.y != null] && [nonlinear rthis ir rnext]] [then {
|
||||||
|
right.push (.x rthis.x .y rthis.y .onCurve true) (.x ir.x .y ir.y .onCurve false)
|
||||||
|
}] [else {
|
||||||
|
right.push (.x rthis.x .y rthis.y .onCurve true)
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
left.push [begin [local last [curve.offset 1 [f1 t]]] (.x last.x .y last.y .onCurve true)]
|
||||||
|
right.push [begin [local last [curve.offset 1 [-[f2 t]]]] (.x last.x .y last.y .onCurve true)]
|
||||||
|
|
||||||
|
local shape : left.concat [right.reverse] :.map [[p] -> (.x p.x .y p.y .onCurve p.onCurve)]
|
||||||
|
return (shape)
|
||||||
|
}
|
||||||
|
|
||||||
|
define [Ring u d l r] : begin {
|
||||||
|
local my [[u + d] / 2]
|
||||||
|
local mx [[l + r] / 2]
|
||||||
|
local s : new Stroke
|
||||||
|
:.start-from mx d
|
||||||
|
:.cubic-to [mx + [l - mx] * BKAPPA] d l [my + [d - my] * BKAPPA] l my
|
||||||
|
:.cubic-to l [my + [u - my] * BKAPPA] [mx + [l - mx] * BKAPPA] u mx u
|
||||||
|
:.cubic-to [mx + [r - mx] * BKAPPA] u r [my + [u - my] * BKAPPA] r my
|
||||||
|
:.cubic-to r [my + [d - my] * BKAPPA] [mx + [r - mx] * BKAPPA] d mx d
|
||||||
|
return s.points
|
||||||
|
}
|
||||||
|
define [ORing u d l r smooth] : begin {
|
||||||
|
local myu [u - smooth]
|
||||||
|
local myd [d + smooth]
|
||||||
|
local mx [[l + r] / 2]
|
||||||
|
local s : new Stroke
|
||||||
|
:.start-from mx d
|
||||||
|
:.cubic-to [mx + [l - mx] * BKAPPA] d l [myd + [d - myd] * BKAPPA] l myd
|
||||||
|
:.line-to l myu
|
||||||
|
:.cubic-to l [myu + [u - myu] * BKAPPA] [mx + [l - mx] * BKAPPA] u mx u
|
||||||
|
:.cubic-to [mx + [r - mx] * BKAPPA] u r [myu + [u - myu] * BKAPPA] r myu
|
||||||
|
:.line-to r myd
|
||||||
|
:.cubic-to r [myd + [d - myd] * BKAPPA] [mx + [r - mx] * BKAPPA] d mx d
|
||||||
|
return s.points
|
||||||
|
}
|
||||||
|
|
||||||
|
define-macro glyph-construction : syntax-rules {
|
||||||
|
@`[glyph-construction @::steps] ('.syntactic-closure' @`[lambda [] [begin {
|
||||||
|
local set-width : this.set-width.bind this
|
||||||
|
local assign-unicode : this.assign-unicode.bind this
|
||||||
|
local start-from : this.start-from.bind this
|
||||||
|
local line-to : this.line-to.bind this
|
||||||
|
local curve-to : this.curve-to.bind this
|
||||||
|
local cubic-to : this.cubic-to.bind this
|
||||||
|
local put-shapes : this.put-shapes.bind this
|
||||||
|
local reverse-last : this.reverse-last.bind this
|
||||||
|
begin @::[steps.map formOf]
|
||||||
|
return nothing
|
||||||
|
}]] env)
|
||||||
|
}
|
||||||
|
|
||||||
|
define [create-glyph name actions] : begin {
|
||||||
|
define glyphObject [new Glyph name]
|
||||||
|
glyphList.push glyphObject
|
||||||
|
glyphs`name = glyphObject
|
||||||
|
actions.call glyphObject
|
||||||
|
return glyphObject
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
### GLYPHS
|
||||||
|
create-glyph 'space' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode ' '
|
||||||
|
}
|
||||||
|
create-glyph 'bar' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode '|'
|
||||||
|
put-shapes : new Stroke :.start-from MIDDLE [DESCENDER / 2]
|
||||||
|
:.set-width [STROKE / 2] [STROKE / 2]
|
||||||
|
:.line-to MIDDLE [CAP - DESCENDER / 2]
|
||||||
|
:.form-stroke
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'A' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'A'
|
||||||
|
|
||||||
|
local TURN [XH * 0.1]
|
||||||
|
|
||||||
|
local leftbar : new Stroke
|
||||||
|
leftbar.start-from SB 0
|
||||||
|
:.line-to SB TURN
|
||||||
|
:.curve-to SB [TURN + 0.27 * [CAP - TURN]] [MIDDLE - STROKE / 2] CAP
|
||||||
|
|
||||||
|
local rightbar : new Stroke
|
||||||
|
rightbar.start-from RIGHTSB 0
|
||||||
|
:.line-to RIGHTSB TURN
|
||||||
|
:.curve-to RIGHTSB [TURN + 0.27 * [CAP - TURN]] [MIDDLE + STROKE / 2] CAP
|
||||||
|
|
||||||
|
local hbar : new Stroke
|
||||||
|
hbar.start-from [SB + STROKE] [XH / 2] :.line-to [RIGHTSB - STROKE] [XH / 2]
|
||||||
|
|
||||||
|
put-shapes : leftbar.form-stroke 0 STROKE
|
||||||
|
put-shapes : hbar.form-stroke 0 STROKE
|
||||||
|
put-shapes : rightbar.form-stroke STROKE 0
|
||||||
|
|
||||||
|
#top cap
|
||||||
|
start-from [MIDDLE - STROKE / 2] CAP
|
||||||
|
line-to [MIDDLE + STROKE / 2] CAP
|
||||||
|
line-to MIDDLE [CAP - STROKE]
|
||||||
|
}
|
||||||
|
create-glyph 'X' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'X'
|
||||||
|
|
||||||
|
local TURN [XH * 0.05]
|
||||||
|
local straight 0.6
|
||||||
|
local strench 0.125
|
||||||
|
|
||||||
|
local barone : new Stroke
|
||||||
|
:.start-from [SB + HALFSTROKE] 0
|
||||||
|
:.set-width HALFSTROKE HALFSTROKE
|
||||||
|
:.line-to [SB + HALFSTROKE] TURN
|
||||||
|
:.curve-to [SB + HALFSTROKE] [TURN + strench * [CAP - TURN]] [MIDDLE + straight * [SB + HALFSTROKE - MIDDLE]] [CAPMIDDLE + straight * [TURN + strench * [CAP - TURN] - CAPMIDDLE]]
|
||||||
|
:.line-to [MIDDLE + straight * [RIGHTSB - HALFSTROKE - MIDDLE]] [CAPMIDDLE + straight * [CAP - TURN - strench * [CAP - TURN] - CAPMIDDLE]]
|
||||||
|
:.curve-to [RIGHTSB - HALFSTROKE] [CAP - TURN - strench * [CAP - TURN]] [RIGHTSB - HALFSTROKE] [CAP - TURN]
|
||||||
|
:.line-to [RIGHTSB - HALFSTROKE] CAP
|
||||||
|
:.form-stroke
|
||||||
|
|
||||||
|
local bartwo : list : barone.0.map [[pt] -> (.x [WIDTH - pt.x] .y pt.y .onCurve pt.onCurve .cubic pt.cubic)] :.reverse
|
||||||
|
|
||||||
|
put-shapes barone
|
||||||
|
put-shapes bartwo
|
||||||
|
}
|
||||||
|
create-glyph 'Y' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'Y'
|
||||||
|
|
||||||
|
local TURN [XH * 0.05]
|
||||||
|
local straight 0.6
|
||||||
|
local strench 0.15
|
||||||
|
local cross [CAP * 0.4]
|
||||||
|
|
||||||
|
local barone : new Stroke
|
||||||
|
:.start-from MIDDLE cross
|
||||||
|
:.set-width HALFSTROKE HALFSTROKE
|
||||||
|
:.line-to [MIDDLE + straight * [RIGHTSB - HALFSTROKE - MIDDLE]] [cross + straight * [CAP - TURN - strench * [CAP - TURN] - cross]]
|
||||||
|
:.curve-to [RIGHTSB - HALFSTROKE] [CAP - TURN - strench * [CAP - TURN]] [RIGHTSB - HALFSTROKE] [CAP - TURN]
|
||||||
|
:.line-to [RIGHTSB - HALFSTROKE] CAP
|
||||||
|
:.form-stroke
|
||||||
|
|
||||||
|
local bartwo : list : barone.0.map [[pt] -> (.x [WIDTH - pt.x] .y pt.y .onCurve pt.onCurve .cubic pt.cubic)] :.reverse
|
||||||
|
|
||||||
|
put-shapes barone
|
||||||
|
put-shapes bartwo
|
||||||
|
put-shapes : new Stroke :.start-from MIDDLE 0 :.set-width HALFSTROKE HALFSTROKE :.line-to MIDDLE [cross + HALFSTROKE] :.form-stroke
|
||||||
|
}
|
||||||
|
create-glyph 'x' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'x'
|
||||||
|
|
||||||
|
local TURN [XH * 0.1]
|
||||||
|
|
||||||
|
local barone : new Stroke
|
||||||
|
:.start-from [SB + HALFSTROKE] 0
|
||||||
|
:.set-width HALFSTROKE HALFSTROKE
|
||||||
|
:.cubic-to [SB + HALFSTROKE] [TURN + 0.17 * [XH - TURN]] [RIGHTSB - HALFSTROKE] [XH - TURN - 0.17 * [XH - TURN]] [RIGHTSB - HALFSTROKE] XH
|
||||||
|
:.form-stroke
|
||||||
|
|
||||||
|
local bartwo : list : barone.0.map [[pt] -> (.x [WIDTH - pt.x] .y pt.y .onCurve pt.onCurve .cubic pt.cubic)] :.reverse
|
||||||
|
|
||||||
|
put-shapes barone
|
||||||
|
put-shapes bartwo
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'B' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'B'
|
||||||
|
|
||||||
|
local bowl 451
|
||||||
|
local tkappa [COKAPPA - 0.22]
|
||||||
|
local bkappa [COKAPPA - 0.2]
|
||||||
|
|
||||||
|
local turntop : [CAP + [bowl - STROKE]] / 2
|
||||||
|
local turnbottom : bowl / 2
|
||||||
|
|
||||||
|
local topbowl : new Stroke
|
||||||
|
topbowl.start-from SB CAP
|
||||||
|
:.line-to [RIGHTSB - SB * 0.5 - turnbottom] CAP
|
||||||
|
:.cubic-to [RIGHTSB - SB * 0.5 - tkappa * turnbottom] CAP [RIGHTSB - SB * 0.5] [turntop + [CAP - turntop] * KAPPA] [RIGHTSB - SB * 0.5] turntop
|
||||||
|
:.cubic-to [RIGHTSB - SB * 0.5] [turntop + KAPPA * [bowl - STROKE - turntop]] [RIGHTSB - SB * 0.5 - tkappa * turnbottom] [bowl - STROKE] [RIGHTSB - SB * 0.5 - turnbottom] [bowl - STROKE]
|
||||||
|
:.line-to SB [bowl - STROKE]
|
||||||
|
|
||||||
|
local bottombowl : new Stroke
|
||||||
|
bottombowl.start-from SB 0
|
||||||
|
:.line-to [RIGHTSB - turnbottom] 0
|
||||||
|
:.cubic-to [RIGHTSB - bkappa * turnbottom] 0 RIGHTSB [turnbottom * KAPPA] RIGHTSB turnbottom
|
||||||
|
:.cubic-to RIGHTSB [turnbottom + KAPPA * [bowl - turnbottom]] [RIGHTSB - bkappa * turnbottom] bowl [RIGHTSB - turnbottom] bowl
|
||||||
|
:.line-to SB bowl
|
||||||
|
|
||||||
|
local leftbar : new Stroke :.start-from SB 0 :.line-to SB CAP
|
||||||
|
|
||||||
|
put-shapes : topbowl.form-stroke 0 STROKE
|
||||||
|
put-shapes : bottombowl.form-stroke STROKE 0
|
||||||
|
put-shapes : leftbar.form-stroke 0 STROKE
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'C' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'C'
|
||||||
|
local outline : new Stroke
|
||||||
|
outline.start-from [RIGHTSB - SB * 0.1] [CAP - HOOK]
|
||||||
|
:.curve-to [MIDDLE + KAPPA_HOOK * [MIDDLE - para.sb]] CAPO MIDDLE CAPO
|
||||||
|
:.cubic-to [SB + [1 - BKAPPA] * [WIDTH / 2 - SB]] CAPO SB [CAP - COBKAPPA * SMOOTH] SB CAP_SMOOTH
|
||||||
|
:.line-to SB SMOOTH
|
||||||
|
:.cubic-to SB [COBKAPPA * SMOOTH] [SB + [1 - BKAPPA] * [WIDTH / 2 - SB]] O [WIDTH / 2] O
|
||||||
|
:.curve-to [MIDDLE + KAPPA_HOOK * [MIDDLE - SB]] O [RIGHTSB - SB * 0.1] HOOK
|
||||||
|
put-shapes : outline.form-stroke STROKE 0
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'D' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'D'
|
||||||
|
|
||||||
|
local dsmooth [SMOOTH * 1.55]
|
||||||
|
local bsmooth [SMOOTH * 1.3]
|
||||||
|
local bkappa [COKAPPA - 0.2]
|
||||||
|
|
||||||
|
local leftbar : new Stroke :.start-from SB 0 :.line-to SB CAP
|
||||||
|
|
||||||
|
local bowl : new Stroke
|
||||||
|
bowl.start-from SB 0
|
||||||
|
:.line-to [RIGHTSB - bsmooth] 0
|
||||||
|
:.cubic-to [RIGHTSB - bkappa * bsmooth] 0 RIGHTSB [COBKAPPA * dsmooth] RIGHTSB dsmooth
|
||||||
|
:.line-to RIGHTSB [CAP - dsmooth]
|
||||||
|
:.cubic-to RIGHTSB [CAP - COBKAPPA * dsmooth] [RIGHTSB - bkappa * bsmooth] CAP [RIGHTSB - bsmooth] CAP
|
||||||
|
:.line-to SB CAP
|
||||||
|
|
||||||
|
put-shapes : bowl.form-stroke STROKE 0
|
||||||
|
put-shapes : leftbar.form-stroke 0 STROKE
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'G' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'G'
|
||||||
|
local outline : new Stroke
|
||||||
|
outline.start-from [RIGHTSB - SB * 0.1] [CAP - HOOK]
|
||||||
|
:.curve-to [MIDDLE + KAPPA_HOOK * [MIDDLE - para.sb]] CAPO MIDDLE CAPO
|
||||||
|
:.cubic-to [SB + [1 - BKAPPA] * [WIDTH / 2 - SB]] CAPO SB [CAP - COBKAPPA * SMOOTH] SB CAP_SMOOTH
|
||||||
|
:.line-to SB SMOOTH
|
||||||
|
:.cubic-to SB [COBKAPPA * SMOOTH] [SB + [1 - BKAPPA] * [WIDTH / 2 - SB]] O [WIDTH / 2] O
|
||||||
|
:.cubic-to [MIDDLE + BKAPPA * [RIGHTSB - MIDDLE]] O RIGHTSB [COBKAPPA * SMOOTH] RIGHTSB SMOOTH
|
||||||
|
:.line-to RIGHTSB [CAP / 2 + STROKE / 2]
|
||||||
|
put-shapes : outline.form-stroke STROKE 0
|
||||||
|
|
||||||
|
local bar : new Stroke :.start-from MIDDLE [CAP / 2 + STROKE / 2] :.line-to RIGHTSB [CAP / 2 + STROKE / 2]
|
||||||
|
put-shapes : bar.form-stroke 0 STROKE
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'O' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'O'
|
||||||
|
local outline : new Stroke
|
||||||
|
outline.start-from MIDDLE CAPO
|
||||||
|
:.cubic-to [SB + [1 - BKAPPA] * [WIDTH / 2 - SB]] CAPO SB [CAP - COBKAPPA * SMOOTH] SB [CAP - SMOOTH]
|
||||||
|
:.line-to SB SMOOTH
|
||||||
|
:.cubic-to SB [COBKAPPA * SMOOTH] [SB + [1 - BKAPPA] * [WIDTH / 2 - SB]] O [WIDTH / 2] O
|
||||||
|
:.cubic-to [MIDDLE + BKAPPA * [RIGHTSB - MIDDLE]] O RIGHTSB [COBKAPPA * SMOOTH] RIGHTSB SMOOTH
|
||||||
|
:.line-to RIGHTSB [CAP - SMOOTH]
|
||||||
|
:.cubic-to RIGHTSB [CAP - COBKAPPA * SMOOTH] [MIDDLE + BKAPPA * [RIGHTSB - MIDDLE]] CAPO MIDDLE CAPO
|
||||||
|
put-shapes : outline.form-stroke STROKE 0
|
||||||
|
}
|
||||||
|
create-glyph 'o' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'o'
|
||||||
|
put-shapes : list {
|
||||||
|
ORing XO O SB RIGHTSB SMALLSMOOTH
|
||||||
|
ORing [XO - STROKE] [O + STROKE] [SB + STROKE] [RIGHTSB - STROKE] [SMALLSMOOTH - STROKE]
|
||||||
|
}
|
||||||
|
reverse-last
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'o.left' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
# build outline manually
|
||||||
|
put-shapes : list {
|
||||||
|
ORing XO O [SB + STROKE / 2] RIGHTSB SMALLSMOOTH
|
||||||
|
ORing [XO - STROKE] [O + STROKE] [SB + STROKE] [RIGHTSB - STROKE] [SMALLSMOOTH - STROKE]
|
||||||
|
}
|
||||||
|
reverse-last
|
||||||
|
}
|
||||||
|
create-glyph 'o.right' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
# build outline manually
|
||||||
|
put-shapes : list {
|
||||||
|
ORing XO O SB [RIGHTSB - STROKE / 2] SMALLSMOOTH
|
||||||
|
ORing [XO - STROKE] [O + STROKE] [SB + STROKE] [RIGHTSB - STROKE] [SMALLSMOOTH - STROKE]
|
||||||
|
}
|
||||||
|
reverse-last
|
||||||
|
}
|
||||||
|
create-glyph 'p' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'p'
|
||||||
|
put-shapes glyphs.'o.left'.contours
|
||||||
|
put-shapes : new Stroke :.start-from SB XH :.set-width STROKE 0 :.line-to SB DESCENDER :.form-stroke
|
||||||
|
}
|
||||||
|
create-glyph 'b' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'b'
|
||||||
|
put-shapes glyphs.'o.left'.contours
|
||||||
|
put-shapes : new Stroke :.start-from SB 0 :.set-width 0 STROKE :.line-to SB CAP :.form-stroke
|
||||||
|
}
|
||||||
|
create-glyph 'q' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'q'
|
||||||
|
put-shapes glyphs.'o.right'.contours
|
||||||
|
put-shapes : new Stroke :.start-from RIGHTSB XH :.set-width 0 STROKE :.line-to RIGHTSB DESCENDER :.form-stroke
|
||||||
|
}
|
||||||
|
create-glyph 'g' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'g'
|
||||||
|
|
||||||
|
put-shapes : list {
|
||||||
|
Ring XO [XH * 0.4] [SB * 1.5] [RIGHTSB - 0.5 * SB] SMALLSMOOTH
|
||||||
|
Ring [XO - STROKE] [[XH * 0.4] + STROKE] [SB * 1.5 + STROKE] [[RIGHTSB - 0.5 * SB] - STROKE] [SMALLSMOOTH - STROKE]
|
||||||
|
}
|
||||||
|
reverse-last
|
||||||
|
|
||||||
|
put-shapes : new Stroke
|
||||||
|
:.start-from MIDDLE [XH * 0.4]
|
||||||
|
:.set-width 0 [STROKE * 0.75]
|
||||||
|
:.arc-hv-to [SB * 1.5 + STROKE] [[O - DESCENDER * 0.85 + XH * 0.4] / 2]
|
||||||
|
:.set-width 0 STROKE
|
||||||
|
:.arc-vh-to [MIDDLE + DESCENDER * 0.15] [O - DESCENDER * 0.85]
|
||||||
|
:.line-to [MIDDLE - DESCENDER * 0.15] [O - DESCENDER * 0.85]
|
||||||
|
:.arc-hv-to [RIGHTSB - O * 2] 0
|
||||||
|
:.arc-vh-to MIDDLE [DESCENDER + O]
|
||||||
|
:.arc-hv-to SB [DESCENDER * 0.1]
|
||||||
|
:.arc-vh-to [MIDDLE + DESCENDER * 0.15] [O - DESCENDER * 0.85]
|
||||||
|
:.form-stroke
|
||||||
|
|
||||||
|
start-from RIGHTSB XH
|
||||||
|
line-to RIGHTSB [XH - STROKE]
|
||||||
|
line-to MIDDLE [XH - STROKE - O]
|
||||||
|
line-to MODDLE XH
|
||||||
|
}
|
||||||
|
create-glyph 'd' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'd'
|
||||||
|
put-shapes glyphs.'o.right'.contours
|
||||||
|
put-shapes : new Stroke :.start-from RIGHTSB 0 :.set-width STROKE 0 :.line-to RIGHTSB CAP :.form-stroke
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'zero' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode '0'
|
||||||
|
put-shapes glyphs.O.contours
|
||||||
|
|
||||||
|
local bar : new Stroke :.start-from [SB + STROKE / 2] [CAP * [1 - 0.65]] :.line-to [RIGHTSB - STROKE / 2] [CAP * 0.65]
|
||||||
|
put-shapes : bar.form-stroke [STROKE / 2] [STROKE / 2]
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'Q' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'Q'
|
||||||
|
|
||||||
|
put-shapes glyphs.O.contours
|
||||||
|
start-from MIDDLE 0
|
||||||
|
line-to [MIDDLE + STROKE / 2] [-CAP * 0.2]
|
||||||
|
line-to [MIDDLE + STROKE / 2 + STROKE] [-CAP * 0.2]
|
||||||
|
line-to [MIDDLE + STROKE] 0
|
||||||
|
line-to [MIDDLE + STROKE * [1 - 0.5 / 3]] [STROKE * 0.5]
|
||||||
|
reverse-last
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'H' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'H'
|
||||||
|
|
||||||
|
put-shapes : new Stroke :.start-from SB 0 :.set-width 0 STROKE :.line-to SB CAP :.form-stroke
|
||||||
|
put-shapes : new Stroke :.start-from RIGHTSB 0 :.set-width STROKE 0 :.line-to RIGHTSB CAP :.form-stroke
|
||||||
|
put-shapes : new Stroke :.start-from SB [CAP / 2] :.set-width HALFSTROKE HALFSTROKE :.line-to RIGHTSB [CAP / 2] :.form-stroke
|
||||||
|
}
|
||||||
|
|
||||||
|
create-glyph 'L' : glyph-construction {
|
||||||
|
set-width WIDTH
|
||||||
|
assign-unicode 'L'
|
||||||
|
|
||||||
|
put-shapes : new Stroke :.start-from [SB * 1.5] CAP :.line-to [SB * 1.5] 0 :.form-stroke STROKE 0
|
||||||
|
put-shapes : new Stroke :.start-from [SB * 1.5] 0 :.line-to RIGHTSB 0 :.form-stroke STROKE 0
|
||||||
|
}
|
||||||
|
create-glyph 'S' : glyph-construction {
|
||||||
|
set-width WIDTH; assign-unicode 'S'
|
||||||
|
|
||||||
|
local slope 0.11
|
||||||
|
|
||||||
|
local bowltop : new Stroke
|
||||||
|
bowltop.start-from [RIGHTSB - SB * 0.1] [CAP - HOOK]
|
||||||
|
:.set-width STROKE 0
|
||||||
|
:.curve-to [MIDDLE + KAPPA_HOOK * [MIDDLE - para.sb]] CAPO MIDDLE CAPO
|
||||||
|
:.cubic-to [SB + [1 - BKAPPA] * [WIDTH / 2 - SB]] CAPO SB [CAP - COBKAPPA * SMOOTH] SB CAP_SMOOTH
|
||||||
|
|
||||||
|
local strokemiddle : new Stroke
|
||||||
|
strokemiddle.start-from [SB + STROKE / 2] CAP_SMOOTH
|
||||||
|
:.set-width [STROKE / 2] [STROKE / 2]
|
||||||
|
:.curve-to [SB + STROKE / 2] [[0.5 + slope] * CAP + [2 * slope * CAP] / [0.4 * WIDTH] * [0.3 * WIDTH - SB - STROKE / 2]] [0.3 * WIDTH] [[0.5 + slope] * CAP]
|
||||||
|
:.line-to [0.7 * WIDTH] [[0.5 - slope] * CAP]
|
||||||
|
:.curve-to [RIGHTSB - STROKE / 2] [[0.5 - slope] * CAP - [2 * slope * CAP] / [0.4 * WIDTH] * [0.3 * WIDTH - SB - STROKE / 2]] [RIGHTSB - STROKE / 2] SMOOTH
|
||||||
|
|
||||||
|
local bowlbottom : new Stroke
|
||||||
|
bowlbottom.start-from RIGHTSB SMOOTH :.set-width 0 STROKE
|
||||||
|
:.cubic-to RIGHTSB [COBKAPPA * SMOOTH] [MIDDLE + BKAPPA * [RIGHTSB - MIDDLE]] O MIDDLE O
|
||||||
|
:.curve-to [MIDDLE - KAPPA_HOOK * [MIDDLE - para.sb]] O [SB * 1.1] HOOK
|
||||||
|
|
||||||
|
put-shapes : bowltop.form-stroke
|
||||||
|
put-shapes : strokemiddle.form-stroke
|
||||||
|
put-shapes : bowlbottom.form-stroke
|
||||||
|
}
|
||||||
|
create-glyph 'dollar' : glyph-construction {
|
||||||
|
set-width WIDTH; assign-unicode '$'
|
||||||
|
put-shapes glyphs.S.contours
|
||||||
|
put-shapes : new Stroke :.start-from MIDDLE CAP :.set-width HALFSTROKE HALFSTROKE :.line-to MIDDLE [CAP - DESCENDER / 2] :.form-stroke
|
||||||
|
put-shapes : new Stroke :.start-from MIDDLE [DESCENDER / 2] :.set-width HALFSTROKE HALFSTROKE :.line-to MIDDLE 0 :.form-stroke
|
||||||
|
}
|
||||||
|
exports.font = font
|
51
generate.js
Normal file
51
generate.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
var font = require('./font.js');
|
||||||
|
var TTFWriter = require('node-sfnt').TTFWriter;
|
||||||
|
var TTF = require('node-sfnt').TTF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* buffer转换成ArrayBuffer
|
||||||
|
*
|
||||||
|
* @param {Buffer} buffer 缓冲数组
|
||||||
|
* @return {ArrayBuffer}
|
||||||
|
*/
|
||||||
|
function toArrayBuffer(buffer) {
|
||||||
|
var length = buffer.length;
|
||||||
|
var view = new DataView(new ArrayBuffer(length), 0, length);
|
||||||
|
for (var i = 0, l = length; i < l; i++) {
|
||||||
|
view.setUint8(i, buffer[i], false);
|
||||||
|
}
|
||||||
|
return view.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ArrayBuffer转换成Buffer
|
||||||
|
*
|
||||||
|
* @param {ArrayBuffer} arrayBuffer 缓冲数组
|
||||||
|
* @return {Buffer}
|
||||||
|
*/
|
||||||
|
function toBuffer(arrayBuffer) {
|
||||||
|
var length = arrayBuffer.byteLength;
|
||||||
|
var view = new DataView(arrayBuffer, 0, length);
|
||||||
|
var buffer = new Buffer(length);
|
||||||
|
for (var i = 0, l = length; i < l; i++) {
|
||||||
|
buffer[i] = view.getUint8(i, false);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = {preserveOS2Version: true}
|
||||||
|
|
||||||
|
function readttf(file) {
|
||||||
|
var data = fs.readFileSync(file);
|
||||||
|
var buffer = toArrayBuffer(data);
|
||||||
|
var ttf = (new OTFReader(options)).read(buffer);
|
||||||
|
return ttf;
|
||||||
|
}
|
||||||
|
|
||||||
|
function writettf(ttf, file){
|
||||||
|
var buffer = new TTFWriter(options).write(ttf);
|
||||||
|
fs.writeFileSync(file, toBuffer(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(process.argv[2], toBuffer(new TTFWriter(options).write(font.font)));
|
38
intersection.js
Normal file
38
intersection.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
exports.intersection = function (line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY) {
|
||||||
|
// if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
|
||||||
|
var denominator, a, b, numerator1, numerator2, result = {
|
||||||
|
x: null,
|
||||||
|
y: null,
|
||||||
|
onLine1: false,
|
||||||
|
onLine2: false
|
||||||
|
};
|
||||||
|
denominator = ((line2EndY - line2StartY) * (line1EndX - line1StartX)) - ((line2EndX - line2StartX) * (line1EndY - line1StartY));
|
||||||
|
if (Math.abs(denominator) < 0.000000000001) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
a = line1StartY - line2StartY;
|
||||||
|
b = line1StartX - line2StartX;
|
||||||
|
numerator1 = ((line2EndX - line2StartX) * a) - ((line2EndY - line2StartY) * b);
|
||||||
|
numerator2 = ((line1EndX - line1StartX) * a) - ((line1EndY - line1StartY) * b);
|
||||||
|
a = numerator1 / denominator;
|
||||||
|
b = numerator2 / denominator;
|
||||||
|
|
||||||
|
// if we cast these lines infinitely in both directions, they intersect here:
|
||||||
|
result.x = line1StartX + (a * (line1EndX - line1StartX));
|
||||||
|
result.y = line1StartY + (a * (line1EndY - line1StartY));
|
||||||
|
/*
|
||||||
|
// it is worth noting that this should be the same as:
|
||||||
|
x = line2StartX + (b * (line2EndX - line2StartX));
|
||||||
|
y = line2StartX + (b * (line2EndY - line2StartY));
|
||||||
|
*/
|
||||||
|
// if line1 is a segment and line2 is infinite, they intersect if:
|
||||||
|
if (a > 0 && a < 1) {
|
||||||
|
result.onLine1 = true;
|
||||||
|
}
|
||||||
|
// if line2 is a segment and line1 is infinite, they intersect if:
|
||||||
|
if (b > 0 && b < 1) {
|
||||||
|
result.onLine2 = true;
|
||||||
|
}
|
||||||
|
// if line1 and line2 are segments, they intersect if both of the above are true
|
||||||
|
return result;
|
||||||
|
};
|
8
makefile
Normal file
8
makefile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
JSFILES = font.js
|
||||||
|
|
||||||
|
all : $(JSFILES)
|
||||||
|
|
||||||
|
$(JSFILES) :
|
||||||
|
patel-c $< -o $@
|
||||||
|
|
||||||
|
font.js : font.patel
|
411
smooth.js
Normal file
411
smooth.js
Normal file
|
@ -0,0 +1,411 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
Smooth.js version 0.1.7
|
||||||
|
|
||||||
|
Turn arrays into smooth functions.
|
||||||
|
|
||||||
|
Copyright 2012 Spencer Cohen
|
||||||
|
Licensed under MIT license (see "Smooth.js MIT license.txt")
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*Constants (these are accessible by Smooth.WHATEVER in user space)
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var AbstractInterpolator, CubicInterpolator, Enum, LinearInterpolator, NearestInterpolator, PI, SincFilterInterpolator, Smooth, clipClamp, clipMirror, clipPeriodic, defaultConfig, getColumn, getType, isValidNumber, k, makeLanczosWindow, makeScaledFunction, makeSincKernel, normalizeScaleTo, shallowCopy, sin, sinc, v, validateNumber, validateVector,
|
||||||
|
__hasProp = Object.prototype.hasOwnProperty,
|
||||||
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
|
||||||
|
|
||||||
|
Enum = {
|
||||||
|
/*Interpolation methods
|
||||||
|
*/
|
||||||
|
METHOD_NEAREST: 'nearest',
|
||||||
|
METHOD_LINEAR: 'linear',
|
||||||
|
METHOD_CUBIC: 'cubic',
|
||||||
|
METHOD_LANCZOS: 'lanczos',
|
||||||
|
METHOD_SINC: 'sinc',
|
||||||
|
/*Input clipping modes
|
||||||
|
*/
|
||||||
|
CLIP_CLAMP: 'clamp',
|
||||||
|
CLIP_ZERO: 'zero',
|
||||||
|
CLIP_PERIODIC: 'periodic',
|
||||||
|
CLIP_MIRROR: 'mirror',
|
||||||
|
/* Constants for control over the cubic interpolation tension
|
||||||
|
*/
|
||||||
|
CUBIC_TENSION_DEFAULT: 0,
|
||||||
|
CUBIC_TENSION_CATMULL_ROM: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultConfig = {
|
||||||
|
method: Enum.METHOD_CUBIC,
|
||||||
|
cubicTension: Enum.CUBIC_TENSION_DEFAULT,
|
||||||
|
clip: Enum.CLIP_CLAMP,
|
||||||
|
scaleTo: 0,
|
||||||
|
sincFilterSize: 2,
|
||||||
|
sincWindow: void 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/*Index clipping functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
clipClamp = function(i, n) {
|
||||||
|
return Math.max(0, Math.min(i, n - 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
clipPeriodic = function(i, n) {
|
||||||
|
i = i % n;
|
||||||
|
if (i < 0) i += n;
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
|
||||||
|
clipMirror = function(i, n) {
|
||||||
|
var period;
|
||||||
|
period = 2 * (n - 1);
|
||||||
|
i = clipPeriodic(i, period);
|
||||||
|
if (i > n - 1) i = period - i;
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Abstract scalar interpolation class which provides common functionality for all interpolators
|
||||||
|
|
||||||
|
Subclasses must override interpolate().
|
||||||
|
*/
|
||||||
|
|
||||||
|
AbstractInterpolator = (function() {
|
||||||
|
|
||||||
|
function AbstractInterpolator(array, config) {
|
||||||
|
this.array = array.slice(0);
|
||||||
|
this.length = this.array.length;
|
||||||
|
if (!(this.clipHelper = {
|
||||||
|
clamp: this.clipHelperClamp,
|
||||||
|
zero: this.clipHelperZero,
|
||||||
|
periodic: this.clipHelperPeriodic,
|
||||||
|
mirror: this.clipHelperMirror
|
||||||
|
}[config.clip])) {
|
||||||
|
throw "Invalid clip: " + config.clip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractInterpolator.prototype.getClippedInput = function(i) {
|
||||||
|
if ((0 <= i && i < this.length)) {
|
||||||
|
return this.array[i];
|
||||||
|
} else {
|
||||||
|
return this.clipHelper(i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractInterpolator.prototype.clipHelperClamp = function(i) {
|
||||||
|
return this.array[clipClamp(i, this.length)];
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractInterpolator.prototype.clipHelperZero = function(i) {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractInterpolator.prototype.clipHelperPeriodic = function(i) {
|
||||||
|
return this.array[clipPeriodic(i, this.length)];
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractInterpolator.prototype.clipHelperMirror = function(i) {
|
||||||
|
return this.array[clipMirror(i, this.length)];
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractInterpolator.prototype.interpolate = function(t) {
|
||||||
|
throw 'Subclasses of AbstractInterpolator must override the interpolate() method.';
|
||||||
|
};
|
||||||
|
|
||||||
|
return AbstractInterpolator;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
NearestInterpolator = (function(_super) {
|
||||||
|
|
||||||
|
__extends(NearestInterpolator, _super);
|
||||||
|
|
||||||
|
function NearestInterpolator() {
|
||||||
|
NearestInterpolator.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
NearestInterpolator.prototype.interpolate = function(t) {
|
||||||
|
return this.getClippedInput(Math.round(t));
|
||||||
|
};
|
||||||
|
|
||||||
|
return NearestInterpolator;
|
||||||
|
|
||||||
|
})(AbstractInterpolator);
|
||||||
|
|
||||||
|
LinearInterpolator = (function(_super) {
|
||||||
|
|
||||||
|
__extends(LinearInterpolator, _super);
|
||||||
|
|
||||||
|
function LinearInterpolator() {
|
||||||
|
LinearInterpolator.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearInterpolator.prototype.interpolate = function(t) {
|
||||||
|
var k;
|
||||||
|
k = Math.floor(t);
|
||||||
|
t -= k;
|
||||||
|
return (1 - t) * this.getClippedInput(k) + t * this.getClippedInput(k + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
return LinearInterpolator;
|
||||||
|
|
||||||
|
})(AbstractInterpolator);
|
||||||
|
|
||||||
|
CubicInterpolator = (function(_super) {
|
||||||
|
|
||||||
|
__extends(CubicInterpolator, _super);
|
||||||
|
|
||||||
|
function CubicInterpolator(array, config) {
|
||||||
|
this.tangentFactor = 1 - Math.max(0, Math.min(1, config.cubicTension));
|
||||||
|
CubicInterpolator.__super__.constructor.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
CubicInterpolator.prototype.getTangent = function(k) {
|
||||||
|
return this.tangentFactor * (this.getClippedInput(k + 1) - this.getClippedInput(k - 1)) / 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
CubicInterpolator.prototype.interpolate = function(t) {
|
||||||
|
var k, m, p, t2, t3;
|
||||||
|
k = Math.floor(t);
|
||||||
|
m = [this.getTangent(k), this.getTangent(k + 1)];
|
||||||
|
p = [this.getClippedInput(k), this.getClippedInput(k + 1)];
|
||||||
|
t -= k;
|
||||||
|
t2 = t * t;
|
||||||
|
t3 = t * t2;
|
||||||
|
return (2 * t3 - 3 * t2 + 1) * p[0] + (t3 - 2 * t2 + t) * m[0] + (-2 * t3 + 3 * t2) * p[1] + (t3 - t2) * m[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
return CubicInterpolator;
|
||||||
|
|
||||||
|
})(AbstractInterpolator);
|
||||||
|
|
||||||
|
sin = Math.sin, PI = Math.PI;
|
||||||
|
|
||||||
|
sinc = function(x) {
|
||||||
|
if (x === 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return sin(PI * x) / (PI * x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
makeLanczosWindow = function(a) {
|
||||||
|
return function(x) {
|
||||||
|
return sinc(x / a);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
makeSincKernel = function(window) {
|
||||||
|
return function(x) {
|
||||||
|
return sinc(x) * window(x);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
SincFilterInterpolator = (function(_super) {
|
||||||
|
|
||||||
|
__extends(SincFilterInterpolator, _super);
|
||||||
|
|
||||||
|
function SincFilterInterpolator(array, config) {
|
||||||
|
SincFilterInterpolator.__super__.constructor.apply(this, arguments);
|
||||||
|
this.a = config.sincFilterSize;
|
||||||
|
if (!config.sincWindow) throw 'No sincWindow provided';
|
||||||
|
this.kernel = makeSincKernel(config.sincWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
SincFilterInterpolator.prototype.interpolate = function(t) {
|
||||||
|
var k, n, sum, _ref, _ref2;
|
||||||
|
k = Math.floor(t);
|
||||||
|
sum = 0;
|
||||||
|
for (n = _ref = k - this.a + 1, _ref2 = k + this.a; _ref <= _ref2 ? n <= _ref2 : n >= _ref2; _ref <= _ref2 ? n++ : n--) {
|
||||||
|
sum += this.kernel(t - n) * this.getClippedInput(n);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
};
|
||||||
|
|
||||||
|
return SincFilterInterpolator;
|
||||||
|
|
||||||
|
})(AbstractInterpolator);
|
||||||
|
|
||||||
|
getColumn = function(arr, i) {
|
||||||
|
var row, _i, _len, _results;
|
||||||
|
_results = [];
|
||||||
|
for (_i = 0, _len = arr.length; _i < _len; _i++) {
|
||||||
|
row = arr[_i];
|
||||||
|
_results.push(row[i]);
|
||||||
|
}
|
||||||
|
return _results;
|
||||||
|
};
|
||||||
|
|
||||||
|
makeScaledFunction = function(f, baseScale, scaleRange) {
|
||||||
|
var scaleFactor, translation;
|
||||||
|
if (scaleRange.join === '0,1') {
|
||||||
|
return f;
|
||||||
|
} else {
|
||||||
|
scaleFactor = baseScale / (scaleRange[1] - scaleRange[0]);
|
||||||
|
translation = scaleRange[0];
|
||||||
|
return function(t) {
|
||||||
|
return f(scaleFactor * (t - translation));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getType = function(x) {
|
||||||
|
return Object.prototype.toString.call(x).slice('[object '.length, -1);
|
||||||
|
};
|
||||||
|
|
||||||
|
validateNumber = function(n) {
|
||||||
|
if (isNaN(n)) throw 'NaN in Smooth() input';
|
||||||
|
if (getType(n) !== 'Number') throw 'Non-number in Smooth() input';
|
||||||
|
if (!isFinite(n)) throw 'Infinity in Smooth() input';
|
||||||
|
};
|
||||||
|
|
||||||
|
validateVector = function(v, dimension) {
|
||||||
|
var n, _i, _len;
|
||||||
|
if (getType(v) !== 'Array') throw 'Non-vector in Smooth() input';
|
||||||
|
if (v.length !== dimension) throw 'Inconsistent dimension in Smooth() input';
|
||||||
|
for (_i = 0, _len = v.length; _i < _len; _i++) {
|
||||||
|
n = v[_i];
|
||||||
|
validateNumber(n);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
isValidNumber = function(n) {
|
||||||
|
return (getType(n) === 'Number') && isFinite(n) && !isNaN(n);
|
||||||
|
};
|
||||||
|
|
||||||
|
normalizeScaleTo = function(s) {
|
||||||
|
var invalidErr;
|
||||||
|
invalidErr = "scaleTo param must be number or array of two numbers";
|
||||||
|
switch (getType(s)) {
|
||||||
|
case 'Number':
|
||||||
|
if (!isValidNumber(s)) throw invalidErr;
|
||||||
|
s = [0, s];
|
||||||
|
break;
|
||||||
|
case 'Array':
|
||||||
|
if (s.length !== 2) throw invalidErr;
|
||||||
|
if (!(isValidNumber(s[0]) && isValidNumber(s[1]))) throw invalidErr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw invalidErr;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
shallowCopy = function(obj) {
|
||||||
|
var copy, k, v;
|
||||||
|
copy = {};
|
||||||
|
for (k in obj) {
|
||||||
|
if (!__hasProp.call(obj, k)) continue;
|
||||||
|
v = obj[k];
|
||||||
|
copy[k] = v;
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
};
|
||||||
|
|
||||||
|
Smooth = function(arr, config) {
|
||||||
|
var baseDomainEnd, dimension, i, interpolator, interpolatorClass, interpolators, k, n, properties, smoothFunc, v;
|
||||||
|
if (config == null) config = {};
|
||||||
|
properties = {};
|
||||||
|
config = shallowCopy(config);
|
||||||
|
properties.config = shallowCopy(config);
|
||||||
|
if (config.scaleTo == null) config.scaleTo = config.period;
|
||||||
|
if (config.sincFilterSize == null) {
|
||||||
|
config.sincFilterSize = config.lanczosFilterSize;
|
||||||
|
}
|
||||||
|
for (k in defaultConfig) {
|
||||||
|
if (!__hasProp.call(defaultConfig, k)) continue;
|
||||||
|
v = defaultConfig[k];
|
||||||
|
if (config[k] == null) config[k] = v;
|
||||||
|
}
|
||||||
|
if (!(interpolatorClass = {
|
||||||
|
nearest: NearestInterpolator,
|
||||||
|
linear: LinearInterpolator,
|
||||||
|
cubic: CubicInterpolator,
|
||||||
|
lanczos: SincFilterInterpolator,
|
||||||
|
sinc: SincFilterInterpolator
|
||||||
|
}[config.method])) {
|
||||||
|
throw "Invalid method: " + config.method;
|
||||||
|
}
|
||||||
|
if (config.method === 'lanczos') {
|
||||||
|
config.sincWindow = makeLanczosWindow(config.sincFilterSize);
|
||||||
|
}
|
||||||
|
if (arr.length < 2) throw 'Array must have at least two elements';
|
||||||
|
properties.count = arr.length;
|
||||||
|
smoothFunc = (function() {
|
||||||
|
var _i, _j, _len, _len2;
|
||||||
|
switch (getType(arr[0])) {
|
||||||
|
case 'Number':
|
||||||
|
properties.dimension = 'scalar';
|
||||||
|
if (Smooth.deepValidation) {
|
||||||
|
for (_i = 0, _len = arr.length; _i < _len; _i++) {
|
||||||
|
n = arr[_i];
|
||||||
|
validateNumber(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interpolator = new interpolatorClass(arr, config);
|
||||||
|
return function(t) {
|
||||||
|
return interpolator.interpolate(t);
|
||||||
|
};
|
||||||
|
case 'Array':
|
||||||
|
properties.dimension = dimension = arr[0].length;
|
||||||
|
if (!dimension) throw 'Vectors must be non-empty';
|
||||||
|
if (Smooth.deepValidation) {
|
||||||
|
for (_j = 0, _len2 = arr.length; _j < _len2; _j++) {
|
||||||
|
v = arr[_j];
|
||||||
|
validateVector(v, dimension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interpolators = (function() {
|
||||||
|
var _results;
|
||||||
|
_results = [];
|
||||||
|
for (i = 0; 0 <= dimension ? i < dimension : i > dimension; 0 <= dimension ? i++ : i--) {
|
||||||
|
_results.push(new interpolatorClass(getColumn(arr, i), config));
|
||||||
|
}
|
||||||
|
return _results;
|
||||||
|
})();
|
||||||
|
return function(t) {
|
||||||
|
var interpolator, _k, _len3, _results;
|
||||||
|
_results = [];
|
||||||
|
for (_k = 0, _len3 = interpolators.length; _k < _len3; _k++) {
|
||||||
|
interpolator = interpolators[_k];
|
||||||
|
_results.push(interpolator.interpolate(t));
|
||||||
|
}
|
||||||
|
return _results;
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw "Invalid element type: " + (getType(arr[0]));
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
if (config.clip === 'periodic') {
|
||||||
|
baseDomainEnd = arr.length;
|
||||||
|
} else {
|
||||||
|
baseDomainEnd = arr.length - 1;
|
||||||
|
}
|
||||||
|
config.scaleTo || (config.scaleTo = baseDomainEnd);
|
||||||
|
properties.domain = normalizeScaleTo(config.scaleTo);
|
||||||
|
smoothFunc = makeScaledFunction(smoothFunc, baseDomainEnd, properties.domain);
|
||||||
|
properties.domain.sort();
|
||||||
|
/*copy properties
|
||||||
|
*/
|
||||||
|
for (k in properties) {
|
||||||
|
if (!__hasProp.call(properties, k)) continue;
|
||||||
|
v = properties[k];
|
||||||
|
smoothFunc[k] = v;
|
||||||
|
}
|
||||||
|
return smoothFunc;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (k in Enum) {
|
||||||
|
if (!__hasProp.call(Enum, k)) continue;
|
||||||
|
v = Enum[k];
|
||||||
|
Smooth[k] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Smooth.deepValidation = true;
|
||||||
|
|
||||||
|
(typeof exports !== "undefined" && exports !== null ? exports : window).Smooth = Smooth;
|
||||||
|
|
||||||
|
}).call(this);
|
Loading…
Reference in New Issue
Block a user