// Copyright (c) CypherCore All rights reserved. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. using System; using System.Numerics; using System.Runtime.Serialization; namespace Framework.GameMath { /// /// Represents an axis aligned box in 3D space. /// /// /// An axis-aligned box is a box whose faces coincide with the standard basis axes. /// [Serializable] public struct AxisAlignedBox : ISerializable, ICloneable { #region Private Fields private Vector3 _lo; private Vector3 _hi; #endregion #region Constructors /// /// Initializes a new instance of the class using given minimum and maximum points. /// /// A instance representing the minimum point. /// A instance representing the maximum point. public AxisAlignedBox(Vector3 min, Vector3 max) { _lo = min; _hi = max; } /// /// Initializes a new instance of the class using given values from another box instance. /// /// A instance to take values from. public AxisAlignedBox(AxisAlignedBox box) { _lo = box.Lo; _hi = box.Hi; } /// /// Initializes a new instance of the class with serialized data. /// /// The object that holds the serialized object data. /// The contextual information about the source or destination. private AxisAlignedBox(SerializationInfo info, StreamingContext context) { _lo = (Vector3)info.GetValue("Min", typeof(Vector3)); _hi = (Vector3)info.GetValue("Max", typeof(Vector3)); } #endregion #region Public Properties /// /// Gets or sets the minimum point which is the box's minimum X and Y coordinates. /// public Vector3 Lo { get { return _lo; } set { _lo = value; } } /// /// Gets or sets the maximum point which is the box's maximum X and Y coordinates. /// public Vector3 Hi { get { return _hi; } set { _hi = value; } } #endregion #region ISerializable Members /// /// Populates a with the data needed to serialize the target object. /// /// The to populate with data. /// The destination (see ) for this serialization. //[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Max", _hi, typeof(Vector3)); info.AddValue("Min", _lo, typeof(Vector3)); } #endregion #region ICloneable Members /// /// Creates an exact copy of this object. /// /// The object this method creates, cast as an object. object ICloneable.Clone() { return new AxisAlignedBox(this); } /// /// Creates an exact copy of this object. /// /// The object this method creates. public AxisAlignedBox Clone() { return new AxisAlignedBox(this); } #endregion #region Public Methods /// /// Computes the box vertices. /// /// An array of containing the box vertices. public Vector3[] ComputeVertices() { Vector3[] vertices = new Vector3[8]; vertices[0] = _lo; vertices[1] = new Vector3(_hi.X, _lo.Y, _lo.Z); vertices[2] = new Vector3(_hi.X, _hi.Y, _lo.Z); vertices[3] = new Vector3(_lo.X, _hi.Y, _lo.Z); vertices[4] = new Vector3(_lo.X, _lo.Y, _hi.Z); vertices[5] = new Vector3(_hi.X, _lo.Y, _hi.Z); vertices[6] = _hi; vertices[7] = new Vector3(_lo.X, _hi.Y, _hi.Z); return vertices; } #endregion #region Overrides /// /// Returns the hashcode for this instance. /// /// A 32-bit signed integer hash code. public override int GetHashCode() { return _lo.GetHashCode() ^ _hi.GetHashCode(); } /// /// Returns a value indicating whether this instance is equal to /// the specified object. /// /// An object to compare to this instance. /// True if is a and has the same values as this instance; otherwise, False. public override bool Equals(object obj) { if (obj is AxisAlignedBox) { AxisAlignedBox box = (AxisAlignedBox)obj; return (_lo == box.Lo) && (_hi == box.Hi); } return false; } /// /// Returns a string representation of this object. /// /// A string representation of this object. public override string ToString() { return $"AxisAlignedBox(Min={_lo}, Max={_hi})"; } #endregion #region Comparison Operators /// /// Checks if the two given boxes are equal. /// /// The first of two boxes to compare. /// The second of two boxes to compare. /// true if the boxes are equal; otherwise, false. public static bool operator ==(AxisAlignedBox a, AxisAlignedBox b) { if (Equals(a, null)) { return Equals(b, null); } if (Equals(b, null)) { return Equals(a, null); } return (a.Lo == b.Lo) && (a.Hi == b.Hi); } /// /// Checks if the two given boxes are not equal. /// /// The first of two boxes to compare. /// The second of two boxes to compare. /// true if the vectors are not equal; otherwise, false. public static bool operator !=(AxisAlignedBox a, AxisAlignedBox b) { if (Object.Equals(a, null) == true) { return !Object.Equals(b, null); } else if (Object.Equals(b, null) == true) { return !Object.Equals(a, null); } return !((a.Lo == b.Lo) && (a.Hi == b.Hi)); } #endregion public bool contains(Vector3 point) { return (point.X >= _lo.X) && (point.Y >= _lo.Y) && (point.Z >= _lo.Z) && (point.X <= _hi.X) && (point.Y <= _hi.Y) && (point.Z <= _hi.Z); } public void merge(AxisAlignedBox a) { Lo = Vector3.Min(_lo, a.Lo); Hi = Vector3.Max(Hi, a.Hi); } public void merge(Vector3 a) { _lo = Vector3.Min(_lo, a); _hi = Vector3.Max(_hi, a); } public static AxisAlignedBox Zero() { return new AxisAlignedBox(Vector3.Zero, Vector3.Zero); } public Vector3 corner(int index) { // default constructor inits all components to 0 Vector3 v = new(); switch (index) { case 0: v.X = _lo.X; v.Y = _lo.Y; v.Z = _hi.Z; break; case 1: v.X = _hi.X; v.Y = _lo.Y; v.Z = _hi.Z; break; case 2: v.X = _hi.X; v.Y = _hi.Y; v.Z = _hi.Z; break; case 3: v.X = _lo.X; v.Y = _hi.Y; v.Z = _hi.Z; break; case 4: v.X = _lo.X; v.Y = _lo.Y; v.Z = _lo.Z; break; case 5: v.X = _hi.X; v.Y = _lo.Y; v.Z = _lo.Z; break; case 6: v.X = _hi.X; v.Y = _hi.Y; v.Z = _lo.Z; break; case 7: v.X = _lo.X; v.Y = _hi.Y; v.Z = _lo.Z; break; default: break; } return v; } public Vector3 extent() { if (Lo.IsEmpty()) return Vector3.Zero; return Hi - Lo; } public static AxisAlignedBox operator +(AxisAlignedBox box, Vector3 v) { AxisAlignedBox outt = new(); outt.Lo = box.Lo + v; outt.Hi = box.Hi + v; return outt; } } }