We have a better o.

This commit is contained in:
be5invis 2015-08-17 12:28:19 +08:00
parent b9772b6c22
commit 1301b024d3
3 changed files with 107 additions and 19 deletions

View File

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

View File

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

View File

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