679 lines
18 KiB
C++
679 lines
18 KiB
C++
/*
|
|
* Copyright (C) 2012 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.
|
|
*
|
|
*/
|
|
/* Desc: A world state
|
|
* Author: Nate Koenig
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
// Ensure that Winsock2.h is included before Windows.h, which can get
|
|
// pulled in by anybody (e.g., Boost).
|
|
#include <Winsock2.h>
|
|
#endif
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
#include "gazebo/common/Console.hh"
|
|
#include "gazebo/common/Exception.hh"
|
|
#include "gazebo/physics/World.hh"
|
|
#include "gazebo/physics/Model.hh"
|
|
#include "gazebo/physics/Light.hh"
|
|
#include "gazebo/physics/WorldState.hh"
|
|
|
|
using namespace gazebo;
|
|
using namespace physics;
|
|
|
|
// TODO added here for ABI compatibility
|
|
// move to class when merging forward
|
|
static std::string worldStateFilter;
|
|
|
|
/////////////////////////////////////////////////
|
|
WorldState::WorldState()
|
|
: State()
|
|
{
|
|
worldStateFilter = "";
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
WorldState::WorldState(const WorldPtr _world)
|
|
: State(_world->GetName(), _world->GetRealTime(), _world->GetSimTime(),
|
|
_world->GetIterations())
|
|
{
|
|
this->world = _world;
|
|
|
|
// Add a state for all the models
|
|
Model_V models = _world->GetModels();
|
|
for (Model_V::const_iterator iter = models.begin();
|
|
iter != models.end(); ++iter)
|
|
{
|
|
this->modelStates.insert(std::make_pair((*iter)->GetName(),
|
|
ModelState(*iter, this->realTime, this->simTime, this->iterations)));
|
|
}
|
|
|
|
// Add states for all the lights
|
|
for (const auto &light : _world->Lights())
|
|
{
|
|
this->lightStates.insert(std::make_pair(light->GetName(),
|
|
LightState(light, this->realTime, this->simTime, this->iterations)));
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
WorldState::WorldState(const sdf::ElementPtr _sdf)
|
|
: State()
|
|
{
|
|
this->Load(_sdf);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
WorldState::~WorldState()
|
|
{
|
|
this->world.reset();
|
|
this->modelStates.clear();
|
|
this->lightStates.clear();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::LoadWithFilter(const WorldPtr _world,
|
|
const std::string &_filter)
|
|
{
|
|
worldStateFilter = _filter;
|
|
this->Load(_world);
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::Load(const WorldPtr _world)
|
|
{
|
|
this->world = _world;
|
|
this->name = _world->GetName();
|
|
this->wallTime = common::Time::GetWallTime();
|
|
this->simTime = _world->GetSimTime();
|
|
this->realTime = _world->GetRealTime();
|
|
this->iterations = _world->GetIterations();
|
|
this->insertions.clear();
|
|
this->deletions.clear();
|
|
|
|
std::string filter = worldStateFilter;
|
|
std::list<std::string> mainParts, parts;
|
|
boost::split(mainParts, filter, boost::is_any_of("/"));
|
|
|
|
// Create the model filter
|
|
if (!mainParts.empty())
|
|
{
|
|
boost::split(parts, mainParts.front(), boost::is_any_of("."));
|
|
if (parts.empty() && !mainParts.front().empty())
|
|
parts.push_back(mainParts.front());
|
|
}
|
|
std::list<std::string>::iterator partIter = parts.begin();
|
|
|
|
// Add a state for all the models that match the filter
|
|
Model_V models = _world->GetModels();
|
|
for (Model_V::const_iterator iter = models.begin();
|
|
iter != models.end(); ++iter)
|
|
{
|
|
bool add = true;
|
|
|
|
// The first element in the filter must be a model name or a star.
|
|
if (partIter != parts.end() && !parts.empty() &&
|
|
!(*partIter).empty() && (*partIter) != "*")
|
|
{
|
|
std::string regexStr = *partIter;
|
|
boost::replace_all(regexStr, "*", ".*");
|
|
boost::regex regex(regexStr);
|
|
add = boost::regex_match((*iter)->GetName(), regex);
|
|
}
|
|
|
|
if (add)
|
|
{
|
|
this->modelStates[(*iter)->GetName()].Load(*iter, this->realTime,
|
|
this->simTime, this->iterations);
|
|
}
|
|
}
|
|
|
|
// Remove models that no longer exist. We determine this by check the time
|
|
// stamp on each model.
|
|
for (ModelState_M::iterator iter = this->modelStates.begin();
|
|
iter != this->modelStates.end();)
|
|
{
|
|
if (iter->second.GetRealTime() != this->realTime)
|
|
this->modelStates.erase(iter++);
|
|
else
|
|
++iter;
|
|
}
|
|
|
|
// Add states for all the lights
|
|
this->lightStates.clear();
|
|
Light_V lights = _world->Lights();
|
|
for (const auto &light : lights)
|
|
{
|
|
this->lightStates[light->GetName()].Load(light, this->realTime,
|
|
this->simTime, this->iterations);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::Load(const sdf::ElementPtr _elem)
|
|
{
|
|
// Copy the name and time information
|
|
this->name = _elem->Get<std::string>("world_name");
|
|
this->simTime = _elem->Get<common::Time>("sim_time");
|
|
this->wallTime = _elem->Get<common::Time>("wall_time");
|
|
this->realTime = _elem->Get<common::Time>("real_time");
|
|
this->iterations = _elem->Get<uint64_t>("iterations");
|
|
|
|
// Add the model states
|
|
this->modelStates.clear();
|
|
if (_elem->HasElement("model"))
|
|
{
|
|
sdf::ElementPtr childElem = _elem->GetElement("model");
|
|
|
|
while (childElem)
|
|
{
|
|
std::string modelName = childElem->Get<std::string>("name");
|
|
this->modelStates.insert(std::make_pair(
|
|
modelName, ModelState(childElem)));
|
|
this->modelStates[modelName].SetSimTime(this->simTime);
|
|
this->modelStates[modelName].SetWallTime(this->wallTime);
|
|
this->modelStates[modelName].SetRealTime(this->realTime);
|
|
this->modelStates[modelName].SetIterations(this->iterations);
|
|
childElem = childElem->GetNextElement("model");
|
|
}
|
|
}
|
|
|
|
// Add the light states
|
|
this->lightStates.clear();
|
|
if (_elem->HasElement("light"))
|
|
{
|
|
sdf::ElementPtr childElem = _elem->GetElement("light");
|
|
|
|
while (childElem)
|
|
{
|
|
LightState lightState(childElem);
|
|
lightState.SetSimTime(this->simTime);
|
|
lightState.SetWallTime(this->wallTime);
|
|
lightState.SetRealTime(this->realTime);
|
|
lightState.SetIterations(this->iterations);
|
|
|
|
std::string lightName = childElem->Get<std::string>("name");
|
|
this->lightStates.insert(std::make_pair(
|
|
lightName, lightState));
|
|
|
|
childElem = childElem->GetNextElement("light");
|
|
}
|
|
}
|
|
|
|
// Add insertions
|
|
this->insertions.clear();
|
|
if (_elem->HasElement("insertions"))
|
|
{
|
|
sdf::ElementPtr insertionsElem = _elem->GetElement("insertions");
|
|
|
|
// Models
|
|
if (insertionsElem->HasElement("model"))
|
|
{
|
|
sdf::ElementPtr modelElem = insertionsElem->GetElement("model");
|
|
|
|
while (modelElem)
|
|
{
|
|
this->insertions.push_back(modelElem->ToString(""));
|
|
modelElem = modelElem->GetNextElement("model");
|
|
}
|
|
}
|
|
|
|
// Lights
|
|
if (insertionsElem->HasElement("light"))
|
|
{
|
|
sdf::ElementPtr lightElem = insertionsElem->GetElement("light");
|
|
|
|
while (lightElem)
|
|
{
|
|
this->insertions.push_back(lightElem->ToString(""));
|
|
lightElem = lightElem->GetNextElement("light");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add deletions
|
|
this->deletions.clear();
|
|
if (_elem->HasElement("deletions"))
|
|
{
|
|
sdf::ElementPtr deletionsElem = _elem->GetElement("deletions");
|
|
|
|
if (deletionsElem->HasElement("name"))
|
|
{
|
|
sdf::ElementPtr nameElem = deletionsElem->GetElement("name");
|
|
|
|
while (nameElem)
|
|
{
|
|
this->deletions.push_back(nameElem->Get<std::string>());
|
|
nameElem = nameElem->GetNextElement("name");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::SetWorld(const WorldPtr _world)
|
|
{
|
|
this->world = _world;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
const ModelState_M &WorldState::GetModelStates() const
|
|
{
|
|
return this->modelStates;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
const LightState_M &WorldState::LightStates() const
|
|
{
|
|
return this->lightStates;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
ModelState_M WorldState::GetModelStates(const boost::regex &_regex) const
|
|
{
|
|
ModelState_M result;
|
|
|
|
// Search for matching link names
|
|
for (ModelState_M::const_iterator iter = this->modelStates.begin();
|
|
iter != this->modelStates.end(); ++iter)
|
|
{
|
|
if (boost::regex_match(iter->first, _regex))
|
|
result.insert(std::make_pair(iter->first, iter->second));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
unsigned int WorldState::GetModelStateCount() const
|
|
{
|
|
return this->modelStates.size();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
unsigned int WorldState::LightStateCount() const
|
|
{
|
|
return this->lightStates.size();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
ModelState WorldState::GetModelState(const std::string &_modelName) const
|
|
{
|
|
// Search for the model name
|
|
ModelState_M::const_iterator iter = this->modelStates.find(_modelName);
|
|
if (iter != this->modelStates.end())
|
|
return iter->second;
|
|
|
|
// Error if the model name doesn't exist.
|
|
gzerr << "Invalid model name[" + _modelName + "]." << std::endl;
|
|
return ModelState();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
LightState WorldState::GetLightState(const std::string &_lightName) const
|
|
{
|
|
// Search for the light name
|
|
auto iter = this->lightStates.find(_lightName);
|
|
if (iter != this->lightStates.end())
|
|
return iter->second;
|
|
|
|
// Error if the light name doesn't exist.
|
|
gzerr << "Invalid light name[" + _lightName + "]." << std::endl;
|
|
return LightState();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
bool WorldState::HasModelState(const std::string &_modelName) const
|
|
{
|
|
return this->modelStates.find(_modelName) != this->modelStates.end();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
bool WorldState::HasLightState(const std::string &_lightName) const
|
|
{
|
|
return this->lightStates.find(_lightName) != this->lightStates.end();
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
const std::vector<std::string> &WorldState::Insertions() const
|
|
{
|
|
return this->insertions;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::SetInsertions(const std::vector<std::string> &_insertions)
|
|
{
|
|
static sdf::SDFPtr rootSDF = nullptr;
|
|
if (rootSDF == nullptr)
|
|
{
|
|
rootSDF.reset(new sdf::SDF);
|
|
sdf::initFile("root.sdf", rootSDF);
|
|
}
|
|
|
|
// Unwrap insertions from <sdf>
|
|
for (const auto &insertion : _insertions)
|
|
{
|
|
rootSDF->Root()->ClearElements();
|
|
// <sdf>
|
|
if (sdf::readString(insertion, rootSDF))
|
|
{
|
|
// <model>
|
|
if (rootSDF->Root()->HasElement("model"))
|
|
{
|
|
this->insertions.push_back(
|
|
rootSDF->Root()->GetElement("model")->ToString(""));
|
|
}
|
|
// <light>
|
|
else if (rootSDF->Root()->HasElement("light"))
|
|
{
|
|
this->insertions.push_back(
|
|
rootSDF->Root()->GetElement("light")->ToString(""));
|
|
}
|
|
// <actor>
|
|
else if (rootSDF->Root()->HasElement("actor"))
|
|
{
|
|
this->insertions.push_back(
|
|
rootSDF->Root()->GetElement("actor")->ToString(""));
|
|
}
|
|
else
|
|
{
|
|
gzwarn << "Unsupported insertion [" << insertion << "]" << std::endl;
|
|
continue;
|
|
}
|
|
}
|
|
// Otherwise copy as-is without validating
|
|
else
|
|
{
|
|
this->insertions.push_back(insertion);
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
const std::vector<std::string> &WorldState::Deletions() const
|
|
{
|
|
return this->deletions;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::SetDeletions(const std::vector<std::string> &_deletions)
|
|
{
|
|
this->deletions = _deletions;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
bool WorldState::IsZero() const
|
|
{
|
|
bool result = this->insertions.size() == 0 && this->deletions.size() == 0;
|
|
|
|
// Model
|
|
for (ModelState_M::const_iterator iter = this->modelStates.begin();
|
|
iter != this->modelStates.end() && result; ++iter)
|
|
{
|
|
result = result && iter->second.IsZero();
|
|
}
|
|
|
|
// Light
|
|
for (const auto &light : this->lightStates)
|
|
{
|
|
result = result && light.second.IsZero();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
WorldState &WorldState::operator=(const WorldState &_state)
|
|
{
|
|
State::operator=(_state);
|
|
|
|
// Clear the states
|
|
this->modelStates.clear();
|
|
this->lightStates.clear();
|
|
|
|
this->insertions.clear();
|
|
this->deletions.clear();
|
|
|
|
// Copy the model states.
|
|
for (ModelState_M::const_iterator iter =
|
|
_state.modelStates.begin(); iter != _state.modelStates.end(); ++iter)
|
|
{
|
|
this->modelStates.insert(std::make_pair(iter->first,
|
|
ModelState(iter->second)));
|
|
}
|
|
|
|
// Copy the light states.
|
|
for (const auto &light : _state.lightStates)
|
|
{
|
|
this->lightStates.insert(std::make_pair(light.first,
|
|
LightState(light.second)));
|
|
}
|
|
|
|
// Copy the insertions
|
|
std::copy(_state.insertions.begin(),
|
|
_state.insertions.end(), this->insertions.begin());
|
|
|
|
// Copy the deletions
|
|
std::copy(_state.deletions.begin(),
|
|
_state.deletions.end(), this->deletions.begin());
|
|
|
|
return *this;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
WorldState WorldState::operator-(const WorldState &_state) const
|
|
{
|
|
WorldState result;
|
|
|
|
result.name = this->name;
|
|
result.simTime = this->simTime;
|
|
result.realTime = this->realTime;
|
|
result.wallTime = this->wallTime;
|
|
result.iterations = this->iterations;
|
|
|
|
// Subtract the model states.
|
|
for (ModelState_M::const_iterator iter =
|
|
_state.modelStates.begin(); iter != _state.modelStates.end(); ++iter)
|
|
{
|
|
if (this->HasModelState(iter->second.GetName()))
|
|
{
|
|
ModelState state = this->GetModelState(iter->second.GetName()) -
|
|
iter->second;
|
|
|
|
if (!state.IsZero())
|
|
{
|
|
result.modelStates.insert(std::make_pair(state.GetName(), state));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.deletions.push_back(iter->second.GetName());
|
|
}
|
|
}
|
|
|
|
// Subtract the light states.
|
|
for (const auto &light : _state.lightStates)
|
|
{
|
|
if (this->HasLightState(light.second.GetName()))
|
|
{
|
|
LightState state = this->GetLightState(light.second.GetName()) -
|
|
light.second;
|
|
|
|
if (!state.IsZero())
|
|
{
|
|
result.lightStates.insert(std::make_pair(state.GetName(), state));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.deletions.push_back(light.second.GetName());
|
|
}
|
|
}
|
|
|
|
// Add in the new model states
|
|
for (const auto &modelState : this->modelStates)
|
|
{
|
|
if (!_state.HasModelState(modelState.second.GetName()) && this->world)
|
|
{
|
|
ModelPtr model = this->world->GetModel(modelState.second.GetName());
|
|
if (model)
|
|
result.insertions.push_back(model->UnscaledSDF()->ToString(""));
|
|
}
|
|
}
|
|
|
|
// Add in the new light states
|
|
for (const auto &light : this->lightStates)
|
|
{
|
|
if (!_state.HasLightState(light.second.GetName()) && this->world)
|
|
{
|
|
LightPtr lightPtr = this->world->Light(light.second.GetName());
|
|
result.insertions.push_back(lightPtr->GetSDF()->ToString(""));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
WorldState WorldState::operator+(const WorldState &_state) const
|
|
{
|
|
WorldState result;
|
|
|
|
result.name = this->name;
|
|
result.simTime = this->simTime;
|
|
result.realTime = this->realTime;
|
|
result.wallTime = this->wallTime;
|
|
result.iterations = this->iterations;
|
|
|
|
// Add the model states.
|
|
for (ModelState_M::const_iterator iter =
|
|
_state.modelStates.begin(); iter != _state.modelStates.end(); ++iter)
|
|
{
|
|
ModelState state = this->GetModelState(iter->second.GetName()) +
|
|
iter->second;
|
|
result.modelStates.insert(std::make_pair(state.GetName(), state));
|
|
}
|
|
|
|
// Add the light states.
|
|
for (const auto &light : _state.lightStates)
|
|
{
|
|
LightState state = this->GetLightState(light.second.GetName()) +
|
|
light.second;
|
|
result.lightStates.insert(std::make_pair(state.GetName(), state));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::FillSDF(sdf::ElementPtr _sdf)
|
|
{
|
|
_sdf->ClearElements();
|
|
|
|
_sdf->GetAttribute("world_name")->Set(this->name);
|
|
_sdf->GetElement("sim_time")->Set(this->simTime);
|
|
_sdf->GetElement("real_time")->Set(this->realTime);
|
|
_sdf->GetElement("wall_time")->Set(this->wallTime);
|
|
_sdf->GetElement("iterations")->Set(this->iterations);
|
|
|
|
// Models
|
|
for (ModelState_M::iterator iter =
|
|
this->modelStates.begin(); iter != this->modelStates.end(); ++iter)
|
|
{
|
|
sdf::ElementPtr elem = _sdf->AddElement("model");
|
|
iter->second.FillSDF(elem);
|
|
}
|
|
|
|
// Lights
|
|
for (auto &light : this->lightStates)
|
|
{
|
|
sdf::ElementPtr elem = _sdf->AddElement("light");
|
|
light.second.FillSDF(elem);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::SetWallTime(const common::Time &_time)
|
|
{
|
|
State::SetWallTime(_time);
|
|
|
|
// Models
|
|
for (ModelState_M::iterator iter = this->modelStates.begin();
|
|
iter != this->modelStates.end(); ++iter)
|
|
{
|
|
iter->second.SetWallTime(_time);
|
|
}
|
|
|
|
// Lights
|
|
for (auto &light : this->lightStates)
|
|
{
|
|
light.second.SetWallTime(_time);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::SetRealTime(const common::Time &_time)
|
|
{
|
|
State::SetRealTime(_time);
|
|
|
|
// Models
|
|
for (ModelState_M::iterator iter = this->modelStates.begin();
|
|
iter != this->modelStates.end(); ++iter)
|
|
{
|
|
iter->second.SetRealTime(_time);
|
|
}
|
|
|
|
// Lights
|
|
for (auto &light : this->lightStates)
|
|
{
|
|
light.second.SetRealTime(_time);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::SetSimTime(const common::Time &_time)
|
|
{
|
|
State::SetSimTime(_time);
|
|
|
|
// Models
|
|
for (ModelState_M::iterator iter = this->modelStates.begin();
|
|
iter != this->modelStates.end(); ++iter)
|
|
{
|
|
iter->second.SetSimTime(_time);
|
|
}
|
|
|
|
// Lights
|
|
for (auto &light : this->lightStates)
|
|
{
|
|
light.second.SetSimTime(_time);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
void WorldState::SetIterations(const uint64_t _iterations)
|
|
{
|
|
State::SetIterations(_iterations);
|
|
|
|
// Models
|
|
for (auto &modelState : this->modelStates)
|
|
modelState.second.SetIterations(_iterations);
|
|
|
|
// Lights
|
|
for (auto &lightState : this->lightStates)
|
|
lightState.second.SetIterations(_iterations);
|
|
}
|