80 lines
1.7 KiB
Go
80 lines
1.7 KiB
Go
package pncdsl
|
|
|
|
import "math"
|
|
|
|
type Point struct {
|
|
X, Y float64
|
|
}
|
|
|
|
func (p Point) Add(q Point) Point { return Point{p.X + q.X, p.Y + q.Y} }
|
|
func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} }
|
|
func (p Point) Dist(q Point) float64 {
|
|
dx, dy := p.X-q.X, p.Y-q.Y
|
|
return math.Sqrt(dx*dx + dy*dy)
|
|
}
|
|
|
|
// Shape is a hotspot area. Rectangle and Polygon both satisfy it.
|
|
type Shape interface {
|
|
Contains(p Point) bool
|
|
Bounds() Rectangle
|
|
}
|
|
|
|
type Rectangle struct {
|
|
X, Y, W, H float64
|
|
}
|
|
|
|
func Rect(x, y, w, h float64) Rectangle { return Rectangle{X: x, Y: y, W: w, H: h} }
|
|
|
|
func (r Rectangle) Contains(p Point) bool {
|
|
return p.X >= r.X && p.X < r.X+r.W && p.Y >= r.Y && p.Y < r.Y+r.H
|
|
}
|
|
|
|
func (r Rectangle) Bounds() Rectangle { return r }
|
|
|
|
func (r Rectangle) Center() Point { return Point{X: r.X + r.W/2, Y: r.Y + r.H/2} }
|
|
|
|
type Polygon struct {
|
|
Points []Point
|
|
}
|
|
|
|
func Poly(pts ...Point) Polygon { return Polygon{Points: pts} }
|
|
|
|
func (g Polygon) Contains(pt Point) bool {
|
|
n := len(g.Points)
|
|
if n < 3 {
|
|
return false
|
|
}
|
|
inside := false
|
|
for i, j := 0, n-1; i < n; j, i = i, i+1 {
|
|
pi, pj := g.Points[i], g.Points[j]
|
|
if (pi.Y > pt.Y) != (pj.Y > pt.Y) &&
|
|
pt.X < (pj.X-pi.X)*(pt.Y-pi.Y)/(pj.Y-pi.Y)+pi.X {
|
|
inside = !inside
|
|
}
|
|
}
|
|
return inside
|
|
}
|
|
|
|
func (g Polygon) Bounds() Rectangle {
|
|
if len(g.Points) == 0 {
|
|
return Rectangle{}
|
|
}
|
|
minX, maxX := g.Points[0].X, g.Points[0].X
|
|
minY, maxY := g.Points[0].Y, g.Points[0].Y
|
|
for _, p := range g.Points[1:] {
|
|
if p.X < minX {
|
|
minX = p.X
|
|
}
|
|
if p.X > maxX {
|
|
maxX = p.X
|
|
}
|
|
if p.Y < minY {
|
|
minY = p.Y
|
|
}
|
|
if p.Y > maxY {
|
|
maxY = p.Y
|
|
}
|
|
}
|
|
return Rectangle{X: minX, Y: minY, W: maxX - minX, H: maxY - minY}
|
|
}
|