Shape2p5.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2024 Jose Luis Blanco Claraco |
5  | Copyright (C) 2017 Borys Tymchenko (Odessa Polytechnic University) |
6  | Distributed under 3-clause BSD License |
7  | See COPYING |
8  +-------------------------------------------------------------------------+ */
9 
10 #include <box2d/b2_settings.h> // b2_maxPolygonVertices
11 #include <mrpt/containers/yaml.h>
12 #include <mrpt/maps/CSimplePointsMap.h>
13 #include <mrpt/math/TBoundingBox.h>
14 #include <mrpt/math/TLine2D.h>
15 #include <mrpt/math/TObject2D.h>
16 #include <mrpt/math/geometry.h>
17 #include <mrpt/opengl/COpenGLScene.h>
18 #include <mrpt/opengl/CPointCloud.h>
19 #include <mrpt/opengl/CSetOfLines.h>
20 #include <mrpt/opengl/CSetOfTriangles.h>
21 #include <mrpt/opengl/CTexturedPlane.h>
22 #include <mrpt/opengl/stock_objects.h>
23 #include <mvsim/Shape2p5.h>
24 
25 #include <cmath>
26 #include <iostream>
27 #include <queue>
28 
29 // Uncomment only for development debugging
30 //#define DEBUG_DUMP_ALL_TEMPORARY_GRIDS
31 //#define DEBUG_DUMP_TRIANGLES
32 
33 using namespace mvsim;
34 
35 using mrpt::math::TPoint2Df;
36 using mrpt::math::TPoint3Df;
37 
38 constexpr uint8_t CELL_UNDEFINED = 0x80;
39 constexpr uint8_t CELL_OCCUPIED = 0x00;
40 constexpr uint8_t CELL_FREE = 0xff;
41 constexpr uint8_t CELL_VISITED = 0x40;
42 
43 double Shape2p5::volume() const
44 {
45  return std::abs(mrpt::math::signedArea(getContour())) * std::abs(zMin_ - zMax_);
46 }
47 
49 {
50  using mrpt::math::TPoint3Df;
51 
52  const auto& ca = this->getContour();
53  const auto& cb = s.getContour();
54 
55  // gross BB:
56  auto bb = mrpt::math::TBoundingBoxf::PlusMinusInfinity();
57  for (const auto& p : ca) bb.updateWithPoint(TPoint3Df(p.x, p.y, zMin()));
58  for (const auto& p : cb) bb.updateWithPoint(TPoint3Df(p.x, p.y, s.zMin()));
59 
60  bb.updateWithPoint(TPoint3Df(bb.min.x, bb.min.y, s.zMax()));
61  bb.updateWithPoint(TPoint3Df(bb.max.x, bb.max.y, this->zMax()));
62 
63  // convert to triangles:
64  Shape2p5 newShape;
65  newShape.buildInit({bb.min.x, bb.min.y}, {bb.max.x, bb.max.y});
66  for (size_t i = 0; i < ca.size(); i++)
67  {
68  size_t im1 = i == 0 ? (ca.size() - 1) : i - 1;
69  const auto p0 = ca.at(im1);
70  const auto p1 = ca.at(i);
71 
72  mrpt::opengl::TTriangle t;
73  t.vertex(0) = TPoint3Df(p0.x, p0.y, bb.min.z);
74  t.vertex(1) = TPoint3Df(p1.x, p1.y, bb.min.z);
75  t.vertex(2) = TPoint3Df(p1.x, p1.y, bb.max.z);
76  newShape.buildAddTriangle(t);
77  }
78  for (size_t i = 0; i < cb.size(); i++)
79  {
80  size_t im1 = i == 0 ? (cb.size() - 1) : i - 1;
81  const auto p0 = cb.at(im1);
82  const auto p1 = cb.at(i);
83 
84  mrpt::opengl::TTriangle t;
85  t.vertex(0) = TPoint3Df(p0.x, p0.y, bb.min.z);
86  t.vertex(1) = TPoint3Df(p1.x, p1.y, bb.min.z);
87  t.vertex(2) = TPoint3Df(p1.x, p1.y, bb.max.z);
88  newShape.buildAddTriangle(t);
89  }
90 
91  // re-generate again:
92  *this = newShape;
93 }
94 
95 const mrpt::math::TPolygon2D& Shape2p5::getContour() const
96 {
97  if (!contour_) computeShape();
98  return *contour_;
99 }
100 
101 // For debugging only:
102 #ifdef DEBUG_DUMP_TRIANGLES
103 static auto glDebugTriangles = mrpt::opengl::CSetOfTriangles::Create();
104 #endif
105 
107  const mrpt::math::TPoint2Df& bbMin, const mrpt::math::TPoint2Df& bbMax, int numCells)
108 {
109  contour_.reset(); // start from scratch
110 
111  // grid resolution:
112  const float r = (bbMax - bbMin).norm() / numCells;
113  // border to ensure we have a free row/col all around the shape
114  const float b = r * 1.5f;
115  grid_.emplace(bbMin.x - b, bbMax.x + b, bbMin.y - b, bbMax.y + b, r);
116 
117  zMin_ = std::numeric_limits<float>::max();
118  zMax_ = -std::numeric_limits<float>::max();
119  grid_->fill(CELL_UNDEFINED);
120 
121 #ifdef DEBUG_DUMP_TRIANGLES
122  glDebugTriangles->clearTriangles();
123 #endif
124 }
125 
126 void Shape2p5::buildAddPoint(const mrpt::math::TPoint3Df& pt)
127 {
128  mrpt::keep_max(zMax_, pt.z);
129  mrpt::keep_min(zMin_, pt.z);
130  uint8_t* c = grid_->cellByPos(pt.x, pt.y);
131  ASSERT_(c);
132  *c = CELL_OCCUPIED;
133 }
134 
135 void Shape2p5::buildAddTriangle(const mrpt::opengl::TTriangle& t)
136 {
137  const float step = grid_->getResolution();
138 
139  for (int i0 = 0; i0 < 3; i0++)
140  {
141  const int i1 = (i0 + 1) % 3;
142  const auto& v0 = t.vertex(i0);
143  const auto& v1 = t.vertex(i1);
144 
145  const auto v01 = v1 - v0;
146 
147  const int nSteps = static_cast<int>(std::ceil(v01.norm() / step));
148 
149  mrpt::math::TPoint3Df p = v0;
150  const mrpt::math::TVector3Df Ap = v01 * (1.0f / nSteps);
151 
152  for (int s = 0; s < nSteps; s++, p += Ap)
153  {
154  uint8_t* c = grid_->cellByPos(p.x, p.y);
155  if (!c) continue;
156 
157  *c = CELL_OCCUPIED;
158  mrpt::keep_max(zMax_, p.z);
159  mrpt::keep_min(zMin_, p.z);
160  }
161  }
162 
163 #ifdef DEBUG_DUMP_TRIANGLES
164  glDebugTriangles->insertTriangle(t);
165 #endif
166 }
167 
168 // Computes contour_ from the contents in grid_
170 {
171  ASSERT_(grid_);
172  ASSERT_(!contour_);
173 
174 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS
175  // Debug save initial grid:
177 #endif
178 
179  // 0) Filter spurious occupied cells, due to (rare) lost points in the 3D
180  // model:
182 
183  // 1) Flood-fill the grid with "FREE color" to allow detecting the outer
184  // shape:
186 
187  // 2) Detect the outer contour with full grid resolution:
188  const mrpt::math::TPolygon2D rawGridContour = internalGridContour();
189 
190  // 3) convex hull:
191  // Eventually, b2Box library will use convex hull anyway, so let's use it
192  // here too:
193 
194  // 4) Polygon pruning until edge count is <= b2_maxPolygonVertices
195  const auto finalPoly = internalPrunePolygon(rawGridContour);
196 
197  // 5) Save result if output structure:
198  contour_.emplace(finalPoly);
199 
200 // DEBUG:
201 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS
202  debugSaveGridTo3DSceneFile(rawGridContour);
203 #endif
204 
205  grid_.reset();
206 
207 #ifdef DEBUG_DUMP_TRIANGLES
208  {
209  static int cnt = 0;
210  mrpt::opengl::COpenGLScene scene;
211  scene.insert(glDebugTriangles);
212  scene.saveToFile(mrpt::format("debug_shape2p5_triangles_%04i.3Dscene", cnt++));
213  }
214 #endif
215 }
216 
218  const mrpt::math::TPolygon2D& contour, const float zMin, const float zMax)
219 {
220  grid_.reset();
221  contour_ = contour;
222  zMin_ = zMin;
223  zMax_ = zMax;
224 }
225 
227 {
228  ASSERT_(grid_);
229 
230  const int cxMax = grid_->getSizeX() - 1;
231  const int cyMax = grid_->getSizeY() - 1;
232 
233  for (int cx = 1; cx < cxMax; cx++)
234  {
235  for (int cy = 1; cy < cyMax; cy++)
236  {
237  auto* thisCell = grid_->cellByIndex(cx, cy);
238  if (*thisCell != CELL_OCCUPIED) continue;
239  // it's occupied:
240  // reset to unknown if no other neighbors is occupied:
241  bool anyNN = (*grid_->cellByIndex(cx - 1, cy - 1) == CELL_OCCUPIED) ||
242  (*grid_->cellByIndex(cx - 1, cy + 0) == CELL_OCCUPIED) ||
243  (*grid_->cellByIndex(cx - 1, cy + 1) == CELL_OCCUPIED) ||
244  (*grid_->cellByIndex(cx + 0, cy - 1) == CELL_OCCUPIED) ||
245  (*grid_->cellByIndex(cx + 0, cy + 1) == CELL_OCCUPIED) ||
246  (*grid_->cellByIndex(cx + 1, cy - 1) == CELL_OCCUPIED) ||
247  (*grid_->cellByIndex(cx + 1, cy + 0) == CELL_OCCUPIED) ||
248  (*grid_->cellByIndex(cx + 1, cy + 1) == CELL_OCCUPIED);
249 
250  if (!anyNN) *thisCell = CELL_UNDEFINED;
251  }
252  }
253 }
254 
256 {
257  ASSERT_(grid_);
258 
259  // Algorithm:
260  // Heckbert, Paul S (1990). "IV.10: A Seed Fill Algorithm". In Glassner,
261  // Andrew S (ed.). Graphics Gems. Academic Press. pp. 275–277.
262  // https://en.wikipedia.org/wiki/Flood_fill
263 
264  const int cxMax = grid_->getSizeX() - 1;
265  const int cyMax = grid_->getSizeY() - 1;
266 
267  const auto Inside = [&](int x, int y)
268  {
269  if (x < 0 || y < 0) return false;
270  if (x > cxMax || y > cyMax) return false;
271  uint8_t* c = grid_->cellByIndex(x, y);
272  if (!c) return false;
273 
274  return *c == CELL_UNDEFINED;
275  };
276 
277  const auto Set = [&](int x, int y)
278  {
279  if (x < 0 || y < 0) return;
280  if (x > cxMax || y > cyMax) return;
281  uint8_t* c = grid_->cellByIndex(x, y);
282  if (!c) return;
283  *c = CELL_FREE;
284  };
285 
286  const int x0 = 0, y0 = 0; // start pixel for flood fill.
287 
288  /*
289  fn fill(x, y):
290  if not Inside(x, y) then return
291  let s = new empty stack or queue
292  Add (x, y) to s
293  while s is not empty:
294  Remove an (x, y) from s
295  let lx = x
296  while Inside(lx - 1, y):
297  Set(lx - 1, y)
298  lx = lx - 1
299  while Inside(x, y):
300  Set(x, y)
301  x = x + 1
302  scan(lx, x - 1, y + 1, s)
303  scan(lx, x - 1, y - 1, s)
304 
305  fn scan(lx, rx, y, s):
306  let span_added = false
307  for x in lx .. rx:
308  if not Inside(x, y):
309  span_added = false
310  else if not span_added:
311  Add (x, y) to s
312  span_added = true
313  */
314 
315  if (!Inside(x0, y0)) return;
316 
317  struct Coord
318  {
319  Coord() = default;
320  Coord(int X, int Y) : x_(X), y_(Y) {}
321 
322  int x_ = 0, y_ = 0;
323  };
324 
325  std::queue<Coord> s;
326 
327  const auto lambdaScan = [&s, &Inside](int lx, int rx, int y)
328  {
329  bool spanAdded = false;
330  for (int x = lx; x <= rx; x++)
331  {
332  if (!Inside(x, y))
333  {
334  spanAdded = false;
335  }
336  else if (!spanAdded)
337  {
338  s.emplace(x, y);
339  spanAdded = true;
340  }
341  }
342  };
343 
344  s.emplace(x0, y0);
345  while (!s.empty())
346  {
347  auto [x, y] = s.front();
348  s.pop();
349  int lx = x;
350  while (Inside(lx - 1, y))
351  {
352  Set(lx - 1, y);
353  lx--;
354  }
355  while (Inside(x, y))
356  {
357  Set(x, y);
358  x++;
359  }
360  lambdaScan(lx, x - 1, y + 1);
361  lambdaScan(lx, x - 1, y - 1);
362  }
363 }
364 
365 // Detects the outter polygon of the grid, after having been flood filled.
366 mrpt::math::TPolygon2D Shape2p5::internalGridContour() const
367 {
368  ASSERT_(grid_);
369 
370  mrpt::math::TPolygon2D p;
371 
372  const int nx = grid_->getSizeX();
373  const int ny = grid_->getSizeY();
374 
375  const std::vector<std::pair<int, int>> dirs = {
376  // first, straight directions (important!)
377  {+1, 0},
378  {-1, 0},
379  {0, +1},
380  {0, -1},
381  // second, diagonals:
382  {+1, +1},
383  {+1, -1},
384  {-1, +1},
385  {-1, -1},
386  };
387 
388  auto lambdaCellIsBorderSimple = [&](int cx, int cy)
389  {
390  auto* c = grid_->cellByIndex(cx, cy);
391  if (!c) return false;
392 
393  if (*c != CELL_OCCUPIED) return false;
394 
395  // check 4 neighbors:
396  if (auto* cS = grid_->cellByIndex(cx, cy - 1); cS && *cS == CELL_FREE) return true;
397  if (auto* cN = grid_->cellByIndex(cx, cy + 1); cN && *cN == CELL_FREE) return true;
398  if (auto* cE = grid_->cellByIndex(cx + 1, cy); cE && *cE == CELL_FREE) return true;
399  if (auto* cW = grid_->cellByIndex(cx - 1, cy); cW && *cW == CELL_FREE) return true;
400 
401  return false;
402  };
403 
404  auto lambdaStillHasUnexploredNeighbors = [&](int cx, int cy)
405  {
406  // precondition: (cx,cy) is VISITED.
407  // We check 8-neighbors:
408 
409  for (const auto& dir : dirs)
410  {
411  const int ix = dir.first, iy = dir.second;
412  const bool isBorder = lambdaCellIsBorderSimple(cx + ix, cy + iy);
413  if (isBorder) return true;
414  }
415  return false;
416  };
417 
418  auto lambdaCellIsBorder = [&](int cx, int cy, bool considerRevisits)
419  {
420  auto* c = grid_->cellByIndex(cx, cy);
421  if (!c) return false;
422 
423  if (*c == CELL_UNDEFINED) return false;
424  if (*c == CELL_FREE) return false;
425  if (*c == CELL_VISITED)
426  {
427  // only consider it if it still has possible free ways to move
428  // around:
429  if (considerRevisits && lambdaStillHasUnexploredNeighbors(cx, cy))
430  return true;
431  else
432  return false;
433  }
434 
435  // check 4 neighbors:
436  if (auto* cS = grid_->cellByIndex(cx, cy - 1); cS && *cS == CELL_FREE) return true;
437  if (auto* cN = grid_->cellByIndex(cx, cy + 1); cN && *cN == CELL_FREE) return true;
438  if (auto* cE = grid_->cellByIndex(cx + 1, cy); cE && *cE == CELL_FREE) return true;
439  if (auto* cW = grid_->cellByIndex(cx - 1, cy); cW && *cW == CELL_FREE) return true;
440 
441  return false;
442  };
443 
444  // 1) Look for the first CELL_OCCUPIED cell:
445  int cx = 0, cy = 0;
446  while (*grid_->cellByIndex(cx, cy) != CELL_OCCUPIED)
447  {
448  cx++;
449  if (cx >= nx)
450  {
451  cx = 0;
452  cy++;
453  ASSERT_(cy < ny);
454  }
455  }
456 
457  // 2) Iterate:
458  // - mark current cell as CELL_VISITED, add to polygon.
459  // - Look in 8 neighbors for a CELL_OCCUPIED with a CELL_FREE cell in
460  // one of its 4 main directions.
461  for (;;)
462  {
463  auto* c = grid_->cellByIndex(cx, cy);
464  ASSERT_(c);
465  *c = CELL_VISITED;
466 
467  // save into polygon too:
468  p.emplace_back(grid_->idx2x(cx), grid_->idx2y(cy));
469 
470  bool cellDone = false;
471 
472  for (int pass = 0; pass < 2 && !cellDone; pass++)
473  {
474  for (const auto& dir : dirs)
475  {
476  const int ix = dir.first, iy = dir.second;
477  const bool isBorder = lambdaCellIsBorder(cx + ix, cy + iy, pass == 1);
478 
479  if (isBorder)
480  {
481 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS
483 #endif
484  // Save for next iter:
485  cellDone = true;
486  cx = cx + ix;
487  cy = cy + iy;
488  break;
489  }
490  }
491  }
492  if (!cellDone) break;
493  }
494 
495  return p;
496 }
497 
499  const mrpt::math::TPolygon2D& rawGridContour, const std::string& debugStr) const
500 {
501  mrpt::opengl::COpenGLScene scene;
502 
503  auto glGrid = mrpt::opengl::CTexturedPlane::Create();
504  glGrid->setPlaneCorners(grid_->getXMin(), grid_->getXMax(), grid_->getYMin(), grid_->getYMax());
505 
506  mrpt::math::CMatrixDouble mat;
507  grid_->getAsMatrix(mat);
508 
509  mrpt::img::CImage im;
510  im.setFromMatrix(mat, false /* matrix is [0,255]*/);
511 
512  glGrid->assignImage(im);
513 
514  scene.insert(mrpt::opengl::stock_objects::CornerXYZSimple());
515  scene.insert(glGrid);
516 
517  auto lambdaRenderPoly =
518  [&scene](const mrpt::math::TPolygon2D& p, const mrpt::img::TColor& color, double z)
519  {
520  auto glPts = mrpt::opengl::CPointCloud::Create();
521  auto glPoly = mrpt::opengl::CSetOfLines::Create();
522  glPoly->setColor_u8(color);
523  glPts->setColor_u8(color);
524  glPts->setPointSize(4.0f);
525  const auto N = p.size();
526  for (size_t j = 0; j < N; j++)
527  {
528  const size_t j1 = (j + 1) % N;
529  const auto& p0 = p.at(j);
530  const auto& p1 = p.at(j1);
531  glPoly->appendLine(p0.x, p0.y, z + 1e-4 * j, p1.x, p1.y, z + 1e-4 * (j + 1));
532  glPts->insertPoint(p0.x, p0.y, z + 1e-4 * j);
533  }
534  scene.insert(glPoly);
535  scene.insert(glPts);
536  };
537 
538  lambdaRenderPoly(*contour_, {0xff, 0x00, 0x00}, 0.10);
539  lambdaRenderPoly(rawGridContour, {0x00, 0xff, 0x00}, 0.05);
540 
541  if (!debugStr.empty()) scene.getViewport()->addTextMessage(5, 5, debugStr);
542 
543  static int i = 0;
544  scene.saveToFile(mrpt::format("collision_grid_%05i.3Dscene", i++));
545 }
546 
547 std::optional<Shape2p5::RemovalCandidate> Shape2p5::lossOfRemovingVertex(
548  size_t i, const mrpt::math::TPolygon2D& p, bool allowApproxEdges) const
549 {
550  // 1st: check if removing that vertex leads to edges crossing
551  // CELL_UNDEFINED or CELL_OCCUPIED cells:
552 
553  size_t im1 = i > 0 ? i - 1 : (p.size() - 1);
554  size_t ip1 = i == (p.size() - 1) ? 0 : i + 1;
555 
556  const auto& pt_im1 = p[im1];
557  const auto& pt_ip1 = p[ip1];
558  const auto delta = pt_ip1 - pt_im1;
559  const size_t nSteps = static_cast<size_t>(ceil(delta.norm() / grid_->getResolution()));
560  const auto d = delta * (1.0 / nSteps);
561  for (size_t k = 0; k < nSteps; k++)
562  {
563  const auto pt = pt_im1 + d * k;
564  const auto* c = grid_->cellByPos(pt.x, pt.y);
565  if (!c) return {}; // should never happen (!)
566 
567  if (!allowApproxEdges)
568  {
569  // removing this vertex leads to unacceptable approximation:
570  if (*c == CELL_UNDEFINED || *c == CELL_OCCUPIED) return {};
571  }
572  }
573 
574  // ok, removing the vertex is ok.
575  // now, let's quantify the increase in area ("loss"):
577  rc.next = p;
578  rc.next.erase(rc.next.begin() + i);
579 
580  const double originalArea = std::abs(mrpt::math::signedArea(p));
581  const double newArea = std::abs(mrpt::math::signedArea(rc.next));
582  rc.loss = newArea - originalArea;
583 
584  if (allowApproxEdges) rc.loss = -rc.loss;
585 
586  return rc;
587 }
588 
589 mrpt::math::TPolygon2D Shape2p5::internalPrunePolygon(const mrpt::math::TPolygon2D& poly) const
590 {
591  using namespace std::string_literals;
592 
593  mrpt::math::TPolygon2D p = poly;
594 
595  // Algorithm:
596  // Pass #1: go thru all vertices, and pick the one that minimizes
597  // the increase of polygon area while not crossing through any grid cell
598  // that is either CELL_UNDEFINED or CELL_OCCUPIED.
599  // Pass #2: idem, but allow crossing cells.
600  for (int pass = 0; pass < 2; pass++)
601  {
602  while (p.size() > b2_maxPolygonVertices)
603  {
604  std::optional<RemovalCandidate> best;
605 
606  for (size_t i = 0; i < p.size(); i++)
607  {
608  std::optional<RemovalCandidate> rc = lossOfRemovingVertex(i, p, pass == 1);
609  if (rc && (!best || rc->loss < best->loss)) best = *rc;
610  }
611 
612  if (!best) break; // No more vertices found to remove
613 
614  p = best->next;
615 
616 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS
617  debugSaveGridTo3DSceneFile(p, mrpt::format("pass #%i loss=%f", pass, best->loss));
618 #endif
619  }
620  }
621 
622  return p;
623 }
624 
625 void Shape2p5::clipZMin(float v)
626 {
627  if (zMin_ < v) zMin_ = v;
628 }
629 
630 void Shape2p5::clipZMax(float v)
631 {
632  if (zMax_ > v) zMax_ = v;
633 }
634 
635 std::string Shape2p5::asString() const
636 {
637  std::stringstream s;
638  s << getContour().asYAML();
639  return s.str();
640 }
mvsim::Shape2p5::internalGridContour
mrpt::math::TPolygon2D internalGridContour() const
Definition: Shape2p5.cpp:366
mvsim
Definition: Client.h:21
mvsim::Shape2p5::zMax
float zMax() const
Definition: Shape2p5.h:50
b2_settings.h
CELL_VISITED
constexpr uint8_t CELL_VISITED
Definition: Shape2p5.cpp:41
mvsim::Shape2p5::setShapeManual
void setShapeManual(const mrpt::math::TPolygon2D &contour, const float zMin, const float zMax)
Definition: Shape2p5.cpp:217
CELL_FREE
constexpr uint8_t CELL_FREE
Definition: Shape2p5.cpp:40
mvsim::Shape2p5::zMin
float zMin() const
Definition: Shape2p5.h:49
s
XmlRpcServer s
mvsim::Shape2p5::RemovalCandidate::loss
double loss
Definition: Shape2p5.h:86
mvsim::Shape2p5::asString
std::string asString() const
Definition: Shape2p5.cpp:635
step
unsigned int step
mvsim::Shape2p5::volume
double volume() const
Definition: Shape2p5.cpp:43
CELL_UNDEFINED
constexpr uint8_t CELL_UNDEFINED
Definition: Shape2p5.cpp:38
f
f
mvsim::Shape2p5::internalGridFloodFill
void internalGridFloodFill() const
Definition: Shape2p5.cpp:255
mvsim::Shape2p5::mergeWith
void mergeWith(const Shape2p5 &s)
Definition: Shape2p5.cpp:48
mvsim::Shape2p5::zMin_
float zMin_
Definition: Shape2p5.h:59
CELL_OCCUPIED
constexpr uint8_t CELL_OCCUPIED
Definition: Shape2p5.cpp:39
mvsim::Shape2p5
Definition: Shape2p5.h:31
mvsim::Shape2p5::debugSaveGridTo3DSceneFile
void debugSaveGridTo3DSceneFile(const mrpt::math::TPolygon2D &rawGridContour, const std::string &debugStr={}) const
Definition: Shape2p5.cpp:498
Shape2p5.h
mvsim::Shape2p5::grid_
std::optional< SimpleOccGrid > grid_
Definition: Shape2p5.h:74
d
d
mvsim::Shape2p5::RemovalCandidate
Definition: Shape2p5.h:84
mvsim::Shape2p5::RemovalCandidate::next
mrpt::math::TPolygon2D next
Definition: Shape2p5.h:87
mvsim::Shape2p5::internalGridFilterSpurious
void internalGridFilterSpurious() const
Definition: Shape2p5.cpp:226
mvsim::Shape2p5::clipZMax
void clipZMax(float v)
Definition: Shape2p5.cpp:630
mvsim::Shape2p5::contour_
std::optional< mrpt::math::TPolygon2D > contour_
Definition: Shape2p5.h:58
mvsim::Shape2p5::clipZMin
void clipZMin(float v)
Definition: Shape2p5.cpp:625
mvsim::Shape2p5::buildInit
void buildInit(const mrpt::math::TPoint2Df &bbMin, const mrpt::math::TPoint2Df &bbMax, int numCells=100)
Definition: Shape2p5.cpp:106
mvsim::Shape2p5::lossOfRemovingVertex
std::optional< RemovalCandidate > lossOfRemovingVertex(size_t i, const mrpt::math::TPolygon2D &p, bool allowApproxEdges) const
Definition: Shape2p5.cpp:547
mvsim::Shape2p5::zMax_
float zMax_
Definition: Shape2p5.h:59
mvsim::Shape2p5::buildAddPoint
void buildAddPoint(const mrpt::math::TPoint3Df &pt)
Definition: Shape2p5.cpp:126
t
geometry_msgs::TransformStamped t
mvsim::Shape2p5::getContour
const mrpt::math::TPolygon2D & getContour() const
Definition: Shape2p5.cpp:95
mvsim::Shape2p5::computeShape
void computeShape() const
Computes contour_ from the contents in grid_.
Definition: Shape2p5.cpp:169
mvsim::Shape2p5::buildAddTriangle
void buildAddTriangle(const mrpt::opengl::TTriangle &t)
Definition: Shape2p5.cpp:135
b2_maxPolygonVertices
#define b2_maxPolygonVertices
Definition: b2_settings.h:53
mvsim::Shape2p5::internalPrunePolygon
mrpt::math::TPolygon2D internalPrunePolygon(const mrpt::math::TPolygon2D &poly) const
Definition: Shape2p5.cpp:589


mvsim
Author(s):
autogenerated on Wed May 28 2025 02:13:08