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 inverse [require './support/transform'].inverse
|
||||
|
||||
define libspiro : require 'libspiro-js'
|
||||
|
||||
### COMMON FUNCTIONS
|
||||
|
||||
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.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
|
||||
define-macro glyph-construction : syntax-rules {
|
||||
@`[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
|
||||
if [u - d > sma + smb] {
|
||||
then : begin {
|
||||
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]
|
||||
include : spiro {
|
||||
PREPARE : WIDTHS width 0
|
||||
G4 [middle - mc] [u - O]
|
||||
INTERPOLATE 0.5 0.11
|
||||
LEFT [l + O] [u - sma]
|
||||
RIGHT [l + O] [d + smb]
|
||||
INTERPOLATE 0.5 0.89
|
||||
G4 [middle + mc] [d + O]
|
||||
INTERPOLATE 0.5 0.11
|
||||
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 {
|
||||
local ymiddlea : mix d u [smb / [sma + smb]]
|
||||
|
|
|
@ -29,6 +29,8 @@ define [Stroke] : begin {
|
|||
.x 0
|
||||
.y 0
|
||||
)
|
||||
this.defaultd1 = 0
|
||||
this.defaultd2 = 0
|
||||
return this
|
||||
}
|
||||
define Stroke.is : object {
|
||||
|
@ -47,8 +49,16 @@ define [Stroke.bindParameters para] : begin {
|
|||
}
|
||||
define [Stroke.prototype.set-width d1 d2] : begin {
|
||||
local point this.points`[this.points.length - 1]
|
||||
point.d1 = d1
|
||||
point.d2 = d2
|
||||
if point {
|
||||
then {
|
||||
point.d1 = d1
|
||||
point.d2 = d2
|
||||
}
|
||||
else {
|
||||
this.defaultd1 = d1
|
||||
this.defualtd2 = d2
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
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 {
|
||||
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 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 pdys (0)
|
||||
local ts (0)
|
||||
local brk ()
|
||||
|
||||
local samples : fallback _samples this.samples SAMPLES
|
||||
local minSamples : fallback _samples this.samples SAMPLES
|
||||
local shapes ()
|
||||
local subSegments ()
|
||||
|
||||
|
@ -146,6 +157,7 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
arcLengthSofar = arcLengthSofar + [seg.length]
|
||||
if [not p1.subdivided] : begin {
|
||||
ts.push arcLengthSofar
|
||||
brk.[subSegments.length - 1] = true
|
||||
d1s.push : set d1 [if [p1.d1 >= 0] p1.d1 d1]
|
||||
d2s.push : set d2 [if [p1.d2 >= 0] p1.d2 d2]
|
||||
local normalpt : seg.normal 1
|
||||
|
@ -161,6 +173,7 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
arcLengthSofar = arcLengthSofar + [seg.length]
|
||||
if [not p3.subdivided] : begin {
|
||||
ts.push arcLengthSofar
|
||||
brk.[subSegments.length - 1] = true
|
||||
d1s.push : set d1 [if [p3.d1 >= 0] p3.d1 d1]
|
||||
d2s.push : set d2 [if [p3.d2 >= 0] p3.d2 d2]
|
||||
local normalpt : seg.normal 1
|
||||
|
@ -176,6 +189,7 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
arcLengthSofar = arcLengthSofar + [seg.length]
|
||||
if [not p2.subdivided] : begin {
|
||||
ts.push arcLengthSofar
|
||||
brk.[subSegments.length - 1] = true
|
||||
d1s.push : set d1 [if [p2.d1 >= 0] p2.d1 d1]
|
||||
d2s.push : set d2 [if [p2.d2 >= 0] p2.d2 d2]
|
||||
local normalpt : seg.normal 1
|
||||
|
@ -203,12 +217,14 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
local curve subSegments`j
|
||||
local segLength : curve.length
|
||||
local segLengths (0)
|
||||
|
||||
local samples : Math.max minSamples : Math.ceil : segLength / 150
|
||||
|
||||
foreach sample [range 1 till samples] : begin {
|
||||
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)]
|
||||
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 {
|
||||
local t : arcLengthSofar + segLengths.(sample)
|
||||
local tn : arcLengthSofar + segLengths.[sample + 1]
|
||||
|
@ -250,6 +266,13 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
}]
|
||||
}
|
||||
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]
|
||||
set left ()
|
||||
set right ()
|
||||
|
@ -257,13 +280,14 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
|
||||
return : shapes.map : function [shape] : begin {
|
||||
# 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 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]]
|
||||
|
||||
# Remove colinear oncurve points
|
||||
for [local j 0] [j < shape.length - 1] [inc j] : begin {
|
||||
local p0 shape`j
|
||||
local still true
|
||||
|
@ -279,6 +303,7 @@ define [Stroke.prototype.to-outline d1 d2 _samples straight] : begin {
|
|||
set j [k - 1]
|
||||
}
|
||||
set shape : shape.filter : function [point] [point && [not point.removable]]
|
||||
|
||||
# Remove removable midpoints
|
||||
for [local j 1] [j < shape.length - 2] [inc j] : begin {
|
||||
local p0 shape`j
|
||||
|
|
Loading…
Reference in New Issue
Block a user