123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- // 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.Globalization;
- using System.Runtime.Serialization;
- using System.Diagnostics;
- namespace CommonLang.Geometry
- {
-
-
- public struct BoundingSphere : IEquatable<BoundingSphere>
- {
- #region Public Fields
-
- public Vector3 Center;
-
- public float Radius;
- #endregion Public Fields
- #region Constructors
- public BoundingSphere(Vector3 center, float radius)
- {
- this.Center = center;
- this.Radius = radius;
- }
- #endregion Constructors
- #region Public Methods
- public BoundingSphere Transform(Matrix matrix)
- {
- BoundingSphere sphere = new BoundingSphere();
- sphere.Center = Vector3.Transform(this.Center, matrix);
- sphere.Radius = this.Radius * ((float)Math.Sqrt((double)Math.Max(((matrix.M11 * matrix.M11) + (matrix.M12 * matrix.M12)) + (matrix.M13 * matrix.M13), Math.Max(((matrix.M21 * matrix.M21) + (matrix.M22 * matrix.M22)) + (matrix.M23 * matrix.M23), ((matrix.M31 * matrix.M31) + (matrix.M32 * matrix.M32)) + (matrix.M33 * matrix.M33)))));
- return sphere;
- }
- public void Transform(ref Matrix matrix, out BoundingSphere result)
- {
- result.Center = Vector3.Transform(this.Center, matrix);
- result.Radius = this.Radius * ((float)Math.Sqrt((double)Math.Max(((matrix.M11 * matrix.M11) + (matrix.M12 * matrix.M12)) + (matrix.M13 * matrix.M13), Math.Max(((matrix.M21 * matrix.M21) + (matrix.M22 * matrix.M22)) + (matrix.M23 * matrix.M23), ((matrix.M31 * matrix.M31) + (matrix.M32 * matrix.M32)) + (matrix.M33 * matrix.M33)))));
- }
- public ContainmentType Contains(BoundingBox box)
- {
- //check if all corner is in sphere
- bool inside = true;
- foreach (Vector3 corner in box.GetCorners())
- {
- if (this.Contains(corner) == ContainmentType.Disjoint)
- {
- inside = false;
- break;
- }
- }
- if (inside)
- return ContainmentType.Contains;
- //check if the distance from sphere center to cube face < radius
- double dmin = 0;
- if (Center.X < box.Min.X)
- dmin += (Center.X - box.Min.X) * (Center.X - box.Min.X);
- else if (Center.X > box.Max.X)
- dmin += (Center.X - box.Max.X) * (Center.X - box.Max.X);
- if (Center.Y < box.Min.Y)
- dmin += (Center.Y - box.Min.Y) * (Center.Y - box.Min.Y);
- else if (Center.Y > box.Max.Y)
- dmin += (Center.Y - box.Max.Y) * (Center.Y - box.Max.Y);
- if (Center.Z < box.Min.Z)
- dmin += (Center.Z - box.Min.Z) * (Center.Z - box.Min.Z);
- else if (Center.Z > box.Max.Z)
- dmin += (Center.Z - box.Max.Z) * (Center.Z - box.Max.Z);
- if (dmin <= Radius * Radius)
- return ContainmentType.Intersects;
-
- //else disjoint
- return ContainmentType.Disjoint;
- }
- public void Contains(ref BoundingBox box, out ContainmentType result)
- {
- result = this.Contains(box);
- }
- public ContainmentType Contains(BoundingFrustum frustum)
- {
- //check if all corner is in sphere
- bool inside = true;
- Vector3[] corners = frustum.GetCorners();
- foreach (Vector3 corner in corners)
- {
- if (this.Contains(corner) == ContainmentType.Disjoint)
- {
- inside = false;
- break;
- }
- }
- if (inside)
- return ContainmentType.Contains;
- //check if the distance from sphere center to frustrum face < radius
- double dmin = 0;
- //TODO : calcul dmin
- if (dmin <= Radius * Radius)
- return ContainmentType.Intersects;
- //else disjoint
- return ContainmentType.Disjoint;
- }
- public ContainmentType Contains(BoundingSphere sphere)
- {
- ContainmentType result;
- Contains(ref sphere, out result);
- return result;
- }
- public void Contains(ref BoundingSphere sphere, out ContainmentType result)
- {
- float sqDistance;
- Vector3.DistanceSquared(ref sphere.Center, ref Center, out sqDistance);
- if (sqDistance > (sphere.Radius + Radius) * (sphere.Radius + Radius))
- result = ContainmentType.Disjoint;
- else if (sqDistance <= (Radius - sphere.Radius) * (Radius - sphere.Radius))
- result = ContainmentType.Contains;
- else
- result = ContainmentType.Intersects;
- }
- public ContainmentType Contains(Vector3 point)
- {
- ContainmentType result;
- Contains(ref point, out result);
- return result;
- }
- public void Contains(ref Vector3 point, out ContainmentType result)
- {
- float sqRadius = Radius * Radius;
- float sqDistance;
- Vector3.DistanceSquared(ref point, ref Center, out sqDistance);
-
- if (sqDistance > sqRadius)
- result = ContainmentType.Disjoint;
- else if (sqDistance < sqRadius)
- result = ContainmentType.Contains;
- else
- result = ContainmentType.Intersects;
- }
- public static BoundingSphere CreateFromBoundingBox(BoundingBox box)
- {
- BoundingSphere result;
- CreateFromBoundingBox(ref box, out result);
- return result;
- }
- public static void CreateFromBoundingBox(ref BoundingBox box, out BoundingSphere result)
- {
- // Find the center of the box.
- Vector3 center = new Vector3((box.Min.X + box.Max.X) / 2.0f,
- (box.Min.Y + box.Max.Y) / 2.0f,
- (box.Min.Z + box.Max.Z) / 2.0f);
- // Find the distance between the center and one of the corners of the box.
- float radius = Vector3.Distance(center, box.Max);
- result = new BoundingSphere(center, radius);
- }
- public static BoundingSphere CreateFromFrustum(BoundingFrustum frustum)
- {
- return BoundingSphere.CreateFromPoints(frustum.GetCorners());
- }
- public static BoundingSphere CreateFromPoints(IEnumerable<Vector3> points)
- {
- if (points == null )
- throw new ArgumentNullException("points");
- // From "Real-Time Collision Detection" (Page 89)
- var minx = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
- var maxx = -minx;
- var miny = minx;
- var maxy = -minx;
- var minz = minx;
- var maxz = -minx;
- // Find the most extreme points along the principle axis.
- var numPoints = 0;
- foreach (var pt in points)
- {
- ++numPoints;
- if (pt.X < minx.X)
- minx = pt;
- if (pt.X > maxx.X)
- maxx = pt;
- if (pt.Y < miny.Y)
- miny = pt;
- if (pt.Y > maxy.Y)
- maxy = pt;
- if (pt.Z < minz.Z)
- minz = pt;
- if (pt.Z > maxz.Z)
- maxz = pt;
- }
- if (numPoints == 0)
- throw new ArgumentException("You should have at least one point in points.");
- var sqDistX = Vector3.DistanceSquared(maxx, minx);
- var sqDistY = Vector3.DistanceSquared(maxy, miny);
- var sqDistZ = Vector3.DistanceSquared(maxz, minz);
- // Pick the pair of most distant points.
- var min = minx;
- var max = maxx;
- if (sqDistY > sqDistX && sqDistY > sqDistZ)
- {
- max = maxy;
- min = miny;
- }
- if (sqDistZ > sqDistX && sqDistZ > sqDistY)
- {
- max = maxz;
- min = minz;
- }
-
- var center = (min + max) * 0.5f;
- var radius = Vector3.Distance(max, center);
-
- // Test every point and expand the sphere.
- // The current bounding sphere is just a good approximation and may not enclose all points.
- // From: Mathematics for 3D Game Programming and Computer Graphics, Eric Lengyel, Third Edition.
- // Page 218
- float sqRadius = radius * radius;
- foreach (var pt in points)
- {
- Vector3 diff = (pt-center);
- float sqDist = diff.LengthSquared();
- if (sqDist > sqRadius)
- {
- float distance = (float)Math.Sqrt(sqDist); // equal to diff.Length();
- Vector3 direction = diff / distance;
- Vector3 G = center - radius * direction;
- center = (G + pt) / 2;
- radius = Vector3.Distance(pt, center);
- sqRadius = radius * radius;
- }
- }
- return new BoundingSphere(center, radius);
- }
- public static BoundingSphere CreateMerged(BoundingSphere original, BoundingSphere additional)
- {
- BoundingSphere result;
- CreateMerged(ref original, ref additional, out result);
- return result;
- }
- public static void CreateMerged(ref BoundingSphere original, ref BoundingSphere additional, out BoundingSphere result)
- {
- Vector3 ocenterToaCenter = Vector3.Subtract(additional.Center, original.Center);
- float distance = ocenterToaCenter.Length();
- if (distance <= original.Radius + additional.Radius)//intersect
- {
- if (distance <= original.Radius - additional.Radius)//original contain additional
- {
- result = original;
- return;
- }
- if (distance <= additional.Radius - original.Radius)//additional contain original
- {
- result = additional;
- return;
- }
- }
- //else find center of new sphere and radius
- float leftRadius = Math.Max(original.Radius - distance, additional.Radius);
- float Rightradius = Math.Max(original.Radius + distance, additional.Radius);
- ocenterToaCenter = ocenterToaCenter + (((leftRadius - Rightradius) / (2 * ocenterToaCenter.Length())) * ocenterToaCenter);//oCenterToResultCenter
- result = new BoundingSphere();
- result.Center = original.Center + ocenterToaCenter;
- result.Radius = (leftRadius + Rightradius) / 2;
- }
- public bool Equals(BoundingSphere other)
- {
- return this.Center == other.Center && this.Radius == other.Radius;
- }
- public override bool Equals(object obj)
- {
- if (obj is BoundingSphere)
- return this.Equals((BoundingSphere)obj);
- return false;
- }
- public override int GetHashCode()
- {
- return this.Center.GetHashCode() + this.Radius.GetHashCode();
- }
- public bool Intersects(BoundingBox box)
- {
- return box.Intersects(this);
- }
- public void Intersects(ref BoundingBox box, out bool result)
- {
- box.Intersects(ref this, out result);
- }
- /*
- public bool Intersects(BoundingFrustum frustum)
- {
- if (frustum == null)
- throw new NullReferenceException();
- throw new NotImplementedException();
- }
- */
- public bool Intersects(BoundingSphere sphere)
- {
- bool result;
- Intersects(ref sphere, out result);
- return result;
- }
- public void Intersects(ref BoundingSphere sphere, out bool result)
- {
- float sqDistance;
- Vector3.DistanceSquared(ref sphere.Center, ref Center, out sqDistance);
- if (sqDistance > (sphere.Radius + Radius) * (sphere.Radius + Radius))
- result = false;
- else
- result = true;
- }
- public PlaneIntersectionType Intersects(Plane plane)
- {
- var result = default(PlaneIntersectionType);
- // TODO: we might want to inline this for performance reasons
- this.Intersects(ref plane, out result);
- return result;
- }
- public void Intersects(ref Plane plane, out PlaneIntersectionType result)
- {
- var distance = default(float);
- // TODO: we might want to inline this for performance reasons
- Vector3.Dot(ref plane.Normal, ref this.Center, out distance);
- distance += plane.D;
- if (distance > this.Radius)
- result = PlaneIntersectionType.Front;
- else if (distance < -this.Radius)
- result = PlaneIntersectionType.Back;
- else
- result = PlaneIntersectionType.Intersecting;
- }
- public Nullable<float> Intersects(Ray ray)
- {
- return ray.Intersects(this);
- }
- public void Intersects(ref Ray ray, out Nullable<float> result)
- {
- ray.Intersects(ref this, out result);
- }
- public static bool operator == (BoundingSphere a, BoundingSphere b)
- {
- return a.Equals(b);
- }
- public static bool operator != (BoundingSphere a, BoundingSphere b)
- {
- return !a.Equals(b);
- }
- internal string DebugDisplayString
- {
- get
- {
- return string.Concat(
- "Pos( ", this.Center.DebugDisplayString, " ) \r\n",
- "Radius( ", this.Radius.ToString(), " )"
- );
- }
- }
- public override string ToString()
- {
- return "{{Center:" + this.Center.ToString() + " Radius:" + this.Radius.ToString() + "}}";
- }
- #endregion Public Methods
- }
- }
|