Add simple line rasteriser
This commit is contained in:
parent
9606b186e0
commit
713b1fa1f6
5 changed files with 235 additions and 140 deletions
|
@ -15,7 +15,7 @@ core
|
||||||
_obj
|
_obj
|
||||||
_test
|
_test
|
||||||
out.png
|
out.png
|
||||||
_testmain.go
|
_test*
|
||||||
|
|
||||||
syntax: regexp
|
syntax: regexp
|
||||||
\.dll$
|
\.dll$
|
||||||
|
|
|
@ -11,11 +11,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type CubicCurveFloat64 struct {
|
type CubicCurveFloat64 struct {
|
||||||
x1, y1, x2, y2, x3, y3, x4, y4 float64
|
X1, Y1, X2, Y2, X3, Y3, X4, Y4 float64
|
||||||
}
|
|
||||||
|
|
||||||
func NewCubicCurveFloat64(x1, y1, x2, y2, x3, y3, x4, y4 float64) *CubicCurveFloat64 {
|
|
||||||
return &CubicCurveFloat64{x1, y1, x2, y2, x3, y3, x4, y4}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//mu ranges from 0 to 1, start to end of curve
|
//mu ranges from 0 to 1, start to end of curve
|
||||||
|
@ -25,107 +21,112 @@ func (c *CubicCurveFloat64) ArbitraryPoint(mu float64) (x, y float64) {
|
||||||
mum13 := mum1 * mum1 * mum1
|
mum13 := mum1 * mum1 * mum1
|
||||||
mu3 := mu * mu * mu
|
mu3 := mu * mu * mu
|
||||||
|
|
||||||
x = mum13*c.x1 + 3*mu*mum1*mum1*c.x2 + 3*mu*mu*mum1*c.x3 + mu3*c.x4
|
x = mum13*c.X1 + 3*mu*mum1*mum1*c.X2 + 3*mu*mu*mum1*c.X3 + mu3*c.X4
|
||||||
y = mum13*c.y1 + 3*mu*mum1*mum1*c.y2 + 3*mu*mu*mum1*c.y3 + mu3*c.y4
|
y = mum13*c.Y1 + 3*mu*mum1*mum1*c.Y2 + 3*mu*mu*mum1*c.Y3 + mu3*c.Y4
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CubicCurveFloat64) SubdivideAt(c1, c2 *CubicCurveFloat64, t float64) {
|
func (c *CubicCurveFloat64) SubdivideAt(c1, c2 *CubicCurveFloat64, t float64) {
|
||||||
inv_t := (1 - t)
|
inv_t := (1 - t)
|
||||||
c1.x1, c1.y1 = c.x1, c.y1
|
c1.X1, c1.Y1 = c.X1, c.Y1
|
||||||
c2.x4, c2.y4 = c.x4, c.y4
|
c2.X4, c2.Y4 = c.X4, c.Y4
|
||||||
|
|
||||||
c1.x2 = inv_t * c.x1 + t * c.x2
|
c1.X2 = inv_t * c.X1 + t * c.X2
|
||||||
c1.y2 = inv_t * c.y1 + t * c.y2
|
c1.Y2 = inv_t * c.Y1 + t * c.Y2
|
||||||
|
|
||||||
x23 := inv_t * c.x2 + t * c.x3
|
x23 := inv_t * c.X2 + t * c.X3
|
||||||
y23 := inv_t * c.y2 + t * c.y3
|
y23 := inv_t * c.Y2 + t * c.Y3
|
||||||
|
|
||||||
c2.x3 = inv_t * c.x3 + t * c.x4
|
c2.X3 = inv_t * c.X3 + t * c.X4
|
||||||
c2.y3 = inv_t * c.y3 + t * c.y4
|
c2.Y3 = inv_t * c.Y3 + t * c.Y4
|
||||||
|
|
||||||
c1.x3 = inv_t * c1.x2 + t * x23
|
c1.X3 = inv_t * c1.X2 + t * x23
|
||||||
c1.y3 = inv_t * c1.y2 + t * y23
|
c1.Y3 = inv_t * c1.Y2 + t * y23
|
||||||
|
|
||||||
c2.x2 = inv_t * x23 + t * c2.x3
|
c2.X2 = inv_t * x23 + t * c2.X3
|
||||||
c2.y2 = inv_t * y23 + t * c2.y3
|
c2.Y2 = inv_t * y23 + t * c2.Y3
|
||||||
|
|
||||||
c1.x4 = inv_t * c1.x3 + t * c2.x2
|
c1.X4 = inv_t * c1.X3 + t * c2.X2
|
||||||
c1.y4 = inv_t * c1.y3 + t * c2.y2
|
c1.Y4 = inv_t * c1.Y3 + t * c2.Y2
|
||||||
|
|
||||||
c2.x1, c2.y1 = c1.x4, c1.y4
|
c2.X1, c2.Y1 = c1.X4, c1.Y4
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) {
|
func (c *CubicCurveFloat64) Subdivide(c1, c2 *CubicCurveFloat64) {
|
||||||
// Calculate all the mid-points of the line segments
|
// Calculate all the mid-points of the line segments
|
||||||
//----------------------
|
//----------------------
|
||||||
c1.x1, c1.y1 = c.x1, c.y1
|
c1.X1, c1.Y1 = c.X1, c.Y1
|
||||||
c2.x4, c2.y4 = c.x4, c.y4
|
c2.X4, c2.Y4 = c.X4, c.Y4
|
||||||
c1.x2 = (c.x1 + c.x2) / 2
|
c1.X2 = (c.X1 + c.X2) / 2
|
||||||
c1.y2 = (c.y1 + c.y2) / 2
|
c1.Y2 = (c.Y1 + c.Y2) / 2
|
||||||
x23 := (c.x2 + c.x3) / 2
|
x23 := (c.X2 + c.X3) / 2
|
||||||
y23 := (c.y2 + c.y3) / 2
|
y23 := (c.Y2 + c.Y3) / 2
|
||||||
c2.x3 = (c.x3 + c.x4) / 2
|
c2.X3 = (c.X3 + c.X4) / 2
|
||||||
c2.y3 = (c.y3 + c.y4) / 2
|
c2.Y3 = (c.Y3 + c.Y4) / 2
|
||||||
c1.x3 = (c1.x2 + x23) / 2
|
c1.X3 = (c1.X2 + x23) / 2
|
||||||
c1.y3 = (c1.y2 + y23) / 2
|
c1.Y3 = (c1.Y2 + y23) / 2
|
||||||
c2.x2 = (x23 + c2.x3) / 2
|
c2.X2 = (x23 + c2.X3) / 2
|
||||||
c2.y2 = (y23 + c2.y3) / 2
|
c2.Y2 = (y23 + c2.Y3) / 2
|
||||||
c1.x4 = (c1.x3 + c2.x2) / 2
|
c1.X4 = (c1.X3 + c2.X2) / 2
|
||||||
c1.y4 = (c1.y3 + c2.y2) / 2
|
c1.Y4 = (c1.Y3 + c2.Y2) / 2
|
||||||
c2.x1, c2.y1 = c1.x4, c1.y4
|
c2.X1, c2.Y1 = c1.X4, c1.Y4
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CubicCurveFloat64) EstimateDistance() float64 {
|
func (c *CubicCurveFloat64) EstimateDistance() float64 {
|
||||||
dx1 := c.x2 - c.x1
|
dx1 := c.X2 - c.X1
|
||||||
dy1 := c.y2 - c.y1
|
dy1 := c.Y2 - c.Y1
|
||||||
dx2 := c.x3 - c.x2
|
dx2 := c.X3 - c.X2
|
||||||
dy2 := c.y3 - c.y2
|
dy2 := c.Y3 - c.Y2
|
||||||
dx3 := c.x4 - c.x3
|
dx3 := c.X4 - c.X3
|
||||||
dy3 := c.y4 - c.y3
|
dy3 := c.Y4 - c.Y3
|
||||||
return math.Sqrt(dx1*dx1+dy1*dy1) + math.Sqrt(dx2*dx2+dy2*dy2) + math.Sqrt(dx3*dx3+dy3*dy3)
|
return math.Sqrt(dx1*dx1+dy1*dy1) + math.Sqrt(dx2*dx2+dy2*dy2) + math.Sqrt(dx3*dx3+dy3*dy3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// subdivide the curve in straight lines using Casteljau subdivision
|
// subdivide the curve in straight lines using straight line approximation and Casteljau recursive subdivision
|
||||||
// and computing minimal distance tolerance
|
// and computing minimal distance tolerance
|
||||||
func (c *CubicCurveFloat64) SegmentCasteljauRec(segments []float64) []float64 {
|
func (c *CubicCurveFloat64) SegmentRec(segments []float64) []float64 {
|
||||||
// reinit segments
|
// reinit segments
|
||||||
segments = segments[0 : len(segments)+2]
|
segments = segments[0 : len(segments)+2]
|
||||||
segments[len(segments)-2] = c.x1
|
segments[len(segments)-2] = c.X1
|
||||||
segments[len(segments)-1] = c.y1
|
segments[len(segments)-1] = c.Y1
|
||||||
segments = c.segmentCasteljauRec(segments)
|
segments = c.segmentRec(segments)
|
||||||
segments = segments[0 : len(segments)+2]
|
segments = segments[0 : len(segments)+2]
|
||||||
segments[len(segments)-2] = c.x4
|
segments[len(segments)-2] = c.X4
|
||||||
segments[len(segments)-1] = c.y4
|
segments[len(segments)-1] = c.Y4
|
||||||
return segments
|
return segments
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CubicCurveFloat64) segmentCasteljauRec(segments []float64) []float64 {
|
func (c *CubicCurveFloat64) segmentRec(segments []float64) []float64 {
|
||||||
var c1, c2 CubicCurveFloat64
|
var c1, c2 CubicCurveFloat64
|
||||||
c.Subdivide(&c1, &c2)
|
c.Subdivide(&c1, &c2)
|
||||||
|
|
||||||
// Try to approximate the full cubic curve by a single straight line
|
// Try to approximate the full cubic curve by a single straight line
|
||||||
//------------------
|
//------------------
|
||||||
dx := c.x4 - c.x1
|
dx := c.X4 - c.X1
|
||||||
dy := c.y4 - c.y1
|
dy := c.Y4 - c.Y1
|
||||||
|
|
||||||
d2 := math.Fabs(((c.x2-c.x4)*dy - (c.y2-c.y4)*dx))
|
d2 := math.Fabs(((c.X2-c.X4)*dy - (c.Y2-c.Y4)*dx))
|
||||||
d3 := math.Fabs(((c.x3-c.x4)*dy - (c.y3-c.y4)*dx))
|
d3 := math.Fabs(((c.X3-c.X4)*dy - (c.Y3-c.Y4)*dx))
|
||||||
|
|
||||||
if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) {
|
if (d2+d3)*(d2+d3) < flattening_threshold*(dx*dx+dy*dy) {
|
||||||
segments = segments[0 : len(segments)+2]
|
segments = segments[0 : len(segments)+2]
|
||||||
segments[len(segments)-2] = c2.x1
|
segments[len(segments)-2] = c2.X4
|
||||||
segments[len(segments)-1] = c2.y1
|
segments[len(segments)-1] = c2.Y4
|
||||||
return segments
|
return segments
|
||||||
}
|
}
|
||||||
// Continue subdivision
|
// Continue subdivision
|
||||||
//----------------------
|
//----------------------
|
||||||
segments = c1.segmentCasteljauRec(segments)
|
segments = c1.segmentRec(segments)
|
||||||
segments = c2.segmentCasteljauRec(segments)
|
segments = c2.segmentRec(segments)
|
||||||
return segments
|
return segments
|
||||||
}
|
}
|
||||||
|
|
||||||
func (curve *CubicCurveFloat64) SegmentCasteljau(segments []float64) ([]float64) {
|
func (curve *CubicCurveFloat64) Segment(segments []float64) ([]float64) {
|
||||||
|
// Add the first point
|
||||||
|
segments = segments[0 : len(segments)+2]
|
||||||
|
segments[len(segments)-2] = curve.X1
|
||||||
|
segments[len(segments)-1] = curve.Y1
|
||||||
|
|
||||||
var curves [32]CubicCurveFloat64
|
var curves [32]CubicCurveFloat64
|
||||||
curves[0] = *curve
|
curves[0] = *curve
|
||||||
i := 0
|
i := 0
|
||||||
|
@ -134,16 +135,16 @@ func (curve *CubicCurveFloat64) SegmentCasteljau(segments []float64) ([]float64)
|
||||||
var dx, dy, d2, d3 float64
|
var dx, dy, d2, d3 float64
|
||||||
for i >= 0 {
|
for i >= 0 {
|
||||||
c = &curves[i]
|
c = &curves[i]
|
||||||
dx = c.x4 - c.x1
|
dx = c.X4 - c.X1
|
||||||
dy = c.y4 - c.y1
|
dy = c.Y4 - c.Y1
|
||||||
|
|
||||||
d2 = math.Fabs(((c.x2-c.x4)*dy - (c.y2-c.y4)*dx))
|
d2 = math.Fabs(((c.X2-c.X4)*dy - (c.Y2-c.Y4)*dx))
|
||||||
d3 = math.Fabs(((c.x3-c.x4)*dy - (c.y3-c.y4)*dx))
|
d3 = math.Fabs(((c.X3-c.X4)*dy - (c.Y3-c.Y4)*dx))
|
||||||
|
|
||||||
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 {
|
||||||
segments = segments[0 : len(segments)+2]
|
segments = segments[0 : len(segments)+2]
|
||||||
segments[len(segments)-2] = c.x1
|
segments[len(segments)-2] = c.X4
|
||||||
segments[len(segments)-1] = c.y1
|
segments[len(segments)-1] = c.Y4
|
||||||
i--;
|
i--;
|
||||||
} else {
|
} else {
|
||||||
// second half of bezier go lower onto the stack
|
// second half of bezier go lower onto the stack
|
||||||
|
@ -151,8 +152,6 @@ func (curve *CubicCurveFloat64) SegmentCasteljau(segments []float64) ([]float64)
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
segments = segments[0 : len(segments)+2]
|
|
||||||
segments[len(segments)-2] = curve.x1
|
|
||||||
segments[len(segments)-1] = curve.y1
|
|
||||||
return segments
|
return segments
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,86 +3,128 @@ package curve
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"log"
|
"log"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"bufio"
|
||||||
|
"image"
|
||||||
|
"image/png"
|
||||||
|
"exp/draw"
|
||||||
|
"draw2d.googlecode.com/hg/draw2d/raster"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cf64Test1 = NewCubicCurveFloat64(100, 100, 200, 100, 100, 200, 200, 200)
|
testsFloat64 = []CubicCurveFloat64 {
|
||||||
cf64Test2 = NewCubicCurveFloat64(100, 100, 300, 200, 200, 200, 200, 100)
|
CubicCurveFloat64{100, 100, 200, 100, 100, 200, 200, 200},
|
||||||
|
CubicCurveFloat64{100, 100, 300, 200, 200, 200, 200, 100},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCubicCurveCasteljauRecTest1(t *testing.T) {
|
func init() {
|
||||||
var s []float64
|
f, err := os.Create("_test.html")
|
||||||
d := cf64Test1.EstimateDistance()
|
if err != nil {
|
||||||
log.Printf("Distance estimation: %f\n", d)
|
log.Println(err)
|
||||||
numSegments := int(d * 0.25)
|
os.Exit(1)
|
||||||
log.Printf("Max segments estimation: %d\n", numSegments)
|
}
|
||||||
s = make([]float64, 0, numSegments)
|
defer f.Close()
|
||||||
s = cf64Test1.SegmentCasteljauRec(s)
|
log.Printf("Create html viewer")
|
||||||
log.Printf("points: %v\n", s)
|
f.Write([]byte("<html><body>"))
|
||||||
log.Printf("Num of points: %d\n", len(s))
|
for i := 0; i < len(testsFloat64); i++ {
|
||||||
|
f.Write([]byte(fmt.Sprintf("<div><img src='_testRec%d.png'/><img src='_test%d.png'/></div>", i, i)))
|
||||||
|
}
|
||||||
|
f.Write([]byte("</body></html>"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCubicCurveCasteljauTest1(t *testing.T) {
|
func rasterPolyline(img draw.Image, c image.Color, s ...float64) image.Image {
|
||||||
var s []float64
|
for i := 2; i < len(s); i+=2 {
|
||||||
d := cf64Test1.EstimateDistance()
|
raster.Bresenham(img, c, int(s[i-2]+0.5), int(s[i-1]+0.5), int(s[i]+0.5), int(s[i+1]+0.5))
|
||||||
log.Printf("Distance estimation: %f\n", d)
|
}
|
||||||
numSegments := int(d * 0.25)
|
return img
|
||||||
log.Printf("Max segments estimation: %d\n", numSegments)
|
}
|
||||||
s = make([]float64, 0, numSegments)
|
|
||||||
s = cf64Test1.SegmentCasteljau(s)
|
func savepng(filePath string, m image.Image) {
|
||||||
log.Printf("points: %v\n", s)
|
f, err := os.Create(filePath)
|
||||||
log.Printf("Num of points: %d\n", len(s))
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
b := bufio.NewWriter(f)
|
||||||
|
err = png.Encode(b, m)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err = b.Flush()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func BenchmarkCubicCurveCasteljauRecTest1(b *testing.B) {
|
func TestCubicCurveCasteljauRec(t *testing.T) {
|
||||||
var s []float64
|
for i, curve := range testsFloat64 {
|
||||||
d := cf64Test1.EstimateDistance()
|
d := curve.EstimateDistance()
|
||||||
log.Printf("Distance estimation: %f\n", d)
|
log.Printf("Distance estimation: %f\n", d)
|
||||||
numSegments := int(d * 0.25)
|
numSegments := int(d * 0.25)
|
||||||
log.Printf("Max segments estimation: %d\n", numSegments)
|
log.Printf("Max segments estimation: %d\n", numSegments)
|
||||||
|
s := make([]float64, 0, numSegments)
|
||||||
|
s = curve.SegmentRec(s)
|
||||||
|
img := image.NewNRGBA(300, 300)
|
||||||
|
rasterPolyline(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
||||||
|
savepng(fmt.Sprintf("_testRec%d.png", i), rasterPolyline(img, image.Black, s...))
|
||||||
|
log.Printf("Num of points: %d\n", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCubicCurveCasteljau(t *testing.T) {
|
||||||
|
for i, curve := range testsFloat64 {
|
||||||
|
d := curve.EstimateDistance()
|
||||||
|
log.Printf("Distance estimation: %f\n", d)
|
||||||
|
numSegments := int(d * 0.25)
|
||||||
|
log.Printf("Max segments estimation: %d\n", numSegments)
|
||||||
|
s := make([]float64, 0, numSegments)
|
||||||
|
s = curve.Segment(s)
|
||||||
|
img := image.NewNRGBA(300, 300)
|
||||||
|
rasterPolyline(img, image.NRGBAColor{0xff, 0, 0, 0xff}, curve.X1, curve.Y1, curve.X2, curve.Y2, curve.X3, curve.Y3, curve.X4, curve.Y4)
|
||||||
|
savepng(fmt.Sprintf("_test%d.png", i), rasterPolyline(img, image.Black, s...))
|
||||||
|
log.Printf("Num of points: %d\n", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func BenchmarkCubicCurveCasteljauRec(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
s = make([]float64, 0, numSegments)
|
for _, curve := range testsFloat64 {
|
||||||
s = cf64Test1.SegmentCasteljauRec(s)
|
d := curve.EstimateDistance()
|
||||||
|
numSegments := int(d * 0.25)
|
||||||
|
s := make([]float64, 0, numSegments)
|
||||||
|
curve.SegmentRec(s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log.Printf("Num of points: %d\n", len(s))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCubicCurveCasteljauRecTest2(b *testing.B) {
|
func BenchmarkCubicCurveCasteljau(b *testing.B) {
|
||||||
var s []float64
|
|
||||||
d := cf64Test1.EstimateDistance()
|
|
||||||
log.Printf("Distance estimation: %f\n", d)
|
|
||||||
numSegments := int(d * 0.25)
|
|
||||||
log.Printf("Max segments estimation: %d\n", numSegments)
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
s = make([]float64, 0, numSegments)
|
for _, curve := range testsFloat64 {
|
||||||
s = cf64Test2.SegmentCasteljauRec(s)
|
d := curve.EstimateDistance()
|
||||||
}
|
|
||||||
log.Printf("Num of points: %d\n", len(s))
|
|
||||||
}
|
|
||||||
func BenchmarkCubicCurveCasteljauTest1(b *testing.B) {
|
|
||||||
var s []float64
|
|
||||||
d := cf64Test1.EstimateDistance()
|
|
||||||
log.Printf("Distance estimation: %f\n", d)
|
|
||||||
numSegments := int(d * 0.25)
|
numSegments := int(d * 0.25)
|
||||||
log.Printf("Max segments estimation: %d\n", numSegments)
|
s := make([]float64, 0, numSegments)
|
||||||
for i := 0; i < b.N; i++ {
|
curve.Segment(s)
|
||||||
s = make([]float64, 0, numSegments)
|
}
|
||||||
s = cf64Test1.SegmentCasteljau(s)
|
|
||||||
}
|
}
|
||||||
log.Printf("Num of points: %d\n", len(s))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCubicCurveCasteljauTest2(b *testing.B) {
|
|
||||||
var s []float64
|
|
||||||
d := cf64Test1.EstimateDistance()
|
|
||||||
log.Printf("Distance estimation: %f\n", d)
|
|
||||||
numSegments := int(d * 0.25)
|
|
||||||
log.Printf("Max segments estimation: %d\n", numSegments)
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
s = make([]float64, 0, numSegments)
|
|
||||||
s = cf64Test2.SegmentCasteljau(s)
|
|
||||||
}
|
|
||||||
log.Printf("Num of points: %d\n", len(s))
|
|
||||||
}
|
|
||||||
|
|
7
draw2d/raster/Makefile
Normal file
7
draw2d/raster/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
include $(GOROOT)/src/Make.inc
|
||||||
|
|
||||||
|
TARG=draw2d.googlecode.com/hg/draw2d/raster
|
||||||
|
GOFILES=\
|
||||||
|
line.go\
|
||||||
|
|
||||||
|
include $(GOROOT)/src/Make.pkg
|
47
draw2d/raster/line.go
Normal file
47
draw2d/raster/line.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package raster
|
||||||
|
|
||||||
|
import (
|
||||||
|
"exp/draw"
|
||||||
|
"image"
|
||||||
|
)
|
||||||
|
|
||||||
|
func abs(i int) int {
|
||||||
|
if i < 0 {
|
||||||
|
return -i
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bresenham(img draw.Image, color image.Color, x0, y0, x1, y1 int) {
|
||||||
|
dx := abs(x1 - x0)
|
||||||
|
dy := abs(y1 - y0)
|
||||||
|
var sx, sy int
|
||||||
|
if x0 < x1 {
|
||||||
|
sx = 1
|
||||||
|
} else {
|
||||||
|
sx = -1
|
||||||
|
}
|
||||||
|
if y0 < y1 {
|
||||||
|
sy = 1
|
||||||
|
} else {
|
||||||
|
sy = -1
|
||||||
|
}
|
||||||
|
err := dx - dy
|
||||||
|
|
||||||
|
var e2 int
|
||||||
|
for {
|
||||||
|
img.Set(x0, y0, color)
|
||||||
|
if x0 == x1 && y0 == y1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e2 = 2 * err
|
||||||
|
if e2 > -dy {
|
||||||
|
err = err - dy
|
||||||
|
x0 = x0 + sx
|
||||||
|
}
|
||||||
|
if e2 < dx {
|
||||||
|
err = err + dx
|
||||||
|
y0 = y0 + sy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue