Add arc segmentation

This commit is contained in:
Laurent Le Goff 2011-05-19 23:54:22 +02:00
parent 4dd2a24c2d
commit f4a9d29b42
5 changed files with 49 additions and 12 deletions

37
draw2d/curve/arc.go Normal file
View 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)
}

View file

@ -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

View file

@ -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.

View file

@ -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)
} }
} }

View file

@ -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