mesh_display_custom.cpp
Go to the documentation of this file.
00001 /*
00002  * MeshDisplayCustom class implementation.
00003  *
00004  * Author: Felipe Bacim.
00005  *
00006  * Based on the rviz image display class.
00007  *
00008  * Latest changes (12/11/2012):
00009  * - fixed segfault issues
00010  */
00011 /*
00012  * Copyright (c) 2008, Willow Garage, Inc.
00013  * All rights reserved.
00014  *
00015  * Redistribution and use in source and binary forms, with or without
00016  * modification, are permitted provided that the following conditions are met:
00017  *
00018  *     * Redistributions of source code must retain the above copyright
00019  *       notice, this list of conditions and the following disclaimer.
00020  *     * Redistributions in binary form must reproduce the above copyright
00021  *       notice, this list of conditions and the following disclaimer in the
00022  *       documentation and/or other materials provided with the distribution.
00023  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00024  *       contributors may be used to endorse or promote products derived from
00025  *       this software without specific prior written permission.
00026  *
00027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00031  * LIABLE FOR ANY DImesh, INDImesh, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00037  * POSSIBILITY OF SUCH DAMAGE.
00038  */
00039 
00040 #include <OGRE/OgreSceneNode.h>
00041 #include <OGRE/OgreSceneManager.h> 
00042 #include <OGRE/OgreMovableObject.h>
00043 #include <OGRE/OgreMaterialManager.h>
00044 #include <OGRE/OgreFrustum.h>
00045 
00046 #include "rviz/display_context.h"
00047 #include "rviz/robot/robot.h"
00048 #include "rviz/robot/tf_link_updater.h"
00049 #include "rviz/properties/color_property.h"
00050 #include "rviz/properties/vector_property.h"
00051 #include "rviz/properties/ros_topic_property.h"
00052 #include "rviz/properties/float_property.h"
00053 #include "rviz/properties/string_property.h"
00054 #include "rviz/properties/quaternion_property.h"
00055 #include "rviz/render_panel.h"
00056 #include "rviz/validate_floats.h"
00057 #include "rviz/view_manager.h"
00058 #include "rviz/visualization_manager.h"
00059 
00060 #include <image_transport/camera_common.h>
00061 
00062 #include <sensor_msgs/image_encodings.h>
00063 #include <cv_bridge/cv_bridge.h>
00064 #include <opencv2/imgproc/imgproc.hpp>
00065 #include <opencv2/highgui/highgui.hpp>
00066 
00067 #include "mesh_display_custom.h"
00068 
00069 namespace rviz
00070 {
00071 
00072 bool validateFloats(const sensor_msgs::CameraInfo& msg)
00073 {
00074     bool valid = true;
00075     valid = valid && validateFloats( msg.D );
00076     valid = valid && validateFloats( msg.K );
00077     valid = valid && validateFloats( msg.R );
00078     valid = valid && validateFloats( msg.P );
00079     return valid;
00080 }
00081 
00082 MeshDisplayCustom::MeshDisplayCustom()
00083     : Display()
00084     , time_since_last_transform_( 0.0f )
00085     , initialized_(false)
00086 {
00087     display_images_topic_property_ = new RosTopicProperty( "Display Images Topic", "",
00088                                             QString::fromStdString( ros::message_traits::datatype<rviz_textured_quads::TexturedQuadArray>() ),
00089                                             "shape_msgs::Mesh topic to subscribe to.",
00090                                             this, SLOT( updateDisplayImages() ));
00091 
00092     text_color_property_ = new ColorProperty (  "Text Color", QColor( 255, 255, 255 ),
00093                                               "caption color.", this, SLOT( updateMeshProperties() )  );
00094 
00095     text_height_property_ = new FloatProperty( "Text Height", 0.1f,
00096                                               "font size of caption", this, SLOT( updateMeshProperties() ) );
00097 
00098     text_bottom_offset_ =  new FloatProperty( "Text Bottom Offset", 0.18f,
00099                                               "text placement offset below", this, SLOT( updateMeshProperties() ) );
00100 }
00101 
00102 MeshDisplayCustom::~MeshDisplayCustom()
00103 {
00104     unsubscribe();
00105 
00106     // TODO: Why am I doing this? switch to shared ptrs Argh!!!!!! 
00107 
00108     // clear manual objects
00109     for (std::vector<Ogre::ManualObject*>::iterator it = manual_objects_.begin() ; it != manual_objects_.end(); ++it)
00110     {
00111       delete (*it);
00112     } 
00113     manual_objects_.clear();
00114 
00115     // clear decal frustrums
00116     for (std::vector<Ogre::Frustum*>::iterator it = decal_frustums_.begin() ; it != decal_frustums_.end(); ++it)
00117     {
00118       delete (*it);
00119     } 
00120     decal_frustums_.clear();
00121 
00122     // clear textures
00123     for (std::vector<ROSImageTexture*>::iterator it = textures_.begin() ; it != textures_.end(); ++it)
00124     {
00125       delete (*it);
00126     } 
00127     textures_.clear();
00128 
00129     // clear textures
00130     for (std::vector<Ogre::SceneNode*>::iterator it = mesh_nodes_.begin() ; it != mesh_nodes_.end(); ++it)
00131     {
00132       delete (*it);
00133     } 
00134     mesh_nodes_.clear();
00135 
00136     // clear text nodes
00137     for (std::vector<rviz_textured_quads::TextNode*>::iterator it = text_nodes_.begin() ; it != text_nodes_.end(); ++it)
00138     {
00139       delete (*it);
00140     } 
00141     text_nodes_.clear();
00142 
00143     // TODO: clean up other things
00144 }
00145 
00146 void MeshDisplayCustom::onInitialize()
00147 {
00148     Display::onInitialize();
00149 }
00150 
00151 void MeshDisplayCustom::createProjector(int index)
00152 {
00153     decal_frustums_[index] = new Ogre::Frustum();
00154 
00155     projector_nodes_[index] = scene_manager_->getRootSceneNode()->createChildSceneNode();
00156     projector_nodes_[index]->attachObject(decal_frustums_[index]);
00157 
00158     Ogre::SceneNode* filter_node;
00159 
00160     //back filter
00161     filter_frustums_[index].push_back(new Ogre::Frustum());
00162     filter_frustums_[index].back()->setProjectionType(Ogre::PT_ORTHOGRAPHIC);
00163     filter_node = projector_nodes_[index]->createChildSceneNode();
00164     filter_node->attachObject(filter_frustums_[index].back());
00165     filter_node->setOrientation(Ogre::Quaternion(Ogre::Degree(90),Ogre::Vector3::UNIT_Y));
00166 }
00167 
00168 void MeshDisplayCustom::addDecalToMaterial(int index, const Ogre::String& matName)
00169 {
00170     Ogre::MaterialPtr mat = (Ogre::MaterialPtr)Ogre::MaterialManager::getSingleton().getByName(matName);
00171     mat->setCullingMode(Ogre::CULL_NONE);
00172     Ogre::Pass* pass = mat->getTechnique(0)->createPass();
00173 
00174     pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
00175     pass->setDepthBias(1);
00176     //pass->setLightingEnabled(true);
00177 
00178     // need the decal_filter to avoid back projection
00179     Ogre::String resource_group_name = "decal_textures_folder";
00180     Ogre::ResourceGroupManager& resource_manager = Ogre::ResourceGroupManager::getSingleton();
00181     if(!resource_manager.resourceGroupExists(resource_group_name))
00182     {
00183         resource_manager.createResourceGroup(resource_group_name);
00184         resource_manager.addResourceLocation(ros::package::getPath("rviz_textured_quads")+"/tests/textures/", "FileSystem", resource_group_name, false);
00185         resource_manager.initialiseResourceGroup(resource_group_name);
00186     }
00187     // loads files into our resource manager
00188     resource_manager.loadResourceGroup(resource_group_name);
00189 
00190     Ogre::TextureUnitState* tex_state = pass->createTextureUnitState();//"Decal.png");
00191     tex_state->setTextureName(textures_[index]->getTexture()->getName());
00192     tex_state->setProjectiveTexturing(true, decal_frustums_[index]);
00193 
00194     tex_state->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
00195     tex_state->setTextureFiltering(Ogre::FO_POINT, Ogre::FO_LINEAR, Ogre::FO_NONE);
00196     tex_state->setColourOperation(Ogre::LBO_REPLACE); //don't accept additional effects
00197 
00198     for(int i = 0; i < filter_frustums_[index].size(); i++)
00199     {
00200         tex_state = pass->createTextureUnitState("Decal_filter.png");
00201         tex_state->setProjectiveTexturing(true, filter_frustums_[index][i]);
00202         tex_state->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
00203         tex_state->setTextureFiltering(Ogre::TFO_NONE);
00204     }
00205 }
00206 
00207 shape_msgs::Mesh MeshDisplayCustom::constructMesh( geometry_msgs::Pose mesh_origin, float width, float height, float border_size )
00208 {
00209     shape_msgs::Mesh mesh;
00210 
00211     Eigen::Affine3d trans_mat;
00212     tf::poseMsgToEigen(mesh_origin, trans_mat);
00213 
00214     // Rviz Coordinate System: x-right, y-forward, z-down
00215     // create mesh vertices and tranform them to the specified pose
00216 
00217     Eigen::Vector4d top_left(-width/2.0f - border_size, 0.0f, -height/2.0f - border_size, 1.0f);
00218     Eigen::Vector4d top_right(width/2.0f + border_size, 0.0f, -height/2.0f - border_size, 1.0f);
00219     Eigen::Vector4d bottom_left(-width/2.0f - border_size, 0.0f, height/2.0f + border_size, 1.0f);
00220     Eigen::Vector4d bottom_right(width/2.0f + border_size, 0.0f, height/2.0f + border_size, 1.0f);
00221 
00222     Eigen::Vector4d trans_top_left = trans_mat.matrix() * top_left;
00223     Eigen::Vector4d trans_top_right = trans_mat.matrix() * top_right;
00224     Eigen::Vector4d trans_bottom_left = trans_mat.matrix() * bottom_left;
00225     Eigen::Vector4d trans_bottom_right = trans_mat.matrix() * bottom_right;
00226 
00227     std::vector<geometry_msgs::Point> vertices(4);
00228     vertices.at(0).x = trans_top_left[0]; 
00229     vertices.at(0).y = trans_top_left[1];  
00230     vertices.at(0).z = trans_top_left[2];  
00231     vertices.at(1).x = trans_top_right[0];
00232     vertices.at(1).y = trans_top_right[1];
00233     vertices.at(1).z = trans_top_right[2];
00234     vertices.at(2).x = trans_bottom_left[0];
00235     vertices.at(2).y = trans_bottom_left[1];
00236     vertices.at(2).z = trans_bottom_left[2];
00237     vertices.at(3).x = trans_bottom_right[0];
00238     vertices.at(3).y = trans_bottom_right[1];
00239     vertices.at(3).z = trans_bottom_right[2];
00240     mesh.vertices = vertices;
00241 
00242     std::vector<shape_msgs::MeshTriangle> triangles(2);
00243     triangles.at(0).vertex_indices[0] = 0;
00244     triangles.at(0).vertex_indices[1] = 1; 
00245     triangles.at(0).vertex_indices[2] = 2; 
00246     triangles.at(1).vertex_indices[0] = 1;
00247     triangles.at(1).vertex_indices[1] = 2; 
00248     triangles.at(1).vertex_indices[2] = 3; 
00249     mesh.triangles = triangles;
00250 
00251     return mesh;
00252 }
00253 
00254 void MeshDisplayCustom::clearStates(int num_quads)
00255 {
00256     for (int q=0; q<manual_objects_.size(); q++)
00257     {
00258         manual_objects_[q]->clear();
00259     }
00260 
00261     for (int q=0; q<text_nodes_.size(); q++)
00262     {
00263         text_nodes_[q]->clear();
00264     }
00265 
00266     // resize state vectors   
00267     mesh_poses_.resize(num_quads);
00268     img_widths_.resize(num_quads);
00269     img_heights_.resize(num_quads);
00270     physical_widths_.resize(num_quads);
00271     physical_heights_.resize(num_quads);
00272 
00273     manual_objects_.resize(num_quads);
00274     last_meshes_.resize(num_quads);
00275     
00276     last_images_.resize(num_quads);
00277     textures_.resize(num_quads);
00278     decal_frustums_.resize(num_quads);
00279     projector_nodes_.resize(num_quads);
00280     filter_frustums_.resize(num_quads);
00281     mesh_materials_.resize(num_quads);
00282     mesh_nodes_.resize(num_quads);
00283     text_nodes_.resize(num_quads);
00284 
00285     border_colors_.resize(num_quads);
00286     border_sizes_.resize(num_quads);  
00287 }
00288 
00289 void MeshDisplayCustom::constructQuads( const rviz_textured_quads::TexturedQuadArray::ConstPtr& images )
00290 {
00291     int num_quads = images->quads.size();
00292 
00293     clearStates(num_quads);
00294 
00295     for (int q=0; q<num_quads; q++)
00296     {
00297         processImage(q, images->quads[q].image);
00298 
00299         geometry_msgs::Pose mesh_origin = images->quads[q].pose;
00300 
00301         // Rotate from x-y to x-z plane:
00302         Eigen::Affine3d trans_mat;
00303         tf::poseMsgToEigen(mesh_origin, trans_mat);
00304         trans_mat = trans_mat * Eigen::Quaterniond(0.70710678, -0.70710678f, 0.0f, 0.0f);
00305         
00306         Eigen::Quaterniond xz_quat(trans_mat.rotation());
00307         mesh_origin.orientation.x = xz_quat.x();
00308         mesh_origin.orientation.y = xz_quat.y();
00309         mesh_origin.orientation.z = xz_quat.z();
00310         mesh_origin.orientation.w = xz_quat.w();
00311 
00312         float width = images->quads[q].width;
00313         float height = images->quads[q].height;
00314 
00315         // set properties
00316         mesh_poses_[q] = mesh_origin;
00317         img_widths_[q] = images->quads[q].image.width;
00318         img_heights_[q] = images->quads[q].image.height;
00319 
00320         border_colors_[q].resize(4);
00321 
00322         if (images->quads[q].border_color.size() == 4) 
00323         {
00324             border_colors_[q][0] = images->quads[q].border_color[0];
00325             border_colors_[q][1] = images->quads[q].border_color[1];
00326             border_colors_[q][2] = images->quads[q].border_color[2];
00327             border_colors_[q][3] = images->quads[q].border_color[3];
00328         }
00329         else
00330         {
00331             // default white border
00332             border_colors_[q][0] = 255.0f;
00333             border_colors_[q][1] = 255.0f;
00334             border_colors_[q][2] = 255.0f;
00335             border_colors_[q][3] = 255.0f;
00336         }
00337 
00338         if (images->quads[q].border_size >= 0.0f)
00339         {
00340             border_sizes_[q] = images->quads[q].border_size;
00341         }
00342         else
00343         {
00344             // default border size (no border)
00345             border_sizes_[q] = 0.0f;
00346         }
00347 
00348         shape_msgs::Mesh mesh = constructMesh(mesh_origin, width, height, border_sizes_[q]);
00349 
00350         physical_widths_[q] = width;
00351         physical_heights_[q] = height;
00352 
00353         boost::mutex::scoped_lock lock( mesh_mutex_ );
00354 
00355         // create our scenenode and material
00356         load(q);
00357 
00358         Ogre::Vector3 caption_position = Ogre::Vector3(mesh_origin.position.x, mesh_origin.position.y + 0.5f*height + text_bottom_offset_->getFloat(), mesh_origin.position.z);
00359 
00360         if (!manual_objects_[q])
00361         {
00362             static uint32_t count = 0;
00363             std::stringstream ss;
00364             ss << "MeshObject" << count++ << "Index" << q;
00365             manual_objects_[q] = context_->getSceneManager()->createManualObject(ss.str());
00366             mesh_nodes_[q]->attachObject(manual_objects_[q]);
00367         }
00368 
00369         // If we have the same number of tris as previously, just update the object
00370         if (last_meshes_[q].vertices.size() > 0 && mesh.vertices.size()*2 == last_meshes_[q].vertices.size())
00371         {
00372             manual_objects_[q]->beginUpdate(0);
00373         }
00374         else // Otherwise clear it and begin anew
00375         {
00376             manual_objects_[q]->clear();
00377             manual_objects_[q]->estimateVertexCount(mesh.vertices.size()*2);
00378             manual_objects_[q]->begin(mesh_materials_[q]->getName(), Ogre::RenderOperation::OT_TRIANGLE_LIST);
00379         }
00380 
00381         const std::vector<geometry_msgs::Point>& points = mesh.vertices;
00382         for(size_t i = 0; i < mesh.triangles.size(); i++)
00383         {
00384             // make sure we have front-face/back-face triangles
00385             for(int side = 0; side < 2; side++)
00386             {
00387                 std::vector<Ogre::Vector3> corners(3);
00388                 for(size_t c = 0; c < 3; c++)
00389                 {
00390                     size_t corner = side ? 2-c : c; // order of corners if side == 1
00391                     corners[corner] = Ogre::Vector3(points[mesh.triangles[i].vertex_indices[corner]].x, points[mesh.triangles[i].vertex_indices[corner]].y, points[mesh.triangles[i].vertex_indices[corner]].z);
00392                 }
00393                 Ogre::Vector3 normal = (corners[1] - corners[0]).crossProduct(corners[2] - corners[0]);
00394                 normal.normalise();
00395 
00396                 for(size_t c = 0; c < 3; c++)
00397                 {
00398                     manual_objects_[q]->position(corners[c]);
00399                     manual_objects_[q]->normal(normal);
00400                 }
00401             }
00402         }
00403 
00404         manual_objects_[q]->end();
00405 
00406         mesh_materials_[q]->setCullingMode(Ogre::CULL_NONE);
00407 
00408         last_meshes_[q] = mesh;
00409 
00410         Ogre::ColourValue text_color(text_color_property_->getColor().redF(), text_color_property_->getColor().greenF(), text_color_property_->getColor().blueF(), 1.0f);
00411 
00412         if (!text_nodes_[q])
00413         {
00414             text_nodes_[q] = new rviz_textured_quads::TextNode(context_->getSceneManager(), manual_objects_[q]->getParentSceneNode(), caption_position);
00415             text_nodes_[q]->setCaption(images->quads[q].caption);
00416             text_nodes_[q]->setCharacterHeight(text_height_property_->getFloat());
00417             text_nodes_[q]->setColor(text_color);
00418         } 
00419         else
00420         {
00421             text_nodes_[q]->setCaption(images->quads[q].caption);
00422             text_nodes_[q]->setPosition(caption_position);
00423             text_nodes_[q]->setCharacterHeight(text_height_property_->getFloat());
00424             text_nodes_[q]->setColor(text_color);
00425 
00426         }
00427 
00428     }
00429 }
00430 
00431 void MeshDisplayCustom::updateImageMeshes( const rviz_textured_quads::TexturedQuadArray::ConstPtr& images )
00432 {
00433     constructQuads(images);
00434     updateMeshProperties();
00435 }
00436 
00437 void MeshDisplayCustom::updateMeshProperties()
00438 {
00439     for (int i=0; i<mesh_materials_.size(); i++)
00440     {
00441         // update color/alpha
00442         Ogre::Technique* technique = mesh_materials_[i]->getTechnique(0);
00443         Ogre::Pass* pass = technique->getPass(0);
00444 
00445         Ogre::ColourValue self_illumination_color(0.0f, 0.0f, 0.0f, 0.0f);// border_colors_[i][3]);
00446         pass->setSelfIllumination(self_illumination_color);
00447 
00448         Ogre::ColourValue diffuse_color(0.0f, 0.0f, 0.0f, 1.0f/*border_colors_[i][0], border_colors_[i][1], border_colors_[i][2], border_colors_[i][3]*/);
00449         pass->setDiffuse(diffuse_color);
00450 
00451         Ogre::ColourValue ambient_color(border_colors_[i][0], border_colors_[i][1], border_colors_[i][2], border_colors_[i][3]);
00452         pass->setAmbient(ambient_color);
00453 
00454         Ogre::ColourValue specular_color(0.0f, 0.0f, 0.0f, 1.0f);
00455         pass->setSpecular(specular_color);
00456 
00457         Ogre::Real shininess = 64.0f;
00458         pass->setShininess(shininess);
00459 
00460         pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
00461         pass->setDepthWriteEnabled(false);
00462 
00463         context_->queueRender();
00464     }
00465 
00466 }
00467 
00468 void MeshDisplayCustom::updateDisplayImages()
00469 {
00470     unsubscribe();
00471     subscribe();
00472 }
00473 
00474 void MeshDisplayCustom::subscribe()
00475 {
00476     if ( !isEnabled() )
00477     {
00478         return;
00479     }
00480 
00481     if( !display_images_topic_property_->getTopic().isEmpty() )
00482     {
00483         try
00484         {
00485             rviz_display_images_sub_ = nh_.subscribe(display_images_topic_property_->getTopicStd(), 1, &MeshDisplayCustom::updateImageMeshes, this);
00486             setStatus( StatusProperty::Ok, "Display Images Topic", "OK" );
00487         }
00488         catch( ros::Exception& e )
00489         {
00490             setStatus( StatusProperty::Error, "Display Images Topic", QString( "Error subscribing: " ) + e.what() );
00491         }
00492     }
00493 }
00494 
00495 void MeshDisplayCustom::unsubscribe()
00496 {
00497     rviz_display_images_sub_.shutdown();
00498 }
00499 
00500 void MeshDisplayCustom::load(int index)
00501 {   
00502     if(mesh_nodes_[index] != NULL)
00503         return;
00504 
00505     static int count = 0;
00506     std::stringstream ss;
00507     ss << "MeshNode" << count++ << "GroupIndex" << index;
00508     Ogre::MaterialManager& material_manager = Ogre::MaterialManager::getSingleton();
00509     Ogre::String resource_group_name =  ss.str();
00510 
00511     Ogre::ResourceGroupManager& rg_mgr = Ogre::ResourceGroupManager::getSingleton();
00512 
00513     Ogre::String material_name = resource_group_name+"MeshMaterial";
00514 
00515     if(!rg_mgr.resourceGroupExists(resource_group_name))
00516     {
00517         rg_mgr.createResourceGroup(resource_group_name);
00518 
00519         mesh_materials_[index] = material_manager.create(material_name,resource_group_name);
00520         Ogre::Technique* technique = mesh_materials_[index]->getTechnique(0);
00521         Ogre::Pass* pass = technique->getPass(0);
00522 
00523         Ogre::ColourValue self_illumnation_color(0.0f, 0.0f, 0.0f, border_colors_[index][3]);
00524         pass->setSelfIllumination(self_illumnation_color);
00525 
00526         Ogre::ColourValue diffuse_color(border_colors_[index][0], border_colors_[index][1], border_colors_[index][2], border_colors_[index][3]);
00527         pass->setDiffuse(diffuse_color);
00528 
00529         Ogre::ColourValue ambient_color(border_colors_[index][0], border_colors_[index][1], border_colors_[index][2], border_colors_[index][3]);
00530         pass->setAmbient(ambient_color);
00531 
00532         Ogre::ColourValue specular_color(1.0f, 1.0f, 1.0f, 1.0f);
00533         pass->setSpecular(specular_color);
00534 
00535         Ogre::Real shininess = 64.0f;
00536         pass->setShininess(shininess);
00537 
00538         pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
00539 
00540         mesh_materials_[index]->setCullingMode(Ogre::CULL_NONE);
00541     }
00542 
00543     mesh_nodes_[index] = this->scene_node_->createChildSceneNode();
00544 
00545 }
00546 
00547 void MeshDisplayCustom::onEnable()
00548 {
00549     subscribe();
00550 }
00551 
00552 void MeshDisplayCustom::onDisable()
00553 {
00554     unsubscribe();
00555 }
00556 
00557 void MeshDisplayCustom::update( float wall_dt, float ros_dt )
00558 {
00559     time_since_last_transform_ += wall_dt;
00560 
00561     if( !display_images_topic_property_->getTopic().isEmpty() )
00562     {
00563         try
00564         {
00565             for (int i=0; i<textures_.size(); i++)
00566             {
00567                 updateCamera(i, textures_[i]->update());
00568             }
00569         }
00570         catch( UnsupportedImageEncoding& e )
00571         {
00572             setStatus(StatusProperty::Error, "Display Image", e.what());
00573         }
00574     }
00575 }
00576 
00577 bool MeshDisplayCustom::updateCamera(int index, bool update_image)
00578 {
00579     if(update_image)
00580     {
00581         last_images_[index] = textures_[index]->getImage();
00582     }
00583 
00584     if(!img_heights_[index] || !img_widths_[index] || 
00585        !physical_widths_[index] || !physical_heights_[index] || 
00586        !last_images_[index])
00587     {        
00588         return false;
00589     }
00590 
00591     boost::mutex::scoped_lock lock( mesh_mutex_ );
00592 
00593     float img_width  = img_widths_[index];
00594     float img_height = img_heights_[index];
00595 
00596     Ogre::Vector3 position;
00597     Ogre::Quaternion orientation;
00598 
00599     context_->getFrameManager()->getTransform( last_images_[index]->header.frame_id, last_images_[index]->header.stamp, position, orientation );
00600 
00601     Eigen::Affine3d trans_mat;
00602     tf::poseMsgToEigen(mesh_poses_[index], trans_mat);
00603 
00604     // Rotate by 90 deg to get xz plane
00605     trans_mat = trans_mat * Eigen::Quaterniond(0.70710678, -0.70710678f, 0.0f, 0.0f);
00606 
00607     float z_offset = (img_width > img_height) ? img_width : img_height;
00608     float scale_factor = 1.0f / (physical_widths_[index] > physical_heights_[index] ? physical_widths_[index] : physical_heights_[index]);
00609 
00610     Eigen::Vector4d projector_origin(0.0f, 0.0f, 1.0f / (z_offset * scale_factor), 1.0f);
00611     Eigen::Vector4d projector_point = trans_mat.matrix() * projector_origin;
00612 
00613     position = Ogre::Vector3(projector_point[0], projector_point[1], projector_point[2] );
00614     orientation = Ogre::Quaternion(mesh_poses_[index].orientation.w, mesh_poses_[index].orientation.x, mesh_poses_[index].orientation.y, mesh_poses_[index].orientation.z);
00615 
00616     // Update orientation with 90 deg offset (xy to xz)
00617     orientation = orientation * Ogre::Quaternion( Ogre::Degree( -90 ), Ogre::Vector3::UNIT_X );
00618 
00619     // convert vision (Z-forward) frame to ogre frame (Z-out)
00620     orientation = orientation * Ogre::Quaternion( Ogre::Degree( 180 ), Ogre::Vector3::UNIT_Z );
00621 
00622 
00623     // std::cout << "CameraInfo dimensions: " << last_info_->width << " x " << last_info_->height << std::endl;
00624     // std::cout << "Texture dimensions: " << last_image_->width << " x " << last_image_->height << std::endl;
00625     //std::cout << "Original image dimensions: " << last_image_->width*full_image_binning_ << " x " << last_image_->height*full_image_binning_ << std::endl;
00626 
00627     // If the image width/height is 0 due to a malformed caminfo, try to grab the width from the image.
00628     if( img_width <= 0 )
00629     {
00630       ROS_ERROR( "Malformed CameraInfo on camera [%s], width = 0", qPrintable( getName() ));
00631       // use texture size, but have to remove border from the perspective calculations
00632       img_width = textures_[index]->getWidth()-2;
00633     }
00634 
00635     if (img_height <= 0)
00636     {
00637         ROS_ERROR( "Malformed CameraInfo on camera [%s], height = 0", qPrintable( getName() ));
00638         // use texture size, but have to remove border from the perspective calculations
00639         img_height = textures_[index]->getHeight()-2;
00640     }
00641 
00642     // if even the texture has 0 size, return
00643     if( img_height <= 0.0 || img_width <= 0.0 )
00644     {
00645         setStatus( StatusProperty::Error, "Camera Info",
00646                  "Could not determine width/height of image due to malformed CameraInfo (either width or height is 0) and texture." );
00647         return false;
00648     }
00649 
00650     // projection matrix
00651     float P[12] = {1.0, 0.0, img_width / 2.0f, 0.0, 
00652                    0.0, 1.0, img_height / 2.0f, 0.0, 
00653                    0.0, 0.0, 1.0, 0.0 };
00654 
00655     // calculate projection matrix
00656     double fx = P[0];
00657     double fy = P[5];
00658 
00659     // Add the camera's translation relative to the left camera (from P[3]);
00660     double tx = -1 * (P[3] / fx);
00661     Ogre::Vector3 right = orientation * Ogre::Vector3::UNIT_X;
00662     position = position + (right * tx);
00663 
00664     double ty = -1 * (P[7] / fy);
00665     Ogre::Vector3 down = orientation * Ogre::Vector3::UNIT_Y;
00666     position = position + (down * ty);
00667 
00668     if( !validateFloats( position ))
00669     {
00670         ROS_ERROR( "position error");
00671         setStatus( StatusProperty::Error, "Camera Info", "CameraInfo/P resulted in an invalid position calculation (nans or infs)" );
00672         return false;
00673     }
00674 
00675     if(projector_nodes_[index] != NULL)
00676     {
00677         projector_nodes_[index]->setPosition( position );
00678         projector_nodes_[index]->setOrientation( orientation );
00679     }
00680 
00681     // calculate the projection matrix
00682     double cx = P[2];
00683     double cy = P[6];
00684 
00685     double far_plane = 100;
00686     double near_plane = 0.01;
00687 
00688     Ogre::Matrix4 proj_matrix;
00689     proj_matrix = Ogre::Matrix4::ZERO;
00690 
00691     proj_matrix[0][0]= 2.0 * fx/img_width;
00692     proj_matrix[1][1]= 2.0 * fy/img_height;
00693 
00694     proj_matrix[0][2]= 2.0 * (0.5 - cx/img_width);
00695     proj_matrix[1][2]= 2.0 * (cy/img_height - 0.5);
00696 
00697     proj_matrix[2][2]= -(far_plane+near_plane) / (far_plane-near_plane);
00698     proj_matrix[2][3]= -2.0*far_plane*near_plane / (far_plane-near_plane);
00699 
00700     proj_matrix[3][2]= -1;
00701 
00702     if(decal_frustums_[index] != NULL)
00703         decal_frustums_[index]->setCustomProjectionMatrix(true, proj_matrix);
00704 
00705     // ROS_INFO(" Camera (%f, %f)", proj_matrix[0][0], proj_matrix[1][1]);
00706     // ROS_INFO(" Render Panel: %x   Viewport: %x", render_panel_, render_panel_->getViewport());
00707 
00708 
00709     setStatus( StatusProperty::Ok, "Time", "ok" );
00710     setStatus( StatusProperty::Ok, "Camera Info", "ok" );
00711 
00712     if(mesh_nodes_[index] != NULL && filter_frustums_[index].size() == 0 && !mesh_materials_[index].isNull())
00713     {
00714         createProjector(index);
00715 
00716         addDecalToMaterial(index, mesh_materials_[index]->getName());
00717     }
00718 
00719     return true;
00720 }
00721 
00722 void MeshDisplayCustom::clear()
00723 {
00724     for (int i=0; i<textures_.size(); i++)
00725     {
00726         textures_[i]->clear();
00727     }
00728 
00729     context_->queueRender();
00730 
00731     setStatus( StatusProperty::Warn, "Image", "No Image received");
00732 }
00733 
00734 void MeshDisplayCustom::reset()
00735 {
00736     Display::reset();
00737     clear();
00738 }
00739 
00740 void MeshDisplayCustom::processImage(int index, const sensor_msgs::Image& msg)
00741 {
00742     //std::cout<<"camera image received"<<std::endl;
00743     cv_bridge::CvImagePtr cv_ptr;
00744 
00745     // simply converting every image to RGBA
00746     try
00747     {
00748         cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::RGBA8);
00749     }
00750     catch (cv_bridge::Exception& e)
00751     {
00752         ROS_ERROR("MeshDisplayCustom: cv_bridge exception: %s", e.what());
00753         return;
00754     }
00755 
00756     // add completely white transparent border to the image so that it won't replicate colored pixels all over the mesh
00757     cv::Scalar value(255,255,255,0);
00758     cv::copyMakeBorder(cv_ptr->image,cv_ptr->image,1,1,1,1,cv::BORDER_CONSTANT,value);
00759     cv::flip(cv_ptr->image,cv_ptr->image,-1);
00760 
00761     // Output modified video stream
00762     if (textures_[index] == NULL)
00763         textures_[index] = new ROSImageTexture();
00764 
00765     textures_[index]->addMessage(cv_ptr->toImageMsg());
00766 }
00767 
00768 } // namespace rviz


rviz_textured_quads
Author(s): Mohit Shridhar
autogenerated on Thu Jun 6 2019 19:50:52