aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/llgcode/draw2d/draw2dbase
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/llgcode/draw2d/draw2dbase')
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/README.md7
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/curve.go161
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/curve_test.go134
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/dasher.go89
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/demux_flattener.go35
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/flattener.go127
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/line.go58
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/stack_gc.go203
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/stroker.go90
-rw-r--r--vendor/github.com/llgcode/draw2d/draw2dbase/text.go68
10 files changed, 972 insertions, 0 deletions
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/README.md b/vendor/github.com/llgcode/draw2d/draw2dbase/README.md
new file mode 100644
index 0000000..3296f5e
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/README.md
@@ -0,0 +1,7 @@
+draw2d/draw2dbase
+=================
+
+[![Coverage](http://gocover.io/_badge/github.com/llgcode/draw2d/draw2dbase?0)](http://gocover.io/github.com/llgcode/draw2d/draw2dbase)
+[![GoDoc](https://godoc.org/github.com/llgcode/draw2d/draw2dbase?status.svg)](https://godoc.org/github.com/llgcode/draw2d/draw2dbase)
+
+Base package implementation that is used by pdf, svg, img, gl implementations.
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/curve.go b/vendor/github.com/llgcode/draw2d/draw2dbase/curve.go
new file mode 100644
index 0000000..211e107
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/curve.go
@@ -0,0 +1,161 @@
+// Copyright 2010 The draw2d Authors. All rights reserved.
+// created: 17/05/2011 by Laurent Le Goff
+
+package draw2dbase
+
+import (
+ "math"
+)
+
+const (
+ // CurveRecursionLimit represents the maximum recursion that is really necessary to subsivide a curve into straight lines
+ CurveRecursionLimit = 32
+)
+
+// Cubic
+// x1, y1, cpx1, cpy1, cpx2, cpy2, x2, y2 float64
+
+// SubdivideCubic 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 Liner
+// flattening_threshold helps determines the flattening expectation of the curve
+func TraceCubic(t Liner, cubic []float64, flatteningThreshold 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) < flatteningThreshold*(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
+
+// SubdivideQuad 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
+}
+
+// TraceQuad generate lines subdividing the curve using a Liner
+// flattening_threshold helps determines the flattening expectation of the curve
+func TraceQuad(t Liner, quad []float64, flatteningThreshold 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) < flatteningThreshold*(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 Liner
+func TraceArc(t Liner, 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)
+ }
+}
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/curve_test.go b/vendor/github.com/llgcode/draw2d/draw2dbase/curve_test.go
new file mode 100644
index 0000000..fa954df
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/curve_test.go
@@ -0,0 +1,134 @@
+package draw2dbase
+
+import (
+ "bufio"
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "image/png"
+ "log"
+ "os"
+ "testing"
+)
+
+var (
+ flatteningThreshold = 0.5
+ testsCubicFloat64 = []float64{
+ 100, 100, 200, 100, 100, 200, 200, 200,
+ 100, 100, 300, 200, 200, 200, 300, 100,
+ 100, 100, 0, 300, 200, 0, 300, 300,
+ 150, 290, 10, 10, 290, 10, 150, 290,
+ 10, 290, 10, 10, 290, 10, 290, 290,
+ 100, 290, 290, 10, 10, 10, 200, 290,
+ }
+ testsQuadFloat64 = []float64{
+ 100, 100, 200, 100, 200, 200,
+ 100, 100, 290, 200, 290, 100,
+ 100, 100, 0, 290, 200, 290,
+ 150, 290, 10, 10, 290, 290,
+ 10, 290, 10, 10, 290, 290,
+ 100, 290, 290, 10, 120, 290,
+ }
+)
+
+func init() {
+ os.Mkdir("test_results", 0666)
+ f, err := os.Create("../output/curve/_test.html")
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ defer f.Close()
+ log.Printf("Create html viewer")
+ f.Write([]byte("<html><body>"))
+ for i := 0; i < len(testsCubicFloat64)/8; i++ {
+ f.Write([]byte(fmt.Sprintf("<div><img src='_test%d.png'/></div>\n", i)))
+ }
+ for i := 0; i < len(testsQuadFloat64); i++ {
+ f.Write([]byte(fmt.Sprintf("<div><img src='_testQuad%d.png'/>\n</div>\n", i)))
+ }
+ f.Write([]byte("</body></html>"))
+
+}
+
+func drawPoints(img draw.Image, c color.Color, s ...float64) image.Image {
+ for i := 0; i < len(s); i += 2 {
+ x, y := int(s[i]+0.5), int(s[i+1]+0.5)
+ img.Set(x, y, c)
+ img.Set(x, y+1, c)
+ img.Set(x, y-1, c)
+ img.Set(x+1, y, c)
+ img.Set(x+1, y+1, c)
+ img.Set(x+1, y-1, c)
+ img.Set(x-1, y, c)
+ img.Set(x-1, y+1, c)
+ img.Set(x-1, y-1, c)
+
+ }
+ return img
+}
+
+func TestCubicCurve(t *testing.T) {
+ for i := 0; i < len(testsCubicFloat64); i += 8 {
+ var p SegmentedPath
+ p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
+ TraceCubic(&p, testsCubicFloat64[i:], flatteningThreshold)
+ img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
+ PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsCubicFloat64[i:i+8]...)
+ 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...)
+ SaveToPngFile(fmt.Sprintf("../output/curve/_test%d.png", i/8), img)
+ 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 SegmentedPath
+ p.MoveTo(testsQuadFloat64[i], testsQuadFloat64[i+1])
+ TraceQuad(&p, testsQuadFloat64[i:], flatteningThreshold)
+ img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
+ PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsQuadFloat64[i:i+6]...)
+ 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...)
+ SaveToPngFile(fmt.Sprintf("../output/curve/_testQuad%d.png", i), img)
+ log.Printf("Num of points: %d\n", len(p.Points))
+ }
+ fmt.Println()
+}
+
+func BenchmarkCubicCurve(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for i := 0; i < len(testsCubicFloat64); i += 8 {
+ var p SegmentedPath
+ p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
+ TraceCubic(&p, testsCubicFloat64[i:], flatteningThreshold)
+ }
+ }
+}
+
+// SaveToPngFile create and save an image to a file using PNG format
+func SaveToPngFile(filePath string, m image.Image) error {
+ // Create the file
+ f, err := os.Create(filePath)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ // Create Writer from file
+ b := bufio.NewWriter(f)
+ // Write the image into the buffer
+ err = png.Encode(b, m)
+ if err != nil {
+ return err
+ }
+ err = b.Flush()
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/dasher.go b/vendor/github.com/llgcode/draw2d/draw2dbase/dasher.go
new file mode 100644
index 0000000..6f8260c
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/dasher.go
@@ -0,0 +1,89 @@
+// Copyright 2010 The draw2d Authors. All rights reserved.
+// created: 13/12/2010 by Laurent Le Goff
+
+package draw2dbase
+
+type DashVertexConverter struct {
+ next Flattener
+ x, y, distance float64
+ dash []float64
+ currentDash int
+ dashOffset float64
+}
+
+func NewDashConverter(dash []float64, dashOffset float64, flattener Flattener) *DashVertexConverter {
+ var dasher DashVertexConverter
+ dasher.dash = dash
+ dasher.currentDash = 0
+ dasher.dashOffset = dashOffset
+ dasher.next = flattener
+ return &dasher
+}
+
+func (dasher *DashVertexConverter) LineTo(x, y float64) {
+ dasher.lineTo(x, y)
+}
+
+func (dasher *DashVertexConverter) MoveTo(x, y float64) {
+ dasher.next.MoveTo(x, y)
+ dasher.x, dasher.y = x, y
+ dasher.distance = dasher.dashOffset
+ dasher.currentDash = 0
+}
+
+func (dasher *DashVertexConverter) LineJoin() {
+ dasher.next.LineJoin()
+}
+
+func (dasher *DashVertexConverter) Close() {
+ dasher.next.Close()
+}
+
+func (dasher *DashVertexConverter) End() {
+ dasher.next.End()
+}
+
+func (dasher *DashVertexConverter) lineTo(x, y float64) {
+ rest := dasher.dash[dasher.currentDash] - dasher.distance
+ for rest < 0 {
+ dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
+ dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
+ rest = dasher.dash[dasher.currentDash] - dasher.distance
+ }
+ d := distance(dasher.x, dasher.y, x, y)
+ for d >= rest {
+ k := rest / d
+ lx := dasher.x + k*(x-dasher.x)
+ ly := dasher.y + k*(y-dasher.y)
+ if dasher.currentDash%2 == 0 {
+ // line
+ dasher.next.LineTo(lx, ly)
+ } else {
+ // gap
+ dasher.next.End()
+ dasher.next.MoveTo(lx, ly)
+ }
+ d = d - rest
+ dasher.x, dasher.y = lx, ly
+ dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
+ rest = dasher.dash[dasher.currentDash]
+ }
+ dasher.distance = d
+ if dasher.currentDash%2 == 0 {
+ // line
+ dasher.next.LineTo(x, y)
+ } else {
+ // gap
+ dasher.next.End()
+ dasher.next.MoveTo(x, y)
+ }
+ if dasher.distance >= dasher.dash[dasher.currentDash] {
+ dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
+ dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
+ }
+ dasher.x, dasher.y = x, y
+}
+
+func distance(x1, y1, x2, y2 float64) float64 {
+ return vectorDistance(x2-x1, y2-y1)
+}
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/demux_flattener.go b/vendor/github.com/llgcode/draw2d/draw2dbase/demux_flattener.go
new file mode 100644
index 0000000..13b6c40
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/demux_flattener.go
@@ -0,0 +1,35 @@
+package draw2dbase
+
+type DemuxFlattener struct {
+ Flatteners []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()
+ }
+}
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/flattener.go b/vendor/github.com/llgcode/draw2d/draw2dbase/flattener.go
new file mode 100644
index 0000000..c62d1bc
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/flattener.go
@@ -0,0 +1,127 @@
+// Copyright 2010 The draw2d Authors. All rights reserved.
+// created: 06/12/2010 by Laurent Le Goff
+
+package draw2dbase
+
+import (
+ "github.com/llgcode/draw2d"
+)
+
+// Liner receive segment definition
+type Liner interface {
+ // LineTo Draw a line from the current position to the point (x, y)
+ LineTo(x, y float64)
+}
+
+// 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 use Round, Bevel or miter to join points
+ 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()
+}
+
+// Flatten convert curves into straight segments keeping join segments info
+func Flatten(path *draw2d.Path, flattener Flattener, scale float64) {
+ // First Point
+ var startX, startY float64 = 0, 0
+ // Current Point
+ var x, y float64 = 0, 0
+ i := 0
+ for _, cmp := range path.Components {
+ switch cmp {
+ case draw2d.MoveToCmp:
+ x, y = path.Points[i], path.Points[i+1]
+ startX, startY = x, y
+ if i != 0 {
+ flattener.End()
+ }
+ flattener.MoveTo(x, y)
+ i += 2
+ case draw2d.LineToCmp:
+ x, y = path.Points[i], path.Points[i+1]
+ flattener.LineTo(x, y)
+ flattener.LineJoin()
+ i += 2
+ case draw2d.QuadCurveToCmp:
+ TraceQuad(flattener, path.Points[i-2:], 0.5)
+ x, y = path.Points[i+2], path.Points[i+3]
+ flattener.LineTo(x, y)
+ i += 4
+ case draw2d.CubicCurveToCmp:
+ TraceCubic(flattener, path.Points[i-2:], 0.5)
+ x, y = path.Points[i+4], path.Points[i+5]
+ flattener.LineTo(x, y)
+ i += 6
+ case draw2d.ArcToCmp:
+ 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 draw2d.CloseCmp:
+ flattener.LineTo(startX, startY)
+ flattener.Close()
+ }
+ }
+ flattener.End()
+}
+
+// Transformer apply the Matrix transformation tr
+type Transformer struct {
+ Tr draw2d.Matrix
+ Flattener Flattener
+}
+
+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 (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 (t Transformer) LineJoin() {
+ t.Flattener.LineJoin()
+}
+
+func (t Transformer) Close() {
+ t.Flattener.Close()
+}
+
+func (t Transformer) End() {
+ t.Flattener.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
+}
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/line.go b/vendor/github.com/llgcode/draw2d/draw2dbase/line.go
new file mode 100644
index 0000000..a83bbc3
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/line.go
@@ -0,0 +1,58 @@
+// Copyright 2011 The draw2d Authors. All rights reserved.
+// created: 27/05/2011 by Laurent Le Goff
+
+package draw2dbase
+
+import (
+ "image/color"
+ "image/draw"
+)
+
+func abs(i int) int {
+ if i < 0 {
+ return -i
+ }
+ return i
+}
+
+// PolylineBresenham draws a polyline to an image
+func PolylineBresenham(img draw.Image, c color.Color, s ...float64) {
+ for i := 2; i < len(s); i += 2 {
+ Bresenham(img, c, int(s[i-2]+0.5), int(s[i-1]+0.5), int(s[i]+0.5), int(s[i+1]+0.5))
+ }
+}
+
+// Bresenham draws a line between (x0, y0) and (x1, y1)
+func Bresenham(img draw.Image, color color.Color, x0, y0, x1, y1 int) {
+ dx := abs(x1 - x0)
+ dy := abs(y1 - y0)
+ var sx, sy int
+ if x0 < x1 {
+ sx = 1
+ } else {
+ sx = -1
+ }
+ if y0 < y1 {
+ sy = 1
+ } else {
+ sy = -1
+ }
+ err := dx - dy
+
+ var e2 int
+ for {
+ img.Set(x0, y0, color)
+ if x0 == x1 && y0 == y1 {
+ return
+ }
+ e2 = 2 * err
+ if e2 > -dy {
+ err = err - dy
+ x0 = x0 + sx
+ }
+ if e2 < dx {
+ err = err + dx
+ y0 = y0 + sy
+ }
+ }
+}
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/stack_gc.go b/vendor/github.com/llgcode/draw2d/draw2dbase/stack_gc.go
new file mode 100644
index 0000000..77622bb
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/stack_gc.go
@@ -0,0 +1,203 @@
+// Copyright 2010 The draw2d Authors. All rights reserved.
+// created: 21/11/2010 by Laurent Le Goff
+
+package draw2dbase
+
+import (
+ "fmt"
+ "image"
+ "image/color"
+
+ "github.com/llgcode/draw2d"
+
+ "github.com/golang/freetype/truetype"
+)
+
+var DefaultFontData = draw2d.FontData{Name: "luxi", Family: draw2d.FontFamilySans, Style: draw2d.FontStyleNormal}
+
+type StackGraphicContext struct {
+ Current *ContextStack
+}
+
+type ContextStack struct {
+ Tr draw2d.Matrix
+ Path *draw2d.Path
+ LineWidth float64
+ Dash []float64
+ DashOffset float64
+ StrokeColor color.Color
+ FillColor color.Color
+ FillRule draw2d.FillRule
+ Cap draw2d.LineCap
+ Join draw2d.LineJoin
+ FontSize float64
+ FontData draw2d.FontData
+
+ 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 float64
+
+ Previous *ContextStack
+}
+
+/**
+ * Create a new Graphic context from an image
+ */
+func NewStackGraphicContext() *StackGraphicContext {
+ gc := &StackGraphicContext{}
+ gc.Current = new(ContextStack)
+ 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 = draw2d.RoundCap
+ gc.Current.FillRule = draw2d.FillRuleEvenOdd
+ gc.Current.Join = draw2d.RoundJoin
+ gc.Current.FontSize = 10
+ gc.Current.FontData = DefaultFontData
+ return gc
+}
+
+func (gc *StackGraphicContext) GetMatrixTransform() draw2d.Matrix {
+ return gc.Current.Tr
+}
+
+func (gc *StackGraphicContext) SetMatrixTransform(Tr draw2d.Matrix) {
+ gc.Current.Tr = Tr
+}
+
+func (gc *StackGraphicContext) ComposeMatrixTransform(Tr draw2d.Matrix) {
+ gc.Current.Tr.Compose(Tr)
+}
+
+func (gc *StackGraphicContext) Rotate(angle float64) {
+ gc.Current.Tr.Rotate(angle)
+}
+
+func (gc *StackGraphicContext) Translate(tx, ty float64) {
+ gc.Current.Tr.Translate(tx, ty)
+}
+
+func (gc *StackGraphicContext) Scale(sx, sy float64) {
+ gc.Current.Tr.Scale(sx, sy)
+}
+
+func (gc *StackGraphicContext) SetStrokeColor(c color.Color) {
+ gc.Current.StrokeColor = c
+}
+
+func (gc *StackGraphicContext) SetFillColor(c color.Color) {
+ gc.Current.FillColor = c
+}
+
+func (gc *StackGraphicContext) SetFillRule(f draw2d.FillRule) {
+ gc.Current.FillRule = f
+}
+
+func (gc *StackGraphicContext) SetLineWidth(lineWidth float64) {
+ gc.Current.LineWidth = lineWidth
+}
+
+func (gc *StackGraphicContext) SetLineCap(cap draw2d.LineCap) {
+ gc.Current.Cap = cap
+}
+
+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) SetFontSize(fontSize float64) {
+ gc.Current.FontSize = fontSize
+}
+
+func (gc *StackGraphicContext) GetFontSize() float64 {
+ return gc.Current.FontSize
+}
+
+func (gc *StackGraphicContext) SetFontData(fontData draw2d.FontData) {
+ gc.Current.FontData = fontData
+}
+
+func (gc *StackGraphicContext) GetFontData() draw2d.FontData {
+ return gc.Current.FontData
+}
+
+func (gc *StackGraphicContext) BeginPath() {
+ gc.Current.Path.Clear()
+}
+
+func (gc *StackGraphicContext) GetPath() draw2d.Path {
+ return *gc.Current.Path.Copy()
+}
+
+func (gc *StackGraphicContext) IsEmpty() bool {
+ return gc.Current.Path.IsEmpty()
+}
+
+func (gc *StackGraphicContext) LastPoint() (float64, float64) {
+ return gc.Current.Path.LastPoint()
+}
+
+func (gc *StackGraphicContext) MoveTo(x, y float64) {
+ gc.Current.Path.MoveTo(x, y)
+}
+
+func (gc *StackGraphicContext) LineTo(x, y float64) {
+ gc.Current.Path.LineTo(x, y)
+}
+
+func (gc *StackGraphicContext) QuadCurveTo(cx, cy, x, y float64) {
+ gc.Current.Path.QuadCurveTo(cx, cy, x, y)
+}
+
+func (gc *StackGraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) {
+ gc.Current.Path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y)
+}
+
+func (gc *StackGraphicContext) ArcTo(cx, cy, rx, ry, startAngle, angle float64) {
+ gc.Current.Path.ArcTo(cx, cy, rx, ry, startAngle, angle)
+}
+
+func (gc *StackGraphicContext) Close() {
+ gc.Current.Path.Close()
+}
+
+func (gc *StackGraphicContext) Save() {
+ context := new(ContextStack)
+ context.FontSize = gc.Current.FontSize
+ context.FontData = gc.Current.FontData
+ context.LineWidth = gc.Current.LineWidth
+ context.StrokeColor = gc.Current.StrokeColor
+ context.FillColor = gc.Current.FillColor
+ context.FillRule = gc.Current.FillRule
+ context.Dash = gc.Current.Dash
+ context.DashOffset = gc.Current.DashOffset
+ 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
+ copy(context.Tr[:], gc.Current.Tr[:])
+ context.Previous = gc.Current
+ gc.Current = context
+}
+
+func (gc *StackGraphicContext) Restore() {
+ if gc.Current.Previous != nil {
+ oldContext := gc.Current
+ gc.Current = gc.Current.Previous
+ oldContext.Previous = nil
+ }
+}
+
+func (gc *StackGraphicContext) GetFontName() string {
+ fontData := gc.Current.FontData
+ return fmt.Sprintf("%s:%d:%d:%d", fontData.Name, fontData.Family, fontData.Style, gc.Current.FontSize)
+}
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/stroker.go b/vendor/github.com/llgcode/draw2d/draw2dbase/stroker.go
new file mode 100644
index 0000000..640b228
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/stroker.go
@@ -0,0 +1,90 @@
+// Copyright 2010 The draw2d Authors. All rights reserved.
+// created: 13/12/2010 by Laurent Le Goff
+
+package draw2dbase
+
+import (
+ "math"
+
+ "github.com/llgcode/draw2d"
+)
+
+type LineStroker struct {
+ Flattener Flattener
+ HalfLineWidth float64
+ Cap draw2d.LineCap
+ Join draw2d.LineJoin
+ vertices []float64
+ rewind []float64
+ x, y, nx, ny float64
+}
+
+func NewLineStroker(c draw2d.LineCap, j draw2d.LineJoin, flattener Flattener) *LineStroker {
+ l := new(LineStroker)
+ l.Flattener = flattener
+ l.HalfLineWidth = 0.5
+ l.Cap = c
+ l.Join = j
+ return l
+}
+
+func (l *LineStroker) MoveTo(x, y float64) {
+ l.x, l.y = x, y
+}
+
+func (l *LineStroker) LineTo(x, y float64) {
+ l.line(l.x, l.y, x, y)
+}
+
+func (l *LineStroker) LineJoin() {
+
+}
+
+func (l *LineStroker) line(x1, y1, x2, y2 float64) {
+ dx := (x2 - x1)
+ dy := (y2 - y1)
+ d := vectorDistance(dx, dy)
+ if d != 0 {
+ nx := dy * l.HalfLineWidth / d
+ ny := -(dx * l.HalfLineWidth / d)
+ l.appendVertex(x1+nx, y1+ny, x2+nx, y2+ny, x1-nx, y1-ny, x2-nx, y2-ny)
+ l.x, l.y, l.nx, l.ny = x2, y2, nx, ny
+ }
+}
+
+func (l *LineStroker) Close() {
+ if len(l.vertices) > 1 {
+ l.appendVertex(l.vertices[0], l.vertices[1], l.rewind[0], l.rewind[1])
+ }
+}
+
+func (l *LineStroker) End() {
+ if len(l.vertices) > 1 {
+ l.Flattener.MoveTo(l.vertices[0], l.vertices[1])
+ for i, j := 2, 3; j < len(l.vertices); i, j = i+2, j+2 {
+ l.Flattener.LineTo(l.vertices[i], l.vertices[j])
+ }
+ }
+ for i, j := len(l.rewind)-2, len(l.rewind)-1; j > 0; i, j = i-2, j-2 {
+ l.Flattener.LineTo(l.rewind[i], l.rewind[j])
+ }
+ if len(l.vertices) > 1 {
+ l.Flattener.LineTo(l.vertices[0], l.vertices[1])
+ }
+ l.Flattener.End()
+ // reinit vertices
+ l.vertices = l.vertices[0:0]
+ l.rewind = l.rewind[0:0]
+ l.x, l.y, l.nx, l.ny = 0, 0, 0, 0
+
+}
+
+func (l *LineStroker) appendVertex(vertices ...float64) {
+ s := len(vertices) / 2
+ 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))
+}
diff --git a/vendor/github.com/llgcode/draw2d/draw2dbase/text.go b/vendor/github.com/llgcode/draw2d/draw2dbase/text.go
new file mode 100644
index 0000000..4283bad
--- /dev/null
+++ b/vendor/github.com/llgcode/draw2d/draw2dbase/text.go
@@ -0,0 +1,68 @@
+package draw2dbase
+
+import "github.com/llgcode/draw2d"
+
+var glyphCache map[string]map[rune]*Glyph
+
+func init() {
+ glyphCache = make(map[string]map[rune]*Glyph)
+}
+
+// FetchGlyph fetches a glyph from the cache, calling renderGlyph first if it doesn't already exist
+func FetchGlyph(gc draw2d.GraphicContext, fontName string, chr rune) *Glyph {
+ if glyphCache[fontName] == nil {
+ glyphCache[fontName] = make(map[rune]*Glyph, 60)
+ }
+ if glyphCache[fontName][chr] == nil {
+ glyphCache[fontName][chr] = renderGlyph(gc, fontName, chr)
+ }
+ return glyphCache[fontName][chr].Copy()
+}
+
+// renderGlyph renders a glyph then caches and returns it
+func renderGlyph(gc draw2d.GraphicContext, fontName string, chr rune) *Glyph {
+ gc.Save()
+ defer gc.Restore()
+ gc.BeginPath()
+ width := gc.CreateStringPath(string(chr), 0, 0)
+ path := gc.GetPath()
+ return &Glyph{
+ path: &path,
+ Width: width,
+ }
+}
+
+// Glyph represents a rune which has been converted to a Path and width
+type Glyph struct {
+ // path represents a glyph, it is always at (0, 0)
+ path *draw2d.Path
+ // Width of the glyph
+ Width float64
+}
+
+func (g *Glyph) Copy() *Glyph {
+ return &Glyph{
+ path: g.path.Copy(),
+ Width: g.Width,
+ }
+}
+
+// Fill copies a glyph from the cache, and fills it
+func (g *Glyph) Fill(gc draw2d.GraphicContext, x, y float64) float64 {
+ gc.Save()
+ gc.BeginPath()
+ gc.Translate(x, y)
+ gc.Fill(g.path)
+ gc.Restore()
+ return g.Width
+}
+
+// Stroke fetches a glyph from the cache, and strokes it
+func (g *Glyph) Stroke(gc draw2d.GraphicContext, x, y float64) float64 {
+ gc.Save()
+ gc.BeginPath()
+ gc.Translate(x, y)
+ gc.Stroke(g.path)
+ gc.Restore()
+ return g.Width
+}