Browse Source

Moved this to a repo

Beacause it's **now** a repo, I can now make this a library, I just need
to tag a release and I should be able to make use of this within other
code, without needing these files around.
Apollo 1 year ago
commit
a8d3ce06fa
4 changed files with 571 additions and 0 deletions
  1. 30 0
      README.md
  2. 3 0
      go.mod
  3. 192 0
      point.go
  4. 346 0
      point_test.go

+ 30 - 0
README.md

@@ -0,0 +1,30 @@
+# Point 2D
+
+A 2 dimensional Point.
+
+Get it `go get git.red-green.com/david/point2d`
+
+## Example
+
+```go
+package main
+
+import (
+    "fmt"
+    "git.red-green.com/david/point2d"
+)
+
+func main() {
+    var p *point2d.Point = new(point2d.Point)
+    fmt.Println(p) // Automatically calls p.String()
+    p.Set(3, 2) // Set's the Point's position to (3, 2)
+    if p.Equal(3, 2) {
+       fmt.Println("p is equal (3, 2)")
+    } else {
+       fmt.Println("p is not equal (3, 2), p is", p.String())
+    }
+    var p2 *point2d.Point = point2d.AsPoint(3, 9)
+    var dist int = p.DistanceTo(&p2)
+    fmt.Printf("p is %d away from p2\n", dist)
+}
+```

+ 3 - 0
go.mod

@@ -0,0 +1,3 @@
+module git.red-green.com/david/point2d
+
+go 1.20

+ 192 - 0
point.go

@@ -0,0 +1,192 @@
+package point2d
+
+import (
+	"fmt"
+	"math"
+)
+
+// A Point 2D
+type Point struct {
+	X int64 // X Axis (Horizontal)
+	Y int64 // Y Axis (Vertical)
+}
+
+// Creates a new point at (0, 0)
+func NewPoint() *Point {
+	return &Point{}
+}
+
+// Creates a new point given 1-2 integers (more integers are ignored)
+func AsPoint(to ...int64) *Point {
+	var p *Point = &Point{}
+	if len(to) == 1 {
+		p.X = to[0]
+		p.Y = to[0]
+	} else if len(to) >= 2 {
+		p.X = to[0]
+		p.Y = to[1]
+	}
+	return p
+}
+
+// Assignment by 1-2 integers (more integers are ignored)
+func (p *Point) Set(to ...int64) *Point {
+	if len(to) == 1 {
+		p.X = to[0]
+		p.Y = to[0]
+	} else if len(to) >= 2 {
+		p.X = to[0]
+		p.Y = to[1]
+	}
+	return p
+}
+
+// Assignment to another Point's location
+func (p *Point) SetTo(o *Point) *Point {
+	p.X = o.X
+	p.Y = o.Y
+	return p
+}
+
+// Translate by 1-2 integers (more integers are ignored)
+func (p *Point) Move(by ...int64) *Point {
+	if len(by) == 1 {
+		p.X += by[0]
+		p.Y += by[0]
+	} else if len(by) >= 2 {
+		p.X += by[0]
+		p.Y += by[1]
+	}
+	return p
+}
+
+// Translate by another Point's location
+func (p *Point) MoveBy(o *Point) *Point {
+	p.X += o.X
+	p.Y += o.Y
+	return p
+}
+
+// Assigns this Point to (0, 0)
+func (p *Point) Zero() *Point {
+	p.X = 0
+	p.Y = 0
+	return p
+}
+
+// Flips both the X and Y axis's signs
+func (p *Point) Negate() *Point {
+	p.X = -p.X
+	p.Y = -p.Y
+	return p
+}
+
+// Makes both X and Y axis's positive
+func (p *Point) Abs() *Point {
+	if p.X < 0 {
+		p.X = -p.X
+	}
+	if p.Y < 0 {
+		p.Y = -p.Y
+	}
+	return p
+}
+
+// Makes a copy of the Point's location
+func (p *Point) Copy() *Point {
+	return &Point{p.X, p.Y}
+}
+
+// Outputs the Point as "X Y"
+func (p *Point) String() string {
+	return fmt.Sprintf("%d %d", p.X, p.Y)
+}
+
+// Compares if the Point is (0, 0)
+func (p *Point) IsZero() bool {
+	return p.X == 0 && p.Y == 0
+}
+
+// Compares if the Point's X is the same as given X axis
+func (p *Point) IsX(x int64) bool {
+	return p.X == x
+}
+
+// Compares if the Point's Y is the same as given Y axis
+func (p *Point) IsY(y int64) bool {
+	return p.Y == y
+}
+
+// Compares if the Point is equal to the 1-2 integers (more integers are ignored)
+func (p *Point) Equal(to ...int64) bool {
+	if len(to) == 1 {
+		return p.X == to[0] && p.Y == to[0]
+	} else if len(to) >= 2 {
+		return p.X == to[0] && p.Y == to[1]
+	}
+	return false
+}
+
+// Compares the Point to another Point
+func (p *Point) EqualTo(o *Point) bool {
+	return p.X == o.X && p.Y == o.Y
+}
+
+// Compares the Point against 1-2 integers (more integers are ignored)
+func (p *Point) Less(than ...int64) bool {
+	if len(than) == 1 {
+		return p.X <= than[0] && p.Y <= than[0]
+	} else if len(than) >= 2 {
+		return p.X <= than[0] && p.Y <= than[1]
+	}
+	return false
+}
+
+// Compares the Point against another Point
+func (p *Point) LessThan(o *Point) bool {
+	return p.X <= o.X && p.Y <= o.Y
+}
+
+// Compares the Point against 1-2 integers (more integers are ignored)
+func (p *Point) Greater(than ...int64) bool {
+	if len(than) == 1 {
+		return p.X >= than[0] && p.Y >= than[0]
+	} else if len(than) >= 2 {
+		return p.X >= than[0] && p.Y >= than[1]
+	}
+	return false
+}
+
+// Compares the Point to another Point
+func (p *Point) GreaterThan(o *Point) bool {
+	return p.X >= o.X && p.Y >= o.Y
+}
+
+// Compares the Point to see if it's within the 2 other Points
+//
+// Supports if you gave the parameters backwards
+func (p *Point) Within(topLeft, botRight *Point) bool {
+	if p.EqualTo(topLeft) || p.EqualTo(botRight) {
+		return true
+	}
+	if topLeft.EqualTo(botRight) {
+		// We didn't match either and they both are the same
+		return false
+	}
+	if topLeft.GreaterThan(botRight) {
+		topLeft, botRight = botRight, topLeft
+	}
+	return (p.X >= topLeft.X && p.X <= botRight.X) && (p.Y >= topLeft.Y && p.Y <= botRight.Y)
+}
+
+// The distance from the Point to the assumed location
+func (p *Point) Distance(x, y int64) int {
+	a := float64(p.X - x)
+	b := float64(p.Y - y)
+	return int(math.Max(math.Abs(a), math.Abs(b)))
+}
+
+// The distance from the Point to another Point
+func (p *Point) DistanceTo(o *Point) int {
+	return p.Distance(o.X, o.Y)
+}

+ 346 - 0
point_test.go

@@ -0,0 +1,346 @@
+package point2d
+
+import (
+	"testing"
+)
+
+func TestPoint2Set(t *testing.T) {
+	p := &Point{
+		1,
+		3,
+	}
+	if p.X != 1 || p.Y != 3 {
+		t.Fail()
+		t.Logf("Point expected to be '1 3' got '%d %d'", p.X, p.Y)
+	}
+	if p.String() != "1 3" {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point.String() expected to be '1 3' got '%s'", p.String())
+	}
+	p.Set(2)
+	if p.X != 2 || p.Y != 2 {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '2 2' got '%s'", p)
+	}
+	p.SetTo(&Point{3, 4})
+	if p.X != 3 || p.Y != 4 {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '3 4' got '%s'", p)
+	}
+}
+
+func TestPoint2Move(t *testing.T) {
+	p := &Point{1, 1}
+	if p.X != 1 || p.Y != 1 {
+		t.Fail()
+		t.Logf("Point expected to be '1 1' got '%s'", p)
+	}
+	p.Move(1, -1)
+	if p.X != 2 || p.Y != 0 {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '2 0' got '%s'", p)
+	}
+	p.Set(1, 1)
+	p.MoveBy(&Point{1, -1})
+	if p.X != 2 || p.Y != 0 {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '2 0' got '%s'", p)
+	}
+	p.Move(-2, 2).Move(1, -1)
+	if p.X != 1 || p.Y != 1 {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '1 1' got '%s'", p)
+	}
+	p.Set(1, 1)
+	p.Move(3)
+	if !p.Equal(4) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '4 4' got '%s'", p)
+	}
+	if p.Equal() {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point.Equal called with no values, should always return false")
+	}
+}
+
+func TestPoint2Zero(t *testing.T) {
+	p := &Point{1, 1}
+	if p.X != 1 || p.Y != 1 {
+		t.Fail()
+		t.Logf("Point expected to be '1 1' got '%s'", p)
+	}
+	if p.IsZero() {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point not zero, Point is '%s'", p)
+	}
+	p.Zero()
+	if p.X != 0 || p.Y != 0 {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '0 0' got '%s'", p)
+	}
+	if !p.IsZero() {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point is zero, Point is '%s'", p)
+	}
+}
+
+func TestPoint2Negate(t *testing.T) {
+	p := &Point{1, 1}
+	if !p.Equal(1) {
+		t.Fail()
+		t.Logf("Point expected to be '1 1' got '%s'", p)
+	}
+	p.Negate()
+	if p.X != -1 || p.Y != -1 {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '-1 -1' got '%s'", p)
+	}
+	p.Negate()
+	if !p.EqualTo(&Point{1, 1}) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '1 1' got '%s'", p)
+	}
+	p.Set(-3, -4)
+	if !p.Equal(-3, -4) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected ot be '-3 -4' got '%s'", p)
+	}
+	p.Abs()
+	if !p.Equal(3, 4) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point expected to be '3 4' got '%s'", p)
+	}
+}
+
+func TestPoint2Copy(t *testing.T) {
+	p := &Point{3, 4}
+	p2 := p.Copy()
+	p.Set(2)
+	if p2.EqualTo(p) {
+		t.Fail()
+		t.Logf("p2 expected to not equal '2 2' got '%s' (Point = '%s')", p2, p)
+	}
+}
+
+func TestPoint2Axis(t *testing.T) {
+	p := &Point{3, 4}
+	if p.IsX(2) {
+		t.Fail()
+		t.Logf("Point not on X axis 2, Point is '%s'", p)
+	}
+	if !p.IsY(4) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point is on Y axis 4, Point is '%s'", p)
+	}
+}
+
+func TestPoint2LessGreater(t *testing.T) {
+	p := &Point{3, 4}
+	if !p.Equal(3, 4) {
+		t.Fail()
+		t.Logf("Point expected to be '3 4' got '%s'", p)
+	}
+	if p.Greater(5) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point should be less than 5, Point is '%s'", p)
+	}
+	if !p.Greater(3, 3) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point should be greater than 3 3, Point is '%s'", p)
+	}
+	if p.Greater() {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point.Greater() should always return false")
+	}
+	if !p.GreaterThan(&Point{2, 2}) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point should be greater than '2 2', Point is '%s'", p)
+	}
+	if p.Less(1) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point should be greater than 1, Point is '%s'", p)
+	}
+	if !p.Less(10, 10) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point should be less than 10 10, Point is '%s'", p)
+	}
+	if p.Less() {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point.Less() should always return false")
+	}
+	if !p.LessThan(&Point{15, 15}) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point should be less than '15 15', Point is '%s'", p)
+	}
+}
+
+func TestPoint2Distance(t *testing.T) {
+	p := &Point{3, 4}
+	if !p.Equal(3, 4) {
+		t.Fail()
+		t.Logf("Point expected to be '3 4' got '%s'", p)
+	}
+	if p.Distance(0, 0) != 4 {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point distance to 0 0 should be 4, got %d", p.Distance(0, 0))
+	}
+	if p.DistanceTo(&Point{0, 0}) != 4 {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Point distance to '0 0' should be 4, got %d", p.DistanceTo(&Point{0, 0}))
+	}
+}
+
+func TestPoint2Within(t *testing.T) {
+	p := &Point{5, 5}
+
+	if !p.Equal(5) {
+		t.Fail()
+		t.Logf("Points not equal assigned values p='%s'", p)
+	}
+
+	if !p.Within(&Point{5, 5}, &Point{10, 10}) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("p == topLeft, but returned false")
+	}
+	p.Set(10, 10)
+	if !p.Within(&Point{5, 5}, &Point{10, 10}) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("p == botRight, but returned false")
+	}
+	p.Set(5, 5)
+
+	var (
+		tmp *Point = &Point{}
+		y   int64
+		x   int64
+	)
+	for y = 0; y <= 11; y++ {
+		for x = 0; x <= 11; x++ {
+			tmp.Set(x, y)
+			if tmp.X == 0 || tmp.Y == 0 {
+				if !tmp.Within(&Point{0, 0}, &Point{11, 11}) {
+					if !t.Failed() {
+						t.Fail()
+					}
+					t.Logf("'%s' not in '0 0' '11 11'?", tmp)
+				}
+			}
+			if !tmp.Within(&Point{}, &Point{11, 11}) {
+				if !t.Failed() {
+					t.Fail()
+				}
+				t.Logf("'%s' not in '0 0' '11 11'?", tmp)
+			}
+		}
+	}
+
+	if p.Within(&Point{20, 25}, &Point{15, 12}) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("'%s' in '15 12' '20 25'?", p)
+	}
+	if p.Within(&Point{10, 10}, &Point{10, 10}) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("'%s' in '10 10' '10 10'?", p)
+	}
+}
+
+func TestPointNew(t *testing.T) {
+	var p *Point = NewPoint()
+	if p == nil {
+		t.Fail()
+		t.Logf("Expected a point at '0 0', but got nil")
+	}
+	if !p.IsZero() {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Expected a point at '0 0', but got '%s'", p)
+	}
+}
+
+func TestPointAs(t *testing.T) {
+	var p *Point = AsPoint(3, 2)
+	if p == nil {
+		t.Fail()
+		t.Logf("Expected a point, got nil")
+	}
+	if !p.Equal(3, 2) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Expected a point at '3 2', got '%s'", p)
+	}
+	p = AsPoint(5)
+	if p == nil {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Expected a point, got nil")
+	}
+	if !p.Equal(5, 5) {
+		if !t.Failed() {
+			t.Fail()
+		}
+		t.Logf("Expected a point at '5 5', got '%s'", p)
+	}
+}