From 34dcbc0445269a6fb8377842714b9ed9fd09ecf7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 29 Oct 2024 23:55:42 +0100 Subject: [PATCH] Add `Vector3.SignedAngle` utility method Merge 072f7c7e45757f011ebd6936e4b2e01d9833abfe and c1bd42ff7eb71824683bb8ba63f0c9173281bb4d --- Source/Engine/Core/Math/Vector3.cpp | 32 +++++++++++++++++++++++++---- Source/Engine/Core/Math/Vector3.cs | 17 ++++++++++++++- Source/Engine/Core/Math/Vector3.h | 13 ++++++++++-- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/Source/Engine/Core/Math/Vector3.cpp b/Source/Engine/Core/Math/Vector3.cpp index 5a26f2309..d11df8f6d 100644 --- a/Source/Engine/Core/Math/Vector3.cpp +++ b/Source/Engine/Core/Math/Vector3.cpp @@ -320,8 +320,17 @@ float Float3::Angle(const Float3& from, const Float3& to) { const float dot = Math::Clamp(Dot(Normalize(from), Normalize(to)), -1.0f, 1.0f); if (Math::Abs(dot) > 1.0f - ZeroTolerance) - return dot > 0.0f ? 0.0f : PI; - return Math::Acos(dot); + return dot > 0.0f ? 0.0f : 180.0f; + return Math::Acos(dot) * RadiansToDegrees; +} + +template<> +float Float3::SignedAngle(const Float3& from, const Float3& to, const Float3& axis) +{ + const float angle = Angle(from, to); + const Float3 cross = Cross(from, to); + const float sign = Math::Sign(axis.X * cross.X + axis.Y * cross.Y + axis.Z * cross.Z); + return angle * sign; } template<> @@ -648,8 +657,17 @@ double Double3::Angle(const Double3& from, const Double3& to) { const double dot = Math::Clamp(Dot(Normalize(from), Normalize(to)), -1.0, 1.0); if (Math::Abs(dot) > 1.0 - ZeroTolerance) - return dot > 0.0 ? 0.0 : PI; - return Math::Acos(dot); + return dot > 0.0 ? 0.0 : 180.0; + return Math::Acos(dot) * RadiansToDegrees; +} + +template<> +double Double3::SignedAngle(const Double3& from, const Double3& to, const Double3& axis) +{ + const double angle = Angle(from, to); + const Double3 cross = Cross(from, to); + const double sign = Math::Sign(axis.X * cross.X + axis.Y * cross.Y + axis.Z * cross.Z); + return angle * sign; } template<> @@ -881,6 +899,12 @@ int32 Int3::Angle(const Int3& from, const Int3& to) return 0; } +template<> +int32 Int3::SignedAngle(const Int3& from, const Int3& to, const Int3& axis) +{ + return 0; +} + template<> Int3 Int3::SnapToGrid(const Int3& pos, const Int3& gridSize) { diff --git a/Source/Engine/Core/Math/Vector3.cs b/Source/Engine/Core/Math/Vector3.cs index 61d0e51f0..360057f5d 100644 --- a/Source/Engine/Core/Math/Vector3.cs +++ b/Source/Engine/Core/Math/Vector3.cs @@ -1345,7 +1345,7 @@ namespace FlaxEngine } /// - /// Calculates the angle (in degrees) between and . This is always the smallest value. + /// Calculates the angle (in degrees) between and vectors. This is always the smallest value. /// /// The first vector. /// The second vector. @@ -1358,6 +1358,21 @@ namespace FlaxEngine return (Real)Math.Acos(dot) * Mathr.RadiansToDegrees; } + /// + /// Calculates the signed angle (in degrees) between and vectors. This is always the smallest value. The sign of the result depends on: the order of input vectors, and the direction of the vector. + /// + /// The first vector. + /// The second vector. + /// The axis around which the vectors are rotated. + /// The angle (in degrees). + public static Real SignedAngle(Vector3 from, Vector3 to, Vector3 axis) + { + Real angle = Angle(from, to); + Vector3 cross = Cross(from, to); + Real sign = Mathr.Sign(axis.X * cross.X + axis.Y * cross.Y + axis.Z * cross.Z); + return angle * sign; + } + /// /// Projects a 3D vector from object space into screen space. /// diff --git a/Source/Engine/Core/Math/Vector3.h b/Source/Engine/Core/Math/Vector3.h index 67f8e7d44..10271dece 100644 --- a/Source/Engine/Core/Math/Vector3.h +++ b/Source/Engine/Core/Math/Vector3.h @@ -812,13 +812,22 @@ public: static FLAXENGINE_API T TriangleArea(const Vector3Base& v0, const Vector3Base& v1, const Vector3Base& v2); /// - /// Calculates the angle (in radians) between from and to. This is always the smallest value. + /// Calculates the angle (in degrees) between from and to. This is always the smallest value. /// /// The first vector. /// The second vector. - /// The angle (in radians). + /// The angle (in degrees). static FLAXENGINE_API T Angle(const Vector3Base& from, const Vector3Base& to); + /// + /// Calculates the signed angle (in degrees) between from and to vectors. This is always the smallest value. The sign of the result depends on: the order of input vectors, and the direction of the axis vector. + /// + /// The first vector. + /// The second vector. + /// The axis around which the vectors are rotated. + /// The angle (in degrees). + static FLAXENGINE_API T SignedAngle(const Vector3Base& from, const Vector3Base& to, const Vector3Base& axis); + /// /// Snaps the input position onto the grid. ///