Nav2 Navigation Stack - kilted  kilted
ROS 2 Navigation Stack
voxel_grid.hpp
1 /*********************************************************************
2  *
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2008, Willow Garage, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the Willow Garage nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Author: Eitan Marder-Eppstein
36  *********************************************************************/
37 #ifndef NAV2_VOXEL_GRID__VOXEL_GRID_HPP_
38 #define NAV2_VOXEL_GRID__VOXEL_GRID_HPP_
39 
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <stdint.h>
44 #include <math.h>
45 #include <limits.h>
46 #include <algorithm>
47 
48 #include <rclcpp/logger.hpp>
49 #include <rclcpp/logging.hpp>
50 
57 namespace nav2_voxel_grid
58 {
59 
60 enum VoxelStatus
61 {
62  FREE = 0,
63  UNKNOWN = 1,
64  MARKED = 2,
65 };
66 
67 class VoxelGrid
68 {
69 public:
76  VoxelGrid(unsigned int size_x, unsigned int size_y, unsigned int size_z);
77 
78  ~VoxelGrid();
79 
86  void resize(unsigned int size_x, unsigned int size_y, unsigned int size_z);
87 
88  void reset();
89  uint32_t * getData() {return data_;}
90 
91  inline void markVoxel(unsigned int x, unsigned int y, unsigned int z)
92  {
93  if (x >= size_x_ || y >= size_y_ || z >= size_z_) {
94  RCLCPP_DEBUG(logger, "Error, voxel out of bounds.\n");
95  return;
96  }
97  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
98  data_[y * size_x_ + x] |= full_mask; // clear unknown and mark cell
99  }
100 
101  inline bool markVoxelInMap(
102  unsigned int x, unsigned int y, unsigned int z,
103  unsigned int marked_threshold)
104  {
105  if (x >= size_x_ || y >= size_y_ || z >= size_z_) {
106  RCLCPP_DEBUG(logger, "Error, voxel out of bounds.\n");
107  return false;
108  }
109 
110  int index = y * size_x_ + x;
111  uint32_t * col = &data_[index];
112  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
113  *col |= full_mask; // clear unknown and mark cell
114 
115  unsigned int marked_bits = *col >> 16;
116 
117  // make sure the number of bits in each is below our thresholds
118  return !bitsBelowThreshold(marked_bits, marked_threshold);
119  }
120 
121  inline void clearVoxel(unsigned int x, unsigned int y, unsigned int z)
122  {
123  if (x >= size_x_ || y >= size_y_ || z >= size_z_) {
124  RCLCPP_DEBUG(logger, "Error, voxel out of bounds.\n");
125  return;
126  }
127  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
128  data_[y * size_x_ + x] &= ~(full_mask); // clear unknown and clear cell
129  }
130 
131  inline void clearVoxelColumn(unsigned int index)
132  {
133  assert(index < size_x_ * size_y_);
134  data_[index] = 0;
135  }
136 
137  inline void clearVoxelInMap(unsigned int x, unsigned int y, unsigned int z)
138  {
139  if (x >= size_x_ || y >= size_y_ || z >= size_z_) {
140  RCLCPP_DEBUG(logger, "Error, voxel out of bounds.\n");
141  return;
142  }
143  int index = y * size_x_ + x;
144  uint32_t * col = &data_[index];
145  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
146  *col &= ~(full_mask); // clear unknown and clear cell
147 
148  unsigned int unknown_bits = uint16_t(*col >> 16) ^ uint16_t(*col);
149  unsigned int marked_bits = *col >> 16;
150 
151  // make sure the number of bits in each is below our thresholds
152  if (bitsBelowThreshold(unknown_bits, 1) && bitsBelowThreshold(marked_bits, 1)) {
153  costmap[index] = 0;
154  }
155  }
156 
157  inline bool bitsBelowThreshold(unsigned int n, unsigned int bit_threshold)
158  {
159  unsigned int bit_count;
160  for (bit_count = 0; n; ) {
161  ++bit_count;
162  if (bit_count > bit_threshold) {
163  return false;
164  }
165  n &= n - 1; // clear the least significant bit set
166  }
167  return true;
168  }
169 
170  static inline unsigned int numBits(unsigned int n)
171  {
172  unsigned int bit_count;
173  for (bit_count = 0; n; ++bit_count) {
174  n &= n - 1; // clear the least significant bit set
175  }
176  return bit_count;
177  }
178 
179  static VoxelStatus getVoxel(
180  unsigned int x, unsigned int y, unsigned int z,
181  unsigned int size_x, unsigned int size_y, unsigned int size_z, const uint32_t * data)
182  {
183  if (x >= size_x || y >= size_y || z >= size_z) {
184  return UNKNOWN;
185  }
186  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
187  uint32_t result = data[y * size_x + x] & full_mask;
188  unsigned int bits = numBits(result);
189 
190  // known marked: 11 = 2 bits, unknown: 01 = 1 bit, known free: 00 = 0 bits
191  if (bits < 2) {
192  if (bits < 1) {
193  return FREE;
194  }
195  return UNKNOWN;
196  }
197  return MARKED;
198  }
199 
200  void markVoxelLine(
201  double x0, double y0, double z0, double x1, double y1, double z1,
202  unsigned int max_length = UINT_MAX);
203  void clearVoxelLine(
204  double x0, double y0, double z0, double x1, double y1, double z1,
205  unsigned int max_length = UINT_MAX, unsigned int min_length = 0);
206  void clearVoxelLineInMap(
207  double x0, double y0, double z0, double x1, double y1, double z1, unsigned char * map_2d,
208  unsigned int unknown_threshold, unsigned int mark_threshold,
209  unsigned char free_cost = 0, unsigned char unknown_cost = 255,
210  unsigned int max_length = UINT_MAX, unsigned int min_length = 0);
211 
212  VoxelStatus getVoxel(unsigned int x, unsigned int y, unsigned int z);
213 
214  // Are there any obstacles at that (x, y) location in the grid?
215  VoxelStatus getVoxelColumn(
216  unsigned int x, unsigned int y,
217  unsigned int unknown_threshold = 0, unsigned int marked_threshold = 0);
218 
219  void printVoxelGrid();
220  void printColumnGrid();
221  unsigned int sizeX();
222  unsigned int sizeY();
223  unsigned int sizeZ();
224 
225  template<class ActionType>
226  inline void raytraceLine(
227  ActionType at, double x0, double y0, double z0,
228  double x1, double y1, double z1, unsigned int max_length = UINT_MAX,
229  unsigned int min_length = 0)
230  {
231  // we need to chose how much to scale our dominant dimension, based on the
232  // maximum length of the line
233  double dist = sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1) + (z0 - z1) * (z0 - z1));
234  if ((unsigned int)(dist) < min_length) {
235  return;
236  }
237  double scale, min_x0, min_y0, min_z0;
238  if (dist > 0.0) {
239  scale = std::min(1.0, max_length / dist);
240 
241  // Updating starting point to the point at distance min_length from the initial point
242  min_x0 = x0 + (x1 - x0) / dist * min_length;
243  min_y0 = y0 + (y1 - y0) / dist * min_length;
244  min_z0 = z0 + (z1 - z0) / dist * min_length;
245  } else {
246  // dist can be 0 if [x0, y0, z0]==[x1, y1, z1].
247  // In this case only this voxel should be processed.
248  scale = 1.0;
249  min_x0 = x0;
250  min_y0 = y0;
251  min_z0 = z0;
252  }
253 
254  int dx = int(x1) - int(min_x0); // NOLINT
255  int dy = int(y1) - int(min_y0); // NOLINT
256  int dz = int(z1) - int(min_z0); // NOLINT
257 
258  unsigned int abs_dx = abs(dx);
259  unsigned int abs_dy = abs(dy);
260  unsigned int abs_dz = abs(dz);
261 
262  int offset_dx = sign(dx);
263  int offset_dy = sign(dy) * size_x_;
264  int offset_dz = sign(dz);
265 
266  unsigned int z_mask = ((1 << 16) | 1) << (unsigned int)min_z0;
267  unsigned int offset = (unsigned int)min_y0 * size_x_ + (unsigned int)min_x0;
268 
269  GridOffset grid_off(offset);
270  ZOffset z_off(z_mask);
271 
272  // is x dominant
273  if (abs_dx >= max(abs_dy, abs_dz)) {
274  int error_y = abs_dx / 2;
275  int error_z = abs_dx / 2;
276 
277  bresenham3D(
278  at, grid_off, grid_off, z_off, abs_dx, abs_dy, abs_dz, error_y, error_z,
279  offset_dx, offset_dy, offset_dz, offset, z_mask, (unsigned int)(scale * abs_dx));
280  return;
281  }
282 
283  // y is dominant
284  if (abs_dy >= abs_dz) {
285  int error_x = abs_dy / 2;
286  int error_z = abs_dy / 2;
287 
288  bresenham3D(
289  at, grid_off, grid_off, z_off, abs_dy, abs_dx, abs_dz, error_x, error_z,
290  offset_dy, offset_dx, offset_dz, offset, z_mask, (unsigned int)(scale * abs_dy));
291  return;
292  }
293 
294  // otherwise, z is dominant
295  int error_x = abs_dz / 2;
296  int error_y = abs_dz / 2;
297 
298  bresenham3D(
299  at, z_off, grid_off, grid_off, abs_dz, abs_dx, abs_dy, error_x, error_y, offset_dz,
300  offset_dx, offset_dy, offset, z_mask, (unsigned int)(scale * abs_dz));
301  }
302 
303 private:
304  // the real work is done here... 3D bresenham implementation
305  template<class ActionType, class OffA, class OffB, class OffC>
306  inline void bresenham3D(
307  ActionType at, OffA off_a, OffB off_b, OffC off_c,
308  unsigned int abs_da, unsigned int abs_db, unsigned int abs_dc,
309  int error_b, int error_c, int offset_a, int offset_b, int offset_c, unsigned int & offset,
310  unsigned int & z_mask, unsigned int max_length = UINT_MAX)
311  {
312  unsigned int end = std::min(max_length, abs_da);
313  for (unsigned int i = 0; i < end; ++i) {
314  at(offset, z_mask);
315  off_a(offset_a);
316  error_b += abs_db;
317  error_c += abs_dc;
318  if ((unsigned int)error_b >= abs_da) {
319  off_b(offset_b);
320  error_b -= abs_da;
321  }
322  if ((unsigned int)error_c >= abs_da) {
323  off_c(offset_c);
324  error_c -= abs_da;
325  }
326  }
327  at(offset, z_mask);
328  }
329 
330  inline int sign(int i)
331  {
332  return i > 0 ? 1 : -1;
333  }
334 
335  inline unsigned int max(unsigned int x, unsigned int y)
336  {
337  return x > y ? x : y;
338  }
339 
340  unsigned int size_x_, size_y_, size_z_;
341  uint32_t * data_;
342  unsigned char * costmap;
343  rclcpp::Logger logger;
344 
345  // Aren't functors so much fun... used to recreate the Bresenham macro Eric
346  // wrote in the original version, but in "proper" c++
347  class MarkVoxel
348  {
349 public:
350  explicit MarkVoxel(uint32_t * data)
351  : data_(data) {}
352  inline void operator()(unsigned int offset, unsigned int z_mask)
353  {
354  data_[offset] |= z_mask; // clear unknown and mark cell
355  }
356 
357 private:
358  uint32_t * data_;
359  };
360 
361  class ClearVoxel
362  {
363 public:
364  explicit ClearVoxel(uint32_t * data)
365  : data_(data) {}
366  inline void operator()(unsigned int offset, unsigned int z_mask)
367  {
368  data_[offset] &= ~(z_mask); // clear unknown and clear cell
369  }
370 
371 private:
372  uint32_t * data_;
373  };
374 
375  class ClearVoxelInMap
376  {
377 public:
378  ClearVoxelInMap(
379  uint32_t * data, unsigned char * costmap,
380  unsigned int unknown_clear_threshold, unsigned int marked_clear_threshold,
381  unsigned char free_cost = 0, unsigned char unknown_cost = 255)
382  : data_(data), costmap_(costmap),
383  unknown_clear_threshold_(unknown_clear_threshold), marked_clear_threshold_(
384  marked_clear_threshold),
385  free_cost_(free_cost), unknown_cost_(unknown_cost)
386  {
387  }
388 
389  inline void operator()(unsigned int offset, unsigned int z_mask)
390  {
391  uint32_t * col = &data_[offset];
392  *col &= ~(z_mask); // clear unknown and clear cell
393 
394  unsigned int unknown_bits = uint16_t(*col >> 16) ^ uint16_t(*col);
395  unsigned int marked_bits = *col >> 16;
396 
397  // make sure the number of bits in each is below our thresholds
398  if (bitsBelowThreshold(marked_bits, marked_clear_threshold_)) {
399  if (bitsBelowThreshold(unknown_bits, unknown_clear_threshold_)) {
400  costmap_[offset] = free_cost_;
401  } else {
402  costmap_[offset] = unknown_cost_;
403  }
404  }
405  }
406 
407 private:
408  inline bool bitsBelowThreshold(unsigned int n, unsigned int bit_threshold)
409  {
410  unsigned int bit_count;
411  for (bit_count = 0; n; ) {
412  ++bit_count;
413  if (bit_count > bit_threshold) {
414  return false;
415  }
416  n &= n - 1; // clear the least significant bit set
417  }
418  return true;
419  }
420 
421  uint32_t * data_;
422  unsigned char * costmap_;
423  unsigned int unknown_clear_threshold_, marked_clear_threshold_;
424  unsigned char free_cost_, unknown_cost_;
425  };
426 
427  class GridOffset
428  {
429 public:
430  explicit GridOffset(unsigned int & offset)
431  : offset_(offset) {}
432  inline void operator()(int offset_val)
433  {
434  offset_ += offset_val;
435  }
436 
437 private:
438  unsigned int & offset_;
439  };
440 
441  class ZOffset
442  {
443 public:
444  explicit ZOffset(unsigned int & z_mask)
445  : z_mask_(z_mask) {}
446  inline void operator()(int offset_val)
447  {
448  offset_val > 0 ? z_mask_ <<= 1 : z_mask_ >>= 1;
449  }
450 
451 private:
452  unsigned int & z_mask_;
453  };
454 };
455 
456 } // namespace nav2_voxel_grid
457 
458 #endif // NAV2_VOXEL_GRID__VOXEL_GRID_HPP_
void resize(unsigned int size_x, unsigned int size_y, unsigned int size_z)
Resizes a voxel grid to the desired size.
Definition: voxel_grid.cpp:67
VoxelGrid(unsigned int size_x, unsigned int size_y, unsigned int size_z)
Constructor for a voxel grid.
Definition: voxel_grid.cpp:44