// Copyright (c) 2013-2015 Robert Rouhani and other contributors (see CONTRIBUTORS file). // Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE using System; using System.Runtime.InteropServices; #if MONOGAME using Vector3 = Microsoft.Xna.Framework.Vector3; #elif OPENTK using Vector3 = OpenTK.Vector3; #elif SHARPDX using Vector3 = SharpDX.Vector3; #endif namespace SharpNav.Geometry { /// /// A 3d triangle. /// [Serializable] [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Triangle3 : IEquatable { #region Fields /// /// The first point. /// public Vector3 A; /// /// The second point. /// public Vector3 B; /// /// The third point. /// public Vector3 C; #endregion #region Constructors /// /// Initializes a new instance of the struct. /// /// The second point. /// The first point. /// The third point. public Triangle3(Vector3 a, Vector3 b, Vector3 c) { A = a; B = b; C = c; } #endregion #region Properties /// /// Gets the directed line segment from to . /// public Vector3 AB { get { Vector3 result; Vector3.Subtract(ref B, ref A, out result); return result; } } /// /// Gets the directed line segment from to . /// public Vector3 AC { get { Vector3 result; Vector3.Subtract(ref C, ref A, out result); return result; } } /// /// Gets the directed line segment from to . /// public Vector3 BA { get { Vector3 result; Vector3.Subtract(ref A, ref B, out result); return result; } } /// /// Gets the directed line segment from to . /// public Vector3 BC { get { Vector3 result; Vector3.Subtract(ref C, ref B, out result); return result; } } /// /// Gets the directed line segment from to . /// public Vector3 CA { get { Vector3 result; Vector3.Subtract(ref A, ref C, out result); return result; } } /// /// Gets the directed line segment from to . /// public Vector3 CB { get { Vector3 result; Vector3.Subtract(ref B, ref C, out result); return result; } } /// /// Gets the area of the triangle. /// public float Area { get { return Vector3.Cross(AB, AC).Length() * 0.5f; } } /// /// Gets the perimeter of the triangle. /// public float Perimeter { get { return AB.Length() + AC.Length() + BC.Length(); } } /// /// Gets the centroid of the triangle. /// public Vector3 Centroid { get { const float OneThird = 1f / 3f; return A * OneThird + B * OneThird + C * OneThird; } } /// /// Gets the 's surface normal. Assumes clockwise ordering of A, B, and C. /// public Vector3 Normal { get { return Vector3.Normalize(Vector3.Cross(AB, AC)); } } #endregion #region Operators /// /// Compares two 's for equality. /// /// The first triangle. /// The second triangle. /// A value indicating whether the two triangles are equal. public static bool operator ==(Triangle3 left, Triangle3 right) { return left.Equals(right); } /// /// Compares two 's for inequality. /// /// The first triangle. /// The second triangle. /// A value indicating whether the two triangles are not equal. public static bool operator !=(Triangle3 left, Triangle3 right) { return !left.Equals(right); } #endregion #region Methods /// /// Calculates the bounding box of a triangle. /// /// A triangle. /// The triangle's bounding box. public static BBox3 GetBoundingBox(Triangle3 tri) { BBox3 b; GetBoundingBox(ref tri, out b); return b; } /// /// Calculates the bounding box of a triangle. /// /// A triangle. /// The triangle's bounding box. public static void GetBoundingBox(ref Triangle3 tri, out BBox3 bbox) { GetBoundingBox(ref tri.A, ref tri.B, ref tri.C, out bbox); } /// /// Calculates the bounding box of a triangle from its vertices. /// /// The first vertex. /// The second vertex. /// The third vertex. /// The bounding box between the points. public static void GetBoundingBox(ref Vector3 a, ref Vector3 b, ref Vector3 c, out BBox3 bbox) { Vector3 min = a, max = a; if (b.X < min.X) min.X = b.X; if (b.Y < min.Y) min.Y = b.Y; if (b.Z < min.Z) min.Z = b.Z; if (c.X < min.X) min.X = c.X; if (c.Y < min.Y) min.Y = c.Y; if (c.Z < min.Z) min.Z = c.Z; if (b.X > max.X) max.X = b.X; if (b.Y > max.Y) max.Y = b.Y; if (b.Z > max.Z) max.Z = b.Z; if (c.X > max.X) max.X = c.X; if (c.Y > max.Y) max.Y = c.Y; if (c.Z > max.Z) max.Z = c.Z; bbox.Min = min; bbox.Max = max; } /// /// Gets the area of the triangle projected onto the XZ-plane. /// /// The first point. /// The second point. /// The third point. /// The calculated area. public static void Area2D(ref Vector3 a, ref Vector3 b, ref Vector3 c, out float area) { float abx = b.X - a.X; float abz = b.Z - a.Z; float acx = c.X - a.X; float acz = c.Z - a.Z; area = acx * abz - abx * acz; } /// /// Gets the area of the triangle projected onto the XZ-plane. /// /// The first point. /// The second point. /// The third point. /// The calculated area. public static float Area2D(Vector3 a, Vector3 b, Vector3 c) { float result; Area2D(ref a, ref b, ref c, out result); return result; } /// /// Checks for equality with another . /// /// The other triangle. /// A value indicating whether other is equivalent to the triangle. public bool Equals(Triangle3 other) { return A.Equals(other.A) && B.Equals(other.B) && C.Equals(other.C); } /// /// Checks for equality with another object. /// /// The other object. /// A value indicating whether other is equivalent to the triangle. public override bool Equals(object obj) { Triangle3? other = obj as Triangle3?; if (other.HasValue) return this.Equals(other.Value); else return false; } /// /// Gets a unique hash code for the triangle. /// /// A hash code. public override int GetHashCode() { //see http://stackoverflow.com/a/263416/1122135 int hash = 17; hash = hash * 23 + A.GetHashCode(); hash = hash * 23 + B.GetHashCode(); hash = hash * 23 + C.GetHashCode(); return hash; } /// /// Converts the triangle's data into a human-readable format. /// /// A string containing the triangle's data. public override string ToString() { return "(" + A.ToString() + ", " + B.ToString() + ", " + C.ToString() + ")"; } #endregion } }