PlayRho  1.1.0
An Interactive Real-Time-Oriented C++ Physics Engine & Library
DistanceJoint.cpp

This is the googletest based unit testing file for the interfaces to playrho::d2::DistanceJointConf.

/*
* Copyright (c) 2020 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/Joints/DistanceJointConf.hpp>
#include <PlayRho/Dynamics/Joints/Joint.hpp>
#include <PlayRho/Dynamics/World.hpp>
#include <PlayRho/Dynamics/WorldJoint.hpp>
#include <PlayRho/Dynamics/WorldBody.hpp>
#include <PlayRho/Dynamics/WorldMisc.hpp>
#include <PlayRho/Dynamics/WorldFixture.hpp>
#include <PlayRho/Dynamics/StepConf.hpp>
#include <PlayRho/Dynamics/BodyConf.hpp>
#include <PlayRho/Collision/Shapes/DiskShapeConf.hpp>
#include <stdexcept> // for std::invalid_argument
using namespace playrho;
using namespace playrho::d2;
TEST(DistanceJointConf, ByteSize)
{
// Check size at test runtime instead of compile-time via static_assert to avoid stopping
// builds and to report actual size rather than just reporting that expected size is wrong.
switch (sizeof(Real)) {
case 4:
EXPECT_EQ(sizeof(DistanceJointConf), std::size_t(76));
break;
case 8:
EXPECT_EQ(sizeof(DistanceJointConf), std::size_t(144));
break;
case 16:
EXPECT_EQ(sizeof(DistanceJointConf), std::size_t(288));
break;
default:
FAIL();
break;
}
}
TEST(DistanceJointConf, DefaultConstruction)
{
auto def = DistanceJointConf{};
EXPECT_EQ(def.bodyA, InvalidBodyID);
EXPECT_EQ(def.bodyB, InvalidBodyID);
EXPECT_EQ(def.collideConnected, false);
EXPECT_EQ(def.localAnchorA, (Length2{}));
EXPECT_EQ(def.localAnchorB, (Length2{}));
EXPECT_EQ(def.length, 1_m);
EXPECT_EQ(def.frequency, 0_Hz);
EXPECT_EQ(def.dampingRatio, Real(0));
}
TEST(DistanceJointConf, UseLength)
{
const auto value = Length(31_m);
EXPECT_NE(DistanceJointConf{}.length, value);
EXPECT_EQ(DistanceJointConf{}.UseLength(value).length, value);
}
TEST(DistanceJointConf, UseFrequency)
{
const auto value = 19_Hz;
EXPECT_NE(DistanceJointConf{}.frequency, value);
EXPECT_EQ(DistanceJointConf{}.UseFrequency(value).frequency, value);
}
TEST(DistanceJointConf, UseDampingRatio)
{
const auto value = Real(0.4);
EXPECT_NE(DistanceJointConf{}.dampingRatio, value);
EXPECT_EQ(DistanceJointConf{}.UseDampingRatio(value).dampingRatio, value);
}
TEST(DistanceJoint, TypeCast)
{
const auto joint = Joint{DistanceJointConf{}};
EXPECT_THROW(TypeCast<int>(joint), std::bad_cast);
EXPECT_NO_THROW(TypeCast<DistanceJointConf>(joint));
}
TEST(DistanceJoint, Construction)
{
auto world = World{};
const auto body0 = CreateBody(world, BodyConf{}.UseType(BodyType::Dynamic));
const auto body1 = CreateBody(world, BodyConf{}.UseType(BodyType::Dynamic));
auto def = DistanceJointConf{body0, body1};
const auto joint = CreateJoint(world, Joint{def});
EXPECT_EQ(GetType(world, joint), GetTypeID<DistanceJointConf>());
EXPECT_EQ(GetBodyA(world, joint), def.bodyA);
EXPECT_EQ(GetBodyB(world, joint), def.bodyB);
EXPECT_EQ(GetCollideConnected(world, joint), def.collideConnected);
EXPECT_EQ(GetLinearReaction(world, joint), Momentum2{});
EXPECT_EQ(GetAngularReaction(world, joint), AngularMomentum{0});
EXPECT_EQ(GetLocalAnchorA(world, joint), def.localAnchorA);
EXPECT_EQ(GetLocalAnchorB(world, joint), def.localAnchorB);
EXPECT_EQ(GetFrequency(world, joint), def.frequency);
EXPECT_EQ(GetLength(world, joint), def.length);
EXPECT_EQ(GetDampingRatio(world, joint), def.dampingRatio);
}
TEST(DistanceJoint, ShiftOrigin)
{
auto world = World{};
const auto body0 = CreateBody(world, BodyConf{}.UseType(BodyType::Dynamic));
const auto body1 = CreateBody(world, BodyConf{}.UseType(BodyType::Dynamic));
auto def = DistanceJointConf{body0, body1};
const auto joint = CreateJoint(world, def);
const auto newOrigin = Length2{1_m, 1_m};
EXPECT_FALSE(ShiftOrigin(world, joint, newOrigin));
}
TEST(DistanceJoint, InZeroGravBodiesMoveOutToLength)
{
auto world = World{};
const auto shape = Shape{DiskShapeConf{}.UseRadius(0.2_m)};
const auto location1 = Length2{-1_m, 0_m};
const auto body1 =
CreateBody(world, BodyConf{}.UseType(BodyType::Dynamic).UseLocation(location1));
ASSERT_EQ(GetLocation(world, body1), location1);
ASSERT_NE(CreateFixture(world, body1, shape), InvalidFixtureID);
const auto location2 = Length2{+1_m, 0_m};
const auto body2 =
CreateBody(world, BodyConf{}.UseType(BodyType::Dynamic).UseLocation(location2));
ASSERT_EQ(GetLocation(world, body2), location2);
ASSERT_NE(CreateFixture(world, body2, shape), InvalidFixtureID);
auto jointdef = DistanceJointConf{};
jointdef.bodyA = body1;
jointdef.bodyB = body2;
jointdef.collideConnected = false;
jointdef.localAnchorA = Length2{};
jointdef.localAnchorB = Length2{};
jointdef.length = 5_m;
jointdef.frequency = 0_Hz;
jointdef.dampingRatio = 0;
EXPECT_NE(CreateJoint(world, Joint{jointdef}), InvalidJointID);
auto oldDistance = GetMagnitude(GetLocation(world, body1) - GetLocation(world, body2));
auto distanceMet = 0u;
auto stepConf = StepConf{};
for (auto i = 0u; !distanceMet || i < distanceMet + 100; ++i) {
Step(world, stepConf);
const auto newDistance =
GetMagnitude(GetLocation(world, body1) - GetLocation(world, body2));
if (distanceMet) {
EXPECT_NEAR(double(Real{newDistance / Meter}), double(Real{oldDistance / Meter}), 0.01);
}
else {
EXPECT_GE(newDistance, oldDistance);
}
if (!distanceMet && (abs(newDistance - jointdef.length) < 0.01_m)) {
distanceMet = i;
}
oldDistance = newDistance;
}
}
TEST(DistanceJoint, InZeroGravBodiesMoveInToLength)
{
auto world = World{};
const auto shape = Shape{DiskShapeConf{}.UseRadius(0.2_m).UseDensity(1_kgpm2)};
const auto location1 = Length2{-10_m, 10_m};
const auto body1 =
CreateBody(world, BodyConf{}.UseType(BodyType::Dynamic).UseLocation(location1));
ASSERT_EQ(GetLocation(world, body1), location1);
ASSERT_NE(CreateFixture(world, body1, shape), InvalidFixtureID);
const auto location2 = Length2{+10_m, -10_m};
const auto body2 =
CreateBody(world, BodyConf{}.UseType(BodyType::Dynamic).UseLocation(location2));
ASSERT_EQ(GetLocation(world, body2), location2);
ASSERT_NE(CreateFixture(world, body2, shape), InvalidFixtureID);
auto jointdef = DistanceJointConf{};
jointdef.bodyA = body1;
jointdef.bodyB = body2;
jointdef.collideConnected = false;
jointdef.localAnchorA = Length2{};
jointdef.localAnchorB = Length2{};
jointdef.length = 5_m;
jointdef.frequency = 60_Hz;
jointdef.dampingRatio = 0;
EXPECT_NE(CreateJoint(world, Joint{jointdef}), InvalidJointID);
auto oldDistance = GetMagnitude(GetLocation(world, body1) - GetLocation(world, body2));
auto distanceMet = 0u;
auto stepConf = StepConf{};
for (auto i = 0u; !distanceMet || i < distanceMet + 1000; ++i) {
Step(world, stepConf);
const auto newDistance =
GetMagnitude(GetLocation(world, body1) - GetLocation(world, body2));
if (!distanceMet && (newDistance - oldDistance) >= 0_m) {
distanceMet = i;
}
if (distanceMet) {
EXPECT_NEAR(double(Real{newDistance / Meter}), double(Real{oldDistance / Meter}), 2.5);
}
else {
EXPECT_LE(newDistance, oldDistance);
}
oldDistance = newDistance;
}
EXPECT_NEAR(double(Real{oldDistance / Meter}), double(Real{jointdef.length / Meter}), 0.1);
}
TEST(DistanceJointConf, GetDistanceJointDefFreeFunction)
{
auto world = World{};
const auto bA = CreateBody(world);
ASSERT_NE(bA, InvalidBodyID);
const auto bB = CreateBody(world);
ASSERT_NE(bB, InvalidBodyID);
auto def = DistanceJointConf{};
def.bodyA = bA;
def.bodyB = bB;
def.collideConnected = false;
def.localAnchorA = Length2(21_m, -2_m);
def.localAnchorB = Length2(13_m, 12_m);
def.length = 5_m;
def.frequency = 67_Hz;
def.dampingRatio = Real(0.8);
const auto joint = CreateJoint(world, def);
const auto got = GetDistanceJointConf(GetJoint(world, joint));
EXPECT_EQ(def.bodyA, got.bodyA);
EXPECT_EQ(def.bodyB, got.bodyB);
EXPECT_EQ(def.localAnchorA, got.localAnchorA);
EXPECT_EQ(def.localAnchorB, got.localAnchorB);
EXPECT_EQ(def.length, got.length);
EXPECT_EQ(def.frequency, got.frequency);
EXPECT_EQ(def.dampingRatio, got.dampingRatio);
}
TEST(DistanceJointConf, GetReferenceAngleThrows)
{
auto world = World{};
const auto bA = CreateBody(world);
ASSERT_NE(bA, InvalidBodyID);
const auto bB = CreateBody(world);
ASSERT_NE(bB, InvalidBodyID);
auto def = DistanceJointConf{};
def.bodyA = bA;
def.bodyB = bB;
def.collideConnected = false;
def.localAnchorA = Length2(21_m, -2_m);
def.localAnchorB = Length2(13_m, 12_m);
def.length = 5_m;
def.frequency = 67_Hz;
def.dampingRatio = Real(0.8);
const auto joint = CreateJoint(world, def);
EXPECT_THROW(GetReferenceAngle(GetJoint(world, joint)), std::invalid_argument);
}
TEST(DistanceJointConf, GetMotorSpeedThrows)
{
const auto joint = Joint{DistanceJointConf{}};
EXPECT_THROW(GetMotorSpeed(joint), std::invalid_argument);
}
TEST(DistanceJointConf, SetMotorSpeedThrows)
{
auto joint = Joint{DistanceJointConf{}};
EXPECT_THROW(SetMotorSpeed(joint, 1_rpm), std::invalid_argument);
}
TEST(DistanceJointConf, SetFrequencyFreeFunction)
{
auto def = DistanceJointConf{};
def.collideConnected = false;
def.localAnchorA = Length2(21_m, -2_m);
def.localAnchorB = Length2(13_m, 12_m);
def.length = 5_m;
def.frequency = 67_Hz;
def.dampingRatio = Real(0.8);
auto joint = Joint(def);
EXPECT_EQ(GetFrequency(joint), 67_Hz);
EXPECT_NO_THROW(SetFrequency(joint, 2_Hz));
EXPECT_EQ(GetFrequency(joint), 2_Hz);
}
TEST(DistanceJointConf, EqualsOperator)
{
EXPECT_TRUE(DistanceJointConf() == DistanceJointConf());
{
auto conf = DistanceJointConf{};
conf.localAnchorA = Length2{1.2_m, -3_m};
EXPECT_TRUE(conf == conf);
EXPECT_FALSE(DistanceJointConf() == conf);
}
{
auto conf = DistanceJointConf{};
conf.localAnchorB = Length2{1.2_m, -3_m};
EXPECT_TRUE(conf == conf);
EXPECT_FALSE(DistanceJointConf() == conf);
}
{
auto conf = DistanceJointConf{};
conf.length = 2.4_m;
EXPECT_TRUE(conf == conf);
EXPECT_FALSE(DistanceJointConf() == conf);
}
{
auto conf = DistanceJointConf{};
conf.bias = 1.5_mps;
EXPECT_TRUE(conf == conf);
EXPECT_FALSE(DistanceJointConf() == conf);
}
// TODO: test remaining fields.
}
TEST(DistanceJointConf, NotEqualsOperator)
{
EXPECT_FALSE(DistanceJointConf() != DistanceJointConf());
{
auto conf = DistanceJointConf{};
conf.dampingRatio = Real(2.3);
EXPECT_FALSE(conf != conf);
EXPECT_TRUE(DistanceJointConf() != conf);
}
// TODO: test remaining fields.
}
{
EXPECT_STREQ(GetName(GetTypeID<DistanceJointConf>()), "d2::DistanceJointConf");
}
playrho::d2::DistanceJointConf::UseDampingRatio
constexpr auto & UseDampingRatio(Real v) noexcept
Uses the given damping ratio.
Definition: DistanceJointConf.hpp:83
playrho::BodyType::Static
@ Static
Static body type.
playrho::RadianPerSquareSecond
constexpr auto RadianPerSquareSecond
Radian per square second unit of angular acceleration.
Definition: Units.hpp:394
playrho::MeterPerSquareSecond
constexpr auto MeterPerSquareSecond
Meter per square second unit of linear acceleration.
Definition: Units.hpp:345
playrho::d2::CreateBody
BodyID CreateBody(World &world, const BodyConf &def)
Creates a rigid body with the given configuration.
Definition: WorldBody.cpp:58
playrho::d2::DistanceJointConf::dampingRatio
Real dampingRatio
Damping ratio.
Definition: DistanceJointConf.hpp:109
playrho::d2::BodyConf::UseType
constexpr BodyConf & UseType(BodyType t) noexcept
Use the given type.
Definition: BodyConf.hpp:166
playrho::Length
PLAYRHO_QUANTITY(boost::units::si::length) Length
Length quantity.
Definition: Units.hpp:158
playrho::d2::DistanceJointConf::localAnchorA
Length2 localAnchorA
Local anchor point relative to body A's origin.
Definition: DistanceJointConf.hpp:91
playrho::d2
Name space for 2-dimensionally related PlayRho names.
Definition: AABB.cpp:34
playrho::d2::JointConf::bodyA
BodyID bodyA
1st attached body.
Definition: JointConf.hpp:36
playrho::InvalidJointID
constexpr auto InvalidJointID
Invalid joint ID value.
Definition: JointID.hpp:33
playrho::GetMagnitude
auto GetMagnitude(T value)
Gets the magnitude of the given value.
Definition: Math.hpp:329
playrho::d2::SetFrequency
constexpr void SetFrequency(DistanceJointConf &object, NonNegative< Frequency > value) noexcept
Free function for setting the frequency value of the given configuration.
Definition: DistanceJointConf.hpp:205
playrho::d2::GetName
const char * GetName(Manifold::Type type) noexcept
Gets a unique name for the given manifold type.
Definition: Manifold.cpp:788
playrho::d2::ShapeBuilder::UseDensity
constexpr ConcreteConf & UseDensity(NonNegative< AreaDensity > value) noexcept
Uses the given density.
Definition: ShapeConf.hpp:111
playrho
Name space for all PlayRho related names.
Definition: AABB.cpp:33
playrho::d2::DistanceJointConf::localAnchorB
Length2 localAnchorB
Local anchor point relative to body B's origin.
Definition: DistanceJointConf.hpp:95
playrho::d2::GetJoint
const Joint & GetJoint(const WorldImpl &world, JointID id)
Gets the identified joint's value.
Definition: WorldImplJoint.cpp:57
playrho::d2::GetLocalAnchorA
Length2 GetLocalAnchorA(const Joint &object)
Get the anchor point on body-A in local coordinates.
Definition: Joint.cpp:62
playrho::d2::DistanceJointConf::UseLength
constexpr auto & UseLength(Length v) noexcept
Uses the given length.
Definition: DistanceJointConf.hpp:69
playrho::d2::World
Definition of an independent and simulatable "world".
Definition: World.hpp:129
playrho::InvalidFixtureID
constexpr auto InvalidFixtureID
Invalid fixture ID value.
Definition: FixtureID.hpp:33
playrho::d2::DistanceJointConf::UseFrequency
constexpr auto & UseFrequency(NonNegative< Frequency > v) noexcept
Uses the given frequency.
Definition: DistanceJointConf.hpp:76
playrho::d2::DistanceJointConf::bias
LinearVelocity bias
Bias. 4-bytes (with 4-byte Real).
Definition: DistanceJointConf.hpp:121
playrho::d2::ShiftOrigin
constexpr bool ShiftOrigin(DistanceJointConf &, Length2) noexcept
Shifts the origin notion of the given configuration.
Definition: DistanceJointConf.hpp:177
playrho::d2::GetBodyB
BodyID GetBodyB(const Contact &contact) noexcept
Gets the body B ID of the given contact.
Definition: Contact.hpp:588
playrho::d2::GetCollideConnected
bool GetCollideConnected(const Joint &object) noexcept
Gets collide connected.
Definition: Joint.hpp:293
playrho::d2::GetDistanceJointConf
DistanceJointConf GetDistanceJointConf(const Joint &joint) noexcept
Gets the definition data for the given joint.
Definition: DistanceJointConf.cpp:68
playrho::d2::GetBodyA
BodyID GetBodyA(const Contact &contact) noexcept
Gets the body A ID of the given contact.
Definition: Contact.hpp:581
playrho::d2::GetReferenceAngle
Angle GetReferenceAngle(const Joint &object)
Gets the reference angle of the joint if it has one.
Definition: Joint.cpp:215
playrho::Meter
constexpr auto Meter
Meter unit of Length.
Definition: Units.hpp:337
playrho::d2::TypeCast
std::add_pointer_t< std::add_const_t< T > > TypeCast(const Shape *value) noexcept
Converts the given shape into its current configuration value.
Definition: Shape.hpp:610
playrho::d2::CreateJoint
JointID CreateJoint(WorldImpl &world, const Joint &def)
Creates a new joint.
Definition: WorldImplJoint.cpp:47
playrho::d2::GetLocalAnchorB
Length2 GetLocalAnchorB(const Joint &object)
Get the anchor point on body-B in local coordinates.
Definition: Joint.cpp:96
playrho::abs
constexpr Fixed< BT, FB > abs(Fixed< BT, FB > arg)
Computes the absolute value.
Definition: FixedMath.hpp:48
playrho::InvalidBodyID
constexpr auto InvalidBodyID
Invalid body ID value.
Definition: BodyID.hpp:33
playrho::AngularMomentum
PLAYRHO_QUANTITY(boost::units::si::angular_momentum) AngularMomentum
Angular momentum quantity.
Definition: Units.hpp:304
playrho::StepConf
Step configuration.
Definition: StepConf.hpp:42
playrho::d2::GetMotorSpeed
AngularVelocity GetMotorSpeed(const Joint &object)
Gets the given joint's motor speed if its type supports that.
Definition: Joint.cpp:254
playrho::d2::GetFrequency
Frequency GetFrequency(const Joint &object)
Gets the frequency of the joint if it has this property.
Definition: Joint.cpp:407
playrho::d2::DistanceJointConf::frequency
NonNegative< Frequency > frequency
Mass-spring-damper frequency.
Definition: DistanceJointConf.hpp:104
playrho::d2::GetAngularReaction
constexpr AngularMomentum GetAngularReaction(const DistanceJointConf &) noexcept
Gets the current angular reaction for the given configuration.
Definition: DistanceJointConf.hpp:170
playrho::d2::CreateFixture
FixtureID CreateFixture(World &world, FixtureConf def, bool resetMassData)
Creates a fixture within the specified world.
Definition: WorldFixture.cpp:48
playrho::Real
float Real
Real-number type.
Definition: Real.hpp:69
playrho::d2::DiskShapeConf::UseRadius
constexpr DiskShapeConf & UseRadius(NonNegative< Length > r) noexcept
Uses the given value as the radius.
Definition: DiskShapeConf.hpp:65
playrho::d2::BodyConf
Configuration for a body.
Definition: BodyConf.hpp:50
playrho::d2::GetLocation
constexpr Length2 GetLocation(const Transformation &value) noexcept
Gets the location information from the given transformation.
Definition: Transformation.hpp:69
playrho::d2::GetLength
constexpr auto GetLength(const DistanceJointConf &object) noexcept
Free function for getting the length value of the given configuration.
Definition: DistanceJointConf.hpp:219
playrho::d2::GetDampingRatio
Real GetDampingRatio(const Joint &object)
Gets the given joint's damping ratio property if it has one.
Definition: Joint.cpp:389
playrho::d2::DistanceJointConf
Distance joint definition.
Definition: DistanceJointConf.hpp:52
playrho::d2::SetMotorSpeed
void SetMotorSpeed(Joint &object, AngularVelocity value)
Sets the given joint's motor speed if its type supports that.
Definition: Joint.cpp:269
playrho::Vector
Vector.
Definition: Vector.hpp:49
playrho::d2::GetType
TypeID GetType(const Shape &shape) noexcept
Gets the type info of the use of the given shape.
Definition: Shape.hpp:329
playrho::d2::GetLinearReaction
constexpr Momentum2 GetLinearReaction(const DistanceJointConf &object) noexcept
Gets the current linear reaction for the given configuration.
Definition: DistanceJointConf.hpp:163
playrho::d2::Acceleration
2-D acceleration related data structure.
Definition: Acceleration.hpp:33
playrho::d2::Joint
A joint-like constraint on one or more bodies.
Definition: Joint.hpp:144
playrho::d2::Shape
Shape.
Definition: Shape.hpp:183
playrho::d2::DistanceJointConf::length
Length length
Natural length between the anchor points.
Definition: DistanceJointConf.hpp:99
playrho::Length2
Vector2< Length > Length2
2-element vector of Length quantities.
Definition: Vector2.hpp:43
playrho::d2::SetAccelerations
void SetAccelerations(World &world, Acceleration acceleration) noexcept
Sets the accelerations of all the world's bodies to the given value.
Definition: WorldBody.cpp:558
playrho::d2::Step
StepStats Step(WorldImpl &world, const StepConf &conf)
Steps the given world the specified amount.
Definition: WorldImplMisc.cpp:85
playrho::d2::JointConf::collideConnected
bool collideConnected
Collide connected.
Definition: JointConf.hpp:43
playrho::d2::DiskShapeConf
Disk shape configuration.
Definition: DiskShapeConf.hpp:42