d47e08f7c9
- make PathStorage Commands and Vertices public, so they can be accessed by the pdf backend - start every path with MoveTo (also before ArcTo)
173 lines
4.9 KiB
Go
173 lines
4.9 KiB
Go
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
// created: 06/12/2010 by Laurent Le Goff
|
|
|
|
package draw2d
|
|
|
|
import (
|
|
"math"
|
|
)
|
|
|
|
type PathConverter struct {
|
|
converter VertexConverter
|
|
ApproximationScale, AngleTolerance, CuspLimit float64
|
|
startX, startY, x, y float64
|
|
}
|
|
|
|
func NewPathConverter(converter VertexConverter) *PathConverter {
|
|
return &PathConverter{converter, 1, 0, 0, 0, 0, 0, 0}
|
|
}
|
|
|
|
func (c *PathConverter) Convert(paths ...*PathStorage) {
|
|
for _, path := range paths {
|
|
j := 0
|
|
for _, cmd := range path.Commands {
|
|
j = j + c.ConvertCommand(cmd, path.Vertices[j:]...)
|
|
}
|
|
c.converter.NextCommand(VertexStopCommand)
|
|
}
|
|
}
|
|
|
|
func (c *PathConverter) ConvertCommand(cmd PathCmd, vertices ...float64) int {
|
|
switch cmd {
|
|
case MoveTo:
|
|
c.x, c.y = vertices[0], vertices[1]
|
|
c.startX, c.startY = c.x, c.y
|
|
c.converter.NextCommand(VertexStopCommand)
|
|
c.converter.NextCommand(VertexStartCommand)
|
|
c.converter.Vertex(c.x, c.y)
|
|
return 2
|
|
case LineTo:
|
|
c.x, c.y = vertices[0], vertices[1]
|
|
if c.startX == c.x && c.startY == c.y {
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
}
|
|
c.converter.Vertex(c.x, c.y)
|
|
c.converter.NextCommand(VertexJoinCommand)
|
|
return 2
|
|
case QuadCurveTo:
|
|
quadraticBezier(c.converter, c.x, c.y, vertices[0], vertices[1], vertices[2], vertices[3], c.ApproximationScale, c.AngleTolerance)
|
|
c.x, c.y = vertices[2], vertices[3]
|
|
if c.startX == c.x && c.startY == c.y {
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
}
|
|
c.converter.Vertex(c.x, c.y)
|
|
return 4
|
|
case CubicCurveTo:
|
|
cubicBezier(c.converter, c.x, c.y, vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5], c.ApproximationScale, c.AngleTolerance, c.CuspLimit)
|
|
c.x, c.y = vertices[4], vertices[5]
|
|
if c.startX == c.x && c.startY == c.y {
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
}
|
|
c.converter.Vertex(c.x, c.y)
|
|
return 6
|
|
case ArcTo:
|
|
c.x, c.y = arc(c.converter, vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5], c.ApproximationScale)
|
|
if c.startX == c.x && c.startY == c.y {
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
}
|
|
c.converter.Vertex(c.x, c.y)
|
|
return 6
|
|
case Close:
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
c.converter.Vertex(c.startX, c.startY)
|
|
return 0
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (c *PathConverter) MoveTo(x, y float64) *PathConverter {
|
|
c.x, c.y = x, y
|
|
c.startX, c.startY = c.x, c.y
|
|
c.converter.NextCommand(VertexStopCommand)
|
|
c.converter.NextCommand(VertexStartCommand)
|
|
c.converter.Vertex(c.x, c.y)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) RMoveTo(dx, dy float64) *PathConverter {
|
|
c.MoveTo(c.x+dx, c.y+dy)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) LineTo(x, y float64) *PathConverter {
|
|
c.x, c.y = x, y
|
|
if c.startX == c.x && c.startY == c.y {
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
}
|
|
c.converter.Vertex(c.x, c.y)
|
|
c.converter.NextCommand(VertexJoinCommand)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) RLineTo(dx, dy float64) *PathConverter {
|
|
c.LineTo(c.x+dx, c.y+dy)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) QuadCurveTo(cx, cy, x, y float64) *PathConverter {
|
|
quadraticBezier(c.converter, c.x, c.y, cx, cy, x, y, c.ApproximationScale, c.AngleTolerance)
|
|
c.x, c.y = x, y
|
|
if c.startX == c.x && c.startY == c.y {
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
}
|
|
c.converter.Vertex(c.x, c.y)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) RQuadCurveTo(dcx, dcy, dx, dy float64) *PathConverter {
|
|
c.QuadCurveTo(c.x+dcx, c.y+dcy, c.x+dx, c.y+dy)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) *PathConverter {
|
|
cubicBezier(c.converter, c.x, c.y, cx1, cy1, cx2, cy2, x, y, c.ApproximationScale, c.AngleTolerance, c.CuspLimit)
|
|
c.x, c.y = x, y
|
|
if c.startX == c.x && c.startY == c.y {
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
}
|
|
c.converter.Vertex(c.x, c.y)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) *PathConverter {
|
|
c.CubicCurveTo(c.x+dcx1, c.y+dcy1, c.x+dcx2, c.y+dcy2, c.x+dx, c.y+dy)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) ArcTo(cx, cy, rx, ry, startAngle, angle float64) *PathConverter {
|
|
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 + math.Cos(startAngle)*rx
|
|
startY := cy + math.Sin(startAngle)*ry
|
|
c.MoveTo(startX, startY)
|
|
c.x, c.y = arc(c.converter, cx, cy, rx, ry, startAngle, angle, c.ApproximationScale)
|
|
if c.startX == c.x && c.startY == c.y {
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
}
|
|
c.converter.Vertex(c.x, c.y)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) *PathConverter {
|
|
c.ArcTo(c.x+dcx, c.y+dcy, rx, ry, startAngle, angle)
|
|
return c
|
|
}
|
|
|
|
func (c *PathConverter) Close() *PathConverter {
|
|
c.converter.NextCommand(VertexCloseCommand)
|
|
c.converter.Vertex(c.startX, c.startY)
|
|
return c
|
|
}
|