Visualizer.hpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
5 * Karlsruhe Institute of Technology (KIT), all rights reserved.
6 *
7 * ArmarX is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * ArmarX is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author Rainer Kartmann (rainer dot kartmann at student dot kit dot edu)
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
24#pragma once
25
26#include <thread>
27
28#include <Eigen/Geometry>
29
30#include <VirtualRobot/math/Helpers.h>
31
33
34#include "VoxelGrid.hpp"
35
36namespace visionx::voxelgrid
37{
38
39 /**
40 * Visualizer for voxel grids of with voxel type VoxelT.
41 */
42 template <typename VoxelT>
44 {
45 public:
46 /// Default constructor.
48 /// Initialize with debug drawer and voxel grid.
50 const std::string& voxelLayer = "VoxelGrid");
51
52 /// Virtual destructor.
53 virtual ~Visualizer()
54 {
55 }
56
57 /// Clear the layer.
58 void clearLayer();
59 /// Clear the voxel layer.
60 void clearVoxelLayer(bool sleep = false);
61
62 /// Draw the voxel grid.
63 void draw(const VoxelGrid<VoxelT>& grid);
64
65 /// Draw the bounding edges of the voxel grid.
67
68 /// Draw the bounding edges of the voxel grid.
70 float lineWidth = 1,
71 const armarx::DrawColor& colorEdges = {0, .5, 1, 1},
72 const armarx::DrawColor& colorStructure = {0, 1, 1, 1},
73 bool drawOriginVoxel = false);
74
75 /// Set the debug drawer.
76 void
78 {
79 this->_debugDrawer = debugDrawer;
80 }
81
82 /// Set the layer name.
83 void
84 setLayer(const std::string& layer)
85 {
86 this->_layer = layer;
87 }
88
89 operator bool() const
90 {
91 return _debugDrawer.operator bool();
92 }
93
94
95 protected:
96 /// Information about a voxel about to-be-drawn.
98 {
99 const VoxelGrid<VoxelT>& grid; /// The voxel grid.
100 const std::string& name; /// A unique visu name for this voxel.
101
102 std::size_t index; /// The voxel's index.
103 const VoxelT& voxel; /// The voxel.
104
105 const Eigen::Vector3f& pos; /// The voxel's position.
106 const Eigen::Quaternionf& ori; /// The voxel's orientation.
107 const Eigen::Vector3f& extents; /// The voxel extents.
108 };
109
110 /// Indicate whether a voxel shall be drawn.
111 /// Voxels for which this method returns false are not passed to drawVoxel().
112 virtual bool
113 isVisible(const VoxelVisuData& visu) const
114 {
115 (void)visu;
116 return true;
117 }
118
119 /// Draw a voxel.
120 virtual void drawVoxel(const VoxelVisuData& visu);
121
122 /// Get the debug drawer.
125 {
126 return _debugDrawer;
127 }
128
130 drawer() const
131 {
132 return _debugDrawer;
133 }
134
135 /// Get the layer name.
136 std::string
138 {
139 return _layer + "_voxels";
140 }
141
142
143 private:
144 /// The debug drawer.
145 armarx::DebugDrawerTopic _debugDrawer;
146
147 /// The layer name.
148 std::string _layer;
149 };
150
151 // IMPLEMENTATION
152
153
154 template <typename VT>
158
159 template <typename VT>
161 const std::string& layer) :
162 _debugDrawer(debugDrawer), _layer(layer)
163 {
164 using namespace std::chrono_literals;
165 _debugDrawer.setLayer(layer);
166 _debugDrawer.setShortSleepDuration(100ms);
167 }
168
169 template <typename VT>
170 void
172 {
173 _debugDrawer.clearLayer(_layer);
174 }
175
176 template <typename VT>
177 void
179 {
180 _debugDrawer.clearLayer(getVoxelLayer(), sleep);
181 }
182
183 template <typename VT>
184 void
186 {
187 if (!_debugDrawer)
188 {
189 return;
190 }
191
192 std::vector<Eigen::Vector3f> points;
193 float width = 0.025f;
194 armarx::DrawColor color{0, 1, 1, 1};
195
196 const Eigen::Matrix32f bb = grid.getLocalBoundingBox();
197 const Eigen::Matrix4f pose = grid.getPose();
198
199 auto addLine = [&](int x1, int y1, int z1, int x2, int y2, int z2)
200 {
201 Eigen::Vector3f start = {bb.col(x1).x(), bb.col(y1).y(), bb.col(z1).z()};
202 Eigen::Vector3f end = {bb.col(x2).x(), bb.col(y2).y(), bb.col(z2).z()};
203
204 start = math::Helpers::TransformPosition(pose, start);
205 end = math::Helpers::TransformPosition(pose, end);
206
207 points.push_back({start.x(), start.y(), start.z()});
208 points.push_back({end.x(), end.y(), end.z()});
209 };
210
211 /* 001 +-----+ 011
212 * /| 111/|
213 * 101 +-----+ |
214 * | +---|-+ 010
215 * |/000 |/
216 * 100 +-----+ 110
217 */
218
219 // 000 -> 100, 010, 001
220 addLine(0, 0, 0, 1, 0, 0);
221 addLine(0, 0, 0, 0, 1, 0);
222 addLine(0, 0, 0, 0, 0, 1);
223
224 // 111 -> 011, 101, 110
225 addLine(1, 1, 1, 0, 1, 1);
226 addLine(1, 1, 1, 1, 0, 1);
227 addLine(1, 1, 1, 1, 1, 0);
228
229 // 100 -> 101, 110
230 addLine(1, 0, 0, 1, 0, 1);
231 addLine(1, 0, 0, 1, 1, 0);
232
233 // 010 -> 110, 011
234 addLine(0, 1, 0, 1, 1, 0);
235 addLine(0, 1, 0, 0, 1, 1);
236
237 // 001 -> 101, 011
238 addLine(0, 0, 1, 1, 0, 1);
239 addLine(0, 0, 1, 0, 1, 1);
240
241 _debugDrawer.drawLineSet({_layer, "edges"}, points, width, color);
242 }
243
244 template <typename VT>
245 void
247 float lineWidth,
248 const armarx::DrawColor& colorEdges,
249 const armarx::DrawColor& colorStructure,
250 bool drawOriginVoxel)
251 {
252 if (!_debugDrawer)
253 {
254 return;
255 }
256
257 armarx::DebugDrawerLineSet lines;
258 lines.lineWidth = lineWidth;
259 lines.colorNoIntensity = colorStructure;
260 lines.colorFullIntensity = colorEdges;
261
262 const Eigen::Matrix32f bb = grid.getLocalBoundingBox();
263 const Eigen::Matrix4f pose = grid.getPose();
264
265 auto addLine = [&](const Eigen::Vector3f& startLocal,
266 const Eigen::Vector3f& endLocal,
267 float intensity = 1)
268 {
269 const Eigen::Vector3f start = math::Helpers::TransformPosition(pose, startLocal);
270 const Eigen::Vector3f end = math::Helpers::TransformPosition(pose, endLocal);
271
272 lines.points.push_back({start.x(), start.y(), start.z()});
273 lines.points.push_back({end.x(), end.y(), end.z()});
274
275 lines.intensities.push_back(intensity);
276 };
277
278 auto addEdge = [&](int x1, int y1, int z1, int x2, int y2, int z2)
279 {
280 const Eigen::Vector3f start = {bb.col(x1).x(), bb.col(y1).y(), bb.col(z1).z()};
281 const Eigen::Vector3f end = {bb.col(x2).x(), bb.col(y2).y(), bb.col(z2).z()};
282 addLine(start, end, 1);
283 };
284
285 /* 001 +-----+ 011
286 * /| 111/|
287 * 101 +-----+ |
288 * | +---|-+ 010
289 * |/000 |/
290 * 100 +-----+ 110
291 */
292
293 // 000 -> 100, 010, 001
294 addEdge(0, 0, 0, 1, 0, 0);
295 addEdge(0, 0, 0, 0, 1, 0);
296 addEdge(0, 0, 0, 0, 0, 1);
297
298 // 111 -> 011, 101, 110
299 addEdge(1, 1, 1, 0, 1, 1);
300 addEdge(1, 1, 1, 1, 0, 1);
301 addEdge(1, 1, 1, 1, 1, 0);
302
303 // 100 -> 101, 110
304 addEdge(1, 0, 0, 1, 0, 1);
305 addEdge(1, 0, 0, 1, 1, 0);
306
307 // 010 -> 110, 011
308 addEdge(0, 1, 0, 1, 1, 0);
309 addEdge(0, 1, 0, 0, 1, 1);
310
311 // 001 -> 101, 011
312 addEdge(0, 0, 1, 1, 0, 1);
313 addEdge(0, 0, 1, 0, 1, 1);
314
315 const auto min = bb.col(0);
316 const auto max = bb.col(1);
317
318 auto addQuad = [&](const Eigen::Vector3f& center, int h1, int h2, float intensity = 0)
319 {
320 /* -/+ D----^----C +/+
321 * | h2| |
322 * | +---->
323 * | c h1 |
324 * -/- A---------B +/-
325 */
326
327 Eigen::Vector3f A, B, C, D;
328 A = B = C = D = center;
329
330 A(h1) = min(h1);
331 A(h2) = min(h2);
332
333 B(h1) = max(h1);
334 B(h2) = min(h2);
335
336 C(h1) = max(h1);
337 C(h2) = max(h2);
338
339 D(h1) = min(h1);
340 D(h2) = max(h2);
341
342 addLine(A, B, intensity);
343 addLine(B, C, intensity);
344 addLine(C, D, intensity);
345 addLine(D, A, intensity);
346 };
347
348
349 Eigen::Vector3i index = index.Zero();
350 Eigen::Vector3f center = center.Zero();
351
352 const Eigen::Vector3i indicesMinMax[2] = {grid.getVoxelGridIndexMin(),
353 grid.getVoxelGridIndexMax()};
354
355 for (int i = 0; i < 3; ++i)
356 {
357 int h1 = (i + 1) % 3;
358 int h2 = (i + 2) % 3;
359
360 for (int mm : {0, 1}) // min / max
361 {
362 index(i) = indicesMinMax[mm](i);
363 center(i) = grid.getVoxelCenter(index, true)(i);
364
365 // Shift: min => -size, max => +size
366 float shift = (mm == 0 ? -1 : +1) * grid.getVoxelSizes()(i);
367
368 // Add quad at bounding edge (shift one voxel to center).
369 // (min => +shift, max => -shift)
370 center(i) -= shift;
371 addQuad(center, h1, h2);
372
373 // Add quad at origin (at +- size/2 around origin).
374 center(i) = shift / 2;
375 addQuad(center, h1, h2);
376 }
377 if (grid.getGridSizes()(i) % 2 == 0)
378 {
379 // Also add a quad at origin for min of voxels at -1.
380 center(i) = -1.5 * grid.getVoxelSizes()(i);
381 addQuad(center, h1, h2);
382 }
383 }
384
385 _debugDrawer.drawLineSet({_layer, "structure"}, lines);
386
387 if (drawOriginVoxel)
388 {
389 _debugDrawer.drawBox({_layer, "origin_voxel"},
390 grid.getOrigin(),
391 grid.getOrientation(),
392 grid.getVoxelSizes(),
393 _debugDrawer.toDrawColor(colorEdges, .25));
394 }
395 }
396
397 template <typename VoxelT>
398 void
400 {
401 if (!_debugDrawer)
402 {
403 return;
404 }
405
406 for (std::size_t i = 0; i < grid.numVoxels(); ++i)
407 {
408 const VoxelT& voxel = grid.getVoxels()[i];
409 const Eigen::Vector3f center = grid.getVoxelCenter(i);
410
411 VoxelVisuData visu{grid,
412 "voxel_" + std::to_string(i),
413 i,
414 voxel,
415 center,
416 grid.getOrientation(),
417 grid.getVoxelSizes()};
418
419 if (isVisible(visu))
420 {
421 drawVoxel(visu);
422 }
423 }
424 }
425
426 template <typename VoxelT>
427 void
429 {
430 const armarx::DrawColor color{.5, .5, .5, 1};
431 drawer().drawBox({getVoxelLayer(), visu.name}, visu.pos, visu.ori, visu.extents, color);
432 }
433
434} // namespace visionx::voxelgrid
uint8_t index
class A(deque< T, A >)) ARMARX_OVERLOAD_STD_HASH_FOR_ITERABLE((class T
Enables hashing of std::list.
The DebugDrawerTopic wraps a DebugDrawerInterfacePrx and provides a more useful interface than the Ic...
std::string getVoxelLayer() const
Get the layer name.
const armarx::DebugDrawerTopic & drawer() const
void setDebugDrawer(const armarx::DebugDrawerInterfacePrx &debugDrawer)
Set the debug drawer.
void setLayer(const std::string &layer)
Set the layer name.
void drawBoundingEdges(const VoxelGrid< VoxelT > &grid)
Draw the bounding edges of the voxel grid.
void clearVoxelLayer(bool sleep=false)
Clear the voxel layer.
armarx::DebugDrawerTopic & drawer()
virtual bool isVisible(const VoxelVisuData &visu) const
Indicate whether a voxel shall be drawn.
void draw(const VoxelGrid< VoxelT > &grid)
Draw the voxel grid.
Visualizer()
Default constructor.
void drawStructure(const VoxelGrid< VoxelT > &grid, float lineWidth=1, const armarx::DrawColor &colorEdges={0,.5, 1, 1}, const armarx::DrawColor &colorStructure={0, 1, 1, 1}, bool drawOriginVoxel=false)
Draw the bounding edges of the voxel grid.
Visualizer(const armarx::DebugDrawerTopic &drawer, const std::string &voxelLayer="VoxelGrid")
Initialize with debug drawer and voxel grid.
virtual void drawVoxel(const VoxelVisuData &visu)
Draw a voxel.
void clearLayer()
Clear the layer.
virtual ~Visualizer()
Virtual destructor.
A 3D grid of voxels of type _VoxelT.
Definition VoxelGrid.hpp:50
Eigen::Vector3f getOrigin() const
Get the grid origin in the world frame (center of voxel [0 0 0]).
Eigen::Matrix32f getLocalBoundingBox() const
Get the local axis aligned bounding box of the grid (minimal/maximal values in columns).
Eigen::Vector3f getVoxelCenter(std::size_t index, bool local=false) const
Get the center of the voxel with the given index.
std::size_t numVoxels() const
Get the number of voxels in the grid.
Eigen::Vector3i getGridSizes() const
Get the grid size.
const std::vector< VoxelT > & getVoxels() const
Get the voxels.
Eigen::Vector3f getVoxelSizes() const
Get the voxel size.
Eigen::Vector3i getVoxelGridIndexMin() const
Get the minimal (along each axis) voxel grid index.
Eigen::Matrix4f getPose() const
Get the grid pose in the world frame.
Eigen::Quaternionf getOrientation() const
Get the grid orienation in the world frame.
Eigen::Vector3i getVoxelGridIndexMax() const
Get the maximal (along each axis) voxel grid index.
T min(T t1, T t2)
Definition gdiam.h:44
T max(T t1, T t2)
Definition gdiam.h:51
Quaternion< float, 0 > Quaternionf
Matrix< float, 3, 2 > Matrix32f
A 3x2 matrix.
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface > DebugDrawerInterfacePrx
Information about a voxel about to-be-drawn.
const std::string & name
The voxel grid.
const Eigen::Vector3f & pos
The voxel.
const VoxelT & voxel
The voxel's index.
const Eigen::Quaternionf & ori
The voxel's position.
const Eigen::Vector3f & extents
The voxel's orientation.
std::size_t index
A unique visu name for this voxel.