Add arc segmentation
This commit is contained in:
parent
4dd2a24c2d
commit
f4a9d29b42
5 changed files with 49 additions and 12 deletions
37
draw2d/curve/arc.go
Normal file
37
draw2d/curve/arc.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
|
// created: 21/11/2010 by Laurent Le Goff
|
||||||
|
package draw2d
|
||||||
|
|
||||||
|
import (
|
||||||
|
"freetype-go.googlecode.com/hg/freetype/raster"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SegmentArc(t LineTracer, x, y, rx, ry, start, angle, scale float64) {
|
||||||
|
end := start + angle
|
||||||
|
clockWise := true
|
||||||
|
if angle < 0 {
|
||||||
|
clockWise = false
|
||||||
|
}
|
||||||
|
ra := (math.Fabs(rx) + math.Fabs(ry)) / 2
|
||||||
|
da := math.Acos(ra/(ra+0.125/scale)) * 2
|
||||||
|
//normalize
|
||||||
|
if !clockWise {
|
||||||
|
da = -da
|
||||||
|
}
|
||||||
|
angle = start + da
|
||||||
|
var curX, curY float64
|
||||||
|
for {
|
||||||
|
if (angle < end-da/4) != clockWise {
|
||||||
|
curX = x + math.Cos(end)*rx
|
||||||
|
curY = y + math.Sin(end)*ry
|
||||||
|
return curX, curY
|
||||||
|
}
|
||||||
|
curX = x + math.Cos(angle)*rx
|
||||||
|
curY = y + math.Sin(angle)*ry
|
||||||
|
|
||||||
|
angle += da
|
||||||
|
t.LineTo(curX, curY)
|
||||||
|
}
|
||||||
|
t.LineTo(curX, curY)
|
||||||
|
}
|
|
@ -40,9 +40,6 @@ func (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) (x23, y23 float
|
||||||
}
|
}
|
||||||
|
|
||||||
func (curve *CubicCurveFloat64) Segment(t LineTracer, flattening_threshold float64) {
|
func (curve *CubicCurveFloat64) Segment(t LineTracer, flattening_threshold float64) {
|
||||||
// Add the first point
|
|
||||||
t.LineTo(curve.X1, curve.Y1)
|
|
||||||
|
|
||||||
var curves [CurveRecursionLimit]CubicCurveFloat64
|
var curves [CurveRecursionLimit]CubicCurveFloat64
|
||||||
curves[0] = *curve
|
curves[0] = *curve
|
||||||
i := 0
|
i := 0
|
||||||
|
|
|
@ -63,8 +63,6 @@ func (c *CubicCurveFloat64) EstimateDistance() float64 {
|
||||||
|
|
||||||
// subdivide the curve in straight lines using line approximation and Casteljau recursive subdivision
|
// subdivide the curve in straight lines using line approximation and Casteljau recursive subdivision
|
||||||
func (c *CubicCurveFloat64) SegmentRec(t LineTracer, flattening_threshold float64) {
|
func (c *CubicCurveFloat64) SegmentRec(t LineTracer, flattening_threshold float64) {
|
||||||
// reinit segments
|
|
||||||
t.LineTo(c.X1, c.Y1)
|
|
||||||
c.segmentRec(t, flattening_threshold)
|
c.segmentRec(t, flattening_threshold)
|
||||||
t.LineTo(c.X4, c.Y4)
|
t.LineTo(c.X4, c.Y4)
|
||||||
}
|
}
|
||||||
|
@ -115,7 +113,6 @@ func (c *CubicCurveFloat64) AdaptiveSegmentRec(t LineTracer, approximationScale,
|
||||||
cuspLimit = computeCuspLimit(cuspLimit)
|
cuspLimit = computeCuspLimit(cuspLimit)
|
||||||
distanceToleranceSquare := 0.5 / approximationScale
|
distanceToleranceSquare := 0.5 / approximationScale
|
||||||
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
||||||
t.LineTo(c.X1, c.Y1)
|
|
||||||
c.adaptiveSegmentRec(t, 0, distanceToleranceSquare, angleTolerance, cuspLimit)
|
c.adaptiveSegmentRec(t, 0, distanceToleranceSquare, angleTolerance, cuspLimit)
|
||||||
t.LineTo(c.X4, c.Y4)
|
t.LineTo(c.X4, c.Y4)
|
||||||
}
|
}
|
||||||
|
@ -314,8 +311,6 @@ func (c *CubicCurveFloat64) adaptiveSegmentRec(t LineTracer, level int, distance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) {
|
func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale, angleTolerance, cuspLimit float64) {
|
||||||
// Add the first point
|
|
||||||
t.LineTo(curve.X1, curve.Y1)
|
|
||||||
cuspLimit = computeCuspLimit(cuspLimit)
|
cuspLimit = computeCuspLimit(cuspLimit)
|
||||||
distanceToleranceSquare := 0.5 / approximationScale
|
distanceToleranceSquare := 0.5 / approximationScale
|
||||||
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
||||||
|
@ -529,7 +524,6 @@ func (curve *CubicCurveFloat64) AdaptiveSegment(t LineTracer, approximationScale
|
||||||
|
|
||||||
|
|
||||||
func (c *CubicCurveFloat64) ParabolicSegment(t LineTracer, flattening_threshold float64) {
|
func (c *CubicCurveFloat64) ParabolicSegment(t LineTracer, flattening_threshold float64) {
|
||||||
t.LineTo(c.X1, c.Y1)
|
|
||||||
estimatedIFP := c.numberOfInflectionPoints()
|
estimatedIFP := c.numberOfInflectionPoints()
|
||||||
if estimatedIFP == 0 {
|
if estimatedIFP == 0 {
|
||||||
// If no inflection points then apply PA on the full Bezier segment.
|
// If no inflection points then apply PA on the full Bezier segment.
|
||||||
|
|
|
@ -108,6 +108,7 @@ func drawPoints(img draw.Image, c image.Color, s ...float64) image.Image {
|
||||||
func TestCubicCurveRec(t *testing.T) {
|
func TestCubicCurveRec(t *testing.T) {
|
||||||
for i, curve := range testsCubicFloat64 {
|
for i, curve := range testsCubicFloat64 {
|
||||||
var p Path
|
var p Path
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.SegmentRec(&p, flattening_threshold)
|
curve.SegmentRec(&p, flattening_threshold)
|
||||||
img := image.NewNRGBA(300, 300)
|
img := image.NewNRGBA(300, 300)
|
||||||
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
||||||
|
@ -123,6 +124,7 @@ func TestCubicCurveRec(t *testing.T) {
|
||||||
func TestCubicCurve(t *testing.T) {
|
func TestCubicCurve(t *testing.T) {
|
||||||
for i, curve := range testsCubicFloat64 {
|
for i, curve := range testsCubicFloat64 {
|
||||||
var p Path
|
var p Path
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.Segment(&p, flattening_threshold)
|
curve.Segment(&p, flattening_threshold)
|
||||||
img := image.NewNRGBA(300, 300)
|
img := image.NewNRGBA(300, 300)
|
||||||
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
||||||
|
@ -138,6 +140,7 @@ func TestCubicCurve(t *testing.T) {
|
||||||
func TestCubicCurveAdaptiveRec(t *testing.T) {
|
func TestCubicCurveAdaptiveRec(t *testing.T) {
|
||||||
for i, curve := range testsCubicFloat64 {
|
for i, curve := range testsCubicFloat64 {
|
||||||
var p Path
|
var p Path
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.AdaptiveSegmentRec(&p, 1, 0, 0)
|
curve.AdaptiveSegmentRec(&p, 1, 0, 0)
|
||||||
img := image.NewNRGBA(300, 300)
|
img := image.NewNRGBA(300, 300)
|
||||||
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
||||||
|
@ -153,6 +156,7 @@ func TestCubicCurveAdaptiveRec(t *testing.T) {
|
||||||
func TestCubicCurveAdaptive(t *testing.T) {
|
func TestCubicCurveAdaptive(t *testing.T) {
|
||||||
for i, curve := range testsCubicFloat64 {
|
for i, curve := range testsCubicFloat64 {
|
||||||
var p Path
|
var p Path
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.AdaptiveSegment(&p, 1, 0, 0)
|
curve.AdaptiveSegment(&p, 1, 0, 0)
|
||||||
img := image.NewNRGBA(300, 300)
|
img := image.NewNRGBA(300, 300)
|
||||||
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
||||||
|
@ -168,6 +172,7 @@ func TestCubicCurveAdaptive(t *testing.T) {
|
||||||
func TestCubicCurveParabolic(t *testing.T) {
|
func TestCubicCurveParabolic(t *testing.T) {
|
||||||
for i, curve := range testsCubicFloat64 {
|
for i, curve := range testsCubicFloat64 {
|
||||||
var p Path
|
var p Path
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.ParabolicSegment(&p, flattening_threshold)
|
curve.ParabolicSegment(&p, flattening_threshold)
|
||||||
img := image.NewNRGBA(300, 300)
|
img := image.NewNRGBA(300, 300)
|
||||||
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
||||||
|
@ -184,6 +189,7 @@ func TestCubicCurveParabolic(t *testing.T) {
|
||||||
func TestQuadCurve(t *testing.T) {
|
func TestQuadCurve(t *testing.T) {
|
||||||
for i, curve := range testsQuadFloat64 {
|
for i, curve := range testsQuadFloat64 {
|
||||||
var p Path
|
var p Path
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.Segment(&p, flattening_threshold)
|
curve.Segment(&p, flattening_threshold)
|
||||||
img := image.NewNRGBA(300, 300)
|
img := image.NewNRGBA(300, 300)
|
||||||
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3)
|
raster.PolylineBresenham(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3)
|
||||||
|
@ -199,6 +205,7 @@ func BenchmarkCubicCurveRec(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for _, curve := range testsCubicFloat64 {
|
for _, curve := range testsCubicFloat64 {
|
||||||
p := Path{make([]float64, 0, 32)}
|
p := Path{make([]float64, 0, 32)}
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.SegmentRec(&p, flattening_threshold)
|
curve.SegmentRec(&p, flattening_threshold)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,6 +215,7 @@ func BenchmarkCubicCurve(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for _, curve := range testsCubicFloat64 {
|
for _, curve := range testsCubicFloat64 {
|
||||||
p := Path{make([]float64, 0, 32)}
|
p := Path{make([]float64, 0, 32)}
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.Segment(&p, flattening_threshold)
|
curve.Segment(&p, flattening_threshold)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,6 +225,7 @@ func BenchmarkCubicCurveAdaptiveRec(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for _, curve := range testsCubicFloat64 {
|
for _, curve := range testsCubicFloat64 {
|
||||||
p := Path{make([]float64, 0, 32)}
|
p := Path{make([]float64, 0, 32)}
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.AdaptiveSegmentRec(&p, 1, 0, 0)
|
curve.AdaptiveSegmentRec(&p, 1, 0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,6 +235,7 @@ func BenchmarkCubicCurveAdaptive(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for _, curve := range testsCubicFloat64 {
|
for _, curve := range testsCubicFloat64 {
|
||||||
p := Path{make([]float64, 0, 32)}
|
p := Path{make([]float64, 0, 32)}
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.AdaptiveSegment(&p, 1, 0, 0)
|
curve.AdaptiveSegment(&p, 1, 0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,6 +245,7 @@ func BenchmarkCubicCurveParabolic(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for _, curve := range testsCubicFloat64 {
|
for _, curve := range testsCubicFloat64 {
|
||||||
p := Path{make([]float64, 0, 32)}
|
p := Path{make([]float64, 0, 32)}
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.ParabolicSegment(&p, flattening_threshold)
|
curve.ParabolicSegment(&p, flattening_threshold)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,6 +255,7 @@ func BenchmarkQuadCurve(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
for _, curve := range testsQuadFloat64 {
|
for _, curve := range testsQuadFloat64 {
|
||||||
p := Path{make([]float64, 0, 32)}
|
p := Path{make([]float64, 0, 32)}
|
||||||
|
p.LineTo(curve.X1, Y1)
|
||||||
curve.Segment(&p, flattening_threshold)
|
curve.Segment(&p, flattening_threshold)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,6 @@ func (c *QuadCurveFloat64) Subdivide(c1, c2 *QuadCurveFloat64) {
|
||||||
|
|
||||||
|
|
||||||
func (curve *QuadCurveFloat64) Segment(t LineTracer, flattening_threshold float64) {
|
func (curve *QuadCurveFloat64) Segment(t LineTracer, flattening_threshold float64) {
|
||||||
// Add the first point
|
|
||||||
t.LineTo(curve.X1, curve.Y1)
|
|
||||||
|
|
||||||
var curves [CurveRecursionLimit]QuadCurveFloat64
|
var curves [CurveRecursionLimit]QuadCurveFloat64
|
||||||
curves[0] = *curve
|
curves[0] = *curve
|
||||||
i := 0
|
i := 0
|
||||||
|
|
Loading…
Reference in a new issue