Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

For real concept 2017112701 #224

Merged
merged 4 commits into from
Nov 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PlayRho/Collision/Simplex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ namespace playrho {
#ifndef NDEBUG
const auto sum = std::accumulate(std::begin(normalizedWeights), std::end(normalizedWeights),
Real(0));
assert(AlmostEqual(1, sum));
assert(AlmostEqual(Real{1}, sum));
#endif
}

Expand Down
2 changes: 1 addition & 1 deletion PlayRho/Collision/TimeOfImpact.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ TOIOutput GetToiViaSat(const DistanceProxy& proxyA, const Sweep& sweepA,
//assert(minTarget > 0_m && !AlmostZero(minTarget / Meter));

const auto minTargetSquared = Square(minTarget);
if (!IsFinite(minTargetSquared) && IsFinite(minTargetSquared))
if (!IsFinite(minTargetSquared) && IsFinite(minTarget))
{
return TOIOutput{0, stats, TOIOutput::e_minTargetSquaredOverflow};
}
Expand Down
46 changes: 32 additions & 14 deletions PlayRho/Common/Fixed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,38 @@ namespace playrho
&& (value < Fixed<BT, FB>::GetInfinity());
}

/// @brief Computes the rounded value of the given value.
template <typename BT, unsigned int FB>
inline Fixed<BT, FB> RoundOff(Fixed<BT, FB> value, std::uint32_t precision = 100000)
{
const auto factor = Fixed<BT, FB>(precision);
return Round(value * factor) / factor;
}

/// @brief Gets whether a given value is almost zero.
/// @details An almost zero value is "subnormal". Dividing by these values can lead to
/// odd results like a divide by zero trap occurring.
/// @return <code>true</code> if the given value is almost zero, <code>false</code> otherwise.
template <typename BT, unsigned int FB>
constexpr inline bool AlmostZero(Fixed<BT, FB> value)
{
return value == 0;
}

/// @brief Determines whether the given two values are "almost equal".
template <typename BT, unsigned int FB>
constexpr inline bool AlmostEqual(Fixed<BT, FB> x, Fixed<BT, FB> y, int ulp = 2)
{
return Abs(x - y) <= Fixed<BT, FB>{0, static_cast<std::uint32_t>(ulp)};
}

/// @brief Gets an invalid value.
template <typename BT, unsigned int FB>
constexpr Fixed<BT, FB> GetInvalid() noexcept
{
return Fixed<BT, FB>::GetNaN();
}

/// @brief Output stream operator.
template <typename BT, unsigned int FB>
inline ::std::ostream& operator<<(::std::ostream& os, const Fixed<BT, FB>& value)
Expand Down Expand Up @@ -828,13 +860,6 @@ namespace playrho
const auto result = lhs.Compare(rhs);
return result == Fixed32::CmpResult::GreaterThan;
}

/// @brief Gets an invalid value.
template <>
constexpr Fixed32 GetInvalid() noexcept
{
return Fixed32::GetNaN();
}

/// @brief Gets the specialized name for the Fixed32 type.
/// @details Provides an interface to a specialized function for getting C-style
Expand Down Expand Up @@ -926,13 +951,6 @@ namespace playrho
template<> struct Wider<Fixed32> {
using type = Fixed64; ///< Wider type.
};

/// @brief Gets an invalid value.
template <>
constexpr Fixed64 GetInvalid() noexcept
{
return Fixed64::GetNaN();
}

/// @brief Gets the specialized name for the Fixed64 type.
/// @details Provides an interface to a specialized function for getting C-style
Expand Down
125 changes: 11 additions & 114 deletions PlayRho/Common/Math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ inline typename std::enable_if<std::is_arithmetic<T>::value, bool>::type IsFinit

/// @brief Rounds the given value.
template <typename T>
inline T Round(T arg)
inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type Round(T arg)
{
return std::round(arg);
}
Expand Down Expand Up @@ -236,15 +236,6 @@ inline auto Atan2(T y, T x)
return Angle{static_cast<Real>(std::atan2(StripUnit(y), StripUnit(x))) * Radian};
}

/// @brief Computes the arc-tangent of the given y and x values.
/// @return Normalized angle - an angle between -Pi and Pi inclusively.
/// @sa http://en.cppreference.com/w/cpp/numeric/math/atan2
template<>
inline auto Atan2(double y, double x)
{
return Angle{static_cast<Real>(std::atan2(y, x)) * Radian};
}

/// @brief Computes the average of the given values.
template <typename T>
inline auto Average(Span<const T> span)
Expand All @@ -264,54 +255,15 @@ inline auto Average(Span<const T> span)

/// @brief Computes the rounded value of the given value.
template <typename T>
inline T RoundOff(T value, unsigned precision = 100000);

/// @brief Computes the rounded value of the given value.
template <>
inline float RoundOff(float value, std::uint32_t precision)
{
const auto factor = float(static_cast<std::int64_t>(precision));
return std::round(value * factor) / factor;
}

/// @brief Computes the rounded value of the given value.
template <>
inline double RoundOff(double value, std::uint32_t precision)
inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type
RoundOff(T value, unsigned precision = 100000)
{
const auto factor = double(static_cast<std::int64_t>(precision));
const auto factor = static_cast<T>(precision);
return std::round(value * factor) / factor;
}

/// @brief Computes the rounded value of the given value.
template <>
inline long double RoundOff(long double value, std::uint32_t precision)
{
using ldouble = long double;
const auto factor = ldouble(static_cast<std::int64_t>(precision));
return std::round(value * factor) / factor;
}

/// @brief Computes the rounded value of the given value.
template <>
inline Fixed32 RoundOff(Fixed32 value, std::uint32_t precision)
{
const auto factor = Fixed32(precision);
return Round(value * factor) / factor;
}

#ifndef _WIN32
/// @brief Computes the rounded value of the given value.
template <>
inline Fixed64 RoundOff(Fixed64 value, std::uint32_t precision)
{
const auto factor = Fixed64(precision);
return Round(value * factor) / factor;
}
#endif

/// @brief Computes the rounded value of the given value.
template <>
inline Vec2 RoundOff(Vec2 value, std::uint32_t precision)
inline Vec2 RoundOff(Vec2 value, std::uint32_t precision = 100000)
{
return Vec2{RoundOff(value[0], precision), RoundOff(value[1], precision)};
}
Expand All @@ -333,81 +285,26 @@ AlmostZero(T value)
return Abs(value) < std::numeric_limits<T>::min();
}

/// @brief Gets whether a given value is almost zero.
/// @details An almost zero value is "subnormal". Dividing by these values can lead to
/// odd results like a divide by zero trap occurring.
/// @return <code>true</code> if the given value is almost zero, <code>false</code> otherwise.
constexpr inline bool AlmostZero(Fixed32 value)
{
return value == 0;
}

#ifndef _WIN32
/// @brief Gets whether a given value is almost zero.
/// @details An almost zero value is "subnormal". Dividing by these values can lead to
/// odd results like a divide by zero trap occurring.
/// @return <code>true</code> if the given value is almost zero, <code>false</code> otherwise.
constexpr inline bool AlmostZero(Fixed64 value)
{
return value == 0;
}
#endif

/// @brief Determines whether the given two values are "almost equal".
constexpr inline bool AlmostEqual(float x, float y, int ulp = 2)
{
// 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<float>::epsilon() * Abs(x + y) * ulp)) || AlmostZero(x - y);
}

/// @brief Determines whether the given two values are "almost equal".
constexpr inline bool AlmostEqual(double x, double y, int ulp = 2)
{
// 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<double>::epsilon() * Abs(x + y) * ulp)) || AlmostZero(x - y);
}

/// @brief Determines whether the given two values are "almost equal".
constexpr inline bool AlmostEqual(long double x, long double y, int ulp = 2)
template <typename T>
constexpr inline typename std::enable_if<std::is_floating_point<T>::value, bool>::type
AlmostEqual(T x, T y, int ulp = 2)
{
// 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<long double>::epsilon() * Abs(x + y) * ulp)) || AlmostZero(x - y);
return (Abs(x - y) < (std::numeric_limits<T>::epsilon() * Abs(x + y) * ulp)) || AlmostZero(x - y);
}

/// @brief Determines whether the given two values are "almost equal".
constexpr inline bool AlmostEqual(Fixed32 x, Fixed32 y, int ulp = 2)
{
return Abs(x - y) <= Fixed32{0, static_cast<std::uint32_t>(ulp)};
}

#ifndef _WIN32
/// @brief Determines whether the given two values are "almost equal".
constexpr inline bool AlmostEqual(Fixed64 x, Fixed64 y, int ulp = 2)
{
return Abs(x - y) <= Fixed64{0, static_cast<std::uint32_t>(ulp)};
}
#endif

/// @brief Modulo operation using std::fmod.
/// @note Modulo via std::fmod appears slower than via std::trunc.
/// @sa ModuloViaTrunc
template <typename T>
inline auto ModuloViaFmod(T dividend, T divisor) noexcept
inline typename std::enable_if<std::is_floating_point<T>::value, T>::type
ModuloViaFmod(T dividend, T divisor) noexcept
{
// Note: modulo via std::fmod appears slower than via std::trunc.
return static_cast<T>(std::fmod(dividend, divisor));
Expand Down
6 changes: 2 additions & 4 deletions PlayRho/Dynamics/StepConf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,9 @@ class StepConf

/// @brief Target depth.
/// @details Target depth of overlap for calculating the TOI for CCD elligible bodies.
/// @note Must be greater than 0.
/// @note Must not be subnormal.
/// @note Must be less than twice the world's minimum vertex radius.
/// @note Recommend value that's less than twice the world's minimum vertex radius.
/// @note Used in the TOI phase of step processing.
Positive<Length> targetDepth = DefaultLinearSlop * Real{3};
Length targetDepth = DefaultLinearSlop * Real{3};

/// @brief Tolerance.
/// @details The acceptable plus or minus tolerance from the target depth for TOI calculations.
Expand Down
3 changes: 3 additions & 0 deletions PlayRho/Dynamics/World.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,9 @@ World::UpdateContactsData World::UpdateContactTOIs(const StepConf& conf)
// Compute the TOI for this contact (one or both bodies are active and impenetrable).
// Computes the time of impact in interval [0, 1]
const auto output = CalcToi(c, toiConf);
assert((output.state == TOIOutput::State::e_touching)
|| (output.state == TOIOutput::State::e_separated)
|| (output.state == TOIOutput::State::e_overlapped));

// Use Min function to handle floating point imprecision which possibly otherwise
// could provide a TOI that's greater than 1.
Expand Down
10 changes: 8 additions & 2 deletions Testbed/Tests/SolarSystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ class SolarSystem: public Test
os << " km (" << minName << "), to ";
os << static_cast<float>(Real{maxRadius / 1_km});
os << " km (" << maxName << ").";
if (std::is_same<Real, float>::value)
{
os << "\n\n";
os << "Note: recompile with playrho::Real set to use double (or bigger)";
os << " for collisions to work better at these scales.";
}

auto conf = Test::Conf{};
conf.description = os.str();
Expand All @@ -93,7 +99,7 @@ class SolarSystem: public Test
conf.neededSettings |= (1u << NeedDrawLabelsField);
conf.neededSettings |= (1u << NeedMaxTranslation);
conf.neededSettings |= (1u << NeedDeltaTime);
conf.settings.linearSlop = 1000.0f; // minRadius / 1000_m;
conf.settings.linearSlop = 200 * 1000.0f; // 200_km;
conf.settings.cameraZoom = 2.2e11f;
conf.settings.drawLabels = true;
conf.settings.maxTranslation = std::numeric_limits<float>::infinity();
Expand All @@ -106,7 +112,7 @@ class SolarSystem: public Test
SolarSystem(): Test(GetTestConf())
{
m_world.SetGravity(LinearAcceleration2{});
const auto DynamicBD = BodyDef{}.UseType(BodyType::Dynamic);
const auto DynamicBD = BodyDef{}.UseType(BodyType::Dynamic).UseBullet(true);
for (auto& sso: SolarSystemBodies)
{
const auto p = sso.orbitalPeriod;
Expand Down
30 changes: 15 additions & 15 deletions UnitTests/CollideShapes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,20 +847,20 @@ TEST(CollideShapes, HorizontalOverlappingRects2)
EXPECT_EQ(manifold.GetPointCount(), Manifold::size_type(2));

ASSERT_GT(manifold.GetPointCount(), Manifold::size_type(0));
EXPECT_TRUE(AlmostEqual(GetX(manifold.GetPoint(0).localPoint) / Meter, Real(-2.0))); // left
EXPECT_TRUE(AlmostEqual(GetY(manifold.GetPoint(0).localPoint) / Meter, Real(-1.5))); // top
EXPECT_TRUE(AlmostEqual(manifold.GetPoint(0).normalImpulse / (1_Ns), Real(0)));
EXPECT_TRUE(AlmostEqual(manifold.GetPoint(0).tangentImpulse / (1_Ns), Real(0)));
EXPECT_TRUE(AlmostEqual(Real{GetX(manifold.GetPoint(0).localPoint) / Meter}, Real(-2.0))); // left
EXPECT_TRUE(AlmostEqual(Real{GetY(manifold.GetPoint(0).localPoint) / Meter}, Real(-1.5))); // top
EXPECT_TRUE(AlmostEqual(Real{manifold.GetPoint(0).normalImpulse / 1_Ns}, Real(0)));
EXPECT_TRUE(AlmostEqual(Real{manifold.GetPoint(0).tangentImpulse / 1_Ns}, Real(0)));
EXPECT_EQ(manifold.GetPoint(0).contactFeature.typeA, ContactFeature::e_vertex);
EXPECT_EQ(manifold.GetPoint(0).contactFeature.indexA, 0);
EXPECT_EQ(manifold.GetPoint(0).contactFeature.typeB, ContactFeature::e_face);
EXPECT_EQ(manifold.GetPoint(0).contactFeature.indexB, 2);

ASSERT_GT(manifold.GetPointCount(), Manifold::size_type(1));
EXPECT_TRUE(AlmostEqual(GetX(manifold.GetPoint(1).localPoint) / Meter, Real(-2.0))); // left
EXPECT_TRUE(AlmostEqual(GetY(manifold.GetPoint(1).localPoint) / Meter, Real(+1.5))); // bottom
EXPECT_TRUE(AlmostEqual(manifold.GetPoint(1).normalImpulse / (1_Ns), Real(0)));
EXPECT_TRUE(AlmostEqual(manifold.GetPoint(1).tangentImpulse / (1_Ns), Real(0)));
EXPECT_TRUE(AlmostEqual(Real{GetX(manifold.GetPoint(1).localPoint) / Meter}, Real(-2.0))); // left
EXPECT_TRUE(AlmostEqual(Real{GetY(manifold.GetPoint(1).localPoint) / Meter}, Real(+1.5))); // bottom
EXPECT_TRUE(AlmostEqual(Real{manifold.GetPoint(1).normalImpulse / 1_Ns}, Real(0)));
EXPECT_TRUE(AlmostEqual(Real{manifold.GetPoint(1).tangentImpulse / 1_Ns}, Real(0)));
EXPECT_EQ(manifold.GetPoint(1).contactFeature.typeA, ContactFeature::e_vertex);
EXPECT_EQ(manifold.GetPoint(1).contactFeature.indexA, 1);
EXPECT_EQ(manifold.GetPoint(1).contactFeature.typeB, ContactFeature::e_face);
Expand All @@ -875,12 +875,12 @@ TEST(CollideShapes, HorizontalOverlappingRects2)
EXPECT_TRUE(AlmostEqual(world_manifold.GetNormal().GetY(), Real(0)));

ASSERT_GT(world_manifold.GetPointCount(), Manifold::size_type(0));
EXPECT_TRUE(AlmostEqual(GetX(world_manifold.GetPoint(0)) / Meter, Real(+0.5)));
EXPECT_TRUE(AlmostEqual(GetY(world_manifold.GetPoint(0)) / Meter, Real(-1.5)));
EXPECT_TRUE(AlmostEqual(Real{GetX(world_manifold.GetPoint(0)) / Meter}, Real(+0.5)));
EXPECT_TRUE(AlmostEqual(Real{GetY(world_manifold.GetPoint(0)) / Meter}, Real(-1.5)));

ASSERT_GT(world_manifold.GetPointCount(), Manifold::size_type(1));
EXPECT_TRUE(AlmostEqual(GetX(world_manifold.GetPoint(1)) / Meter, Real(+0.5)));
EXPECT_TRUE(AlmostEqual(GetY(world_manifold.GetPoint(1)) / Meter, Real(+1.5)));
EXPECT_TRUE(AlmostEqual(Real{GetX(world_manifold.GetPoint(1)) / Meter}, Real(+0.5)));
EXPECT_TRUE(AlmostEqual(Real{GetY(world_manifold.GetPoint(1)) / Meter}, Real(+1.5)));
}

TEST(CollideShapes, EdgeBelowPolygon)
Expand Down Expand Up @@ -1398,14 +1398,14 @@ TEST(CollideShapes, EdgePolygonFaceB2)

EXPECT_EQ(manifold.GetType(), Manifold::e_faceB);
EXPECT_NEAR(double(StripUnit(GetX(manifold.GetLocalPoint()))), 0.0, 0.0001);
EXPECT_TRUE(AlmostEqual(GetY(manifold.GetLocalPoint()) / Meter, Real{0.5f}));
EXPECT_TRUE(AlmostEqual(Real{GetY(manifold.GetLocalPoint()) / Meter}, Real{0.5f}));
EXPECT_TRUE(AlmostEqual(GetX(GetVec2(manifold.GetLocalNormal())), Real{0.0f}));
EXPECT_TRUE(AlmostEqual(GetY(GetVec2(manifold.GetLocalNormal())), Real{1.0f}));
EXPECT_EQ(manifold.GetPointCount(), Manifold::size_type(1));
ASSERT_GT(manifold.GetPointCount(), Manifold::size_type(0));
EXPECT_EQ(manifold.GetContactFeature(0), GetVertexFaceContactFeature(1, 1));
EXPECT_TRUE(AlmostEqual(GetX(manifold.GetOpposingPoint(0)) / Meter, Real{-6.0f}));
EXPECT_TRUE(AlmostEqual(GetY(manifold.GetOpposingPoint(0)) / Meter, Real{0.0f}));
EXPECT_TRUE(AlmostEqual(Real{GetX(manifold.GetOpposingPoint(0)) / Meter}, Real{-6.0f}));
EXPECT_TRUE(AlmostEqual(Real{GetY(manifold.GetOpposingPoint(0)) / Meter}, Real{0.0f}));
}

#if 0
Expand Down
Loading