track current point; emulate cubic beziers

This commit is contained in:
Michael Fogleman 2016-02-20 23:11:34 -05:00
parent a4a5e21ecd
commit 5cc58d1aa5
4 changed files with 84 additions and 20 deletions

View File

@ -55,6 +55,7 @@ DrawImageAnchored(im image.Image, x, y int, ax, ay float64)
MoveTo(x, y float64)
LineTo(x, y float64)
QuadraticTo(x1, y1, x2, y2 float64)
CubicTo(x1, y1, x2, y2, x3, y3 float64)
ClosePath()
ClearPath()
@ -132,7 +133,6 @@ even better, implement it and submit a pull request!
- Clipping Regions
- Gradients / Patterns
- Cubic Beziers
- Dashed Lines
## How Do it Do?

32
bezier.go Normal file
View File

@ -0,0 +1,32 @@
package gg
import "math"
func cubic(x0, y0, x1, y1, x2, y2, x3, y3, t float64) (x, y float64) {
u := 1 - t
a := u * u * u
b := 3 * u * u * t
c := 3 * u * t * t
d := t * t * t
x = a*x0 + b*x1 + c*x2 + d*x3
y = a*y0 + b*y1 + c*y2 + d*y3
return
}
func CubicBezier(x0, y0, x1, y1, x2, y2, x3, y3 float64) []Point {
l := (math.Hypot(x1-x0, y1-y0) +
math.Hypot(x2-x1, y2-y1) +
math.Hypot(x3-x2, y3-y2))
n := int((l + 0.5))
if n < 4 {
n = 4
}
d := float64(n) - 1
result := make([]Point, n)
for i := 0; i < n; i++ {
t := float64(i) / d
x, y := cubic(x0, y0, x1, y1, x2, y2, x3, y3, t)
result[i] = Point{x, y}
}
return result
}

View File

@ -9,7 +9,6 @@ import (
"github.com/golang/freetype/raster"
"golang.org/x/image/font"
"golang.org/x/image/font/basicfont"
"golang.org/x/image/math/fixed"
)
type LineCap int
@ -41,7 +40,8 @@ type Context struct {
color color.Color
strokePath raster.Path
fillPath raster.Path
start fixed.Point26_6
start Point
current Point
lineWidth float64
lineCap LineCap
lineJoin LineJoin
@ -170,12 +170,14 @@ func (dc *Context) SetRGB(r, g, b float64) {
func (dc *Context) MoveTo(x, y float64) {
if len(dc.fillPath) > 0 {
dc.fillPath.Add1(dc.start)
dc.fillPath.Add1(dc.start.Fixed())
}
x, y = dc.TransformPoint(x, y)
dc.start = fp(x, y)
dc.strokePath.Start(dc.start)
dc.fillPath.Start(dc.start)
p := Point{x, y}
dc.strokePath.Start(p.Fixed())
dc.fillPath.Start(p.Fixed())
dc.start = p
dc.current = p
}
func (dc *Context) LineTo(x, y float64) {
@ -183,29 +185,48 @@ func (dc *Context) LineTo(x, y float64) {
dc.MoveTo(x, y)
} else {
x, y = dc.TransformPoint(x, y)
p := fp(x, y)
dc.strokePath.Add1(p)
dc.fillPath.Add1(p)
p := Point{x, y}
dc.strokePath.Add1(p.Fixed())
dc.fillPath.Add1(p.Fixed())
dc.current = p
}
}
func (dc *Context) QuadraticTo(x1, y1, x2, y2 float64) {
if len(dc.strokePath) == 0 {
dc.MoveTo(x1, y1)
} else {
x1, y1 = dc.TransformPoint(x1, y1)
x2, y2 = dc.TransformPoint(x2, y2)
p1 := fp(x1, y1)
p2 := fp(x2, y2)
dc.strokePath.Add2(p1, p2)
dc.fillPath.Add2(p1, p2)
}
x1, y1 = dc.TransformPoint(x1, y1)
x2, y2 = dc.TransformPoint(x2, y2)
p1 := Point{x1, y1}
p2 := Point{x2, y2}
dc.strokePath.Add2(p1.Fixed(), p2.Fixed())
dc.fillPath.Add2(p1.Fixed(), p2.Fixed())
dc.current = p2
}
func (dc *Context) CubicTo(x1, y1, x2, y2, x3, y3 float64) {
if len(dc.strokePath) == 0 {
dc.MoveTo(x1, y1)
}
x0, y0 := dc.current.X, dc.current.Y
x1, y1 = dc.TransformPoint(x1, y1)
x2, y2 = dc.TransformPoint(x2, y2)
x3, y3 = dc.TransformPoint(x3, y3)
points := CubicBezier(x0, y0, x1, y1, x2, y2, x3, y3)
for _, p := range points[1:] {
f := p.Fixed()
dc.strokePath.Add1(f)
dc.fillPath.Add1(f)
dc.current = p
}
}
func (dc *Context) ClosePath() {
if len(dc.strokePath) > 0 {
dc.strokePath.Add1(dc.start)
dc.fillPath.Add1(dc.start)
dc.strokePath.Add1(dc.start.Fixed())
dc.fillPath.Add1(dc.start.Fixed())
dc.current = dc.start
}
}
@ -257,7 +278,7 @@ func (dc *Context) FillPreserve() {
if len(dc.fillPath) > 0 {
path = make(raster.Path, len(dc.fillPath))
copy(path, dc.fillPath)
path.Add1(dc.start)
path.Add1(dc.start.Fixed())
}
painter := raster.NewRGBAPainter(dc.im)
painter.SetColor(dc.color)

11
point.go Normal file
View File

@ -0,0 +1,11 @@
package gg
import "golang.org/x/image/math/fixed"
type Point struct {
X, Y float64
}
func (p Point) Fixed() fixed.Point26_6 {
return fp(p.X, p.Y)
}