218 lines
4.8 KiB
Go
218 lines
4.8 KiB
Go
package svg
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type (
|
|
D []PathCommand
|
|
|
|
PathCommand interface {
|
|
PrintPathCommand() (string, string, bool)
|
|
PrintPathCommandParameters() string
|
|
}
|
|
|
|
// PathCommand implementations
|
|
|
|
// PathRelative makes any PathCommand and converts it into a relative command (makes lowercase)
|
|
PathRelative[C PathCommand] struct {
|
|
Command C
|
|
}
|
|
|
|
PathMoveTo struct {
|
|
X, Y float64
|
|
}
|
|
|
|
PathLineTo struct {
|
|
X, Y float64
|
|
}
|
|
PathHorizontalLine float64
|
|
PathVerticalLine float64
|
|
|
|
PathCubicBezier []PathCubicBezierParameterTuple
|
|
PathCubicBezierParameterTuple struct {
|
|
X1, Y1 float64
|
|
X2, Y2 float64
|
|
X, Y float64
|
|
}
|
|
PathSmoothCubicBezier []PathSmoothCubicBezierParameterTuple
|
|
PathSmoothCubicBezierParameterTuple struct {
|
|
X2, Y2 float64
|
|
X, Y float64
|
|
}
|
|
|
|
PathQuadraticBezier []PathQuadraticBezierParameterTuple
|
|
PathQuadraticBezierParameterTuple struct {
|
|
X1, Y1 float64
|
|
X, Y float64
|
|
}
|
|
PathSmoothQuadraticBezier []PathSmoothQuadraticBezierParameterTuple
|
|
PathSmoothQuadraticBezierParameterTuple struct {
|
|
X, Y float64
|
|
}
|
|
|
|
PathElliptical []PathEllipticalParameterTuple
|
|
PathEllipticalParameterTuple struct {
|
|
RX, RY float64
|
|
Angle float64
|
|
LargeArc bool
|
|
Clockwise bool
|
|
X, Y float64
|
|
}
|
|
|
|
PathClose struct{}
|
|
)
|
|
|
|
func PrintPathCommand(c PathCommand) (string, bool) {
|
|
cmd, params, ok := c.PrintPathCommand()
|
|
if !ok {
|
|
return "", false
|
|
}
|
|
return fmt.Sprintf("%s %s", cmd, params), true
|
|
}
|
|
|
|
func (c PathRelative[C]) PrintPathCommand() (string, string, bool) {
|
|
cmd, params, ok := c.Command.PrintPathCommand()
|
|
return strings.ToLower(cmd), params, ok
|
|
}
|
|
|
|
func (c PathMoveTo) PrintPathCommand() (string, string, bool) {
|
|
return "M", fmt.Sprintf("%v,%v", c.X, c.Y), true
|
|
}
|
|
|
|
func (c PathLineTo) PrintPathCommand() (string, string, bool) {
|
|
return "L", fmt.Sprintf("%v,%v", c.X, c.Y), true
|
|
}
|
|
|
|
func (c PathHorizontalLine) PrintPathCommand() (string, string, bool) {
|
|
return "H", fmt.Sprintf("%v", float64(c)), true
|
|
}
|
|
|
|
func (c PathVerticalLine) PrintPathCommand() (string, string, bool) {
|
|
return "V", fmt.Sprintf("%v", float64(c)), false
|
|
}
|
|
|
|
func (c PathCubicBezier) PrintPathCommand() (string, string, bool) {
|
|
if len(c) == 0 {
|
|
return "", "", false
|
|
}
|
|
return "C", printTuples(c), true
|
|
}
|
|
|
|
func (c PathCubicBezier) Append(x1, y1, x2, y2, x, y float64) PathCubicBezier {
|
|
return append(c, PathCubicBezierParameterTuple{
|
|
X1: x1,
|
|
Y1: y1,
|
|
X2: x2,
|
|
Y2: y2,
|
|
X: x,
|
|
Y: y,
|
|
})
|
|
}
|
|
|
|
func (t PathCubicBezierParameterTuple) String() string {
|
|
return fmt.Sprintf("%v,%v %v,%v %v,%v", t.X1, t.Y1, t.X2, t.Y2, t.X, t.Y)
|
|
}
|
|
|
|
func (c PathSmoothCubicBezier) PrintPathCommand() (string, string, bool) {
|
|
if len(c) == 0 {
|
|
return "", "", false
|
|
}
|
|
return "S", printTuples(c), true
|
|
}
|
|
|
|
func (c PathSmoothCubicBezier) Append(x2, y2, x, y float64) PathSmoothCubicBezier {
|
|
return append(c, PathSmoothCubicBezierParameterTuple{
|
|
X2: x2,
|
|
Y2: y2,
|
|
X: x,
|
|
Y: y,
|
|
})
|
|
}
|
|
|
|
func (t PathSmoothCubicBezierParameterTuple) String() string {
|
|
return fmt.Sprintf("%v,%v %v,%v", t.X2, t.Y2, t.X, t.Y)
|
|
}
|
|
|
|
func (c PathQuadraticBezier) PrintPathCommand() (string, string, bool) {
|
|
if len(c) == 0 {
|
|
return "", "", false
|
|
}
|
|
return "Q", printTuples(c), true
|
|
}
|
|
|
|
func (c PathQuadraticBezier) Append(x1, y1, x, y float64) PathQuadraticBezier {
|
|
return append(c, PathQuadraticBezierParameterTuple{
|
|
X1: x1,
|
|
Y1: y1,
|
|
X: x,
|
|
Y: y,
|
|
})
|
|
}
|
|
|
|
func (t PathQuadraticBezierParameterTuple) String() string {
|
|
return fmt.Sprintf("%v,%v %v,%v", t.X1, t.Y1, t.X, t.Y)
|
|
}
|
|
|
|
func (c PathSmoothQuadraticBezier) PrintPathCommand() (string, string, bool) {
|
|
if len(c) == 0 {
|
|
return "", "", false
|
|
}
|
|
return "T", printTuples(c), true
|
|
}
|
|
|
|
func (c PathSmoothQuadraticBezier) Append(x, y float64) PathSmoothQuadraticBezier {
|
|
return append(c, PathSmoothQuadraticBezierParameterTuple{
|
|
X: x,
|
|
Y: y,
|
|
})
|
|
}
|
|
|
|
func (t PathSmoothQuadraticBezierParameterTuple) String() string {
|
|
return fmt.Sprintf("%v,%v", t.X, t.Y)
|
|
}
|
|
|
|
func (c PathElliptical) PrintPathCommand() (string, string, bool) {
|
|
if len(c) == 0 {
|
|
return "", "", false
|
|
}
|
|
return "A", printTuples(c), true
|
|
}
|
|
|
|
func (c PathElliptical) Append(rx, ry, angle float64, largeArc, clockwise bool, x, y float64) PathElliptical {
|
|
return append(c, PathEllipticalParameterTuple{
|
|
RX: rx,
|
|
RY: ry,
|
|
Angle: angle,
|
|
LargeArc: largeArc,
|
|
Clockwise: clockwise,
|
|
X: x,
|
|
Y: y,
|
|
})
|
|
}
|
|
|
|
func (t PathEllipticalParameterTuple) String() string {
|
|
var (
|
|
largeArcFlag int
|
|
sweepFlag int
|
|
)
|
|
|
|
if t.LargeArc {
|
|
largeArcFlag = 1
|
|
}
|
|
if t.Clockwise {
|
|
sweepFlag = 1
|
|
}
|
|
|
|
return fmt.Sprintf("%v,%v,%v,%d,%d,%v,%v", t.RX, t.RY, t.Angle, largeArcFlag, sweepFlag, t.X, t.Y)
|
|
}
|
|
|
|
func printTuples[S fmt.Stringer](vs []S) string {
|
|
ss := make([]string, len(vs))
|
|
for i, v := range vs {
|
|
ss[i] = fmt.Sprint(v)
|
|
}
|
|
return strings.Join(ss, " ")
|
|
}
|