From 4b3ba53f4c46f15cd095e50aa9c811489df63471 Mon Sep 17 00:00:00 2001 From: Laurent Le Goff Date: Thu, 23 Apr 2015 10:05:48 +0200 Subject: [PATCH] migrating to new curve package --- arc.go | 2 +- curve/arc.go | 4 +- curve/{cubic_float64.go => cubic.go} | 22 ++--- curve/curve_test.go | 95 +++++++++++++--------- curve/{quad_float64.go => quad.go} | 21 +++-- curve/tracer.go | 3 +- curves.go | 34 ++++---- dasher.go | 12 +-- demux_converter.go | 4 +- path_adder.go | 2 +- path_converter.go | 117 +++++++++++++-------------- path_storage.go | 24 +++--- raster/raster_test.go | 16 ++-- stroker.go | 8 +- transform.go | 4 +- vertex2d.go | 2 +- 16 files changed, 192 insertions(+), 178 deletions(-) rename curve/{cubic_float64.go => cubic.go} (75%) rename curve/{quad_float64.go => quad.go} (74%) diff --git a/arc.go b/arc.go index 1bfef06..a40c8b8 100644 --- a/arc.go +++ b/arc.go @@ -33,7 +33,7 @@ func arc(t VertexConverter, x, y, rx, ry, start, angle, scale float64) (lastX, l curY = y + math.Sin(angle)*ry angle += da - t.Vertex(curX, curY) + t.AddPoint(curX, curY) } return curX, curY } diff --git a/curve/arc.go b/curve/arc.go index 9c8fb82..1ed1426 100644 --- a/curve/arc.go +++ b/curve/arc.go @@ -32,7 +32,7 @@ func TraceArc(t LineTracer, x, y, rx, ry, start, angle, scale float64) { curY = y + math.Sin(angle)*ry angle += da - t.LineTo(curX, curY) + t.AddPoint(curX, curY) } - t.LineTo(curX, curY) + t.AddPoint(curX, curY) } diff --git a/curve/cubic_float64.go b/curve/cubic.go similarity index 75% rename from curve/cubic_float64.go rename to curve/cubic.go index 8c19eb2..af7995d 100644 --- a/curve/cubic_float64.go +++ b/curve/cubic.go @@ -12,12 +12,12 @@ const ( CurveRecursionLimit = 32 ) -// x1, y1, cpx1, cpx2, cpx2, cpy2, x2, y2 float64 -type CubicCurveFloat64 [8]float64 +// 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 (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) { +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 @@ -46,21 +46,21 @@ func (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) { c2[0], c2[1] = c1[6], c1[7] } -// Trace generate lines subdividing the curve using a LineTracer +// TraceCubic generate lines subdividing the cubic curve using a LineTracer // flattening_threshold helps determines the flattening expectation of the curve -func (curve *CubicCurveFloat64) Trace(t LineTracer, flattening_threshold float64) { +func TraceCubic(t LineTracer, cubic []float64, flattening_threshold float64) { // Allocation curves - var curves [CurveRecursionLimit]CubicCurveFloat64 - curves[0] = *curve + var curves [CurveRecursionLimit * 8]float64 + copy(curves[0:8], cubic[0:8]) i := 0 // current curve - var c *CubicCurveFloat64 + var c []float64 var dx, dy, d2, d3 float64 for i >= 0 { - c = &curves[i] + c = curves[i*8:] dx = c[6] - c[0] dy = c[7] - c[1] @@ -69,11 +69,11 @@ func (curve *CubicCurveFloat64) Trace(t LineTracer, flattening_threshold float64 // 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]) + t.AddPoint(c[6], c[7]) i-- } else { // second half of bezier go lower onto the stack - c.Subdivide(&curves[i+1], &curves[i]) + SubdivideCubic(c, curves[(i+1)*8:], curves[i*8:]) i++ } } diff --git a/curve/curve_test.go b/curve/curve_test.go index 2b4bb6a..e480a93 100644 --- a/curve/curve_test.go +++ b/curve/curve_test.go @@ -1,35 +1,36 @@ package curve import ( + "bufio" "fmt" "image" "image/color" "image/draw" + "image/png" "log" "os" "testing" - "github.com/llgcode/draw2d" "github.com/llgcode/draw2d/raster" ) var ( flattening_threshold float64 = 0.5 - testsCubicFloat64 = []CubicCurveFloat64{ - CubicCurveFloat64{100, 100, 200, 100, 100, 200, 200, 200}, - CubicCurveFloat64{100, 100, 300, 200, 200, 200, 300, 100}, - CubicCurveFloat64{100, 100, 0, 300, 200, 0, 300, 300}, - CubicCurveFloat64{150, 290, 10, 10, 290, 10, 150, 290}, - CubicCurveFloat64{10, 290, 10, 10, 290, 10, 290, 290}, - CubicCurveFloat64{100, 290, 290, 10, 10, 10, 200, 290}, + 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 = []QuadCurveFloat64{ - QuadCurveFloat64{100, 100, 200, 100, 200, 200}, - QuadCurveFloat64{100, 100, 290, 200, 290, 100}, - QuadCurveFloat64{100, 100, 0, 290, 200, 290}, - QuadCurveFloat64{150, 290, 10, 10, 290, 290}, - QuadCurveFloat64{10, 290, 10, 10, 290, 290}, - QuadCurveFloat64{100, 290, 290, 10, 120, 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, } ) @@ -37,16 +38,8 @@ type Path struct { points []float64 } -func (p *Path) LineTo(x, y float64) { - if len(p.points)+2 > cap(p.points) { - points := make([]float64, len(p.points)+2, len(p.points)+32) - copy(points, p.points) - p.points = points - } else { - p.points = p.points[0 : len(p.points)+2] - } - p.points[len(p.points)-2] = x - p.points[len(p.points)-1] = y +func (p *Path) AddPoint(x, y float64) { + p.points = append(p.points, x, y) } func init() { @@ -59,7 +52,7 @@ func init() { defer f.Close() log.Printf("Create html viewer") f.Write([]byte("")) - for i := 0; i < len(testsCubicFloat64); i++ { + for i := 0; i < len(testsCubicFloat64)/8; i++ { f.Write([]byte(fmt.Sprintf("
\n", i))) } for i := 0; i < len(testsQuadFloat64); i++ { @@ -87,32 +80,32 @@ func drawPoints(img draw.Image, c color.Color, s ...float64) image.Image { } func TestCubicCurve(t *testing.T) { - for i, curve := range testsCubicFloat64 { + for i := 0; i < len(testsCubicFloat64); i += 8 { var p Path - p.LineTo(curve[0], curve[1]) - curve.Trace(&p, flattening_threshold) + p.AddPoint(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}, curve[:]...) + raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsCubicFloat64[i:i+8]...) 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...) - draw2d.SaveToPngFile(fmt.Sprintf("test_results/_test%d.png", i), img) + SaveToPngFile(fmt.Sprintf("test_results/_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, curve := range testsQuadFloat64 { + for i := 0; i < len(testsQuadFloat64); i += 6 { var p Path - p.LineTo(curve[0], curve[1]) - curve.Trace(&p, flattening_threshold) + p.AddPoint(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}, curve[:]...) + raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsQuadFloat64[i:i+6]...) 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...) - draw2d.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)) } fmt.Println() @@ -120,10 +113,32 @@ func TestQuadCurve(t *testing.T) { func BenchmarkCubicCurve(b *testing.B) { for i := 0; i < b.N; i++ { - for _, curve := range testsCubicFloat64 { - p := Path{make([]float64, 0, 32)} - p.LineTo(curve[0], curve[1]) - curve.Trace(&p, flattening_threshold) + for i := 0; i < len(testsCubicFloat64); i += 8 { + var p Path + p.AddPoint(testsCubicFloat64[i], testsCubicFloat64[i+1]) + TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold) } } } + +// 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/curve/quad_float64.go b/curve/quad.go similarity index 74% rename from curve/quad_float64.go rename to curve/quad.go index 6cb2891..6feb669 100644 --- a/curve/quad_float64.go +++ b/curve/quad.go @@ -7,13 +7,12 @@ import ( "math" ) -//x1, y1, cpx1, cpy2, x2, y2 float64 -type QuadCurveFloat64 [6]float64 +// 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 (c *QuadCurveFloat64) Subdivide(c1, c2 *QuadCurveFloat64) { - +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 @@ -32,17 +31,17 @@ func (c *QuadCurveFloat64) Subdivide(c1, c2 *QuadCurveFloat64) { // Trace generate lines subdividing the curve using a LineTracer // flattening_threshold helps determines the flattening expectation of the curve -func (curve *QuadCurveFloat64) Trace(t LineTracer, flattening_threshold float64) { +func TraceQuad(t LineTracer, quad []float64, flattening_threshold float64) { // Allocates curves stack - var curves [CurveRecursionLimit]QuadCurveFloat64 - curves[0] = *curve + var curves [CurveRecursionLimit * 6]float64 + copy(curves[0:6], quad[0:6]) i := 0 // current curve - var c *QuadCurveFloat64 + var c []float64 var dx, dy, d float64 for i >= 0 { - c = &curves[i] + c = curves[i*6:] dx = c[4] - c[0] dy = c[5] - c[1] @@ -50,11 +49,11 @@ func (curve *QuadCurveFloat64) Trace(t LineTracer, flattening_threshold float64) // 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]) + t.AddPoint(c[4], c[5]) i-- } else { // second half of bezier go lower onto the stack - c.Subdivide(&curves[i+1], &curves[i]) + SubdivideQuad(c, curves[(i+1)*6:], curves[i*6:]) i++ } } diff --git a/curve/tracer.go b/curve/tracer.go index e80ce1d..7cfb997 100644 --- a/curve/tracer.go +++ b/curve/tracer.go @@ -2,5 +2,6 @@ package curve // LineTracer is an interface that help segmenting curve into small lines type LineTracer interface { - LineTo(x, y float64) + // AddPoint a point + AddPoint(x, y float64) } diff --git a/curves.go b/curves.go index 98c9a97..7b8c0eb 100644 --- a/curves.go +++ b/curves.go @@ -88,7 +88,7 @@ func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 fl // we tend to finish subdivisions. //---------------------- if angleTolerance < CurveAngleToleranceEpsilon { - v.Vertex(x123, y123) + v.AddPoint(x123, y123) return } @@ -102,7 +102,7 @@ func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 fl if da < angleTolerance { // Finally we can stop the recursion //---------------------- - v.Vertex(x123, y123) + v.AddPoint(x123, y123) return } } @@ -128,7 +128,7 @@ func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 fl } } if d < distanceToleranceSquare { - v.Vertex(x2, y2) + v.AddPoint(x2, y2) return } } @@ -209,12 +209,12 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa } if d2 > d3 { if d2 < distanceToleranceSquare { - v.Vertex(x2, y2) + v.AddPoint(x2, y2) return } } else { if d3 < distanceToleranceSquare { - v.Vertex(x3, y3) + v.AddPoint(x3, y3) return } } @@ -225,7 +225,7 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa //---------------------- if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) { if angleTolerance < CurveAngleToleranceEpsilon { - v.Vertex(x23, y23) + v.AddPoint(x23, y23) return } @@ -237,14 +237,14 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa } if da1 < angleTolerance { - v.Vertex(x2, y2) - v.Vertex(x3, y3) + v.AddPoint(x2, y2) + v.AddPoint(x3, y3) return } if cuspLimit != 0.0 { if da1 > cuspLimit { - v.Vertex(x3, y3) + v.AddPoint(x3, y3) return } } @@ -256,7 +256,7 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa //---------------------- if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) { if angleTolerance < CurveAngleToleranceEpsilon { - v.Vertex(x23, y23) + v.AddPoint(x23, y23) return } @@ -268,14 +268,14 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa } if da1 < angleTolerance { - v.Vertex(x2, y2) - v.Vertex(x3, y3) + v.AddPoint(x2, y2) + v.AddPoint(x3, y3) return } if cuspLimit != 0.0 { if da1 > cuspLimit { - v.Vertex(x2, y2) + v.AddPoint(x2, y2) return } } @@ -290,7 +290,7 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa // we tend to finish subdivisions. //---------------------- if angleTolerance < CurveAngleToleranceEpsilon { - v.Vertex(x23, y23) + v.AddPoint(x23, y23) return } @@ -309,18 +309,18 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa if da1+da2 < angleTolerance { // Finally we can stop the recursion //---------------------- - v.Vertex(x23, y23) + v.AddPoint(x23, y23) return } if cuspLimit != 0.0 { if da1 > cuspLimit { - v.Vertex(x2, y2) + v.AddPoint(x2, y2) return } if da2 > cuspLimit { - v.Vertex(x3, y3) + v.AddPoint(x3, y3) return } } diff --git a/dasher.go b/dasher.go index 5210299..b4d4977 100644 --- a/dasher.go +++ b/dasher.go @@ -28,7 +28,7 @@ func (dasher *DashVertexConverter) NextCommand(cmd VertexCommand) { } } -func (dasher *DashVertexConverter) Vertex(x, y float64) { +func (dasher *DashVertexConverter) AddPoint(x, y float64) { switch dasher.command { case VertexStartCommand: dasher.start(x, y) @@ -40,7 +40,7 @@ func (dasher *DashVertexConverter) Vertex(x, y float64) { func (dasher *DashVertexConverter) start(x, y float64) { dasher.next.NextCommand(VertexStartCommand) - dasher.next.Vertex(x, y) + dasher.next.AddPoint(x, y) dasher.x, dasher.y = x, y dasher.distance = dasher.dashOffset dasher.currentDash = 0 @@ -60,12 +60,12 @@ func (dasher *DashVertexConverter) lineTo(x, y float64) { ly := dasher.y + k*(y-dasher.y) if dasher.currentDash%2 == 0 { // line - dasher.next.Vertex(lx, ly) + dasher.next.AddPoint(lx, ly) } else { // gap dasher.next.NextCommand(VertexStopCommand) dasher.next.NextCommand(VertexStartCommand) - dasher.next.Vertex(lx, ly) + dasher.next.AddPoint(lx, ly) } d = d - rest dasher.x, dasher.y = lx, ly @@ -75,12 +75,12 @@ func (dasher *DashVertexConverter) lineTo(x, y float64) { dasher.distance = d if dasher.currentDash%2 == 0 { // line - dasher.next.Vertex(x, y) + dasher.next.AddPoint(x, y) } else { // gap dasher.next.NextCommand(VertexStopCommand) dasher.next.NextCommand(VertexStartCommand) - dasher.next.Vertex(x, y) + dasher.next.AddPoint(x, y) } if dasher.distance >= dasher.dash[dasher.currentDash] { dasher.distance = dasher.distance - dasher.dash[dasher.currentDash] diff --git a/demux_converter.go b/demux_converter.go index b5c871d..98524c8 100644 --- a/demux_converter.go +++ b/demux_converter.go @@ -16,8 +16,8 @@ func (dc *DemuxConverter) NextCommand(cmd VertexCommand) { converter.NextCommand(cmd) } } -func (dc *DemuxConverter) Vertex(x, y float64) { +func (dc *DemuxConverter) AddPoint(x, y float64) { for _, converter := range dc.converters { - converter.Vertex(x, y) + converter.AddPoint(x, y) } } diff --git a/path_adder.go b/path_adder.go index c5efd2b..c40c039 100644 --- a/path_adder.go +++ b/path_adder.go @@ -20,7 +20,7 @@ func (vertexAdder *VertexAdder) NextCommand(cmd VertexCommand) { vertexAdder.command = cmd } -func (vertexAdder *VertexAdder) Vertex(x, y float64) { +func (vertexAdder *VertexAdder) AddPoint(x, y float64) { switch vertexAdder.command { case VertexStartCommand: vertexAdder.adder.Start(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)}) diff --git a/path_converter.go b/path_converter.go index 0ef96b8..b1bd9a4 100644 --- a/path_converter.go +++ b/path_converter.go @@ -4,74 +4,73 @@ package draw2d import ( + "github.com/llgcode/draw2d/curve" "math" ) type PathConverter struct { - converter VertexConverter - ApproximationScale, AngleTolerance, CuspLimit float64 - startX, startY, x, y float64 + converter VertexConverter + ApproximationScale float64 + startX, startY, x, y float64 } func NewPathConverter(converter VertexConverter) *PathConverter { - return &PathConverter{converter, 1, 0, 0, 0, 0, 0, 0} + return &PathConverter{converter, 1, 0, 0, 0, 0} } func (c *PathConverter) Convert(paths ...*PathStorage) { for _, path := range paths { - j := 0 + i := 0 for _, cmd := range path.commands { - j = j + c.ConvertCommand(cmd, path.vertices[j:]...) + switch cmd { + case MoveTo: + c.x, c.y = path.vertices[i], path.vertices[i+1] + c.startX, c.startY = c.x, c.y + c.converter.NextCommand(VertexStopCommand) + c.converter.NextCommand(VertexStartCommand) + c.converter.AddPoint(c.x, c.y) + i += 2 + case LineTo: + c.x, c.y = path.vertices[i], path.vertices[i+1] + if c.startX == c.x && c.startY == c.y { + c.converter.NextCommand(VertexCloseCommand) + } + c.converter.AddPoint(c.x, c.y) + c.converter.NextCommand(VertexJoinCommand) + i += 2 + case QuadCurveTo: + curve.TraceQuad(c.converter, path.vertices[i-2:], 0.5) + c.x, c.y = path.vertices[i+2], path.vertices[i+3] + if c.startX == c.x && c.startY == c.y { + c.converter.NextCommand(VertexCloseCommand) + } + c.converter.AddPoint(c.x, c.y) + i += 4 + case CubicCurveTo: + curve.TraceCubic(c.converter, path.vertices[i-2:], 0.5) + c.x, c.y = path.vertices[i+4], path.vertices[i+5] + if c.startX == c.x && c.startY == c.y { + c.converter.NextCommand(VertexCloseCommand) + } + c.converter.AddPoint(c.x, c.y) + i += 6 + case ArcTo: + c.x, c.y = arc(c.converter, path.vertices[i], path.vertices[i+1], path.vertices[i+2], path.vertices[i+3], path.vertices[i+4], path.vertices[i+5], c.ApproximationScale) + if c.startX == c.x && c.startY == c.y { + c.converter.NextCommand(VertexCloseCommand) + } + c.converter.AddPoint(c.x, c.y) + i += 6 + case Close: + c.converter.NextCommand(VertexCloseCommand) + c.converter.AddPoint(c.startX, c.startY) + } } c.converter.NextCommand(VertexStopCommand) } } -func (c *PathConverter) ConvertCommand(cmd PathCmd, vertices ...float64) int { - switch cmd { - case MoveTo: - c.x, c.y = vertices[0], vertices[1] - c.startX, c.startY = c.x, c.y - c.converter.NextCommand(VertexStopCommand) - c.converter.NextCommand(VertexStartCommand) - c.converter.Vertex(c.x, c.y) - return 2 - case LineTo: - c.x, c.y = vertices[0], vertices[1] - if c.startX == c.x && c.startY == c.y { - c.converter.NextCommand(VertexCloseCommand) - } - c.converter.Vertex(c.x, c.y) - c.converter.NextCommand(VertexJoinCommand) - return 2 - case QuadCurveTo: - quadraticBezier(c.converter, c.x, c.y, vertices[0], vertices[1], vertices[2], vertices[3], c.ApproximationScale, c.AngleTolerance) - c.x, c.y = vertices[2], vertices[3] - if c.startX == c.x && c.startY == c.y { - c.converter.NextCommand(VertexCloseCommand) - } - c.converter.Vertex(c.x, c.y) - return 4 - case CubicCurveTo: - cubicBezier(c.converter, c.x, c.y, vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5], c.ApproximationScale, c.AngleTolerance, c.CuspLimit) - c.x, c.y = vertices[4], vertices[5] - if c.startX == c.x && c.startY == c.y { - c.converter.NextCommand(VertexCloseCommand) - } - c.converter.Vertex(c.x, c.y) - return 6 - case ArcTo: - c.x, c.y = arc(c.converter, vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5], c.ApproximationScale) - if c.startX == c.x && c.startY == c.y { - c.converter.NextCommand(VertexCloseCommand) - } - c.converter.Vertex(c.x, c.y) - return 6 - case Close: - c.converter.NextCommand(VertexCloseCommand) - c.converter.Vertex(c.startX, c.startY) - return 0 - } +func (c *PathConverter) convertCommand(cmd PathCmd, vertices ...float64) int { return 0 } @@ -80,7 +79,7 @@ func (c *PathConverter) MoveTo(x, y float64) *PathConverter { c.startX, c.startY = c.x, c.y c.converter.NextCommand(VertexStopCommand) c.converter.NextCommand(VertexStartCommand) - c.converter.Vertex(c.x, c.y) + c.converter.AddPoint(c.x, c.y) return c } @@ -94,7 +93,7 @@ func (c *PathConverter) LineTo(x, y float64) *PathConverter { if c.startX == c.x && c.startY == c.y { c.converter.NextCommand(VertexCloseCommand) } - c.converter.Vertex(c.x, c.y) + c.converter.AddPoint(c.x, c.y) c.converter.NextCommand(VertexJoinCommand) return c } @@ -105,12 +104,12 @@ func (c *PathConverter) RLineTo(dx, dy float64) *PathConverter { } func (c *PathConverter) QuadCurveTo(cx, cy, x, y float64) *PathConverter { - quadraticBezier(c.converter, c.x, c.y, cx, cy, x, y, c.ApproximationScale, c.AngleTolerance) + curve.TraceQuad(c.converter, []float64{c.x, c.y, cx, cy, x, y}, 0.5) c.x, c.y = x, y if c.startX == c.x && c.startY == c.y { c.converter.NextCommand(VertexCloseCommand) } - c.converter.Vertex(c.x, c.y) + c.converter.AddPoint(c.x, c.y) return c } @@ -120,12 +119,12 @@ func (c *PathConverter) RQuadCurveTo(dcx, dcy, dx, dy float64) *PathConverter { } func (c *PathConverter) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) *PathConverter { - cubicBezier(c.converter, c.x, c.y, cx1, cy1, cx2, cy2, x, y, c.ApproximationScale, c.AngleTolerance, c.CuspLimit) + curve.TraceCubic(c.converter, []float64{c.x, c.y, cx1, cy1, cx2, cy2, x, y}, 0.5) c.x, c.y = x, y if c.startX == c.x && c.startY == c.y { c.converter.NextCommand(VertexCloseCommand) } - c.converter.Vertex(c.x, c.y) + c.converter.AddPoint(c.x, c.y) return c } @@ -157,7 +156,7 @@ func (c *PathConverter) ArcTo(cx, cy, rx, ry, startAngle, angle float64) *PathCo if c.startX == c.x && c.startY == c.y { c.converter.NextCommand(VertexCloseCommand) } - c.converter.Vertex(c.x, c.y) + c.converter.AddPoint(c.x, c.y) return c } @@ -168,6 +167,6 @@ func (c *PathConverter) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) *Pat func (c *PathConverter) Close() *PathConverter { c.converter.NextCommand(VertexCloseCommand) - c.converter.Vertex(c.startX, c.startY) + c.converter.AddPoint(c.startX, c.startY) return c } diff --git a/path_storage.go b/path_storage.go index c2a8870..b773d2b 100644 --- a/path_storage.go +++ b/path_storage.go @@ -39,18 +39,8 @@ func (p *PathStorage) Clear() { } func (p *PathStorage) appendToPath(cmd PathCmd, vertices ...float64) { - if cap(p.vertices) <= len(p.vertices)+6 { - a := make([]PathCmd, len(p.commands), cap(p.commands)+256) - b := make([]float64, len(p.vertices), cap(p.vertices)+256) - copy(a, p.commands) - p.commands = a - copy(b, p.vertices) - p.vertices = b - } - p.commands = p.commands[0 : len(p.commands)+1] - p.commands[len(p.commands)-1] = cmd - copy(p.vertices[len(p.vertices):len(p.vertices)+len(vertices)], vertices) - p.vertices = p.vertices[0 : len(p.vertices)+len(vertices)] + p.commands = append(p.commands, cmd) + p.vertices = append(p.vertices, vertices...) } func (src *PathStorage) Copy() (dest *PathStorage) { @@ -77,6 +67,7 @@ func (p *PathStorage) Close() *PathStorage { func (p *PathStorage) MoveTo(x, y float64) *PathStorage { p.appendToPath(MoveTo, x, y) + p.x = x p.y = y return p @@ -89,6 +80,9 @@ func (p *PathStorage) RMoveTo(dx, dy float64) *PathStorage { } func (p *PathStorage) LineTo(x, y float64) *PathStorage { + if len(p.commands) == 0 { //special case when no move has been done + p.MoveTo(0, 0) + } p.appendToPath(LineTo, x, y) p.x = x p.y = y @@ -102,6 +96,9 @@ func (p *PathStorage) RLineTo(dx, dy float64) *PathStorage { } func (p *PathStorage) QuadCurveTo(cx, cy, x, y float64) *PathStorage { + if len(p.commands) == 0 { //special case when no move has been done + p.MoveTo(0, 0) + } p.appendToPath(QuadCurveTo, cx, cy, x, y) p.x = x p.y = y @@ -115,6 +112,9 @@ func (p *PathStorage) RQuadCurveTo(dcx, dcy, dx, dy float64) *PathStorage { } func (p *PathStorage) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) *PathStorage { + if len(p.commands) == 0 { //special case when no move has been done + p.MoveTo(0, 0) + } p.appendToPath(CubicCurveTo, cx1, cy1, cx2, cy2, x, y) p.x = x p.y = y diff --git a/raster/raster_test.go b/raster/raster_test.go index 7d595cc..ac1dd57 100644 --- a/raster/raster_test.go +++ b/raster/raster_test.go @@ -55,7 +55,7 @@ func TestFreetype(t *testing.T) { var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} - c.Segment(&p, flattening_threshold) + c.Trace(&p, flattening_threshold) poly := Polygon(p.points) color := color.RGBA{0, 0, 0, 0xff} @@ -77,7 +77,7 @@ func TestFreetypeNonZeroWinding(t *testing.T) { var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} - c.Segment(&p, flattening_threshold) + c.Trace(&p, flattening_threshold) poly := Polygon(p.points) color := color.RGBA{0, 0, 0, 0xff} @@ -100,7 +100,7 @@ func TestRasterizer(t *testing.T) { var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} - c.Segment(&p, flattening_threshold) + c.Trace(&p, flattening_threshold) poly := Polygon(p.points) color := color.RGBA{0, 0, 0, 0xff} tr := [6]float64{1, 0, 0, 1, 0, 0} @@ -116,7 +116,7 @@ func TestRasterizerNonZeroWinding(t *testing.T) { var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} - c.Segment(&p, flattening_threshold) + c.Trace(&p, flattening_threshold) poly := Polygon(p.points) color := color.RGBA{0, 0, 0, 0xff} tr := [6]float64{1, 0, 0, 1, 0, 0} @@ -131,7 +131,7 @@ func BenchmarkFreetype(b *testing.B) { var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} - c.Segment(&p, flattening_threshold) + c.Trace(&p, flattening_threshold) poly := Polygon(p.points) color := color.RGBA{0, 0, 0, 0xff} @@ -152,7 +152,7 @@ func BenchmarkFreetypeNonZeroWinding(b *testing.B) { var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} - c.Segment(&p, flattening_threshold) + c.Trace(&p, flattening_threshold) poly := Polygon(p.points) color := color.RGBA{0, 0, 0, 0xff} @@ -174,7 +174,7 @@ func BenchmarkRasterizerNonZeroWinding(b *testing.B) { var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} - c.Segment(&p, flattening_threshold) + c.Trace(&p, flattening_threshold) poly := Polygon(p.points) color := color.RGBA{0, 0, 0, 0xff} tr := [6]float64{1, 0, 0, 1, 0, 0} @@ -189,7 +189,7 @@ func BenchmarkRasterizer(b *testing.B) { var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} - c.Segment(&p, flattening_threshold) + c.Trace(&p, flattening_threshold) poly := Polygon(p.points) color := color.RGBA{0, 0, 0, 0xff} tr := [6]float64{1, 0, 0, 1, 0, 0} diff --git a/stroker.go b/stroker.go index 9e40361..b46586c 100644 --- a/stroker.go +++ b/stroker.go @@ -47,16 +47,16 @@ func (l *LineStroker) NextCommand(command VertexCommand) { if command == VertexStopCommand { l.Next.NextCommand(VertexStartCommand) for i, j := 0, 1; j < len(l.vertices); i, j = i+2, j+2 { - l.Next.Vertex(l.vertices[i], l.vertices[j]) + l.Next.AddPoint(l.vertices[i], l.vertices[j]) l.Next.NextCommand(VertexNoCommand) } for i, j := len(l.rewind)-2, len(l.rewind)-1; j > 0; i, j = i-2, j-2 { l.Next.NextCommand(VertexNoCommand) - l.Next.Vertex(l.rewind[i], l.rewind[j]) + l.Next.AddPoint(l.rewind[i], l.rewind[j]) } if len(l.vertices) > 1 { l.Next.NextCommand(VertexNoCommand) - l.Next.Vertex(l.vertices[0], l.vertices[1]) + l.Next.AddPoint(l.vertices[0], l.vertices[1]) } l.Next.NextCommand(VertexStopCommand) // reinit vertices @@ -66,7 +66,7 @@ func (l *LineStroker) NextCommand(command VertexCommand) { } } -func (l *LineStroker) Vertex(x, y float64) { +func (l *LineStroker) AddPoint(x, y float64) { switch l.command { case VertexNoCommand: l.line(l.x, l.y, x, y) diff --git a/transform.go b/transform.go index 61d3f35..3766a22 100644 --- a/transform.go +++ b/transform.go @@ -266,10 +266,10 @@ func (vmt *VertexMatrixTransform) NextCommand(command VertexCommand) { vmt.Next.NextCommand(command) } -func (vmt *VertexMatrixTransform) Vertex(x, y float64) { +func (vmt *VertexMatrixTransform) AddPoint(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.Vertex(u, v) + vmt.Next.AddPoint(u, v) } // this adder apply a Matrix transformation to points diff --git a/vertex2d.go b/vertex2d.go index 4e4d4fd..9cf928a 100644 --- a/vertex2d.go +++ b/vertex2d.go @@ -15,5 +15,5 @@ const ( type VertexConverter interface { NextCommand(cmd VertexCommand) - Vertex(x, y float64) + AddPoint(x, y float64) }