diff --git a/plugin_description.xml b/plugin_description.xml new file mode 100644 index 0000000000000000000000000000000000000000..85d68053e51b01b1283cdbe715b0ef795000dfc1 --- /dev/null +++ b/plugin_description.xml @@ -0,0 +1,7 @@ +<library path="lib/liblrs_rviz_plugin"> + <class name="lrs_rviz/Image" type="lrs_rviz::ImageDisplay" base_class_type="rviz::Display"> + <description> + Displays an image on the ground plane. + </description> + </class> +</library> diff --git a/src/image_display.cc b/src/image_display.cc new file mode 100644 index 0000000000000000000000000000000000000000..cd15c6050af2064d0ed3cdcff6bd78a1dd0ee00f --- /dev/null +++ b/src/image_display.cc @@ -0,0 +1,167 @@ +#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> +#include <rviz/properties/int_property.h> +#include <rviz/properties/string_property.h> +#include <rviz/properties/property.h> +#include <rviz/frame_manager.h> + +#include "image_visual.h" + +#include "image_display.h" + +namespace lrs_rviz { + + ImageDisplay::ImageDisplay() : x_offset(0.0), y_offset(0.0), z_offset(0.0), Display() { + + visual_enabled_property_ = + new rviz::Property( "Visual Enabled", true, + "Whether to display the visual representation of the image.", + this, SLOT( updateVisualVisible() )); + + image_description_property_ = + new rviz::StringProperty( "Image Description", "image_description", + "Name of the parameter to search for to load the image filename.", + this, SLOT( updateImageDescription() )); + + z_offset_property_ = + new rviz::FloatProperty( "Z offset", 0.0, "z_offset of image in meter.", this, SLOT( update_z_offset() )); + + +#if 0 + dx_property_ = + new rviz::IntProperty( "DX", 0, "x width of image in meter.", this, SLOT( updateDx() )); + + dy_property_ = + new rviz::IntProperty( "DY", 0, "y width of image in meter.", this, SLOT( updateDy() )); +#endif + } + + ImageDisplay::~ImageDisplay() { + if ( initialized() ) { + delete image_visual; + } + } + + + void ImageDisplay::onInitialize() { + load(); + if ((image_filename == "") || (dx <= 0) || (dy <= 0)) { + return; + } + image_visual = new ImageVisual(scene_node_, context_, + image_filename, dx, dy, + x_offset, y_offset, z_offset, + this); + updateVisualVisible(); + } + + void ImageDisplay::updateVisualVisible() { + image_visual->setVisualVisible( visual_enabled_property_->getValue().toBool() ); + context_->queueRender(); + } + + void ImageDisplay::updateImageDescription() { + // load(); + } + + void ImageDisplay::updateDx() { + + } + + void ImageDisplay::updateDy() { + + } + + void ImageDisplay::update_z_offset() { + float z_offset = z_offset_property_->getFloat(); + image_visual->set_z_offset(z_offset); + } + + + void ImageDisplay::reset() { + Display::reset(); + } + + void ImageDisplay::load() { + std::string filename; + if( !update_nh_.getParam(image_description_property_->getStdString() + "/filename", filename)) { + setStatus( rviz::StatusProperty::Error, "FILENAME", + "Parameter [" + image_description_property_->getString() + "/filename" + + "] does not exist" ); + return; + } else { + setStatus( rviz::StatusProperty::Ok, "FILENAME", filename.c_str()); + } + + dx = 0; + if( !update_nh_.getParam(image_description_property_->getStdString() + "/dx", dx)) { + setStatus( rviz::StatusProperty::Error, "DX", + "Parameter [" + image_description_property_->getString() + "/dx" + + "] does not exist" ); + return; + } else { + setStatus( rviz::StatusProperty::Ok, "DX", QString::number(dx)); + } + + dy = 0; + if( !update_nh_.getParam(image_description_property_->getStdString() + "/dy", dy)) { + setStatus( rviz::StatusProperty::Error, "DY", + "Parameter [" + image_description_property_->getString() + "/dy" + + "] does not exist" ); + return; + } else { + setStatus( rviz::StatusProperty::Ok, "DY", QString::number(dy)); + } + + update_nh_.getParam(image_description_property_->getStdString() + "/x_offset", x_offset); + update_nh_.getParam(image_description_property_->getStdString() + "/y_offset", y_offset); + + if( filename.empty() ) { + setStatus( rviz::StatusProperty::Error, "FILENAME", "Filename is empty" ); + return; + } + + if( dx <= 0 ) { + setStatus( rviz::StatusProperty::Error, "DX", "Zero is not allowed as value" ); + return; + } + + if( dy <= 0 ) { + setStatus( rviz::StatusProperty::Error, "DY", "Zero is not allowed as value" ); + return; + } + + if( filename == image_filename ) { + return; + } + + image_filename = filename; + + // + // Create visual thingy + // + + } + +void ImageDisplay::onEnable() { + load(); + image_visual->setVisualVisible( true ); +} + +void ImageDisplay::onDisable() { + image_visual->setVisualVisible( false ); +} + + +} + +// 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(lrs_rviz::ImageDisplay,rviz::Display ) diff --git a/src/image_display.h b/src/image_display.h new file mode 100644 index 0000000000000000000000000000000000000000..ed615420f7b89a62c8735a7b5407594ae7453c9f --- /dev/null +++ b/src/image_display.h @@ -0,0 +1,77 @@ +#ifndef IMAGE_DISPLAY_H +#define IMAGE_DISPLAY_H + +#include "rviz/display.h" +#include <OgreVector3.h> + +#include <map> + +namespace Ogre +{ +class Entity; +class SceneNode; +} + +namespace rviz +{ +class Property; +class StringProperty; +class IntProperty; +class FloatProperty; +} + +namespace lrs_rviz +{ + class ImageVisual; + + class ImageDisplay: public rviz::Display { +Q_OBJECT + public: + ImageDisplay(); + virtual ~ImageDisplay(); + + // 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: + virtual void onInitialize(); + + // A helper to clear this display back to the initial state. + virtual void reset(); + + virtual void load(); + virtual void onEnable(); + virtual void onDisable(); + + // These Qt slots get connected to signals indicating changes in the user-editable properties. + private Q_SLOTS: + void updateImageDescription(); + void updateVisualVisible(); + void updateDx(); + void updateDy(); + void update_x_offset(); + void update_y_offset(); + void update_z_offset(); + + + private: + std::string image_filename; + int dx; + int dy; + float x_offset; + float y_offset; + float z_offset; + ImageVisual * image_visual; + + rviz::Property* visual_enabled_property_; + rviz::StringProperty* image_description_property_; + rviz::FloatProperty* z_offset_property_; +// rviz::IntProperty* dx_property_; +// rviz::IntProperty* dy_property_; + }; +}; + + +#endif diff --git a/src/image_visual.cc b/src/image_visual.cc new file mode 100644 index 0000000000000000000000000000000000000000..9e10c97581eeb9d10b20b8796e04c00516fb3842 --- /dev/null +++ b/src/image_visual.cc @@ -0,0 +1,114 @@ +#include "image_visual.h" +//#include "properties/property.h" +//#include "properties/enum_property.h" +//#include "properties/bool_property.h" +#include "display_context.h" + +#include "ogre_helpers/object.h" +#include "ogre_helpers/shape.h" +#include "ogre_helpers/axes.h" + +#include <OgreSceneNode.h> +#include <OgreSceneManager.h> +#include <OgreEntity.h> +#include <OgreMaterialManager.h> +#include <OgreMaterial.h> +#include <OgreResourceGroupManager.h> +#include <OgreManualObject.h> + + +bool LoadImage(const Ogre::String& texture_name, const Ogre::String& texture_path) +{ + bool image_loaded = false; + std::ifstream ifs(texture_path.c_str(), std::ios::binary|std::ios::in); + if (ifs.is_open()) + { + Ogre::String tex_ext; + Ogre::String::size_type index_of_extension = texture_path.find_last_of('.'); + if (index_of_extension != Ogre::String::npos) + { + tex_ext = texture_path.substr(index_of_extension+1); + Ogre::DataStreamPtr data_stream(new Ogre::FileStreamDataStream(texture_path, &ifs, false)); + Ogre::Image img; + img.load(data_stream, tex_ext); + Ogre::TextureManager::getSingleton().loadImage(texture_name, + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, img, Ogre::TEX_TYPE_2D, 0, 1.0f); + image_loaded = true; + } + ifs.close(); + } + return image_loaded; +} + +namespace lrs_rviz { + + ImageVisual::ImageVisual(Ogre::SceneNode* root_node, rviz::DisplayContext* context, + const std::string& filename, int dx, int dy, + float x_off, float y_off, float z_off, + rviz::Property* parent_property ) + : scene_manager_(context->getSceneManager()) + , visual_visible_(true), x_offset(x_off), y_offset(y_off), z_offset(z_off) { + + root_visual_node_ = root_node->createChildSceneNode(); + + if (LoadImage("image_ground", filename)) { + + Ogre::MaterialPtr material = + Ogre::MaterialManager::getSingleton().create("image_ground_material", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + + material->getTechnique(0)->getPass(0)->createTextureUnitState("image_ground"); + material->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); + + manual = scene_manager_->createManualObject("manual"); + // manual->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_STRIP); + // manual->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_POINT_LIST); + manual->begin("image_ground_material", Ogre::RenderOperation::OT_TRIANGLE_LIST); + + int x0 = -dx/2.0; + int x1 = dx/2.0; + int y0 = -dy/2.0; + int y1 = dy/2.0; + + float z = 0.0; + + manual->position(x0, y0, z); + manual->textureCoord(0,1); + manual->position(x1, y0, z); + manual->textureCoord(1,1); + manual->position(x1, y1, z); + manual->textureCoord(1,0); + + + manual->position(x1, y1, z); + manual->textureCoord(1,0); + manual->position(x0, y1, z); + manual->textureCoord(0,0); + manual->position(x0, y0, z); + manual->textureCoord(0,1); + + manual->end(); + root_visual_node_->attachObject(manual); + } + + root_visual_node_->setPosition(x_offset, y_offset, z_offset); + + setVisualVisible( visual_visible_ ); + + + } + + ImageVisual::~ImageVisual() { + scene_manager_->destroySceneNode( root_visual_node_->getName() ); + } + + void ImageVisual::setVisualVisible(bool visible) { + visual_visible_ = visible; + } + + void ImageVisual::set_z_offset(float offset) { + z_offset = offset; + root_visual_node_->setPosition(x_offset, y_offset, z_offset); + } + +} diff --git a/src/image_visual.h b/src/image_visual.h new file mode 100644 index 0000000000000000000000000000000000000000..79822e569f553dd8f4512af99b4b6407709a4e7f --- /dev/null +++ b/src/image_visual.h @@ -0,0 +1,51 @@ +#ifndef _IMAGEVISUAL_H +#define _IMAGEVISUAL_H + +#include <QObject> + +namespace Ogre { + class Vector3; + class Quaternion; + class SceneManager; + class SceneNode; + class ManualObject; +} + +namespace rviz { + class DisplayContext; + class Property; +} + +namespace lrs_rviz { + + class ImageVisual : public QObject { + Q_OBJECT + private: + Ogre::SceneManager* scene_manager_; + Ogre::SceneNode* root_visual_node_; ///< Node all our visual nodes are children of + bool visual_visible_; ///< Should we show the visual representation? + rviz::DisplayContext* context_; + Ogre::ManualObject* manual; + float x_offset; + float y_offset; + float z_offset; + +public: + // ImageVisual( Ogre::SceneManager* scene_manager, Ogre::SceneNode* parent_node ); + // virtual ~ImageVisual(); + + ImageVisual(Ogre::SceneNode* root_node, rviz::DisplayContext* context, + const std::string& filename, int dx, int dy, + float x_offset, float y_offset, float z_offset, + rviz::Property* parent_property); + virtual ~ImageVisual(); + + //virtual void setVisible( bool visible ); + + void setVisualVisible( bool visible ); + void set_z_offset(float offset); +}; + +}; + +#endif