Skip to content
Snippets Groups Projects
Commit 3b2c5746 authored by Antoine Lima's avatar Antoine Lima
Browse files

Rewrite to separate perception display from state visuals

Hopping this will boost performance as now we are building a big
array of simple object instead of an array of complex objects (themselves
composed of simple objects)
parent 0b5f3b1c
No related branches found
No related tags found
No related merge requests found
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <rviz/default_plugin/covariance_property.h> #include <rviz/default_plugin/covariance_property.h>
#include <rviz/properties/int_property.h> #include <rviz/properties/int_property.h>
#include <rviz/ogre_helpers/shape.h> #include <rviz/ogre_helpers/shape.h>
#include <rviz/ogre_helpers/arrow.h>
#include <rviz/ogre_helpers/movable_text.h> #include <rviz/ogre_helpers/movable_text.h>
#include <rviz/ogre_helpers/billboard_line.h> #include <rviz/ogre_helpers/billboard_line.h>
#include <rviz/frame_manager.h> #include <rviz/frame_manager.h>
...@@ -19,8 +20,6 @@ ...@@ -19,8 +20,6 @@
namespace rviz_multiception namespace rviz_multiception
{ {
// The constructor must have no arguments, so we can't give the
// constructor the parameters it needs to fully initialize.
PerceptionsDisplay::PerceptionsDisplay() PerceptionsDisplay::PerceptionsDisplay()
{ {
color_property_ = new rviz::ColorProperty( "Color", QColor( 10, 10, 10 ), color_property_ = new rviz::ColorProperty( "Color", QColor( 10, 10, 10 ),
...@@ -47,55 +46,55 @@ PerceptionsDisplay::PerceptionsDisplay() ...@@ -47,55 +46,55 @@ PerceptionsDisplay::PerceptionsDisplay()
this, SLOT( queueRender() )); this, SLOT( queueRender() ));
} }
// After the top-level rviz::Display::initialize() does its own setup,
// it calls the subclass's onInitialize() function. This is where we
// instantiate all the workings of the class. We make sure to also
// call our immediate super-class's onInitialize() function, since it
// does important stuff setting up the message filter.
//
// Note that "MFDClass" is a typedef of
// ``MessageFilterDisplay<message type>``, to save typing that long
// templated class name every time you need to refer to the
// superclass.
void PerceptionsDisplay::onInitialize() void PerceptionsDisplay::onInitialize()
{ {
MFDClass::onInitialize(); MFDClass::onInitialize();
frame_node_ = scene_node_->createChildSceneNode();
} }
PerceptionsDisplay::~PerceptionsDisplay() PerceptionsDisplay::~PerceptionsDisplay()
{ {
scene_manager_->destroySceneNode(frame_node_);
} }
// Clear the visuals by deleting their objects. // Clear the visuals by deleting their objects.
void PerceptionsDisplay::reset() void PerceptionsDisplay::reset()
{ {
MFDClass::reset(); MFDClass::reset();
state_visuals_.clear(); resetVectors();
shape_visuals_.clear(); }
text_visuals_.clear();
trace_buffer_.clear(); void PerceptionsDisplay::resetVectors(size_t N)
trace_visuals_.clear(); {
for(Ogre::SceneNode* textNode: text_nodes_) context_->getSceneManager()->destroySceneNode(textNode); pose_visuals_.clear(); pose_visuals_.reserve(N);
text_nodes_.clear(); shape_visuals_.clear(); shape_visuals_.reserve(N);
text_visuals_.clear(); cov_visuals_.clear(); cov_visuals_.reserve(N);
text_visuals_.clear(); text_visuals_.reserve(N);
for(Ogre::SceneNode* textNode: text_nodes_) scene_manager_->destroySceneNode(textNode);
text_nodes_.clear(); text_nodes_.reserve(N);
frame_node_->detachAllObjects();
frame_node_->removeAndDestroyAllChildren();
} }
// Set the current color and alpha values for each visual. // Set the current color and alpha values for each visual.
void PerceptionsDisplay::updateColorAndAlpha() void PerceptionsDisplay::updateColorAndAlpha()
{ {
float alpha = alpha_property_->getFloat(); const float alpha = alpha_property_->getFloat();
float shape_alpha = shape_alpha_property_->getFloat(); const float shape_alpha = shape_alpha_property_->getFloat();
Ogre::ColourValue color = color_property_->getOgreColor(); const Ogre::ColourValue color = color_property_->getOgreColor();
const Ogre::ColourValue textColor = text_color_property_->getOgreColor();
for(size_t i=0; i<state_visuals_.size(); i++) for(size_t i=0; i<pose_visuals_.size(); i++)
{ {
state_visuals_[i]->setColor(color.r, color.g, color.b, alpha); pose_visuals_[i]->setColor(color.r, color.g, color.b, alpha);
shape_visuals_[i]->setColor(color.r, color.g, color.b, shape_alpha); shape_visuals_[i]->setColor(color.r, color.g, color.b, alpha*shape_alpha);
// cov_visuals_[i]->setColor(color.r, color.g, color.b, alpha*shape_alpha);
} }
for(size_t i=0; i<state_visuals_.size(); i++) for(size_t i=0; i<text_visuals_.size(); i++)
{ {
trace_visuals_[i]->setColor(color.r, color.g, color.b, alpha); text_visuals_[i]->setColor(textColor);
} }
} }
...@@ -116,79 +115,57 @@ void PerceptionsDisplay::filterTraceBuffer() ...@@ -116,79 +115,57 @@ void PerceptionsDisplay::filterTraceBuffer()
}); });
} }
// This is our callback to handle an incoming message.
void PerceptionsDisplay::processMessage(const multiception::Perceptions::ConstPtr& msg) void PerceptionsDisplay::processMessage(const multiception::Perceptions::ConstPtr& msg)
{ {
// Here we call the rviz::FrameManager to get the transform from the if(msg->perceptions.size()>0)
// fixed frame to the frame in the header of this message. If {
// it fails, we can't do anything else so we return. resetVectors(msg->perceptions.size());
const size_t N = msg->perceptions.size(); }
if(N==0) else
{ {
return; return;
} }
// We are keeping a vector of state visual pointers Ogre::Vector3 position;
state_visuals_.clear(); state_visuals_.reserve(N); Ogre::Quaternion orientation;
shape_visuals_.clear(); shape_visuals_.reserve(N); if(context_->getFrameManager()->getTransform(msg->header.frame_id, msg->header.stamp, position, orientation))
for(Ogre::SceneNode* textNode: text_nodes_) context_->getSceneManager()->destroySceneNode(textNode); {
text_nodes_.clear(); text_nodes_.reserve(N); frame_node_->setPosition(position);
text_visuals_.clear(); text_visuals_.reserve(N); frame_node_->setOrientation(orientation);
}
const float alpha = alpha_property_->getFloat(); else
const float shape_alpha = shape_alpha_property_->getFloat(); {
const Ogre::ColourValue color = color_property_->getOgreColor(); ROS_DEBUG("Error transforming from frame '%s' to frame '%s'", msg->header.frame_id.c_str(), qPrintable(fixed_frame_));
return;
}
// Process the perceptions in the message // Process the perceptions in the message
for(const multiception::Perception& perception : msg->perceptions) for(const multiception::Perception& perception : msg->perceptions)
{ {
Ogre::Quaternion orientation; boost::shared_ptr<rviz::Arrow> arrowVis { new rviz::Arrow(scene_manager_, frame_node_) };
Ogre::Vector3 position; boost::shared_ptr<rviz::Shape> shapeVis { new rviz::Shape(rviz::Shape::Cube, scene_manager_, frame_node_) };
boost::shared_ptr<rviz::CovarianceVisual> covVis = covariance_property_->createAndPushBackVisual(scene_manager_, frame_node_);
if(!context_->getFrameManager()->getTransform(perception.header.frame_id, perception.header.stamp, position, orientation)) computeStateObjects(perception.state, *arrowVis, *covVis);
{
ROS_DEBUG("Error transforming from frame '%s' to frame '%s'", perception.header.frame_id.c_str(), qPrintable(fixed_frame_));
continue;
}
boost::shared_ptr<StateVisual> state(new StateVisual(context_->getSceneManager(), scene_node_, covariance_property_)); // Process the shape
boost::shared_ptr<rviz::Shape> shape(new rviz::Shape(rviz::Shape::Cube, context_->getSceneManager(), scene_node_));
// Set the state visual's pose and content
state->setContent(perception.state);
state->setFramePosition(position);
state->setFrameOrientation(orientation);
// Set the shape visual's pose and shape
const float z = (perception.height>0.1) ? perception.height/2+.1 : 1; const float z = (perception.height>0.1) ? perception.height/2+.1 : 1;
Ogre::Vector3 shapePose(perception.state.x, perception.state.y, z); shapeVis->setScale( Ogre::Vector3(perception.length, perception.width, std::max(0.1f, perception.height)) );
Ogre::Quaternion shapeOrientation(Ogre::Radian(perception.state.yaw), Ogre::Vector3::UNIT_Z); shapeVis->setPosition( Ogre::Vector3(perception.state.x, perception.state.y, z) );
Ogre::Vector3 shapeScale (perception.length, perception.width, std::max(0.1f, perception.height)); shapeVis->setOrientation( Ogre::Quaternion(Ogre::Radian(perception.state.yaw), Ogre::Vector3::UNIT_Z) );
shape->setPosition(shapePose);
shape->setOrientation(shapeOrientation);
shape->setScale(shapeScale);
state->setColor(color.r, color.g, color.b, alpha);
shape->setColor(color.r, color.g, color.b, shape_alpha);
// Create a hovering debug text if one is provided // Process the debug text
if(!perception.debug.empty()) if(!perception.debug.empty())
{ {
Ogre::SceneNode* childNode = scene_node_->createChildSceneNode(); Ogre::SceneNode* childNode = frame_node_->createChildSceneNode();
boost::shared_ptr<rviz::MovableText> debugText { new rviz::MovableText(perception.debug, "Liberation Sans", .7, text_color_property_->getOgreColor()) }; boost::shared_ptr<rviz::MovableText> debugText { new rviz::MovableText(perception.debug, "Liberation Sans", .7) };
debugText->setTextAlignment(rviz::MovableText::H_CENTER, rviz::MovableText::V_CENTER); debugText->setTextAlignment(rviz::MovableText::H_CENTER, rviz::MovableText::V_CENTER);
shapePose.z = z+perception.height/2+.1+1; childNode->setPosition(Ogre::Vector3(perception.state.x, perception.state.y, z+perception.height/2+.1+1) );
childNode->setPosition(shapePose);
childNode->attachObject(debugText.get()); childNode->attachObject(debugText.get());
text_visuals_.push_back(debugText); text_visuals_.push_back(debugText);
text_nodes_.push_back(childNode); text_nodes_.push_back(childNode);
} }
// And add it to the vector
state_visuals_.push_back(state);
shape_visuals_.push_back(shape);
}
// Process the buffered trace // Process the buffered trace
trace_buffer_.push_back(msg); filterTraceBuffer(); trace_visuals_.clear(); trace_buffer_.push_back(msg); filterTraceBuffer(); trace_visuals_.clear();
...@@ -208,14 +185,17 @@ void PerceptionsDisplay::processMessage(const multiception::Perceptions::ConstPt ...@@ -208,14 +185,17 @@ void PerceptionsDisplay::processMessage(const multiception::Perceptions::ConstPt
trace_visuals_[p.object_id]->addPoint(Ogre::Vector3(p.state.x, p.state.y, 0), color); trace_visuals_[p.object_id]->addPoint(Ogre::Vector3(p.state.x, p.state.y, 0), color);
} }
} }
pose_visuals_.push_back(arrowVis);
shape_visuals_.push_back(shapeVis);
cov_visuals_.push_back(covVis);
} }
updateColorAndAlpha();
context_->queueRender(); context_->queueRender();
} }
} // end namespace rviz_multiception } // end namespace rviz_multiception
// Tell pluginlib about this class. It is important to do this in
// global scope, outside our package's namespace.
#include <pluginlib/class_list_macros.h> #include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(rviz_multiception::PerceptionsDisplay,rviz::Display) PLUGINLIB_EXPORT_CLASS(rviz_multiception::PerceptionsDisplay,rviz::Display)
...@@ -18,28 +18,17 @@ namespace rviz ...@@ -18,28 +18,17 @@ namespace rviz
class ColorProperty; class ColorProperty;
class FloatProperty; class FloatProperty;
class IntProperty; class IntProperty;
class CovarianceProperty;
class Shape; class Shape;
class BillboardLine; class BillboardLine;
class MovableText; class MovableText;
class Arrow;
class CovarianceVisual;
class CovarianceProperty;
} }
// All the source in this plugin is in its own namespace. This is not
// required but is good practice.
namespace rviz_multiception namespace rviz_multiception
{ {
class StateVisual;
// Here we declare our new subclass of rviz::Display. Every display
// which can be listed in the "Displays" panel is a subclass of
// rviz::Display.
//
// The PerceptionsDisplay class just implements the vector,
// editable parameters, and Display subclass machinery. The visuals
// themselves are represented by separate classes. The
// idiom for the visuals is that when the objects exist, they appear
// in the scene, and when they are deleted, they disappear.
class PerceptionsDisplay: public rviz::MessageFilterDisplay<multiception::Perceptions> class PerceptionsDisplay: public rviz::MessageFilterDisplay<multiception::Perceptions>
{ {
Q_OBJECT Q_OBJECT
...@@ -49,16 +38,12 @@ public: ...@@ -49,16 +38,12 @@ public:
PerceptionsDisplay(); PerceptionsDisplay();
virtual ~PerceptionsDisplay(); virtual ~PerceptionsDisplay();
// Overrides of protected virtual functions from Display. As much
// as possible, when Displays are not enabled, they should not be
// subscribed to incoming data and should not show anything in the
// 3D view. These functions are where these connections are made
// and broken.
protected: protected:
virtual void onInitialize(); virtual void onInitialize();
// A helper to clear this display back to the initial state. // A helper to clear this display back to the initial state.
virtual void reset(); virtual void reset();
void resetVectors(size_t N=0);
// Qt slots connected to signals indicating changes in the user-editable properties. // Qt slots connected to signals indicating changes in the user-editable properties.
private Q_SLOTS: private Q_SLOTS:
...@@ -70,14 +55,16 @@ private: ...@@ -70,14 +55,16 @@ private:
void processMessage(const multiception::Perceptions::ConstPtr& msg); void processMessage(const multiception::Perceptions::ConstPtr& msg);
// Storage for the list of visuals // Storage for the list of visuals
std::vector<boost::shared_ptr<StateVisual>> state_visuals_; std::vector<boost::shared_ptr<rviz::Arrow>> pose_visuals_;
std::vector<boost::shared_ptr<rviz::Shape>> shape_visuals_; std::vector<boost::shared_ptr<rviz::Shape>> shape_visuals_;
std::vector<boost::shared_ptr<rviz::CovarianceVisual>> cov_visuals_;
std::vector<boost::shared_ptr<rviz::MovableText>> text_visuals_; std::vector<boost::shared_ptr<rviz::MovableText>> text_visuals_;
std::map<uint8_t, boost::shared_ptr<rviz::BillboardLine>> trace_visuals_; std::map<uint8_t, boost::shared_ptr<rviz::BillboardLine>> trace_visuals_;
std::vector<Ogre::SceneNode*> text_nodes_; std::vector<Ogre::SceneNode*> text_nodes_;
std::vector<multiception::Perceptions::ConstPtr> trace_buffer_; std::vector<multiception::Perceptions::ConstPtr> trace_buffer_;
float trace_duration_; float trace_duration_;
Ogre::SceneNode* frame_node_;
// User-editable property variables. // User-editable property variables.
rviz::ColorProperty* color_property_; rviz::ColorProperty* color_property_;
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <tf/transform_listener.h> #include <tf/transform_listener.h>
#include <rviz/visualization_manager.h> #include <rviz/visualization_manager.h>
#include <rviz/ogre_helpers/arrow.h>
#include <rviz/default_plugin/covariance_visual.h>
#include <rviz/properties/color_property.h> #include <rviz/properties/color_property.h>
#include <rviz/properties/float_property.h> #include <rviz/properties/float_property.h>
#include <rviz/default_plugin/covariance_property.h> #include <rviz/default_plugin/covariance_property.h>
...@@ -16,8 +18,6 @@ ...@@ -16,8 +18,6 @@
namespace rviz_multiception namespace rviz_multiception
{ {
// The constructor must have no arguments, so we can't give the
// constructor the parameters it needs to fully initialize.
StateDisplay::StateDisplay() StateDisplay::StateDisplay()
{ {
color_property_ = new rviz::ColorProperty( "Color", QColor( 204, 51, 204 ), color_property_ = new rviz::ColorProperty( "Color", QColor( 204, 51, 204 ),
...@@ -32,72 +32,60 @@ StateDisplay::StateDisplay() ...@@ -32,72 +32,60 @@ StateDisplay::StateDisplay()
this, SLOT( queueRender() )); this, SLOT( queueRender() ));
} }
// After the top-level rviz::Display::initialize() does its own setup,
// it calls the subclass's onInitialize() function. This is where we
// instantiate all the workings of the class. We make sure to also
// call our immediate super-class's onInitialize() function, since it
// does important stuff setting up the message filter.
//
// Note that "MFDClass" is a typedef of
// ``MessageFilterDisplay<message type>``, to save typing that long
// templated class name every time you need to refer to the
// superclass.
void StateDisplay::onInitialize() void StateDisplay::onInitialize()
{ {
MFDClass::onInitialize(); MFDClass::onInitialize();
frame_node_ = scene_node_->createChildSceneNode();
} }
StateDisplay::~StateDisplay() StateDisplay::~StateDisplay()
{ {
frame_node_->detachAllObjects();
frame_node_->removeAndDestroyAllChildren();
scene_manager_->destroySceneNode(frame_node_);
} }
// Clear the visuals by deleting their objects.
void StateDisplay::reset() void StateDisplay::reset()
{ {
MFDClass::reset(); MFDClass::reset();
visual_.reset(); pose_visual_.reset();
cov_visual_.reset();
} }
// Set the current color and alpha values for each visual.
void StateDisplay::updateColorAndAlpha() void StateDisplay::updateColorAndAlpha()
{ {
if(visual_) if(pose_visual_)
{ {
float alpha = alpha_property_->getFloat(); const float alpha = alpha_property_->getFloat();
Ogre::ColourValue color = color_property_->getOgreColor(); const Ogre::ColourValue color = color_property_->getOgreColor();
visual_->setColor(color.r, color.g, color.b, alpha);
pose_visual_->setColor(color.r, color.g, color.b, alpha);
// cov_visual_->setColor(color.r, color.g, color.b, alpha);
} }
} }
// This is our callback to handle an incoming message.
void StateDisplay::processMessage(const multiception::StateStamped::ConstPtr& msg) void StateDisplay::processMessage(const multiception::StateStamped::ConstPtr& msg)
{ {
// Here we call the rviz::FrameManager to get the transform from the
// fixed frame to the frame in the header of this message. If
// it fails, we can't do anything else so we return.
Ogre::Quaternion orientation;
Ogre::Vector3 position; Ogre::Vector3 position;
Ogre::Quaternion orientation;
if(!context_->getFrameManager()->getTransform(msg->header.frame_id, msg->header.stamp, position, orientation)) if(context_->getFrameManager()->getTransform(msg->header.frame_id, msg->header.stamp, position, orientation))
{
frame_node_->setPosition(position);
frame_node_->setOrientation(orientation);
}
else
{ {
ROS_DEBUG("Error transforming from frame '%s' to frame '%s'", msg->header.frame_id.c_str(), qPrintable(fixed_frame_)); ROS_DEBUG("Error transforming from frame '%s' to frame '%s'", msg->header.frame_id.c_str(), qPrintable(fixed_frame_));
return; return;
} }
visual_.reset(new StateVisual(context_->getSceneManager(), scene_node_, covariance_property_)); pose_visual_.reset( new rviz::Arrow(scene_manager_, frame_node_) );
cov_visual_ = covariance_property_->createAndPushBackVisual(scene_manager_, frame_node_);
// Now set or update the contents of the visual.
visual_->setContent(msg->state);
visual_->setFramePosition(position);
visual_->setFrameOrientation(orientation);
updateColorAndAlpha(); computeStateObjects(msg->state, *pose_visual_, *cov_visual_);
context_->queueRender();
} }
} // end namespace rviz_multiception } // end namespace rviz_multiception
// Tell pluginlib about this class. It is important to do this in
// global scope, outside our package's namespace.
#include <pluginlib/class_list_macros.h> #include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(rviz_multiception::StateDisplay,rviz::Display) PLUGINLIB_EXPORT_CLASS(rviz_multiception::StateDisplay,rviz::Display)
...@@ -15,28 +15,17 @@ class SceneNode; ...@@ -15,28 +15,17 @@ class SceneNode;
namespace rviz namespace rviz
{ {
class Arrow;
class CovarianceVisual;
class ColorProperty; class ColorProperty;
class FloatProperty; class FloatProperty;
class IntProperty; class IntProperty;
class CovarianceProperty; class CovarianceProperty;
} }
// All the source in this plugin is in its own namespace. This is not
// required but is good practice.
namespace rviz_multiception namespace rviz_multiception
{ {
class StateVisual;
// Here we declare our new subclass of rviz::Display. Every display
// which can be listed in the "Displays" panel is a subclass of
// rviz::Display.
//
// The StateDisplay class just implements the vector,
// editable parameters, and Display subclass machinery. The visuals
// themselves are represented by a separate class, StateVisual. The
// idiom for the visuals is that when the objects exist, they appear
// in the scene, and when they are deleted, they disappear.
class StateDisplay: public rviz::MessageFilterDisplay<multiception::StateStamped> class StateDisplay: public rviz::MessageFilterDisplay<multiception::StateStamped>
{ {
Q_OBJECT Q_OBJECT
...@@ -66,7 +55,10 @@ private: ...@@ -66,7 +55,10 @@ private:
void processMessage(const multiception::StateStamped::ConstPtr& msg); void processMessage(const multiception::StateStamped::ConstPtr& msg);
// Storage of the visual // Storage of the visual
boost::shared_ptr<StateVisual> visual_; boost::shared_ptr<rviz::Arrow> pose_visual_;
boost::shared_ptr<rviz::CovarianceVisual> cov_visual_;
Ogre::SceneNode* frame_node_;
// User-editable property variables. // User-editable property variables.
rviz::ColorProperty* color_property_; rviz::ColorProperty* color_property_;
......
#include <OGRE/OgreVector3.h> #include <OGRE/OgreVector3.h>
#include <OGRE/OgreSceneNode.h> #include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <ros/console.h> #include <ros/console.h>
#include <rviz/ogre_helpers/arrow.h> #include <rviz/ogre_helpers/arrow.h>
#include <rviz/default_plugin/covariance_visual.h> #include <rviz/default_plugin/covariance_visual.h>
#include <rviz/default_plugin/covariance_property.h>
#include <geometry_msgs/Vector3.h> #include <geometry_msgs/Vector3.h>
#include <tf2/LinearMath/Quaternion.h> #include <tf2/LinearMath/Quaternion.h>
...@@ -16,92 +14,46 @@ ...@@ -16,92 +14,46 @@
namespace rviz_multiception namespace rviz_multiception
{ {
StateVisual::StateVisual(Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node, rviz::CovarianceProperty* covariance_property) void computeStateObjects(const multiception::State& state, rviz::Arrow& arrowVis, rviz::CovarianceVisual& covVis) {
{ // Process the pose arrow, scaled by velocity and oriented by heading
scene_manager_ = scene_manager;
// Ogre::SceneNode s form a tree, with each node storing the
// transform (position and orientation) of itself relative to its
// parent. Ogre does the math of combining those transforms when it
// is time to render.
//
// Here we create a node to store the pose of the header frame
// relative to the RViz fixed frame.
frame_node_ = parent_node->createChildSceneNode();
// We create the arrow object within the frame node so that we can
// set its position and direction relative to its header frame.
pose_arrow_.reset(new rviz::Arrow(scene_manager_, frame_node_));
covariance_ = covariance_property->createAndPushBackVisual(scene_manager, frame_node_);
}
StateVisual::~StateVisual()
{
// Destroy the frame node since we don't need it anymore.
scene_manager_->destroySceneNode(frame_node_);
}
void StateVisual::setContent(const multiception::State& state)
{
// Convert the geometry_msgs::Vector3 to an Ogre::Vector3.
Ogre::Vector3 pose(state.x, state.y, 1.5); Ogre::Vector3 pose(state.x, state.y, 1.5);
pose_arrow_->setPosition(pose); arrowVis.setPosition(pose);
// Scale the arrow by the bounded velocity // Special case, if yaw is 0, we consider the state to be static
// without orientation (e.g: pole) and displaying an orientation makes no sense
float length = std::min(4.0, std::max(1.0, state.v/5.0)); float length = std::min(4.0, std::max(1.0, state.v/5.0));
Ogre::Vector3 scale(length, 1, 1); if(state.v<=0) arrowVis.setScale(Ogre::Vector3(0.1, 0.1, 0.1));
pose_arrow_->setScale(scale); else arrowVis.setScale(Ogre::Vector3(length, 1, 1));
// Set the orientation of the arrow according to the heading.
Ogre::Vector3 direction(std::cos(state.yaw), std::sin(state.yaw), 0); Ogre::Vector3 direction(std::cos(state.yaw), std::sin(state.yaw), 0);
pose_arrow_->setDirection(direction); arrowVis.setDirection(direction);
// Set the covariance ellipsis // Process the covariance ellipsis
std::array<double, 36> covTot; std::array<double, 36> covTot;
for(size_t i=0;i<covTot.size(); i++) covTot[i] = state.cov[i] + state.cov_ind[i]; for(size_t i=0;i<covTot.size(); i++) covTot[i] = state.cov[i] + state.cov_ind[i];
geometry_msgs::PoseWithCovariance cov; geometry_msgs::PoseWithCovariance cov;
//cov.pose.position.x = state.x; cov.pose.position.y = state.y; cov.pose.position.x = state.x; cov.pose.position.y = state.y;
tf2::Quaternion q; q.setRPY(0.0, 0.0, state.yaw); tf2::Quaternion q; q.setRPY(0.0, 0.0, state.yaw);
cov.pose.orientation = tf2::toMsg(q); cov.pose.orientation = tf2::toMsg(q);
cov.covariance[0*6+0] = covTot[0*6+0]; // xx cov.covariance[0*6+0] = covTot[0*6+0]; // xx
cov.covariance[0*6+1] = covTot[0*6+1]; // xy cov.covariance[0*6+1] = covTot[0*6+1]; // xy
cov.covariance[1*6+0] = covTot[1*6+0]; // yx cov.covariance[1*6+0] = covTot[1*6+0]; // yx
cov.covariance[1*6+1] = covTot[1*6+1]; // yy cov.covariance[1*6+1] = covTot[1*6+1]; // yy
// Special case, if yaw is 0, we consider the state to be static if(state.v>0)
// without orientation (e.g: pole) and displaying an orientation makes no sense
if(state.v==0) pose_arrow_->setScale(Ogre::Vector3(0.1, 0.1, 0.1));
else if(covTot[2*6+2]<M_PI)
{ {
cov.covariance[0*6+5] = covTot[0*6+2]; // xyaw cov.covariance[0*6+5] = covTot[0*6+2]; // xyaw
cov.covariance[1*6+5] = covTot[1*6+2]; // yyaw cov.covariance[1*6+5] = covTot[1*6+2]; // yyaw
cov.covariance[5*6+0] = covTot[2*6+0]; // yawx cov.covariance[5*6+0] = covTot[2*6+0]; // yawx
cov.covariance[5*6+1] = covTot[2*6+1]; // yawy cov.covariance[5*6+1] = covTot[2*6+1]; // yawy
cov.covariance[5*6+5] = std::max(.0, covTot[2*6+2]); // yawyaw cov.covariance[5*6+5] = std::max(0., std::min(2., covTot[2*6+2])); // yawyaw
} }
covariance_->setCovariance(cov);
covariance_->setPosition(pose);
Ogre::Quaternion covq(Ogre::Radian(state.yaw), Ogre::Vector3::UNIT_Z); Ogre::Quaternion covq(Ogre::Radian(state.yaw), Ogre::Vector3::UNIT_Z);
covariance_->setOrientation(covq); covVis.setCovariance(cov);
} covVis.setPosition(pose);
covVis.setOrientation(covq);
// Position and orientation are passed through to the SceneNode.
void StateVisual::setFramePosition(const Ogre::Vector3& position)
{
frame_node_->setPosition(position);
}
void StateVisual::setFrameOrientation(const Ogre::Quaternion& orientation)
{
frame_node_->setOrientation(orientation);
}
// Color is passed through to the Arrow object.
void StateVisual::setColor(float r, float g, float b, float a)
{
pose_arrow_->setColor(r, g, b, a);
} }
} // namespace rviz_multiception } // namespace rviz_multiception
......
...@@ -3,66 +3,16 @@ ...@@ -3,66 +3,16 @@
#include <multiception/Perception.h> #include <multiception/Perception.h>
namespace Ogre
{
class Vector3;
class Quaternion;
}
namespace rviz namespace rviz
{ {
class Arrow; class Arrow;
class CovarianceVisual; class CovarianceVisual;
class CovarianceProperty;
} }
namespace rviz_multiception namespace rviz_multiception
{ {
// Declare the visual class for this display. void computeStateObjects(const multiception::State& state, rviz::Arrow& arrowVis, rviz::CovarianceVisual& covVis);
//
// Each instance of StateVisual represents the visualization of a single
// multiception::Perception message. Currently it just shows an arrow with
// the direction and magnitude of the acceleration vector, but could
// easily be expanded to include more of the message data.
class StateVisual
{
public:
// Constructor. Creates the visual stuff and puts it into the
// scene, but in an unconfigured state.
StateVisual(Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node, rviz::CovarianceProperty* covariance_property);
// Destructor. Removes the visual stuff from the scene.
virtual ~StateVisual();
// Configure the visual to show the data in the message.
void setContent(const multiception::State& state);
// Set the pose of the coordinate frame the message refers to.
// These could be done inside setMessage(), but that would require
// calls to FrameManager and error handling inside setMessage(),
// which doesn't seem as clean. This way PerceptionVisual is only
// responsible for visualization.
void setFramePosition(const Ogre::Vector3& position);
void setFrameOrientation(const Ogre::Quaternion& orientation);
// Set the color and alpha of the visual, which are user-editable
// parameters and therefore don't come from the message.
void setColor(float r, float g, float b, float a);
private:
// The object implementing the actual arrow shape
boost::shared_ptr<rviz::Arrow> pose_arrow_;
boost::shared_ptr<rviz::CovarianceVisual> covariance_;
// A SceneNode whose pose is set to match the coordinate frame of
// the Imu message header.
Ogre::SceneNode* frame_node_;
// The SceneManager, kept here only so the destructor can ask it to
// destroy the ``frame_node_``.
Ogre::SceneManager* scene_manager_;
};
} // namespace rviz_multiception } // namespace rviz_multiception
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment