Initial version of the geom package

- Includes PointF, RectangleF and PolygonF. Additional it includes the 32 bit floating point PointF32 and wrappers to image.Point and image.Rectangle.
This commit is contained in:
Sander Schobers 2017-11-01 06:51:41 +01:00
commit 26bac636bc
9 changed files with 204 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Sander Schobers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# geom package
The geom packages exposes some basic geometries using floating point numbers. The package is licensed under [MIT](LICENSE). Currently this package is still under development and thus the API may break.

13
point.go Normal file
View File

@ -0,0 +1,13 @@
package geom
import (
_image "image"
)
// Point is exposing the standard library image.Point in the geom package.
type Point _image.Point
// Pt is a shorthand function to create a point.
func Pt(x, y int) Point {
return Point{x, y}
}

81
pointf.go Normal file
View File

@ -0,0 +1,81 @@
package geom
import (
"math"
"strconv"
)
// PointF is an X, Y coordinate pair (floating point).
type PointF struct {
X, Y float64
}
// PtF is a shorthand function to create a point.
func PtF(x, y float64) PointF {
return PointF{X: x, Y: y}
}
// String formats the point p as a string.
func (p Point) String() string {
return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
}
// To32 transforms the point p into a PointF32.
func (p PointF) To32() PointF32 {
return PointF32{float32(p.X), float32(p.Y)}
}
// Add adds q as a vector to p
func (p PointF) Add(q PointF) PointF {
return PointF{p.X + q.X, p.Y + q.Y}
}
// AngleTo calculates the angle [0..2*Pi) from point p to point q.
func (p PointF) AngleTo(q PointF) float64 {
a := math.Atan((p.Y - q.Y) / (p.X - q.X))
if q.X < p.X {
return a + math.Pi
}
if a < 0 {
a += 2 * math.Pi
}
return a
}
// Distance calculates the distance between points p and q.
func (p PointF) Distance(q PointF) float64 {
return math.Sqrt(p.Distance2(q))
}
// Distance2 calculates the squared distance between points p and q.
func (p PointF) Distance2(q PointF) float64 {
dx := q.X - p.X
dy := q.Y - p.Y
return dx*dx + dy*dy
}
// In tests if the point p is inside the rectangle r.
func (p PointF) In(r RectangleF) bool {
if p.X < r.Min.X || p.X >= r.Max.X || p.Y < r.Min.Y || p.Y >= r.Max.Y {
return false
}
return true
}
// InPolygon tests is the point p is inside the polygon q.
func (p PointF) InPolygon(q PolygonF) bool {
var n = len(q.Points)
var c = false
var i = 0
var j = n - 1
for i < n {
if ((q.Points[i].Y >= p.Y) != (q.Points[j].Y >= p.Y)) &&
(p.X <= (q.Points[j].X-q.Points[i].X)*(p.Y-q.Points[i].Y)/(q.Points[j].Y-q.Points[i].Y)+q.Points[i].X) {
c = !c
}
j = i
i++
}
return c
}

6
pointf32.go Normal file
View File

@ -0,0 +1,6 @@
package geom
// PointF32 is an X, Y coordinate pair (floating point, 32 bits).
type PointF32 struct {
X, Y float32
}

31
pointf_test.go Normal file
View File

@ -0,0 +1,31 @@
package geom
import (
"math"
"testing"
"github.com/stretchr/testify/assert"
)
func TestPointFAngleTo(t *testing.T) {
for a := .0; a <= 2*math.Pi; a += math.Pi * 0.25 {
assert.InDelta(t, a, PtF(0, 0).AngleTo(PtF(100*math.Cos(a), 100*math.Sin(a))), 0.000001)
}
}
func TestPointInPolygon(t *testing.T) {
pol := PolygonF{[]PointF{PtF(0, 0), PtF(0, 3), PtF(1, 3), PtF(2, 1), PtF(3, 3), PtF(5, 3), PtF(5, 2), PtF(3, 1), PtF(5, 0)}}
assert.True(t, PtF(1, 2).InPolygon(pol))
assert.True(t, PtF(3, 2).InPolygon(pol))
assert.True(t, PtF(4, 2).InPolygon(pol))
// assert.True(t, PtF(0, 0).InPolygon(pol)) // Corner = out
// assert.True(t, PtF(0, 3).InPolygon(pol)) // Corner = out
// assert.True(t, PtF(5, 3).InPolygon(pol)) // Corner = in
// assert.True(t, PtF(5, 0).InPolygon(pol)) // Corner = out
assert.False(t, PtF(0, -1).InPolygon(pol))
assert.False(t, PtF(-1, 0).InPolygon(pol))
assert.False(t, PtF(2, 2).InPolygon(pol))
assert.False(t, PtF(2, 3).InPolygon(pol))
assert.False(t, PtF(4, 1).InPolygon(pol))
assert.False(t, PtF(5, 1).InPolygon(pol))
}

14
polygonf.go Normal file
View File

@ -0,0 +1,14 @@
package geom
// PolygonF is defined by a set of points (floating point).
type PolygonF struct {
Points []PointF
}
// Add creates a new polyqon based on p with one or more extra points q.
func (p PolygonF) Add(q ...PointF) PolygonF {
var t = PolygonF{make([]PointF, len(p.Points)+len(q))}
copy(t.Points, p.Points)
copy(t.Points[len(p.Points):], q)
return t
}

13
rectangle.go Normal file
View File

@ -0,0 +1,13 @@
package geom
import (
_image "image"
)
// Rectangle is exposing the standard library image.Rectangle in the geom package.
type Rectangle _image.Rectangle
// Rect is a shorthand function to create a rectangle.
func Rect(x0, y0, x1, y1 int) Rectangle {
return Rectangle(_image.Rect(x0, y0, x1, y1))
}

22
rectanglef.go Normal file
View File

@ -0,0 +1,22 @@
package geom
// RectangleF is defined by two points, the minimum and maximum (floating point).
type RectangleF struct {
Min, Max PointF
}
// RectF is a shorthand function to create a rectangle.
func RectF(x0, y0, x1, y1 float64) RectangleF {
if x0 > x1 {
x0, x1 = x1, x0
}
if y0 > y1 {
y0, y1 = y1, y0
}
return RectangleF{PtF(x0, y0), PtF(x1, y1)}
}
// Size returns the size of the rectangle.
func (r RectangleF) Size() PointF {
return PtF(r.Max.X-r.Min.X, r.Max.Y-r.Min.Y)
}