diff --git a/cmd/draw2dgl.go b/cmd/draw2dgl.go index e0db898..1d8e734 100644 --- a/cmd/draw2dgl.go +++ b/cmd/draw2dgl.go @@ -18,15 +18,15 @@ package main import ( - "os" - "math" - "io/ioutil" - "strings" + "code.google.com/p/draw2d/draw2dgl" + "code.google.com/p/draw2d/postscript" "gl" "glut" - "draw2d.googlecode.com/hg/draw2dgl" - "draw2d.googlecode.com/hg/postscript" + "io/ioutil" "log" + "math" + "os" + "strings" "time" ) @@ -69,9 +69,9 @@ func display() { gc.Translate(-380, -400) interpreter := postscript.NewInterpreter(gc) reader := strings.NewReader(postscriptContent) - lastTime := time.Nanoseconds() + lastTime := time.Now() interpreter.Execute(reader) - dt := time.Nanoseconds() - lastTime + dt := time.Now().Sub(lastTime) log.Printf("Redraw in : %f ms\n", float64(dt)*1e-6) gl.Flush() /* Single buffered, so needs a flush. */ glut.PostRedisplay() diff --git a/cmd/gettingStarted.go b/cmd/gettingStarted.go index 457de48..a0c11ca 100644 --- a/cmd/gettingStarted.go +++ b/cmd/gettingStarted.go @@ -4,17 +4,16 @@ package main import ( + "bufio" "fmt" "log" "os" - "bufio" + "code.google.com/p/draw2d/draw2d" "image" "image/png" - "draw2d.googlecode.com/hg/draw2d" ) - func saveToPngFile(filePath string, m image.Image) { f, err := os.Create(filePath) if err != nil { @@ -37,7 +36,7 @@ func saveToPngFile(filePath string, m image.Image) { } func main() { - i := image.NewRGBA(image.Rect(0,0,200, 200)) + i := image.NewRGBA(image.Rect(0, 0, 200, 200)) gc := draw2d.NewGraphicContext(i) gc.MoveTo(10.0, 10.0) gc.LineTo(100.0, 10.0) diff --git a/cmd/testWalkDraw.go b/cmd/testWalkDraw.go index 11be091..4950618 100644 --- a/cmd/testWalkDraw.go +++ b/cmd/testWalkDraw.go @@ -5,17 +5,18 @@ package main import ( + "code.google.com/p/draw2d/draw2d" + "code.google.com/p/draw2d/postscript" + "code.google.com/p/draw2d/wingui" "fmt" - "syscall" - "os" - "unsafe" "image" + "image/color" "io/ioutil" + "os" "strings" + "syscall" "time" - "draw2d.googlecode.com/hg/draw2d" - "draw2d.googlecode.com/hg/postscript" - "draw2d.googlecode.com/hg/wingui" + "unsafe" ) // some help functions @@ -31,7 +32,6 @@ func abortErrNo(funcname string, err int) { // global vars - func TestDrawCubicCurve(gc draw2d.GraphicContext) { // draw a cubic curve x, y := 25.6, 128.0 @@ -39,13 +39,13 @@ func TestDrawCubicCurve(gc draw2d.GraphicContext) { x2, y2 := 153.6, 25.6 x3, y3 := 230.4, 128.0 - gc.SetFillColor(image.NRGBAColor{0xAA, 0xAA, 0xAA, 0xFF}) + gc.SetFillColor(color.NRGBA{0xAA, 0xAA, 0xAA, 0xFF}) gc.SetLineWidth(10) gc.MoveTo(x, y) gc.CubicCurveTo(x1, y1, x2, y2, x3, y3) gc.Stroke() - gc.SetStrokeColor(image.NRGBAColor{0xFF, 0x33, 0x33, 0x88}) + gc.SetStrokeColor(color.NRGBA{0xFF, 0x33, 0x33, 0x88}) gc.SetLineWidth(6) // draw segment of curve @@ -61,7 +61,7 @@ var ( wndBufferHeader uint32 wndBuffer wingui.BITMAP hdcWndBuffer uint32 - ppvBits *image.RGBAColor + ppvBits *color.RGBA backBuffer *image.RGBA postscriptContent string ) @@ -102,7 +102,7 @@ func WndProc(hwnd, msg uint32, wparam, lparam int32) uintptr { hdcWndBuffer = wingui.CreateCompatibleDC(hdc) wingui.SelectObject(hdcWndBuffer, wndBufferHeader) - pixel := (*[600 * 800]image.RGBAColor)(unsafe.Pointer(ppvBits)) + pixel := (*[600 * 800]color.RGBA)(unsafe.Pointer(ppvBits)) pixelSlice := pixel[:] backBuffer = &image.RGBA{pixelSlice, 600, image.Rect(0, 0, 600, 800)} fmt.Println("Create windows") @@ -114,17 +114,17 @@ func WndProc(hwnd, msg uint32, wparam, lparam int32) uintptr { } case wingui.WM_PAINT: var ps wingui.PAINTSTRUCT - lastTime := time.Nanoseconds() + lastTime := time.Now() hdc := wingui.BeginPaint(hwnd, &ps) gc := draw2d.NewGraphicContext(backBuffer) - gc.SetFillColor(image.RGBAColor{0xFF, 0xFF, 0xFF, 0xFF}) + gc.SetFillColor(color.RGBA{0xFF, 0xFF, 0xFF, 0xFF}) // gc.Clear() gc.Save() //gc.Translate(0, -380) interpreter := postscript.NewInterpreter(gc) reader := strings.NewReader(postscriptContent) interpreter.Execute(reader) - dt := time.Nanoseconds() - lastTime + dt := time.Now().Sub(lastTime) gc.Restore() // back buf in diff --git a/cmd/testX11draw.go b/cmd/testX11draw.go index 35ff3ab..f6825d3 100644 --- a/cmd/testX11draw.go +++ b/cmd/testX11draw.go @@ -1,12 +1,12 @@ package main import ( - "fmt" + "code.google.com/p/draw2d/draw2d" "exp/gui" "exp/gui/x11" + "fmt" "image" "math" - "draw2d.googlecode.com/hg/draw2d" ) func main() { diff --git a/cmd/testandroid.go b/cmd/testandroid.go index 8c7dd11..25fbb80 100644 --- a/cmd/testandroid.go +++ b/cmd/testandroid.go @@ -1,17 +1,17 @@ package main - import ( + "bufio" "fmt" "log" "os" - "bufio" "time" - "math" + "code.google.com/p/draw2d/draw2d" "image" + "image/color" "image/png" - "draw2d.googlecode.com/hg/draw2d" + "math" ) const ( @@ -24,9 +24,9 @@ var ( ) func initGc(w, h int) (image.Image, draw2d.GraphicContext) { - i := image.NewRGBA(image.Rect(0, 0,w, h)) + i := image.NewRGBA(image.Rect(0, 0, w, h)) gc := draw2d.NewGraphicContext(i) - lastTime = time.Nanoseconds() + lastTime = time.Now() gc.SetStrokeColor(image.Black) gc.SetFillColor(image.White) @@ -37,7 +37,7 @@ func initGc(w, h int) (image.Image, draw2d.GraphicContext) { } func saveToPngFile(TestName string, m image.Image) { - dt := time.Nanoseconds() - lastTime + dt := time.Now().Sub(lastTime) fmt.Printf("%s during: %f ms\n", TestName, float64(dt)*1e-6) filePath := folder + TestName + ".png" f, err := os.Create(filePath) @@ -88,11 +88,10 @@ func android(gc draw2d.GraphicContext, x, y float64) { gc.FillStroke() } - func main() { i, gc := initGc(width, height) - gc.SetFillColor(image.RGBAColor{0x44, 0xff, 0x44, 0xff}) - gc.SetStrokeColor(image.RGBAColor{0x44, 0x44, 0x44, 0xff}) + gc.SetFillColor(color.RGBA{0x44, 0xff, 0x44, 0xff}) + gc.SetStrokeColor(color.RGBA{0x44, 0x44, 0x44, 0xff}) android(gc, 10, 10) saveToPngFile("TestAndroid", i) } diff --git a/cmd/testdraw2d.go b/cmd/testdraw2d.go index 4c35e91..1b0c0d4 100644 --- a/cmd/testdraw2d.go +++ b/cmd/testdraw2d.go @@ -4,16 +4,17 @@ package main import ( + "bufio" "fmt" "log" "os" - "bufio" "time" - "math" + "code.google.com/p/draw2d/draw2d" "image" + "image/color" "image/png" - "draw2d.googlecode.com/hg/draw2d" + "math" ) const ( @@ -28,7 +29,7 @@ var ( func initGc(w, h int) (image.Image, draw2d.GraphicContext) { i := image.NewRGBA(image.Rect(0, 0, w, h)) gc := draw2d.NewGraphicContext(i) - lastTime = time.Nanoseconds() + lastTime = time.Now() gc.SetStrokeColor(image.Black) gc.SetFillColor(image.White) @@ -39,8 +40,8 @@ func initGc(w, h int) (image.Image, draw2d.GraphicContext) { } func saveToPngFile(TestName string, m image.Image) { - t := time.Nanoseconds() - dt := t - lastTime + t := time.Now() + dt := t.Sub(lastTime) fmt.Printf("%s during: %f ms\n", TestName, float64(dt)*1e-6) filePath := folder + TestName + ".png" f, err := os.Create(filePath) @@ -60,7 +61,7 @@ func saveToPngFile(TestName string, m image.Image) { log.Println(err) os.Exit(1) } - dt = time.Nanoseconds() - t + dt = time.Now().Sub(t) fmt.Printf("Wrote %s OK in %f ms.\n", filePath, float64(dt)*1e-6) } @@ -79,7 +80,6 @@ func TestPath() { saveToPngFile("TestPath", i) } - /* */ @@ -96,8 +96,8 @@ func TestDrawArc() { gc.ArcTo(xc, yc, radiusX, radiusY, startAngle, angle) gc.Stroke() // fill a circle - gc.SetStrokeColor(image.NRGBAColor{255, 0x33, 0x33, 0x80}) - gc.SetFillColor(image.NRGBAColor{255, 0x33, 0x33, 0x80}) + gc.SetStrokeColor(color.NRGBA{255, 0x33, 0x33, 0x80}) + gc.SetFillColor(color.NRGBA{255, 0x33, 0x33, 0x80}) gc.SetLineWidth(6) gc.MoveTo(xc, yc) @@ -110,6 +110,7 @@ func TestDrawArc() { gc.Fill() saveToPngFile("TestDrawArc", i) } + /* */ @@ -127,8 +128,8 @@ func TestDrawArcNegative() { gc.ArcTo(xc, yc, radiusX, radiusY, startAngle, angle) gc.Stroke() // fill a circle - gc.SetStrokeColor(image.NRGBAColor{255, 0x33, 0x33, 0x80}) - gc.SetFillColor(image.NRGBAColor{255, 0x33, 0x33, 0x80}) + gc.SetStrokeColor(color.NRGBA{255, 0x33, 0x33, 0x80}) + gc.SetFillColor(color.NRGBA{255, 0x33, 0x33, 0x80}) gc.SetLineWidth(6) gc.MoveTo(xc, yc) @@ -189,13 +190,14 @@ func TestCurveRectangle() { } gc.Close() - gc.SetFillColor(image.NRGBAColor{0x80, 0x80, 0xFF, 0xFF}) - gc.SetStrokeColor(image.NRGBAColor{0x80, 0, 0, 0x80}) + gc.SetFillColor(color.NRGBA{0x80, 0x80, 0xFF, 0xFF}) + gc.SetStrokeColor(color.NRGBA{0x80, 0, 0, 0x80}) gc.SetLineWidth(10.0) gc.FillStroke() saveToPngFile("TestCurveRectangle", i) } + /* */ @@ -207,13 +209,13 @@ func TestDrawCubicCurve() { x2, y2 := 153.6, 25.6 x3, y3 := 230.4, 128.0 - gc.SetFillColor(image.NRGBAColor{0xAA, 0xAA, 0xAA, 0xFF}) + gc.SetFillColor(color.NRGBA{0xAA, 0xAA, 0xAA, 0xFF}) gc.SetLineWidth(10) gc.MoveTo(x, y) gc.CubicCurveTo(x1, y1, x2, y2, x3, y3) gc.Stroke() - gc.SetStrokeColor(image.NRGBAColor{0xFF, 0x33, 0x33, 0x88}) + gc.SetStrokeColor(color.NRGBA{0xFF, 0x33, 0x33, 0x88}) gc.SetLineWidth(6) // draw segment of curve @@ -245,7 +247,6 @@ func TestDash() { saveToPngFile("TestDash", i) } - /* */ @@ -264,7 +265,7 @@ func TestFillStroke() { gc.Close() gc.SetLineWidth(10.0) - gc.SetFillColor(image.NRGBAColor{0, 0, 0xFF, 0xFF}) + gc.SetFillColor(color.NRGBA{0, 0, 0xFF, 0xFF}) gc.SetStrokeColor(image.Black) gc.FillStroke() saveToPngFile("TestFillStroke", i) @@ -285,7 +286,7 @@ func TestFillStyle() { wheel2.ArcTo(192, 64, 40, 40, 0, 2*math.Pi) gc.SetFillRule(draw2d.FillRuleEvenOdd) - gc.SetFillColor(image.NRGBAColor{0, 0xB2, 0, 0xFF}) + gc.SetFillColor(color.NRGBA{0, 0xB2, 0, 0xFF}) gc.SetStrokeColor(image.Black) gc.FillStroke(wheel1, wheel2) @@ -297,7 +298,7 @@ func TestFillStyle() { wheel2.ArcTo(192, 192, 40, 40, 0, -2*math.Pi) gc.SetFillRule(draw2d.FillRuleWinding) - gc.SetFillColor(image.NRGBAColor{0, 0, 0xE5, 0xFF}) + gc.SetFillColor(color.NRGBA{0, 0, 0xE5, 0xFF}) gc.FillStroke(wheel1, wheel2) saveToPngFile("TestFillStyle", i) } @@ -319,7 +320,6 @@ func TestMultiSegmentCaps() { saveToPngFile("TestMultiSegmentCaps", i) } - func TestRoundRectangle() { i, gc := initGc(w, h) /* a custom shape that could be wrapped in a function */ @@ -337,8 +337,8 @@ func TestRoundRectangle() { gc.ArcTo(x+radius, y+radius, radius, radius, 180*degrees, 90*degrees) gc.Close() - gc.SetFillColor(image.NRGBAColor{0x80, 0x80, 0xFF, 0xFF}) - gc.SetStrokeColor(image.NRGBAColor{0x80, 0, 0, 0x80}) + gc.SetFillColor(color.NRGBA{0x80, 0x80, 0xFF, 0xFF}) + gc.SetStrokeColor(color.NRGBA{0x80, 0, 0, 0x80}) gc.SetLineWidth(10.0) gc.FillStroke() @@ -362,7 +362,7 @@ func TestLineCap() { gc.Stroke() /* draw helping lines */ - gc.SetStrokeColor(image.NRGBAColor{0xFF, 0x33, 0x33, 0xFF}) + gc.SetStrokeColor(color.NRGBA{0xFF, 0x33, 0x33, 0xFF}) gc.SetLineWidth(2.56) gc.MoveTo(64.0, 50.0) gc.LineTo(64.0, 200.0) @@ -513,7 +513,7 @@ func TestBigPicture() { } func main() { - t := time.Nanoseconds() + t := time.Now() TestPath() TestDrawArc() TestDrawArcNegative() @@ -532,6 +532,6 @@ func main() { TestPathTransform() TestFillString() TestBigPicture() - dt := time.Nanoseconds() - t + dt := time.Now().Sub(t) fmt.Printf("All tests during: %f ms\n", float64(dt)*1e-6) } diff --git a/cmd/testgopher.go b/cmd/testgopher.go index b950c8a..0d9c1fd 100644 --- a/cmd/testgopher.go +++ b/cmd/testgopher.go @@ -1,17 +1,17 @@ package main - import ( + "bufio" "fmt" "log" - "os" - "bufio" - "time" "math" + "os" + "time" + "code.google.com/p/draw2d/draw2d" "image" + "image/color" "image/png" - "draw2d.googlecode.com/hg/draw2d" ) const ( @@ -26,7 +26,7 @@ var ( func initGc(w, h int) (image.Image, draw2d.GraphicContext) { i := image.NewRGBA(image.Rect(0, 0, w, h)) gc := draw2d.NewGraphicContext(i) - lastTime = time.Nanoseconds() + lastTime = time.Now() gc.SetStrokeColor(image.Black) gc.SetFillColor(image.White) @@ -37,7 +37,7 @@ func initGc(w, h int) (image.Image, draw2d.GraphicContext) { } func saveToPngFile(TestName string, m image.Image) { - dt := time.Nanoseconds() - lastTime + dt := time.Now().Sub(lastTime) fmt.Printf("%s during: %f ms\n", TestName, float64(dt)*1e-6) filePath := folder + TestName + ".png" f, err := os.Create(filePath) @@ -63,11 +63,11 @@ func saveToPngFile(TestName string, m image.Image) { func gordon(gc draw2d.GraphicContext, x, y, w, h float64) { h23 := (h * 2) / 3 - blf := image.RGBAColor{0, 0, 0, 0xff} - wf := image.RGBAColor{0xff, 0xff, 0xff, 0xff} - nf := image.RGBAColor{0x8B, 0x45, 0x13, 0xff} - brf := image.RGBAColor{0x8B, 0x45, 0x13, 0x99} - brb := image.RGBAColor{0x8B, 0x45, 0x13, 0xBB} + blf := color.RGBA{0, 0, 0, 0xff} + wf := color.RGBA{0xff, 0xff, 0xff, 0xff} + nf := color.RGBA{0x8B, 0x45, 0x13, 0xff} + brf := color.RGBA{0x8B, 0x45, 0x13, 0x99} + brb := color.RGBA{0x8B, 0x45, 0x13, 0xBB} gc.MoveTo(x, y+h) gc.CubicCurveTo(x, y+h, x+w/2, y-h, x+w, y+h) diff --git a/cmd/testimage.go b/cmd/testimage.go index c17bebe..3dd8b1f 100644 --- a/cmd/testimage.go +++ b/cmd/testimage.go @@ -1,19 +1,18 @@ package main import ( - "fmt" - "log" - "os" "bufio" - "math" + "code.google.com/p/draw2d/draw2d" + "fmt" "image" - "time" - "image/png" "image/draw" - "draw2d.googlecode.com/hg/draw2d" + "image/png" + "log" + "math" + "os" + "time" ) - func saveToPngFile(filePath string, m image.Image) { f, err := os.Create(filePath) if err != nil { @@ -52,7 +51,6 @@ func loadFromPngFile(filePath string) image.Image { return i } - func main() { source := loadFromPngFile("../resource/image/TestAndroid.png") dest := image.NewRGBA(image.Rect(0, 0, 1024, 768)) @@ -63,9 +61,9 @@ func main() { //tr.Scale(3, 3) tr.Translate(-width/2, -height/2) tr.Translate(200, 5) - lastTime := time.Nanoseconds() + lastTime := time.Now() draw2d.DrawImage(source, dest, tr, draw.Over, draw2d.BilinearFilter) - dt := time.Nanoseconds() - lastTime + dt := time.Now().Sub(lastTime) fmt.Printf("Draw image: %f ms\n", float64(dt)*1e-6) saveToPngFile("../resource/result/TestDrawImage.png", dest) } diff --git a/cmd/testpostscript.go b/cmd/testpostscript.go index 157eff1..735843c 100644 --- a/cmd/testpostscript.go +++ b/cmd/testpostscript.go @@ -1,21 +1,19 @@ package main - import ( - "fmt" - "time" - "log" - "os" - "io/ioutil" "bufio" - "strings" + "code.google.com/p/draw2d/draw2d" + "code.google.com/p/draw2d/postscript" + "fmt" "image" "image/png" - "draw2d.googlecode.com/hg/draw2d" - "draw2d.googlecode.com/hg/postscript" + "io/ioutil" + "log" + "os" + "strings" + "time" ) - func saveToPngFile(filePath string, m image.Image) { f, err := os.Create(filePath) if err != nil { @@ -51,9 +49,9 @@ func main() { bytes, err := ioutil.ReadAll(src) reader := strings.NewReader(string(bytes)) interpreter := postscript.NewInterpreter(gc) - lastTime := time.Nanoseconds() + lastTime := time.Now() interpreter.Execute(reader) - dt := time.Nanoseconds() - lastTime + dt := time.Now().Sub(lastTime) fmt.Printf("Draw image: %f ms\n", float64(dt)*1e-6) saveToPngFile("../resource/result/TestPostscript.png", i) } diff --git a/draw2d/Makefile b/draw2d/Makefile index 036f105..a68287c 100644 --- a/draw2d/Makefile +++ b/draw2d/Makefile @@ -1,6 +1,6 @@ include $(GOROOT)/src/Make.inc -TARG=draw2d.googlecode.com/hg/draw2d +TARG=code.google.com/p/draw2d/draw2d GOFILES=\ draw2d.go\ arc.go\ diff --git a/draw2d/arc.go b/draw2d/arc.go index 69db1ea..7e8b78e 100644 --- a/draw2d/arc.go +++ b/draw2d/arc.go @@ -3,7 +3,7 @@ package draw2d import ( - "freetype-go.googlecode.com/hg/freetype/raster" + "code.google.com/p/freetype-go/freetype/raster" "math" ) @@ -13,7 +13,7 @@ func arc(t VertexConverter, x, y, rx, ry, start, angle, scale float64) (lastX, l if angle < 0 { clockWise = false } - ra := (math.Fabs(rx) + math.Fabs(ry)) / 2 + ra := (math.Abs(rx) + math.Abs(ry)) / 2 da := math.Acos(ra/(ra+0.125/scale)) * 2 //normalize if !clockWise { @@ -36,14 +36,13 @@ func arc(t VertexConverter, x, y, rx, ry, start, angle, scale float64) (lastX, l return curX, curY } - func arcAdder(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.Fabs(rx) + math.Fabs(ry)) / 2 + ra := (math.Abs(rx) + math.Abs(ry)) / 2 da := math.Acos(ra/(ra+0.125/scale)) * 2 //normalize if !clockWise { diff --git a/draw2d/curve/_testmain.go b/draw2d/curve/_testmain.go index eff0174..e0b6f45 100644 --- a/draw2d/curve/_testmain.go +++ b/draw2d/curve/_testmain.go @@ -1,6 +1,6 @@ package main -import "draw2d.googlecode.com/hg/draw2d/curve" +import "code.google.com/p/draw2d/draw2d/curve" import "testing" import __os__ "os" import __regexp__ "regexp" @@ -14,7 +14,7 @@ var tests = []testing.InternalTest{ {"curve.TestQuadCurve", curve.TestQuadCurve}, } -var benchmarks = []testing.InternalBenchmark{ {"curve.BenchmarkCubicCurveRec", curve.BenchmarkCubicCurveRec}, +var benchmarks = []testing.InternalBenchmark{{"curve.BenchmarkCubicCurveRec", curve.BenchmarkCubicCurveRec}, {"curve.BenchmarkCubicCurve", curve.BenchmarkCubicCurve}, {"curve.BenchmarkCubicCurveAdaptiveRec", curve.BenchmarkCubicCurveAdaptiveRec}, {"curve.BenchmarkCubicCurveAdaptive", curve.BenchmarkCubicCurveAdaptive}, diff --git a/draw2d/curve/arc.go b/draw2d/curve/arc.go index 7e560be..d96011b 100644 --- a/draw2d/curve/arc.go +++ b/draw2d/curve/arc.go @@ -3,7 +3,7 @@ package draw2d import ( - "freetype-go.googlecode.com/hg/freetype/raster" + "code.google.com/p/freetype-go/freetype/raster" "math" ) @@ -13,7 +13,7 @@ func SegmentArc(t LineTracer, x, y, rx, ry, start, angle, scale float64) { if angle < 0 { clockWise = false } - ra := (math.Fabs(rx) + math.Fabs(ry)) / 2 + ra := (math.Abs(rx) + math.Abs(ry)) / 2 da := math.Acos(ra/(ra+0.125/scale)) * 2 //normalize if !clockWise { diff --git a/draw2d/curve/cubic_float64.go b/draw2d/curve/cubic_float64.go index d33c582..ee7eeb7 100644 --- a/draw2d/curve/cubic_float64.go +++ b/draw2d/curve/cubic_float64.go @@ -1,67 +1,67 @@ // Copyright 2010 The draw2d Authors. All rights reserved. // created: 17/05/2011 by Laurent Le Goff -package curve - -import ( - "math" -) - -const ( - CurveRecursionLimit = 32 -) - +package curve + +import ( + "math" +) + +const ( + CurveRecursionLimit = 32 +) + // X1, Y1, X2, Y2, X3, Y3, X4, Y4 float64 -type CubicCurveFloat64 [8]float64 - -type LineTracer interface { - LineTo(x, y float64) -} - -func (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) (x23, y23 float64) { +type CubicCurveFloat64 [8]float64 + +type LineTracer interface { + LineTo(x, y float64) +} + +func (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) (x23, y23 float64) { // Calculate all the mid-points of the line segments //---------------------- - c1[0], c1[1] = c[0], c[1] - c2[6], c2[7] = c[6], c[7] - c1[2] = (c[0] + c[2]) / 2 - c1[3] = (c[1] + c[3]) / 2 - x23 = (c[2] + c[4]) / 2 - y23 = (c[3] + c[5]) / 2 - c2[4] = (c[4] + c[6]) / 2 - c2[5] = (c[5] + c[7]) / 2 - c1[4] = (c1[2] + x23) / 2 - c1[5] = (c1[3] + y23) / 2 - c2[2] = (x23 + c2[4]) / 2 - c2[3] = (y23 + c2[5]) / 2 - c1[6] = (c1[4] + c2[2]) / 2 - c1[7] = (c1[5] + c2[3]) / 2 - c2[0], c2[1] = c1[6], c1[7] - return -} - -func (curve *CubicCurveFloat64) Segment(t LineTracer, flattening_threshold float64) { - var curves [CurveRecursionLimit]CubicCurveFloat64 - curves[0] = *curve - i := 0 + c1[0], c1[1] = c[0], c[1] + c2[6], c2[7] = c[6], c[7] + c1[2] = (c[0] + c[2]) / 2 + c1[3] = (c[1] + c[3]) / 2 + x23 = (c[2] + c[4]) / 2 + y23 = (c[3] + c[5]) / 2 + c2[4] = (c[4] + c[6]) / 2 + c2[5] = (c[5] + c[7]) / 2 + c1[4] = (c1[2] + x23) / 2 + c1[5] = (c1[3] + y23) / 2 + c2[2] = (x23 + c2[4]) / 2 + c2[3] = (y23 + c2[5]) / 2 + c1[6] = (c1[4] + c2[2]) / 2 + c1[7] = (c1[5] + c2[3]) / 2 + c2[0], c2[1] = c1[6], c1[7] + return +} + +func (curve *CubicCurveFloat64) Segment(t LineTracer, flattening_threshold float64) { + var curves [CurveRecursionLimit]CubicCurveFloat64 + curves[0] = *curve + i := 0 // current curve - var c *CubicCurveFloat64 - - var dx, dy, d2, d3 float64 - - for i >= 0 { - c = &curves[i] - dx = c[6] - c[0] - dy = c[7] - c[1] - - d2 = math.Fabs(((c[2]-c[6])*dy - (c[3]-c[7])*dx)) - d3 = math.Fabs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) - - if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 { - t.LineTo(c[6], c[7]) - i-- - } else { + var c *CubicCurveFloat64 + + var dx, dy, d2, d3 float64 + + for i >= 0 { + c = &curves[i] + 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 (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 - c.Subdivide(&curves[i+1], &curves[i]) - i++ - } - } -} + c.Subdivide(&curves[i+1], &curves[i]) + i++ + } + } +} diff --git a/draw2d/curve/cubic_float64_others.go b/draw2d/curve/cubic_float64_others.go index 4b915e8..2b99455 100644 --- a/draw2d/curve/cubic_float64_others.go +++ b/draw2d/curve/cubic_float64_others.go @@ -1,94 +1,93 @@ // Copyright 2010 The draw2d Authors. All rights reserved. // created: 17/05/2011 by Laurent Le Goff -package curve - -import ( - "math" -) - -const ( - CurveCollinearityEpsilon = 1e-30 - CurveAngleToleranceEpsilon = 0.01 -) - - +package curve + +import ( + "math" +) + +const ( + CurveCollinearityEpsilon = 1e-30 + CurveAngleToleranceEpsilon = 0.01 +) + //mu ranges from 0 to 1, start to end of curve -func (c *CubicCurveFloat64) ArbitraryPoint(mu float64) (x, y float64) { - - mum1 := 1 - mu - mum13 := mum1 * mum1 * mum1 - mu3 := mu * mu * mu - - x = mum13*c[0] + 3*mu*mum1*mum1*c[2] + 3*mu*mu*mum1*c[4] + mu3*c[6] - y = mum13*c[1] + 3*mu*mum1*mum1*c[3] + 3*mu*mu*mum1*c[5] + mu3*c[7] - return -} - -func (c *CubicCurveFloat64) SubdivideAt(c1, c2 *CubicCurveFloat64, t float64) (x23, y23 float64) { - inv_t := (1 - t) - c1[0], c1[1] = c[0], c[1] - c2[6], c2[7] = c[6], c[7] - - c1[2] = inv_t*c[0] + t*c[2] - c1[3] = inv_t*c[1] + t*c[3] - - x23 = inv_t*c[2] + t*c[4] - y23 = inv_t*c[3] + t*c[5] - - c2[4] = inv_t*c[4] + t*c[6] - c2[5] = inv_t*c[5] + t*c[7] - - c1[4] = inv_t*c1[2] + t*x23 - c1[5] = inv_t*c1[3] + t*y23 - - c2[2] = inv_t*x23 + t*c2[4] - c2[3] = inv_t*y23 + t*c2[5] - - c1[6] = inv_t*c1[4] + t*c2[2] - c1[7] = inv_t*c1[5] + t*c2[3] - - c2[0], c2[1] = c1[6], c1[7] - return -} - -func (c *CubicCurveFloat64) EstimateDistance() float64 { - dx1 := c[2] - c[0] - dy1 := c[3] - c[1] - dx2 := c[4] - c[2] - dy2 := c[5] - c[3] - dx3 := c[6] - c[4] - dy3 := c[7] - c[5] - return math.Sqrt(dx1*dx1+dy1*dy1) + math.Sqrt(dx2*dx2+dy2*dy2) + math.Sqrt(dx3*dx3+dy3*dy3) -} - +func (c *CubicCurveFloat64) ArbitraryPoint(mu float64) (x, y float64) { + + mum1 := 1 - mu + mum13 := mum1 * mum1 * mum1 + mu3 := mu * mu * mu + + x = mum13*c[0] + 3*mu*mum1*mum1*c[2] + 3*mu*mu*mum1*c[4] + mu3*c[6] + y = mum13*c[1] + 3*mu*mum1*mum1*c[3] + 3*mu*mu*mum1*c[5] + mu3*c[7] + return +} + +func (c *CubicCurveFloat64) SubdivideAt(c1, c2 *CubicCurveFloat64, t float64) (x23, y23 float64) { + inv_t := (1 - t) + c1[0], c1[1] = c[0], c[1] + c2[6], c2[7] = c[6], c[7] + + c1[2] = inv_t*c[0] + t*c[2] + c1[3] = inv_t*c[1] + t*c[3] + + x23 = inv_t*c[2] + t*c[4] + y23 = inv_t*c[3] + t*c[5] + + c2[4] = inv_t*c[4] + t*c[6] + c2[5] = inv_t*c[5] + t*c[7] + + c1[4] = inv_t*c1[2] + t*x23 + c1[5] = inv_t*c1[3] + t*y23 + + c2[2] = inv_t*x23 + t*c2[4] + c2[3] = inv_t*y23 + t*c2[5] + + c1[6] = inv_t*c1[4] + t*c2[2] + c1[7] = inv_t*c1[5] + t*c2[3] + + c2[0], c2[1] = c1[6], c1[7] + return +} + +func (c *CubicCurveFloat64) EstimateDistance() float64 { + dx1 := c[2] - c[0] + dy1 := c[3] - c[1] + dx2 := c[4] - c[2] + dy2 := c[5] - c[3] + dx3 := c[6] - c[4] + dy3 := c[7] - c[5] + return math.Sqrt(dx1*dx1+dy1*dy1) + math.Sqrt(dx2*dx2+dy2*dy2) + math.Sqrt(dx3*dx3+dy3*dy3) +} + // subdivide the curve in straight lines using line approximation and Casteljau recursive subdivision -func (c *CubicCurveFloat64) SegmentRec(t LineTracer, flattening_threshold float64) { - c.segmentRec(t, flattening_threshold) - t.LineTo(c[6], c[7]) -} - -func (c *CubicCurveFloat64) segmentRec(t LineTracer, flattening_threshold float64) { - var c1, c2 CubicCurveFloat64 - c.Subdivide(&c1, &c2) - +func (c *CubicCurveFloat64) SegmentRec(t LineTracer, flattening_threshold float64) { + c.segmentRec(t, flattening_threshold) + t.LineTo(c[6], c[7]) +} + +func (c *CubicCurveFloat64) segmentRec(t LineTracer, flattening_threshold float64) { + var c1, c2 CubicCurveFloat64 + c.Subdivide(&c1, &c2) + // Try to approximate the full cubic curve by a single straight line //------------------ - dx := c[6] - c[0] - dy := c[7] - c[1] - - d2 := math.Fabs(((c[2]-c[6])*dy - (c[3]-c[7])*dx)) - d3 := math.Fabs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) - - if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) { - t.LineTo(c[6], c[7]) - return - } + 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 (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) { + t.LineTo(c[6], c[7]) + return + } // Continue subdivision //---------------------- - c1.segmentRec(t, flattening_threshold) - c2.segmentRec(t, flattening_threshold) -} - + c1.segmentRec(t, flattening_threshold) + c2.segmentRec(t, flattening_threshold) +} + /* The function has the following parameters: approximationScale : @@ -108,593 +107,590 @@ func (c *CubicCurveFloat64) segmentRec(t LineTracer, flattening_threshold float6 If more than 0, it will restrict the sharpness. The more this value is the less sharp turns will be cut. Typically it should not exceed 10-15 degrees. -*/ -func (c *CubicCurveFloat64) AdaptiveSegmentRec(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) { - cuspLimit = computeCuspLimit(cuspLimit) - distanceToleranceSquare := 0.5 / approximationScale - distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare - c.adaptiveSegmentRec(t, 0, distanceToleranceSquare, angleTolerance, cuspLimit) - t.LineTo(c[6], c[7]) -} - -func computeCuspLimit(v float64) (r float64) { - if v == 0.0 { - r = 0.0 - } else { - r = math.Pi - v - } - return -} - -func squareDistance(x1, y1, x2, y2 float64) float64 { - dx := x2 - x1 - dy := y2 - y1 - return dx*dx + dy*dy -} - +*/ +func (c *CubicCurveFloat64) AdaptiveSegmentRec(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) { + cuspLimit = computeCuspLimit(cuspLimit) + distanceToleranceSquare := 0.5 / approximationScale + distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare + c.adaptiveSegmentRec(t, 0, distanceToleranceSquare, angleTolerance, cuspLimit) + t.LineTo(c[6], c[7]) +} + +func computeCuspLimit(v float64) (r float64) { + if v == 0.0 { + r = 0.0 + } else { + r = math.Pi - v + } + return +} + +func squareDistance(x1, y1, x2, y2 float64) float64 { + dx := x2 - x1 + dy := y2 - y1 + return dx*dx + dy*dy +} + /** * http://www.antigrain.com/research/adaptive_bezier/index.html - */ -func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) { - if level > CurveRecursionLimit { - return - } - var c1, c2 CubicCurveFloat64 - x23, y23 := c.Subdivide(&c1, &c2) - + */ +func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) { + if level > CurveRecursionLimit { + return + } + var c1, c2 CubicCurveFloat64 + x23, y23 := c.Subdivide(&c1, &c2) + // Try to approximate the full cubic curve by a single straight line //------------------ - dx := c[6] - c[0] - dy := c[7] - c[1] - - d2 := math.Fabs(((c[2]-c[6])*dy - (c[3]-c[7])*dx)) - d3 := math.Fabs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) - switch { - case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: + 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)) + switch { + case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: // All collinear OR p1==p4 //---------------------- - k := dx*dx + dy*dy - if k == 0 { - d2 = squareDistance(c[0], c[1], c[2], c[3]) - d3 = squareDistance(c[6], c[7], c[4], c[5]) - } else { - k = 1 / k - da1 := c[2] - c[0] - da2 := c[3] - c[1] - d2 = k * (da1*dx + da2*dy) - da1 = c[4] - c[0] - da2 = c[5] - c[1] - d3 = k * (da1*dx + da2*dy) - if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 { + k := dx*dx + dy*dy + if k == 0 { + d2 = squareDistance(c[0], c[1], c[2], c[3]) + d3 = squareDistance(c[6], c[7], c[4], c[5]) + } else { + k = 1 / k + da1 := c[2] - c[0] + da2 := c[3] - c[1] + d2 = k * (da1*dx + da2*dy) + da1 = c[4] - c[0] + da2 = c[5] - c[1] + d3 = k * (da1*dx + da2*dy) + if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 { // Simple collinear case, 1---2---3---4 // We can leave just two endpoints - return - } - if d2 <= 0 { - d2 = squareDistance(c[2], c[3], c[0], c[1]) - } else if d2 >= 1 { - d2 = squareDistance(c[2], c[3], c[6], c[7]) - } else { - d2 = squareDistance(c[2], c[3], c[0]+d2*dx, c[1]+d2*dy) - } - - if d3 <= 0 { - d3 = squareDistance(c[4], c[5], c[0], c[1]) - } else if d3 >= 1 { - d3 = squareDistance(c[4], c[5], c[6], c[7]) - } else { - d3 = squareDistance(c[4], c[5], c[0]+d3*dx, c[1]+d3*dy) - } - } - if d2 > d3 { - if d2 < distanceToleranceSquare { - t.LineTo(c[2], c[3]) - return - } - } else { - if d3 < distanceToleranceSquare { - t.LineTo(c[4], c[5]) - return - } - } - - case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: + return + } + if d2 <= 0 { + d2 = squareDistance(c[2], c[3], c[0], c[1]) + } else if d2 >= 1 { + d2 = squareDistance(c[2], c[3], c[6], c[7]) + } else { + d2 = squareDistance(c[2], c[3], c[0]+d2*dx, c[1]+d2*dy) + } + + if d3 <= 0 { + d3 = squareDistance(c[4], c[5], c[0], c[1]) + } else if d3 >= 1 { + d3 = squareDistance(c[4], c[5], c[6], c[7]) + } else { + d3 = squareDistance(c[4], c[5], c[0]+d3*dx, c[1]+d3*dy) + } + } + if d2 > d3 { + if d2 < distanceToleranceSquare { + t.LineTo(c[2], c[3]) + return + } + } else { + if d3 < distanceToleranceSquare { + t.LineTo(c[4], c[5]) + return + } + } + + case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: // p1,p2,p4 are collinear, p3 is significant //---------------------- - if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) { - if angleTolerance < CurveAngleToleranceEpsilon { - t.LineTo(x23, y23) - return - } - + if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) { + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + return + } + // Angle Condition //---------------------- - da1 := math.Fabs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2])) - if da1 >= math.Pi { - da1 = 2*math.Pi - da1 - } - - if da1 < angleTolerance { - t.LineTo(c[2], c[3]) - t.LineTo(c[4], c[5]) - return - } - - if cuspLimit != 0.0 { - if da1 > cuspLimit { - t.LineTo(c[4], c[5]) - return - } - } - } - - case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: + da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2])) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + + if da1 < angleTolerance { + t.LineTo(c[2], c[3]) + t.LineTo(c[4], c[5]) + return + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[4], c[5]) + return + } + } + } + + case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: // p1,p3,p4 are collinear, p2 is significant //---------------------- - if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) { - if angleTolerance < CurveAngleToleranceEpsilon { - t.LineTo(x23, y23) - return - } - + if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) { + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + return + } + // Angle Condition //---------------------- - da1 := math.Fabs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0])) - if da1 >= math.Pi { - da1 = 2*math.Pi - da1 - } - - if da1 < angleTolerance { - t.LineTo(c[2], c[3]) - t.LineTo(c[4], c[5]) - return - } - - if cuspLimit != 0.0 { - if da1 > cuspLimit { - t.LineTo(c[2], c[3]) - return - } - } - } - - case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: + da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0])) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + + if da1 < angleTolerance { + t.LineTo(c[2], c[3]) + t.LineTo(c[4], c[5]) + return + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[2], c[3]) + return + } + } + } + + case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: // Regular case //----------------- - if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) { + if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) { // If the curvature doesn't exceed the distanceTolerance value // we tend to finish subdivisions. //---------------------- - if angleTolerance < CurveAngleToleranceEpsilon { - t.LineTo(x23, y23) - return - } - + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + return + } + // Angle & Cusp Condition //---------------------- - k := math.Atan2(c[5]-c[3], c[4]-c[2]) - da1 := math.Fabs(k - math.Atan2(c[3]-c[1], c[2]-c[0])) - da2 := math.Fabs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k) - if da1 >= math.Pi { - da1 = 2*math.Pi - da1 - } - if da2 >= math.Pi { - da2 = 2*math.Pi - da2 - } - - if da1+da2 < angleTolerance { + k := math.Atan2(c[5]-c[3], c[4]-c[2]) + da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0])) + da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + if da2 >= math.Pi { + da2 = 2*math.Pi - da2 + } + + if da1+da2 < angleTolerance { // Finally we can stop the recursion //---------------------- - t.LineTo(x23, y23) - return - } - - if cuspLimit != 0.0 { - if da1 > cuspLimit { - t.LineTo(c[2], c[3]) - return - } - - if da2 > cuspLimit { - t.LineTo(c[4], c[5]) - return - } - } - } - } - + t.LineTo(x23, y23) + return + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[2], c[3]) + return + } + + if da2 > cuspLimit { + t.LineTo(c[4], c[5]) + return + } + } + } + } + // Continue subdivision //---------------------- - c1.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit) - c2.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit) - -} - -func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) { - cuspLimit = computeCuspLimit(cuspLimit) - distanceToleranceSquare := 0.5 / approximationScale - distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare - - var curves [CurveRecursionLimit]CubicCurveFloat64 - curves[0] = *curve - i := 0 + c1.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit) + c2.adaptiveSegmentRec(t, level+1, distanceToleranceSquare, angleTolerance, cuspLimit) + +} + +func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) { + cuspLimit = computeCuspLimit(cuspLimit) + distanceToleranceSquare := 0.5 / approximationScale + distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare + + var curves [CurveRecursionLimit]CubicCurveFloat64 + curves[0] = *curve + i := 0 // current curve - var c *CubicCurveFloat64 - var c1, c2 CubicCurveFloat64 - var dx, dy, d2, d3, k, x23, y23 float64 - for i >= 0 { - c = &curves[i] - x23, y23 = c.Subdivide(&c1, &c2) - + var c *CubicCurveFloat64 + var c1, c2 CubicCurveFloat64 + var dx, dy, d2, d3, k, x23, y23 float64 + for i >= 0 { + c = &curves[i] + x23, y23 = c.Subdivide(&c1, &c2) + // Try to approximate the full cubic curve by a single straight line //------------------ - dx = c[6] - c[0] - dy = c[7] - c[1] - - d2 = math.Fabs(((c[2]-c[6])*dy - (c[3]-c[7])*dx)) - d3 = math.Fabs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) - switch { - case i == len(curves)-1: - t.LineTo(c[6], c[7]) - i-- - continue - case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: + 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)) + switch { + case i == len(curves)-1: + t.LineTo(c[6], c[7]) + i-- + continue + case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: // All collinear OR p1==p4 //---------------------- - k = dx*dx + dy*dy - if k == 0 { - d2 = squareDistance(c[0], c[1], c[2], c[3]) - d3 = squareDistance(c[6], c[7], c[4], c[5]) - } else { - k = 1 / k - da1 := c[2] - c[0] - da2 := c[3] - c[1] - d2 = k * (da1*dx + da2*dy) - da1 = c[4] - c[0] - da2 = c[5] - c[1] - d3 = k * (da1*dx + da2*dy) - if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 { + k = dx*dx + dy*dy + if k == 0 { + d2 = squareDistance(c[0], c[1], c[2], c[3]) + d3 = squareDistance(c[6], c[7], c[4], c[5]) + } else { + k = 1 / k + da1 := c[2] - c[0] + da2 := c[3] - c[1] + d2 = k * (da1*dx + da2*dy) + da1 = c[4] - c[0] + da2 = c[5] - c[1] + d3 = k * (da1*dx + da2*dy) + if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 { // Simple collinear case, 1---2---3---4 // We can leave just two endpoints - i-- - continue - } - if d2 <= 0 { - d2 = squareDistance(c[2], c[3], c[0], c[1]) - } else if d2 >= 1 { - d2 = squareDistance(c[2], c[3], c[6], c[7]) - } else { - d2 = squareDistance(c[2], c[3], c[0]+d2*dx, c[1]+d2*dy) - } - - if d3 <= 0 { - d3 = squareDistance(c[4], c[5], c[0], c[1]) - } else if d3 >= 1 { - d3 = squareDistance(c[4], c[5], c[6], c[7]) - } else { - d3 = squareDistance(c[4], c[5], c[0]+d3*dx, c[1]+d3*dy) - } - } - if d2 > d3 { - if d2 < distanceToleranceSquare { - t.LineTo(c[2], c[3]) - i-- - continue - } - } else { - if d3 < distanceToleranceSquare { - t.LineTo(c[4], c[5]) - i-- - continue - } - } - - case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: + i-- + continue + } + if d2 <= 0 { + d2 = squareDistance(c[2], c[3], c[0], c[1]) + } else if d2 >= 1 { + d2 = squareDistance(c[2], c[3], c[6], c[7]) + } else { + d2 = squareDistance(c[2], c[3], c[0]+d2*dx, c[1]+d2*dy) + } + + if d3 <= 0 { + d3 = squareDistance(c[4], c[5], c[0], c[1]) + } else if d3 >= 1 { + d3 = squareDistance(c[4], c[5], c[6], c[7]) + } else { + d3 = squareDistance(c[4], c[5], c[0]+d3*dx, c[1]+d3*dy) + } + } + if d2 > d3 { + if d2 < distanceToleranceSquare { + t.LineTo(c[2], c[3]) + i-- + continue + } + } else { + if d3 < distanceToleranceSquare { + t.LineTo(c[4], c[5]) + i-- + continue + } + } + + case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: // p1,p2,p4 are collinear, p3 is significant //---------------------- - if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) { - if angleTolerance < CurveAngleToleranceEpsilon { - t.LineTo(x23, y23) - i-- - continue - } - + if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) { + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + i-- + continue + } + // Angle Condition //---------------------- - da1 := math.Fabs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2])) - if da1 >= math.Pi { - da1 = 2*math.Pi - da1 - } - - if da1 < angleTolerance { - t.LineTo(c[2], c[3]) - t.LineTo(c[4], c[5]) - i-- - continue - } - - if cuspLimit != 0.0 { - if da1 > cuspLimit { - t.LineTo(c[4], c[5]) - i-- - continue - } - } - } - - case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: + da1 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - math.Atan2(c[5]-c[3], c[4]-c[2])) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + + if da1 < angleTolerance { + t.LineTo(c[2], c[3]) + t.LineTo(c[4], c[5]) + i-- + continue + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[4], c[5]) + i-- + continue + } + } + } + + case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: // p1,p3,p4 are collinear, p2 is significant //---------------------- - if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) { - if angleTolerance < CurveAngleToleranceEpsilon { - t.LineTo(x23, y23) - i-- - continue - } - + if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) { + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + i-- + continue + } + // Angle Condition //---------------------- - da1 := math.Fabs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0])) - if da1 >= math.Pi { - da1 = 2*math.Pi - da1 - } - - if da1 < angleTolerance { - t.LineTo(c[2], c[3]) - t.LineTo(c[4], c[5]) - i-- - continue - } - - if cuspLimit != 0.0 { - if da1 > cuspLimit { - t.LineTo(c[2], c[3]) - i-- - continue - } - } - } - - case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: + da1 := math.Abs(math.Atan2(c[5]-c[3], c[4]-c[2]) - math.Atan2(c[3]-c[1], c[2]-c[0])) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + + if da1 < angleTolerance { + t.LineTo(c[2], c[3]) + t.LineTo(c[4], c[5]) + i-- + continue + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[2], c[3]) + i-- + continue + } + } + } + + case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon: // Regular case //----------------- - if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) { + if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) { // If the curvature doesn't exceed the distanceTolerance value // we tend to finish subdivisions. //---------------------- - if angleTolerance < CurveAngleToleranceEpsilon { - t.LineTo(x23, y23) - i-- - continue - } - + if angleTolerance < CurveAngleToleranceEpsilon { + t.LineTo(x23, y23) + i-- + continue + } + // Angle & Cusp Condition //---------------------- - k := math.Atan2(c[5]-c[3], c[4]-c[2]) - da1 := math.Fabs(k - math.Atan2(c[3]-c[1], c[2]-c[0])) - da2 := math.Fabs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k) - if da1 >= math.Pi { - da1 = 2*math.Pi - da1 - } - if da2 >= math.Pi { - da2 = 2*math.Pi - da2 - } - - if da1+da2 < angleTolerance { + k := math.Atan2(c[5]-c[3], c[4]-c[2]) + da1 := math.Abs(k - math.Atan2(c[3]-c[1], c[2]-c[0])) + da2 := math.Abs(math.Atan2(c[7]-c[5], c[6]-c[4]) - k) + if da1 >= math.Pi { + da1 = 2*math.Pi - da1 + } + if da2 >= math.Pi { + da2 = 2*math.Pi - da2 + } + + if da1+da2 < angleTolerance { // Finally we can stop the recursion //---------------------- - t.LineTo(x23, y23) - i-- - continue - } - - if cuspLimit != 0.0 { - if da1 > cuspLimit { - t.LineTo(c[2], c[3]) - i-- - continue - } - - if da2 > cuspLimit { - t.LineTo(c[4], c[5]) - i-- - continue - } - } - } - } - + t.LineTo(x23, y23) + i-- + continue + } + + if cuspLimit != 0.0 { + if da1 > cuspLimit { + t.LineTo(c[2], c[3]) + i-- + continue + } + + if da2 > cuspLimit { + t.LineTo(c[4], c[5]) + i-- + continue + } + } + } + } + // Continue subdivision //---------------------- - curves[i+1], curves[i] = c1, c2 - i++ - } - t.LineTo(curve[6], curve[7]) -} - - -/********************** Ahmad thesis *******************/ - + curves[i+1], curves[i] = c1, c2 + i++ + } + t.LineTo(curve[6], curve[7]) +} + +/********************** Ahmad thesis *******************/ + /************************************************************************************** * This code is the implementation of the Parabolic Approximation (PA). Although * * it uses recursive subdivision as a safe net for the failing cases, this is an * * iterative routine and reduces considerably the number of vertices (point) * * generation. * -**************************************************************************************/ - - -func (c *CubicCurveFloat64) ParabolicSegment(t LineTracer, flattening_threshold float64) { - estimatedIFP := c.numberOfInflectionPoints() - if estimatedIFP == 0 { +**************************************************************************************/ + +func (c *CubicCurveFloat64) ParabolicSegment(t LineTracer, flattening_threshold float64) { + estimatedIFP := c.numberOfInflectionPoints() + if estimatedIFP == 0 { // If no inflection points then apply PA on the full Bezier segment. - c.doParabolicApproximation(t, flattening_threshold) - return - } + c.doParabolicApproximation(t, flattening_threshold) + return + } // If one or more inflection point then we will have to subdivide the curve - numOfIfP, t1, t2 := c.findInflectionPoints() - if numOfIfP == 2 { + numOfIfP, t1, t2 := c.findInflectionPoints() + if numOfIfP == 2 { // Case when 2 inflection points then divide at the smallest one first - var sub1, tmp1, sub2, sub3 CubicCurveFloat64 - c.SubdivideAt(&sub1, &tmp1, t1) + var sub1, tmp1, sub2, sub3 CubicCurveFloat64 + c.SubdivideAt(&sub1, &tmp1, t1) // Now find the second inflection point in the second curve an subdivide - numOfIfP, t1, t2 = tmp1.findInflectionPoints() - if numOfIfP == 2 { - tmp1.SubdivideAt(&sub2, &sub3, t2) - } else if numOfIfP == 1 { - tmp1.SubdivideAt(&sub2, &sub3, t1) - } else { - return - } + numOfIfP, t1, t2 = tmp1.findInflectionPoints() + if numOfIfP == 2 { + tmp1.SubdivideAt(&sub2, &sub3, t2) + } else if numOfIfP == 1 { + tmp1.SubdivideAt(&sub2, &sub3, t1) + } else { + return + } // Use PA for first subsegment - sub1.doParabolicApproximation(t, flattening_threshold) + sub1.doParabolicApproximation(t, flattening_threshold) // Use RS for the second (middle) subsegment - sub2.Segment(t, flattening_threshold) + sub2.Segment(t, flattening_threshold) // Drop the last point in the array will be added by the PA in third subsegment //noOfPoints--; // Use PA for the third curve - sub3.doParabolicApproximation(t, flattening_threshold) - } else if numOfIfP == 1 { + sub3.doParabolicApproximation(t, flattening_threshold) + } else if numOfIfP == 1 { // Case where there is one inflection point, subdivide once and use PA on // both subsegments - var sub1, sub2 CubicCurveFloat64 - c.SubdivideAt(&sub1, &sub2, t1) - sub1.doParabolicApproximation(t, flattening_threshold) + var sub1, sub2 CubicCurveFloat64 + c.SubdivideAt(&sub1, &sub2, t1) + sub1.doParabolicApproximation(t, flattening_threshold) //noOfPoints--; - sub2.doParabolicApproximation(t, flattening_threshold) - } else { + sub2.doParabolicApproximation(t, flattening_threshold) + } else { // Case where there is no inflection USA PA directly - c.doParabolicApproximation(t, flattening_threshold) - } -} - + c.doParabolicApproximation(t, flattening_threshold) + } +} + // Find the third control point deviation form the axis -func (c *CubicCurveFloat64) thirdControlPointDeviation() float64 { - dx := c[2] - c[0] - dy := c[3] - c[1] - l2 := dx*dx + dy*dy - if l2 == 0 { - return 0 - } - l := math.Sqrt(l2) - r := (c[3] - c[1]) / l - s := (c[0] - c[2]) / l - u := (c[2]*c[1] - c[0]*c[3]) / l - return math.Fabs(r*c[4] + s*c[5] + u) -} - +func (c *CubicCurveFloat64) thirdControlPointDeviation() float64 { + dx := c[2] - c[0] + dy := c[3] - c[1] + l2 := dx*dx + dy*dy + if l2 == 0 { + return 0 + } + l := math.Sqrt(l2) + r := (c[3] - c[1]) / l + s := (c[0] - c[2]) / l + u := (c[2]*c[1] - c[0]*c[3]) / l + return math.Abs(r*c[4] + s*c[5] + u) +} + // Find the number of inflection point -func (c *CubicCurveFloat64) numberOfInflectionPoints() int { - dx21 := (c[2] - c[0]) - dy21 := (c[3] - c[1]) - dx32 := (c[4] - c[2]) - dy32 := (c[5] - c[3]) - dx43 := (c[6] - c[4]) - dy43 := (c[7] - c[5]) - if ((dx21*dy32 - dy21*dx32) * (dx32*dy43 - dy32*dx43)) < 0 { +func (c *CubicCurveFloat64) numberOfInflectionPoints() int { + dx21 := (c[2] - c[0]) + dy21 := (c[3] - c[1]) + dx32 := (c[4] - c[2]) + dy32 := (c[5] - c[3]) + dx43 := (c[6] - c[4]) + dy43 := (c[7] - c[5]) + if ((dx21*dy32 - dy21*dx32) * (dx32*dy43 - dy32*dx43)) < 0 { return 1 // One inflection point - } else if ((dx21*dy32 - dy21*dx32) * (dx21*dy43 - dy21*dx43)) > 0 { + } else if ((dx21*dy32 - dy21*dx32) * (dx21*dy43 - dy21*dx43)) > 0 { return 0 // No inflection point - } else { + } else { // Most cases no inflection point - b1 := (dx21*dx32 + dy21*dy32) > 0 - b2 := (dx32*dx43 + dy32*dy43) > 0 + b1 := (dx21*dx32 + dy21*dy32) > 0 + b2 := (dx32*dx43 + dy32*dy43) > 0 if b1 || b2 && !(b1 && b2) { // xor!! - return 0 - } - } + return 0 + } + } return -1 // cases where there in zero or two inflection points -} - - +} + // This is the main function where all the work is done -func (curve *CubicCurveFloat64) doParabolicApproximation(tracer LineTracer, flattening_threshold float64) { - var c *CubicCurveFloat64 - c = curve - var d, t, dx, dy, d2, d3 float64 - for { - dx = c[6] - c[0] - dy = c[7] - c[1] - - d2 = math.Fabs(((c[2]-c[6])*dy - (c[3]-c[7])*dx)) - d3 = math.Fabs(((c[4]-c[6])*dy - (c[5]-c[7])*dx)) - - if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) { +func (curve *CubicCurveFloat64) doParabolicApproximation(tracer LineTracer, flattening_threshold float64) { + var c *CubicCurveFloat64 + c = curve + var d, t, dx, dy, d2, d3 float64 + for { + 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 (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) { // If the subsegment deviation satisfy the flatness then store the last // point and stop - tracer.LineTo(c[6], c[7]) - break - } + tracer.LineTo(c[6], c[7]) + break + } // Find the third control point deviation and the t values for subdivision - d = c.thirdControlPointDeviation() - t = 2 * math.Sqrt(flattening_threshold/d/3) - if t > 1 { + d = c.thirdControlPointDeviation() + t = 2 * math.Sqrt(flattening_threshold/d/3) + if t > 1 { // Case where the t value calculated is invalid so using RS - c.Segment(tracer, flattening_threshold) - break - } + c.Segment(tracer, flattening_threshold) + break + } // Valid t value to subdivide at that calculated value - var b1, b2 CubicCurveFloat64 - c.SubdivideAt(&b1, &b2, t) + var b1, b2 CubicCurveFloat64 + c.SubdivideAt(&b1, &b2, t) // First subsegment should have its deviation equal to flatness - dx = b1[6] - b1[0] - dy = b1[7] - b1[1] - - d2 = math.Fabs(((b1[2]-b1[6])*dy - (b1[3]-b1[7])*dx)) - d3 = math.Fabs(((b1[4]-b1[6])*dy - (b1[5]-b1[7])*dx)) - - if (d2+d3)*(d2+d3) > flattening_threshold*(dx*dx+dy*dy) { + dx = b1[6] - b1[0] + dy = b1[7] - b1[1] + + d2 = math.Abs(((b1[2]-b1[6])*dy - (b1[3]-b1[7])*dx)) + d3 = math.Abs(((b1[4]-b1[6])*dy - (b1[5]-b1[7])*dx)) + + if (d2+d3)*(d2+d3) > flattening_threshold*(dx*dx+dy*dy) { // if not then use RS to handle any mathematical errors - b1.Segment(tracer, flattening_threshold) - } else { - tracer.LineTo(b1[6], b1[7]) - } + b1.Segment(tracer, flattening_threshold) + } else { + tracer.LineTo(b1[6], b1[7]) + } // repeat the process for the left over subsegment. - c = &b2 - } -} - + c = &b2 + } +} + // Find the actual inflection points and return the number of inflection points found // if 2 inflection points found, the first one returned will be with smaller t value. -func (curve *CubicCurveFloat64) findInflectionPoints() (int, firstIfp, secondIfp float64) { +func (curve *CubicCurveFloat64) findInflectionPoints() (int, firstIfp, secondIfp float64) { // For Cubic Bezier curve with equation P=a*t^3 + b*t^2 + c*t + d // slope of the curve dP/dt = 3*a*t^2 + 2*b*t + c // a = (float)(-bez.p1 + 3*bez.p2 - 3*bez.p3 + bez.p4); // b = (float)(3*bez.p1 - 6*bez.p2 + 3*bez.p3); // c = (float)(-3*bez.p1 + 3*bez.p2); - ax := (-curve[0] + 3*curve[2] - 3*curve[4] + curve[6]) - bx := (3*curve[0] - 6*curve[2] + 3*curve[4]) - cx := (-3*curve[0] + 3*curve[2]) - ay := (-curve[1] + 3*curve[3] - 3*curve[5] + curve[7]) - by := (3*curve[1] - 6*curve[3] + 3*curve[5]) - cy := (-3*curve[1] + 3*curve[3]) - a := (3 * (ay*bx - ax*by)) - b := (3 * (ay*cx - ax*cy)) - c := (by*cx - bx*cy) - r2 := (b*b - 4*a*c) - firstIfp = 0.0 - secondIfp = 0.0 - if r2 >= 0.0 && a != 0.0 { - r := math.Sqrt(r2) - firstIfp = ((-b + r) / (2 * a)) - secondIfp = ((-b - r) / (2 * a)) - if (firstIfp > 0.0 && firstIfp < 1.0) && (secondIfp > 0.0 && secondIfp < 1.0) { - if firstIfp > secondIfp { - tmp := firstIfp - firstIfp = secondIfp - secondIfp = tmp - } - if secondIfp-firstIfp > 0.00001 { - return 2, firstIfp, secondIfp - } else { - return 1, firstIfp, secondIfp - } - } else if firstIfp > 0.0 && firstIfp < 1.0 { - return 1, firstIfp, secondIfp - } else if secondIfp > 0.0 && secondIfp < 1.0 { - firstIfp = secondIfp - return 1, firstIfp, secondIfp - } - return 0, firstIfp, secondIfp - } - return 0, firstIfp, secondIfp -} + ax := (-curve[0] + 3*curve[2] - 3*curve[4] + curve[6]) + bx := (3*curve[0] - 6*curve[2] + 3*curve[4]) + cx := (-3*curve[0] + 3*curve[2]) + ay := (-curve[1] + 3*curve[3] - 3*curve[5] + curve[7]) + by := (3*curve[1] - 6*curve[3] + 3*curve[5]) + cy := (-3*curve[1] + 3*curve[3]) + a := (3 * (ay*bx - ax*by)) + b := (3 * (ay*cx - ax*cy)) + c := (by*cx - bx*cy) + r2 := (b*b - 4*a*c) + firstIfp = 0.0 + secondIfp = 0.0 + if r2 >= 0.0 && a != 0.0 { + r := math.Sqrt(r2) + firstIfp = ((-b + r) / (2 * a)) + secondIfp = ((-b - r) / (2 * a)) + if (firstIfp > 0.0 && firstIfp < 1.0) && (secondIfp > 0.0 && secondIfp < 1.0) { + if firstIfp > secondIfp { + tmp := firstIfp + firstIfp = secondIfp + secondIfp = tmp + } + if secondIfp-firstIfp > 0.00001 { + return 2, firstIfp, secondIfp + } else { + return 1, firstIfp, secondIfp + } + } else if firstIfp > 0.0 && firstIfp < 1.0 { + return 1, firstIfp, secondIfp + } else if secondIfp > 0.0 && secondIfp < 1.0 { + firstIfp = secondIfp + return 1, firstIfp, secondIfp + } + return 0, firstIfp, secondIfp + } + return 0, firstIfp, secondIfp +} diff --git a/draw2d/curve/curve_test.go b/draw2d/curve/curve_test.go index 7c3ff5e..496466d 100644 --- a/draw2d/curve/curve_test.go +++ b/draw2d/curve/curve_test.go @@ -1,94 +1,94 @@ -package curve - -import ( - "testing" - "log" - "fmt" - "os" - "bufio" - "image" - "image/png" - "image/draw" - "draw2d.googlecode.com/hg/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}, - } - 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 image.Color, s ...float64) image.Image { +package curve + +import ( + "bufio" + "code.google.com/p/draw2d/draw2d/raster" + "fmt" + "image" + "image/color" + "image/draw" + "image/png" + "log" + "os" + "testing" +) + +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}, + } + 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) @@ -100,164 +100,163 @@ func drawPoints(img draw.Image, c image.Color, s ...float64) image.Image { 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, flattening_threshold) - img := image.NewNRGBA(300, 300) - raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve[:]...) - raster.PolylineBresenham(img, image.Black, p.points...) + + }*/ + return img +} + +func TestCubicCurveRec(t *testing.T) { + for i, curve := range testsCubicFloat64 { + var p Path + p.LineTo(curve[0], curve[1]) + curve.SegmentRec(&p, flattening_threshold) + 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, image.NRGBAColor{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, flattening_threshold) - img := image.NewNRGBA(300, 300) - raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve[:]...) - raster.PolylineBresenham(img, image.Black, p.points...) + 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, flattening_threshold) + 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, image.NRGBAColor{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(300, 300) - raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve[:]...) - raster.PolylineBresenham(img, image.Black, p.points...) + 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, image.NRGBAColor{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(300, 300) - raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve[:]...) - raster.PolylineBresenham(img, image.Black, p.points...) + 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, image.NRGBAColor{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, flattening_threshold) - img := image.NewNRGBA(300, 300) - raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve[:]...) - raster.PolylineBresenham(img, image.Black, p.points...) + 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, flattening_threshold) + 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, image.NRGBAColor{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, flattening_threshold) - img := image.NewNRGBA(300, 300) - raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve[:]...) - raster.PolylineBresenham(img, image.Black, p.points...) + 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, flattening_threshold) + 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, image.NRGBAColor{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, flattening_threshold) - } - } -} - -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, flattening_threshold) - } - } -} - -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, flattening_threshold) - } - } -} - -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, flattening_threshold) - } - } -} + 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, flattening_threshold) + } + } +} + +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, flattening_threshold) + } + } +} + +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, flattening_threshold) + } + } +} + +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, flattening_threshold) + } + } +} diff --git a/draw2d/curve/quad_float64.go b/draw2d/curve/quad_float64.go index c1e5989..91584f3 100644 --- a/draw2d/curve/quad_float64.go +++ b/draw2d/curve/quad_float64.go @@ -1,53 +1,51 @@ // Copyright 2010 The draw2d Authors. All rights reserved. // created: 17/05/2011 by Laurent Le Goff -package curve - -import ( - "math" -) +package curve + +import ( + "math" +) + //X1, Y1, X2, Y2, X3, Y3 float64 -type QuadCurveFloat64 [6]float64 - - - -func (c *QuadCurveFloat64) Subdivide(c1, c2 *QuadCurveFloat64) { +type QuadCurveFloat64 [6]float64 + +func (c *QuadCurveFloat64) Subdivide(c1, c2 *QuadCurveFloat64) { // Calculate all the mid-points of the line segments //---------------------- - c1[0], c1[1] = c[0], c[1] - c2[4], c2[5] = c[4], c[5] - 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 -} - - -func (curve *QuadCurveFloat64) Segment(t LineTracer, flattening_threshold float64) { - var curves [CurveRecursionLimit]QuadCurveFloat64 - curves[0] = *curve - i := 0 + c1[0], c1[1] = c[0], c[1] + c2[4], c2[5] = c[4], c[5] + 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 +} + +func (curve *QuadCurveFloat64) Segment(t LineTracer, flattening_threshold float64) { + var curves [CurveRecursionLimit]QuadCurveFloat64 + curves[0] = *curve + i := 0 // current curve - var c *QuadCurveFloat64 - var dx, dy, d float64 - - for i >= 0 { - c = &curves[i] - dx = c[4] - c[0] - dy = c[5] - c[1] - - d = math.Fabs(((c[2]-c[4])*dy - (c[3]-c[5])*dx)) - - if (d*d) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 { - t.LineTo(c[4], c[5]) - i-- - } else { + var c *QuadCurveFloat64 + var dx, dy, d float64 + + for i >= 0 { + c = &curves[i] + dx = c[4] - c[0] + dy = c[5] - c[1] + + d = math.Abs(((c[2]-c[4])*dy - (c[3]-c[5])*dx)) + + 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 - c.Subdivide(&curves[i+1], &curves[i]) - i++ - } - } -} + c.Subdivide(&curves[i+1], &curves[i]) + i++ + } + } +} diff --git a/draw2d/curves.go b/draw2d/curves.go index 885d7fa..a2f4d9a 100644 --- a/draw2d/curves.go +++ b/draw2d/curves.go @@ -39,7 +39,6 @@ func cubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4, approximatio recursiveCubicBezier(v, x1, y1, x2, y2, x3, y3, x4, y4, 0, distanceToleranceSquare, angleTolerance, cuspLimit) } - /* * see cubicBezier comments for approximationScale and angleTolerance definition */ @@ -50,7 +49,6 @@ func quadraticBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, approximationSca recursiveQuadraticBezierBezier(v, x1, y1, x2, y2, x3, y3, 0, distanceToleranceSquare, angleTolerance) } - func computeCuspLimit(v float64) (r float64) { if v == 0.0 { r = 0.0 @@ -60,7 +58,6 @@ func computeCuspLimit(v float64) (r float64) { return } - /** * http://www.antigrain.com/research/adaptive_bezier/index.html */ @@ -80,7 +77,7 @@ func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 fl dx := x3 - x1 dy := y3 - y1 - d := math.Fabs(((x2-x3)*dy - (y2-y3)*dx)) + d := math.Abs(((x2-x3)*dy - (y2-y3)*dx)) if d > CurveCollinearityEpsilon { // Regular case @@ -96,7 +93,7 @@ func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 fl // Angle & Cusp Condition //---------------------- - da := math.Fabs(math.Atan2(y3-y2, x3-x2) - math.Atan2(y2-y1, x2-x1)) + da := math.Abs(math.Atan2(y3-y2, x3-x2) - math.Atan2(y2-y1, x2-x1)) if da >= math.Pi { da = 2*math.Pi - da } @@ -169,8 +166,8 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa dx := x4 - x1 dy := y4 - y1 - d2 := math.Fabs(((x2-x4)*dy - (y2-y4)*dx)) - d3 := math.Fabs(((x3-x4)*dy - (y3-y4)*dx)) + d2 := math.Abs(((x2-x4)*dy - (y2-y4)*dx)) + d3 := math.Abs(((x3-x4)*dy - (y3-y4)*dx)) switch { case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon: @@ -233,7 +230,7 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa // Angle Condition //---------------------- - da1 := math.Fabs(math.Atan2(y4-y3, x4-x3) - math.Atan2(y3-y2, x3-x2)) + da1 := math.Abs(math.Atan2(y4-y3, x4-x3) - math.Atan2(y3-y2, x3-x2)) if da1 >= math.Pi { da1 = 2*math.Pi - da1 } @@ -264,7 +261,7 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa // Angle Condition //---------------------- - da1 := math.Fabs(math.Atan2(y3-y2, x3-x2) - math.Atan2(y2-y1, x2-x1)) + da1 := math.Abs(math.Atan2(y3-y2, x3-x2) - math.Atan2(y2-y1, x2-x1)) if da1 >= math.Pi { da1 = 2*math.Pi - da1 } @@ -299,8 +296,8 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa // Angle & Cusp Condition //---------------------- k := math.Atan2(y3-y2, x3-x2) - da1 := math.Fabs(k - math.Atan2(y2-y1, x2-x1)) - da2 := math.Fabs(math.Atan2(y4-y3, x4-x3) - k) + da1 := math.Abs(k - math.Atan2(y2-y1, x2-x1)) + da2 := math.Abs(math.Atan2(y4-y3, x4-x3) - k) if da1 >= math.Pi { da1 = 2*math.Pi - da1 } diff --git a/draw2d/font.go b/draw2d/font.go index f0322aa..114c511 100644 --- a/draw2d/font.go +++ b/draw2d/font.go @@ -2,22 +2,19 @@ // created: 13/12/2010 by Laurent Le Goff package draw2d - import ( - "freetype-go.googlecode.com/hg/freetype" - "freetype-go.googlecode.com/hg/freetype/truetype" - "path" - "log" + "code.google.com/p/freetype-go/freetype" + "code.google.com/p/freetype-go/freetype/truetype" "io/ioutil" + "log" + "path" ) - var ( fontFolder = "../resource/font/" fonts = make(map[string]*truetype.Font) ) - type FontStyle byte const ( @@ -34,14 +31,12 @@ const ( FontFamilyMono ) - type FontData struct { Name string Family FontFamily Style FontStyle } - func GetFont(fontData FontData) *truetype.Font { fontFileName := fontData.Name switch fontData.Family { diff --git a/draw2d/gc.go b/draw2d/gc.go index 94ab547..105ba23 100644 --- a/draw2d/gc.go +++ b/draw2d/gc.go @@ -4,6 +4,7 @@ package draw2d import ( "image" + "image/color" ) type FillRule int @@ -22,8 +23,8 @@ type GraphicContext interface { Rotate(angle float64) Translate(tx, ty float64) Scale(sx, sy float64) - SetStrokeColor(c image.Color) - SetFillColor(c image.Color) + SetStrokeColor(c color.Color) + SetFillColor(c color.Color) SetFillRule(f FillRule) SetLineWidth(lineWidth float64) SetLineCap(cap Cap) diff --git a/draw2d/image.go b/draw2d/image.go index f5e3c93..9df39e4 100644 --- a/draw2d/image.go +++ b/draw2d/image.go @@ -3,16 +3,17 @@ package draw2d import ( - "image/draw" + "code.google.com/p/freetype-go/freetype" + "code.google.com/p/freetype-go/freetype/raster" "image" + "image/color" + "image/draw" "log" - "freetype-go.googlecode.com/hg/freetype" - "freetype-go.googlecode.com/hg/freetype/raster" ) type Painter interface { raster.Painter - SetColor(color image.Color) + SetColor(color color.Color) } var ( @@ -60,7 +61,6 @@ func NewGraphicContext(img draw.Image) *ImageGraphicContext { return gc } - func (gc *ImageGraphicContext) SetDPI(dpi int) { gc.DPI = dpi gc.freetype.SetDPI(dpi) @@ -76,7 +76,7 @@ func (gc *ImageGraphicContext) Clear() { } func (gc *ImageGraphicContext) ClearRect(x1, y1, x2, y2 int) { - imageColor := image.NewColorImage(gc.Current.FillColor) + imageColor := image.NewUniform(gc.Current.FillColor) draw.Draw(gc.img, image.Rect(x1, y1, x2, y2), imageColor, image.ZP, draw.Over) } @@ -85,7 +85,7 @@ func (gc *ImageGraphicContext) DrawImage(img image.Image) { } func (gc *ImageGraphicContext) FillString(text string) (cursor float64) { - gc.freetype.SetSrc(image.NewColorImage(gc.Current.StrokeColor)) + gc.freetype.SetSrc(image.NewUniform(gc.Current.StrokeColor)) // Draw the text. x, y := gc.Current.Path.LastPoint() gc.Current.Tr.Transform(&x, &y) @@ -112,8 +112,7 @@ func (gc *ImageGraphicContext) FillString(text string) (cursor float64) { return width } - -func (gc *ImageGraphicContext) paint(rasterizer *raster.Rasterizer, color image.Color) { +func (gc *ImageGraphicContext) paint(rasterizer *raster.Rasterizer, color color.Color) { gc.painter.SetColor(color) rasterizer.Rasterize(gc.painter) rasterizer.Clear() @@ -173,7 +172,6 @@ func (gc *ImageGraphicContext) FillStroke(paths ...*PathStorage) { gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor) } - func (f FillRule) UseNonZeroWinding() bool { switch f { case FillRuleEvenOdd: diff --git a/draw2d/path_adder.go b/draw2d/path_adder.go index 3ffd341..4e64c64 100644 --- a/draw2d/path_adder.go +++ b/draw2d/path_adder.go @@ -2,12 +2,10 @@ // created: 13/12/2010 by Laurent Le Goff package draw2d - import ( - "freetype-go.googlecode.com/hg/freetype/raster" + "code.google.com/p/freetype-go/freetype/raster" ) - type VertexAdder struct { command VertexCommand adder raster.Adder @@ -31,7 +29,6 @@ func (vertexAdder *VertexAdder) Vertex(x, y float64) { vertexAdder.command = VertexNoCommand } - type PathAdder struct { adder raster.Adder firstPoint raster.Point @@ -42,7 +39,6 @@ func NewPathAdder(adder raster.Adder) *PathAdder { return &PathAdder{adder, raster.Point{0, 0}, 1} } - func (pathAdder *PathAdder) Convert(paths ...*PathStorage) { for _, path := range paths { j := 0 diff --git a/draw2d/raster/fillerAA.go b/draw2d/raster/fillerAA.go index fa81348..33236be 100644 --- a/draw2d/raster/fillerAA.go +++ b/draw2d/raster/fillerAA.go @@ -4,6 +4,7 @@ package raster import ( "image" + "image/color" "unsafe" ) @@ -87,7 +88,7 @@ func intersect(r1, r2 [4]float64) [4]float64 { return r1 } -func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) { +func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { // memset 0 the mask buffer r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) @@ -169,7 +170,7 @@ func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) { } // Renders the mask to the canvas with even-odd fill. -func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) { +func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { var x, y uint32 minX := uint32(clipBound[0]) @@ -221,7 +222,7 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBACo * param aColor the color to be used for rendering. * param aTransformation the transformation matrix. */ -func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) { +func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT) @@ -253,9 +254,8 @@ func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *ima r.fillNonZero(img, color, clipRect) } - //! Renders the mask to the canvas with non-zero winding fill. -func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) { +func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { var x, y uint32 minX := uint32(clipBound[0]) diff --git a/draw2d/raster/fillerV1/fillerAA.go b/draw2d/raster/fillerV1/fillerAA.go index 9aace0a..2a929b6 100644 --- a/draw2d/raster/fillerV1/fillerAA.go +++ b/draw2d/raster/fillerV1/fillerAA.go @@ -4,6 +4,7 @@ package raster import ( "image" + "image/color" "unsafe" ) @@ -87,7 +88,7 @@ func intersect(r1, r2 [4]float64) [4]float64 { return r1 } -func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) { +func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { // memset 0 the mask buffer r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) @@ -134,7 +135,7 @@ func (r *Rasterizer8BitsSample) addEvenOddEdge(edge *PolygonEdge) { } // Renders the mask to the canvas with even-odd fill. -func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) { +func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { var x, y uint32 minX := uint32(clipBound[0]) @@ -186,7 +187,7 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBACo * param aColor the color to be used for rendering. * param aTransformation the transformation matrix. */ -func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) { +func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT) @@ -237,7 +238,7 @@ func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) { } //! Renders the mask to the canvas with non-zero winding fill. -func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) { +func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { var x, y uint32 minX := uint32(clipBound[0]) diff --git a/draw2d/raster/fillerV2/fillerAA.go b/draw2d/raster/fillerV2/fillerAA.go index 444e99b..ff7634d 100644 --- a/draw2d/raster/fillerV2/fillerAA.go +++ b/draw2d/raster/fillerV2/fillerAA.go @@ -4,6 +4,7 @@ package raster import ( "image" + "image/color" "unsafe" ) @@ -87,7 +88,7 @@ func intersect(r1, r2 [4]float64) [4]float64 { return r1 } -func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) { +func (r *Rasterizer8BitsSample) RenderEvenOdd(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { // memset 0 the mask buffer r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) @@ -169,7 +170,7 @@ func (r *Rasterizer8BitsSample) addNonZeroEdge(edge *PolygonEdge) { } // Renders the mask to the canvas with even-odd fill. -func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) { +func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { var x, y uint32 minX := uint32(clipBound[0]) @@ -221,7 +222,7 @@ func (r *Rasterizer8BitsSample) fillEvenOdd(img *image.RGBA, color *image.RGBACo * param aColor the color to be used for rendering. * param aTransformation the transformation matrix. */ -func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *image.RGBAColor, polygon *Polygon, tr [6]float64) { +func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *color.RGBA, polygon *Polygon, tr [6]float64) { r.MaskBuffer = make([]SUBPIXEL_DATA, r.BufferWidth*r.Height) r.WindingBuffer = make([]NON_ZERO_MASK_DATA_UNIT, r.BufferWidth*r.Height*SUBPIXEL_COUNT) @@ -253,9 +254,8 @@ func (r *Rasterizer8BitsSample) RenderNonZeroWinding(img *image.RGBA, color *ima r.fillNonZero(img, color, clipRect) } - //! Renders the mask to the canvas with non-zero winding fill. -func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *image.RGBAColor, clipBound [4]float64) { +func (r *Rasterizer8BitsSample) fillNonZero(img *image.RGBA, color *color.RGBA, clipBound [4]float64) { var x, y uint32 minX := uint32(clipBound[0]) diff --git a/draw2d/raster/line.go b/draw2d/raster/line.go index 92fed7a..ae0095b 100644 --- a/draw2d/raster/line.go +++ b/draw2d/raster/line.go @@ -3,8 +3,8 @@ package raster import ( + "image/color" "image/draw" - "image" ) func abs(i int) int { @@ -14,13 +14,13 @@ func abs(i int) int { return i } -func PolylineBresenham(img draw.Image, c image.Color, s ...float64) { +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)) } } -func Bresenham(img draw.Image, color image.Color, x0, y0, x1, y1 int) { +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 diff --git a/draw2d/raster/raster_test.go b/draw2d/raster/raster_test.go index 56e306b..c339d9b 100644 --- a/draw2d/raster/raster_test.go +++ b/draw2d/raster/raster_test.go @@ -1,14 +1,15 @@ package raster import ( - "testing" - "log" - "image" - "os" "bufio" + "code.google.com/p/draw2d/draw2d/curve" + "code.google.com/p/freetype-go/freetype/raster" + "image" + "image/color" "image/png" - "draw2d.googlecode.com/hg/draw2d/curve" - "freetype-go.googlecode.com/hg/freetype/raster" + "log" + "os" + "testing" ) var flattening_threshold float64 = 0.5 @@ -55,9 +56,9 @@ func TestFreetype(t *testing.T) { c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c.Segment(&p, flattening_threshold) poly := Polygon(p.points) - color := image.RGBAColor{0, 0, 0, 0xff} + color := color.RGBA{0, 0, 0, 0xff} - img := image.NewRGBA(200, 200) + img := image.NewRGBA(image.Rect(0, 0, 200, 200)) rasterizer := raster.NewRasterizer(200, 200) rasterizer.UseNonZeroWinding = false rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)}) @@ -77,9 +78,9 @@ func TestFreetypeNonZeroWinding(t *testing.T) { c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c.Segment(&p, flattening_threshold) poly := Polygon(p.points) - color := image.RGBAColor{0, 0, 0, 0xff} + color := color.RGBA{0, 0, 0, 0xff} - img := image.NewRGBA(200, 200) + img := image.NewRGBA(image.Rect(0, 0, 200, 200)) rasterizer := raster.NewRasterizer(200, 200) rasterizer.UseNonZeroWinding = true rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)}) @@ -94,35 +95,33 @@ func TestFreetypeNonZeroWinding(t *testing.T) { } func TestRasterizer(t *testing.T) { - img := image.NewRGBA(200, 200) + img := image.NewRGBA(image.Rect(0, 0, 200, 200)) var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c.Segment(&p, flattening_threshold) poly := Polygon(p.points) - color := image.RGBAColor{0, 0, 0, 0xff} + color := color.RGBA{0, 0, 0, 0xff} tr := [6]float64{1, 0, 0, 1, 0, 0} r := NewRasterizer8BitsSample(200, 200) //PolylineBresenham(img, image.Black, poly...) - r.RenderEvenOdd(img, &color, &poly, tr) savepng("_testRasterizer.png", img) } func TestRasterizerNonZeroWinding(t *testing.T) { - img := image.NewRGBA(200, 200) + img := image.NewRGBA(image.Rect(0, 0, 200, 200)) var p Path p.LineTo(10, 190) c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c.Segment(&p, flattening_threshold) poly := Polygon(p.points) - color := image.RGBAColor{0, 0, 0, 0xff} + color := color.RGBA{0, 0, 0, 0xff} tr := [6]float64{1, 0, 0, 1, 0, 0} r := NewRasterizer8BitsSample(200, 200) //PolylineBresenham(img, image.Black, poly...) - r.RenderNonZeroWinding(img, &color, &poly, tr) savepng("_testRasterizerNonZeroWinding.png", img) } @@ -133,10 +132,10 @@ func BenchmarkFreetype(b *testing.B) { c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c.Segment(&p, flattening_threshold) poly := Polygon(p.points) - color := image.RGBAColor{0, 0, 0, 0xff} + color := color.RGBA{0, 0, 0, 0xff} for i := 0; i < b.N; i++ { - img := image.NewRGBA(200, 200) + img := image.NewRGBA(image.Rect(0, 0, 200, 200)) rasterizer := raster.NewRasterizer(200, 200) rasterizer.UseNonZeroWinding = false rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)}) @@ -154,10 +153,10 @@ func BenchmarkFreetypeNonZeroWinding(b *testing.B) { c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c.Segment(&p, flattening_threshold) poly := Polygon(p.points) - color := image.RGBAColor{0, 0, 0, 0xff} + color := color.RGBA{0, 0, 0, 0xff} for i := 0; i < b.N; i++ { - img := image.NewRGBA(200, 200) + img := image.NewRGBA(image.Rect(0, 0, 200, 200)) rasterizer := raster.NewRasterizer(200, 200) rasterizer.UseNonZeroWinding = true rasterizer.Start(raster.Point{raster.Fix32(10 * 256), raster.Fix32(190 * 256)}) @@ -176,10 +175,10 @@ func BenchmarkRasterizerNonZeroWinding(b *testing.B) { c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c.Segment(&p, flattening_threshold) poly := Polygon(p.points) - color := image.RGBAColor{0, 0, 0, 0xff} + color := color.RGBA{0, 0, 0, 0xff} tr := [6]float64{1, 0, 0, 1, 0, 0} for i := 0; i < b.N; i++ { - img := image.NewRGBA(200, 200) + img := image.NewRGBA(image.Rect(0, 0, 200, 200)) rasterizer := NewRasterizer8BitsSample(200, 200) rasterizer.RenderNonZeroWinding(img, &color, &poly, tr) } @@ -191,10 +190,10 @@ func BenchmarkRasterizer(b *testing.B) { c := curve.CubicCurveFloat64{10, 190, 10, 10, 190, 10, 190, 190} c.Segment(&p, flattening_threshold) poly := Polygon(p.points) - color := image.RGBAColor{0, 0, 0, 0xff} + color := color.RGBA{0, 0, 0, 0xff} tr := [6]float64{1, 0, 0, 1, 0, 0} for i := 0; i < b.N; i++ { - img := image.NewRGBA(200, 200) + img := image.NewRGBA(image.Rect(0, 0, 200, 200)) rasterizer := NewRasterizer8BitsSample(200, 200) rasterizer.RenderEvenOdd(img, &color, &poly, tr) } diff --git a/draw2d/rgba_interpolation.go b/draw2d/rgba_interpolation.go index c70ae5a..5b065f6 100644 --- a/draw2d/rgba_interpolation.go +++ b/draw2d/rgba_interpolation.go @@ -2,8 +2,9 @@ package draw2d import ( - "image/draw" "image" + "image/color" + "image/draw" "math" ) @@ -16,11 +17,11 @@ const ( ) //see http://pippin.gimp.org/image_processing/chap_resampling.html -func getColorLinear(img image.Image, x, y float64) image.Color { +func getColorLinear(img image.Image, x, y float64) color.Color { return img.At(int(x), int(y)) } -func getColorBilinear(img image.Image, x, y float64) image.Color { +func getColorBilinear(img image.Image, x, y float64) color.Color { x0 := math.Floor(x) y0 := math.Floor(y) dx := x - x0 @@ -39,8 +40,9 @@ func getColorBilinear(img image.Image, x, y float64) image.Color { g := int(lerp(lerp(g0, g1, dx), lerp(g3, g2, dx), dy)) b := int(lerp(lerp(b0, b1, dx), lerp(b3, b2, dx), dy)) a := int(lerp(lerp(a0, a1, dx), lerp(a3, a2, dx), dy)) - return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} + return color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} } + /** -- LERP -- /lerp/, vi.,n. @@ -53,8 +55,7 @@ func lerp(v1, v2, ratio float64) float64 { return v1*(1-ratio) + v2*ratio } - -func getColorCubicRow(img image.Image, x, y, offset float64) image.Color { +func getColorCubicRow(img image.Image, x, y, offset float64) color.Color { c0 := img.At(int(x), int(y)) c1 := img.At(int(x+1), int(y)) c2 := img.At(int(x+2), int(y)) @@ -68,10 +69,10 @@ func getColorCubicRow(img image.Image, x, y, offset float64) image.Color { rt, gt, bt, at = c3.RGBA() r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at) r, g, b, a := cubic(offset, r0, r1, r2, r3), cubic(offset, g0, g1, g2, g3), cubic(offset, b0, b1, b2, b3), cubic(offset, a0, a1, a2, a3) - return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} + return color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} } -func getColorBicubic(img image.Image, x, y float64) image.Color { +func getColorBicubic(img image.Image, x, y float64) color.Color { x0 := math.Floor(x) y0 := math.Floor(y) dx := x - x0 @@ -89,7 +90,7 @@ func getColorBicubic(img image.Image, x, y float64) image.Color { rt, gt, bt, at = c3.RGBA() r3, g3, b3, a3 := float64(rt), float64(gt), float64(bt), float64(at) r, g, b, a := cubic(dy, r0, r1, r2, r3), cubic(dy, g0, g1, g2, g3), cubic(dy, b0, b1, b2, b3), cubic(dy, a0, a1, a2, a3) - return image.RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} + return color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} } func cubic(offset, v0, v1, v2, v3 float64) uint32 { @@ -104,9 +105,9 @@ func DrawImage(src image.Image, dest draw.Image, tr MatrixTransform, op draw.Op, 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) var x, y, u, v float64 - var c1, c2, cr image.Color + var c1, c2, cr color.Color var r, g, b, a, ia, r1, g1, b1, a1, r2, g2, b2, a2 uint32 - var color image.RGBAColor + var color color.RGBA for x = x0; x < x1; x++ { for y = y0; y < y1; y++ { u = x diff --git a/draw2d/stack_gc.go b/draw2d/stack_gc.go index 94d275f..cc7b795 100644 --- a/draw2d/stack_gc.go +++ b/draw2d/stack_gc.go @@ -4,6 +4,7 @@ package draw2d import ( "image" + "image/color" ) type StackGraphicContext struct { @@ -16,8 +17,8 @@ type ContextStack struct { LineWidth float64 Dash []float64 DashOffset float64 - StrokeColor image.Color - FillColor image.Color + StrokeColor color.Color + FillColor color.Color FillRule FillRule Cap Cap Join Join @@ -26,7 +27,6 @@ type ContextStack struct { previous *ContextStack } - /** * Create a new Graphic context from an image */ @@ -46,7 +46,6 @@ func NewStackGraphicContext() *StackGraphicContext { return gc } - func (gc *StackGraphicContext) GetMatrixTransform() MatrixTransform { return gc.Current.Tr } @@ -71,11 +70,11 @@ func (gc *StackGraphicContext) Scale(sx, sy float64) { gc.Current.Tr = NewScaleMatrix(sx, sy).Multiply(gc.Current.Tr) } -func (gc *StackGraphicContext) SetStrokeColor(c image.Color) { +func (gc *StackGraphicContext) SetStrokeColor(c color.Color) { gc.Current.StrokeColor = c } -func (gc *StackGraphicContext) SetFillColor(c image.Color) { +func (gc *StackGraphicContext) SetFillColor(c color.Color) { gc.Current.FillColor = c } diff --git a/draw2d/transform.go b/draw2d/transform.go index d14ed4c..1f39b9f 100644 --- a/draw2d/transform.go +++ b/draw2d/transform.go @@ -3,7 +3,7 @@ package draw2d import ( - "freetype-go.googlecode.com/hg/freetype/raster" + "code.google.com/p/freetype-go/freetype/raster" "math" ) @@ -140,7 +140,6 @@ func (tr MatrixTransform) GetInverseTransformation() MatrixTransform { (tr[1]*tr[4] - tr[0]*tr[5]) / d} } - func (tr1 MatrixTransform) Multiply(tr2 MatrixTransform) MatrixTransform { return [6]float64{ tr1[0]*tr2[0] + tr1[1]*tr2[2], @@ -151,7 +150,6 @@ func (tr1 MatrixTransform) Multiply(tr2 MatrixTransform) MatrixTransform { tr1[5]*tr2[3] + tr1[4]*tr2[1] + tr2[5]} } - func (tr *MatrixTransform) Scale(sx, sy float64) *MatrixTransform { tr[0] = sx * tr[0] tr[1] = sx * tr[1] @@ -195,8 +193,8 @@ func (tr MatrixTransform) GetScale() float64 { } func (tr MatrixTransform) GetMaxAbsScaling() (s float64) { - sx := math.Fabs(tr[0]) - sy := math.Fabs(tr[3]) + sx := math.Abs(tr[0]) + sy := math.Abs(tr[3]) if sx > sy { return sx } @@ -204,8 +202,8 @@ func (tr MatrixTransform) GetMaxAbsScaling() (s float64) { } func (tr MatrixTransform) GetMinAbsScaling() (s float64) { - sx := math.Fabs(tr[0]) - sy := math.Fabs(tr[3]) + sx := math.Abs(tr[0]) + sy := math.Abs(tr[3]) if sx > sy { return sy } @@ -248,7 +246,7 @@ func (tr MatrixTransform) IsTranslation() bool { * return true if the distance between the two floats is less than epsilon, false otherwise */ func fequals(float1, float2 float64) bool { - return math.Fabs(float1-float2) <= epsilon + return math.Abs(float1-float2) <= epsilon } // this VertexConverter apply the Matrix transformation tr @@ -272,7 +270,6 @@ func (vmt *VertexMatrixTransform) Vertex(x, y float64) { vmt.Next.Vertex(u, v) } - // this adder apply a Matrix transformation to points type MatrixTransformAdder struct { tr MatrixTransform @@ -283,7 +280,6 @@ func NewMatrixTransformAdder(tr MatrixTransform, adder raster.Adder) *MatrixTran return &MatrixTransformAdder{tr, adder} } - // Start starts a new curve at the given point. func (mta MatrixTransformAdder) Start(a raster.Point) { mta.tr.TransformRasterPoint(&a) diff --git a/draw2dgl/gc.go b/draw2dgl/gc.go index e87807d..6b7316b 100644 --- a/draw2dgl/gc.go +++ b/draw2dgl/gc.go @@ -1,11 +1,12 @@ package draw2dgl import ( - "image" - "image/draw" + "code.google.com/p/draw2d/draw2d" + "code.google.com/p/freetype-go/freetype/raster" "gl" - "freetype-go.googlecode.com/hg/freetype/raster" - "draw2d.googlecode.com/hg/draw2d" + "image" + "image/color" + "image/draw" //"log" ) @@ -81,9 +82,8 @@ func (p *GLPainter) Flush() { } } - // SetColor sets the color to paint the spans. -func (p *GLPainter) SetColor(c image.Color) { +func (p *GLPainter) SetColor(c color.Color) { r, g, b, a := c.RGBA() if a == 0 { p.cr = 0 @@ -106,7 +106,6 @@ func NewGLPainter() *GLPainter { return p } - type GraphicContext struct { *draw2d.StackGraphicContext painter *GLPainter @@ -118,7 +117,6 @@ type GLVertex struct { x, y float64 } - func NewGLVertex() *GLVertex { return &GLVertex{} } @@ -168,8 +166,7 @@ func (gc *GraphicContext) FillString(text string) (cursor float64) { return 0 } - -func (gc *GraphicContext) paint(rasterizer *raster.Rasterizer, color image.Color) { +func (gc *GraphicContext) paint(rasterizer *raster.Rasterizer, color color.Color) { gc.painter.SetColor(color) rasterizer.Rasterize(gc.painter) rasterizer.Clear() @@ -207,6 +204,7 @@ func (gc *GraphicContext) Fill(paths ...*draw2d.PathStorage) { gc.paint(gc.fillRasterizer, gc.Current.FillColor) gc.Current.Path.Clear() } + /* func (gc *GraphicContext) Fill(paths ...*draw2d.PathStorage) { paths = append(paths, gc.Current.Path) diff --git a/postscript/Makefile b/postscript/Makefile index 1afc401..a037095 100644 --- a/postscript/Makefile +++ b/postscript/Makefile @@ -1,6 +1,6 @@ include $(GOROOT)/src/Make.inc -TARG=draw2d.googlecode.com/hg/postscript +TARG=code.google.com/p/draw2d/postscript GOFILES=operators_array.go\ operators_dictionary.go\ operators_misc.go\ diff --git a/postscript/interpreter.go b/postscript/interpreter.go index ea391a9..cf77261 100644 --- a/postscript/interpreter.go +++ b/postscript/interpreter.go @@ -4,14 +4,13 @@ package postscript import ( - "os" - "log" - "strconv" + "code.google.com/p/draw2d/draw2d" "io" - "draw2d.googlecode.com/hg/draw2d" + "log" + "os" + "strconv" ) - type Interpreter struct { valueStack ValueStack dictionaryStack DictionaryStack @@ -58,10 +57,10 @@ func (interpreter *Interpreter) Execute(reader io.Reader) { } } -func (interpreter *Interpreter) ExecuteFile(filePath string) os.Error { +func (interpreter *Interpreter) ExecuteFile(filePath string) error { src, err := os.Open(filePath) if src == nil { - log.Printf("can't open file; err=%s\n", err.String()) + log.Printf("can't open file; err=%s\n", err.Error()) return err } defer src.Close() @@ -102,7 +101,7 @@ func (interpreter *Interpreter) scan(scanner *Scanner, token int) { // procedure interpreter.Push(interpreter.scanProcedure(scanner)) } else if token == Float || token == Int { - f, err := strconv.Atof64(scanner.TokenText()) + f, err := strconv.ParseFloat(scanner.TokenText(), 64) if err != nil { log.Printf("Float expected: %s\n", scanner.TokenText()) interpreter.Push(scanner.TokenText()) @@ -217,7 +216,6 @@ func (interpreter *Interpreter) SystemDefine(name string, value Value) { interpreter.dictionaryStack[0][name] = value } - //Operand Operation func (interpreter *Interpreter) Push(operand Value) { diff --git a/postscript/operators_graphics.go b/postscript/operators_graphics.go index 0ed7c63..66d0a5d 100644 --- a/postscript/operators_graphics.go +++ b/postscript/operators_graphics.go @@ -5,13 +5,12 @@ package postscript import ( - "image" - "draw2d.googlecode.com/hg/draw2d" - "math" + "code.google.com/p/draw2d/draw2d" + "image/color" "log" + "math" ) - //Path Construction Operators func newpath(interpreter *Interpreter) { interpreter.GetGraphicContext().BeginPath() @@ -102,7 +101,7 @@ func grestore(interpreter *Interpreter) { func setgray(interpreter *Interpreter) { gray := interpreter.PopFloat() - color := image.RGBAColor{uint8(gray * 0xff), uint8(gray * 0xff), uint8(gray * 0xff), 0xff} + color := color.RGBA{uint8(gray * 0xff), uint8(gray * 0xff), uint8(gray * 0xff), 0xff} interpreter.GetGraphicContext().SetStrokeColor(color) interpreter.GetGraphicContext().SetFillColor(color) } @@ -111,7 +110,7 @@ func setrgbcolor(interpreter *Interpreter) { blue := interpreter.PopFloat() green := interpreter.PopFloat() red := interpreter.PopFloat() - color := image.RGBAColor{uint8(red * 0xff), uint8(green * 0xff), uint8(blue * 0xff), 0xff} + color := color.RGBA{uint8(red * 0xff), uint8(green * 0xff), uint8(blue * 0xff), 0xff} interpreter.GetGraphicContext().SetStrokeColor(color) interpreter.GetGraphicContext().SetFillColor(color) } @@ -169,7 +168,7 @@ func sethsbcolor(interpreter *Interpreter) { saturation := interpreter.PopFloat() hue := interpreter.PopFloat() red, green, blue := hsbtorgb(hue, saturation, brightness) - color := image.RGBAColor{uint8(red), uint8(green), uint8(blue), 0xff} + color := color.RGBA{uint8(red), uint8(green), uint8(blue), 0xff} interpreter.GetGraphicContext().SetStrokeColor(color) interpreter.GetGraphicContext().SetFillColor(color) } @@ -193,7 +192,7 @@ func setcmybcolor(interpreter *Interpreter) { green = (1.0-green)*255.0 + 0.5 blue = (1.0-blue)*255.0 + 0.5 - color := image.RGBAColor{uint8(red), uint8(green), uint8(blue), 0xff} + color := color.RGBA{uint8(red), uint8(green), uint8(blue), 0xff} interpreter.GetGraphicContext().SetStrokeColor(color) interpreter.GetGraphicContext().SetFillColor(color) } @@ -246,6 +245,7 @@ func show(interpreter *Interpreter) { interpreter.GetGraphicContext().FillString(s) log.Printf("show not really implemented") } + //ax ay string ashow – -> Add (ax , ay) to width of each glyph while showing string func ashow(interpreter *Interpreter) { log.Printf("ashow not really implemented") @@ -283,7 +283,6 @@ func currentflat(interpreter *Interpreter) { log.Printf("currentflat not yet implemented") } - // Coordinate System and Matrix operators func matrix(interpreter *Interpreter) { interpreter.Push(draw2d.NewIdentityMatrix()) @@ -420,7 +419,6 @@ func scale(interpreter *Interpreter) { } } - func initDrawingOperators(interpreter *Interpreter) { interpreter.SystemDefine("stroke", NewOperator(stroke)) diff --git a/postscript/operators_math.go b/postscript/operators_math.go index 477718c..0537ea6 100644 --- a/postscript/operators_math.go +++ b/postscript/operators_math.go @@ -6,8 +6,9 @@ package postscript import ( "math" - "rand" + "math/rand" ) + // begin Primitive Operator implementation //num1 num2 add sum -> Return num1 plus num2 @@ -16,6 +17,7 @@ func add(interpreter *Interpreter) { num1 := interpreter.PopFloat() interpreter.Push(num1 + num2) } + //num1 num2 div quotient -> Return num1 divided by num2 func div(interpreter *Interpreter) { num2 := interpreter.PopFloat() @@ -29,6 +31,7 @@ func idiv(interpreter *Interpreter) { int1 := interpreter.PopInt() interpreter.Push(float64(int1 / int2)) } + //int int mod remainder -> Return remainder after dividing int by int func mod(interpreter *Interpreter) { int2 := interpreter.PopInt() @@ -42,89 +45,106 @@ func mul(interpreter *Interpreter) { num1 := interpreter.PopFloat() interpreter.Push(num1 * num2) } + //num1 num2 sub difference -> Return num1 minus num2 func sub(interpreter *Interpreter) { num2 := interpreter.PopFloat() num1 := interpreter.PopFloat() interpreter.Push(num1 - num2) } + //num1 abs num2 -> Return absolute value of num1 func abs(interpreter *Interpreter) { f := interpreter.PopFloat() - interpreter.Push(math.Fabs(f)) + interpreter.Push(math.Abs(f)) } + //num1 neg num2 -> Return negative of num1 func neg(interpreter *Interpreter) { f := interpreter.PopFloat() interpreter.Push(-f) } + //num1 ceiling num2 -> Return ceiling of num1 func ceiling(interpreter *Interpreter) { f := interpreter.PopFloat() interpreter.Push(float64(int(f + 1))) } + //num1 floor num2 -> Return floor of num1 func floor(interpreter *Interpreter) { f := interpreter.PopFloat() interpreter.Push(math.Floor(f)) } + //num1 round num2 -> Round num1 to nearest integer func round(interpreter *Interpreter) { f := interpreter.PopFloat() interpreter.Push(float64(int(f + 0.5))) } + //num1 truncate num2 -> Remove fractional part of num1 func truncate(interpreter *Interpreter) { f := interpreter.PopFloat() interpreter.Push(float64(int(f))) } + //num sqrt real -> Return square root of num func sqrt(interpreter *Interpreter) { f := interpreter.PopFloat() interpreter.Push(float64(math.Sqrt(f))) } + //num den atan angle -> Return arctangent of num/den in degrees func atan(interpreter *Interpreter) { den := interpreter.PopFloat() num := interpreter.PopFloat() interpreter.Push(math.Atan2(num, den) * (180.0 / math.Pi)) } + //angle cos real -> Return cosine of angle degrees func cos(interpreter *Interpreter) { a := interpreter.PopFloat() * math.Pi / 180 interpreter.Push(math.Cos(a)) } + //angle sin real -> Return sine of angle degrees func sin(interpreter *Interpreter) { a := interpreter.PopFloat() * math.Pi / 180 interpreter.Push(math.Sin(a)) } + //base exponent exp real -> Raise base to exponent power func exp(interpreter *Interpreter) { exponent := interpreter.PopFloat() base := interpreter.PopFloat() interpreter.Push(math.Pow(base, exponent)) } + //num ln real -> Return natural logarithm (base e) func ln(interpreter *Interpreter) { num := interpreter.PopFloat() interpreter.Push(math.Log(num)) } + //num log real -> Return common logarithm (base 10) func log10(interpreter *Interpreter) { num := interpreter.PopFloat() interpreter.Push(math.Log10(num)) } + //– rand int Generate pseudo-random integer func randInt(interpreter *Interpreter) { interpreter.Push(float64(rand.Int())) } var randGenerator *rand.Rand + //int srand – -> Set random number seed func srand(interpreter *Interpreter) { randGenerator = rand.New(rand.NewSource(int64(interpreter.PopInt()))) } + //– rrand int -> Return random number seed func rrand(interpreter *Interpreter) { interpreter.Push(float64(randGenerator.Int())) diff --git a/postscript/scanner.go b/postscript/scanner.go index 79aa3d5..c957561 100644 --- a/postscript/scanner.go +++ b/postscript/scanner.go @@ -10,10 +10,9 @@ import ( "io" "os" "unicode" - "utf8" + "unicode/utf8" ) - // A source position is represented by a Position value. // A position is valid if Line > 0. type Position struct { @@ -23,11 +22,9 @@ type Position struct { Column int // column number, starting at 0 (character count per line) } - // IsValid returns true if the position is valid. func (pos *Position) IsValid() bool { return pos.Line > 0 } - func (pos Position) String() string { s := pos.Filename if pos.IsValid() { @@ -42,7 +39,6 @@ func (pos Position) String() string { return s } - // Predefined mode bits to control recognition of tokens. For instance, // to configure a Scanner such that it only recognizes (Go) identifiers, // integers, and skips comments, set the Scanner's Mode field to: @@ -61,7 +57,6 @@ const ( GoTokens = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments ) - // The result of Scan is one of the following tokens or a Unicode character. const ( EOF = -(iota + 1) @@ -75,7 +70,6 @@ const ( skipComment ) - var tokenString = map[int]string{ EOF: "EOF", Ident: "Ident", @@ -87,7 +81,6 @@ var tokenString = map[int]string{ Comment: "Comment", } - // TokenString returns a (visible) string for a token or Unicode character. func TokenString(tok int) string { if s, found := tokenString[tok]; found { @@ -96,12 +89,10 @@ func TokenString(tok int) string { return fmt.Sprintf("U+%04X", tok) } - // GoWhitespace is the default value for the Scanner's Whitespace field. // Its value selects Go's white space characters. const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' ' - const bufLen = 1024 // at least utf8.UTFMax // A Scanner implements reading of Unicode characters and tokens from an io.Reader. @@ -128,7 +119,7 @@ type Scanner struct { tokEnd int // token text tail end (srcBuf index) // One character look-ahead - ch int // character before current srcPos + ch rune // character before current srcPos // Error is called for each error encountered. If no Error // function is set, the error is reported to os.Stderr. @@ -154,7 +145,6 @@ type Scanner struct { Position } - // Init initializes a Scanner with a new source and returns itself. // Error is set to nil, ErrorCount is set to 0, Mode is set to GoTokens, // and Whitespace is set to GoWhitespace. @@ -186,13 +176,12 @@ func (s *Scanner) Init(src io.Reader) *Scanner { return s } - // next reads and returns the next Unicode character. It is designed such // that only a minimal amount of work needs to be done in the common ASCII // case (one test to check for both ASCII and end-of-buffer, and one test // to check for newlines). -func (s *Scanner) next() int { - ch := int(s.srcBuf[s.srcPos]) +func (s *Scanner) next() rune { + ch := rune(s.srcBuf[s.srcPos]) if ch >= utf8.RuneSelf { // uncommon case: not ASCII or not enough bytes @@ -216,14 +205,14 @@ func (s *Scanner) next() int { if s.srcEnd == 0 { return EOF } - if err != os.EOF { - s.error(err.String()) + if err != io.EOF { + s.error(err.Error()) break } } } // at least one byte - ch = int(s.srcBuf[s.srcPos]) + ch = rune(s.srcBuf[s.srcPos]) if ch >= utf8.RuneSelf { // uncommon case: not ASCII var width int @@ -249,29 +238,26 @@ func (s *Scanner) next() int { return ch } - // Next reads and returns the next Unicode character. // It returns EOF at the end of the source. It reports // a read error by calling s.Error, if set, or else // prints an error message to os.Stderr. Next does not // update the Scanner's Position field; use Pos() to // get the current position. -func (s *Scanner) Next() int { +func (s *Scanner) Next() rune { s.tokPos = -1 // don't collect token text ch := s.ch s.ch = s.next() return ch } - // Peek returns the next Unicode character in the source without advancing // the scanner. It returns EOF if the scanner's position is at the last // character of the source. -func (s *Scanner) Peek() int { +func (s *Scanner) Peek() rune { return s.ch } - func (s *Scanner) error(msg string) { s.ErrorCount++ if s.Error != nil { @@ -281,8 +267,7 @@ func (s *Scanner) error(msg string) { fmt.Fprintf(os.Stderr, "%s: %s", s.Position, msg) } - -func (s *Scanner) scanIdentifier() int { +func (s *Scanner) scanIdentifier() rune { ch := s.next() // read character after first '_' or letter for ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch) || ch == '.' || ch == '-' || ch == '`' { ch = s.next() @@ -290,8 +275,7 @@ func (s *Scanner) scanIdentifier() int { return ch } - -func digitVal(ch int) int { +func digitVal(ch rune) rune { switch { case '0' <= ch && ch <= '9': return ch - '0' @@ -303,27 +287,23 @@ func digitVal(ch int) int { return 16 // larger than any legal digit val } +func isDecimal(ch rune) bool { return '0' <= ch && ch <= '9' } -func isDecimal(ch int) bool { return '0' <= ch && ch <= '9' } - - -func (s *Scanner) scanMantissa(ch int) int { +func (s *Scanner) scanMantissa(ch rune) rune { for isDecimal(ch) { ch = s.next() } return ch } - -func (s *Scanner) scanFraction(ch int) int { +func (s *Scanner) scanFraction(ch rune) rune { if ch == '.' { ch = s.scanMantissa(s.next()) } return ch } - -func (s *Scanner) scanExponent(ch int) int { +func (s *Scanner) scanExponent(ch rune) rune { if ch == 'e' || ch == 'E' { ch = s.next() if ch == '-' || ch == '+' { @@ -334,8 +314,7 @@ func (s *Scanner) scanExponent(ch int) int { return ch } - -func (s *Scanner) scanNumber(ch int) (int, int) { +func (s *Scanner) scanNumber(ch rune) (int, rune) { // isDecimal(ch) if ch == '0' { // int or float @@ -379,9 +358,8 @@ func (s *Scanner) scanNumber(ch int) (int, int) { return Int, ch } - -func (s *Scanner) scanDigits(ch, base, n int) int { - for n > 0 && digitVal(ch) < base { +func (s *Scanner) scanDigits(ch rune, base, n int) rune { + for n > 0 && int(digitVal(ch)) < base { ch = s.next() n-- } @@ -391,8 +369,7 @@ func (s *Scanner) scanDigits(ch, base, n int) int { return ch } - -func (s *Scanner) scanEscape(quote int) int { +func (s *Scanner) scanEscape(quote rune) rune { ch := s.next() // read character after '/' switch ch { case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote: @@ -412,8 +389,7 @@ func (s *Scanner) scanEscape(quote int) int { return ch } - -func (s *Scanner) scanString(quote int) (n int) { +func (s *Scanner) scanString(quote rune) (n int) { ch := s.next() // read character after quote for ch != quote { if ch == '\n' || ch < 0 { @@ -430,7 +406,6 @@ func (s *Scanner) scanString(quote int) (n int) { return } - func (s *Scanner) scanRawString() { ch := s.next() // read character after '`' for ch != '`' { @@ -442,7 +417,6 @@ func (s *Scanner) scanRawString() { } } - func (s *Scanner) scanLineComment() { ch := s.next() // read character after "//" for ch != '\n' { @@ -454,12 +428,10 @@ func (s *Scanner) scanLineComment() { } } - -func (s *Scanner) scanComment(ch int) { +func (s *Scanner) scanComment(ch rune) { s.scanLineComment() } - // Scan reads the next token or Unicode character from source and returns it. // It only recognizes tokens t for which the respective Mode bit (1<<-t) is set. // It returns EOF at the end of the source. It reports scanner errors (read and @@ -487,7 +459,7 @@ redo: s.Column = s.column // determine token value - tok := ch + tok := int(ch) switch { case unicode.IsLetter(ch) || ch == '_' || ch == '`': if s.Mode&ScanIdents != 0 { @@ -560,7 +532,6 @@ redo: return tok } - // Position returns the current source position. If called before Next() // or Scan(), it returns the position of the next Unicode character or token // returned by these functions. If called afterwards, it returns the position @@ -575,7 +546,6 @@ func (s *Scanner) Pos() Position { } } - // TokenText returns the string corresponding to the most recently scanned token. // Valid after calling Scan(). func (s *Scanner) TokenText() string {