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 } // Distance calculates the distance between points p and q. func (p PointF32) Distance(q PointF32) float32 { return float32(math.Sqrt(float64(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) } // 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} } // Mul multiplier 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) } // 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} } // To64 transforms the point p into a PointF. func (p PointF32) To64() 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)} } // 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)) }