Skip to content
Snippets Groups Projects
perceptions_display.cpp 8.23 KiB
Newer Older
#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>

#include <tf/transform_listener.h>

#include <rviz/visualization_manager.h>
#include <rviz/properties/color_property.h>
#include <rviz/properties/float_property.h>
Antoine Lima's avatar
Antoine Lima committed
#include <rviz/default_plugin/covariance_property.h>
#include <rviz/properties/int_property.h>
#include <rviz/ogre_helpers/shape.h>
#include <rviz/ogre_helpers/movable_text.h>
#include <rviz/ogre_helpers/billboard_line.h>
#include <rviz/frame_manager.h>

Antoine Lima's avatar
Antoine Lima committed
#include "state_visual.h"
#include "perceptions_display.h"

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()
{
Antoine Lima's avatar
Antoine Lima committed
	color_property_ = new rviz::ColorProperty( "Color", QColor( 10, 10, 10 ),
	                                           "Color to draw the arrows.",
	                                           this, SLOT( updateColorAndAlpha() ));

	alpha_property_ = new rviz::FloatProperty( "Alpha", 1.0,
	                                           "State transparency, 0 is fully transparent, 1.0 is fully opaque.",
	                                           this, SLOT( updateColorAndAlpha() ));

	shape_alpha_property_ = new rviz::FloatProperty( "Shape Alpha", 0.4,
	                                           "Shape transparency, 0 is fully transparent, 1.0 is fully opaque.",
	                                           this, SLOT( updateColorAndAlpha() ));
	trace_duration_property_ = new rviz::FloatProperty( "Trace Duration (s)", 1,
	                                           "Duration of state traces, in seconds.",
	                                           this, SLOT( filterTraceBuffer() ));

	text_color_property_ = new rviz::ColorProperty( "Debug Text Color", QColor( 10, 10, 10 ),
	                                           "Color of the debug text.",
	                                           this, SLOT( updateColorAndAlpha() ));

Antoine Lima's avatar
Antoine Lima committed
	covariance_property_ = new rviz::CovarianceProperty( "Covariance", true, "Whether or not the covariances of the messages should be shown.",
	                                                     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()
{
	MFDClass::onInitialize();
}

PerceptionsDisplay::~PerceptionsDisplay()
{
}

// Clear the visuals by deleting their objects.
void PerceptionsDisplay::reset()
{
	MFDClass::reset();
	state_visuals_.clear();
	shape_visuals_.clear();
	text_visuals_.clear();
	trace_buffer_.clear();
	trace_visuals_.clear();
	for(Ogre::SceneNode* textNode: text_nodes_) context_->getSceneManager()->destroySceneNode(textNode);
	text_nodes_.clear();
	text_visuals_.clear();
}

// Set the current color and alpha values for each visual.
void PerceptionsDisplay::updateColorAndAlpha()
{
	float alpha = alpha_property_->getFloat();
	float shape_alpha = shape_alpha_property_->getFloat();
	Ogre::ColourValue color = color_property_->getOgreColor();

	for(size_t i=0; i<state_visuals_.size(); i++)
		state_visuals_[i]->setColor(color.r, color.g, color.b, alpha);
		shape_visuals_[i]->setColor(color.r, color.g, color.b, shape_alpha);

	for(size_t i=0; i<state_visuals_.size(); i++)
	{
		trace_visuals_[i]->setColor(color.r, color.g, color.b, alpha);
	}
}

void PerceptionsDisplay::filterTraceBuffer()
{
	float duration = trace_duration_property_->getFloat();
	double oldestTimePossible = ros::Time::now().toSec() - duration;

	auto newEnd = std::remove_if(trace_buffer_.begin(), trace_buffer_.end(), [oldestTimePossible](const multiception::Perceptions::ConstPtr& s)
	{
		return !s || s->header.stamp.toSec()<oldestTimePossible;
	});
	trace_buffer_.erase(newEnd, trace_buffer_.end());

	std::sort(trace_buffer_.begin(), trace_buffer_.end(), [](const multiception::Perceptions::ConstPtr& a, const multiception::Perceptions::ConstPtr& b)
	{
		return a->header.stamp<b->header.stamp;
	});
}

// This is our callback to handle an incoming message.
void PerceptionsDisplay::processMessage(const multiception::Perceptions::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.
	const size_t N = msg->perceptions.size();
	if(N==0)
	{
		return;
	}

Antoine Lima's avatar
Antoine Lima committed
	// We are keeping a vector of state visual pointers
	state_visuals_.clear(); state_visuals_.reserve(N);
	shape_visuals_.clear(); shape_visuals_.reserve(N);
	for(Ogre::SceneNode* textNode: text_nodes_) context_->getSceneManager()->destroySceneNode(textNode);
	text_nodes_.clear(); text_nodes_.reserve(N);
	text_visuals_.clear(); text_visuals_.reserve(N);
	
	const float alpha = alpha_property_->getFloat();
	const float shape_alpha = shape_alpha_property_->getFloat();
	const Ogre::ColourValue color = color_property_->getOgreColor();
	// Process the perceptions in the message
	for(const multiception::Perception& perception : msg->perceptions)
	{
		Ogre::Quaternion orientation;
		Ogre::Vector3 position;

		if(!context_->getFrameManager()->getTransform(perception.header.frame_id, perception.header.stamp, position, orientation))
		{
			ROS_DEBUG("Error transforming from frame '%s' to frame '%s'", perception.header.frame_id.c_str(), qPrintable(fixed_frame_));
Antoine Lima's avatar
Antoine Lima committed
			continue;
Antoine Lima's avatar
Antoine Lima committed
		boost::shared_ptr<StateVisual> state(new StateVisual(context_->getSceneManager(), scene_node_, covariance_property_));
		boost::shared_ptr<rviz::Shape> shape(new rviz::Shape(rviz::Shape::Cube, context_->getSceneManager(), scene_node_));
		// Set the state visual's pose and content
Antoine Lima's avatar
Antoine Lima committed
		state->setContent(perception.state);
		state->setFramePosition(position);
		state->setFrameOrientation(orientation);
		// Set the shape visual's pose and shape
		Ogre::Vector3 shapePose(perception.state.x, perception.state.y, 0.1);
		Ogre::Quaternion shapeOrientation(Ogre::Radian(perception.state.yaw), Ogre::Vector3::UNIT_Z);
		Ogre::Vector3 shapeScale (perception.length, perception.width, std::max(0.1f, perception.height));
		shape->setPosition(shapePose);
		shape->setOrientation(shapeOrientation);
		shape->setScale(shapeScale);

Antoine Lima's avatar
Antoine Lima committed
		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
		if(!perception.debug.empty())
		{
			Ogre::SceneNode* childNode = scene_node_->createChildSceneNode();
			boost::shared_ptr<rviz::MovableText> debugText { new rviz::MovableText(perception.debug, "Liberation Sans", .7, text_color_property_->getOgreColor()) };
			debugText->setTextAlignment(rviz::MovableText::H_CENTER, rviz::MovableText::V_CENTER);
			shapePose.z = z+perception.height/2+.1+1;
			childNode->setPosition(shapePose);
			childNode->attachObject(debugText.get());
			text_visuals_.push_back(debugText);
			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
	trace_buffer_.push_back(msg); filterTraceBuffer(); trace_visuals_.clear();

	for(const auto& perceptions : trace_buffer_)
	{
		for(const auto& p : perceptions->perceptions)
		{
			// ID 0 represent untracked perception, thus a perception trace is not relevant
			if(p.object_id!=0)
			{
				// Create the visual for this object if non-existent
				if(trace_visuals_.count(p.object_id)==0) 
				{
					trace_visuals_[p.object_id] = boost::make_shared<rviz::BillboardLine>(scene_manager_, scene_node_);
				}

				trace_visuals_[p.object_id]->addPoint(Ogre::Vector3(p.state.x, p.state.y, 0), color);
			}
		}
	}

Antoine Lima's avatar
Antoine Lima committed
	context_->queueRender();
}

} // 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>
PLUGINLIB_EXPORT_CLASS(rviz_multiception::PerceptionsDisplay,rviz::Display)