geom/polygonf.go
Sander Schobers e01aa3242d Added TriangleF.
Renamed Add to Extend on PolygonF{,32}.
Add now translates a polygon.
2021-08-09 01:37:16 +02:00

110 lines
2.4 KiB
Go

package geom
import "log"
// PointsF is a set of points.
type PointsF []PointF
// PolF creates a polygon of points q.
func PolF(q ...PointF) PolygonF { return PolygonF{Points: q} }
// PolygonF is defined by a set of points (floating point).
type PolygonF struct {
Points PointsF
}
// Add adds q as a vector to all points in p.
func (p PolygonF) Add(q PointF) PolygonF {
var r = p.copy()
for i, pt := range r.Points {
r.Points[i] = pt.Add(q)
}
return r
}
func (p PolygonF) copy() PolygonF {
var q = PolygonF{make(PointsF, len(p.Points))}
copy(q.Points, p.Points)
return q
}
// Extend creates a new polygon based on p with one or more extra points q.
func (p PolygonF) Extend(q ...PointF) PolygonF {
var t = PolygonF{make(PointsF, len(p.Points)+len(q))}
copy(t.Points, p.Points)
copy(t.Points[len(p.Points):], q)
return t
}
// Mul multiplies the points of polygon p with t and returns the result.
func (p PolygonF) Mul(t float64) PolygonF {
var q = p.copy()
for i, pt := range q.Points {
q.Points[i] = pt.Mul(t)
}
return q
}
// Triangulate triangulates the polygon p.
func (p PolygonF) Triangulate() []TriangleF {
var triangles []TriangleF
points := p.copy().Points[:]
n := len(points)
if n > 0 && points[0] == points[n-1] { // remove first point if polygon is closed
points = points[1:]
n--
}
triangle := func(i int) TriangleF {
return TrF(points[(i+n-1)%n], points[i], points[(i+1)%n])
}
ear := func(i int) (TriangleF, bool) {
t := triangle(i)
if t.Winding() == WindingCounterClockwise {
return TriangleF{}, false
}
for j := 0; j < n-3; j++ {
p := points[(i+2+j)%n]
if t.Contains(p) {
return TriangleF{}, false
}
}
return t, true
}
for n >= 3 {
leastSharp := -1
var leastSharpAngle float64
for i := range points {
if t, ok := ear(i); ok {
sharpAngle := t.SmallestAngle()
if leastSharp < 0 || sharpAngle > leastSharpAngle {
leastSharp = i
leastSharpAngle = sharpAngle
}
}
}
if leastSharp < 0 {
if n >= 3 {
log.Println("not fully triangulated")
}
break
}
triangles = append(triangles, triangle(leastSharp))
points = append(points[:leastSharp], points[leastSharp+1:]...)
n = len(points)
}
return triangles
}
// Reverse reverses the order of the points of polygon p.
func (p PolygonF) Reverse() PolygonF {
n := len(p.Points)
var q = PolygonF{make(PointsF, n)}
for i := 0; i < n/2; i++ {
q.Points[i], q.Points[n-i-1] = p.Points[n-i-1], p.Points[i]
}
return q
}