94 lines
2.5 KiB
Go
94 lines
2.5 KiB
Go
|
package geom
|
||
|
|
||
|
import (
|
||
|
"math"
|
||
|
)
|
||
|
|
||
|
// TriangleF is defined by three points that describe a 2D triangle.
|
||
|
type TriangleF struct {
|
||
|
Points [3]PointF
|
||
|
}
|
||
|
|
||
|
// TrF is a shorthand method to create a TriangleF.
|
||
|
func TrF(q, r, s PointF) TriangleF {
|
||
|
return TriangleF{Points: [3]PointF{q, r, s}}
|
||
|
}
|
||
|
|
||
|
// Add translates the triangle by point p.
|
||
|
func (t TriangleF) Add(p PointF) TriangleF {
|
||
|
return TriangleF{Points: [3]PointF{
|
||
|
t.Points[0].Add(p),
|
||
|
t.Points[1].Add(p),
|
||
|
t.Points[2].Add(p),
|
||
|
}}
|
||
|
}
|
||
|
|
||
|
// Center gives the average of the three points.
|
||
|
func (t TriangleF) Center() PointF {
|
||
|
return t.Points[0].Add(t.Points[1]).Add(t.Points[2]).Mul(1. / 3)
|
||
|
}
|
||
|
|
||
|
// Contains tests if point p lies in the triangle.
|
||
|
func (t TriangleF) Contains(p PointF) bool {
|
||
|
u, v, w := t.Points[0], t.Points[1], t.Points[2]
|
||
|
const eps = 1e-9
|
||
|
q := 1 / (-v.Y*w.X + u.Y*(-v.X+w.X) + u.X*(v.Y-w.Y) + v.X*w.Y)
|
||
|
r := (u.Y*w.X - u.X*w.Y + (w.Y-u.Y)*p.X + (u.X-w.X)*p.Y) * q
|
||
|
s := (u.X*v.Y - u.Y*v.X + (u.Y-v.Y)*p.X + (v.X-u.X)*p.Y) * q
|
||
|
if r < -eps || r > 1+eps || s < -eps || s > 1+eps || r+s > 1+eps {
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// Inset insets all the points of the triangle towards the center of the triangle with distance f.
|
||
|
func (t TriangleF) Inset(f float64) TriangleF {
|
||
|
center := t.Center()
|
||
|
inset := func(p PointF) PointF {
|
||
|
centered := p.Sub(center)
|
||
|
length := p.Distance(center)
|
||
|
factor := (length - f) / length
|
||
|
return center.Add(centered.Mul(factor))
|
||
|
}
|
||
|
return TriangleF{Points: [3]PointF{
|
||
|
inset(t.Points[0]),
|
||
|
inset(t.Points[1]),
|
||
|
inset(t.Points[2]),
|
||
|
}}
|
||
|
}
|
||
|
|
||
|
// Mul multiplies all the points of the triangle with f.
|
||
|
func (t TriangleF) Mul(f float64) TriangleF {
|
||
|
return TriangleF{Points: [3]PointF{
|
||
|
t.Points[0].Mul(f),
|
||
|
t.Points[1].Mul(f),
|
||
|
t.Points[2].Mul(f),
|
||
|
}}
|
||
|
}
|
||
|
|
||
|
// SmallestAngle returns the smallest/sharpest angle of the triangle.
|
||
|
func (t TriangleF) SmallestAngle() float64 {
|
||
|
u, v, w := t.Points[0], t.Points[1], t.Points[2]
|
||
|
q := math.Acos(w.Sub(u).Norm().Dot(v.Sub(u).Norm()))
|
||
|
r := math.Acos(u.Sub(v).Norm().Dot(w.Sub(v).Norm()))
|
||
|
s := math.Acos(v.Sub(w).Norm().Dot(u.Sub(w).Norm()))
|
||
|
return math.Min(q, math.Min(r, s))
|
||
|
}
|
||
|
|
||
|
// Winding determines the winding of the triangle.
|
||
|
func (t TriangleF) Winding() Winding {
|
||
|
u, v := t.Points[1].Sub(t.Points[0]), t.Points[2].Sub(t.Points[1])
|
||
|
if u.X*v.Y-u.Y*v.X > 0 {
|
||
|
return WindingClockwise
|
||
|
}
|
||
|
return WindingCounterClockwise
|
||
|
}
|
||
|
|
||
|
// Winding describes the order of points.
|
||
|
type Winding bool
|
||
|
|
||
|
const (
|
||
|
WindingClockwise Winding = false
|
||
|
WindingCounterClockwise Winding = true
|
||
|
)
|