occupancy_grid_display.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, 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  * Author: Julius Kammerl (jkammerl@willowgarage.com)
30  *
31  */
32 #include <QObject>
33 
35 
36 #include <boost/bind.hpp>
37 #include <boost/shared_ptr.hpp>
38 
39 #include <OGRE/OgreSceneNode.h>
40 #include <OGRE/OgreSceneManager.h>
41 
43 #include "rviz/frame_manager.h"
48 
49 #include <octomap/octomap.h>
50 #include <octomap/ColorOcTree.h>
51 #include <octomap_msgs/Octomap.h>
53 
54 
55 #include <sstream>
56 
57 
58 using namespace rviz;
59 
60 namespace octomap_rviz_plugin
61 {
62 
63 static const std::size_t max_octree_depth_ = sizeof(unsigned short) * 8;
64 
66 {
69 };
70 
72 {
76 };
77 
78 OccupancyGridDisplay::OccupancyGridDisplay() :
79  rviz::Display(),
80  new_points_received_(false),
81  messages_received_(0),
82  queue_size_(5),
83  color_factor_(0.8)
84 {
85 
86  octomap_topic_property_ = new RosTopicProperty( "Octomap Topic",
87  "",
88  QString::fromStdString(ros::message_traits::datatype<octomap_msgs::Octomap>()),
89  "octomap_msgs::Octomap topic to subscribe to (binary or full probability map)",
90  this,
91  SLOT( updateTopic() ));
92 
93  queue_size_property_ = new IntProperty( "Queue Size",
95  "Advanced: set the size of the incoming message queue. Increasing this "
96  "is useful if your incoming TF data is delayed significantly from your"
97  " image data, but it can greatly increase memory usage if the messages are big.",
98  this,
99  SLOT( updateQueueSize() ));
101 
102  octree_render_property_ = new rviz::EnumProperty( "Voxel Rendering", "Occupied Voxels",
103  "Select voxel type.",
104  this,
105  SLOT( updateOctreeRenderMode() ) );
106 
110 
111  octree_coloring_property_ = new rviz::EnumProperty( "Voxel Coloring", "Z-Axis",
112  "Select voxel coloring mode",
113  this,
114  SLOT( updateOctreeColorMode() ) );
115 
119  alpha_property_ = new rviz::FloatProperty( "Voxel Alpha", 1.0, "Set voxel transparency alpha",
120  this,
121  SLOT( updateAlpha() ) );
122  alpha_property_->setMin(0.0);
123  alpha_property_->setMax(1.0);
124 
125  tree_depth_property_ = new IntProperty("Max. Octree Depth",
126  max_octree_depth_,
127  "Defines the maximum tree depth",
128  this,
129  SLOT (updateTreeDepth() ));
131 
132  max_height_property_ = new FloatProperty("Max. Height Display",
133  std::numeric_limits<double>::infinity(),
134  "Defines the maximum height to display",
135  this,
136  SLOT (updateMaxHeight() ));
137 
138  min_height_property_ = new FloatProperty("Min. Height Display",
139  -std::numeric_limits<double>::infinity(),
140  "Defines the minimum height to display",
141  this,
142  SLOT (updateMinHeight() ));
143 }
144 
146 {
147  boost::mutex::scoped_lock lock(mutex_);
148 
149  box_size_.resize(max_octree_depth_);
150  cloud_.resize(max_octree_depth_);
151  point_buf_.resize(max_octree_depth_);
152  new_points_.resize(max_octree_depth_);
153 
154  for (std::size_t i = 0; i < max_octree_depth_; ++i)
155  {
156  std::stringstream sname;
157  sname << "PointCloud Nr." << i;
158  cloud_[i] = new rviz::PointCloud();
159  cloud_[i]->setName(sname.str());
160  cloud_[i]->setRenderMode(rviz::PointCloud::RM_BOXES);
161  scene_node_->attachObject(cloud_[i]);
162  }
163 }
164 
166 {
167  std::size_t i;
168 
169  unsubscribe();
170 
171  for (std::vector<rviz::PointCloud*>::iterator it = cloud_.begin(); it != cloud_.end(); ++it) {
172  delete *(it);
173  }
174 
175  if (scene_node_)
176  scene_node_->detachAllObjects();
177 }
178 
180 {
182 
183  subscribe();
184 }
185 
187 {
188  scene_node_->setVisible(true);
189  subscribe();
190 }
191 
193 {
194  scene_node_->setVisible(false);
195  unsubscribe();
196 
197  clear();
198 }
199 
201 {
202  if (!isEnabled())
203  {
204  return;
205  }
206 
207  try
208  {
209  unsubscribe();
210 
211  const std::string& topicStr = octomap_topic_property_->getStdString();
212 
213  if (!topicStr.empty())
214  {
215 
217 
218  sub_->subscribe(threaded_nh_, topicStr, queue_size_);
219  sub_->registerCallback(boost::bind(&OccupancyGridDisplay::incomingMessageCallback, this, _1));
220 
221  }
222  }
223  catch (ros::Exception& e)
224  {
225  setStatus(StatusProperty::Error, "Topic", (std::string("Error subscribing: ") + e.what()).c_str());
226  }
227 
228 }
229 
231 {
232  clear();
233 
234  try
235  {
236  // reset filters
237  sub_.reset();
238  }
239  catch (ros::Exception& e)
240  {
241  setStatus(StatusProperty::Error, "Topic", (std::string("Error unsubscribing: ") + e.what()).c_str());
242  }
243 
244 }
245 
246 // method taken from octomap_server package
247 void OccupancyGridDisplay::setColor(double z_pos, double min_z, double max_z, double color_factor,
249 {
250  int i;
251  double m, n, f;
252 
253  double s = 1.0;
254  double v = 1.0;
255 
256  double h = (1.0 - std::min(std::max((z_pos - min_z) / (max_z - min_z), 0.0), 1.0)) * color_factor;
257 
258  h -= floor(h);
259  h *= 6;
260  i = floor(h);
261  f = h - i;
262  if (!(i & 1))
263  f = 1 - f; // if i is even
264  m = v * (1 - s);
265  n = v * (1 - s * f);
266 
267  switch (i)
268  {
269  case 6:
270  case 0:
271  point.setColor(v, n, m);
272  break;
273  case 1:
274  point.setColor(n, v, m);
275  break;
276  case 2:
277  point.setColor(m, v, n);
278  break;
279  case 3:
280  point.setColor(m, n, v);
281  break;
282  case 4:
283  point.setColor(n, m, v);
284  break;
285  case 5:
286  point.setColor(v, m, n);
287  break;
288  default:
289  point.setColor(1, 0.5, 0.5);
290  break;
291  }
292 }
293 
295 {
296  updateTopic();
297 }
298 
300 {
301  updateTopic();
302 }
303 
305 {
306  updateTopic();
307 }
308 
310 {
311  updateTopic();
312 }
313 
315 {
316  updateTopic();
317 }
318 
320 {
321  updateTopic();
322 }
323 
325 {
326 
327  boost::mutex::scoped_lock lock(mutex_);
328 
329  // reset rviz pointcloud boxes
330  for (size_t i = 0; i < cloud_.size(); ++i)
331  {
332  cloud_[i]->clear();
333  }
334 }
335 
336 void OccupancyGridDisplay::update(float wall_dt, float ros_dt)
337 {
339  {
340  boost::mutex::scoped_lock lock(mutex_);
341 
342  for (size_t i = 0; i < max_octree_depth_; ++i)
343  {
344  double size = box_size_[i];
345 
346  cloud_[i]->clear();
347  cloud_[i]->setDimensions(size, size, size);
348 
349  cloud_[i]->addPoints(&new_points_[i].front(), new_points_[i].size());
350  new_points_[i].clear();
351  cloud_[i]->setAlpha(alpha_property_->getFloat());
352  }
353  new_points_received_ = false;
354  }
355  updateFromTF();
356 }
357 
359 {
360  clear();
361  messages_received_ = 0;
362  setStatus(StatusProperty::Ok, "Messages", QString("0 binary octomap messages received"));
363 }
364 
366 {
367  unsubscribe();
368  reset();
369  subscribe();
371 }
372 
373 template <typename OcTreeType>
375 {
376  //General case: Need to be specialized for every used case
377  setStatus(StatusProperty::Warn, "Messages", QString("Cannot verify octomap type"));
378  return true; //Try deserialization, might crash though
379 }
380 
381 template <>
383 {
384  if(type_id == "OcTreeStamped") return true;
385  else return false;
386 }
387 template <>
389 {
390  if(type_id == "OcTree") return true;
391  else return false;
392 }
393 
394 template <>
396 {
397  if(type_id == "ColorOcTree") return true;
398  else return false;
399 }
400 
401 template <typename OcTreeType>
403  typename OcTreeType::NodeType& node,
404  double minZ, double maxZ)
405 {
407  float cell_probability;
408  switch (octree_color_mode)
409  {
410  case OCTOMAP_CELL_COLOR:
411  setStatus(StatusProperty::Error, "Messages", QString("Cannot extract color"));
412  //Intentional fall-through for else-case
414  setColor(newPoint.position.z, minZ, maxZ, color_factor_, newPoint);
415  break;
417  cell_probability = node.getOccupancy();
418  newPoint.setColor((1.0f-cell_probability), cell_probability, 0.0);
419  break;
420  default:
421  break;
422  }
423 }
424 
425 //Specialization for ColorOcTreeNode, which can set the voxel color from the node itself
426 template <>
429  double minZ, double maxZ)
430 {
431  float cell_probability;
433  switch (octree_color_mode)
434  {
435  case OCTOMAP_CELL_COLOR:
436  {
437  const float b2f = 1./256.;
438  octomap::ColorOcTreeNode::Color& color = node.getColor();
439  newPoint.setColor(b2f*color.r, b2f*color.g, b2f*color.b, node.getOccupancy());
440  break;
441  }
443  setColor(newPoint.position.z, minZ, maxZ, color_factor_, newPoint);
444  break;
446  cell_probability = node.getOccupancy();
447  newPoint.setColor((1.0f-cell_probability), cell_probability, 0.0);
448  break;
449  default:
450  break;
451  }
452 }
453 
454 
456 {
457  // get tf transform
458  Ogre::Vector3 pos;
459  Ogre::Quaternion orient;
460  if (!context_->getFrameManager()->getTransform(header_, pos, orient)) {
461  return false;
462  }
463 
464  scene_node_->setOrientation(orient);
465  scene_node_->setPosition(pos);
466  return true;
467 }
468 
469 
470 template <typename OcTreeType>
471 void TemplatedOccupancyGridDisplay<OcTreeType>::incomingMessageCallback(const octomap_msgs::OctomapConstPtr& msg)
472 {
474  setStatus(StatusProperty::Ok, "Messages", QString::number(messages_received_) + " octomap messages received");
475  setStatusStd(StatusProperty::Ok, "Type", msg->id.c_str());
476  if(!checkType(msg->id)){
477  setStatusStd(StatusProperty::Error, "Message", "Wrong octomap type. Use a different display type.");
478  return;
479  }
480 
481  ROS_DEBUG("Received OctomapBinary message (size: %d bytes)", (int)msg->data.size());
482 
483  header_ = msg->header;
484  if (!updateFromTF()) {
485  std::stringstream ss;
486  ss << "Failed to transform from frame [" << header_.frame_id << "] to frame ["
487  << context_->getFrameManager()->getFixedFrame() << "]";
488  setStatusStd(StatusProperty::Error, "Message", ss.str());
489  return;
490  }
491 
492  // creating octree
493  OcTreeType* octomap = NULL;
495  if (tree){
496  octomap = dynamic_cast<OcTreeType*>(tree);
497  if(!octomap){
498  setStatusStd(StatusProperty::Error, "Message", "Wrong octomap type. Use a different display type.");
499  }
500  }
501  else
502  {
503  setStatusStd(StatusProperty::Error, "Message", "Failed to deserialize octree message.");
504  return;
505  }
506 
507 
508  tree_depth_property_->setMax(octomap->getTreeDepth());
509 
510  // get dimensions of octree
511  double minX, minY, minZ, maxX, maxY, maxZ;
512  octomap->getMetricMin(minX, minY, minZ);
513  octomap->getMetricMax(maxX, maxY, maxZ);
514 
515  // reset rviz pointcloud classes
516  for (std::size_t i = 0; i < max_octree_depth_; ++i)
517  {
518  point_buf_[i].clear();
519  box_size_[i] = octomap->getNodeSize(i + 1);
520  }
521 
522  size_t pointCount = 0;
523  {
524  // traverse all leafs in the tree:
525  unsigned int treeDepth = std::min<unsigned int>(tree_depth_property_->getInt(), octomap->getTreeDepth());
526  double maxHeight = std::min<double>(max_height_property_->getFloat(), maxZ);
527  double minHeight = std::max<double>(min_height_property_->getFloat(), minZ);
528  int stepSize = 1 << (octomap->getTreeDepth() - treeDepth); // for pruning of occluded voxels
529  for (typename OcTreeType::iterator it = octomap->begin(treeDepth), end = octomap->end(); it != end; ++it)
530  {
531  if(it.getZ() <= maxHeight && it.getZ() >= minHeight)
532  {
533  int render_mode_mask = octree_render_property_->getOptionInt();
534 
535  bool display_voxel = false;
536 
537  // the left part evaluates to 1 for free voxels and 2 for occupied voxels
538  if (((int)octomap->isNodeOccupied(*it) + 1) & render_mode_mask)
539  {
540  // check if current voxel has neighbors on all sides -> no need to be displayed
541  bool allNeighborsFound = true;
542 
543  octomap::OcTreeKey key;
544  octomap::OcTreeKey nKey = it.getKey();
545 
546  // determine indices of potentially neighboring voxels for depths < maximum tree depth
547  // +/-1 at maximum depth, +2^(depth_difference-1) and -2^(depth_difference-1)-1 on other depths
548  int diffBase = (it.getDepth() < octomap->getTreeDepth()) ? 1 << (octomap->getTreeDepth() - it.getDepth() - 1) : 1;
549  int diff[2] = {-((it.getDepth() == octomap->getTreeDepth()) ? diffBase : diffBase + 1), diffBase};
550 
551  // cells with adjacent faces can occlude a voxel, iterate over the cases x,y,z (idxCase) and +/- (diff)
552  for (unsigned int idxCase = 0; idxCase < 3; ++idxCase)
553  {
554  int idx_0 = idxCase % 3;
555  int idx_1 = (idxCase + 1) % 3;
556  int idx_2 = (idxCase + 2) % 3;
557 
558  for (int i = 0; allNeighborsFound && i < 2; ++i)
559  {
560  key[idx_0] = nKey[idx_0] + diff[i];
561  // if rendering is restricted to treeDepth < maximum tree depth inner nodes with distance stepSize can already occlude a voxel
562  for (key[idx_1] = nKey[idx_1] + diff[0] + 1; allNeighborsFound && key[idx_1] < nKey[idx_1] + diff[1]; key[idx_1] += stepSize)
563  {
564  for (key[idx_2] = nKey[idx_2] + diff[0] + 1; allNeighborsFound && key[idx_2] < nKey[idx_2] + diff[1]; key[idx_2] += stepSize)
565  {
566  typename OcTreeType::NodeType* node = octomap->search(key, treeDepth);
567 
568  // the left part evaluates to 1 for free voxels and 2 for occupied voxels
569  if (!(node && ((((int)octomap->isNodeOccupied(node)) + 1) & render_mode_mask)))
570  {
571  // we do not have a neighbor => break!
572  allNeighborsFound = false;
573  }
574  }
575  }
576  }
577  }
578 
579  display_voxel |= !allNeighborsFound;
580  }
581 
582 
583  if (display_voxel)
584  {
585  PointCloud::Point newPoint;
586 
587  newPoint.position.x = it.getX();
588  newPoint.position.y = it.getY();
589  newPoint.position.z = it.getZ();
590 
591 
592 
593  setVoxelColor(newPoint, *it, minZ, maxZ);
594  // push to point vectors
595  unsigned int depth = it.getDepth();
596  point_buf_[depth - 1].push_back(newPoint);
597 
598  ++pointCount;
599  }
600  }
601  }
602  }
603 
604  if (pointCount)
605  {
606  boost::mutex::scoped_lock lock(mutex_);
607 
608  new_points_received_ = true;
609 
610  for (size_t i = 0; i < max_octree_depth_; ++i)
611  new_points_[i].swap(point_buf_[i]);
612 
613  }
614  delete octomap;
615 }
616 
617 } // namespace octomap_rviz_plugin
618 
620 
624 
626 PLUGINLIB_EXPORT_CLASS( ColorOcTreeGridDisplay, rviz::Display)
627 PLUGINLIB_EXPORT_CLASS( OcTreeStampedGridDisplay, rviz::Display)
628 
#define NULL
void setStatusStd(StatusProperty::Level level, const std::string &name, const std::string &text)
void setMin(float min)
std::vector< rviz::PointCloud * > cloud_
void setMax(float max)
octomap_rviz_plugin::TemplatedOccupancyGridDisplay< octomap::ColorOcTree > ColorOcTreeGridDisplay
f
static const std::size_t max_octree_depth_
virtual void update(float wall_dt, float ros_dt)
DisplayContext * context_
virtual int getInt() const
XmlRpcServer s
virtual void incomingMessageCallback(const octomap_msgs::OctomapConstPtr &msg)=0
static octomap::AbstractOcTree * msgToMap(const Octomap &msg)
IMETHOD Vector diff(const Vector &p_w_a, const Vector &p_w_b, double dt=1)
virtual float getFloat() const
void setMin(int min)
octomap_rviz_plugin::TemplatedOccupancyGridDisplay< octomap::OcTreeStamped > OcTreeStampedGridDisplay
Ogre::SceneNode * scene_node_
std::string getStdString()
void setMax(int max)
bool isEnabled() const
boost::shared_ptr< message_filters::Subscriber< octomap_msgs::Octomap > > sub_
virtual void addOption(const QString &option, int value=0)
octomap_rviz_plugin::TemplatedOccupancyGridDisplay< octomap::OcTree > OcTreeGridDisplay
void setColor(double z_pos, double min_z, double max_z, double color_factor, rviz::PointCloud::Point &point)
virtual FrameManager * getFrameManager() const =0
tree
const std::string & getFixedFrame()
void incomingMessageCallback(const octomap_msgs::OctomapConstPtr &msg)
virtual void queueRender()=0
ros::NodeHandle threaded_nh_
bool getTransform(const Header &header, Ogre::Vector3 &position, Ogre::Quaternion &orientation)
void setVoxelColor(rviz::PointCloud::Point &newPoint, typename OcTreeType::NodeType &node, double minZ, double maxZ)
void swap(scoped_ptr< T > &, scoped_ptr< T > &)
virtual int getOptionInt()
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
virtual void setStatus(StatusProperty::Level level, const QString &name, const QString &text)
void setColor(float r, float g, float b, float a=1.0)
#define ROS_DEBUG(...)


octomap_rviz_plugins
Author(s): Julius Kammerl
autogenerated on Wed Jan 20 2021 03:10:00