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:
commit
26bac636bc
21
LICENSE
Normal file
21
LICENSE
Normal 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
3
README.md
Normal 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
13
point.go
Normal 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
81
pointf.go
Normal 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
6
pointf32.go
Normal 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
31
pointf_test.go
Normal 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
14
polygonf.go
Normal 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
13
rectangle.go
Normal 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
22
rectanglef.go
Normal 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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user