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 (
|
||||
"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() {
|
||||
os.Mkdir("test_results", 0666)
|
||||
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) {
|
||||
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
||||
var p Path
|
||||
var p SegmentedPath
|
||||
p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
||||
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
||||
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, image.Black, p.points...)
|
||||
raster.PolylineBresenham(img, image.Black, p.Points...)
|
||||
//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)
|
||||
log.Printf("Num of points: %d\n", len(p.points))
|
||||
log.Printf("Num of points: %d\n", len(p.Points))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func TestQuadCurve(t *testing.T) {
|
||||
for i := 0; i < len(testsQuadFloat64); i += 6 {
|
||||
var p Path
|
||||
var p SegmentedPath
|
||||
p.MoveTo(testsQuadFloat64[i], testsQuadFloat64[i+1])
|
||||
TraceQuad(&p, testsQuadFloat64[i:], flattening_threshold)
|
||||
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, image.Black, p.points...)
|
||||
raster.PolylineBresenham(img, image.Black, p.Points...)
|
||||
//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)
|
||||
log.Printf("Num of points: %d\n", len(p.points))
|
||||
log.Printf("Num of points: %d\n", len(p.Points))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
@ -118,7 +106,7 @@ func TestQuadCurve(t *testing.T) {
|
|||
func BenchmarkCubicCurve(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
||||
var p Path
|
||||
var p SegmentedPath
|
||||
p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
||||
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
||||
}
|
|
@ -1,17 +1,21 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 13/12/2010 by Laurent Le Goff
|
||||
|
||||
package path
|
||||
package draw2dbase
|
||||
|
||||
import (
|
||||
"github.com/llgcode/draw2d"
|
||||
)
|
||||
|
||||
type DashVertexConverter struct {
|
||||
next LineBuilder
|
||||
next draw2d.Flattener
|
||||
x, y, distance float64
|
||||
dash []float64
|
||||
currentDash int
|
||||
dashOffset float64
|
||||
}
|
||||
|
||||
func NewDashConverter(dash []float64, dashOffset float64, converter LineBuilder) *DashVertexConverter {
|
||||
func NewDashConverter(dash []float64, dashOffset float64, converter draw2d.Flattener) *DashVertexConverter {
|
||||
var dasher DashVertexConverter
|
||||
dasher.dash = dash
|
||||
dasher.currentDash = 0
|
||||
|
@ -83,3 +87,7 @@ func (dasher *DashVertexConverter) lineTo(x, y float64) {
|
|||
}
|
||||
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.
|
||||
// created: 21/11/2010 by Laurent Le Goff
|
||||
|
||||
package draw2d
|
||||
package draw2dbase
|
||||
|
||||
import (
|
||||
"github.com/llgcode/draw2d/path"
|
||||
"github.com/llgcode/draw2d"
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype/truetype"
|
||||
)
|
||||
|
||||
var DefaultFontData = draw2d.FontData{"luxi", draw2d.FontFamilySans, draw2d.FontStyleNormal}
|
||||
|
||||
type StackGraphicContext struct {
|
||||
Current *ContextStack
|
||||
}
|
||||
|
||||
type ContextStack struct {
|
||||
Tr MatrixTransform
|
||||
Path *path.Path
|
||||
Tr draw2d.MatrixTransform
|
||||
Path *draw2d.Path
|
||||
LineWidth float64
|
||||
Dash []float64
|
||||
DashOffset float64
|
||||
StrokeColor color.Color
|
||||
FillColor color.Color
|
||||
FillRule FillRule
|
||||
Cap path.Cap
|
||||
Join path.Join
|
||||
FillRule draw2d.FillRule
|
||||
Cap draw2d.LineCap
|
||||
Join draw2d.LineJoin
|
||||
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
|
||||
// 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 {
|
||||
gc := &StackGraphicContext{}
|
||||
gc.Current = new(ContextStack)
|
||||
gc.Current.Tr = NewIdentityMatrix()
|
||||
gc.Current.Path = new(path.Path)
|
||||
gc.Current.Tr = draw2d.NewIdentityMatrix()
|
||||
gc.Current.Path = new(draw2d.Path)
|
||||
gc.Current.LineWidth = 1.0
|
||||
gc.Current.StrokeColor = image.Black
|
||||
gc.Current.FillColor = image.White
|
||||
gc.Current.Cap = path.RoundCap
|
||||
gc.Current.FillRule = FillRuleEvenOdd
|
||||
gc.Current.Join = path.RoundJoin
|
||||
gc.Current.Cap = draw2d.RoundCap
|
||||
gc.Current.FillRule = draw2d.FillRuleEvenOdd
|
||||
gc.Current.Join = draw2d.RoundJoin
|
||||
gc.Current.FontSize = 10
|
||||
gc.Current.FontData = defaultFontData
|
||||
gc.Current.FontData = DefaultFontData
|
||||
return gc
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) GetMatrixTransform() MatrixTransform {
|
||||
func (gc *StackGraphicContext) GetMatrixTransform() draw2d.MatrixTransform {
|
||||
return gc.Current.Tr
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) SetMatrixTransform(Tr MatrixTransform) {
|
||||
func (gc *StackGraphicContext) SetMatrixTransform(Tr draw2d.MatrixTransform) {
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
|
@ -88,40 +90,40 @@ func (gc *StackGraphicContext) SetFillColor(c color.Color) {
|
|||
gc.Current.FillColor = c
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) SetFillRule(f FillRule) {
|
||||
func (gc *StackGraphicContext) SetFillRule(f draw2d.FillRule) {
|
||||
gc.Current.FillRule = f
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) SetLineWidth(LineWidth float64) {
|
||||
gc.Current.LineWidth = LineWidth
|
||||
func (gc *StackGraphicContext) SetLineWidth(lineWidth float64) {
|
||||
gc.Current.LineWidth = lineWidth
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) SetLineCap(cap path.Cap) {
|
||||
func (gc *StackGraphicContext) SetLineCap(cap draw2d.LineCap) {
|
||||
gc.Current.Cap = cap
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) SetLineJoin(join path.Join) {
|
||||
func (gc *StackGraphicContext) SetLineJoin(join draw2d.LineJoin) {
|
||||
gc.Current.Join = join
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) SetLineDash(Dash []float64, DashOffset float64) {
|
||||
gc.Current.Dash = Dash
|
||||
gc.Current.DashOffset = DashOffset
|
||||
func (gc *StackGraphicContext) SetLineDash(dash []float64, dashOffset float64) {
|
||||
gc.Current.Dash = dash
|
||||
gc.Current.DashOffset = dashOffset
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) SetFontSize(FontSize float64) {
|
||||
gc.Current.FontSize = FontSize
|
||||
func (gc *StackGraphicContext) SetFontSize(fontSize float64) {
|
||||
gc.Current.FontSize = fontSize
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) GetFontSize() float64 {
|
||||
return gc.Current.FontSize
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) SetFontData(FontData FontData) {
|
||||
gc.Current.FontData = FontData
|
||||
func (gc *StackGraphicContext) SetFontData(fontData draw2d.FontData) {
|
||||
gc.Current.FontData = fontData
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) GetFontData() FontData {
|
||||
func (gc *StackGraphicContext) GetFontData() draw2d.FontData {
|
||||
return gc.Current.FontData
|
||||
}
|
||||
|
||||
|
@ -174,17 +176,17 @@ func (gc *StackGraphicContext) Save() {
|
|||
context.Cap = gc.Current.Cap
|
||||
context.Join = gc.Current.Join
|
||||
context.Path = gc.Current.Path.Copy()
|
||||
context.font = gc.Current.font
|
||||
context.scale = gc.Current.scale
|
||||
context.Font = gc.Current.Font
|
||||
context.Scale = gc.Current.Scale
|
||||
copy(context.Tr[:], gc.Current.Tr[:])
|
||||
context.previous = gc.Current
|
||||
context.Previous = gc.Current
|
||||
gc.Current = context
|
||||
}
|
||||
|
||||
func (gc *StackGraphicContext) Restore() {
|
||||
if gc.Current.previous != nil {
|
||||
if gc.Current.Previous != nil {
|
||||
oldContext := gc.Current
|
||||
gc.Current = gc.Current.previous
|
||||
oldContext.previous = nil
|
||||
gc.Current = gc.Current.Previous
|
||||
oldContext.Previous = nil
|
||||
}
|
||||
}
|
|
@ -1,66 +1,50 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 13/12/2010 by Laurent Le Goff
|
||||
|
||||
package path
|
||||
package draw2dbase
|
||||
|
||||
import (
|
||||
"code.google.com/p/freetype-go/freetype/raster"
|
||||
"github.com/llgcode/draw2d"
|
||||
"math"
|
||||
)
|
||||
|
||||
type Cap int
|
||||
|
||||
const (
|
||||
RoundCap Cap = iota
|
||||
ButtCap
|
||||
SquareCap
|
||||
)
|
||||
|
||||
func (c Cap) Convert() raster.Capper {
|
||||
func toFtCap(c draw2d.LineCap) raster.Capper {
|
||||
switch c {
|
||||
case RoundCap:
|
||||
case draw2d.RoundCap:
|
||||
return raster.RoundCapper
|
||||
case ButtCap:
|
||||
case draw2d.ButtCap:
|
||||
return raster.ButtCapper
|
||||
case SquareCap:
|
||||
case draw2d.SquareCap:
|
||||
return raster.SquareCapper
|
||||
}
|
||||
return raster.RoundCapper
|
||||
}
|
||||
|
||||
type Join int
|
||||
|
||||
const (
|
||||
BevelJoin Join = iota
|
||||
RoundJoin
|
||||
MiterJoin
|
||||
)
|
||||
|
||||
func (j Join) Convert() raster.Joiner {
|
||||
func toFtJoin(j draw2d.LineJoin) raster.Joiner {
|
||||
switch j {
|
||||
case RoundJoin:
|
||||
case draw2d.RoundJoin:
|
||||
return raster.RoundJoiner
|
||||
case BevelJoin:
|
||||
case draw2d.BevelJoin:
|
||||
return raster.BevelJoiner
|
||||
}
|
||||
return raster.RoundJoiner
|
||||
}
|
||||
|
||||
type LineStroker struct {
|
||||
Next LineBuilder
|
||||
Next draw2d.Flattener
|
||||
HalfLineWidth float64
|
||||
Cap Cap
|
||||
Join Join
|
||||
Cap draw2d.LineCap
|
||||
Join draw2d.LineJoin
|
||||
vertices []float64
|
||||
rewind []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.Next = converter
|
||||
l.Next = flattener
|
||||
l.HalfLineWidth = 0.5
|
||||
l.vertices = make([]float64, 0, 256)
|
||||
l.rewind = make([]float64, 0, 256)
|
||||
l.Cap = c
|
||||
l.Join = j
|
||||
return l
|
||||
|
@ -122,3 +106,7 @@ func (l *LineStroker) appendVertex(vertices ...float64) {
|
|||
l.vertices = append(l.vertices, 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"
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/path"
|
||||
"github.com/llgcode/draw2d/draw2dbase"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -113,7 +113,7 @@ func NewPainter() *Painter {
|
|||
}
|
||||
|
||||
type GraphicContext struct {
|
||||
*draw2d.StackGraphicContext
|
||||
*draw2dbase.StackGraphicContext
|
||||
painter *Painter
|
||||
fillRasterizer *raster.Rasterizer
|
||||
strokeRasterizer *raster.Rasterizer
|
||||
|
@ -122,7 +122,7 @@ type GraphicContext struct {
|
|||
// NewGraphicContext creates a new Graphic context from an image.
|
||||
func NewGraphicContext(width, height int) *GraphicContext {
|
||||
gc := &GraphicContext{
|
||||
draw2d.NewStackGraphicContext(),
|
||||
draw2dbase.NewStackGraphicContext(),
|
||||
NewPainter(),
|
||||
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()
|
||||
}
|
||||
|
||||
func (gc *GraphicContext) Stroke(paths ...*path.Path) {
|
||||
func (gc *GraphicContext) Stroke(paths ...*draw2d.Path) {
|
||||
paths = append(paths, gc.Current.Path)
|
||||
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
|
||||
|
||||
var liner path.LineBuilder
|
||||
var liner draw2d.Flattener
|
||||
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 {
|
||||
liner = stroker
|
||||
}
|
||||
|
||||
for _, p := range paths {
|
||||
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)
|
||||
}
|
||||
|
||||
func (gc *GraphicContext) Fill(paths ...*path.Path) {
|
||||
func (gc *GraphicContext) Fill(paths ...*draw2d.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 {
|
||||
p.Flatten(flattener, gc.Current.Tr.GetScale())
|
||||
}
|
||||
|
||||
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)
|
||||
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
||||
gc.fillRasterizer.UseNonZeroWinding = useNonZeroWinding(gc.Current.FillRule)
|
||||
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
|
||||
|
||||
var liner path.LineBuilder
|
||||
var liner draw2d.Flattener
|
||||
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 {
|
||||
liner = stroker
|
||||
}
|
||||
|
||||
demux := path.NewLineBuilders(flattener, liner)
|
||||
demux := draw2dbase.DemuxFlattener{[]draw2d.Flattener{flattener, liner}}
|
||||
for _, p := range paths {
|
||||
p.Flatten(demux, gc.Current.Tr.GetScale())
|
||||
}
|
||||
|
@ -245,3 +244,13 @@ func (gc *GraphicContext) FillStroke(paths ...*path.Path) {
|
|||
// Stroke
|
||||
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 (
|
||||
"bufio"
|
|
@ -1,11 +1,12 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 21/11/2010 by Laurent Le Goff
|
||||
|
||||
package draw2d
|
||||
package draw2dimg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/llgcode/draw2d/path"
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/draw2dbase"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
|
@ -21,12 +22,8 @@ type Painter interface {
|
|||
SetColor(color color.Color)
|
||||
}
|
||||
|
||||
var (
|
||||
defaultFontData = FontData{"luxi", FontFamilySans, FontStyleNormal}
|
||||
)
|
||||
|
||||
type ImageGraphicContext struct {
|
||||
*StackGraphicContext
|
||||
type GraphicContext struct {
|
||||
*draw2dbase.StackGraphicContext
|
||||
img draw.Image
|
||||
painter Painter
|
||||
fillRasterizer *raster.Rasterizer
|
||||
|
@ -38,7 +35,7 @@ type ImageGraphicContext struct {
|
|||
/**
|
||||
* Create a new Graphic context from an image
|
||||
*/
|
||||
func NewGraphicContext(img draw.Image) *ImageGraphicContext {
|
||||
func NewGraphicContext(img draw.Image) *GraphicContext {
|
||||
var painter Painter
|
||||
switch selectImage := img.(type) {
|
||||
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)
|
||||
func NewGraphicContextWithPainter(img draw.Image, painter Painter) *ImageGraphicContext {
|
||||
func NewGraphicContextWithPainter(img draw.Image, painter Painter) *GraphicContext {
|
||||
width, height := img.Bounds().Dx(), img.Bounds().Dy()
|
||||
dpi := 92
|
||||
gc := &ImageGraphicContext{
|
||||
NewStackGraphicContext(),
|
||||
gc := &GraphicContext{
|
||||
draw2dbase.NewStackGraphicContext(),
|
||||
img,
|
||||
painter,
|
||||
raster.NewRasterizer(width, height),
|
||||
|
@ -65,48 +62,48 @@ func NewGraphicContextWithPainter(img draw.Image, painter Painter) *ImageGraphic
|
|||
return gc
|
||||
}
|
||||
|
||||
func (gc *ImageGraphicContext) GetDPI() int {
|
||||
func (gc *GraphicContext) GetDPI() int {
|
||||
return gc.DPI
|
||||
}
|
||||
|
||||
func (gc *ImageGraphicContext) Clear() {
|
||||
func (gc *GraphicContext) Clear() {
|
||||
width, height := gc.img.Bounds().Dx(), gc.img.Bounds().Dy()
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
func (gc *ImageGraphicContext) FillString(text string) (cursor float64) {
|
||||
func (gc *GraphicContext) FillString(text string) (cursor float64) {
|
||||
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)
|
||||
gc.Fill()
|
||||
return width
|
||||
}
|
||||
|
||||
func (gc *ImageGraphicContext) StrokeString(text string) (cursor float64) {
|
||||
func (gc *GraphicContext) StrokeString(text string) (cursor float64) {
|
||||
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)
|
||||
gc.Stroke()
|
||||
return width
|
||||
}
|
||||
|
||||
func (gc *ImageGraphicContext) loadCurrentFont() (*truetype.Font, error) {
|
||||
font := GetFont(gc.Current.FontData)
|
||||
func (gc *GraphicContext) loadCurrentFont() (*truetype.Font, error) {
|
||||
font := draw2d.GetFont(gc.Current.FontData)
|
||||
if font == nil {
|
||||
font = GetFont(defaultFontData)
|
||||
font = draw2d.GetFont(draw2dbase.DefaultFontData)
|
||||
}
|
||||
if font == nil {
|
||||
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.
|
||||
func (gc *ImageGraphicContext) drawContour(ps []truetype.Point, dx, dy float64) {
|
||||
func (gc *GraphicContext) drawContour(ps []truetype.Point, dx, dy float64) {
|
||||
if len(ps) == 0 {
|
||||
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 {
|
||||
if err := gc.glyphBuf.Load(gc.Current.font, gc.Current.scale, glyph, truetype.NoHinting); err != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
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.
|
||||
// For example, drawing a string that starts with a 'J' in an italic font may
|
||||
// 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()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
@ -193,14 +190,14 @@ func (gc *ImageGraphicContext) CreateStringPath(s string, x, y float64) float64
|
|||
for _, rune := range s {
|
||||
index := font.Index(rune)
|
||||
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)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
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
|
||||
}
|
||||
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
|
||||
// and the baseline intersect at 0, 0 in the returned coordinates.
|
||||
// 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()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
@ -222,9 +219,9 @@ func (gc *ImageGraphicContext) GetStringBounds(s string) (left, top, right, bott
|
|||
for _, rune := range s {
|
||||
index := font.Index(rune)
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
cursor += fUnitsToFloat64(font.HMetric(gc.Current.scale, index).AdvanceWidth)
|
||||
cursor += fUnitsToFloat64(font.HMetric(gc.Current.Scale, index).AdvanceWidth)
|
||||
prev, hasPrev = index, true
|
||||
}
|
||||
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
|
||||
// resolution and font metrics, and invalidates the glyph cache.
|
||||
func (gc *ImageGraphicContext) recalc() {
|
||||
gc.Current.scale = int32(gc.Current.FontSize * float64(gc.DPI) * (64.0 / 72.0))
|
||||
func (gc *GraphicContext) recalc() {
|
||||
gc.Current.Scale = int32(gc.Current.FontSize * float64(gc.DPI) * (64.0 / 72.0))
|
||||
}
|
||||
|
||||
// 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.recalc()
|
||||
}
|
||||
|
||||
// SetFont sets the font used to draw text.
|
||||
func (gc *ImageGraphicContext) SetFont(font *truetype.Font) {
|
||||
gc.Current.font = font
|
||||
func (gc *GraphicContext) SetFont(font *truetype.Font) {
|
||||
gc.Current.Font = 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.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)
|
||||
rasterizer.Rasterize(gc.painter)
|
||||
rasterizer.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)
|
||||
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
|
||||
|
||||
var liner path.LineBuilder
|
||||
var liner draw2d.Flattener
|
||||
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 {
|
||||
liner = stroker
|
||||
}
|
||||
|
@ -295,12 +292,12 @@ func (gc *ImageGraphicContext) Stroke(paths ...*path.Path) {
|
|||
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)
|
||||
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
||||
gc.fillRasterizer.UseNonZeroWinding = useNonZeroWinding(gc.Current.FillRule)
|
||||
|
||||
/**** 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 {
|
||||
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)
|
||||
}
|
||||
|
||||
func (gc *ImageGraphicContext) FillStroke(paths ...*path.Path) {
|
||||
func (gc *GraphicContext) FillStroke(paths ...*draw2d.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
|
||||
|
||||
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
|
||||
|
||||
var liner path.LineBuilder
|
||||
var liner draw2d.Flattener
|
||||
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 {
|
||||
liner = stroker
|
||||
}
|
||||
|
||||
demux := path.NewLineBuilders(flattener, liner)
|
||||
demux := draw2dbase.DemuxFlattener{[]draw2d.Flattener{flattener, liner}}
|
||||
for _, p := range paths {
|
||||
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)
|
||||
}
|
||||
|
||||
func (f FillRule) UseNonZeroWinding() bool {
|
||||
func useNonZeroWinding(f draw2d.FillRule) bool {
|
||||
switch f {
|
||||
case FillRuleEvenOdd:
|
||||
case draw2d.FillRuleEvenOdd:
|
||||
return false
|
||||
case FillRuleWinding:
|
||||
case draw2d.FillRuleWinding:
|
||||
return true
|
||||
}
|
||||
return false
|
|
@ -2,9 +2,10 @@
|
|||
// created: 21/11/2010 by Laurent Le Goff
|
||||
// see http://pippin.gimp.org/image_processing/chap_resampling.html
|
||||
|
||||
package draw2d
|
||||
package draw2dimg
|
||||
|
||||
import (
|
||||
"github.com/llgcode/draw2d"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
|
@ -17,6 +18,7 @@ const (
|
|||
LinearFilter ImageFilter = iota
|
||||
BilinearFilter
|
||||
BicubicFilter
|
||||
M = 1<<16 - 1
|
||||
)
|
||||
|
||||
//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)
|
||||
}
|
||||
|
||||
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()
|
||||
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)
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 13/12/2010 by Laurent Le Goff
|
||||
|
||||
package path
|
||||
package draw2d
|
||||
|
||||
import (
|
||||
"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
|
||||
|
||||
import (
|
||||
"github.com/llgcode/draw2d/path"
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
@ -17,7 +16,7 @@ const (
|
|||
)
|
||||
|
||||
type GraphicContext interface {
|
||||
path.PathBuilder
|
||||
PathBuilder
|
||||
// Create a new path
|
||||
BeginPath()
|
||||
GetMatrixTransform() MatrixTransform
|
||||
|
@ -30,8 +29,8 @@ type GraphicContext interface {
|
|||
SetFillColor(c color.Color)
|
||||
SetFillRule(f FillRule)
|
||||
SetLineWidth(lineWidth float64)
|
||||
SetLineCap(cap path.Cap)
|
||||
SetLineJoin(join path.Join)
|
||||
SetLineCap(cap LineCap)
|
||||
SetLineJoin(join LineJoin)
|
||||
SetLineDash(dash []float64, dashOffset float64)
|
||||
SetFontSize(fontSize float64)
|
||||
GetFontSize() float64
|
||||
|
@ -50,7 +49,7 @@ type GraphicContext interface {
|
|||
FillStringAt(text string, x, y float64) (cursor float64)
|
||||
StrokeString(text string) (cursor float64)
|
||||
StrokeStringAt(text string, x, y float64) (cursor float64)
|
||||
Stroke(paths ...*path.Path)
|
||||
Fill(paths ...*path.Path)
|
||||
FillStroke(paths ...*path.Path)
|
||||
Stroke(paths ...*Path)
|
||||
Fill(paths ...*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
|
||||
|
||||
// Package path implements function to build path
|
||||
package path
|
||||
package draw2d
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/llgcode/draw2d/curve"
|
||||
"math"
|
||||
)
|
||||
|
||||
|
@ -177,7 +176,7 @@ func (p *Path) String() string {
|
|||
}
|
||||
|
||||
// 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
|
||||
var startX, startY float64 = 0, 0
|
||||
// Current Point
|
||||
|
@ -189,33 +188,33 @@ func (path *Path) Flatten(liner LineBuilder, scale float64) {
|
|||
x, y = path.Points[i], path.Points[i+1]
|
||||
startX, startY = x, y
|
||||
if i != 0 {
|
||||
liner.End()
|
||||
flattener.End()
|
||||
}
|
||||
liner.MoveTo(x, y)
|
||||
flattener.MoveTo(x, y)
|
||||
i += 2
|
||||
case LineToCmp:
|
||||
x, y = path.Points[i], path.Points[i+1]
|
||||
liner.LineTo(x, y)
|
||||
liner.LineJoin()
|
||||
flattener.LineTo(x, y)
|
||||
flattener.LineJoin()
|
||||
i += 2
|
||||
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]
|
||||
liner.LineTo(x, y)
|
||||
flattener.LineTo(x, y)
|
||||
i += 4
|
||||
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]
|
||||
liner.LineTo(x, y)
|
||||
flattener.LineTo(x, y)
|
||||
i += 6
|
||||
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)
|
||||
liner.LineTo(x, y)
|
||||
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)
|
||||
flattener.LineTo(x, y)
|
||||
i += 6
|
||||
case CloseCmp:
|
||||
liner.LineTo(startX, startY)
|
||||
liner.Close()
|
||||
flattener.LineTo(startX, startY)
|
||||
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"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype/raster"
|
||||
"github.com/llgcode/draw2d/path"
|
||||
)
|
||||
|
||||
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) {
|
||||
x1 := *x2
|
||||
y1 := *y0
|
||||
|
@ -252,38 +258,34 @@ func fequals(float1, float2 float64) bool {
|
|||
return math.Abs(float1-float2) <= epsilon
|
||||
}
|
||||
|
||||
// this VertexConverter apply the Matrix transformation tr
|
||||
type VertexMatrixTransform struct {
|
||||
tr MatrixTransform
|
||||
Next path.LineBuilder
|
||||
// Transformer apply the Matrix transformation tr
|
||||
type Transformer struct {
|
||||
Tr MatrixTransform
|
||||
Flattener Flattener
|
||||
}
|
||||
|
||||
func NewVertexMatrixTransform(tr MatrixTransform, converter path.LineBuilder) *VertexMatrixTransform {
|
||||
return &VertexMatrixTransform{tr, converter}
|
||||
func (t Transformer) MoveTo(x, y float64) {
|
||||
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) {
|
||||
u := x*vmt.tr[0] + y*vmt.tr[2] + vmt.tr[4]
|
||||
v := x*vmt.tr[1] + y*vmt.tr[3] + vmt.tr[5]
|
||||
vmt.Next.MoveTo(u, v)
|
||||
func (t Transformer) LineTo(x, y float64) {
|
||||
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.LineTo(u, v)
|
||||
}
|
||||
|
||||
func (vmt *VertexMatrixTransform) LineTo(x, y float64) {
|
||||
u := x*vmt.tr[0] + y*vmt.tr[2] + vmt.tr[4]
|
||||
v := x*vmt.tr[1] + y*vmt.tr[3] + vmt.tr[5]
|
||||
vmt.Next.LineTo(u, v)
|
||||
func (t Transformer) LineJoin() {
|
||||
t.Flattener.LineJoin()
|
||||
}
|
||||
|
||||
func (vmt *VertexMatrixTransform) LineJoin() {
|
||||
vmt.Next.LineJoin()
|
||||
func (t Transformer) Close() {
|
||||
t.Flattener.Close()
|
||||
}
|
||||
|
||||
func (vmt *VertexMatrixTransform) Close() {
|
||||
vmt.Next.Close()
|
||||
}
|
||||
|
||||
func (vmt *VertexMatrixTransform) End() {
|
||||
vmt.Next.End()
|
||||
func (t Transformer) End() {
|
||||
t.Flattener.End()
|
||||
}
|
||||
|
||||
// this adder apply a Matrix transformation to points
|
||||
|
@ -292,10 +294,6 @@ type MatrixTransformAdder struct {
|
|||
next raster.Adder
|
||||
}
|
||||
|
||||
func NewMatrixTransformAdder(tr MatrixTransform, adder raster.Adder) *MatrixTransformAdder {
|
||||
return &MatrixTransformAdder{tr, adder}
|
||||
}
|
||||
|
||||
// Start starts a new curve at the given point.
|
||||
func (mta MatrixTransformAdder) Start(a raster.Point) {
|
||||
mta.tr.TransformRasterPoint(&a)
|
||||
|
|
Loading…
Reference in a new issue