This commit is contained in:
Evan Burkey 2022-05-17 09:20:48 -07:00
commit 79d7e1e43d
7 changed files with 139 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.idea

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
Copyright 2022 Evan Burkey <dev@fputs.com>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# Bresenham
A quick generic implementation of Bresenham's Line Algorithm.
## Usage
Arguments are constrained to signed types. The line is returned as a slice of type `Point[T]`, a type provided by the library.

58
bresenham.go Normal file
View File

@ -0,0 +1,58 @@
// Package bresenham provides a generic implementation of
// Bresenham's Line Algorithm
package bresenham
import "golang.org/x/exp/constraints"
// Point is a generic struct holding two generic coordinates
// with a constraint of Signed
type Point[T constraints.Signed] struct {
X T
Y T
}
func abs[T constraints.Signed](a T) T {
if a < 0 {
return -a
}
return a
}
// Bresenham requires arguments of any signed type. The line is generated
// and returned as a slice of Point[T]
func Bresenham[T constraints.Signed](x0, y0, x1, y1 T) []Point[T] {
var line []Point[T]
var cx, cy, dx, dy, sx, sy, err T
cx = x0
cy = y0
dx = abs(x1 - x0)
dy = abs(y1 - y0)
if cx < x1 {
sx = 1
} else {
sx = -1
}
if cy < y1 {
sy = 1
} else {
sy = -1
}
err = dx - dy
for {
line = append(line, Point[T]{cx, cy})
if cx == x1 && cy == y1 {
return line
}
e2 := 2 * err
if e2 > 0-dy {
err = err - dy
cx = cx + sx
}
if e2 < dx {
err = err + dx
cy = cy + sy
}
}
}

53
bresenham_test.go Normal file
View File

@ -0,0 +1,53 @@
package bresenham
import (
"testing"
)
func TestBresenhamInt(t *testing.T) {
var x0, y0, x1, y1 int
x0 = 1
y0 = 1
x1 = 3
y1 = 4
res := []Point[int]{
{1, 1}, {2, 2}, {2, 3}, {3, 4},
}
line := Bresenham(x0, y0, x1, y1)
if line[0].X != res[0].X && line[0].Y != line[0].Y {
t.Errorf("Wanted %d,%d, got %d,%d", res[0].X, res[0].Y, line[0].X, line[0].Y)
}
}
func TestBresenhamIntNegative(t *testing.T) {
var x0, y0, x1, y1 int
x0 = -1
y0 = 2
x1 = 3
y1 = -4
res := []Point[int]{
{-1, 2}, {0, 1}, {0, 0}, {1, -1}, {2, -2}, {2, -3}, {3, -4},
}
line := Bresenham(x0, y0, x1, y1)
if line[0].X != res[0].X && line[0].Y != line[0].Y {
t.Errorf("Wanted %d,%d, got %d,%d", res[0].X, res[0].Y, line[0].X, line[0].Y)
}
}
func TestBresenhamInt64(t *testing.T) {
var x0, y0, x1, y1 int64
x0 = 1
y0 = 1
x1 = 3
y1 = 4
res := []Point[int64]{
{1, 1}, {2, 2}, {2, 3}, {3, 4},
}
line := Bresenham(x0, y0, x1, y1)
if line[0].X != res[0].X && line[0].Y != line[0].Y {
t.Errorf("Wanted %d,%d, got %d,%d", res[0].X, res[0].Y, line[0].X, line[0].Y)
}
}

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module bresenham
go 1.18
require golang.org/x/exp v0.0.0-20220516143420-24438e51023a // indirect

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
golang.org/x/exp v0.0.0-20220516143420-24438e51023a h1:tiLLxEjKNE6Hrah/Dp/cyHvsyjDLcMFSocOHO5XDmOM=
golang.org/x/exp v0.0.0-20220516143420-24438e51023a/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=