2017-11-01 05:51:41 +00:00
|
|
|
package geom
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
|
|
|
// PointF is an X, Y coordinate pair (floating point).
|
|
|
|
type PointF struct {
|
|
|
|
X, Y float64
|
|
|
|
}
|
|
|
|
|
2017-11-06 06:04:21 +00:00
|
|
|
// ZeroPtF is initialized on (0, 0).
|
|
|
|
var ZeroPtF = PointF{X: 0, Y: 0}
|
|
|
|
|
2017-11-01 05:51:41 +00:00
|
|
|
// 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)}
|
|
|
|
}
|
|
|
|
|
2017-11-06 21:14:48 +00:00
|
|
|
// Add adds q as a vector to p.
|
2017-11-01 05:51:41 +00:00
|
|
|
func (p PointF) Add(q PointF) PointF {
|
|
|
|
return PointF{p.X + q.X, p.Y + q.Y}
|
|
|
|
}
|
|
|
|
|
2017-11-06 21:14:48 +00:00
|
|
|
// Sub subtracts q as a vector from p.
|
|
|
|
func (p PointF) Sub(q PointF) PointF {
|
|
|
|
return PointF{p.X - q.X, p.Y - q.Y}
|
|
|
|
}
|
|
|
|
|
2017-11-01 05:51:41 +00:00
|
|
|
// 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
|
|
|
|
}
|