VoxelGridStructure.cpp
Go to the documentation of this file.
2
3#include <VirtualRobot/math/Helpers.h>
4
6
7namespace visionx::voxelgrid
8{
9
10 template <typename Derived>
11 using ScalarFunction = std::function<typename Eigen::MatrixBase<Derived>::Scalar(
12 typename Eigen::MatrixBase<Derived>::Scalar)>;
13
14 template <typename Derived>
15 static Derived
16 cwise(ScalarFunction<Derived> function, const Eigen::MatrixBase<Derived>& matrix)
17 {
18 Derived result = matrix;
19 for (typename Derived::Index i = 0; i < result.size(); ++i)
20 {
21 result(i) = function(result(i));
22 }
23 return result;
24 }
25
26 const Eigen::IOFormat VoxelGridStructure::_iofVector = {5, 0, " ", " ", "", "", "[", "]"};
27 const Eigen::IOFormat VoxelGridStructure::_iofTimes = {5, 0, "", " x ", "", "", "", ""};
28
32
34 float voxelSize,
35 const Eigen::Vector3f& origin,
36 const Eigen::Quaternionf& orientation) :
37 VoxelGridStructure(Eigen::Vector3i::Constant(gridSize),
38 Eigen::Vector3f::Constant(voxelSize),
39 origin,
40 orientation)
41 {
42 }
43
44 VoxelGridStructure::VoxelGridStructure(const Eigen::Vector3i& gridSize,
45 float voxelSize,
46 const Eigen::Vector3f& origin,
47 const Eigen::Quaternionf& orientation) :
48 VoxelGridStructure(gridSize, Eigen::Vector3f::Constant(voxelSize), origin, orientation)
49 {
50 }
51
53 const Eigen::Vector3f& voxelSize,
54 const Eigen::Vector3f& origin,
55 const Eigen::Quaternionf& orientation) :
56 VoxelGridStructure(Eigen::Vector3i::Constant(gridSize), voxelSize, origin, orientation)
57 {
58 }
59
60 VoxelGridStructure::VoxelGridStructure(const Eigen::Vector3i& gridSize,
61 const Eigen::Vector3f& voxelSize,
62 const Eigen::Vector3f& origin,
63 const Eigen::Quaternionf& orientation) :
64 _gridSize(gridSize), _voxelSize(voxelSize), _origin(origin), _orientation(orientation)
65 {
66 ARMARX_CHECK_NONNEGATIVE(voxelSize.minCoeff()) << "Voxel sizes must not be negative.";
67 ARMARX_CHECK_NONNEGATIVE(gridSize.minCoeff()) << "Grid sizes must not be negative.";
68 }
69
70 Eigen::Vector3i
72 {
73 return _gridSize;
74 }
75
76 void
78 {
79 setGridSize(Eigen::Vector3i::Constant(gridSize));
80 }
81
82 void
83 VoxelGridStructure::setGridSize(const Eigen::Vector3i& gridSize)
84 {
85 _gridSize = gridSize;
86 }
87
88 Eigen::Vector3f
90 {
91 return _voxelSize;
92 }
93
94 void
96 {
97 setVoxelSize(Eigen::Vector3f::Constant(voxelSize));
98 }
99
100 void
101 VoxelGridStructure::setVoxelSize(const Eigen::Vector3f& voxelSize)
102 {
103 _voxelSize = voxelSize;
104 }
105
106 std::size_t
108 {
109 return static_cast<std::size_t>(_gridSize.prod());
110 }
111
112 std::size_t
113 VoxelGridStructure::getFlatIndex(int x, int y, int z) const
114 {
115 return getFlatIndex(Eigen::Vector3i(x, y, z));
116 }
117
118 std::size_t
119 VoxelGridStructure::getFlatIndex(const Eigen::Vector3i& indices) const
120 {
121 const Eigen::Vector3f _halfGridSizes = halfGridSize();
122
123 checkIsInside(indices);
124
125 long index = static_cast<long>(
126 (indices.x() + _halfGridSizes.x()) * _gridSize.z() * _gridSize.y() // skips y*z
127 + (indices.y() + _halfGridSizes.y()) * _gridSize.z() // skips z
128 + (indices.z() + _halfGridSizes.z()));
129
131 return static_cast<std::size_t>(index);
132 }
133
134 std::size_t
135 VoxelGridStructure::getFlatIndex(const Eigen::Vector3f& point, bool local) const
136 {
137 return getFlatIndex(getGridIndex(point, local));
138 }
139
140 Eigen::Vector3i
142 {
143 // FITS_SIZE triggers: comparison of unsigned expression >= 0 is always true [-Werror=type-limits]
144 //ARMARX_CHECK_FITS_SIZE(index, getNumVoxels());
146 int x = static_cast<int>(index / static_cast<std::size_t>(_gridSize.z() * _gridSize.y()));
147 int rest =
148 static_cast<int>(index % static_cast<std::size_t>(_gridSize.z() * _gridSize.y()));
149 int y = rest / _gridSize.z();
150 int z = rest % _gridSize.z();
151 return Eigen::Vector3i{x, y, z} + getGridIndexMin();
152 }
153
154 Eigen::Vector3i
155 VoxelGridStructure::getGridIndex(const Eigen::Vector3f& point, bool local) const
156 {
157 Eigen::Vector3f pointLocal;
158 if (local)
159 {
160 pointLocal = point;
161 }
162 else
163 {
164 // pose = local -> global => inv_pose = global -> locals
165 pointLocal =
166 math::Helpers::TransformPosition(math::Helpers::InvertedPose(getPose()), point);
167 }
168
169 Eigen::Vector3f scaled = (pointLocal.array() / _voxelSize.array()).matrix();
170
171 return cwise<Eigen::Vector3f>(&std::roundf, scaled).template cast<int>();
172 }
173
174 Eigen::Vector3i
176 {
177 // 3 -> 1.5 -> 1 -> -1
178 // 4 -> 2.0 -> 2 -> -2
179 // 5 -> 2.5 -> 2 -> -2
180 // 6 -> 3.0 -> 3 -> -3
181 return -cwise<Eigen::Vector3f>(&floorf, halfGridSize()).template cast<int>();
182 }
183
184 Eigen::Vector3i
186 {
187 // 3 -> 1.5 -> 1.0 -> 1
188 // 4 -> 2.0 -> 1.5 -> 1
189 // 5 -> 2.5 -> 2.0 -> 2
190 // 6 -> 3.0 -> 2.5 -> 2
191 const Eigen::Vector3f half = halfGridSize().array() - 0.5f;
192 return cwise<Eigen::Vector3f>(&floorf, half).template cast<int>();
193 }
194
195 Eigen::Vector3f
196 VoxelGridStructure::getVoxelCenter(std::size_t index, bool local) const
197 {
198 return getVoxelCenter(getGridIndex(index), local);
199 }
200
201 Eigen::Vector3f
202 VoxelGridStructure::getVoxelCenter(int x, int y, int z, bool local) const
203 {
204 return getVoxelCenter({x, y, z}, local);
205 }
206
207 Eigen::Vector3f
208 VoxelGridStructure::getVoxelCenter(const Eigen::Vector3i& indices, bool local) const
209 {
210 checkIsInside(indices);
211 auto center = _voxelSize.array() * indices.array().cast<float>();
212 if (local)
213 {
214 return center;
215 }
216 else
217 {
218 return math::Helpers::TransformPosition(getPose(), center);
219 }
220 }
221
222 Eigen::Vector3f
224 {
225 return _origin;
226 }
227
228 void
229 VoxelGridStructure::setOrigin(const Eigen::Vector3f& origin)
230 {
231 _origin = origin;
232 }
233
236 {
237 return _orientation;
238 }
239
240 void
242 {
243 _orientation = orientation;
244 }
245
246 Eigen::Vector3f
248 {
249 return _origin + getOriginToGridCenter(false);
250 }
251
252 void
253 VoxelGridStructure::setCenter(const Eigen::Vector3f& center)
254 {
255 setOrigin(center - getOriginToGridCenter(false));
256 }
257
258 Eigen::Matrix4f
260 {
261 return math::Helpers::Pose(_origin, _orientation);
262 }
263
264 void
265 VoxelGridStructure::setPose(const Eigen::Matrix4f& pose)
266 {
267 setOrigin(math::Helpers::Position(pose));
268 setOrientation(Eigen::Quaternionf(math::Helpers::Orientation(pose)));
269 }
270
271 Eigen::Matrix4f
273 {
274 return math::Helpers::Pose(getCenter(), _orientation);
275 }
276
277 void
278 VoxelGridStructure::setCenterPose(const Eigen::Matrix4f& pose)
279 {
280 setOrientation(Eigen::Quaternionf(math::Helpers::Orientation(pose)));
281 setCenter(math::Helpers::Position(pose));
282 }
283
284 Eigen::Vector3f
286 {
287 return getExtentOfCenters() + _voxelSize;
288 }
289
290 Eigen::Vector3f
292 {
293 return _gridSize.cast<float>().array() * _voxelSize.array();
294 }
295
298 {
300 bb.col(0) -= _voxelSize / 2;
301 bb.col(1) += _voxelSize / 2;
302 return bb;
303 }
304
307 {
309 bb.col(0) = getVoxelCenter(getGridIndexMin(), true);
310 bb.col(1) = getVoxelCenter(getGridIndexMax(), true);
311 return bb;
312 }
313
314 bool
315 VoxelGridStructure::isInside(const Eigen::Vector3i& indices) const
316 {
317 const Eigen::Vector3i min = getGridIndexMin();
318 const Eigen::Vector3i max = getGridIndexMax();
319
320 for (int i = 0; i < indices.size(); ++i)
321 {
322 if (!(min(i) <= indices(i) && indices(i) <= max(i)))
323 {
324 return false;
325 }
326 }
327 return true;
328 }
329
330 bool
331 VoxelGridStructure::isInside(const Eigen::Vector3f& point, bool local) const
332 {
333 return isInside(getGridIndex(point, local));
334 }
335
336 void
337 VoxelGridStructure::checkIsInside(const Eigen::Vector3i& indices) const
338 {
340 << "Indices must be inside voxel grid. "
341 << "\n- given: " << indices.format(_iofVector)
342 << "\n- allowed range: " << getGridIndexMin().format(_iofVector) << " .. "
343 << getGridIndexMax().format(_iofVector);
344 }
345
346 bool
348 {
349 return _gridSize == rhs._gridSize && _voxelSize.isApprox(rhs._voxelSize) &&
350 _origin.isApprox(rhs._origin) && _orientation.isApprox(rhs._orientation);
351 }
352
353 bool
355 {
356 return !(*this == rhs);
357 }
358
359 Eigen::Vector3f
360 VoxelGridStructure::halfGridSize() const
361 {
362 return _gridSize.cast<float>() / 2;
363 }
364
365 Eigen::Vector3f
366 VoxelGridStructure::getOriginToGridCenter(bool local) const
367 {
368 Eigen::Vector3f shift = shift.Zero();
369 for (Eigen::Vector3f::Index i = 0; i < shift.size(); ++i)
370 {
371 if (_gridSize(i) % 2 == 0)
372 {
373 shift(i) = -_voxelSize(i) / 2;
374 }
375 }
376 return local ? shift : (_orientation * shift);
377 }
378
379 std::ostream&
380 operator<<(std::ostream& os, const VoxelGridStructure& rhs)
381 {
382 os << "Structure with " << rhs.getNumVoxels() << " voxels";
383 os << "\n- Origin: \t" << rhs._origin.format(rhs._iofVector);
384 os << "\n- Voxel size:\t" << rhs._voxelSize.format(rhs._iofTimes);
385 os << "\n- Grid size: \t" << rhs._gridSize.format(rhs._iofTimes);
386 os << "\n- Indices: \t" << rhs.getGridIndexMin().format(rhs._iofVector) << " .. "
387 << rhs.getGridIndexMax().format(rhs._iofVector);
388 os << "\n- Centers: \t"
389 << rhs.getVoxelCenter(rhs.getGridIndexMin()).format(rhs._iofVector) << " .. "
390 << rhs.getVoxelCenter(rhs.getGridIndexMax()).format(rhs._iofVector);
391
392 return os;
393 }
394
395} // namespace visionx::voxelgrid
uint8_t index
std::size_t getNumVoxels() const
Get the number of voxels contained in the structure.
Eigen::Matrix4f getCenterPose() const
Get the grid pose positioned at the grid center in the world frame.
Eigen::Vector3f getOrigin() const
Get the grid origin in the world frame (center of voxel [0 0 0]).
bool operator!=(const VoxelGridStructure &rhs) const
Eigen::Matrix32f getLocalBoundingBox() const
Get the local axis aligned bounding box of the grid (minimal/maximal values in columns).
std::size_t getFlatIndex(int x, int y, int z) const
Get the flat index for the given grid indices.
void setVoxelSize(float voxelSize)
Set the voxel size for cubic voxels.
Eigen::Vector3f getVoxelCenter(std::size_t index, bool local=false) const
Get the center of the voxel with the given indices.
Eigen::Vector3f getCenter() const
Get the geometric center of the grid the world frame (which differs from the origin for even grid siz...
void setOrientation(const Eigen::Quaternionf &value)
Set the grid orienation in the world frame.
Eigen::Matrix32f getLocalBoundingBoxOfCenters() const
Get the local axis aligned bounding box of the voxel centers (minimal/maximal values in columns).
void setOrigin(const Eigen::Vector3f &value)
Set the grid origin the world frame (center of voxel [0 0 0]).
Eigen::Vector3i getGridSize() const
Get the grid size.
Eigen::Vector3i getGridIndex(size_t index) const
Get the voxel indices of the voxel with the given index.
void setCenter(const Eigen::Vector3f &center)
Set the geometric center of the grid the world frame (which differs from the origin for even grid siz...
Eigen::Vector3f getVoxelSize() const
Get the voxel size.
Eigen::Vector3f getExtent() const
Get extent of the grid along each axis (encompassing the whole voxels).
bool operator==(const VoxelGridStructure &rhs) const
Indicates whether rhs is equal to *this.
void setCenterPose(const Eigen::Matrix4f &pose)
Set the grid pose so that the grid center is the position of the given pose under the given orientati...
VoxelGridStructure()
Construct an empty grid structure (0 voxels with size 1.0).
bool isInside(const Eigen::Vector3i &indices) const
Indicate whether the given point is inside the voxel.
void checkIsInside(const Eigen::Vector3i &indices) const
Assert that the given indices are valid grid indices.
void setPose(const Eigen::Matrix4f &pose)
Get the grid pose in the world frame.
Eigen::Vector3f getExtentOfCenters() const
Get extent of the grid along each axis (encompassing only voxel centers).
Eigen::Matrix4f getPose() const
Get the grid pose in the world frame.
void setGridSize(int gridSize)
Set the grid size for a cubic grid.
Eigen::Vector3i getGridIndexMax() const
Get the maximal (along each axis) grid index.
Eigen::Vector3i getGridIndexMin() const
Get the minimal (along each axis) grid index.
Eigen::Quaternionf getOrientation() const
Get the grid orienation in the world frame.
T min(T t1, T t2)
Definition gdiam.h:44
T max(T t1, T t2)
Definition gdiam.h:51
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_CHECK_LESS(lhs, rhs)
This macro evaluates whether lhs is less (<) than rhs and if it turns out to be false it will throw a...
#define ARMARX_CHECK_NONNEGATIVE(number)
Check whether number is nonnegative (>= 0).
Quaternion< float, 0 > Quaternionf
Matrix< float, 3, 2 > Matrix32f
A 3x2 matrix.
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::ostream & operator<<(std::ostream &os, const VoxelGrid< VT > &grid)
std::function< typename Eigen::MatrixBase< Derived >::Scalar( typename Eigen::MatrixBase< Derived >::Scalar)> ScalarFunction