Click here to Skip to main content
15,895,084 members
Articles / Programming Languages / C#

Sharp3D.Math - A 3D math library for .NET

Rate me:
Please Sign up or sign in to vote.
4.30/5 (32 votes)
9 Jun 20041 min read 223.8K   6.6K   79  
A 3D math library written in C#
#region Sharp3D.Math, Copyright(C) 2003-2004 Eran Kampf, Licensed under LGPL.
//	Sharp3D.Math math library
//	Copyright (C) 2003-2004  
//	Eran Kampf
//	tentacle@zahav.net.il
//	http://tentacle.flipcode.com
//
//	This library is free software; you can redistribute it and/or
//	modify it under the terms of the GNU Lesser General Public
//	License as published by the Free Software Foundation; either
//	version 2.1 of the License, or (at your option) any later version.
//
//	This library is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//	Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public
//	License along with this library; if not, write to the Free Software
//	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#endregion
using System;
using System.Diagnostics;
using System.Collections;
using System.Runtime.Serialization;
using System.Security.Permissions;

using Sharp3D.Math.Core;

namespace Sharp3D.Math.Geometry2D
{
	/// <summary>
	/// Represents a circle in 2D space.
	/// </summary>
	[Serializable]
	public struct Circle : ICloneable, ISerializable
	{
		private Vector2F center;
		private float radius;

		#region Constructors
		/// <summary>
		/// Initializes a new instance of the <see cref="Circle"/> class using center and radius values.
		/// </summary>
		/// <param name="center">The circle's center point.</param>
		/// <param name="radius">The circle's radius.</param>
		public Circle(Vector2F center, float radius)
		{
			this.center = center;
			this.radius = radius;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="Circle"/> class using values from another circle instance.
		/// </summary>
		/// <param name="circle">A <see cref="Circle"/> instance to take values from.</param>
		public Circle(Circle circle)
		{
			this.center = circle.center;
			this.radius = circle.radius;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="Vector2F"/> class with serialized data.
		/// </summary>
		/// <param name="info">The object that holds the serialized object data.</param>
		/// <param name="context">The contextual information about the source or destination.</param>
		private Circle(SerializationInfo info, StreamingContext context)
		{
			this.center = (Vector2F)info.GetValue("Center", typeof(Vector2F));
			this.radius = info.GetSingle("Radius");
		}
		#endregion

		#region Constants
		/// <summary>
		/// Unit sphere.
		/// </summary>
		public static readonly Circle UnitCircle	= new Circle(new Vector2F(0.0f,0.0f), 1.0f);
		#endregion

		#region Public Properties
		/// <summary>
		/// The circle's center.
		/// </summary>
		public Vector2F Center
		{
			get
			{
				return this.center;
			}
			set
			{
				this.center = value;
			}
		}
		/// <summary>
		/// The circle's radius.
		/// </summary>
		public float Radius
		{
			get
			{
				return this.radius;
			}
			set
			{
				this.radius = value;
			}
		}
		#endregion

		#region ISerializable Members
		/// <summary>
		/// Populates a <see cref="SerializationInfo"/> with the data needed to serialize the target object.
		/// </summary>
		/// <param name="info">The <see cref="SerializationInfo"/> to populate with data. </param>
		/// <param name="context">The destination (see <see cref="StreamingContext"/>) for this serialization.</param>
		[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Center", this.center, typeof(Vector2F));
			info.AddValue("Radius", this.radius);
		}
		#endregion
	
		#region ICloneable Members
		/// <summary>
		/// Creates a new object that is a copy of the current instance.
		/// </summary>
		/// <returns>A new object that is a copy of this instance.</returns>
		object ICloneable.Clone()
		{
			return new Circle(this);
		}
		/// <summary>
		/// Creates a new object that is a copy of the current instance.
		/// </summary>
		/// <returns>A new object that is a copy of this instance.</returns>
		public Circle Clone()
		{
			return new Circle(this);
		}
		#endregion

		#region Overrides
		/// <summary>
		/// Get the hashcode for this vector instance.
		/// </summary>
		/// <returns>Returns the hash code for this vector instance.</returns>
		public override int	GetHashCode() 
		{
			return this.center.GetHashCode() ^ this.radius.GetHashCode();
		}
		/// <summary>
		/// Checks if a given <see cref="Circle"/> equals to self.
		/// </summary>
		/// <param name="o">Object to check if equal to.</param>
		/// <returns></returns>
		public override bool Equals(object o) 
		{
			if( o is Circle ) 
			{
				Circle c = (Circle) o;
				return 
					(this.center == c.Center) && (this.radius == c.radius);
			}
			return false;
		}
		/// <summary>
		/// Convert <see cref="Circle"/> to a string.
		/// </summary>
		/// <returns></returns>
		public override string ToString() 
		{
			return	string.Format( "Circle(Center={0}, Radius={1})", this.center, this.radius);
		}
		#endregion

		#region Operators
		/// <summary>
		/// Checks if the two given circles are equal.
		/// </summary>
		/// <param name="a">The first of two 2D circles to compare.</param>
		/// <param name="b">The second of two 2D circles to compare.</param>
		/// <returns><b>true</b> if the circles are equal; otherwise, <b>false</b>.</returns>
		public static bool operator==(Circle a, Circle b) 
		{
			if(Object.Equals(a, null) == true) 
			{
				return Object.Equals(b, null);
			}
			
			if(Object.Equals(b, null) == true) 
			{
				return Object.Equals(a, null);
			}

			return 
				(a.center == b.center) && (a.radius == b.radius);
		}

		/// <summary>
		/// Checks if the two given circles are not equal.
		/// </summary>
		/// <param name="a">The first of two 2D circles to compare.</param>
		/// <param name="b">The second of two 2D circles to compare.</param>
		/// <returns><b>true</b> if the circles are not equal; otherwise, <b>false</b>.</returns>
		public static bool operator!=(Circle a, Circle b) 
		{
			if( Object.Equals(a, null) == true ) 
			{
				return !Object.Equals(b, null );
			}
			else if( Object.Equals(b, null) == true ) 
			{
				return !Object.Equals(a, null);
			}
			return !((a.center == b.center) && (a.radius == b.radius));
		}
		#endregion

		/// <summary>
		/// Tests if a ray intersects the sphere.
		/// </summary>
		/// <param name="ray">The ray to test.</param>
		/// <returns>Returns True if the ray intersects the sphere. Otherwise, False.</returns>
		public bool TestIntersection(Ray ray)
		{
			float squaredDistance = DistanceMethods.SquaredDistance(this.center, ray);
			return (squaredDistance <= this.radius*this.radius);
		}

		/// <summary>
		/// Find the intersection of a ray and a sphere.
		/// Only works with unit rays (normalized direction)!!!
		/// </summary>
		/// <remarks>
		/// This is the optimized Ray-Sphere intersection algorithms described in Realtime-Rendering.
		/// </remarks>
		/// <param name="ray">The ray to test.</param>
		/// <param name="t">
		/// If intersection accurs, the function outputs the distance from the ray's origin 
		/// to the closest intersection point to this parameter.
		/// </param>
		/// <returns>Returns True if the ray intersects the sphere. Otherwise, False.</returns>
		public bool FindIntersections(Ray ray, ref float t)
		{
			// Only gives correct result for unit rays.
			//Debug.Assert(MathUtils.ApproxEquals(1.0f, ray.Direction.GetLength()), "Ray direction should be normalized!");

			// Calculates a vector from the ray origin to the sphere center.
			Vector2F diff		= this.center - ray.Origin;
			// Compute the projection of diff onto the ray direction
			float d = Vector2F.DotProduct(diff, ray.Direction);
		
			float diffSquared	= diff.GetLengthSquared();
			float radiusSquared = this.radius * this.radius;

			// First rejection test : 
			// if d<0 and the ray origin is outside the sphere than the sphere is behind the ray
			if ((d < 0.0f) && (diffSquared > radiusSquared))
			{
				return false;
			}

			// Compute the distance from the sphere center to the projection
			float mSquared = diffSquared - d*d;

			// Second rejection test:
			// if mSquared > radiusSquared than the ray misses the sphere
			if (mSquared > radiusSquared)
			{
				return false;
			}

			float q = (float)System.Math.Sqrt(radiusSquared - mSquared);

			// We are interested only in the first intersection point:
			if (diffSquared > radiusSquared)
			{
				// If the origin is outside the sphere t = d - q is the first intersection point
				t = d - q;
			}
			else 
			{
				// If the origin is inside the sphere t = d + q is the first intersection point
				t = d + q;
			}
			return true;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions