package curve import ( "bufio" "fmt" "image" "image/color" "image/draw" "image/png" "log" "os" "testing" "github.com/llgcode/draw2d/raster" ) var ( flatteningThreshold = 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}, } 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}, } ) 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 init() { f, err := os.Create("_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); i++ { f.Write([]byte(fmt.Sprintf("
\n\n\n\n\n
\n", i, i, i, i, i))) } for i := 0; i < len(testsQuadFloat64); i++ { f.Write([]byte(fmt.Sprintf("
\n
\n", i))) } f.Write([]byte("")) } func savepng(filePath string, m image.Image) { f, err := os.Create(filePath) if err != nil { log.Println(err) os.Exit(1) } defer f.Close() b := bufio.NewWriter(f) err = png.Encode(b, m) if err != nil { log.Println(err) os.Exit(1) } err = b.Flush() if err != nil { log.Println(err) os.Exit(1) } } 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 TestCubicCurveRec(t *testing.T) { for i, curve := range testsCubicFloat64 { var p Path p.LineTo(curve[0], curve[1]) curve.SegmentRec(&p, flatteningThreshold) img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) 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...) savepng(fmt.Sprintf("_testRec%d.png", i), img) log.Printf("Num of points: %d\n", len(p.points)) } fmt.Println() } func TestCubicCurve(t *testing.T) { for i, curve := range testsCubicFloat64 { var p Path p.LineTo(curve[0], curve[1]) curve.Segment(&p, flatteningThreshold) img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) 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...) savepng(fmt.Sprintf("_test%d.png", i), img) log.Printf("Num of points: %d\n", len(p.points)) } fmt.Println() } func TestCubicCurveAdaptiveRec(t *testing.T) { for i, curve := range testsCubicFloat64 { var p Path p.LineTo(curve[0], curve[1]) curve.AdaptiveSegmentRec(&p, 1, 0, 0) img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) 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...) savepng(fmt.Sprintf("_testAdaptiveRec%d.png", i), img) log.Printf("Num of points: %d\n", len(p.points)) } fmt.Println() } func TestCubicCurveAdaptive(t *testing.T) { for i, curve := range testsCubicFloat64 { var p Path p.LineTo(curve[0], curve[1]) curve.AdaptiveSegment(&p, 1, 0, 0) img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) 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...) savepng(fmt.Sprintf("_testAdaptive%d.png", i), img) log.Printf("Num of points: %d\n", len(p.points)) } fmt.Println() } func TestCubicCurveParabolic(t *testing.T) { for i, curve := range testsCubicFloat64 { var p Path p.LineTo(curve[0], curve[1]) curve.ParabolicSegment(&p, flatteningThreshold) img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) 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...) savepng(fmt.Sprintf("_testParabolic%d.png", i), img) log.Printf("Num of points: %d\n", len(p.points)) } fmt.Println() } func TestQuadCurve(t *testing.T) { for i, curve := range testsQuadFloat64 { var p Path p.LineTo(curve[0], curve[1]) curve.Segment(&p, flatteningThreshold) img := image.NewNRGBA(image.Rect(0, 0, 300, 300)) raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, curve[:]...) 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...) savepng(fmt.Sprintf("_testQuad%d.png", i), img) log.Printf("Num of points: %d\n", len(p.points)) } fmt.Println() } func BenchmarkCubicCurveRec(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.SegmentRec(&p, flatteningThreshold) } } } 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.Segment(&p, flatteningThreshold) } } } func BenchmarkCubicCurveAdaptiveRec(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.AdaptiveSegmentRec(&p, 1, 0, 0) } } } func BenchmarkCubicCurveAdaptive(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.AdaptiveSegment(&p, 1, 0, 0) } } } func BenchmarkCubicCurveParabolic(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.ParabolicSegment(&p, flatteningThreshold) } } } func BenchmarkQuadCurve(b *testing.B) { for i := 0; i < b.N; i++ { for _, curve := range testsQuadFloat64 { p := Path{make([]float64, 0, 32)} p.LineTo(curve[0], curve[1]) curve.Segment(&p, flatteningThreshold) } } }