pxmlw6n2f/Gazebo_Distributed_MPI/gazebo/physics/World.cc

3337 lines
101 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.
*
*/
#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 <mpi.h> // Added by zhangshuai 2019.04.23 for MPI
#include <time.h>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <sdf/sdf.hh>
#include <deque>
#include <list>
#include <set>
#include <string>
#include <vector>
#include <boost/algorithm/string/predicate.hpp>
#include <ignition/math/Rand.hh>
#include "gazebo/math/Rand.hh"
#include "gazebo/transport/Node.hh"
#include "gazebo/transport/TransportIface.hh"
#include "gazebo/transport/Publisher.hh"
#include "gazebo/transport/Subscriber.hh"
#include "gazebo/util/LogPlay.hh"
#include "gazebo/common/ModelDatabase.hh"
#include "gazebo/common/CommonIface.hh"
#include "gazebo/common/Events.hh"
#include "gazebo/common/Exception.hh"
#include "gazebo/common/Console.hh"
#include "gazebo/common/Plugin.hh"
#include "gazebo/common/Time.hh"
#include "gazebo/math/Vector3.hh"
#include "gazebo/msgs/msgs.hh"
#include "gazebo/util/OpenAL.hh"
#include "gazebo/util/Diagnostics.hh"
#include "gazebo/util/LogRecord.hh"
#include "gazebo/physics/Road.hh"
#include "gazebo/physics/RayShape.hh"
#include "gazebo/physics/Link.hh"
#include "gazebo/physics/PhysicsEngine.hh"
#include "gazebo/physics/PhysicsFactory.hh"
#include "gazebo/physics/PresetManager.hh"
#include "gazebo/physics/UserCmdManager.hh"
#include "gazebo/physics/Model.hh"
#include "gazebo/physics/Light.hh"
#include "gazebo/physics/Actor.hh"
#include "gazebo/physics/WorldPrivate.hh"
#include "gazebo/physics/World.hh"
#include "gazebo/common/SphericalCoordinates.hh"
#include "gazebo/physics/Collision.hh"
#include "gazebo/physics/ContactManager.hh"
#include "gazebo/physics/Population.hh"
#include "gazebo/countTime.hh" // Added by zhangshuai 2019.04.03 for count time
using namespace gazebo;
using namespace physics;
/// \brief Flag used to say if/when to clear all models.
/// This will be replaced with a class member variable in Gazebo 3.0
bool g_clearModels;
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
double before_worldUpdateBeginTime = 0;
double worldUpdateBeginTime = 0;
double modelUpdateFuncTime = 0;
double updateCollisionTime = 0;
double loggingTime = 0;
double before_updatePhysicsTime = 0;
double updatePhysicsTime = 0;
double before_tcpTime = 0;
double tcpTime = 0;
double after_tcpTime = 0;
double wholeUpdataTime = 0;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
class ModelUpdate_TBB
{
public:
ModelUpdate_TBB(Model_V *_models) : models(_models) {}
public:
void operator()(const tbb::blocked_range<size_t> &_r) const
{
for (size_t i = _r.begin(); i != _r.end(); i++)
{
(*models)[i]->Update();
}
}
private:
Model_V *models;
};
//////////////////////////////////////////////////
World::World(const std::string &_name)
: dataPtr(new WorldPrivate)
{
g_clearModels = false;
this->dataPtr->sdf.reset(new sdf::Element);
sdf::initFile("world.sdf", this->dataPtr->sdf);
// Keep this in the constructor for performance.
// sdf::initFile causes disk access.
this->dataPtr->factorySDF.reset(new sdf::SDF);
sdf::initFile("root.sdf", this->dataPtr->factorySDF);
this->dataPtr->logPlayStateSDF.reset(new sdf::Element);
sdf::initFile("state.sdf", this->dataPtr->logPlayStateSDF);
this->dataPtr->receiveMutex = new boost::recursive_mutex();
this->dataPtr->loadModelMutex = new boost::mutex();
this->dataPtr->initialized = false;
this->dataPtr->loaded = false;
this->dataPtr->stepInc = 0;
this->dataPtr->pause = false;
this->dataPtr->thread = nullptr;
this->dataPtr->logThread = nullptr;
this->dataPtr->stop = false;
this->dataPtr->currentStateBuffer = 0;
this->dataPtr->stateToggle = 0;
this->dataPtr->pluginsLoaded = false;
this->dataPtr->name = _name;
this->dataPtr->needsReset = false;
this->dataPtr->resetAll = true;
this->dataPtr->resetTimeOnly = false;
this->dataPtr->resetModelOnly = false;
this->dataPtr->enablePhysicsEngine = true;
this->dataPtr->setWorldPoseMutex = new boost::mutex();
this->dataPtr->worldUpdateMutex = new boost::recursive_mutex();
this->dataPtr->sleepOffset = common::Time(0);
this->dataPtr->prevStatTime = common::Time::GetWallTime();
this->dataPtr->prevProcessMsgsTime = common::Time::GetWallTime();
this->dataPtr->connections.push_back(
event::Events::ConnectStep(boost::bind(&World::OnStep, this)));
this->dataPtr->connections.push_back(
event::Events::ConnectPause(
boost::bind(&World::SetPaused, this, _1)));
}
//////////////////////////////////////////////////
World::~World()
{
this->Fini();
delete this->dataPtr;
this->dataPtr = nullptr;
}
//////////////////////////////////////////////////
void World::Load(sdf::ElementPtr _sdf)
{
this->dataPtr->loaded = false;
this->dataPtr->sdf = _sdf;
if (this->dataPtr->sdf->Get<std::string>("name").empty())
gzwarn << "create_world(world_name =["
<< this->dataPtr->name << "]) overwrites sdf world name\n!";
else
this->dataPtr->name = this->dataPtr->sdf->Get<std::string>("name");
#ifdef HAVE_OPENAL
util::OpenAL::Instance()->Load(this->dataPtr->sdf->GetElement("audio"));
#endif
this->dataPtr->sceneMsg.CopyFrom(
msgs::SceneFromSDF(this->dataPtr->sdf->GetElement("scene")));
this->dataPtr->sceneMsg.set_name(this->GetName());
// The period at which messages are processed
this->dataPtr->processMsgsPeriod = common::Time(0, 200000000);
this->dataPtr->node = transport::NodePtr(new transport::Node());
this->dataPtr->node->Init(this->GetName());
// pose pub for server side, mainly used for updating and timestamping
// Scene, which in turn will be used by rendering sensors.
// TODO: replace local communication with shared memory for efficiency.
this->dataPtr->poseLocalPub =
this->dataPtr->node->Advertise<msgs::PosesStamped>("~/pose/local/info", 10);
// pose pub for client with a cap on publishing rate to reduce traffic
// overhead
this->dataPtr->posePub = this->dataPtr->node->Advertise<msgs::PosesStamped>(
"~/pose/info", 10, 60);
this->dataPtr->guiPub = this->dataPtr->node->Advertise<msgs::GUI>("~/gui", 5);
if (this->dataPtr->sdf->HasElement("gui"))
{
this->dataPtr->guiPub->Publish(
msgs::GUIFromSDF(this->dataPtr->sdf->GetElement("gui")));
}
this->dataPtr->factorySub = this->dataPtr->node->Subscribe("~/factory",
&World::OnFactoryMsg, this);
this->dataPtr->controlSub = this->dataPtr->node->Subscribe("~/world_control",
&World::OnControl, this);
this->dataPtr->playbackControlSub = this->dataPtr->node->Subscribe(
"~/playback_control", &World::OnPlaybackControl, this);
this->dataPtr->requestSub = this->dataPtr->node->Subscribe("~/request",
&World::OnRequest, this, true);
this->dataPtr->jointSub = this->dataPtr->node->Subscribe("~/joint",
&World::JointLog, this);
this->dataPtr->lightSub = this->dataPtr->node->Subscribe("~/light",
&World::OnLightMsg, this);
this->dataPtr->lightFactorySub =
this->dataPtr->node->Subscribe("~/factory/light",
&World::OnLightFactoryMsg, this);
this->dataPtr->lightModifySub =
this->dataPtr->node->Subscribe("~/light/modify",
&World::OnLightModifyMsg, this);
this->dataPtr->modelSub = this->dataPtr->node->Subscribe<msgs::Model>(
"~/model/modify", &World::OnModelMsg, this);
this->dataPtr->responsePub = this->dataPtr->node->Advertise<msgs::Response>(
"~/response");
this->dataPtr->statPub =
this->dataPtr->node->Advertise<msgs::WorldStatistics>(
"~/world_stats", 100, 5);
this->dataPtr->modelPub = this->dataPtr->node->Advertise<msgs::Model>(
"~/model/info");
this->dataPtr->lightPub = this->dataPtr->node->Advertise<msgs::Light>(
"~/light/modify");
this->dataPtr->lightFactoryPub = this->dataPtr->node->Advertise<msgs::Light>(
"~/factory/light");
// Added by zhangshuai based on zenglei 2019.04.23 ----Begin
if (this->dataPtr->sdf->HasElement("distribution"))
{
sdf::ElementPtr distributionElem = this->dataPtr->sdf->GetElement("distribution");
int nproc;
char proc_name[MPI_MAX_PROCESSOR_NAME];
int nameLength;
MPI_Comm_rank(MPI_COMM_WORLD, &this->gazeboLocalID);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Get_processor_name(proc_name, &nameLength);
printf("Gazebo, Iam host %s with rank %d of %d\n", proc_name, this->gazeboLocalID, nproc);
this->flag = distributionElem->Get<int>("flag");
std::cout << "================= gazebo_local_ID: " << this->gazeboLocalID << "\t Flag: " << this->flag << " =================" << std::endl;
if (1 == this->flag)
{
DistributionPtr distribution_tmp(new physics::Distribution());
this->distribution = distribution_tmp;
this->distribution->Load(distributionElem);
std::cout << "================= gazebo_counts: " << this->distribution->GetGazeboCount() << " =================" << std::endl;
std::cout << "================= gazebo_ID: " << this->distribution->GetGazeboIDPtr(this->gazeboLocalID)->GetGazeboID() << " =================" << std::endl;
std::cout << "================= model_counts: " << this->distribution->GetGazeboIDPtr(this->gazeboLocalID)->GetModelCount() << " =================" << std::endl;
}
}
//Added by zhangshuai based on zenglei 2019.03.19 ----End
// This should come before loading of entities
sdf::ElementPtr physicsElem = this->dataPtr->sdf->GetElement("physics");
std::string type = physicsElem->Get<std::string>("type");
this->dataPtr->physicsEngine = PhysicsFactory::NewPhysicsEngine(type,
shared_from_this());
if (this->dataPtr->physicsEngine == nullptr)
gzthrow("Unable to create physics engine\n");
this->dataPtr->physicsEngine->Load(physicsElem);
// This should also come before loading of entities
{
sdf::ElementPtr spherical = this->dataPtr->sdf->GetElement(
"spherical_coordinates");
common::SphericalCoordinates::SurfaceType surfaceType =
common::SphericalCoordinates::Convert(
spherical->Get<std::string>("surface_model"));
ignition::math::Angle latitude, longitude, heading;
double elevation = spherical->Get<double>("elevation");
latitude.Degree(spherical->Get<double>("latitude_deg"));
longitude.Degree(spherical->Get<double>("longitude_deg"));
heading.Degree(spherical->Get<double>("heading_deg"));
this->dataPtr->sphericalCoordinates.reset(new common::SphericalCoordinates(
surfaceType, latitude, longitude, elevation, heading));
}
if (this->dataPtr->sphericalCoordinates == nullptr)
gzthrow("Unable to create spherical coordinates data structure\n");
this->dataPtr->rootElement.reset(new Base(BasePtr()));
this->dataPtr->rootElement->SetName(this->GetName());
this->dataPtr->rootElement->SetWorld(shared_from_this());
// A special order is necessary when loading a world that contains state
// information. The joints must be created last, otherwise they get
// initialized improperly.
{
// Create all the entities
this->LoadEntities(this->dataPtr->sdf, this->dataPtr->rootElement);
for (unsigned int i = 0; i < this->GetModelCount(); ++i)
this->GetModel(i)->LoadJoints();
}
// TODO: Performance test to see if TBB model updating is necessary
// Choose threaded or unthreaded model updating depending on the number of
// models in the scene
// if (this->GetModelCount() < 20)
this->dataPtr->modelUpdateFunc = &World::ModelUpdateSingleLoop;
// else
// this->dataPtr->modelUpdateFunc = &World::ModelUpdateTBB;
event::Events::worldCreated(this->GetName());
this->dataPtr->userCmdManager = UserCmdManagerPtr(
new UserCmdManager(shared_from_this()));
this->dataPtr->loaded = true;
}
//////////////////////////////////////////////////
void World::Save(const std::string &_filename)
{
this->UpdateStateSDF();
std::string data;
data = "<?xml version ='1.0'?>\n";
data += "<sdf version='" +
boost::lexical_cast<std::string>(SDF_VERSION) + "'>\n";
data += this->dataPtr->sdf->ToString("");
data += "</sdf>\n";
std::ofstream out(_filename.c_str(), std::ios::out);
if (!out)
gzerr << "Unable to open file[" << _filename << "]\n";
else
out << data;
out.close();
}
//////////////////////////////////////////////////
void World::Init()
{
// Initialize all the entities (i.e. Model)
for (unsigned int i = 0; i < this->dataPtr->rootElement->GetChildCount(); i++)
this->dataPtr->rootElement->GetChild(i)->Init();
// Initialize the physics engine
this->dataPtr->physicsEngine->Init();
this->dataPtr->presetManager = PresetManagerPtr(
new PresetManager(this->dataPtr->physicsEngine, this->dataPtr->sdf));
this->dataPtr->testRay = boost::dynamic_pointer_cast<RayShape>(
this->GetPhysicsEngine()->CreateShape("ray", CollisionPtr()));
this->dataPtr->prevStates[0].SetWorld(shared_from_this());
this->dataPtr->prevStates[1].SetWorld(shared_from_this());
this->dataPtr->prevStates[0].SetName(this->GetName());
this->dataPtr->prevStates[1].SetName(this->GetName());
this->dataPtr->updateInfo.worldName = this->GetName();
this->dataPtr->iterations = 0;
this->dataPtr->logPrevIteration = 0;
util::DiagnosticManager::Instance()->Init(this->GetName());
util::LogRecord::Instance()->Add(this->GetName(), "state.log",
boost::bind(&World::OnLog, this, _1));
// Check if we have to insert an object population.
if (this->dataPtr->sdf->HasElement("population"))
{
Population population(this->dataPtr->sdf, shared_from_this());
population.PopulateAll();
}
// Set the state of the entities
if (this->dataPtr->sdf->HasElement("state"))
{
sdf::ElementPtr childElem = this->dataPtr->sdf->GetElement("state");
while (childElem)
{
WorldState myState;
myState.Load(childElem);
this->SetState(myState);
childElem = childElem->GetNextElement("state");
// TODO: We currently load just the first state data. Need to
// implement a better mechanism for handling multiple states
break;
}
}
this->dataPtr->initialized = true;
// Mark the world initialization
gzlog << "Init world[" << this->GetName() << "]" << std::endl;
}
//////////////////////////////////////////////////
void World::Run(unsigned int _iterations)
{
this->dataPtr->stop = false;
this->dataPtr->stopIterations = _iterations;
this->dataPtr->thread = new boost::thread(boost::bind(&World::RunLoop, this));
}
//////////////////////////////////////////////////
void World::RunBlocking(unsigned int _iterations)
{
this->dataPtr->stop = false;
this->dataPtr->stopIterations = _iterations;
this->RunLoop();
}
//////////////////////////////////////////////////
void World::RemoveModel(ModelPtr _model)
{
if (_model)
this->RemoveModel(_model->GetName());
}
//////////////////////////////////////////////////
bool World::GetRunning() const
{
return !this->dataPtr->stop;
}
//////////////////////////////////////////////////
void World::Stop()
{
this->dataPtr->stop = true;
if (this->dataPtr->thread)
{
this->dataPtr->thread->join();
delete this->dataPtr->thread;
this->dataPtr->thread = nullptr;
}
}
//////////////////////////////////////////////////
void World::RunLoop()
{
this->dataPtr->physicsEngine->InitForThread();
this->dataPtr->startTime = common::Time::GetWallTime();
// This fixes a minor issue when the world is paused before it's started
if (this->IsPaused())
this->dataPtr->pauseStartTime = this->dataPtr->startTime;
this->dataPtr->prevStepWallTime = common::Time::GetWallTime();
// Get the first state
this->dataPtr->prevStates[0] = WorldState(shared_from_this());
this->dataPtr->prevStates[1] = WorldState(shared_from_this());
this->dataPtr->stateToggle = 0;
this->dataPtr->logThread =
new boost::thread(boost::bind(&World::LogWorker, this));
if (!util::LogPlay::Instance()->IsOpen())
{
for (this->dataPtr->iterations = 0; !this->dataPtr->stop &&
(!this->dataPtr->stopIterations ||
(this->dataPtr->iterations < this->dataPtr->stopIterations));)
{
this->Step();
}
}
else
{
this->dataPtr->enablePhysicsEngine = false;
for (this->dataPtr->iterations = 0; !this->dataPtr->stop &&
(!this->dataPtr->stopIterations ||
(this->dataPtr->iterations < this->dataPtr->stopIterations));)
{
this->LogStep();
}
}
this->dataPtr->stop = true;
if (this->dataPtr->logThread)
{
this->dataPtr->logCondition.notify_all();
{
boost::mutex::scoped_lock lock(this->dataPtr->logMutex);
this->dataPtr->logCondition.notify_all();
}
this->dataPtr->logThread->join();
delete this->dataPtr->logThread;
this->dataPtr->logThread = nullptr;
}
}
//////////////////////////////////////////////////
void World::LogStep()
{
{
boost::recursive_mutex::scoped_lock lk(*this->dataPtr->worldUpdateMutex);
if (!this->IsPaused() || this->dataPtr->stepInc != 0)
{
if (!this->IsPaused() && this->dataPtr->stepInc == 0)
this->dataPtr->stepInc = 1;
std::string data;
if (!util::LogPlay::Instance()->Step(this->dataPtr->stepInc, data))
{
// There are no more chunks, time to exit.
this->SetPaused(true);
this->dataPtr->stepInc = 0;
}
else
{
this->dataPtr->stepInc = 1;
this->dataPtr->logPlayStateSDF->ClearElements();
sdf::readString(data, this->dataPtr->logPlayStateSDF);
this->dataPtr->logPlayState.Load(this->dataPtr->logPlayStateSDF);
// If the log file does not contain iterations we have to manually
// increase the iteration counter in logPlayState.
if (!util::LogPlay::Instance()->HasIterations())
{
this->dataPtr->logPlayState.SetIterations(
this->dataPtr->iterations + 1);
}
this->SetState(this->dataPtr->logPlayState);
this->Update();
}
if (this->dataPtr->stepInc > 0)
this->dataPtr->stepInc--;
}
}
this->PublishWorldStats();
this->ProcessMessages();
}
//////////////////////////////////////////////////
void World::_SetSensorsInitialized(const bool _init)
{
this->dataPtr->sensorsInitialized = _init;
}
//////////////////////////////////////////////////
bool World::SensorsInitialized() const
{
return this->dataPtr->sensorsInitialized;
}
//////////////////////////////////////////////////
void World::Step()
{
DIAG_TIMER_START("World::Step");
/// need this because ODE does not call dxReallocateWorldProcessContext()
/// until dWorld.*Step
/// Plugins that manipulate joints (and probably other properties) require
/// one iteration of the physics engine. Do not remove this.
if (!this->dataPtr->pluginsLoaded && this->SensorsInitialized())
{
this->LoadPlugins();
this->dataPtr->pluginsLoaded = true;
}
DIAG_TIMER_LAP("World::Step", "loadPlugins");
// Send statistics about the world simulation
this->PublishWorldStats();
DIAG_TIMER_LAP("World::Step", "publishWorldStats");
double updatePeriod = this->dataPtr->physicsEngine->GetUpdatePeriod();
// sleep here to get the correct update rate
common::Time tmpTime = common::Time::GetWallTime();
common::Time sleepTime = this->dataPtr->prevStepWallTime +
common::Time(updatePeriod) - tmpTime - this->dataPtr->sleepOffset;
common::Time actualSleep = 0;
if (sleepTime > 0)
{
common::Time::Sleep(sleepTime);
actualSleep = common::Time::GetWallTime() - tmpTime;
}
else
sleepTime = 0;
// exponentially avg out
this->dataPtr->sleepOffset = (actualSleep - sleepTime) * 0.01 +
this->dataPtr->sleepOffset * 0.99;
DIAG_TIMER_LAP("World::Step", "sleepOffset");
// throttling update rate, with sleepOffset as tolerance
// the tolerance is needed as the sleep time is not exact
if (common::Time::GetWallTime() - this->dataPtr->prevStepWallTime +
this->dataPtr->sleepOffset >=
common::Time(updatePeriod))
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->worldUpdateMutex);
DIAG_TIMER_LAP("World::Step", "worldUpdateMutex");
this->dataPtr->prevStepWallTime = common::Time::GetWallTime();
double stepTime = this->dataPtr->physicsEngine->GetMaxStepSize();
if (!this->IsPaused() || this->dataPtr->stepInc > 0 || this->dataPtr->needsReset)
{
// query timestep to allow dynamic time step size updates
this->dataPtr->simTime += stepTime;
this->dataPtr->iterations++;
this->Update();
DIAG_TIMER_LAP("World::Step", "update");
if (this->IsPaused() && this->dataPtr->stepInc > 0)
this->dataPtr->stepInc--;
}
else
{
// Flush the log record buffer, if there is data in it.
if (util::LogRecord::Instance()->BufferSize() > 0)
util::LogRecord::Instance()->Notify();
this->dataPtr->pauseTime += stepTime;
}
}
this->ProcessMessages();
DIAG_TIMER_STOP("World::Step");
if (g_clearModels)
this->ClearModels();
}
//////////////////////////////////////////////////
void World::Step(unsigned int _steps)
{
if (!this->IsPaused())
{
gzwarn << "Calling World::Step(steps) while world is not paused\n";
this->SetPaused(true);
}
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->worldUpdateMutex);
this->dataPtr->stepInc = _steps;
}
// block on completion
bool wait = true;
while (wait)
{
common::Time::NSleep(1);
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->worldUpdateMutex);
if (this->dataPtr->stepInc == 0 || this->dataPtr->stop)
wait = false;
}
}
//////////////////////////////////////////////////
void World::Update()
{
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
struct timeval tv;
double cur_time;
double start_time;
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
start_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
DIAG_TIMER_START("World::Update");
if (this->dataPtr->needsReset)
{
if (this->dataPtr->resetAll)
this->Reset();
else if (this->dataPtr->resetTimeOnly)
this->ResetTime();
else if (this->dataPtr->resetModelOnly)
this->ResetEntities(Base::MODEL);
this->dataPtr->needsReset = false;
return;
}
DIAG_TIMER_LAP("World::Update", "needsReset");
this->dataPtr->updateInfo.simTime = this->GetSimTime();
this->dataPtr->updateInfo.realTime = this->GetRealTime();
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
before_worldUpdateBeginTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
event::Events::worldUpdateBegin(this->dataPtr->updateInfo);
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
worldUpdateBeginTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
DIAG_TIMER_LAP("World::Update", "Events::worldUpdateBegin");
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// Update all the models
(*this.*dataPtr->modelUpdateFunc)();
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
modelUpdateFuncTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
DIAG_TIMER_LAP("World::Update", "Model::Update");
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// This must be called before PhysicsEngine::UpdatePhysics.
this->dataPtr->physicsEngine->UpdateCollision();
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
updateCollisionTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
DIAG_TIMER_LAP("World::Update", "PhysicsEngine::UpdateCollision");
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// Wait for logging to finish, if it's running.
if (util::LogRecord::Instance()->Running())
{
boost::mutex::scoped_lock lock(this->dataPtr->logMutex);
// It's possible the logWorker thread never processed the previous
// state. This checks to make sure that we don't continute until the log
// worker catchs up.
if (this->dataPtr->iterations - this->dataPtr->logPrevIteration > 1)
{
this->dataPtr->logCondition.notify_one();
this->dataPtr->logContinueCondition.wait(lock);
}
}
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
loggingTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// Give clients a possibility to react to collisions before the physics
// gets updated.
this->dataPtr->updateInfo.realTime = this->GetRealTime();
event::Events::beforePhysicsUpdate(this->dataPtr->updateInfo);
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
before_updatePhysicsTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
DIAG_TIMER_LAP("World::Update", "Events::beforePhysicsUpdate");
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// Update the physics engine
if (this->dataPtr->enablePhysicsEngine && this->dataPtr->physicsEngine)
{
// This must be called directly after PhysicsEngine::UpdateCollision.
this->dataPtr->physicsEngine->UpdatePhysics();
DIAG_TIMER_LAP("World::Update", "PhysicsEngine::UpdatePhysics");
// do this after physics update as
// ode --> MoveCallback sets the dirtyPoses
// and we need to propagate it into Entity::worldPose
{
// block any other pose updates (e.g. Joint::SetPosition)
boost::recursive_mutex::scoped_lock lock(
*this->dataPtr->physicsEngine->GetPhysicsUpdateMutex());
for (auto &dirtyEntity : this->dataPtr->dirtyPoses)
{
dirtyEntity->SetWorldPose(dirtyEntity->GetDirtyPose(), false);
}
this->dataPtr->dirtyPoses.clear();
}
DIAG_TIMER_LAP("World::Update", "SetWorldPose(dirtyPoses)");
}
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
updatePhysicsTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// Added by zhangshuai 2019.04.23 for MPI communication----Begin
if (1 == this->flag)
{
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
MPI_Status *status = (MPI_Status *)malloc(sizeof(MPI_Status) * (this->distribution->GetGazeboCount()));
MPI_Request *request = (MPI_Request *)malloc(sizeof(MPI_Request) * (this->distribution->GetGazeboCount()));
msgs::Pose_V modelPoseListSend;
for (unsigned int i = 0; i < this->distribution->GetGazeboIDPtr(this->gazeboLocalID)->GetModelCount(); i++)
{
msgs::Pose *modelPose;
modelPose = modelPoseListSend.add_pose();
std::string tmp_model_name = this->distribution->GetGazeboIDPtr(this->gazeboLocalID)->GetModelName(i);
modelPose->set_name(tmp_model_name);
modelPose->set_id(this->GetModel(tmp_model_name)->GetLink("canonical")->GetId());
modelPose->mutable_position()->set_x(this->GetModel(tmp_model_name)->GetLink("canonical")->GetWorldPose().pos.x);
modelPose->mutable_position()->set_y(this->GetModel(tmp_model_name)->GetLink("canonical")->GetWorldPose().pos.y);
modelPose->mutable_position()->set_z(this->GetModel(tmp_model_name)->GetLink("canonical")->GetWorldPose().pos.z);
modelPose->mutable_orientation()->set_x(this->GetModel(tmp_model_name)->GetLink("canonical")->GetWorldPose().rot.x);
modelPose->mutable_orientation()->set_y(this->GetModel(tmp_model_name)->GetLink("canonical")->GetWorldPose().rot.y);
modelPose->mutable_orientation()->set_z(this->GetModel(tmp_model_name)->GetLink("canonical")->GetWorldPose().rot.z);
modelPose->mutable_orientation()->set_w(this->GetModel(tmp_model_name)->GetLink("canonical")->GetWorldPose().rot.w);
tmp_model_name.clear();
}
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
before_tcpTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
//send poses to another process
for (int tmp_gazebo_id = 0; tmp_gazebo_id < this->distribution->GetGazeboCount(); tmp_gazebo_id++)
{
if (this->gazeboLocalID != tmp_gazebo_id)
{
std::string send_messages = "";
if (modelPoseListSend.pose_size() > 0)
{
modelPoseListSend.SerializeToString(&send_messages);
modelPoseListSend.clear_pose();
}
int bufferLen = send_messages.size();
char *sendBuffer = new char[bufferLen + 1];
for (int i = 0; i < bufferLen; i++)
{
sendBuffer[i] = send_messages[i];
}
sendBuffer[bufferLen] = '\0';
send_messages.clear();
MPI_Isend(sendBuffer, bufferLen, MPI_CHAR, tmp_gazebo_id, 99, MPI_COMM_WORLD, &request[tmp_gazebo_id]);
}
}
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
tcpTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
cur_time = (double)tv.tv_sec + (double)tv.tv_usec / 1.e6;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
//receive and get information from other processes
for (int tmp_gazebo_id = 0; tmp_gazebo_id < this->distribution->GetGazeboCount(); tmp_gazebo_id++)
{
if (this->gazeboLocalID != tmp_gazebo_id)
{
MPI_Probe(tmp_gazebo_id, 99, MPI_COMM_WORLD, &status[tmp_gazebo_id]);
int size;
MPI_Get_count(&status[tmp_gazebo_id], MPI_CHAR, &size);
char *receiveBuffer = (char *)malloc(sizeof(char) * (size));
MPI_Recv(receiveBuffer, size, MPI_CHAR, tmp_gazebo_id, 99, MPI_COMM_WORLD, &status[tmp_gazebo_id]);
if (size > 0)
{
std::string receive_messages;
for (int j = 0; j < size; j++)
{
receive_messages.push_back(receiveBuffer[j]);
}
msgs::Pose_V modelPoseListReceive;
modelPoseListReceive.ParseFromString(receive_messages);
receive_messages.clear();
//insert models according to name,pose,vel from process 0
for (int i = 0; i < modelPoseListReceive.pose_size(); i++)
{
math::Pose tmp_pose;
std::string tmp_model_name = modelPoseListReceive.pose(i).name();
// std::string tmp_model_name = this->distribution->GetGazeboIDPtr(1)->GetModelName(i);
tmp_pose.pos.x = modelPoseListReceive.pose(i).position().x();
tmp_pose.pos.y = modelPoseListReceive.pose(i).position().y();
tmp_pose.pos.z = modelPoseListReceive.pose(i).position().z();
tmp_pose.rot.x = modelPoseListReceive.pose(i).orientation().x();
tmp_pose.rot.y = modelPoseListReceive.pose(i).orientation().y();
tmp_pose.rot.z = modelPoseListReceive.pose(i).orientation().z();
tmp_pose.rot.w = modelPoseListReceive.pose(i).orientation().w();
this->GetModel(tmp_model_name)->GetLink("canonical")->SetWorldPose(tmp_pose);
}
}
}
}
// Added by zhangshuai 2019.04.03 for count time ----Begin
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
after_tcpTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - cur_time;
#endif
// Added by zhangshuai 2019.04.03 for count time ----End
// MPI_Waitall(this->distribution->GetGazeboCount(), request, status);
// MPI_Barrier(MPI_COMM_WORLD);
}
MPI_Barrier(MPI_COMM_WORLD);
// Added by zhangshuai 2019.04.23 for MPI communication ----End
// Only update state information if logging data.
if (util::LogRecord::Instance()->Running())
this->dataPtr->logCondition.notify_one();
DIAG_TIMER_LAP("World::Update", "LogRecordNotify");
// Output the contact information
this->dataPtr->physicsEngine->GetContactManager()->PublishContacts();
DIAG_TIMER_LAP("World::Update", "ContactManager::PublishContacts");
event::Events::worldUpdateEnd();
DIAG_TIMER_STOP("World::Update");
#ifdef USE_COUNT_TIME
gettimeofday(&tv, NULL);
wholeUpdataTime += (double)tv.tv_sec + (double)tv.tv_usec / 1.e6 - start_time;
#endif
// std::cout << "===== iterations:\t" << this->dataPtr->iterations << std::endl;
if (this->dataPtr->iterations == 100000)
{
if (this->gazeboLocalID == 0)
{
std::cout << "===== average before_worldUpdateBeginTime:\t" << before_worldUpdateBeginTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average worldUpdateBeginTime:\t" << worldUpdateBeginTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average modelUpdateFuncTime:\t" << modelUpdateFuncTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average updateCollisionTime:\t" << updateCollisionTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average loggingTime:\t" << loggingTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average before_updatePhysicsTime:\t" << before_updatePhysicsTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average updatePhysicsTime:\t" << updatePhysicsTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average before_tcpTime:\t" << before_tcpTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average tcpTime:\t" << tcpTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average after_tcpTime:\t" << after_tcpTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
double wholeTcpTime = before_tcpTime + tcpTime + after_tcpTime;
std::cout << "===== average wholeTcpTime:\t" << wholeTcpTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
double wholeAddTime = before_worldUpdateBeginTime + worldUpdateBeginTime + modelUpdateFuncTime + updateCollisionTime + loggingTime + before_updatePhysicsTime + updatePhysicsTime + before_tcpTime + tcpTime + after_tcpTime;
std::cout << "===== average wholeAddTime:\t" << wholeAddTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
std::cout << "===== average wholeUpdateTime:\t" << wholeUpdataTime * 1000.0 / this->dataPtr->iterations << "\tms =====" << std::endl;
}
}
}
//////////////////////////////////////////////////
void World::Fini()
{
this->dataPtr->stop = true;
#ifdef HAVE_OPENAL
util::OpenAL::Instance()->Fini();
#endif
// Clean transport
{
this->dataPtr->deleteEntity.clear();
this->dataPtr->requestMsgs.clear();
this->dataPtr->factoryMsgs.clear();
this->dataPtr->modelMsgs.clear();
this->dataPtr->lightFactoryMsgs.clear();
this->dataPtr->lightModifyMsgs.clear();
this->dataPtr->playbackControlMsgs.clear();
this->dataPtr->poseLocalPub.reset();
this->dataPtr->posePub.reset();
this->dataPtr->guiPub.reset();
this->dataPtr->responsePub.reset();
this->dataPtr->statPub.reset();
this->dataPtr->modelPub.reset();
this->dataPtr->lightPub.reset();
this->dataPtr->lightFactoryPub.reset();
this->dataPtr->factorySub.reset();
this->dataPtr->controlSub.reset();
this->dataPtr->playbackControlSub.reset();
this->dataPtr->requestSub.reset();
this->dataPtr->jointSub.reset();
this->dataPtr->lightSub.reset();
this->dataPtr->lightFactorySub.reset();
this->dataPtr->lightModifySub.reset();
this->dataPtr->modelSub.reset();
this->dataPtr->node.reset();
}
this->dataPtr->connections.clear();
this->dataPtr->sdf.reset();
this->dataPtr->testRay.reset();
this->dataPtr->plugins.clear();
this->dataPtr->publishModelPoses.clear();
this->dataPtr->publishModelScales.clear();
this->dataPtr->publishLightPoses.clear();
// Clean entities
for (auto &model : this->dataPtr->models)
{
if (model)
model->Fini();
}
this->dataPtr->models.clear();
for (auto &light : this->dataPtr->lights)
{
if (light)
light->Fini();
}
this->dataPtr->lights.clear();
if (this->dataPtr->rootElement)
{
this->dataPtr->rootElement->Fini();
this->dataPtr->rootElement.reset();
}
this->dataPtr->prevStates[0].SetWorld(WorldPtr());
this->dataPtr->prevStates[1].SetWorld(WorldPtr());
this->dataPtr->prevUnfilteredState.SetWorld(WorldPtr());
this->dataPtr->logPlayState.SetWorld(WorldPtr());
this->dataPtr->states[0].clear();
this->dataPtr->states[1].clear();
this->dataPtr->presetManager.reset();
this->dataPtr->userCmdManager.reset();
this->dataPtr->physicsEngine.reset();
// Clean mutexes
if (this->dataPtr->receiveMutex)
{
delete this->dataPtr->receiveMutex;
this->dataPtr->receiveMutex = nullptr;
}
if (this->dataPtr->loadModelMutex)
{
delete this->dataPtr->loadModelMutex;
this->dataPtr->loadModelMutex = nullptr;
}
if (this->dataPtr->setWorldPoseMutex)
{
delete this->dataPtr->setWorldPoseMutex;
this->dataPtr->setWorldPoseMutex = nullptr;
}
if (this->dataPtr->worldUpdateMutex)
{
delete this->dataPtr->worldUpdateMutex;
this->dataPtr->worldUpdateMutex = nullptr;
}
// End world run thread
if (this->dataPtr->thread)
{
this->dataPtr->thread->join();
delete this->dataPtr->thread;
this->dataPtr->thread = nullptr;
}
}
//////////////////////////////////////////////////
void World::Clear()
{
g_clearModels = true;
/// \todo Clear lights too?
}
//////////////////////////////////////////////////
void World::ClearModels()
{
g_clearModels = false;
bool pauseState = this->IsPaused();
this->SetPaused(true);
while (!this->dataPtr->models.empty())
{
this->RemoveModel(this->dataPtr->models[0]);
}
this->dataPtr->models.clear();
this->SetPaused(pauseState);
}
//////////////////////////////////////////////////
std::string World::GetName() const
{
return this->dataPtr->name;
}
//////////////////////////////////////////////////
PhysicsEnginePtr World::GetPhysicsEngine() const
{
return this->dataPtr->physicsEngine;
}
//////////////////////////////////////////////////
PresetManagerPtr World::GetPresetManager() const
{
return this->dataPtr->presetManager;
}
//////////////////////////////////////////////////
common::SphericalCoordinatesPtr World::GetSphericalCoordinates() const
{
return this->dataPtr->sphericalCoordinates;
}
//////////////////////////////////////////////////
ignition::math::Vector3d World::Gravity() const
{
return this->dataPtr->sdf->Get<ignition::math::Vector3d>("gravity");
}
//////////////////////////////////////////////////
void World::SetGravity(const ignition::math::Vector3d &_gravity)
{
// This function calls `PhysicsEngine::SetGravity`,
// which in turn should call `World::SetGravitySDF`.
this->dataPtr->physicsEngine->SetGravity(_gravity);
}
//////////////////////////////////////////////////
void World::SetGravitySDF(const ignition::math::Vector3d &_gravity)
{
this->dataPtr->sdf->GetElement("gravity")->Set(_gravity);
}
//////////////////////////////////////////////////
ignition::math::Vector3d World::MagneticField() const
{
return this->dataPtr->sdf->Get<ignition::math::Vector3d>("magnetic_field");
}
//////////////////////////////////////////////////
void World::SetMagneticField(const ignition::math::Vector3d &_mag)
{
this->dataPtr->sdf->GetElement("magnetic_field")->Set(_mag);
}
//////////////////////////////////////////////////
BasePtr World::GetByName(const std::string &_name)
{
if (this->dataPtr->rootElement)
return this->dataPtr->rootElement->GetByName(_name);
else
return BasePtr();
}
/////////////////////////////////////////////////
ModelPtr World::GetModelById(unsigned int _id)
{
return boost::dynamic_pointer_cast<Model>(
this->dataPtr->rootElement->GetById(_id));
}
//////////////////////////////////////////////////
ModelPtr World::GetModel(const std::string &_name)
{
boost::mutex::scoped_lock lock(*this->dataPtr->loadModelMutex);
return boost::dynamic_pointer_cast<Model>(this->GetByName(_name));
}
//////////////////////////////////////////////////
LightPtr World::Light(const std::string &_name)
{
std::lock_guard<std::mutex> lock(this->dataPtr->loadLightMutex);
return boost::dynamic_pointer_cast<physics::Light>(this->GetByName(_name));
}
//////////////////////////////////////////////////
EntityPtr World::GetEntity(const std::string &_name)
{
return boost::dynamic_pointer_cast<Entity>(this->GetByName(_name));
}
//////////////////////////////////////////////////
ModelPtr World::LoadModel(sdf::ElementPtr _sdf, BasePtr _parent)
{
boost::mutex::scoped_lock lock(*this->dataPtr->loadModelMutex);
ModelPtr model;
if (_sdf->GetName() == "model")
{
std::string modelName = _sdf->Get<std::string>("name");
for (auto const m : this->dataPtr->models)
{
if (m->GetName() == modelName)
{
gzwarn << "Model with name [" << modelName << "] already exists. "
<< "Not inserting model. This warning can be ignored in certain "
<< "situations such as rewind during log playback.\n";
return model;
}
}
model = this->dataPtr->physicsEngine->CreateModel(_parent);
model->SetWorld(shared_from_this());
model->Load(_sdf);
event::Events::addEntity(model->GetScopedName());
msgs::Model msg;
model->FillMsg(msg);
this->dataPtr->modelPub->Publish(msg);
this->EnableAllModels();
}
else
{
gzerr << "SDF is missing the <model> tag:\n";
}
this->PublishModelPose(model);
this->dataPtr->models.push_back(model);
return model;
}
//////////////////////////////////////////////////
LightPtr World::LoadLight(const sdf::ElementPtr &_sdf, const BasePtr &_parent)
{
std::lock_guard<std::mutex> lock(this->dataPtr->loadLightMutex);
if (_sdf->GetName() != "light")
{
gzerr << "SDF is missing the <light> tag" << std::endl;
return nullptr;
}
// Add to scene message
msgs::Light *msg = this->dataPtr->sceneMsg.add_light();
msg->CopyFrom(msgs::LightFromSDF(_sdf));
// Create new light object
LightPtr light(new physics::Light(_parent));
light->ProcessMsg(*msg);
light->SetWorld(shared_from_this());
light->Load(_sdf);
this->dataPtr->lights.push_back(light);
// msg should contain scoped name (consistent with other entities)
msg->set_name(light->GetScopedName());
// publish after adding light to the lights vector
// we also process light factory msg in World so this avoids creating a
// duplicate light
// Note: models uses /model/info topic. We can consider adding a
// /light/info topic for this, see issue #2288
this->dataPtr->lightFactoryPub->Publish(*msg);
return light;
}
//////////////////////////////////////////////////
ActorPtr World::LoadActor(sdf::ElementPtr _sdf, BasePtr _parent)
{
ActorPtr actor(new Actor(_parent));
actor->SetWorld(shared_from_this());
actor->Load(_sdf);
event::Events::addEntity(actor->GetScopedName());
msgs::Model msg;
actor->FillMsg(msg);
this->dataPtr->modelPub->Publish(msg);
return actor;
}
//////////////////////////////////////////////////
RoadPtr World::LoadRoad(sdf::ElementPtr _sdf, BasePtr _parent)
{
RoadPtr road(new Road(_parent));
road->Load(_sdf);
return road;
}
//////////////////////////////////////////////////
void World::LoadEntities(sdf::ElementPtr _sdf, BasePtr _parent)
{
if (_sdf->HasElement("light"))
{
sdf::ElementPtr childElem = _sdf->GetElement("light");
while (childElem)
{
this->LoadLight(childElem, _parent);
childElem = childElem->GetNextElement("light");
}
}
if (_sdf->HasElement("model"))
{
sdf::ElementPtr childElem = _sdf->GetElement("model");
while (childElem)
{
this->LoadModel(childElem, _parent);
// TODO : Put back in the ability to nest models. We should do this
// without requiring a joint.
childElem = childElem->GetNextElement("model");
}
}
if (_sdf->HasElement("actor"))
{
sdf::ElementPtr childElem = _sdf->GetElement("actor");
while (childElem)
{
this->LoadActor(childElem, _parent);
childElem = childElem->GetNextElement("actor");
}
}
if (_sdf->HasElement("road"))
{
sdf::ElementPtr childElem = _sdf->GetElement("road");
while (childElem)
{
this->LoadRoad(childElem, _parent);
childElem = childElem->GetNextElement("road");
}
}
}
//////////////////////////////////////////////////
unsigned int World::GetModelCount() const
{
return this->dataPtr->models.size();
}
//////////////////////////////////////////////////
unsigned int World::LightCount() const
{
return this->dataPtr->lights.size();
}
//////////////////////////////////////////////////
ModelPtr World::GetModel(unsigned int _index) const
{
if (_index >= this->dataPtr->models.size())
{
gzerr << "Given model index[" << _index << "] is out of range[0.."
<< this->dataPtr->models.size() << "]\n";
return ModelPtr();
}
return this->dataPtr->models[_index];
}
//////////////////////////////////////////////////
Model_V World::GetModels() const
{
return this->dataPtr->models;
}
//////////////////////////////////////////////////
Light_V World::Lights() const
{
return this->dataPtr->lights;
}
//////////////////////////////////////////////////
void World::ResetTime()
{
this->dataPtr->simTime = common::Time(0);
this->dataPtr->pauseTime = common::Time(0);
this->dataPtr->startTime = common::Time::GetWallTime();
this->dataPtr->realTimeOffset = common::Time(0);
this->dataPtr->iterations = 0;
if (this->IsPaused())
this->dataPtr->pauseStartTime = this->dataPtr->startTime;
// Signal a reset has occurred. The SensorManager listens to this event
// to reset each sensor's last update time.
event::Events::timeReset();
}
//////////////////////////////////////////////////
void World::ResetEntities(Base::EntityType _type)
{
this->dataPtr->rootElement->Reset(_type);
}
//////////////////////////////////////////////////
void World::Reset()
{
bool currentlyPaused = this->IsPaused();
this->SetPaused(true);
{
boost::recursive_mutex::scoped_lock lk(*this->dataPtr->worldUpdateMutex);
math::Rand::SetSeed(math::Rand::GetSeed());
ignition::math::Rand::Seed(ignition::math::Rand::Seed());
this->dataPtr->physicsEngine->SetSeed(math::Rand::GetSeed());
this->ResetTime();
this->ResetEntities(Base::BASE);
for (auto &plugin : this->dataPtr->plugins)
{
plugin->Reset();
}
this->dataPtr->physicsEngine->Reset();
// Signal a reset has occurred
event::Events::worldReset();
}
this->SetPaused(currentlyPaused);
}
//////////////////////////////////////////////////
void World::OnStep()
{
this->dataPtr->stepInc = 1;
}
//////////////////////////////////////////////////
void World::PrintEntityTree()
{
// Initialize all the entities
for (unsigned int i = 0; i < this->dataPtr->rootElement->GetChildCount(); i++)
this->dataPtr->rootElement->GetChild(i)->Print("");
}
//////////////////////////////////////////////////
gazebo::common::Time World::GetSimTime() const
{
return this->dataPtr->simTime;
}
//////////////////////////////////////////////////
void World::SetSimTime(const common::Time &_t)
{
this->dataPtr->simTime = _t;
}
//////////////////////////////////////////////////
gazebo::common::Time World::GetPauseTime() const
{
return this->dataPtr->pauseTime;
}
//////////////////////////////////////////////////
gazebo::common::Time World::GetStartTime() const
{
return this->dataPtr->startTime;
}
//////////////////////////////////////////////////
common::Time World::GetRealTime() const
{
if (!util::LogPlay::Instance()->IsOpen())
{
if (this->dataPtr->pause)
{
return (this->dataPtr->pauseStartTime - this->dataPtr->startTime) -
this->dataPtr->realTimeOffset;
}
else
{
return (common::Time::GetWallTime() - this->dataPtr->startTime) -
this->dataPtr->realTimeOffset;
}
}
else
return this->dataPtr->logRealTime;
}
//////////////////////////////////////////////////
bool World::IsPaused() const
{
return this->dataPtr->pause;
}
//////////////////////////////////////////////////
void World::SetPaused(bool _p)
{
if (this->dataPtr->pause == _p)
return;
{
boost::recursive_mutex::scoped_lock lk(*this->dataPtr->worldUpdateMutex);
this->dataPtr->pause = _p;
}
if (_p)
{
// This is also a good time to clear out the logging buffer.
util::LogRecord::Instance()->Notify();
this->dataPtr->pauseStartTime = common::Time::GetWallTime();
}
else
{
this->dataPtr->realTimeOffset += common::Time::GetWallTime() -
this->dataPtr->pauseStartTime;
}
event::Events::pause(_p);
}
//////////////////////////////////////////////////
void World::OnFactoryMsg(ConstFactoryPtr &_msg)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
this->dataPtr->factoryMsgs.push_back(*_msg);
}
//////////////////////////////////////////////////
void World::OnControl(ConstWorldControlPtr &_data)
{
if (_data->has_pause())
this->SetPaused(_data->pause());
if (_data->has_step())
this->OnStep();
if (_data->has_multi_step())
{
// stepWorld is a blocking call so set stepInc directly so that world stats
// will still be published
this->SetPaused(true);
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->worldUpdateMutex);
this->dataPtr->stepInc = _data->multi_step();
}
if (_data->has_seed())
{
math::Rand::SetSeed(_data->seed());
ignition::math::Rand::Seed(_data->seed());
this->dataPtr->physicsEngine->SetSeed(_data->seed());
}
if (_data->has_reset())
{
this->dataPtr->needsReset = true;
if (_data->reset().has_all() && _data->reset().all())
{
this->dataPtr->resetAll = true;
}
else
{
this->dataPtr->resetAll = false;
if (_data->reset().has_time_only() && _data->reset().time_only())
this->dataPtr->resetTimeOnly = true;
if (_data->reset().has_model_only() && _data->reset().model_only())
this->dataPtr->resetModelOnly = true;
}
}
}
//////////////////////////////////////////////////
void World::OnPlaybackControl(ConstLogPlaybackControlPtr &_data)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
this->dataPtr->playbackControlMsgs.push_back(*_data);
}
//////////////////////////////////////////////////
void World::ProcessPlaybackControlMsgs()
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->worldUpdateMutex);
for (auto const &msg : this->dataPtr->playbackControlMsgs)
{
if (msg.has_pause())
this->SetPaused(msg.pause());
if (msg.has_multi_step())
{
// stepWorld is a blocking call so set stepInc directly so that
// world stats will still be published
this->SetPaused(true);
this->dataPtr->stepInc += msg.multi_step();
}
if (msg.has_seek())
{
common::Time targetSimTime = msgs::Convert(msg.seek());
util::LogPlay::Instance()->Seek(targetSimTime);
this->dataPtr->stepInc = 1;
}
if (msg.has_rewind() && msg.rewind())
{
util::LogPlay::Instance()->Rewind();
this->dataPtr->stepInc = 1;
if (!util::LogPlay::Instance()->HasIterations())
this->dataPtr->iterations = 0;
}
if (msg.has_forward() && msg.forward())
{
util::LogPlay::Instance()->Forward();
this->dataPtr->stepInc = -1;
this->SetPaused(true);
// ToDo: Update iterations if the log doesn't have it.
}
}
this->dataPtr->playbackControlMsgs.clear();
}
//////////////////////////////////////////////////
void World::OnRequest(ConstRequestPtr &_msg)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
this->dataPtr->requestMsgs.push_back(*_msg);
}
//////////////////////////////////////////////////
void World::JointLog(ConstJointPtr &_msg)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
int i = 0;
for (; i < this->dataPtr->sceneMsg.joint_size(); i++)
{
if (this->dataPtr->sceneMsg.joint(i).name() == _msg->name())
{
this->dataPtr->sceneMsg.mutable_joint(i)->CopyFrom(*_msg);
break;
}
}
if (i >= this->dataPtr->sceneMsg.joint_size())
{
msgs::Joint *newJoint = this->dataPtr->sceneMsg.add_joint();
newJoint->CopyFrom(*_msg);
}
}
//////////////////////////////////////////////////
void World::OnModelMsg(ConstModelPtr &_msg)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
this->dataPtr->modelMsgs.push_back(*_msg);
}
//////////////////////////////////////////////////
void World::BuildSceneMsg(msgs::Scene &_scene, BasePtr _entity)
{
if (_entity)
{
if (_entity->HasType(Entity::MODEL))
{
msgs::Model *modelMsg = _scene.add_model();
boost::static_pointer_cast<Model>(_entity)->FillMsg(*modelMsg);
}
else if (_entity->HasType(Entity::LIGHT))
{
msgs::Light *lightMsg = _scene.add_light();
boost::static_pointer_cast<physics::Light>(_entity)->FillMsg(*lightMsg);
}
for (unsigned int i = 0; i < _entity->GetChildCount(); ++i)
{
this->BuildSceneMsg(_scene, _entity->GetChild(i));
}
}
}
//////////////////////////////////////////////////
// void World::ModelUpdateTBB()
// {
// tbb::parallel_for (tbb::blocked_range<size_t>(0,
// this->dataPtr->models.size(), 10),
// ModelUpdate_TBB(&this->dataPtr->models));
// }
//////////////////////////////////////////////////
void World::ModelUpdateSingleLoop()
{
// Update all the models
for (unsigned int i = 0; i < this->dataPtr->rootElement->GetChildCount(); i++)
this->dataPtr->rootElement->GetChild(i)->Update();
}
//////////////////////////////////////////////////
void World::LoadPlugins()
{
// Load the plugins
if (this->dataPtr->sdf->HasElement("plugin"))
{
sdf::ElementPtr pluginElem = this->dataPtr->sdf->GetElement("plugin");
while (pluginElem)
{
this->LoadPlugin(pluginElem);
pluginElem = pluginElem->GetNextElement("plugin");
}
}
// Load the plugins for all the models
for (unsigned int i = 0; i < this->dataPtr->rootElement->GetChildCount(); i++)
{
if (this->dataPtr->rootElement->GetChild(i)->HasType(Base::MODEL))
{
ModelPtr model = boost::static_pointer_cast<Model>(
this->dataPtr->rootElement->GetChild(i));
// Modified by zhangshuai 2019.04.02 ----Begin
if (this->flag == 1)
{
// Judge if the model to load is simulated in this gazebo
for (unsigned int j = 0; j < this->distribution->GetGazeboIDPtr(gazeboLocalID)->GetModelCount(); j++)
{
if (model->GetName() == this->distribution->GetGazeboIDPtr(gazeboLocalID)->GetModelName(j))
{
// Original part
model->LoadPlugins();
// Original part
}
}
}
else
{
model->LoadPlugins();
}
// Modified by zhangshuai 2019.04.02 ----End
// model->LoadPlugins();
}
}
}
//////////////////////////////////////////////////
void World::LoadPlugin(const std::string &_filename,
const std::string &_name,
sdf::ElementPtr _sdf)
{
gazebo::WorldPluginPtr plugin = gazebo::WorldPlugin::Create(_filename,
_name);
if (plugin)
{
if (plugin->GetType() != WORLD_PLUGIN)
{
gzerr << "World[" << this->GetName() << "] is attempting to load "
<< "a plugin, but detected an incorrect plugin type. "
<< "Plugin filename[" << _filename << "] name[" << _name << "]\n";
return;
}
plugin->Load(shared_from_this(), _sdf);
this->dataPtr->plugins.push_back(plugin);
if (this->dataPtr->initialized)
plugin->Init();
}
}
//////////////////////////////////////////////////
void World::RemovePlugin(const std::string &_name)
{
for (auto plugin = this->dataPtr->plugins.begin();
plugin != this->dataPtr->plugins.end(); ++plugin)
{
if ((*plugin)->GetHandle() == _name)
{
this->dataPtr->plugins.erase(plugin);
break;
}
}
}
//////////////////////////////////////////////////
void World::LoadPlugin(sdf::ElementPtr _sdf)
{
std::string pluginName = _sdf->Get<std::string>("name");
std::string filename = _sdf->Get<std::string>("filename");
this->LoadPlugin(filename, pluginName, _sdf);
}
//////////////////////////////////////////////////
void World::ProcessEntityMsgs()
{
boost::mutex::scoped_lock lock(this->dataPtr->entityDeleteMutex);
for (auto &entityName : this->dataPtr->deleteEntity)
{
this->RemoveModel(entityName);
}
if (!this->dataPtr->deleteEntity.empty())
{
this->EnableAllModels();
this->dataPtr->deleteEntity.clear();
}
}
//////////////////////////////////////////////////
void World::ProcessRequestMsgs()
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
msgs::Response response;
for (auto const &requestMsg : this->dataPtr->requestMsgs)
{
bool send = true;
response.set_id(requestMsg.id());
response.set_request(requestMsg.request());
response.set_response("success");
if (requestMsg.request() == "entity_list")
{
msgs::Model_V modelVMsg;
for (unsigned int i = 0;
i < this->dataPtr->rootElement->GetChildCount(); ++i)
{
BasePtr entity = this->dataPtr->rootElement->GetChild(i);
if (entity->HasType(Base::MODEL))
{
msgs::Model *modelMsg = modelVMsg.add_models();
ModelPtr model = boost::dynamic_pointer_cast<Model>(entity);
model->FillMsg(*modelMsg);
}
}
response.set_type(modelVMsg.GetTypeName());
std::string *serializedData = response.mutable_serialized_data();
modelVMsg.SerializeToString(serializedData);
}
else if (requestMsg.request() == "entity_delete")
{
boost::mutex::scoped_lock lock2(this->dataPtr->entityDeleteMutex);
this->dataPtr->deleteEntity.push_back(requestMsg.data());
}
else if (requestMsg.request() == "entity_info")
{
BasePtr entity = this->dataPtr->rootElement->GetByName(requestMsg.data());
if (entity)
{
if (entity->HasType(Base::MODEL))
{
msgs::Model modelMsg;
ModelPtr model = boost::dynamic_pointer_cast<Model>(entity);
model->FillMsg(modelMsg);
std::string *serializedData = response.mutable_serialized_data();
modelMsg.SerializeToString(serializedData);
response.set_type(modelMsg.GetTypeName());
}
else if (entity->HasType(Base::LINK))
{
msgs::Link linkMsg;
LinkPtr link = boost::dynamic_pointer_cast<Link>(entity);
link->FillMsg(linkMsg);
std::string *serializedData = response.mutable_serialized_data();
linkMsg.SerializeToString(serializedData);
response.set_type(linkMsg.GetTypeName());
}
else if (entity->HasType(Base::COLLISION))
{
msgs::Collision collisionMsg;
CollisionPtr collision =
boost::dynamic_pointer_cast<Collision>(entity);
collision->FillMsg(collisionMsg);
std::string *serializedData = response.mutable_serialized_data();
collisionMsg.SerializeToString(serializedData);
response.set_type(collisionMsg.GetTypeName());
}
else if (entity->HasType(Base::JOINT))
{
msgs::Joint jointMsg;
JointPtr joint = boost::dynamic_pointer_cast<Joint>(entity);
joint->FillMsg(jointMsg);
std::string *serializedData = response.mutable_serialized_data();
jointMsg.SerializeToString(serializedData);
response.set_type(jointMsg.GetTypeName());
}
}
else
{
response.set_type("error");
response.set_response("nonexistent");
}
}
else if (requestMsg.request().find("world_sdf") != std::string::npos)
{
this->UpdateStateSDF();
sdf::ElementPtr newSdf(this->dataPtr->sdf);
// FIXME: Handle scale better on the server so we don't need to unscale
// SDF here. Issue #1825
if (requestMsg.request() == "world_sdf_save")
{
// Substitute all models sdf with unscaled versions
if (newSdf->HasElement("model"))
{
auto modelElem = newSdf->GetElement("model");
while (modelElem)
{
auto name = modelElem->GetAttribute("name")->GetAsString();
auto model = this->GetModel(name);
if (model)
{
auto unscaled = model->UnscaledSDF()->Clone();
modelElem->Copy(unscaled);
}
modelElem = modelElem->GetNextElement("model");
}
}
}
msgs::GzString msg;
std::ostringstream stream;
stream << "<?xml version='1.0'?>\n"
<< "<sdf version='" << SDF_VERSION << "'>\n"
<< newSdf->ToString("")
<< "</sdf>";
msg.set_data(stream.str());
std::string *serializedData = response.mutable_serialized_data();
msg.SerializeToString(serializedData);
response.set_type(msg.GetTypeName());
}
else if (requestMsg.request() == "scene_info")
{
this->dataPtr->sceneMsg.clear_model();
this->dataPtr->sceneMsg.clear_light();
this->BuildSceneMsg(this->dataPtr->sceneMsg, this->dataPtr->rootElement);
std::string *serializedData = response.mutable_serialized_data();
this->dataPtr->sceneMsg.SerializeToString(serializedData);
response.set_type(this->dataPtr->sceneMsg.GetTypeName());
}
else if (requestMsg.request() == "spherical_coordinates_info")
{
msgs::SphericalCoordinates sphereCoordMsg;
msgs::Set(&sphereCoordMsg, *(this->dataPtr->sphericalCoordinates));
std::string *serializedData = response.mutable_serialized_data();
sphereCoordMsg.SerializeToString(serializedData);
response.set_type(sphereCoordMsg.GetTypeName());
}
else
send = false;
if (send)
{
this->dataPtr->responsePub->Publish(response);
}
}
this->dataPtr->requestMsgs.clear();
}
//////////////////////////////////////////////////
void World::ProcessModelMsgs()
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
for (auto const &modelMsg : this->dataPtr->modelMsgs)
{
ModelPtr model;
if (modelMsg.has_id())
model = this->GetModelById(modelMsg.id());
else
model = this->GetModel(modelMsg.name());
if (!model)
gzerr << "Unable to find model["
<< modelMsg.name() << "] Id[" << modelMsg.id() << "]\n";
else
{
model->ProcessMsg(modelMsg);
// May 30, 2013: The following code was removed because it has a
// major performance impact when dragging complex object via the GUI.
// This code also does not seem to be necessary, since can just
// publish the incoming changes instead of a full model message. We
// are leaving it temporarily in case we find a need for it.
//
// Let all other subscribers know about the change
// msgs::Model msg;
// model->FillMsg(msg);
// // FillMsg fills the visual components from initial sdf
// // but problem is that Visuals may have changed e.g. through ~/visual,
// // so don't publish them to subscribers.
// for (int i = 0; i < msg.link_size(); ++i)
// {
// msg.mutable_link(i)->clear_visual();
// for (int j = 0; j < msg.link(i).collision_size(); ++j)
// {
// msg.mutable_link(i)->mutable_collision(j)->clear_visual();
// }
// }
this->dataPtr->modelPub->Publish(modelMsg);
}
}
if (!this->dataPtr->modelMsgs.empty())
{
this->EnableAllModels();
this->dataPtr->modelMsgs.clear();
}
}
//////////////////////////////////////////////////
void World::ProcessLightModifyMsgs()
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
for (auto const &lightModifyMsg : this->dataPtr->lightModifyMsgs)
{
LightPtr light = this->Light(lightModifyMsg.name());
if (!light)
{
gzerr << "Light [" << lightModifyMsg.name() << "] not found."
<< " Use topic ~/factory/light to spawn a new light." << std::endl;
continue;
}
else
{
// Update in scene message
for (int i = 0; i < this->dataPtr->sceneMsg.light_size(); ++i)
{
if (this->dataPtr->sceneMsg.light(i).name() == lightModifyMsg.name())
{
this->dataPtr->sceneMsg.mutable_light(i)->MergeFrom(lightModifyMsg);
break;
}
}
// Update light object
light->ProcessMsg(lightModifyMsg);
}
}
if (!this->dataPtr->lightModifyMsgs.empty())
{
this->dataPtr->lightModifyMsgs.clear();
}
}
//////////////////////////////////////////////////
void World::ProcessLightFactoryMsgs()
{
// LoadLight also publishes to ~/light/factory so copy light factory msgs to
// avoid deadlock in OnLightFactory callback when trying to lock receiveMutex
std::list<msgs::Light> lightFactoryMsgsCopy;
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
std::copy(this->dataPtr->lightFactoryMsgs.begin(),
this->dataPtr->lightFactoryMsgs.end(),
std::back_inserter(lightFactoryMsgsCopy));
this->dataPtr->lightFactoryMsgs.clear();
}
for (auto const &lightFactoryMsg : lightFactoryMsgsCopy)
{
LightPtr light = this->Light(lightFactoryMsg.name());
if (light)
{
continue;
}
else
{
// Add to world SDF
sdf::ElementPtr lightSDF = msgs::LightToSDF(lightFactoryMsg);
lightSDF->SetParent(this->dataPtr->sdf);
lightSDF->GetParent()->InsertElement(lightSDF);
// Create new light object
this->LoadLight(lightSDF, this->dataPtr->rootElement);
}
}
}
//////////////////////////////////////////////////
void World::ProcessFactoryMsgs()
{
std::list<sdf::ElementPtr> modelsToLoad, lightsToLoad;
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
for (auto const &factoryMsg : this->dataPtr->factoryMsgs)
{
this->dataPtr->factorySDF->Root()->ClearElements();
if (factoryMsg.has_sdf() && !factoryMsg.sdf().empty())
{
// SDF Parsing happens here
if (!sdf::readString(factoryMsg.sdf(), this->dataPtr->factorySDF))
{
gzerr << "Unable to read sdf string[" << factoryMsg.sdf() << "]\n";
continue;
}
}
else if (factoryMsg.has_sdf_filename() &&
!factoryMsg.sdf_filename().empty())
{
std::string filename = common::ModelDatabase::Instance()->GetModelFile(
factoryMsg.sdf_filename());
if (!sdf::readFile(filename, this->dataPtr->factorySDF))
{
gzerr << "Unable to read sdf file.\n";
continue;
}
}
else if (factoryMsg.has_clone_model_name())
{
ModelPtr model = this->GetModel(factoryMsg.clone_model_name());
if (!model)
{
gzerr << "Unable to clone model[" << factoryMsg.clone_model_name()
<< "]. Model not found.\n";
continue;
}
this->dataPtr->factorySDF->Root()->InsertElement(
model->GetSDF()->Clone());
std::string newName = model->GetName() + "_clone";
newName = this->UniqueModelName(newName);
this->dataPtr->factorySDF->Root()->GetElement("model")->GetAttribute(
"name")
->Set(newName);
}
else
{
gzerr << "Unable to load sdf from factory message."
<< "No SDF or SDF filename specified.\n";
continue;
}
if (factoryMsg.has_edit_name())
{
BasePtr base =
this->dataPtr->rootElement->GetByName(factoryMsg.edit_name());
if (base)
{
sdf::ElementPtr elem;
if (this->dataPtr->factorySDF->Root()->GetName() == "sdf")
elem = this->dataPtr->factorySDF->Root()->GetFirstElement();
else
elem = this->dataPtr->factorySDF->Root();
base->UpdateParameters(elem);
}
}
else
{
bool isActor = false;
bool isModel = false;
bool isLight = false;
sdf::ElementPtr elem = this->dataPtr->factorySDF->Root()->Clone();
if (!elem)
{
gzerr << "Invalid SDF:";
this->dataPtr->factorySDF->Root()->PrintValues("");
continue;
}
if (elem->HasElement("world"))
elem = elem->GetElement("world");
if (elem->HasElement("model"))
{
elem = elem->GetElement("model");
isModel = true;
}
else if (elem->HasElement("light"))
{
elem = elem->GetElement("light");
isLight = true;
}
else if (elem->HasElement("actor"))
{
elem = elem->GetElement("actor");
isActor = true;
}
else
{
gzerr << "Unable to find a model, light, or actor in:\n";
this->dataPtr->factorySDF->Root()->PrintValues("");
continue;
}
elem->SetParent(this->dataPtr->sdf);
elem->GetParent()->InsertElement(elem);
if (factoryMsg.has_pose())
{
elem->GetElement("pose")->Set(msgs::ConvertIgn(factoryMsg.pose()));
}
if (isActor)
{
ActorPtr actor = this->LoadActor(elem, this->dataPtr->rootElement);
actor->Init();
}
else if (isModel)
{
// Make sure model name is unique
auto entityName = elem->Get<std::string>("name");
entityName = this->UniqueModelName(entityName);
elem->GetAttribute("name")->Set(entityName);
modelsToLoad.push_back(elem);
}
else if (isLight)
{
lightsToLoad.push_back(elem);
}
}
}
this->dataPtr->factoryMsgs.clear();
}
// Load models
for (auto const &elem : modelsToLoad)
{
try
{
boost::mutex::scoped_lock lock(this->dataPtr->factoryDeleteMutex);
ModelPtr model = this->LoadModel(elem, this->dataPtr->rootElement);
if (model != nullptr)
{
model->Init();
// Modified by zhangshuai 2019.04.02 ----Begin
if (this->flag == 1)
{
// Judge if the model to load is simulated in this gazebo
for (unsigned int i = 0; i < this->distribution->GetGazeboIDPtr(gazeboLocalID)->GetModelCount(); i++)
{
if (model->GetName() == this->distribution->GetGazeboIDPtr(gazeboLocalID)->GetModelName(i))
{
// Original part
model->LoadPlugins();
// Original part
}
}
}
else
{
model->LoadPlugins();
}
// Modified by zhangshuai 2019.04.02 ----End
}
}
catch (...)
{
gzerr << "Loading model from factory message failed\n";
}
}
// Load lights
for (auto const &elem : lightsToLoad)
{
try
{
boost::mutex::scoped_lock lock(this->dataPtr->factoryDeleteMutex);
LightPtr light = this->LoadLight(elem, this->dataPtr->rootElement);
light->Init();
}
catch (...)
{
gzerr << "Loading light from factory message failed\n";
}
}
}
//////////////////////////////////////////////////
ModelPtr World::GetModelBelowPoint(const math::Vector3 &_pt)
{
ModelPtr model;
EntityPtr entity = this->GetEntityBelowPoint(_pt);
if (entity)
model = entity->GetParentModel();
else
gzerr << "Unable to find entity below point[" << _pt << "]\n";
return model;
}
//////////////////////////////////////////////////
EntityPtr World::GetEntityBelowPoint(const math::Vector3 &_pt)
{
std::string entityName;
double dist;
math::Vector3 end;
end = _pt;
end.z -= 1000;
this->dataPtr->physicsEngine->InitForThread();
this->dataPtr->testRay->SetPoints(_pt, end);
this->dataPtr->testRay->GetIntersection(dist, entityName);
return this->GetEntity(entityName);
}
//////////////////////////////////////////////////
void World::SetState(const WorldState &_state)
{
this->SetSimTime(_state.GetSimTime());
this->dataPtr->logRealTime = _state.GetRealTime();
this->dataPtr->iterations = _state.GetIterations();
// Insertions (adapted from ProcessFactoryMsgs)
auto insertions = _state.Insertions();
for (auto const &insertion : insertions)
{
this->dataPtr->factorySDF->Root()->ClearElements();
std::stringstream sdfStr;
sdfStr << "<sdf version='" << SDF_VERSION << "'>"
<< insertion
<< "</sdf>";
// SDF Parsing happens here
if (!sdf::readString(sdfStr.str(), this->dataPtr->factorySDF))
{
gzerr << "Unable to read sdf string[" << insertion << "]" << std::endl;
continue;
}
// Get entity being inserted
bool isModel = false;
bool isLight = false;
auto elem = this->dataPtr->factorySDF->Root()->Clone();
if (!elem)
{
gzerr << "Invalid SDF:" << std::endl;
this->dataPtr->factorySDF->Root()->PrintValues("");
continue;
}
if (elem->HasElement("world"))
elem = elem->GetElement("world");
if (elem->HasElement("model"))
{
elem = elem->GetElement("model");
isModel = true;
}
else if (elem->HasElement("light"))
{
elem = elem->GetElement("light");
isLight = true;
}
else
{
gzerr << "Unable to find a model or light in:" << std::endl;
this->dataPtr->factorySDF->Root()->PrintValues("");
continue;
}
elem->SetParent(this->dataPtr->sdf);
elem->GetParent()->InsertElement(elem);
if (isModel)
{
try
{
boost::mutex::scoped_lock lock(this->dataPtr->factoryDeleteMutex);
ModelPtr model = this->LoadModel(elem, this->dataPtr->rootElement);
if (model != nullptr)
{
model->Init();
if (!util::LogPlay::Instance()->IsOpen())
model->LoadPlugins();
}
}
catch (...)
{
gzerr << "Loading model from world state insertion failed" << std::endl;
}
}
else if (isLight)
{
try
{
boost::mutex::scoped_lock lock(this->dataPtr->factoryDeleteMutex);
LightPtr light = this->LoadLight(elem, this->dataPtr->rootElement);
light->Init();
}
catch (...)
{
gzerr << "Loading light from world state insertion failed." << std::endl;
}
}
}
// Model updates
const ModelState_M modelStates = _state.GetModelStates();
for (auto const &modelState : modelStates)
{
ModelPtr model = this->GetModel(modelState.second.GetName());
if (model)
model->SetState(modelState.second);
else
gzerr << "Unable to find model[" << modelState.second.GetName() << "]\n";
}
// Light updates
const LightState_M lightStates = _state.LightStates();
for (auto const &lightState : lightStates)
{
LightPtr light = this->Light(lightState.second.GetName());
if (light)
light->SetState(lightState.second);
else
{
gzerr << "Unable to find light[" << lightState.second.GetName() << "]"
<< std::endl;
}
}
// Deletions
auto deletions = _state.Deletions();
for (auto const &deletion : deletions)
{
// This works for models and lights
this->RemoveModel(deletion);
}
}
//////////////////////////////////////////////////
void World::InsertModelFile(const std::string &_sdfFilename)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
msgs::Factory msg;
msg.set_sdf_filename(_sdfFilename);
this->dataPtr->factoryMsgs.push_back(msg);
}
//////////////////////////////////////////////////
void World::InsertModelSDF(const sdf::SDF &_sdf)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
msgs::Factory msg;
msg.set_sdf(_sdf.ToString());
this->dataPtr->factoryMsgs.push_back(msg);
}
//////////////////////////////////////////////////
void World::InsertModelString(const std::string &_sdfString)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
msgs::Factory msg;
msg.set_sdf(_sdfString);
this->dataPtr->factoryMsgs.push_back(msg);
}
//////////////////////////////////////////////////
std::string World::StripWorldName(const std::string &_name) const
{
if (_name.find(this->GetName() + "::") == 0)
return _name.substr(this->GetName().size() + 2);
else
return _name;
}
//////////////////////////////////////////////////
void World::EnableAllModels()
{
for (auto &model : this->dataPtr->models)
{
model->SetEnabled(true);
}
}
//////////////////////////////////////////////////
void World::DisableAllModels()
{
for (auto &model : this->dataPtr->models)
{
model->SetEnabled(false);
}
}
//////////////////////////////////////////////////
void World::UpdateStateSDF()
{
this->dataPtr->sdf->Update();
sdf::ElementPtr stateElem = this->dataPtr->sdf->GetElement("state");
stateElem->ClearElements();
WorldState currentState(shared_from_this());
currentState.FillSDF(stateElem);
}
//////////////////////////////////////////////////
void World::LogModelResources()
{
if (!util::LogRecord::Instance()->RecordResources())
return;
std::set<std::string> modelNames;
std::set<std::string> fileNames;
auto addModelResource = [&](const std::string &_uri) {
if (_uri.empty())
return;
const std::string modelPrefix = "model://";
const std::string filePrefix = "file://";
if (_uri.find(modelPrefix) == 0)
{
std::string modelName = _uri.substr(modelPrefix.size(),
_uri.find("/", modelPrefix.size()) - modelPrefix.size());
modelNames.insert(modelName);
}
else if (_uri.find(filePrefix) == 0 || _uri[0] == '/')
{
fileNames.insert(_uri);
}
};
// record model resources if option is enabled.
for (auto const &model : this->dataPtr->models)
{
sdf::ElementPtr modelElem = model->GetSDF();
if (modelElem->HasElement("link"))
{
sdf::ElementPtr linkElem = modelElem->GetElement("link");
while (linkElem)
{
if (linkElem->HasElement("visual"))
{
sdf::ElementPtr visualElem = linkElem->GetElement("visual");
while (visualElem)
{
sdf::ElementPtr geomElem = visualElem->GetElement("geometry");
if (geomElem->HasElement("mesh"))
{
const std::string meshUri = geomElem->GetElement("mesh")
->Get<std::string>("uri");
if (!meshUri.empty())
{
addModelResource(meshUri);
}
}
if (visualElem->HasElement("material"))
{
sdf::ElementPtr matElem = visualElem->GetElement("material");
if (matElem->HasElement("script"))
{
sdf::ElementPtr scriptElem = matElem->GetElement("script");
if (scriptElem->HasElement("uri"))
{
std::string matUri = scriptElem->Get<std::string>("uri");
if (!matUri.empty())
{
addModelResource(matUri);
}
}
}
}
visualElem = visualElem->GetNextElement("visual");
}
}
if (linkElem->HasElement("collision"))
{
sdf::ElementPtr collisionElem = linkElem->GetElement("collision");
while (collisionElem)
{
sdf::ElementPtr geomElem = collisionElem->GetElement("geometry");
if (geomElem->HasElement("mesh"))
{
const std::string meshUri = geomElem->GetElement("mesh")
->Get<std::string>("uri");
if (!meshUri.empty())
{
addModelResource(meshUri);
}
}
collisionElem = collisionElem->GetNextElement("collision");
}
}
linkElem = linkElem->GetNextElement("link");
}
}
}
if (!util::LogRecord::Instance()->SaveModels(modelNames) ||
!util::LogRecord::Instance()->SaveFiles(fileNames))
{
gzwarn << "Failed to save model resources during logging\n";
}
}
//////////////////////////////////////////////////
bool World::OnLog(std::ostringstream &_stream)
{
int bufferIndex = this->dataPtr->currentStateBuffer;
// Save the entire state when its the first call to OnLog.
if (util::LogRecord::Instance()->FirstUpdate())
{
this->dataPtr->sdf->Update();
_stream << "<sdf version ='";
_stream << SDF_VERSION;
_stream << "'>\n";
_stream << this->dataPtr->sdf->ToString("");
_stream << "</sdf>\n";
}
else if (this->dataPtr->states[bufferIndex].size() >= 1)
{
{
boost::mutex::scoped_lock lock(this->dataPtr->logBufferMutex);
this->dataPtr->currentStateBuffer ^= 1;
}
for (auto const &worldState : this->dataPtr->states[bufferIndex])
{
_stream << "<sdf version='" << SDF_VERSION << "'>"
<< worldState
<< "</sdf>";
}
this->dataPtr->states[bufferIndex].clear();
}
// Logging has stopped. Wait for log worker to finish. Output last bit
// of data, and reset states.
if (!util::LogRecord::Instance()->Running())
{
boost::mutex::scoped_lock lock(this->dataPtr->logBufferMutex);
// Output any data that may have been pushed onto the queue
for (size_t i = 0;
i < this->dataPtr->states[this->dataPtr->currentStateBuffer ^ 1].size();
++i)
{
_stream << "<sdf version='" << SDF_VERSION << "'>"
<< this->dataPtr->states[this->dataPtr->currentStateBuffer ^ 1][i]
<< "</sdf>";
}
for (size_t i = 0;
i < this->dataPtr->states[this->dataPtr->currentStateBuffer].size();
++i)
{
_stream << "<sdf version='" << SDF_VERSION << "'>"
<< this->dataPtr->states[this->dataPtr->currentStateBuffer][i]
<< "</sdf>";
}
// Clear everything.
this->dataPtr->states[0].clear();
this->dataPtr->states[1].clear();
this->dataPtr->stateToggle = 0;
this->dataPtr->prevStates[0] = WorldState();
this->dataPtr->prevStates[1] = WorldState();
}
this->LogModelResources();
return true;
}
//////////////////////////////////////////////////
void World::ProcessMessages()
{
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
if ((this->dataPtr->posePub && this->dataPtr->posePub->HasConnections()) ||
(this->dataPtr->poseLocalPub &&
this->dataPtr->poseLocalPub->HasConnections()))
{
msgs::PosesStamped msg;
// Time stamp this PosesStamped message
msgs::Set(msg.mutable_time(), this->GetSimTime());
if (!this->dataPtr->publishModelPoses.empty() ||
!this->dataPtr->publishLightPoses.empty())
{
for (auto const &model : this->dataPtr->publishModelPoses)
{
std::list<ModelPtr> modelList;
modelList.push_back(model);
while (!modelList.empty())
{
ModelPtr m = modelList.front();
modelList.pop_front();
msgs::Pose *poseMsg = msg.add_pose();
// Publish the model's relative pose
poseMsg->set_name(m->GetScopedName());
poseMsg->set_id(m->GetId());
msgs::Set(poseMsg, m->GetRelativePose().Ign());
// Publish each of the model's child links relative poses
Link_V links = m->GetLinks();
for (auto const &link : links)
{
poseMsg = msg.add_pose();
poseMsg->set_name(link->GetScopedName());
poseMsg->set_id(link->GetId());
msgs::Set(poseMsg, link->GetRelativePose().Ign());
}
// add all nested models to the queue
Model_V models = m->NestedModels();
for (auto const &n : models)
modelList.push_back(n);
}
}
for (auto const &light : this->dataPtr->publishLightPoses)
{
msgs::Pose *poseMsg = msg.add_pose();
// Publish the light's pose
poseMsg->set_name(light->GetScopedName());
// \todo Change to relative once lights can be attached to links
// on the rendering side
// \todo Hack: we use empty id to indicate it's pose of a light
// Need to add an id field to light.proto
// poseMsg->set_id(light->GetId());
msgs::Set(poseMsg, light->GetWorldPose().Ign());
}
if (this->dataPtr->posePub && this->dataPtr->posePub->HasConnections())
this->dataPtr->posePub->Publish(msg);
}
if (this->dataPtr->poseLocalPub &&
this->dataPtr->poseLocalPub->HasConnections())
{
// rendering::Scene depends on this timestamp, which is used by
// rendering sensors to time stamp their data
this->dataPtr->poseLocalPub->Publish(msg);
}
}
this->dataPtr->publishModelPoses.clear();
this->dataPtr->publishLightPoses.clear();
}
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
if (this->dataPtr->modelPub && this->dataPtr->modelPub->HasConnections())
{
if (!this->dataPtr->publishModelScales.empty())
{
for (auto const &model : this->dataPtr->publishModelScales)
{
std::list<ModelPtr> modelList;
modelList.push_back(model);
while (!modelList.empty())
{
ModelPtr m = modelList.front();
modelList.pop_front();
// Publish the model's scale
msgs::Model msg;
msg.set_name(m->GetScopedName());
msg.set_id(m->GetId());
msgs::Set(msg.mutable_scale(), m->Scale());
// Not publishing for links for now
// add all nested models to the queue
Model_V models = m->NestedModels();
for (auto const &n : models)
modelList.push_back(n);
this->dataPtr->modelPub->Publish(msg);
}
}
}
}
this->dataPtr->publishModelScales.clear();
}
if (common::Time::GetWallTime() - this->dataPtr->prevProcessMsgsTime >
this->dataPtr->processMsgsPeriod)
{
this->ProcessPlaybackControlMsgs();
this->ProcessEntityMsgs();
this->ProcessRequestMsgs();
this->ProcessFactoryMsgs();
this->ProcessModelMsgs();
this->ProcessLightFactoryMsgs();
this->ProcessLightModifyMsgs();
this->dataPtr->prevProcessMsgsTime = common::Time::GetWallTime();
}
}
//////////////////////////////////////////////////
void World::PublishWorldStats()
{
this->dataPtr->worldStatsMsg.Clear();
msgs::Set(this->dataPtr->worldStatsMsg.mutable_sim_time(),
this->GetSimTime());
msgs::Set(this->dataPtr->worldStatsMsg.mutable_real_time(),
this->GetRealTime());
msgs::Set(this->dataPtr->worldStatsMsg.mutable_pause_time(),
this->GetPauseTime());
this->dataPtr->worldStatsMsg.set_iterations(this->dataPtr->iterations);
this->dataPtr->worldStatsMsg.set_paused(this->IsPaused());
if (util::LogPlay::Instance()->IsOpen())
{
msgs::LogPlaybackStatistics logStats;
msgs::Set(logStats.mutable_start_time(),
util::LogPlay::Instance()->LogStartTime());
msgs::Set(logStats.mutable_end_time(),
util::LogPlay::Instance()->LogEndTime());
this->dataPtr->worldStatsMsg.mutable_log_playback_stats()->CopyFrom(
logStats);
}
if (this->dataPtr->statPub && this->dataPtr->statPub->HasConnections())
this->dataPtr->statPub->Publish(this->dataPtr->worldStatsMsg);
this->dataPtr->prevStatTime = common::Time::GetWallTime();
}
//////////////////////////////////////////////////
bool World::IsLoaded() const
{
return this->dataPtr->loaded;
}
//////////////////////////////////////////////////
void World::PublishModelPose(physics::ModelPtr _model)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
// Only add if the model name is not in the list
this->dataPtr->publishModelPoses.insert(_model);
}
//////////////////////////////////////////////////
void World::PublishModelScale(physics::ModelPtr _model)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
// Only add if the model name is not in the list
this->dataPtr->publishModelScales.insert(_model);
}
//////////////////////////////////////////////////
void World::PublishLightPose(const physics::LightPtr _light)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
// Only add if the light name is not in the list
this->dataPtr->publishLightPoses.insert(_light);
}
//////////////////////////////////////////////////
void World::LogWorker()
{
boost::mutex::scoped_lock lock(this->dataPtr->logMutex);
WorldPtr self = shared_from_this();
this->dataPtr->logPrevIteration = this->dataPtr->iterations;
GZ_ASSERT(self, "Self pointer to World is invalid");
// Init the prevUnfilteredState
this->dataPtr->prevUnfilteredState.Load(self);
while (!this->dataPtr->stop)
{
// get unfiltered world state
WorldState unfilteredState;
{
boost::mutex::scoped_lock dLock(this->dataPtr->entityDeleteMutex);
unfilteredState.Load(self);
}
// compute world state diff and find out about insertions and deletions
std::vector<std::string> insertions;
std::vector<std::string> deletions;
bool insertDelete = false;
{
WorldState unfilteredDiffState = unfilteredState -
this->dataPtr->prevUnfilteredState;
if (!unfilteredDiffState.IsZero())
{
insertions = unfilteredDiffState.Insertions();
deletions = unfilteredDiffState.Deletions();
insertDelete = !insertions.empty() || !deletions.empty();
}
}
this->dataPtr->prevUnfilteredState = unfilteredState;
// Throttle state capture based on log recording frequency.
auto simTime = this->GetSimTime();
if ((simTime - this->dataPtr->logLastStateTime >=
util::LogRecord::Instance()->Period()) ||
insertDelete)
{
int currState = (this->dataPtr->stateToggle + 1) % 2;
std::string filterStr = util::LogRecord::Instance()->Filter();
// compute diff for filtered states
{
boost::mutex::scoped_lock dLock(this->dataPtr->entityDeleteMutex);
this->dataPtr->prevStates[currState].LoadWithFilter(self, filterStr);
}
WorldState diffState = this->dataPtr->prevStates[currState] -
this->dataPtr->prevStates[this->dataPtr->stateToggle];
this->dataPtr->logPrevIteration = this->dataPtr->iterations;
if (!diffState.IsZero() || insertDelete)
{
this->dataPtr->stateToggle = currState;
{
// Store the entire current state (instead of the diffState). A slow
// moving link may never be captured if only diff state is recorded.
boost::mutex::scoped_lock bLock(this->dataPtr->logBufferMutex);
this->dataPtr->prevStates[currState].SetInsertions(insertions);
this->dataPtr->prevStates[currState].SetDeletions(deletions);
this->dataPtr->states[this->dataPtr->currentStateBuffer].push_back(
this->dataPtr->prevStates[currState]);
// Tell the logger to update, once the number of states exceeds 1000
if (this->dataPtr->states[this->dataPtr->currentStateBuffer].size() >
1000)
{
util::LogRecord::Instance()->Notify();
}
}
}
this->dataPtr->logLastStateTime = simTime;
}
this->dataPtr->logContinueCondition.notify_all();
// Wait until there is work to be done.
this->dataPtr->logCondition.wait(lock);
}
// Make sure nothing is blocked by this thread.
this->dataPtr->logContinueCondition.notify_all();
}
/////////////////////////////////////////////////
uint32_t World::GetIterations() const
{
return this->dataPtr->iterations;
}
//////////////////////////////////////////////////
void World::RemoveModel(const std::string &_name)
{
boost::recursive_mutex::scoped_lock plock(
*this->GetPhysicsEngine()->GetPhysicsUpdateMutex());
boost::mutex::scoped_lock flock(this->dataPtr->factoryDeleteMutex);
// Remove all the dirty poses from the delete entity.
{
for (auto entity = this->dataPtr->dirtyPoses.begin();
entity != this->dataPtr->dirtyPoses.end(); ++entity)
{
if ((*entity)->GetName() == _name ||
((*entity)->GetParent() && (*entity)->GetParent()->GetName() == _name))
{
this->dataPtr->dirtyPoses.erase(entity++);
}
else
++entity;
}
}
// Remove from SDF
if (this->dataPtr->sdf->HasElement("model"))
{
sdf::ElementPtr childElem = this->dataPtr->sdf->GetElement("model");
while (childElem && childElem->Get<std::string>("name") != _name)
childElem = childElem->GetNextElement("model");
if (childElem)
{
this->dataPtr->sdf->RemoveChild(childElem);
}
}
if (this->dataPtr->sdf->HasElement("light"))
{
sdf::ElementPtr childElem = this->dataPtr->sdf->GetElement("light");
while (childElem && childElem->Get<std::string>("name") != _name)
childElem = childElem->GetNextElement("light");
if (childElem)
{
this->dataPtr->sdf->RemoveChild(childElem);
}
}
// remove objects in world
{
boost::recursive_mutex::scoped_lock lock(
*this->GetPhysicsEngine()->GetPhysicsUpdateMutex());
// Remove model object
for (auto model = this->dataPtr->models.begin();
model != this->dataPtr->models.end(); ++model)
{
if ((*model)->GetName() == _name || (*model)->GetScopedName() == _name)
{
this->dataPtr->models.erase(model);
this->dataPtr->rootElement->RemoveChild(_name);
break;
}
}
// Remove light object
for (auto light = this->dataPtr->lights.begin();
light != this->dataPtr->lights.end(); ++light)
{
if ((*light)->GetScopedName() == _name)
{
if ((*light)->GetParent())
{
// Avoid calling: this->dataPtr->rootElement->RemoveChild(_name);
// which removes the first child it finds with _name, ignoring
// entity type (model or light) and scoping of names,
// e.g. In a world with "point" and "parent::point" entities,
// removing "point" will remove "parent::child" if it's first in the
// list
(*light)->GetParent()->RemoveChild(*light);
}
this->dataPtr->lights.erase(light);
break;
}
}
// Find the light by name in the scene msg, and remove it.
for (int i = 0; i < this->dataPtr->sceneMsg.light_size(); ++i)
{
if (this->dataPtr->sceneMsg.light(i).name() == _name)
{
this->dataPtr->sceneMsg.mutable_light()->SwapElements(i,
this->dataPtr->sceneMsg.light_size() - 1);
this->dataPtr->sceneMsg.mutable_light()->RemoveLast();
break;
}
}
}
// Cleanup the publishModelPoses list.
{
boost::recursive_mutex::scoped_lock lock2(*this->dataPtr->receiveMutex);
for (auto model = this->dataPtr->publishModelPoses.begin();
model != this->dataPtr->publishModelPoses.end(); ++model)
{
if ((*model)->GetName() == _name || (*model)->GetScopedName() == _name)
{
this->dataPtr->publishModelPoses.erase(model);
break;
}
}
}
// Cleanup the publishLightPoses list.
{
boost::recursive_mutex::scoped_lock lock2(*this->dataPtr->receiveMutex);
for (auto light : this->dataPtr->publishLightPoses)
{
if (light->GetName() == _name || light->GetScopedName() == _name)
{
this->dataPtr->publishLightPoses.erase(light);
break;
}
}
}
}
/////////////////////////////////////////////////
void World::OnLightMsg(ConstLightPtr & /*_msg*/)
{
gzerr << "Topic ~/light deprecated, use ~/factory/light to spawn new lights "
<< "and ~/light/modify to modify existing lights." << std::endl;
}
/////////////////////////////////////////////////
void World::OnLightModifyMsg(ConstLightPtr &_msg)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
this->dataPtr->lightModifyMsgs.push_back(*_msg);
}
/////////////////////////////////////////////////
void World::OnLightFactoryMsg(ConstLightPtr &_msg)
{
boost::recursive_mutex::scoped_lock lock(*this->dataPtr->receiveMutex);
this->dataPtr->lightFactoryMsgs.push_back(*_msg);
}
/////////////////////////////////////////////////
msgs::Scene World::GetSceneMsg() const
{
return this->dataPtr->sceneMsg;
}
/////////////////////////////////////////////////
boost::mutex *World::GetSetWorldPoseMutex() const
{
return this->dataPtr->setWorldPoseMutex;
}
/////////////////////////////////////////////////
bool World::GetEnablePhysicsEngine()
{
return this->dataPtr->enablePhysicsEngine;
}
/////////////////////////////////////////////////
void World::EnablePhysicsEngine(bool _enable)
{
this->dataPtr->enablePhysicsEngine = _enable;
}
/////////////////////////////////////////////////
void World::_AddDirty(Entity *_entity)
{
GZ_ASSERT(_entity != nullptr, "_entity is nullptr");
this->dataPtr->dirtyPoses.push_back(_entity);
}
/////////////////////////////////////////////////
void World::ResetPhysicsStates()
{
for (auto &model : this->dataPtr->models)
model->ResetPhysicsStates();
}
//////////////////////////////////////////////////
std::string World::UniqueModelName(const std::string &_name)
{
std::string result = _name;
int i = 0;
while (this->GetModel(result))
result = _name + "_" + std::to_string(i++);
return result;
}
// Added by zhangshuai 2019.04.02 ----Begin
//////////////////////////////////////////////////
/// add for read the element of "distribution"
DistributionPtr World::GetDistribution()
{
return this->distribution;
}
//////////////////////////////////////////////////
/// add for read the element of "gazeboLocalID"
int World::GetGazeboLocalID()
{
return this->gazeboLocalID;
}
//////////////////////////////////////////////////
/// add for read the element of "flag"
int World::GetFlag()
{
return this->flag;
}
// Added by zhangshuai 2019.04.02 ----End