mirror of https://github.com/tidwall/tile38.git
121 lines
2.5 KiB
Go
121 lines
2.5 KiB
Go
// Package poly provides polygon detection methods.
|
|
package poly
|
|
|
|
import "fmt"
|
|
|
|
// Point is simple 2D point
|
|
// For geo locations: X is lat, Y is lon, and Z is elev or time measure.
|
|
type Point struct {
|
|
X, Y, Z float64
|
|
}
|
|
|
|
// InsideRect detects point is inside of another rect
|
|
func (p Point) InsideRect(rect Rect) bool {
|
|
if p.X < rect.Min.X || p.X > rect.Max.X {
|
|
return false
|
|
}
|
|
if p.Y < rect.Min.Y || p.Y > rect.Max.Y {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Polygon is series of points that make up a polygon
|
|
type Polygon []Point
|
|
|
|
// InsideRect detects polygon is inside of another rect
|
|
func (p Polygon) InsideRect(rect Rect) bool {
|
|
if len(p) == 0 {
|
|
return false
|
|
}
|
|
for _, p := range p {
|
|
if !p.InsideRect(rect) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// IntersectsRect detects polygon is inside of another rect
|
|
func (p Polygon) IntersectsRect(rect Rect) bool {
|
|
if len(p) == 0 {
|
|
return false
|
|
}
|
|
rectPoly := Polygon{rect.Min, {rect.Min.X, rect.Max.Y, 0}, rect.Max, {rect.Max.X, rect.Min.Y, 0}, rect.Min}
|
|
return p.Intersects(rectPoly, nil)
|
|
}
|
|
|
|
// String returns a string representation of the polygon.
|
|
func (p Polygon) String() string {
|
|
s := "{"
|
|
for i, p := range p {
|
|
if i > 0 {
|
|
s += ", "
|
|
}
|
|
s += fmt.Sprintf("{%v, %v}", p.X, p.Y)
|
|
}
|
|
s += "}"
|
|
return s
|
|
}
|
|
|
|
// Rect is rectangle
|
|
type Rect struct {
|
|
Min, Max Point
|
|
}
|
|
|
|
// Polygon returns a polygon for the rect
|
|
func (r Rect) Polygon() Polygon {
|
|
p := Polygon(make([]Point, 5))
|
|
p[0] = Point{X: r.Min.X, Y: r.Max.Y}
|
|
p[1] = Point{X: r.Max.X, Y: r.Max.Y}
|
|
p[2] = Point{X: r.Max.X, Y: r.Min.Y}
|
|
p[3] = Point{X: r.Min.X, Y: r.Min.Y}
|
|
p[4] = Point{X: r.Min.X, Y: r.Max.Y}
|
|
return p
|
|
}
|
|
|
|
// Rect returns the bounding box rectangle for the polygon
|
|
func (p Polygon) Rect() Rect {
|
|
var bbox Rect
|
|
for i, p := range p {
|
|
if i == 0 {
|
|
bbox.Min = p
|
|
bbox.Max = p
|
|
} else {
|
|
if p.X < bbox.Min.X {
|
|
bbox.Min.X = p.X
|
|
} else if p.X > bbox.Max.X {
|
|
bbox.Max.X = p.X
|
|
}
|
|
if p.Y < bbox.Min.Y {
|
|
bbox.Min.Y = p.Y
|
|
} else if p.Y > bbox.Max.Y {
|
|
bbox.Max.Y = p.Y
|
|
}
|
|
}
|
|
}
|
|
return bbox
|
|
}
|
|
|
|
// IntersectsRect detects if two bboxes intersect.
|
|
func (r Rect) IntersectsRect(rect Rect) bool {
|
|
if r.Min.Y > rect.Max.Y || r.Max.Y < rect.Min.Y {
|
|
return false
|
|
}
|
|
if r.Min.X > rect.Max.X || r.Max.X < rect.Min.X {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// InsideRect detects rect is inside of another rect
|
|
func (r Rect) InsideRect(rect Rect) bool {
|
|
if r.Min.X < rect.Min.X || r.Max.X > rect.Max.X {
|
|
return false
|
|
}
|
|
if r.Min.Y < rect.Min.Y || r.Max.Y > rect.Max.Y {
|
|
return false
|
|
}
|
|
return true
|
|
}
|