remove path package and create draw2dimg package
This commit is contained in:
parent
24d62b9aa7
commit
966a9b73f7
24 changed files with 506 additions and 598 deletions
161
curve.go
Normal file
161
curve.go
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
|
// created: 17/05/2011 by Laurent Le Goff
|
||||||
|
|
||||||
|
package draw2d
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CurveRecursionLimit = 32
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cubic
|
||||||
|
// x1, y1, cpx1, cpy1, cpx2, cpy2, x2, y2 float64
|
||||||
|
|
||||||
|
// Subdivide a Bezier cubic curve in 2 equivalents Bezier cubic curves.
|
||||||
|
// c1 and c2 parameters are the resulting curves
|
||||||
|
func SubdivideCubic(c, c1, c2 []float64) {
|
||||||
|
// First point of c is the first point of c1
|
||||||
|
c1[0], c1[1] = c[0], c[1]
|
||||||
|
// Last point of c is the last point of c2
|
||||||
|
c2[6], c2[7] = c[6], c[7]
|
||||||
|
|
||||||
|
// Subdivide segment using midpoints
|
||||||
|
c1[2] = (c[0] + c[2]) / 2
|
||||||
|
c1[3] = (c[1] + c[3]) / 2
|
||||||
|
|
||||||
|
midX := (c[2] + c[4]) / 2
|
||||||
|
midY := (c[3] + c[5]) / 2
|
||||||
|
|
||||||
|
c2[4] = (c[4] + c[6]) / 2
|
||||||
|
c2[5] = (c[5] + c[7]) / 2
|
||||||
|
|
||||||
|
c1[4] = (c1[2] + midX) / 2
|
||||||
|
c1[5] = (c1[3] + midY) / 2
|
||||||
|
|
||||||
|
c2[2] = (midX + c2[4]) / 2
|
||||||
|
c2[3] = (midY + c2[5]) / 2
|
||||||
|
|
||||||
|
c1[6] = (c1[4] + c2[2]) / 2
|
||||||
|
c1[7] = (c1[5] + c2[3]) / 2
|
||||||
|
|
||||||
|
// Last Point of c1 is equal to the first point of c2
|
||||||
|
c2[0], c2[1] = c1[6], c1[7]
|
||||||
|
}
|
||||||
|
|
||||||
|
// TraceCubic generate lines subdividing the cubic curve using a Flattener
|
||||||
|
// flattening_threshold helps determines the flattening expectation of the curve
|
||||||
|
func TraceCubic(t Flattener, cubic []float64, flattening_threshold float64) {
|
||||||
|
// Allocation curves
|
||||||
|
var curves [CurveRecursionLimit * 8]float64
|
||||||
|
copy(curves[0:8], cubic[0:8])
|
||||||
|
i := 0
|
||||||
|
|
||||||
|
// current curve
|
||||||
|
var c []float64
|
||||||
|
|
||||||
|
var dx, dy, d2, d3 float64
|
||||||
|
|
||||||
|
for i >= 0 {
|
||||||
|
c = curves[i*8:]
|
||||||
|
dx = c[6] - c[0]
|
||||||
|
dy = c[7] - c[1]
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
// if it's flat then trace a line
|
||||||
|
if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
|
||||||
|
t.LineTo(c[6], c[7])
|
||||||
|
i--
|
||||||
|
} else {
|
||||||
|
// second half of bezier go lower onto the stack
|
||||||
|
SubdivideCubic(c, curves[(i+1)*8:], curves[i*8:])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quad
|
||||||
|
// x1, y1, cpx1, cpy2, x2, y2 float64
|
||||||
|
|
||||||
|
// Subdivide a Bezier quad curve in 2 equivalents Bezier quad curves.
|
||||||
|
// c1 and c2 parameters are the resulting curves
|
||||||
|
func SubdivideQuad(c, c1, c2 []float64) {
|
||||||
|
// First point of c is the first point of c1
|
||||||
|
c1[0], c1[1] = c[0], c[1]
|
||||||
|
// Last point of c is the last point of c2
|
||||||
|
c2[4], c2[5] = c[4], c[5]
|
||||||
|
|
||||||
|
// Subdivide segment using midpoints
|
||||||
|
c1[2] = (c[0] + c[2]) / 2
|
||||||
|
c1[3] = (c[1] + c[3]) / 2
|
||||||
|
c2[2] = (c[2] + c[4]) / 2
|
||||||
|
c2[3] = (c[3] + c[5]) / 2
|
||||||
|
c1[4] = (c1[2] + c2[2]) / 2
|
||||||
|
c1[5] = (c1[3] + c2[3]) / 2
|
||||||
|
c2[0], c2[1] = c1[4], c1[5]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace generate lines subdividing the curve using a Flattener
|
||||||
|
// flattening_threshold helps determines the flattening expectation of the curve
|
||||||
|
func TraceQuad(t Flattener, quad []float64, flattening_threshold float64) {
|
||||||
|
// Allocates curves stack
|
||||||
|
var curves [CurveRecursionLimit * 6]float64
|
||||||
|
copy(curves[0:6], quad[0:6])
|
||||||
|
i := 0
|
||||||
|
// current curve
|
||||||
|
var c []float64
|
||||||
|
var dx, dy, d float64
|
||||||
|
|
||||||
|
for i >= 0 {
|
||||||
|
c = curves[i*6:]
|
||||||
|
dx = c[4] - c[0]
|
||||||
|
dy = c[5] - c[1]
|
||||||
|
|
||||||
|
d = math.Abs(((c[2]-c[4])*dy - (c[3]-c[5])*dx))
|
||||||
|
|
||||||
|
// if it's flat then trace a line
|
||||||
|
if (d*d) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
|
||||||
|
t.LineTo(c[4], c[5])
|
||||||
|
i--
|
||||||
|
} else {
|
||||||
|
// second half of bezier go lower onto the stack
|
||||||
|
SubdivideQuad(c, curves[(i+1)*6:], curves[i*6:])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TraceArc trace an arc using a Flattener
|
||||||
|
func TraceArc(t Flattener, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) {
|
||||||
|
end := start + angle
|
||||||
|
clockWise := true
|
||||||
|
if angle < 0 {
|
||||||
|
clockWise = false
|
||||||
|
}
|
||||||
|
ra := (math.Abs(rx) + math.Abs(ry)) / 2
|
||||||
|
da := math.Acos(ra/(ra+0.125/scale)) * 2
|
||||||
|
//normalize
|
||||||
|
if !clockWise {
|
||||||
|
da = -da
|
||||||
|
}
|
||||||
|
angle = start + da
|
||||||
|
var curX, curY float64
|
||||||
|
for {
|
||||||
|
if (angle < end-da/4) != clockWise {
|
||||||
|
curX = x + math.Cos(end)*rx
|
||||||
|
curY = y + math.Sin(end)*ry
|
||||||
|
return curX, curY
|
||||||
|
}
|
||||||
|
curX = x + math.Cos(angle)*rx
|
||||||
|
curY = y + math.Sin(angle)*ry
|
||||||
|
|
||||||
|
angle += da
|
||||||
|
t.LineTo(curX, curY)
|
||||||
|
}
|
||||||
|
return curX, curY
|
||||||
|
}
|
70
curve/arc.go
70
curve/arc.go
|
@ -1,70 +0,0 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
||||||
// created: 21/11/2010 by Laurent Le Goff
|
|
||||||
|
|
||||||
package curve
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"code.google.com/p/freetype-go/freetype/raster"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TraceArc trace an arc using a LineBuilder
|
|
||||||
func TraceArc(t LineBuilder, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) {
|
|
||||||
end := start + angle
|
|
||||||
clockWise := true
|
|
||||||
if angle < 0 {
|
|
||||||
clockWise = false
|
|
||||||
}
|
|
||||||
ra := (math.Abs(rx) + math.Abs(ry)) / 2
|
|
||||||
da := math.Acos(ra/(ra+0.125/scale)) * 2
|
|
||||||
//normalize
|
|
||||||
if !clockWise {
|
|
||||||
da = -da
|
|
||||||
}
|
|
||||||
angle = start + da
|
|
||||||
var curX, curY float64
|
|
||||||
for {
|
|
||||||
if (angle < end-da/4) != clockWise {
|
|
||||||
curX = x + math.Cos(end)*rx
|
|
||||||
curY = y + math.Sin(end)*ry
|
|
||||||
return curX, curY
|
|
||||||
}
|
|
||||||
curX = x + math.Cos(angle)*rx
|
|
||||||
curY = y + math.Sin(angle)*ry
|
|
||||||
|
|
||||||
angle += da
|
|
||||||
t.LineTo(curX, curY)
|
|
||||||
}
|
|
||||||
return curX, curY
|
|
||||||
}
|
|
||||||
|
|
||||||
// TraceArc trace an arc using a Freetype
|
|
||||||
func TraceArcFt(adder raster.Adder, x, y, rx, ry, start, angle, scale float64) raster.Point {
|
|
||||||
end := start + angle
|
|
||||||
clockWise := true
|
|
||||||
if angle < 0 {
|
|
||||||
clockWise = false
|
|
||||||
}
|
|
||||||
ra := (math.Abs(rx) + math.Abs(ry)) / 2
|
|
||||||
da := math.Acos(ra/(ra+0.125/scale)) * 2
|
|
||||||
//normalize
|
|
||||||
if !clockWise {
|
|
||||||
da = -da
|
|
||||||
}
|
|
||||||
angle = start + da
|
|
||||||
var curX, curY float64
|
|
||||||
for {
|
|
||||||
if (angle < end-da/4) != clockWise {
|
|
||||||
curX = x + math.Cos(end)*rx
|
|
||||||
curY = y + math.Sin(end)*ry
|
|
||||||
return raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)}
|
|
||||||
}
|
|
||||||
curX = x + math.Cos(angle)*rx
|
|
||||||
curY = y + math.Sin(angle)*ry
|
|
||||||
|
|
||||||
angle += da
|
|
||||||
adder.Add1(raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)})
|
|
||||||
}
|
|
||||||
return raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
||||||
// created: 17/05/2011 by Laurent Le Goff
|
|
||||||
|
|
||||||
// Package curve implements Bezier Curve Subdivision using De Casteljau's algorithm
|
|
||||||
package curve
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
CurveRecursionLimit = 32
|
|
||||||
)
|
|
||||||
|
|
||||||
// x1, y1, cpx1, cpy1, cpx2, cpy2, x2, y2 float64
|
|
||||||
// type Cubic []float64
|
|
||||||
|
|
||||||
// Subdivide a Bezier cubic curve in 2 equivalents Bezier cubic curves.
|
|
||||||
// c1 and c2 parameters are the resulting curves
|
|
||||||
func SubdivideCubic(c, c1, c2 []float64) {
|
|
||||||
// First point of c is the first point of c1
|
|
||||||
c1[0], c1[1] = c[0], c[1]
|
|
||||||
// Last point of c is the last point of c2
|
|
||||||
c2[6], c2[7] = c[6], c[7]
|
|
||||||
|
|
||||||
// Subdivide segment using midpoints
|
|
||||||
c1[2] = (c[0] + c[2]) / 2
|
|
||||||
c1[3] = (c[1] + c[3]) / 2
|
|
||||||
|
|
||||||
midX := (c[2] + c[4]) / 2
|
|
||||||
midY := (c[3] + c[5]) / 2
|
|
||||||
|
|
||||||
c2[4] = (c[4] + c[6]) / 2
|
|
||||||
c2[5] = (c[5] + c[7]) / 2
|
|
||||||
|
|
||||||
c1[4] = (c1[2] + midX) / 2
|
|
||||||
c1[5] = (c1[3] + midY) / 2
|
|
||||||
|
|
||||||
c2[2] = (midX + c2[4]) / 2
|
|
||||||
c2[3] = (midY + c2[5]) / 2
|
|
||||||
|
|
||||||
c1[6] = (c1[4] + c2[2]) / 2
|
|
||||||
c1[7] = (c1[5] + c2[3]) / 2
|
|
||||||
|
|
||||||
// Last Point of c1 is equal to the first point of c2
|
|
||||||
c2[0], c2[1] = c1[6], c1[7]
|
|
||||||
}
|
|
||||||
|
|
||||||
// TraceCubic generate lines subdividing the cubic curve using a LineBuilder
|
|
||||||
// flattening_threshold helps determines the flattening expectation of the curve
|
|
||||||
func TraceCubic(t LineBuilder, cubic []float64, flattening_threshold float64) {
|
|
||||||
// Allocation curves
|
|
||||||
var curves [CurveRecursionLimit * 8]float64
|
|
||||||
copy(curves[0:8], cubic[0:8])
|
|
||||||
i := 0
|
|
||||||
|
|
||||||
// current curve
|
|
||||||
var c []float64
|
|
||||||
|
|
||||||
var dx, dy, d2, d3 float64
|
|
||||||
|
|
||||||
for i >= 0 {
|
|
||||||
c = curves[i*8:]
|
|
||||||
dx = c[6] - c[0]
|
|
||||||
dy = c[7] - c[1]
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
// if it's flat then trace a line
|
|
||||||
if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
|
|
||||||
t.LineTo(c[6], c[7])
|
|
||||||
i--
|
|
||||||
} else {
|
|
||||||
// second half of bezier go lower onto the stack
|
|
||||||
SubdivideCubic(c, curves[(i+1)*8:], curves[i*8:])
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package curve
|
|
||||||
|
|
||||||
// LineBuilder is an interface that help segmenting curve into small lines
|
|
||||||
type LineBuilder interface {
|
|
||||||
// LineTo a point
|
|
||||||
LineTo(x, y float64)
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
||||||
// created: 17/05/2011 by Laurent Le Goff
|
|
||||||
|
|
||||||
package curve
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
// x1, y1, cpx1, cpy2, x2, y2 float64
|
|
||||||
// type Quad [6]float64
|
|
||||||
|
|
||||||
// Subdivide a Bezier quad curve in 2 equivalents Bezier quad curves.
|
|
||||||
// c1 and c2 parameters are the resulting curves
|
|
||||||
func SubdivideQuad(c, c1, c2 []float64) {
|
|
||||||
// First point of c is the first point of c1
|
|
||||||
c1[0], c1[1] = c[0], c[1]
|
|
||||||
// Last point of c is the last point of c2
|
|
||||||
c2[4], c2[5] = c[4], c[5]
|
|
||||||
|
|
||||||
// Subdivide segment using midpoints
|
|
||||||
c1[2] = (c[0] + c[2]) / 2
|
|
||||||
c1[3] = (c[1] + c[3]) / 2
|
|
||||||
c2[2] = (c[2] + c[4]) / 2
|
|
||||||
c2[3] = (c[3] + c[5]) / 2
|
|
||||||
c1[4] = (c1[2] + c2[2]) / 2
|
|
||||||
c1[5] = (c1[3] + c2[3]) / 2
|
|
||||||
c2[0], c2[1] = c1[4], c1[5]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trace generate lines subdividing the curve using a LineBuilder
|
|
||||||
// flattening_threshold helps determines the flattening expectation of the curve
|
|
||||||
func TraceQuad(t LineBuilder, quad []float64, flattening_threshold float64) {
|
|
||||||
// Allocates curves stack
|
|
||||||
var curves [CurveRecursionLimit * 6]float64
|
|
||||||
copy(curves[0:6], quad[0:6])
|
|
||||||
i := 0
|
|
||||||
// current curve
|
|
||||||
var c []float64
|
|
||||||
var dx, dy, d float64
|
|
||||||
|
|
||||||
for i >= 0 {
|
|
||||||
c = curves[i*6:]
|
|
||||||
dx = c[4] - c[0]
|
|
||||||
dy = c[5] - c[1]
|
|
||||||
|
|
||||||
d = math.Abs(((c[2]-c[4])*dy - (c[3]-c[5])*dx))
|
|
||||||
|
|
||||||
// if it's flat then trace a line
|
|
||||||
if (d*d) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
|
|
||||||
t.LineTo(c[4], c[5])
|
|
||||||
i--
|
|
||||||
} else {
|
|
||||||
// second half of bezier go lower onto the stack
|
|
||||||
SubdivideQuad(c, curves[(i+1)*6:], curves[i*6:])
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package curve
|
package draw2d
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
@ -34,18 +34,6 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type Path struct {
|
|
||||||
points []float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Path) MoveTo(x, y float64) {
|
|
||||||
p.points = append(p.points, x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Path) LineTo(x, y float64) {
|
|
||||||
p.points = append(p.points, x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
os.Mkdir("test_results", 0666)
|
os.Mkdir("test_results", 0666)
|
||||||
f, err := os.Create("test_results/_test.html")
|
f, err := os.Create("test_results/_test.html")
|
||||||
|
@ -85,32 +73,32 @@ func drawPoints(img draw.Image, c color.Color, s ...float64) image.Image {
|
||||||
|
|
||||||
func TestCubicCurve(t *testing.T) {
|
func TestCubicCurve(t *testing.T) {
|
||||||
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
||||||
var p Path
|
var p SegmentedPath
|
||||||
p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
||||||
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
||||||
img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
|
img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
|
||||||
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsCubicFloat64[i:i+8]...)
|
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsCubicFloat64[i:i+8]...)
|
||||||
raster.PolylineBresenham(img, image.Black, p.points...)
|
raster.PolylineBresenham(img, image.Black, p.Points...)
|
||||||
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
|
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
|
||||||
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
|
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.Points...)
|
||||||
SaveToPngFile(fmt.Sprintf("test_results/_test%d.png", i/8), img)
|
SaveToPngFile(fmt.Sprintf("test_results/_test%d.png", i/8), img)
|
||||||
log.Printf("Num of points: %d\n", len(p.points))
|
log.Printf("Num of points: %d\n", len(p.Points))
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQuadCurve(t *testing.T) {
|
func TestQuadCurve(t *testing.T) {
|
||||||
for i := 0; i < len(testsQuadFloat64); i += 6 {
|
for i := 0; i < len(testsQuadFloat64); i += 6 {
|
||||||
var p Path
|
var p SegmentedPath
|
||||||
p.MoveTo(testsQuadFloat64[i], testsQuadFloat64[i+1])
|
p.MoveTo(testsQuadFloat64[i], testsQuadFloat64[i+1])
|
||||||
TraceQuad(&p, testsQuadFloat64[i:], flattening_threshold)
|
TraceQuad(&p, testsQuadFloat64[i:], flattening_threshold)
|
||||||
img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
|
img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
|
||||||
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsQuadFloat64[i:i+6]...)
|
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsQuadFloat64[i:i+6]...)
|
||||||
raster.PolylineBresenham(img, image.Black, p.points...)
|
raster.PolylineBresenham(img, image.Black, p.Points...)
|
||||||
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
|
//drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...)
|
||||||
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.points...)
|
drawPoints(img, color.NRGBA{0, 0, 0, 0xff}, p.Points...)
|
||||||
SaveToPngFile(fmt.Sprintf("test_results/_testQuad%d.png", i), img)
|
SaveToPngFile(fmt.Sprintf("test_results/_testQuad%d.png", i), img)
|
||||||
log.Printf("Num of points: %d\n", len(p.points))
|
log.Printf("Num of points: %d\n", len(p.Points))
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
@ -118,7 +106,7 @@ func TestQuadCurve(t *testing.T) {
|
||||||
func BenchmarkCubicCurve(b *testing.B) {
|
func BenchmarkCubicCurve(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
||||||
var p Path
|
var p SegmentedPath
|
||||||
p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
||||||
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
||||||
}
|
}
|
|
@ -1,17 +1,21 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
// created: 13/12/2010 by Laurent Le Goff
|
// created: 13/12/2010 by Laurent Le Goff
|
||||||
|
|
||||||
package path
|
package draw2dbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/llgcode/draw2d"
|
||||||
|
)
|
||||||
|
|
||||||
type DashVertexConverter struct {
|
type DashVertexConverter struct {
|
||||||
next LineBuilder
|
next draw2d.Flattener
|
||||||
x, y, distance float64
|
x, y, distance float64
|
||||||
dash []float64
|
dash []float64
|
||||||
currentDash int
|
currentDash int
|
||||||
dashOffset float64
|
dashOffset float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDashConverter(dash []float64, dashOffset float64, converter LineBuilder) *DashVertexConverter {
|
func NewDashConverter(dash []float64, dashOffset float64, converter draw2d.Flattener) *DashVertexConverter {
|
||||||
var dasher DashVertexConverter
|
var dasher DashVertexConverter
|
||||||
dasher.dash = dash
|
dasher.dash = dash
|
||||||
dasher.currentDash = 0
|
dasher.currentDash = 0
|
||||||
|
@ -83,3 +87,7 @@ func (dasher *DashVertexConverter) lineTo(x, y float64) {
|
||||||
}
|
}
|
||||||
dasher.x, dasher.y = x, y
|
dasher.x, dasher.y = x, y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func distance(x1, y1, x2, y2 float64) float64 {
|
||||||
|
return vectorDistance(x2-x1, y2-y1)
|
||||||
|
}
|
39
draw2dbase/demux_flattener.go
Normal file
39
draw2dbase/demux_flattener.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package draw2dbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/llgcode/draw2d"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DemuxFlattener struct {
|
||||||
|
Flatteners []draw2d.Flattener
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc DemuxFlattener) MoveTo(x, y float64) {
|
||||||
|
for _, flattener := range dc.Flatteners {
|
||||||
|
flattener.MoveTo(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc DemuxFlattener) LineTo(x, y float64) {
|
||||||
|
for _, flattener := range dc.Flatteners {
|
||||||
|
flattener.LineTo(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc DemuxFlattener) LineJoin() {
|
||||||
|
for _, flattener := range dc.Flatteners {
|
||||||
|
flattener.LineJoin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc DemuxFlattener) Close() {
|
||||||
|
for _, flattener := range dc.Flatteners {
|
||||||
|
flattener.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc DemuxFlattener) End() {
|
||||||
|
for _, flattener := range dc.Flatteners {
|
||||||
|
flattener.End()
|
||||||
|
}
|
||||||
|
}
|
29
draw2dbase/ftpath.go
Normal file
29
draw2dbase/ftpath.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
|
// created: 13/12/2010 by Laurent Le Goff
|
||||||
|
|
||||||
|
package draw2dbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.google.com/p/freetype-go/freetype/raster"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FtLineBuilder struct {
|
||||||
|
Adder raster.Adder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (liner FtLineBuilder) MoveTo(x, y float64) {
|
||||||
|
liner.Adder.Start(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (liner FtLineBuilder) LineTo(x, y float64) {
|
||||||
|
liner.Adder.Add1(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (liner FtLineBuilder) LineJoin() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (liner FtLineBuilder) Close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (liner FtLineBuilder) End() {
|
||||||
|
}
|
|
@ -1,40 +1,42 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
// created: 21/11/2010 by Laurent Le Goff
|
// created: 21/11/2010 by Laurent Le Goff
|
||||||
|
|
||||||
package draw2d
|
package draw2dbase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/llgcode/draw2d/path"
|
"github.com/llgcode/draw2d"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"code.google.com/p/freetype-go/freetype/truetype"
|
"code.google.com/p/freetype-go/freetype/truetype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var DefaultFontData = draw2d.FontData{"luxi", draw2d.FontFamilySans, draw2d.FontStyleNormal}
|
||||||
|
|
||||||
type StackGraphicContext struct {
|
type StackGraphicContext struct {
|
||||||
Current *ContextStack
|
Current *ContextStack
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContextStack struct {
|
type ContextStack struct {
|
||||||
Tr MatrixTransform
|
Tr draw2d.MatrixTransform
|
||||||
Path *path.Path
|
Path *draw2d.Path
|
||||||
LineWidth float64
|
LineWidth float64
|
||||||
Dash []float64
|
Dash []float64
|
||||||
DashOffset float64
|
DashOffset float64
|
||||||
StrokeColor color.Color
|
StrokeColor color.Color
|
||||||
FillColor color.Color
|
FillColor color.Color
|
||||||
FillRule FillRule
|
FillRule draw2d.FillRule
|
||||||
Cap path.Cap
|
Cap draw2d.LineCap
|
||||||
Join path.Join
|
Join draw2d.LineJoin
|
||||||
FontSize float64
|
FontSize float64
|
||||||
FontData FontData
|
FontData draw2d.FontData
|
||||||
|
|
||||||
font *truetype.Font
|
Font *truetype.Font
|
||||||
// fontSize and dpi are used to calculate scale. scale is the number of
|
// fontSize and dpi are used to calculate scale. scale is the number of
|
||||||
// 26.6 fixed point units in 1 em.
|
// 26.6 fixed point units in 1 em.
|
||||||
scale int32
|
Scale int32
|
||||||
|
|
||||||
previous *ContextStack
|
Previous *ContextStack
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,41 +45,41 @@ type ContextStack struct {
|
||||||
func NewStackGraphicContext() *StackGraphicContext {
|
func NewStackGraphicContext() *StackGraphicContext {
|
||||||
gc := &StackGraphicContext{}
|
gc := &StackGraphicContext{}
|
||||||
gc.Current = new(ContextStack)
|
gc.Current = new(ContextStack)
|
||||||
gc.Current.Tr = NewIdentityMatrix()
|
gc.Current.Tr = draw2d.NewIdentityMatrix()
|
||||||
gc.Current.Path = new(path.Path)
|
gc.Current.Path = new(draw2d.Path)
|
||||||
gc.Current.LineWidth = 1.0
|
gc.Current.LineWidth = 1.0
|
||||||
gc.Current.StrokeColor = image.Black
|
gc.Current.StrokeColor = image.Black
|
||||||
gc.Current.FillColor = image.White
|
gc.Current.FillColor = image.White
|
||||||
gc.Current.Cap = path.RoundCap
|
gc.Current.Cap = draw2d.RoundCap
|
||||||
gc.Current.FillRule = FillRuleEvenOdd
|
gc.Current.FillRule = draw2d.FillRuleEvenOdd
|
||||||
gc.Current.Join = path.RoundJoin
|
gc.Current.Join = draw2d.RoundJoin
|
||||||
gc.Current.FontSize = 10
|
gc.Current.FontSize = 10
|
||||||
gc.Current.FontData = defaultFontData
|
gc.Current.FontData = DefaultFontData
|
||||||
return gc
|
return gc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) GetMatrixTransform() MatrixTransform {
|
func (gc *StackGraphicContext) GetMatrixTransform() draw2d.MatrixTransform {
|
||||||
return gc.Current.Tr
|
return gc.Current.Tr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetMatrixTransform(Tr MatrixTransform) {
|
func (gc *StackGraphicContext) SetMatrixTransform(Tr draw2d.MatrixTransform) {
|
||||||
gc.Current.Tr = Tr
|
gc.Current.Tr = Tr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) ComposeMatrixTransform(Tr MatrixTransform) {
|
func (gc *StackGraphicContext) ComposeMatrixTransform(Tr draw2d.MatrixTransform) {
|
||||||
gc.Current.Tr = Tr.Multiply(gc.Current.Tr)
|
gc.Current.Tr = Tr.Multiply(gc.Current.Tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) Rotate(angle float64) {
|
func (gc *StackGraphicContext) Rotate(angle float64) {
|
||||||
gc.Current.Tr = NewRotationMatrix(angle).Multiply(gc.Current.Tr)
|
gc.Current.Tr = draw2d.NewRotationMatrix(angle).Multiply(gc.Current.Tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) Translate(tx, ty float64) {
|
func (gc *StackGraphicContext) Translate(tx, ty float64) {
|
||||||
gc.Current.Tr = NewTranslationMatrix(tx, ty).Multiply(gc.Current.Tr)
|
gc.Current.Tr = draw2d.NewTranslationMatrix(tx, ty).Multiply(gc.Current.Tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) Scale(sx, sy float64) {
|
func (gc *StackGraphicContext) Scale(sx, sy float64) {
|
||||||
gc.Current.Tr = NewScaleMatrix(sx, sy).Multiply(gc.Current.Tr)
|
gc.Current.Tr = draw2d.NewScaleMatrix(sx, sy).Multiply(gc.Current.Tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetStrokeColor(c color.Color) {
|
func (gc *StackGraphicContext) SetStrokeColor(c color.Color) {
|
||||||
|
@ -88,40 +90,40 @@ func (gc *StackGraphicContext) SetFillColor(c color.Color) {
|
||||||
gc.Current.FillColor = c
|
gc.Current.FillColor = c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetFillRule(f FillRule) {
|
func (gc *StackGraphicContext) SetFillRule(f draw2d.FillRule) {
|
||||||
gc.Current.FillRule = f
|
gc.Current.FillRule = f
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetLineWidth(LineWidth float64) {
|
func (gc *StackGraphicContext) SetLineWidth(lineWidth float64) {
|
||||||
gc.Current.LineWidth = LineWidth
|
gc.Current.LineWidth = lineWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetLineCap(cap path.Cap) {
|
func (gc *StackGraphicContext) SetLineCap(cap draw2d.LineCap) {
|
||||||
gc.Current.Cap = cap
|
gc.Current.Cap = cap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetLineJoin(join path.Join) {
|
func (gc *StackGraphicContext) SetLineJoin(join draw2d.LineJoin) {
|
||||||
gc.Current.Join = join
|
gc.Current.Join = join
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetLineDash(Dash []float64, DashOffset float64) {
|
func (gc *StackGraphicContext) SetLineDash(dash []float64, dashOffset float64) {
|
||||||
gc.Current.Dash = Dash
|
gc.Current.Dash = dash
|
||||||
gc.Current.DashOffset = DashOffset
|
gc.Current.DashOffset = dashOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetFontSize(FontSize float64) {
|
func (gc *StackGraphicContext) SetFontSize(fontSize float64) {
|
||||||
gc.Current.FontSize = FontSize
|
gc.Current.FontSize = fontSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) GetFontSize() float64 {
|
func (gc *StackGraphicContext) GetFontSize() float64 {
|
||||||
return gc.Current.FontSize
|
return gc.Current.FontSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetFontData(FontData FontData) {
|
func (gc *StackGraphicContext) SetFontData(fontData draw2d.FontData) {
|
||||||
gc.Current.FontData = FontData
|
gc.Current.FontData = fontData
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) GetFontData() FontData {
|
func (gc *StackGraphicContext) GetFontData() draw2d.FontData {
|
||||||
return gc.Current.FontData
|
return gc.Current.FontData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,17 +176,17 @@ func (gc *StackGraphicContext) Save() {
|
||||||
context.Cap = gc.Current.Cap
|
context.Cap = gc.Current.Cap
|
||||||
context.Join = gc.Current.Join
|
context.Join = gc.Current.Join
|
||||||
context.Path = gc.Current.Path.Copy()
|
context.Path = gc.Current.Path.Copy()
|
||||||
context.font = gc.Current.font
|
context.Font = gc.Current.Font
|
||||||
context.scale = gc.Current.scale
|
context.Scale = gc.Current.Scale
|
||||||
copy(context.Tr[:], gc.Current.Tr[:])
|
copy(context.Tr[:], gc.Current.Tr[:])
|
||||||
context.previous = gc.Current
|
context.Previous = gc.Current
|
||||||
gc.Current = context
|
gc.Current = context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) Restore() {
|
func (gc *StackGraphicContext) Restore() {
|
||||||
if gc.Current.previous != nil {
|
if gc.Current.Previous != nil {
|
||||||
oldContext := gc.Current
|
oldContext := gc.Current
|
||||||
gc.Current = gc.Current.previous
|
gc.Current = gc.Current.Previous
|
||||||
oldContext.previous = nil
|
oldContext.Previous = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,66 +1,50 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
// created: 13/12/2010 by Laurent Le Goff
|
// created: 13/12/2010 by Laurent Le Goff
|
||||||
|
|
||||||
package path
|
package draw2dbase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.google.com/p/freetype-go/freetype/raster"
|
"code.google.com/p/freetype-go/freetype/raster"
|
||||||
|
"github.com/llgcode/draw2d"
|
||||||
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Cap int
|
func toFtCap(c draw2d.LineCap) raster.Capper {
|
||||||
|
|
||||||
const (
|
|
||||||
RoundCap Cap = iota
|
|
||||||
ButtCap
|
|
||||||
SquareCap
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c Cap) Convert() raster.Capper {
|
|
||||||
switch c {
|
switch c {
|
||||||
case RoundCap:
|
case draw2d.RoundCap:
|
||||||
return raster.RoundCapper
|
return raster.RoundCapper
|
||||||
case ButtCap:
|
case draw2d.ButtCap:
|
||||||
return raster.ButtCapper
|
return raster.ButtCapper
|
||||||
case SquareCap:
|
case draw2d.SquareCap:
|
||||||
return raster.SquareCapper
|
return raster.SquareCapper
|
||||||
}
|
}
|
||||||
return raster.RoundCapper
|
return raster.RoundCapper
|
||||||
}
|
}
|
||||||
|
|
||||||
type Join int
|
func toFtJoin(j draw2d.LineJoin) raster.Joiner {
|
||||||
|
|
||||||
const (
|
|
||||||
BevelJoin Join = iota
|
|
||||||
RoundJoin
|
|
||||||
MiterJoin
|
|
||||||
)
|
|
||||||
|
|
||||||
func (j Join) Convert() raster.Joiner {
|
|
||||||
switch j {
|
switch j {
|
||||||
case RoundJoin:
|
case draw2d.RoundJoin:
|
||||||
return raster.RoundJoiner
|
return raster.RoundJoiner
|
||||||
case BevelJoin:
|
case draw2d.BevelJoin:
|
||||||
return raster.BevelJoiner
|
return raster.BevelJoiner
|
||||||
}
|
}
|
||||||
return raster.RoundJoiner
|
return raster.RoundJoiner
|
||||||
}
|
}
|
||||||
|
|
||||||
type LineStroker struct {
|
type LineStroker struct {
|
||||||
Next LineBuilder
|
Next draw2d.Flattener
|
||||||
HalfLineWidth float64
|
HalfLineWidth float64
|
||||||
Cap Cap
|
Cap draw2d.LineCap
|
||||||
Join Join
|
Join draw2d.LineJoin
|
||||||
vertices []float64
|
vertices []float64
|
||||||
rewind []float64
|
rewind []float64
|
||||||
x, y, nx, ny float64
|
x, y, nx, ny float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLineStroker(c Cap, j Join, converter LineBuilder) *LineStroker {
|
func NewLineStroker(c draw2d.LineCap, j draw2d.LineJoin, flattener draw2d.Flattener) *LineStroker {
|
||||||
l := new(LineStroker)
|
l := new(LineStroker)
|
||||||
l.Next = converter
|
l.Next = flattener
|
||||||
l.HalfLineWidth = 0.5
|
l.HalfLineWidth = 0.5
|
||||||
l.vertices = make([]float64, 0, 256)
|
|
||||||
l.rewind = make([]float64, 0, 256)
|
|
||||||
l.Cap = c
|
l.Cap = c
|
||||||
l.Join = j
|
l.Join = j
|
||||||
return l
|
return l
|
||||||
|
@ -122,3 +106,7 @@ func (l *LineStroker) appendVertex(vertices ...float64) {
|
||||||
l.vertices = append(l.vertices, vertices[:s]...)
|
l.vertices = append(l.vertices, vertices[:s]...)
|
||||||
l.rewind = append(l.rewind, vertices[s:]...)
|
l.rewind = append(l.rewind, vertices[s:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func vectorDistance(dx, dy float64) float64 {
|
||||||
|
return float64(math.Sqrt(dx*dx + dy*dy))
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"code.google.com/p/freetype-go/freetype/raster"
|
"code.google.com/p/freetype-go/freetype/raster"
|
||||||
"github.com/go-gl/gl/v2.1/gl"
|
"github.com/go-gl/gl/v2.1/gl"
|
||||||
"github.com/llgcode/draw2d"
|
"github.com/llgcode/draw2d"
|
||||||
"github.com/llgcode/draw2d/path"
|
"github.com/llgcode/draw2d/draw2dbase"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -113,7 +113,7 @@ func NewPainter() *Painter {
|
||||||
}
|
}
|
||||||
|
|
||||||
type GraphicContext struct {
|
type GraphicContext struct {
|
||||||
*draw2d.StackGraphicContext
|
*draw2dbase.StackGraphicContext
|
||||||
painter *Painter
|
painter *Painter
|
||||||
fillRasterizer *raster.Rasterizer
|
fillRasterizer *raster.Rasterizer
|
||||||
strokeRasterizer *raster.Rasterizer
|
strokeRasterizer *raster.Rasterizer
|
||||||
|
@ -122,7 +122,7 @@ type GraphicContext struct {
|
||||||
// NewGraphicContext creates a new Graphic context from an image.
|
// NewGraphicContext creates a new Graphic context from an image.
|
||||||
func NewGraphicContext(width, height int) *GraphicContext {
|
func NewGraphicContext(width, height int) *GraphicContext {
|
||||||
gc := &GraphicContext{
|
gc := &GraphicContext{
|
||||||
draw2d.NewStackGraphicContext(),
|
draw2dbase.NewStackGraphicContext(),
|
||||||
NewPainter(),
|
NewPainter(),
|
||||||
raster.NewRasterizer(width, height),
|
raster.NewRasterizer(width, height),
|
||||||
raster.NewRasterizer(width, height),
|
raster.NewRasterizer(width, height),
|
||||||
|
@ -184,20 +184,19 @@ func (gc *GraphicContext) paint(rasterizer *raster.Rasterizer, color color.Color
|
||||||
gc.Current.Path.Clear()
|
gc.Current.Path.Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *GraphicContext) Stroke(paths ...*path.Path) {
|
func (gc *GraphicContext) Stroke(paths ...*draw2d.Path) {
|
||||||
paths = append(paths, gc.Current.Path)
|
paths = append(paths, gc.Current.Path)
|
||||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||||
|
|
||||||
stroker := path.NewLineStroker(gc.Current.Cap, gc.Current.Join, draw2d.NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.strokeRasterizer)))
|
stroker := draw2dbase.NewLineStroker(gc.Current.Cap, gc.Current.Join, draw2d.Transformer{gc.Current.Tr, draw2dbase.FtLineBuilder{gc.strokeRasterizer}})
|
||||||
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
||||||
|
|
||||||
var liner path.LineBuilder
|
var liner draw2d.Flattener
|
||||||
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
||||||
liner = path.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
liner = draw2dbase.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
||||||
} else {
|
} else {
|
||||||
liner = stroker
|
liner = stroker
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
p.Flatten(liner, gc.Current.Tr.GetScale())
|
p.Flatten(liner, gc.Current.Tr.GetScale())
|
||||||
}
|
}
|
||||||
|
@ -205,37 +204,37 @@ func (gc *GraphicContext) Stroke(paths ...*path.Path) {
|
||||||
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *GraphicContext) Fill(paths ...*path.Path) {
|
func (gc *GraphicContext) Fill(paths ...*draw2d.Path) {
|
||||||
paths = append(paths, gc.Current.Path)
|
paths = append(paths, gc.Current.Path)
|
||||||
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
gc.fillRasterizer.UseNonZeroWinding = useNonZeroWinding(gc.Current.FillRule)
|
||||||
|
|
||||||
flattener := draw2d.NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.fillRasterizer))
|
/**** first method ****/
|
||||||
|
flattener := draw2d.Transformer{gc.Current.Tr, draw2dbase.FtLineBuilder{gc.fillRasterizer}}
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
p.Flatten(flattener, gc.Current.Tr.GetScale())
|
p.Flatten(flattener, gc.Current.Tr.GetScale())
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
|
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
|
||||||
gc.Current.Path.Clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *GraphicContext) FillStroke(paths ...*path.Path) {
|
func (gc *GraphicContext) FillStroke(paths ...*draw2d.Path) {
|
||||||
paths = append(paths, gc.Current.Path)
|
paths = append(paths, gc.Current.Path)
|
||||||
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
gc.fillRasterizer.UseNonZeroWinding = useNonZeroWinding(gc.Current.FillRule)
|
||||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||||
|
|
||||||
flattener := draw2d.NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.fillRasterizer))
|
flattener := draw2d.Transformer{gc.Current.Tr, draw2dbase.FtLineBuilder{gc.fillRasterizer}}
|
||||||
|
|
||||||
stroker := path.NewLineStroker(gc.Current.Cap, gc.Current.Join, draw2d.NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.strokeRasterizer)))
|
stroker := draw2dbase.NewLineStroker(gc.Current.Cap, gc.Current.Join, draw2d.Transformer{gc.Current.Tr, draw2dbase.FtLineBuilder{gc.strokeRasterizer}})
|
||||||
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
||||||
|
|
||||||
var liner path.LineBuilder
|
var liner draw2d.Flattener
|
||||||
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
||||||
liner = path.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
liner = draw2dbase.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
||||||
} else {
|
} else {
|
||||||
liner = stroker
|
liner = stroker
|
||||||
}
|
}
|
||||||
|
|
||||||
demux := path.NewLineBuilders(flattener, liner)
|
demux := draw2dbase.DemuxFlattener{[]draw2d.Flattener{flattener, liner}}
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
p.Flatten(demux, gc.Current.Tr.GetScale())
|
p.Flatten(demux, gc.Current.Tr.GetScale())
|
||||||
}
|
}
|
||||||
|
@ -245,3 +244,13 @@ func (gc *GraphicContext) FillStroke(paths ...*path.Path) {
|
||||||
// Stroke
|
// Stroke
|
||||||
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func useNonZeroWinding(f draw2d.FillRule) bool {
|
||||||
|
switch f {
|
||||||
|
case draw2d.FillRuleEvenOdd:
|
||||||
|
return false
|
||||||
|
case draw2d.FillRuleWinding:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package draw2d
|
package draw2dimg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
|
@ -1,11 +1,12 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
// created: 21/11/2010 by Laurent Le Goff
|
// created: 21/11/2010 by Laurent Le Goff
|
||||||
|
|
||||||
package draw2d
|
package draw2dimg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/llgcode/draw2d/path"
|
"github.com/llgcode/draw2d"
|
||||||
|
"github.com/llgcode/draw2d/draw2dbase"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
|
@ -21,12 +22,8 @@ type Painter interface {
|
||||||
SetColor(color color.Color)
|
SetColor(color color.Color)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
type GraphicContext struct {
|
||||||
defaultFontData = FontData{"luxi", FontFamilySans, FontStyleNormal}
|
*draw2dbase.StackGraphicContext
|
||||||
)
|
|
||||||
|
|
||||||
type ImageGraphicContext struct {
|
|
||||||
*StackGraphicContext
|
|
||||||
img draw.Image
|
img draw.Image
|
||||||
painter Painter
|
painter Painter
|
||||||
fillRasterizer *raster.Rasterizer
|
fillRasterizer *raster.Rasterizer
|
||||||
|
@ -38,7 +35,7 @@ type ImageGraphicContext struct {
|
||||||
/**
|
/**
|
||||||
* Create a new Graphic context from an image
|
* Create a new Graphic context from an image
|
||||||
*/
|
*/
|
||||||
func NewGraphicContext(img draw.Image) *ImageGraphicContext {
|
func NewGraphicContext(img draw.Image) *GraphicContext {
|
||||||
var painter Painter
|
var painter Painter
|
||||||
switch selectImage := img.(type) {
|
switch selectImage := img.(type) {
|
||||||
case *image.RGBA:
|
case *image.RGBA:
|
||||||
|
@ -50,11 +47,11 @@ func NewGraphicContext(img draw.Image) *ImageGraphicContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new Graphic context from an image and a Painter (see Freetype-go)
|
// Create a new Graphic context from an image and a Painter (see Freetype-go)
|
||||||
func NewGraphicContextWithPainter(img draw.Image, painter Painter) *ImageGraphicContext {
|
func NewGraphicContextWithPainter(img draw.Image, painter Painter) *GraphicContext {
|
||||||
width, height := img.Bounds().Dx(), img.Bounds().Dy()
|
width, height := img.Bounds().Dx(), img.Bounds().Dy()
|
||||||
dpi := 92
|
dpi := 92
|
||||||
gc := &ImageGraphicContext{
|
gc := &GraphicContext{
|
||||||
NewStackGraphicContext(),
|
draw2dbase.NewStackGraphicContext(),
|
||||||
img,
|
img,
|
||||||
painter,
|
painter,
|
||||||
raster.NewRasterizer(width, height),
|
raster.NewRasterizer(width, height),
|
||||||
|
@ -65,48 +62,48 @@ func NewGraphicContextWithPainter(img draw.Image, painter Painter) *ImageGraphic
|
||||||
return gc
|
return gc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) GetDPI() int {
|
func (gc *GraphicContext) GetDPI() int {
|
||||||
return gc.DPI
|
return gc.DPI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) Clear() {
|
func (gc *GraphicContext) Clear() {
|
||||||
width, height := gc.img.Bounds().Dx(), gc.img.Bounds().Dy()
|
width, height := gc.img.Bounds().Dx(), gc.img.Bounds().Dy()
|
||||||
gc.ClearRect(0, 0, width, height)
|
gc.ClearRect(0, 0, width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) ClearRect(x1, y1, x2, y2 int) {
|
func (gc *GraphicContext) ClearRect(x1, y1, x2, y2 int) {
|
||||||
imageColor := image.NewUniform(gc.Current.FillColor)
|
imageColor := image.NewUniform(gc.Current.FillColor)
|
||||||
draw.Draw(gc.img, image.Rect(x1, y1, x2, y2), imageColor, image.ZP, draw.Over)
|
draw.Draw(gc.img, image.Rect(x1, y1, x2, y2), imageColor, image.ZP, draw.Over)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) DrawImage(img image.Image) {
|
func (gc *GraphicContext) DrawImage(img image.Image) {
|
||||||
DrawImage(img, gc.img, gc.Current.Tr, draw.Over, BilinearFilter)
|
DrawImage(img, gc.img, gc.Current.Tr, draw.Over, BilinearFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) FillString(text string) (cursor float64) {
|
func (gc *GraphicContext) FillString(text string) (cursor float64) {
|
||||||
return gc.FillStringAt(text, 0, 0)
|
return gc.FillStringAt(text, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) FillStringAt(text string, x, y float64) (cursor float64) {
|
func (gc *GraphicContext) FillStringAt(text string, x, y float64) (cursor float64) {
|
||||||
width := gc.CreateStringPath(text, x, y)
|
width := gc.CreateStringPath(text, x, y)
|
||||||
gc.Fill()
|
gc.Fill()
|
||||||
return width
|
return width
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) StrokeString(text string) (cursor float64) {
|
func (gc *GraphicContext) StrokeString(text string) (cursor float64) {
|
||||||
return gc.StrokeStringAt(text, 0, 0)
|
return gc.StrokeStringAt(text, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) StrokeStringAt(text string, x, y float64) (cursor float64) {
|
func (gc *GraphicContext) StrokeStringAt(text string, x, y float64) (cursor float64) {
|
||||||
width := gc.CreateStringPath(text, x, y)
|
width := gc.CreateStringPath(text, x, y)
|
||||||
gc.Stroke()
|
gc.Stroke()
|
||||||
return width
|
return width
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) loadCurrentFont() (*truetype.Font, error) {
|
func (gc *GraphicContext) loadCurrentFont() (*truetype.Font, error) {
|
||||||
font := GetFont(gc.Current.FontData)
|
font := draw2d.GetFont(gc.Current.FontData)
|
||||||
if font == nil {
|
if font == nil {
|
||||||
font = GetFont(defaultFontData)
|
font = draw2d.GetFont(draw2dbase.DefaultFontData)
|
||||||
}
|
}
|
||||||
if font == nil {
|
if font == nil {
|
||||||
return nil, errors.New("No font set, and no default font available.")
|
return nil, errors.New("No font set, and no default font available.")
|
||||||
|
@ -129,7 +126,7 @@ func pointToF64Point(p truetype.Point) (x, y float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// drawContour draws the given closed contour at the given sub-pixel offset.
|
// drawContour draws the given closed contour at the given sub-pixel offset.
|
||||||
func (gc *ImageGraphicContext) drawContour(ps []truetype.Point, dx, dy float64) {
|
func (gc *GraphicContext) drawContour(ps []truetype.Point, dx, dy float64) {
|
||||||
if len(ps) == 0 {
|
if len(ps) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -164,8 +161,8 @@ func (gc *ImageGraphicContext) drawContour(ps []truetype.Point, dx, dy float64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) drawGlyph(glyph truetype.Index, dx, dy float64) error {
|
func (gc *GraphicContext) drawGlyph(glyph truetype.Index, dx, dy float64) error {
|
||||||
if err := gc.glyphBuf.Load(gc.Current.font, gc.Current.scale, glyph, truetype.NoHinting); err != nil {
|
if err := gc.glyphBuf.Load(gc.Current.Font, gc.Current.Scale, glyph, truetype.NoHinting); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
e0 := 0
|
e0 := 0
|
||||||
|
@ -182,7 +179,7 @@ func (gc *ImageGraphicContext) drawGlyph(glyph truetype.Index, dx, dy float64) e
|
||||||
// above and to the right of the point, but some may be below or to the left.
|
// above and to the right of the point, but some may be below or to the left.
|
||||||
// For example, drawing a string that starts with a 'J' in an italic font may
|
// For example, drawing a string that starts with a 'J' in an italic font may
|
||||||
// affect pixels below and left of the point.
|
// affect pixels below and left of the point.
|
||||||
func (gc *ImageGraphicContext) CreateStringPath(s string, x, y float64) float64 {
|
func (gc *GraphicContext) CreateStringPath(s string, x, y float64) float64 {
|
||||||
font, err := gc.loadCurrentFont()
|
font, err := gc.loadCurrentFont()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
@ -193,14 +190,14 @@ func (gc *ImageGraphicContext) CreateStringPath(s string, x, y float64) float64
|
||||||
for _, rune := range s {
|
for _, rune := range s {
|
||||||
index := font.Index(rune)
|
index := font.Index(rune)
|
||||||
if hasPrev {
|
if hasPrev {
|
||||||
x += fUnitsToFloat64(font.Kerning(gc.Current.scale, prev, index))
|
x += fUnitsToFloat64(font.Kerning(gc.Current.Scale, prev, index))
|
||||||
}
|
}
|
||||||
err := gc.drawGlyph(index, x, y)
|
err := gc.drawGlyph(index, x, y)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return startx - x
|
return startx - x
|
||||||
}
|
}
|
||||||
x += fUnitsToFloat64(font.HMetric(gc.Current.scale, index).AdvanceWidth)
|
x += fUnitsToFloat64(font.HMetric(gc.Current.Scale, index).AdvanceWidth)
|
||||||
prev, hasPrev = index, true
|
prev, hasPrev = index, true
|
||||||
}
|
}
|
||||||
return x - startx
|
return x - startx
|
||||||
|
@ -210,7 +207,7 @@ func (gc *ImageGraphicContext) CreateStringPath(s string, x, y float64) float64
|
||||||
// The the left edge of the em square of the first character of s
|
// The the left edge of the em square of the first character of s
|
||||||
// and the baseline intersect at 0, 0 in the returned coordinates.
|
// and the baseline intersect at 0, 0 in the returned coordinates.
|
||||||
// Therefore the top and left coordinates may well be negative.
|
// Therefore the top and left coordinates may well be negative.
|
||||||
func (gc *ImageGraphicContext) GetStringBounds(s string) (left, top, right, bottom float64) {
|
func (gc *GraphicContext) GetStringBounds(s string) (left, top, right, bottom float64) {
|
||||||
font, err := gc.loadCurrentFont()
|
font, err := gc.loadCurrentFont()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
@ -222,9 +219,9 @@ func (gc *ImageGraphicContext) GetStringBounds(s string) (left, top, right, bott
|
||||||
for _, rune := range s {
|
for _, rune := range s {
|
||||||
index := font.Index(rune)
|
index := font.Index(rune)
|
||||||
if hasPrev {
|
if hasPrev {
|
||||||
cursor += fUnitsToFloat64(font.Kerning(gc.Current.scale, prev, index))
|
cursor += fUnitsToFloat64(font.Kerning(gc.Current.Scale, prev, index))
|
||||||
}
|
}
|
||||||
if err := gc.glyphBuf.Load(gc.Current.font, gc.Current.scale, index, truetype.NoHinting); err != nil {
|
if err := gc.glyphBuf.Load(gc.Current.Font, gc.Current.Scale, index, truetype.NoHinting); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return 0, 0, 0, 0
|
return 0, 0, 0, 0
|
||||||
}
|
}
|
||||||
|
@ -239,7 +236,7 @@ func (gc *ImageGraphicContext) GetStringBounds(s string) (left, top, right, bott
|
||||||
right = math.Max(right, x+cursor)
|
right = math.Max(right, x+cursor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursor += fUnitsToFloat64(font.HMetric(gc.Current.scale, index).AdvanceWidth)
|
cursor += fUnitsToFloat64(font.HMetric(gc.Current.Scale, index).AdvanceWidth)
|
||||||
prev, hasPrev = index, true
|
prev, hasPrev = index, true
|
||||||
}
|
}
|
||||||
return left, top, right, bottom
|
return left, top, right, bottom
|
||||||
|
@ -247,44 +244,44 @@ func (gc *ImageGraphicContext) GetStringBounds(s string) (left, top, right, bott
|
||||||
|
|
||||||
// recalc recalculates scale and bounds values from the font size, screen
|
// recalc recalculates scale and bounds values from the font size, screen
|
||||||
// resolution and font metrics, and invalidates the glyph cache.
|
// resolution and font metrics, and invalidates the glyph cache.
|
||||||
func (gc *ImageGraphicContext) recalc() {
|
func (gc *GraphicContext) recalc() {
|
||||||
gc.Current.scale = int32(gc.Current.FontSize * float64(gc.DPI) * (64.0 / 72.0))
|
gc.Current.Scale = int32(gc.Current.FontSize * float64(gc.DPI) * (64.0 / 72.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDPI sets the screen resolution in dots per inch.
|
// SetDPI sets the screen resolution in dots per inch.
|
||||||
func (gc *ImageGraphicContext) SetDPI(dpi int) {
|
func (gc *GraphicContext) SetDPI(dpi int) {
|
||||||
gc.DPI = dpi
|
gc.DPI = dpi
|
||||||
gc.recalc()
|
gc.recalc()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFont sets the font used to draw text.
|
// SetFont sets the font used to draw text.
|
||||||
func (gc *ImageGraphicContext) SetFont(font *truetype.Font) {
|
func (gc *GraphicContext) SetFont(font *truetype.Font) {
|
||||||
gc.Current.font = font
|
gc.Current.Font = font
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFontSize sets the font size in points (as in ``a 12 point font'').
|
// SetFontSize sets the font size in points (as in ``a 12 point font'').
|
||||||
func (gc *ImageGraphicContext) SetFontSize(fontSize float64) {
|
func (gc *GraphicContext) SetFontSize(fontSize float64) {
|
||||||
gc.Current.FontSize = fontSize
|
gc.Current.FontSize = fontSize
|
||||||
gc.recalc()
|
gc.recalc()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) paint(rasterizer *raster.Rasterizer, color color.Color) {
|
func (gc *GraphicContext) paint(rasterizer *raster.Rasterizer, color color.Color) {
|
||||||
gc.painter.SetColor(color)
|
gc.painter.SetColor(color)
|
||||||
rasterizer.Rasterize(gc.painter)
|
rasterizer.Rasterize(gc.painter)
|
||||||
rasterizer.Clear()
|
rasterizer.Clear()
|
||||||
gc.Current.Path.Clear()
|
gc.Current.Path.Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) Stroke(paths ...*path.Path) {
|
func (gc *GraphicContext) Stroke(paths ...*draw2d.Path) {
|
||||||
paths = append(paths, gc.Current.Path)
|
paths = append(paths, gc.Current.Path)
|
||||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||||
|
|
||||||
stroker := path.NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.strokeRasterizer)))
|
stroker := draw2dbase.NewLineStroker(gc.Current.Cap, gc.Current.Join, draw2d.Transformer{gc.Current.Tr, draw2dbase.FtLineBuilder{gc.strokeRasterizer}})
|
||||||
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
||||||
|
|
||||||
var liner path.LineBuilder
|
var liner draw2d.Flattener
|
||||||
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
||||||
liner = path.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
liner = draw2dbase.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
||||||
} else {
|
} else {
|
||||||
liner = stroker
|
liner = stroker
|
||||||
}
|
}
|
||||||
|
@ -295,12 +292,12 @@ func (gc *ImageGraphicContext) Stroke(paths ...*path.Path) {
|
||||||
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) Fill(paths ...*path.Path) {
|
func (gc *GraphicContext) Fill(paths ...*draw2d.Path) {
|
||||||
paths = append(paths, gc.Current.Path)
|
paths = append(paths, gc.Current.Path)
|
||||||
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
gc.fillRasterizer.UseNonZeroWinding = useNonZeroWinding(gc.Current.FillRule)
|
||||||
|
|
||||||
/**** first method ****/
|
/**** first method ****/
|
||||||
flattener := NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.fillRasterizer))
|
flattener := draw2d.Transformer{gc.Current.Tr, draw2dbase.FtLineBuilder{gc.fillRasterizer}}
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
p.Flatten(flattener, gc.Current.Tr.GetScale())
|
p.Flatten(flattener, gc.Current.Tr.GetScale())
|
||||||
}
|
}
|
||||||
|
@ -308,24 +305,24 @@ func (gc *ImageGraphicContext) Fill(paths ...*path.Path) {
|
||||||
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
|
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *ImageGraphicContext) FillStroke(paths ...*path.Path) {
|
func (gc *GraphicContext) FillStroke(paths ...*draw2d.Path) {
|
||||||
paths = append(paths, gc.Current.Path)
|
paths = append(paths, gc.Current.Path)
|
||||||
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
gc.fillRasterizer.UseNonZeroWinding = useNonZeroWinding(gc.Current.FillRule)
|
||||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||||
|
|
||||||
flattener := NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.fillRasterizer))
|
flattener := draw2d.Transformer{gc.Current.Tr, draw2dbase.FtLineBuilder{gc.fillRasterizer}}
|
||||||
|
|
||||||
stroker := path.NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.strokeRasterizer)))
|
stroker := draw2dbase.NewLineStroker(gc.Current.Cap, gc.Current.Join, draw2d.Transformer{gc.Current.Tr, draw2dbase.FtLineBuilder{gc.strokeRasterizer}})
|
||||||
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
||||||
|
|
||||||
var liner path.LineBuilder
|
var liner draw2d.Flattener
|
||||||
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
||||||
liner = path.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
liner = draw2dbase.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
||||||
} else {
|
} else {
|
||||||
liner = stroker
|
liner = stroker
|
||||||
}
|
}
|
||||||
|
|
||||||
demux := path.NewLineBuilders(flattener, liner)
|
demux := draw2dbase.DemuxFlattener{[]draw2d.Flattener{flattener, liner}}
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
p.Flatten(demux, gc.Current.Tr.GetScale())
|
p.Flatten(demux, gc.Current.Tr.GetScale())
|
||||||
}
|
}
|
||||||
|
@ -336,11 +333,11 @@ func (gc *ImageGraphicContext) FillStroke(paths ...*path.Path) {
|
||||||
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FillRule) UseNonZeroWinding() bool {
|
func useNonZeroWinding(f draw2d.FillRule) bool {
|
||||||
switch f {
|
switch f {
|
||||||
case FillRuleEvenOdd:
|
case draw2d.FillRuleEvenOdd:
|
||||||
return false
|
return false
|
||||||
case FillRuleWinding:
|
case draw2d.FillRuleWinding:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
|
@ -2,9 +2,10 @@
|
||||||
// created: 21/11/2010 by Laurent Le Goff
|
// created: 21/11/2010 by Laurent Le Goff
|
||||||
// see http://pippin.gimp.org/image_processing/chap_resampling.html
|
// see http://pippin.gimp.org/image_processing/chap_resampling.html
|
||||||
|
|
||||||
package draw2d
|
package draw2dimg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/llgcode/draw2d"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
|
@ -17,6 +18,7 @@ const (
|
||||||
LinearFilter ImageFilter = iota
|
LinearFilter ImageFilter = iota
|
||||||
BilinearFilter
|
BilinearFilter
|
||||||
BicubicFilter
|
BicubicFilter
|
||||||
|
M = 1<<16 - 1
|
||||||
)
|
)
|
||||||
|
|
||||||
//see http://pippin.gimp.org/image_processing/chap_resampling.html
|
//see http://pippin.gimp.org/image_processing/chap_resampling.html
|
||||||
|
@ -103,7 +105,7 @@ func cubic(offset, v0, v1, v2, v3 float64) uint32 {
|
||||||
(-9*v0+9*v2))*offset + (v0 + 16*v1 + v2)) / 18.0)
|
(-9*v0+9*v2))*offset + (v0 + 16*v1 + v2)) / 18.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DrawImage(src image.Image, dest draw.Image, tr MatrixTransform, op draw.Op, filter ImageFilter) {
|
func DrawImage(src image.Image, dest draw.Image, tr draw2d.MatrixTransform, op draw.Op, filter ImageFilter) {
|
||||||
bounds := src.Bounds()
|
bounds := src.Bounds()
|
||||||
x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Max.X), float64(bounds.Max.Y)
|
x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Max.X), float64(bounds.Max.Y)
|
||||||
tr.TransformRectangle(&x0, &y0, &x1, &y1)
|
tr.TransformRectangle(&x0, &y0, &x1, &y1)
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
// created: 13/12/2010 by Laurent Le Goff
|
// created: 13/12/2010 by Laurent Le Goff
|
||||||
|
|
||||||
package path
|
package draw2d
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
59
flattener.go
Normal file
59
flattener.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
|
// created: 06/12/2010 by Laurent Le Goff
|
||||||
|
|
||||||
|
package draw2d
|
||||||
|
|
||||||
|
// Flattener receive segment definition
|
||||||
|
type Flattener interface {
|
||||||
|
// MoveTo Start a New line from the point (x, y)
|
||||||
|
MoveTo(x, y float64)
|
||||||
|
// LineTo Draw a line from the current position to the point (x, y)
|
||||||
|
LineTo(x, y float64)
|
||||||
|
// LineJoin add the most recent starting point to close the path to create a polygon
|
||||||
|
LineJoin()
|
||||||
|
// Close add the most recent starting point to close the path to create a polygon
|
||||||
|
Close()
|
||||||
|
// End mark the current line as finished so we can draw caps
|
||||||
|
End()
|
||||||
|
}
|
||||||
|
|
||||||
|
type SegmentedPath struct {
|
||||||
|
Points []float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SegmentedPath) MoveTo(x, y float64) {
|
||||||
|
p.Points = append(p.Points, x, y)
|
||||||
|
// TODO need to mark this point as moveto
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SegmentedPath) LineTo(x, y float64) {
|
||||||
|
p.Points = append(p.Points, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SegmentedPath) LineJoin() {
|
||||||
|
// TODO need to mark the current point as linejoin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SegmentedPath) Close() {
|
||||||
|
// TODO Close
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SegmentedPath) End() {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineCap int
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoundCap LineCap = iota
|
||||||
|
ButtCap
|
||||||
|
SquareCap
|
||||||
|
)
|
||||||
|
|
||||||
|
type LineJoin int
|
||||||
|
|
||||||
|
const (
|
||||||
|
BevelJoin LineJoin = iota
|
||||||
|
RoundJoin
|
||||||
|
MiterJoin
|
||||||
|
)
|
13
gc.go
13
gc.go
|
@ -4,7 +4,6 @@
|
||||||
package draw2d
|
package draw2d
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/llgcode/draw2d/path"
|
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
)
|
)
|
||||||
|
@ -17,7 +16,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type GraphicContext interface {
|
type GraphicContext interface {
|
||||||
path.PathBuilder
|
PathBuilder
|
||||||
// Create a new path
|
// Create a new path
|
||||||
BeginPath()
|
BeginPath()
|
||||||
GetMatrixTransform() MatrixTransform
|
GetMatrixTransform() MatrixTransform
|
||||||
|
@ -30,8 +29,8 @@ type GraphicContext interface {
|
||||||
SetFillColor(c color.Color)
|
SetFillColor(c color.Color)
|
||||||
SetFillRule(f FillRule)
|
SetFillRule(f FillRule)
|
||||||
SetLineWidth(lineWidth float64)
|
SetLineWidth(lineWidth float64)
|
||||||
SetLineCap(cap path.Cap)
|
SetLineCap(cap LineCap)
|
||||||
SetLineJoin(join path.Join)
|
SetLineJoin(join LineJoin)
|
||||||
SetLineDash(dash []float64, dashOffset float64)
|
SetLineDash(dash []float64, dashOffset float64)
|
||||||
SetFontSize(fontSize float64)
|
SetFontSize(fontSize float64)
|
||||||
GetFontSize() float64
|
GetFontSize() float64
|
||||||
|
@ -50,7 +49,7 @@ type GraphicContext interface {
|
||||||
FillStringAt(text string, x, y float64) (cursor float64)
|
FillStringAt(text string, x, y float64) (cursor float64)
|
||||||
StrokeString(text string) (cursor float64)
|
StrokeString(text string) (cursor float64)
|
||||||
StrokeStringAt(text string, x, y float64) (cursor float64)
|
StrokeStringAt(text string, x, y float64) (cursor float64)
|
||||||
Stroke(paths ...*path.Path)
|
Stroke(paths ...*Path)
|
||||||
Fill(paths ...*path.Path)
|
Fill(paths ...*Path)
|
||||||
FillStroke(paths ...*path.Path)
|
FillStroke(paths ...*Path)
|
||||||
}
|
}
|
||||||
|
|
11
math.go
11
math.go
|
@ -1,11 +0,0 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
||||||
// created: 21/11/2010 by Laurent Le Goff
|
|
||||||
|
|
||||||
package draw2d
|
|
||||||
|
|
||||||
func minMax(x, y float64) (min, max float64) {
|
|
||||||
if x > y {
|
|
||||||
return y, x
|
|
||||||
}
|
|
||||||
return x, y
|
|
||||||
}
|
|
|
@ -2,11 +2,10 @@
|
||||||
// created: 21/11/2010 by Laurent Le Goff
|
// created: 21/11/2010 by Laurent Le Goff
|
||||||
|
|
||||||
// Package path implements function to build path
|
// Package path implements function to build path
|
||||||
package path
|
package draw2d
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/llgcode/draw2d/curve"
|
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -177,7 +176,7 @@ func (p *Path) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten convert curves in straight segments keeping join segements
|
// Flatten convert curves in straight segments keeping join segements
|
||||||
func (path *Path) Flatten(liner LineBuilder, scale float64) {
|
func (path *Path) Flatten(flattener Flattener, scale float64) {
|
||||||
// First Point
|
// First Point
|
||||||
var startX, startY float64 = 0, 0
|
var startX, startY float64 = 0, 0
|
||||||
// Current Point
|
// Current Point
|
||||||
|
@ -189,33 +188,33 @@ func (path *Path) Flatten(liner LineBuilder, scale float64) {
|
||||||
x, y = path.Points[i], path.Points[i+1]
|
x, y = path.Points[i], path.Points[i+1]
|
||||||
startX, startY = x, y
|
startX, startY = x, y
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
liner.End()
|
flattener.End()
|
||||||
}
|
}
|
||||||
liner.MoveTo(x, y)
|
flattener.MoveTo(x, y)
|
||||||
i += 2
|
i += 2
|
||||||
case LineToCmp:
|
case LineToCmp:
|
||||||
x, y = path.Points[i], path.Points[i+1]
|
x, y = path.Points[i], path.Points[i+1]
|
||||||
liner.LineTo(x, y)
|
flattener.LineTo(x, y)
|
||||||
liner.LineJoin()
|
flattener.LineJoin()
|
||||||
i += 2
|
i += 2
|
||||||
case QuadCurveToCmp:
|
case QuadCurveToCmp:
|
||||||
curve.TraceQuad(liner, path.Points[i-2:], 0.5)
|
TraceQuad(flattener, path.Points[i-2:], 0.5)
|
||||||
x, y = path.Points[i+2], path.Points[i+3]
|
x, y = path.Points[i+2], path.Points[i+3]
|
||||||
liner.LineTo(x, y)
|
flattener.LineTo(x, y)
|
||||||
i += 4
|
i += 4
|
||||||
case CubicCurveToCmp:
|
case CubicCurveToCmp:
|
||||||
curve.TraceCubic(liner, path.Points[i-2:], 0.5)
|
TraceCubic(flattener, path.Points[i-2:], 0.5)
|
||||||
x, y = path.Points[i+4], path.Points[i+5]
|
x, y = path.Points[i+4], path.Points[i+5]
|
||||||
liner.LineTo(x, y)
|
flattener.LineTo(x, y)
|
||||||
i += 6
|
i += 6
|
||||||
case ArcToCmp:
|
case ArcToCmp:
|
||||||
x, y = curve.TraceArc(liner, path.Points[i], path.Points[i+1], path.Points[i+2], path.Points[i+3], path.Points[i+4], path.Points[i+5], scale)
|
x, y = TraceArc(flattener, path.Points[i], path.Points[i+1], path.Points[i+2], path.Points[i+3], path.Points[i+4], path.Points[i+5], scale)
|
||||||
liner.LineTo(x, y)
|
flattener.LineTo(x, y)
|
||||||
i += 6
|
i += 6
|
||||||
case CloseCmp:
|
case CloseCmp:
|
||||||
liner.LineTo(startX, startY)
|
flattener.LineTo(startX, startY)
|
||||||
liner.Close()
|
flattener.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
liner.End()
|
flattener.End()
|
||||||
}
|
}
|
|
@ -1,56 +0,0 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
||||||
// created: 06/12/2010 by Laurent Le Goff
|
|
||||||
|
|
||||||
package path
|
|
||||||
|
|
||||||
// LineBuilder defines drawing line methods
|
|
||||||
type LineBuilder interface {
|
|
||||||
// MoveTo Start a New line from the point (x, y)
|
|
||||||
MoveTo(x, y float64)
|
|
||||||
// LineTo Draw a line from the current position to the point (x, y)
|
|
||||||
LineTo(x, y float64)
|
|
||||||
// LineJoin add the most recent starting point to close the path to create a polygon
|
|
||||||
LineJoin()
|
|
||||||
// Close add the most recent starting point to close the path to create a polygon
|
|
||||||
Close()
|
|
||||||
// End mark the current line as finished so we can draw caps
|
|
||||||
End()
|
|
||||||
}
|
|
||||||
|
|
||||||
type LineBuilders struct {
|
|
||||||
builders []LineBuilder
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLineBuilders(builders ...LineBuilder) *LineBuilders {
|
|
||||||
return &LineBuilders{builders}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dc *LineBuilders) MoveTo(x, y float64) {
|
|
||||||
for _, converter := range dc.builders {
|
|
||||||
converter.MoveTo(x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dc *LineBuilders) LineTo(x, y float64) {
|
|
||||||
for _, converter := range dc.builders {
|
|
||||||
converter.LineTo(x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dc *LineBuilders) LineJoin() {
|
|
||||||
for _, converter := range dc.builders {
|
|
||||||
converter.LineJoin()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dc *LineBuilders) Close() {
|
|
||||||
for _, converter := range dc.builders {
|
|
||||||
converter.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dc *LineBuilders) End() {
|
|
||||||
for _, converter := range dc.builders {
|
|
||||||
converter.End()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
||||||
// created: 13/12/2010 by Laurent Le Goff
|
|
||||||
|
|
||||||
package path
|
|
||||||
|
|
||||||
import (
|
|
||||||
"code.google.com/p/freetype-go/freetype/raster"
|
|
||||||
"github.com/llgcode/draw2d/curve"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FtLineBuilder struct {
|
|
||||||
adder raster.Adder
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFtLineBuilder(adder raster.Adder) *FtLineBuilder {
|
|
||||||
return &FtLineBuilder{adder}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (FtLineBuilder *FtLineBuilder) MoveTo(x, y float64) {
|
|
||||||
FtLineBuilder.adder.Start(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (FtLineBuilder *FtLineBuilder) LineTo(x, y float64) {
|
|
||||||
FtLineBuilder.adder.Add1(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (FtLineBuilder *FtLineBuilder) LineJoin() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (FtLineBuilder *FtLineBuilder) Close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (FtLineBuilder *FtLineBuilder) End() {
|
|
||||||
}
|
|
||||||
|
|
||||||
type PathAdder struct {
|
|
||||||
adder raster.Adder
|
|
||||||
firstPoint raster.Point
|
|
||||||
ApproximationScale float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPathAdder(adder raster.Adder) *PathAdder {
|
|
||||||
return &PathAdder{adder, raster.Point{0, 0}, 1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pathAdder *PathAdder) Convert(paths ...*Path) {
|
|
||||||
for _, apath := range paths {
|
|
||||||
j := 0
|
|
||||||
for _, cmd := range apath.Components {
|
|
||||||
switch cmd {
|
|
||||||
case MoveToCmp:
|
|
||||||
pathAdder.firstPoint = raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)}
|
|
||||||
pathAdder.adder.Start(pathAdder.firstPoint)
|
|
||||||
j += 2
|
|
||||||
case LineToCmp:
|
|
||||||
pathAdder.adder.Add1(raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)})
|
|
||||||
j += 2
|
|
||||||
case QuadCurveToCmp:
|
|
||||||
pathAdder.adder.Add2(raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)}, raster.Point{raster.Fix32(apath.Points[j+2] * 256), raster.Fix32(apath.Points[j+3] * 256)})
|
|
||||||
j += 4
|
|
||||||
case CubicCurveToCmp:
|
|
||||||
pathAdder.adder.Add3(raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)}, raster.Point{raster.Fix32(apath.Points[j+2] * 256), raster.Fix32(apath.Points[j+3] * 256)}, raster.Point{raster.Fix32(apath.Points[j+4] * 256), raster.Fix32(apath.Points[j+5] * 256)})
|
|
||||||
j += 6
|
|
||||||
case ArcToCmp:
|
|
||||||
lastPoint := curve.TraceArcFt(pathAdder.adder, apath.Points[j], apath.Points[j+1], apath.Points[j+2], apath.Points[j+3], apath.Points[j+4], apath.Points[j+5], pathAdder.ApproximationScale)
|
|
||||||
pathAdder.adder.Add1(lastPoint)
|
|
||||||
j += 6
|
|
||||||
case CloseCmp:
|
|
||||||
pathAdder.adder.Add1(pathAdder.firstPoint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package path
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
func distance(x1, y1, x2, y2 float64) float64 {
|
|
||||||
return vectorDistance(x2-x1, y2-y1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func vectorDistance(dx, dy float64) float64 {
|
|
||||||
return float64(math.Sqrt(dx*dx + dy*dy))
|
|
||||||
}
|
|
52
transform.go
52
transform.go
|
@ -7,7 +7,6 @@ import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"code.google.com/p/freetype-go/freetype/raster"
|
"code.google.com/p/freetype-go/freetype/raster"
|
||||||
"github.com/llgcode/draw2d/path"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type MatrixTransform [6]float64
|
type MatrixTransform [6]float64
|
||||||
|
@ -38,6 +37,13 @@ func (tr MatrixTransform) TransformArray(points []float64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func minMax(x, y float64) (min, max float64) {
|
||||||
|
if x > y {
|
||||||
|
return y, x
|
||||||
|
}
|
||||||
|
return x, y
|
||||||
|
}
|
||||||
|
|
||||||
func (tr MatrixTransform) TransformRectangle(x0, y0, x2, y2 *float64) {
|
func (tr MatrixTransform) TransformRectangle(x0, y0, x2, y2 *float64) {
|
||||||
x1 := *x2
|
x1 := *x2
|
||||||
y1 := *y0
|
y1 := *y0
|
||||||
|
@ -252,38 +258,34 @@ func fequals(float1, float2 float64) bool {
|
||||||
return math.Abs(float1-float2) <= epsilon
|
return math.Abs(float1-float2) <= epsilon
|
||||||
}
|
}
|
||||||
|
|
||||||
// this VertexConverter apply the Matrix transformation tr
|
// Transformer apply the Matrix transformation tr
|
||||||
type VertexMatrixTransform struct {
|
type Transformer struct {
|
||||||
tr MatrixTransform
|
Tr MatrixTransform
|
||||||
Next path.LineBuilder
|
Flattener Flattener
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVertexMatrixTransform(tr MatrixTransform, converter path.LineBuilder) *VertexMatrixTransform {
|
func (t Transformer) MoveTo(x, y float64) {
|
||||||
return &VertexMatrixTransform{tr, converter}
|
u := x*t.Tr[0] + y*t.Tr[2] + t.Tr[4]
|
||||||
|
v := x*t.Tr[1] + y*t.Tr[3] + t.Tr[5]
|
||||||
|
t.Flattener.MoveTo(u, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vmt *VertexMatrixTransform) MoveTo(x, y float64) {
|
func (t Transformer) LineTo(x, y float64) {
|
||||||
u := x*vmt.tr[0] + y*vmt.tr[2] + vmt.tr[4]
|
u := x*t.Tr[0] + y*t.Tr[2] + t.Tr[4]
|
||||||
v := x*vmt.tr[1] + y*vmt.tr[3] + vmt.tr[5]
|
v := x*t.Tr[1] + y*t.Tr[3] + t.Tr[5]
|
||||||
vmt.Next.MoveTo(u, v)
|
t.Flattener.LineTo(u, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vmt *VertexMatrixTransform) LineTo(x, y float64) {
|
func (t Transformer) LineJoin() {
|
||||||
u := x*vmt.tr[0] + y*vmt.tr[2] + vmt.tr[4]
|
t.Flattener.LineJoin()
|
||||||
v := x*vmt.tr[1] + y*vmt.tr[3] + vmt.tr[5]
|
|
||||||
vmt.Next.LineTo(u, v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vmt *VertexMatrixTransform) LineJoin() {
|
func (t Transformer) Close() {
|
||||||
vmt.Next.LineJoin()
|
t.Flattener.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vmt *VertexMatrixTransform) Close() {
|
func (t Transformer) End() {
|
||||||
vmt.Next.Close()
|
t.Flattener.End()
|
||||||
}
|
|
||||||
|
|
||||||
func (vmt *VertexMatrixTransform) End() {
|
|
||||||
vmt.Next.End()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this adder apply a Matrix transformation to points
|
// this adder apply a Matrix transformation to points
|
||||||
|
@ -292,10 +294,6 @@ type MatrixTransformAdder struct {
|
||||||
next raster.Adder
|
next raster.Adder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMatrixTransformAdder(tr MatrixTransform, adder raster.Adder) *MatrixTransformAdder {
|
|
||||||
return &MatrixTransformAdder{tr, adder}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start starts a new curve at the given point.
|
// Start starts a new curve at the given point.
|
||||||
func (mta MatrixTransformAdder) Start(a raster.Point) {
|
func (mta MatrixTransformAdder) Start(a raster.Point) {
|
||||||
mta.tr.TransformRasterPoint(&a)
|
mta.tr.TransformRasterPoint(&a)
|
||||||
|
|
Loading…
Reference in a new issue