/Assets/Tools/Octave3D World Builder/Scripts/Math/Triangle/Triangle3D.cs

https://bitbucket.org/Jackie0100/abovequantum · C# · 349 lines · 284 code · 49 blank · 16 comment · 35 complexity · bcc1ec21fc2a6dfc8861467b90a68c6c MD5 · raw file

  1. #if UNITY_EDITOR
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. namespace O3DWB
  5. {
  6. public class Triangle3D
  7. {
  8. #region Private Variables
  9. private Vector3[] _points = new Vector3[3];
  10. private Plane _plane;
  11. private float _area;
  12. #endregion
  13. #region Public Properties
  14. public Vector3 Point0 { get { return _points[0]; } }
  15. public Vector3 Point1 { get { return _points[1]; } }
  16. public Vector3 Point2 { get { return _points[2]; } }
  17. public Vector3 Normal { get { return _plane.normal; } }
  18. public Plane Plane { get { return _plane; } }
  19. public float Area { get { return _area; } }
  20. public bool IsDegenerate { get { return _area == 0.0f || float.IsNaN(_area); } }
  21. #endregion
  22. #region Constructors
  23. public Triangle3D(Triangle3D source)
  24. {
  25. _points = new Vector3[3];
  26. _points[0] = source.Point0;
  27. _points[1] = source.Point1;
  28. _points[2] = source.Point2;
  29. _plane = source._plane;
  30. _area = source._area;
  31. }
  32. public Triangle3D(Vector3 point0, Vector3 point1, Vector3 point2)
  33. {
  34. _points = new Vector3[3];
  35. _points[0] = point0;
  36. _points[1] = point1;
  37. _points[2] = point2;
  38. CalculateAreaAndPlane();
  39. }
  40. #endregion
  41. #region Public Methods
  42. public void TransformPoints(TransformMatrix transformMatrix)
  43. {
  44. _points[0] = transformMatrix.MultiplyPoint(_points[0]);
  45. _points[1] = transformMatrix.MultiplyPoint(_points[1]);
  46. _points[2] = transformMatrix.MultiplyPoint(_points[2]);
  47. CalculateAreaAndPlane();
  48. }
  49. public void TransformPoints(Matrix4x4 transformMatrix)
  50. {
  51. _points[0] = transformMatrix.MultiplyPoint(_points[0]);
  52. _points[1] = transformMatrix.MultiplyPoint(_points[1]);
  53. _points[2] = transformMatrix.MultiplyPoint(_points[2]);
  54. CalculateAreaAndPlane();
  55. }
  56. public Box GetEncapsulatingBox()
  57. {
  58. List<Vector3> points = GetPoints();
  59. Vector3 minPoint, maxPoint;
  60. Vector3Extensions.GetMinMaxPoints(points, out minPoint, out maxPoint);
  61. return new Box((minPoint + maxPoint) * 0.5f, maxPoint - minPoint);
  62. }
  63. public bool IntersectsBox(Box box)
  64. {
  65. // Store needed data
  66. Vector3 boxCenter = box.Center;
  67. float eX = box.Extents.x;
  68. float eY = box.Extents.y;
  69. float eZ = box.Extents.z;
  70. // The triangle points expressed relative to the center of the box
  71. Vector3 v0 = _points[0] - boxCenter;
  72. Vector3 v1 = _points[1] - boxCenter;
  73. Vector3 v2 = _points[2] - boxCenter;
  74. // Triangle edges
  75. Vector3 e0 = v1 - v0;
  76. Vector3 e1 = v2 - v1;
  77. Vector3 e2 = v0 - v2;
  78. // Use the separating axis test for all 9 axes which result from crossing the box's local axes
  79. // with the triangle esges.
  80. // Test a00 = <1, 0, 0> X e0 = <0, -e0.z, e0.y>
  81. Vector3 axis = new Vector3(0.0f, -e0.z, e0.y);
  82. float v0Prj = Vector3.Dot(v0, axis);
  83. float v1Prj = Vector3.Dot(v1, axis);
  84. float v2Prj = Vector3.Dot(v2, axis);
  85. float prjEx = Mathf.Abs(eY * axis.y) + Mathf.Abs(eZ * axis.z);
  86. float minPrj = MathfEx.Min(v0Prj, v1Prj, v2Prj);
  87. float maxPrj = MathfEx.Max(v0Prj, v1Prj, v2Prj);
  88. if (Mathf.Max(-maxPrj, minPrj) > prjEx) return false;
  89. // Test a01 = <1, 0, 0> X e1 = <0, -e1.z, e1.y>
  90. axis = new Vector3(0.0f, -e1.z, e1.y);
  91. v0Prj = Vector3.Dot(v0, axis);
  92. v1Prj = Vector3.Dot(v1, axis);
  93. v2Prj = Vector3.Dot(v2, axis);
  94. prjEx = Mathf.Abs(eY * axis.y) + Mathf.Abs(eZ * axis.z);
  95. minPrj = MathfEx.Min(v0Prj, v1Prj, v2Prj);
  96. maxPrj = MathfEx.Max(v0Prj, v1Prj, v2Prj);
  97. if (Mathf.Max(-maxPrj, minPrj) > prjEx) return false;
  98. // Test a02 = <1, 0, 0> X e2 = <0, -e2.z, e2.y>
  99. axis = new Vector3(0.0f, -e2.z, e2.y);
  100. v0Prj = Vector3.Dot(v0, axis);
  101. v1Prj = Vector3.Dot(v1, axis);
  102. v2Prj = Vector3.Dot(v2, axis);
  103. prjEx = Mathf.Abs(eY * axis.y) + Mathf.Abs(eZ * axis.z);
  104. minPrj = MathfEx.Min(v0Prj, v1Prj, v2Prj);
  105. maxPrj = MathfEx.Max(v0Prj, v1Prj, v2Prj);
  106. if (Mathf.Max(-maxPrj, minPrj) > prjEx) return false;
  107. // Test a10 = <0, 1, 0> X e0 = <e0.z, 0, -e0.x>
  108. axis = new Vector3(e0.z, 0.0f, -e0.x);
  109. v0Prj = Vector3.Dot(v0, axis);
  110. v1Prj = Vector3.Dot(v1, axis);
  111. v2Prj = Vector3.Dot(v2, axis);
  112. prjEx = Mathf.Abs(eX * axis.x) + Mathf.Abs(eZ * axis.z);
  113. minPrj = MathfEx.Min(v0Prj, v1Prj, v2Prj);
  114. maxPrj = MathfEx.Max(v0Prj, v1Prj, v2Prj);
  115. if (Mathf.Max(-maxPrj, minPrj) > prjEx) return false;
  116. // Test a11 = <0, 1, 0> X e1 = <e1.z, 0, -e1.x>
  117. axis = new Vector3(e1.z, 0.0f, -e1.x);
  118. v0Prj = Vector3.Dot(v0, axis);
  119. v1Prj = Vector3.Dot(v1, axis);
  120. v2Prj = Vector3.Dot(v2, axis);
  121. prjEx = Mathf.Abs(eX * axis.x) + Mathf.Abs(eZ * axis.z);
  122. minPrj = MathfEx.Min(v0Prj, v1Prj, v2Prj);
  123. maxPrj = MathfEx.Max(v0Prj, v1Prj, v2Prj);
  124. if (Mathf.Max(-maxPrj, minPrj) > prjEx) return false;
  125. // Test a12 = <0, 1, 0> X e2 = <e2.z, 0, -e2.x>
  126. axis = new Vector3(e2.z, 0.0f, -e2.x);
  127. v0Prj = Vector3.Dot(v0, axis);
  128. v1Prj = Vector3.Dot(v1, axis);
  129. v2Prj = Vector3.Dot(v2, axis);
  130. prjEx = Mathf.Abs(eX * axis.x) + Mathf.Abs(eZ * axis.z);
  131. minPrj = MathfEx.Min(v0Prj, v1Prj, v2Prj);
  132. maxPrj = MathfEx.Max(v0Prj, v1Prj, v2Prj);
  133. if (Mathf.Max(-maxPrj, minPrj) > prjEx) return false;
  134. // Test a20 = <0, 0, 1> X e0 = <-e0.y, e0.x, 0>
  135. axis = new Vector3(-e0.y, e0.x, 0.0f);
  136. v0Prj = Vector3.Dot(v0, axis);
  137. v1Prj = Vector3.Dot(v1, axis);
  138. v2Prj = Vector3.Dot(v2, axis);
  139. prjEx = Mathf.Abs(eX * axis.x) + Mathf.Abs(eY * axis.y);
  140. minPrj = MathfEx.Min(v0Prj, v1Prj, v2Prj);
  141. maxPrj = MathfEx.Max(v0Prj, v1Prj, v2Prj);
  142. if (Mathf.Max(-maxPrj, minPrj) > prjEx) return false;
  143. // Test a21 = <0, 0, 1> X e1 = <-e1.y, e1.x, 0>
  144. axis = new Vector3(-e1.y, e1.x, 0.0f);
  145. v0Prj = Vector3.Dot(v0, axis);
  146. v1Prj = Vector3.Dot(v1, axis);
  147. v2Prj = Vector3.Dot(v2, axis);
  148. prjEx = Mathf.Abs(eX * axis.x) + Mathf.Abs(eY * axis.y);
  149. minPrj = MathfEx.Min(v0Prj, v1Prj, v2Prj);
  150. maxPrj = MathfEx.Max(v0Prj, v1Prj, v2Prj);
  151. if (Mathf.Max(-maxPrj, minPrj) > prjEx) return false;
  152. // Test a22 = <0, 0, 1> X e2 = <-e2.y, e2.x, 0>
  153. axis = new Vector3(-e2.y, e2.x, 0.0f);
  154. v0Prj = Vector3.Dot(v0, axis);
  155. v1Prj = Vector3.Dot(v1, axis);
  156. v2Prj = Vector3.Dot(v2, axis);
  157. prjEx = Mathf.Abs(eX * axis.x) + Mathf.Abs(eY * axis.y);
  158. minPrj = MathfEx.Min(v0Prj, v1Prj, v2Prj);
  159. maxPrj = MathfEx.Max(v0Prj, v1Prj, v2Prj);
  160. if (Mathf.Max(-maxPrj, minPrj) > prjEx) return false;
  161. // Check if the triangle's box intersects the box
  162. Box trianlgeBox = GetEncapsulatingBox();
  163. if (trianlgeBox.IntersectsBox(box, true)) return true;
  164. // Check if the box spans the triangle plane
  165. BoxPlaneClassificationResult boxPlaneCalssifyResult = Plane.ClassifyBox(box);
  166. return (boxPlaneCalssifyResult == BoxPlaneClassificationResult.Spanning || boxPlaneCalssifyResult == BoxPlaneClassificationResult.OnPlane);
  167. }
  168. public List<Segment3D> GetSegments()
  169. {
  170. var segments = new List<Segment3D>();
  171. segments.Add(new Segment3D(Point0, Point1));
  172. segments.Add(new Segment3D(Point1, Point2));
  173. segments.Add(new Segment3D(Point2, Point0));
  174. return segments;
  175. }
  176. public Plane GetSegmentPlane(int segmentIndex)
  177. {
  178. Segment3D segment = GetSegment(segmentIndex);
  179. Vector3 segmentPlaneNormal = Vector3.Cross(segment.Direction, _plane.normal);
  180. segmentPlaneNormal.Normalize();
  181. return new Plane(segmentPlaneNormal, segment.StartPoint);
  182. }
  183. public Segment3D GetSegment(int segmentIndex)
  184. {
  185. return new Segment3D(_points[segmentIndex], _points[(segmentIndex + 1) % 3]);
  186. }
  187. public bool Raycast(Ray ray, out float t)
  188. {
  189. if (_plane.Raycast(ray, out t))
  190. {
  191. Vector3 intersectionPoint = ray.GetPoint(t);
  192. return ContainsPoint(intersectionPoint);
  193. }
  194. else return false;
  195. }
  196. public bool Raycast(Ray3D ray, out float t)
  197. {
  198. if(ray.IntersectsPlane(_plane, out t))
  199. {
  200. Vector3 intersectionPoint = ray.GetPoint(t);
  201. return ContainsPoint(intersectionPoint);
  202. }
  203. return false;
  204. }
  205. public bool ContainsPoint(Vector3 point)
  206. {
  207. for(int segmentIndex = 0; segmentIndex < 3; ++segmentIndex)
  208. {
  209. Plane segmentPlane = GetSegmentPlane(segmentIndex);
  210. if (segmentPlane.IsPointInFront(point)) return false;
  211. }
  212. return true;
  213. }
  214. public Sphere GetEncapsulatingSphere()
  215. {
  216. return GetEncapsulatingBox().GetEncpasulatingSphere();
  217. }
  218. public Vector3 GetCenter()
  219. {
  220. Vector3 pointSum = Point0 + Point1 + Point2;
  221. return pointSum / 3.0f;
  222. }
  223. public List<Vector3> GetPoints()
  224. {
  225. return new List<Vector3> { Point0, Point1, Point2 };
  226. }
  227. public Vector3 GetPointClosestToPoint(Vector3 point)
  228. {
  229. return Vector3Extensions.GetClosestPointToPoint(GetPoints(), point);
  230. }
  231. public bool IntersectsTriangle(Triangle3D triangle)
  232. {
  233. if (triangle.Normal.IsAlignedWith(Normal)) return false;
  234. float t;
  235. List<Segment3D> otherTriSegments = triangle.GetSegments();
  236. var firstTriIntersectionPoints = new List<Vector3>();
  237. foreach (var segment in otherTriSegments)
  238. {
  239. Ray3D ray = new Ray3D(segment.StartPoint, segment.EndPoint);
  240. if (Raycast(ray, out t)) firstTriIntersectionPoints.Add(ray.GetPoint(t));
  241. }
  242. List<Segment3D> thisTriSegments = GetSegments();
  243. var secondTriIntersectionPoints = new List<Vector3>();
  244. foreach (var segment in thisTriSegments)
  245. {
  246. Ray3D ray = new Ray3D(segment.StartPoint, segment.EndPoint);
  247. if (triangle.Raycast(ray, out t)) secondTriIntersectionPoints.Add(ray.GetPoint(t));
  248. }
  249. if (firstTriIntersectionPoints.Count != 0 || secondTriIntersectionPoints.Count != 0) return true;
  250. return false;
  251. }
  252. public bool IntersectsTriangle(Triangle3D triangle, out Triangle3DIntersectInfo intersectInfo)
  253. {
  254. intersectInfo = new Triangle3DIntersectInfo();
  255. if (triangle.Normal.IsAlignedWith(Normal)) return false;
  256. float t;
  257. List<Segment3D> otherTriSegments = triangle.GetSegments();
  258. var firstTriIntersectionPoints = new List<Vector3>();
  259. foreach (var segment in otherTriSegments)
  260. {
  261. Ray3D ray = new Ray3D(segment.StartPoint, segment.EndPoint);
  262. if (Raycast(ray, out t)) firstTriIntersectionPoints.Add(ray.GetPoint(t));
  263. }
  264. List<Segment3D> thisTriSegments = GetSegments();
  265. var secondTriIntersectionPoints = new List<Vector3>();
  266. foreach(var segment in thisTriSegments)
  267. {
  268. Ray3D ray = new Ray3D(segment.StartPoint, segment.EndPoint);
  269. if (triangle.Raycast(ray, out t)) secondTriIntersectionPoints.Add(ray.GetPoint(t));
  270. }
  271. if (firstTriIntersectionPoints.Count != 0 || secondTriIntersectionPoints.Count != 0)
  272. {
  273. intersectInfo = new Triangle3DIntersectInfo(this, triangle, firstTriIntersectionPoints, secondTriIntersectionPoints);
  274. return true;
  275. }
  276. return false;
  277. }
  278. #endregion
  279. #region Private Methods
  280. private void CalculateAreaAndPlane()
  281. {
  282. Vector3 edge0 = Point1 - Point0;
  283. Vector3 edge1 = Point2 - Point0;
  284. Vector3 normal = Vector3.Cross(edge0, edge1);
  285. if(normal.magnitude < 1e-5f)
  286. {
  287. _area = 0.0f;
  288. _plane = new Plane(Vector3.zero, Vector3.zero);
  289. }
  290. else
  291. {
  292. _area = normal.magnitude * 0.5f;
  293. normal.Normalize();
  294. _plane = new Plane(normal, Point0);
  295. }
  296. }
  297. #endregion
  298. }
  299. }
  300. #endif