diff --git a/Benchmark/BenchmarkMain.cpp b/Benchmark/BenchmarkMain.cpp index cde7d0cf09..077451b838 100644 --- a/Benchmark/BenchmarkMain.cpp +++ b/Benchmark/BenchmarkMain.cpp @@ -32,6 +32,7 @@ */ #include + #include #include #include @@ -85,6 +86,10 @@ #include #endif // BENCHMARK_BOX2D +using playrho::isnormal; +using playrho::sqrt; +using playrho::hypot; + template static T Rand(T lo, T hi) { @@ -1077,8 +1082,8 @@ static void UnitVectorFromVector(benchmark::State& state) static playrho::Vec2 GetUnitVec1(playrho::Vec2 vec, playrho::Vec2 fallback) { const auto magSquared = playrho::Square(vec[0]) + playrho::Square(vec[1]); - if (playrho::isnormal(magSquared)) { - const auto mag = playrho::sqrt(magSquared); + if (isnormal(magSquared)) { + const auto mag = sqrt(magSquared); return playrho::Vec2{vec[0] / mag, vec[1] / mag}; } return fallback; @@ -1087,12 +1092,12 @@ static playrho::Vec2 GetUnitVec1(playrho::Vec2 vec, playrho::Vec2 fallback) static playrho::Vec2 GetUnitVec2(playrho::Vec2 vec, playrho::Vec2 fallback) { const auto magSquared = playrho::Square(vec[0]) + playrho::Square(vec[1]); - if (playrho::isnormal(magSquared)) { - const auto mag = playrho::sqrt(magSquared); + if (isnormal(magSquared)) { + const auto mag = sqrt(magSquared); return playrho::Vec2{vec[0] / mag, vec[1] / mag}; } - const auto mag = playrho::hypot(vec[0], vec[1]); - if (playrho::isnormal(mag)) { + const auto mag = hypot(vec[0], vec[1]); + if (isnormal(mag)) { return playrho::Vec2{vec[0] / mag, vec[1] / mag}; } return fallback; diff --git a/Library/include/playrho/BodyID.hpp b/Library/include/playrho/BodyID.hpp index 86fd3dc923..e620fead65 100644 --- a/Library/include/playrho/BodyID.hpp +++ b/Library/include/playrho/BodyID.hpp @@ -36,20 +36,12 @@ using BodyID = detail::IndexingNamedType; /// @see BodyID. constexpr auto InvalidBodyID = static_cast(static_cast(-1)); -/// @brief Gets an invalid value for the BodyID type. -/// @see BodyID. -template <> -constexpr BodyID GetInvalid() noexcept -{ - return InvalidBodyID; -} - /// @brief Determines if the given value is valid. /// @see BodyID. template <> constexpr bool IsValid(const BodyID& value) noexcept { - return value != GetInvalid(); + return value != InvalidBodyID; } } // namespace playrho diff --git a/Library/include/playrho/ContactID.hpp b/Library/include/playrho/ContactID.hpp index 5c33a13d0c..9de5c24e00 100644 --- a/Library/include/playrho/ContactID.hpp +++ b/Library/include/playrho/ContactID.hpp @@ -36,18 +36,11 @@ using ContactID = detail::IndexingNamedType(static_cast(-1)); -/// @brief Gets an invalid value for the ContactID type. -template <> -constexpr ContactID GetInvalid() noexcept -{ - return InvalidContactID; -} - /// @brief Determines if the given value is valid. template <> constexpr bool IsValid(const ContactID& value) noexcept { - return value != GetInvalid(); + return value != InvalidContactID; } } // namespace playrho diff --git a/Library/include/playrho/JointID.hpp b/Library/include/playrho/JointID.hpp index 84117bcf25..431e401bc3 100644 --- a/Library/include/playrho/JointID.hpp +++ b/Library/include/playrho/JointID.hpp @@ -35,18 +35,11 @@ using JointID = detail::IndexingNamedType; /// @brief Invalid joint ID value. constexpr auto InvalidJointID = static_cast(static_cast(-1)); -/// @brief Gets an invalid value for the JointID type. -template <> -constexpr JointID GetInvalid() noexcept -{ - return InvalidJointID; -} - /// @brief Determines if the given value is valid. template <> constexpr bool IsValid(const JointID& value) noexcept { - return value != GetInvalid(); + return value != InvalidJointID; } } // namespace playrho diff --git a/Library/include/playrho/Math.hpp b/Library/include/playrho/Math.hpp index 8731e47430..c99d04f08f 100644 --- a/Library/include/playrho/Math.hpp +++ b/Library/include/playrho/Math.hpp @@ -26,6 +26,7 @@ /// @brief Conventional and custom math related code. #include +#include // for std::numeric_limits #include #include // for std::decay_t #include @@ -171,18 +172,28 @@ constexpr auto AlmostZero(const T& value) -> decltype(abs(value) < std::numeric_ } /// @brief Determines whether the given two values are "almost equal". +/// @note A default ULP of 4 is what googletest uses in its @c kMaxUlps setting for its +/// @c AlmostEquals function found in its @c gtest/internal/gtest-internal.h file. +/// @see https://github.com/google/googletest/blob/main/googletest/include/gtest/internal/gtest-internal.h template -constexpr auto AlmostEqual(const T& x, const T& y, int ulp = 2) --> std::enable_if_t, bool> +constexpr auto AlmostEqual(T a, T b, int ulp = 4) + -> std::enable_if_t, bool> { +#if 0 // From http://en.cppreference.com/w/cpp/types/numeric_limits/epsilon : // "the machine epsilon has to be scaled to the magnitude of the values used // and multiplied by the desired precision in ULPs (units in the last place) // unless the result is subnormal". // Where "subnormal" means almost zero. // - return (abs(x - y) < (std::numeric_limits::epsilon() * abs(x + y) * static_cast(ulp))) || - AlmostZero(x - y); + return (abs(a - b) < (std::numeric_limits::epsilon() * abs(a + b) * static_cast(ulp))) || + AlmostZero(a - b); +#else + for (; (a != b) && (ulp > 0); --ulp) { + a = nextafter(a, b); + } + return a == b; +#endif } /// @brief Constant expression enhanced truncate function. diff --git a/Library/include/playrho/Matrix.hpp b/Library/include/playrho/Matrix.hpp index f73c861c4b..d4af8f0d2e 100644 --- a/Library/include/playrho/Matrix.hpp +++ b/Library/include/playrho/Matrix.hpp @@ -215,13 +215,6 @@ constexpr bool IsValid(const Mat22& value) noexcept return IsValid(get<0>(value)) && IsValid(get<1>(value)); } -/// @brief Gets an invalid value for a Mat22. -template <> -constexpr Mat22 GetInvalid() noexcept -{ - return Mat22{GetInvalid(), GetInvalid()}; -} - } // namespace playrho #endif // PLAYRHO_MATRIX_HPP diff --git a/Library/include/playrho/Positive.hpp b/Library/include/playrho/Positive.hpp index ae02cb665c..66d0a8f3d6 100644 --- a/Library/include/playrho/Positive.hpp +++ b/Library/include/playrho/Positive.hpp @@ -24,6 +24,8 @@ /// @file /// @brief Definition of the @c Positive value checked types and related code. +#include // for std::numeric_limits + #include #include diff --git a/Library/include/playrho/Real.hpp b/Library/include/playrho/Real.hpp index 29a34eb362..76579a8415 100644 --- a/Library/include/playrho/Real.hpp +++ b/Library/include/playrho/Real.hpp @@ -26,6 +26,8 @@ * @brief Real number definition file. */ +#include // for std::numeric_limits + #include // for IsArithmeticV // Any header(s) for a user defined arithmetic type for Real go here... @@ -64,6 +66,12 @@ using Real = float; static_assert(IsArithmeticV); +// Requirements on Real per std::numeric_limits... +static_assert(!std::numeric_limits::is_integer); +static_assert(std::numeric_limits::is_signed); +static_assert(std::numeric_limits::has_infinity); +static_assert(std::numeric_limits::has_signaling_NaN || std::numeric_limits::has_quiet_NaN); + } // namespace playrho #endif // PLAYRHO_REAL_HPP diff --git a/Library/include/playrho/Real.hpp.in b/Library/include/playrho/Real.hpp.in index a3f217456d..3eeb34a12d 100644 --- a/Library/include/playrho/Real.hpp.in +++ b/Library/include/playrho/Real.hpp.in @@ -27,6 +27,8 @@ * @note This file was generated from the Real.hpp.in file. */ +#include // for std::numeric_limits + #include // for IsArithmeticV // Any header(s) for a user defined arithmetic type for Real go here... @@ -66,6 +68,12 @@ using Real = @PLAYRHO_REAL_TYPE@; static_assert(IsArithmeticV); +// Requirements on Real per std::numeric_limits... +static_assert(!std::numeric_limits::is_integer); +static_assert(std::numeric_limits::is_signed); +static_assert(std::numeric_limits::has_infinity); +static_assert(std::numeric_limits::has_signaling_NaN || std::numeric_limits::has_quiet_NaN); + } // namespace playrho #endif // PLAYRHO_REAL_HPP diff --git a/Library/include/playrho/Settings.hpp b/Library/include/playrho/Settings.hpp index 25db56baf1..871ef690b8 100644 --- a/Library/include/playrho/Settings.hpp +++ b/Library/include/playrho/Settings.hpp @@ -29,12 +29,13 @@ #ifndef PLAYRHO_SETTINGS_HPP #define PLAYRHO_SETTINGS_HPP +#include #include #include #include #include #include -#include +#include // for std::numeric_limits #include #include @@ -228,6 +229,13 @@ constexpr auto DefaultAngularSleepTolerance = Real((Pi * 2) / 180) * RadianPerSe /// biased normal collisions. constexpr auto DefaultCirclesRatio = Real(10); +/// @brief Invalid value of the template's instantiated numeric type +template ::has_signaling_NaN || std::numeric_limits::has_quiet_NaN, int> = 0> +constexpr auto Invalid = std::numeric_limits::has_signaling_NaN + ? std::numeric_limits::signaling_NaN() + : std::numeric_limits::quiet_NaN(); + } // namespace playrho #endif // PLAYRHO_SETTINGS_HPP diff --git a/Library/include/playrho/Settings.hpp.in b/Library/include/playrho/Settings.hpp.in index 769146f82b..7d90cf6ed5 100644 --- a/Library/include/playrho/Settings.hpp.in +++ b/Library/include/playrho/Settings.hpp.in @@ -30,12 +30,13 @@ #ifndef PLAYRHO_SETTINGS_HPP #define PLAYRHO_SETTINGS_HPP +#include #include #include #include #include #include -#include +#include // for std::numeric_limits #include #include @@ -229,6 +230,13 @@ constexpr auto DefaultAngularSleepTolerance = Real((Pi * 2) / 180) * RadianPerSe /// biased normal collisions. constexpr auto DefaultCirclesRatio = Real(10); +/// @brief Invalid value of the template's instantiated numeric type +template ::has_signaling_NaN || std::numeric_limits::has_quiet_NaN, int> = 0> +constexpr auto Invalid = std::numeric_limits::has_signaling_NaN + ? std::numeric_limits::signaling_NaN() + : std::numeric_limits::quiet_NaN(); + } // namespace playrho #endif // PLAYRHO_SETTINGS_HPP diff --git a/Library/include/playrho/ShapeID.hpp b/Library/include/playrho/ShapeID.hpp index 8e945de530..4105031587 100644 --- a/Library/include/playrho/ShapeID.hpp +++ b/Library/include/playrho/ShapeID.hpp @@ -35,18 +35,11 @@ using ShapeID = detail::IndexingNamedType; /// @brief Invalid fixture ID value. constexpr auto InvalidShapeID = static_cast(static_cast(-1)); -/// @brief Gets an invalid value for the ShapeID type. -template <> -constexpr ShapeID GetInvalid() noexcept -{ - return InvalidShapeID; -} - /// @brief Determines if the given value is valid. template <> constexpr bool IsValid(const ShapeID& value) noexcept { - return value != GetInvalid(); + return value != InvalidShapeID; } } // namespace playrho diff --git a/Library/include/playrho/Templates.hpp b/Library/include/playrho/Templates.hpp index 0b834bf751..222326650b 100644 --- a/Library/include/playrho/Templates.hpp +++ b/Library/include/playrho/Templates.hpp @@ -28,18 +28,7 @@ namespace playrho { -/// @brief Gets an invalid value for the type. -/// @tparam T Type to get an invalid value for. -/// @note Specialize this function for the types which have an invalid value concept. -/// @see IsValid. -template -constexpr T GetInvalid() noexcept -{ - static_assert(sizeof(T) == 0, "No available specialization"); -} - /// @brief Determines if the given value is valid. -/// @see GetInvalid. template constexpr bool IsValid(const T& value) noexcept { @@ -56,43 +45,13 @@ constexpr bool IsValid(const T& value) noexcept return value == value; // NOLINT(misc-redundant-expression) } -// GetInvalid template specializations. - -/// @brief Gets an invalid value for the float type. -template <> -constexpr float GetInvalid() noexcept -{ - return std::numeric_limits::signaling_NaN(); -} - -/// @brief Gets an invalid value for the double type. -template <> -constexpr double GetInvalid() noexcept -{ - return std::numeric_limits::signaling_NaN(); -} - -/// @brief Gets an invalid value for the long double type. -template <> -constexpr long double GetInvalid() noexcept -{ - return std::numeric_limits::signaling_NaN(); -} - -/// @brief Gets an invalid value for the std::size_t type. -template <> -constexpr std::size_t GetInvalid() noexcept -{ - return static_cast(-1); -} - // IsValid template specializations. /// @brief Determines if the given value is valid. template <> constexpr bool IsValid(const std::size_t& value) noexcept { - return value != GetInvalid(); + return value != static_cast(-1); } // Other templates. diff --git a/Library/include/playrho/Units.hpp b/Library/include/playrho/Units.hpp index e18273cdd3..75f3f11c1e 100644 --- a/Library/include/playrho/Units.hpp +++ b/Library/include/playrho/Units.hpp @@ -999,105 +999,6 @@ constexpr auto StripUnit(const boost::units::quantity source) return source.value(); } -/// @brief Gets an invalid value for the Angle type. -template <> -constexpr Angle GetInvalid() noexcept -{ - return GetInvalid() * Radian; -} - -/// @brief Gets an invalid value for the Frequency type. -template <> -constexpr Frequency GetInvalid() noexcept -{ - return GetInvalid() * Hertz; -} - -/// @brief Gets an invalid value for the AngularVelocity type. -template <> -constexpr AngularVelocity GetInvalid() noexcept -{ - return GetInvalid() * RadianPerSecond; -} - -/// @brief Gets an invalid value for the Time type. -template <> -constexpr Time GetInvalid() noexcept -{ - return GetInvalid() * Second; -} - -/// @brief Gets an invalid value for the Length type. -template <> -constexpr Length GetInvalid() noexcept -{ - return GetInvalid() * Meter; -} - -/// @brief Gets an invalid value for the Mass type. -template <> -constexpr Mass GetInvalid() noexcept -{ - return GetInvalid() * Kilogram; -} - -/// @brief Gets an invalid value for the InvMass type. -template <> -constexpr InvMass GetInvalid() noexcept -{ - return GetInvalid() / Kilogram; -} - -/// @brief Gets an invalid value for the Momentum type. -template <> -constexpr Momentum GetInvalid() noexcept -{ - return GetInvalid() * Kilogram * MeterPerSecond; -} - -/// @brief Gets an invalid value for the Force type. -template <> -constexpr Force GetInvalid() noexcept -{ - return GetInvalid() * Newton; -} - -/// @brief Gets an invalid value for the Torque type. -template <> -constexpr Torque GetInvalid() noexcept -{ - return GetInvalid() * NewtonMeter; -} - -/// @brief Gets an invalid value for the LinearVelocity type. -template <> -constexpr LinearVelocity GetInvalid() noexcept -{ - return GetInvalid() * MeterPerSecond; -} - -/// @brief Gets an invalid value for the LinearAcceleration type. -template <> -constexpr LinearAcceleration GetInvalid() noexcept -{ - return GetInvalid() * MeterPerSquareSecond; -} - -/// @brief Gets an invalid value for the AngularAcceleration type. -template <> -constexpr AngularAcceleration GetInvalid() noexcept -{ - return GetInvalid() * RadianPerSquareSecond; -} - -/// @brief Gets an invalid value for the RotInertia type. -template <> -constexpr RotInertia GetInvalid() noexcept -{ - // RotInertia is L^2 M QP^-2 - return GetInvalid() * SquareMeter * Kilogram / SquareRadian; -} - #endif // defined(PLAYRHO_USE_BOOST_UNITS) /// @brief Strips the unit from the given value. diff --git a/Library/include/playrho/Vector2.hpp b/Library/include/playrho/Vector2.hpp index ea503c80c0..56f91f02ff 100644 --- a/Library/include/playrho/Vector2.hpp +++ b/Library/include/playrho/Vector2.hpp @@ -25,6 +25,8 @@ /// @file /// @brief Definition of the @c Vector2 alias template and closely related code. +#include // for std::numeric_limits + #include #include @@ -44,6 +46,9 @@ using Vec2 = Vector2; /// @note Often used as a 2-dimensional distance or location vector. using Length2 = Vector2; +/// @brief Invalid @c Length2 constant. +constexpr auto InvalidLength2 = Length2{Invalid, Invalid}; + /// @brief 2-element vector of linear velocity (LinearVelocity) quantities. /// @note Often used as a 2-dimensional speed vector. using LinearVelocity2 = Vector2; @@ -104,13 +109,6 @@ constexpr auto GetFwdPerpendicular(const Vector2& vector) noexcept -> Vector2 return {get<1>(vector), -get<0>(vector)}; } -/// @brief Gets an invalid value for the Vec2 type. -template <> -constexpr Vec2 GetInvalid() noexcept -{ - return Vec2{GetInvalid(), GetInvalid()}; -} - /// @brief Determines whether the given vector contains finite coordinates. template constexpr bool IsValid(const Vector2& value) noexcept @@ -118,37 +116,6 @@ constexpr bool IsValid(const Vector2& value) noexcept return IsValid(get<0>(value)) && IsValid(get<1>(value)); } -#ifdef PLAYRHO_USE_BOOST_UNITS -/// @brief Gets an invalid value for the Length2 type. -template <> -constexpr Length2 GetInvalid() noexcept -{ - return Length2{GetInvalid(), GetInvalid()}; -} - -/// @brief Gets an invalid value for the LinearVelocity2 type. -template <> -constexpr LinearVelocity2 GetInvalid() noexcept -{ - return LinearVelocity2{GetInvalid(), GetInvalid()}; -} - -/// @brief Gets an invalid value for the Force2 type. -template <> -constexpr Force2 GetInvalid() noexcept -{ - return Force2{GetInvalid(), GetInvalid()}; -} - -/// @brief Gets an invalid value for the Momentum2 type. -template <> -constexpr Momentum2 GetInvalid() noexcept -{ - return Momentum2{GetInvalid(), GetInvalid()}; -} - -#endif - namespace d2 { /// @brief Earthly gravity in 2-dimensions. diff --git a/Library/include/playrho/Vector3.hpp b/Library/include/playrho/Vector3.hpp index c0fa5cee5b..419ed2f338 100644 --- a/Library/include/playrho/Vector3.hpp +++ b/Library/include/playrho/Vector3.hpp @@ -44,13 +44,6 @@ using Mass3 = Vector3; /// @brief 3-element vector of inverse mass (InvMass) quantities. using InvMass3 = Vector3; -/// @brief Gets an invalid value for the 3-element vector of real (Vec3) type. -template <> -constexpr Vec3 GetInvalid() noexcept -{ - return Vec3{GetInvalid(), GetInvalid(), GetInvalid()}; -} - /// @brief Determines whether the given vector contains finite coordinates. template <> constexpr bool IsValid(const Vec3& value) noexcept diff --git a/Library/include/playrho/d2/AABB.hpp b/Library/include/playrho/d2/AABB.hpp index 0bbedae811..f360598052 100644 --- a/Library/include/playrho/d2/AABB.hpp +++ b/Library/include/playrho/d2/AABB.hpp @@ -24,12 +24,13 @@ /// @file /// @brief Declaration of the AABB class and free functions that return instances of it. +#include #include // for LengthInterval, IsIntersecting -#include +#include // for Invalid #include // for ChildCounter, etc. -#include -#include #include +#include +#include #include @@ -54,6 +55,12 @@ using ::playrho::detail::TestOverlap; /// @brief 2-Dimensional Axis Aligned Bounding Box. using AABB = ::playrho::detail::AABB<2>; +/// @brief Invalid AABB value. +constexpr auto InvalidAABB = AABB{ + LengthInterval{Invalid}, + LengthInterval{Invalid} +}; + /// @brief Gets the perimeter length of the 2-dimensional AABB. /// @pre The sizes of each of the AABB's ranges are representable. /// @return Twice the sum of the width and height. @@ -118,14 +125,6 @@ AABB GetAABB(const playrho::detail::RayCastInput<2>& input) noexcept; } // namespace d2 -/// @brief Gets an invalid AABB value. -/// @relatedalso detail::AABB -template <> -constexpr d2::AABB GetInvalid() noexcept -{ - return d2::AABB{LengthInterval{GetInvalid()}, LengthInterval{GetInvalid()}}; -} - } // namespace playrho #endif // PLAYRHO_D2_AABB_HPP diff --git a/Library/include/playrho/d2/DistanceProxy.hpp b/Library/include/playrho/d2/DistanceProxy.hpp index 7cf3a210d6..20da87148f 100644 --- a/Library/include/playrho/d2/DistanceProxy.hpp +++ b/Library/include/playrho/d2/DistanceProxy.hpp @@ -249,7 +249,7 @@ bool TestPoint(const DistanceProxy& proxy, const Length2& point) noexcept; /// @brief Finds the index of the lowest right most vertex in the given collection. /// @return Index of the lowest right most vertex in the given collection, or -/// GetInvalid() for empty container. +/// std::size_t(-1) for empty container. std::size_t FindLowestRightMostVertex(Span vertices) noexcept; /// @brief Gets the convex hull for the given collection of vertices as a vector. diff --git a/Library/include/playrho/d2/IndexPair.hpp b/Library/include/playrho/d2/IndexPair.hpp index 2d53365a43..a7a5742637 100644 --- a/Library/include/playrho/d2/IndexPair.hpp +++ b/Library/include/playrho/d2/IndexPair.hpp @@ -22,10 +22,11 @@ #ifndef PLAYRHO_D2_INDEXPAIR_HPP #define PLAYRHO_D2_INDEXPAIR_HPP -#include #include #include +#include + namespace playrho { /// @brief Index pair. @@ -133,7 +134,7 @@ VertexCounter GetSecondShapeVertexIdx(const detail::SeparationInfo& info) noe /// for the type. struct LengthIndexPair { - Length distance = GetInvalid(); ///< Separation. + Length distance = Length(); ///< Separation. IndexPair indices = InvalidIndexPair; ///< Index pair. }; diff --git a/Library/include/playrho/d2/Manifold.hpp b/Library/include/playrho/d2/Manifold.hpp index 234fc206cb..b4c045e95e 100644 --- a/Library/include/playrho/d2/Manifold.hpp +++ b/Library/include/playrho/d2/Manifold.hpp @@ -160,7 +160,7 @@ class Manifold static Manifold GetForCircles(const Length2& vA, CfIndex iA, const Length2& vB, CfIndex iB) noexcept { return Manifold{e_circles, - GetInvalid(), + UnitVec(), vA, 1, {{Point{vB, GetVertexVertexContactFeature(iA, iB)}}}}; @@ -246,9 +246,9 @@ class Manifold na, pa, 0, - {{Point{GetInvalid(), + {{Point{InvalidLength2, ContactFeature{ContactFeature::e_face, ia, ContactFeature::e_face, 0}}, - Point{GetInvalid(), + Point{InvalidLength2, ContactFeature{ContactFeature::e_face, ia, ContactFeature::e_face, 0}}}}}; } @@ -260,9 +260,9 @@ class Manifold nb, pb, 0, - {{Point{GetInvalid(), + {{Point{InvalidLength2, ContactFeature{ContactFeature::e_face, 0, ContactFeature::e_face, ib}}, - Point{GetInvalid(), + Point{InvalidLength2, ContactFeature{ContactFeature::e_face, 0, ContactFeature::e_face, ib}}}}}; } @@ -467,12 +467,12 @@ class Manifold /// Local normal. /// @details Exact usage depends on manifold type. /// @note Invalid for the unset and circle manifold types. - UnitVec m_localNormal = GetInvalid(); + UnitVec m_localNormal; /// Local point. /// @details Exact usage depends on manifold type. /// @note Invalid for the unset manifold type. - Length2 m_localPoint = GetInvalid(); + Length2 m_localPoint = InvalidLength2; PointArray m_points; ///< Points of contact. @see pointCount. }; diff --git a/Library/include/playrho/d2/Math.hpp b/Library/include/playrho/d2/Math.hpp index 2f52398d0c..53707cb915 100644 --- a/Library/include/playrho/d2/Math.hpp +++ b/Library/include/playrho/d2/Math.hpp @@ -122,7 +122,6 @@ constexpr auto InverseRotate(const Vector2& vector, const UnitVec& angle) noe /// @param fallback Fallback unit vector value to use in case a unit vector can't effectively be /// calculated from the given value. /// @return value divided by its length if length not almost zero otherwise invalid value. -/// @see AlmostEqual. template inline UnitVec GetUnitVector(const Vector2& value, const UnitVec& fallback = UnitVec::GetDefaultFallback()) noexcept diff --git a/Library/include/playrho/d2/Simplex.hpp b/Library/include/playrho/d2/Simplex.hpp index ff5177bf7e..99d2a55785 100644 --- a/Library/include/playrho/d2/Simplex.hpp +++ b/Library/include/playrho/d2/Simplex.hpp @@ -72,7 +72,7 @@ class Simplex struct Cache { /// @brief Metric. /// @details Metric based on a length or area value of edges. - Real metric = GetInvalid(); + Real metric = Invalid; /// @brief Indices. /// @details Collection of index-pairs. @@ -145,10 +145,8 @@ inline Simplex::Simplex(const SimplexEdges& simplexEdges, : m_simplexEdges{simplexEdges}, m_normalizedWeights{normalizedWeights} { assert(simplexEdges.size() == normalizedWeights.size()); -#ifndef NDEBUG - const auto sum = std::accumulate(begin(normalizedWeights), end(normalizedWeights), Real{0}); - assert(AlmostEqual(Real{1}, sum)); -#endif + assert(AlmostEqual(Real{1}, std::accumulate(begin(normalizedWeights), + end(normalizedWeights), Real(0)), 3)); } constexpr SimplexEdges Simplex::GetEdges() const noexcept diff --git a/Library/include/playrho/d2/TargetJointConf.hpp b/Library/include/playrho/d2/TargetJointConf.hpp index f16e180c43..42c095c0b1 100644 --- a/Library/include/playrho/d2/TargetJointConf.hpp +++ b/Library/include/playrho/d2/TargetJointConf.hpp @@ -83,7 +83,7 @@ struct TargetJointConf : public JointBuilder { /// @note Typically this would be the value of: /// bodyB != InvalidBodyID /// ? GetLocalPoint(GetBody(world, bodyB), target) - /// : GetInvalid(). + /// : Length2(). constexpr auto& UseAnchor(const Length2& v) noexcept { localAnchorB = v; diff --git a/Library/include/playrho/d2/UnitVec.hpp b/Library/include/playrho/d2/UnitVec.hpp index d2ca4fbca2..8cb4e76264 100644 --- a/Library/include/playrho/d2/UnitVec.hpp +++ b/Library/include/playrho/d2/UnitVec.hpp @@ -416,9 +416,6 @@ inline ::std::ostream& operator<<(::std::ostream& os, const UnitVec& value) } // namespace d2 -/// @brief Gets an invalid value for the UnitVec type. -template <> constexpr d2::UnitVec GetInvalid() noexcept { return d2::UnitVec{}; } - /// @brief Determines if the given value is valid. template <> constexpr bool IsValid(const d2::UnitVec& value) noexcept { diff --git a/Library/include/playrho/d2/VelocityConstraint.hpp b/Library/include/playrho/d2/VelocityConstraint.hpp index 80565734a6..827d7f8624 100644 --- a/Library/include/playrho/d2/VelocityConstraint.hpp +++ b/Library/include/playrho/d2/VelocityConstraint.hpp @@ -68,10 +68,11 @@ class VelocityConstraint return Conf{}; } - /// Default constructor. - /// @details - /// Initializes object with: a zero point count, an invalid K, an invalid normal mass, - /// an invalid normal, invalid friction, invalid restitution, an invalid tangent speed. + /// @brief Default constructor. + /// @post @c GetNormal() and @c GetTangent() return a default constructed @c UnitVec . + /// @post GetPointCount(), GetFriction(), + /// GetRestitution(), GetTangentSpeed(), + /// GetK(), GetNormalMass() all return zero. VelocityConstraint() = default; /// @brief Copy constructor. @@ -87,66 +88,66 @@ class VelocityConstraint BodyID bB, const Span& bodies, const Conf& conf = GetDefaultConf()); - + /// Gets the normal of the contact in world coordinates. /// @note This value is set on construction. /// @return The contact normal (in world coordinates) if previously set, an invalid value /// otherwise. UnitVec GetNormal() const noexcept { return m_normal; } - + /// @brief Gets the tangent. UnitVec GetTangent() const noexcept { return GetFwdPerpendicular(m_normal); } - + /// Gets the count of points added to this object. /// @return Value between 0 and MaxManifoldPoints. /// @see MaxManifoldPoints. /// @see AddPoint. size_type GetPointCount() const noexcept { return m_pointCount; } - + /// Gets the "K" value. /// @note This value is only valid if previously set to a valid value. /// @return "K" value previously set or the zero initialized value. InvMass22 GetK() const noexcept; - + /// Gets the normal mass. /// @note This value is only valid if previously set. /// @return normal mass previously set or the zero initialized value. Mass22 GetNormalMass() const noexcept; - + /// Gets the combined friction of the associated contact. Real GetFriction() const noexcept { return m_friction; } - + /// Gets the combined restitution of the associated contact. Real GetRestitution() const noexcept { return m_restitution; } - + /// Gets the tangent speed of the associated contact. LinearVelocity GetTangentSpeed() const noexcept { return m_tangentSpeed; } - + /// @brief Gets identifier of body A. BodyID GetBodyA() const noexcept { return m_bodyA; } - + /// @brief Gets identifier of body B. BodyID GetBodyB() const noexcept { return m_bodyB; } - + /// Gets the normal impulse at the given point. /// @note Call the AddPoint or SetNormalImpulseAtPoint function /// to set this value. /// @return Value previously set, or an invalid value. /// @see SetNormalImpulseAtPoint. Momentum GetNormalImpulseAtPoint(size_type index) const noexcept; - + /// Gets the tangent impulse at the given point. /// @note Call the AddPoint or SetTangentImpulseAtPoint function /// to set this value. /// @return Value previously set, or an invalid value. /// @see SetTangentImpulseAtPoint. Momentum GetTangentImpulseAtPoint(size_type index) const noexcept; - + /// Gets the velocity bias at the given point. /// @note The AddPoint function sets this value. /// @return Previously set value or an invalid value. LinearVelocity GetVelocityBiasAtPoint(size_type index) const noexcept; - + /// Gets the normal mass at the given point. /// @note This value depends on the values of: /// the sum of the inverse-masses of the two bodies, @@ -155,7 +156,7 @@ class VelocityConstraint /// the normal. /// @note The AddPoint function sets this value. Mass GetNormalMassAtPoint(size_type index) const noexcept; - + /// Gets the tangent mass at the given point. /// @note This value depends on the values of: /// the sum of the inverse-masses of the two bodies, @@ -164,23 +165,23 @@ class VelocityConstraint /// the tangent. /// @note The AddPoint function sets this value. Mass GetTangentMassAtPoint(size_type index) const noexcept; - + /// Gets the point relative position of A. /// @note The AddPoint function sets this value. /// @return Previously set value or an invalid value. Length2 GetPointRelPosA(size_type index) const noexcept; - + /// Gets the point relative position of B. /// @note The AddPoint function sets this value. /// @return Previously set value or an invalid value. Length2 GetPointRelPosB(size_type index) const noexcept; - + /// @brief Sets the normal impulse at the given point. void SetNormalImpulseAtPoint(size_type index, Momentum value); - + /// @brief Sets the tangent impulse at the given point. void SetTangentImpulseAtPoint(size_type index, Momentum value); - + /// @brief Velocity constraint point. /// @note Default initialized to values that make this point ineffective if it got /// processed counter to being a valid point per the point count property. @@ -191,31 +192,31 @@ class VelocityConstraint { /// Position of body A relative to world manifold point. Length2 relA = Length2{}; - + /// Position of body B relative to world manifold point. Length2 relB = Length2{}; - + /// Normal impulse. Momentum normalImpulse = 0_Ns; - + /// Tangent impulse. Momentum tangentImpulse = 0_Ns; - + /// Normal mass. /// @note 0 or greater. /// @note Dependent on relA and relB. Mass normalMass = 0_kg; - + /// Tangent mass. /// @note 0 or greater. /// @note Dependent on relA and relB. Mass tangentMass = 0_kg; - + /// Velocity bias. /// @note A product of the contact restitution. LinearVelocity velocityBias = 0_mps; }; - + /// @brief Accesses the point identified by the given index. /// @param index Index of the point to return. This should be a value less than returned /// by GetPointCount. @@ -228,9 +229,9 @@ class VelocityConstraint assert(index < MaxManifoldPoints); return m_points[index]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) } - + private: - + /// @brief Adds the given point to this contact velocity constraint object. /// @details Adds up to MaxManifoldPoints points. To find out how many points /// have already been added, call GetPointCount. @@ -239,15 +240,15 @@ class VelocityConstraint void AddPoint(Momentum normalImpulse, Momentum tangentImpulse, const Length2& relA, const Length2& relB, const Span& bodies, const Conf& conf); - + /// Removes the last point added. void RemovePoint() noexcept; - + /// @brief Gets a point instance for the given parameters. Point GetPoint(Momentum normalImpulse, Momentum tangentImpulse, const Length2& relA, const Length2& relB, const Span& bodies, const Conf& conf) const noexcept; - + /// Accesses the point identified by the given index. /// @param index Index of the point to return. This should be a value less than returned /// by GetPointCount. @@ -260,34 +261,34 @@ class VelocityConstraint assert(index < MaxManifoldPoints); return m_points[index]; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) } - + Point m_points[MaxManifoldPoints]; ///< Velocity constraint points array. - + // K and normalMass fields are only used for the block solver. - + /// Block solver "K" info. /// @note Depends on the total inverse mass, the normal, and the point relative positions. /// @note Only used by block solver. InvMass3 m_K = InvMass3{}; - + /// Normal mass information. /// @details This is the cached inverse of the K value or the zero initialized value. /// @note Depends on the K value. /// @note Only used by block solver. Mass3 m_normalMass = Mass3{}; - + BodyID m_bodyA = InvalidBodyID; ///< Identifier for body-A. BodyID m_bodyB = InvalidBodyID; ///< Identifier for body-B. - - UnitVec m_normal = GetInvalid(); ///< Normal of the world manifold. - + + UnitVec m_normal; ///< Normal of the world manifold. + /// Friction coefficient. Usually in the range of [0,1]. - Real m_friction = GetInvalid(); - - Real m_restitution = GetInvalid(); ///< Restitution coefficient. - - LinearVelocity m_tangentSpeed = GetInvalid(); ///< Tangent speed. - + Real m_friction = Real{}; + + Real m_restitution = Real{}; ///< Restitution coefficient. + + LinearVelocity m_tangentSpeed = LinearVelocity{}; ///< Tangent speed. + size_type m_pointCount = 0; ///< Point count. }; diff --git a/Library/include/playrho/d2/WorldManifold.hpp b/Library/include/playrho/d2/WorldManifold.hpp index ea57a7b7e9..3d7e3ecf45 100644 --- a/Library/include/playrho/d2/WorldManifold.hpp +++ b/Library/include/playrho/d2/WorldManifold.hpp @@ -42,19 +42,19 @@ class World; class WorldManifold { private: - UnitVec m_normal = GetInvalid(); ///< world vector pointing from A to B + UnitVec m_normal; ///< world vector pointing from A to B /// @brief Points. /// @details Manifold's contact points in world coordinates (mid-point of intersection) - Length2 m_points[MaxManifoldPoints] = {GetInvalid(), GetInvalid()}; + Length2 m_points[MaxManifoldPoints] = {InvalidLength2, InvalidLength2}; /// @brief Impulses. Momentum2 m_impulses[MaxManifoldPoints] = {Momentum2{}, Momentum2{}}; /// @brief Separations. /// @details A negative value indicates overlap. - Length m_separations[MaxManifoldPoints] = {GetInvalid(), GetInvalid()}; - + Length m_separations[MaxManifoldPoints] = {Invalid, Invalid}; + public: /// @brief Size type. @@ -87,9 +87,9 @@ class WorldManifold /// @pre IsValid(normal) is true. constexpr explicit WorldManifold(const UnitVec& normal, const PointData& ps0) noexcept: m_normal{normal}, - m_points{ps0.location, GetInvalid()}, + m_points{ps0.location, InvalidLength2}, m_impulses{ps0.impulse, Momentum2{}}, - m_separations{ps0.separation, GetInvalid()} + m_separations{ps0.separation, Invalid} { assert(IsValid(normal)); // Intentionally empty. diff --git a/Library/include/playrho/detail/Templates.hpp b/Library/include/playrho/detail/Templates.hpp index fc9720f81e..066538c416 100644 --- a/Library/include/playrho/detail/Templates.hpp +++ b/Library/include/playrho/detail/Templates.hpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include // for std::declval diff --git a/Library/source/playrho/BlockAllocator.cpp b/Library/source/playrho/BlockAllocator.cpp index e68b299cd7..affd73d6c7 100644 --- a/Library/source/playrho/BlockAllocator.cpp +++ b/Library/source/playrho/BlockAllocator.cpp @@ -19,11 +19,12 @@ * 3. This notice may not be removed or altered from any source distribution. */ -#include -#include -#include #include #include +#include // for std::numeric_limits + +#include +#include namespace playrho { diff --git a/Library/source/playrho/Math.cpp b/Library/source/playrho/Math.cpp index fb3102677b..d98f0896b9 100644 --- a/Library/source/playrho/Math.cpp +++ b/Library/source/playrho/Math.cpp @@ -140,7 +140,7 @@ Length2 ComputeCentroid(const Span& vertices) { switch (size(vertices)) { case 0: - return GetInvalid(); + return InvalidLength2; case 1: return vertices[0]; case 2: diff --git a/Library/source/playrho/d2/DistanceProxy.cpp b/Library/source/playrho/d2/DistanceProxy.cpp index 304c12b0bf..9800a27f77 100644 --- a/Library/source/playrho/d2/DistanceProxy.cpp +++ b/Library/source/playrho/d2/DistanceProxy.cpp @@ -56,7 +56,7 @@ std::size_t FindLowestRightMostVertex(Span vertices) noexcept } return i0; } - return GetInvalid(); + return static_cast(-1); } std::vector GetConvexHullAsVector(Span vertices) @@ -65,7 +65,7 @@ std::vector GetConvexHullAsVector(Span vertices) // Create the convex hull using the Gift wrapping algorithm // http://en.wikipedia.org/wiki/Gift_wrapping_algorithm const auto index0 = FindLowestRightMostVertex(vertices); - if (index0 != GetInvalid()) + if (index0 != static_cast(-1)) { const auto numVertices = size(vertices); auto hull = std::vector(); diff --git a/Library/source/playrho/d2/DynamicTree.cpp b/Library/source/playrho/d2/DynamicTree.cpp index f30f666e92..0d2ad96fdd 100644 --- a/Library/source/playrho/d2/DynamicTree.cpp +++ b/Library/source/playrho/d2/DynamicTree.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include // for std::numeric_limits #include #include diff --git a/Library/source/playrho/d2/Manifold.cpp b/Library/source/playrho/d2/Manifold.cpp index 07292516f3..f70ecf950d 100644 --- a/Library/source/playrho/d2/Manifold.cpp +++ b/Library/source/playrho/d2/Manifold.cpp @@ -710,22 +710,5 @@ bool operator!=(const Manifold& lhs, const Manifold& rhs) noexcept return !(lhs == rhs); } -#if 0 -Length2 GetLocalPoint(const DistanceProxy& proxy, ContactFeature::Type type, - ContactFeature::Index index) -{ - switch (type) - { - case ContactFeature::e_vertex: - return proxy.GetVertex(index); - case ContactFeature::e_face: - { - return proxy.GetVertex(index); - } - } - return GetInvalid(); -} -#endif - } // namespace d2 } // namespace playrho diff --git a/Library/source/playrho/d2/PositionSolverManifold.cpp b/Library/source/playrho/d2/PositionSolverManifold.cpp index 4531e8f40b..715589e2da 100644 --- a/Library/source/playrho/d2/PositionSolverManifold.cpp +++ b/Library/source/playrho/d2/PositionSolverManifold.cpp @@ -104,7 +104,7 @@ PositionSolverManifold GetPSM(const Manifold& manifold, Manifold::size_type inde break; } assert(manifold.GetType() == Manifold::e_unset); - return PositionSolverManifold{GetInvalid(), GetInvalid(), GetInvalid()}; + return PositionSolverManifold{UnitVec(), InvalidLength2, Invalid}; } } // namespace d2 diff --git a/Library/source/playrho/d2/RayCastOutput.cpp b/Library/source/playrho/d2/RayCastOutput.cpp index 043e6eaeca..c0cd23d870 100644 --- a/Library/source/playrho/d2/RayCastOutput.cpp +++ b/Library/source/playrho/d2/RayCastOutput.cpp @@ -173,7 +173,7 @@ RayCastOutput RayCast(const DistanceProxy& proxy, const RayCastInput& input, const auto ray = transformedInput.p2 - transformedInput.p1; // Ray delta (p2 - p1) auto minT = nextafter(Real{input.maxFraction}, Real(2)); - auto normalFound = GetInvalid(); + auto normalFound = UnitVec(); for (auto i = decltype(vertexCount){0}; i < vertexCount; ++i) { diff --git a/UnitTests/AABB.cpp b/UnitTests/AABB.cpp index e9724e0d29..9aa8de272d 100644 --- a/UnitTests/AABB.cpp +++ b/UnitTests/AABB.cpp @@ -172,8 +172,8 @@ TEST(AABB, InitializingConstruction) EXPECT_EQ(GetY(GetUpperBound(foo)), upper_y); } { - const auto pa = Length2{GetInvalid(), GetInvalid()}; - const auto pb = Length2{GetInvalid(), GetInvalid()}; + const auto pa = InvalidLength2; + const auto pb = InvalidLength2; AABB foo{pa, pb}; EXPECT_TRUE(isnan(StripUnit(GetX(GetLowerBound(foo))))); EXPECT_TRUE(isnan(StripUnit(GetY(GetLowerBound(foo))))); @@ -181,8 +181,8 @@ TEST(AABB, InitializingConstruction) EXPECT_TRUE(isnan(StripUnit(GetY(GetUpperBound(foo))))); } { - const auto pa = Length2{GetInvalid(), GetInvalid()}; - const auto pb = Length2{GetInvalid(), 0_m}; + const auto pa = InvalidLength2; + const auto pb = Length2{std::numeric_limits::quiet_NaN(), 0_m}; AABB foo{pa, pb}; EXPECT_TRUE(isnan(StripUnit(GetX(GetLowerBound(foo))))); EXPECT_TRUE(isnan(StripUnit(GetY(GetLowerBound(foo))))); @@ -190,8 +190,8 @@ TEST(AABB, InitializingConstruction) EXPECT_FALSE(isnan(StripUnit(GetY(GetUpperBound(foo))))); } { - const auto pa = Length2{GetInvalid(), 0_m}; - const auto pb = Length2{GetInvalid(), GetInvalid()}; + const auto pa = Length2{std::numeric_limits::quiet_NaN(), 0_m}; + const auto pb = InvalidLength2; AABB foo{pa, pb}; EXPECT_TRUE(isnan(StripUnit(GetX(GetLowerBound(foo))))); EXPECT_FALSE(isnan(StripUnit(GetY(GetLowerBound(foo))))); @@ -199,8 +199,8 @@ TEST(AABB, InitializingConstruction) EXPECT_TRUE(isnan(StripUnit(GetY(GetUpperBound(foo))))); } { - const auto pa = Length2{GetInvalid(), 0_m}; - const auto pb = Length2{GetInvalid(), 0_m}; + const auto pa = Length2{std::numeric_limits::quiet_NaN(), 0_m}; + const auto pb = Length2{std::numeric_limits::quiet_NaN(), 0_m}; AABB foo{pa, pb}; EXPECT_TRUE(isnan(StripUnit(GetX(GetLowerBound(foo))))); EXPECT_FALSE(isnan(StripUnit(GetY(GetLowerBound(foo))))); @@ -285,9 +285,9 @@ TEST(AABB, Contains) EXPECT_TRUE((Contains(AABB{Length2{}, Length2{}}, AABB{Length2{}}))); EXPECT_TRUE((Contains(AABB{Length2{}}, AABB{Length2{}, Length2{}}))); EXPECT_TRUE((Contains(AABB{Length2{1_m, 2_m}}, AABB{}))); - EXPECT_FALSE(Contains(GetInvalid(), GetInvalid())); - EXPECT_FALSE(Contains(GetInvalid(), AABB{})); - EXPECT_FALSE(Contains(AABB{}, GetInvalid())); + EXPECT_FALSE(Contains(InvalidAABB, InvalidAABB)); + EXPECT_FALSE(Contains(InvalidAABB, AABB{})); + EXPECT_FALSE(Contains(AABB{}, InvalidAABB)); } TEST(AABB, TestOverlap) diff --git a/UnitTests/BodyID.cpp b/UnitTests/BodyID.cpp index 10dda36d45..ab34cbc446 100644 --- a/UnitTests/BodyID.cpp +++ b/UnitTests/BodyID.cpp @@ -54,7 +54,8 @@ TEST(BodyID, swap) EXPECT_EQ(b1, BodyID(0u)); } -TEST(BodyID, GetInvalid) +TEST(BodyID, IsValid) { - EXPECT_EQ(InvalidBodyID, GetInvalid()); + EXPECT_TRUE(IsValid(BodyID(0u))); + EXPECT_FALSE(IsValid(InvalidBodyID)); } diff --git a/UnitTests/DistanceProxy.cpp b/UnitTests/DistanceProxy.cpp index b495078867..0ac3adf091 100644 --- a/UnitTests/DistanceProxy.cpp +++ b/UnitTests/DistanceProxy.cpp @@ -145,8 +145,8 @@ TEST(DistanceProxy, FindLowestRightMostVertexForEmpty) { const auto vertices = std::vector(); const auto result = FindLowestRightMostVertex(vertices); - ASSERT_EQ(GetInvalid(), static_cast(-1)); - EXPECT_EQ(result, GetInvalid()); + ASSERT_FALSE(IsValid(static_cast(-1))); + EXPECT_EQ(result, static_cast(-1)); } TEST(DistanceProxy, FindLowestRightMostVertexForOne) diff --git a/UnitTests/Epsilon.cpp b/UnitTests/Epsilon.cpp index 3d312e095e..a2c8bf6ada 100644 --- a/UnitTests/Epsilon.cpp +++ b/UnitTests/Epsilon.cpp @@ -57,8 +57,10 @@ TEST(Epsilon, AlmostEqual) } { const auto a = float(1000); - const auto b = float(1000 + 0.0001); + const auto b = float(nextafter(1000.0f, 2000.0f)); + ASSERT_NE(a, b); EXPECT_FLOAT_EQ(a, b); + EXPECT_FALSE(AlmostEqual(a, b, 0)); EXPECT_TRUE(AlmostEqual(a, b, 1)); EXPECT_TRUE(AlmostEqual(a, b, 2)); EXPECT_TRUE(AlmostEqual(a, b, 3)); @@ -85,13 +87,14 @@ TEST(Epsilon, AlmostEqual) EXPECT_FALSE(AlmostEqual(std::numeric_limits::min() * 2, std::numeric_limits::min())); EXPECT_FALSE(AlmostEqual(std::numeric_limits::min(), 0.0f)); EXPECT_FALSE(AlmostEqual(std::numeric_limits::min() * float(1.001), 0.0f)); - EXPECT_TRUE(AlmostEqual(std::numeric_limits::min() * 0.5f, std::numeric_limits::min())); - EXPECT_TRUE(AlmostEqual(std::numeric_limits::min() * 0.5f, 0.0f)); - EXPECT_TRUE(AlmostZero(std::numeric_limits::min() * 0.5f)); + EXPECT_TRUE(AlmostEqual(std::numeric_limits::denorm_min() * 0.5f, + std::numeric_limits::denorm_min())); + EXPECT_TRUE(AlmostEqual(std::numeric_limits::denorm_min() * 0.5f, 0.0f)); + EXPECT_TRUE(AlmostZero(std::numeric_limits::denorm_min() * 0.5f)); // (abs(x - y) < (std::numeric_limits::epsilon() * abs(x + y) * ulp)) } - EXPECT_TRUE(AlmostEqual(50.0001373f, 50.0001564f)); + EXPECT_TRUE(AlmostEqual(50.0001373f, 50.0001564f, 5)); } TEST(Epsilon, ten_epsilon_equal) diff --git a/UnitTests/Math.cpp b/UnitTests/Math.cpp index 1953277517..c7c24601d5 100644 --- a/UnitTests/Math.cpp +++ b/UnitTests/Math.cpp @@ -273,25 +273,28 @@ TEST(Math, CrossProductOfTwoVecTwoIsAntiCommutative) EXPECT_EQ(Cross(a, b), -Cross(b, a)); } +constexpr auto InvalidVec2 = Vec2{ + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN() +}; + TEST(Math, DotProductOfInvalidIsInvalid) { - EXPECT_TRUE(isnan(Dot(GetInvalid(), GetInvalid()))); + EXPECT_TRUE(isnan(Dot(InvalidVec2, InvalidVec2))); - EXPECT_TRUE(isnan(Dot(Vec2(0, 0), GetInvalid()))); - EXPECT_TRUE(isnan(Dot(Vec2(0, 0), Vec2(GetInvalid(), 0)))); - EXPECT_TRUE(isnan(Dot(Vec2(0, 0), Vec2(0, GetInvalid())))); + EXPECT_TRUE(isnan(Dot(Vec2(0, 0), InvalidVec2))); + EXPECT_TRUE(isnan(Dot(Vec2(0, 0), Vec2(std::numeric_limits::quiet_NaN(), 0)))); + EXPECT_TRUE(isnan(Dot(Vec2(0, 0), Vec2(0, std::numeric_limits::quiet_NaN())))); - EXPECT_TRUE(isnan(Dot(GetInvalid(), Vec2(0, 0)))); - EXPECT_TRUE(isnan(Dot(Vec2(GetInvalid(), 0), Vec2(0, 0)))); - EXPECT_TRUE(isnan(Dot(Vec2(0, GetInvalid()), Vec2(0, 0)))); + EXPECT_TRUE(isnan(Dot(InvalidVec2, Vec2(0, 0)))); + EXPECT_TRUE(isnan(Dot(Vec2(std::numeric_limits::quiet_NaN(), 0), Vec2(0, 0)))); + EXPECT_TRUE(isnan(Dot(Vec2(0, std::numeric_limits::quiet_NaN()), Vec2(0, 0)))); - EXPECT_TRUE(isnan(Dot(GetInvalid(), GetInvalid()))); - //EXPECT_TRUE(isnan(Dot(Vec2(0, 0), GetInvalid()))); - EXPECT_TRUE(isnan(Dot(GetInvalid(), UnitVec::GetZero()))); + EXPECT_TRUE(isnan(Dot(InvalidVec2, UnitVec()))); + EXPECT_TRUE(isnan(Dot(InvalidVec2, UnitVec::GetZero()))); - EXPECT_TRUE(isnan(Dot(GetInvalid(), GetInvalid()))); - //EXPECT_TRUE(isnan(Dot(GetInvalid(), Vec2(0, 0)))); - EXPECT_TRUE(isnan(Dot(UnitVec::GetZero(), GetInvalid()))); + EXPECT_TRUE(isnan(Dot(UnitVec(), InvalidVec2))); + EXPECT_TRUE(isnan(Dot(UnitVec::GetZero(), InvalidVec2))); } TEST(Math, Vec2NegationAndRotationIsOrderIndependent) @@ -605,8 +608,8 @@ TEST(Math, Subtracting2UlpAlmostEqualNumbersNotAlmostZero) const auto a = 0.863826155f; const auto b = 0.863826453f; ASSERT_NE(a, b); - ASSERT_TRUE(AlmostEqual(a, b, 2)); - ASSERT_FALSE(AlmostEqual(a, b, 1)); + EXPECT_TRUE(AlmostEqual(a, b, 5)); + EXPECT_FALSE(AlmostEqual(a, b, 4)); EXPECT_FALSE(AlmostZero((a >= b)? a - b: b - a)); } diff --git a/UnitTests/TargetJoint.cpp b/UnitTests/TargetJoint.cpp index 0eac0bf6f4..8d58acab13 100644 --- a/UnitTests/TargetJoint.cpp +++ b/UnitTests/TargetJoint.cpp @@ -82,24 +82,6 @@ TEST(TargetJointConf, UseDampingRatio) EXPECT_EQ(TargetJointConf{}.UseDampingRatio(value).dampingRatio, value); } -#if 0 -TEST(TargetJoint, IsOkay) -{ - auto def = TargetJointConf{}; - - ASSERT_FALSE(Joint::IsOkay(def)); - def.bodyA = static_cast(1u); - def.bodyB = static_cast(2u); - ASSERT_TRUE(Joint::IsOkay(def)); - - EXPECT_TRUE(TargetJoint::IsOkay(def)); - def.bodyA = InvalidBodyID; - EXPECT_TRUE(TargetJoint::IsOkay(def)); - def.target = GetInvalid(); - EXPECT_FALSE(TargetJoint::IsOkay(def)); -} -#endif - TEST(TargetJoint, DefaultInitialized) { const auto def = TargetJointConf{}; diff --git a/UnitTests/UnitVec.cpp b/UnitTests/UnitVec.cpp index c4ebed9b55..f275c6c5e8 100644 --- a/UnitTests/UnitVec.cpp +++ b/UnitTests/UnitVec.cpp @@ -139,18 +139,18 @@ TEST(UnitVec, ByAngleInRadiansNearOriented) TEST(UnitVec, GetForInvalid) { { - const auto x = GetInvalid(); - const auto y = GetInvalid(); + const auto x = std::numeric_limits::signaling_NaN(); + const auto y = std::numeric_limits::quiet_NaN(); EXPECT_FALSE(IsValid(UnitVec::Get(x, y).first)); } { - const auto x = GetInvalid(); + const auto x = std::numeric_limits::quiet_NaN(); const auto y = Real(0); EXPECT_FALSE(IsValid(UnitVec::Get(x, y).first)); } { const auto x = Real(0); - const auto y = GetInvalid(); + const auto y = std::numeric_limits::quiet_NaN(); EXPECT_FALSE(IsValid(UnitVec::Get(x, y).first)); } { diff --git a/UnitTests/VelocityConstraint.cpp b/UnitTests/VelocityConstraint.cpp index d22d2472bf..efa83f1097 100644 --- a/UnitTests/VelocityConstraint.cpp +++ b/UnitTests/VelocityConstraint.cpp @@ -46,13 +46,18 @@ TEST(VelocityConstraint, DefaultInit) { const auto vc = VelocityConstraint{}; - //EXPECT_FALSE(IsValid(vc.GetK())); - //EXPECT_FALSE(IsValid(vc.GetNormalMass())); EXPECT_FALSE(IsValid(vc.GetNormal())); - //EXPECT_FALSE(IsValid(vc.GetFriction())); - //EXPECT_FALSE(IsValid(vc.GetRestitution())); - //EXPECT_FALSE(IsValid(vc.GetTangentSpeed())); - + EXPECT_EQ(vc.GetNormal(), UnitVec()); + EXPECT_FALSE(IsValid(vc.GetTangent())); + EXPECT_EQ(vc.GetTangent(), UnitVec()); + EXPECT_EQ(vc.GetFriction(), Real()); + EXPECT_EQ(vc.GetRestitution(), Real()); + EXPECT_EQ(vc.GetTangentSpeed(), LinearVelocity()); + EXPECT_EQ(vc.GetK(), InvMass22()); + EXPECT_EQ(vc.GetNormalMass(), Mass22()); + EXPECT_FALSE(IsValid(vc.GetBodyA())); + EXPECT_FALSE(IsValid(vc.GetBodyB())); + EXPECT_EQ(vc.GetPointCount(), VelocityConstraint::size_type{0}); EXPECT_TRUE(IsValid(vc.GetNormalImpulseAtPoint(0))); diff --git a/UnitTests/World.cpp b/UnitTests/World.cpp index e2e60fed98..e9def5b2a2 100644 --- a/UnitTests/World.cpp +++ b/UnitTests/World.cpp @@ -2785,18 +2785,18 @@ TEST(World_Longer, TilesComesToRest) switch (sizeof(Real)) { case 4u: #if defined(__core2__) - EXPECT_EQ(GetContactRange(*world), 1447u); - EXPECT_EQ(totalBodiesSlept, createdBodyCount + 1u); + EXPECT_EQ(GetContactRange(*world), 1451u); + EXPECT_EQ(totalBodiesSlept, 667u); EXPECT_TRUE(firstStepWithZeroMoved); if (firstStepWithZeroMoved) { EXPECT_EQ(*firstStepWithZeroMoved, 1798u); } #elif defined(_WIN64) EXPECT_EQ(GetContactRange(*world), 1448u); - EXPECT_EQ(totalBodiesSlept, 667u); + EXPECT_EQ(totalBodiesSlept, 671u); EXPECT_TRUE(firstStepWithZeroMoved); if (firstStepWithZeroMoved) { - EXPECT_EQ(*firstStepWithZeroMoved, 1812u); + EXPECT_EQ(*firstStepWithZeroMoved, 1800u); } #elif defined(_WIN32) EXPECT_EQ(GetContactRange(*world), 1448u); @@ -2822,7 +2822,7 @@ TEST(World_Longer, TilesComesToRest) #if defined(PLAYRHO_USE_BOOST_UNITS) EXPECT_GE(*firstStepWithZeroMoved, 1797u); #else - EXPECT_GE(*firstStepWithZeroMoved, 1798u); + EXPECT_GE(*firstStepWithZeroMoved, 1797u); #endif EXPECT_LE(*firstStepWithZeroMoved, 1812u); } @@ -2877,7 +2877,7 @@ TEST(World_Longer, TilesComesToRest) EXPECT_EQ(awakeCount, 0u); if (awakeCount == 0u) { -#if defined(_WIN32) || defined(PLAYRHO_USE_BOOST_UNITS) // odd +#if defined(PLAYRHO_USE_BOOST_UNITS) // odd EXPECT_EQ(lastStats.reg.proxiesMoved, 1u); #else EXPECT_EQ(lastStats.reg.proxiesMoved, 0u); @@ -2922,10 +2922,10 @@ TEST(World_Longer, TilesComesToRest) { #ifndef __FAST_MATH__ EXPECT_EQ(numSteps, 1799ul); - EXPECT_EQ(sumRegPosIters, 36515ul); - EXPECT_EQ(sumRegVelIters, 46956ul); - EXPECT_EQ(sumToiPosIters, 44131ul); - EXPECT_EQ(sumToiVelIters, 114088ul); + EXPECT_EQ(sumRegPosIters, 36512ul); + EXPECT_EQ(sumRegVelIters, 46931ul); + EXPECT_EQ(sumToiPosIters, 43985ul); + EXPECT_EQ(sumToiVelIters, 113859ul); #else EXPECT_EQ(numSteps, 1003ul); EXPECT_EQ(sumRegPosIters, 52909ul); @@ -2981,11 +2981,11 @@ TEST(World_Longer, TilesComesToRest) } } #elif defined(_WIN64) // This is likely wrong as the results are more likely arch dependent - EXPECT_EQ(numSteps, 1814ul); - EXPECT_EQ(sumRegPosIters, 36530ul); - EXPECT_EQ(sumRegVelIters, 47061ul); - EXPECT_EQ(sumToiPosIters, 43786ul); - EXPECT_EQ(sumToiVelIters, 112952ul); + EXPECT_EQ(numSteps, 1801ul); + EXPECT_EQ(sumRegPosIters, 36523ul); + EXPECT_EQ(sumRegVelIters, 46973ul); + EXPECT_EQ(sumToiPosIters, 43974ul); + EXPECT_EQ(sumToiVelIters, 113085ul); #elif defined(_WIN32) EXPECT_EQ(numSteps, 1803ul); EXPECT_EQ(sumRegPosIters, 36528ul); @@ -3005,11 +3005,11 @@ TEST(World_Longer, TilesComesToRest) EXPECT_EQ(sumToiPosIters, 44022ul); EXPECT_EQ(sumToiVelIters, 113284ul); #else - EXPECT_EQ(numSteps, 1804ul); - EXPECT_EQ(sumRegPosIters, 36527ul); - EXPECT_EQ(sumRegVelIters, 46979ul); - EXPECT_EQ(sumToiPosIters, 43806ul); - EXPECT_EQ(sumToiVelIters, 112175ul); + EXPECT_EQ(numSteps, 1798ul); + EXPECT_EQ(sumRegPosIters, 36508ul); + EXPECT_EQ(sumRegVelIters, 46931ul); + EXPECT_EQ(sumToiPosIters, 44061ul); + EXPECT_EQ(sumToiVelIters, 113150ul); #endif #else EXPECT_EQ(numSteps, 1799ul); diff --git a/UnitTests/double.cpp b/UnitTests/double.cpp index 7f4e375fb3..e0e7c3d62c 100644 --- a/UnitTests/double.cpp +++ b/UnitTests/double.cpp @@ -25,12 +25,13 @@ #include #include -TEST(double, GetInvalid) +using namespace playrho; + +TEST(double, IsValid) { - auto val = playrho::GetInvalid(); - EXPECT_TRUE(std::isnan(val)); - const auto same = std::is_same_v; - EXPECT_TRUE(same); + EXPECT_FALSE(IsValid(std::numeric_limits::signaling_NaN())); + EXPECT_FALSE(IsValid(std::numeric_limits::quiet_NaN())); + EXPECT_TRUE(IsValid(0.0)); } TEST(double, GetTypeName) diff --git a/UnitTests/float.cpp b/UnitTests/float.cpp index ef89a3ecdf..bd45dc07cf 100644 --- a/UnitTests/float.cpp +++ b/UnitTests/float.cpp @@ -29,6 +29,8 @@ #include #include +using namespace playrho; + TEST(float, BiggerValsIncreasinglyInaccurate) { // This test is meant to demonstrate the increasing inaccuracy of the float type and help @@ -361,12 +363,11 @@ TEST(float, zero) EXPECT_EQ(-3.0f * 0.0f, -0.0f); } -TEST(float, GetInvalid) +TEST(float, IsValid) { - auto val = playrho::GetInvalid(); - EXPECT_TRUE(std::isnan(val)); - const auto same = std::is_same_v; - EXPECT_TRUE(same); + EXPECT_FALSE(IsValid(std::numeric_limits::signaling_NaN())); + EXPECT_FALSE(IsValid(std::numeric_limits::quiet_NaN())); + EXPECT_TRUE(IsValid(0.0f)); } TEST(float, GetTypeName)