MRPT  1.9.9
CMesh.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "opengl-precomp.h" // Precompiled header
11 
12 #include <mrpt/poses/CPose3D.h>
13 #include <mrpt/opengl/CMesh.h>
15 #include <mrpt/img/color_maps.h>
17 
18 #include "opengl_internals.h"
19 
20 using namespace mrpt;
21 using namespace mrpt::opengl;
22 using namespace mrpt::poses;
23 using namespace mrpt::math;
24 using namespace std;
25 using mrpt::img::CImage;
26 
28 
30  bool enableTransparency, float xMin_p, float xMax_p, float yMin_p,
31  float yMax_p)
32  : m_textureImage(0, 0),
33  m_enableTransparency(enableTransparency),
34  m_colorFromZ(false),
35  m_isWireFrame(false),
36  m_isImage(false),
37  Z(0, 0),
38  mask(0, 0),
39  U(0, 0),
40  V(0, 0),
41  C(0, 0),
42  C_r(0, 0),
43  C_g(0, 0),
44  C_b(0, 0),
45  m_colorMap(mrpt::img::cmHOT),
46  m_modified_Z(true),
47  m_modified_Image(false),
48  xMin(xMin_p),
49  xMax(xMax_p),
50  yMin(yMin_p),
51  yMax(yMax_p),
52  trianglesUpToDate(false)
53 {
54  m_color.A = 255;
55  m_color.R = 0;
56  m_color.G = 0;
57  m_color.B = 150;
58 }
59 
62 {
64 
65  // Remember:
66  /** List of triangles in the mesh */
67  // mutable
68  // std::vector<std::pair<CSetOfTriangles::TTriangle,TTriangleVertexIndices>
69  // > actualMesh;
70  /** The accumulated normals & counts for each vertex, so normals can be
71  * averaged. */
72  // mutable std::vector<std::pair<mrpt::math::TPoint3D,size_t> >
73  // vertex_normals;
74 
75  const auto cols = Z.cols();
76  const auto rows = Z.rows();
77 
78  actualMesh.clear();
79  if (cols == 0 && rows == 0) return; // empty mesh
80 
81  ASSERT_(cols > 0 && rows > 0);
82  ASSERT_(xMax > xMin && yMax > yMin);
83 
84  // we have 1 more row & col of vertices than of triangles:
85  vertex_normals.assign(
86  (1 + cols) * (1 + rows),
87  std::pair<TPoint3D, size_t>(TPoint3D(0, 0, 0), 0));
88 
89  float cR[3], cG[3], cB[3], cA[3];
90  cA[0] = cA[1] = cA[2] = m_color.A / 255.f;
91 
92  if ((m_colorFromZ) || (m_isImage))
93  {
94  updateColorsMatrix();
95  }
96  else
97  {
98  cR[0] = cR[1] = cR[2] = m_color.R / 255.f;
99  cG[0] = cG[1] = cG[2] = m_color.G / 255.f;
100  cB[0] = cB[1] = cB[2] = m_color.B / 255.f;
101  }
102 
103  bool useMask = false;
104  if (mask.cols() != 0 && mask.rows() != 0)
105  {
106  ASSERT_(mask.cols() == cols && mask.rows() == rows);
107  useMask = true;
108  }
109  const float sCellX = (xMax - xMin) / (rows - 1);
110  const float sCellY = (yMax - yMin) / (cols - 1);
111 
113  for (int iX = 0; iX < rows - 1; iX++)
114  for (int iY = 0; iY < cols - 1; iY++)
115  {
116  if (useMask && (!mask(iX, iY) || !mask(iX + 1, iY + 1))) continue;
117  tri.x[0] = xMin + iX * sCellX;
118  tri.y[0] = yMin + iY * sCellY;
119  tri.z[0] = Z(iX, iY);
120  tri.x[2] = tri.x[0] + sCellX;
121  tri.y[2] = tri.y[0] + sCellY;
122  tri.z[2] = Z(iX + 1, iY + 1);
123 
124  // Vertex indices:
126  tvi.vind[0] = iX + rows * iY;
127  tvi.vind[2] = (iX + 1) + rows * (iY + 1);
128 
129  // Each quadrangle has up to 2 triangles:
130  // [0]
131  // |
132  // |
133  // [1]--[2]
134  // Order: 0,1,2
135  if (!useMask || mask(iX + 1, iY))
136  {
137  tri.x[1] = tri.x[2];
138  tri.y[1] = tri.y[0];
139  tri.z[1] = Z(iX + 1, iY);
140  for (int i = 0; i < 3; i++)
141  tri.a[i] = cA[i]; // Assign alpha channel
142 
143  if (m_colorFromZ)
144  {
145  colormap(
146  m_colorMap, C(iX, iY), tri.r[0], tri.g[0], tri.b[0]);
147  colormap(
148  m_colorMap, C(iX + 1, iY), tri.r[1], tri.g[1],
149  tri.b[1]);
150  colormap(
151  m_colorMap, C(iX + 1, iY + 1), tri.r[2], tri.g[2],
152  tri.b[2]);
153  }
154  else if (m_isImage)
155  {
156  if (m_textureImage.isColor())
157  {
158  tri.r[0] = tri.r[1] = tri.r[2] = C_r(iX, iY);
159  tri.g[0] = tri.g[1] = tri.g[2] = C_g(iX, iY);
160  tri.b[0] = tri.b[1] = tri.b[2] = C_b(iX, iY);
161  }
162  else
163  {
164  tri.r[0] = tri.r[1] = tri.r[2] = C(iX, iY);
165  tri.g[0] = tri.g[1] = tri.g[2] = C(iX, iY);
166  tri.b[0] = tri.b[1] = tri.b[2] = C(iX, iY);
167  }
168  }
169  else
170  {
171  tri.r[0] = tri.r[1] = tri.r[2] = m_color.R / 255.f;
172  tri.g[0] = tri.g[1] = tri.g[2] = m_color.G / 255.f;
173  tri.b[0] = tri.b[1] = tri.b[2] = m_color.B / 255.f;
174  }
175 
176  // Compute normal of this triangle, and add it up to the 3
177  // neighboring vertices:
178  // A = P1 - P0, B = P2 - P0
179  float ax = tri.x[1] - tri.x[0];
180  float bx = tri.x[2] - tri.x[0];
181  float ay = tri.y[1] - tri.y[0];
182  float by = tri.y[2] - tri.y[0];
183  float az = tri.z[1] - tri.z[0];
184  float bz = tri.z[2] - tri.z[0];
185  const TPoint3D this_normal(
186  ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx);
187 
188  // Vertex indices:
189  tvi.vind[1] = iX + 1 + rows * iY;
190 
191  // Add triangle:
192  actualMesh.push_back(
193  std::pair<
195  tri, tvi));
196 
197  // For averaging normals:
198  for (int k = 0; k < 3; k++)
199  {
200  vertex_normals[tvi.vind[k]].first += this_normal;
201  vertex_normals[tvi.vind[k]].second++;
202  }
203  }
204  // 2:
205  // [0]--[1->2]
206  // \ |
207  // \|
208  // [2->1]
209  // Order: 0,2,1
210  if (!useMask || mask(iX, iY + 1))
211  {
212  tri.x[1] = tri.x[2];
213  tri.y[1] = tri.y[2];
214  tri.z[1] = tri.z[2];
215 
216  tri.x[2] = tri.x[0];
217  // tri.y[2]=tri.y[1];
218  tri.z[2] = Z(iX, iY + 1);
219  if (m_colorFromZ)
220  {
221  colormap(
222  m_colorMap, C(iX, iY), tri.r[0], tri.g[0], tri.b[0]);
223  colormap(
224  m_colorMap, C(iX + 1, iY + 1), tri.r[1], tri.g[1],
225  tri.b[1]);
226  colormap(
227  m_colorMap, C(iX, iY + 1), tri.r[2], tri.g[2],
228  tri.b[2]);
229  }
230  else if (m_isImage)
231  {
232  if (m_textureImage.isColor())
233  {
234  tri.r[0] = tri.r[1] = tri.r[2] = C_r(iX, iY);
235  tri.g[0] = tri.g[1] = tri.g[2] = C_g(iX, iY);
236  tri.b[0] = tri.b[1] = tri.b[2] = C_b(iX, iY);
237  }
238  else
239  {
240  tri.r[0] = tri.r[1] = tri.r[2] = C(iX, iY);
241  tri.g[0] = tri.g[1] = tri.g[2] = C(iX, iY);
242  tri.b[0] = tri.b[1] = tri.b[2] = C(iX, iY);
243  }
244  }
245  else
246  {
247  tri.r[0] = tri.r[1] = tri.r[2] = m_color.R / 255.f;
248  tri.g[0] = tri.g[1] = tri.g[2] = m_color.G / 255.f;
249  tri.b[0] = tri.b[1] = tri.b[2] = m_color.B / 255.f;
250  }
251 
252  // Compute normal of this triangle, and add it up to the 3
253  // neighboring vertices:
254  // A = P1 - P0, B = P2 - P0
255  float ax = tri.x[1] - tri.x[0];
256  float bx = tri.x[2] - tri.x[0];
257  float ay = tri.y[1] - tri.y[0];
258  float by = tri.y[2] - tri.y[0];
259  float az = tri.z[1] - tri.z[0];
260  float bz = tri.z[2] - tri.z[0];
261  const TPoint3D this_normal(
262  ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx);
263 
264  // Vertex indices:
265  tvi.vind[1] = tvi.vind[2];
266  tvi.vind[2] = iX + rows * (iY + 1);
267 
268  // Add triangle:
269  actualMesh.push_back(
270  std::pair<
272  tri, tvi));
273 
274  // For averaging normals:
275  for (int k = 0; k < 3; k++)
276  {
277  vertex_normals[tvi.vind[k]].first += this_normal;
278  vertex_normals[tvi.vind[k]].second++;
279  }
280  }
281  }
282 
283  // Average normals:
284  for (size_t i = 0; i < vertex_normals.size(); i++)
285  {
286  const size_t N = vertex_normals[i].second;
287  if (N > 0) vertex_normals[i].first *= 1.0 / N;
288  }
289 
290  trianglesUpToDate = true;
291  polygonsUpToDate = false;
292 }
293 
294 /*---------------------------------------------------------------
295  render
296  ---------------------------------------------------------------*/
297 void CMesh::render_dl() const
298 {
299 #if MRPT_HAS_OPENGL_GLUT
300  if (m_enableTransparency)
301  {
305  }
306  else
307  {
310  }
311  glEnable(GL_NORMALIZE); // So the GPU normalizes the normals instead of
312  // doing it in the CPU
315  if (!trianglesUpToDate) updateTriangles();
316  if (!m_isWireFrame) glBegin(GL_TRIANGLES);
317  for (size_t i = 0; i < actualMesh.size(); i++)
318  {
319  const CSetOfTriangles::TTriangle& t = actualMesh[i].first;
320  const TTriangleVertexIndices& tvi = actualMesh[i].second;
321 
322  if (m_isWireFrame)
323  {
324  glDisable(GL_LIGHTING); // Disable lights when drawing lines
326  }
327  for (int k = 0; k < 3; k++)
328  {
329  const mrpt::math::TPoint3D& n = vertex_normals[tvi.vind[k]].first;
330  glNormal3f(n.x, n.y, n.z);
331  glColor4f(t.r[k], t.g[k], t.b[k], t.a[k]);
332  glVertex3f(t.x[k], t.y[k], t.z[k]);
333  }
334  if (m_isWireFrame)
335  {
336  glEnd();
338  }
339  }
340  if (!m_isWireFrame) glEnd();
344 #endif
345 }
346 
347 /*---------------------------------------------------------------
348  assignImage
349  ---------------------------------------------------------------*/
351 {
352  MRPT_START
353 
354  // Make a copy:
355  m_textureImage = img;
356 
357  // Delete content in Z
358  Z.setSize(img.getHeight(), img.getWidth());
359  Z.assign(0);
360 
361  m_modified_Image = true;
362  m_enableTransparency = false;
363  m_colorFromZ = false;
364  m_isImage = true;
365  trianglesUpToDate = false;
366 
368 
369  MRPT_END
370 }
371 
374 {
375  MRPT_START
376 
377  ASSERT_(
378  (img.getWidth() == static_cast<size_t>(in_Z.cols())) &&
379  (img.getHeight() == static_cast<size_t>(in_Z.rows())));
380 
381  Z = in_Z;
382 
383  // Make a copy:
384  m_textureImage = img;
385 
386  m_modified_Image = true;
387  m_enableTransparency = false;
388  m_colorFromZ = false;
389  m_isImage = true;
390  trianglesUpToDate = false;
391 
393 
394  MRPT_END
395 }
396 
397 uint8_t CMesh::serializeGetVersion() const { return 1; }
399 {
400  writeToStreamRender(out);
401 
402  // Version 0:
403  out << m_textureImage;
404  out << xMin << xMax << yMin << yMax;
405  out << Z << U << V << mask; // We don't need to serialize C, it's computed
406  out << m_enableTransparency;
407  out << m_colorFromZ;
408  // new in v1
409  out << m_isWireFrame;
410  out << int16_t(m_colorMap);
411 }
412 
414 {
415  switch (version)
416  {
417  case 0:
418  case 1:
419  {
420  readFromStreamRender(in);
421 
422  in >> m_textureImage;
423 
424  in >> xMin;
425  in >> xMax;
426  in >> yMin;
427  in >> yMax;
428 
429  in >> Z >> U >> V >> mask;
430  in >> m_enableTransparency;
431  in >> m_colorFromZ;
432 
433  if (version >= 1)
434  {
435  in >> m_isWireFrame;
436  int16_t i;
437  in >> i;
438  m_colorMap = mrpt::img::TColormap(i);
439  }
440  else
441  m_isWireFrame = false;
442 
443  m_modified_Z = true;
444  }
445  trianglesUpToDate = false;
446  break;
447  default:
449  };
450  trianglesUpToDate = false;
452 }
453 
455 {
456  if ((!m_modified_Z) && (!m_modified_Image)) return;
457 
459 
460  if (m_isImage)
461  {
462  const int cols = m_textureImage.getWidth();
463  const int rows = m_textureImage.getHeight();
464 
465  if ((cols != Z.cols()) || (rows != Z.rows()))
466  printf("\nTexture Image and Z sizes have to be equal");
467 
468  else if (m_textureImage.isColor())
469  {
470  C_r.setSize(rows, cols);
471  C_g.setSize(rows, cols);
472  C_b.setSize(rows, cols);
473  m_textureImage.getAsRGBMatrices(C_r, C_g, C_b);
474  }
475  else
476  {
477  C.setSize(rows, cols);
478  m_textureImage.getAsMatrix(C);
479  }
480  }
481  else
482  {
483  const size_t cols = Z.cols();
484  const size_t rows = Z.rows();
485  C.setSize(rows, cols);
486 
487  // Color is proportional to height:
488  C = Z;
489 
490  // If mask is empty -> Normalize the whole mesh
491  if (mask.empty()) C.normalize(0.01f, 0.99f);
492 
493  // Else -> Normalize color ignoring masked-out cells:
494  else
495  {
496  float val_max = -std::numeric_limits<float>::max(),
497  val_min = std::numeric_limits<float>::max();
498  bool any_valid = false;
499 
500  for (size_t c = 0; c < cols; c++)
501  for (size_t r = 0; r < rows; r++)
502  {
503  if (!mask(r, c)) continue;
504  any_valid = true;
505  const float val = C(r, c);
506  mrpt::keep_max(val_max, val);
507  mrpt::keep_min(val_min, val);
508  }
509 
510  if (any_valid)
511  {
512  float minMaxDelta = val_max - val_min;
513  if (minMaxDelta == 0) minMaxDelta = 1;
514  const float minMaxDelta_ = 1.0f / minMaxDelta;
515  C.array() = (C.array() - val_min) * minMaxDelta_;
516  }
517  }
518  }
519 
520  m_modified_Image = false;
521  m_modified_Z = false;
522  trianglesUpToDate = false;
523 }
524 
526 {
527  Z = in_Z;
528  m_modified_Z = true;
529  trianglesUpToDate = false;
530 
531  // Delete previously loaded images
532  m_isImage = false;
533 
535 }
536 
538 {
539  mask = in_mask;
540  trianglesUpToDate = false;
542 }
543 
547 {
548  U = in_U;
549  V = in_V;
551 }
552 
553 bool CMesh::traceRay(const mrpt::poses::CPose3D& o, double& dist) const
554 {
555  if (!trianglesUpToDate || !polygonsUpToDate) updatePolygons();
556  return mrpt::math::traceRay(tmpPolys, (o - this->m_pose).asTPose(), dist);
557 }
558 
561  const std::pair<CSetOfTriangles::TTriangle, CMesh::TTriangleVertexIndices>&
562  p)
563 {
564  const CSetOfTriangles::TTriangle& t = p.first;
565  for (size_t i = 0; i < 3; i++)
566  {
567  tmpPoly[i].x = t.x[i];
568  tmpPoly[i].y = t.y[i];
569  tmpPoly[i].z = t.z[i];
570  }
572 }
573 
575 {
576  if (!trianglesUpToDate) updateTriangles();
577  size_t N = actualMesh.size();
578  tmpPolys.resize(N);
579  transform(
580  actualMesh.begin(), actualMesh.end(), tmpPolys.begin(),
582  polygonsUpToDate = true;
584 }
585 
587  mrpt::math::TPoint3D& bb_min, mrpt::math::TPoint3D& bb_max) const
588 {
589  bb_min.x = xMin;
590  bb_min.y = yMin;
591  bb_min.z = Z.minCoeff();
592 
593  bb_max.x = xMax;
594  bb_max.y = yMax;
595  bb_max.z = Z.maxCoeff();
596 
597  // Convert to coordinates of my parent:
598  m_pose.composePoint(bb_min, bb_min);
599  m_pose.composePoint(bb_max, bb_max);
600 }
mrpt::math::TPolygonWithPlane createPolygonFromTriangle(const std::pair< CSetOfTriangles::TTriangle, CMesh::TTriangleVertexIndices > &p)
Definition: CMesh.cpp:560
static math::TPolygon3D tmpPoly(3)
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:131
3D polygon, inheriting from std::vector<TPoint3D>
Slightly heavyweight type to speed-up calculations with polygons in 3D.
Definition: geometry.h:30
A planar (XY) grid where each cell has an associated height and, optionally, a texture map.
Definition: CMesh.h:38
bool traceRay(const mrpt::poses::CPose3D &o, double &dist) const override
Trace ray.
Definition: CMesh.cpp:553
void updateColorsMatrix() const
Called internally to assure C is updated.
Definition: CMesh.cpp:454
virtual ~CMesh()
Private, virtual destructor: only can be deleted from smart pointers.
Definition: CMesh.cpp:60
uint8_t serializeGetVersion() const override
Must return the current versioning number of the object.
Definition: CMesh.cpp:397
void getBoundingBox(mrpt::math::TPoint3D &bb_min, mrpt::math::TPoint3D &bb_max) const override
Evaluates the bounding box of this object (including possible children) in the coordinate frame of th...
Definition: CMesh.cpp:586
void updatePolygons() const
Definition: CMesh.cpp:574
void serializeTo(mrpt::serialization::CArchive &out) const override
Pure virtual method for writing (serializing) to an abstract archive.
Definition: CMesh.cpp:398
void setZ(const mrpt::math::CMatrixTemplateNumeric< float > &in_Z)
This method sets the matrix of heights for each position (cell) in the mesh grid.
Definition: CMesh.cpp:525
void assignImage(const mrpt::img::CImage &img)
Assigns a texture image, and disable transparency.
Definition: CMesh.cpp:350
void updateTriangles() const
Called internally to assure the triangle list is updated.
Definition: CMesh.cpp:61
void assignImageAndZ(const mrpt::img::CImage &img, const mrpt::math::CMatrixTemplateNumeric< float > &in_Z)
Assigns a texture image and Z simultaneously, and disable transparency.
Definition: CMesh.cpp:372
void setMask(const mrpt::math::CMatrixTemplateNumeric< float > &in_mask)
This method sets the boolean mask of valid heights for each position (cell) in the mesh grid.
Definition: CMesh.cpp:537
void render_dl() const override
Render.
Definition: CMesh.cpp:297
void setUV(const mrpt::math::CMatrixTemplateNumeric< float > &in_U, const mrpt::math::CMatrixTemplateNumeric< float > &in_V)
Sets the (u,v) texture coordinates (in range [0,1]) for each cell.
Definition: CMesh.cpp:544
void serializeFrom(mrpt::serialization::CArchive &in, uint8_t serial_version) override
Pure virtual method for reading (deserializing) from an abstract archive.
Definition: CMesh.cpp:413
A renderizable object suitable for rendering with OpenGL's display lists.
EIGEN_STRONG_INLINE void notifyChange() const
Must be called to notify that the object has changed (so, the display list must be updated)
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:87
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:53
#define MRPT_START
Definition: exceptions.h:262
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:113
#define MRPT_END
Definition: exceptions.h:266
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
Definition: exceptions.h:90
GLAPI void GLAPIENTRY glEnable(GLenum cap)
#define GL_DEPTH_TEST
Definition: glew.h:401
#define GL_SRC_ALPHA
Definition: glew.h:286
#define GL_NORMALIZE
Definition: glew.h:416
#define GL_SMOOTH
Definition: glew.h:635
#define GL_TRIANGLES
Definition: glew.h:276
GLAPI void GLAPIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor)
GLAPI void GLAPIENTRY glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz)
GLAPI void GLAPIENTRY glBegin(GLenum mode)
GLAPI void GLAPIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z)
#define GL_COLOR_MATERIAL
Definition: glew.h:392
#define GL_BLEND
Definition: glew.h:432
#define GL_ONE_MINUS_SRC_ALPHA
Definition: glew.h:287
GLAPI void GLAPIENTRY glEnd(void)
#define GL_LINE_LOOP
Definition: glew.h:274
GLAPI void GLAPIENTRY glDisable(GLenum cap)
GLAPI void GLAPIENTRY glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
GLAPI void GLAPIENTRY glShadeModel(GLenum mode)
#define GL_LIGHTING
Definition: glew.h:385
GLdouble GLdouble t
Definition: glext.h:3689
GLenum GLsizei n
Definition: glext.h:5074
GLuint GLenum GLenum transform
Definition: glext.h:6975
GLbyte GLbyte bz
Definition: glext.h:6105
const GLubyte * c
Definition: glext.h:6313
GLenum GLint GLuint mask
Definition: glext.h:4050
GLuint in
Definition: glext.h:7274
GLint GLvoid * img
Definition: glext.h:3763
GLfloat GLfloat p
Definition: glext.h:6305
GLdouble GLdouble GLdouble r
Definition: glext.h:3705
GLbyte by
Definition: glext.h:6105
void colormap(const TColormap &color_map, const float color_index, float &r, float &g, float &b)
Transform a float number in the range [0,1] into RGB components.
Definition: color_maps.cpp:113
TColormap
Different colormaps for use in mrpt::img::colormap()
Definition: color_maps.h:30
@ cmHOT
[New in MRPT 1.5.0]
Definition: color_maps.h:35
bool traceRay(const std::vector< TPolygonWithPlane > &vec, const mrpt::math::TPose3D &pose, double &dist)
Fast ray tracing method using polygons' properties.
Definition: geometry.cpp:2590
int val
Definition: mrpt_jpeglib.h:955
This base provides a set of functions for maths stuff.
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:16
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
mrpt::img::CImage CImage
Definition: utils/CImage.h:5
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void keep_min(T &var, const K test_val)
If the second argument is below the first one, set the first argument to this lower value.
void keep_max(T &var, const K test_val)
If the second argument is above the first one, set the first argument to this higher value.
__int16 int16_t
Definition: rptypes.h:43
unsigned char uint8_t
Definition: rptypes.h:41
Lightweight 3D point.
double x
X,Y,Z coordinates.



Page generated by Doxygen 1.9.1 for MRPT 1.9.9 Git: 814d80880 Fri Aug 24 01:51:28 2018 +0200 at mar 26 may 2026 12:30:59 CEST