/* Copyright (C) <2009-2011> * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ using System; namespace TrueSync { /// /// A vector structure. /// public struct TSVector { private static FP ZeroEpsilonSq = TSMath.Epsilon; internal static TSVector InternalZero; internal static TSVector Arbitrary; /// The X component of the vector. public FP x; /// The Y component of the vector. public FP y; /// The Z component of the vector. public FP z; #region Static readonly variables /// /// A vector with components (0,0,0); /// public static readonly TSVector zero; /// /// A vector with components (-1,0,0); /// public static readonly TSVector left; /// /// A vector with components (1,0,0); /// public static readonly TSVector right; /// /// A vector with components (0,1,0); /// public static readonly TSVector up; /// /// A vector with components (0,-1,0); /// public static readonly TSVector down; /// /// A vector with components (0,0,-1); /// public static readonly TSVector back; /// /// A vector with components (0,0,1); /// public static readonly TSVector forward; /// /// A vector with components (1,1,1); /// public static readonly TSVector one; /// /// A vector with components /// (FP.MinValue,FP.MinValue,FP.MinValue); /// public static readonly TSVector MinValue; /// /// A vector with components /// (FP.MaxValue,FP.MaxValue,FP.MaxValue); /// public static readonly TSVector MaxValue; #endregion #region Private static constructor static TSVector() { one = new TSVector(1, 1, 1); zero = new TSVector(0, 0, 0); left = new TSVector(-1, 0, 0); right = new TSVector(1, 0, 0); up = new TSVector(0, 1, 0); down = new TSVector(0, -1, 0); back = new TSVector(0, 0, -1); forward = new TSVector(0, 0, 1); MinValue = new TSVector(FP.MinValue); MaxValue = new TSVector(FP.MaxValue); Arbitrary = new TSVector(1, 1, 1); InternalZero = zero; } #endregion public static TSVector Abs(TSVector other) { return new TSVector(FP.Abs(other.x), FP.Abs(other.y), FP.Abs(other.z)); } /// /// Gets the squared length of the vector. /// /// Returns the squared length of the vector. public FP sqrMagnitude { get { return (((this.x * this.x) + (this.y * this.y)) + (this.z * this.z)); } } /// /// Gets the length of the vector. /// /// Returns the length of the vector. public FP magnitude { get { FP num = ((this.x * this.x) + (this.y * this.y)) + (this.z * this.z); return FP.Sqrt(num); } } public static TSVector ClampMagnitude(TSVector vector, FP maxLength) { return Normalize(vector) * maxLength; } /// /// Gets a normalized version of the vector. /// /// Returns a normalized version of the vector. public TSVector normalized { get { TSVector result = new TSVector(this.x, this.y, this.z); result.Normalize(); return result; } } /// /// Constructor initializing a new instance of the structure /// /// The X component of the vector. /// The Y component of the vector. /// The Z component of the vector. public TSVector(int x,int y,int z) { this.x = (FP)x; this.y = (FP)y; this.z = (FP)z; } public TSVector(FP x, FP y, FP z) { this.x = x; this.y = y; this.z = z; } /// /// Multiplies each component of the vector by the same components of the provided vector. /// public void Scale(TSVector other) { this.x = x * other.x; this.y = y * other.y; this.z = z * other.z; } /// /// Sets all vector component to specific values. /// /// The X component of the vector. /// The Y component of the vector. /// The Z component of the vector. public void Set(FP x, FP y, FP z) { this.x = x; this.y = y; this.z = z; } /// /// Constructor initializing a new instance of the structure /// /// All components of the vector are set to xyz public TSVector(FP xyz) { this.x = xyz; this.y = xyz; this.z = xyz; } public static TSVector Lerp(TSVector from, TSVector to, FP percent) { return from + (to - from) * percent; } /// /// Builds a string from the JVector. /// /// A string containing all three components. #region public override string ToString() public override string ToString() { return string.Format("({0:f1}, {1:f1}, {2:f1})", x.AsFloat(), y.AsFloat(), z.AsFloat()); } #endregion /// /// Tests if an object is equal to this vector. /// /// The object to test. /// Returns true if they are euqal, otherwise false. #region public override bool Equals(object obj) public override bool Equals(object obj) { if (!(obj is TSVector)) return false; TSVector other = (TSVector)obj; return (((x == other.x) && (y == other.y)) && (z == other.z)); } #endregion /// /// Multiplies each component of the vector by the same components of the provided vector. /// public static TSVector Scale(TSVector vecA, TSVector vecB) { TSVector result; result.x = vecA.x * vecB.x; result.y = vecA.y * vecB.y; result.z = vecA.z * vecB.z; return result; } /// /// Tests if two JVector are equal. /// /// The first value. /// The second value. /// Returns true if both values are equal, otherwise false. #region public static bool operator ==(JVector value1, JVector value2) public static bool operator ==(TSVector value1, TSVector value2) { return (((value1.x == value2.x) && (value1.y == value2.y)) && (value1.z == value2.z)); } #endregion /// /// Tests if two JVector are not equal. /// /// The first value. /// The second value. /// Returns false if both values are equal, otherwise true. #region public static bool operator !=(JVector value1, JVector value2) public static bool operator !=(TSVector value1, TSVector value2) { if ((value1.x == value2.x) && (value1.y == value2.y)) { return (value1.z != value2.z); } return true; } #endregion /// /// Gets a vector with the minimum x,y and z values of both vectors. /// /// The first value. /// The second value. /// A vector with the minimum x,y and z values of both vectors. #region public static JVector Min(JVector value1, JVector value2) public static TSVector Min(TSVector value1, TSVector value2) { TSVector result; TSVector.Min(ref value1, ref value2, out result); return result; } /// /// Gets a vector with the minimum x,y and z values of both vectors. /// /// The first value. /// The second value. /// A vector with the minimum x,y and z values of both vectors. public static void Min(ref TSVector value1, ref TSVector value2, out TSVector result) { result.x = (value1.x < value2.x) ? value1.x : value2.x; result.y = (value1.y < value2.y) ? value1.y : value2.y; result.z = (value1.z < value2.z) ? value1.z : value2.z; } #endregion /// /// Gets a vector with the maximum x,y and z values of both vectors. /// /// The first value. /// The second value. /// A vector with the maximum x,y and z values of both vectors. #region public static JVector Max(JVector value1, JVector value2) public static TSVector Max(TSVector value1, TSVector value2) { TSVector result; TSVector.Max(ref value1, ref value2, out result); return result; } public static FP Distance(TSVector v1, TSVector v2) { return FP.Sqrt ((v1.x - v2.x) * (v1.x - v2.x) + (v1.y - v2.y) * (v1.y - v2.y) + (v1.z - v2.z) * (v1.z - v2.z)); } /// /// Gets a vector with the maximum x,y and z values of both vectors. /// /// The first value. /// The second value. /// A vector with the maximum x,y and z values of both vectors. public static void Max(ref TSVector value1, ref TSVector value2, out TSVector result) { result.x = (value1.x > value2.x) ? value1.x : value2.x; result.y = (value1.y > value2.y) ? value1.y : value2.y; result.z = (value1.z > value2.z) ? value1.z : value2.z; } #endregion /// /// Sets the length of the vector to zero. /// #region public void MakeZero() public void MakeZero() { x = FP.Zero; y = FP.Zero; z = FP.Zero; } #endregion /// /// Checks if the length of the vector is zero. /// /// Returns true if the vector is zero, otherwise false. #region public bool IsZero() public bool IsZero() { return (this.sqrMagnitude == FP.Zero); } /// /// Checks if the length of the vector is nearly zero. /// /// Returns true if the vector is nearly zero, otherwise false. public bool IsNearlyZero() { return (this.sqrMagnitude < ZeroEpsilonSq); } #endregion /// /// Transforms a vector by the given matrix. /// /// The vector to transform. /// The transform matrix. /// The transformed vector. #region public static JVector Transform(JVector position, JMatrix matrix) public static TSVector Transform(TSVector position, TSMatrix matrix) { TSVector result; TSVector.Transform(ref position, ref matrix, out result); return result; } /// /// Transforms a vector by the given matrix. /// /// The vector to transform. /// The transform matrix. /// The transformed vector. public static void Transform(ref TSVector position, ref TSMatrix matrix, out TSVector result) { FP num0 = ((position.x * matrix.M11) + (position.y * matrix.M21)) + (position.z * matrix.M31); FP num1 = ((position.x * matrix.M12) + (position.y * matrix.M22)) + (position.z * matrix.M32); FP num2 = ((position.x * matrix.M13) + (position.y * matrix.M23)) + (position.z * matrix.M33); result.x = num0; result.y = num1; result.z = num2; } /// /// Transforms a vector by the transposed of the given Matrix. /// /// The vector to transform. /// The transform matrix. /// The transformed vector. public static void TransposedTransform(ref TSVector position, ref TSMatrix matrix, out TSVector result) { FP num0 = ((position.x * matrix.M11) + (position.y * matrix.M12)) + (position.z * matrix.M13); FP num1 = ((position.x * matrix.M21) + (position.y * matrix.M22)) + (position.z * matrix.M23); FP num2 = ((position.x * matrix.M31) + (position.y * matrix.M32)) + (position.z * matrix.M33); result.x = num0; result.y = num1; result.z = num2; } #endregion /// /// Calculates the dot product of two vectors. /// /// The first vector. /// The second vector. /// Returns the dot product of both vectors. #region public static FP Dot(JVector vector1, JVector vector2) public static FP Dot(TSVector vector1, TSVector vector2) { return TSVector.Dot(ref vector1, ref vector2); } /// /// Calculates the dot product of both vectors. /// /// The first vector. /// The second vector. /// Returns the dot product of both vectors. public static FP Dot(ref TSVector vector1, ref TSVector vector2) { return ((vector1.x * vector2.x) + (vector1.y * vector2.y)) + (vector1.z * vector2.z); } #endregion // Projects a vector onto another vector. public static TSVector Project(TSVector vector, TSVector onNormal) { FP sqrtMag = Dot(onNormal, onNormal); if (sqrtMag < TSMath.Epsilon) return zero; else return onNormal * Dot(vector, onNormal) / sqrtMag; } // Projects a vector onto a plane defined by a normal orthogonal to the plane. public static TSVector ProjectOnPlane(TSVector vector, TSVector planeNormal) { return vector - Project(vector, planeNormal); } // Returns the angle in degrees between /from/ and /to/. This is always the smallest public static FP Angle(TSVector from, TSVector to) { return TSMath.Acos(TSMath.Clamp(Dot(from.normalized, to.normalized), -FP.ONE, FP.ONE)) * TSMath.Rad2Deg; } // The smaller of the two possible angles between the two vectors is returned, therefore the result will never be greater than 180 degrees or smaller than -180 degrees. // If you imagine the from and to vectors as lines on a piece of paper, both originating from the same point, then the /axis/ vector would point up out of the paper. // The measured angle between the two vectors would be positive in a clockwise direction and negative in an anti-clockwise direction. public static FP SignedAngle(TSVector from, TSVector to, TSVector axis) { TSVector fromNorm = from.normalized, toNorm = to.normalized; FP unsignedAngle = TSMath.Acos(TSMath.Clamp(Dot(fromNorm, toNorm), -FP.ONE, FP.ONE)) * TSMath.Rad2Deg; FP sign = TSMath.Sign(Dot(axis, Cross(fromNorm, toNorm))); return unsignedAngle * sign; } /// /// Adds two vectors. /// /// The first vector. /// The second vector. /// The sum of both vectors. #region public static void Add(JVector value1, JVector value2) public static TSVector Add(TSVector value1, TSVector value2) { TSVector result; TSVector.Add(ref value1, ref value2, out result); return result; } /// /// Adds to vectors. /// /// The first vector. /// The second vector. /// The sum of both vectors. public static void Add(ref TSVector value1, ref TSVector value2, out TSVector result) { FP num0 = value1.x + value2.x; FP num1 = value1.y + value2.y; FP num2 = value1.z + value2.z; result.x = num0; result.y = num1; result.z = num2; } #endregion /// /// Divides a vector by a factor. /// /// The vector to divide. /// The scale factor. /// Returns the scaled vector. public static TSVector Divide(TSVector value1, FP scaleFactor) { TSVector result; TSVector.Divide(ref value1, scaleFactor, out result); return result; } /// /// Divides a vector by a factor. /// /// The vector to divide. /// The scale factor. /// Returns the scaled vector. public static void Divide(ref TSVector value1, FP scaleFactor, out TSVector result) { result.x = value1.x / scaleFactor; result.y = value1.y / scaleFactor; result.z = value1.z / scaleFactor; } /// /// Subtracts two vectors. /// /// The first vector. /// The second vector. /// The difference of both vectors. #region public static JVector Subtract(JVector value1, JVector value2) public static TSVector Subtract(TSVector value1, TSVector value2) { TSVector result; TSVector.Subtract(ref value1, ref value2, out result); return result; } /// /// Subtracts to vectors. /// /// The first vector. /// The second vector. /// The difference of both vectors. public static void Subtract(ref TSVector value1, ref TSVector value2, out TSVector result) { FP num0 = value1.x - value2.x; FP num1 = value1.y - value2.y; FP num2 = value1.z - value2.z; result.x = num0; result.y = num1; result.z = num2; } #endregion /// /// The cross product of two vectors. /// /// The first vector. /// The second vector. /// The cross product of both vectors. #region public static JVector Cross(JVector vector1, JVector vector2) public static TSVector Cross(TSVector vector1, TSVector vector2) { TSVector result; TSVector.Cross(ref vector1, ref vector2, out result); return result; } /// /// The cross product of two vectors. /// /// The first vector. /// The second vector. /// The cross product of both vectors. public static void Cross(ref TSVector vector1, ref TSVector vector2, out TSVector result) { FP num3 = (vector1.y * vector2.z) - (vector1.z * vector2.y); FP num2 = (vector1.z * vector2.x) - (vector1.x * vector2.z); FP num = (vector1.x * vector2.y) - (vector1.y * vector2.x); result.x = num3; result.y = num2; result.z = num; } #endregion /// /// Gets the hashcode of the vector. /// /// Returns the hashcode of the vector. #region public override int GetHashCode() public override int GetHashCode() { return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); } #endregion /// /// Inverses the direction of the vector. /// #region public static JVector Negate(JVector value) public void Negate() { this.x = -this.x; this.y = -this.y; this.z = -this.z; } /// /// Inverses the direction of a vector. /// /// The vector to inverse. /// The negated vector. public static TSVector Negate(TSVector value) { TSVector result; TSVector.Negate(ref value,out result); return result; } /// /// Inverses the direction of a vector. /// /// The vector to inverse. /// The negated vector. public static void Negate(ref TSVector value, out TSVector result) { FP num0 = -value.x; FP num1 = -value.y; FP num2 = -value.z; result.x = num0; result.y = num1; result.z = num2; } #endregion /// /// Normalizes the given vector. /// /// The vector which should be normalized. /// A normalized vector. #region public static JVector Normalize(JVector value) public static TSVector Normalize(TSVector value) { TSVector result; TSVector.Normalize(ref value, out result); return result; } /// /// Normalizes this vector. /// public void Normalize() { FP num2 = ((this.x * this.x) + (this.y * this.y)) + (this.z * this.z); FP num = FP.One / FP.Sqrt(num2); this.x *= num; this.y *= num; this.z *= num; } /// /// Normalizes the given vector. /// /// The vector which should be normalized. /// A normalized vector. public static void Normalize(ref TSVector value, out TSVector result) { FP num2 = ((value.x * value.x) + (value.y * value.y)) + (value.z * value.z); FP num = FP.One / FP.Sqrt(num2); result.x = value.x * num; result.y = value.y * num; result.z = value.z * num; } #endregion #region public static void Swap(ref JVector vector1, ref JVector vector2) /// /// Swaps the components of both vectors. /// /// The first vector to swap with the second. /// The second vector to swap with the first. public static void Swap(ref TSVector vector1, ref TSVector vector2) { FP temp; temp = vector1.x; vector1.x = vector2.x; vector2.x = temp; temp = vector1.y; vector1.y = vector2.y; vector2.y = temp; temp = vector1.z; vector1.z = vector2.z; vector2.z = temp; } #endregion /// /// Multiply a vector with a factor. /// /// The vector to multiply. /// The scale factor. /// Returns the multiplied vector. #region public static JVector Multiply(JVector value1, FP scaleFactor) public static TSVector Multiply(TSVector value1, FP scaleFactor) { TSVector result; TSVector.Multiply(ref value1, scaleFactor, out result); return result; } /// /// Multiply a vector with a factor. /// /// The vector to multiply. /// The scale factor. /// Returns the multiplied vector. public static void Multiply(ref TSVector value1, FP scaleFactor, out TSVector result) { result.x = value1.x * scaleFactor; result.y = value1.y * scaleFactor; result.z = value1.z * scaleFactor; } #endregion /// /// Calculates the cross product of two vectors. /// /// The first vector. /// The second vector. /// Returns the cross product of both. #region public static JVector operator %(JVector value1, JVector value2) public static TSVector operator %(TSVector value1, TSVector value2) { TSVector result; TSVector.Cross(ref value1, ref value2, out result); return result; } #endregion /// /// Calculates the dot product of two vectors. /// /// The first vector. /// The second vector. /// Returns the dot product of both. #region public static FP operator *(JVector value1, JVector value2) public static FP operator *(TSVector value1, TSVector value2) { return TSVector.Dot(ref value1, ref value2); } #endregion /// /// Multiplies a vector by a scale factor. /// /// The vector to scale. /// The scale factor. /// Returns the scaled vector. #region public static JVector operator *(JVector value1, FP value2) public static TSVector operator *(TSVector value1, FP value2) { TSVector result; TSVector.Multiply(ref value1, value2,out result); return result; } #endregion /// /// Multiplies a vector by a scale factor. /// /// The vector to scale. /// The scale factor. /// Returns the scaled vector. #region public static JVector operator *(FP value1, JVector value2) public static TSVector operator *(FP value1, TSVector value2) { TSVector result; TSVector.Multiply(ref value2, value1, out result); return result; } #endregion /// /// Subtracts two vectors. /// /// The first vector. /// The second vector. /// The difference of both vectors. #region public static JVector operator -(JVector value1, JVector value2) public static TSVector operator -(TSVector value1, TSVector value2) { TSVector result; TSVector.Subtract(ref value1, ref value2, out result); return result; } #endregion /// /// Adds two vectors. /// /// The first vector. /// The second vector. /// The sum of both vectors. #region public static JVector operator +(JVector value1, JVector value2) public static TSVector operator +(TSVector value1, TSVector value2) { TSVector result; TSVector.Add(ref value1, ref value2, out result); return result; } #endregion /// /// Divides a vector by a factor. /// /// The vector to divide. /// The scale factor. /// Returns the scaled vector. public static TSVector operator /(TSVector value1, FP value2) { TSVector result; TSVector.Divide(ref value1, value2, out result); return result; } public TSVector2 ToTSVector2() { return new TSVector2(this.x, this.y); } public TSVector4 ToTSVector4() { return new TSVector4(this.x, this.y, this.z, FP.One); } } }