MIRA
VoxelMap.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) by
3  * MetraLabs GmbH (MLAB), GERMANY
4  * and
5  * Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
6  * All rights reserved.
7  *
8  * Redistribution and modification of this code is strictly prohibited.
9  *
10  * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
11  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
12  * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
13  * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
16  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
18  * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
19  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
20  */
21 
30 #ifndef _MIRA_VOXELMAP_H_
31 #define _MIRA_VOXELMAP_H_
32 
33 #include <cmath>
34 #include <type_traits>
35 
36 #include <image/Img.h>
37 #include <geometry/Size.h>
38 #include <geometry/Rect.h>
40 
41 namespace mira { namespace maps {
42 
44 
45 template <typename T>
46 class VoxelMap
47 {
48 public:
49  // the is_pod check is too hard here, since user defined constructors
50  // are allowed, as long there is a trivial default constructor,
51  // copy constructor and trivial destructor
52  static_assert(std::has_trivial_destructor<T>::value,
53  "Can be used with types that have trivial destructor only");
54 
55 #ifndef MIRA_WINDOWS
56  // VC++2010 does not yet support the "Explicitly-defaulted and deleted
57  // special member functions"-syntax, therefore we must skip these checks
58  static_assert(std::has_trivial_default_constructor<T>::value,
59  "Can be used with types that have a trivial default constructor only");
60  static_assert(std::has_trivial_copy_constructor<T>::value,
61  "Can be used with types that have a trivial copy constructor only");
62 #endif
63 
64 public:
65 
66  typedef typename boost::multi_array<T,3> Array;
67  typedef typename boost::multi_array::extent_range Range;
68 
69 private:
70 
71  void init(const Size3i& size, float cellSize, const Point3i& offset)
72  {
73  mCellSize = cellSize;
74  mOffset = offset;
75  mSize = size;
76 
77  Point3i a = -mOffset;
78  Point3i b = a + mSize;
79 
80  mData = createArray(a,b);
81  }
82 
83  Array* createArray(const Point3i& a, const Point3i& b) {
84  typename Array::extent_gen extents;
85  return new Array(extents[Range(a(0),b(0))]
86  [Range(a(1),b(1))]
87  [Range(a(2),b(2))]);
88  }
89 
90 
91 public:
92 
93  VoxelMap(float cellSize=0.1f) : mCellSize(cellSize), mOffset(0, 0, 0) { mData = new Array; }
94 
95  VoxelMap(const Size3i& size, float cellSize, const Point3i& offset = Point3i(0, 0, 0)) {
96  init(size, cellSize, offset);
97  }
98 
107  VoxelMap(const Box3f& region, float cellSize)
108  {
109  auto p = getOffsetAndSize(region,cellSize);
110  init(p.second, cellSize, p.first);
111  }
112 
113  VoxelMap(const Box3i& region, float cellSize) {
114  init(region.size(), cellSize, -region.minCorner);
115  }
116 
117  ~VoxelMap() { delete mData; }
118 
119 public:
120 
122  float getCellSize() const { return mCellSize; }
123 
125  Point3i getOffset() const { return mOffset; }
126 
127 public:
128 
132  VoxelMap& operator=(const T& value) {
133 
134  Point3i a = -mOffset;
135  Point3i b = a + mSize;
136  for(int i=a(0); i<b(0); ++i)
137  for(int j=a(1); j<b(1); ++j)
138  for(int k=a(2); k<b(2); ++k)
139  (*mData)[i][j][k] = value;
140  return *this;
141  }
142 
143 public:
144 
148  Box3f getRegion() const { return Box3f(-mOffset*mCellSize, mSize*mCellSize); }
149 
153  Box3i getMapRegion() const { return Box3f(-mOffset, mSize); }
154 
155 public:
156 
157 
158  Array& data() { return *mData; }
159  const Array& data() const { return *mData; }
160 
161  T& operator()(const Point3i& idx) {
162  return data()[idx(0)][idx(1)][idx(2)];
163  }
164 
165  const T& operator()(const Point3i& idx) const {
166  return data()[idx(0)][idx(1)][idx(2)];
167  }
168 
169 
170 public:
171 
178  Point3i world2map(const Point3f& p) const {
179  float ioff = 1.0f / mCellSize;
180  return p * ioff + mOffset;
181  }
182 
188  Point3f map2world(const Point3i& p) const {
189  return (p - mOffset) * mCellSize;
190  }
191 
192 
193 public:
194 
195  void clip(const Box3i& region, const T& valueForNewCells);
196 
197 #if 0
198 
199  void grow(const Index& pMin, const Index& pMax)
200  {
201  if(pMin >= mMin && pMax <= mMax)
202  return;
203 
204  //std::cout << "VoxelMap::grow " << endl;
205 
206  Index min;
207  Index max;
208  for(int i=0; i<3; ++i) {
209  min(i) = std::min(mMin(i), pMin(i));
210  max(i) = std::max(mMax(i), pMax(i));
211  }
212 
213  typename Array::extent_gen extents;
214  Array* newData = new Array(extents[Range(min(0),max(0)+1)]
215  [Range(min(1),max(1)+1)]
216  [Range(min(2),max(2)+1)]);
217 
218  // copy old content in new map
219  for(int i=mMin(0); i<=mMax(0); ++i)
220  for(int j=mMin(1); j<=mMax(1); ++j)
221  for(int k=mMin(2); k<=mMax(2); ++k)
222  (*newData)[i][j][k] = (*mData)[i][j][k];
223 
224  Array* oldData = mData;
225  mData = newData;
226  mMin = min;
227  mMax = max;
228  delete oldData;
229  }
230 
231  void grow(const MetricIndex& pMin, const MetricIndex& pMax) {
232  grow(metricToCell(pMin), metricToCell(pMax));
233  }
234 
235 
236  void resize(const Index& min, const Index& max)
237  {
238  if(min == mMin && max == mMax)
239  return;
240 
241  //std::cout << "VoxelMap::resize " << endl;
242 
243  typename Array::extent_gen extents;
244  Array* newData = new Array(extents[Range(min(0),max(0)+1)]
245  [Range(min(1),max(1)+1)]
246  [Range(min(2),max(2)+1)]);
247 
248  // get the intersecting region, that needs to be copied
249  Index interMin;
250  Index interMax;
251 
252  for(int i=0; i<3; ++i) {
253  interMin(i) = std::max(mMin(i), min(i));
254  interMax(i) = std::min(mMax(i), max(i));
255  }
256 
257  // copy content in intersecting region into new map
258  for(int i=interMin(0); i<=interMax(0); ++i)
259  for(int j=interMin(1); j<=interMax(1); ++j)
260  for(int k=interMin(2); k<=interMax(2); ++k)
261  (*newData)[i][j][k] = (*mData)[i][j][k];
262 
263  Array* oldData = mData;
264  mData = newData;
265  mMin = min;
266  mMax = max;
267  delete oldData;
268  }
269 
270  void resize(const MetricIndex& pMin, const MetricIndex& pMax) {
271  resize(metricToCell(pMin), metricToCell(pMax));
272  }
273 
274 #endif
275 
276 
277 private:
278 
279  static std::pair<Point3i, Size3i> getOffsetAndSize(const Box3f& region, float cellSize);
280 
281 private:
282 
283  float mCellSize;
284  Point3i mOffset;
285  Size3i mSize;
286 
287  Array* mData;
288 };
289 
290 
291 template<typename T>
292 inline void VoxelMap<T>::clip(const Box3i& region, const T& valueForNewCells)
293 {
294  Box3i oldRegion = getMapRegion();
295  if(region==oldRegion)
296  return; // nothing to do
297 
298  // newBuffer:
299  // ------------
300  // | new :
301  // | ------:-----------------|
302  // | | copy: |
303  // |....|.....: oldBuffer |
304  // | |
305  // | |
306  // -------------------------
307 
308 
309  Point3i growLowerLeft = oldRegion.minCorner - region.minCorner;
310  Point3i growUpperRight = region.maxCorner - oldRegion.maxCorner;
311 
312  Point3i copyRegionInNewLL(0,0,0);
313  Point3i copyRegionInOldLL(0,0,0);
314 
315  for(int i=0; i<3; ++i)
316  {
317  if(oldRegion.minCorner(i) > region.minCorner(i))
318  copyRegionInNewLL(i) = oldRegion.minCorner(i) - region.minCorner(i);
319  else
320  copyRegionInOldLL(i) = region.minCorner(i) - oldRegion.minCorner(i);
321  }
322 
323  Box3i intersection = oldRegion & region;
324 
325  Array* oldBuffer = this->mData;
326  Array* newBuffer = createArray(region.minCorner, region.maxCorner);
327 
328  if(intersection.isValid()) {
329 
330  Point3i copyRegionInNewUR = copyRegionInNewLL + intersection.size();
331  Point3i copyRegionInOldUR = copyRegionInOldLL + intersection.size();
332 
333  // detailed view for copying:
334  // ------------------------------
335  // | above |
336  // |----------------------------|
337  // | | | |
338  // | | oldBuffer | |
339  // |left| | right |
340  // | | | |
341  // | | | |
342  // |----------------------------|
343  // | below |
344  // |----------------------------|
345 
346 
347  // fill in new parts
348  // above
349  assert(copyRegionInNewLL.y()<=newBuffer.height());
350  for(int y=0; y<copyRegionInNewLL.y(); ++y)
351  {
352  CellType* dest = newBuffer[y];
353  for(int x=0; x<newBuffer.width(); ++x)
354  dest[x] = valueForNewCells;
355  }
356 
357  // left and right
358  assert(copyRegionInNewLL.y()>=0 && copyRegionInNewUR.y()<=newBuffer.height());
359  assert(copyRegionInNewUR.x()>=0 && copyRegionInNewLL.x()<=newBuffer.width());
360  for(int y=copyRegionInNewLL.y(); y<copyRegionInNewUR.y(); ++y)
361  {
362  CellType* dest = newBuffer[y];
363  // left
364  for(int x=0; x<copyRegionInNewLL.x(); ++x)
365  dest[x] = valueForNewCells;
366  // right
367  for(int x=copyRegionInNewUR.x(); x<newBuffer.width(); ++x)
368  dest[x] = valueForNewCells;
369  }
370 
371  // below
372  assert(copyRegionInNewUR.y()>=0);
373  for(int y=copyRegionInNewUR.y(); y<newBuffer.height(); ++y)
374  {
375  CellType* dest = newBuffer[y];
376  for(int x=0; x<newBuffer.width(); ++x)
377  dest[x] = valueForNewCells;
378  }
379 
380  // copy the overlapping content (scanline by scanline)
381  for(int y=0; y<intersection.height(); ++y)
382  {
383  const CellType* src = oldBuffer[y+copyRegionInOldLL.y()]+copyRegionInOldLL.x();
384  CellType* dest = newBuffer[y+copyRegionInNewLL.y()]+copyRegionInNewLL.x();
385  memcpy(dest, src, intersection.width()*sizeof(CellType));
386  }
387  } else {
388  // no intersection between old and new buffer, so simply fill the
389  // new buffer
390  newBuffer = valueForNewCells;
391  }
392 
393  mOffset = -region.minCorner;
394  oldBuffer = newBuffer;
395 
396 }
397 
398 template<typename T>
399 inline std::pair<Point3i, Size3i> VoxelMap<T>::getOffsetAndSize(const Box3f& region, float cellSize)
400 {
401  Point3i lowerLeft (std::floor(region.x0() / cellSize),
402  std::floor(region.y0() / cellSize),
403  std::floor(region.z0() / cellSize));
404  Point3i upperRight(std::ceil(region.x1() / cellSize),
405  std::ceil(region.y1() / cellSize),
406  std::ceil(region.z1() / cellSize));
407 
408  // compute required size and offset of the map
409  Size3i size = upperRight - lowerLeft;
410  Point3i offset = -lowerLeft;
411  return std::make_pair(offset,size);
412 }
413 
415 
416 }} // namespace
417 
418 #endif /* _MIRA_GRIDMAP_H_ */
VoxelMap(const Size3i &size, float cellSize, const Point3i &offset=Point3i(0, 0, 0))
Definition: VoxelMap.h:95
boost::multi_array::extent_range Range
Definition: VoxelMap.h:67
Box3i getMapRegion() const
Retuns the region that is covered by the GridMap in grid cells.
Definition: VoxelMap.h:153
T k
VoxelMap & operator=(const T &value)
Set all voxel cells to the specified value.
Definition: VoxelMap.h:132
json_spirit::mArray Array
VoxelMap(const Box3i &region, float cellSize)
Definition: VoxelMap.h:113
boost::multi_array< T, 3 > Array
Definition: VoxelMap.h:53
const T & operator()(const Point3i &idx) const
Definition: VoxelMap.h:165
Rect< float, 3 > Box3f
bool isValid() const
void clip(const Box3i &region, const T &valueForNewCells)
Definition: VoxelMap.h:292
PointType minCorner
Point3f map2world(const Point3i &p) const
Convert a given point to world coordinates.
Definition: VoxelMap.h:188
Point< int, 3 > Point3i
T & operator()(const Point3i &idx)
Definition: VoxelMap.h:161
Size< int, 3 > Size3i
Definition: VoxelMap.h:46
const Array & data() const
Definition: VoxelMap.h:159
PointType maxCorner
~VoxelMap()
Definition: VoxelMap.h:117
Point3i getOffset() const
Returns the offset of the map, e.g. the index of the cell that is located in the origin.
Definition: VoxelMap.h:125
VoxelMap(float cellSize=0.1f)
Definition: VoxelMap.h:93
VoxelMap(const Box3f &region, float cellSize)
Creates a new voxel map that covers the specified region.
Definition: VoxelMap.h:107
Box3f getRegion() const
Retuns the region that is covered by the GridMap.
Definition: VoxelMap.h:148
Array & data()
Definition: VoxelMap.h:158
SizeType size() const
Point3i world2map(const Point3f &p) const
Convert a given point to map coordinates.
Definition: VoxelMap.h:178
float getCellSize() const
Returns the size of each cell in meter.
Definition: VoxelMap.h:122