geom/pointf32.go
2021-08-09 01:35:30 +02:00

212 lines
5.3 KiB
Go

package geom
import (
"math"
)
// PointF32 is an X, Y coordinate pair (floating point, 32 bits).
type PointF32 struct {
X, Y float32
}
// ZeroPtF32 is initialized on (0, 0).
var ZeroPtF32 = PointF32{X: 0, Y: 0}
// PtF32 is a shorthand function to create a point.
func PtF32(x, y float32) PointF32 {
return PointF32{x, y}
}
// Add adds q as a vector to p.
func (p PointF32) Add(q PointF32) PointF32 {
return PointF32{p.X + q.X, p.Y + q.Y}
}
// Add2D adds x and y to X and Y of point p and returns the sum.
func (p PointF32) Add2D(x, y float32) PointF32 {
return PtF32(p.X+x, p.Y+y)
}
// AngleTo calculates the angle [0..2*Pi) from point p to point q.
func (p PointF32) AngleTo(q PointF32) float32 {
a := float32(math.Atan(float64((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
}
// Atan2 returns the arc tangent of y/x.
func (p PointF32) Atan2() float32 {
return Atan232(p.Y, p.X)
}
// Distance calculates the distance between points p and q.
func (p PointF32) Distance(q PointF32) float32 {
return Sqrt32(p.Distance2(q))
}
// Distance2 calculates the squared distance between points p and q.
func (p PointF32) Distance2(q PointF32) float32 {
dx := q.X - p.X
dy := q.Y - p.Y
return dx*dx + dy*dy
}
// DistanceToLine calculates the distance to the line segment a, b.
func (p PointF32) DistanceToLine(a, b PointF32) float32 {
dx1, dy1 := (a.X - p.X), (a.Y - p.Y)
dx2, dy2 := (b.X - a.X), (b.Y - a.Y)
t := -((dx1*dx2 + dy1*dy2) / (dx2*dx2 + dy2*dy2))
if 0 <= t && t <= 1 {
return Abs32(dx2*dy1-dy2*dx1) / Sqrt32(dx2*dx2+dy2*dy2)
}
d1, d2 := Sqrt32(Sq32(b.X-p.X)+Sq32(b.Y-p.Y)), Sqrt32(dx1*dx1+dy1*dy1)
if d1 < d2 {
return d1
}
return d2
}
// DistanceToLines calculates the smallest distance to the line segments of q.
func (p PointF32) DistanceToLines(q PointsF32) float32 {
n := len(q)
if n == 0 {
return NaN32()
}
if n == 1 {
return p.Distance(q[0])
}
min := p.DistanceToLine(q[0], q[1])
for i := range q {
if i < 2 {
continue
}
d := p.DistanceToLine(q[i-1], q[i])
if d < min {
min = d
}
}
return min
}
// DistanceToPolygon calculates the smallest distance to the polygon q.
func (p PointF32) DistanceToPolygon(q PolygonF32) float32 {
if len(q.Points) == 0 {
return NaN32()
}
return p.DistanceToLines(append(q.Points, q.Points[0]))
}
// Div divides the X and Y values of point p with t and returns the result.
func (p PointF32) Div(t float32) PointF32 {
return PtF32(p.X/t, p.Y/t)
}
// Dot returns the dot product of p and q.
func (p PointF32) Dot(q PointF32) float32 {
return p.X*q.X + p.Y*q.Y
}
// In tests if the point p is inside the rectangle r.
func (p PointF32) In(r RectangleF32) 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 PointF32) InPolygon(q PolygonF32) 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
}
// Invert changes the sign of the components.
func (p PointF32) Invert() PointF32 {
return PointF32{-p.X, -p.Y}
}
// Len returns the length of the vector.
func (p PointF32) Len() float32 {
return Sqrt32(p.X*p.X + p.Y*p.Y)
}
// Mul multiplies the X and Y values of point p with t and returns the result.
func (p PointF32) Mul(t float32) PointF32 {
return PtF32(p.X*t, p.Y*t)
}
// Mul2D multiplies the X and Y values of point p with x and y and returns the result.
func (p PointF32) Mul2D(x, y float32) PointF32 {
return PtF32(p.X*x, p.Y*y)
}
// Norm returns the normalized vector of x and y.
func (p PointF32) Norm() PointF32 {
return p.Mul(1 / p.Len())
}
// Rect returns a rectangle starting from point p to given point q
func (p PointF32) Rect(q PointF32) RectangleF32 {
return RectangleF32{Min: p, Max: q}
}
// Rect2D returns a rectangle starting from point p to given coordinate (x, y)
func (p PointF32) Rect2D(x, y float32) RectangleF32 {
return RectangleF32{Min: p, Max: PtF32(x, y)}
}
// RectRel returns a rectangle starting from point p with the given size.
func (p PointF32) RectRel(size PointF32) RectangleF32 {
return RectRelF32(p.X, p.Y, size.X, size.Y)
}
// RectRel2D returns a rectangle starting from point p with the given width and height
func (p PointF32) RectRel2D(width, height float32) RectangleF32 {
return RectRelF32(p.X, p.Y, width, height)
}
// Sub subtracts q as a vector from p.
func (p PointF32) Sub(q PointF32) PointF32 {
return PointF32{p.X - q.X, p.Y - q.Y}
}
// ToF transforms the point p into a PointF.
func (p PointF32) ToF() PointF {
return PointF{float64(p.X), float64(p.Y)}
}
// ToInt transforms the point p into a Point.
func (p PointF32) ToInt() Point {
return Point{int(p.X), int(p.Y)}
}
// XY returns the X and Y component of the coordinate.
func (p PointF32) XY() (float32, float32) { return p.X, p.Y }
// MaxPtF32 returns the point that is at the largest X & Y position of a and b.
func MaxPtF32(a, b PointF32) PointF32 {
return PtF32(Max32(a.X, b.X), Max32(a.Y, b.Y))
}
// MinPtF32 returns the point that is at the smallest X & Y position of a and b.
func MinPtF32(a, b PointF32) PointF32 {
return PtF32(Min32(a.X, b.X), Min32(a.Y, b.Y))
}