/Utilities/Datatypes/BoundingSphere.cs
C# | 382 lines | 254 code | 25 blank | 103 comment | 19 complexity | 104a88761d095fd460380071d532bb2a MD5 | raw file
Possible License(s): Apache-2.0
- using System;
- using System.IO;
- using Delta.Utilities.Datatypes.Advanced;
- using NUnit.Framework;
-
- namespace Delta.Utilities.Datatypes
- {
- /// <summary>
- /// Bounding sphere struct with basically just a center position in 3D and
- /// a radius. Allows quick collision and bounding sphere intersection tests
- /// and is sometimes even more useful than bounding boxes.
- /// </summary>
- public struct BoundingSphere : ISaveLoadBinary, IEquatable<BoundingSphere>
- {
- #region CreateFromMinMax (Static)
- /// <summary>
- /// Create from minimum maximum
- /// </summary>
- /// <param name="max">Max</param>
- /// <param name="min">Min</param>
- /// <returns>
- /// Bounding sphere created from the given minimum and maximum vector.
- /// </returns>
- public static BoundingSphere CreateFromMinMax(Vector min, Vector max)
- {
- Vector center = (max + min) * 0.5f;
- Vector sidelengths = (max - min) * 0.5f;
- float radius = sidelengths.Length;
-
- return new BoundingSphere(center, radius);
- }
- #endregion
-
- #region Center (Public)
- /// <summary>
- /// Center
- /// </summary>
- public Vector Center;
- #endregion
-
- #region Radius (Public)
- /// <summary>
- /// Radius
- /// </summary>
- public float Radius;
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create bounding sphere
- /// </summary>
- /// <param name="setCenter">Set Center</param>
- /// <param name="setRadius">Set Radius</param>
- public BoundingSphere(Vector setCenter, float setRadius)
- {
- Center = setCenter;
- Radius = setRadius;
- }
- #endregion
-
- #region IEquatable<BoundingSphere> Members
- /// <summary>
- /// Does another bounding sphere have the same values as this one?
- /// </summary>
- /// <param name="other">Other</param>
- /// <returns>
- /// True if the other bounding sphere has the same values, false otherwise.
- /// </returns>
- public bool Equals(BoundingSphere other)
- {
- return Center == other.Center &&
- Radius == other.Radius;
- }
- #endregion
-
- #region ISaveLoadBinary Members
- /// <summary>
- /// Loads the BoundingSphere (Center+Radius) from a stream.
- /// </summary>
- /// <param name="reader">Reader</param>
- public void Load(BinaryReader reader)
- {
- Center.Load(reader);
- Radius = reader.ReadSingle();
- }
-
- /// <summary>
- /// Saves the BoundingSphere (Center+Radius) to a stream.
- /// </summary>
- /// <param name="writer">Writer</param>
- public void Save(BinaryWriter writer)
- {
- Center.Save(writer);
- writer.Write(Radius);
- }
- #endregion
-
- #region op_Equality (Operator)
- /// <summary>
- /// Check for equality
- /// </summary>
- /// <param name="value1">Value 1</param>
- /// <param name="value2">Value 2</param>
- /// <returns>True if the spheres are equal, false otherwise.</returns>
- public static bool operator ==(BoundingSphere value1,
- BoundingSphere value2)
- {
- return value1.Center == value2.Center &&
- value1.Radius == value2.Radius;
- }
- #endregion
-
- #region op_Inequality (Operator)
- /// <summary>
- /// Check for inequality
- /// </summary>
- /// <param name="value1">Value 1</param>
- /// <param name="value2">Value 2</param>
- /// <returns>True if both spheres are not equal, false otherwise.</returns>
- public static bool operator !=(BoundingSphere value1,
- BoundingSphere value2)
- {
- return value1.Center != value2.Center ||
- value1.Radius != value2.Radius;
- }
- #endregion
-
- #region Contains (Public)
- /// <summary>
- /// Check whether a Sphere contains another sphere
- /// </summary>
- /// <param name="sphere">The sphere.</param>
- /// <returns>
- /// Containment type (fully, partial or none)
- /// </returns>
- public ContainmentType Contains(BoundingSphere sphere)
- {
- float distance = Vector.Distance(Center, sphere.Center);
- if (distance - (sphere.Radius + Radius) > 0)
- {
- return ContainmentType.None;
- }
- else
- {
- if (distance + sphere.Radius < Radius)
- {
- return ContainmentType.Fully;
- }
- else
- {
- return ContainmentType.Partial;
- }
- }
- }
-
- /// <summary>
- /// Check whether a Sphere contains a bounding box
- /// </summary>
- /// <param name="box">The box.</param>
- /// <returns>Containment type (fully, partial or none)</returns>
- public ContainmentType Contains(BoundingBox box)
- {
- Vector closestPoint = Vector.Clamp(Center, box.Min, box.Max);
- float distance = Vector.DistanceSquared(Center, closestPoint);
- if (distance > Radius * Radius)
- {
- return ContainmentType.None;
- }
- float radiussquared = Radius * Radius;
- Vector objectsDistance = new Vector(
- Center.X - box.Min.X, Center.Y - box.Max.Y, Center.Z - box.Max.Z);
- if (objectsDistance.LengthSquared > radiussquared)
- {
- return ContainmentType.Partial;
- }
- objectsDistance.X = Center.X - box.Max.X;
- objectsDistance.Y = Center.Y - box.Max.Y;
- objectsDistance.Z = Center.Z - box.Max.Z;
- if (objectsDistance.LengthSquared > radiussquared)
- {
- return ContainmentType.Partial;
- }
- objectsDistance.X = Center.X - box.Max.X;
- objectsDistance.Y = Center.Y - box.Min.Y;
- objectsDistance.Z = Center.Z - box.Max.Z;
- if (objectsDistance.LengthSquared > radiussquared)
- {
- return ContainmentType.Partial;
- }
- objectsDistance.X = Center.X - box.Min.X;
- objectsDistance.Y = Center.Y - box.Min.Y;
- objectsDistance.Z = Center.Z - box.Max.Z;
- if (objectsDistance.LengthSquared > radiussquared)
- {
- return ContainmentType.Partial;
- }
- objectsDistance.X = Center.X - box.Min.X;
- objectsDistance.Y = Center.Y - box.Max.Y;
- objectsDistance.Z = Center.Z - box.Min.Z;
- if (objectsDistance.LengthSquared > radiussquared)
- {
- return ContainmentType.Partial;
- }
- objectsDistance.X = Center.X - box.Max.X;
- objectsDistance.Y = Center.Y - box.Max.Y;
- objectsDistance.Z = Center.Z - box.Min.Z;
- if (objectsDistance.LengthSquared > radiussquared)
- {
- return ContainmentType.Partial;
- }
- objectsDistance.X = Center.X - box.Max.X;
- objectsDistance.Y = Center.Y - box.Min.Y;
- objectsDistance.Z = Center.Z - box.Min.Z;
- if (objectsDistance.LengthSquared > radiussquared)
- {
- return ContainmentType.Partial;
- }
- objectsDistance.X = Center.X - box.Min.X;
- objectsDistance.Y = Center.Y - box.Min.Y;
- objectsDistance.Z = Center.Z - box.Min.Z;
- if (objectsDistance.LengthSquared > radiussquared)
- {
- return ContainmentType.Partial;
- }
- return ContainmentType.Fully;
- }
-
- /// <summary>
- /// Check if the Point lays inside this sphere or not.
- /// </summary>
- /// <param name="point">Point to check containment for.</param>
- /// <returns>True if the point lays inside of the sphere.</returns>
- public ContainmentType Contains(Vector point)
- {
- float distance = Vector.Distance(Center, point);
- if ((distance - Radius) > 0)
- {
- return ContainmentType.None;
- }
- else
- {
- return ContainmentType.Fully;
- }
- }
- #endregion
-
- #region Equals (Public)
- /// <summary>
- /// Is another object an bounding sphere and has it the same values?
- /// </summary>
- /// <param name="obj">Object to compare.</param>
- /// <returns>
- /// True if the other bounding sphere has the same values, false otherwise.
- /// </returns>
- public override bool Equals(object obj)
- {
- if (obj is BoundingSphere)
- {
- return Equals((BoundingSphere)obj);
- }
- return base.Equals(obj);
- }
- #endregion
-
- #region GetHashCode (Public)
- /// <summary>
- /// Get hash code
- /// </summary>
- /// <returns>hash code</returns>
- public override int GetHashCode()
- {
- return Center.GetHashCode() ^ Radius.GetHashCode();
- }
- #endregion
-
- /// <summary>
- /// Tests
- /// </summary>
- internal class BoundingSphereTests
- {
- #region CreateFromMinMax
- /// <summary>
- /// Create a sphere from a Min, Max vectors
- /// </summary>
- [Test]
- public void CreateFromMinMax()
- {
- Vector one = new Vector(1, 2, 3);
- Vector two = new Vector(4, 5, 6);
- Vector max = (one + two) * 0.5f;
- Vector min = (two - one) * 0.5f;
- float rad = min.Length;
- BoundingSphere bOne = new BoundingSphere(max, rad);
- BoundingSphere bTwo = BoundingSphere.CreateFromMinMax(one, two);
- Assert.Equals(bOne, bTwo);
- }
- #endregion
-
- #region TestIntersects
- /// <summary>
- /// Test Intersection
- /// </summary>
- [Test]
- public void TestIntersects()
- {
- // Contains Sphere
- BoundingSphere one =
- BoundingSphere.CreateFromMinMax(
- new Vector(1, 2, 3), new Vector(10, 20, 30));
- BoundingSphere two =
- BoundingSphere.CreateFromMinMax(
- new Vector(-1, -2, -3), new Vector(5, 10, 15));
- BoundingSphere three =
- BoundingSphere.CreateFromMinMax(
- new Vector(40, 40, 40), new Vector(45, 45, 45));
- BoundingSphere four =
- BoundingSphere.CreateFromMinMax(
- new Vector(2, 3, 4), new Vector(4, 14, 24));
- // Contains Point
- Vector pt = new Vector(4, 4, 4);
- // Contains Box
- BoundingBox box1 = new BoundingBox(new Vector(2, 3, 4),
- new Vector(3, 4, 4));
-
- Assert.Equal(one.Contains(two), ContainmentType.Partial);
- Assert.Equal(one.Contains(three), ContainmentType.None);
- Assert.Equal(one.Contains(four), ContainmentType.Fully);
- Assert.Equal(one.Contains(box1), ContainmentType.Fully);
- Assert.Equals(one.Contains(pt), true);
- }
- #endregion
-
- #region Equality
- /// <summary>
- /// Equality
- /// </summary>
- [Test]
- public void Equality()
- {
- Assert.Equal(new BoundingSphere(),
- new BoundingSphere(Vector.Zero, 0.0f));
- }
- #endregion
-
- #region SaveAndLoad
- /// <summary>
- /// Test to save and load spheres into a binary stream
- /// </summary>
- [Test]
- public void SaveAndLoad()
- {
- BoundingSphere sphere = new BoundingSphere(Vector.Zero, 0.5f);
- MemoryStream memHandle = new MemoryStream();
- Assert.Equal(0, memHandle.Position);
- BinaryWriter writer = new BinaryWriter(memHandle);
-
- // save all the current data
- sphere.Save(writer);
-
- // and finally check (for saving) if the file was written correctly
- Assert.NotEqual(0, memHandle.Length);
-
- // then we create an "empty" material
- BoundingSphere loadsphere = new BoundingSphere
- (Vector.Half, 0.8f);
- memHandle.Position = 0;
-
- // which we use to load the material values from the the file
- // Note: The using closes the file access too
- BinaryReader reader = new BinaryReader(memHandle);
- loadsphere.Load(reader);
-
- // before we finally check if everything is loaded correctly
- Assert.Equal(sphere, loadsphere);
- writer.Close();
- reader.Close();
- memHandle.Close();
- }
- #endregion
- }
- }
- }