MRPT  1.9.9
CRandomFieldGridMap3D.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 "maps-precomp.h" // Precomp header
11 
14 #include <mrpt/system/CTicTac.h>
15 #include <fstream>
16 #include <mrpt/config.h>
17 
18 #if MRPT_HAS_VTK
19 #include <vtkStructuredGrid.h>
20 #include <vtkDoubleArray.h>
21 #include <vtkPointData.h>
22 #include <vtkVersion.h>
23 #include <vtkCellArray.h>
24 #include <vtkPoints.h>
25 #include <vtkXMLStructuredGridWriter.h>
26 #include <vtkSmartPointer.h>
27 #endif
28 
29 using namespace mrpt;
30 using namespace mrpt::maps;
31 using namespace mrpt::system;
32 using namespace std;
33 
35 
36 /*---------------------------------------------------------------
37  Constructor
38  ---------------------------------------------------------------*/
40  double x_min, double x_max, double y_min, double y_max, double z_min,
41  double z_max, double voxel_size, bool call_initialize_now)
42  : CDynamicGrid3D<TRandomFieldVoxel>(
43  x_min, x_max, y_min, y_max, z_min, z_max, voxel_size /*xy*/,
44  voxel_size /*z*/),
46 {
47  if (call_initialize_now) this->internal_initialize();
48 }
49 
50 /** Changes the size of the grid, erasing previous contents */
52  const double x_min, const double x_max, const double y_min,
53  const double y_max, const double z_min, const double z_max,
54  const double resolution_xy, const double resolution_z,
55  const TRandomFieldVoxel* fill_value)
56 {
57  MRPT_START;
58 
60  x_min, x_max, y_min, y_max, z_min, z_max, resolution_xy, resolution_z,
61  fill_value);
62  this->internal_initialize();
63 
64  MRPT_END;
65 }
66 
68  double new_x_min, double new_x_max, double new_y_min, double new_y_max,
69  double new_z_min, double new_z_max,
70  const TRandomFieldVoxel& defaultValueNewCells,
71  double additionalMarginMeters)
72 {
73  MRPT_START;
74 
76  new_x_min, new_x_max, new_y_min, new_y_max, new_z_min, new_z_max,
77  defaultValueNewCells, additionalMarginMeters);
78  this->internal_initialize(false);
79 
80  MRPT_END;
81 }
82 
84 {
86  internal_initialize();
87 }
88 
89 void CRandomFieldGridMap3D::internal_initialize(bool erase_prev_contents)
90 {
91  if (erase_prev_contents)
92  {
93  // Set the gridmap (m_map) to initial values:
94  TRandomFieldVoxel def(0, 0); // mean, std
95  fill(def);
96  }
97 
98  // Reset gmrf:
99  m_gmrf.setVerbosityLevel(this->getMinLoggingLevel());
100  if (erase_prev_contents)
101  {
102  m_gmrf.clear();
103  m_mrf_factors_activeObs.clear();
104  }
105  else
106  {
107  // Only remove priors, leave observations:
108  m_gmrf.clearAllConstraintsByType_Binary();
109  }
110  m_mrf_factors_priors.clear();
111 
112  // Initiating prior:
113  const size_t nodeCount = m_map.size();
114  ASSERT_EQUAL_(nodeCount, m_size_x * m_size_y * m_size_z);
115  ASSERT_EQUAL_(m_size_x_times_y, m_size_x * m_size_y);
116 
118  "[internal_initialize] Creating priors for GMRF with "
119  << nodeCount << " nodes." << std::endl);
120  CTicTac tictac;
121  tictac.Tic();
122 
123  m_mrf_factors_activeObs.resize(nodeCount); // Alloc space for obs
124  m_gmrf.initialize(nodeCount);
125 
126  ConnectivityDescriptor* custom_connectivity =
127  m_gmrf_connectivity
128  .get(); // Use a raw ptr to avoid the cost in the inner loops
129 
130  size_t cx = 0, cy = 0, cz = 0;
131  for (size_t j = 0; j < nodeCount; j++)
132  {
133  // add factors between this node and:
134  // 1) the right node: j +1
135  // 2) the back node: j+m_size_x
136  // 3) the top node: j+m_size_x*m_size*y
137  //-------------------------------------------------
138  const size_t c_idx_to_check[3] = {cx, cy, cz};
139  const size_t c_idx_to_check_limits[3] = {m_size_x - 1, m_size_y - 1,
140  m_size_z - 1};
141  const size_t c_neighbor_idx_incr[3] = {1, m_size_x, m_size_x_times_y};
142 
143  for (int dir = 0; dir < 3; dir++)
144  {
145  if (c_idx_to_check[dir] >= c_idx_to_check_limits[dir]) continue;
146 
147  const size_t i = j + c_neighbor_idx_incr[dir];
148  ASSERT_(i < nodeCount);
149 
150  double edge_lamdba = .0;
151  if (custom_connectivity != nullptr)
152  {
153  const bool is_connected =
154  custom_connectivity->getEdgeInformation(
155  this, cx, cy, cz, cx + (dir == 0 ? 1 : 0),
156  cy + (dir == 1 ? 1 : 0), cz + (dir == 2 ? 1 : 0),
157  edge_lamdba);
158  if (!is_connected) continue;
159  }
160  else
161  {
162  edge_lamdba = insertionOptions.GMRF_lambdaPrior;
163  }
164 
165  TPriorFactorGMRF new_prior(*this);
166  new_prior.node_id_i = i;
167  new_prior.node_id_j = j;
168  new_prior.Lambda = edge_lamdba;
169 
170  m_mrf_factors_priors.push_back(new_prior);
171  m_gmrf.addConstraint(
172  *m_mrf_factors_priors.rbegin()); // add to graph
173  }
174 
175  // Increment coordinates:
176  if (++cx >= m_size_x)
177  {
178  cx = 0;
179  if (++cy >= m_size_y)
180  {
181  cy = 0;
182  cz++;
183  }
184  }
185  } // end for "j"
186 
188  "[internal_initialize] Prior built in " << tictac.Tac() << " s\n"
189  << std::endl);
190 }
191 
192 /*---------------------------------------------------------------
193  TInsertionOptions
194  ---------------------------------------------------------------*/
196  : GMRF_lambdaPrior(0.01f), // [GMRF model] The information (Lambda) of
197  // fixed map constraints
198  GMRF_skip_variance(false)
199 {
200 }
201 
203  std::ostream& out) const
204 {
205  out << mrpt::format(
206  "GMRF_lambdaPrior = %f\n", GMRF_lambdaPrior);
207  out << mrpt::format(
208  "GMRF_skip_variance = %s\n",
209  GMRF_skip_variance ? "true" : "false");
210 }
211 
213  const mrpt::config::CConfigFileBase& iniFile, const std::string& section)
214 {
215  GMRF_lambdaPrior = iniFile.read_double(
216  section.c_str(), "GMRF_lambdaPrior", GMRF_lambdaPrior);
217  GMRF_skip_variance = iniFile.read_bool(
218  section.c_str(), "GMRF_skip_variance", GMRF_skip_variance);
219 }
220 
221 /** Save the current estimated grid to a VTK file (.vts) as a "structured grid".
222  * \sa saveAsCSV */
224  const std::string& fil) const
225 {
226  MRPT_START;
227 #if MRPT_HAS_VTK
228 
229  vtkStructuredGrid* vtkGrid = vtkStructuredGrid::New();
230  this->getAsVtkStructuredGrid(vtkGrid);
231 
232  // Write file
233  vtkSmartPointer<vtkXMLStructuredGridWriter> writer =
234  vtkSmartPointer<vtkXMLStructuredGridWriter>::New();
235  writer->SetFileName(fil.c_str());
236 
237 #if VTK_MAJOR_VERSION <= 5
238  writer->SetInput(vtkGrid);
239 #else
240  writer->SetInputData(vtkGrid);
241 #endif
242 
243  int ret = writer->Write();
244 
245  vtkGrid->Delete();
246 
247  return ret == 0;
248 #else
249  THROW_EXCEPTION("This method requires building MRPT against VTK!");
250 #endif
251  MRPT_END
252 }
253 
255  const std::string& filName_mean, const std::string& filName_stddev) const
256 {
257  std::ofstream f_mean, f_stddev;
258 
259  f_mean.open(filName_mean);
260  if (!f_mean.is_open())
261  {
262  return false;
263  }
264  else
265  {
266  f_mean << "x coord, y coord, z coord, scalar\n";
267  }
268 
269  if (!filName_stddev.empty())
270  {
271  f_stddev.open(filName_stddev);
272  if (!f_stddev.is_open())
273  {
274  return false;
275  }
276  else
277  {
278  f_mean << "x coord, y coord, z coord, scalar\n";
279  }
280  }
281 
282  const size_t nodeCount = m_map.size();
283  size_t cx = 0, cy = 0, cz = 0;
284  for (size_t j = 0; j < nodeCount; j++)
285  {
286  const double x = idx2x(cx), y = idx2y(cy), z = idx2z(cz);
287  const double mean_val = m_map[j].mean_value;
288  const double stddev_val = m_map[j].stddev_value;
289 
290  f_mean << mrpt::format("%f, %f, %f, %e\n", x, y, z, mean_val);
291 
292  if (f_stddev.is_open())
293  f_stddev << mrpt::format("%f, %f, %f, %e\n", x, y, z, stddev_val);
294 
295  // Increment coordinates:
296  if (++cx >= m_size_x)
297  {
298  cx = 0;
299  if (++cy >= m_size_y)
300  {
301  cy = 0;
302  cz++;
303  }
304  }
305  } // end for "j"
306 
307  return true;
308 }
309 
311 {
312  ASSERTMSG_(
313  !m_mrf_factors_activeObs.empty(),
314  "Cannot update a map with no observations!");
315 
316  Eigen::VectorXd x_incr, x_var;
318  x_incr, insertionOptions.GMRF_skip_variance ? NULL : &x_var);
319 
320  ASSERT_(size_t(m_map.size()) == size_t(x_incr.size()));
321  ASSERT_(
323  size_t(m_map.size()) == size_t(x_var.size()));
324 
325  // Update Mean-Variance in the base grid class
326  for (size_t j = 0; j < m_map.size(); j++)
327  {
328  m_map[j].mean_value += x_incr[j];
329  m_map[j].stddev_value =
330  insertionOptions.GMRF_skip_variance ? .0 : std::sqrt(x_var[j]);
331  }
332 }
333 
335  const ConnectivityDescriptor::Ptr& new_connectivity_descriptor)
336 {
337  m_gmrf_connectivity = new_connectivity_descriptor;
338 }
339 
341  /** [in] The value observed in the (x,y,z) position */
342  const double sensorReading,
343  /** [in] The variance of the sensor observation */
344  const double sensorVariance,
345  /** [in] The (x,y,z) location */
346  const mrpt::math::TPoint3D& point,
347  /** [in] Voxel interpolation method: how many voxels will be affected by the
348  reading */
349  const TVoxelInterpolationMethod method,
350  /** [in] Run a global map update after inserting this observatin
351  (algorithm-dependant) */
352  const bool update_map)
353 {
354  MRPT_START;
355 
356  ASSERT_ABOVE_(sensorVariance, .0);
357  ASSERTMSG_(
358  m_mrf_factors_activeObs.size() == m_map.size(),
359  "Trying to insert observation in uninitialized map (!)");
360 
361  const size_t cell_idx =
362  cellAbsIndexFromCXCYCZ(x2idx(point.x), y2idx(point.y), z2idx(point.z));
363  if (cell_idx == INVALID_VOXEL_IDX) return false;
364 
365  TObservationGMRF new_obs(*this);
366  new_obs.node_id = cell_idx;
367  new_obs.obsValue = sensorReading;
368  new_obs.Lambda = 1.0 / sensorVariance;
369 
370  m_mrf_factors_activeObs[cell_idx].push_back(new_obs);
372  *m_mrf_factors_activeObs[cell_idx].rbegin()); // add to graph
373 
374  if (update_map) this->updateMapEstimation();
375 
376  return true;
377 
378  MRPT_END;
379 }
380 
384 {
386 
387  // To assure compatibility: The size of each cell:
388  uint32_t n = static_cast<uint32_t>(sizeof(TRandomFieldVoxel));
389  out << n;
390 
391  // Save the map contents:
392  n = static_cast<uint32_t>(m_map.size());
393  out << n;
394 
395 // Save the "m_map": This requires special handling for big endian systems:
396 #if MRPT_IS_BIG_ENDIAN
397  for (uint32_t i = 0; i < n; i++)
398  out << m_map[i].mean_value << m_map[i].stddev_value;
399 #else
400  // Little endian: just write all at once:
401  out.WriteBuffer(&m_map[0], sizeof(m_map[0]) * m_map.size());
402 #endif
403 
406 }
407 
410 {
411  switch (version)
412  {
413  case 0:
414  {
416 
417  // To assure compatibility: The size of each cell:
418  uint32_t n;
419  in >> n;
420 
421  ASSERT_EQUAL_(n, static_cast<uint32_t>(sizeof(TRandomFieldVoxel)));
422  // Load the map contents:
423  in >> n;
424  m_map.resize(n);
425 
426 // Read the note in writeToStream()
427 #if MRPT_IS_BIG_ENDIAN
428  for (uint32_t i = 0; i < n; i++)
429  in >> m_map[i].mean_value >> m_map[i].stddev_value;
430 #else
431  // Little endian: just read all at once:
432  in.ReadBuffer(&m_map[0], sizeof(m_map[0]) * m_map.size());
433 #endif
436  }
437  break;
438  default:
440  };
441 }
442 
444  vtkStructuredGrid* output, const std::string& label_mean,
445  const std::string& label_stddev) const
446 {
447  MRPT_START;
448 #if MRPT_HAS_VTK
449 
450  const size_t nx = this->getSizeX(), ny = this->getSizeY(),
451  nz = this->getSizeZ();
452 
453  const int num_values = nx * ny * nz;
454 
455  vtkPoints* newPoints = vtkPoints::New();
456 
457  vtkDoubleArray* newData = vtkDoubleArray::New();
458  newData->SetNumberOfComponents(3);
459  newData->SetNumberOfTuples(num_values);
460 
461  vtkDoubleArray* mean_arr = vtkDoubleArray::New();
462  mean_arr->SetNumberOfComponents(1);
463  mean_arr->SetNumberOfTuples(num_values);
464 
465  vtkDoubleArray* std_arr = vtkDoubleArray::New();
466  std_arr->SetNumberOfComponents(1);
467  std_arr->SetNumberOfTuples(num_values);
468 
469  vtkIdType numtuples = newData->GetNumberOfTuples();
470 
471  {
472  size_t cx = 0, cy = 0, cz = 0;
473  for (vtkIdType cc = 0; cc < numtuples; cc++)
474  {
475  const double x = idx2x(cx), y = idx2y(cy), z = idx2z(cz);
476 
477  newData->SetComponent(cc, 0, x);
478  newData->SetComponent(cc, 1, y);
479  newData->SetComponent(cc, 2, z);
480 
481  mean_arr->SetComponent(cc, 0, m_map[cc].mean_value);
482  std_arr->SetComponent(cc, 0, m_map[cc].stddev_value);
483 
484  // Increment coordinates:
485  if (++cx >= m_size_x)
486  {
487  cx = 0;
488  if (++cy >= m_size_y)
489  {
490  cy = 0;
491  cz++;
492  }
493  }
494  }
495  ASSERT_(size_t(m_map.size()) == size_t(numtuples));
496  }
497 
498  newPoints->SetData(newData);
499  newData->Delete();
500 
501  output->SetExtent(0, nx - 1, 0, ny - 1, 0, nz - 1);
502  output->SetPoints(newPoints);
503  newPoints->Delete();
504 
505  mean_arr->SetName(label_mean.c_str());
506  std_arr->SetName(label_stddev.c_str());
507  output->GetPointData()->AddArray(mean_arr);
508  output->GetPointData()->AddArray(std_arr);
509 
510  mean_arr->Delete();
511  std_arr->Delete();
512 
513 #else
514  THROW_EXCEPTION("This method requires building MRPT against VTK!");
515 #endif // VTK
516  MRPT_END;
517 }
518 
519 // ============ TObservationGMRF ===========
521 {
522  return m_parent->m_map[this->node_id].mean_value - this->obsValue;
523 }
525 {
526  return this->Lambda;
527 }
529 {
530  dr_dx = 1.0;
531 }
532 // ============ TPriorFactorGMRF ===========
534 {
535  return m_parent->m_map[this->node_id_i].mean_value -
536  m_parent->m_map[this->node_id_j].mean_value;
537 }
539 {
540  return this->Lambda;
541 }
543  double& dr_dx_i, double& dr_dx_j) const
544 {
545  dr_dx_i = +1.0;
546  dr_dx_j = -1.0;
547 }
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
auto dir
This class allows loading and storing values and vectors of different types from a configuration text...
virtual void resize(double new_x_min, double new_x_max, double new_y_min, double new_y_max, double new_z_min, double new_z_max, const TRandomFieldVoxel &defaultValueNewCells, double additionalMarginMeters=2.0)
Changes the size of the grid, maintaining previous contents.
std::vector< TRandomFieldVoxel > m_map
The cells.
void dyngridcommon_writeToStream(ARCHIVE &out) const
Serialization of all parameters, except the contents of each voxel (responsability of the derived cla...
double idx2x(int cx) const
Transform a voxel index into a coordinate value of the voxel central point.
int x2idx(double x) const
Transform a coordinate values into voxel indexes.
size_t cellAbsIndexFromCXCYCZ(const int cx, const int cy, const int cz) const
Gets the absolute index of a voxel in the linear container m_map[] from its cx,cy,...
virtual void clear()
Erase the contents of all the cells, setting them to their default values (default ctor).
void dyngridcommon_readFromStream(ARCHIVE &in)
Serialization of all parameters, except the contents of each voxel (responsability of the derived cla...
void addConstraint(const UnaryFactorVirtualBase &listOfConstraints)
Insert constraints into the GMRF problem.
void updateEstimation(Eigen::VectorXd &solved_x_inc, Eigen::VectorXd *solved_variances=nullptr)
CRandomFieldGridMap3D represents a 3D regular grid where each voxel is associated one real-valued pro...
std::vector< std::deque< TObservationGMRF > > m_mrf_factors_activeObs
Vector with the active observations and their respective Information, for each map cell.
bool insertIndividualReading(const double sensorReading, const double sensorVariance, const mrpt::math::TPoint3D &point, const TVoxelInterpolationMethod method, const bool update_map)
Direct update of the map with a reading in a given position of the map.
void updateMapEstimation()
Run the method-specific procedure required to ensure that the mean & variances are up-to-date with al...
ConnectivityDescriptor::Ptr m_gmrf_connectivity
Empty: default.
void serializeFrom(mrpt::serialization::CArchive &in, uint8_t serial_version) override
Pure virtual method for reading (deserializing) from an abstract archive.
virtual void setSize(const double x_min, const double x_max, const double y_min, const double y_max, const double z_min, const double z_max, const double resolution_xy, const double resolution_z=-1.0, const TRandomFieldVoxel *fill_value=nullptr) override
Changes the size of the grid, erasing previous contents.If resolution_z<0, the same resolution will b...
uint8_t serializeGetVersion() const override
Must return the current versioning number of the object.
void internal_initialize(bool erase_prev_contents=true)
Internal: called called after each change of resolution, size, etc.
void clear() override
Erases all added observations and start again with an empty gridmap.
mrpt::graphs::ScalarFactorGraph m_gmrf
bool saveAsVtkStructuredGrid(const std::string &fil) const
Save the current estimated grid to a VTK file (.vts) as a "structured grid".
virtual void resize(double new_x_min, double new_x_max, double new_y_min, double new_y_max, double new_z_min, double new_z_max, const TRandomFieldVoxel &defaultValueNewvoxels, double additionalMarginMeters=2.0) override
Changes the size of the grid, maintaining previous contents.
bool saveAsCSV(const std::string &filName_mean, const std::string &filName_stddev=std::string()) const
Save the current estimated mean values to a CSV file (compatible with Paraview) with fields x y z mea...
void setVoxelsConnectivity(const ConnectivityDescriptor::Ptr &new_connectivity_descriptor)
Sets a custom object to define the connectivity between voxels.
void serializeTo(mrpt::serialization::CArchive &out) const override
Pure virtual method for writing (serializing) to an abstract archive.
void getAsVtkStructuredGrid(vtkStructuredGrid *output, const std::string &label_mean=std::string("mean"), const std::string &label_stddev=std::string("stddev")) const
Returns the 3D grid contents as an VTK grid.
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:53
void WriteBuffer(const void *Buffer, size_t Count)
Writes a block of bytes to the stream from Buffer.
Definition: CArchive.cpp:48
Versatile class for consistent logging and management of output messages.
A high-performance stopwatch, with typical resolution of nanoseconds.
void Tic() noexcept
Starts the stopwatch.
Definition: CTicTac.cpp:79
double Tac() noexcept
Stops the stopwatch.
Definition: CTicTac.cpp:90
EIGEN_STRONG_INLINE void fill(const Scalar v)
Definition: eigen_plugins.h:46
EIGEN_STRONG_INLINE void setSize(size_t row, size_t col)
Changes the size of matrix, maintaining its previous content as possible and padding with zeros where...
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure.
Definition: exceptions.h:153
#define ASSERT_ABOVE_(__A, __B)
Definition: exceptions.h:171
#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
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:41
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism.
Definition: exceptions.h:101
GLenum GLsizei n
Definition: glext.h:5074
GLfloat GLfloat nz
Definition: glext.h:6292
GLfloat ny
Definition: glext.h:6292
GLenum GLint GLint y
Definition: glext.h:3538
GLfloat GLfloat GLfloat GLfloat nx
Definition: glext.h:6296
GLuint in
Definition: glext.h:7274
GLenum GLint x
Definition: glext.h:3538
GLdouble GLdouble z
Definition: glext.h:3872
GLsizei const GLchar ** string
Definition: glext.h:4101
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:16
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
unsigned __int32 uint32_t
Definition: rptypes.h:47
unsigned char uint8_t
Definition: rptypes.h:41
Base class for user-supplied objects capable of describing voxels connectivity, used to build prior f...
virtual bool getEdgeInformation(const CRandomFieldGridMap3D *parent, size_t icx, size_t icy, size_t icz, size_t jcx, size_t jcy, size_t jcz, double &out_edge_information)=0
Implement the check of whether node i=(icx,icy,icz) is connected with node j=(jcx,...
void dumpToTextStream(std::ostream &out) const
See utils::CLoadableOptions.
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string &section)
See utils::CLoadableOptions.
bool GMRF_skip_variance
(Default:false) Skip the computation of the variance, just compute the mean
double GMRF_lambdaPrior
The information (Lambda) of fixed map constraints.
void evalJacobian(double &dr_dx) const override
Returns the derivative of the residual wrt the node value.
double evaluateResidual() const override
Return the residual/error of this observation.
double getInformation() const override
Return the inverse of the variance of this constraint.
double Lambda
"Information" of the observation (=inverse of the variance)
double Lambda
"Information" of the observation (=inverse of the variance)
double evaluateResidual() const override
Return the residual/error of this observation.
void evalJacobian(double &dr_dx_i, double &dr_dx_j) const override
Returns the derivative of the residual wrt the node values.
double getInformation() const override
Return the inverse of the variance of this constraint.
The contents of each voxel in a CRandomFieldGridMap3D map.
Lightweight 3D point.
double x
X,Y,Z coordinates.
#define MRPT_LOG_DEBUG_STREAM(__CONTENTS)
Use: MRPT_LOG_DEBUG_STREAM("Var=" << value << " foo=" << foo_var);
string iniFile(myDataDir+string("benchmark-options.ini"))



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