$search
00001 /* 00002 * Copyright (c) 2008, Willow Garage, Inc. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of the Willow Garage, Inc. nor the names of its 00014 * contributors may be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 #include "marker_display.h" 00031 #include "rviz/visualization_manager.h" 00032 #include "rviz/properties/property_manager.h" 00033 #include "rviz/properties/property.h" 00034 #include "rviz/selection/selection_manager.h" 00035 #include "rviz/frame_manager.h" 00036 #include "rviz/validate_floats.h" 00037 00038 #include "markers/shape_marker.h" 00039 #include "markers/arrow_marker.h" 00040 #include "markers/line_list_marker.h" 00041 #include "markers/line_strip_marker.h" 00042 #include "markers/points_marker.h" 00043 #include "markers/text_view_facing_marker.h" 00044 #include "markers/mesh_resource_marker.h" 00045 #include "markers/triangle_list_marker.h" 00046 00047 #include <ogre_tools/arrow.h> 00048 #include <ogre_tools/shape.h> 00049 #include <ogre_tools/billboard_line.h> 00050 00051 #include <tf/transform_listener.h> 00052 00053 #include <OGRE/OgreSceneNode.h> 00054 #include <OGRE/OgreSceneManager.h> 00055 00056 namespace rviz 00057 { 00058 00062 00063 MarkerDisplay::MarkerDisplay() 00064 : Display() 00065 , marker_topic_("visualization_marker") 00066 { 00067 } 00068 00069 void MarkerDisplay::onInitialize() 00070 { 00071 tf_filter_ = new tf::MessageFilter<visualization_msgs::Marker>(*vis_manager_->getTFClient(), "", 100, update_nh_); 00072 scene_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode(); 00073 00074 tf_filter_->connectInput(sub_); 00075 tf_filter_->registerCallback(boost::bind(&MarkerDisplay::incomingMarker, this, _1)); 00076 tf_filter_->registerFailureCallback(boost::bind(&MarkerDisplay::failedMarker, this, _1, _2)); 00077 } 00078 00079 MarkerDisplay::~MarkerDisplay() 00080 { 00081 unsubscribe(); 00082 00083 clearMarkers(); 00084 00085 delete tf_filter_; 00086 } 00087 00088 MarkerBasePtr MarkerDisplay::getMarker(MarkerID id) 00089 { 00090 M_IDToMarker::iterator it = markers_.find(id); 00091 if (it != markers_.end()) 00092 { 00093 return it->second; 00094 } 00095 00096 return MarkerBasePtr(); 00097 } 00098 00099 void MarkerDisplay::clearMarkers() 00100 { 00101 markers_.clear(); 00102 markers_with_expiration_.clear(); 00103 frame_locked_markers_.clear(); 00104 tf_filter_->clear(); 00105 00106 if (property_manager_) 00107 { 00108 M_Namespace::iterator it = namespaces_.begin(); 00109 M_Namespace::iterator end = namespaces_.end(); 00110 for (; it != end; ++it) 00111 { 00112 property_manager_->deleteProperty(it->second.prop.lock()); 00113 } 00114 } 00115 00116 namespaces_.clear(); 00117 } 00118 00119 void MarkerDisplay::onEnable() 00120 { 00121 subscribe(); 00122 00123 scene_node_->setVisible( true ); 00124 } 00125 00126 void MarkerDisplay::onDisable() 00127 { 00128 unsubscribe(); 00129 tf_filter_->clear(); 00130 00131 clearMarkers(); 00132 00133 scene_node_->setVisible( false ); 00134 } 00135 00136 void MarkerDisplay::setMarkerTopic(const std::string& topic) 00137 { 00138 unsubscribe(); 00139 marker_topic_ = topic; 00140 subscribe(); 00141 00142 propertyChanged(marker_topic_property_); 00143 } 00144 00145 void MarkerDisplay::subscribe() 00146 { 00147 if ( !isEnabled() ) 00148 { 00149 return; 00150 } 00151 00152 if (!marker_topic_.empty()) 00153 { 00154 array_sub_.shutdown(); 00155 sub_.unsubscribe(); 00156 00157 try 00158 { 00159 sub_.subscribe(update_nh_, marker_topic_, 1000); 00160 array_sub_ = update_nh_.subscribe(marker_topic_ + "_array", 1000, &MarkerDisplay::incomingMarkerArray, this); 00161 setStatus(status_levels::Ok, "Topic", "OK"); 00162 } 00163 catch (ros::Exception& e) 00164 { 00165 setStatus(status_levels::Error, "Topic", std::string("Error subscribing: ") + e.what()); 00166 } 00167 } 00168 } 00169 00170 void MarkerDisplay::unsubscribe() 00171 { 00172 sub_.unsubscribe(); 00173 array_sub_.shutdown(); 00174 } 00175 00176 void MarkerDisplay::deleteMarker(MarkerID id) 00177 { 00178 deleteMarkerStatus(id); 00179 00180 M_IDToMarker::iterator it = markers_.find(id); 00181 if (it != markers_.end()) 00182 { 00183 markers_with_expiration_.erase(it->second); 00184 frame_locked_markers_.erase(it->second); 00185 markers_.erase(it); 00186 } 00187 } 00188 00189 void MarkerDisplay::setNamespaceEnabled(const std::string& ns, bool enabled) 00190 { 00191 M_Namespace::iterator it = namespaces_.find(ns); 00192 if (it != namespaces_.end()) 00193 { 00194 it->second.enabled = enabled; 00195 00196 std::vector<MarkerID> to_delete; 00197 00198 // TODO: this is inefficient, should store every in-use id per namespace and lookup by that 00199 M_IDToMarker::iterator marker_it = markers_.begin(); 00200 M_IDToMarker::iterator marker_end = markers_.end(); 00201 for (; marker_it != marker_end; ++marker_it) 00202 { 00203 if (marker_it->first.first == ns) 00204 { 00205 to_delete.push_back(marker_it->first); 00206 } 00207 } 00208 00209 { 00210 std::vector<MarkerID>::iterator it = to_delete.begin(); 00211 std::vector<MarkerID>::iterator end = to_delete.end(); 00212 for (; it != end; ++it) 00213 { 00214 deleteMarker(*it); 00215 } 00216 } 00217 } 00218 } 00219 00220 bool MarkerDisplay::isNamespaceEnabled(const std::string& ns) 00221 { 00222 M_Namespace::iterator it = namespaces_.find(ns); 00223 if (it != namespaces_.end()) 00224 { 00225 return it->second.enabled; 00226 } 00227 00228 return true; 00229 } 00230 00231 void MarkerDisplay::setMarkerStatus(MarkerID id, StatusLevel level, const std::string& text) 00232 { 00233 std::stringstream ss; 00234 ss << id.first << "/" << id.second; 00235 std::string marker_name = ss.str(); 00236 setStatus(level, marker_name, text); 00237 } 00238 00239 void MarkerDisplay::deleteMarkerStatus(MarkerID id) 00240 { 00241 std::stringstream ss; 00242 ss << id.first << "/" << id.second; 00243 std::string marker_name = ss.str(); 00244 deleteStatus(marker_name); 00245 } 00246 00247 void MarkerDisplay::incomingMarkerArray(const visualization_msgs::MarkerArray::ConstPtr& array) 00248 { 00249 std::vector<visualization_msgs::Marker>::const_iterator it = array->markers.begin(); 00250 std::vector<visualization_msgs::Marker>::const_iterator end = array->markers.end(); 00251 for (; it != end; ++it) 00252 { 00253 const visualization_msgs::Marker& marker = *it; 00254 tf_filter_->add(visualization_msgs::Marker::Ptr(new visualization_msgs::Marker(marker))); 00255 } 00256 } 00257 00258 void MarkerDisplay::incomingMarker( const visualization_msgs::Marker::ConstPtr& marker ) 00259 { 00260 boost::mutex::scoped_lock lock(queue_mutex_); 00261 00262 message_queue_.push_back(marker); 00263 } 00264 00265 void MarkerDisplay::failedMarker(const visualization_msgs::Marker::ConstPtr& marker, tf::FilterFailureReason reason) 00266 { 00267 std::string error = FrameManager::instance()->discoverFailureReason(marker->header.frame_id, marker->header.stamp, marker->__connection_header ? (*marker->__connection_header)["callerid"] : "unknown", reason); 00268 setMarkerStatus(MarkerID(marker->ns, marker->id), status_levels::Error, error); 00269 } 00270 00271 bool validateFloats(const visualization_msgs::Marker& msg) 00272 { 00273 bool valid = true; 00274 valid = valid && validateFloats(msg.pose); 00275 valid = valid && validateFloats(msg.scale); 00276 valid = valid && validateFloats(msg.color); 00277 valid = valid && validateFloats(msg.points); 00278 return valid; 00279 } 00280 00281 void MarkerDisplay::processMessage( const visualization_msgs::Marker::ConstPtr& message ) 00282 { 00283 if (!validateFloats(*message)) 00284 { 00285 setMarkerStatus(MarkerID(message->ns, message->id), status_levels::Error, "Contains invalid floating point values (nans or infs)"); 00286 return; 00287 } 00288 00289 switch ( message->action ) 00290 { 00291 case visualization_msgs::Marker::ADD: 00292 processAdd( message ); 00293 break; 00294 00295 case visualization_msgs::Marker::DELETE: 00296 processDelete( message ); 00297 break; 00298 00299 default: 00300 ROS_ERROR( "Unknown marker action: %d\n", message->action ); 00301 } 00302 } 00303 00304 void MarkerDisplay::processAdd( const visualization_msgs::Marker::ConstPtr& message ) 00305 { 00306 // 00307 M_Namespace::iterator ns_it = namespaces_.find(message->ns); 00308 if (ns_it == namespaces_.end()) 00309 { 00310 Namespace ns; 00311 ns.name = message->ns; 00312 ns.enabled = true; 00313 00314 if (property_manager_) 00315 { 00316 ns.prop = property_manager_->createProperty<BoolProperty>(ns.name, property_prefix_, boost::bind(&MarkerDisplay::isNamespaceEnabled, this, ns.name), 00317 boost::bind(&MarkerDisplay::setNamespaceEnabled, this, ns.name, _1), namespaces_category_, this); 00318 setPropertyHelpText(ns.prop, "Enable/disable all markers in this namespace."); 00319 } 00320 00321 ns_it = namespaces_.insert(std::make_pair(ns.name, ns)).first; 00322 } 00323 00324 if (!ns_it->second.enabled) 00325 { 00326 return; 00327 } 00328 00329 deleteMarkerStatus(MarkerID(message->ns, message->id)); 00330 00331 bool create = true; 00332 MarkerBasePtr marker; 00333 00334 M_IDToMarker::iterator it = markers_.find( MarkerID(message->ns, message->id) ); 00335 if ( it != markers_.end() ) 00336 { 00337 marker = it->second; 00338 markers_with_expiration_.erase(marker); 00339 if ( message->type == marker->getMessage()->type ) 00340 { 00341 create = false; 00342 } 00343 else 00344 { 00345 markers_.erase( it ); 00346 } 00347 } 00348 00349 if ( create ) 00350 { 00351 switch ( message->type ) 00352 { 00353 case visualization_msgs::Marker::CUBE: 00354 case visualization_msgs::Marker::CYLINDER: 00355 case visualization_msgs::Marker::SPHERE: 00356 { 00357 marker.reset(new ShapeMarker(this, vis_manager_, scene_node_)); 00358 } 00359 break; 00360 00361 case visualization_msgs::Marker::ARROW: 00362 { 00363 marker.reset(new ArrowMarker(this, vis_manager_, scene_node_)); 00364 } 00365 break; 00366 00367 case visualization_msgs::Marker::LINE_STRIP: 00368 { 00369 marker.reset(new LineStripMarker(this, vis_manager_, scene_node_)); 00370 } 00371 break; 00372 case visualization_msgs::Marker::LINE_LIST: 00373 { 00374 marker.reset(new LineListMarker(this, vis_manager_, scene_node_)); 00375 } 00376 break; 00377 case visualization_msgs::Marker::SPHERE_LIST: 00378 case visualization_msgs::Marker::CUBE_LIST: 00379 case visualization_msgs::Marker::POINTS: 00380 { 00381 marker.reset(new PointsMarker(this, vis_manager_, scene_node_)); 00382 } 00383 break; 00384 case visualization_msgs::Marker::TEXT_VIEW_FACING: 00385 { 00386 marker.reset(new TextViewFacingMarker(this, vis_manager_, scene_node_)); 00387 } 00388 break; 00389 case visualization_msgs::Marker::MESH_RESOURCE: 00390 { 00391 marker.reset(new MeshResourceMarker(this, vis_manager_, scene_node_)); 00392 } 00393 break; 00394 00395 case visualization_msgs::Marker::TRIANGLE_LIST: 00396 { 00397 marker.reset(new TriangleListMarker(this, vis_manager_, scene_node_)); 00398 } 00399 break; 00400 default: 00401 ROS_ERROR( "Unknown marker type: %d", message->type ); 00402 } 00403 00404 markers_.insert(std::make_pair(MarkerID(message->ns, message->id), marker)); 00405 } 00406 00407 if (marker) 00408 { 00409 marker->setMessage(message); 00410 00411 if (message->lifetime.toSec() > 0.0001f) 00412 { 00413 markers_with_expiration_.insert(marker); 00414 } 00415 00416 if (message->frame_locked) 00417 { 00418 frame_locked_markers_.insert(marker); 00419 } 00420 00421 causeRender(); 00422 } 00423 } 00424 00425 void MarkerDisplay::processDelete( const visualization_msgs::Marker::ConstPtr& message ) 00426 { 00427 deleteMarker(MarkerID(message->ns, message->id)); 00428 causeRender(); 00429 } 00430 00431 void MarkerDisplay::update(float wall_dt, float ros_dt) 00432 { 00433 V_MarkerMessage local_queue; 00434 00435 { 00436 boost::mutex::scoped_lock lock(queue_mutex_); 00437 00438 local_queue.swap( message_queue_ ); 00439 } 00440 00441 if ( !local_queue.empty() ) 00442 { 00443 V_MarkerMessage::iterator message_it = local_queue.begin(); 00444 V_MarkerMessage::iterator message_end = local_queue.end(); 00445 for ( ; message_it != message_end; ++message_it ) 00446 { 00447 visualization_msgs::Marker::ConstPtr& marker = *message_it; 00448 00449 processMessage( marker ); 00450 } 00451 } 00452 00453 { 00454 S_MarkerBase::iterator it = markers_with_expiration_.begin(); 00455 S_MarkerBase::iterator end = markers_with_expiration_.end(); 00456 for (; it != end;) 00457 { 00458 MarkerBasePtr marker = *it; 00459 if (marker->expired()) 00460 { 00461 S_MarkerBase::iterator copy = it; 00462 ++it; 00463 deleteMarker(marker->getID()); 00464 } 00465 else 00466 { 00467 ++it; 00468 } 00469 } 00470 } 00471 00472 { 00473 S_MarkerBase::iterator it = frame_locked_markers_.begin(); 00474 S_MarkerBase::iterator end = frame_locked_markers_.end(); 00475 for (; it != end; ++it) 00476 { 00477 MarkerBasePtr marker = *it; 00478 marker->updateFrameLocked(); 00479 } 00480 } 00481 } 00482 00483 void MarkerDisplay::targetFrameChanged() 00484 { 00485 } 00486 00487 void MarkerDisplay::fixedFrameChanged() 00488 { 00489 tf_filter_->setTargetFrame( fixed_frame_ ); 00490 00491 clearMarkers(); 00492 } 00493 00494 void MarkerDisplay::reset() 00495 { 00496 Display::reset(); 00497 clearMarkers(); 00498 } 00499 00500 void MarkerDisplay::createProperties() 00501 { 00502 marker_topic_property_ = property_manager_->createProperty<ROSTopicStringProperty>( "Marker Topic", property_prefix_, boost::bind( &MarkerDisplay::getMarkerTopic, this ), 00503 boost::bind( &MarkerDisplay::setMarkerTopic, this, _1 ), parent_category_, this ); 00504 setPropertyHelpText(marker_topic_property_, "visualization_msgs::Marker topic to subscribe to. <topic>_array will also automatically be subscribed with type visualization_msgs::MarkerArray."); 00505 ROSTopicStringPropertyPtr topic_prop = marker_topic_property_.lock(); 00506 topic_prop->setMessageType(ros::message_traits::datatype<visualization_msgs::Marker>()); 00507 00508 namespaces_category_ = property_manager_->createCategory("Namespaces", property_prefix_, parent_category_, this); 00509 } 00510 00511 } // namespace rviz