We have a better o.
This commit is contained in:
parent
b9772b6c22
commit
1301b024d3
|
@ -3,6 +3,8 @@ define Stroke [require './support/stroke'].Stroke
|
||||||
define tp [require './support/transform'].transformPoint
|
define tp [require './support/transform'].transformPoint
|
||||||
define inverse [require './support/transform'].inverse
|
define inverse [require './support/transform'].inverse
|
||||||
|
|
||||||
|
define libspiro : require 'libspiro-js'
|
||||||
|
|
||||||
### COMMON FUNCTIONS
|
### COMMON FUNCTIONS
|
||||||
|
|
||||||
define [mix a b p] : a + [b - a] * p
|
define [mix a b p] : a + [b - a] * p
|
||||||
|
@ -211,6 +213,53 @@ define [buildFont para recursive] : begin {
|
||||||
set font.'OS/2'.sxHeight XH
|
set font.'OS/2'.sxHeight XH
|
||||||
set font.post.italicAnvle [0 - para.italicangle]
|
set font.post.italicAnvle [0 - para.italicangle]
|
||||||
|
|
||||||
|
### Spiro constructions
|
||||||
|
define [flatten knots] : begin {
|
||||||
|
local a ()
|
||||||
|
foreach p [items-of knots] : piecewise {
|
||||||
|
[p <@ Array] : set a : a.concat [flatten p]
|
||||||
|
true : a.push p
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
define [afInterpolate before after args] : G2 [mix before.x after.x args.rx] [mix before.y after.y args.ry] VIRTUAL
|
||||||
|
define [G4 x y f] (.x x .y y .type 'g4' .af f)
|
||||||
|
define [G2 x y f] (.x x .y y .type 'g2' .af f)
|
||||||
|
define [LEFT x y f] (.x x .y y .type 'left' .af f)
|
||||||
|
define [RIGHT x y f] (.x x .y y .type 'right' .af f)
|
||||||
|
define [CLOSE f] (.type 'close' .af f)
|
||||||
|
define [PREPARE f] (.type 'prepare' .af f)
|
||||||
|
define [WIDTHS l r] : lambda [] : this.set-width l r
|
||||||
|
define [VIRTUAL] : this.points.[this.points.length - 1].subdivided = true
|
||||||
|
define [INTERPOLATE rx ry] (.type 'interpolate' .rx rx .ry ry .af afInterpolate)
|
||||||
|
define [spiro] : begin {
|
||||||
|
local s : new Stroke
|
||||||
|
s.set-transform globalTransform
|
||||||
|
local knots : ().slice.call arguments 0
|
||||||
|
local closed false
|
||||||
|
local lastaf
|
||||||
|
if [knots.0 && knots.0.type === 'prepare'] : begin {
|
||||||
|
knots.0.af.call s
|
||||||
|
set knots : knots.slice 1
|
||||||
|
}
|
||||||
|
if [knots.[knots.length - 1] && knots.[knots.length - 1].type === 'close'] : begin {
|
||||||
|
set closed true
|
||||||
|
set lastaf knots.[knots.length - 1].af
|
||||||
|
set knots : knots.slice 0 [-1]
|
||||||
|
}
|
||||||
|
set knots : flatten knots
|
||||||
|
if closed : knots.push knots.0
|
||||||
|
foreach j [range 0 knots.length] : if [knots.(j) && knots.(j).type === 'interpolate'] : begin {
|
||||||
|
set knots.(j) : knots.(j).af.call s knots.[j - 1] knots.[j + 1] knots.(j)
|
||||||
|
}
|
||||||
|
if closed : knots.pop
|
||||||
|
set knots : flatten knots
|
||||||
|
s.set-samples 1
|
||||||
|
libspiro.spiroToBezierOnContext knots closed s
|
||||||
|
if lastaf : lastaf.call s
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
### Necessary macros
|
### Necessary macros
|
||||||
define-macro glyph-construction : syntax-rules {
|
define-macro glyph-construction : syntax-rules {
|
||||||
@`[glyph-construction @::steps] ('.syntactic-closure' @`[lambda [] [begin {
|
@`[glyph-construction @::steps] ('.syntactic-closure' @`[lambda [] [begin {
|
||||||
|
|
|
@ -221,16 +221,30 @@ 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
|
PREPARE : WIDTHS width 0
|
||||||
:.start-from [middle - mc] [u - O]
|
G4 [middle - mc] [u - O]
|
||||||
:.set-width width 0
|
INTERPOLATE 0.5 0.11
|
||||||
:.arc-hv-to [l + O] [u - sma]
|
LEFT [l + O] [u - sma]
|
||||||
:.line-to [l + O] [d + smb]
|
RIGHT [l + O] [d + smb]
|
||||||
:.arc-vh-to [middle + mc] [d + O]
|
INTERPOLATE 0.5 0.89
|
||||||
:.arc-hv-to [r - O] [d + sma]
|
G4 [middle + mc] [d + O]
|
||||||
:.line-to [r - O] [u - smb]
|
INTERPOLATE 0.5 0.11
|
||||||
:.arc-vh-to [middle - mc] [u - O]
|
LEFT [r - O] [d + sma]
|
||||||
|
RIGHT [r - O] [u - smb]
|
||||||
|
INTERPOLATE 0.5 0.89
|
||||||
|
CLOSE
|
||||||
|
}
|
||||||
|
# include : create-stroke
|
||||||
|
# :.set-transform globalTransform
|
||||||
|
# :.start-from [middle - mc] [u - O]
|
||||||
|
# :.set-width width 0
|
||||||
|
# :.arc-hv-to [l + O] [u - sma]
|
||||||
|
# :.line-to [l + O] [d + smb]
|
||||||
|
# :.arc-vh-to [middle + mc] [d + O]
|
||||||
|
# :.arc-hv-to [r - O] [d + sma]
|
||||||
|
# :.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]]
|
||||||
|
|
|
@ -29,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 {
|
||||||
|
@ -47,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]
|
||||||
point.d1 = d1
|
if point {
|
||||||
point.d2 = d2
|
then {
|
||||||
|
point.d1 = d1
|
||||||
|
point.d2 = d2
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.defaultd1 = d1
|
||||||
|
this.defualtd2 = d2
|
||||||
|
}
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
define [Stroke.prototype.heads-to x y] : begin {
|
define [Stroke.prototype.heads-to x y] : begin {
|
||||||
|
@ -126,13 +136,14 @@ define [computeOffsetPoint curve t j sl foffset fpdx fpdy] : begin {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 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 d2]])
|
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 ts (0)
|
local ts (0)
|
||||||
|
local brk ()
|
||||||
|
|
||||||
local samples : fallback _samples this.samples SAMPLES
|
local minSamples : fallback _samples this.samples SAMPLES
|
||||||
local shapes ()
|
local shapes ()
|
||||||
local subSegments ()
|
local subSegments ()
|
||||||
|
|
||||||
|
@ -146,6 +157,7 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
arcLengthSofar = arcLengthSofar + [seg.length]
|
arcLengthSofar = arcLengthSofar + [seg.length]
|
||||||
if [not p1.subdivided] : begin {
|
if [not p1.subdivided] : begin {
|
||||||
ts.push arcLengthSofar
|
ts.push arcLengthSofar
|
||||||
|
brk.[subSegments.length - 1] = true
|
||||||
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
|
||||||
|
@ -161,6 +173,7 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
arcLengthSofar = arcLengthSofar + [seg.length]
|
arcLengthSofar = arcLengthSofar + [seg.length]
|
||||||
if [not p3.subdivided] : begin {
|
if [not p3.subdivided] : begin {
|
||||||
ts.push arcLengthSofar
|
ts.push arcLengthSofar
|
||||||
|
brk.[subSegments.length - 1] = true
|
||||||
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
|
||||||
|
@ -176,6 +189,7 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
arcLengthSofar = arcLengthSofar + [seg.length]
|
arcLengthSofar = arcLengthSofar + [seg.length]
|
||||||
if [not p2.subdivided] : begin {
|
if [not p2.subdivided] : begin {
|
||||||
ts.push arcLengthSofar
|
ts.push arcLengthSofar
|
||||||
|
brk.[subSegments.length - 1] = true
|
||||||
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
|
||||||
|
@ -203,12 +217,14 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
local curve subSegments`j
|
local curve subSegments`j
|
||||||
local segLength : curve.length
|
local segLength : curve.length
|
||||||
local segLengths (0)
|
local segLengths (0)
|
||||||
|
|
||||||
|
local samples : Math.max minSamples : Math.ceil : segLength / 150
|
||||||
|
|
||||||
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 arcLengthSofar arcLengthSofar segLength 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 arcLengthSofar arcLengthSofar segLength 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 : arcLengthSofar + segLengths.(sample)
|
local t : arcLengthSofar + segLengths.(sample)
|
||||||
local tn : arcLengthSofar + segLengths.[sample + 1]
|
local tn : arcLengthSofar + segLengths.[sample + 1]
|
||||||
|
@ -250,6 +266,13 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
arcLengthSofar = arcLengthSofar + segLength
|
arcLengthSofar = arcLengthSofar + segLength
|
||||||
|
if brk.(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 ()
|
||||||
|
@ -257,13 +280,14 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
|
|
||||||
return : shapes.map : function [shape] : begin {
|
return : shapes.map : function [shape] : begin {
|
||||||
# Remove duplicate points
|
# Remove duplicate points
|
||||||
for [local j] [j < shape.length - 1] [inc j] : begin {
|
for [local j 0] [j < shape.length - 1] [inc j] : begin {
|
||||||
local p0 shape.(j)
|
local p0 shape.(j)
|
||||||
local p1 shape.[j + 1]
|
local p1 shape.[j + 1]
|
||||||
if [p0.onCurve && p1.onCurve && p0.x === p1.x && p0.y === p1.y] : set p1.removable true
|
if [p0.onCurve && p1.onCurve && [Math.abs : p0.x - p1.x] <= 0.1 && [Math.abs : p0.y - p1.y] <= 0.1] : set p1.removable true
|
||||||
}
|
}
|
||||||
# Remove colinear oncurve points
|
|
||||||
set shape : shape.filter : function [point] [point && [not point.removable]]
|
set shape : shape.filter : function [point] [point && [not point.removable]]
|
||||||
|
|
||||||
|
# Remove colinear oncurve points
|
||||||
for [local j 0] [j < shape.length - 1] [inc j] : begin {
|
for [local j 0] [j < shape.length - 1] [inc j] : begin {
|
||||||
local p0 shape`j
|
local p0 shape`j
|
||||||
local still true
|
local still true
|
||||||
|
@ -279,6 +303,7 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
||||||
set j [k - 1]
|
set j [k - 1]
|
||||||
}
|
}
|
||||||
set shape : shape.filter : function [point] [point && [not point.removable]]
|
set shape : shape.filter : function [point] [point && [not point.removable]]
|
||||||
|
|
||||||
# Remove removable midpoints
|
# Remove removable midpoints
|
||||||
for [local j 1] [j < shape.length - 2] [inc j] : begin {
|
for [local j 1] [j < shape.length - 2] [inc j] : begin {
|
||||||
local p0 shape`j
|
local p0 shape`j
|
||||||
|
|
Loading…
Reference in New Issue
Block a user