// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
//
// -----------------------------------------------------------------------------
// Original code from SlimMath project. http://code.google.com/p/slimmath/
// Greetings to SlimDX Group. Original code published with the following license:
// -----------------------------------------------------------------------------
/*
* Copyright (c) 2007-2011 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
namespace math
{
///
/// Represents a three dimensional mathematical vector.
///
[DataContract( Name = "float3")]
[DataStyle(DataStyle.Compact)]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct Vec3 : IEquatable, IFormattable
{
///
/// The size of the type, in bytes.
///
public static readonly int SizeInBytes = lib.Util.SizeOf();
///
/// A with all of its components set to zero.
///
public static readonly Vec3 Zero = new Vec3();
///
/// The X unit (1, 0, 0).
///
public static readonly Vec3 UnitX = new Vec3(1.0f, 0.0f, 0.0f);
///
/// The Y unit (0, 1, 0).
///
public static readonly Vec3 UnitY = new Vec3(0.0f, 1.0f, 0.0f);
///
/// The Z unit (0, 0, 1).
///
public static readonly Vec3 UnitZ = new Vec3(0.0f, 0.0f, 1.0f);
///
/// A with all of its components set to one.
///
public static readonly Vec3 One = new Vec3(1.0f, 1.0f, 1.0f);
///
/// The X component of the vector.
///
[DataMember( Order = 0 )]
public float X;
///
/// The Y component of the vector.
///
[DataMember( Order = 1 )]
public float Y;
///
/// The Z component of the vector.
///
[DataMember( Order = 2 )]
public float Z;
///
/// Initializes a new instance of the struct.
///
/// The value that will be assigned to all components.
public Vec3(float value)
{
X = value;
Y = value;
Z = value;
}
///
/// Initializes a new instance of the struct.
///
/// Initial value for the X component of the vector.
/// Initial value for the Y component of the vector.
/// Initial value for the Z component of the vector.
public Vec3(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
///
/// Initializes a new instance of the struct.
///
/// A vector containing the values with which to initialize the X and Y components.
/// Initial value for the Z component of the vector.
public Vec3(Vec2 value, float z)
{
X = value.X;
Y = value.Y;
Z = z;
}
///
/// Initializes a new instance of the struct.
///
/// The values to assign to the X, Y, and Z components of the vector. This must be an array with three elements.
/// Thrown when is null.
/// Thrown when contains more or less than three elements.
public Vec3(float[] values)
{
if (values == null)
throw new ArgumentNullException("values");
if (values.Length != 3)
throw new ArgumentOutOfRangeException("values", "There must be three and only three input values for Vector3.");
X = values[0];
Y = values[1];
Z = values[2];
}
///
/// Gets a value indicting whether this instance is normalized.
///
public bool IsNormalized
{
get { return Math.Abs((X * X) + (Y * Y) + (Z * Z) - 1f) < MathUtil.ZeroTolerance; }
}
///
/// Gets or sets the component at the specified index.
///
/// The value of the X, Y, or Z component, depending on the index.
/// The index of the component to access. Use 0 for the X component, 1 for the Y component, and 2 for the Z component.
/// The value of the component at the specified index.
/// Thrown when the is out of the range [0, 2].
public float this[int index]
{
get
{
switch (index)
{
case 0: return X;
case 1: return Y;
case 2: return Z;
}
throw new ArgumentOutOfRangeException("index", "Indices for Vector3 run from 0 to 2, inclusive.");
}
set
{
switch (index)
{
case 0: X = value; break;
case 1: Y = value; break;
case 2: Z = value; break;
default: throw new ArgumentOutOfRangeException("index", "Indices for Vector3 run from 0 to 2, inclusive.");
}
}
}
///
/// Calculates the length of the vector.
///
/// The length of the vector.
///
/// may be preferred when only the relative length is needed
/// and speed is of the essence.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float Length()
{
return (float)Math.Sqrt((X * X) + (Y * Y) + (Z * Z));
}
///
/// Calculates the squared length of the vector.
///
/// The squared length of the vector.
///
/// This method may be preferred to when only a relative length is needed
/// and speed is of the essence.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float LengthSquared()
{
return (X * X) + (Y * Y) + (Z * Z);
}
///
/// Converts the vector into a unit vector.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Normalize()
{
float length = Length();
if (length > MathUtil.ZeroTolerance)
{
float inv = 1.0f / length;
X *= inv;
Y *= inv;
Z *= inv;
}
}
///
/// Raises the exponent for each components.
///
/// The exponent.
public void Pow(float exponent)
{
X = (float)Math.Pow(X, exponent);
Y = (float)Math.Pow(Y, exponent);
Z = (float)Math.Pow(Z, exponent);
}
///
/// Creates an array containing the elements of the vector.
///
/// A three-element array containing the components of the vector.
public float[] ToArray()
{
return new float[] { X, Y, Z };
}
///
/// Adds two vectors.
///
/// The first vector to add.
/// The second vector to add.
/// When the method completes, contains the sum of the two vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add(ref Vec3 left, ref Vec3 right, out Vec3 result)
{
result = new Vec3(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
}
///
/// Adds two vectors.
///
/// The first vector to add.
/// The second vector to add.
/// The sum of the two vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Add(Vec3 left, Vec3 right)
{
return new Vec3(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
}
///
/// Subtracts two vectors.
///
/// The first vector to subtract.
/// The second vector to subtract.
/// When the method completes, contains the difference of the two vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Subtract(ref Vec3 left, ref Vec3 right, out Vec3 result)
{
result = new Vec3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
}
///
/// Subtracts two vectors.
///
/// The first vector to subtract.
/// The second vector to subtract.
/// The difference of the two vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Subtract(Vec3 left, Vec3 right)
{
return new Vec3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
}
///
/// Scales a vector by the given value.
///
/// The vector to scale.
/// The amount by which to scale the vector.
/// When the method completes, contains the scaled vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Multiply(ref Vec3 value, float scale, out Vec3 result)
{
result = new Vec3(value.X * scale, value.Y * scale, value.Z * scale);
}
///
/// Scales a vector by the given value.
///
/// The vector to scale.
/// The amount by which to scale the vector.
/// The scaled vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Multiply(Vec3 value, float scale)
{
return new Vec3(value.X * scale, value.Y * scale, value.Z * scale);
}
///
/// Modulates a vector with another by performing component-wise multiplication.
///
/// The first vector to modulate.
/// The second vector to modulate.
/// When the method completes, contains the modulated vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Modulate(ref Vec3 left, ref Vec3 right, out Vec3 result)
{
result = new Vec3(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
}
///
/// Modulates a vector with another by performing component-wise multiplication.
///
/// The first vector to modulate.
/// The second vector to modulate.
/// The modulated vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Modulate(Vec3 left, Vec3 right)
{
return new Vec3(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
}
///
/// Scales a vector by the given value.
///
/// The vector to scale.
/// The amount by which to scale the vector.
/// When the method completes, contains the scaled vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Divide(ref Vec3 value, float scale, out Vec3 result)
{
result = new Vec3(value.X / scale, value.Y / scale, value.Z / scale);
}
///
/// Scales a vector by the given value.
///
/// The vector to scale.
/// The amount by which to scale the vector.
/// The scaled vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Divide(Vec3 value, float scale)
{
return new Vec3(value.X / scale, value.Y / scale, value.Z / scale);
}
///
/// Demodulates a vector with another by performing component-wise division.
///
/// The first vector to demodulate.
/// The second vector to demodulate.
/// When the method completes, contains the demodulated vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Demodulate(ref Vec3 left, ref Vec3 right, out Vec3 result)
{
result = new Vec3(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
}
///
/// Demodulates a vector with another by performing component-wise division.
///
/// The first vector to demodulate.
/// The second vector to demodulate.
/// The demodulated vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Demodulate(Vec3 left, Vec3 right)
{
return new Vec3(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
}
///
/// Reverses the direction of a given vector.
///
/// The vector to negate.
/// When the method completes, contains a vector facing in the opposite direction.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Negate(ref Vec3 value, out Vec3 result)
{
result = new Vec3(-value.X, -value.Y, -value.Z);
}
///
/// Reverses the direction of a given vector.
///
/// The vector to negate.
/// A vector facing in the opposite direction.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Negate(Vec3 value)
{
return new Vec3(-value.X, -value.Y, -value.Z);
}
///
/// Returns a containing the 3D Cartesian coordinates of a point specified in Barycentric coordinates relative to a 3D triangle.
///
/// A containing the 3D Cartesian coordinates of vertex 1 of the triangle.
/// A containing the 3D Cartesian coordinates of vertex 2 of the triangle.
/// A containing the 3D Cartesian coordinates of vertex 3 of the triangle.
/// Barycentric coordinate b2, which expresses the weighting factor toward vertex 2 (specified in ).
/// Barycentric coordinate b3, which expresses the weighting factor toward vertex 3 (specified in ).
/// When the method completes, contains the 3D Cartesian coordinates of the specified point.
public static void Barycentric(ref Vec3 value1, ref Vec3 value2, ref Vec3 value3, float amount1, float amount2, out Vec3 result)
{
result = new Vec3(
(value1.X + (amount1 * (value2.X - value1.X))) + (amount2 * (value3.X - value1.X)),
(value1.Y + (amount1 * (value2.Y - value1.Y))) + (amount2 * (value3.Y - value1.Y)),
(value1.Z + (amount1 * (value2.Z - value1.Z))) + (amount2 * (value3.Z - value1.Z)));
}
///
/// Returns a containing the 3D Cartesian coordinates of a point specified in Barycentric coordinates relative to a 3D triangle.
///
/// A containing the 3D Cartesian coordinates of vertex 1 of the triangle.
/// A containing the 3D Cartesian coordinates of vertex 2 of the triangle.
/// A containing the 3D Cartesian coordinates of vertex 3 of the triangle.
/// Barycentric coordinate b2, which expresses the weighting factor toward vertex 2 (specified in ).
/// Barycentric coordinate b3, which expresses the weighting factor toward vertex 3 (specified in ).
/// A new containing the 3D Cartesian coordinates of the specified point.
public static Vec3 Barycentric(Vec3 value1, Vec3 value2, Vec3 value3, float amount1, float amount2)
{
Vec3 result;
Barycentric(ref value1, ref value2, ref value3, amount1, amount2, out result);
return result;
}
///
/// Restricts a value to be within a specified range.
///
/// The value to clamp.
/// The minimum value.
/// The maximum value.
/// When the method completes, contains the clamped value.
public static void Clamp(ref Vec3 value, ref Vec3 min, ref Vec3 max, out Vec3 result)
{
float x = value.X;
x = (x > max.X) ? max.X : x;
x = (x < min.X) ? min.X : x;
float y = value.Y;
y = (y > max.Y) ? max.Y : y;
y = (y < min.Y) ? min.Y : y;
float z = value.Z;
z = (z > max.Z) ? max.Z : z;
z = (z < min.Z) ? min.Z : z;
result = new Vec3(x, y, z);
}
///
/// Restricts a value to be within a specified range.
///
/// The value to clamp.
/// The minimum value.
/// The maximum value.
/// The clamped value.
public static Vec3 Clamp(Vec3 value, Vec3 min, Vec3 max)
{
Vec3 result;
Clamp(ref value, ref min, ref max, out result);
return result;
}
///
/// Calculates the cross product of two vectors.
///
/// First source vector.
/// Second source vector.
/// When the method completes, contains he cross product of the two vectors.
public static void Cross(ref Vec3 left, ref Vec3 right, out Vec3 result)
{
result = new Vec3(
(left.Y * right.Z) - (left.Z * right.Y),
(left.Z * right.X) - (left.X * right.Z),
(left.X * right.Y) - (left.Y * right.X));
}
///
/// Calculates the cross product of two vectors.
///
/// First source vector.
/// Second source vector.
/// The cross product of the two vectors.
public static Vec3 Cross(Vec3 left, Vec3 right)
{
Vec3 result;
Cross(ref left, ref right, out result);
return result;
}
///
/// Calculates the distance between two vectors.
///
/// The first vector.
/// The second vector.
/// When the method completes, contains the distance between the two vectors.
///
/// may be preferred when only the relative distance is needed
/// and speed is of the essence.
///
public static void Distance(ref Vec3 value1, ref Vec3 value2, out float result)
{
float x = value1.X - value2.X;
float y = value1.Y - value2.Y;
float z = value1.Z - value2.Z;
result = (float)Math.Sqrt((x * x) + (y * y) + (z * z));
}
///
/// Calculates the distance between two vectors.
///
/// The first vector.
/// The second vector.
/// The distance between the two vectors.
///
/// may be preferred when only the relative distance is needed
/// and speed is of the essence.
///
public static float Distance(Vec3 value1, Vec3 value2)
{
float x = value1.X - value2.X;
float y = value1.Y - value2.Y;
float z = value1.Z - value2.Z;
return (float)Math.Sqrt((x * x) + (y * y) + (z * z));
}
///
/// Calculates the squared distance between two vectors.
///
/// The first vector.
/// The second vector.
/// When the method completes, contains the squared distance between the two vectors.
/// Distance squared is the value before taking the square root.
/// Distance squared can often be used in place of distance if relative comparisons are being made.
/// For example, consider three points A, B, and C. To determine whether B or C is further from A,
/// compare the distance between A and B to the distance between A and C. Calculating the two distances
/// involves two square roots, which are computationally expensive. However, using distance squared
/// provides the same information and avoids calculating two square roots.
///
public static void DistanceSquared(ref Vec3 value1, ref Vec3 value2, out float result)
{
float x = value1.X - value2.X;
float y = value1.Y - value2.Y;
float z = value1.Z - value2.Z;
result = (x * x) + (y * y) + (z * z);
}
///
/// Calculates the squared distance between two vectors.
///
/// The first vector.
/// The second vector.
/// The squared distance between the two vectors.
/// Distance squared is the value before taking the square root.
/// Distance squared can often be used in place of distance if relative comparisons are being made.
/// For example, consider three points A, B, and C. To determine whether B or C is further from A,
/// compare the distance between A and B to the distance between A and C. Calculating the two distances
/// involves two square roots, which are computationally expensive. However, using distance squared
/// provides the same information and avoids calculating two square roots.
///
public static float DistanceSquared(Vec3 value1, Vec3 value2)
{
float x = value1.X - value2.X;
float y = value1.Y - value2.Y;
float z = value1.Z - value2.Z;
return (x * x) + (y * y) + (z * z);
}
///
/// Calculates the dot product of two vectors.
///
/// First source vector.
/// Second source vector.
/// When the method completes, contains the dot product of the two vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Dot(ref Vec3 left, ref Vec3 right, out float result)
{
result = (left.X * right.X) + (left.Y * right.Y) + (left.Z * right.Z);
}
///
/// Calculates the dot product of two vectors.
///
/// First source vector.
/// Second source vector.
/// The dot product of the two vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Dot(Vec3 left, Vec3 right)
{
return (left.X * right.X) + (left.Y * right.Y) + (left.Z * right.Z);
}
///
/// Converts the vector into a unit vector.
///
/// The vector to normalize.
/// When the method completes, contains the normalized vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Normalize(ref Vec3 value, out Vec3 result)
{
result = value;
result.Normalize();
}
///
/// Converts the vector into a unit vector.
///
/// The vector to normalize.
/// The normalized vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Normalize(Vec3 value)
{
value.Normalize();
return value;
}
///
/// Performs a linear interpolation between two vectors.
///
/// Start vector.
/// End vector.
/// Value between 0 and 1 indicating the weight of .
/// When the method completes, contains the linear interpolation of the two vectors.
///
/// This method performs the linear interpolation based on the following formula.
/// start + (end - start) * amount
/// Passing a value of 0 will cause to be returned; a value of 1 will cause to be returned.
///
public static void Lerp(ref Vec3 start, ref Vec3 end, float amount, out Vec3 result)
{
result.X = start.X + ((end.X - start.X) * amount);
result.Y = start.Y + ((end.Y - start.Y) * amount);
result.Z = start.Z + ((end.Z - start.Z) * amount);
}
///
/// Performs a linear interpolation between two vectors.
///
/// Start vector.
/// End vector.
/// Value between 0 and 1 indicating the weight of .
/// The linear interpolation of the two vectors.
///
/// This method performs the linear interpolation based on the following formula.
/// start + (end - start) * amount
/// Passing a value of 0 will cause to be returned; a value of 1 will cause to be returned.
///
public static Vec3 Lerp(Vec3 start, Vec3 end, float amount)
{
Vec3 result;
Lerp(ref start, ref end, amount, out result);
return result;
}
///
/// Performs a cubic interpolation between two vectors.
///
/// Start vector.
/// End vector.
/// Value between 0 and 1 indicating the weight of .
/// When the method completes, contains the cubic interpolation of the two vectors.
public static void SmoothStep(ref Vec3 start, ref Vec3 end, float amount, out Vec3 result)
{
amount = (amount > 1.0f) ? 1.0f : ((amount < 0.0f) ? 0.0f : amount);
amount = (amount * amount) * (3.0f - (2.0f * amount));
result.X = start.X + ((end.X - start.X) * amount);
result.Y = start.Y + ((end.Y - start.Y) * amount);
result.Z = start.Z + ((end.Z - start.Z) * amount);
}
///
/// Performs a cubic interpolation between two vectors.
///
/// Start vector.
/// End vector.
/// Value between 0 and 1 indicating the weight of .
/// The cubic interpolation of the two vectors.
public static Vec3 SmoothStep(Vec3 start, Vec3 end, float amount)
{
Vec3 result;
SmoothStep(ref start, ref end, amount, out result);
return result;
}
///
/// Performs a Hermite spline interpolation.
///
/// First source position vector.
/// First source tangent vector.
/// Second source position vector.
/// Second source tangent vector.
/// Weighting factor.
/// When the method completes, contains the result of the Hermite spline interpolation.
public static void Hermite(ref Vec3 value1, ref Vec3 tangent1, ref Vec3 value2, ref Vec3 tangent2, float amount, out Vec3 result)
{
float squared = amount * amount;
float cubed = amount * squared;
float part1 = ((2.0f * cubed) - (3.0f * squared)) + 1.0f;
float part2 = (-2.0f * cubed) + (3.0f * squared);
float part3 = (cubed - (2.0f * squared)) + amount;
float part4 = cubed - squared;
result.X = (((value1.X * part1) + (value2.X * part2)) + (tangent1.X * part3)) + (tangent2.X * part4);
result.Y = (((value1.Y * part1) + (value2.Y * part2)) + (tangent1.Y * part3)) + (tangent2.Y * part4);
result.Z = (((value1.Z * part1) + (value2.Z * part2)) + (tangent1.Z * part3)) + (tangent2.Z * part4);
}
///
/// Performs a Hermite spline interpolation.
///
/// First source position vector.
/// First source tangent vector.
/// Second source position vector.
/// Second source tangent vector.
/// Weighting factor.
/// The result of the Hermite spline interpolation.
public static Vec3 Hermite(Vec3 value1, Vec3 tangent1, Vec3 value2, Vec3 tangent2, float amount)
{
Vec3 result;
Hermite(ref value1, ref tangent1, ref value2, ref tangent2, amount, out result);
return result;
}
///
/// Performs a Catmull-Rom interpolation using the specified positions.
///
/// The first position in the interpolation.
/// The second position in the interpolation.
/// The third position in the interpolation.
/// The fourth position in the interpolation.
/// Weighting factor.
/// When the method completes, contains the result of the Catmull-Rom interpolation.
public static void CatmullRom(ref Vec3 value1, ref Vec3 value2, ref Vec3 value3, ref Vec3 value4, float amount, out Vec3 result)
{
float squared = amount * amount;
float cubed = amount * squared;
result.X = 0.5f * ((((2.0f * value2.X) + ((-value1.X + value3.X) * amount)) +
(((((2.0f * value1.X) - (5.0f * value2.X)) + (4.0f * value3.X)) - value4.X) * squared)) +
((((-value1.X + (3.0f * value2.X)) - (3.0f * value3.X)) + value4.X) * cubed));
result.Y = 0.5f * ((((2.0f * value2.Y) + ((-value1.Y + value3.Y) * amount)) +
(((((2.0f * value1.Y) - (5.0f * value2.Y)) + (4.0f * value3.Y)) - value4.Y) * squared)) +
((((-value1.Y + (3.0f * value2.Y)) - (3.0f * value3.Y)) + value4.Y) * cubed));
result.Z = 0.5f * ((((2.0f * value2.Z) + ((-value1.Z + value3.Z) * amount)) +
(((((2.0f * value1.Z) - (5.0f * value2.Z)) + (4.0f * value3.Z)) - value4.Z) * squared)) +
((((-value1.Z + (3.0f * value2.Z)) - (3.0f * value3.Z)) + value4.Z) * cubed));
}
///
/// Performs a Catmull-Rom interpolation using the specified positions.
///
/// The first position in the interpolation.
/// The second position in the interpolation.
/// The third position in the interpolation.
/// The fourth position in the interpolation.
/// Weighting factor.
/// A vector that is the result of the Catmull-Rom interpolation.
public static Vec3 CatmullRom(Vec3 value1, Vec3 value2, Vec3 value3, Vec3 value4, float amount)
{
Vec3 result;
CatmullRom(ref value1, ref value2, ref value3, ref value4, amount, out result);
return result;
}
///
/// Returns a vector containing the smallest components of the specified vectors.
///
/// The first source vector.
/// The second source vector.
/// When the method completes, contains an new vector composed of the largest components of the source vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Max(ref Vec3 left, ref Vec3 right, out Vec3 result)
{
result.X = (left.X > right.X) ? left.X : right.X;
result.Y = (left.Y > right.Y) ? left.Y : right.Y;
result.Z = (left.Z > right.Z) ? left.Z : right.Z;
}
///
/// Returns a vector containing the largest components of the specified vectors.
///
/// The first source vector.
/// The second source vector.
/// A vector containing the largest components of the source vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Max(Vec3 left, Vec3 right)
{
Vec3 result;
Max(ref left, ref right, out result);
return result;
}
///
/// Returns a vector containing the smallest components of the specified vectors.
///
/// The first source vector.
/// The second source vector.
/// When the method completes, contains an new vector composed of the smallest components of the source vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Min(ref Vec3 left, ref Vec3 right, out Vec3 result)
{
result.X = (left.X < right.X) ? left.X : right.X;
result.Y = (left.Y < right.Y) ? left.Y : right.Y;
result.Z = (left.Z < right.Z) ? left.Z : right.Z;
}
///
/// Returns a vector containing the smallest components of the specified vectors.
///
/// The first source vector.
/// The second source vector.
/// A vector containing the smallest components of the source vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 Min(Vec3 left, Vec3 right)
{
Vec3 result;
Min(ref left, ref right, out result);
return result;
}
///
/// Projects a 3D vector from object space into screen space.
///
/// The vector to project.
/// The X position of the viewport.
/// The Y position of the viewport.
/// The width of the viewport.
/// The height of the viewport.
/// The minimum depth of the viewport.
/// The maximum depth of the viewport.
/// The combined world-view-projection matrix.
/// When the method completes, contains the vector in screen space.
public static void Project(ref Vec3 vector, float x, float y, float width, float height, float minZ, float maxZ, ref Matrix worldViewProjection, out Vec3 result)
{
Vec3 v;
TransformCoordinate(ref vector, ref worldViewProjection, out v);
result = new Vec3(((1.0f + v.X) * 0.5f * width) + x, ((1.0f - v.Y) * 0.5f * height) + y, (v.Z * (maxZ - minZ)) + minZ);
}
///
/// Projects a 3D vector from object space into screen space.
///
/// The vector to project.
/// The X position of the viewport.
/// The Y position of the viewport.
/// The width of the viewport.
/// The height of the viewport.
/// The minimum depth of the viewport.
/// The maximum depth of the viewport.
/// The combined world-view-projection matrix.
/// The vector in screen space.
public static Vec3 Project(Vec3 vector, float x, float y, float width, float height, float minZ, float maxZ, Matrix worldViewProjection)
{
Vec3 result;
Project(ref vector, x, y, width, height, minZ, maxZ, ref worldViewProjection, out result);
return result;
}
///
/// Projects a 3D vector from screen space into object space.
///
/// The vector to project.
/// The X position of the viewport.
/// The Y position of the viewport.
/// The width of the viewport.
/// The height of the viewport.
/// The minimum depth of the viewport.
/// The maximum depth of the viewport.
/// The combined world-view-projection matrix.
/// When the method completes, contains the vector in object space.
public static void Unproject(ref Vec3 vector, float x, float y, float width, float height, float minZ, float maxZ, ref Matrix worldViewProjection, out Vec3 result)
{
Vec3 v = new Vec3();
Matrix matrix;
Matrix.Invert(ref worldViewProjection, out matrix);
v.X = (((vector.X - x) / width) * 2.0f) - 1.0f;
v.Y = -((((vector.Y - y) / height) * 2.0f) - 1.0f);
v.Z = (vector.Z - minZ) / (maxZ - minZ);
TransformCoordinate(ref v, ref matrix, out result);
}
///
/// Projects a 3D vector from screen space into object space.
///
/// The vector to project.
/// The X position of the viewport.
/// The Y position of the viewport.
/// The width of the viewport.
/// The height of the viewport.
/// The minimum depth of the viewport.
/// The maximum depth of the viewport.
/// The combined world-view-projection matrix.
/// The vector in object space.
public static Vec3 Unproject(Vec3 vector, float x, float y, float width, float height, float minZ, float maxZ, Matrix worldViewProjection)
{
Vec3 result;
Unproject(ref vector, x, y, width, height, minZ, maxZ, ref worldViewProjection, out result);
return result;
}
///
/// Returns the reflection of a vector off a surface that has the specified normal.
///
/// The source vector.
/// Normal of the surface.
/// When the method completes, contains the reflected vector.
/// Reflect only gives the direction of a reflection off a surface, it does not determine
/// whether the original vector was close enough to the surface to hit it.
public static void Reflect(ref Vec3 vector, ref Vec3 normal, out Vec3 result)
{
float dot = (vector.X * normal.X) + (vector.Y * normal.Y) + (vector.Z * normal.Z);
result.X = vector.X - ((2.0f * dot) * normal.X);
result.Y = vector.Y - ((2.0f * dot) * normal.Y);
result.Z = vector.Z - ((2.0f * dot) * normal.Z);
}
///
/// Returns the reflection of a vector off a surface that has the specified normal.
///
/// The source vector.
/// Normal of the surface.
/// The reflected vector.
/// Reflect only gives the direction of a reflection off a surface, it does not determine
/// whether the original vector was close enough to the surface to hit it.
public static Vec3 Reflect(Vec3 vector, Vec3 normal)
{
Vec3 result;
Reflect(ref vector, ref normal, out result);
return result;
}
///
/// Orthogonalizes a list of vectors.
///
/// The list of orthogonalized vectors.
/// The list of vectors to orthogonalize.
///
/// Orthogonalization is the process of making all vectors orthogonal to each other. This
/// means that any given vector in the list will be orthogonal to any other given vector in the
/// list.
/// Because this method uses the modified Gram-Schmidt process, the resulting vectors
/// tend to be numerically unstable. The numeric stability decreases according to the vectors
/// position in the list so that the first vector is the most stable and the last vector is the
/// least stable.
///
/// Thrown when or is null.
/// Thrown when is shorter in length than .
public static void Orthogonalize(Vec3[] destination, params Vec3[] source)
{
//Uses the modified Gram-Schmidt process.
//q1 = m1
//q2 = m2 - ((q1 ⋅ m2) / (q1 ⋅ q1)) * q1
//q3 = m3 - ((q1 ⋅ m3) / (q1 ⋅ q1)) * q1 - ((q2 ⋅ m3) / (q2 ⋅ q2)) * q2
//q4 = m4 - ((q1 ⋅ m4) / (q1 ⋅ q1)) * q1 - ((q2 ⋅ m4) / (q2 ⋅ q2)) * q2 - ((q3 ⋅ m4) / (q3 ⋅ q3)) * q3
//q5 = ...
if (source == null)
throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");
if (destination.Length < source.Length)
throw new ArgumentOutOfRangeException("destination", "The destination array must be of same length or larger length than the source array.");
for (int i = 0; i < source.Length; ++i)
{
Vec3 newvector = source[i];
for (int r = 0; r < i; ++r)
{
newvector -= (Vec3.Dot(destination[r], newvector) / Vec3.Dot(destination[r], destination[r])) * destination[r];
}
destination[i] = newvector;
}
}
///
/// Orthonormalizes a list of vectors.
///
/// The list of orthonormalized vectors.
/// The list of vectors to orthonormalize.
///
/// Orthonormalization is the process of making all vectors orthogonal to each
/// other and making all vectors of unit length. This means that any given vector will
/// be orthogonal to any other given vector in the list.
/// Because this method uses the modified Gram-Schmidt process, the resulting vectors
/// tend to be numerically unstable. The numeric stability decreases according to the vectors
/// position in the list so that the first vector is the most stable and the last vector is the
/// least stable.
///
/// Thrown when or is null.
/// Thrown when is shorter in length than .
public static void Orthonormalize(Vec3[] destination, params Vec3[] source)
{
//Uses the modified Gram-Schmidt process.
//Because we are making unit vectors, we can optimize the math for orthogonalization
//and simplify the projection operation to remove the division.
//q1 = m1 / |m1|
//q2 = (m2 - (q1 ⋅ m2) * q1) / |m2 - (q1 ⋅ m2) * q1|
//q3 = (m3 - (q1 ⋅ m3) * q1 - (q2 ⋅ m3) * q2) / |m3 - (q1 ⋅ m3) * q1 - (q2 ⋅ m3) * q2|
//q4 = (m4 - (q1 ⋅ m4) * q1 - (q2 ⋅ m4) * q2 - (q3 ⋅ m4) * q3) / |m4 - (q1 ⋅ m4) * q1 - (q2 ⋅ m4) * q2 - (q3 ⋅ m4) * q3|
//q5 = ...
if (source == null)
throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");
if (destination.Length < source.Length)
throw new ArgumentOutOfRangeException("destination", "The destination array must be of same length or larger length than the source array.");
for (int i = 0; i < source.Length; ++i)
{
Vec3 newvector = source[i];
for (int r = 0; r < i; ++r)
{
newvector -= Vec3.Dot(destination[r], newvector) * destination[r];
}
newvector.Normalize();
destination[i] = newvector;
}
}
///
/// Transforms a 3D vector by the given rotation.
///
/// The vector to rotate.
/// The rotation to apply.
/// When the method completes, contains the transformed .
public static void Transform(ref Vec3 vector, ref Quaternion rotation, out Vec3 result)
{
float x = rotation.X + rotation.X;
float y = rotation.Y + rotation.Y;
float z = rotation.Z + rotation.Z;
float wx = rotation.W * x;
float wy = rotation.W * y;
float wz = rotation.W * z;
float xx = rotation.X * x;
float xy = rotation.X * y;
float xz = rotation.X * z;
float yy = rotation.Y * y;
float yz = rotation.Y * z;
float zz = rotation.Z * z;
result = new Vec3(
((vector.X * ((1.0f - yy) - zz)) + (vector.Y * (xy - wz))) + (vector.Z * (xz + wy)),
((vector.X * (xy + wz)) + (vector.Y * ((1.0f - xx) - zz))) + (vector.Z * (yz - wx)),
((vector.X * (xz - wy)) + (vector.Y * (yz + wx))) + (vector.Z * ((1.0f - xx) - yy)));
}
///
/// Transforms a 3D vector by the given rotation.
///
/// The vector to rotate.
/// The rotation to apply.
/// The transformed .
public static Vec3 Transform(Vec3 vector, Quaternion rotation)
{
Vec3 result;
Transform(ref vector, ref rotation, out result);
return result;
}
///
/// Transforms an array of vectors by the given rotation.
///
/// The array of vectors to transform.
/// The rotation to apply.
/// The array for which the transformed vectors are stored.
/// This array may be the same array as .
/// Thrown when or is null.
/// Thrown when is shorter in length than .
public static void Transform(Vec3[] source, ref Quaternion rotation, Vec3[] destination)
{
if (source == null)
throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");
if (destination.Length < source.Length)
throw new ArgumentOutOfRangeException("destination", "The destination array must be of same length or larger length than the source array.");
float x = rotation.X + rotation.X;
float y = rotation.Y + rotation.Y;
float z = rotation.Z + rotation.Z;
float wx = rotation.W * x;
float wy = rotation.W * y;
float wz = rotation.W * z;
float xx = rotation.X * x;
float xy = rotation.X * y;
float xz = rotation.X * z;
float yy = rotation.Y * y;
float yz = rotation.Y * z;
float zz = rotation.Z * z;
float num1 = ((1.0f - yy) - zz);
float num2 = (xy - wz);
float num3 = (xz + wy);
float num4 = (xy + wz);
float num5 = ((1.0f - xx) - zz);
float num6 = (yz - wx);
float num7 = (xz - wy);
float num8 = (yz + wx);
float num9 = ((1.0f - xx) - yy);
for (int i = 0; i < source.Length; ++i)
{
destination[i] = new Vec3(
((source[i].X * num1) + (source[i].Y * num2)) + (source[i].Z * num3),
((source[i].X * num4) + (source[i].Y * num5)) + (source[i].Z * num6),
((source[i].X * num7) + (source[i].Y * num8)) + (source[i].Z * num9));
}
}
///
/// Transforms a 3D vector by the given .
///
/// The source vector.
/// The transformation .
/// When the method completes, contains the transformed .
public static void Transform(ref Vec3 vector, ref Matrix transform, out Vec4 result)
{
result = new Vec4(
(vector.X * transform.M11) + (vector.Y * transform.M21) + (vector.Z * transform.M31) + transform.M41,
(vector.X * transform.M12) + (vector.Y * transform.M22) + (vector.Z * transform.M32) + transform.M42,
(vector.X * transform.M13) + (vector.Y * transform.M23) + (vector.Z * transform.M33) + transform.M43,
(vector.X * transform.M14) + (vector.Y * transform.M24) + (vector.Z * transform.M34) + transform.M44);
}
///
/// Transforms a 3D vector by the given .
///
/// The source vector.
/// The transformation .
/// When the method completes, contains the transformed .
public static void Transform(ref Vec3 vector, ref Matrix transform, out Vec3 result)
{
result = new Vec3(
(vector.X * transform.M11) + (vector.Y * transform.M21) + (vector.Z * transform.M31) + transform.M41,
(vector.X * transform.M12) + (vector.Y * transform.M22) + (vector.Z * transform.M32) + transform.M42,
(vector.X * transform.M13) + (vector.Y * transform.M23) + (vector.Z * transform.M33) + transform.M43);
}
///
/// Transforms a 3D vector by the given .
///
/// The source vector.
/// The transformation .
/// The transformed .
public static Vec4 Transform(Vec3 vector, Matrix transform)
{
Vec4 result;
Transform(ref vector, ref transform, out result);
return result;
}
///
/// Transforms an array of 3D vectors by the given .
///
/// The array of vectors to transform.
/// The transformation .
/// The array for which the transformed vectors are stored.
/// Thrown when or is null.
/// Thrown when is shorter in length than .
public static void Transform(Vec3[] source, ref Matrix transform, Vec4[] destination)
{
if (source == null)
throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");
if (destination.Length < source.Length)
throw new ArgumentOutOfRangeException("destination", "The destination array must be of same length or larger length than the source array.");
for (int i = 0; i < source.Length; ++i)
{
Transform(ref source[i], ref transform, out destination[i]);
}
}
///
/// Performs a coordinate transformation using the given .
///
/// The coordinate vector to transform.
/// The transformation .
/// When the method completes, contains the transformed coordinates.
///
/// A coordinate transform performs the transformation with the assumption that the w component
/// is one. The four dimensional vector obtained from the transformation operation has each
/// component in the vector divided by the w component. This forces the wcomponent to be one and
/// therefore makes the vector homogeneous. The homogeneous vector is often prefered when working
/// with coordinates as the w component can safely be ignored.
///
public static void TransformCoordinate(ref Vec3 coordinate, ref Matrix transform, out Vec3 result)
{
var invW = 1f / ((coordinate.X * transform.M14) + (coordinate.Y * transform.M24) + (coordinate.Z * transform.M34) + transform.M44);
result = new Vec3(
((coordinate.X * transform.M11) + (coordinate.Y * transform.M21) + (coordinate.Z * transform.M31) + transform.M41) * invW,
((coordinate.X * transform.M12) + (coordinate.Y * transform.M22) + (coordinate.Z * transform.M32) + transform.M42) * invW,
((coordinate.X * transform.M13) + (coordinate.Y * transform.M23) + (coordinate.Z * transform.M33) + transform.M43) * invW);
}
///
/// Performs a coordinate transformation using the given .
///
/// The coordinate vector to transform.
/// The transformation .
/// The transformed coordinates.
///
/// A coordinate transform performs the transformation with the assumption that the w component
/// is one. The four dimensional vector obtained from the transformation operation has each
/// component in the vector divided by the w component. This forces the wcomponent to be one and
/// therefore makes the vector homogeneous. The homogeneous vector is often prefered when working
/// with coordinates as the w component can safely be ignored.
///
public static Vec3 TransformCoordinate(Vec3 coordinate, Matrix transform)
{
Vec3 result;
TransformCoordinate(ref coordinate, ref transform, out result);
return result;
}
///
/// Performs a coordinate transformation on an array of vectors using the given .
///
/// The array of coordinate vectors to trasnform.
/// The transformation .
/// The array for which the transformed vectors are stored.
/// This array may be the same array as .
/// Thrown when or is null.
/// Thrown when is shorter in length than .
///
/// A coordinate transform performs the transformation with the assumption that the w component
/// is one. The four dimensional vector obtained from the transformation operation has each
/// component in the vector divided by the w component. This forces the wcomponent to be one and
/// therefore makes the vector homogeneous. The homogeneous vector is often prefered when working
/// with coordinates as the w component can safely be ignored.
///
public static void TransformCoordinate(Vec3[] source, ref Matrix transform, Vec3[] destination)
{
if (source == null)
throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");
if (destination.Length < source.Length)
throw new ArgumentOutOfRangeException("destination", "The destination array must be of same length or larger length than the source array.");
for (int i = 0; i < source.Length; ++i)
{
TransformCoordinate(ref source[i], ref transform, out destination[i]);
}
}
///
/// Performs a normal transformation using the given .
///
/// The normal vector to transform.
/// The transformation .
/// When the method completes, contains the transformed normal.
///
/// A normal transform performs the transformation with the assumption that the w component
/// is zero. This causes the fourth row and fourth collumn of the matrix to be unused. The
/// end result is a vector that is not translated, but all other transformation properties
/// apply. This is often prefered for normal vectors as normals purely represent direction
/// rather than location because normal vectors should not be translated.
///
public static void TransformNormal(ref Vec3 normal, ref Matrix transform, out Vec3 result)
{
result = new Vec3(
(normal.X * transform.M11) + (normal.Y * transform.M21) + (normal.Z * transform.M31),
(normal.X * transform.M12) + (normal.Y * transform.M22) + (normal.Z * transform.M32),
(normal.X * transform.M13) + (normal.Y * transform.M23) + (normal.Z * transform.M33));
}
///
/// Performs a normal transformation using the given .
///
/// The normal vector to transform.
/// The transformation .
/// The transformed normal.
///
/// A normal transform performs the transformation with the assumption that the w component
/// is zero. This causes the fourth row and fourth collumn of the matrix to be unused. The
/// end result is a vector that is not translated, but all other transformation properties
/// apply. This is often prefered for normal vectors as normals purely represent direction
/// rather than location because normal vectors should not be translated.
///
public static Vec3 TransformNormal(Vec3 normal, Matrix transform)
{
Vec3 result;
TransformNormal(ref normal, ref transform, out result);
return result;
}
///
/// Performs a normal transformation on an array of vectors using the given .
///
/// The array of normal vectors to transform.
/// The transformation .
/// The array for which the transformed vectors are stored.
/// This array may be the same array as .
/// Thrown when or is null.
/// Thrown when is shorter in length than .
///
/// A normal transform performs the transformation with the assumption that the w component
/// is zero. This causes the fourth row and fourth collumn of the matrix to be unused. The
/// end result is a vector that is not translated, but all other transformation properties
/// apply. This is often prefered for normal vectors as normals purely represent direction
/// rather than location because normal vectors should not be translated.
///
public static void TransformNormal(Vec3[] source, ref Matrix transform, Vec3[] destination)
{
if (source == null)
throw new ArgumentNullException("source");
if (destination == null)
throw new ArgumentNullException("destination");
if (destination.Length < source.Length)
throw new ArgumentOutOfRangeException("destination", "The destination array must be of same length or larger length than the source array.");
for (int i = 0; i < source.Length; ++i)
{
TransformNormal(ref source[i], ref transform, out destination[i]);
}
}
///
/// Calculate the yaw/pitch/roll rotation equivalent to the provided quaterion.
///
/// The input rotation as quaternion
/// The equivation yaw/pitch/roll rotation
public static Vec3 RotationYawPitchRoll(Quaternion quaternion)
{
Vec3 yawPitchRoll;
Quaternion.RotationYawPitchRoll(ref quaternion, out yawPitchRoll.X, out yawPitchRoll.Y, out yawPitchRoll.Z);
return yawPitchRoll;
}
///
/// Calculate the yaw/pitch/roll rotation equivalent to the provided quaterion.
///
/// The input rotation as quaternion
/// The equivation yaw/pitch/roll rotation
public static void RotationYawPitchRoll(ref Quaternion quaternion, out Vec3 yawPitchRoll)
{
Quaternion.RotationYawPitchRoll(ref quaternion, out yawPitchRoll.X, out yawPitchRoll.Y, out yawPitchRoll.Z);
}
///
/// Adds two vectors.
///
/// The first vector to add.
/// The second vector to add.
/// The sum of the two vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator +(Vec3 left, Vec3 right)
{
return new Vec3(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
}
///
/// Assert a vector (return it unchanged).
///
/// The vector to assert (unchange).
/// The asserted (unchanged) vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator +(Vec3 value)
{
return value;
}
///
/// Subtracts two vectors.
///
/// The first vector to subtract.
/// The second vector to subtract.
/// The difference of the two vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator -(Vec3 left, Vec3 right)
{
return new Vec3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
}
///
/// Reverses the direction of a given vector.
///
/// The vector to negate.
/// A vector facing in the opposite direction.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator -(Vec3 value)
{
return new Vec3(-value.X, -value.Y, -value.Z);
}
///
/// Scales a vector by the given value.
///
/// The vector to scale.
/// The amount by which to scale the vector.
/// The scaled vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator *(float scale, Vec3 value)
{
return new Vec3(value.X * scale, value.Y * scale, value.Z * scale);
}
///
/// Scales a vector by the given value.
///
/// The vector to scale.
/// The amount by which to scale the vector.
/// The scaled vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator *(Vec3 value, float scale)
{
return new Vec3(value.X * scale, value.Y * scale, value.Z * scale);
}
///
/// Modulates a vector with another by performing component-wise multiplication.
///
/// The first vector to multiply.
/// The second vector to multiply.
/// The multiplication of the two vectors.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator *(Vec3 left, Vec3 right)
{
return new Vec3(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
}
///
/// Adds a vector with the given value.
///
/// The vector to scale.
/// The amount by which to scale the vector.
/// The vector offset.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator +(Vec3 value, float scale)
{
return new Vec3(value.X + scale, value.Y + scale, value.Z + scale);
}
///
/// Substracts a vector by the given value.
///
/// The vector to scale.
/// The amount by which to scale the vector.
/// The vector offset.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator -(Vec3 value, float scale)
{
return new Vec3(value.X - scale, value.Y - scale, value.Z - scale);
}
///
/// Divides a numerator by a vector.
///
/// The numerator.
/// The value.
/// The scaled vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator /(float numerator, Vec3 value)
{
return new Vec3(numerator / value.X, numerator / value.Y, numerator / value.Z);
}
///
/// Scales a vector by the given value.
///
/// The vector to scale.
/// The amount by which to scale the vector.
/// The scaled vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator /(Vec3 value, float scale)
{
return new Vec3(value.X / scale, value.Y / scale, value.Z / scale);
}
///
/// Divides a vector by the given vector, component-wise.
///
/// The vector to scale.
/// The by.
/// The scaled vector.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator /(Vec3 value, Vec3 by)
{
return new Vec3(value.X / by.X, value.Y / by.Y, value.Z / by.Z);
}
///
/// Tests for equality between two objects.
///
/// The first value to compare.
/// The second value to compare.
/// true if has the same value as ; otherwise, false.
public static bool operator ==(Vec3 left, Vec3 right)
{
return left.Equals(right);
}
///
/// Tests for inequality between two objects.
///
/// The first value to compare.
/// The second value to compare.
/// true if has a different value than ; otherwise, false.
public static bool operator !=(Vec3 left, Vec3 right)
{
return !left.Equals(right);
}
///
/// Performs an explicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static explicit operator Vec2(Vec3 value)
{
return new Vec2(value.X, value.Y);
}
///
/// Performs an explicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static explicit operator Vec4(Vec3 value)
{
return new Vec4(value, 0.0f);
}
///
/// Tests whether one 3D vector is near another 3D vector.
///
/// The left vector.
/// The right vector.
/// The epsilon.
/// true if left and right are near another 3D, false otherwise
public static bool NearEqual(Vec3 left, Vec3 right, Vec3 epsilon)
{
return NearEqual(ref left, ref right, ref epsilon);
}
///
/// Tests whether one 3D vector is near another 3D vector.
///
/// The left vector.
/// The right vector.
/// The epsilon.
/// true if left and right are near another 3D, false otherwise
public static bool NearEqual(ref Vec3 left, ref Vec3 right, ref Vec3 epsilon)
{
return MathUtil.WithinEpsilon(left.X, right.X, epsilon.X) &&
MathUtil.WithinEpsilon(left.Y, right.Y, epsilon.Y) &&
MathUtil.WithinEpsilon(left.Z, right.Z, epsilon.Z);
}
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
return string.Format(CultureInfo.CurrentCulture, "X:{0} Y:{1} Z:{2}", X, Y, Z);
}
///
/// Returns a that represents this instance.
///
/// The format.
///
/// A that represents this instance.
///
public string ToString(string format)
{
if (format == null)
return ToString();
return string.Format(CultureInfo.CurrentCulture, "X:{0} Y:{1} Z:{2}", X.ToString(format, CultureInfo.CurrentCulture),
Y.ToString(format, CultureInfo.CurrentCulture), Z.ToString(format, CultureInfo.CurrentCulture));
}
///
/// Returns a that represents this instance.
///
/// The format provider.
///
/// A that represents this instance.
///
public string ToString(IFormatProvider formatProvider)
{
return string.Format(formatProvider, "X:{0} Y:{1} Z:{2}", X, Y, Z);
}
///
/// Returns a that represents this instance.
///
/// The format.
/// The format provider.
///
/// A that represents this instance.
///
public string ToString(string format, IFormatProvider formatProvider)
{
if (format == null)
return ToString(formatProvider);
return string.Format(formatProvider, "X:{0} Y:{1} Z:{2}", X.ToString(format, formatProvider),
Y.ToString(format, formatProvider), Z.ToString(format, formatProvider));
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
///
public override int GetHashCode()
{
return X.GetHashCode() + Y.GetHashCode() + Z.GetHashCode();
}
///
/// Determines whether the specified is equal to this instance.
///
/// The to compare with this instance.
///
/// true if the specified is equal to this instance; otherwise, false.
///
public bool Equals(Vec3 other)
{
return ((float)Math.Abs(other.X - X) < MathUtil.ZeroTolerance &&
(float)Math.Abs(other.Y - Y) < MathUtil.ZeroTolerance &&
(float)Math.Abs(other.Z - Z) < MathUtil.ZeroTolerance);
}
///
/// Determines whether the specified is equal to this instance.
///
/// The to compare with this instance.
///
/// true if the specified is equal to this instance; otherwise, false.
///
public override bool Equals(object value)
{
if (value == null)
return false;
if (value.GetType() != GetType())
return false;
return Equals((Vec3)value);
}
#if WPFInterop
///
/// Performs an implicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static implicit operator System.Windows.Media.Media3D.Vector3D(Vector3 value)
{
return new System.Windows.Media.Media3D.Vector3D(value.X, value.Y, value.Z);
}
///
/// Performs an explicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static explicit operator Vector3(System.Windows.Media.Media3D.Vector3D value)
{
return new Vector3((float)value.X, (float)value.Y, (float)value.Z);
}
#endif
#if XnaInterop
///
/// Performs an implicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static implicit operator Microsoft.Xna.Framework.Vector3(Vector3 value)
{
return new Microsoft.Xna.Framework.Vector3(value.X, value.Y, value.Z);
}
///
/// Performs an implicit conversion from to .
///
/// The value.
/// The result of the conversion.
public static implicit operator Vector3(Microsoft.Xna.Framework.Vector3 value)
{
return new Vector3(value.X, value.Y, value.Z);
}
#endif
}
}