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)
|
MoveTo(x, y float64)
|
||||||
LineTo(x, y float64)
|
LineTo(x, y float64)
|
||||||
QuadraticTo(x1, y1, x2, y2 float64)
|
QuadraticTo(x1, y1, x2, y2 float64)
|
||||||
|
CubicTo(x1, y1, x2, y2, x3, y3 float64)
|
||||||
ClosePath()
|
ClosePath()
|
||||||
ClearPath()
|
ClearPath()
|
||||||
|
|
||||||
@ -132,7 +133,6 @@ even better, implement it and submit a pull request!
|
|||||||
|
|
||||||
- Clipping Regions
|
- Clipping Regions
|
||||||
- Gradients / Patterns
|
- Gradients / Patterns
|
||||||
- Cubic Beziers
|
|
||||||
- Dashed Lines
|
- Dashed Lines
|
||||||
|
|
||||||
## How Do it Do?
|
## 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"
|
"github.com/golang/freetype/raster"
|
||||||
"golang.org/x/image/font"
|
"golang.org/x/image/font"
|
||||||
"golang.org/x/image/font/basicfont"
|
"golang.org/x/image/font/basicfont"
|
||||||
"golang.org/x/image/math/fixed"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type LineCap int
|
type LineCap int
|
||||||
@ -41,7 +40,8 @@ type Context struct {
|
|||||||
color color.Color
|
color color.Color
|
||||||
strokePath raster.Path
|
strokePath raster.Path
|
||||||
fillPath raster.Path
|
fillPath raster.Path
|
||||||
start fixed.Point26_6
|
start Point
|
||||||
|
current Point
|
||||||
lineWidth float64
|
lineWidth float64
|
||||||
lineCap LineCap
|
lineCap LineCap
|
||||||
lineJoin LineJoin
|
lineJoin LineJoin
|
||||||
@ -170,12 +170,14 @@ func (dc *Context) SetRGB(r, g, b float64) {
|
|||||||
|
|
||||||
func (dc *Context) MoveTo(x, y float64) {
|
func (dc *Context) MoveTo(x, y float64) {
|
||||||
if len(dc.fillPath) > 0 {
|
if len(dc.fillPath) > 0 {
|
||||||
dc.fillPath.Add1(dc.start)
|
dc.fillPath.Add1(dc.start.Fixed())
|
||||||
}
|
}
|
||||||
x, y = dc.TransformPoint(x, y)
|
x, y = dc.TransformPoint(x, y)
|
||||||
dc.start = fp(x, y)
|
p := Point{x, y}
|
||||||
dc.strokePath.Start(dc.start)
|
dc.strokePath.Start(p.Fixed())
|
||||||
dc.fillPath.Start(dc.start)
|
dc.fillPath.Start(p.Fixed())
|
||||||
|
dc.start = p
|
||||||
|
dc.current = p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *Context) LineTo(x, y float64) {
|
func (dc *Context) LineTo(x, y float64) {
|
||||||
@ -183,29 +185,48 @@ func (dc *Context) LineTo(x, y float64) {
|
|||||||
dc.MoveTo(x, y)
|
dc.MoveTo(x, y)
|
||||||
} else {
|
} else {
|
||||||
x, y = dc.TransformPoint(x, y)
|
x, y = dc.TransformPoint(x, y)
|
||||||
p := fp(x, y)
|
p := Point{x, y}
|
||||||
dc.strokePath.Add1(p)
|
dc.strokePath.Add1(p.Fixed())
|
||||||
dc.fillPath.Add1(p)
|
dc.fillPath.Add1(p.Fixed())
|
||||||
|
dc.current = p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *Context) QuadraticTo(x1, y1, x2, y2 float64) {
|
func (dc *Context) QuadraticTo(x1, y1, x2, y2 float64) {
|
||||||
if len(dc.strokePath) == 0 {
|
if len(dc.strokePath) == 0 {
|
||||||
dc.MoveTo(x1, y1)
|
dc.MoveTo(x1, y1)
|
||||||
} else {
|
}
|
||||||
x1, y1 = dc.TransformPoint(x1, y1)
|
x1, y1 = dc.TransformPoint(x1, y1)
|
||||||
x2, y2 = dc.TransformPoint(x2, y2)
|
x2, y2 = dc.TransformPoint(x2, y2)
|
||||||
p1 := fp(x1, y1)
|
p1 := Point{x1, y1}
|
||||||
p2 := fp(x2, y2)
|
p2 := Point{x2, y2}
|
||||||
dc.strokePath.Add2(p1, p2)
|
dc.strokePath.Add2(p1.Fixed(), p2.Fixed())
|
||||||
dc.fillPath.Add2(p1, p2)
|
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() {
|
func (dc *Context) ClosePath() {
|
||||||
if len(dc.strokePath) > 0 {
|
if len(dc.strokePath) > 0 {
|
||||||
dc.strokePath.Add1(dc.start)
|
dc.strokePath.Add1(dc.start.Fixed())
|
||||||
dc.fillPath.Add1(dc.start)
|
dc.fillPath.Add1(dc.start.Fixed())
|
||||||
|
dc.current = dc.start
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +278,7 @@ func (dc *Context) FillPreserve() {
|
|||||||
if len(dc.fillPath) > 0 {
|
if len(dc.fillPath) > 0 {
|
||||||
path = make(raster.Path, len(dc.fillPath))
|
path = make(raster.Path, len(dc.fillPath))
|
||||||
copy(path, dc.fillPath)
|
copy(path, dc.fillPath)
|
||||||
path.Add1(dc.start)
|
path.Add1(dc.start.Fixed())
|
||||||
}
|
}
|
||||||
painter := raster.NewRGBAPainter(dc.im)
|
painter := raster.NewRGBAPainter(dc.im)
|
||||||
painter.SetColor(dc.color)
|
painter.SetColor(dc.color)
|
||||||
|
Loading…
Reference in New Issue
Block a user