(61d00a474) v0.9.7.1

This commit is contained in:
Regalis
2020-03-04 13:04:10 +01:00
parent 3c50efa5c9
commit 3c09ebe02f
5086 changed files with 786063 additions and 295871 deletions

View File

@@ -0,0 +1,538 @@
// 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 Microsoft.Xna.Framework
{
[DataContract]
[DebuggerDisplay("{DebugDisplayString,nq}")]
public struct BoundingBox : IEquatable<BoundingBox>
{
#region Public Fields
[DataMember]
public Vector3 Min;
[DataMember]
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;
}
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() + "}}";
}
/// <summary>
/// Deconstruction method for <see cref="BoundingBox"/>.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public void Deconstruct(out Vector3 min, out Vector3 max)
{
min = Min;
max = Max;
}
#endregion Public Methods
}
}

View File

@@ -0,0 +1,578 @@
// 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.Diagnostics;
namespace Microsoft.Xna.Framework
{
/// <summary>
/// Defines a viewing frustum for intersection operations.
/// </summary>
[DebuggerDisplay("{DebugDisplayString,nq}")]
public class BoundingFrustum : IEquatable<BoundingFrustum>
{
#region Private Fields
private Matrix _matrix;
private readonly Vector3[] _corners = new Vector3[CornerCount];
private readonly Plane[] _planes = new Plane[PlaneCount];
#endregion
#region Public Fields
/// <summary>
/// The number of planes in the frustum.
/// </summary>
public const int PlaneCount = 6;
/// <summary>
/// The number of corner points in the frustum.
/// </summary>
public const int CornerCount = 8;
#endregion
#region Properties
/// <summary>
/// Gets or sets the <see cref="Matrix"/> of the frustum.
/// </summary>
public Matrix Matrix
{
get { return this._matrix; }
set
{
this._matrix = value;
this.CreatePlanes(); // FIXME: The odds are the planes will be used a lot more often than the matrix
this.CreateCorners(); // is updated, so this should help performance. I hope ;)
}
}
/// <summary>
/// Gets the near plane of the frustum.
/// </summary>
public Plane Near
{
get { return this._planes[0]; }
}
/// <summary>
/// Gets the far plane of the frustum.
/// </summary>
public Plane Far
{
get { return this._planes[1]; }
}
/// <summary>
/// Gets the left plane of the frustum.
/// </summary>
public Plane Left
{
get { return this._planes[2]; }
}
/// <summary>
/// Gets the right plane of the frustum.
/// </summary>
public Plane Right
{
get { return this._planes[3]; }
}
/// <summary>
/// Gets the top plane of the frustum.
/// </summary>
public Plane Top
{
get { return this._planes[4]; }
}
/// <summary>
/// Gets the bottom plane of the frustum.
/// </summary>
public Plane Bottom
{
get { return this._planes[5]; }
}
#endregion
#region Internal Properties
internal string DebugDisplayString
{
get
{
return string.Concat(
"Near( ", this._planes[0].DebugDisplayString, " ) \r\n",
"Far( ", this._planes[1].DebugDisplayString, " ) \r\n",
"Left( ", this._planes[2].DebugDisplayString, " ) \r\n",
"Right( ", this._planes[3].DebugDisplayString, " ) \r\n",
"Top( ", this._planes[4].DebugDisplayString, " ) \r\n",
"Bottom( ", this._planes[5].DebugDisplayString, " ) "
);
}
}
#endregion
#region Constructors
/// <summary>
/// Constructs the frustum by extracting the view planes from a matrix.
/// </summary>
/// <param name="value">Combined matrix which usually is (View * Projection).</param>
public BoundingFrustum(Matrix value)
{
this._matrix = value;
this.CreatePlanes();
this.CreateCorners();
}
#endregion
#region Operators
/// <summary>
/// Compares whether two <see cref="BoundingFrustum"/> instances are equal.
/// </summary>
/// <param name="a"><see cref="BoundingFrustum"/> instance on the left of the equal sign.</param>
/// <param name="b"><see cref="BoundingFrustum"/> instance on the right of the equal sign.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public static bool operator ==(BoundingFrustum a, BoundingFrustum b)
{
if (Equals(a, null))
return (Equals(b, null));
if (Equals(b, null))
return (Equals(a, null));
return a._matrix == (b._matrix);
}
/// <summary>
/// Compares whether two <see cref="BoundingFrustum"/> instances are not equal.
/// </summary>
/// <param name="a"><see cref="BoundingFrustum"/> instance on the left of the not equal sign.</param>
/// <param name="b"><see cref="BoundingFrustum"/> instance on the right of the not equal sign.</param>
/// <returns><c>true</c> if the instances are not equal; <c>false</c> otherwise.</returns>
public static bool operator !=(BoundingFrustum a, BoundingFrustum b)
{
return !(a == b);
}
#endregion
#region Public Methods
#region Contains
/// <summary>
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingBox"/>.
/// </summary>
/// <param name="box">A <see cref="BoundingBox"/> for testing.</param>
/// <returns>Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingBox"/>.</returns>
public ContainmentType Contains(BoundingBox box)
{
var result = default(ContainmentType);
this.Contains(ref box, out result);
return result;
}
/// <summary>
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingBox"/>.
/// </summary>
/// <param name="box">A <see cref="BoundingBox"/> for testing.</param>
/// <param name="result">Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingBox"/> as an output parameter.</param>
public void Contains(ref BoundingBox box, out ContainmentType result)
{
var intersects = false;
for (var i = 0; i < PlaneCount; ++i)
{
var planeIntersectionType = default(PlaneIntersectionType);
box.Intersects(ref this._planes[i], out planeIntersectionType);
switch (planeIntersectionType)
{
case PlaneIntersectionType.Front:
result = ContainmentType.Disjoint;
return;
case PlaneIntersectionType.Intersecting:
intersects = true;
break;
}
}
result = intersects ? ContainmentType.Intersects : ContainmentType.Contains;
}
/// <summary>
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="frustum">A <see cref="BoundingFrustum"/> for testing.</param>
/// <returns>Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingFrustum"/>.</returns>
public ContainmentType Contains(BoundingFrustum frustum)
{
if (this == frustum) // We check to see if the two frustums are equal
return ContainmentType.Contains;// If they are, there's no need to go any further.
var intersects = false;
for (var i = 0; i < PlaneCount; ++i)
{
PlaneIntersectionType planeIntersectionType;
frustum.Intersects(ref _planes[i], out planeIntersectionType);
switch (planeIntersectionType)
{
case PlaneIntersectionType.Front:
return ContainmentType.Disjoint;
case PlaneIntersectionType.Intersecting:
intersects = true;
break;
}
}
return intersects ? ContainmentType.Intersects : ContainmentType.Contains;
}
/// <summary>
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingSphere"/>.
/// </summary>
/// <param name="sphere">A <see cref="BoundingSphere"/> for testing.</param>
/// <returns>Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingSphere"/>.</returns>
public ContainmentType Contains(BoundingSphere sphere)
{
var result = default(ContainmentType);
this.Contains(ref sphere, out result);
return result;
}
/// <summary>
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingSphere"/>.
/// </summary>
/// <param name="sphere">A <see cref="BoundingSphere"/> for testing.</param>
/// <param name="result">Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="BoundingSphere"/> as an output parameter.</param>
public void Contains(ref BoundingSphere sphere, out ContainmentType result)
{
var intersects = false;
for (var i = 0; i < PlaneCount; ++i)
{
var planeIntersectionType = default(PlaneIntersectionType);
// TODO: we might want to inline this for performance reasons
sphere.Intersects(ref this._planes[i], out planeIntersectionType);
switch (planeIntersectionType)
{
case PlaneIntersectionType.Front:
result = ContainmentType.Disjoint;
return;
case PlaneIntersectionType.Intersecting:
intersects = true;
break;
}
}
result = intersects ? ContainmentType.Intersects : ContainmentType.Contains;
}
/// <summary>
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="Vector3"/>.
/// </summary>
/// <param name="point">A <see cref="Vector3"/> for testing.</param>
/// <returns>Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="Vector3"/>.</returns>
public ContainmentType Contains(Vector3 point)
{
var result = default(ContainmentType);
this.Contains(ref point, out result);
return result;
}
/// <summary>
/// Containment test between this <see cref="BoundingFrustum"/> and specified <see cref="Vector3"/>.
/// </summary>
/// <param name="point">A <see cref="Vector3"/> for testing.</param>
/// <param name="result">Result of testing for containment between this <see cref="BoundingFrustum"/> and specified <see cref="Vector3"/> as an output parameter.</param>
public void Contains(ref Vector3 point, out ContainmentType result)
{
for (var i = 0; i < PlaneCount; ++i)
{
// TODO: we might want to inline this for performance reasons
if (PlaneHelper.ClassifyPoint(ref point, ref this._planes[i]) > 0)
{
result = ContainmentType.Disjoint;
return;
}
}
result = ContainmentType.Contains;
}
#endregion
/// <summary>
/// Compares whether current instance is equal to specified <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="other">The <see cref="BoundingFrustum"/> to compare.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public bool Equals(BoundingFrustum other)
{
return (this == other);
}
/// <summary>
/// Compares whether current instance is equal to specified <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="obj">The <see cref="Object"/> to compare.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public override bool Equals(object obj)
{
return (obj is BoundingFrustum) && this == ((BoundingFrustum)obj);
}
/// <summary>
/// Returns a copy of internal corners array.
/// </summary>
/// <returns>The array of corners.</returns>
public Vector3[] GetCorners()
{
return (Vector3[])this._corners.Clone();
}
/// <summary>
/// Returns a copy of internal corners array.
/// </summary>
/// <param name="corners">The array which values will be replaced to corner values of this instance. It must have size of <see cref="BoundingFrustum.CornerCount"/>.</param>
public void GetCorners(Vector3[] corners)
{
if (corners == null) throw new ArgumentNullException("corners");
if (corners.Length < CornerCount) throw new ArgumentOutOfRangeException("corners");
this._corners.CopyTo(corners, 0);
}
/// <summary>
/// Gets the hash code of this <see cref="BoundingFrustum"/>.
/// </summary>
/// <returns>Hash code of this <see cref="BoundingFrustum"/>.</returns>
public override int GetHashCode()
{
return this._matrix.GetHashCode();
}
/// <summary>
/// Gets whether or not a specified <see cref="BoundingBox"/> intersects with this <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="box">A <see cref="BoundingBox"/> for intersection test.</param>
/// <returns><c>true</c> if specified <see cref="BoundingBox"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise.</returns>
public bool Intersects(BoundingBox box)
{
var result = false;
this.Intersects(ref box, out result);
return result;
}
/// <summary>
/// Gets whether or not a specified <see cref="BoundingBox"/> intersects with this <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="box">A <see cref="BoundingBox"/> for intersection test.</param>
/// <param name="result"><c>true</c> if specified <see cref="BoundingBox"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise as an output parameter.</param>
public void Intersects(ref BoundingBox box, out bool result)
{
var containment = default(ContainmentType);
this.Contains(ref box, out containment);
result = containment != ContainmentType.Disjoint;
}
/// <summary>
/// Gets whether or not a specified <see cref="BoundingFrustum"/> intersects with this <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="frustum">An other <see cref="BoundingFrustum"/> for intersection test.</param>
/// <returns><c>true</c> if other <see cref="BoundingFrustum"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise.</returns>
public bool Intersects(BoundingFrustum frustum)
{
return Contains(frustum) != ContainmentType.Disjoint;
}
/// <summary>
/// Gets whether or not a specified <see cref="BoundingSphere"/> intersects with this <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="sphere">A <see cref="BoundingSphere"/> for intersection test.</param>
/// <returns><c>true</c> if specified <see cref="BoundingSphere"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise.</returns>
public bool Intersects(BoundingSphere sphere)
{
var result = default(bool);
this.Intersects(ref sphere, out result);
return result;
}
/// <summary>
/// Gets whether or not a specified <see cref="BoundingSphere"/> intersects with this <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="sphere">A <see cref="BoundingSphere"/> for intersection test.</param>
/// <param name="result"><c>true</c> if specified <see cref="BoundingSphere"/> intersects with this <see cref="BoundingFrustum"/>; <c>false</c> otherwise as an output parameter.</param>
public void Intersects(ref BoundingSphere sphere, out bool result)
{
var containment = default(ContainmentType);
this.Contains(ref sphere, out containment);
result = containment != ContainmentType.Disjoint;
}
/// <summary>
/// Gets type of intersection between specified <see cref="Plane"/> and this <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="plane">A <see cref="Plane"/> for intersection test.</param>
/// <returns>A plane intersection type.</returns>
public PlaneIntersectionType Intersects(Plane plane)
{
PlaneIntersectionType result;
Intersects(ref plane, out result);
return result;
}
/// <summary>
/// Gets type of intersection between specified <see cref="Plane"/> and this <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="plane">A <see cref="Plane"/> for intersection test.</param>
/// <param name="result">A plane intersection type as an output parameter.</param>
public void Intersects(ref Plane plane, out PlaneIntersectionType result)
{
result = plane.Intersects(ref _corners[0]);
for (int i = 1; i < _corners.Length; i++)
if (plane.Intersects(ref _corners[i]) != result)
result = PlaneIntersectionType.Intersecting;
}
/// <summary>
/// Gets the distance of intersection of <see cref="Ray"/> and this <see cref="BoundingFrustum"/> or null if no intersection happens.
/// </summary>
/// <param name="ray">A <see cref="Ray"/> for intersection test.</param>
/// <returns>Distance at which ray intersects with this <see cref="BoundingFrustum"/> or null if no intersection happens.</returns>
public float? Intersects(Ray ray)
{
float? result;
Intersects(ref ray, out result);
return result;
}
/// <summary>
/// Gets the distance of intersection of <see cref="Ray"/> and this <see cref="BoundingFrustum"/> or null if no intersection happens.
/// </summary>
/// <param name="ray">A <see cref="Ray"/> for intersection test.</param>
/// <param name="result">Distance at which ray intersects with this <see cref="BoundingFrustum"/> or null if no intersection happens as an output parameter.</param>
public void Intersects(ref Ray ray, out float? result)
{
ContainmentType ctype;
this.Contains(ref ray.Position, out ctype);
switch (ctype)
{
case ContainmentType.Disjoint:
result = null;
return;
case ContainmentType.Contains:
result = 0.0f;
return;
case ContainmentType.Intersects:
throw new NotImplementedException();
default:
throw new ArgumentOutOfRangeException();
}
}
/// <summary>
/// Returns a <see cref="String"/> representation of this <see cref="BoundingFrustum"/> in the format:
/// {Near:[nearPlane] Far:[farPlane] Left:[leftPlane] Right:[rightPlane] Top:[topPlane] Bottom:[bottomPlane]}
/// </summary>
/// <returns><see cref="String"/> representation of this <see cref="BoundingFrustum"/>.</returns>
public override string ToString()
{
return "{Near: " + this._planes[0] +
" Far:" + this._planes[1] +
" Left:" + this._planes[2] +
" Right:" + this._planes[3] +
" Top:" + this._planes[4] +
" Bottom:" + this._planes[5] +
"}";
}
#endregion
#region Private Methods
private void CreateCorners()
{
IntersectionPoint(ref this._planes[0], ref this._planes[2], ref this._planes[4], out this._corners[0]);
IntersectionPoint(ref this._planes[0], ref this._planes[3], ref this._planes[4], out this._corners[1]);
IntersectionPoint(ref this._planes[0], ref this._planes[3], ref this._planes[5], out this._corners[2]);
IntersectionPoint(ref this._planes[0], ref this._planes[2], ref this._planes[5], out this._corners[3]);
IntersectionPoint(ref this._planes[1], ref this._planes[2], ref this._planes[4], out this._corners[4]);
IntersectionPoint(ref this._planes[1], ref this._planes[3], ref this._planes[4], out this._corners[5]);
IntersectionPoint(ref this._planes[1], ref this._planes[3], ref this._planes[5], out this._corners[6]);
IntersectionPoint(ref this._planes[1], ref this._planes[2], ref this._planes[5], out this._corners[7]);
}
private void CreatePlanes()
{
this._planes[0] = new Plane(-this._matrix.M13, -this._matrix.M23, -this._matrix.M33, -this._matrix.M43);
this._planes[1] = new Plane(this._matrix.M13 - this._matrix.M14, this._matrix.M23 - this._matrix.M24, this._matrix.M33 - this._matrix.M34, this._matrix.M43 - this._matrix.M44);
this._planes[2] = new Plane(-this._matrix.M14 - this._matrix.M11, -this._matrix.M24 - this._matrix.M21, -this._matrix.M34 - this._matrix.M31, -this._matrix.M44 - this._matrix.M41);
this._planes[3] = new Plane(this._matrix.M11 - this._matrix.M14, this._matrix.M21 - this._matrix.M24, this._matrix.M31 - this._matrix.M34, this._matrix.M41 - this._matrix.M44);
this._planes[4] = new Plane(this._matrix.M12 - this._matrix.M14, this._matrix.M22 - this._matrix.M24, this._matrix.M32 - this._matrix.M34, this._matrix.M42 - this._matrix.M44);
this._planes[5] = new Plane(-this._matrix.M14 - this._matrix.M12, -this._matrix.M24 - this._matrix.M22, -this._matrix.M34 - this._matrix.M32, -this._matrix.M44 - this._matrix.M42);
this.NormalizePlane(ref this._planes[0]);
this.NormalizePlane(ref this._planes[1]);
this.NormalizePlane(ref this._planes[2]);
this.NormalizePlane(ref this._planes[3]);
this.NormalizePlane(ref this._planes[4]);
this.NormalizePlane(ref this._planes[5]);
}
private static void IntersectionPoint(ref Plane a, ref Plane b, ref Plane c, out Vector3 result)
{
// Formula used
// d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 )
//P = -------------------------------------------------------------------------
// N1 . ( N2 * N3 )
//
// Note: N refers to the normal, d refers to the displacement. '.' means dot product. '*' means cross product
Vector3 v1, v2, v3;
Vector3 cross;
Vector3.Cross(ref b.Normal, ref c.Normal, out cross);
float f;
Vector3.Dot(ref a.Normal, ref cross, out f);
f *= -1.0f;
Vector3.Cross(ref b.Normal, ref c.Normal, out cross);
Vector3.Multiply(ref cross, a.D, out v1);
//v1 = (a.D * (Vector3.Cross(b.Normal, c.Normal)));
Vector3.Cross(ref c.Normal, ref a.Normal, out cross);
Vector3.Multiply(ref cross, b.D, out v2);
//v2 = (b.D * (Vector3.Cross(c.Normal, a.Normal)));
Vector3.Cross(ref a.Normal, ref b.Normal, out cross);
Vector3.Multiply(ref cross, c.D, out v3);
//v3 = (c.D * (Vector3.Cross(a.Normal, b.Normal)));
result.X = (v1.X + v2.X + v3.X) / f;
result.Y = (v1.Y + v2.Y + v3.Y) / f;
result.Z = (v1.Z + v2.Z + v3.Z) / f;
}
private void NormalizePlane(ref Plane p)
{
float factor = 1f / p.Normal.Length();
p.Normal.X *= factor;
p.Normal.Y *= factor;
p.Normal.Z *= factor;
p.D *= factor;
}
#endregion
}
}

View File

@@ -0,0 +1,640 @@
// 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 Microsoft.Xna.Framework
{
/// <summary>
/// Describes a sphere in 3D-space for bounding operations.
/// </summary>
[DataContract]
[DebuggerDisplay("{DebugDisplayString,nq}")]
public struct BoundingSphere : IEquatable<BoundingSphere>
{
#region Public Fields
/// <summary>
/// The sphere center.
/// </summary>
[DataMember]
public Vector3 Center;
/// <summary>
/// The sphere radius.
/// </summary>
[DataMember]
public float Radius;
#endregion
#region Internal Properties
internal string DebugDisplayString
{
get
{
return string.Concat(
"Center( ", this.Center.DebugDisplayString, " ) \r\n",
"Radius( ", this.Radius.ToString(), " )"
);
}
}
#endregion
#region Constructors
/// <summary>
/// Constructs a bounding sphere with the specified center and radius.
/// </summary>
/// <param name="center">The sphere center.</param>
/// <param name="radius">The sphere radius.</param>
public BoundingSphere(Vector3 center, float radius)
{
this.Center = center;
this.Radius = radius;
}
#endregion
#region Public Methods
#region Contains
/// <summary>
/// Test if a bounding box is fully inside, outside, or just intersecting the sphere.
/// </summary>
/// <param name="box">The box for testing.</param>
/// <returns>The containment type.</returns>
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;
}
/// <summary>
/// Test if a bounding box is fully inside, outside, or just intersecting the sphere.
/// </summary>
/// <param name="box">The box for testing.</param>
/// <param name="result">The containment type as an output parameter.</param>
public void Contains(ref BoundingBox box, out ContainmentType result)
{
result = this.Contains(box);
}
/// <summary>
/// Test if a frustum is fully inside, outside, or just intersecting the sphere.
/// </summary>
/// <param name="frustum">The frustum for testing.</param>
/// <returns>The containment type.</returns>
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;
}
/// <summary>
/// Test if a frustum is fully inside, outside, or just intersecting the sphere.
/// </summary>
/// <param name="frustum">The frustum for testing.</param>
/// <param name="result">The containment type as an output parameter.</param>
public void Contains(ref BoundingFrustum frustum,out ContainmentType result)
{
result = this.Contains(frustum);
}
/// <summary>
/// Test if a sphere is fully inside, outside, or just intersecting the sphere.
/// </summary>
/// <param name="sphere">The other sphere for testing.</param>
/// <returns>The containment type.</returns>
public ContainmentType Contains(BoundingSphere sphere)
{
ContainmentType result;
Contains(ref sphere, out result);
return result;
}
/// <summary>
/// Test if a sphere is fully inside, outside, or just intersecting the sphere.
/// </summary>
/// <param name="sphere">The other sphere for testing.</param>
/// <param name="result">The containment type as an output parameter.</param>
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;
}
/// <summary>
/// Test if a point is fully inside, outside, or just intersecting the sphere.
/// </summary>
/// <param name="point">The vector in 3D-space for testing.</param>
/// <returns>The containment type.</returns>
public ContainmentType Contains(Vector3 point)
{
ContainmentType result;
Contains(ref point, out result);
return result;
}
/// <summary>
/// Test if a point is fully inside, outside, or just intersecting the sphere.
/// </summary>
/// <param name="point">The vector in 3D-space for testing.</param>
/// <param name="result">The containment type as an output parameter.</param>
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;
}
#endregion
#region CreateFromBoundingBox
/// <summary>
/// Creates the smallest <see cref="BoundingSphere"/> that can contain a specified <see cref="BoundingBox"/>.
/// </summary>
/// <param name="box">The box to create the sphere from.</param>
/// <returns>The new <see cref="BoundingSphere"/>.</returns>
public static BoundingSphere CreateFromBoundingBox(BoundingBox box)
{
BoundingSphere result;
CreateFromBoundingBox(ref box, out result);
return result;
}
/// <summary>
/// Creates the smallest <see cref="BoundingSphere"/> that can contain a specified <see cref="BoundingBox"/>.
/// </summary>
/// <param name="box">The box to create the sphere from.</param>
/// <param name="result">The new <see cref="BoundingSphere"/> as an output parameter.</param>
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);
}
#endregion
/// <summary>
/// Creates the smallest <see cref="BoundingSphere"/> that can contain a specified <see cref="BoundingFrustum"/>.
/// </summary>
/// <param name="frustum">The frustum to create the sphere from.</param>
/// <returns>The new <see cref="BoundingSphere"/>.</returns>
public static BoundingSphere CreateFromFrustum(BoundingFrustum frustum)
{
return CreateFromPoints(frustum.GetCorners());
}
/// <summary>
/// Creates the smallest <see cref="BoundingSphere"/> that can contain a specified list of points in 3D-space.
/// </summary>
/// <param name="points">List of point to create the sphere from.</param>
/// <returns>The new <see cref="BoundingSphere"/>.</returns>
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);
}
/// <summary>
/// Creates the smallest <see cref="BoundingSphere"/> that can contain two spheres.
/// </summary>
/// <param name="original">First sphere.</param>
/// <param name="additional">Second sphere.</param>
/// <returns>The new <see cref="BoundingSphere"/>.</returns>
public static BoundingSphere CreateMerged(BoundingSphere original, BoundingSphere additional)
{
BoundingSphere result;
CreateMerged(ref original, ref additional, out result);
return result;
}
/// <summary>
/// Creates the smallest <see cref="BoundingSphere"/> that can contain two spheres.
/// </summary>
/// <param name="original">First sphere.</param>
/// <param name="additional">Second sphere.</param>
/// <param name="result">The new <see cref="BoundingSphere"/> as an output parameter.</param>
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;
}
/// <summary>
/// Compares whether current instance is equal to specified <see cref="BoundingSphere"/>.
/// </summary>
/// <param name="other">The <see cref="BoundingSphere"/> to compare.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public bool Equals(BoundingSphere other)
{
return this.Center == other.Center && this.Radius == other.Radius;
}
/// <summary>
/// Compares whether current instance is equal to specified <see cref="Object"/>.
/// </summary>
/// <param name="obj">The <see cref="Object"/> to compare.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public override bool Equals(object obj)
{
if (obj is BoundingSphere)
return this.Equals((BoundingSphere)obj);
return false;
}
/// <summary>
/// Gets the hash code of this <see cref="BoundingSphere"/>.
/// </summary>
/// <returns>Hash code of this <see cref="BoundingSphere"/>.</returns>
public override int GetHashCode()
{
return this.Center.GetHashCode() + this.Radius.GetHashCode();
}
#region Intersects
/// <summary>
/// Gets whether or not a specified <see cref="BoundingBox"/> intersects with this sphere.
/// </summary>
/// <param name="box">The box for testing.</param>
/// <returns><c>true</c> if <see cref="BoundingBox"/> intersects with this sphere; <c>false</c> otherwise.</returns>
public bool Intersects(BoundingBox box)
{
return box.Intersects(this);
}
/// <summary>
/// Gets whether or not a specified <see cref="BoundingBox"/> intersects with this sphere.
/// </summary>
/// <param name="box">The box for testing.</param>
/// <param name="result"><c>true</c> if <see cref="BoundingBox"/> intersects with this sphere; <c>false</c> otherwise. As an output parameter.</param>
public void Intersects(ref BoundingBox box, out bool result)
{
box.Intersects(ref this, out result);
}
/*
TODO : Make the public bool Intersects(BoundingFrustum frustum) overload
public bool Intersects(BoundingFrustum frustum)
{
if (frustum == null)
throw new NullReferenceException();
throw new NotImplementedException();
}
*/
/// <summary>
/// Gets whether or not the other <see cref="BoundingSphere"/> intersects with this sphere.
/// </summary>
/// <param name="sphere">The other sphere for testing.</param>
/// <returns><c>true</c> if other <see cref="BoundingSphere"/> intersects with this sphere; <c>false</c> otherwise.</returns>
public bool Intersects(BoundingSphere sphere)
{
bool result;
Intersects(ref sphere, out result);
return result;
}
/// <summary>
/// Gets whether or not the other <see cref="BoundingSphere"/> intersects with this sphere.
/// </summary>
/// <param name="sphere">The other sphere for testing.</param>
/// <param name="result"><c>true</c> if other <see cref="BoundingSphere"/> intersects with this sphere; <c>false</c> otherwise. As an output parameter.</param>
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;
}
/// <summary>
/// Gets whether or not a specified <see cref="Plane"/> intersects with this sphere.
/// </summary>
/// <param name="plane">The plane for testing.</param>
/// <returns>Type of intersection.</returns>
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;
}
/// <summary>
/// Gets whether or not a specified <see cref="Plane"/> intersects with this sphere.
/// </summary>
/// <param name="plane">The plane for testing.</param>
/// <param name="result">Type of intersection as an output parameter.</param>
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;
}
/// <summary>
/// Gets whether or not a specified <see cref="Ray"/> intersects with this sphere.
/// </summary>
/// <param name="ray">The ray for testing.</param>
/// <returns>Distance of ray intersection or <c>null</c> if there is no intersection.</returns>
public float? Intersects(Ray ray)
{
return ray.Intersects(this);
}
/// <summary>
/// Gets whether or not a specified <see cref="Ray"/> intersects with this sphere.
/// </summary>
/// <param name="ray">The ray for testing.</param>
/// <param name="result">Distance of ray intersection or <c>null</c> if there is no intersection as an output parameter.</param>
public void Intersects(ref Ray ray, out float? result)
{
ray.Intersects(ref this, out result);
}
#endregion
/// <summary>
/// Returns a <see cref="String"/> representation of this <see cref="BoundingSphere"/> in the format:
/// {Center:[<see cref="Center"/>] Radius:[<see cref="Radius"/>]}
/// </summary>
/// <returns>A <see cref="String"/> representation of this <see cref="BoundingSphere"/>.</returns>
public override string ToString()
{
return "{Center:" + this.Center + " Radius:" + this.Radius + "}";
}
#region Transform
/// <summary>
/// Creates a new <see cref="BoundingSphere"/> that contains a transformation of translation and scale from this sphere by the specified <see cref="Matrix"/>.
/// </summary>
/// <param name="matrix">The transformation <see cref="Matrix"/>.</param>
/// <returns>Transformed <see cref="BoundingSphere"/>.</returns>
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;
}
/// <summary>
/// Creates a new <see cref="BoundingSphere"/> that contains a transformation of translation and scale from this sphere by the specified <see cref="Matrix"/>.
/// </summary>
/// <param name="matrix">The transformation <see cref="Matrix"/>.</param>
/// <param name="result">Transformed <see cref="BoundingSphere"/> as an output parameter.</param>
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)))));
}
#endregion
/// <summary>
/// Deconstruction method for <see cref="BoundingSphere"/>.
/// </summary>
/// <param name="center"></param>
/// <param name="radius"></param>
public void Deconstruct(out Vector3 center, out float radius)
{
center = Center;
radius = Radius;
}
#endregion
#region Operators
/// <summary>
/// Compares whether two <see cref="BoundingSphere"/> instances are equal.
/// </summary>
/// <param name="a"><see cref="BoundingSphere"/> instance on the left of the equal sign.</param>
/// <param name="b"><see cref="BoundingSphere"/> instance on the right of the equal sign.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public static bool operator == (BoundingSphere a, BoundingSphere b)
{
return a.Equals(b);
}
/// <summary>
/// Compares whether two <see cref="BoundingSphere"/> instances are not equal.
/// </summary>
/// <param name="a"><see cref="BoundingSphere"/> instance on the left of the not equal sign.</param>
/// <param name="b"><see cref="BoundingSphere"/> instance on the right of the not equal sign.</param>
/// <returns><c>true</c> if the instances are not equal; <c>false</c> otherwise.</returns>
public static bool operator != (BoundingSphere a, BoundingSphere b)
{
return !a.Equals(b);
}
#endregion
}
}

1821
Libraries/XNATypes/Color.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
// 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.
namespace Microsoft.Xna.Framework
{
/// <summary>
/// Defines how the bounding volumes intersects or contain one another.
/// </summary>
public enum ContainmentType
{
/// <summary>
/// Indicates that there is no overlap between two bounding volumes.
/// </summary>
Disjoint,
/// <summary>
/// Indicates that one bounding volume completely contains another volume.
/// </summary>
Contains,
/// <summary>
/// Indicates that bounding volumes partially overlap one another.
/// </summary>
Intersects
}
}

View File

@@ -0,0 +1,320 @@
// 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;
namespace Microsoft.Xna.Framework
{
/// <summary>
/// Contains commonly used precalculated values and mathematical operations.
/// </summary>
public static class MathHelper
{
/// <summary>
/// Represents the mathematical constant e(2.71828175).
/// </summary>
public const float E = (float)Math.E;
/// <summary>
/// Represents the log base ten of e(0.4342945).
/// </summary>
public const float Log10E = 0.4342945f;
/// <summary>
/// Represents the log base two of e(1.442695).
/// </summary>
public const float Log2E = 1.442695f;
/// <summary>
/// Represents the value of pi(3.14159274).
/// </summary>
public const float Pi = (float)Math.PI;
/// <summary>
/// Represents the value of pi divided by two(1.57079637).
/// </summary>
public const float PiOver2 = (float)(Math.PI / 2.0);
/// <summary>
/// Represents the value of pi divided by four(0.7853982).
/// </summary>
public const float PiOver4 = (float)(Math.PI / 4.0);
/// <summary>
/// Represents the value of pi times two(6.28318548).
/// </summary>
public const float TwoPi = (float)(Math.PI * 2.0);
/// <summary>
/// Returns the Cartesian coordinate for one axis of a point that is defined by a given triangle and two normalized barycentric (areal) coordinates.
/// </summary>
/// <param name="value1">The coordinate on one axis of vertex 1 of the defining triangle.</param>
/// <param name="value2">The coordinate on the same axis of vertex 2 of the defining triangle.</param>
/// <param name="value3">The coordinate on the same axis of vertex 3 of the defining triangle.</param>
/// <param name="amount1">The normalized barycentric (areal) coordinate b2, equal to the weighting factor for vertex 2, the coordinate of which is specified in value2.</param>
/// <param name="amount2">The normalized barycentric (areal) coordinate b3, equal to the weighting factor for vertex 3, the coordinate of which is specified in value3.</param>
/// <returns>Cartesian coordinate of the specified point with respect to the axis being used.</returns>
public static float Barycentric(float value1, float value2, float value3, float amount1, float amount2)
{
return value1 + (value2 - value1) * amount1 + (value3 - value1) * amount2;
}
/// <summary>
/// Performs a Catmull-Rom interpolation using the specified positions.
/// </summary>
/// <param name="value1">The first position in the interpolation.</param>
/// <param name="value2">The second position in the interpolation.</param>
/// <param name="value3">The third position in the interpolation.</param>
/// <param name="value4">The fourth position in the interpolation.</param>
/// <param name="amount">Weighting factor.</param>
/// <returns>A position that is the result of the Catmull-Rom interpolation.</returns>
public static float CatmullRom(float value1, float value2, float value3, float value4, float amount)
{
// Using formula from http://www.mvps.org/directx/articles/catmull/
// Internally using doubles not to lose precission
double amountSquared = amount * amount;
double amountCubed = amountSquared * amount;
return (float)(0.5 * (2.0 * value2 +
(value3 - value1) * amount +
(2.0 * value1 - 5.0 * value2 + 4.0 * value3 - value4) * amountSquared +
(3.0 * value2 - value1 - 3.0 * value3 + value4) * amountCubed));
}
/// <summary>
/// Restricts a value to be within a specified range.
/// </summary>
/// <param name="value">The value to clamp.</param>
/// <param name="min">The minimum value. If <c>value</c> is less than <c>min</c>, <c>min</c> will be returned.</param>
/// <param name="max">The maximum value. If <c>value</c> is greater than <c>max</c>, <c>max</c> will be returned.</param>
/// <returns>The clamped value.</returns>
public static float Clamp(float value, float min, float max)
{
// First we check to see if we're greater than the max
value = (value > max) ? max : value;
// Then we check to see if we're less than the min.
value = (value < min) ? min : value;
// There's no check to see if min > max.
return value;
}
/// <summary>
/// Restricts a value to be within a specified range.
/// </summary>
/// <param name="value">The value to clamp.</param>
/// <param name="min">The minimum value. If <c>value</c> is less than <c>min</c>, <c>min</c> will be returned.</param>
/// <param name="max">The maximum value. If <c>value</c> is greater than <c>max</c>, <c>max</c> will be returned.</param>
/// <returns>The clamped value.</returns>
public static int Clamp(int value, int min, int max)
{
value = (value > max) ? max : value;
value = (value < min) ? min : value;
return value;
}
/// <summary>
/// Calculates the absolute value of the difference of two values.
/// </summary>
/// <param name="value1">Source value.</param>
/// <param name="value2">Source value.</param>
/// <returns>Distance between the two values.</returns>
public static float Distance(float value1, float value2)
{
return Math.Abs(value1 - value2);
}
/// <summary>
/// Performs a Hermite spline interpolation.
/// </summary>
/// <param name="value1">Source position.</param>
/// <param name="tangent1">Source tangent.</param>
/// <param name="value2">Source position.</param>
/// <param name="tangent2">Source tangent.</param>
/// <param name="amount">Weighting factor.</param>
/// <returns>The result of the Hermite spline interpolation.</returns>
public static float Hermite(float value1, float tangent1, float value2, float tangent2, float amount)
{
// All transformed to double not to lose precission
// Otherwise, for high numbers of param:amount the result is NaN instead of Infinity
double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result;
double sCubed = s * s * s;
double sSquared = s * s;
if (amount == 0f)
result = value1;
else if (amount == 1f)
result = value2;
else
result = (2 * v1 - 2 * v2 + t2 + t1) * sCubed +
(3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared +
t1 * s +
v1;
return (float)result;
}
/// <summary>
/// Linearly interpolates between two values.
/// </summary>
/// <param name="value1">Source value.</param>
/// <param name="value2">Destination value.</param>
/// <param name="amount">Value between 0 and 1 indicating the weight of value2.</param>
/// <returns>Interpolated value.</returns>
/// <remarks>This method performs the linear interpolation based on the following formula:
/// <code>value1 + (value2 - value1) * amount</code>.
/// Passing amount a value of 0 will cause value1 to be returned, a value of 1 will cause value2 to be returned.
/// See <see cref="MathHelper.LerpPrecise"/> for a less efficient version with more precision around edge cases.
/// </remarks>
public static float Lerp(float value1, float value2, float amount)
{
return value1 + (value2 - value1) * amount;
}
/// <summary>
/// Linearly interpolates between two values.
/// This method is a less efficient, more precise version of <see cref="MathHelper.Lerp"/>.
/// See remarks for more info.
/// </summary>
/// <param name="value1">Source value.</param>
/// <param name="value2">Destination value.</param>
/// <param name="amount">Value between 0 and 1 indicating the weight of value2.</param>
/// <returns>Interpolated value.</returns>
/// <remarks>This method performs the linear interpolation based on the following formula:
/// <code>((1 - amount) * value1) + (value2 * amount)</code>.
/// Passing amount a value of 0 will cause value1 to be returned, a value of 1 will cause value2 to be returned.
/// This method does not have the floating point precision issue that <see cref="MathHelper.Lerp"/> has.
/// i.e. If there is a big gap between value1 and value2 in magnitude (e.g. value1=10000000000000000, value2=1),
/// right at the edge of the interpolation range (amount=1), <see cref="MathHelper.Lerp"/> will return 0 (whereas it should return 1).
/// This also holds for value1=10^17, value2=10; value1=10^18,value2=10^2... so on.
/// For an in depth explanation of the issue, see below references:
/// Relevant Wikipedia Article: https://en.wikipedia.org/wiki/Linear_interpolation#Programming_language_support
/// Relevant StackOverflow Answer: http://stackoverflow.com/questions/4353525/floating-point-linear-interpolation#answer-23716956
/// </remarks>
public static float LerpPrecise(float value1, float value2, float amount)
{
return ((1 - amount) * value1) + (value2 * amount);
}
/// <summary>
/// Returns the greater of two values.
/// </summary>
/// <param name="value1">Source value.</param>
/// <param name="value2">Source value.</param>
/// <returns>The greater value.</returns>
public static float Max(float value1, float value2)
{
return value1 > value2 ? value1 : value2;
}
/// <summary>
/// Returns the greater of two values.
/// </summary>
/// <param name="value1">Source value.</param>
/// <param name="value2">Source value.</param>
/// <returns>The greater value.</returns>
public static int Max(int value1, int value2)
{
return value1 > value2 ? value1 : value2;
}
/// <summary>
/// Returns the lesser of two values.
/// </summary>
/// <param name="value1">Source value.</param>
/// <param name="value2">Source value.</param>
/// <returns>The lesser value.</returns>
public static float Min(float value1, float value2)
{
return value1 < value2 ? value1 : value2;
}
/// <summary>
/// Returns the lesser of two values.
/// </summary>
/// <param name="value1">Source value.</param>
/// <param name="value2">Source value.</param>
/// <returns>The lesser value.</returns>
public static int Min(int value1, int value2)
{
return value1 < value2 ? value1 : value2;
}
/// <summary>
/// Interpolates between two values using a cubic equation.
/// </summary>
/// <param name="value1">Source value.</param>
/// <param name="value2">Source value.</param>
/// <param name="amount">Weighting value.</param>
/// <returns>Interpolated value.</returns>
public static float SmoothStep(float value1, float value2, float amount)
{
// It is expected that 0 < amount < 1
// If amount < 0, return value1
// If amount > 1, return value2
float result = MathHelper.Clamp(amount, 0f, 1f);
result = MathHelper.Hermite(value1, 0f, value2, 0f, result);
return result;
}
/// <summary>
/// Converts radians to degrees.
/// </summary>
/// <param name="radians">The angle in radians.</param>
/// <returns>The angle in degrees.</returns>
/// <remarks>
/// This method uses double precission internally,
/// though it returns single float
/// Factor = 180 / pi
/// </remarks>
public static float ToDegrees(float radians)
{
return (float)(radians * 57.295779513082320876798154814105);
}
/// <summary>
/// Converts degrees to radians.
/// </summary>
/// <param name="degrees">The angle in degrees.</param>
/// <returns>The angle in radians.</returns>
/// <remarks>
/// This method uses double precission internally,
/// though it returns single float
/// Factor = pi / 180
/// </remarks>
public static float ToRadians(float degrees)
{
return (float)(degrees * 0.017453292519943295769236907684886);
}
/// <summary>
/// Reduces a given angle to a value between π and -π.
/// </summary>
/// <param name="angle">The angle to reduce, in radians.</param>
/// <returns>The new angle, in radians.</returns>
public static float WrapAngle(float angle)
{
if ((angle > -Pi) && (angle <= Pi))
return angle;
angle %= TwoPi;
if (angle <= -Pi)
return angle + TwoPi;
if (angle > Pi)
return angle - TwoPi;
return angle;
}
/// <summary>
/// Determines if value is powered by two.
/// </summary>
/// <param name="value">A value.</param>
/// <returns><c>true</c> if <c>value</c> is powered by two; otherwise <c>false</c>.</returns>
public static bool IsPowerOfTwo(int value)
{
return (value > 0) && ((value & (value - 1)) == 0);
}
}
}

2474
Libraries/XNATypes/Matrix.cs Normal file

File diff suppressed because it is too large Load Diff

296
Libraries/XNATypes/Plane.cs Normal file
View File

@@ -0,0 +1,296 @@
// 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.Diagnostics;
using System.Runtime.Serialization;
namespace Microsoft.Xna.Framework
{
internal class PlaneHelper
{
/// <summary>
/// Returns a value indicating what side (positive/negative) of a plane a point is
/// </summary>
/// <param name="point">The point to check with</param>
/// <param name="plane">The plane to check against</param>
/// <returns>Greater than zero if on the positive side, less than zero if on the negative size, 0 otherwise</returns>
public static float ClassifyPoint(ref Vector3 point, ref Plane plane)
{
return point.X * plane.Normal.X + point.Y * plane.Normal.Y + point.Z * plane.Normal.Z + plane.D;
}
/// <summary>
/// Returns the perpendicular distance from a point to a plane
/// </summary>
/// <param name="point">The point to check</param>
/// <param name="plane">The place to check</param>
/// <returns>The perpendicular distance from the point to the plane</returns>
public static float PerpendicularDistance(ref Vector3 point, ref Plane plane)
{
// dist = (ax + by + cz + d) / sqrt(a*a + b*b + c*c)
return (float)Math.Abs((plane.Normal.X * point.X + plane.Normal.Y * point.Y + plane.Normal.Z * point.Z)
/ Math.Sqrt(plane.Normal.X * plane.Normal.X + plane.Normal.Y * plane.Normal.Y + plane.Normal.Z * plane.Normal.Z));
}
}
[DataContract]
[DebuggerDisplay("{DebugDisplayString,nq}")]
public struct Plane : IEquatable<Plane>
{
#region Public Fields
[DataMember]
public float D;
[DataMember]
public Vector3 Normal;
#endregion Public Fields
#region Constructors
public Plane(Vector4 value)
: this(new Vector3(value.X, value.Y, value.Z), value.W)
{
}
public Plane(Vector3 normal, float d)
{
Normal = normal;
D = d;
}
public Plane(Vector3 a, Vector3 b, Vector3 c)
{
Vector3 ab = b - a;
Vector3 ac = c - a;
Vector3 cross = Vector3.Cross(ab, ac);
Vector3.Normalize(ref cross, out Normal);
D = -(Vector3.Dot(Normal, a));
}
public Plane(float a, float b, float c, float d)
: this(new Vector3(a, b, c), d)
{
}
#endregion Constructors
#region Public Methods
public float Dot(Vector4 value)
{
return ((((this.Normal.X * value.X) + (this.Normal.Y * value.Y)) + (this.Normal.Z * value.Z)) + (this.D * value.W));
}
public void Dot(ref Vector4 value, out float result)
{
result = (((this.Normal.X * value.X) + (this.Normal.Y * value.Y)) + (this.Normal.Z * value.Z)) + (this.D * value.W);
}
public float DotCoordinate(Vector3 value)
{
return ((((this.Normal.X * value.X) + (this.Normal.Y * value.Y)) + (this.Normal.Z * value.Z)) + this.D);
}
public void DotCoordinate(ref Vector3 value, out float result)
{
result = (((this.Normal.X * value.X) + (this.Normal.Y * value.Y)) + (this.Normal.Z * value.Z)) + this.D;
}
public float DotNormal(Vector3 value)
{
return (((this.Normal.X * value.X) + (this.Normal.Y * value.Y)) + (this.Normal.Z * value.Z));
}
public void DotNormal(ref Vector3 value, out float result)
{
result = ((this.Normal.X * value.X) + (this.Normal.Y * value.Y)) + (this.Normal.Z * value.Z);
}
/// <summary>
/// Transforms a normalized plane by a matrix.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed plane.</returns>
public static Plane Transform(Plane plane, Matrix matrix)
{
Plane result;
Transform(ref plane, ref matrix, out result);
return result;
}
/// <summary>
/// Transforms a normalized plane by a matrix.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <param name="result">The transformed plane.</param>
public static void Transform(ref Plane plane, ref Matrix matrix, out Plane result)
{
// See "Transforming Normals" in http://www.glprogramming.com/red/appendixf.html
// for an explanation of how this works.
Matrix transformedMatrix;
Matrix.Invert(ref matrix, out transformedMatrix);
Matrix.Transpose(ref transformedMatrix, out transformedMatrix);
var vector = new Vector4(plane.Normal, plane.D);
Vector4 transformedVector;
Vector4.Transform(ref vector, ref transformedMatrix, out transformedVector);
result = new Plane(transformedVector);
}
/// <summary>
/// Transforms a normalized plane by a quaternion rotation.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="rotation">The quaternion rotation.</param>
/// <returns>The transformed plane.</returns>
public static Plane Transform(Plane plane, Quaternion rotation)
{
Plane result;
Transform(ref plane, ref rotation, out result);
return result;
}
/// <summary>
/// Transforms a normalized plane by a quaternion rotation.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="rotation">The quaternion rotation.</param>
/// <param name="result">The transformed plane.</param>
public static void Transform(ref Plane plane, ref Quaternion rotation, out Plane result)
{
Vector3.Transform(ref plane.Normal, ref rotation, out result.Normal);
result.D = plane.D;
}
public void Normalize()
{
float length = Normal.Length();
float factor = 1f / length;
Vector3.Multiply(ref Normal, factor, out Normal);
D = D * factor;
}
public static Plane Normalize(Plane value)
{
Plane ret;
Normalize(ref value, out ret);
return ret;
}
public static void Normalize(ref Plane value, out Plane result)
{
float length = value.Normal.Length();
float factor = 1f / length;
Vector3.Multiply(ref value.Normal, factor, out result.Normal);
result.D = value.D * factor;
}
public static bool operator !=(Plane plane1, Plane plane2)
{
return !plane1.Equals(plane2);
}
public static bool operator ==(Plane plane1, Plane plane2)
{
return plane1.Equals(plane2);
}
public override bool Equals(object other)
{
return (other is Plane) ? this.Equals((Plane)other) : false;
}
public bool Equals(Plane other)
{
return ((Normal == other.Normal) && (D == other.D));
}
public override int GetHashCode()
{
return Normal.GetHashCode() ^ D.GetHashCode();
}
public PlaneIntersectionType Intersects(BoundingBox box)
{
return box.Intersects(this);
}
public void Intersects(ref BoundingBox box, out PlaneIntersectionType result)
{
box.Intersects (ref this, out result);
}
public PlaneIntersectionType Intersects(BoundingFrustum frustum)
{
return frustum.Intersects(this);
}
public PlaneIntersectionType Intersects(BoundingSphere sphere)
{
return sphere.Intersects(this);
}
public void Intersects(ref BoundingSphere sphere, out PlaneIntersectionType result)
{
sphere.Intersects(ref this, out result);
}
internal PlaneIntersectionType Intersects(ref Vector3 point)
{
float distance;
DotCoordinate(ref point, out distance);
if (distance > 0)
return PlaneIntersectionType.Front;
if (distance < 0)
return PlaneIntersectionType.Back;
return PlaneIntersectionType.Intersecting;
}
internal string DebugDisplayString
{
get
{
return string.Concat(
this.Normal.DebugDisplayString, " ",
this.D.ToString()
);
}
}
public override string ToString()
{
return "{Normal:" + Normal + " D:" + D + "}";
}
/// <summary>
/// Deconstruction method for <see cref="Plane"/>.
/// </summary>
/// <param name="normal"></param>
/// <param name="d"></param>
public void Deconstruct(out Vector3 normal, out float d)
{
normal = Normal;
d = D;
}
#endregion
}
}

View File

@@ -0,0 +1,25 @@
// 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.
namespace Microsoft.Xna.Framework
{
/// <summary>
/// Defines the intersection between a <see cref="Plane"/> and a bounding volume.
/// </summary>
public enum PlaneIntersectionType
{
/// <summary>
/// There is no intersection, the bounding volume is in the negative half space of the plane.
/// </summary>
Front,
/// <summary>
/// There is no intersection, the bounding volume is in the positive half space of the plane.
/// </summary>
Back,
/// <summary>
/// The plane is intersected.
/// </summary>
Intersecting
}
}

219
Libraries/XNATypes/Point.cs Normal file
View File

@@ -0,0 +1,219 @@
// 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.Diagnostics;
namespace Microsoft.Xna.Framework
{
/// <summary>
/// Describes a 2D-point.
/// </summary>
[DebuggerDisplay("{DebugDisplayString,nq}")]
public struct Point : IEquatable<Point>
{
#region Private Fields
private static readonly Point zeroPoint = new Point();
#endregion
#region Public Fields
/// <summary>
/// The x coordinate of this <see cref="Point"/>.
/// </summary>
public int X;
/// <summary>
/// The y coordinate of this <see cref="Point"/>.
/// </summary>
public int Y;
#endregion
#region Properties
/// <summary>
/// Returns a <see cref="Point"/> with coordinates 0, 0.
/// </summary>
public static Point Zero
{
get { return zeroPoint; }
}
#endregion
#region Internal Properties
internal string DebugDisplayString
{
get
{
return string.Concat(
this.X.ToString(), " ",
this.Y.ToString()
);
}
}
#endregion
#region Constructors
/// <summary>
/// Constructs a point with X and Y from two values.
/// </summary>
/// <param name="x">The x coordinate in 2d-space.</param>
/// <param name="y">The y coordinate in 2d-space.</param>
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
/// <summary>
/// Constructs a point with X and Y set to the same value.
/// </summary>
/// <param name="value">The x and y coordinates in 2d-space.</param>
public Point(int value)
{
this.X = value;
this.Y = value;
}
#endregion
#region Operators
/// <summary>
/// Adds two points.
/// </summary>
/// <param name="value1">Source <see cref="Point"/> on the left of the add sign.</param>
/// <param name="value2">Source <see cref="Point"/> on the right of the add sign.</param>
/// <returns>Sum of the points.</returns>
public static Point operator +(Point value1, Point value2)
{
return new Point(value1.X + value2.X, value1.Y + value2.Y);
}
/// <summary>
/// Subtracts a <see cref="Point"/> from a <see cref="Point"/>.
/// </summary>
/// <param name="value1">Source <see cref="Point"/> on the left of the sub sign.</param>
/// <param name="value2">Source <see cref="Point"/> on the right of the sub sign.</param>
/// <returns>Result of the subtraction.</returns>
public static Point operator -(Point value1, Point value2)
{
return new Point(value1.X - value2.X, value1.Y - value2.Y);
}
/// <summary>
/// Multiplies the components of two points by each other.
/// </summary>
/// <param name="value1">Source <see cref="Point"/> on the left of the mul sign.</param>
/// <param name="value2">Source <see cref="Point"/> on the right of the mul sign.</param>
/// <returns>Result of the multiplication.</returns>
public static Point operator *(Point value1, Point value2)
{
return new Point(value1.X * value2.X, value1.Y * value2.Y);
}
/// <summary>
/// Divides the components of a <see cref="Point"/> by the components of another <see cref="Point"/>.
/// </summary>
/// <param name="source">Source <see cref="Point"/> on the left of the div sign.</param>
/// <param name="divisor">Divisor <see cref="Point"/> on the right of the div sign.</param>
/// <returns>The result of dividing the points.</returns>
public static Point operator /(Point source, Point divisor)
{
return new Point(source.X / divisor.X, source.Y / divisor.Y);
}
/// <summary>
/// Compares whether two <see cref="Point"/> instances are equal.
/// </summary>
/// <param name="a"><see cref="Point"/> instance on the left of the equal sign.</param>
/// <param name="b"><see cref="Point"/> instance on the right of the equal sign.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public static bool operator ==(Point a, Point b)
{
return a.Equals(b);
}
/// <summary>
/// Compares whether two <see cref="Point"/> instances are not equal.
/// </summary>
/// <param name="a"><see cref="Point"/> instance on the left of the not equal sign.</param>
/// <param name="b"><see cref="Point"/> instance on the right of the not equal sign.</param>
/// <returns><c>true</c> if the instances are not equal; <c>false</c> otherwise.</returns>
public static bool operator !=(Point a, Point b)
{
return !a.Equals(b);
}
#endregion
#region Public methods
/// <summary>
/// Compares whether current instance is equal to specified <see cref="Object"/>.
/// </summary>
/// <param name="obj">The <see cref="Object"/> to compare.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public override bool Equals(object obj)
{
return (obj is Point) && Equals((Point)obj);
}
/// <summary>
/// Compares whether current instance is equal to specified <see cref="Point"/>.
/// </summary>
/// <param name="other">The <see cref="Point"/> to compare.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public bool Equals(Point other)
{
return ((X == other.X) && (Y == other.Y));
}
/// <summary>
/// Gets the hash code of this <see cref="Point"/>.
/// </summary>
/// <returns>Hash code of this <see cref="Point"/>.</returns>
public override int GetHashCode()
{
unchecked
{
var hash = 17;
hash = hash * 23 + X.GetHashCode();
hash = hash * 23 + Y.GetHashCode();
return hash;
}
}
/// <summary>
/// Returns a <see cref="String"/> representation of this <see cref="Point"/> in the format:
/// {X:[<see cref="X"/>] Y:[<see cref="Y"/>]}
/// </summary>
/// <returns><see cref="String"/> representation of this <see cref="Point"/>.</returns>
public override string ToString()
{
return "{X:" + X + " Y:" + Y + "}";
}
/// <summary>
/// Gets a <see cref="Vector2"/> representation for this object.
/// </summary>
/// <returns>A <see cref="Vector2"/> representation for this object.</returns>
public Vector2 ToVector2()
{
return new Vector2(X, Y);
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

272
Libraries/XNATypes/Ray.cs Normal file
View File

@@ -0,0 +1,272 @@
// 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.Diagnostics;
using System.Runtime.Serialization;
namespace Microsoft.Xna.Framework
{
[DataContract]
[DebuggerDisplay("{DebugDisplayString,nq}")]
public struct Ray : IEquatable<Ray>
{
#region Public Fields
[DataMember]
public Vector3 Direction;
[DataMember]
public Vector3 Position;
#endregion
#region Public Constructors
public Ray(Vector3 position, Vector3 direction)
{
this.Position = position;
this.Direction = direction;
}
#endregion
#region Public Methods
public override bool Equals(object obj)
{
return (obj is Ray) ? this.Equals((Ray)obj) : false;
}
public bool Equals(Ray other)
{
return this.Position.Equals(other.Position) && this.Direction.Equals(other.Direction);
}
public override int GetHashCode()
{
return Position.GetHashCode() ^ Direction.GetHashCode();
}
// adapted from http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/
public float? Intersects(BoundingBox box)
{
const float Epsilon = 1e-6f;
float? tMin = null, tMax = null;
if (Math.Abs(Direction.X) < Epsilon)
{
if (Position.X < box.Min.X || Position.X > box.Max.X)
return null;
}
else
{
tMin = (box.Min.X - Position.X) / Direction.X;
tMax = (box.Max.X - Position.X) / Direction.X;
if (tMin > tMax)
{
var temp = tMin;
tMin = tMax;
tMax = temp;
}
}
if (Math.Abs(Direction.Y) < Epsilon)
{
if (Position.Y < box.Min.Y || Position.Y > box.Max.Y)
return null;
}
else
{
var tMinY = (box.Min.Y - Position.Y) / Direction.Y;
var tMaxY = (box.Max.Y - Position.Y) / Direction.Y;
if (tMinY > tMaxY)
{
var temp = tMinY;
tMinY = tMaxY;
tMaxY = temp;
}
if ((tMin.HasValue && tMin > tMaxY) || (tMax.HasValue && tMinY > tMax))
return null;
if (!tMin.HasValue || tMinY > tMin) tMin = tMinY;
if (!tMax.HasValue || tMaxY < tMax) tMax = tMaxY;
}
if (Math.Abs(Direction.Z) < Epsilon)
{
if (Position.Z < box.Min.Z || Position.Z > box.Max.Z)
return null;
}
else
{
var tMinZ = (box.Min.Z - Position.Z) / Direction.Z;
var tMaxZ = (box.Max.Z - Position.Z) / Direction.Z;
if (tMinZ > tMaxZ)
{
var temp = tMinZ;
tMinZ = tMaxZ;
tMaxZ = temp;
}
if ((tMin.HasValue && tMin > tMaxZ) || (tMax.HasValue && tMinZ > tMax))
return null;
if (!tMin.HasValue || tMinZ > tMin) tMin = tMinZ;
if (!tMax.HasValue || tMaxZ < tMax) tMax = tMaxZ;
}
// having a positive tMin and a negative tMax means the ray is inside the box
// we expect the intesection distance to be 0 in that case
if ((tMin.HasValue && tMin < 0) && tMax > 0) return 0;
// a negative tMin means that the intersection point is behind the ray's origin
// we discard these as not hitting the AABB
if (tMin < 0) return null;
return tMin;
}
public void Intersects(ref BoundingBox box, out float? result)
{
result = Intersects(box);
}
/*
public float? Intersects(BoundingFrustum frustum)
{
if (frustum == null)
{
throw new ArgumentNullException("frustum");
}
return frustum.Intersects(this);
}
*/
public float? Intersects(BoundingSphere sphere)
{
float? result;
Intersects(ref sphere, out result);
return result;
}
public float? Intersects(Plane plane)
{
float? result;
Intersects(ref plane, out result);
return result;
}
public void Intersects(ref Plane plane, out float? result)
{
var den = Vector3.Dot(Direction, plane.Normal);
if (Math.Abs(den) < 0.00001f)
{
result = null;
return;
}
result = (-plane.D - Vector3.Dot(plane.Normal, Position)) / den;
if (result < 0.0f)
{
if (result < -0.00001f)
{
result = null;
return;
}
result = 0.0f;
}
}
public void Intersects(ref BoundingSphere sphere, out float? result)
{
// Find the vector between where the ray starts the the sphere's centre
Vector3 difference = sphere.Center - this.Position;
float differenceLengthSquared = difference.LengthSquared();
float sphereRadiusSquared = sphere.Radius * sphere.Radius;
float distanceAlongRay;
// If the distance between the ray start and the sphere's centre is less than
// the radius of the sphere, it means we've intersected. N.B. checking the LengthSquared is faster.
if (differenceLengthSquared < sphereRadiusSquared)
{
result = 0.0f;
return;
}
Vector3.Dot(ref this.Direction, ref difference, out distanceAlongRay);
// If the ray is pointing away from the sphere then we don't ever intersect
if (distanceAlongRay < 0)
{
result = null;
return;
}
// Next we kinda use Pythagoras to check if we are within the bounds of the sphere
// if x = radius of sphere
// if y = distance between ray position and sphere centre
// if z = the distance we've travelled along the ray
// if x^2 + z^2 - y^2 < 0, we do not intersect
float dist = sphereRadiusSquared + distanceAlongRay * distanceAlongRay - differenceLengthSquared;
result = (dist < 0) ? null : distanceAlongRay - (float?)Math.Sqrt(dist);
}
public static bool operator !=(Ray a, Ray b)
{
return !a.Equals(b);
}
public static bool operator ==(Ray a, Ray b)
{
return a.Equals(b);
}
internal string DebugDisplayString
{
get
{
return string.Concat(
"Pos( ", this.Position.DebugDisplayString, " ) \r\n",
"Dir( ", this.Direction.DebugDisplayString, " )"
);
}
}
public override string ToString()
{
return "{{Position:" + Position.ToString() + " Direction:" + Direction.ToString() + "}}";
}
/// <summary>
/// Deconstruction method for <see cref="Ray"/>.
/// </summary>
/// <param name="position">Receives the start position of the ray.</param>
/// <param name="direction">Receives the direction of the ray.</param>
public void Deconstruct(out Vector3 position, out Vector3 direction)
{
position = Position;
direction = Direction;
}
#endregion
}
}

View File

@@ -0,0 +1,532 @@
// 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.Diagnostics;
namespace Microsoft.Xna.Framework
{
/// <summary>
/// Describes a 2D-rectangle.
/// </summary>
[DebuggerDisplay("{DebugDisplayString,nq}")]
public struct Rectangle : IEquatable<Rectangle>
{
#region Private Fields
private static Rectangle emptyRectangle = new Rectangle();
#endregion
#region Public Fields
/// <summary>
/// The x coordinate of the top-left corner of this <see cref="Rectangle"/>.
/// </summary>
public int X;
/// <summary>
/// The y coordinate of the top-left corner of this <see cref="Rectangle"/>.
/// </summary>
public int Y;
/// <summary>
/// The width of this <see cref="Rectangle"/>.
/// </summary>
public int Width;
/// <summary>
/// The height of this <see cref="Rectangle"/>.
/// </summary>
public int Height;
#endregion
#region Public Properties
/// <summary>
/// Returns a <see cref="Rectangle"/> with X=0, Y=0, Width=0, Height=0.
/// </summary>
public static Rectangle Empty
{
get { return emptyRectangle; }
}
/// <summary>
/// Returns the x coordinate of the left edge of this <see cref="Rectangle"/>.
/// </summary>
public int Left
{
get { return this.X; }
}
/// <summary>
/// Returns the x coordinate of the right edge of this <see cref="Rectangle"/>.
/// </summary>
public int Right
{
get { return (this.X + this.Width); }
}
/// <summary>
/// Returns the y coordinate of the top edge of this <see cref="Rectangle"/>.
/// </summary>
public int Top
{
get { return this.Y; }
}
/// <summary>
/// Returns the y coordinate of the bottom edge of this <see cref="Rectangle"/>.
/// </summary>
public int Bottom
{
get { return (this.Y + this.Height); }
}
/// <summary>
/// Whether or not this <see cref="Rectangle"/> has a <see cref="Width"/> and
/// <see cref="Height"/> of 0, and a <see cref="Location"/> of (0, 0).
/// </summary>
public bool IsEmpty
{
get
{
return ((((this.Width == 0) && (this.Height == 0)) && (this.X == 0)) && (this.Y == 0));
}
}
/// <summary>
/// The top-left coordinates of this <see cref="Rectangle"/>.
/// </summary>
public Point Location
{
get
{
return new Point(this.X, this.Y);
}
set
{
X = value.X;
Y = value.Y;
}
}
/// <summary>
/// The width-height coordinates of this <see cref="Rectangle"/>.
/// </summary>
public Point Size
{
get
{
return new Point(this.Width,this.Height);
}
set
{
Width = value.X;
Height = value.Y;
}
}
/// <summary>
/// A <see cref="Point"/> located in the center of this <see cref="Rectangle"/>.
/// </summary>
/// <remarks>
/// If <see cref="Width"/> or <see cref="Height"/> is an odd number,
/// the center point will be rounded down.
/// </remarks>
public Point Center
{
get
{
return new Point(this.X + (this.Width / 2), this.Y + (this.Height / 2));
}
}
#endregion
#region Internal Properties
internal string DebugDisplayString
{
get
{
return string.Concat(
this.X, " ",
this.Y, " ",
this.Width, " ",
this.Height
);
}
}
#endregion
#region Constructors
/// <summary>
/// Creates a new instance of <see cref="Rectangle"/> struct, with the specified
/// position, width, and height.
/// </summary>
/// <param name="x">The x coordinate of the top-left corner of the created <see cref="Rectangle"/>.</param>
/// <param name="y">The y coordinate of the top-left corner of the created <see cref="Rectangle"/>.</param>
/// <param name="width">The width of the created <see cref="Rectangle"/>.</param>
/// <param name="height">The height of the created <see cref="Rectangle"/>.</param>
public Rectangle(int x, int y, int width, int height)
{
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
}
/// <summary>
/// Creates a new instance of <see cref="Rectangle"/> struct, with the specified
/// location and size.
/// </summary>
/// <param name="location">The x and y coordinates of the top-left corner of the created <see cref="Rectangle"/>.</param>
/// <param name="size">The width and height of the created <see cref="Rectangle"/>.</param>
public Rectangle(Point location,Point size)
{
this.X = location.X;
this.Y = location.Y;
this.Width = size.X;
this.Height = size.Y;
}
#endregion
#region Operators
/// <summary>
/// Compares whether two <see cref="Rectangle"/> instances are equal.
/// </summary>
/// <param name="a"><see cref="Rectangle"/> instance on the left of the equal sign.</param>
/// <param name="b"><see cref="Rectangle"/> instance on the right of the equal sign.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public static bool operator ==(Rectangle a, Rectangle b)
{
return ((a.X == b.X) && (a.Y == b.Y) && (a.Width == b.Width) && (a.Height == b.Height));
}
/// <summary>
/// Compares whether two <see cref="Rectangle"/> instances are not equal.
/// </summary>
/// <param name="a"><see cref="Rectangle"/> instance on the left of the not equal sign.</param>
/// <param name="b"><see cref="Rectangle"/> instance on the right of the not equal sign.</param>
/// <returns><c>true</c> if the instances are not equal; <c>false</c> otherwise.</returns>
public static bool operator !=(Rectangle a, Rectangle b)
{
return !(a == b);
}
#endregion
#region Public Methods
/// <summary>
/// Gets whether or not the provided coordinates lie within the bounds of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="x">The x coordinate of the point to check for containment.</param>
/// <param name="y">The y coordinate of the point to check for containment.</param>
/// <returns><c>true</c> if the provided coordinates lie inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
public bool Contains(int x, int y)
{
return ((((this.X <= x) && (x < (this.X + this.Width))) && (this.Y <= y)) && (y < (this.Y + this.Height)));
}
/// <summary>
/// Gets whether or not the provided coordinates lie within the bounds of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="x">The x coordinate of the point to check for containment.</param>
/// <param name="y">The y coordinate of the point to check for containment.</param>
/// <returns><c>true</c> if the provided coordinates lie inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
public bool Contains(float x, float y)
{
return ((((this.X <= x) && (x < (this.X + this.Width))) && (this.Y <= y)) && (y < (this.Y + this.Height)));
}
/// <summary>
/// Gets whether or not the provided <see cref="Point"/> lies within the bounds of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="value">The coordinates to check for inclusion in this <see cref="Rectangle"/>.</param>
/// <returns><c>true</c> if the provided <see cref="Point"/> lies inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
public bool Contains(Point value)
{
return ((((this.X <= value.X) && (value.X < (this.X + this.Width))) && (this.Y <= value.Y)) && (value.Y < (this.Y + this.Height)));
}
/// <summary>
/// Gets whether or not the provided <see cref="Point"/> lies within the bounds of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="value">The coordinates to check for inclusion in this <see cref="Rectangle"/>.</param>
/// <param name="result"><c>true</c> if the provided <see cref="Point"/> lies inside this <see cref="Rectangle"/>; <c>false</c> otherwise. As an output parameter.</param>
public void Contains(ref Point value, out bool result)
{
result = ((((this.X <= value.X) && (value.X < (this.X + this.Width))) && (this.Y <= value.Y)) && (value.Y < (this.Y + this.Height)));
}
/// <summary>
/// Gets whether or not the provided <see cref="Vector2"/> lies within the bounds of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="value">The coordinates to check for inclusion in this <see cref="Rectangle"/>.</param>
/// <returns><c>true</c> if the provided <see cref="Vector2"/> lies inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
public bool Contains(Vector2 value)
{
return ((((this.X <= value.X) && (value.X < (this.X + this.Width))) && (this.Y <= value.Y)) && (value.Y < (this.Y + this.Height)));
}
/// <summary>
/// Gets whether or not the provided <see cref="Vector2"/> lies within the bounds of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="value">The coordinates to check for inclusion in this <see cref="Rectangle"/>.</param>
/// <param name="result"><c>true</c> if the provided <see cref="Vector2"/> lies inside this <see cref="Rectangle"/>; <c>false</c> otherwise. As an output parameter.</param>
public void Contains(ref Vector2 value, out bool result)
{
result = ((((this.X <= value.X) && (value.X < (this.X + this.Width))) && (this.Y <= value.Y)) && (value.Y < (this.Y + this.Height)));
}
/// <summary>
/// Gets whether or not the provided <see cref="Rectangle"/> lies within the bounds of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="value">The <see cref="Rectangle"/> to check for inclusion in this <see cref="Rectangle"/>.</param>
/// <returns><c>true</c> if the provided <see cref="Rectangle"/>'s bounds lie entirely inside this <see cref="Rectangle"/>; <c>false</c> otherwise.</returns>
public bool Contains(Rectangle value)
{
return ((((this.X <= value.X) && ((value.X + value.Width) <= (this.X + this.Width))) && (this.Y <= value.Y)) && ((value.Y + value.Height) <= (this.Y + this.Height)));
}
/// <summary>
/// Gets whether or not the provided <see cref="Rectangle"/> lies within the bounds of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="value">The <see cref="Rectangle"/> to check for inclusion in this <see cref="Rectangle"/>.</param>
/// <param name="result"><c>true</c> if the provided <see cref="Rectangle"/>'s bounds lie entirely inside this <see cref="Rectangle"/>; <c>false</c> otherwise. As an output parameter.</param>
public void Contains(ref Rectangle value,out bool result)
{
result = ((((this.X <= value.X) && ((value.X + value.Width) <= (this.X + this.Width))) && (this.Y <= value.Y)) && ((value.Y + value.Height) <= (this.Y + this.Height)));
}
/// <summary>
/// Compares whether current instance is equal to specified <see cref="Object"/>.
/// </summary>
/// <param name="obj">The <see cref="Object"/> to compare.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public override bool Equals(object obj)
{
return (obj is Rectangle) && this == ((Rectangle)obj);
}
/// <summary>
/// Compares whether current instance is equal to specified <see cref="Rectangle"/>.
/// </summary>
/// <param name="other">The <see cref="Rectangle"/> to compare.</param>
/// <returns><c>true</c> if the instances are equal; <c>false</c> otherwise.</returns>
public bool Equals(Rectangle other)
{
return this == other;
}
/// <summary>
/// Gets the hash code of this <see cref="Rectangle"/>.
/// </summary>
/// <returns>Hash code of this <see cref="Rectangle"/>.</returns>
public override int GetHashCode()
{
unchecked
{
var hash = 17;
hash = hash * 23 + X.GetHashCode();
hash = hash * 23 + Y.GetHashCode();
hash = hash * 23 + Width.GetHashCode();
hash = hash * 23 + Height.GetHashCode();
return hash;
}
}
/// <summary>
/// Adjusts the edges of this <see cref="Rectangle"/> by specified horizontal and vertical amounts.
/// </summary>
/// <param name="horizontalAmount">Value to adjust the left and right edges.</param>
/// <param name="verticalAmount">Value to adjust the top and bottom edges.</param>
public void Inflate(int horizontalAmount, int verticalAmount)
{
X -= horizontalAmount;
Y -= verticalAmount;
Width += horizontalAmount * 2;
Height += verticalAmount * 2;
}
/// <summary>
/// Adjusts the edges of this <see cref="Rectangle"/> by specified horizontal and vertical amounts.
/// </summary>
/// <param name="horizontalAmount">Value to adjust the left and right edges.</param>
/// <param name="verticalAmount">Value to adjust the top and bottom edges.</param>
public void Inflate(float horizontalAmount, float verticalAmount)
{
X -= (int)horizontalAmount;
Y -= (int)verticalAmount;
Width += (int)horizontalAmount * 2;
Height += (int)verticalAmount * 2;
}
/// <summary>
/// Adjusts the edges of this <see cref="Rectangle"/> by specified horizontal and vertical amounts.
/// </summary>
/// <param name="amount">Value to adjust the edges.</param>
public void Inflate(Vector2 amount)
{
Inflate(amount.X, amount.Y);
}
/// <summary>
/// Gets whether or not the other <see cref="Rectangle"/> intersects with this rectangle.
/// </summary>
/// <param name="value">The other rectangle for testing.</param>
/// <returns><c>true</c> if other <see cref="Rectangle"/> intersects with this rectangle; <c>false</c> otherwise.</returns>
public bool Intersects(Rectangle value)
{
return value.Left < Right &&
Left < value.Right &&
value.Top < Bottom &&
Top < value.Bottom;
}
/// <summary>
/// Gets whether or not the other <see cref="Rectangle"/> intersects with this rectangle.
/// </summary>
/// <param name="value">The other rectangle for testing.</param>
/// <param name="result"><c>true</c> if other <see cref="Rectangle"/> intersects with this rectangle; <c>false</c> otherwise. As an output parameter.</param>
public void Intersects(ref Rectangle value, out bool result)
{
result = value.Left < Right &&
Left < value.Right &&
value.Top < Bottom &&
Top < value.Bottom;
}
/// <summary>
/// Creates a new <see cref="Rectangle"/> that contains overlapping region of two other rectangles.
/// </summary>
/// <param name="value1">The first <see cref="Rectangle"/>.</param>
/// <param name="value2">The second <see cref="Rectangle"/>.</param>
/// <returns>Overlapping region of the two rectangles.</returns>
public static Rectangle Intersect(Rectangle value1, Rectangle value2)
{
Rectangle rectangle;
Intersect(ref value1, ref value2, out rectangle);
return rectangle;
}
/// <summary>
/// Creates a new <see cref="Rectangle"/> that contains overlapping region of two other rectangles.
/// </summary>
/// <param name="value1">The first <see cref="Rectangle"/>.</param>
/// <param name="value2">The second <see cref="Rectangle"/>.</param>
/// <param name="result">Overlapping region of the two rectangles as an output parameter.</param>
public static void Intersect(ref Rectangle value1, ref Rectangle value2, out Rectangle result)
{
if (value1.Intersects(value2))
{
int right_side = Math.Min(value1.X + value1.Width, value2.X + value2.Width);
int left_side = Math.Max(value1.X, value2.X);
int top_side = Math.Max(value1.Y, value2.Y);
int bottom_side = Math.Min(value1.Y + value1.Height, value2.Y + value2.Height);
result = new Rectangle(left_side, top_side, right_side - left_side, bottom_side - top_side);
}
else
{
result = new Rectangle(0, 0, 0, 0);
}
}
/// <summary>
/// Changes the <see cref="Location"/> of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="offsetX">The x coordinate to add to this <see cref="Rectangle"/>.</param>
/// <param name="offsetY">The y coordinate to add to this <see cref="Rectangle"/>.</param>
public void Offset(int offsetX, int offsetY)
{
X += offsetX;
Y += offsetY;
}
/// <summary>
/// Changes the <see cref="Location"/> of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="offsetX">The x coordinate to add to this <see cref="Rectangle"/>.</param>
/// <param name="offsetY">The y coordinate to add to this <see cref="Rectangle"/>.</param>
public void Offset(float offsetX, float offsetY)
{
X += (int)offsetX;
Y += (int)offsetY;
}
/// <summary>
/// Changes the <see cref="Location"/> of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="amount">The x and y components to add to this <see cref="Rectangle"/>.</param>
public void Offset(Point amount)
{
X += amount.X;
Y += amount.Y;
}
/// <summary>
/// Changes the <see cref="Location"/> of this <see cref="Rectangle"/>.
/// </summary>
/// <param name="amount">The x and y components to add to this <see cref="Rectangle"/>.</param>
public void Offset(Vector2 amount)
{
X += (int)amount.X;
Y += (int)amount.Y;
}
/// <summary>
/// Returns a <see cref="String"/> representation of this <see cref="Rectangle"/> in the format:
/// {X:[<see cref="X"/>] Y:[<see cref="Y"/>] Width:[<see cref="Width"/>] Height:[<see cref="Height"/>]}
/// </summary>
/// <returns><see cref="String"/> representation of this <see cref="Rectangle"/>.</returns>
public override string ToString()
{
return "{X:" + X + " Y:" + Y + " Width:" + Width + " Height:" + Height + "}";
}
/// <summary>
/// Creates a new <see cref="Rectangle"/> that completely contains two other rectangles.
/// </summary>
/// <param name="value1">The first <see cref="Rectangle"/>.</param>
/// <param name="value2">The second <see cref="Rectangle"/>.</param>
/// <returns>The union of the two rectangles.</returns>
public static Rectangle Union(Rectangle value1, Rectangle value2)
{
int x = Math.Min(value1.X, value2.X);
int y = Math.Min(value1.Y, value2.Y);
return new Rectangle(x, y,
Math.Max(value1.Right, value2.Right) - x,
Math.Max(value1.Bottom, value2.Bottom) - y);
}
/// <summary>
/// Creates a new <see cref="Rectangle"/> that completely contains two other rectangles.
/// </summary>
/// <param name="value1">The first <see cref="Rectangle"/>.</param>
/// <param name="value2">The second <see cref="Rectangle"/>.</param>
/// <param name="result">The union of the two rectangles as an output parameter.</param>
public static void Union(ref Rectangle value1, ref Rectangle value2, out Rectangle result)
{
result.X = Math.Min(value1.X, value2.X);
result.Y = Math.Min(value1.Y, value2.Y);
result.Width = Math.Max(value1.Right, value2.Right) - result.X;
result.Height = Math.Max(value1.Bottom, value2.Bottom) - result.Y;
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>AnyCPU;x64</Platforms>
<Authors></Authors>
<Company />
</PropertyGroup>
</Project>