123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- // MIT License - Copyright (C) The Mono.Xna Team
- // This file is subject to the terms and conditions defined in
- // file 'LICENSE.txt', which is part of this source code package.
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Runtime.Serialization;
- namespace CommonLang.Geometry
- {
-
-
- public struct BoundingBox : IEquatable<BoundingBox>
- {
- #region Public Fields
-
- public Vector3 Min;
-
-
- public Vector3 Max;
- public const int CornerCount = 8;
- #endregion Public Fields
- #region Public Constructors
- public BoundingBox(Vector3 min, Vector3 max)
- {
- this.Min = min;
- this.Max = max;
- }
- #endregion Public Constructors
- #region Public Methods
- public ContainmentType Contains(BoundingBox box)
- {
- //test if all corner is in the same side of a face by just checking min and max
- if (box.Max.X < Min.X
- || box.Min.X > Max.X
- || box.Max.Y < Min.Y
- || box.Min.Y > Max.Y
- || box.Max.Z < Min.Z
- || box.Min.Z > Max.Z)
- return ContainmentType.Disjoint;
- if (box.Min.X >= Min.X
- && box.Max.X <= Max.X
- && box.Min.Y >= Min.Y
- && box.Max.Y <= Max.Y
- && box.Min.Z >= Min.Z
- && box.Max.Z <= Max.Z)
- return ContainmentType.Contains;
- return ContainmentType.Intersects;
- }
- public void Contains(ref BoundingBox box, out ContainmentType result)
- {
- result = Contains(box);
- }
- public ContainmentType Contains(BoundingFrustum frustum)
- {
- //TODO: bad done here need a fix.
- //Because question is not frustum contain box but reverse and this is not the same
- int i;
- ContainmentType contained;
- Vector3[] corners = frustum.GetCorners();
- // First we check if frustum is in box
- for (i = 0; i < corners.Length; i++)
- {
- this.Contains(ref corners[i], out contained);
- if (contained == ContainmentType.Disjoint)
- break;
- }
- if (i == corners.Length) // This means we checked all the corners and they were all contain or instersect
- return ContainmentType.Contains;
- if (i != 0) // if i is not equal to zero, we can fastpath and say that this box intersects
- return ContainmentType.Intersects;
- // If we get here, it means the first (and only) point we checked was actually contained in the frustum.
- // So we assume that all other points will also be contained. If one of the points is disjoint, we can
- // exit immediately saying that the result is Intersects
- i++;
- for (; i < corners.Length; i++)
- {
- this.Contains(ref corners[i], out contained);
- if (contained != ContainmentType.Contains)
- return ContainmentType.Intersects;
- }
- // If we get here, then we know all the points were actually contained, therefore result is Contains
- return ContainmentType.Contains;
- }
- public ContainmentType Contains(BoundingSphere sphere)
- {
- if (sphere.Center.X - Min.X >= sphere.Radius
- && sphere.Center.Y - Min.Y >= sphere.Radius
- && sphere.Center.Z - Min.Z >= sphere.Radius
- && Max.X - sphere.Center.X >= sphere.Radius
- && Max.Y - sphere.Center.Y >= sphere.Radius
- && Max.Z - sphere.Center.Z >= sphere.Radius)
- return ContainmentType.Contains;
- double dmin = 0;
- double e = sphere.Center.X - Min.X;
- if (e < 0)
- {
- if (e < -sphere.Radius)
- {
- return ContainmentType.Disjoint;
- }
- dmin += e * e;
- }
- else
- {
- e = sphere.Center.X - Max.X;
- if (e > 0)
- {
- if (e > sphere.Radius)
- {
- return ContainmentType.Disjoint;
- }
- dmin += e * e;
- }
- }
- e = sphere.Center.Y - Min.Y;
- if (e < 0)
- {
- if (e < -sphere.Radius)
- {
- return ContainmentType.Disjoint;
- }
- dmin += e * e;
- }
- else
- {
- e = sphere.Center.Y - Max.Y;
- if (e > 0)
- {
- if (e > sphere.Radius)
- {
- return ContainmentType.Disjoint;
- }
- dmin += e * e;
- }
- }
- e = sphere.Center.Z - Min.Z;
- if (e < 0)
- {
- if (e < -sphere.Radius)
- {
- return ContainmentType.Disjoint;
- }
- dmin += e * e;
- }
- else
- {
- e = sphere.Center.Z - Max.Z;
- if (e > 0)
- {
- if (e > sphere.Radius)
- {
- return ContainmentType.Disjoint;
- }
- dmin += e * e;
- }
- }
- if (dmin <= sphere.Radius * sphere.Radius)
- return ContainmentType.Intersects;
- return ContainmentType.Disjoint;
- }
- public void Contains(ref BoundingSphere sphere, out ContainmentType result)
- {
- result = this.Contains(sphere);
- }
- public ContainmentType Contains(Vector3 point)
- {
- ContainmentType result;
- this.Contains(ref point, out result);
- return result;
- }
- public void Contains(ref Vector3 point, out ContainmentType result)
- {
- //first we get if point is out of box
- if (point.X < this.Min.X
- || point.X > this.Max.X
- || point.Y < this.Min.Y
- || point.Y > this.Max.Y
- || point.Z < this.Min.Z
- || point.Z > this.Max.Z)
- {
- result = ContainmentType.Disjoint;
- }//or if point is on box because coordonate of point is lesser or equal
- else if (point.X == this.Min.X
- || point.X == this.Max.X
- || point.Y == this.Min.Y
- || point.Y == this.Max.Y
- || point.Z == this.Min.Z
- || point.Z == this.Max.Z)
- result = ContainmentType.Intersects;
- else
- result = ContainmentType.Contains;
- }
- private static readonly Vector3 MaxVector3 = new Vector3(float.MaxValue);
- private static readonly Vector3 MinVector3 = new Vector3(float.MinValue);
- /// <summary>
- /// Create a bounding box from the given list of points.
- /// </summary>
- /// <param name="points">The list of Vector3 instances defining the point cloud to bound</param>
- /// <returns>A bounding box that encapsulates the given point cloud.</returns>
- /// <exception cref="System.ArgumentException">Thrown if the given list has no points.</exception>
- public static BoundingBox CreateFromPoints(IEnumerable<Vector3> points)
- {
- if (points == null)
- throw new ArgumentNullException();
- var empty = true;
- var minVec = MaxVector3;
- var maxVec = MinVector3;
- foreach (var ptVector in points)
- {
- minVec.X = (minVec.X < ptVector.X) ? minVec.X : ptVector.X;
- minVec.Y = (minVec.Y < ptVector.Y) ? minVec.Y : ptVector.Y;
- minVec.Z = (minVec.Z < ptVector.Z) ? minVec.Z : ptVector.Z;
- maxVec.X = (maxVec.X > ptVector.X) ? maxVec.X : ptVector.X;
- maxVec.Y = (maxVec.Y > ptVector.Y) ? maxVec.Y : ptVector.Y;
- maxVec.Z = (maxVec.Z > ptVector.Z) ? maxVec.Z : ptVector.Z;
- empty = false;
- }
- if (empty)
- throw new ArgumentException();
- return new BoundingBox(minVec, maxVec);
- }
- public static BoundingBox CreateFromSphere(BoundingSphere sphere)
- {
- BoundingBox result;
- CreateFromSphere(ref sphere, out result);
- return result;
- }
- public static void CreateFromSphere(ref BoundingSphere sphere, out BoundingBox result)
- {
- var corner = new Vector3(sphere.Radius);
- result.Min = sphere.Center - corner;
- result.Max = sphere.Center + corner;
- }
- public static BoundingBox CreateMerged(BoundingBox original, BoundingBox additional)
- {
- BoundingBox result;
- CreateMerged(ref original, ref additional, out result);
- return result;
- }
- public static void CreateMerged(ref BoundingBox original, ref BoundingBox additional, out BoundingBox result)
- {
- result.Min.X = Math.Min(original.Min.X, additional.Min.X);
- result.Min.Y = Math.Min(original.Min.Y, additional.Min.Y);
- result.Min.Z = Math.Min(original.Min.Z, additional.Min.Z);
- result.Max.X = Math.Max(original.Max.X, additional.Max.X);
- result.Max.Y = Math.Max(original.Max.Y, additional.Max.Y);
- result.Max.Z = Math.Max(original.Max.Z, additional.Max.Z);
- }
- public bool Equals(BoundingBox other)
- {
- return (this.Min == other.Min) && (this.Max == other.Max);
- }
- public override bool Equals(object obj)
- {
- return (obj is BoundingBox) ? this.Equals((BoundingBox)obj) : false;
- }
- public Vector3[] GetCorners()
- {
- return new Vector3[] {
- new Vector3(this.Min.X, this.Max.Y, this.Max.Z),
- new Vector3(this.Max.X, this.Max.Y, this.Max.Z),
- new Vector3(this.Max.X, this.Min.Y, this.Max.Z),
- new Vector3(this.Min.X, this.Min.Y, this.Max.Z),
- new Vector3(this.Min.X, this.Max.Y, this.Min.Z),
- new Vector3(this.Max.X, this.Max.Y, this.Min.Z),
- new Vector3(this.Max.X, this.Min.Y, this.Min.Z),
- new Vector3(this.Min.X, this.Min.Y, this.Min.Z)
- };
- }
- public void GetCorners(Vector3[] corners)
- {
- if (corners == null)
- {
- throw new ArgumentNullException("corners");
- }
- if (corners.Length < 8)
- {
- throw new ArgumentOutOfRangeException("corners", "Not Enought Corners");
- }
- corners[0].X = this.Min.X;
- corners[0].Y = this.Max.Y;
- corners[0].Z = this.Max.Z;
- corners[1].X = this.Max.X;
- corners[1].Y = this.Max.Y;
- corners[1].Z = this.Max.Z;
- corners[2].X = this.Max.X;
- corners[2].Y = this.Min.Y;
- corners[2].Z = this.Max.Z;
- corners[3].X = this.Min.X;
- corners[3].Y = this.Min.Y;
- corners[3].Z = this.Max.Z;
- corners[4].X = this.Min.X;
- corners[4].Y = this.Max.Y;
- corners[4].Z = this.Min.Z;
- corners[5].X = this.Max.X;
- corners[5].Y = this.Max.Y;
- corners[5].Z = this.Min.Z;
- corners[6].X = this.Max.X;
- corners[6].Y = this.Min.Y;
- corners[6].Z = this.Min.Z;
- corners[7].X = this.Min.X;
- corners[7].Y = this.Min.Y;
- corners[7].Z = this.Min.Z;
- }
- public override int GetHashCode()
- {
- return this.Min.GetHashCode() + this.Max.GetHashCode();
- }
- public bool Intersects(BoundingBox box)
- {
- bool result;
- Intersects(ref box, out result);
- return result;
- }
- public void Intersects(ref BoundingBox box, out bool result)
- {
- if ((this.Max.X >= box.Min.X) && (this.Min.X <= box.Max.X))
- {
- if ((this.Max.Y < box.Min.Y) || (this.Min.Y > box.Max.Y))
- {
- result = false;
- return;
- }
- result = (this.Max.Z >= box.Min.Z) && (this.Min.Z <= box.Max.Z);
- return;
- }
- result = false;
- return;
- }
- public bool Intersects(BoundingFrustum frustum)
- {
- return frustum.Intersects(this);
- }
- public bool Intersects(BoundingSphere sphere)
- {
- if (sphere.Center.X - Min.X > sphere.Radius
- && sphere.Center.Y - Min.Y > sphere.Radius
- && sphere.Center.Z - Min.Z > sphere.Radius
- && Max.X - sphere.Center.X > sphere.Radius
- && Max.Y - sphere.Center.Y > sphere.Radius
- && Max.Z - sphere.Center.Z > sphere.Radius)
- return true;
- double dmin = 0;
- if (sphere.Center.X - Min.X <= sphere.Radius)
- dmin += (sphere.Center.X - Min.X) * (sphere.Center.X - Min.X);
- else if (Max.X - sphere.Center.X <= sphere.Radius)
- dmin += (sphere.Center.X - Max.X) * (sphere.Center.X - Max.X);
- if (sphere.Center.Y - Min.Y <= sphere.Radius)
- dmin += (sphere.Center.Y - Min.Y) * (sphere.Center.Y - Min.Y);
- else if (Max.Y - sphere.Center.Y <= sphere.Radius)
- dmin += (sphere.Center.Y - Max.Y) * (sphere.Center.Y - Max.Y);
- if (sphere.Center.Z - Min.Z <= sphere.Radius)
- dmin += (sphere.Center.Z - Min.Z) * (sphere.Center.Z - Min.Z);
- else if (Max.Z - sphere.Center.Z <= sphere.Radius)
- dmin += (sphere.Center.Z - Max.Z) * (sphere.Center.Z - Max.Z);
- if (dmin <= sphere.Radius * sphere.Radius)
- return true;
- return false;
- }
- public void Intersects(ref BoundingSphere sphere, out bool result)
- {
- result = Intersects(sphere);
- }
- public PlaneIntersectionType Intersects(Plane plane)
- {
- PlaneIntersectionType result;
- Intersects(ref plane, out result);
- return result;
- }
- public void Intersects(ref Plane plane, out PlaneIntersectionType result)
- {
- // See http://zach.in.tu-clausthal.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html
- Vector3 positiveVertex;
- Vector3 negativeVertex;
- if (plane.Normal.X >= 0)
- {
- positiveVertex.X = Max.X;
- negativeVertex.X = Min.X;
- }
- else
- {
- positiveVertex.X = Min.X;
- negativeVertex.X = Max.X;
- }
- if (plane.Normal.Y >= 0)
- {
- positiveVertex.Y = Max.Y;
- negativeVertex.Y = Min.Y;
- }
- else
- {
- positiveVertex.Y = Min.Y;
- negativeVertex.Y = Max.Y;
- }
- if (plane.Normal.Z >= 0)
- {
- positiveVertex.Z = Max.Z;
- negativeVertex.Z = Min.Z;
- }
- else
- {
- positiveVertex.Z = Min.Z;
- negativeVertex.Z = Max.Z;
- }
- // Inline Vector3.Dot(plane.Normal, negativeVertex) + plane.D;
- var distance = plane.Normal.X * negativeVertex.X + plane.Normal.Y * negativeVertex.Y + plane.Normal.Z * negativeVertex.Z + plane.D;
- if (distance > 0)
- {
- result = PlaneIntersectionType.Front;
- return;
- }
- // Inline Vector3.Dot(plane.Normal, positiveVertex) + plane.D;
- distance = plane.Normal.X * positiveVertex.X + plane.Normal.Y * positiveVertex.Y + plane.Normal.Z * positiveVertex.Z + plane.D;
- if (distance < 0)
- {
- result = PlaneIntersectionType.Back;
- return;
- }
- result = PlaneIntersectionType.Intersecting;
- }
- public Nullable<float> Intersects(Ray ray)
- {
- return ray.Intersects(this);
- }
- public void Intersects(ref Ray ray, out Nullable<float> result)
- {
- result = Intersects(ray);
- }
- public static bool operator ==(BoundingBox a, BoundingBox b)
- {
- return a.Equals(b);
- }
- public static bool operator !=(BoundingBox a, BoundingBox b)
- {
- return !a.Equals(b);
- }
- internal string DebugDisplayString
- {
- get
- {
- return string.Concat(
- "Min( ", this.Min.DebugDisplayString, " ) \r\n",
- "Max( ",this.Max.DebugDisplayString, " )"
- );
- }
- }
- public override string ToString()
- {
- return "{{Min:" + this.Min.ToString() + " Max:" + this.Max.ToString() + "}}";
- }
- #endregion Public Methods
- }
- }
|