anx.framework/ANX.Framework/BoundingSphere.cs
Konstantin Koch 8287c54432 Included the Visual Studio extension and made the necessary changes to make it run.
Replaced the old VS templates with ones that offer more flexiblity.
Started replacing the Content Project for the samples with our custom project type.
Inlcuded a basic not yet working AssimpImporter.
2015-04-08 14:50:03 +02:00

463 lines
15 KiB
C#

#region Using Statements
using System;
using System.Collections.Generic;
using System.Globalization;
using ANX.Framework.NonXNA.Development;
using System.ComponentModel;
using ANX.Framework.Design;
#endregion // Using Statements
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ANX.Framework
{
[PercentageComplete(100)]
[Developer("xToast")]
[TestState(TestStateAttribute.TestState.InProgress)]
#if !WINDOWSMETRO
[Serializable]
[TypeConverter(typeof(BoundingSphereConverter))]
#endif
public struct BoundingSphere : IEquatable<BoundingSphere>
{
#region fields
public Vector3 Center;
public float Radius;
#endregion
#region constructors
public BoundingSphere(Vector3 center, float radius)
{
this.Center = center;
this.Radius = radius;
}
#endregion
#region public methods
public ContainmentType Contains(BoundingBox box)
{
ContainmentType result;
this.Contains(ref box, out result);
return result;
}
public void Contains(ref BoundingBox box, out ContainmentType result)
{
byte value = 0;
if (Vector3.DistanceSquared(box.Max, this.Center) < this.Radius * this.Radius)
{
value++;
}
if (Vector3.DistanceSquared(box.Min, this.Center) < this.Radius * this.Radius)
{
value++;
}
result = value == 0 ? ContainmentType.Disjoint : value == 1 ? ContainmentType.Intersects : ContainmentType.Contains;
}
public ContainmentType Contains(BoundingFrustum frustum)
{
Vector3[] points = frustum.GetCorners();
float radiusSquared = this.Radius * this.Radius;
byte pointsIn = 0;
for (int i = 0; i < BoundingFrustum.CornerCount; i++)
{
float distance = Vector3.DistanceSquared(points[i], this.Center);
if (distance > radiusSquared)
continue;
if (i != 0 && pointsIn == 0)
return ContainmentType.Intersects;
pointsIn++;
}
if (pointsIn == BoundingFrustum.CornerCount)
return ContainmentType.Contains;
return ContainmentType.Disjoint;
}
public ContainmentType Contains(BoundingSphere sphere)
{
ContainmentType result;
this.Contains(ref sphere, out result);
return result;
}
public void Contains(ref BoundingSphere sphere, out ContainmentType result)
{
float distance = Vector3.Distance(this.Center, sphere.Center);
float bothRadius = this.Radius + sphere.Radius;
if (distance > bothRadius)
{
result = ContainmentType.Disjoint;
return;
}
if (distance + sphere.Radius < this.Radius)
{
result = ContainmentType.Contains;
return;
}
result = ContainmentType.Intersects;
}
public ContainmentType Contains(Vector3 point)
{
ContainmentType result;
this.Contains(ref point, out result);
return result;
}
public void Contains(ref Vector3 point, out ContainmentType result)
{
float distance = Vector3.DistanceSquared(point, this.Center);
if (distance > this.Radius * this.Radius)
{
result = ContainmentType.Disjoint;
return;
}
else if (distance < this.Radius * this.Radius)
{
result = ContainmentType.Contains;
return;
}
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)
{
result.Center = new Vector3(
(box.Min.X + box.Max.X) * 0.5f,
(box.Min.Y + box.Max.Y) * 0.5f,
(box.Min.Z + box.Max.Z) * 0.5f);
result.Radius = Vector3.Distance(box.Min, result.Center);
}
public static BoundingSphere CreateFromFrustum(BoundingFrustum frustum)
{
return CreateFromPoints(frustum.GetCorners());
}
//source: monoxna
public static BoundingSphere CreateFromPoints(IEnumerable<Vector3> points)
{
if (points == null)
throw new ArgumentNullException("points");
float radius = 0;
Vector3 center = new Vector3();
// First, we'll find the center of gravity for the point 'cloud'.
int num_points = 0; // The number of points (there MUST be a better way to get this instead of counting the number of points one by one?)
foreach (Vector3 v in points)
{
center += v; // If we actually knew the number of points, we'd get better accuracy by adding v / num_points.
++num_points;
}
center /= (float)num_points;
// Calculate the radius of the needed sphere (it equals the distance between the center and the point further away).
foreach (Vector3 v in points)
{
float distance = ((Vector3)(v - center)).Length();
if (distance > radius)
radius = distance;
}
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)
{
float distance = Vector3.Distance(original.Center, additional.Center);
if (distance + additional.Radius < original.Radius)
{
result = original;
return;
}
distance = Vector3.Distance(additional.Center, original.Center);
if (distance + original.Radius < additional.Radius)
{
result = additional;
return;
}
Vector3 difference = Vector3.Subtract(additional.Center, original.Center);
difference.Normalize();
Vector3 additionalNew = additional.Center;
additionalNew.X += additional.Radius * difference.X;
additionalNew.Y += additional.Radius * difference.Y;
additionalNew.Z += additional.Radius * difference.Z;
Vector3 originalNew = original.Center;
originalNew.X -= original.Radius * difference.X;
originalNew.Y -= original.Radius * difference.Y;
originalNew.Z -= original.Radius * difference.Z;
difference = Vector3.Subtract(additionalNew, originalNew) / 2;
result = new BoundingSphere(difference, difference.Length());
}
public override int GetHashCode()
{
return this.Radius.GetHashCode() + this.Center.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 (Vector3.DistanceSquared(box.Max, this.Center) < this.Radius * this.Radius)
{
result = true;
return;
}
if (Vector3.DistanceSquared(box.Min, this.Center) < this.Radius * this.Radius)
{
result = true;
return;
}
result = false;
}
public bool Intersects(BoundingFrustum frustum)
{
Vector3[] points = frustum.GetCorners();
float radiusSquared = this.Radius * this.Radius;
for (int i = 0; i < BoundingFrustum.CornerCount; i++)
{
float distance = Vector3.DistanceSquared(points[i], this.Center);
if (distance > radiusSquared)
continue;
return true;
}
return false;
}
public bool Intersects(BoundingSphere sphere)
{
bool result;
Intersects(ref sphere, out result);
return result;
}
public void Intersects(ref BoundingSphere sphere, out bool result)
{
float distance = Vector3.Distance(this.Center, sphere.Center);
float bothRadius = this.Radius + sphere.Radius;
if (distance > bothRadius)
{
result = false;
return;
}
result = true;
}
public PlaneIntersectionType Intersects(Plane plane)
{
PlaneIntersectionType result;
Intersects(ref plane, out result);
return result;
}
// Source: monoxna
public void Intersects(ref Plane plane, out PlaneIntersectionType result)
{
float distance = Vector3.Dot(plane.Normal, this.Center) + plane.D;
if (distance > this.Radius)
{
result = PlaneIntersectionType.Front;
return;
}
if (distance < -this.Radius)
{
result = PlaneIntersectionType.Back;
return;
}
result = PlaneIntersectionType.Intersecting;
}
public Nullable<float> Intersects(Ray ray)
{
Nullable<float> result;
Intersects(ref ray, out result);
return result;
}
// Method copied from and descriebed here:
// http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
public void Intersects(ref Ray ray, out Nullable<float> result)
{
//TODO: Find an other way, this one often is wrong!
float a;
Vector3.Dot(ref ray.Direction, ref ray.Direction, out a);
float b;
Vector3.Dot(ref ray.Direction, ref ray.Position, out b);
b += b;
float c;
Vector3.Dot(ref ray.Position, ref ray.Position, out c);
c -= Radius * Radius;
//Find discriminant
float disc = b * b - 4 * a * c;
// if discriminant is negative there are no real roots, so return
// false as ray misses sphere
if (disc < 0)
{
result = null;
return;
}
float distSqrt = (float)Math.Sqrt(disc);
float q;
if (b < 0)
q = (-b - distSqrt) / 2.0f;
else
q = (-b + distSqrt) / 2.0f;
// compute t0 and t1
float t0 = q / a;
float t1 = c / q;
// make sure t0 is smaller than t1
if (t0 > t1)
{
// if t0 is bigger than t1 swap them around
float temp = t0;
t0 = t1;
t1 = temp;
}
// if t1 is less than zero, the object is in the ray's negative direction
// and consequently the ray misses the sphere
if (t1 < 0)
{
result = null;
return;
}
// if t0 is less than zero, the intersection point is at t1
if (t0 < 0)
{
result = t1;
return;
}
// else the intersection point is at t0
else
{
//if (float.IsNaN(t0))
// result = null;
//else
// result = t0;
result = t0;
return;
}
}
public BoundingSphere Transform(Matrix matrix)
{
BoundingSphere result;
Transform(ref matrix, out result);
return result;
}
public void Transform(ref Matrix matrix, out BoundingSphere result)
{
result = this;
result.Radius += Math.Max(matrix.M11, Math.Max(matrix.M22, matrix.M33));
result.Center.X += matrix.M41;
result.Center.Y += matrix.M42;
result.Center.Z += matrix.M43;
}
#endregion
#region ToString
public override string ToString()
{
var culture = CultureInfo.CurrentCulture;
// This may look a bit more ugly, but String.Format should be avoided cause of it's bad performance!
return "{Center:" + Center.ToString() + " Radius:" + Radius.ToString(culture) + "}";
}
#endregion
#region IEquatable implementation
public override bool Equals(Object obj)
{
return obj is BoundingSphere && Equals((BoundingSphere)obj);
}
public bool Equals(BoundingSphere other)
{
return this.Center.Equals(other.Center) && this.Radius == other.Radius;
}
#endregion
#region operator overloading
public static bool operator ==(BoundingSphere a, BoundingSphere b)
{
return (a.Center.X == b.Center.X &&
a.Center.Y == b.Center.Y &&
a.Center.Z == b.Center.Z &&
a.Radius == b.Radius);
}
public static bool operator !=(BoundingSphere a, BoundingSphere b)
{
return (a.Center.X != b.Center.X ||
a.Center.Y != b.Center.Y ||
a.Center.Z != b.Center.Z ||
a.Radius != b.Radius);
}
#endregion
}
}