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>
33 using namespace mvsim;
35 using mrpt::math::TPoint2Df;
36 using mrpt::math::TPoint3Df;
50 using mrpt::math::TPoint3Df;
53 const auto& cb =
s.getContour();
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()));
60 bb.updateWithPoint(TPoint3Df(bb.min.x, bb.min.y,
s.zMax()));
61 bb.updateWithPoint(TPoint3Df(bb.max.x, bb.max.y, this->zMax()));
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++)
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);
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);
78 for (
size_t i = 0; i < cb.size(); i++)
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);
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);
102 #ifdef DEBUG_DUMP_TRIANGLES
103 static auto glDebugTriangles = mrpt::opengl::CSetOfTriangles::Create();
107 const mrpt::math::TPoint2Df& bbMin,
const mrpt::math::TPoint2Df& bbMax,
int numCells)
112 const float r = (bbMax - bbMin).norm() / numCells;
114 const float b = r * 1.5f;
115 grid_.emplace(bbMin.x - b, bbMax.x + b, bbMin.y - b, bbMax.y + b, r);
117 zMin_ = std::numeric_limits<float>::max();
118 zMax_ = -std::numeric_limits<float>::max();
121 #ifdef DEBUG_DUMP_TRIANGLES
122 glDebugTriangles->clearTriangles();
128 mrpt::keep_max(
zMax_, pt.z);
129 mrpt::keep_min(
zMin_, pt.z);
130 uint8_t* c =
grid_->cellByPos(pt.x, pt.y);
137 const float step =
grid_->getResolution();
139 for (
int i0 = 0; i0 < 3; i0++)
141 const int i1 = (i0 + 1) % 3;
142 const auto& v0 =
t.vertex(i0);
143 const auto& v1 =
t.vertex(i1);
145 const auto v01 = v1 - v0;
147 const int nSteps =
static_cast<int>(std::ceil(v01.norm() /
step));
149 mrpt::math::TPoint3Df p = v0;
150 const mrpt::math::TVector3Df Ap = v01 * (1.0f / nSteps);
152 for (
int s = 0;
s < nSteps;
s++, p += Ap)
154 uint8_t* c =
grid_->cellByPos(p.x, p.y);
158 mrpt::keep_max(
zMax_, p.z);
159 mrpt::keep_min(
zMin_, p.z);
163 #ifdef DEBUG_DUMP_TRIANGLES
164 glDebugTriangles->insertTriangle(
t);
174 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS
201 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS
207 #ifdef DEBUG_DUMP_TRIANGLES
210 mrpt::opengl::COpenGLScene scene;
211 scene.insert(glDebugTriangles);
212 scene.saveToFile(mrpt::format(
"debug_shape2p5_triangles_%04i.3Dscene", cnt++));
218 const mrpt::math::TPolygon2D& contour,
const float zMin,
const float zMax)
230 const int cxMax =
grid_->getSizeX() - 1;
231 const int cyMax =
grid_->getSizeY() - 1;
233 for (
int cx = 1; cx < cxMax; cx++)
235 for (
int cy = 1; cy < cyMax; cy++)
237 auto* thisCell =
grid_->cellByIndex(cx, cy);
264 const int cxMax =
grid_->getSizeX() - 1;
265 const int cyMax =
grid_->getSizeY() - 1;
267 const auto Inside = [&](
int x,
int y)
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;
277 const auto Set = [&](
int x,
int y)
279 if (x < 0 || y < 0)
return;
280 if (x > cxMax || y > cyMax)
return;
281 uint8_t* c =
grid_->cellByIndex(x, y);
286 const int x0 = 0, y0 = 0;
315 if (!Inside(x0, y0))
return;
320 Coord(
int X,
int Y) : x_(X), y_(Y) {}
327 const auto lambdaScan = [&
s, &Inside](
int lx,
int rx,
int y)
329 bool spanAdded =
false;
330 for (
int x = lx; x <= rx; x++)
347 auto [x, y] =
s.front();
350 while (Inside(lx - 1, y))
360 lambdaScan(lx, x - 1, y + 1);
361 lambdaScan(lx, x - 1, y - 1);
370 mrpt::math::TPolygon2D p;
372 const int nx =
grid_->getSizeX();
373 const int ny =
grid_->getSizeY();
375 const std::vector<std::pair<int, int>> dirs = {
388 auto lambdaCellIsBorderSimple = [&](
int cx,
int cy)
390 auto* c =
grid_->cellByIndex(cx, cy);
391 if (!c)
return false;
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;
404 auto lambdaStillHasUnexploredNeighbors = [&](
int cx,
int cy)
409 for (
const auto& dir : dirs)
411 const int ix = dir.first, iy = dir.second;
412 const bool isBorder = lambdaCellIsBorderSimple(cx + ix, cy + iy);
413 if (isBorder)
return true;
418 auto lambdaCellIsBorder = [&](
int cx,
int cy,
bool considerRevisits)
420 auto* c =
grid_->cellByIndex(cx, cy);
421 if (!c)
return false;
429 if (considerRevisits && lambdaStillHasUnexploredNeighbors(cx, cy))
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;
463 auto* c =
grid_->cellByIndex(cx, cy);
468 p.emplace_back(
grid_->idx2x(cx),
grid_->idx2y(cy));
470 bool cellDone =
false;
472 for (
int pass = 0; pass < 2 && !cellDone; pass++)
474 for (
const auto& dir : dirs)
476 const int ix = dir.first, iy = dir.second;
477 const bool isBorder = lambdaCellIsBorder(cx + ix, cy + iy, pass == 1);
481 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS
492 if (!cellDone)
break;
499 const mrpt::math::TPolygon2D& rawGridContour,
const std::string& debugStr)
const
501 mrpt::opengl::COpenGLScene scene;
503 auto glGrid = mrpt::opengl::CTexturedPlane::Create();
504 glGrid->setPlaneCorners(
grid_->getXMin(),
grid_->getXMax(),
grid_->getYMin(),
grid_->getYMax());
506 mrpt::math::CMatrixDouble mat;
507 grid_->getAsMatrix(mat);
509 mrpt::img::CImage im;
510 im.setFromMatrix(mat,
false );
512 glGrid->assignImage(im);
514 scene.insert(mrpt::opengl::stock_objects::CornerXYZSimple());
515 scene.insert(glGrid);
517 auto lambdaRenderPoly =
518 [&scene](
const mrpt::math::TPolygon2D& p,
const mrpt::img::TColor& color,
double z)
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.0
f);
525 const auto N = p.size();
526 for (
size_t j = 0; j < N; j++)
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);
534 scene.insert(glPoly);
538 lambdaRenderPoly(*
contour_, {0xff, 0x00, 0x00}, 0.10);
539 lambdaRenderPoly(rawGridContour, {0x00, 0xff, 0x00}, 0.05);
541 if (!debugStr.empty()) scene.getViewport()->addTextMessage(5, 5, debugStr);
544 scene.saveToFile(mrpt::format(
"collision_grid_%05i.3Dscene", i++));
548 size_t i,
const mrpt::math::TPolygon2D& p,
bool allowApproxEdges)
const
553 size_t im1 = i > 0 ? i - 1 : (p.size() - 1);
554 size_t ip1 = i == (p.size() - 1) ? 0 : i + 1;
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++)
563 const auto pt = pt_im1 +
d * k;
564 const auto* c =
grid_->cellByPos(pt.x, pt.y);
567 if (!allowApproxEdges)
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;
584 if (allowApproxEdges) rc.
loss = -rc.
loss;
591 using namespace std::string_literals;
593 mrpt::math::TPolygon2D p = poly;
600 for (
int pass = 0; pass < 2; pass++)
604 std::optional<RemovalCandidate> best;
606 for (
size_t i = 0; i < p.size(); i++)
609 if (rc && (!best || rc->loss < best->loss)) best = *rc;
616 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS