vector: Improve the number of segments for a Bézier curve

Updates #844
This commit is contained in:
Hajime Hoshi 2021-07-06 01:12:51 +09:00
parent 59fa689f22
commit ad2999fa04

View File

@ -51,29 +51,28 @@ func (p *Path) LineTo(x, y float32) {
p.cur = point{x: x, y: y} p.cur = point{x: x, y: y}
} }
// nseg returns a number of segments based on the given two points (x0, y0) and (x1, y1). // nseg returns a number of segments based on the given three points for a Bézier curve.
func nseg(x0, y0, x1, y1 float32) int { //
distx := x1 - x0 // See golang.org/x/image/vector's devSquared for more details.
if distx < 0 { func nseg(x0, y0, x1, y1, x2, y2 float32) int {
distx = -distx devx := x0 - 2*x1 + x2
devy := y0 - 2*y1 + y2
devsq := devx*devx + devy*devy
if devsq < 0.333 {
return 0
} }
disty := y1 - y0 const tol = 3
if disty < 0 { return 1 + int(math.Sqrt(math.Sqrt(tol*float64(devsq))))*2
disty = -disty
}
dist := distx
if dist < disty {
dist = disty
}
return int(math.Ceil(float64(dist)))
} }
// QuadTo adds a quadratic Bézier curve to the path. // QuadTo adds a quadratic Bézier curve to the path.
func (p *Path) QuadTo(cpx, cpy, x, y float32) { func (p *Path) QuadTo(cpx, cpy, x, y float32) {
// TODO: Split more appropriate number of segments. // TODO: Split more appropriate number of segments.
c := p.cur c := p.cur
num := nseg(c.x, c.y, x, y) num := nseg(c.x, c.y, cpx, cpy, x, y)
if num == 0 {
return
}
for t := float32(0.0); t <= 1; t += 1.0 / float32(num) { for t := float32(0.0); t <= 1; t += 1.0 / float32(num) {
xf := (1-t)*(1-t)*c.x + 2*t*(1-t)*cpx + t*t*x xf := (1-t)*(1-t)*c.x + 2*t*(1-t)*cpx + t*t*x
yf := (1-t)*(1-t)*c.y + 2*t*(1-t)*cpy + t*t*y yf := (1-t)*(1-t)*c.y + 2*t*(1-t)*cpy + t*t*y
@ -85,7 +84,13 @@ func (p *Path) QuadTo(cpx, cpy, x, y float32) {
func (p *Path) CubicTo(cp0x, cp0y, cp1x, cp1y, x, y float32) { func (p *Path) CubicTo(cp0x, cp0y, cp1x, cp1y, x, y float32) {
// TODO: Split more appropriate number of segments. // TODO: Split more appropriate number of segments.
c := p.cur c := p.cur
num := nseg(c.x, c.y, x, y) num := nseg(c.x, c.y, cp0x, cp0y, x, y)
if num2 := nseg(c.x, c.y, cp1x, cp1y, x, y); num2 > num {
num = num2
}
if num == 0 {
return
}
for t := float32(0.0); t <= 1; t += 1.0 / float32(num) { for t := float32(0.0); t <= 1; t += 1.0 / float32(num) {
xf := (1-t)*(1-t)*(1-t)*c.x + 3*(1-t)*(1-t)*t*cp0x + 3*(1-t)*t*t*cp1x + t*t*t*x xf := (1-t)*(1-t)*(1-t)*c.x + 3*(1-t)*(1-t)*t*cp0x + 3*(1-t)*t*t*cp1x + t*t*t*x
yf := (1-t)*(1-t)*(1-t)*c.y + 3*(1-t)*(1-t)*t*cp0y + 3*(1-t)*t*t*cp1y + t*t*t*y yf := (1-t)*(1-t)*(1-t)*c.y + 3*(1-t)*(1-t)*t*cp0y + 3*(1-t)*t*t*cp1y + t*t*t*y