works more or less

This commit is contained in:
Will Charczuk 2017-03-04 17:42:10 -08:00
parent 17b28beae8
commit 9c65a94050
10 changed files with 248 additions and 43 deletions

View file

@ -1,8 +1,6 @@
package drawing
import (
"math"
)
import "math"
const (
// CurveRecursionLimit represents the maximum recursion that is really necessary to subsivide a curve into straight lines
@ -98,31 +96,60 @@ func SubdivideQuad(c, c1, c2 []float64) {
return
}
func traceWindowIndices(i int) (startAt, endAt int) {
startAt = i * 6
endAt = startAt + 6
return
}
func traceCalcDeltas(c []float64) (dx, dy, d float64) {
dx = c[4] - c[0]
dy = c[5] - c[1]
d = math.Abs(((c[2]-c[4])*dy - (c[3]-c[5])*dx))
return
}
func traceIsFlat(dx, dy, d, threshold float64) bool {
return (d * d) < threshold*(dx*dx+dy*dy)
}
func traceGetWindow(curves []float64, i int) []float64 {
startAt, endAt := traceWindowIndices(i)
return curves[startAt:endAt]
}
// TraceQuad generate lines subdividing the curve using a Liner
// flattening_threshold helps determines the flattening expectation of the curve
func TraceQuad(t Liner, quad []float64, flatteningThreshold float64) {
const curveLen = CurveRecursionLimit * 6
const curveEndIndex = curveLen - 1
const lastIteration = CurveRecursionLimit - 1
// Allocates curves stack
var curves [CurveRecursionLimit * 6]float64
curves := make([]float64, curveLen)
// copy 6 elements from the quad path to the stack
copy(curves[0:6], quad[0:6])
i := 0
// current curve
var i int
var c []float64
var dx, dy, d float64
for i >= 0 {
c = curves[i*6:]
dx = c[4] - c[0]
dy = c[5] - c[1]
c = traceGetWindow(curves, i)
dx, dy, d = traceCalcDeltas(c)
d = math.Abs(((c[2]-c[4])*dy - (c[3]-c[5])*dx))
// bail early if the distance is 0
if d == 0 {
return
}
// if it's flat then trace a line
if (d*d) < flatteningThreshold*(dx*dx+dy*dy) || i == len(curves)-1 {
if traceIsFlat(dx, dy, d, flatteningThreshold) || i == lastIteration {
t.LineTo(c[4], c[5])
i--
} else {
// second half of bezier go lower onto the stack
SubdivideQuad(c, curves[(i+1)*6:], curves[i*6:])
SubdivideQuad(c, traceGetWindow(curves, i+1), traceGetWindow(curves, i))
i++
}
}

35
drawing/curve_test.go Normal file
View file

@ -0,0 +1,35 @@
package drawing
import (
"testing"
assert "github.com/blendlabs/go-assert"
)
type point struct {
X, Y float64
}
type mockLine struct {
inner []point
}
func (ml *mockLine) LineTo(x, y float64) {
ml.inner = append(ml.inner, point{x, y})
}
func (ml mockLine) Len() int {
return len(ml.inner)
}
func TestTraceQuad(t *testing.T) {
assert := assert.New(t)
// Quad
// x1, y1, cpx1, cpy2, x2, y2 float64
// do the 9->12 circle segment
quad := []float64{10, 20, 20, 20, 20, 10}
liner := &mockLine{}
TraceQuad(liner, quad, 0.5)
assert.NotZero(liner.Len())
}

View file

@ -23,10 +23,10 @@ type Flattener interface {
// Flatten convert curves into straight segments keeping join segments info
func Flatten(path *Path, flattener Flattener, scale float64) {
// First Point
var startX, startY float64 = 0, 0
var startX, startY float64
// Current Point
var x, y float64 = 0, 0
i := 0
var x, y float64
var i int
for _, cmp := range path.Components {
switch cmp {
case MoveToComponent:
@ -43,6 +43,7 @@ func Flatten(path *Path, flattener Flattener, scale float64) {
flattener.LineJoin()
i += 2
case QuadCurveToComponent:
// we include the previous point for the start of the curve
TraceQuad(flattener, path.Points[i-2:], 0.5)
x, y = path.Points[i+2], path.Points[i+3]
flattener.LineTo(x, y)