interactive_marker_display.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <tf/transform_listener.h>
31 
32 #include "rviz/frame_manager.h"
36 #include "rviz/validate_floats.h"
38 #include "rviz/display_context.h"
39 
41 
42 
43 namespace rviz
44 {
45 
47 bool validateFloats(const visualization_msgs::InteractiveMarker& msg)
48 {
49  bool valid = true;
50  valid = valid && validateFloats(msg.pose);
51  valid = valid && validateFloats(msg.scale);
52  for ( unsigned c=0; c<msg.controls.size(); c++)
53  {
54  valid = valid && validateFloats( msg.controls[c].orientation );
55  for ( unsigned m=0; m<msg.controls[c].markers.size(); m++ )
56  {
57  valid = valid && validateFloats(msg.controls[c].markers[m].pose);
58  valid = valid && validateFloats(msg.controls[c].markers[m].scale);
59  valid = valid && validateFloats(msg.controls[c].markers[m].color);
60  valid = valid && validateFloats(msg.controls[c].markers[m].points);
61  }
62  }
63  return valid;
64 }
65 
66 bool validateQuaternions(const visualization_msgs::InteractiveMarker &marker)
67 {
68  if ( !validateQuaternions( marker.pose.orientation )) return false;
69  for ( int c = 0; c < marker.controls.size(); ++c )
70  {
71  if ( !validateQuaternions( marker.controls[c].orientation )) return false;
72  for ( int m = 0; m < marker.controls[c].markers.size(); ++m )
73  {
74  if ( !validateQuaternions( marker.controls[c].markers[m].pose.orientation )) return false;
75  }
76  }
77  return true;
78 }
80 
81 
82 
84  : Display()
85 {
86  marker_update_topic_property_ = new RosTopicProperty( "Update Topic", "",
87  ros::message_traits::datatype<visualization_msgs::InteractiveMarkerUpdate>(),
88  "visualization_msgs::InteractiveMarkerUpdate topic to subscribe to.",
89  this, SLOT( updateTopic() ));
90 
91  show_descriptions_property_ = new BoolProperty( "Show Descriptions", true,
92  "Whether or not to show the descriptions of each Interactive Marker.",
93  this, SLOT( updateShowDescriptions() ));
94 
95  show_axes_property_ = new BoolProperty( "Show Axes", false,
96  "Whether or not to show the axes of each Interactive Marker.",
97  this, SLOT( updateShowAxes() ));
98 
99  show_visual_aids_property_ = new BoolProperty( "Show Visual Aids", false,
100  "Whether or not to show visual helpers while moving/rotating Interactive Markers.",
101  this, SLOT( updateShowVisualAids() ));
102  enable_transparency_property_ = new BoolProperty( "Enable Transparency", true,
103  "Whether or not to allow transparency for auto-completed markers (e.g. rings and arrows).",
104  this, SLOT( updateEnableTransparency() ));
105 }
106 
108 {
110  im_client_.reset( new interactive_markers::InteractiveMarkerClient( *tf, fixed_frame_.toStdString() ) );
111 
112  im_client_->setInitCb( boost::bind( &InteractiveMarkerDisplay::initCb, this, _1 ) );
113  im_client_->setUpdateCb( boost::bind( &InteractiveMarkerDisplay::updateCb, this, _1 ) );
114  im_client_->setResetCb( boost::bind( &InteractiveMarkerDisplay::resetCb, this, _1 ) );
115  im_client_->setStatusCb( boost::bind( &InteractiveMarkerDisplay::statusCb, this, _1, _2, _3 ) );
116 
118 
119  onEnable();
120 }
121 
122 void InteractiveMarkerDisplay::setTopic( const QString &topic, const QString &datatype )
123 {
125 }
126 
128 {
129  subscribe();
130 }
131 
133 {
134  unsubscribe();
135 }
136 
138 {
139  unsubscribe();
140 
141  std::string update_topic = marker_update_topic_property_->getTopicStd();
142 
143  size_t idx = update_topic.find( "/update" );
144  if ( idx != std::string::npos )
145  {
146  topic_ns_ = update_topic.substr( 0, idx );
147  subscribe();
148  }
149  else
150  {
151  setStatusStd( StatusProperty::Error, "Topic", "Invalid topic name: " + update_topic );
152  }
153 
154 }
155 
157 {
158  if ( isEnabled() )
159  {
160  im_client_->subscribe(topic_ns_);
161 
162  std::string feedback_topic = topic_ns_+"/feedback";
163  feedback_pub_ = update_nh_.advertise<visualization_msgs::InteractiveMarkerFeedback>( feedback_topic, 100, false );
164  }
165 }
166 
167 void InteractiveMarkerDisplay::publishFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback)
168 {
169  feedback.client_id = client_id_;
170  feedback_pub_.publish( feedback );
171 }
172 
173 void InteractiveMarkerDisplay::onStatusUpdate( StatusProperty::Level level, const std::string& name, const std::string& text )
174 {
175  setStatusStd(level,name,text);
176 }
177 
179 {
180  if (im_client_)
181  {
182  im_client_->shutdown();
183  }
185  Display::reset();
186 }
187 
188 void InteractiveMarkerDisplay::update(float wall_dt, float ros_dt)
189 {
190  im_client_->update();
191 
192  M_StringToStringToIMPtr::iterator server_it;
193  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
194  {
195  M_StringToIMPtr::iterator im_it;
196  for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
197  {
198  im_it->second->update( wall_dt );
199  }
200  }
201 }
202 
204 {
205  M_StringToStringToIMPtr::iterator im_map_it = interactive_markers_.find( server_id );
206 
207  if ( im_map_it == interactive_markers_.end() )
208  {
209  im_map_it = interactive_markers_.insert( std::make_pair( server_id, M_StringToIMPtr() ) ).first;
210  }
211 
212  return im_map_it->second;
213 }
214 
216  const std::string& server_id,
217  const std::vector<visualization_msgs::InteractiveMarker>& markers
218  )
219 {
220  M_StringToIMPtr& im_map = getImMap( server_id );
221 
222  for ( size_t i=0; i<markers.size(); i++ )
223  {
224  const visualization_msgs::InteractiveMarker& marker = markers[i];
225 
226  if ( !validateFloats( marker ) )
227  {
228  setStatusStd( StatusProperty::Error, marker.name, "Marker contains invalid floats!" );
229  //setStatusStd( StatusProperty::Error, "General", "Marker " + marker.name + " contains invalid floats!" );
230  continue;
231  }
232 
233  if( !validateQuaternions( marker ))
234  {
235  ROS_WARN_ONCE_NAMED( "quaternions", "Interactive marker '%s' contains unnormalized quaternions. "
236  "This warning will only be output once but may be true for others; "
237  "enable DEBUG messages for ros.rviz.quaternions to see more details.",
238  marker.name.c_str() );
239  ROS_DEBUG_NAMED( "quaternions", "Interactive marker '%s' contains unnormalized quaternions.",
240  marker.name.c_str() );
241  }
242  ROS_DEBUG("Processing interactive marker '%s'. %d", marker.name.c_str(), (int)marker.controls.size() );
243 
244  std::map< std::string, IMPtr >::iterator int_marker_entry = im_map.find( marker.name );
245 
246  if ( int_marker_entry == im_map.end() )
247  {
248  int_marker_entry = im_map.insert( std::make_pair(marker.name, IMPtr ( new InteractiveMarker(getSceneNode(), context_) ) ) ).first;
249  connect( int_marker_entry->second.get(),
250  SIGNAL( userFeedback(visualization_msgs::InteractiveMarkerFeedback&) ),
251  this,
252  SLOT( publishFeedback(visualization_msgs::InteractiveMarkerFeedback&) ));
253  connect( int_marker_entry->second.get(),
254  SIGNAL( statusUpdate(StatusProperty::Level, const std::string&, const std::string&) ),
255  this,
256  SLOT( onStatusUpdate(StatusProperty::Level, const std::string&, const std::string&) ) );
257  }
258 
259  if ( int_marker_entry->second->processMessage( marker ) )
260  {
261  int_marker_entry->second->setShowAxes( show_axes_property_->getBool() );
262  int_marker_entry->second->setShowVisualAids( show_visual_aids_property_->getBool() );
263  int_marker_entry->second->setShowDescription( show_descriptions_property_->getBool() );
264  }
265  else
266  {
267  unsubscribe();
268  return;
269  }
270  }
271 }
272 
274  const std::string& server_id,
275  const std::vector<std::string>& erases )
276 {
277  M_StringToIMPtr& im_map = getImMap( server_id );
278 
279  for ( size_t i=0; i<erases.size(); i++ )
280  {
281  im_map.erase( erases[i] );
282  deleteStatusStd( erases[i] );
283  }
284 }
285 
287  const std::string& server_id,
288  const std::vector<visualization_msgs::InteractiveMarkerPose>& marker_poses )
289 {
290  M_StringToIMPtr& im_map = getImMap( server_id );
291 
292  for ( size_t i=0; i<marker_poses.size(); i++ )
293  {
294  const visualization_msgs::InteractiveMarkerPose& marker_pose = marker_poses[i];
295 
296  if ( !validateFloats( marker_pose.pose ) )
297  {
298  setStatusStd( StatusProperty::Error, marker_pose.name, "Pose message contains invalid floats!" );
299  return;
300  }
301 
302  if( !validateQuaternions( marker_pose.pose ))
303  {
304  setStatusStd( StatusProperty::Error, marker_pose.name,
305  "Pose message contains invalid quaternions (length not equal to 1)!" );
306  return;
307  }
308 
309  std::map< std::string, IMPtr >::iterator int_marker_entry = im_map.find( marker_pose.name );
310 
311  if ( int_marker_entry != im_map.end() )
312  {
313  int_marker_entry->second->processMessage( marker_pose );
314  }
315  else
316  {
317  setStatusStd( StatusProperty::Error, marker_pose.name, "Pose received for non-existing marker '" + marker_pose.name );
318  unsubscribe();
319  return;
320  }
321  }
322 }
323 
324 void InteractiveMarkerDisplay::initCb( visualization_msgs::InteractiveMarkerInitConstPtr msg )
325 {
326  resetCb( msg->server_id );
327  updateMarkers( msg->server_id, msg->markers );
328 }
329 
330 void InteractiveMarkerDisplay::updateCb( visualization_msgs::InteractiveMarkerUpdateConstPtr msg )
331 {
332  updateMarkers( msg->server_id, msg->markers );
333  updatePoses( msg->server_id, msg->poses );
334  eraseMarkers( msg->server_id, msg->erases );
335 }
336 
337 void InteractiveMarkerDisplay::resetCb( std::string server_id )
338 {
339  interactive_markers_.erase( server_id );
340  deleteStatusStd(server_id);
341 }
342 
345  const std::string& server_id,
346  const std::string& msg )
347 {
348  setStatusStd( static_cast<StatusProperty::Level>(status), server_id, msg );
349 }
350 
352 {
353  if (im_client_)
354  im_client_->setTargetFrame( fixed_frame_.toStdString() );
355  reset();
356 }
357 
359 {
360  Display::reset();
361  unsubscribe();
362  subscribe();
363 }
364 
366 {
368 
369  M_StringToStringToIMPtr::iterator server_it;
370  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
371  {
372  M_StringToIMPtr::iterator im_it;
373  for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
374  {
375  im_it->second->setShowDescription( show );
376  }
377  }
378 }
379 
381 {
382  bool show = show_axes_property_->getBool();
383 
384  M_StringToStringToIMPtr::iterator server_it;
385  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
386  {
387  M_StringToIMPtr::iterator im_it;
388  for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
389  {
390  im_it->second->setShowAxes( show );
391  }
392  }
393 }
394 
396 {
398 
399  M_StringToStringToIMPtr::iterator server_it;
400  for ( server_it = interactive_markers_.begin(); server_it != interactive_markers_.end(); server_it++ )
401  {
402  M_StringToIMPtr::iterator im_it;
403  for ( im_it = server_it->second.begin(); im_it != server_it->second.end(); im_it++ )
404  {
405  im_it->second->setShowVisualAids( show );
406  }
407  }
408 }
409 
411 {
412  // This is not very efficient... but it should do the trick.
413  unsubscribe();
414  im_client_->setEnableAutocompleteTransparency( enable_transparency_property_->getBool() );
415  subscribe();
416 }
417 
418 } // namespace rviz
419 
std::map< std::string, IMPtr > M_StringToIMPtr
void setStatusStd(StatusProperty::Level level, const std::string &name, const std::string &text)
Show status level and text, using a std::string. Convenience function which converts std::string to Q...
Definition: display.h:157
void deleteStatusStd(const std::string &name)
Delete the status entry with the given std::string name. This is thread-safe.
Definition: display.h:166
std::string getNameStd() const
Return the name of this Property as a std::string.
Definition: property.h:177
virtual void setString(const QString &str)
virtual void reset()
Called to tell the display to clear its state.
void updateMarkers(const std::string &server_id, const std::vector< visualization_msgs::InteractiveMarker > &markers)
void publish(const boost::shared_ptr< M > &message) const
void statusCb(interactive_markers::InteractiveMarkerClient::StatusT, const std::string &server_id, const std::string &msg)
void initCb(visualization_msgs::InteractiveMarkerInitConstPtr msg)
M_StringToIMPtr & getImMap(std::string server_id)
DisplayContext * context_
This DisplayContext pointer is the main connection a Display has into the rest of rviz...
Definition: display.h:256
Ogre::SceneNode * getSceneNode() const
Return the Ogre::SceneNode holding all 3D scene elements shown by this Display.
Definition: display.h:174
void eraseMarkers(const std::string &server_id, const std::vector< std::string > &names)
void updateCb(visualization_msgs::InteractiveMarkerUpdateConstPtr msg)
ros::NodeHandle update_nh_
A NodeHandle whose CallbackQueue is run from the main GUI thread (the "update" thread).
Definition: display.h:269
ROSCPP_DECL const std::string & getName()
boost::shared_ptr< interactive_markers::InteractiveMarkerClient > im_client_
void updatePoses(const std::string &server_id, const std::vector< visualization_msgs::InteractiveMarkerPose > &marker_poses)
bool isEnabled() const
Return true if this Display is enabled, false if not.
Definition: display.cpp:281
virtual bool getBool() const
QString fixed_frame_
A convenience variable equal to context_->getFixedFrame().
Definition: display.h:281
virtual void onDisable()
Derived classes override this to do the actual work of disabling themselves.
#define ROS_DEBUG_NAMED(name,...)
virtual void setTopic(const QString &topic, const QString &datatype)
Set the ROS topic to listen to for this display.
void publishFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback)
bool validateFloats(const sensor_msgs::CameraInfo &msg)
virtual void reset()
Called to tell the display to clear its state.
Definition: display.cpp:300
void show()
Show this Property in any PropertyTreeWidgets.
Definition: property.h:377
virtual void onInitialize()
Override this function to do subclass-specific initialization.
virtual FrameManager * getFrameManager() const =0
Return the FrameManager instance.
tf::TransformListener * getTFClient()
Return the tf::TransformListener used to receive transform data.
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
#define ROS_WARN_ONCE_NAMED(name,...)
virtual void onEnable()
Derived classes override this to do the actual work of enabling themselves.
Displays Interactive Markers.
bool validateQuaternions(const visualization_msgs::InteractiveMarker &marker)
virtual void update(float wall_dt, float ros_dt)
Called periodically by the visualization manager.
M_StringToStringToIMPtr interactive_markers_
virtual void fixedFrameChanged()
Called by setFixedFrame(). Override to respond to changes to fixed_frame_.
std::string getTopicStd() const
void onStatusUpdate(StatusProperty::Level level, const std::string &name, const std::string &text)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
BoolProperty(const QString &name=QString(), bool default_value=false, const QString &description=QString(), Property *parent=0, const char *changed_slot=0, QObject *receiver=0)
#define ROS_DEBUG(...)


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Wed Aug 28 2019 04:01:51