96 lines
3.9 KiB
Plaintext
96 lines
3.9 KiB
Plaintext
import 'bezier-js' as Bezier
|
|
define TINY 0.001
|
|
define LITTLE 0.01
|
|
|
|
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 [computeOffsetPoint curve t offset] : begin
|
|
local onpoint : curve.compute t
|
|
local normal : curve.normal t
|
|
return {.x onpoint.x + offset * normal.x .y onpoint.y + offset * normal.y}
|
|
|
|
define [intersection z1 c1 c2 z2] : begin
|
|
define d1 {.x (c1.x - z1.x) .y (c1.y - z1.y)}
|
|
define d2 {.x (c2.x - z2.x) .y (c2.y - z2.y)}
|
|
local det : d2.x * d1.y - d2.y * d1.x
|
|
if ([Math.abs det] <= 1e-8) : return null
|
|
local u : ((z2.y - z1.y) * d2.x - (z2.x - z1.x) * d2.y) / det
|
|
local v : ((z2.y - z1.y) * d1.x - (z2.x - z1.x) * d1.y) / det
|
|
if (u <= 0 || v <= 0) : return null
|
|
return { .x (z1.x + d1.x * u), .y (z1.y + d1.y * u) }
|
|
|
|
export all : define [strokeExpand points f1 f2 samples] : begin
|
|
local shapes {}
|
|
local subSegments {}
|
|
|
|
local p0 points.0
|
|
for [local j 1] (j < points.length) [inc j] : begin
|
|
local p1 points.(j)
|
|
piecewise
|
|
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
|
|
p0 = p1
|
|
p1.cubic : begin
|
|
local p2 points.((j + 1))
|
|
local p3 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
|
|
p0 = p3
|
|
j = j + 2
|
|
true : begin
|
|
local p2 points.((j + 1))
|
|
subSegments.push : local seg : new Bezier p0.x p0.y p1.x p1.y p2.x p2.y
|
|
p0 = p2
|
|
j = j + 1
|
|
|
|
local left {}
|
|
local right {}
|
|
|
|
for [local j 0] (j < subSegments.length) [inc j] : begin
|
|
local curve subSegments.(j)
|
|
|
|
left.push [begin [local last [computeOffsetPoint curve 0 f1]] {.x last.x .y last.y .onCurve true}]
|
|
right.push [begin [local last [computeOffsetPoint curve 0 f2]] {.x last.x .y last.y .onCurve true}]
|
|
foreach sample [range 0 samples] : begin
|
|
local t : sample / samples
|
|
local tn : (sample + 1) / samples
|
|
|
|
local lthis : computeOffsetPoint curve t f1
|
|
local rthis : computeOffsetPoint curve t f2
|
|
local lnext : computeOffsetPoint curve tn f1
|
|
local rnext : computeOffsetPoint curve tn f2
|
|
local lnthis1 : computeOffsetPoint curve (t + TINY) f1
|
|
local rnthis1 : computeOffsetPoint curve (t + TINY) f2
|
|
local lnnext1 : computeOffsetPoint curve (tn - TINY) f1
|
|
local rnnext1 : computeOffsetPoint curve (tn - TINY) f2
|
|
local lnthis2 : computeOffsetPoint curve (t + 2 * TINY) f1
|
|
local rnthis2 : computeOffsetPoint curve (t + 2 * TINY) f2
|
|
local lnnext2 : computeOffsetPoint curve (tn - 2 * TINY) f1
|
|
local rnnext2 : computeOffsetPoint curve (tn - 2 * TINY) f2
|
|
local lnthis3 : computeOffsetPoint curve (t + 3 * TINY) f1
|
|
local rnthis3 : computeOffsetPoint curve (t + 3 * TINY) f2
|
|
local lnnext3 : computeOffsetPoint curve (tn - 3 * TINY) f1
|
|
local rnnext3 : computeOffsetPoint curve (tn - 3 * TINY) f2
|
|
|
|
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 dlthis lnext dlnext
|
|
if il
|
|
: then : left.push {.x il.x .y il.y .onCurve false} {.x lnext.x .y lnext.y .onCurve true}
|
|
: else : left.push {.x lnext.x .y lnext.y .onCurve true}
|
|
|
|
local ir : intersection rthis drthis rnext drnext
|
|
if ir
|
|
: then : right.push {.x ir.x .y ir.y .onCurve false} {.x rnext.x .y rnext.y .onCurve true}
|
|
: else : right.push {.x rnext.x .y rnext.y .onCurve true}
|
|
shapes.push : left.concat [right.reverse]
|
|
return shapes |