diff --git a/draw2d/src/cmd/gettingStarted.go b/draw2d/src/cmd/gettingStarted.go index 3e98f2a..b251763 100644 --- a/draw2d/src/cmd/gettingStarted.go +++ b/draw2d/src/cmd/gettingStarted.go @@ -11,8 +11,8 @@ import ( "image" "image/png" - //"draw2d" - "draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" + "draw2d" + //"draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" ) diff --git a/draw2d/src/cmd/testX11draw.go b/draw2d/src/cmd/testX11draw.go index 7f1229b..e0d627c 100644 --- a/draw2d/src/cmd/testX11draw.go +++ b/draw2d/src/cmd/testX11draw.go @@ -6,8 +6,8 @@ import ( "exp/draw/x11" "image" "math" - //"draw2d" - "draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" + "draw2d" + //"draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" ) func main() { diff --git a/draw2d/src/cmd/test_gopher.go b/draw2d/src/cmd/test_gopher.go index 4039222..efa551f 100644 --- a/draw2d/src/cmd/test_gopher.go +++ b/draw2d/src/cmd/test_gopher.go @@ -11,8 +11,8 @@ import ( "image" "image/png" - //"draw2d" - "draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" + "draw2d" + //"draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" ) const ( @@ -75,52 +75,52 @@ func gordon(gc *draw2d.GraphicContext, x, y, w, h float) { gc.Close() gc.SetFillColor(brb) gc.Fill() - gc.RoundRect(x, y+h, x+ w, y+h+h, 10, 10) + draw2d.RoundRect(gc, x, y+h, x+ w, y+h+h, 10, 10) gc.Fill() - gc.Circle(x, y+h, w/12) // left ear + draw2d.Circle(gc,x, y+h, w/12) // left ear gc.SetFillColor(brf) gc.Fill() - gc.Circle(x, y+h, w/12-10) + draw2d.Circle(gc, x, y+h, w/12-10) gc.SetFillColor(nf) gc.Fill() - gc.Circle(x+w, y+h, w/12) // right ear + draw2d.Circle(gc, x+w, y+h, w/12) // right ear gc.SetFillColor(brf) gc.Fill() - gc.Circle(x+w, y+h, w/12-10) + draw2d.Circle(gc, x+w, y+h, w/12-10) gc.SetFillColor(nf) gc.Fill() - gc.Circle(x+w/3, y+h23, w/9) // left eye + draw2d.Circle(gc, x+w/3, y+h23, w/9) // left eye gc.SetFillColor(wf) gc.Fill() - gc.Circle(x+w/3+10, y+h23, w / 10 - 10) + draw2d.Circle(gc, x+w/3+10, y+h23, w / 10 - 10) gc.SetFillColor(blf) gc.Fill() - gc.Circle(x+w/3+15, y+h23, 5) + draw2d.Circle(gc, x+w/3+15, y+h23, 5) gc.SetFillColor(wf) gc.Fill() - gc.Circle(x+w-w/3, y+h23, w/9) // right eye + draw2d.Circle(gc, x+w-w/3, y+h23, w/9) // right eye gc.Fill() - gc.Circle(x+w-w/3+10, y+h23, w / 10 - 10) + draw2d.Circle(gc, x+w-w/3+10, y+h23, w / 10 - 10) gc.SetFillColor(blf) gc.Fill() - gc.Circle(x+w-(w/3)+15, y+h23, 5) + draw2d.Circle(gc, x+w-(w/3)+15, y+h23, 5) gc.SetFillColor(wf) gc.Fill() gc.SetFillColor(wf) - gc.RoundRect(x+w/2-w/8, y+h+30, x+w/2-w/8 + w/8, y+h+30 + w/6, 5, 5) // left tooth + draw2d.RoundRect(gc, x+w/2-w/8, y+h+30, x+w/2-w/8 + w/8, y+h+30 + w/6, 5, 5) // left tooth gc.Fill() - gc.RoundRect(x+w/2, y+h+30, x+w/2+w/8, y+h+30+w/6, 5, 5) // right tooth + draw2d.RoundRect(gc, x+w/2, y+h+30, x+w/2+w/8, y+h+30+w/6, 5, 5) // right tooth gc.Fill() - gc.Ellipse(x+(w/2), y+h+30, w/6, w/12) // snout + draw2d.Ellipse(gc, x+(w/2), y+h+30, w/6, w/12) // snout gc.SetFillColor(nf) gc.Fill() - gc.Ellipse(x+(w/2), y+h+10, w/10, w/12) // nose + draw2d.Ellipse(gc, x+(w/2), y+h+10, w/10, w/12) // nose gc.SetFillColor(blf) gc.Fill() diff --git a/draw2d/src/cmd/testandroid.go b/draw2d/src/cmd/testandroid.go index 025389b..c1b1ae4 100644 --- a/draw2d/src/cmd/testandroid.go +++ b/draw2d/src/cmd/testandroid.go @@ -11,8 +11,8 @@ import ( "math" "image" "image/png" - //"draw2d" - "draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" + "draw2d" + //"draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" ) const ( @@ -71,21 +71,21 @@ func android(gc *draw2d.GraphicContext, x, y float) { gc.MoveTo(x+100, y+25) gc.LineTo( x+110, y+10) gc.Stroke() - gc.Circle(x+60, y+45, 5) // left eye + draw2d.Circle(gc, x+60, y+45, 5) // left eye gc.FillStroke() - gc.Circle(x+100, y+45, 5) // right eye + draw2d.Circle(gc, x+100, y+45, 5) // right eye gc.FillStroke() - gc.RoundRect(x+30, y+75, x+30+100, y+75+90, 10, 10) // body + draw2d.RoundRect(gc, x+30, y+75, x+30+100, y+75+90, 10, 10) // body gc.FillStroke() - gc.Rect(x+30, y+75, x+30+100, y+75+80) + draw2d.Rect(gc, x+30, y+75, x+30+100, y+75+80) gc.FillStroke() - gc.RoundRect(x+5, y+80, x+5+20, y+80+70, 10, 10) // left arm + draw2d.RoundRect(gc, x+5, y+80, x+5+20, y+80+70, 10, 10) // left arm gc.FillStroke() - gc.RoundRect(x+135, y+80, x+135+20, y+80+70, 10, 10) // right arm + draw2d.RoundRect(gc, x+135, y+80, x+135+20, y+80+70, 10, 10) // right arm gc.FillStroke() - gc.RoundRect(x+50, y+150, x+50+20, y+150+50, 10, 10) // left leg + draw2d.RoundRect(gc, x+50, y+150, x+50+20, y+150+50, 10, 10) // left leg gc.FillStroke() - gc.RoundRect(x+90, y+150, x+90+20, y+150+50, 10, 10) // right leg + draw2d.RoundRect(gc, x+90, y+150, x+90+20, y+150+50, 10, 10) // right leg gc.FillStroke() } diff --git a/draw2d/src/cmd/testdraw2d.go b/draw2d/src/cmd/testdraw2d.go index 627a84e..534ecdb 100644 --- a/draw2d/src/cmd/testdraw2d.go +++ b/draw2d/src/cmd/testdraw2d.go @@ -13,8 +13,8 @@ import ( "math" "image" "image/png" - //"draw2d" - "draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" + "draw2d" + //"draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" ) const ( @@ -283,11 +283,11 @@ func TestFillStyle() { i, gc := initGc(w, h) gc.SetLineWidth(6) - gc.Rect(12, 12, 244, 70) + draw2d.Rect(gc, 12, 12, 244, 70) - wheel1 := new(draw2d.Path) + wheel1 := new(draw2d.PathStorage) wheel1.ArcTo(64, 64, 40, 40, 0, 2*math.Pi) - wheel2 := new(draw2d.Path) + wheel2 := new(draw2d.PathStorage) wheel2.ArcTo(192, 64, 40, 40, 0, 2*math.Pi) gc.SetFillRule(draw2d.FillRuleEvenOdd) @@ -296,10 +296,10 @@ func TestFillStyle() { gc.SetStrokeColor(image.Black) gc.FillStroke(wheel1, wheel2) - gc.Rect(12, 140, 244, 198) - wheel1 = new(draw2d.Path) + draw2d.Rect(gc, 12, 140, 244, 198) + wheel1 = new(draw2d.PathStorage) wheel1.ArcTo(64, 192, 40, 40, 0, 2*math.Pi) - wheel2 = new(draw2d.Path) + wheel2 = new(draw2d.PathStorage) wheel2.ArcTo(192, 192, 40, 40, 0, -2*math.Pi) gc.SetFillRule(draw2d.FillRuleWinding) diff --git a/draw2d/src/cmd/testpath.go b/draw2d/src/cmd/testpath.go deleted file mode 100644 index d2dcbac..0000000 --- a/draw2d/src/cmd/testpath.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2010 The draw2d Authors. All rights reserved. -// created: 21/11/2010 by Laurent Le Goff - -package main - -import ( - //"draw2d" - "draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d" - "fmt" -) - -func main() { - path := new(draw2d.Path) - path.MoveTo(2.0, 3.0) - path.LineTo(2.0, 3.0) - path.QuadCurveTo(2.0, 3.0, 10, 20) - path.CubicCurveTo(2.0, 3.0, 10, 20, 13, 23) - path.Rect(2.0, 3.0, 100, 200) - path.ArcTo(2.0, 3.0, 100, 200, 200, 300) - fmt.Printf("%v\n", path) -} diff --git a/draw2d/src/pkg/draw2d/advanced_path.go b/draw2d/src/pkg/draw2d/advanced_path.go new file mode 100644 index 0000000..ec88083 --- /dev/null +++ b/draw2d/src/pkg/draw2d/advanced_path.go @@ -0,0 +1,39 @@ +package draw2d + +import( + "math" +) + + +//high level path creation +func Rect(path Path, x1, y1, x2, y2 float) { + path.MoveTo(x1, y1) + path.LineTo(x2, y1) + path.LineTo(x2, y2) + path.LineTo(x1, y2) + path.Close() +} + +func RoundRect(path Path, x1, y1, x2, y2, arcWidth, arcHeight float) { + arcWidth = arcWidth/2; + arcHeight = arcHeight/2; + path.MoveTo(x1, y1+ arcHeight); + path.QuadCurveTo(x1, y1, x1 + arcWidth, y1); + path.LineTo(x2-arcWidth, y1); + path.QuadCurveTo(x2, y1, x2, y1 + arcHeight); + path.LineTo(x2, y2-arcHeight); + path.QuadCurveTo(x2, y2, x2 - arcWidth, y2); + path.LineTo(x1 + arcWidth, y2); + path.QuadCurveTo(x1, y2, x1, y2 - arcHeight); + path.Close() +} + +func Ellipse(path Path, cx, cy, rx, ry float) { + path.ArcTo(cx, cy, rx, ry, 0, -math.Pi * 2) + path.Close() +} + +func Circle(path Path, cx, cy, radius float) { + path.ArcTo(cx, cy, radius, radius, 0, -math.Pi * 2) + path.Close() +} \ No newline at end of file diff --git a/draw2d/src/pkg/draw2d/dasher.go b/draw2d/src/pkg/draw2d/dasher.go index 5c1143d..7a01be5 100644 --- a/draw2d/src/pkg/draw2d/dasher.go +++ b/draw2d/src/pkg/draw2d/dasher.go @@ -12,7 +12,7 @@ type DashAdder struct { dashOffset float } -func traceDashPath(dash []float, dashOffset float, approximationScale float, adder raster.Adder, paths ...*Path) { +func traceDashPath(dash []float, dashOffset float, approximationScale float, adder raster.Adder, paths ...*PathStorage) { var dasher DashAdder if dash != nil && len(dash) > 0 { dasher.dash = dash diff --git a/draw2d/src/pkg/draw2d/draw2d.go b/draw2d/src/pkg/draw2d/draw2d.go index 10ce90c..2b4abdf 100644 --- a/draw2d/src/pkg/draw2d/draw2d.go +++ b/draw2d/src/pkg/draw2d/draw2d.go @@ -6,7 +6,6 @@ package draw2d import ( "exp/draw" "image" - "math" "freetype-go.googlecode.com/hg/freetype/raster" ) @@ -41,7 +40,7 @@ type GraphicContext struct { type contextStack struct { tr MatrixTransform - path *Path + path *PathStorage lineWidth float dash []float dashOffset float @@ -65,7 +64,7 @@ func NewGraphicContext(pi *image.RGBA) *GraphicContext { gc.current = new(contextStack) gc.current.tr = NewIdentityMatrix() - gc.current.path = new(Path) + gc.current.path = new(PathStorage) gc.current.lineWidth = 1.0 gc.current.strokeColor = image.Black gc.current.fillColor = image.White @@ -159,7 +158,7 @@ func (gc *GraphicContext) Restore() { } func (gc *GraphicContext) BeginPath() { - gc.current.path = new(Path) + gc.current.path = new(PathStorage) } func (gc *GraphicContext) MoveTo(x, y float) { @@ -202,43 +201,6 @@ func (gc *GraphicContext) RArcTo(dcx, dcy, rx, ry, startAngle, angle float) { gc.current.path.RArcTo(dcx, dcy, rx, ry, startAngle, angle) } -//high level path creation -func (gc *GraphicContext) Rect(x1, y1, x2, y2 float) { - if gc.current.path.isEmpty() { - gc.current.path.MoveTo(x1, y1) - } else { - gc.current.path.LineTo(x1, y1) - } - gc.current.path.LineTo(x2, y1) - gc.current.path.LineTo(x2, y2) - gc.current.path.LineTo(x1, y2) - gc.current.path.Close() -} - -func (gc *GraphicContext) RoundRect(x1, y1, x2, y2, arcWidth, arcHeight float) { - arcWidth = arcWidth/2; - arcHeight = arcHeight/2; - gc.MoveTo(x1, y1+ arcHeight); - gc.QuadCurveTo(x1, y1, x1 + arcWidth, y1); - gc.LineTo(x2-arcWidth, y1); - gc.QuadCurveTo(x2, y1, x2, y1 + arcHeight); - gc.LineTo(x2, y2-arcHeight); - gc.QuadCurveTo(x2, y2, x2 - arcWidth, y2); - gc.LineTo(x1 + arcWidth, y2); - gc.QuadCurveTo(x1, y2, x1, y2 - arcHeight); - gc.Close() -} - -func (gc *GraphicContext) Ellipse(cx, cy, rx, ry float) { - gc.current.path.ArcTo(cx, cy, rx, ry, 0, -math.Pi * 2) - gc.current.path.Close() -} - -func (gc *GraphicContext) Circle(cx, cy, radius float) { - gc.current.path.ArcTo(cx, cy, radius, radius, 0, -math.Pi * 2) - gc.current.path.Close() -} - func (gc *GraphicContext) Close() { gc.current.path.Close() } @@ -248,10 +210,10 @@ func (gc *GraphicContext) paint(color image.Color) { painter.SetColor(color) gc.rasterizer.Rasterize(painter) gc.rasterizer.Clear() - gc.current.path = new(Path) + gc.current.path = new(PathStorage) } -func (gc *GraphicContext) Stroke(paths ...*Path) { +func (gc *GraphicContext) Stroke(paths ...*PathStorage) { paths = append(paths, gc.current.path) gc.rasterizer.UseNonZeroWinding = true rasterPath := new(raster.Path) @@ -265,7 +227,7 @@ func (gc *GraphicContext) Stroke(paths ...*Path) { gc.paint(gc.current.strokeColor) } -func (gc *GraphicContext) Fill(paths ...*Path) { +func (gc *GraphicContext) Fill(paths ...*PathStorage) { paths = append(paths, gc.current.path) gc.rasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule() mta := NewMatrixTransformAdder(gc.current.tr, gc.rasterizer) @@ -273,7 +235,7 @@ func (gc *GraphicContext) Fill(paths ...*Path) { gc.paint(gc.current.fillColor) } -func (gc *GraphicContext) FillStroke(paths ...*Path) { +func (gc *GraphicContext) FillStroke(paths ...*PathStorage) { paths = append(paths, gc.current.path) mta := NewMatrixTransformAdder(gc.current.tr, gc.rasterizer) tracePath(gc.current.tr.GetMaxAbsScaling(), mta, paths...) diff --git a/draw2d/src/pkg/draw2d/path.go b/draw2d/src/pkg/draw2d/path.go index bee511c..dbe21da 100644 --- a/draw2d/src/pkg/draw2d/path.go +++ b/draw2d/src/pkg/draw2d/path.go @@ -3,26 +3,18 @@ package draw2d -import ( - "fmt" - "math" -) - -type PathCmd int - -const ( - MoveTo PathCmd = iota - LineTo - QuadCurveTo - CubicCurveTo - ArcTo - Close -) - -type Path struct { - commands []PathCmd - vertices []float - x, y float +type Path interface { + MoveTo(x, y float) + RMoveTo(dx, dy float) + LineTo(x, y float) + RLineTo(dx, dy float) + QuadCurveTo(cx, cy, x, y float) + RQuadCurveTo(dcx, dcy, dx, dy float) + CubicCurveTo(cx1, cy1, cx2, cy2, x, y float) + RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float) + ArcTo(cx, cy, rx, ry, startAngle, angle float) + RArcTo(dcx, dcy, rx, ry, startAngle, angle float) + Close() } type LineTracer interface { @@ -30,200 +22,3 @@ type LineTracer interface { LineTo(x, y float) } -func (p *Path) appendToPath(cmd PathCmd, vertices ...float) { - p.commands = append(p.commands, cmd) - p.vertices = append(p.vertices, vertices...) -} - -func (src *Path) Copy() (dest *Path) { - dest = new(Path) - dest.commands = make([]PathCmd, len(src.commands)) - copy(dest.commands, src.commands) - dest.vertices = make([]float, len(src.vertices)) - copy(dest.vertices, src.vertices) - return dest -} -func (p *Path) LastPoint() (x, y float) { - return p.x, p.y -} - -func (p *Path) isEmpty() bool { - return len(p.commands) == 0 -} - -func (p *Path) Close() *Path { - p.appendToPath(Close) - return p -} - -func (p *Path) MoveTo(x, y float) *Path { - p.appendToPath(MoveTo, x, y) - p.x = x - p.y = y - return p -} - -func (p *Path) RMoveTo(dx, dy float) *Path { - x, y := p.LastPoint() - p.MoveTo(x+dx, y+dy) - return p -} - -func (p *Path) LineTo(x, y float) *Path { - p.appendToPath(LineTo, x, y) - p.x = x - p.y = y - return p -} - -func (p *Path) RLineTo(dx, dy float) *Path { - x, y := p.LastPoint() - p.LineTo(x+dx, y+dy) - return p -} - -func (p *Path) Rect(x1, y1, x2, y2 float) *Path { - w, h := x2-x1, y2-y1 - if len(p.commands) > 0 { - p.LineTo(x1, y1) - } else { - p.MoveTo(x1, y1) - } - p.LineTo(x1+w, y1) - p.LineTo(x1+w, y1+h) - p.LineTo(x1, y1+h) - p.LineTo(x1, y1) - return p -} - -func (p *Path) RRect(dx1, dy1, dx2, dy2 float) *Path { - x, y := p.LastPoint() - p.Rect(x+dx1, y+dy1, x+dx2, y+dy2) - return p -} - -func (p *Path) QuadCurveTo(cx, cy, x, y float) *Path { - p.appendToPath(QuadCurveTo, cx, cy, x, y) - p.x = x - p.y = y - return p -} - -func (p *Path) RQuadCurveTo(dcx, dcy, dx, dy float) *Path { - x, y := p.LastPoint() - p.RQuadCurveTo(x+dcx, y+dcy, x+dx, y+dy) - return p -} - -func (p *Path) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float) *Path { - p.appendToPath(CubicCurveTo, cx1, cy1, cx2, cy2, x, y) - p.x = x - p.y = y - return p -} - -func (p *Path) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float) *Path { - x, y := p.LastPoint() - p.RCubicCurveTo(x+dcx1, y+dcy1, x+dcx2, y+dcy2, x+dx, y+dy) - return p -} - -func (p *Path) ArcTo(cx, cy, rx, ry, startAngle, angle float) *Path { - endAngle := startAngle + angle - clockWise := true - if angle < 0 { - clockWise = false - } - // normalize - if clockWise { - for endAngle < startAngle { - endAngle += math.Pi * 2.0 - } - } else { - for startAngle < endAngle { - startAngle += math.Pi * 2.0 - } - } - startX := cx + cos(startAngle)*rx - startY := cy + sin(startAngle)*ry - if len(p.commands) > 0 { - p.LineTo(startX, startY) - } else { - p.MoveTo(startX, startY) - } - p.appendToPath(ArcTo, cx, cy, rx, ry, startAngle, angle) - p.x = cx + cos(endAngle)*rx - p.y = cy + sin(endAngle)*ry - return p -} - -func (p *Path) RArcTo(dcx, dcy, rx, ry, startAngle, angle float) *Path { - x, y := p.LastPoint() - p.RArcTo(x+dcx, y+dcy, rx, ry, startAngle, angle) - return p -} - -func (p *Path) TraceLine(tracer LineTracer, approximationScale float) { - j := 0 - x, y := 0.0, 0.0 - firstX, firstY := x, y - if len(p.commands) > 0 { - if p.commands[0] == MoveTo { - firstX, firstY = p.vertices[0], p.vertices[1] - } - } - for _, cmd := range p.commands { - switch cmd { - case MoveTo: - tracer.MoveTo(p.vertices[j], p.vertices[j+1]) - x, y = p.vertices[j], p.vertices[j+1] - firstX, firstY = x, y - j = j + 2 - case LineTo: - tracer.LineTo(p.vertices[j], p.vertices[j+1]) - x, y = p.vertices[j], p.vertices[j+1] - j = j + 2 - case QuadCurveTo: - quadraticBezier(tracer, x, y, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], approximationScale, 0) - x, y = p.vertices[j+2], p.vertices[j+3] - j = j + 4 - case CubicCurveTo: - cubicBezier(tracer, x, y, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5], approximationScale, 0, 0) - x, y = p.vertices[j+4], p.vertices[j+5] - j = j + 6 - case ArcTo: - arc(tracer, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5], approximationScale) - j = j + 6 - case Close: - tracer.LineTo(firstX, firstY) - x, y = firstX, firstY - } - } -} - -func (p *Path) String() string { - s := "" - j := 0 - for _, cmd := range p.commands { - switch cmd { - case MoveTo: - s += fmt.Sprintf("MoveTo: %f, %f\n", p.vertices[j], p.vertices[j+1]) - j = j + 2 - case LineTo: - s += fmt.Sprintf("LineTo: %f, %f\n", p.vertices[j], p.vertices[j+1]) - j = j + 2 - case QuadCurveTo: - s += fmt.Sprintf("QuadCurveTo: %f, %f, %f, %f\n", p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3]) - j = j + 4 - case CubicCurveTo: - s += fmt.Sprintf("CubicCurveTo: %f, %f, %f, %f, %f, %f\n", p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5]) - j = j + 6 - case ArcTo: - s += fmt.Sprintf("ArcTo: %f, %f, %f, %f, %f, %f\n", p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5]) - j = j + 6 - case Close: - s += "Close\n" - } - } - return s -} diff --git a/draw2d/src/pkg/draw2d/path_adder.go b/draw2d/src/pkg/draw2d/path_adder.go index 6b79d35..71524d0 100644 --- a/draw2d/src/pkg/draw2d/path_adder.go +++ b/draw2d/src/pkg/draw2d/path_adder.go @@ -15,7 +15,7 @@ func floatToPoint(x, y float) raster.Point { return raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)} } -func tracePath(approximationScale float, adder raster.Adder, paths ...*Path) { +func tracePath(approximationScale float, adder raster.Adder, paths ...*PathStorage) { pathAdder := &PathAdder{adder} for _, path := range paths { path.TraceLine(pathAdder, approximationScale) diff --git a/draw2d/src/pkg/draw2d/path_storage.go b/draw2d/src/pkg/draw2d/path_storage.go new file mode 100644 index 0000000..b13ed88 --- /dev/null +++ b/draw2d/src/pkg/draw2d/path_storage.go @@ -0,0 +1,203 @@ +// Copyright 2010 The draw2d Authors. All rights reserved. +// created: 21/11/2010 by Laurent Le Goff +package draw2d + +import ( + "fmt" + "math" +) + +type PathCmd int + +const ( + MoveTo PathCmd = iota + LineTo + QuadCurveTo + CubicCurveTo + ArcTo + Close +) + +type PathStorage struct { + commands []PathCmd + vertices []float + x, y float +} + +func (p *PathStorage) appendToPath(cmd PathCmd, vertices ...float) { + p.commands = append(p.commands, cmd) + p.vertices = append(p.vertices, vertices...) +} + +func (src *PathStorage) Copy() (dest *PathStorage) { + dest = new(PathStorage) + dest.commands = make([]PathCmd, len(src.commands)) + copy(dest.commands, src.commands) + dest.vertices = make([]float, len(src.vertices)) + copy(dest.vertices, src.vertices) + return dest +} +func (p *PathStorage) LastPoint() (x, y float) { + return p.x, p.y +} + +func (p *PathStorage) isEmpty() bool { + return len(p.commands) == 0 +} + +func (p *PathStorage) Close() *PathStorage { + p.appendToPath(Close) + return p +} + +func (p *PathStorage) MoveTo(x, y float) *PathStorage { + p.appendToPath(MoveTo, x, y) + p.x = x + p.y = y + return p +} + +func (p *PathStorage) RMoveTo(dx, dy float) *PathStorage { + x, y := p.LastPoint() + p.MoveTo(x+dx, y+dy) + return p +} + +func (p *PathStorage) LineTo(x, y float) *PathStorage { + p.appendToPath(LineTo, x, y) + p.x = x + p.y = y + return p +} + +func (p *PathStorage) RLineTo(dx, dy float) *PathStorage { + x, y := p.LastPoint() + p.LineTo(x+dx, y+dy) + return p +} + +func (p *PathStorage) QuadCurveTo(cx, cy, x, y float) *PathStorage { + p.appendToPath(QuadCurveTo, cx, cy, x, y) + p.x = x + p.y = y + return p +} + +func (p *PathStorage) RQuadCurveTo(dcx, dcy, dx, dy float) *PathStorage { + x, y := p.LastPoint() + p.RQuadCurveTo(x+dcx, y+dcy, x+dx, y+dy) + return p +} + +func (p *PathStorage) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float) *PathStorage { + p.appendToPath(CubicCurveTo, cx1, cy1, cx2, cy2, x, y) + p.x = x + p.y = y + return p +} + +func (p *PathStorage) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float) *PathStorage { + x, y := p.LastPoint() + p.RCubicCurveTo(x+dcx1, y+dcy1, x+dcx2, y+dcy2, x+dx, y+dy) + return p +} + +func (p *PathStorage) ArcTo(cx, cy, rx, ry, startAngle, angle float) *PathStorage { + endAngle := startAngle + angle + clockWise := true + if angle < 0 { + clockWise = false + } + // normalize + if clockWise { + for endAngle < startAngle { + endAngle += math.Pi * 2.0 + } + } else { + for startAngle < endAngle { + startAngle += math.Pi * 2.0 + } + } + startX := cx + cos(startAngle)*rx + startY := cy + sin(startAngle)*ry + if len(p.commands) > 0 { + p.LineTo(startX, startY) + } else { + p.MoveTo(startX, startY) + } + p.appendToPath(ArcTo, cx, cy, rx, ry, startAngle, angle) + p.x = cx + cos(endAngle)*rx + p.y = cy + sin(endAngle)*ry + return p +} + +func (p *PathStorage) RArcTo(dcx, dcy, rx, ry, startAngle, angle float) *PathStorage { + x, y := p.LastPoint() + p.RArcTo(x+dcx, y+dcy, rx, ry, startAngle, angle) + return p +} + +func (p *PathStorage) TraceLine(tracer LineTracer, approximationScale float) { + j := 0 + x, y := 0.0, 0.0 + firstX, firstY := x, y + if len(p.commands) > 0 { + if p.commands[0] == MoveTo { + firstX, firstY = p.vertices[0], p.vertices[1] + } + } + for _, cmd := range p.commands { + switch cmd { + case MoveTo: + tracer.MoveTo(p.vertices[j], p.vertices[j+1]) + x, y = p.vertices[j], p.vertices[j+1] + firstX, firstY = x, y + j = j + 2 + case LineTo: + tracer.LineTo(p.vertices[j], p.vertices[j+1]) + x, y = p.vertices[j], p.vertices[j+1] + j = j + 2 + case QuadCurveTo: + quadraticBezier(tracer, x, y, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], approximationScale, 0) + x, y = p.vertices[j+2], p.vertices[j+3] + j = j + 4 + case CubicCurveTo: + cubicBezier(tracer, x, y, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5], approximationScale, 0, 0) + x, y = p.vertices[j+4], p.vertices[j+5] + j = j + 6 + case ArcTo: + arc(tracer, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5], approximationScale) + j = j + 6 + case Close: + tracer.LineTo(firstX, firstY) + x, y = firstX, firstY + } + } +} + +func (p *PathStorage) String() string { + s := "" + j := 0 + for _, cmd := range p.commands { + switch cmd { + case MoveTo: + s += fmt.Sprintf("MoveTo: %f, %f\n", p.vertices[j], p.vertices[j+1]) + j = j + 2 + case LineTo: + s += fmt.Sprintf("LineTo: %f, %f\n", p.vertices[j], p.vertices[j+1]) + j = j + 2 + case QuadCurveTo: + s += fmt.Sprintf("QuadCurveTo: %f, %f, %f, %f\n", p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3]) + j = j + 4 + case CubicCurveTo: + s += fmt.Sprintf("CubicCurveTo: %f, %f, %f, %f, %f, %f\n", p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5]) + j = j + 6 + case ArcTo: + s += fmt.Sprintf("ArcTo: %f, %f, %f, %f, %f, %f\n", p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5]) + j = j + 6 + case Close: + s += "Close\n" + } + } + return s +}