diff --git a/curve.go b/curve.go deleted file mode 100644 index 3599144..0000000 --- a/curve.go +++ /dev/null @@ -1,161 +0,0 @@ -// 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 -} diff --git a/curve_test.go b/curve_test.go deleted file mode 100644 index c4d2603..0000000 --- a/curve_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package draw2d - -import ( - "bufio" - "fmt" - "image" - "image/color" - "image/draw" - "image/png" - "log" - "os" - "testing" - - "github.com/llgcode/draw2d/raster" -) - -var ( - flattening_threshold float64 = 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("test_results/_test.html") - if err != nil { - log.Println(err) - os.Exit(1) - } - defer f.Close() - log.Printf("Create html viewer") - f.Write([]byte("")) - for i := 0; i < len(testsCubicFloat64)/8; i++ { - f.Write([]byte(fmt.Sprintf("
\n", i))) - } - for i := 0; i < len(testsQuadFloat64); i++ { - f.Write([]byte(fmt.Sprintf("
\n
\n", i))) - } - f.Write([]byte("")) - -} - -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:], 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...) - //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) - 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)) - } - 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:], 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...) - //drawPoints(img, image.NRGBAColor{0, 0, 0, 0xff}, curve[:]...) - 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)) - } - 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:], 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 -}