#include "UnitTests.hpp"
#include <PlayRho/Collision/Shapes/Shape.hpp>
#include <PlayRho/Collision/Shapes/EdgeShapeConf.hpp>
#include <PlayRho/Collision/Shapes/DiskShapeConf.hpp>
#include <PlayRho/Collision/Shapes/PolygonShapeConf.hpp>
#include <PlayRho/Collision/Distance.hpp>
#include <PlayRho/Collision/Manifold.hpp>
#include <any>
#include <chrono>
{
#if defined(_WIN32) && !defined(_WIN64)
EXPECT_EQ(
sizeof(
Shape), std::size_t(8));
#else
EXPECT_EQ(
sizeof(
Shape), std::size_t(16));
#endif
EXPECT_EQ(
sizeof(
Shape),
sizeof(std::shared_ptr<int>));
}
{
EXPECT_TRUE(std::is_default_constructible<Shape>::value);
EXPECT_TRUE(std::is_nothrow_default_constructible<Shape>::value);
EXPECT_FALSE(std::is_trivially_default_constructible<Shape>::value);
EXPECT_TRUE((std::is_constructible<Shape, X>::value));
EXPECT_FALSE((std::is_nothrow_constructible<Shape, X>::value));
EXPECT_FALSE((std::is_trivially_constructible<Shape, X>::value));
EXPECT_FALSE((std::is_constructible<Shape, X, X>::value));
EXPECT_FALSE((std::is_nothrow_constructible<Shape, X, X>::value));
EXPECT_FALSE((std::is_trivially_constructible<Shape, X, X>::value));
EXPECT_TRUE(std::is_copy_constructible<Shape>::value);
EXPECT_TRUE(std::is_nothrow_copy_constructible<Shape>::value);
EXPECT_FALSE(std::is_trivially_copy_constructible<Shape>::value);
EXPECT_TRUE(std::is_move_constructible<Shape>::value);
EXPECT_TRUE(std::is_nothrow_move_constructible<Shape>::value);
EXPECT_FALSE(std::is_trivially_move_constructible<Shape>::value);
EXPECT_TRUE(std::is_copy_assignable<Shape>::value);
EXPECT_TRUE(std::is_nothrow_copy_assignable<Shape>::value);
EXPECT_FALSE(std::is_trivially_copy_assignable<Shape>::value);
EXPECT_TRUE(std::is_move_assignable<Shape>::value);
EXPECT_TRUE(std::is_nothrow_move_assignable<Shape>::value);
EXPECT_FALSE(std::is_trivially_move_assignable<Shape>::value);
EXPECT_TRUE(std::is_destructible<Shape>::value);
EXPECT_TRUE(std::is_nothrow_destructible<Shape>::value);
EXPECT_FALSE(std::is_trivially_destructible<Shape>::value);
EXPECT_TRUE((std::is_constructible<Shape, int>::value));
}
TEST(
Shape, DefaultConstruction)
{
EXPECT_FALSE(s.has_value());
EXPECT_TRUE(s == s);
EXPECT_TRUE(s == t);
EXPECT_EQ(
GetType(s), GetTypeID<void>());
}
namespace sans_some {
namespace {
struct ShapeTest {
int number;
};
{
}
}
}
TEST(
Shape, InitializingConstructor)
{
EXPECT_TRUE((std::is_constructible<Shape, ::sans_some::ShapeTest>::value));
EXPECT_TRUE((std::is_constructible<Shape, DiskShapeConf>::value));
EXPECT_TRUE(s.has_value());
}
{
ASSERT_EQ(
GetType(s), GetTypeID<void>());
const auto friction =
Real(0.1);
const auto restitution =
Real(0.2);
const auto density = 0.4_kgpm2;
EXPECT_NE(
GetType(s), GetTypeID<void>());
EXPECT_EQ(
GetType(s), GetTypeID<DiskShapeConf>());
EXPECT_NE(
GetType(s), GetTypeID<void>());
EXPECT_EQ(
GetType(s), GetTypeID<EdgeShapeConf>());
}
{
const auto shape =
Shape{};
EXPECT_THROW(TypeCast<int>(shape), std::bad_cast);
}
TEST(
Shape, ForConstantDataTypeCastIsLikeAnyCast)
{
EXPECT_TRUE(TypeCast<const DiskShapeConf*>(&foo) == nullptr);
EXPECT_TRUE(std::any_cast<const DiskShapeConf*>(&bar) == nullptr);
EXPECT_TRUE(TypeCast<DiskShapeConf*>(&foo) == nullptr);
EXPECT_TRUE(std::any_cast<DiskShapeConf*>(&bar) == nullptr);
EXPECT_TRUE(TypeCast<const DiskShapeConf>(&foo) != nullptr);
EXPECT_TRUE(std::any_cast<const DiskShapeConf>(&bar) != nullptr);
EXPECT_TRUE(TypeCast<DiskShapeConf>(&foo) != nullptr);
EXPECT_TRUE(std::any_cast<DiskShapeConf>(&bar) != nullptr);
}
TEST(
Shape, ForMutableDataTypeCastIsLikeAnyCast)
{
EXPECT_TRUE(TypeCast<const DiskShapeConf*>(&foo) == nullptr);
EXPECT_TRUE(std::any_cast<const DiskShapeConf*>(&bar) == nullptr);
EXPECT_TRUE(TypeCast<DiskShapeConf*>(&foo) == nullptr);
EXPECT_TRUE(std::any_cast<DiskShapeConf*>(&bar) == nullptr);
EXPECT_TRUE(TypeCast<const DiskShapeConf>(&foo) != nullptr);
EXPECT_TRUE(std::any_cast<const DiskShapeConf>(&bar) != nullptr);
EXPECT_TRUE(TypeCast<DiskShapeConf>(&foo) != nullptr);
EXPECT_TRUE(std::any_cast<DiskShapeConf>(&bar) != nullptr);
}
{
EXPECT_EQ(GetTypeID<DiskShapeConf>(), GetTypeID<DiskShapeConf>());
EXPECT_EQ(
GetTypeID(sc), GetTypeID<DiskShapeConf>());
EXPECT_EQ(GetTypeID<DiskShapeConf>(),
GetTypeID(sc));
EXPECT_NE(GetTypeID<DiskShapeConf>(), GetTypeID<EdgeShapeConf>());
const auto s1 =
Shape{sc};
ASSERT_EQ(GetTypeID<Shape>(),
GetTypeID(s1));
EXPECT_EQ(
GetType(s1), GetTypeID<DiskShapeConf>());
ASSERT_NE(st1, GetTypeID<Shape>());
const auto s2 =
Shape{s1};
}
TEST(
Shape, TestOverlapSlowerThanCollideShapesForCircles)
{
const auto maxloops = 1000000u;
std::chrono::duration<double> elapsed_test_overlap;
std::chrono::duration<double> elapsed_collide_shapes;
for (auto attempt = 0u; attempt < 2u; ++attempt)
{
{
auto count = 0u;
const auto start = std::chrono::high_resolution_clock::now();
for (auto i = decltype(maxloops){0}; i < maxloops; ++i)
{
{
++count;
}
}
const auto end = std::chrono::high_resolution_clock::now();
elapsed_test_overlap = end - start;
ASSERT_EQ(count, maxloops);
}
{
auto count = 0u;
const auto start = std::chrono::high_resolution_clock::now();
for (auto i = decltype(maxloops){0}; i < maxloops; ++i)
{
if (manifold.GetPointCount() > 0)
{
++count;
}
}
const auto end = std::chrono::high_resolution_clock::now();
elapsed_collide_shapes = end - start;
ASSERT_EQ(count, maxloops);
}
EXPECT_GT(elapsed_test_overlap.count(), elapsed_collide_shapes.count());
}
}
TEST(
Shape, TestOverlapFasterThanCollideShapesForPolygons)
{
const auto maxloops = 1000000u;
std::chrono::duration<double> elapsed_test_overlap;
std::chrono::duration<double> elapsed_collide_shapes;
for (auto attempt = 0u; attempt < 2u; ++attempt)
{
{
auto count = 0u;
const auto start = std::chrono::high_resolution_clock::now();
for (auto i = decltype(maxloops){0}; i < maxloops; ++i)
{
{
++count;
}
}
const auto end = std::chrono::high_resolution_clock::now();
elapsed_test_overlap = end - start;
ASSERT_EQ(count, maxloops);
}
{
auto count = 0u;
const auto start = std::chrono::high_resolution_clock::now();
for (auto i = decltype(maxloops){0}; i < maxloops; ++i)
{
if (manifold.GetPointCount() > 0)
{
++count;
}
}
const auto end = std::chrono::high_resolution_clock::now();
elapsed_collide_shapes = end - start;
ASSERT_EQ(count, maxloops);
}
EXPECT_LT(elapsed_test_overlap.count(), elapsed_collide_shapes.count());
}
}
{
EXPECT_TRUE(shapeA == shapeB);
}
{
EXPECT_FALSE(shapeA != shapeB);
}
{
auto shape =
Shape(oldConf);
EXPECT_NO_THROW(
Transform(shape, GetIdentity<Mat22>()));
newConf = TypeCast<DiskShapeConf>(shape);
EXPECT_EQ(oldConf.GetLocation(), newConf.GetLocation());
newConf = TypeCast<DiskShapeConf>(shape);
EXPECT_EQ(
Length2(4_m, 0_m), newConf.GetLocation());
}