module Mittsu class Triangle attr_accessor :a, :b, :c def initialize(a = Mittsu::Vector3.new, b = Mittsu::Vector3.new, c = Mittsu::Vector3.new) @a, @b, @c = a, b, c end def set(a, b, c) @a.copy(a) @b.copy(b) @c.copy(c) self end def set_from_points_and_indices(points, i0, i1, i2) @a.copy(points[i0]) @b.copy(points[i1]) @c.copy(points[i2]) self end def copy(triangle) @a.copy(triangle.a) @b.copy(triangle.b) @c.copy(triangle.c) self end def area v0 = Mittsu::Vector3.new v1 = Mittsu::Vector3.new v0.sub_vectors(@c, @b) v1.sub_vectors(@a, @b) v0.cross(v1).length * 0.5 end def midpoint(target = Mittsu::Vector3.new) target.add_vectors(@a, @b).add(@c).multiply_scalar(1.0 / 3.0) end def normal(target = Mittsu::Vector3.new) Mittsu::Triangle.normal(@a, @b, @c, target) end def plane(target = Mittsu::Plane.new) target.set_from_coplanar_points(@a, @b, @c) end def barycoord_from_point(point, target = Mittsu::Vector3.new) Mittsu::Triangle.barycoord_from_point(point, @a, @b, @c, target) end def contains_point?(point) Mittsu::Triangle.contains_point?(point, @a, @b, @c) end def equals(triangle) triangle.a.equals(@a) && triangle.b.equals(@b) && triangle.c.equals(@c) end def clone Mittsu::Triangle.new.copy(self) end def self.normal(a, b, c, target = Mittsu::Vector3.new) v0 = Mittsu::Vector3.new target.sub_vectors(c, b) v0.sub_vectors(a, b) target.cross(v0) result_length_sq = target.length_sq if (result_length_sq > 0) target.multiply_scalar(1.0 / Math.sqrt(result_length_sq)) else target.set(0.0, 0.0, 0.0) end end # static/instance method to calculate barycoordinates # based on: http://www.blackpawn.com/texts/pointinpoly/default.html def self.barycoord_from_point(point, a, b, c, target = Mittsu::Vector3.new) v0 = Mittsu::Vector3.new v1 = Mittsu::Vector3.new v2 = Mittsu::Vector3.new v0.sub_vectors(c, a) v1.sub_vectors(b, a) v2.sub_vectors(point, a) dot00 = v0.dot(v0) dot01 = v0.dot(v1) dot02 = v0.dot(v2) dot11 = v1.dot(v1) dot12 = v1.dot(v2) denom = dot00 * dot11 - dot01 * dot01 # colinear or singular triangle if denom.zero? # arbitrary location outside of triangle? # not sure if this is the best idea, maybe should be returning undefined return target.set(-2.0, -1.0, -1.0) end inv_denom = 1.0 / denom u = (dot11 * dot02 - dot01 * dot12) * inv_denom v = (dot00 * dot12 - dot01 * dot02) * inv_denom target.set(1.0 - u - v, v, u) end def self.contains_point?(point, a, b, c) v1 = Mittsu::Vector3.new result = Mittsu::Triangle.barycoord_from_point(point, a, b, c, v1) result.x >= 0 && result.y >= 0 && result.x + result.y <= 1 end end end