added more gcem to angle vec2,3

This commit is contained in:
2026-06-11 23:20:18 +03:00
parent 00e7c564fd
commit a2be99be50
6 changed files with 92 additions and 46 deletions
+1 -1
View File
@@ -239,7 +239,7 @@
"hidden": true, "hidden": true,
"inherits": ["darwin-base", "vcpkg-base"], "inherits": ["darwin-base", "vcpkg-base"],
"cacheVariables": { "cacheVariables": {
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;examples;lua" "VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;examples;lua;gcem"
} }
}, },
{ {
+20 -7
View File
@@ -3,6 +3,7 @@
// //
#pragma once #pragma once
#include "omath/internal/optional_constexpr_math.hpp"
#include <cmath> #include <cmath>
#include <format> #include <format>
#include <tuple> #include <tuple>
@@ -116,9 +117,13 @@ namespace omath
// Basic vector operations // Basic vector operations
[[nodiscard("You must use distance")]] [[nodiscard("You must use distance")]]
Type distance_to(const Vector2& other) const noexcept OMATH_CONSTEXPR Type distance_to(const Vector2& other) const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::sqrt(distance_to_sqr(other));
#else
return std::sqrt(distance_to_sqr(other)); return std::sqrt(distance_to_sqr(other));
#endif
} }
[[nodiscard("You must use squared distance")]] [[nodiscard("You must use squared distance")]]
@@ -136,7 +141,11 @@ namespace omath
#ifndef _MSC_VER #ifndef _MSC_VER
[[nodiscard("You must use length")]] constexpr Type length() const noexcept [[nodiscard("You must use length")]] constexpr Type length() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::hypot(this->x, this->y);
#else
return std::hypot(this->x, this->y); return std::hypot(this->x, this->y);
#endif
} }
[[nodiscard("You must use normalized vector")]] constexpr Vector2 normalized() const noexcept [[nodiscard("You must use normalized vector")]] constexpr Vector2 normalized() const noexcept
@@ -146,13 +155,17 @@ namespace omath
} }
#else #else
[[nodiscard("You must use length")]] [[nodiscard("You must use length")]]
Type length() const noexcept OMATH_CONSTEXPR Type length() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::hypot(x, y);
#else
return std::hypot(x, y); return std::hypot(x, y);
#endif
} }
[[nodiscard("You must use normalized vector")]] [[nodiscard("You must use normalized vector")]]
Vector2 normalized() const noexcept OMATH_CONSTEXPR Vector2 normalized() const noexcept
{ {
const Type len = length(); const Type len = length();
return len > static_cast<Type>(0) ? *this / len : *this; return len > static_cast<Type>(0) ? *this / len : *this;
@@ -216,24 +229,24 @@ namespace omath
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator<(const Vector2& other) const noexcept OMATH_CONSTEXPR bool operator<(const Vector2& other) const noexcept
{ {
return length() < other.length(); return length() < other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator>(const Vector2& other) const noexcept OMATH_CONSTEXPR bool operator>(const Vector2& other) const noexcept
{ {
return length() > other.length(); return length() > other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator<=(const Vector2& other) const noexcept OMATH_CONSTEXPR bool operator<=(const Vector2& other) const noexcept
{ {
return length() <= other.length(); return length() <= other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator>=(const Vector2& other) const noexcept OMATH_CONSTEXPR bool operator>=(const Vector2& other) const noexcept
{ {
return length() >= other.length(); return length() >= other.length();
} }
+29 -17
View File
@@ -140,20 +140,24 @@ namespace omath
} }
#ifndef _MSC_VER #ifndef _MSC_VER
[[nodiscard("You must use length")]] constexpr Type length() const [[nodiscard("You must use length")]] constexpr Type length() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::sqrt(this->x * this->x + this->y * this->y + z * z);
#else
return std::hypot(this->x, this->y, z); return std::hypot(this->x, this->y, z);
#endif
} }
[[nodiscard("You must use 2D length")]] constexpr Type length_2d() const [[nodiscard("You must use 2D length")]] constexpr Type length_2d() const noexcept
{ {
return Vector2<Type>::length(); return Vector2<Type>::length();
} }
[[nodiscard("You must use distance")]] Type distance_to(const Vector3& other) const [[nodiscard("You must use distance")]] OMATH_CONSTEXPR Type distance_to(const Vector3& other) const noexcept
{ {
return (*this - other).length(); return (*this - other).length();
} }
[[nodiscard("You must use normalized vector")]] constexpr Vector3 normalized() const [[nodiscard("You must use normalized vector")]] constexpr Vector3 normalized() const noexcept
{ {
const Type length_value = this->length(); const Type length_value = this->length();
@@ -161,13 +165,17 @@ namespace omath
} }
#else #else
[[nodiscard("You must use length")]] [[nodiscard("You must use length")]]
Type length() const noexcept OMATH_CONSTEXPR Type length() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::sqrt(this->x * this->x + this->y * this->y + this->z * this->z);
#else
return std::hypot(this->x, this->y, z); return std::hypot(this->x, this->y, z);
#endif
} }
[[nodiscard("You must use normalized vector")]] [[nodiscard("You must use normalized vector")]]
Vector3 normalized() const noexcept OMATH_CONSTEXPR Vector3 normalized() const noexcept
{ {
const Type len = this->length(); const Type len = this->length();
@@ -175,13 +183,13 @@ namespace omath
} }
[[nodiscard("You must use 2D length")]] [[nodiscard("You must use 2D length")]]
Type length_2d() const noexcept OMATH_CONSTEXPR Type length_2d() const noexcept
{ {
return Vector2<Type>::length(); return Vector2<Type>::length();
} }
[[nodiscard("You must use distance")]] [[nodiscard("You must use distance")]]
Type distance_to(const Vector3& v_other) const noexcept OMATH_CONSTEXPR Type distance_to(const Vector3& v_other) const noexcept
{ {
return (*this - v_other).length(); return (*this - v_other).length();
} }
@@ -249,24 +257,28 @@ namespace omath
} }
[[nodiscard("You must use direction check result")]] [[nodiscard("You must use direction check result")]]
bool point_to_same_direction(const Vector3& other) const OMATH_CONSTEXPR bool point_to_same_direction(const Vector3& other) const
{ {
return dot(other) > static_cast<Type>(0); return dot(other) > static_cast<Type>(0);
} }
[[nodiscard("You must use angle between vectors")]] [[nodiscard("You must use angle between vectors")]]
std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error> OMATH_CONSTEXPR std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error>
angle_between(const Vector3& other) const noexcept angle_between(const Vector3& other) const noexcept
{ {
const auto bottom = length() * other.length(); const auto bottom = length() * other.length();
if (bottom == static_cast<Type>(0)) if (bottom == static_cast<Type>(0))
return std::unexpected(Vector3Error::IMPOSSIBLE_BETWEEN_ANGLE); return std::unexpected(Vector3Error::IMPOSSIBLE_BETWEEN_ANGLE);
#ifdef OMATH_USE_GCEM
return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::from_radians(gcem::acos(dot(other) / bottom));
#else
return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::from_radians(std::acos(dot(other) / bottom)); return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::from_radians(std::acos(dot(other) / bottom));
#endif
} }
[[nodiscard("You must use perpendicularity check result")]] [[nodiscard("You must use perpendicularity check result")]]
bool is_perpendicular(const Vector3& other, Type epsilon = static_cast<Type>(0.0001)) const noexcept OMATH_CONSTEXPR bool is_perpendicular(const Vector3& other,
Type epsilon = static_cast<Type>(0.0001)) const noexcept
{ {
if (const auto angle = angle_between(other)) if (const auto angle = angle_between(other))
return std::abs(angle->as_degrees() - static_cast<Type>(90)) <= epsilon; return std::abs(angle->as_degrees() - static_cast<Type>(90)) <= epsilon;
@@ -287,25 +299,25 @@ namespace omath
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator<(const Vector3& other) const noexcept OMATH_CONSTEXPR bool operator<(const Vector3& other) const noexcept
{ {
return length() < other.length(); return length() < other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator>(const Vector3& other) const noexcept OMATH_CONSTEXPR bool operator>(const Vector3& other) const noexcept
{ {
return length() > other.length(); return length() > other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator<=(const Vector3& other) const noexcept OMATH_CONSTEXPR bool operator<=(const Vector3& other) const noexcept
{ {
return length() <= other.length(); return length() <= other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator>=(const Vector3& other) const noexcept OMATH_CONSTEXPR bool operator>=(const Vector3& other) const noexcept
{ {
return length() >= other.length(); return length() >= other.length();
} }
@@ -321,7 +333,7 @@ namespace omath
template<> struct std::hash<omath::Vector3<float>> template<> struct std::hash<omath::Vector3<float>>
{ {
[[nodiscard("You must use hash value")]] [[nodiscard("You must use hash value")]]
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept constexpr std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
{ {
std::size_t hash = 0; std::size_t hash = 0;
constexpr std::hash<float> hasher; constexpr std::hash<float> hasher;
+8 -3
View File
@@ -3,11 +3,11 @@
// //
#pragma once #pragma once
#include "omath/internal/optional_constexpr_math.hpp"
#include "omath/trigonometry/angles.hpp" #include "omath/trigonometry/angles.hpp"
#include <algorithm> #include <algorithm>
#include <format> #include <format>
#include <utility> #include <utility>
#include "omath/internal/optional_constexpr_math.hpp"
namespace omath namespace omath
{ {
@@ -104,13 +104,18 @@ namespace omath
} }
[[nodiscard]] [[nodiscard]]
Type atan() const noexcept OMATH_CONSTEXPR Type atan() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::atan(as_radians());
#else
return std::atan(as_radians()); return std::atan(as_radians());
#endif
} }
[[nodiscard]] [[nodiscard]]
Type cot() const noexcept OMATH_CONSTEXPR Type cot() const noexcept
{ {
return cos() / sin(); return cos() / sin();
} }
+7 -2
View File
@@ -2,10 +2,10 @@
// Created by Vlad on 02.09.2024. // Created by Vlad on 02.09.2024.
// //
#include <omath/linear_algebra/vector2.hpp>
#include <cfloat> // For FLT_MAX and FLT_MIN #include <cfloat> // For FLT_MAX and FLT_MIN
#include <cmath> // For std::isinf and std::isnan #include <cmath> // For std::isinf and std::isnan
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/linear_algebra/vector2.hpp>
using namespace omath; using namespace omath;
@@ -399,7 +399,6 @@ TEST_F(UnitTestVector2, GreaterEqualOperator)
EXPECT_TRUE(omath::Vector2(1.f, 1.f) >= omath::Vector2<float>{}); EXPECT_TRUE(omath::Vector2(1.f, 1.f) >= omath::Vector2<float>{});
} }
// ── Cast operator tests ────────────────────────────────────────────────────── // ── Cast operator tests ──────────────────────────────────────────────────────
TEST(Vector2Cast, FloatToDouble) TEST(Vector2Cast, FloatToDouble)
@@ -463,3 +462,9 @@ static_assert(Vector2(1.0f, 2.0f).length_sqr() == 5.0f, "LengthSqr should be 5")
static_assert(Vector2(1.0f, 2.0f).dot(Vector2(4.0f, 5.0f)) == 14.0f, "Dot product should be 14"); static_assert(Vector2(1.0f, 2.0f).dot(Vector2(4.0f, 5.0f)) == 14.0f, "Dot product should be 14");
static_assert(Vector2(4.0f, 5.0f).distance_to_sqr(Vector2(1.0f, 2.0f)) == 18.0f, "DistToSqr should be 18"); static_assert(Vector2(4.0f, 5.0f).distance_to_sqr(Vector2(1.0f, 2.0f)) == 18.0f, "DistToSqr should be 18");
static_assert(Vector2(-1.0f, -2.0f).abs() == Vector2(1.0f, 2.0f), "Abs should convert negative values to positive"); static_assert(Vector2(-1.0f, -2.0f).abs() == Vector2(1.0f, 2.0f), "Abs should convert negative values to positive");
#ifdef OMATH_USE_GCEM
static_assert(Vector2(3.0f, 4.0f).length() == 5.0f, "Length should be constexpr with gcem");
static_assert(Vector2(0.0f, 0.0f).distance_to(Vector2(3.0f, 4.0f)) == 5.0f, "Distance should be constexpr with gcem");
static_assert(Vector2(1.0f, 1.0f) < Vector2(3.0f, 4.0f), "Comparison should be constexpr with gcem");
#endif
+27 -16
View File
@@ -2,11 +2,11 @@
// Created by Vlad on 01.09.2024. // Created by Vlad on 01.09.2024.
// //
#include <omath/linear_algebra/vector3.hpp>
#include <cfloat> // For FLT_MAX, FLT_MIN #include <cfloat> // For FLT_MAX, FLT_MIN
#include <cmath> #include <cmath>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <limits> // For std::numeric_limits #include <limits> // For std::numeric_limits
#include <omath/linear_algebra/vector3.hpp>
using namespace omath; using namespace omath;
@@ -31,35 +31,33 @@ TEST(Vector3More, ArithmeticAndDotCross)
constexpr Vector3<float> a{1.f, 0.f, 0.f}; constexpr Vector3<float> a{1.f, 0.f, 0.f};
constexpr Vector3<float> b{0.f, 1.f, 0.f}; constexpr Vector3<float> b{0.f, 1.f, 0.f};
const auto c = a + b; const auto c = a + b;
constexpr Vector3<float> expect_c{1.f,1.f,0.f}; constexpr Vector3<float> expect_c{1.f, 1.f, 0.f};
EXPECT_EQ(c, expect_c); EXPECT_EQ(c, expect_c);
const auto d = a - b; const auto d = a - b;
constexpr Vector3<float> expect_d{1.f,-1.f,0.f}; constexpr Vector3<float> expect_d{1.f, -1.f, 0.f};
EXPECT_EQ(d, expect_d); EXPECT_EQ(d, expect_d);
const auto e = a * 2.f; const auto e = a * 2.f;
constexpr Vector3<float> expect_e{2.f,0.f,0.f}; constexpr Vector3<float> expect_e{2.f, 0.f, 0.f};
EXPECT_EQ(e, expect_e); EXPECT_EQ(e, expect_e);
EXPECT_FLOAT_EQ(a.dot(b), 0.f); EXPECT_FLOAT_EQ(a.dot(b), 0.f);
// manual cross product check // manual cross product check
const auto cr = Vector3<float>{ a.y * b.z - a.z * b.y, const auto cr = Vector3<float>{a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
a.z * b.x - a.x * b.z, constexpr Vector3<float> expect_cr{0.f, 0.f, 1.f};
a.x * b.y - a.y * b.x };
constexpr Vector3<float> expect_cr{0.f,0.f,1.f};
EXPECT_EQ(cr, expect_cr); EXPECT_EQ(cr, expect_cr);
} }
TEST(Vector3More, NormalizationEdgeCases) TEST(Vector3More, NormalizationEdgeCases)
{ {
constexpr Vector3<double> z{0.0,0.0,0.0}; constexpr Vector3<double> z{0.0, 0.0, 0.0};
const auto zn = z.normalized(); const auto zn = z.normalized();
EXPECT_DOUBLE_EQ(zn.x, 0.0); EXPECT_DOUBLE_EQ(zn.x, 0.0);
EXPECT_DOUBLE_EQ(zn.y, 0.0); EXPECT_DOUBLE_EQ(zn.y, 0.0);
EXPECT_DOUBLE_EQ(zn.z, 0.0); EXPECT_DOUBLE_EQ(zn.z, 0.0);
constexpr Vector3<double> v{3.0,4.0,0.0}; constexpr Vector3<double> v{3.0, 4.0, 0.0};
const auto vn = v.normalized(); const auto vn = v.normalized();
EXPECT_NEAR(vn.x, 0.6, 1e-12); EXPECT_NEAR(vn.x, 0.6, 1e-12);
EXPECT_NEAR(vn.y, 0.8, 1e-12); EXPECT_NEAR(vn.y, 0.8, 1e-12);
@@ -481,16 +479,14 @@ TEST_F(UnitTestVector3, AsTuple)
// Test AsTuple method // Test AsTuple method
TEST_F(UnitTestVector3, AngleBeatween) TEST_F(UnitTestVector3, AngleBeatween)
{ {
EXPECT_NEAR(Vector3(0.0f, 0.0f, 1.0f).angle_between({1, 0, 0}).value().as_degrees(), EXPECT_NEAR(Vector3(0.0f, 0.0f, 1.0f).angle_between({1, 0, 0}).value().as_degrees(), 90.0f, 0.001f);
90.0f, 0.001f); EXPECT_NEAR(Vector3(0.0f, 0.0f, 1.0f).angle_between({0.0f, 0.0f, 1.0f}).value().as_degrees(), 0.0f, 0.001f);
EXPECT_NEAR(Vector3(0.0f, 0.0f, 1.0f).angle_between({0.0f, 0.0f, 1.0f}).value().as_degrees(),
0.0f, 0.001f);
EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).angle_between({0.0f, 0.0f, 1.0f}).has_value()); EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).angle_between({0.0f, 0.0f, 1.0f}).has_value());
} }
TEST_F(UnitTestVector3, IsPerpendicular) TEST_F(UnitTestVector3, IsPerpendicular)
{ {
EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({1, 0 ,0}), true); EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({1, 0, 0}), true);
EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({0.0f, 0.0f, 1.0f}), false); EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({0.0f, 0.0f, 1.0f}), false);
EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).is_perpendicular({0.0f, 0.0f, 1.0f})); EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).is_perpendicular({0.0f, 0.0f, 1.0f}));
} }
@@ -585,4 +581,19 @@ TEST(Vector3Cast, SameTypeRoundtrip)
static_assert(Vector3(1.0f, 2.0f, 3.0f).length_sqr() == 14.0f, "LengthSqr should be 14"); static_assert(Vector3(1.0f, 2.0f, 3.0f).length_sqr() == 14.0f, "LengthSqr should be 14");
static_assert(Vector3(1.0f, 2.0f, 3.0f).dot(Vector3(4.0f, 5.0f, 6.0f)) == 32.0f, "Dot product should be 32"); static_assert(Vector3(1.0f, 2.0f, 3.0f).dot(Vector3(4.0f, 5.0f, 6.0f)) == 32.0f, "Dot product should be 32");
static_assert(Vector3(4.0f, 5.0f, 6.0f).distance_to_sqr(Vector3(1.0f, 2.0f, 3.0f)) == 27.0f, "DistToSqr should be 27"); static_assert(Vector3(4.0f, 5.0f, 6.0f).distance_to_sqr(Vector3(1.0f, 2.0f, 3.0f)) == 27.0f, "DistToSqr should be 27");
static_assert(Vector3(-1.0f, -2.0f, -3.0f).abs() == Vector3(1.0f, 2.0f, 3.0f), "Abs should convert negative values to positive"); static_assert(Vector3(-1.0f, -2.0f, -3.0f).abs() == Vector3(1.0f, 2.0f, 3.0f),
"Abs should convert negative values to positive");
#ifdef OMATH_USE_GCEM
static_assert(Vector3(1.0f, 2.0f, 2.0f).length() == 3.0f, "Length should be constexpr with gcem");
static_assert(Vector3(0.0f, 0.0f, 0.0f).distance_to(Vector3(1.0f, 2.0f, 2.0f)) == 3.0f,
"Distance should be constexpr with gcem");
static_assert(Vector3(1.0f, 1.0f, 1.0f) < Vector3(3.0f, 4.0f, 5.0f), "Comparison should be constexpr with gcem");
static_assert(
[]
{
constexpr auto angle = Vector3(1.0f, 0.0f, 0.0f).angle_between(Vector3(0.0f, 1.0f, 0.0f));
return angle.has_value() && angle->as_degrees() > 89.999f && angle->as_degrees() < 90.001f;
}(),
"Angle between should be constexpr with gcem");
#endif