Rename LineTracer and VertexConverter to LineBuilder
This commit is contained in:
parent
4b3ba53f4c
commit
ceb331894d
16 changed files with 180 additions and 177 deletions
4
arc.go
4
arc.go
|
@ -9,7 +9,7 @@ import (
|
||||||
"code.google.com/p/freetype-go/freetype/raster"
|
"code.google.com/p/freetype-go/freetype/raster"
|
||||||
)
|
)
|
||||||
|
|
||||||
func arc(t VertexConverter, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) {
|
func arc(t LineBuilder, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) {
|
||||||
end := start + angle
|
end := start + angle
|
||||||
clockWise := true
|
clockWise := true
|
||||||
if angle < 0 {
|
if angle < 0 {
|
||||||
|
@ -33,7 +33,7 @@ func arc(t VertexConverter, x, y, rx, ry, start, angle, scale float64) (lastX, l
|
||||||
curY = y + math.Sin(angle)*ry
|
curY = y + math.Sin(angle)*ry
|
||||||
|
|
||||||
angle += da
|
angle += da
|
||||||
t.AddPoint(curX, curY)
|
t.LineTo(curX, curY)
|
||||||
}
|
}
|
||||||
return curX, curY
|
return curX, curY
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TraceArc trace an arc using a LineTracer
|
// TraceArc trace an arc using a LineBuilder
|
||||||
func TraceArc(t LineTracer, x, y, rx, ry, start, angle, scale float64) {
|
func TraceArc(t LineBuilder, x, y, rx, ry, start, angle, scale float64) {
|
||||||
end := start + angle
|
end := start + angle
|
||||||
clockWise := true
|
clockWise := true
|
||||||
if angle < 0 {
|
if angle < 0 {
|
||||||
|
@ -32,7 +32,7 @@ func TraceArc(t LineTracer, x, y, rx, ry, start, angle, scale float64) {
|
||||||
curY = y + math.Sin(angle)*ry
|
curY = y + math.Sin(angle)*ry
|
||||||
|
|
||||||
angle += da
|
angle += da
|
||||||
t.AddPoint(curX, curY)
|
t.LineTo(curX, curY)
|
||||||
}
|
}
|
||||||
t.AddPoint(curX, curY)
|
t.LineTo(curX, curY)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,9 +46,9 @@ func SubdivideCubic(c, c1, c2 []float64) {
|
||||||
c2[0], c2[1] = c1[6], c1[7]
|
c2[0], c2[1] = c1[6], c1[7]
|
||||||
}
|
}
|
||||||
|
|
||||||
// TraceCubic generate lines subdividing the cubic curve using a LineTracer
|
// TraceCubic generate lines subdividing the cubic curve using a LineBuilder
|
||||||
// flattening_threshold helps determines the flattening expectation of the curve
|
// flattening_threshold helps determines the flattening expectation of the curve
|
||||||
func TraceCubic(t LineTracer, cubic []float64, flattening_threshold float64) {
|
func TraceCubic(t LineBuilder, cubic []float64, flattening_threshold float64) {
|
||||||
// Allocation curves
|
// Allocation curves
|
||||||
var curves [CurveRecursionLimit * 8]float64
|
var curves [CurveRecursionLimit * 8]float64
|
||||||
copy(curves[0:8], cubic[0:8])
|
copy(curves[0:8], cubic[0:8])
|
||||||
|
@ -69,7 +69,7 @@ func TraceCubic(t LineTracer, cubic []float64, flattening_threshold float64) {
|
||||||
|
|
||||||
// if it's flat then trace a line
|
// if it's flat then trace a line
|
||||||
if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
|
if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
|
||||||
t.AddPoint(c[6], c[7])
|
t.LineTo(c[6], c[7])
|
||||||
i--
|
i--
|
||||||
} else {
|
} else {
|
||||||
// second half of bezier go lower onto the stack
|
// second half of bezier go lower onto the stack
|
||||||
|
|
|
@ -38,7 +38,11 @@ type Path struct {
|
||||||
points []float64
|
points []float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Path) AddPoint(x, y float64) {
|
func (p *Path) MoveTo(x, y float64) {
|
||||||
|
p.points = append(p.points, x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Path) LineTo(x, y float64) {
|
||||||
p.points = append(p.points, x, y)
|
p.points = append(p.points, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +86,7 @@ func drawPoints(img draw.Image, c color.Color, s ...float64) image.Image {
|
||||||
func TestCubicCurve(t *testing.T) {
|
func TestCubicCurve(t *testing.T) {
|
||||||
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
||||||
var p Path
|
var p Path
|
||||||
p.AddPoint(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
||||||
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
||||||
img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
|
img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
|
||||||
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsCubicFloat64[i:i+8]...)
|
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsCubicFloat64[i:i+8]...)
|
||||||
|
@ -98,7 +102,7 @@ func TestCubicCurve(t *testing.T) {
|
||||||
func TestQuadCurve(t *testing.T) {
|
func TestQuadCurve(t *testing.T) {
|
||||||
for i := 0; i < len(testsQuadFloat64); i += 6 {
|
for i := 0; i < len(testsQuadFloat64); i += 6 {
|
||||||
var p Path
|
var p Path
|
||||||
p.AddPoint(testsQuadFloat64[i], testsQuadFloat64[i+1])
|
p.MoveTo(testsQuadFloat64[i], testsQuadFloat64[i+1])
|
||||||
TraceQuad(&p, testsQuadFloat64[i:], flattening_threshold)
|
TraceQuad(&p, testsQuadFloat64[i:], flattening_threshold)
|
||||||
img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
|
img := image.NewNRGBA(image.Rect(0, 0, 300, 300))
|
||||||
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsQuadFloat64[i:i+6]...)
|
raster.PolylineBresenham(img, color.NRGBA{0xff, 0, 0, 0xff}, testsQuadFloat64[i:i+6]...)
|
||||||
|
@ -115,7 +119,7 @@ func BenchmarkCubicCurve(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
for i := 0; i < len(testsCubicFloat64); i += 8 {
|
||||||
var p Path
|
var p Path
|
||||||
p.AddPoint(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
p.MoveTo(testsCubicFloat64[i], testsCubicFloat64[i+1])
|
||||||
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
TraceCubic(&p, testsCubicFloat64[i:], flattening_threshold)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
7
curve/line.go
Normal file
7
curve/line.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package curve
|
||||||
|
|
||||||
|
// LineBuilder is an interface that help segmenting curve into small lines
|
||||||
|
type LineBuilder interface {
|
||||||
|
// LineTo a point
|
||||||
|
LineTo(x, y float64)
|
||||||
|
}
|
|
@ -29,9 +29,9 @@ func SubdivideQuad(c, c1, c2 []float64) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trace generate lines subdividing the curve using a LineTracer
|
// Trace generate lines subdividing the curve using a LineBuilder
|
||||||
// flattening_threshold helps determines the flattening expectation of the curve
|
// flattening_threshold helps determines the flattening expectation of the curve
|
||||||
func TraceQuad(t LineTracer, quad []float64, flattening_threshold float64) {
|
func TraceQuad(t LineBuilder, quad []float64, flattening_threshold float64) {
|
||||||
// Allocates curves stack
|
// Allocates curves stack
|
||||||
var curves [CurveRecursionLimit * 6]float64
|
var curves [CurveRecursionLimit * 6]float64
|
||||||
copy(curves[0:6], quad[0:6])
|
copy(curves[0:6], quad[0:6])
|
||||||
|
@ -49,7 +49,7 @@ func TraceQuad(t LineTracer, quad []float64, flattening_threshold float64) {
|
||||||
|
|
||||||
// if it's flat then trace a line
|
// if it's flat then trace a line
|
||||||
if (d*d) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
|
if (d*d) < flattening_threshold*(dx*dx+dy*dy) || i == len(curves)-1 {
|
||||||
t.AddPoint(c[4], c[5])
|
t.LineTo(c[4], c[5])
|
||||||
i--
|
i--
|
||||||
} else {
|
} else {
|
||||||
// second half of bezier go lower onto the stack
|
// second half of bezier go lower onto the stack
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
package curve
|
|
||||||
|
|
||||||
// LineTracer is an interface that help segmenting curve into small lines
|
|
||||||
type LineTracer interface {
|
|
||||||
// AddPoint a point
|
|
||||||
AddPoint(x, y float64)
|
|
||||||
}
|
|
42
curves.go
42
curves.go
|
@ -33,7 +33,7 @@ var (
|
||||||
The more this value is the less sharp turns will be cut.
|
The more this value is the less sharp turns will be cut.
|
||||||
Typically it should not exceed 10-15 degrees.
|
Typically it should not exceed 10-15 degrees.
|
||||||
*/
|
*/
|
||||||
func cubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4, approximationScale, angleTolerance, cuspLimit float64) {
|
func cubicBezier(v LineBuilder, x1, y1, x2, y2, x3, y3, x4, y4, approximationScale, angleTolerance, cuspLimit float64) {
|
||||||
cuspLimit = computeCuspLimit(cuspLimit)
|
cuspLimit = computeCuspLimit(cuspLimit)
|
||||||
distanceToleranceSquare := 0.5 / approximationScale
|
distanceToleranceSquare := 0.5 / approximationScale
|
||||||
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
||||||
|
@ -43,7 +43,7 @@ func cubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4, approximatio
|
||||||
/*
|
/*
|
||||||
* see cubicBezier comments for approximationScale and angleTolerance definition
|
* see cubicBezier comments for approximationScale and angleTolerance definition
|
||||||
*/
|
*/
|
||||||
func quadraticBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, approximationScale, angleTolerance float64) {
|
func quadraticBezier(v LineBuilder, x1, y1, x2, y2, x3, y3, approximationScale, angleTolerance float64) {
|
||||||
distanceToleranceSquare := 0.5 / approximationScale
|
distanceToleranceSquare := 0.5 / approximationScale
|
||||||
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func computeCuspLimit(v float64) (r float64) {
|
||||||
/**
|
/**
|
||||||
* http://www.antigrain.com/research/adaptive_bezier/index.html
|
* http://www.antigrain.com/research/adaptive_bezier/index.html
|
||||||
*/
|
*/
|
||||||
func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 float64, level int, distanceToleranceSquare, angleTolerance float64) {
|
func recursiveQuadraticBezierBezier(v LineBuilder, x1, y1, x2, y2, x3, y3 float64, level int, distanceToleranceSquare, angleTolerance float64) {
|
||||||
if level > CurveRecursionLimit {
|
if level > CurveRecursionLimit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 fl
|
||||||
// we tend to finish subdivisions.
|
// we tend to finish subdivisions.
|
||||||
//----------------------
|
//----------------------
|
||||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
if angleTolerance < CurveAngleToleranceEpsilon {
|
||||||
v.AddPoint(x123, y123)
|
v.LineTo(x123, y123)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 fl
|
||||||
if da < angleTolerance {
|
if da < angleTolerance {
|
||||||
// Finally we can stop the recursion
|
// Finally we can stop the recursion
|
||||||
//----------------------
|
//----------------------
|
||||||
v.AddPoint(x123, y123)
|
v.LineTo(x123, y123)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 fl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if d < distanceToleranceSquare {
|
if d < distanceToleranceSquare {
|
||||||
v.AddPoint(x2, y2)
|
v.LineTo(x2, y2)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 fl
|
||||||
/**
|
/**
|
||||||
* http://www.antigrain.com/research/adaptive_bezier/index.html
|
* http://www.antigrain.com/research/adaptive_bezier/index.html
|
||||||
*/
|
*/
|
||||||
func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 float64, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) {
|
func recursiveCubicBezier(v LineBuilder, x1, y1, x2, y2, x3, y3, x4, y4 float64, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) {
|
||||||
if level > CurveRecursionLimit {
|
if level > CurveRecursionLimit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -209,12 +209,12 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa
|
||||||
}
|
}
|
||||||
if d2 > d3 {
|
if d2 > d3 {
|
||||||
if d2 < distanceToleranceSquare {
|
if d2 < distanceToleranceSquare {
|
||||||
v.AddPoint(x2, y2)
|
v.LineTo(x2, y2)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if d3 < distanceToleranceSquare {
|
if d3 < distanceToleranceSquare {
|
||||||
v.AddPoint(x3, y3)
|
v.LineTo(x3, y3)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,7 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa
|
||||||
//----------------------
|
//----------------------
|
||||||
if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
||||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
if angleTolerance < CurveAngleToleranceEpsilon {
|
||||||
v.AddPoint(x23, y23)
|
v.LineTo(x23, y23)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,14 +237,14 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa
|
||||||
}
|
}
|
||||||
|
|
||||||
if da1 < angleTolerance {
|
if da1 < angleTolerance {
|
||||||
v.AddPoint(x2, y2)
|
v.LineTo(x2, y2)
|
||||||
v.AddPoint(x3, y3)
|
v.LineTo(x3, y3)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if cuspLimit != 0.0 {
|
if cuspLimit != 0.0 {
|
||||||
if da1 > cuspLimit {
|
if da1 > cuspLimit {
|
||||||
v.AddPoint(x3, y3)
|
v.LineTo(x3, y3)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa
|
||||||
//----------------------
|
//----------------------
|
||||||
if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
||||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
if angleTolerance < CurveAngleToleranceEpsilon {
|
||||||
v.AddPoint(x23, y23)
|
v.LineTo(x23, y23)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,14 +268,14 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa
|
||||||
}
|
}
|
||||||
|
|
||||||
if da1 < angleTolerance {
|
if da1 < angleTolerance {
|
||||||
v.AddPoint(x2, y2)
|
v.LineTo(x2, y2)
|
||||||
v.AddPoint(x3, y3)
|
v.LineTo(x3, y3)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if cuspLimit != 0.0 {
|
if cuspLimit != 0.0 {
|
||||||
if da1 > cuspLimit {
|
if da1 > cuspLimit {
|
||||||
v.AddPoint(x2, y2)
|
v.LineTo(x2, y2)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa
|
||||||
// we tend to finish subdivisions.
|
// we tend to finish subdivisions.
|
||||||
//----------------------
|
//----------------------
|
||||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
if angleTolerance < CurveAngleToleranceEpsilon {
|
||||||
v.AddPoint(x23, y23)
|
v.LineTo(x23, y23)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,18 +309,18 @@ func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 floa
|
||||||
if da1+da2 < angleTolerance {
|
if da1+da2 < angleTolerance {
|
||||||
// Finally we can stop the recursion
|
// Finally we can stop the recursion
|
||||||
//----------------------
|
//----------------------
|
||||||
v.AddPoint(x23, y23)
|
v.LineTo(x23, y23)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if cuspLimit != 0.0 {
|
if cuspLimit != 0.0 {
|
||||||
if da1 > cuspLimit {
|
if da1 > cuspLimit {
|
||||||
v.AddPoint(x2, y2)
|
v.LineTo(x2, y2)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if da2 > cuspLimit {
|
if da2 > cuspLimit {
|
||||||
v.AddPoint(x3, y3)
|
v.LineTo(x3, y3)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
40
dasher.go
40
dasher.go
|
@ -4,15 +4,15 @@
|
||||||
package draw2d
|
package draw2d
|
||||||
|
|
||||||
type DashVertexConverter struct {
|
type DashVertexConverter struct {
|
||||||
command VertexCommand
|
command LineMarker
|
||||||
next VertexConverter
|
next LineBuilder
|
||||||
x, y, distance float64
|
x, y, distance float64
|
||||||
dash []float64
|
dash []float64
|
||||||
currentDash int
|
currentDash int
|
||||||
dashOffset float64
|
dashOffset float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDashConverter(dash []float64, dashOffset float64, converter VertexConverter) *DashVertexConverter {
|
func NewDashConverter(dash []float64, dashOffset float64, converter LineBuilder) *DashVertexConverter {
|
||||||
var dasher DashVertexConverter
|
var dasher DashVertexConverter
|
||||||
dasher.dash = dash
|
dasher.dash = dash
|
||||||
dasher.currentDash = 0
|
dasher.currentDash = 0
|
||||||
|
@ -21,26 +21,20 @@ func NewDashConverter(dash []float64, dashOffset float64, converter VertexConver
|
||||||
return &dasher
|
return &dasher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dasher *DashVertexConverter) NextCommand(cmd VertexCommand) {
|
func (dasher *DashVertexConverter) NextCommand(cmd LineMarker) {
|
||||||
dasher.command = cmd
|
dasher.command = cmd
|
||||||
if dasher.command == VertexStopCommand {
|
if dasher.command == LineEndMarker {
|
||||||
dasher.next.NextCommand(VertexStopCommand)
|
dasher.next.NextCommand(LineEndMarker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dasher *DashVertexConverter) AddPoint(x, y float64) {
|
func (dasher *DashVertexConverter) LineTo(x, y float64) {
|
||||||
switch dasher.command {
|
|
||||||
case VertexStartCommand:
|
|
||||||
dasher.start(x, y)
|
|
||||||
default:
|
|
||||||
dasher.lineTo(x, y)
|
dasher.lineTo(x, y)
|
||||||
}
|
dasher.command = LineNoneMarker
|
||||||
dasher.command = VertexNoCommand
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dasher *DashVertexConverter) start(x, y float64) {
|
func (dasher *DashVertexConverter) MoveTo(x, y float64) {
|
||||||
dasher.next.NextCommand(VertexStartCommand)
|
dasher.next.MoveTo(x, y)
|
||||||
dasher.next.AddPoint(x, y)
|
|
||||||
dasher.x, dasher.y = x, y
|
dasher.x, dasher.y = x, y
|
||||||
dasher.distance = dasher.dashOffset
|
dasher.distance = dasher.dashOffset
|
||||||
dasher.currentDash = 0
|
dasher.currentDash = 0
|
||||||
|
@ -60,12 +54,11 @@ func (dasher *DashVertexConverter) lineTo(x, y float64) {
|
||||||
ly := dasher.y + k*(y-dasher.y)
|
ly := dasher.y + k*(y-dasher.y)
|
||||||
if dasher.currentDash%2 == 0 {
|
if dasher.currentDash%2 == 0 {
|
||||||
// line
|
// line
|
||||||
dasher.next.AddPoint(lx, ly)
|
dasher.next.LineTo(lx, ly)
|
||||||
} else {
|
} else {
|
||||||
// gap
|
// gap
|
||||||
dasher.next.NextCommand(VertexStopCommand)
|
dasher.next.NextCommand(LineEndMarker)
|
||||||
dasher.next.NextCommand(VertexStartCommand)
|
dasher.next.MoveTo(lx, ly)
|
||||||
dasher.next.AddPoint(lx, ly)
|
|
||||||
}
|
}
|
||||||
d = d - rest
|
d = d - rest
|
||||||
dasher.x, dasher.y = lx, ly
|
dasher.x, dasher.y = lx, ly
|
||||||
|
@ -75,12 +68,11 @@ func (dasher *DashVertexConverter) lineTo(x, y float64) {
|
||||||
dasher.distance = d
|
dasher.distance = d
|
||||||
if dasher.currentDash%2 == 0 {
|
if dasher.currentDash%2 == 0 {
|
||||||
// line
|
// line
|
||||||
dasher.next.AddPoint(x, y)
|
dasher.next.LineTo(x, y)
|
||||||
} else {
|
} else {
|
||||||
// gap
|
// gap
|
||||||
dasher.next.NextCommand(VertexStopCommand)
|
dasher.next.NextCommand(LineEndMarker)
|
||||||
dasher.next.NextCommand(VertexStartCommand)
|
dasher.next.MoveTo(x, y)
|
||||||
dasher.next.AddPoint(x, y)
|
|
||||||
}
|
}
|
||||||
if dasher.distance >= dasher.dash[dasher.currentDash] {
|
if dasher.distance >= dasher.dash[dasher.currentDash] {
|
||||||
dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
|
dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
|
||||||
|
|
|
@ -4,20 +4,27 @@
|
||||||
package draw2d
|
package draw2d
|
||||||
|
|
||||||
type DemuxConverter struct {
|
type DemuxConverter struct {
|
||||||
converters []VertexConverter
|
converters []LineBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDemuxConverter(converters ...VertexConverter) *DemuxConverter {
|
func NewDemuxConverter(converters ...LineBuilder) *DemuxConverter {
|
||||||
return &DemuxConverter{converters}
|
return &DemuxConverter{converters}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DemuxConverter) NextCommand(cmd VertexCommand) {
|
func (dc *DemuxConverter) NextCommand(cmd LineMarker) {
|
||||||
for _, converter := range dc.converters {
|
for _, converter := range dc.converters {
|
||||||
converter.NextCommand(cmd)
|
converter.NextCommand(cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (dc *DemuxConverter) AddPoint(x, y float64) {
|
|
||||||
|
func (dc *DemuxConverter) MoveTo(x, y float64) {
|
||||||
for _, converter := range dc.converters {
|
for _, converter := range dc.converters {
|
||||||
converter.AddPoint(x, y)
|
converter.MoveTo(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc *DemuxConverter) LineTo(x, y float64) {
|
||||||
|
for _, converter := range dc.converters {
|
||||||
|
converter.LineTo(x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,26 +8,23 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type VertexAdder struct {
|
type VertexAdder struct {
|
||||||
command VertexCommand
|
|
||||||
adder raster.Adder
|
adder raster.Adder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVertexAdder(adder raster.Adder) *VertexAdder {
|
func NewVertexAdder(adder raster.Adder) *VertexAdder {
|
||||||
return &VertexAdder{VertexNoCommand, adder}
|
return &VertexAdder{adder}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vertexAdder *VertexAdder) NextCommand(cmd VertexCommand) {
|
func (vertexAdder *VertexAdder) NextCommand(cmd LineMarker) {
|
||||||
vertexAdder.command = cmd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vertexAdder *VertexAdder) AddPoint(x, y float64) {
|
func (vertexAdder *VertexAdder) MoveTo(x, y float64) {
|
||||||
switch vertexAdder.command {
|
|
||||||
case VertexStartCommand:
|
|
||||||
vertexAdder.adder.Start(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
vertexAdder.adder.Start(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
||||||
default:
|
|
||||||
vertexAdder.adder.Add1(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
|
||||||
}
|
}
|
||||||
vertexAdder.command = VertexNoCommand
|
|
||||||
|
func (vertexAdder *VertexAdder) LineTo(x, y float64) {
|
||||||
|
vertexAdder.adder.Add1(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
||||||
}
|
}
|
||||||
|
|
||||||
type PathAdder struct {
|
type PathAdder struct {
|
||||||
|
|
|
@ -9,12 +9,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type PathConverter struct {
|
type PathConverter struct {
|
||||||
converter VertexConverter
|
converter LineBuilder
|
||||||
ApproximationScale float64
|
ApproximationScale float64
|
||||||
startX, startY, x, y float64
|
startX, startY, x, y float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPathConverter(converter VertexConverter) *PathConverter {
|
func NewPathConverter(converter LineBuilder) *PathConverter {
|
||||||
return &PathConverter{converter, 1, 0, 0, 0, 0}
|
return &PathConverter{converter, 1, 0, 0, 0, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,47 +26,48 @@ func (c *PathConverter) Convert(paths ...*PathStorage) {
|
||||||
case MoveTo:
|
case MoveTo:
|
||||||
c.x, c.y = path.vertices[i], path.vertices[i+1]
|
c.x, c.y = path.vertices[i], path.vertices[i+1]
|
||||||
c.startX, c.startY = c.x, c.y
|
c.startX, c.startY = c.x, c.y
|
||||||
c.converter.NextCommand(VertexStopCommand)
|
if i != 0 {
|
||||||
c.converter.NextCommand(VertexStartCommand)
|
c.converter.NextCommand(LineEndMarker)
|
||||||
c.converter.AddPoint(c.x, c.y)
|
}
|
||||||
|
c.converter.MoveTo(c.x, c.y)
|
||||||
i += 2
|
i += 2
|
||||||
case LineTo:
|
case LineTo:
|
||||||
c.x, c.y = path.vertices[i], path.vertices[i+1]
|
c.x, c.y = path.vertices[i], path.vertices[i+1]
|
||||||
if c.startX == c.x && c.startY == c.y {
|
if c.startX == c.x && c.startY == c.y {
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
}
|
}
|
||||||
c.converter.AddPoint(c.x, c.y)
|
c.converter.LineTo(c.x, c.y)
|
||||||
c.converter.NextCommand(VertexJoinCommand)
|
c.converter.NextCommand(LineJoinMarker)
|
||||||
i += 2
|
i += 2
|
||||||
case QuadCurveTo:
|
case QuadCurveTo:
|
||||||
curve.TraceQuad(c.converter, path.vertices[i-2:], 0.5)
|
curve.TraceQuad(c.converter, path.vertices[i-2:], 0.5)
|
||||||
c.x, c.y = path.vertices[i+2], path.vertices[i+3]
|
c.x, c.y = path.vertices[i+2], path.vertices[i+3]
|
||||||
if c.startX == c.x && c.startY == c.y {
|
if c.startX == c.x && c.startY == c.y {
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
}
|
}
|
||||||
c.converter.AddPoint(c.x, c.y)
|
c.converter.LineTo(c.x, c.y)
|
||||||
i += 4
|
i += 4
|
||||||
case CubicCurveTo:
|
case CubicCurveTo:
|
||||||
curve.TraceCubic(c.converter, path.vertices[i-2:], 0.5)
|
curve.TraceCubic(c.converter, path.vertices[i-2:], 0.5)
|
||||||
c.x, c.y = path.vertices[i+4], path.vertices[i+5]
|
c.x, c.y = path.vertices[i+4], path.vertices[i+5]
|
||||||
if c.startX == c.x && c.startY == c.y {
|
if c.startX == c.x && c.startY == c.y {
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
}
|
}
|
||||||
c.converter.AddPoint(c.x, c.y)
|
c.converter.LineTo(c.x, c.y)
|
||||||
i += 6
|
i += 6
|
||||||
case ArcTo:
|
case ArcTo:
|
||||||
c.x, c.y = arc(c.converter, path.vertices[i], path.vertices[i+1], path.vertices[i+2], path.vertices[i+3], path.vertices[i+4], path.vertices[i+5], c.ApproximationScale)
|
c.x, c.y = arc(c.converter, path.vertices[i], path.vertices[i+1], path.vertices[i+2], path.vertices[i+3], path.vertices[i+4], path.vertices[i+5], c.ApproximationScale)
|
||||||
if c.startX == c.x && c.startY == c.y {
|
if c.startX == c.x && c.startY == c.y {
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
}
|
}
|
||||||
c.converter.AddPoint(c.x, c.y)
|
c.converter.LineTo(c.x, c.y)
|
||||||
i += 6
|
i += 6
|
||||||
case Close:
|
case Close:
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
c.converter.AddPoint(c.startX, c.startY)
|
c.converter.LineTo(c.startX, c.startY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.converter.NextCommand(VertexStopCommand)
|
c.converter.NextCommand(LineEndMarker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,9 +78,8 @@ func (c *PathConverter) convertCommand(cmd PathCmd, vertices ...float64) int {
|
||||||
func (c *PathConverter) MoveTo(x, y float64) *PathConverter {
|
func (c *PathConverter) MoveTo(x, y float64) *PathConverter {
|
||||||
c.x, c.y = x, y
|
c.x, c.y = x, y
|
||||||
c.startX, c.startY = c.x, c.y
|
c.startX, c.startY = c.x, c.y
|
||||||
c.converter.NextCommand(VertexStopCommand)
|
c.converter.NextCommand(LineEndMarker)
|
||||||
c.converter.NextCommand(VertexStartCommand)
|
c.converter.MoveTo(c.x, c.y)
|
||||||
c.converter.AddPoint(c.x, c.y)
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +91,10 @@ func (c *PathConverter) RMoveTo(dx, dy float64) *PathConverter {
|
||||||
func (c *PathConverter) LineTo(x, y float64) *PathConverter {
|
func (c *PathConverter) LineTo(x, y float64) *PathConverter {
|
||||||
c.x, c.y = x, y
|
c.x, c.y = x, y
|
||||||
if c.startX == c.x && c.startY == c.y {
|
if c.startX == c.x && c.startY == c.y {
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
}
|
}
|
||||||
c.converter.AddPoint(c.x, c.y)
|
c.converter.LineTo(c.x, c.y)
|
||||||
c.converter.NextCommand(VertexJoinCommand)
|
c.converter.NextCommand(LineJoinMarker)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,9 +107,9 @@ func (c *PathConverter) QuadCurveTo(cx, cy, x, y float64) *PathConverter {
|
||||||
curve.TraceQuad(c.converter, []float64{c.x, c.y, cx, cy, x, y}, 0.5)
|
curve.TraceQuad(c.converter, []float64{c.x, c.y, cx, cy, x, y}, 0.5)
|
||||||
c.x, c.y = x, y
|
c.x, c.y = x, y
|
||||||
if c.startX == c.x && c.startY == c.y {
|
if c.startX == c.x && c.startY == c.y {
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
}
|
}
|
||||||
c.converter.AddPoint(c.x, c.y)
|
c.converter.LineTo(c.x, c.y)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,9 +122,9 @@ func (c *PathConverter) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) *PathConv
|
||||||
curve.TraceCubic(c.converter, []float64{c.x, c.y, cx1, cy1, cx2, cy2, x, y}, 0.5)
|
curve.TraceCubic(c.converter, []float64{c.x, c.y, cx1, cy1, cx2, cy2, x, y}, 0.5)
|
||||||
c.x, c.y = x, y
|
c.x, c.y = x, y
|
||||||
if c.startX == c.x && c.startY == c.y {
|
if c.startX == c.x && c.startY == c.y {
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
}
|
}
|
||||||
c.converter.AddPoint(c.x, c.y)
|
c.converter.LineTo(c.x, c.y)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,9 +154,9 @@ func (c *PathConverter) ArcTo(cx, cy, rx, ry, startAngle, angle float64) *PathCo
|
||||||
c.MoveTo(startX, startY)
|
c.MoveTo(startX, startY)
|
||||||
c.x, c.y = arc(c.converter, cx, cy, rx, ry, startAngle, angle, c.ApproximationScale)
|
c.x, c.y = arc(c.converter, cx, cy, rx, ry, startAngle, angle, c.ApproximationScale)
|
||||||
if c.startX == c.x && c.startY == c.y {
|
if c.startX == c.x && c.startY == c.y {
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
}
|
}
|
||||||
c.converter.AddPoint(c.x, c.y)
|
c.converter.LineTo(c.x, c.y)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ func (c *PathConverter) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) *Pat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PathConverter) Close() *PathConverter {
|
func (c *PathConverter) Close() *PathConverter {
|
||||||
c.converter.NextCommand(VertexCloseCommand)
|
c.converter.NextCommand(LineCloseMarker)
|
||||||
c.converter.AddPoint(c.startX, c.startY)
|
c.converter.LineTo(c.startX, c.startY)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,74 +60,65 @@ func (p *PathStorage) IsEmpty() bool {
|
||||||
return len(p.commands) == 0
|
return len(p.commands) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) Close() *PathStorage {
|
func (p *PathStorage) Close() {
|
||||||
p.appendToPath(Close)
|
p.appendToPath(Close)
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) MoveTo(x, y float64) *PathStorage {
|
func (p *PathStorage) MoveTo(x, y float64) {
|
||||||
p.appendToPath(MoveTo, x, y)
|
p.appendToPath(MoveTo, x, y)
|
||||||
|
|
||||||
p.x = x
|
p.x = x
|
||||||
p.y = y
|
p.y = y
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) RMoveTo(dx, dy float64) *PathStorage {
|
func (p *PathStorage) RMoveTo(dx, dy float64) {
|
||||||
x, y := p.LastPoint()
|
x, y := p.LastPoint()
|
||||||
p.MoveTo(x+dx, y+dy)
|
p.MoveTo(x+dx, y+dy)
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) LineTo(x, y float64) *PathStorage {
|
func (p *PathStorage) LineTo(x, y float64) {
|
||||||
if len(p.commands) == 0 { //special case when no move has been done
|
if len(p.commands) == 0 { //special case when no move has been done
|
||||||
p.MoveTo(0, 0)
|
p.MoveTo(0, 0)
|
||||||
}
|
}
|
||||||
p.appendToPath(LineTo, x, y)
|
p.appendToPath(LineTo, x, y)
|
||||||
p.x = x
|
p.x = x
|
||||||
p.y = y
|
p.y = y
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) RLineTo(dx, dy float64) *PathStorage {
|
func (p *PathStorage) RLineTo(dx, dy float64) {
|
||||||
x, y := p.LastPoint()
|
x, y := p.LastPoint()
|
||||||
p.LineTo(x+dx, y+dy)
|
p.LineTo(x+dx, y+dy)
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) QuadCurveTo(cx, cy, x, y float64) *PathStorage {
|
func (p *PathStorage) QuadCurveTo(cx, cy, x, y float64) {
|
||||||
if len(p.commands) == 0 { //special case when no move has been done
|
if len(p.commands) == 0 { //special case when no move has been done
|
||||||
p.MoveTo(0, 0)
|
p.MoveTo(0, 0)
|
||||||
}
|
}
|
||||||
p.appendToPath(QuadCurveTo, cx, cy, x, y)
|
p.appendToPath(QuadCurveTo, cx, cy, x, y)
|
||||||
p.x = x
|
p.x = x
|
||||||
p.y = y
|
p.y = y
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) RQuadCurveTo(dcx, dcy, dx, dy float64) *PathStorage {
|
func (p *PathStorage) RQuadCurveTo(dcx, dcy, dx, dy float64) {
|
||||||
x, y := p.LastPoint()
|
x, y := p.LastPoint()
|
||||||
p.QuadCurveTo(x+dcx, y+dcy, x+dx, y+dy)
|
p.QuadCurveTo(x+dcx, y+dcy, x+dx, y+dy)
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) *PathStorage {
|
func (p *PathStorage) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) {
|
||||||
if len(p.commands) == 0 { //special case when no move has been done
|
if len(p.commands) == 0 { //special case when no move has been done
|
||||||
p.MoveTo(0, 0)
|
p.MoveTo(0, 0)
|
||||||
}
|
}
|
||||||
p.appendToPath(CubicCurveTo, cx1, cy1, cx2, cy2, x, y)
|
p.appendToPath(CubicCurveTo, cx1, cy1, cx2, cy2, x, y)
|
||||||
p.x = x
|
p.x = x
|
||||||
p.y = y
|
p.y = y
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) *PathStorage {
|
func (p *PathStorage) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) {
|
||||||
x, y := p.LastPoint()
|
x, y := p.LastPoint()
|
||||||
p.CubicCurveTo(x+dcx1, y+dcy1, x+dcx2, y+dcy2, x+dx, y+dy)
|
p.CubicCurveTo(x+dcx1, y+dcy1, x+dcx2, y+dcy2, x+dx, y+dy)
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) ArcTo(cx, cy, rx, ry, startAngle, angle float64) *PathStorage {
|
func (p *PathStorage) ArcTo(cx, cy, rx, ry, startAngle, angle float64) {
|
||||||
endAngle := startAngle + angle
|
endAngle := startAngle + angle
|
||||||
clockWise := true
|
clockWise := true
|
||||||
if angle < 0 {
|
if angle < 0 {
|
||||||
|
@ -153,13 +144,11 @@ func (p *PathStorage) ArcTo(cx, cy, rx, ry, startAngle, angle float64) *PathStor
|
||||||
p.appendToPath(ArcTo, cx, cy, rx, ry, startAngle, angle)
|
p.appendToPath(ArcTo, cx, cy, rx, ry, startAngle, angle)
|
||||||
p.x = cx + math.Cos(endAngle)*rx
|
p.x = cx + math.Cos(endAngle)*rx
|
||||||
p.y = cy + math.Sin(endAngle)*ry
|
p.y = cy + math.Sin(endAngle)*ry
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) *PathStorage {
|
func (p *PathStorage) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) {
|
||||||
x, y := p.LastPoint()
|
x, y := p.LastPoint()
|
||||||
p.ArcTo(x+dcx, y+dcy, rx, ry, startAngle, angle)
|
p.ArcTo(x+dcx, y+dcy, rx, ry, startAngle, angle)
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathStorage) String() string {
|
func (p *PathStorage) String() string {
|
||||||
|
|
52
stroker.go
52
stroker.go
|
@ -20,17 +20,17 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type LineStroker struct {
|
type LineStroker struct {
|
||||||
Next VertexConverter
|
Next LineBuilder
|
||||||
HalfLineWidth float64
|
HalfLineWidth float64
|
||||||
Cap Cap
|
Cap Cap
|
||||||
Join Join
|
Join Join
|
||||||
vertices []float64
|
vertices []float64
|
||||||
rewind []float64
|
rewind []float64
|
||||||
x, y, nx, ny float64
|
x, y, nx, ny float64
|
||||||
command VertexCommand
|
command LineMarker
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLineStroker(c Cap, j Join, converter VertexConverter) *LineStroker {
|
func NewLineStroker(c Cap, j Join, converter LineBuilder) *LineStroker {
|
||||||
l := new(LineStroker)
|
l := new(LineStroker)
|
||||||
l.Next = converter
|
l.Next = converter
|
||||||
l.HalfLineWidth = 0.5
|
l.HalfLineWidth = 0.5
|
||||||
|
@ -38,27 +38,29 @@ func NewLineStroker(c Cap, j Join, converter VertexConverter) *LineStroker {
|
||||||
l.rewind = make([]float64, 0, 256)
|
l.rewind = make([]float64, 0, 256)
|
||||||
l.Cap = c
|
l.Cap = c
|
||||||
l.Join = j
|
l.Join = j
|
||||||
l.command = VertexNoCommand
|
l.command = LineNoneMarker
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LineStroker) NextCommand(command VertexCommand) {
|
func (l *LineStroker) NextCommand(command LineMarker) {
|
||||||
l.command = command
|
l.command = command
|
||||||
if command == VertexStopCommand {
|
if command == LineEndMarker {
|
||||||
l.Next.NextCommand(VertexStartCommand)
|
if len(l.vertices) > 1 {
|
||||||
for i, j := 0, 1; j < len(l.vertices); i, j = i+2, j+2 {
|
l.Next.MoveTo(l.vertices[0], l.vertices[1])
|
||||||
l.Next.AddPoint(l.vertices[i], l.vertices[j])
|
for i, j := 2, 3; j < len(l.vertices); i, j = i+2, j+2 {
|
||||||
l.Next.NextCommand(VertexNoCommand)
|
l.Next.LineTo(l.vertices[i], l.vertices[j])
|
||||||
|
l.Next.NextCommand(LineNoneMarker)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for i, j := len(l.rewind)-2, len(l.rewind)-1; j > 0; i, j = i-2, j-2 {
|
for i, j := len(l.rewind)-2, len(l.rewind)-1; j > 0; i, j = i-2, j-2 {
|
||||||
l.Next.NextCommand(VertexNoCommand)
|
l.Next.NextCommand(LineNoneMarker)
|
||||||
l.Next.AddPoint(l.rewind[i], l.rewind[j])
|
l.Next.LineTo(l.rewind[i], l.rewind[j])
|
||||||
}
|
}
|
||||||
if len(l.vertices) > 1 {
|
if len(l.vertices) > 1 {
|
||||||
l.Next.NextCommand(VertexNoCommand)
|
l.Next.NextCommand(LineNoneMarker)
|
||||||
l.Next.AddPoint(l.vertices[0], l.vertices[1])
|
l.Next.LineTo(l.vertices[0], l.vertices[1])
|
||||||
}
|
}
|
||||||
l.Next.NextCommand(VertexStopCommand)
|
l.Next.NextCommand(LineEndMarker)
|
||||||
// reinit vertices
|
// reinit vertices
|
||||||
l.vertices = l.vertices[0:0]
|
l.vertices = l.vertices[0:0]
|
||||||
l.rewind = l.rewind[0:0]
|
l.rewind = l.rewind[0:0]
|
||||||
|
@ -66,20 +68,22 @@ func (l *LineStroker) NextCommand(command VertexCommand) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LineStroker) AddPoint(x, y float64) {
|
func (l *LineStroker) MoveTo(x, y float64) {
|
||||||
switch l.command {
|
|
||||||
case VertexNoCommand:
|
|
||||||
l.line(l.x, l.y, x, y)
|
|
||||||
case VertexJoinCommand:
|
|
||||||
l.joinLine(l.x, l.y, l.nx, l.ny, x, y)
|
|
||||||
case VertexStartCommand:
|
|
||||||
l.x, l.y = x, y
|
l.x, l.y = x, y
|
||||||
case VertexCloseCommand:
|
}
|
||||||
|
|
||||||
|
func (l *LineStroker) LineTo(x, y float64) {
|
||||||
|
switch l.command {
|
||||||
|
case LineJoinMarker:
|
||||||
|
l.joinLine(l.x, l.y, l.nx, l.ny, x, y)
|
||||||
|
case LineCloseMarker:
|
||||||
l.line(l.x, l.y, x, y)
|
l.line(l.x, l.y, x, y)
|
||||||
l.joinLine(l.x, l.y, l.nx, l.ny, x, y)
|
l.joinLine(l.x, l.y, l.nx, l.ny, x, y)
|
||||||
l.closePolygon()
|
l.closePolygon()
|
||||||
|
default:
|
||||||
|
l.line(l.x, l.y, x, y)
|
||||||
}
|
}
|
||||||
l.command = VertexNoCommand
|
l.command = LineNoneMarker
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LineStroker) appendVertex(vertices ...float64) {
|
func (l *LineStroker) appendVertex(vertices ...float64) {
|
||||||
|
|
16
transform.go
16
transform.go
|
@ -254,22 +254,28 @@ func fequals(float1, float2 float64) bool {
|
||||||
// this VertexConverter apply the Matrix transformation tr
|
// this VertexConverter apply the Matrix transformation tr
|
||||||
type VertexMatrixTransform struct {
|
type VertexMatrixTransform struct {
|
||||||
tr MatrixTransform
|
tr MatrixTransform
|
||||||
Next VertexConverter
|
Next LineBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVertexMatrixTransform(tr MatrixTransform, converter VertexConverter) *VertexMatrixTransform {
|
func NewVertexMatrixTransform(tr MatrixTransform, converter LineBuilder) *VertexMatrixTransform {
|
||||||
return &VertexMatrixTransform{tr, converter}
|
return &VertexMatrixTransform{tr, converter}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertex Matrix Transform
|
// Vertex Matrix Transform
|
||||||
func (vmt *VertexMatrixTransform) NextCommand(command VertexCommand) {
|
func (vmt *VertexMatrixTransform) NextCommand(command LineMarker) {
|
||||||
vmt.Next.NextCommand(command)
|
vmt.Next.NextCommand(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vmt *VertexMatrixTransform) AddPoint(x, y float64) {
|
func (vmt *VertexMatrixTransform) MoveTo(x, y float64) {
|
||||||
u := x*vmt.tr[0] + y*vmt.tr[2] + vmt.tr[4]
|
u := x*vmt.tr[0] + y*vmt.tr[2] + vmt.tr[4]
|
||||||
v := x*vmt.tr[1] + y*vmt.tr[3] + vmt.tr[5]
|
v := x*vmt.tr[1] + y*vmt.tr[3] + vmt.tr[5]
|
||||||
vmt.Next.AddPoint(u, v)
|
vmt.Next.MoveTo(u, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vmt *VertexMatrixTransform) LineTo(x, y float64) {
|
||||||
|
u := x*vmt.tr[0] + y*vmt.tr[2] + vmt.tr[4]
|
||||||
|
v := x*vmt.tr[1] + y*vmt.tr[3] + vmt.tr[5]
|
||||||
|
vmt.Next.LineTo(u, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// this adder apply a Matrix transformation to points
|
// this adder apply a Matrix transformation to points
|
||||||
|
|
22
vertex2d.go
22
vertex2d.go
|
@ -3,17 +3,21 @@
|
||||||
|
|
||||||
package draw2d
|
package draw2d
|
||||||
|
|
||||||
type VertexCommand byte
|
type LineMarker byte
|
||||||
|
|
||||||
const (
|
const (
|
||||||
VertexNoCommand VertexCommand = iota
|
LineNoneMarker LineMarker = iota
|
||||||
VertexStartCommand
|
// Mark the current point of the line as a join to it can draw some specific join Bevel, Miter, Rount
|
||||||
VertexJoinCommand
|
LineJoinMarker
|
||||||
VertexCloseCommand
|
// Mark the current point of the line as closed so it draw a line from the current
|
||||||
VertexStopCommand
|
// position to the point specified by the last start marker.
|
||||||
|
LineCloseMarker
|
||||||
|
// Mark the current point of the line as finished. This ending maker allow caps to be drawn
|
||||||
|
LineEndMarker
|
||||||
)
|
)
|
||||||
|
|
||||||
type VertexConverter interface {
|
type LineBuilder interface {
|
||||||
NextCommand(cmd VertexCommand)
|
NextCommand(cmd LineMarker)
|
||||||
AddPoint(x, y float64)
|
MoveTo(x, y float64)
|
||||||
|
LineTo(x, y float64)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue