From eedca14e6f3ba6cc173fda9c68ad4290af51cd34 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Wed, 18 Aug 2021 12:48:39 +0200 Subject: [PATCH] Add Double3 impl. cpp --- Source/Engine/Core/Math/Double3.cpp | 385 +++++++++++ Source/Engine/Core/Math/Double3.h | 970 ++++++++++++++++++++++++++++ 2 files changed, 1355 insertions(+) create mode 100644 Source/Engine/Core/Math/Double3.cpp create mode 100644 Source/Engine/Core/Math/Double3.h diff --git a/Source/Engine/Core/Math/Double3.cpp b/Source/Engine/Core/Math/Double3.cpp new file mode 100644 index 000000000..4c0a31df7 --- /dev/null +++ b/Source/Engine/Core/Math/Double3.cpp @@ -0,0 +1,385 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#include "Double2.h" +#include "Double3.h" +#include "Double4.h" +#include "Vector2.h" +#include "Vector3.h" +#include "Vector4.h" +#include "Quaternion.h" +#include "Matrix.h" +#include "Color.h" +#include "Int2.h" +#include "Int3.h" +#include "Int4.h" +#include "../Types/String.h" + +static_assert(sizeof(Double3) == 24, "Invalid Double3 type size."); + +const Double3 Double3::Zero(0.0); +const Double3 Double3::One(1.0); +const Double3 Double3::Half(0.5); +const Double3 Double3::UnitX(1.0, 0.0, 0.0); +const Double3 Double3::UnitY(0.0, 1.0, 0.0); +const Double3 Double3::UnitZ(0.0, 0.0, 1.0); +const Double3 Double3::Up(0.0, 1.0, 0.0); +const Double3 Double3::Down(0.0, -1.0, 0.0); +const Double3 Double3::Left(-1.0, 0.0, 0.0); +const Double3 Double3::Right(1.0, 0.0, 0.0); +const Double3 Double3::Forward(0.0, 0.0, 1.0); +const Double3 Double3::Backward(0.0, 0.0, -1.0); +const Double3 Double3::Minimum(MIN_double); +const Double3 Double3::Maximum(MAX_double); + +Double3::Double3(const Vector2& xy, double z) + : X(xy.X) + , Y(xy.Y) + , Z(z) +{ +} + +Double3::Double3(const Vector2& xy) + : X(xy.X) + , Y(xy.Y) + , Z(0) +{ +} + +Double3::Double3(const Int2& xy, double z) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) + , Z(z) +{ +} + +Double3::Double3(const Int3& xyz) + : X(static_cast(xyz.X)) + , Y(static_cast(xyz.Y)) + , Z(static_cast(xyz.Z)) +{ +} + +Double3::Double3(const Int4& xyzw) + : X(static_cast(xyzw.X)) + , Y(static_cast(xyzw.Y)) + , Z(static_cast(xyzw.Z)) +{ +} + +Double3::Double3(const Vector4& xyzw) + : X(xyzw.X) + , Y(xyzw.Y) + , Z(xyzw.Z) +{ +} + +Double3::Double3(const Double2& xy) + : X(xy.X) + , Y(xy.Y) + , Z(0) +{ +} + +Double3::Double3(const Double2& xy, double z) + : X(xy.X) + , Y(xy.Y) + , Z(z) +{ +} + +Double3::Double3(const Double4& xyzw) + : X(xyzw.X) + , Y(xyzw.Y) + , Z(xyzw.Z) +{ +} + +Double3::Double3(const Color& color) + : X(color.R) + , Y(color.G) + , Z(color.B) +{ +} + +String Double3::ToString() const +{ + return String::Format(TEXT("{}"), *this); +} + +void Double3::UnwindEuler() +{ + X = Math::UnwindDegrees(X); + Y = Math::UnwindDegrees(Y); + Z = Math::UnwindDegrees(Z); +} + +Double3 Double3::Floor(const Double3& v) +{ + return Double3( + Math::Floor(v.X), + Math::Floor(v.Y), + Math::Floor(v.Z) + ); +} + +Double3 Double3::Frac(const Double3& v) +{ + return Double3( + v.X - (int64)v.X, + v.Y - (int64)v.Y, + v.Z - (int64)v.Z + ); +} + +Double3 Double3::Clamp(const Double3& value, const Double3& min, const Double3& max) +{ + double x = value.X; + x = x > max.X ? max.X : x; + x = x < min.X ? min.X : x; + + double y = value.Y; + y = y > max.Y ? max.Y : y; + y = y < min.Y ? min.Y : y; + + double z = value.Z; + z = z > max.Z ? max.Z : z; + z = z < min.Z ? min.Z : z; + + return Double3(x, y, z); +} + +void Double3::Clamp(const Double3& value, const Double3& min, const Double3& max, Double3& result) +{ + double x = value.X; + x = x > max.X ? max.X : x; + x = x < min.X ? min.X : x; + + double y = value.Y; + y = y > max.Y ? max.Y : y; + y = y < min.Y ? min.Y : y; + + double z = value.Z; + z = z > max.Z ? max.Z : z; + z = z < min.Z ? min.Z : z; + + result = Double3(x, y, z); +} + +double Double3::Distance(const Double3& value1, const Double3& value2) +{ + const double x = value1.X - value2.X; + const double y = value1.Y - value2.Y; + const double z = value1.Z - value2.Z; + return Math::Sqrt(x * x + y * y + z * z); +} + +double Double3::DistanceSquared(const Double3& value1, const Double3& value2) +{ + const double x = value1.X - value2.X; + const double y = value1.Y - value2.Y; + const double z = value1.Z - value2.Z; + return x * x + y * y + z * z; +} + +Double3 Double3::Normalize(const Double3& input) +{ + Double3 output = input; + const double length = input.Length(); + if (!Math::IsZero(length)) + { + const double inv = 1.0f / length; + output.X *= inv; + output.Y *= inv; + output.Z *= inv; + } + return output; +} + +void Double3::Normalize(const Double3& input, Double3& result) +{ + result = input; + const double length = input.Length(); + if (!Math::IsZero(length)) + { + const double inv = 1.0f / length; + result.X *= inv; + result.Y *= inv; + result.Z *= inv; + } +} + +void Double3::Hermite(const Double3& value1, const Double3& tangent1, const Double3& value2, const Double3& tangent2, double amount, Double3& result) +{ + const double squared = amount * amount; + const double cubed = amount * squared; + const double part1 = 2.0 * cubed - 3.0 * squared + 1.0; + const double part2 = -2.0 * cubed + 3.0 * squared; + const double part3 = cubed - 2.0 * squared + amount; + const double 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; +} + +void Double3::Reflect(const Double3& vector, const Double3& normal, Double3& result) +{ + const double dot = vector.X * normal.X + vector.Y * normal.Y + vector.Z * normal.Z; + result.X = vector.X - 2.0 * dot * normal.X; + result.Y = vector.Y - 2.0 * dot * normal.Y; + result.Z = vector.Z - 2.0 * dot * normal.Z; +} + +void Double3::Transform(const Double3& vector, const Quaternion& rotation, Double3& result) +{ + const double x = rotation.X + rotation.X; + const double y = rotation.Y + rotation.Y; + const double z = rotation.Z + rotation.Z; + const double wx = rotation.W * x; + const double wy = rotation.W * y; + const double wz = rotation.W * z; + const double xx = rotation.X * x; + const double xy = rotation.X * y; + const double xz = rotation.X * z; + const double yy = rotation.Y * y; + const double yz = rotation.Y * z; + const double zz = rotation.Z * z; + + result = Double3( + vector.X * (1.0 - yy - zz) + vector.Y * (xy - wz) + vector.Z * (xz + wy), + vector.X * (xy + wz) + vector.Y * (1.0 - xx - zz) + vector.Z * (yz - wx), + vector.X * (xz - wy) + vector.Y * (yz + wx) + vector.Z * (1.0 - xx - yy)); +} + +Double3 Double3::Transform(const Double3& vector, const Quaternion& rotation) +{ + const double x = rotation.X + rotation.X; + const double y = rotation.Y + rotation.Y; + const double z = rotation.Z + rotation.Z; + const double wx = rotation.W * x; + const double wy = rotation.W * y; + const double wz = rotation.W * z; + const double xx = rotation.X * x; + const double xy = rotation.X * y; + const double xz = rotation.X * z; + const double yy = rotation.Y * y; + const double yz = rotation.Y * z; + const double zz = rotation.Z * z; + + return Double3( + vector.X * (1.0 - yy - zz) + vector.Y * (xy - wz) + vector.Z * (xz + wy), + vector.X * (xy + wz) + vector.Y * (1.0 - xx - zz) + vector.Z * (yz - wx), + vector.X * (xz - wy) + vector.Y * (yz + wx) + vector.Z * (1.0 - xx - yy)); +} + +void Double3::Transform(const Double3& vector, const Matrix& transform, Double4& result) +{ + result = Double4( + 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); +} + +void Double3::Transform(const Double3& vector, const Matrix& transform, Double3& result) +{ + result = Double3( + 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); +} + +void Double3::Transform(const Double3* vectors, const Matrix& transform, Double3* results, int32 vectorsCount) +{ + for (int32 i = 0; i < vectorsCount; i++) + { + Transform(vectors[i], transform, results[i]); + } +} + +Double3 Double3::Transform(const Double3& vector, const Matrix& transform) +{ + return Double3( + 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); +} + +void Double3::TransformCoordinate(const Double3& coordinate, const Matrix& transform, Double3& result) +{ + Double4 vector; + vector.X = coordinate.X * transform.M11 + coordinate.Y * transform.M21 + coordinate.Z * transform.M31 + transform.M41; + vector.Y = coordinate.X * transform.M12 + coordinate.Y * transform.M22 + coordinate.Z * transform.M32 + transform.M42; + vector.Z = coordinate.X * transform.M13 + coordinate.Y * transform.M23 + coordinate.Z * transform.M33 + transform.M43; + vector.W = 1.0 / (coordinate.X * transform.M14 + coordinate.Y * transform.M24 + coordinate.Z * transform.M34 + transform.M44); + result = Double3(vector.X * vector.W, vector.Y * vector.W, vector.Z * vector.W); +} + +void Double3::TransformNormal(const Double3& normal, const Matrix& transform, Double3& result) +{ + result = Double3( + 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); +} + +Double3 Double3::Project(const Double3& vector, const Double3& onNormal) +{ + const double sqrMag = Dot(onNormal, onNormal); + if (sqrMag < ZeroTolerance) + return Zero; + return onNormal * Dot(vector, onNormal) / sqrMag; +} + +void Double3::Project(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection, Double3& result) +{ + Double3 v; + TransformCoordinate(vector, worldViewProjection, v); + + result = Double3((1.0 + v.X) * 0.5 * width + x, (1.0 - v.Y) * 0.5 * height + y, v.Z * (maxZ - minZ) + minZ); +} + +void Double3::Unproject(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection, Double3& result) +{ + Matrix matrix; + Matrix::Invert(worldViewProjection, matrix); + + const Double3 v = Double3((vector.X - x) / width * 2.0 - 1.0, -((vector.Y - y) / height * 2.0 - 1.0), (vector.Z - minZ) / (maxZ - minZ)); + + TransformCoordinate(v, matrix, result); +} + +void Double3::CreateOrthonormalBasis(Double3& xAxis, Double3& yAxis, Double3& zAxis) +{ + xAxis -= (xAxis | zAxis) / (zAxis | zAxis) * zAxis; + yAxis -= (yAxis | zAxis) / (zAxis | zAxis) * zAxis; + + if (xAxis.LengthSquared() < ZeroTolerance) + xAxis = yAxis ^ zAxis; + if (yAxis.LengthSquared() < ZeroTolerance) + yAxis = xAxis ^ zAxis; + + xAxis.Normalize(); + yAxis.Normalize(); + zAxis.Normalize(); +} + +void Double3::FindBestAxisVectors(Double3& firstAxis, Double3& secondAxis) const +{ + const double absX = Math::Abs(X); + const double absY = Math::Abs(Y); + const double absZ = Math::Abs(Z); + + if (absZ > absX && absZ > absY) + firstAxis = Double3(1, 0, 0); + else + firstAxis = Double3(0, 0, 1); + + firstAxis = (firstAxis - *this * (firstAxis | *this)).GetNormalized(); + secondAxis = firstAxis ^ *this; +} + +double Double3::TriangleArea(const Double3& v0, const Double3& v1, const Double3& v2) +{ + return (v2 - v0 ^ v1 - v0).Length() * 0.5; +} diff --git a/Source/Engine/Core/Math/Double3.h b/Source/Engine/Core/Math/Double3.h new file mode 100644 index 000000000..f57608190 --- /dev/null +++ b/Source/Engine/Core/Math/Double3.h @@ -0,0 +1,970 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Math.h" +#include "Mathd.h" +#include "Engine/Core/Formatting.h" +#include "Engine/Core/Templates.h" + +struct Double2; +struct Double4; +struct Vector2; +struct Vector3; +struct Vector4; +struct Int2; +struct Int3; +struct Int4; +struct Color; +struct Matrix; + +/// +/// Represents a two dimensional mathematical vector. +/// +API_STRUCT() struct FLAXENGINE_API Double3 +{ +DECLARE_SCRIPTING_TYPE_MINIMAL(Double3); +public: + + union + { + struct + { + /// + /// The X component of the vector. + /// + API_FIELD() double X; + + /// + /// The Y component of the vector. + /// + API_FIELD() double Y; + + /// + /// The Z component of the vector. + /// + API_FIELD() double Z; + }; + + // Raw values + double Raw[3]; + }; + +public: + + // Vector with all components equal 0 + static const Double3 Zero; + + // Vector with all components equal 1 + static const Double3 One; + + // Vector with all components equal half (0.5, 0.5, 0.5) + static const Double3 Half; + + // Vector X=1, Y=0, Z=0 + static const Double3 UnitX; + + // Vector X=0, Y=1, Z=0 + static const Double3 UnitY; + + // Vector X=0, Y=0, Z=1 + static const Double3 UnitZ; + + // A unit vector designating up (0, 1, 0) + static const Double3 Up; + + // A unit vector designating down (0, -1, 0) + static const Double3 Down; + + // A unit vector designating a (-1, 0, 0) + static const Double3 Left; + + // A unit vector designating b (1, 0, 0) + static const Double3 Right; + + // A unit vector designating forward in a a-handed coordinate system (0, 0, 1) + static const Double3 Forward; + + // A unit vector designating backward in a a-handed coordinate system (0, 0, -1) + static const Double3 Backward; + + // A minimum Double3 + static const Double3 Minimum; + + // A maximum Double3 + static const Double3 Maximum; + +public: + + + /// + /// Empty constructor. + /// + Double3() + { + } + + // Init + // @param xyz Value to assign to the all components + Double3(double xyz) + : X(xyz) + , Y(xyz) + , Z(xyz) + { + } + + // Init + // @param x X component value + // @param y Y component value + // @param z Z component value + Double3(double x, double y, double z) + : X(x) + , Y(y) + , Z(z) + { + } + + /// + /// Init + /// + /// X, Y and Z components in an array + explicit Double3(double xyz[3]) + : X(xyz[0]) + , Y(xyz[1]) + , Z(xyz[2]) + { + } + + // Init + // @param xy Vector2 with X and Y components values + // @param z Z component value + explicit Double3(const Vector2& xy, double z); + + // Init + // @param xy Vector2 value + explicit Double3(const Vector2& xy); + + // Init + // @param xy Int22 with X and Y components values + // @param z Z component value + explicit Double3(const Int2& xy, double z); + + // Init + // @param xyz Int3 value + explicit Double3(const Int3& xyz); + + // Init + // @param xyzw Int4 value + explicit Double3(const Int4& xyzw); + + // Init + // @param xyz Vector4 value + explicit Double3(const Vector4& xyzw); + + // Init + // @param xy Double2 value + Double3(const Double2& xy); + + // Init + // @param xy Double2 value + // @param z Z component value + explicit Double3(const Double2& xy, double z); + + + // Init + // @param xyzw Double4 value + explicit Double3(const Double4& xyzw); + + // Init + // @param color Color value + explicit Double3(const Color& color); + +public: + + String ToString() const; + +public: + + // Gets a value indicting whether this instance is normalized + bool IsNormalized() const + { + return Math::IsOne(X * X + Y * Y + Z * Z); + } + + // Gets a value indicting whether this vector is zero + bool IsZero() const + { + return Math::IsZero(X) && Math::IsZero(Y) && Math::IsZero(Z); + } + + // Gets a value indicting whether any vector component is zero + bool IsAnyZero() const + { + return Math::IsZero(X) || Math::IsZero(Y) || Math::IsZero(Z); + } + + // Gets a value indicting whether this vector is one + bool IsOne() const + { + return Math::IsOne(X) && Math::IsOne(Y) && Math::IsOne(Z); + } + + // Calculates length of the vector + // @returns Length of the vector + double Length() const + { + return Math::Sqrt(X * X + Y * Y + Z * Z); + } + + // Calculates the squared length of the vector + // @returns The squared length of the vector + double LengthSquared() const + { + return X * X + Y * Y + Z * Z; + } + + // Calculates inverted length of the vector (1 / Length()) + double InvLength() const + { + return 1.0 / Length(); + } + + /// + /// Calculates a vector with values being absolute values of that vector + /// + /// Absolute vector + Double3 GetAbsolute() const + { + return Double3(Math::Abs(X), Math::Abs(Y), Math::Abs(Z)); + } + + /// + /// Calculates a vector with values being opposite to values of that vector + /// + /// Negative vector + Double3 GetNegative() const + { + return Double3(-X, -Y, -Z); + } + + /// + /// Calculates a normalized vector that has length equal to 1. + /// + /// The normalized vector. + Double3 GetNormalized() const + { + const double rcp = 1.0 / Length(); + return Double3(X * rcp, Y * rcp, Z * rcp); + } + + /// + /// Returns average arithmetic of all the components + /// + /// Average arithmetic of all the components + double AverageArithmetic() const + { + return (X + Y + Z) * 0.333333334; + } + + /// + /// Gets sum of all vector components values + /// + /// Sum of X,Y and Z + double SumValues() const + { + return X + Y + Z; + } + + /// + /// Returns minimum value of all the components + /// + /// Minimum value + double MinValue() const + { + return Math::Min(X, Y, Z); + } + + /// + /// Returns maximum value of all the components + /// + /// Maximum value + double MaxValue() const + { + return Math::Max(X, Y, Z); + } + + /// + /// Returns true if vector has one or more components is not a number (NaN) + /// + /// True if one or more components is not a number (NaN) + bool IsNaN() const + { + return isnan(X) || isnan(Y) || isnan(Z); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity + /// + /// True if one or more components equal to +/- infinity + bool IsInfinity() const + { + return isinf(X) || isinf(Y) || isinf(Z); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity or NaN + /// + /// True if one or more components equal to +/- infinity or NaN + bool IsNanOrInfinity() const + { + return IsInfinity() || IsNaN(); + } + +public: + + /// + /// Performs vector normalization (scales vector up to unit length) + /// + void Normalize() + { + const double length = Length(); + if (!Math::IsZero(length)) + { + const double inv = 1.0f / length; + X *= inv; + Y *= inv; + Z *= inv; + } + } + + /// + /// Performs fast vector normalization (scales vector up to unit length) + /// + void NormalizeFast() + { + const double inv = 1.0f / Length(); + X *= inv; + Y *= inv; + Z *= inv; + } + + /// + /// Sets all vector components to the absolute values + /// + void Absolute() + { + X = Math::Abs(X); + Y = Math::Abs(Y); + Z = Math::Abs(Z); + } + + /// + /// Negates all components of that vector + /// + void Negate() + { + X = -X; + Y = -Y; + Z = -Z; + } + + /// + /// When this vector contains Euler angles (degrees), ensure that angles are between +/-180 + /// + void UnwindEuler(); + +public: + + // Arithmetic operators with Double3 + Double3 operator+(const Double3& b) const + { + return Add(*this, b); + } + + Double3 operator-(const Double3& b) const + { + return Subtract(*this, b); + } + + Double3 operator*(const Double3& b) const + { + return Multiply(*this, b); + } + + Double3 operator/(const Double3& b) const + { + return Divide(*this, b); + } + + Double3 operator-() const + { + return Double3(-X, -Y, -Z); + } + + Double3 operator^(const Double3& b) const + { + return Cross(*this, b); + } + + double operator|(const Double3& b) const + { + return Dot(*this, b); + } + + // op= operators with Vector3 + Double3& operator+=(const Double3& b) + { + *this = Add(*this, b); + return *this; + } + + Double3& operator-=(const Double3& b) + { + *this = Subtract(*this, b); + return *this; + } + + Double3& operator*=(const Double3& b) + { + *this = Multiply(*this, b); + return *this; + } + + Double3& operator/=(const Double3& b) + { + *this = Divide(*this, b); + return *this; + } + + // Arithmetic operators with double + Double3 operator+(double b) const + { + return Add(*this, b); + } + + Double3 operator-(double b) const + { + return Subtract(*this, b); + } + + Double3 operator*(double b) const + { + return Multiply(*this, b); + } + + Double3 operator/(double b) const + { + return Divide(*this, b); + } + + // op= operators with double + Double3& operator+=(double b) + { + *this = Add(*this, b); + return *this; + } + + Double3& operator-=(double b) + { + *this = Subtract(*this, b); + return *this; + } + + Double3& operator*=(double b) + { + *this = Multiply(*this, b); + return *this; + } + + Double3& operator/=(double b) + { + *this = Divide(*this, b); + return *this; + } + + // Comparison operators + bool operator==(const Double3& b) const + { + return X == b.X && Y == b.Y && Z == b.Z; + } + + bool operator!=(const Double3& b) const + { + return X != b.X || Y != b.Y || Z != b.Z; + } + + bool operator>(const Double3& b) const + { + return X > b.X && Y > b.Y && Z > b.Z; + } + + bool operator>=(const Double3& b) const + { + return X >= b.X && Y >= b.Y && Z >= b.Z; + } + + bool operator<(const Double3& b) const + { + return X < b.X && Y < b.Y && Z < b.Z; + } + + bool operator<=(const Double3& b) const + { + return X <= b.X && Y <= b.Y && Z <= b.Z; + } + +public: + + static bool NearEqual(const Double3& a, const Double3& b) + { + return Math::NearEqual(a.X, b.X) && Math::NearEqual(a.Y, b.Y) && Math::NearEqual(a.Z, b.Z); + } + + static bool NearEqual(const Double3& a, const Double3& b, double epsilon) + { + return Math::NearEqual(a.X, b.X, epsilon) && Math::NearEqual(a.Y, b.Y, epsilon) && Math::NearEqual(a.Z, b.Z, epsilon); + } + +public: + + static void Add(const Double3& a, const Double3& b, Double3& result) + { + result.X = a.X + b.X; + result.Y = a.Y + b.Y; + result.Z = a.Z + b.Z; + } + + static Double3 Add(const Double3& a, const Double3& b) + { + Double3 result; + Add(a, b, result); + return result; + } + + static void Subtract(const Double3& a, const Double3& b, Double3& result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + result.Z = a.Z - b.Z; + } + + static Double3 Subtract(const Double3& a, const Double3& b) + { + Double3 result; + Subtract(a, b, result); + return result; + } + + static Double3 Multiply(const Double3& a, const Double3& b) + { + return Double3(a.X * b.X, a.Y * b.Y, a.Z * b.Z); + } + + static void Multiply(const Double3& a, const Double3& b, Double3& result) + { + result = Double3(a.X * b.X, a.Y * b.Y, a.Z * b.Z); + } + + static Double3 Multiply(const Double3& a, double b) + { + return Double3(a.X * b, a.Y * b, a.Z * b); + } + + static Double3 Divide(const Double3& a, const Double3& b) + { + return Double3(a.X / b.X, a.Y / b.Y, a.Z / b.Z); + } + + static void Divide(const Double3& a, const Double3& b, Double3& result) + { + result = Double3(a.X / b.X, a.Y / b.Y, a.Z / b.Z); + } + + static Double3 Divide(const Double3& a, double b) + { + return Double3(a.X / b, a.Y / b, a.Z / b); + } + + static Double3 Floor(const Double3& v); + static Double3 Frac(const Double3& v); + + static double ScalarProduct(const Double3& a, const Double3& b) + { + return a.X * b.X + a.Y * b.Y + a.Z * b.Z; + } + +public: + + // Restricts a value to be within a specified range + // @param value The value to clamp + // @param min The minimum value, + // @param max The maximum value + // @returns Clamped value + static Double3 Clamp(const Double3& value, const Double3& min, const Double3& max); + + // Restricts a value to be within a specified range + // @param value The value to clamp + // @param min The minimum value, + // @param max The maximum value + // @param result When the method completes, contains the clamped value + static void Clamp(const Double3& value, const Double3& min, const Double3& max, Double3& result); + + // Calculates the distance between two vectors + // @param value1 The first vector + // @param value2 The second vector + // @returns The distance between the two vectors + static double Distance(const Double3& value1, const Double3& value2); + + // Calculates the squared distance between two vectors + // @param value1 The first vector + // @param value2 The second vector + // @returns The squared distance between the two vectors + static double DistanceSquared(const Double3& value1, const Double3& value2); + + // Performs vector normalization (scales vector up to unit length) + // @param inout Input vector to normalize + // @returns Output vector that is normalized (has unit length) + static Double3 Normalize(const Double3& input); + + // Performs vector normalization (scales vector up to unit length). This is a faster version that does not performs check for length equal 0 (it assumes that input vector is not empty). + // @param inout Input vector to normalize (cannot be zero). + // @returns Output vector that is normalized (has unit length) + static Double3 NormalizeFast(const Double3& input) + { + const double inv = 1.0 / input.Length(); + return Double3(input.X * inv, input.Y * inv, input.Z * inv); + } + + // Performs vector normalization (scales vector up to unit length) + // @param inout Input vector to normalize + // @param output Output vector that is normalized (has unit length) + static void Normalize(const Double3& input, Double3& result); + + // dot product with another vector + static double Dot(const Double3& a, const Double3& b) + { + return a.X * b.X + a.Y * b.Y + a.Z * b.Z; + } + + // Calculates the cross product of two vectors + // @param a First source vector + // @param b Second source vector + // @param result When the method completes, contains the cross product of the two vectors + static void Cross(const Double3& a, const Double3& b, Double3& result) + { + result = Double3( + a.Y * b.Z - a.Z * b.Y, + a.Z * b.X - a.X * b.Z, + a.X * b.Y - a.Y * b.X); + } + + // Calculates the cross product of two vectors + // @param a First source vector + // @param b Second source vector + // @returns Cross product of the two vectors + static Double3 Cross(const Double3& a, const Double3& b) + { + return Double3( + a.Y * b.Z - a.Z * b.Y, + a.Z * b.X - a.X * b.Z, + a.X * b.Y - a.Y * b.X); + } + + // Performs a linear interpolation between two vectors + // @param start Start vector + // @param end End vector + // @param amount Value between 0 and 1 indicating the weight of end + // @param result When the method completes, contains the linear interpolation of the two vectors + static void Lerp(const Double3& start, const Double3& end, double amount, Double3& result) + { + result.X = Math::Lerp(start.X, end.X, amount); + result.Y = Math::Lerp(start.Y, end.Y, amount); + result.Z = Math::Lerp(start.Z, end.Z, amount); + } + + // + // Performs a linear interpolation between two vectors. + // + // @param start Start vector, + // @param end End vector, + // @param amount Value between 0 and 1 indicating the weight of @paramref end"/>, + // @returns The linear interpolation of the two vectors + static Double3 Lerp(const Double3& start, const Double3& end, double amount) + { + Double3 result; + Lerp(start, end, amount, result); + return result; + } + + // Performs a cubic interpolation between two vectors + // @param start Start vector + // @param end End vector + // @param amount Value between 0 and 1 indicating the weight of end + // @param result When the method completes, contains the cubic interpolation of the two vectors + static void SmoothStep(const Double3& start, const Double3& end, double amount, Double3& result) + { + amount = Math::SmoothStep(amount); + Lerp(start, end, amount, result); + } + + // Performs a Hermite spline interpolation. + // @param value1 First source position vector + // @param tangent1 First source tangent vector + // @param value2 Second source position vector + // @param tangent2 Second source tangent vector + // @param amount Weighting factor, + // @param result When the method completes, contains the result of the Hermite spline interpolation, + static void Hermite(const Double3& value1, const Double3& tangent1, const Double3& value2, const Double3& tangent2, double amount, Double3& result); + + // Returns the reflection of a vector off a surface that has the specified normal + // @param vector The source vector + // @param normal Normal of the surface + // @param result When the method completes, contains the reflected vector + static void Reflect(const Double3& vector, const Double3& normal, Double3& result); + + // Transforms a 3D vector by the given Quaternion rotation + // @param vector The vector to rotate + // @param rotation The Quaternion rotation to apply + // @param result When the method completes, contains the transformed Vector4 + static void Transform(const Double3& vector, const Quaternion& rotation, Double3& result); + + // Transforms a 3D vector by the given Quaternion rotation + // @param vector The vector to rotate + // @param rotation The Quaternion rotation to apply + // @returns The transformed Double3 + static Double3 Transform(const Double3& vector, const Quaternion& rotation); + + // Transforms a 3D vector by the given matrix + // @param vector The source vector + // @param transform The transformation matrix + // @param result When the method completes, contains the transformed Double3 + static void Transform(const Double3& vector, const Matrix& transform, Double3& result); + + // Transforms a 3D vectors by the given matrix + // @param vectors The source vectors + // @param transform The transformation matrix + // @param results When the method completes, contains the transformed Vector3s + // @param vectorsCount Amount of vectors to transform + static void Transform(const Double3* vectors, const Matrix& transform, Double3* results, int32 vectorsCount); + + // Transforms a 3D vector by the given matrix + // @param vector The source vector + // @param transform The transformation matrix + // @returns Transformed Double3 + static Double3 Transform(const Double3& vector, const Matrix& transform); + + // Transforms a 3D vector by the given matrix + // @param vector The source vector + // @param transform The transformation matrix + // @param result When the method completes, contains the transformed Double4 + static void Transform(const Double3& vector, const Matrix& transform, Double4& result); + + // Performs a coordinate transformation using the given matrix + // @param coordinate The coordinate vector to transform + // @param transform The transformation matrix + // @param result When the method completes, contains the transformed coordinates + static void TransformCoordinate(const Double3& coordinate, const Matrix& transform, Double3& result); + + // Performs a normal transformation using the given matrix + // @param normal The normal vector to transform + // @param transform The transformation matrix + // @param result When the method completes, contains the transformed normal + static void TransformNormal(const Double3& normal, const Matrix& transform, Double3& result); + + // Returns a vector containing the largest components of the specified vectors + // @param a The first source vector + // @param b The second source vector + // @param result When the method completes, contains an new vector composed of the largest components of the source vectors + static Double3 Max(const Double3& a, const Double3& b) + { + return Double3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z); + } + + // Returns a vector containing the smallest components of the specified vectors + // @param a The first source vector + // @param b The second source vector + // @param result When the method completes, contains an new vector composed of the smallest components of the source vectors + static Double3 Min(const Double3& a, const Double3& b) + { + return Double3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z); + } + + // Returns a vector containing the largest components of the specified vectors + // @param a The first source vector + // @param b The second source vector + // @param result When the method completes, contains an new vector composed of the largest components of the source vectors + static void Max(const Double3& a, const Double3& b, Double3& result) + { + result = Double3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z); + } + + // Returns a vector containing the smallest components of the specified vectors + // @param a The first source vector + // @param b The second source vector + // @param result When the method completes, contains an new vector composed of the smallest components of the source vectors + static void Min(const Double3& a, const Double3& b, Double3& result) + { + result = Double3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z); + } + + /// + /// Projects a vector onto another vector. + /// + /// The vector to project. + /// The projection normal vector. + /// The projected vector. + static Double3 Project(const Double3& vector, const Double3& onNormal); + + /// + /// Projects a vector onto a plane defined by a normal orthogonal to the plane. + /// + /// The vector to project. + /// The plane normal vector. + /// The projected vector. + static Double3 ProjectOnPlane(const Double3& vector, const Double3& planeNormal) + { + return vector - Project(vector, planeNormal); + } + + // Projects a 3D vector from object space into screen space + // @param vector The vector to project + // @param x The X position of the viewport + // @param y The Y position of the viewport + // @param width The width of the viewport + // @param height The height of the viewport + // @param minZ The minimum depth of the viewport + // @param maxZ The maximum depth of the viewport + // @param worldViewProjection The combined world-view-projection matrix + // @param result When the method completes, contains the vector in screen space + static void Project(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection, Double3& result); + + // Projects a 3D vector from object space into screen space + // @param vector The vector to project + // @param x The X position of the viewport + // @param y The Y position of the viewport + // @param width The width of the viewport + // @param height The height of the viewport + // @param minZ The minimum depth of the viewport + // @param maxZ The maximum depth of the viewport + // @param worldViewProjection The combined world-view-projection matrix + // @returns The vector in screen space + static Double3 Project(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection) + { + Double3 result; + Project(vector, x, y, width, height, minZ, maxZ, worldViewProjection, result); + return result; + } + + // Projects a 3D vector from screen space into object space + // @param vector The vector to project + // @param x The X position of the viewport + // @param y The Y position of the viewport + // @param width The width of the viewport + // @param height The height of the viewport + // @param minZ The minimum depth of the viewport + // @param maxZ The maximum depth of the viewport + // @param worldViewProjection The combined world-view-projection matrix + // @param result When the method completes, contains the vector in object space + static void Unproject(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection, Double3& result); + + // Projects a 3D vector from screen space into object space + // @param vector The vector to project + // @param x The X position of the viewport + // @param y The Y position of the viewport + // @param width The width of the viewport + // @param height The height of the viewport + // @param minZ The minimum depth of the viewport + // @param maxZ The maximum depth of the viewport + // @param worldViewProjection The combined world-view-projection matrix + // @returns The vector in object space + static Double3 Unproject(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection) + { + Double3 result; + Unproject(vector, x, y, width, height, minZ, maxZ, worldViewProjection, result); + return result; + } + + /// + /// Creates an orthonormal basis from a basis with at least two orthogonal vectors. + /// + /// The X axis. + /// The y axis. + /// The z axis. + static void CreateOrthonormalBasis(Double3& xAxis, Double3& yAxis, Double3& zAxis); + + /// + /// Finds the best arbitrary axis vectors to represent U and V axes of a plane, by using this vector as the normal of the plane. + /// + /// The reference to first axis. + /// The reference to second axis. + void FindBestAxisVectors(Double3& firstAxis, Double3& secondAxis) const; + + static Double3 Round(const Double3& v) + { + return Double3( + Math::Round(v.X), + Math::Round(v.Y), + Math::Round(v.Z) + ); + } + + static Double3 Ceil(const Double3& v) + { + return Double3( + Math::Ceil(v.X), + Math::Ceil(v.Y), + Math::Ceil(v.Z) + ); + } + + static Double3 Abs(const Double3& v) + { + return Double3(Math::Abs(v.X), Math::Abs(v.Y), Math::Abs(v.Z)); + } + + /// + /// Calculates the area of the triangle. + /// + /// The first triangle vertex. + /// The second triangle vertex. + /// The third triangle vertex. + /// The triangle area. + static double TriangleArea(const Double3& v0, const Double3& v1, const Double3& v2); + +}; + +inline Double3 operator+(double a, const Double3& b) +{ + return b + a; +} + +inline Double3 operator-(double a, const Double3& b) +{ + return Double3(a) - b; +} + +inline Double3 operator*(double a, const Double3& b) +{ + return b * a; +} + +inline Double3 operator/(double a, const Double3& b) +{ + return Double3(a) / b; +} + +namespace Math +{ + FORCE_INLINE static bool NearEqual(const Double3& a, const Double3& b) + { + return Double3::NearEqual(a, b); + } +} + +template<> +struct TIsPODType +{ + enum { Value = true }; +}; + +DEFINE_DEFAULT_FORMATTING(Double3, "X:{0} Y:{1} Z:{2}", v.X, v.Y, v.Z);