#include "UnitTests.hpp"
#include <any>
#include <chrono>
#include <string>
#include <playrho/d2/Distance.hpp>
#include <playrho/d2/part/Compositor.hpp>
TEST(Shape, Traits)
{
EXPECT_TRUE(std::is_default_constructible_v<Shape>);
EXPECT_TRUE(std::is_nothrow_default_constructible_v<Shape>);
EXPECT_FALSE(std::is_trivially_default_constructible_v<Shape>);
using X = DiskShapeConf;
EXPECT_TRUE((std::is_constructible_v<Shape, X>));
EXPECT_FALSE((std::is_nothrow_constructible_v<Shape, X>));
EXPECT_FALSE((std::is_trivially_constructible_v<Shape, X>));
EXPECT_FALSE((std::is_constructible_v<Shape, X, X>));
EXPECT_FALSE((std::is_nothrow_constructible_v<Shape, X, X>));
EXPECT_FALSE((std::is_trivially_constructible_v<Shape, X, X>));
EXPECT_TRUE(std::is_copy_constructible_v<Shape>);
EXPECT_FALSE(std::is_nothrow_copy_constructible_v<Shape>);
EXPECT_FALSE(std::is_trivially_copy_constructible_v<Shape>);
EXPECT_TRUE(std::is_move_constructible_v<Shape>);
EXPECT_TRUE(std::is_nothrow_move_constructible_v<Shape>);
EXPECT_FALSE(std::is_trivially_move_constructible_v<Shape>);
EXPECT_TRUE(std::is_copy_assignable_v<Shape>);
EXPECT_FALSE(std::is_nothrow_copy_assignable_v<Shape>);
EXPECT_FALSE(std::is_trivially_copy_assignable_v<Shape>);
EXPECT_TRUE(std::is_move_assignable_v<Shape>);
EXPECT_TRUE(std::is_nothrow_move_assignable_v<Shape>);
EXPECT_FALSE(std::is_trivially_move_assignable_v<Shape>);
EXPECT_TRUE(std::is_destructible_v<Shape>);
EXPECT_TRUE(std::is_nothrow_destructible_v<Shape>);
EXPECT_FALSE(std::is_trivially_destructible_v<Shape>);
EXPECT_TRUE((std::is_constructible_v<Shape, int>));
}
TEST(Shape, DefaultConstruction)
{
const auto s = Shape{};
EXPECT_FALSE(s.has_value());
EXPECT_THROW(
GetChild(s, 0), InvalidArgument);
EXPECT_TRUE(s == s);
auto t = Shape{};
EXPECT_TRUE(s == t);
EXPECT_EQ(
GetType(s), GetTypeID<void>());
}
namespace {
struct TestConf {
static int defaultConstructorCalled;
static int copyConstructorCalled;
static int moveConstructorCalled;
static int copyAssignmentCalled;
static int moveAssignmentCalled;
static void resetClass()
{
defaultConstructorCalled = 0;
copyConstructorCalled = 0;
moveConstructorCalled = 0;
copyAssignmentCalled = 0;
moveAssignmentCalled = 0;
}
std::string data;
TestConf()
{
++defaultConstructorCalled;
}
TestConf(const TestConf& other): data{other.data}
{
++copyConstructorCalled;
}
TestConf(TestConf&& other): data{
std::move(other.data)}
{
++moveConstructorCalled;
}
TestConf& operator=(const TestConf& other)
{
data = other.data;
++copyAssignmentCalled;
return *this;
}
TestConf& operator=(TestConf&& other)
{
data = std::move(other.data);
++moveAssignmentCalled;
return *this;
}
};
int TestConf::defaultConstructorCalled;
int TestConf::copyConstructorCalled;
int TestConf::moveConstructorCalled;
int TestConf::copyAssignmentCalled;
int TestConf::moveAssignmentCalled;
bool operator==(
const TestConf& lhs,
const TestConf& rhs) noexcept
{
return lhs.data == rhs.data;
}
{
return 0;
}
{
throw InvalidArgument("not supported");
}
{
return {};
}
{
throw InvalidArgument("not supported");
}
NonNegative<AreaDensity>
GetDensity(
const TestConf&) noexcept
{
return {};
}
{
return {};
}
{
return {};
}
{
}
{
return {};
}
{
return {};
}
static_assert(playrho::d2::detail::IsValidShapeTypeV<TestConf>, "MovableConf must be a valid shape type");
}
TEST(Shape, ConstructionFromMovable)
{
TestConf::resetClass();
ASSERT_FALSE(TestConf::copyConstructorCalled);
ASSERT_FALSE(TestConf::moveConstructorCalled);
TestConf conf;
conf.data = "have some";
Shape s{std::move(conf)};
EXPECT_EQ(std::string(), conf.data);
EXPECT_EQ(0, TestConf::copyConstructorCalled);
EXPECT_EQ(1, TestConf::moveConstructorCalled);
EXPECT_EQ(0, TestConf::copyAssignmentCalled);
EXPECT_EQ(0, TestConf::moveAssignmentCalled);
}
TEST(Shape, AssignmentFromMovable)
{
TestConf::resetClass();
ASSERT_FALSE(TestConf::copyConstructorCalled);
ASSERT_FALSE(TestConf::moveConstructorCalled);
TestConf conf;
conf.data = "have some";
Shape s;
s = std::move(conf);
EXPECT_EQ(std::string(), conf.data);
EXPECT_EQ(0, TestConf::copyConstructorCalled);
EXPECT_EQ(1, TestConf::moveConstructorCalled);
EXPECT_EQ(0, TestConf::copyAssignmentCalled);
EXPECT_EQ(0, TestConf::moveAssignmentCalled);
}
TEST(Shape, ConstructionFromCopyable)
{
TestConf::resetClass();
ASSERT_FALSE(TestConf::copyConstructorCalled);
ASSERT_FALSE(TestConf::moveConstructorCalled);
TestConf conf;
conf.data = "have some";
Shape s{conf};
EXPECT_EQ(std::string("have some"), conf.data);
EXPECT_EQ(1, TestConf::copyConstructorCalled);
EXPECT_EQ(0, TestConf::moveConstructorCalled);
EXPECT_EQ(0, TestConf::copyAssignmentCalled);
EXPECT_EQ(0, TestConf::moveAssignmentCalled);
}
TEST(Shape, AssignmentFromCopyable)
{
TestConf::resetClass();
ASSERT_FALSE(TestConf::copyConstructorCalled);
ASSERT_FALSE(TestConf::moveConstructorCalled);
TestConf conf;
conf.data = "have some";
Shape s;
s = conf;
EXPECT_EQ(std::string("have some"), conf.data);
EXPECT_EQ(1, TestConf::copyConstructorCalled);
EXPECT_EQ(0, TestConf::moveConstructorCalled);
EXPECT_EQ(0, TestConf::copyAssignmentCalled);
EXPECT_EQ(0, TestConf::moveAssignmentCalled);
}
TEST(Shape, SetNoops)
{
TestConf::resetClass();
TestConf conf;
}
namespace sans_some {
namespace {
struct ShapeTest {
int number;
};
{
return 1u;
}
}
}
TEST(Shape, InitializingConstructor)
{
EXPECT_TRUE((std::is_constructible_v<Shape, ::sans_some::ShapeTest>));
EXPECT_FALSE(playrho::d2::detail::IsValidShapeTypeV<::sans_some::ShapeTest>);
EXPECT_TRUE((std::is_constructible_v<Shape, DiskShapeConf>));
EXPECT_TRUE(playrho::d2::detail::IsValidShapeTypeV<DiskShapeConf>);
auto conf = DiskShapeConf{};
auto s = Shape{conf};
EXPECT_TRUE(s.has_value());
conf.UseIsSensor(true);
s = Shape{conf};
}
TEST(Shape, Assignment)
{
auto s = Shape{};
ASSERT_EQ(
GetType(s), GetTypeID<void>());
const auto friction =
Real(0.1);
const auto restitution =
Real(0.2);
const auto density = 0.4_kgpm2;
s = DiskShapeConf{1_m}.UseFriction(friction).UseRestitution(restitution).UseDensity(density);
EXPECT_NE(
GetType(s), GetTypeID<void>());
EXPECT_EQ(
GetType(s), GetTypeID<DiskShapeConf>());
s = EdgeShapeConf();
EXPECT_NE(
GetType(s), GetTypeID<void>());
EXPECT_EQ(
GetType(s), GetTypeID<EdgeShapeConf>());
const auto otherShape = Shape{};
ASSERT_EQ(
GetType(otherShape), GetTypeID<void>());
s = otherShape;
EXPECT_EQ(
GetType(s), GetTypeID<void>());
EXPECT_TRUE(s == otherShape);
}
{
const auto shape = Shape{};
EXPECT_THROW(TypeCast<int>(shape), std::bad_cast);
}
{
auto foo = Shape{DiskShapeConf{1_m}};
const auto radius = NonNegative<Length>(0.42_m);
}
TEST(Shape, ForConstantDataTypeCastIsLikeAnyCast)
{
const auto foo = Shape{DiskShapeConf{1_m}};
const auto bar = std::any{DiskShapeConf{1_m}};
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)
{
auto foo = Shape{DiskShapeConf{1_m}};
auto bar = std::any{DiskShapeConf{1_m}};
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, types)
{
EXPECT_EQ(GetTypeID<DiskShapeConf>(), GetTypeID<DiskShapeConf>());
const auto sc = DiskShapeConf{1_m};
EXPECT_EQ(
GetTypeID(sc), GetTypeID<DiskShapeConf>());
EXPECT_EQ(GetTypeID<DiskShapeConf>(),
GetTypeID(sc));
EXPECT_NE(GetTypeID<DiskShapeConf>(), GetTypeID<EdgeShapeConf>());
EXPECT_EQ(
GetTypeID(Compositor<GeometryIs<StaticRectangle<1, 1>>>{}),
GetTypeID(Compositor<GeometryIs<StaticRectangle<1, 1>>>{}));
const auto s1 = Shape{sc};
ASSERT_EQ(GetTypeID<Shape>(),
GetTypeID(s1));
EXPECT_EQ(
GetType(s1), GetTypeID<DiskShapeConf>());
ASSERT_NE(st1, GetTypeID<Shape>());
EXPECT_EQ(Shape(Compositor<GeometryIs<StaticRectangle<1, 1>>>{}),
Shape(Compositor<GeometryIs<StaticRectangle<1, 1>>>{}));
const auto s2 = Shape{s1};
}
TEST(Shape, TestOverlapSlowerThanCollideShapesForCircles)
{
const auto shape = DiskShapeConf{2_m};
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 shape = PolygonShapeConf{2_m, 2_m};
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());
}
}
TEST(Shape, Equality)
{
EXPECT_TRUE(Shape(EdgeShapeConf()) == Shape(EdgeShapeConf()));
const auto shapeA = Shape(DiskShapeConf{}.UseRadius(100_m));
const auto shapeB = Shape(DiskShapeConf{}.UseRadius(100_m));
EXPECT_TRUE(shapeA == shapeB);
EXPECT_FALSE(Shape(DiskShapeConf()) == Shape(EdgeShapeConf()));
EXPECT_FALSE(Shape(EdgeShapeConf()) == Shape(EdgeShapeConf().UseIsSensor(true)));
const auto filter = Filter{0x2u, 0x8, 0x1};
EXPECT_FALSE(Shape(EdgeShapeConf()) == Shape(EdgeShapeConf().UseFilter(filter)));
}
TEST(Shape, Inequality)
{
EXPECT_FALSE(Shape(EdgeShapeConf()) != Shape(EdgeShapeConf()));
const auto shapeA = Shape(DiskShapeConf{}.UseRadius(100_m));
const auto shapeB = Shape(DiskShapeConf{}.UseRadius(100_m));
EXPECT_FALSE(shapeA != shapeB);
EXPECT_TRUE(Shape(DiskShapeConf()) != Shape(EdgeShapeConf()));
const auto filter = Filter{0x2u, 0x8, 0x1};
EXPECT_TRUE(Shape(EdgeShapeConf()) != Shape(EdgeShapeConf().UseFilter(filter)));
}
TEST(Shape, EmptyShapeTranslateIsNoop)
{
auto s = Shape{};
}
TEST(Shape, EmptyShapeScaleIsNoop)
{
auto s = Shape{};
}
TEST(Shape, EmptyShapeRotateIsNoop)
{
auto s = Shape{};
}
TEST(Shape, EmptyShapeSetVertexRadiusIsNoop)
{
auto s = Shape{};
}
TEST(Shape, DynamicRectangleSmallerThanPolygon)
{
{
#if defined(_WIN64) || !defined(_WIN32)
case 4u:
EXPECT_LT(sizeof(Compositor<GeometryIs<DynamicRectangle<>>,
DensityIs<DynamicAreaDensity<>>,
RestitutionIs<DynamicRestitution<>>,
FrictionIs<DynamicFriction<>>,
SensorIs<DynamicSensor<>>,
FilterIs<DynamicFilter<>>>),
sizeof(PolygonShapeConf));
break;
#endif
default:
break;
}
}
#if 0
#include <cstddef>
#include <variant>
class Foo {
struct Concept {
virtual ~Concept() = default;
virtual std::unique_ptr<Concept> Clone_() const = 0;
virtual void NewTo_(void* buffer) const = 0;
virtual Real GetFriction_() const noexcept = 0;
};
template <typename T>
struct Model final : Concept {
using data_type = T;
Model(T arg) : data{
std::move(arg)} {}
std::unique_ptr<Concept> Clone_() const override
{
return std::make_unique<Model>(data);
}
void NewTo_(void* buffer) const override
{
::new (buffer) Model(data);
}
Real GetFriction_() const noexcept
override
{
}
data_type data;
};
const Concept* GetConcept() const
{
switch (m_type) {
case union_type::pointer:
return m_pointer.get();
case union_type::buffer:
return reinterpret_cast<const Concept*>(::std::addressof(m_buffer));
case union_type::none:
break;
}
return nullptr;
}
public:
#if 1
union {
std::unique_ptr<const Concept> m_pointer;
alignas(std::max_align_t) std::byte m_buffer[alignof(std::max_align_t) * 3u];
};
enum class union_type {none, pointer, buffer};
union_type m_type = union_type::none;
#else
using pointer = std::unique_ptr<const Concept>;
using buffer = std::byte[62u];
std::variant<pointer, buffer> m_data;
#endif
Foo() noexcept {}
~Foo() noexcept
{
#if 0
if (std::holds_alternative<buffer>(m_data)) {
reinterpret_cast<const Concept*>(&std::get<buffer>(m_data))->~Concept();
}
#endif
switch (m_type) {
case union_type::pointer:
m_pointer.~unique_ptr<const Concept>();
break;
case union_type::buffer:
reinterpret_cast<const Concept*>(m_buffer)->~Concept();
break;
case union_type::none:
break;
}
}
template <class T>
Foo(T&& arg)
{
#if 0
static_assert(alignof(Model<T>) <= alignof(decltype(m_buffer)), "bad alignment");
if (sizeof(Model<T>) > sizeof(m_buffer)) {
new (&m_pointer) std::unique_ptr<const Concept>{std::make_unique<Model<T>>(std::forward<T>(arg))};
m_type = union_type::pointer;
}
else {
new (&m_buffer) Model<T>(std::move(arg));
m_type = union_type::buffer;
}
#else
#if 0
if (sizeof(Model<T>) > sizeof(buffer)) {
m_data = std::unique_ptr<const Concept>{std::make_unique<Model<T>>(std::forward<T>(arg))};
}
else {
buffer b;
m_data = b;
new (&std::get<buffer>(m_data)) Model<T>(std::move(arg));
}
#else
if (sizeof(Model<T>) > sizeof(m_buffer)) {
::new ((void*)(::std::addressof(m_pointer))) std::unique_ptr<const Concept>{std::make_unique<Model<T>>(std::forward<T>(arg))};
m_type = union_type::pointer;
}
else {
::new ((void*)(::std::addressof(m_buffer))) Model<T>(std::move(arg));
m_type = union_type::buffer;
}
#endif
#endif
}
Foo(const Foo& other)
{
switch (other.m_type) {
case union_type::buffer:
reinterpret_cast<const Concept*>(::std::addressof(other.m_buffer))->NewTo_(::std::addressof(m_buffer));
m_type = union_type::buffer;
break;
case union_type::pointer:
::new ((void*)(::std::addressof(m_pointer))) std::unique_ptr<const Concept>{other.m_pointer->Clone_()};
m_type = union_type::pointer;
break;
case union_type::none:
break;
}
}
bool has_value() const noexcept
{
return m_type == union_type::buffer || (m_type == union_type::pointer && m_pointer);
}
{
#if 0
return std::holds_alternative<buffer>(foo.m_data)?
reinterpret_cast<const Concept*>(&std::get<buffer>(foo.m_data))->GetFriction_():
std::get<pointer>(foo.m_data)? std::get<pointer>(foo.m_data)->GetFriction_():
Real(0);
#else
const auto c = foo.GetConcept();
return c? c->GetFriction_():
Real(0);
#endif
}
};
struct Foobar {
};
{
return value.f;
}
TEST(Shape, TestFoo)
{
EXPECT_EQ(sizeof(Foo), 64u);
EXPECT_FALSE(Foo().has_value());
EXPECT_TRUE(Foo(Foobar{3.0f}).has_value());
}
class Concept {
public:
virtual ~Concept() {};
};
struct storage {
union {
std::unique_ptr<const Concept> pointer;
alignas(std::max_align_t) std::byte buffer[alignof(std::max_align_t) * 3u];
};
enum class union_type {pointer, buffer};
union_type type = union_type::pointer;
storage(): pointer{} {}
~storage() {
if (type == union_type::pointer) {
pointer.~unique_ptr<const Concept>();
}
else {
reinterpret_cast<const Concept*>(buffer)->~Concept();
}
}
};
TEST(Shape, TestStorage)
{
storage data;
EXPECT_EQ(sizeof(data), 64u);
EXPECT_EQ(sizeof(data.buffer), 48u);
}
#endif
Definition of the DiskShapeConf class and closely related code.
Definition of the EdgeShapeConf class and closely related code.
Definition of the Manifold class and closely related code.
Definition of the PolygonShapeConf class and closely related code.
Definition of the Shape class and closely related code.
static constexpr auto DefaultDensity
Default density of a default-constructed, or otherwise value-less, shape.
Definition: Shape.hpp:222
static constexpr UnitVec GetUp() noexcept
Gets the up-ward oriented unit vector.
Definition: UnitVec.hpp:128
static constexpr UnitVec GetRight() noexcept
Gets the right-ward oriented unit vector.
Definition: UnitVec.hpp:122
auto Translate(T &, const Length2 &value) -> std::enable_if_t< IsValidShapeTypeV< T > &&!HasTranslateV< T >, void >
Fallback translate function that throws unless the given value has no effect.
Definition: ShapeModel.hpp:199
auto SetDensity(T &o, NonNegative< AreaDensity > value) -> std::enable_if_t< IsValidShapeTypeV< T > &&!HasSetDensityV< T >, void >
Fallback density setter that throws unless given the same value as current.
Definition: ShapeModel.hpp:169
auto Scale(T &, const Vec2 &value) -> std::enable_if_t< IsValidShapeTypeV< T > &&!HasScaleV< T >, void >
Fallback scale function that throws unless the given value has no effect.
Definition: ShapeModel.hpp:209
auto SetFilter(T &o, Filter value) -> std::enable_if_t< IsValidShapeTypeV< T > &&!HasSetFilterV< T >, void >
Fallback filter setter that throws unless given the same value as current.
Definition: ShapeModel.hpp:189
auto SetFriction(T &o, NonNegative< Real > value) -> std::enable_if_t< IsValidShapeTypeV< T > &&!HasSetFrictionV< T >, void >
Fallback friction setter that throws unless given the same value as current.
Definition: ShapeModel.hpp:149
auto SetRestitution(T &o, Real value) -> std::enable_if_t< IsValidShapeTypeV< T > &&!HasSetRestitutionV< T >, void >
Fallback restitution setter that throws unless given the same value as current.
Definition: ShapeModel.hpp:179
auto Rotate(T &, const UnitVec &value) -> std::enable_if_t< IsValidShapeTypeV< T > &&!HasRotateV< T >, void >
Fallback rotate function that throws unless the given value has no effect.
Definition: ShapeModel.hpp:219
auto SetSensor(T &o, bool value) -> std::enable_if_t< IsValidShapeTypeV< T > &&!HasSetSensorV< T >, void >
Fallback sensor setter that throws unless given the same value as current.
Definition: ShapeModel.hpp:159
Definition: Compositor.hpp:43
NonNegative< Length > GetVertexRadius(const ChainShapeConf &arg) noexcept
Gets the vertex radius of the given shape configuration.
Definition: ChainShapeConf.hpp:234
void Rotate(ChainShapeConf &arg, const UnitVec &value)
Rotates the given shape's vertices by the given amount.
Definition: ChainShapeConf.hpp:270
::playrho::detail::MassData< 2 > MassData
Mass data alias for 2-D objects.
Definition: MassData.hpp:88
NonNegative< AreaDensity > GetDensity(const Shape &shape) noexcept
Gets the density of the given shape.
Definition: Shape.hpp:353
NonNegativeFF< Real > GetFriction(const Shape &shape) noexcept
Gets the coefficient of friction.
Definition: Shape.hpp:325
void Scale(ChainShapeConf &arg, const Vec2 &value)
Scales the given shape's vertices by the given amount.
Definition: ChainShapeConf.hpp:264
Filter GetFilter(const Shape &shape) noexcept
Gets the filter value for the given shape.
Definition: Shape.hpp:367
BodyType GetType(const Body &body) noexcept
Gets the type of this body.
Definition: Body.hpp:748
void SetVertexRadius(ChainShapeConf &arg, NonNegative< Length > value) noexcept
Sets the vertex radius of the shape.
Definition: ChainShapeConf.hpp:246
std::add_pointer_t< std::add_const_t< T > > TypeCast(const Joint *value) noexcept
Converts the given joint into its current configuration value.
Definition: Joint.hpp:439
void Translate(ChainShapeConf &arg, const Length2 &value)
Translates the given shape's vertices by the given amount.
Definition: ChainShapeConf.hpp:258
Real GetRestitution(const Shape &shape) noexcept
Gets the coefficient of restitution value of the given shape.
Definition: Shape.hpp:339
bool IsSensor(const Shape &shape) noexcept
Gets whether or not the given shape is a sensor.
Definition: Shape.hpp:381
DistanceProxy GetChild(const ChainShapeConf &arg, ChildCounter index)
Gets the "child" shape for a given chain shape configuration.
Definition: ChainShapeConf.hpp:209
bool operator==(const AabbTreeWorld &lhs, const AabbTreeWorld &rhs)
Equality operator for world comparisons.
Definition: AabbTreeWorld.cpp:927
Manifold CollideShapes(const DistanceProxy &shapeA, const Transformation &xfA, const DistanceProxy &shapeB, const Transformation &xfB, const Manifold::Conf &conf=GetDefaultManifoldConf())
Calculates the relevant collision manifold.
Definition: Manifold.cpp:393
Area TestOverlap(const DistanceProxy &proxyA, const Transformation &xfA, const DistanceProxy &proxyB, const Transformation &xfB, DistanceConf conf=DistanceConf{})
Determine if two generic shapes overlap.
Definition: Distance.cpp:205
MassData GetMassData(const ChainShapeConf &arg)
Gets the mass data for a given chain shape configuration.
Definition: ChainShapeConf.hpp:215
ChildCounter GetChildCount(const ChainShapeConf &arg) noexcept
Gets the child count for a given chain shape configuration.
Definition: ChainShapeConf.hpp:203
Definition: ArrayList.hpp:43
std::remove_const_t< decltype(MaxChildCount)> ChildCounter
Child counter type.
Definition: Settings.hpp:57
float Real
Real-number type.
Definition: Real.hpp:69
TypeID GetTypeID() noexcept
Gets the type ID for the function's template parameter type with its name demangled.
Definition: TypeInfo.hpp:121
auto end(ReversionWrapper< T > w)
End function for getting a reversed order iterator.
Definition: Templates.hpp:118
Vector2< Length > Length2
2-element vector of Length quantities.
Definition: Vector2.hpp:51
Vector2< Real > Vec2
Vector with 2 Real elements.
Definition: Vector2.hpp:47
bits_type categoryBits
The collision category bits.
Definition: Filter.hpp:51
index_type groupIndex
Group index.
Definition: Filter.hpp:61
bits_type maskBits
The collision mask bits.
Definition: Filter.hpp:55