Click here to Skip to main content
15,892,575 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.7K   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.ComponentModel;
using System.Diagnostics;
using System.Collections;
using System.IO;
using System.Runtime.Serialization;
using System.Security.Permissions;
using NUnit.Framework;

namespace Sharp3D.Math.Core
{
	/// <summary>
	/// Represents 4-Dimentional vector of double-precision floating point numbers.
	/// </summary>
	[Serializable]
	[TypeConverter(typeof(ExpandableObjectConverter))]
	public struct Vector4D : ISerializable, ICloneable
	{
		#region Private fields
		private double _x;
		private double _y;
		private double _z;
		private double _w;
		#endregion

		#region Constructors
		/// <summary>
		/// Initializes a new instance of the <see cref="Vector4D"/> class with the specified coordinates.
		/// </summary>
		/// <param name="x">The vector's X coordinate.</param>
		/// <param name="y">The vector's Y coordinate.</param>
		/// <param name="z">The vector's Z coordinate.</param>
		/// <param name="w">The vector's W coordinate.</param>
		public Vector4D(double x, double y, double z, double w)
		{
			_x = x;
			_y = y;
			_z = z;
			_w = w;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="Vector4D"/> class with the specified coordinates.
		/// </summary>
		/// <param name="coordinates">An array containing the coordinate parameters.</param>
		public Vector4D(double[] coordinates)
		{
			Debug.Assert(coordinates != null);
			Debug.Assert(coordinates.Length >= 4);

			_x = coordinates[0];
			_y = coordinates[1];
			_z = coordinates[2];
			_w = coordinates[3];
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Vector4D"/> class using coordinates from a given <see cref="Vector4D"/> instance.
		/// </summary>
		/// <param name="vector">A <see cref="Vector4D"/> to get the coordinates from.</param>
		public Vector4D(Vector4D vector)
		{
			_x = vector.X;
			_y = vector.Y;
			_z = vector.Z;
			_w = vector.W;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="Vector4D"/> 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 Vector4D(SerializationInfo info, StreamingContext context)
		{
			_x = info.GetSingle("X");
			_y = info.GetSingle("Y");
			_z = info.GetSingle("Z");
			_w = info.GetSingle("W");
		}
		#endregion

		#region Constants
		/// <summary>
		/// 4-Dimentional double-precision floating point zero vector.
		/// </summary>
		public static readonly Vector4D Zero	= new Vector4D(0.0f, 0.0f, 0.0f, 0.0f);
		/// <summary>
		/// 4-Dimentional double-precision floating point X-Axis vector.
		/// </summary>
		public static readonly Vector4D XAxis	= new Vector4D(1.0f, 0.0f, 0.0f, 0.0f);
		/// <summary>
		/// 4-Dimentional double-precision floating point Y-Axis vector.
		/// </summary>
		public static readonly Vector4D YAxis	= new Vector4D(0.0f, 1.0f, 0.0f, 0.0f);
		/// <summary>
		/// 4-Dimentional double-precision floating point Y-Axis vector.
		/// </summary>
		public static readonly Vector4D ZAxis	= new Vector4D(0.0f, 0.0f, 1.0f, 0.0f);
		/// <summary>
		/// 4-Dimentional double-precision floating point Y-Axis vector.
		/// </summary>
		public static readonly Vector4D WAxis	= new Vector4D(0.0f, 0.0f, 0.0f, 1.0f);
		#endregion

		#region Public properties
		/// <summary>
		/// Gets or sets the x-coordinate of this vector.
		/// </summary>
		/// <value>The x-coordinate of this vector.</value>
		public double X
		{
			get { return _x; }
			set { _x = value;}
		}
		/// <summary>
		/// Gets or sets the y-coordinate of this vector.
		/// </summary>
		/// <value>The y-coordinate of this vector.</value>
		public double Y
		{
			get { return _y; }
			set { _y = value;}
		}
		/// <summary>
		/// Gets or sets the z-coordinate of this vector.
		/// </summary>
		/// <value>The z-coordinate of this vector.</value>
		public double Z
		{
			get { return _z; }
			set { _z = value;}
		}
		/// <summary>
		/// Gets or sets the w-coordinate of this vector.
		/// </summary>
		/// <value>The w-coordinate of this vector.</value>
		public double W
		{
			get { return _w; }
			set { _w = value;}
		}		
		#endregion

		#region ICloneable Members
		/// <summary>
		/// Creates an exact copy of this <see cref="Vector4D"/> object.
		/// </summary>
		/// <returns>The <see cref="Vector4D"/> object this method creates, cast as an object.</returns>
		object ICloneable.Clone()
		{
			return new Vector4D(this);
		}
		/// <summary>
		/// Creates an exact copy of this <see cref="Vector4D"/> object.
		/// </summary>
		/// <returns>The <see cref="Vector4D"/> object this method creates.</returns>
		public Vector4D Clone()
		{
			return new Vector4D(this);
		}
		#endregion

		#region ISerializable Members
		/// <summary>
		/// Populates a <see cref="SerializationInfo"/> with the data needed to serialize this 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("X", _x);
			info.AddValue("Y", _y);
			info.AddValue("Z", _z);
			info.AddValue("W", _w);
		}
		#endregion

		#region Public Static Parse Methods
		/// <summary>
		/// Converts the specified string to its <see cref="Vector4D"/> equivalent.
		/// </summary>
		/// <param name="s">A string representation of a <see cref="Vector4D"/></param>
		/// <returns>A <see cref="Vector4D"/> that represents the vector specified by the <paramref name="s"/> parameter.</returns>
		public static Vector4D Parse(string s)
		{
			throw new NotImplementedException();
		}
		/// <summary>
		/// Converts the specified string to its <see cref="Vector4D"/> equivalent.
		/// </summary>
		/// <param name="reader">A <see cref="TextReader"/> to read the string representation of a <see cref="Vector4D"/> from.</param>
		/// <returns>A <see cref="Vector4D"/> that represents the vector specified by the <paramref name="s"/> parameter.</returns>
		public static Vector4D Parse(TextReader reader)
		{
			throw new NotImplementedException();
		}
		#endregion

		#region Public Static Vector Arithmetics
		/// <summary>
		/// Adds two vectors.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="w">A <see cref="Vector4D"/> instance.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the sum.</returns>
		public static Vector4D Add(Vector4D v, Vector4D w)
		{
			return new Vector4D(v.X + w.X, v.Y + w.Y, v.Z + w.Z, v.W + w.W);
		}
		/// <summary>
		/// Adds a vector and a scalar.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the sum.</returns>
		public static Vector4D Add(Vector4D v, double s)
		{
			return new Vector4D(v.X + s, v.Y + s, v.Z + s, v.W +s);
		}
		/// <summary>
		/// Adds two vectors and put the result in the third vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance</param>
		/// <param name="w">A <see cref="Vector4D"/> instance to hold the result.</param>
		public static void Add(Vector4D u, Vector4D v, Vector4D w)
		{
			w.X = u.X + v.X;
			w.Y = u.Y + v.Y;
			w.Z = u.Z + v.Z;
			w.W = u.W + v.W;
		}
		/// <summary>
		/// Adds a vector and a scalar and put the result into another vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance to hold the result.</param>
		public static void Add(Vector4D u, double s, Vector4D v)
		{
			v.X = u.X + s;
			v.Y = u.Y + s;
			v.Z = u.Z + s;
			v.W = u.W + s;
		}
		/// <summary>
		/// Subtracts a vector from a vector.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="w">A <see cref="Vector4D"/> instance.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the difference.</returns>
		/// <remarks>
		///	result[i] = v[i] - w[i].
		/// </remarks>
		public static Vector4D Subtract(Vector4D v, Vector4D w)
		{
			return new Vector4D(v.X - w.X, v.Y - w.Y, v.Z - w.Z, v.W - w.W);
		}
		/// <summary>
		/// Subtracts a scalar from a vector.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the difference.</returns>
		/// <remarks>
		/// result[i] = v[i] - s
		/// </remarks>
		public static Vector4D Subtract(Vector4D v, double s)
		{
			return new Vector4D(v.X - s, v.Y - s, v.Z - s, v.W - s);
		}
		/// <summary>
		/// Subtracts a vector from a scalar.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the difference.</returns>
		/// <remarks>
		/// result[i] = s - v[i]
		/// </remarks>
		public static Vector4D Subtract(double s, Vector4D v)
		{
			return new Vector4D(s - v.X, s - v.Y, s - v.Z, s - v.W);
		}
		/// <summary>
		/// Subtracts a vector from a second vector and puts the result into a third vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance</param>
		/// <param name="w">A <see cref="Vector4D"/> instance to hold the result.</param>
		/// <remarks>
		///	w[i] = v[i] - w[i].
		/// </remarks>
		public static void Subtract(Vector4D u, Vector4D v, Vector4D w)
		{
			w.X = u.X - v.X;
			w.Y = u.Y - v.Y;
			w.Z = u.Z - v.Z;
			w.W = u.W - v.W;
		}
		/// <summary>
		/// Subtracts a vector from a scalar and put the result into another vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance to hold the result.</param>
		/// <remarks>
		/// v[i] = u[i] - s
		/// </remarks>
		public static void Subtract(Vector4D u, double s, Vector4D v)
		{
			v.X = u.X - s;
			v.Y = u.Y - s;
			v.Z = u.Z - s;
			v.W = u.W - s;
		}
		/// <summary>
		/// Subtracts a scalar from a vector and put the result into another vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance to hold the result.</param>
		/// <remarks>
		/// v[i] = s - u[i]
		/// </remarks>
		public static void Subtract(double s, Vector4D u, Vector4D v)
		{
			v.X = s - u.X;
			v.Y = s - u.Y;
			v.Z = s - u.Z;
			v.W = s - u.W;
		}
		/// <summary>
		/// Divides a vector by another vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <returns>A new <see cref="Vector4D"/> containing the quotient.</returns>
		/// <remarks>
		///	result[i] = u[i] / v[i].
		/// </remarks>
		public static Vector4D Divide(Vector4D u, Vector4D v)
		{
			return new Vector4D(u.X / v.X, u.Y / v.Y, u.Z / v.Z, u.W / v.W);
		}
		/// <summary>
		/// Divides a vector by a scalar.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar</param>
		/// <returns>A new <see cref="Vector4D"/> containing the quotient.</returns>
		/// <remarks>
		/// result[i] = v[i] / s;
		/// </remarks>
		public static Vector4D Divide(Vector4D v, double s)
		{
			return new Vector4D(v.X / s, v.Y / s, v.Z / s, v.W / s);
		}
		/// <summary>
		/// Divides a scalar by a vector.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar</param>
		/// <returns>A new <see cref="Vector4D"/> containing the quotient.</returns>
		/// <remarks>
		/// result[i] = s / v[i]
		/// </remarks>
		public static Vector4D Divide(double s, Vector4D v)
		{
			return new Vector4D(s / v.X, s/ v.Y, s / v.Z, s/ v.W);
		}
		/// <summary>
		/// Divides a vector by another vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="w">A <see cref="Vector4D"/> instance to hold the result.</param>
		/// <remarks>
		/// w[i] = u[i] / v[i]
		/// </remarks>
		public static void Divide(Vector4D u, Vector4D v, Vector4D w)
		{
			w.X = u.X / v.X;
			w.Y = u.Y / v.Y;
			w.Z = u.Z / v.Z;
			w.W = u.W / v.W;
		}
		/// <summary>
		/// Divides a vector by a scalar.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar</param>
		/// <param name="v">A <see cref="Vector4D"/> instance to hold the result.</param>
		/// <remarks>
		/// v[i] = u[i] / s
		/// </remarks>
		public static void Divide(Vector4D u, double s, Vector4D v)
		{
			v.X = u.X / s;
			v.Y = u.Y / s;
			v.Z = u.Z / s;
			v.W = u.W / s;
		}
		/// <summary>
		/// Divides a scalar by a vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar</param>
		/// <param name="v">A <see cref="Vector4D"/> instance to hold the result.</param>
		/// <remarks>
		/// v[i] = s / u[i]
		/// </remarks>
		public static void Divide(double s, Vector4D u, Vector4D v)
		{
			v.X = s / u.X;
			v.Y = s / u.Y;
			v.Z = s / u.Z;
			v.W = s / u.W;
		}
		/// <summary>
		/// Multiplies a vector by a scalar.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> containing the result.</returns>
		public static Vector4D Multiply(Vector4D u, double s)
		{
			return new Vector4D(u.X * s, u.Y * s, u.Z * s, u.W * s);
		}
		/// <summary>
		/// Multiplies a vector by a scalar and put the result in another vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance to hold the result.</param>
		public static void Multiply(Vector4D u, double s, Vector4D v)
		{
			v.X = u.X * s;
			v.Y = u.Y * s;
			v.Z = u.Z * s;
			v.W = u.W * s;
		}
		/// <summary>
		/// Calculates the dot product of two vectors.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <returns>The dot product value.</returns>
		public static double DotProduct(Vector4D u, Vector4D v)
		{
			return (u.X * v.X) + (u.Y * v.Y) + (u.Z * v.Z) + (u.W * v.W);
		}
		/// <summary>
		/// Negates a vector.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the negated values.</returns>
		public static Vector4D Negate(Vector4D v)
		{
			return new Vector4D(-v.X, -v.Y, -v.Z, -v.W);
		}
		/// <summary>
		/// Tests whether two vectors are approximately equal using default tolerance value.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <returns>True if the two vectors are approximately equal; otherwise, False.</returns>
		public static bool ApproxEqual(Vector4D v, Vector4D u)
		{
			return ApproxEqual(v,u, MathFunctions.EpsilonD);
		}
		/// <summary>
		/// Tests whether two vectors are approximately equal given a tolerance value.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="tolerance">The tolerance value used to test approximate equality.</param>
		/// <returns>True if the two vectors are approximately equal; otherwise, False.</returns>
		public static bool ApproxEqual(Vector4D v, Vector4D u, double tolerance)
		{
			return
				(
				(System.Math.Abs(v.X - u.X) <= tolerance) &&
				(System.Math.Abs(v.Y - u.Y) <= tolerance) &&
				(System.Math.Abs(v.Z - u.Z) <= tolerance) &&
				(System.Math.Abs(v.W - u.W) <= tolerance)
				);
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Scale the vector so that its length is 1.
		/// </summary>
		public void Normalize()
		{
			double length = GetLength();
			if (length == 0)
			{
				throw new DivideByZeroException("Trying to normalize a vector with length of zero.");
			}

			_x /= length;
			_y /= length;
			_z /= length;
			_w /= length;
		}
		/// <summary>
		/// Returns the length of the vector.
		/// </summary>
		/// <returns>The length of the vector. (Sqrt(X*X + Y*Y))</returns>
		public double GetLength()
		{
			return System.Math.Sqrt(_x*_x + _y*_y + _z*_z + _w*_w);
		}
		/// <summary>
		/// Returns the squared length of the vector.
		/// </summary>
		/// <returns>The squared length of the vector. (X*X + Y*Y)</returns>
		public double GetLengthSquared()
		{
			return (_x*_x + _y*_y + _z*_z + _w*_w);
		}
		#endregion

		#region Overrides
		/// <summary>
		/// Returns the hashcode for this instance.
		/// </summary>
		/// <returns>A 32-bit signed integer hash code.</returns>
		public override int GetHashCode()
		{
			return _x.GetHashCode() ^ _y.GetHashCode() ^ _z.GetHashCode() ^ _w.GetHashCode();
		}
		/// <summary>
		/// Returns a value indicating whether this instance is equal to
		/// the specified object.
		/// </summary>
		/// <param name="obj">An object to compare to this instance.</param>
		/// <returns>True if <paramref name="obj"/> is a <see cref="Vector4D"/> and has the same values as this instance; otherwise, False.</returns>
		public override bool Equals(object obj)
		{
			if (obj is Vector4D)
			{
				Vector4D v = (Vector4D)obj;
				return (_x == v.X) && (_y == v.Y) && (_z == v.Z) && (_w == v.W);
			}
			return false;
		}

		/// <summary>
		/// Returns a string representation of this object.
		/// </summary>
		/// <returns>A string representation of this object.</returns>
		public override string ToString()
		{
			return string.Format("Vector4D({0}, {1}, {2}, {3})", _x, _y, _z, _w);
		}
		#endregion
		
		#region Comparison Operators
		/// <summary>
		/// Tests whether two specified vectors are equal.
		/// </summary>
		/// <param name="u">The left-hand vector.</param>
		/// <param name="v">The right-hand vector.</param>
		/// <returns>True if the two vectors are equal; otherwise, False.</returns>
		public static bool operator==(Vector4D u, Vector4D v)
		{
			if (Object.Equals(u, null))
			{
				return Object.Equals(v, null);
			}

			if (Object.Equals(v, null))
			{
				return Object.Equals(u, null);
			}

			return (u.X == v.X) && (u.Y == v.Y) && (u.Z == v.Z) && (u.W == v.W);
		}
		/// <summary>
		/// Tests whether two specified vectors are not equal.
		/// </summary>
		/// <param name="u">The left-hand vector.</param>
		/// <param name="v">The right-hand vector.</param>
		/// <returns>True if the two vectors are not equal; otherwise, False.</returns>
		public static bool operator!=(Vector4D u, Vector4D v)
		{
			if (Object.Equals(u, null))
			{
				return !Object.Equals(v, null);
			}

			if (Object.Equals(v, null))
			{
				return !Object.Equals(u, null);
			}

			return !((u.X == v.X) && (u.Y == v.Y) && (u.Z == v.Z) && (u.W == v.W));
		}

		#endregion

		#region Unary Operators
		/// <summary>
		/// Negates the values of the vector.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the negated values.</returns>
		public static Vector4D operator-(Vector4D v)
		{
			return Vector4D.Negate(v);
		}
		#endregion

		#region Binary Operators
		/// <summary>
		/// Adds two vectors.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the sum.</returns>
		public static Vector4D operator+(Vector4D u, Vector4D v)
		{
			return Vector4D.Add(u,v);
		}
		/// <summary>
		/// Adds a vector and a scalar.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the sum.</returns>
		public static Vector4D operator+(Vector4D v, double s)
		{
			return Vector4D.Add(v,s);
		}
		/// <summary>
		/// Adds a vector and a scalar.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the sum.</returns>
		public static Vector4D operator+(double s, Vector4D v)
		{
			return Vector4D.Add(v,s);
		}
		/// <summary>
		/// Subtracts a vector from a vector.
		/// </summary>
		/// <param name="u">A <see cref="Vector4D"/> instance.</param>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the difference.</returns>
		/// <remarks>
		///	result[i] = v[i] - w[i].
		/// </remarks>
		public static Vector4D operator-(Vector4D u, Vector4D v)
		{
			return Vector4D.Subtract(u,v);
		}
		/// <summary>
		/// Subtracts a scalar from a vector.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the difference.</returns>
		/// <remarks>
		/// result[i] = v[i] - s
		/// </remarks>
		public static Vector4D operator-(Vector4D v, double s)
		{
			return Vector4D.Subtract(v, s);
		}
		/// <summary>
		/// Subtracts a vector from a scalar.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> instance containing the difference.</returns>
		/// <remarks>
		/// result[i] = s - v[i]
		/// </remarks>
		public static Vector4D operator-(double s, Vector4D v)
		{
			return Vector4D.Subtract(s, v);
		}

		/// <summary>
		/// Multiplies a vector by a scalar.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> containing the result.</returns>
		public static Vector4D operator*(Vector4D v, double s)
		{
			return Vector4D.Multiply(v,s);
		}
		/// <summary>
		/// Multiplies a vector by a scalar.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar.</param>
		/// <returns>A new <see cref="Vector4D"/> containing the result.</returns>
		public static Vector4D operator*(double s, Vector4D v)
		{
			return Vector4D.Multiply(v,s);
		}
		/// <summary>
		/// Divides a vector by a scalar.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar</param>
		/// <returns>A new <see cref="Vector4D"/> containing the quotient.</returns>
		/// <remarks>
		/// result[i] = v[i] / s;
		/// </remarks>
		public static Vector4D operator/(Vector4D v, double s)
		{
			return Vector4D.Divide(v,s);
		}
		/// <summary>
		/// Divides a scalar by a vector.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <param name="s">A scalar</param>
		/// <returns>A new <see cref="Vector4D"/> containing the quotient.</returns>
		/// <remarks>
		/// result[i] = s / v[i]
		/// </remarks>
		public static Vector4D operator/(double s, Vector4D v)
		{
			return Vector4D.Divide(s,v);
		}
		#endregion

		#region Array Indexing Operator
		/// <summary>
		/// Indexer ( [x, y] ).
		/// </summary>
		public double this[int index]
		{
			get	
			{
				switch( index ) 
				{
					case 0:
						return _x;
					case 1:
						return _y;
					case 2:
						return _z;
					case 3:
						return _w;
					default:
						throw new IndexOutOfRangeException();
				}
			}
			set 
			{
				switch( index ) 
				{
					case 0:
						_x = value;
						break;
					case 1:
						_y = value;
						break;
					case 2:
						_z = value;
						break;
					case 3:
						_w = value;
						break;
					default:
						throw new IndexOutOfRangeException();
				}
			}

		}

		#endregion

		#region Conversion Operators
		/// <summary>
		/// Converts the vector to an array of double-precision floating point values.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <returns>An array of double-precision floating point values.</returns>
		public static explicit operator double[](Vector4D v)
		{
			double[] array = new double[4];
			array[0] = v.X;
			array[1] = v.Y;
			array[2] = v.Z;
			array[3] = v.W;
			return array;
		}
		/// <summary>
		/// Converts the vector to an array of double-precision floating point values.
		/// </summary>
		/// <param name="v">A <see cref="Vector4D"/> instance.</param>
		/// <returns>An array of double-precision floating point values.</returns>
		public static explicit operator DoubleArrayList(Vector4D v)
		{
			DoubleArrayList array = new DoubleArrayList(4);
			array[0] = v.X;
			array[1] = v.Y;
			array[2] = v.Z;
			array[3] = v.W;
			return array;
		}
		#endregion
	}

	#region TestVector4D
	/// <summary>
	/// Tests the Vector4D class.
	/// </summary>
	[TestFixture]
	public class TestVector4D
	{
		/// <summary>
		/// Tests vector initialization.
		/// </summary>
		[Test]
		public void Initialization()
		{
			Vector4D v;

			v = Vector4D.Zero;
			Assert.IsTrue( (v.X == 0) && (v.Y == 0) && (v.Z == 0) && (v.W == 0) );

			v = Vector4D.XAxis;
			Assert.IsTrue( (v.X == 1) && (v.Y == 0) && (v.Z == 0) && (v.W == 0) );

			v = Vector4D.YAxis;
			Assert.IsTrue( (v.X == 0) && (v.Y == 1) && (v.Z == 0) && (v.W == 0) );

			v = Vector4D.ZAxis;
			Assert.IsTrue( (v.X == 0) && (v.Y == 0) && (v.Z == 1) && (v.W == 0) );

			v = Vector4D.WAxis;
			Assert.IsTrue( (v.X == 0) && (v.Y == 0) && (v.Z == 0) && (v.W == 1) );

			v = new Vector4D(0.1, 0.2, 0.3, 0.4);
			Assert.IsTrue( (v.X == 0.1) && (v.Y == 0.2) && (v.Z == 0.3) && (v.W == 0.4) );

			double[] coordinates = {0.1 , 0.2, 0.3, 0.4};
			v = new Vector4D(coordinates);
			Assert.IsTrue( (v.X == 0.1) && (v.Y == 0.2) && (v.Z == 0.3) && (v.W == 0.4) );

			v = new Vector4D(new Vector4D(0.1, 0.2, 0.3, 0.4));
			Assert.IsTrue( (v.X == 0.1) && (v.Y == 0.2) && (v.Z == 0.3) && (v.W == 0.4) );
		}

		/// <summary>
		/// Tests vector accessors.
		/// </summary>
		[Test]
		public void Accessors()
		{
			Vector4D v = new Vector4D(0.1, 0.2, 0.3, 0.4);
			Assertion.AssertEquals(v.X, v[0]);
			Assertion.AssertEquals(v.Y, v[1]);
			Assertion.AssertEquals(v.Z, v[2]);
			Assertion.AssertEquals(v.W, v[3]);
		}

		/// <summary>
		/// Tests unary operators.
		/// </summary>
		public void UnaryOperators()
		{
			Vector4D v = new Vector4D(0.1, 0.2, 0.3, 0.4);
			Assertion.Assert(Vector4D.ApproxEqual(-v, new Vector4D(-0.1, -0.2, -0.3, -0.4)));
		}
		/// <summary>
		/// Tests binary operators.
		/// </summary>
		[Test]
		public void BinaryOperators()
		{
			Vector4D v = new Vector4D(0.1, 0.2, 0.3, 0.4);

			// Scalar operators

			v += 1.0f;
			Assertion.Assert(Vector4D.ApproxEqual(v, new Vector4D(1.1, 1.2, 1.3, 1.4)));

			v -= 1.0f;
			Assertion.Assert(Vector4D.ApproxEqual(v, new Vector4D(0.1, 0.2, 0.3, 0.4)));

			v = v * 2.0f;
			Assertion.Assert(Vector4D.ApproxEqual(v, new Vector4D(0.2, 0.4, 0.6, 0.8)));

			v = v / 2.0f;
			Assertion.Assert(Vector4D.ApproxEqual(v, new Vector4D(0.1, 0.2, 0.3, 0.4)));

			v = 2.0f * v;
			Assertion.Assert(Vector4D.ApproxEqual(v, new Vector4D(0.2, 0.4, 0.6, 0.8)));

			v.X = 2; v.Y = 2; v.Z = 2; v.W = 2;
			v = 1 / v;
			Assertion.Assert(Vector4D.ApproxEqual(v, new Vector4D(0.5, 0.5, 0.5, 0.5)));

			// Vector operators
			v = new Vector4D(1,2,3,4) + new Vector4D(3,4,5,6);
			Assertion.Assert(Vector4D.ApproxEqual(v, new Vector4D(4, 6, 8, 10)));

			v = new Vector4D(1,2,3,4) - new Vector4D(3,4,5,6);
			Assertion.Assert(Vector4D.ApproxEqual(v, new Vector4D(-2, -2, -2, -2)));
		}
		/// <summary>
		/// Tests comparison operators.
		/// </summary>
		[Test]
		public void ComparisonOperators()
		{
			Assert.IsTrue(new Vector4D(2,3,4,5) != new Vector4D(3,10,4,5));
			Assert.IsFalse(new Vector4D(2,3,4,5) == new Vector4D(3,10,4,5));
            
			Assert.IsFalse(new Vector4D(3,4,5,6) != new Vector4D(3,4,5,6));
			Assert.IsTrue(new Vector4D(3,4,5,6) == new Vector4D(3,4,5,6));
		}
		/// <summary>
		/// Tests the vector length methods.
		/// </summary>
		[Test]
		public void Length()
		{
			Vector4D v = new Vector4D(0.1, 0.2, 0.3, 0.4);
			Assertion.Assert(MathFunctions.ApproxEquals(v.GetLength() * v.GetLength(), v.GetLengthSquared()));
		}
	}
	#endregion
}

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