#region License /* MoonWorks - Game Development Framework * Copyright 2021 Evan Hemsley */ /* Derived from code by Ethan Lee (Copyright 2009-2021). * Released under the Microsoft Public License. * See fna.LICENSE for details. * Derived from code by the Mono.Xna Team (Copyright 2006). * Released under the MIT License. See monoxna.LICENSE for details. */ #endregion #region Using Statements using System; using System.Diagnostics; #endregion namespace MoonWorks.Math { [Serializable] [DebuggerDisplay("{DebugDisplayString,nq}")] public struct Plane : IEquatable { #region Internal Properties internal string DebugDisplayString { get { return string.Concat( Normal.DebugDisplayString, " ", D.ToString() ); } } #endregion #region Public Fields public Vector3 Normal; public float D; #endregion #region Public Constructors public Plane(Vector4 value) : this(new Vector3(value.X, value.Y, value.Z), value.W) { } public Plane(Vector3 normal, float d) { Normal = normal; D = d; } public Plane(Vector3 a, Vector3 b, Vector3 c) { Vector3 ab = b - a; Vector3 ac = c - a; Vector3 cross = Vector3.Cross(ab, ac); Vector3.Normalize(ref cross, out Normal); D = -(Vector3.Dot(Normal, a)); } public Plane(float a, float b, float c, float d) : this(new Vector3(a, b, c), d) { } #endregion #region Public Methods public float Dot(Vector4 value) { return ( (this.Normal.X * value.X) + (this.Normal.Y * value.Y) + (this.Normal.Z * value.Z) + (this.D * value.W) ); } public void Dot(ref Vector4 value, out float result) { result = ( (this.Normal.X * value.X) + (this.Normal.Y * value.Y) + (this.Normal.Z * value.Z) + (this.D * value.W) ); } public float DotCoordinate(Vector3 value) { return ( (this.Normal.X * value.X) + (this.Normal.Y * value.Y) + (this.Normal.Z * value.Z) + this.D ); } public void DotCoordinate(ref Vector3 value, out float result) { result = ( (this.Normal.X * value.X) + (this.Normal.Y * value.Y) + (this.Normal.Z * value.Z) + this.D ); } public float DotNormal(Vector3 value) { return ( (this.Normal.X * value.X) + (this.Normal.Y * value.Y) + (this.Normal.Z * value.Z) ); } public void DotNormal(ref Vector3 value, out float result) { result = ( (this.Normal.X * value.X) + (this.Normal.Y * value.Y) + (this.Normal.Z * value.Z) ); } public void Normalize() { float length = Normal.Length(); float factor = 1.0f / length; Vector3.Multiply(ref Normal, factor, out Normal); D = D * factor; } public PlaneIntersectionType Intersects(BoundingBox box) { return box.Intersects(this); } public void Intersects(ref BoundingBox box, out PlaneIntersectionType result) { box.Intersects(ref this, out result); } public PlaneIntersectionType Intersects(BoundingSphere sphere) { return sphere.Intersects(this); } public void Intersects(ref BoundingSphere sphere, out PlaneIntersectionType result) { sphere.Intersects(ref this, out result); } public PlaneIntersectionType Intersects(BoundingFrustum frustum) { return frustum.Intersects(this); } #endregion #region Internal Methods internal PlaneIntersectionType Intersects(ref Vector3 point) { float distance; DotCoordinate(ref point, out distance); if (distance > 0) { return PlaneIntersectionType.Front; } if (distance < 0) { return PlaneIntersectionType.Back; } return PlaneIntersectionType.Intersecting; } #endregion #region Public Static Methods public static Plane Normalize(Plane value) { Plane ret; Normalize(ref value, out ret); return ret; } public static void Normalize(ref Plane value, out Plane result) { float length = value.Normal.Length(); float factor = 1.0f / length; Vector3.Multiply(ref value.Normal, factor, out result.Normal); result.D = value.D * factor; } /// /// Transforms a normalized plane by a matrix. /// /// The normalized plane to transform. /// The transformation matrix. /// The transformed plane. public static Plane Transform(Plane plane, Matrix4x4 matrix) { Plane result; Transform(ref plane, ref matrix, out result); return result; } /// /// Transforms a normalized plane by a matrix. /// /// The normalized plane to transform. /// The transformation matrix. /// The transformed plane. public static void Transform( ref Plane plane, ref Matrix4x4 matrix, out Plane result ) { /* See "Transforming Normals" in * http://www.glprogramming.com/red/appendixf.html * for an explanation of how this works. */ Matrix4x4 transformedMatrix; Matrix4x4.Invert(ref matrix, out transformedMatrix); Matrix4x4.Transpose( ref transformedMatrix, out transformedMatrix ); Vector4 vector = new Vector4(plane.Normal, plane.D); Vector4 transformedVector; Vector4.Transform( ref vector, ref transformedMatrix, out transformedVector ); result = new Plane(transformedVector); } /// /// Transforms a normalized plane by a quaternion rotation. /// /// The normalized plane to transform. /// The quaternion rotation. /// The transformed plane. public static Plane Transform(Plane plane, Quaternion rotation) { Plane result; Transform(ref plane, ref rotation, out result); return result; } /// /// Transforms a normalized plane by a quaternion rotation. /// /// The normalized plane to transform. /// The quaternion rotation. /// The transformed plane. public static void Transform( ref Plane plane, ref Quaternion rotation, out Plane result ) { Vector3.Transform( ref plane.Normal, ref rotation, out result.Normal ); result.D = plane.D; } #endregion #region Public Static Operators and Override Methods public static bool operator !=(Plane plane1, Plane plane2) { return !plane1.Equals(plane2); } public static bool operator ==(Plane plane1, Plane plane2) { return plane1.Equals(plane2); } public override bool Equals(object obj) { return (obj is Plane) && this.Equals((Plane) obj); } public bool Equals(Plane other) { return (Normal == other.Normal && D == other.D); } public override int GetHashCode() { return Normal.GetHashCode() ^ D.GetHashCode(); } public override string ToString() { return ( "{Normal:" + Normal.ToString() + " D:" + D.ToString() + "}" ); } #endregion } }