MRPT  1.9.9
CAngularObservationMesh.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "maps-precomp.h" // Precomp header
11 
13 #include <mrpt/poses/CPoint3D.h>
16 
17 #if MRPT_HAS_OPENGL_GLUT
18 #ifdef _WIN32
19 // Windows:
20 #include <windows.h>
21 #endif
22 
23 #ifdef __APPLE__
24 #include <OpenGL/gl.h>
25 #else
26 #include <GL/gl.h>
27 #endif
28 #endif
29 
30 // Include libraries in linking:
31 #if MRPT_HAS_OPENGL_GLUT && defined(_WIN32)
32 // WINDOWS:
33 #if defined(_MSC_VER)
34 #pragma comment(lib, "opengl32.lib")
35 #pragma comment(lib, "GlU32.lib")
36 #endif
37 #endif // MRPT_HAS_OPENGL_GLUT
38 
39 using namespace mrpt;
40 using namespace mrpt::obs;
41 using namespace mrpt::maps;
42 using namespace mrpt::math;
43 using namespace mrpt::opengl;
44 using namespace mrpt::poses;
45 using namespace mrpt::math;
46 
48 
49 void CAngularObservationMesh::addTriangle(
50  const TPoint3D& p1, const TPoint3D& p2, const TPoint3D& p3) const
51 {
53  t.vertices[0].xyzrgba.pt = p1;
54  t.vertices[1].xyzrgba.pt = p2;
55  t.vertices[2].xyzrgba.pt = p3;
56  t.computeNormals();
57  t.setColor(m_color);
58 
59  triangles.emplace_back(std::move(t));
60  CRenderizable::notifyChange();
61 }
62 
63 void CAngularObservationMesh::updateMesh() const
64 {
65  CRenderizable::notifyChange();
66 
67  size_t numRows = scanSet.size();
68  triangles.clear();
69  if (numRows <= 1)
70  {
71  actualMesh.setSize(0, 0);
72  validityMatrix.setSize(0, 0);
73  meshUpToDate = true;
74  return;
75  }
76  if (pitchBounds.size() != numRows && pitchBounds.size() != 2) return;
77  size_t numCols = scanSet[0].getScanSize();
78  actualMesh.setSize(numRows, numCols);
79  validityMatrix.setSize(numRows, numCols);
80  std::vector<double> pitchs(numRows);
81  if (pitchBounds.size() == 2)
82  {
83  double p1 = pitchBounds[0];
84  double p2 = pitchBounds[1];
85  for (size_t i = 0; i < numRows; i++)
86  pitchs[i] = p1 + (p2 - p1) * static_cast<double>(i) /
87  static_cast<double>(numRows - 1);
88  }
89  else
90  for (size_t i = 0; i < numRows; i++) pitchs[i] = pitchBounds[i];
91  const bool rToL = scanSet[0].rightToLeft;
92  for (size_t i = 0; i < numRows; i++)
93  {
94  const auto& ss_i = scanSet[i];
95  const double pitchIncr = scanSet[i].deltaPitch;
96  const double aperture = scanSet[i].aperture;
97  const CPose3D origin = scanSet[i].sensorPose;
98  // This is not an error...
99  for (size_t j = 0; j < numCols; j++)
100  if ((validityMatrix(i, j) = ss_i.getScanRangeValidity(j)))
101  {
102  double pYaw = aperture * ((static_cast<double>(j) /
103  static_cast<double>(numCols - 1)) -
104  0.5);
105  // Without the pitch since it's already within each sensorPose:
106  actualMesh(i, j) =
107  ((origin +
108  CPose3D(0, 0, 0, rToL ? pYaw : -pYaw, pitchIncr)) +
109  CPoint3D(ss_i.getScanRange(j), 0, 0))
110  .asTPoint();
111  }
112  }
113 
114  triangles.reserve(2 * (numRows - 1) * (numCols - 1));
115  for (size_t k = 0; k < numRows - 1; k++)
116  {
117  for (size_t j = 0; j < numCols - 1; j++)
118  {
119  int b1 = validityMatrix(k, j) ? 1 : 0;
120  int b2 = validityMatrix(k, j + 1) ? 1 : 0;
121  int b3 = validityMatrix(k + 1, j) ? 1 : 0;
122  int b4 = validityMatrix(k + 1, j + 1) ? 1 : 0;
123  switch (b1 + b2 + b3 + b4)
124  {
125  case 0:
126  case 1:
127  case 2:
128  break;
129  case 3:
130  if (!b1)
131  addTriangle(
132  actualMesh(k, j + 1), actualMesh(k + 1, j),
133  actualMesh(k + 1, j + 1));
134  else if (!b2)
135  addTriangle(
136  actualMesh(k, j), actualMesh(k + 1, j),
137  actualMesh(k + 1, j + 1));
138  else if (!b3)
139  addTriangle(
140  actualMesh(k, j), actualMesh(k, j + 1),
141  actualMesh(k + 1, j + 1));
142  else if (!b4)
143  addTriangle(
144  actualMesh(k, j), actualMesh(k, j + 1),
145  actualMesh(k + 1, j));
146  break;
147  case 4:
148  addTriangle(
149  actualMesh(k, j), actualMesh(k, j + 1),
150  actualMesh(k + 1, j));
151  addTriangle(
152  actualMesh(k + 1, j + 1), actualMesh(k, j + 1),
153  actualMesh(k + 1, j));
154  }
155  }
156  }
157  meshUpToDate = true;
158 }
159 
160 void CAngularObservationMesh::render(const RenderContext& rc) const
161 {
162  switch (rc.shader_id)
163  {
164  case DefaultShaderID::TRIANGLES:
165  if (!m_Wireframe) CRenderizableShaderTriangles::render(rc);
166  break;
167  case DefaultShaderID::WIREFRAME:
168  if (m_Wireframe) CRenderizableShaderWireFrame::render(rc);
169  break;
170  };
171 }
172 void CAngularObservationMesh::renderUpdateBuffers() const
173 {
174  CRenderizableShaderTriangles::renderUpdateBuffers();
175  CRenderizableShaderWireFrame::renderUpdateBuffers();
176 }
177 
178 void CAngularObservationMesh::onUpdateBuffers_Wireframe()
179 {
180  auto& vbd = CRenderizableShaderWireFrame::m_vertex_buffer_data;
181  auto& cbd = CRenderizableShaderWireFrame::m_color_buffer_data;
182  vbd.clear();
183  cbd.clear();
184 
185  for (const auto& t : triangles)
186  {
187  // Was: glBegin(GL_LINE_LOOP);
188  for (int k = 0; k <= 3; k++)
189  {
190  int kk = k % 3;
191  vbd.emplace_back(t.x(kk), t.y(kk), t.z(kk));
192  cbd.emplace_back(t.r(kk), t.g(kk), t.b(kk), t.a(kk));
193  }
194  }
195 }
196 
197 void CAngularObservationMesh::onUpdateBuffers_Triangles()
198 {
199  auto& tris = CRenderizableShaderTriangles::m_triangles;
200 
201  tris = this->triangles;
202 
203  // All faces, all vertices, same color:
204  for (auto& t : tris)
205  {
206  t.setColor(m_color);
207  t.computeNormals();
208  }
209 }
210 
212  const mrpt::poses::CPose3D& o, double& dist) const
213 {
215  MRPT_UNUSED_PARAM(dist);
216  // TODO: redo
217  return false;
218 }
219 
220 bool CAngularObservationMesh::setScanSet(
221  const std::vector<mrpt::obs::CObservation2DRangeScan>& scans)
222 {
223  CRenderizable::notifyChange();
224 
225  // Returns false if the scan is inconsistent
226  if (scans.size() > 0)
227  {
228  size_t setSize = scans[0].getScanSize();
229  bool rToL = scans[0].rightToLeft;
230  for (auto it = scans.begin() + 1; it != scans.end(); ++it)
231  {
232  if (it->getScanSize() != setSize) return false;
233  if (it->rightToLeft != rToL) return false;
234  }
235  }
236  scanSet = scans;
237  meshUpToDate = false;
238  CRenderizable::notifyChange();
239  return true;
240 }
241 
242 void CAngularObservationMesh::setPitchBounds(
243  const double initial, const double final)
244 {
245  CRenderizable::notifyChange();
246 
247  pitchBounds.clear();
248  pitchBounds.push_back(initial);
249  pitchBounds.push_back(final);
250  meshUpToDate = false;
251  CRenderizable::notifyChange();
252 }
253 void CAngularObservationMesh::setPitchBounds(const std::vector<double>& bounds)
254 {
255  CRenderizable::notifyChange();
256 
257  pitchBounds = bounds;
258  meshUpToDate = false;
259  CRenderizable::notifyChange();
260 }
261 void CAngularObservationMesh::getPitchBounds(
262  double& initial, double& final) const
263 {
264  initial = pitchBounds.front();
265  final = pitchBounds.back();
266 }
267 void CAngularObservationMesh::getPitchBounds(std::vector<double>& bounds) const
268 {
269  bounds = pitchBounds;
270 }
271 void CAngularObservationMesh::getScanSet(
272  std::vector<CObservation2DRangeScan>& scans) const
273 {
274  scans = scanSet;
275 }
276 
277 void CAngularObservationMesh::generateSetOfTriangles(
278  CSetOfTriangles::Ptr& res) const
279 {
280  if (!meshUpToDate) updateMesh();
281  res->insertTriangles(triangles.begin(), triangles.end());
282 }
283 
285 {
288  inline void operator()(const CObservation2DRangeScan& obj)
289  {
290  m->insertObservation(obj);
291  }
292 };
293 
294 void CAngularObservationMesh::generatePointCloud(CPointsMap* out_map) const
295 {
296  ASSERT_(out_map);
297  out_map->clear();
298  /* size_t numRows=scanSet.size();
299  if ((pitchBounds.size()!=numRows)&&(pitchBounds.size()!=2)) return;
300  std::vector<double> pitchs(numRows);
301  if (pitchBounds.size()==2) {
302  double p1=pitchBounds[0];
303  double p2=pitchBounds[1];
304  for (size_t i=0;i<numRows;i++)
305  pitchs[i]=p1+(p2-p1)*static_cast<double>(i)/static_cast<double>(numRows-1);
306  } else for (size_t i=0;i<numRows;i++) pitchs[i]=pitchBounds[i];
307  for (size_t i=0;i<numRows;i++) out_map->insertObservation(&scanSet[i]);
308  */
309 
310  std::for_each(
311  scanSet.begin(), scanSet.end(), CAngularObservationMesh_fnctr(out_map));
312 }
313 
314 uint8_t CAngularObservationMesh::serializeGetVersion() const { return 0; }
315 void CAngularObservationMesh::serializeTo(
317 {
318  writeToStreamRender(out);
319  // Version 0:
320  out << pitchBounds << scanSet << m_Wireframe << mEnableTransparency;
321 }
322 
323 void CAngularObservationMesh::serializeFrom(
324  mrpt::serialization::CArchive& in, uint8_t version)
325 {
326  switch (version)
327  {
328  case 0:
329  readFromStreamRender(in);
330  in >> pitchBounds >> scanSet >> m_Wireframe >> mEnableTransparency;
331  break;
332  default:
334  };
335  meshUpToDate = false;
336  CRenderizable::notifyChange();
337 }
338 
339 void CAngularObservationMesh::TDoubleRange::values(
340  std::vector<double>& vals) const
341 {
342  double value = initialValue();
343  double incr = increment();
344  size_t am = amount();
345  vals.resize(am);
346  for (size_t i = 0; i < am - 1; i++, value += incr) vals[i] = value;
347  vals[am - 1] = finalValue();
348 }
349 
350 void CAngularObservationMesh::getTracedRays(CSetOfLines::Ptr& res) const
351 {
352  if (!meshUpToDate) updateMesh();
353  size_t count = 0;
354  for (int i = 0; i < validityMatrix.rows(); i++)
355  for (int j = 0; j < validityMatrix.cols(); j++)
356  if (validityMatrix(i, j)) count++;
357  res->reserve(count);
358  for (int i = 0; i < actualMesh.rows(); i++)
359  for (int j = 0; j < actualMesh.cols(); j++)
360  if (validityMatrix(i, j))
361  res->appendLine(
362  (scanSet[i].sensorPose).asTPose(), actualMesh(i, j));
363 }
364 
366 {
367  public:
369  const CPoint3D& pDist;
370  std::vector<double> pitchs;
372  CSetOfLines::Ptr& l, const CPoint3D& p, const std::vector<double>& pi)
373  : lins(l), pDist(p), pitchs()
374  {
375  pitchs.reserve(pi.size());
376  for (auto it = pi.rbegin(); it != pi.rend(); ++it)
377  pitchs.push_back(*it);
378  }
380  {
381  size_t hm = obs.getScanSize();
382  for (size_t i = 0; i < obs.getScanSize(); i++)
383  if (obs.getScanRangeValidity(i)) hm--;
384  lins->reserve(hm);
385  for (size_t i = 0; i < obs.getScanSize(); i++)
386  if (!obs.getScanRangeValidity(i))
387  {
388  double yaw = obs.aperture *
389  ((static_cast<double>(i) /
390  static_cast<double>(obs.getScanSize() - 1)) -
391  0.5);
392  lins->appendLine(
393  obs.sensorPose.asTPose(),
394  (obs.sensorPose +
395  CPose3D(
396  0, 0, 0, obs.rightToLeft ? yaw : -yaw,
397  obs.deltaPitch * i + pitchs.back(), 0) +
398  pDist)
399  .asTPoint());
400  }
401  pitchs.pop_back();
402  }
403 };
404 void CAngularObservationMesh::getUntracedRays(
405  CSetOfLines::Ptr& res, double dist) const
406 {
407  for_each(
408  scanSet.begin(), scanSet.end(),
409  FAddUntracedLines(res, dist, pitchBounds));
410 }
411 
413 {
414  TPolygon3D res(3);
415  for (size_t i = 0; i < 3; i++) res[i] = t.vertices[i].xyzrgba.pt;
416  return res;
417 }
418 
419 void CAngularObservationMesh::generateSetOfTriangles(
420  std::vector<TPolygon3D>& res) const
421 {
422  if (!meshUpToDate) updateMesh();
423  res.resize(triangles.size());
424  transform(
425  triangles.begin(), triangles.end(), res.begin(), createFromTriangle);
426 }
427 
428 void CAngularObservationMesh::getBoundingBox(
430 {
431  if (!meshUpToDate) updateMesh();
432 
434  std::numeric_limits<double>::max(), std::numeric_limits<double>::max(),
435  std::numeric_limits<double>::max());
437  -std::numeric_limits<double>::max(),
438  -std::numeric_limits<double>::max(),
439  -std::numeric_limits<double>::max());
440 
441  for (const auto& t : triangles)
442  {
443  keep_min(bb_min.x, t.x(0));
444  keep_max(bb_max.x, t.x(0));
445  keep_min(bb_min.y, t.y(0));
446  keep_max(bb_max.y, t.y(0));
447  keep_min(bb_min.z, t.z(0));
448  keep_max(bb_max.z, t.z(0));
449 
450  keep_min(bb_min.x, t.x(1));
451  keep_max(bb_max.x, t.x(1));
452  keep_min(bb_min.y, t.y(1));
453  keep_max(bb_max.y, t.y(1));
454  keep_min(bb_min.z, t.z(1));
455  keep_max(bb_max.z, t.z(1));
456 
457  keep_min(bb_min.x, t.x(2));
458  keep_max(bb_max.x, t.x(2));
459  keep_min(bb_min.y, t.y(2));
460  keep_max(bb_max.y, t.y(2));
461  keep_min(bb_min.z, t.z(2));
462  keep_max(bb_max.z, t.z(2));
463  }
464 
465  // Convert to coordinates of my parent:
466  m_pose.composePoint(bb_min, bb_min);
467  m_pose.composePoint(bb_max, bb_max);
468 }
void clear()
Erase all the contents of the map.
Definition: CMetricMap.cpp:30
mrpt::math::TPose3D asTPose() const
Definition: CPose3D.cpp:775
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 operator()(const CObservation2DRangeScan &obs)
A mesh built from a set of 2D laser scan observations.
bool traceRay(const std::vector< TPolygonWithPlane > &vec, const mrpt::math::TPose3D &pose, double &dist)
Fast ray tracing method using polygons&#39; properties.
Definition: geometry.cpp:2551
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
To be added to all CSerializable-classes implementation files.
A triangle (float coordinates) with RGBA colors (u8) and UV (texture coordinates) for each vertex...
Definition: TTriangle.h:35
The base class of 3D objects that can be directly rendered through OpenGL.
Definition: CRenderizable.h:48
size_t getScanSize() const
Get number of scan rays.
TPolygon3D createFromTriangle(const mrpt::opengl::TTriangle &t)
Context for calls to render()
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
Definition: exceptions.h:97
std::array< Vertex, 3 > vertices
Definition: TTriangle.h:88
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans or other sensors...
Definition: CPointsMap.h:65
std::vector< double > pitchs
This base provides a set of functions for maths stuff.
FAddUntracedLines(CSetOfLines::Ptr &l, const CPoint3D &p, const std::vector< double > &pi)
This namespace contains representation of robot actions and observations.
TPoint3D_< double > TPoint3D
Lightweight 3D point.
Definition: TPoint3D.h:268
A class used to store a 3D point.
Definition: CPoint3D.h:31
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
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...
void setColor(const mrpt::img::TColor &c)
Sets the color of all vertices.
Definition: TTriangle.h:116
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A "CObservation"-derived class that represents a 2D range scan measurement (typically from a laser sc...
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:54
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:85
mrpt::vision::TStereoCalibResults out
double deltaPitch
If the laser gathers data by sweeping in the pitch/elevation angle, this holds the increment in "pitc...
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:13
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees)...
const auto bb_max
void operator()(const CObservation2DRangeScan &obj)
void computeNormals()
Compute the three normals from the cross-product of "v01 x v02".
Definition: TTriangle.cpp:21
const auto bb_min
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
3D polygon, inheriting from std::vector<TPoint3D>
Definition: TPolygon3D.h:20
bool insertObservation(const mrpt::obs::CObservation &obs, const mrpt::poses::CPose3D *robotPose=nullptr)
Insert the observation information into this map.
Definition: CMetricMap.cpp:93
bool rightToLeft
The scanning direction: true=counterclockwise; false=clockwise.
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
Definition: common.h:186
bool getScanRangeValidity(const size_t i) const
It&#39;s false (=0) on no reflected rays, referenced to elements in scan.



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 3a26b90fd Wed Mar 25 20:17:03 2020 +0100 at miƩ mar 25 23:05:41 CET 2020