Nav2 Navigation Stack - humble  humble
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 #include "rclcpp/rclcpp.hpp"
48 
55 namespace nav2_voxel_grid
56 {
57 
58 enum VoxelStatus
59 {
60  FREE = 0,
61  UNKNOWN = 1,
62  MARKED = 2,
63 };
64 
65 class VoxelGrid
66 {
67 public:
74  VoxelGrid(unsigned int size_x, unsigned int size_y, unsigned int size_z);
75 
76  ~VoxelGrid();
77 
84  void resize(unsigned int size_x, unsigned int size_y, unsigned int size_z);
85 
86  void reset();
87  uint32_t * getData() {return data_;}
88 
89  inline void markVoxel(unsigned int x, unsigned int y, unsigned int z)
90  {
91  if (x >= size_x_ || y >= size_y_ || z >= size_z_) {
92  RCLCPP_DEBUG(logger, "Error, voxel out of bounds.\n");
93  return;
94  }
95  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
96  data_[y * size_x_ + x] |= full_mask; // clear unknown and mark cell
97  }
98 
99  inline bool markVoxelInMap(
100  unsigned int x, unsigned int y, unsigned int z,
101  unsigned int marked_threshold)
102  {
103  if (x >= size_x_ || y >= size_y_ || z >= size_z_) {
104  RCLCPP_DEBUG(logger, "Error, voxel out of bounds.\n");
105  return false;
106  }
107 
108  int index = y * size_x_ + x;
109  uint32_t * col = &data_[index];
110  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
111  *col |= full_mask; // clear unknown and mark cell
112 
113  unsigned int marked_bits = *col >> 16;
114 
115  // make sure the number of bits in each is below our thresholds
116  return !bitsBelowThreshold(marked_bits, marked_threshold);
117  }
118 
119  inline void clearVoxel(unsigned int x, unsigned int y, unsigned int z)
120  {
121  if (x >= size_x_ || y >= size_y_ || z >= size_z_) {
122  RCLCPP_DEBUG(logger, "Error, voxel out of bounds.\n");
123  return;
124  }
125  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
126  data_[y * size_x_ + x] &= ~(full_mask); // clear unknown and clear cell
127  }
128 
129  inline void clearVoxelColumn(unsigned int index)
130  {
131  assert(index < size_x_ * size_y_);
132  data_[index] = 0;
133  }
134 
135  inline void clearVoxelInMap(unsigned int x, unsigned int y, unsigned int z)
136  {
137  if (x >= size_x_ || y >= size_y_ || z >= size_z_) {
138  RCLCPP_DEBUG(logger, "Error, voxel out of bounds.\n");
139  return;
140  }
141  int index = y * size_x_ + x;
142  uint32_t * col = &data_[index];
143  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
144  *col &= ~(full_mask); // clear unknown and clear cell
145 
146  unsigned int unknown_bits = uint16_t(*col >> 16) ^ uint16_t(*col);
147  unsigned int marked_bits = *col >> 16;
148 
149  // make sure the number of bits in each is below our thresholds
150  if (bitsBelowThreshold(unknown_bits, 1) && bitsBelowThreshold(marked_bits, 1)) {
151  costmap[index] = 0;
152  }
153  }
154 
155  inline bool bitsBelowThreshold(unsigned int n, unsigned int bit_threshold)
156  {
157  unsigned int bit_count;
158  for (bit_count = 0; n; ) {
159  ++bit_count;
160  if (bit_count > bit_threshold) {
161  return false;
162  }
163  n &= n - 1; // clear the least significant bit set
164  }
165  return true;
166  }
167 
168  static inline unsigned int numBits(unsigned int n)
169  {
170  unsigned int bit_count;
171  for (bit_count = 0; n; ++bit_count) {
172  n &= n - 1; // clear the least significant bit set
173  }
174  return bit_count;
175  }
176 
177  static VoxelStatus getVoxel(
178  unsigned int x, unsigned int y, unsigned int z,
179  unsigned int size_x, unsigned int size_y, unsigned int size_z, const uint32_t * data)
180  {
181  if (x >= size_x || y >= size_y || z >= size_z) {
182  return UNKNOWN;
183  }
184  uint32_t full_mask = ((uint32_t)1 << z << 16) | (1 << z);
185  uint32_t result = data[y * size_x + x] & full_mask;
186  unsigned int bits = numBits(result);
187 
188  // known marked: 11 = 2 bits, unknown: 01 = 1 bit, known free: 00 = 0 bits
189  if (bits < 2) {
190  if (bits < 1) {
191  return FREE;
192  }
193  return UNKNOWN;
194  }
195  return MARKED;
196  }
197 
198  void markVoxelLine(
199  double x0, double y0, double z0, double x1, double y1, double z1,
200  unsigned int max_length = UINT_MAX);
201  void clearVoxelLine(
202  double x0, double y0, double z0, double x1, double y1, double z1,
203  unsigned int max_length = UINT_MAX, unsigned int min_length = 0);
204  void clearVoxelLineInMap(
205  double x0, double y0, double z0, double x1, double y1, double z1, unsigned char * map_2d,
206  unsigned int unknown_threshold, unsigned int mark_threshold,
207  unsigned char free_cost = 0, unsigned char unknown_cost = 255,
208  unsigned int max_length = UINT_MAX, unsigned int min_length = 0);
209 
210  VoxelStatus getVoxel(unsigned int x, unsigned int y, unsigned int z);
211 
212  // Are there any obstacles at that (x, y) location in the grid?
213  VoxelStatus getVoxelColumn(
214  unsigned int x, unsigned int y,
215  unsigned int unknown_threshold = 0, unsigned int marked_threshold = 0);
216 
217  void printVoxelGrid();
218  void printColumnGrid();
219  unsigned int sizeX();
220  unsigned int sizeY();
221  unsigned int sizeZ();
222 
223  template<class ActionType>
224  inline void raytraceLine(
225  ActionType at, double x0, double y0, double z0,
226  double x1, double y1, double z1, unsigned int max_length = UINT_MAX,
227  unsigned int min_length = 0)
228  {
229  // we need to chose how much to scale our dominant dimension, based on the
230  // maximum length of the line
231  double dist = sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1) + (z0 - z1) * (z0 - z1));
232  if ((unsigned int)(dist) < min_length) {
233  return;
234  }
235  double scale, min_x0, min_y0, min_z0;
236  if (dist > 0.0) {
237  scale = std::min(1.0, max_length / dist);
238 
239  // Updating starting point to the point at distance min_length from the initial point
240  min_x0 = x0 + (x1 - x0) / dist * min_length;
241  min_y0 = y0 + (y1 - y0) / dist * min_length;
242  min_z0 = z0 + (z1 - z0) / dist * min_length;
243  } else {
244  // dist can be 0 if [x0, y0, z0]==[x1, y1, z1].
245  // In this case only this voxel should be processed.
246  scale = 1.0;
247  min_x0 = x0;
248  min_y0 = y0;
249  min_z0 = z0;
250  }
251 
252  int dx = int(x1) - int(min_x0); // NOLINT
253  int dy = int(y1) - int(min_y0); // NOLINT
254  int dz = int(z1) - int(min_z0); // NOLINT
255 
256  unsigned int abs_dx = abs(dx);
257  unsigned int abs_dy = abs(dy);
258  unsigned int abs_dz = abs(dz);
259 
260  int offset_dx = sign(dx);
261  int offset_dy = sign(dy) * size_x_;
262  int offset_dz = sign(dz);
263 
264  unsigned int z_mask = ((1 << 16) | 1) << (unsigned int)min_z0;
265  unsigned int offset = (unsigned int)min_y0 * size_x_ + (unsigned int)min_x0;
266 
267  GridOffset grid_off(offset);
268  ZOffset z_off(z_mask);
269 
270  // is x dominant
271  if (abs_dx >= max(abs_dy, abs_dz)) {
272  int error_y = abs_dx / 2;
273  int error_z = abs_dx / 2;
274 
275  bresenham3D(
276  at, grid_off, grid_off, z_off, abs_dx, abs_dy, abs_dz, error_y, error_z,
277  offset_dx, offset_dy, offset_dz, offset, z_mask, (unsigned int)(scale * abs_dx));
278  return;
279  }
280 
281  // y is dominant
282  if (abs_dy >= abs_dz) {
283  int error_x = abs_dy / 2;
284  int error_z = abs_dy / 2;
285 
286  bresenham3D(
287  at, grid_off, grid_off, z_off, abs_dy, abs_dx, abs_dz, error_x, error_z,
288  offset_dy, offset_dx, offset_dz, offset, z_mask, (unsigned int)(scale * abs_dy));
289  return;
290  }
291 
292  // otherwise, z is dominant
293  int error_x = abs_dz / 2;
294  int error_y = abs_dz / 2;
295 
296  bresenham3D(
297  at, z_off, grid_off, grid_off, abs_dz, abs_dx, abs_dy, error_x, error_y, offset_dz,
298  offset_dx, offset_dy, offset, z_mask, (unsigned int)(scale * abs_dz));
299  }
300 
301 private:
302  // the real work is done here... 3D bresenham implementation
303  template<class ActionType, class OffA, class OffB, class OffC>
304  inline void bresenham3D(
305  ActionType at, OffA off_a, OffB off_b, OffC off_c,
306  unsigned int abs_da, unsigned int abs_db, unsigned int abs_dc,
307  int error_b, int error_c, int offset_a, int offset_b, int offset_c, unsigned int & offset,
308  unsigned int & z_mask, unsigned int max_length = UINT_MAX)
309  {
310  unsigned int end = std::min(max_length, abs_da);
311  for (unsigned int i = 0; i < end; ++i) {
312  at(offset, z_mask);
313  off_a(offset_a);
314  error_b += abs_db;
315  error_c += abs_dc;
316  if ((unsigned int)error_b >= abs_da) {
317  off_b(offset_b);
318  error_b -= abs_da;
319  }
320  if ((unsigned int)error_c >= abs_da) {
321  off_c(offset_c);
322  error_c -= abs_da;
323  }
324  }
325  at(offset, z_mask);
326  }
327 
328  inline int sign(int i)
329  {
330  return i > 0 ? 1 : -1;
331  }
332 
333  inline unsigned int max(unsigned int x, unsigned int y)
334  {
335  return x > y ? x : y;
336  }
337 
338  unsigned int size_x_, size_y_, size_z_;
339  uint32_t * data_;
340  unsigned char * costmap;
341  rclcpp::Logger logger;
342 
343  // Aren't functors so much fun... used to recreate the Bresenham macro Eric
344  // wrote in the original version, but in "proper" c++
345  class MarkVoxel
346  {
347 public:
348  explicit MarkVoxel(uint32_t * data)
349  : data_(data) {}
350  inline void operator()(unsigned int offset, unsigned int z_mask)
351  {
352  data_[offset] |= z_mask; // clear unknown and mark cell
353  }
354 
355 private:
356  uint32_t * data_;
357  };
358 
359  class ClearVoxel
360  {
361 public:
362  explicit ClearVoxel(uint32_t * data)
363  : data_(data) {}
364  inline void operator()(unsigned int offset, unsigned int z_mask)
365  {
366  data_[offset] &= ~(z_mask); // clear unknown and clear cell
367  }
368 
369 private:
370  uint32_t * data_;
371  };
372 
373  class ClearVoxelInMap
374  {
375 public:
376  ClearVoxelInMap(
377  uint32_t * data, unsigned char * costmap,
378  unsigned int unknown_clear_threshold, unsigned int marked_clear_threshold,
379  unsigned char free_cost = 0, unsigned char unknown_cost = 255)
380  : data_(data), costmap_(costmap),
381  unknown_clear_threshold_(unknown_clear_threshold), marked_clear_threshold_(
382  marked_clear_threshold),
383  free_cost_(free_cost), unknown_cost_(unknown_cost)
384  {
385  }
386 
387  inline void operator()(unsigned int offset, unsigned int z_mask)
388  {
389  uint32_t * col = &data_[offset];
390  *col &= ~(z_mask); // clear unknown and clear cell
391 
392  unsigned int unknown_bits = uint16_t(*col >> 16) ^ uint16_t(*col);
393  unsigned int marked_bits = *col >> 16;
394 
395  // make sure the number of bits in each is below our thresholds
396  if (bitsBelowThreshold(marked_bits, marked_clear_threshold_)) {
397  if (bitsBelowThreshold(unknown_bits, unknown_clear_threshold_)) {
398  costmap_[offset] = free_cost_;
399  } else {
400  costmap_[offset] = unknown_cost_;
401  }
402  }
403  }
404 
405 private:
406  inline bool bitsBelowThreshold(unsigned int n, unsigned int bit_threshold)
407  {
408  unsigned int bit_count;
409  for (bit_count = 0; n; ) {
410  ++bit_count;
411  if (bit_count > bit_threshold) {
412  return false;
413  }
414  n &= n - 1; // clear the least significant bit set
415  }
416  return true;
417  }
418 
419  uint32_t * data_;
420  unsigned char * costmap_;
421  unsigned int unknown_clear_threshold_, marked_clear_threshold_;
422  unsigned char free_cost_, unknown_cost_;
423  };
424 
425  class GridOffset
426  {
427 public:
428  explicit GridOffset(unsigned int & offset)
429  : offset_(offset) {}
430  inline void operator()(int offset_val)
431  {
432  offset_ += offset_val;
433  }
434 
435 private:
436  unsigned int & offset_;
437  };
438 
439  class ZOffset
440  {
441 public:
442  explicit ZOffset(unsigned int & z_mask)
443  : z_mask_(z_mask) {}
444  inline void operator()(int offset_val)
445  {
446  offset_val > 0 ? z_mask_ <<= 1 : z_mask_ >>= 1;
447  }
448 
449 private:
450  unsigned int & z_mask_;
451  };
452 };
453 
454 } // namespace nav2_voxel_grid
455 
456 #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:64
VoxelGrid(unsigned int size_x, unsigned int size_y, unsigned int size_z)
Constructor for a voxel grid.
Definition: voxel_grid.cpp:41