/*
* Copyright (C) 2015 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "gazebo/test/ServerFixture.hh"
#include "test/util.hh"
#include "gazebo/physics/PhysicsTypes.hh"
#include "gazebo/physics/World.hh"
#include "gazebo/physics/WorldState.hh"
using namespace gazebo;
class WorldStateTest : public ServerFixture { };
//////////////////////////////////////////////////
TEST_F(WorldStateTest, SDFConstructor)
{
// Create the state sdf
std::ostringstream sdfStr;
sdfStr << ""
<< ""
<< ""
<< ""
<< " 1 1 1 0 0 0"
<< " "
<< " 0.1 0.2 0.3 0.4 0.5 0.6"
<< " "
<< ""
<< ""
<< " 2 1 1 0 0 0"
<< " "
<< " "
<< ""
<< ""
<< " 10 20 30 0 0 0"
<< ""
<< ""
<< " 1 2 3 0 0 0"
<< ""
<< ""
<< ""
<< "";
sdf::SDFPtr worldSDF(new sdf::SDF);
worldSDF->SetFromString(sdfStr.str());
EXPECT_TRUE(worldSDF->Root()->HasElement("world"));
auto worldElem = worldSDF->Root()->GetElement("world");
EXPECT_TRUE(worldElem->HasElement("state"));
// Create the world state
physics::WorldState worldState(worldElem->GetElement("state"));
// Check world state against values from the sdf string
EXPECT_EQ(worldState.GetModelStateCount(), 2u);
EXPECT_EQ(worldState.LightStateCount(), 2u);
auto modelStates = worldState.GetModelStates();
EXPECT_EQ(modelStates.size(), 2u);
EXPECT_EQ(modelStates["ground_plane"].GetPose(),
ignition::math::Pose3d(1, 1, 1, 0, 0, 0));
EXPECT_EQ(modelStates["model_1"].GetPose(),
ignition::math::Pose3d(2, 1, 1, 0, 0, 0));
EXPECT_EQ(modelStates["fake_model"].GetPose(),
ignition::math::Pose3d(0, 0, 0, 0, 0, 0));
auto lightStates = worldState.LightStates();
EXPECT_EQ(lightStates.size(), 2u);
EXPECT_EQ(lightStates["sun"].Pose(),
ignition::math::Pose3d(10, 20, 30, 0, 0, 0));
EXPECT_EQ(lightStates["light_1"].Pose(),
ignition::math::Pose3d(1, 2, 3, 0, 0, 0));
EXPECT_EQ(lightStates["fake_light"].Pose(),
ignition::math::Pose3d(0, 0, 0, 0, 0, 0));
}
//////////////////////////////////////////////////
TEST_F(WorldStateTest, WorldConstructor)
{
// Load a world
this->Load("worlds/empty.world", true);
physics::WorldPtr world = physics::get_world("default");
// Create the world state
physics::WorldState worldState(world);
// Check world state
EXPECT_EQ(worldState.GetModelStateCount(), 1u);
EXPECT_EQ(worldState.LightStateCount(), 1u);
auto modelStates = worldState.GetModelStates();
EXPECT_EQ(modelStates.size(), 1u);
EXPECT_EQ(modelStates["ground_plane"].GetPose(),
ignition::math::Pose3d(0, 0, 0, 0, 0, 0));
auto lightStates = worldState.LightStates();
EXPECT_EQ(lightStates.size(), 1u);
EXPECT_EQ(lightStates["sun"].Pose(),
ignition::math::Pose3d(0, 0, 10, 0, 0, 0));
}
//////////////////////////////////////////////////
TEST_F(WorldStateTest, FillSDF)
{
// Load a world
this->Load("worlds/empty.world", true);
physics::WorldPtr world = physics::get_world("default");
// Create the world state
physics::WorldState worldState(world);
// Fill SDF
sdf::ElementPtr filledSDF(new sdf::Element);
sdf::initFile("state.sdf", filledSDF);
worldState.FillSDF(filledSDF);
EXPECT_TRUE(filledSDF->HasAttribute("world_name"));
EXPECT_EQ(filledSDF->Get("world_name"),
"default");
EXPECT_TRUE(filledSDF->HasElement("model"));
EXPECT_EQ(filledSDF->GetElement("model")->Get("name"),
"ground_plane");
EXPECT_TRUE(filledSDF->HasElement("light"));
EXPECT_EQ(filledSDF->GetElement("light")->Get("name"),
"sun");
}
//////////////////////////////////////////////////
TEST_F(WorldStateTest, OperatorsNoInsertionsDeletions)
{
// Load a world
this->Load("worlds/shapes.world", true);
physics::WorldPtr world = physics::get_world("default");
// Create a world state
physics::WorldState worldState0(world);
// Create the "next state"
// Only checking a case without insertions or deletions
std::ostringstream sdfStr;
sdfStr << ""
<< ""
<< ""
<< ""
<< " 0 0 0 0 0 0"
<< ""
<< ""
<< " 0 0 0.5 0 0 0"
<< ""
<< ""
<< " 2 4 6 0 0 0"
<< ""
<< ""
<< " 3 6 9 0 1.5707 0"
<< ""
<< ""
<< " 10 20 30 0 0 0"
<< ""
<< ""
<< ""
<< "";
sdf::SDFPtr worldSDF(new sdf::SDF);
worldSDF->SetFromString(sdfStr.str());
EXPECT_TRUE(worldSDF->Root()->HasElement("world"));
auto worldElem = worldSDF->Root()->GetElement("world");
EXPECT_TRUE(worldElem->HasElement("state"));
physics::WorldState worldState1(worldElem->GetElement("state"));
// Check that the 2 states are of the same world, with same entities
EXPECT_EQ(worldState0.GetName(), worldState1.GetName());
EXPECT_EQ(worldState0.GetModelStateCount(), worldState1.GetModelStateCount());
EXPECT_EQ(worldState0.LightStateCount(), worldState1.LightStateCount());
// Check subtraction
auto worldState2 = worldState1 - worldState0;
EXPECT_FALSE(worldState2.IsZero());
// Check there were no deletions or insertions
auto deletions = worldState2.Deletions();
EXPECT_EQ(deletions.size(), 0u);
auto insertions = worldState2.Insertions();
EXPECT_EQ(insertions.size(), 0u);
// Check that entities which are the same in both states were removed
EXPECT_EQ(worldState2.GetModelStateCount(), 2u);
EXPECT_EQ(worldState2.LightStateCount(), 1u);
auto modelStates = worldState2.GetModelStates();
EXPECT_EQ(modelStates.size(), 2u);
EXPECT_EQ(modelStates["sphere"].GetPose(),
ignition::math::Pose3d(2, 2.5, 5.5, 0, 0, 0));
EXPECT_EQ(modelStates["cylinder"].GetPose(),
ignition::math::Pose3d(3, 7.5, 8.5, 0, 0, 0));
EXPECT_EQ(modelStates["fake_model"].GetPose(),
ignition::math::Pose3d(0, 0, 0, 0, 0, 0));
auto lightStates = worldState2.LightStates();
EXPECT_EQ(lightStates.size(), 1u);
EXPECT_EQ(lightStates["sun"].Pose(),
ignition::math::Pose3d(10, 20, 20, 0, 0, 0));
EXPECT_EQ(lightStates["fake_light"].Pose(),
ignition::math::Pose3d(0, 0, 0, 0, 0, 0));
// Check addition
worldState2 = worldState1 + worldState0;
EXPECT_FALSE(worldState2.IsZero());
// Check there were no deletions or insertions
deletions = worldState2.Deletions();
EXPECT_EQ(deletions.size(), 0u);
insertions = worldState2.Insertions();
EXPECT_EQ(insertions.size(), 0u);
// Check that all entities are present
EXPECT_EQ(worldState2.GetModelStateCount(), 4u);
EXPECT_EQ(worldState2.LightStateCount(), 1u);
modelStates = worldState2.GetModelStates();
EXPECT_EQ(modelStates.size(), 4u);
EXPECT_EQ(modelStates["ground_plane"].GetPose(),
ignition::math::Pose3d(0, 0, 0, 0, 0, 0));
EXPECT_EQ(modelStates["box"].GetPose(),
ignition::math::Pose3d(0, 0, 1, 0, 0, 0));
EXPECT_EQ(modelStates["sphere"].GetPose(),
ignition::math::Pose3d(2, 5.5, 6.5, 0, 0, 0));
EXPECT_EQ(modelStates["cylinder"].GetPose().pos,
ignition::math::Vector3d(3, 4.5, 9.5));
lightStates = worldState2.LightStates();
EXPECT_EQ(lightStates.size(), 1u);
EXPECT_EQ(lightStates["sun"].Pose(),
ignition::math::Pose3d(10, 20, 40, 0, 0, 0));
// Copy by assignment
worldState1 = worldState0;
// Check states are equal
EXPECT_EQ(worldState0.GetName(), worldState1.GetName());
EXPECT_TRUE((worldState0 - worldState1).IsZero());
}
//////////////////////////////////////////////////
TEST_F(WorldStateTest, InsertionOfMeshModel)
{
// Load a world
this->Load("worlds/empty.world", true);
physics::WorldPtr world = physics::get_world("default");
// Create a world state
physics::WorldState worldState0(world);
// Insert a model with a scaled mesh
msgs::Factory msg;
std::ostringstream newModelStr;
newModelStr << ""
<< ""
<< "2 2 2 0.1 0.1 0.1"
<< ""
<< " "
<< " "
<< " "
<< " " << std::string(PROJECT_SOURCE_PATH)
<< "/test/data/box_offset.dae"
<< " 0.2 0.3 0.4"
<< " "
<< " "
<< " "
<< " "
<< " "
<< " "
<< " " << std::string(PROJECT_SOURCE_PATH)
<< "/test/data/box_offset.dae"
<< " 0.5 0.6 0.7"
<< " "
<< " "
<< " "
<< ""
<< ""
<< "";
msg.set_sdf(newModelStr.str());
this->factoryPub->Publish(msg);
this->WaitUntilEntitySpawn("test_model", 100, 100);
ASSERT_TRUE(world->GetModel("test_model") != nullptr);
// Create a new world state
physics::WorldState worldState1(world);
// Check that the 2nd state has more entities
EXPECT_EQ(worldState0.GetModelStateCount(), 1u);
EXPECT_EQ(worldState1.GetModelStateCount(), 2u);
// Difference between states to generate insertion
auto worldState2 = worldState1 - worldState0;
EXPECT_FALSE(worldState2.IsZero());
// Check there were no deletions
auto deletions = worldState2.Deletions();
EXPECT_EQ(deletions.size(), 0u);
// Check the old entity disappears and the new entity appears as insertion
EXPECT_EQ(worldState2.GetModelStateCount(), 0u);
auto insertions = worldState2.Insertions();
EXPECT_EQ(insertions.size(), 1u);
// Check that inserted entity's scale wasn't changed
auto inserted = insertions[0];
EXPECT_TRUE(inserted.find("0.2 0.3 0.4") != std::string::npos);
EXPECT_TRUE(inserted.find("0.5 0.6 0.7") != std::string::npos);
}
//////////////////////////////////////////////////
TEST_F(WorldStateTest, Times)
{
// Load a world
this->Load("worlds/empty.world", true);
physics::WorldPtr world = physics::get_world("default");
// Create the world state
physics::WorldState worldState(world);
// Check default times
EXPECT_EQ(worldState.GetSimTime(), common::Time(0));
EXPECT_GT(worldState.GetWallTime(), common::Time(0));
EXPECT_EQ(worldState.GetRealTime(), common::Time(0));
// Set times
worldState.SetSimTime(common::Time(1));
worldState.SetWallTime(common::Time(2));
worldState.SetRealTime(common::Time(3));
// Check times
EXPECT_EQ(worldState.GetSimTime(), common::Time(1));
EXPECT_EQ(worldState.GetWallTime(), common::Time(2));
EXPECT_EQ(worldState.GetRealTime(), common::Time(3));
}