draw2d/curve/cubic.go

81 lines
1.9 KiB
Go
Raw Normal View History

2015-04-16 09:51:13 +00:00
// Copyright 2010 The draw2d Authors. All rights reserved.
// created: 17/05/2011 by Laurent Le Goff
2015-04-22 17:07:03 +00:00
// Package curve implements Bezier Curve Subdivision using De Casteljau's algorithm
2012-01-13 09:14:12 +00:00
package curve
import (
"math"
)
const (
CurveRecursionLimit = 32
)
2015-04-23 08:05:48 +00:00
// x1, y1, cpx1, cpy1, cpx2, cpy2, x2, y2 float64
// type Cubic []float64
2012-01-13 09:14:12 +00:00
2015-04-22 17:07:03 +00:00
// Subdivide a Bezier cubic curve in 2 equivalents Bezier cubic curves.
// c1 and c2 parameters are the resulting curves
2015-04-23 08:05:48 +00:00
func SubdivideCubic(c, c1, c2 []float64) {
2015-04-22 17:07:03 +00:00
// First point of c is the first point of c1
2012-01-13 09:14:12 +00:00
c1[0], c1[1] = c[0], c[1]
2015-04-22 17:07:03 +00:00
// Last point of c is the last point of c2
2012-01-13 09:14:12 +00:00
c2[6], c2[7] = c[6], c[7]
2015-04-22 17:07:03 +00:00
// Subdivide segment using midpoints
2012-01-13 09:14:12 +00:00
c1[2] = (c[0] + c[2]) / 2
c1[3] = (c[1] + c[3]) / 2
2015-04-22 17:07:03 +00:00
midX := (c[2] + c[4]) / 2
midY := (c[3] + c[5]) / 2
2012-01-13 09:14:12 +00:00
c2[4] = (c[4] + c[6]) / 2
c2[5] = (c[5] + c[7]) / 2
2015-04-22 17:07:03 +00:00
c1[4] = (c1[2] + midX) / 2
c1[5] = (c1[3] + midY) / 2
c2[2] = (midX + c2[4]) / 2
c2[3] = (midY + c2[5]) / 2
2012-01-13 09:14:12 +00:00
c1[6] = (c1[4] + c2[2]) / 2
c1[7] = (c1[5] + c2[3]) / 2
2015-04-22 17:07:03 +00:00
// Last Point of c1 is equal to the first point of c2
2012-01-13 09:14:12 +00:00
c2[0], c2[1] = c1[6], c1[7]
}
// TraceCubic generate lines subdividing the cubic curve using a LineBuilder
2015-04-22 17:07:03 +00:00
// flattening_threshold helps determines the flattening expectation of the curve
func TraceCubic(t LineBuilder, cubic []float64, flattening_threshold float64) {
2015-04-22 17:07:03 +00:00
// Allocation curves
2015-04-23 08:05:48 +00:00
var curves [CurveRecursionLimit * 8]float64
copy(curves[0:8], cubic[0:8])
2012-01-13 09:14:12 +00:00
i := 0
2015-04-22 17:07:03 +00:00
2015-04-16 09:51:13 +00:00
// current curve
2015-04-23 08:05:48 +00:00
var c []float64
2012-01-13 09:14:12 +00:00
var dx, dy, d2, d3 float64
for i >= 0 {
2015-04-23 08:05:48 +00:00
c = curves[i*8:]
2012-01-13 09:14:12 +00:00
dx = c[6] - c[0]
dy = c[7] - c[1]
2015-04-22 17:07:03 +00:00
d2 = math.Abs((c[2]-c[6])*dy - (c[3]-c[7])*dx)
d3 = math.Abs((c[4]-c[6])*dy - (c[5]-c[7])*dx)
2012-01-13 09:14:12 +00:00
2015-04-22 17:07:03 +00:00
// if it's flat then trace a line
2012-01-13 09:14:12 +00:00
if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
t.LineTo(c[6], c[7])
2012-01-13 09:14:12 +00:00
i--
} else {
2015-04-16 09:51:13 +00:00
// second half of bezier go lower onto the stack
2015-04-23 08:05:48 +00:00
SubdivideCubic(c, curves[(i+1)*8:], curves[i*8:])
2012-01-13 09:14:12 +00:00
i++
}
}
}