track current point; emulate cubic beziers
This commit is contained in:
parent
a4a5e21ecd
commit
5cc58d1aa5
@ -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
32
bezier.go
Normal 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
|
||||
}
|
55
context.go
55
context.go
@ -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)
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user