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 )