Body.cpp
This is the googletest
based unit testing file for the playrho::d2::Body
class.
/*
* Copyright (c) 2017 Louis Langholtz https://github.com/louis-langholtz/PlayRho
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "UnitTests.hpp"
#include <PlayRho/Dynamics/Body.hpp>
#include <PlayRho/Dynamics/BodyConf.hpp>
#include <PlayRho/Dynamics/World.hpp>
#include <PlayRho/Dynamics/StepConf.hpp>
#include <PlayRho/Dynamics/Fixture.hpp>
#include <PlayRho/Dynamics/Joints/Joint.hpp>
#include <PlayRho/Collision/Shapes/DiskShapeConf.hpp>
#include <chrono>
using namespace playrho;
using namespace playrho::d2;
TEST(BodyConf, UsePosition)
{
}
TEST(BodyConf, UseVelocity)
{
}
TEST(Body, ContactsByteSize)
{
#if defined(__APPLE__)
EXPECT_EQ(sizeof(Body::Contacts), std::size_t(24));
#elif defined(__linux__)
EXPECT_EQ(sizeof(Body::Contacts), std::size_t(24));
#elif defined(_WIN64)
#if !defined(NDEBUG)
EXPECT_EQ(sizeof(Body::Contacts), std::size_t(32));
#else
EXPECT_EQ(sizeof(Body::Contacts), std::size_t(24));
#endif
#elif defined(_WIN32)
#if !defined(NDEBUG)
EXPECT_EQ(sizeof(Body::Contacts), std::size_t(16));
#else
EXPECT_EQ(sizeof(Body::Contacts), std::size_t(12));
#endif
#else
// Intentionally fail for unknown platform...
EXPECT_EQ(sizeof(Body::Contacts), std::size_t(0));
#endif
}
TEST(Body, JointsByteSize)
{
#ifdef __APPLE__
EXPECT_EQ(sizeof(Body::Joints), std::size_t(24));
#elif __linux__
EXPECT_EQ(sizeof(Body::Joints), std::size_t(24));
#elif _WIN64
#if defined(NDEBUG)
EXPECT_EQ(sizeof(Body::Joints), std::size_t(24));
#else
EXPECT_EQ(sizeof(Body::Joints), std::size_t(32));
#endif
#elif _WIN32
#if defined(NDEBUG)
EXPECT_EQ(sizeof(Body::Joints), std::size_t(12));
#else
EXPECT_EQ(sizeof(Body::Joints), std::size_t(16));
#endif
#else // !__APPLE__ && !__linux__ && !_WIN64 && !_WIN32
// Intentionally fail for unknown platform...
EXPECT_EQ(sizeof(Body::Joints), std::size_t(0));
#endif
}
TEST(Body, FixturesByteSize)
{
// Size is arch, os, or library dependent.
#ifdef __APPLE__
EXPECT_EQ(sizeof(Body::Fixtures), std::size_t(24));
#elif __linux__
EXPECT_EQ(sizeof(Body::Fixtures), std::size_t(24));
#elif _WIN64
#if !defined(NDEBUG)
EXPECT_EQ(sizeof(Body::Fixtures), std::size_t(32));
#else
EXPECT_EQ(sizeof(Body::Fixtures), std::size_t(24));
#endif
#elif _WIN32
#if !defined(NDEBUG)
EXPECT_EQ(sizeof(Body::Fixtures), std::size_t(16));
#else
EXPECT_EQ(sizeof(Body::Fixtures), std::size_t(12));
#endif
#else
// Intentionally fail for unknown platform...
EXPECT_EQ(sizeof(Body::Fixtures), std::size_t(0));
#endif
}
TEST(Body, ByteSize)
{
const auto allSize = contactsSize + jointsSize + fixturesSize;
#if defined(_WIN64)
#if !defined(NDEBUG)
EXPECT_EQ(allSize, std::size_t(96));
#else
EXPECT_EQ(allSize, std::size_t(72));
#endif
#elif defined(_WIN32)
#if !defined(NDEBUG)
EXPECT_EQ(allSize, std::size_t(48));
#else
EXPECT_EQ(allSize, std::size_t(36));
#endif
#else
EXPECT_EQ(allSize, std::size_t(72));
#endif
// architecture dependent...
{
case 4:
#if defined(_WIN64)
EXPECT_EQ(sizeof(Body), std::size_t(192));
#elif defined(_WIN32)
#if !defined(NDEBUG)
// Win32 debug
EXPECT_EQ(sizeof(Body), std::size_t(192));
#else
// Win32 release
EXPECT_EQ(sizeof(Body), std::size_t(144));
#endif
#else
EXPECT_EQ(sizeof(Body), std::size_t(192));
#endif
break;
case 8:
EXPECT_EQ(sizeof(Body), std::size_t(288));
break;
case 16:
EXPECT_EQ(sizeof(Body), std::size_t(496));
break;
default: FAIL(); break;
}
}
TEST(Body, Traits)
{
using Type = Body;
EXPECT_FALSE(IsIterable<Type>::value);
EXPECT_FALSE(IsAddable<Type>::value);
EXPECT_FALSE((IsAddable<Type, Type>::value));
EXPECT_FALSE(std::is_default_constructible<Type>::value);
EXPECT_FALSE(std::is_nothrow_default_constructible<Type>::value);
EXPECT_FALSE(std::is_trivially_default_constructible<Type>::value);
EXPECT_FALSE(std::is_constructible<Type>::value);
EXPECT_FALSE(std::is_nothrow_constructible<Type>::value);
EXPECT_FALSE(std::is_trivially_constructible<Type>::value);
EXPECT_FALSE(std::is_copy_constructible<Type>::value);
EXPECT_FALSE(std::is_nothrow_copy_constructible<Type>::value);
EXPECT_FALSE(std::is_trivially_copy_constructible<Type>::value);
EXPECT_FALSE(std::is_copy_assignable<Type>::value);
EXPECT_FALSE(std::is_nothrow_copy_assignable<Type>::value);
EXPECT_FALSE(std::is_trivially_copy_assignable<Type>::value);
EXPECT_FALSE(std::is_destructible<Type>::value);
EXPECT_FALSE(std::is_nothrow_destructible<Type>::value);
EXPECT_FALSE(std::is_trivially_destructible<Type>::value);
}
TEST(Body, GetFlagsStatic)
{
EXPECT_TRUE(Body::GetFlags(BodyConf{}
.UseAllowSleep(false)
}
TEST(Body, WorldCreated)
{
ASSERT_NE(body, nullptr);
EXPECT_EQ(body->GetWorld(), &world);
EXPECT_EQ(body->GetUserData(), nullptr);
EXPECT_TRUE(body->IsEnabled());
EXPECT_FALSE(body->IsAwake());
EXPECT_FALSE(body->IsSpeedable());
EXPECT_FALSE(body->IsAccelerable());
EXPECT_FALSE(Awaken(*body));
EXPECT_TRUE(body->GetFixtures().empty());
{
auto i = 0;
for (auto&& fixture: body->GetFixtures())
{
EXPECT_EQ(GetRef(fixture).GetBody(), body);
++i;
}
EXPECT_EQ(i, 0);
}
EXPECT_TRUE(body->GetJoints().empty());
{
auto i = 0;
for (auto&& joint: body->GetJoints())
{
NOT_USED(joint);
++i;
}
EXPECT_EQ(i, 0);
}
EXPECT_TRUE(body->GetContacts().empty());
{
auto i = 0;
for (auto&& ce: body->GetContacts())
{
NOT_USED(ce);
++i;
}
EXPECT_EQ(i, 0);
}
}
TEST(Body, SetVelocityDoesNothingToStatic)
{
LinearVelocity2{0_mps, 0_mps},
};
auto world = World{};
ASSERT_NE(body, nullptr);
ASSERT_FALSE(body->IsAwake());
ASSERT_FALSE(body->IsSpeedable());
ASSERT_FALSE(body->IsAccelerable());
ASSERT_EQ(body->GetVelocity(), zeroVelocity);
LinearVelocity2{1.1_mps, 1.1_mps},
};
body->SetVelocity(velocity);
EXPECT_NE(body->GetVelocity(), velocity);
EXPECT_EQ(body->GetVelocity(), zeroVelocity);
}
TEST(Body, CreateFixture)
{
auto world = World{};
EXPECT_EQ(GetFixtureCount(*body), std::size_t(0));
EXPECT_EQ(GetFixtureCount(*body), std::size_t(1));
const auto minRadius = world.GetMinVertexRadius();
const auto maxRadius = world.GetMaxVertexRadius();
EXPECT_THROW(body->CreateFixture(Shape{DiskShapeConf{maxRadius + maxRadius / 10}}), InvalidArgument);
}
TEST(Body, Destroy)
{
auto world = World{};
const auto bodyB = world.CreateBody();
ASSERT_EQ(GetFixtureCount(*bodyA), std::size_t(0));
ASSERT_EQ(GetFixtureCount(*bodyB), std::size_t(0));
ASSERT_NE(fixtureA, nullptr);
ASSERT_EQ(GetFixtureCount(*bodyA), std::size_t(1));
EXPECT_FALSE(bodyB->Destroy(fixtureA));
EXPECT_EQ(GetFixtureCount(*bodyA), std::size_t(1));
EXPECT_TRUE(bodyA->Destroy(fixtureA));
EXPECT_EQ(GetFixtureCount(*bodyA), std::size_t(0));
}
TEST(Body, SetEnabled)
{
auto world = World{};
ASSERT_EQ(world.GetFixturesForProxies().size(), 0u);
ASSERT_EQ(world.GetBodiesForProxies().size(), 0u);
const auto body = world.CreateBody();
ASSERT_NE(fixture, nullptr);
ASSERT_TRUE(body->IsEnabled());
ASSERT_EQ(fixture->GetProxyCount(), 0u);
EXPECT_EQ(world.GetFixturesForProxies().size(), 1u);
EXPECT_EQ(world.GetBodiesForProxies().size(), 0u);
world.Step(stepConf);
EXPECT_EQ(fixture->GetProxyCount(), 1u);
EXPECT_EQ(world.GetFixturesForProxies().size(), 0u);
EXPECT_EQ(world.GetBodiesForProxies().size(), 0u);
// Test that set enabled to flag already set is not a toggle
body->SetEnabled(true);
EXPECT_TRUE(body->IsEnabled());
EXPECT_EQ(fixture->GetProxyCount(), 1u);
EXPECT_EQ(world.GetFixturesForProxies().size(), 0u);
EXPECT_EQ(world.GetBodiesForProxies().size(), 0u);
body->SetEnabled(false);
EXPECT_FALSE(body->IsEnabled());
EXPECT_EQ(fixture->GetProxyCount(), 1u);
EXPECT_EQ(world.GetFixturesForProxies().size(), 1u);
EXPECT_EQ(world.GetBodiesForProxies().size(), 0u);
world.Step(stepConf);
EXPECT_EQ(fixture->GetProxyCount(), 0u);
EXPECT_EQ(world.GetFixturesForProxies().size(), 0u);
EXPECT_EQ(world.GetBodiesForProxies().size(), 0u);
body->SetEnabled(true);
EXPECT_TRUE(body->IsEnabled());
EXPECT_EQ(world.GetFixturesForProxies().size(), 1u);
EXPECT_EQ(world.GetBodiesForProxies().size(), 0u);
world.Step(stepConf);
EXPECT_EQ(fixture->GetProxyCount(), 1u);
EXPECT_EQ(world.GetFixturesForProxies().size(), 0u);
EXPECT_EQ(world.GetBodiesForProxies().size(), 0u);
}
TEST(Body, SetFixedRotation)
{
auto world = World{};
ASSERT_NE(body->CreateFixture(valid_shape, FixtureConf{}), nullptr);
ASSERT_FALSE(body->IsFixedRotation());
// Test that set fixed rotation to flag already set is not a toggle
body->SetFixedRotation(false);
EXPECT_FALSE(body->IsFixedRotation());
body->SetFixedRotation(true);
EXPECT_TRUE(body->IsFixedRotation());
body->SetFixedRotation(false);
EXPECT_FALSE(body->IsFixedRotation());
}
TEST(Body, CreateAndDestroyFixture)
{
auto world = World{};
auto body = world.CreateBody();
ASSERT_NE(body, nullptr);
EXPECT_TRUE(body->GetFixtures().empty());
EXPECT_FALSE(body->IsMassDataDirty());
auto conf = DiskShapeConf{};
conf.vertexRadius = 2.871_m;
conf.location = Vec2{1.912f, -77.31f} * 1_m;
conf.density = 1_kgpm2;
{
const auto fshape = fixture->GetShape();
EXPECT_FALSE(body->GetFixtures().empty());
{
auto i = 0;
for (auto&& f: body->GetFixtures())
{
EXPECT_EQ(GetPtr(f), fixture);
++i;
}
EXPECT_EQ(i, 1);
}
EXPECT_TRUE(body->IsMassDataDirty());
body->ResetMassData();
EXPECT_FALSE(body->IsMassDataDirty());
ASSERT_EQ(world.GetFixturesForProxies().size(), std::size_t{1});
EXPECT_EQ(*world.GetFixturesForProxies().begin(), fixture);
body->Destroy(fixture, false);
EXPECT_TRUE(body->GetFixtures().empty());
EXPECT_TRUE(body->IsMassDataDirty());
EXPECT_EQ(world.GetFixturesForProxies().size(), std::size_t{0});
body->ResetMassData();
EXPECT_FALSE(body->IsMassDataDirty());
body->DestroyFixtures();
EXPECT_TRUE(body->GetFixtures().empty());
}
{
const auto fshape = fixture->GetShape();
EXPECT_EQ(GetVertexRadius(fshape, 0), GetVertexRadius(shape, 0));
EXPECT_FALSE(body->GetFixtures().empty());
{
auto i = 0;
for (auto&& f: body->GetFixtures())
{
EXPECT_EQ(GetPtr(f), fixture);
++i;
}
EXPECT_EQ(i, 1);
}
EXPECT_TRUE(body->IsMassDataDirty());
body->ResetMassData();
EXPECT_FALSE(body->IsMassDataDirty());
EXPECT_FALSE(body->GetFixtures().empty());
body->DestroyFixtures();
EXPECT_TRUE(body->GetFixtures().empty());
EXPECT_FALSE(body->IsMassDataDirty());
}
}
TEST(Body, SetType)
{
auto bd = BodyConf{};
bd.type = BodyType::Dynamic;
auto world = World{};
ASSERT_EQ(world.GetBodiesForProxies().size(), 0u);
ASSERT_EQ(body->GetType(), BodyType::Dynamic);
body->SetType(BodyType::Static);
EXPECT_EQ(world.GetBodiesForProxies().size(), 1u);
EXPECT_EQ(body->GetType(), BodyType::Static);
body->SetType(BodyType::Kinematic);
EXPECT_EQ(world.GetBodiesForProxies().size(), 1u);
EXPECT_EQ(body->GetType(), BodyType::Kinematic);
body->SetType(BodyType::Dynamic);
EXPECT_EQ(body->GetType(), BodyType::Dynamic);
EXPECT_EQ(world.GetBodiesForProxies().size(), 1u);
}
TEST(Body, StaticIsExpected)
{
auto world = World{};
EXPECT_FALSE(body->IsAccelerable());
EXPECT_FALSE(body->IsSpeedable());
EXPECT_TRUE( body->IsImpenetrable());
}
TEST(Body, KinematicIsExpected)
{
auto world = World{};
EXPECT_FALSE(body->IsAccelerable());
EXPECT_TRUE( body->IsSpeedable());
EXPECT_TRUE( body->IsImpenetrable());
}
TEST(Body, DynamicIsExpected)
{
auto world = World{};
EXPECT_TRUE(body->IsAccelerable());
EXPECT_TRUE(body->IsSpeedable());
EXPECT_FALSE(body->IsImpenetrable());
}
TEST(Body, SetMassData)
{
const auto mass = 32_kg;
const auto rotInertia = 3 * rotInertiaUnits; // L^2 M QP^-2
// has effect on dynamic bodies...
{
auto world = World{};
EXPECT_EQ(GetMass(*body), 1_kg);
EXPECT_EQ(GetRotInertia(*body), std::numeric_limits<Real>::infinity() * rotInertiaUnits);
body->SetMassData(massData);
EXPECT_EQ(GetMass(*body), mass);
EXPECT_EQ(GetRotInertia(*body), rotInertia);
}
// has no rotational effect on fixed rotation dynamic bodies...
{
auto world = World{};
EXPECT_EQ(GetMass(*body), 1_kg);
EXPECT_EQ(GetRotInertia(*body), std::numeric_limits<Real>::infinity() * rotInertiaUnits);
body->SetMassData(massData);
EXPECT_EQ(GetMass(*body), mass);
EXPECT_EQ(GetRotInertia(*body), std::numeric_limits<Real>::infinity() * rotInertiaUnits);
}
// has no effect on static bodies...
{
auto world = World{};
EXPECT_EQ(GetMass(*body), 0_kg);
EXPECT_EQ(GetRotInertia(*body), std::numeric_limits<Real>::infinity() * rotInertiaUnits);
body->SetMassData(massData);
EXPECT_EQ(GetMass(*body), 0_kg);
EXPECT_EQ(GetRotInertia(*body), std::numeric_limits<Real>::infinity() * rotInertiaUnits);
}
}
TEST(Body, SetTransform)
{
auto bd = BodyConf{};
bd.type = BodyType::Dynamic;
auto world = World{};
ASSERT_EQ(world.GetBodiesForProxies().size(), 0u);
const auto body = world.CreateBody(bd);
ASSERT_EQ(body->GetTransformation(), xfm1);
ASSERT_EQ(world.GetBodiesForProxies().size(), 0u);
body->SetTransform(xfm2.p, GetAngle(xfm2.q));
EXPECT_EQ(body->GetTransformation().p, xfm2.p);
0.001);
0.001);
EXPECT_EQ(world.GetBodiesForProxies().size(), 1u);
world.Destroy(body);
EXPECT_EQ(world.GetBodiesForProxies().size(), 0u);
}
{
const auto someLinearAccel = LinearAcceleration2{2 * MeterPerSquareSecond, 3 * MeterPerSquareSecond};
{
auto world = World{};
ASSERT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
ASSERT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
ASSERT_FALSE(body->IsAwake());
body->UnsetAwake();
ASSERT_FALSE(body->IsAwake());
body->SetAcceleration(LinearAcceleration2{}, AngularAcceleration{});
EXPECT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
EXPECT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
EXPECT_FALSE(body->IsAwake());
body->SetAcceleration(LinearAcceleration2{}, someAngularAccel);
EXPECT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
EXPECT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
EXPECT_FALSE(body->IsAwake());
body->SetAcceleration(someLinearAccel, AngularAcceleration{});
EXPECT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
EXPECT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
EXPECT_FALSE(body->IsAwake());
}
// Kinematic and dynamic bodies awake at creation...
{
auto world = World{};
ASSERT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
ASSERT_TRUE(body->IsAwake());
body->UnsetAwake();
ASSERT_FALSE(body->IsAwake());
body->SetAcceleration(LinearAcceleration2{}, AngularAcceleration{});
EXPECT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
EXPECT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
EXPECT_FALSE(body->IsAwake());
body->SetAcceleration(LinearAcceleration2{}, someAngularAccel);
EXPECT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
EXPECT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
EXPECT_FALSE(body->IsAwake());
body->SetAcceleration(someLinearAccel, AngularAcceleration{});
EXPECT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
EXPECT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
EXPECT_FALSE(body->IsAwake());
}
// Dynamic bodies take a non-zero linear or angular acceleration.
{
auto world = World{};
ASSERT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
ASSERT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
ASSERT_TRUE(body->IsAwake());
body->UnsetAwake();
ASSERT_FALSE(body->IsAwake());
body->SetAcceleration(LinearAcceleration2{}, AngularAcceleration{});
EXPECT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
EXPECT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
EXPECT_FALSE(body->IsAwake());
body->SetAcceleration(LinearAcceleration2{}, someAngularAccel);
EXPECT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
EXPECT_EQ(body->GetAngularAcceleration(), someAngularAccel);
EXPECT_TRUE(body->IsAwake());
body->SetAcceleration(someLinearAccel, AngularAcceleration{});
EXPECT_EQ(body->GetLinearAcceleration(), someLinearAccel);
EXPECT_EQ(body->GetAngularAcceleration(), 0 * RadianPerSquareSecond);
EXPECT_TRUE(body->IsAwake());
body->SetAcceleration(someLinearAccel, someAngularAccel);
EXPECT_EQ(body->GetLinearAcceleration(), someLinearAccel);
EXPECT_EQ(body->GetAngularAcceleration(), someAngularAccel);
EXPECT_TRUE(body->IsAwake());
body->UnsetAwake();
ASSERT_FALSE(body->IsAwake());
EXPECT_EQ(body->GetLinearAcceleration(), someLinearAccel);
EXPECT_EQ(body->GetAngularAcceleration(), someAngularAccel);
// Reseting to same acceleration shouldn't change asleep status...
body->SetAcceleration(someLinearAccel, someAngularAccel);
EXPECT_FALSE(body->IsAwake());
EXPECT_EQ(body->GetLinearAcceleration(), someLinearAccel);
EXPECT_EQ(body->GetAngularAcceleration(), someAngularAccel);
// Seting to lower acceleration shouldn't change asleep status...
body->SetAcceleration(someLinearAccel * 0.5f, someAngularAccel * 0.9f);
EXPECT_FALSE(body->IsAwake());
EXPECT_EQ(body->GetLinearAcceleration(), someLinearAccel * 0.5f);
EXPECT_EQ(body->GetAngularAcceleration(), someAngularAccel * 0.9f);
// Seting to higher acceleration or new direction should awaken...
body->SetAcceleration(someLinearAccel * 1.5f, someAngularAccel * 1.9f);
EXPECT_TRUE(body->IsAwake());
EXPECT_EQ(body->GetLinearAcceleration(), someLinearAccel * 1.5f);
EXPECT_EQ(body->GetAngularAcceleration(), someAngularAccel * 1.9f);
body->UnsetAwake();
ASSERT_FALSE(body->IsAwake());
body->SetAcceleration(someLinearAccel * 1.5f, someAngularAccel * 2.0f);
EXPECT_TRUE(body->IsAwake());
EXPECT_EQ(body->GetLinearAcceleration(), someLinearAccel * 1.5f);
EXPECT_EQ(body->GetAngularAcceleration(), someAngularAccel * 2.0f);
body->UnsetAwake();
ASSERT_FALSE(body->IsAwake());
body->SetAcceleration(someLinearAccel * 2.0f, someAngularAccel * 2.0f);
EXPECT_TRUE(body->IsAwake());
EXPECT_EQ(body->GetLinearAcceleration(), someLinearAccel * 2.0f);
EXPECT_EQ(body->GetAngularAcceleration(), someAngularAccel * 2.0f);
body->UnsetAwake();
ASSERT_FALSE(body->IsAwake());
body->SetAcceleration(someLinearAccel * -1.0f, someAngularAccel * 2.0f);
EXPECT_TRUE(body->IsAwake());
EXPECT_EQ(body->GetLinearAcceleration(), someLinearAccel * -1.0f);
EXPECT_EQ(body->GetAngularAcceleration(), someAngularAccel * 2.0f);
}
}
TEST(Body, CreateLotsOfFixtures)
{
auto bd = BodyConf{};
bd.type = BodyType::Dynamic;
auto conf = DiskShapeConf{};
conf.vertexRadius = 2.871_m;
conf.location = Vec2{1.912f, -77.31f} * 1_m;
conf.density = 1.3_kgpm2;
const auto num = 5000;
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
{
auto world = World{};
auto body = world.CreateBody(bd);
ASSERT_NE(body, nullptr);
EXPECT_TRUE(body->GetFixtures().empty());
for (auto i = decltype(num){0}; i < num; ++i)
{
ASSERT_NE(fixture, nullptr);
}
body->ResetMassData();
EXPECT_FALSE(body->GetFixtures().empty());
{
int i = decltype(num){0};
for (auto&& f: body->GetFixtures())
{
NOT_USED(f);
++i;
}
EXPECT_EQ(i, num);
}
}
end = std::chrono::system_clock::now();
const std::chrono::duration<double> elapsed_secs_resetting_at_end = end - start;
start = std::chrono::system_clock::now();
{
auto world = World{};
auto body = world.CreateBody(bd);
ASSERT_NE(body, nullptr);
EXPECT_TRUE(body->GetFixtures().empty());
for (auto i = decltype(num){0}; i < num; ++i)
{
ASSERT_NE(fixture, nullptr);
}
EXPECT_FALSE(body->GetFixtures().empty());
{
auto i = decltype(num){0};
for (auto&& f: body->GetFixtures())
{
NOT_USED(f);
++i;
}
EXPECT_EQ(i, num);
}
}
end = std::chrono::system_clock::now();
const std::chrono::duration<double> elapsed_secs_resetting_in_create = end - start;
EXPECT_LT(elapsed_secs_resetting_at_end.count(), elapsed_secs_resetting_in_create.count());
}
{
auto world = World{};
ASSERT_EQ(world.GetBodies().size(), std::size_t(0));
const auto body0 = world.CreateBody();
ASSERT_EQ(world.GetBodies().size(), std::size_t(1));
const auto body1 = world.CreateBody();
ASSERT_EQ(world.GetBodies().size(), std::size_t(2));
EXPECT_EQ(GetWorldIndex(body1), BodyCounter(1));
const auto body2 = world.CreateBody();
ASSERT_EQ(world.GetBodies().size(), std::size_t(3));
EXPECT_EQ(GetWorldIndex(body2), BodyCounter(2));
}
TEST(Body, ApplyLinearAccelDoesNothingToStatic)
{
auto world = World{};
ASSERT_NE(body, nullptr);
ASSERT_FALSE(body->IsAwake());
ASSERT_FALSE(body->IsSpeedable());
ASSERT_FALSE(body->IsAccelerable());
};
};
ApplyLinearAcceleration(*body, linAccel);
EXPECT_NE(body->GetLinearAcceleration(), linAccel);
EXPECT_EQ(body->GetLinearAcceleration(), zeroAccel);
}
TEST(Body, GetAccelerationFF)
{
auto world = World{};
ASSERT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
ASSERT_EQ(body->GetAngularAcceleration(), AngularAcceleration{});
}
TEST(Body, SetAccelerationFF)
{
auto world = World{};
ASSERT_EQ(body->GetLinearAcceleration(), LinearAcceleration2{});
ASSERT_EQ(body->GetAngularAcceleration(), AngularAcceleration{});
};
SetAcceleration(*body, newAccel);
EXPECT_EQ(GetAcceleration(*body), newAccel);
}
{
auto world = World{};
b1->CreateFixture(shape);
EXPECT_EQ(CalcGravitationalAcceleration(*b1), Acceleration{});
b2->CreateFixture(shape);
0.032761313021183014, 0.032761313021183014/100);
EXPECT_EQ(GetY(accel.linear), 0 * MeterPerSquareSecond);
EXPECT_EQ(accel.angular, 0 * RadianPerSquareSecond);
EXPECT_EQ(CalcGravitationalAcceleration(*b3), Acceleration{});
}
TEST(Body, RotateAboutWorldPointFF)
{
auto world = World{};
ASSERT_EQ(locationA, Length2(0_m, 0_m));
const auto locationB = body->GetLocation();
}
TEST(Body, RotateAboutLocalPointFF)
{
auto world = World{};
ASSERT_EQ(locationA, Length2(0_m, 0_m));
const auto locationB = body->GetLocation();
}
{
auto world = World{};
body->CreateFixture(shape);
}
TEST(Body, GetPositionFF)
{
auto world = World{};
auto body = world.CreateBody();
EXPECT_NE(GetPosition(*body), position);
SetLocation(*body, position.linear);
SetAngle(*body, position.angular);
EXPECT_EQ(GetPosition(*body), position);
}
TEST(Body, GetSetTransformationFF)
{
auto world = World{};
auto body = world.CreateBody();
EXPECT_NE(GetTransformation(*body), xfm0);
SetTransformation(*body, xfm0);
EXPECT_EQ(xfm1.p, xfm0.p);
}