11 #include <mrpt/maps/CSimplePointsMap.h> 12 #include <mrpt/math/TBoundingBox.h> 13 #include <mrpt/math/TLine2D.h> 14 #include <mrpt/math/TObject2D.h> 15 #include <mrpt/math/geometry.h> 16 #include <mrpt/opengl/COpenGLScene.h> 17 #include <mrpt/opengl/CPointCloud.h> 18 #include <mrpt/opengl/CSetOfLines.h> 19 #include <mrpt/opengl/CSetOfTriangles.h> 20 #include <mrpt/opengl/CTexturedPlane.h> 21 #include <mrpt/opengl/stock_objects.h> 32 using namespace mvsim;
34 using mrpt::math::TPoint2Df;
35 using mrpt::math::TPoint3Df;
44 return std::abs(mrpt::math::signedArea(
getContour())) *
50 using mrpt::math::TPoint3Df;
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,
113 const float r = (bbMax - bbMin).norm() / numCells;
115 const float b = r * 1.5f;
116 grid_.emplace(bbMin.x - b, bbMax.x + b, bbMin.y - b, bbMax.y + b, r);
118 zMin_ = std::numeric_limits<float>::max();
119 zMax_ = -std::numeric_limits<float>::max();
122 #ifdef DEBUG_DUMP_TRIANGLES 123 glDebugTriangles->clearTriangles();
129 mrpt::keep_max(
zMax_, pt.z);
130 mrpt::keep_min(
zMin_, pt.z);
131 uint8_t* c =
grid_->cellByPos(pt.x, pt.y);
138 const float step =
grid_->getResolution();
140 for (
int i0 = 0; i0 < 3; i0++)
142 const int i1 = (i0 + 1) % 3;
143 const auto& v0 = t.vertex(i0);
144 const auto& v1 = t.vertex(i1);
146 const auto v01 = v1 - v0;
148 const int nSteps =
static_cast<int>(std::ceil(v01.norm() / step));
150 mrpt::math::TPoint3Df p = v0;
151 const mrpt::math::TVector3Df Ap = v01 * (1.0f / nSteps);
153 for (
int s = 0;
s < nSteps;
s++, p += Ap)
155 uint8_t* c =
grid_->cellByPos(p.x, p.y);
159 mrpt::keep_max(
zMax_, p.z);
160 mrpt::keep_min(
zMin_, p.z);
164 #ifdef DEBUG_DUMP_TRIANGLES 165 glDebugTriangles->insertTriangle(t);
175 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS 202 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS 208 #ifdef DEBUG_DUMP_TRIANGLES 211 mrpt::opengl::COpenGLScene scene;
212 scene.insert(glDebugTriangles);
214 mrpt::format(
"debug_shape2p5_triangles_%04i.3Dscene", cnt++));
220 const mrpt::math::TPolygon2D& contour,
const float zMin,
const float zMax)
232 const int cxMax =
grid_->getSizeX() - 1;
233 const int cyMax =
grid_->getSizeY() - 1;
235 for (
int cx = 1; cx < cxMax; cx++)
237 for (
int cy = 1; cy < cyMax; cy++)
239 auto* thisCell =
grid_->cellByIndex(cx, cy);
267 const int cxMax =
grid_->getSizeX() - 1;
268 const int cyMax =
grid_->getSizeY() - 1;
270 const auto Inside = [&](
int x,
int y) {
271 if (x < 0 || y < 0)
return false;
272 if (x > cxMax || y > cyMax)
return false;
273 uint8_t* c =
grid_->cellByIndex(x, y);
274 if (!c)
return false;
279 const auto Set = [&](
int x,
int y) {
280 if (x < 0 || y < 0)
return;
281 if (x > cxMax || y > cyMax)
return;
282 uint8_t* c =
grid_->cellByIndex(x, y);
287 const int x0 = 0, y0 = 0;
316 if (!Inside(x0, y0))
return;
321 Coord(
int X,
int Y) : x_(X), y_(Y) {}
328 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) {
389 auto* c =
grid_->cellByIndex(cx, cy);
390 if (!c)
return false;
395 if (
auto* cS =
grid_->cellByIndex(cx, cy - 1); cS && *cS ==
CELL_FREE)
397 if (
auto* cN =
grid_->cellByIndex(cx, cy + 1); cN && *cN ==
CELL_FREE)
399 if (
auto* cE =
grid_->cellByIndex(cx + 1, cy); cE && *cE ==
CELL_FREE)
401 if (
auto* cW =
grid_->cellByIndex(cx - 1, cy); cW && *cW ==
CELL_FREE)
407 auto lambdaStillHasUnexploredNeighbors = [&](
int cx,
int cy) {
411 for (
const auto& dir : dirs)
413 const int ix = dir.first, iy = dir.second;
414 const bool isBorder = lambdaCellIsBorderSimple(cx + ix, cy + iy);
415 if (isBorder)
return true;
420 auto lambdaCellIsBorder = [&](
int cx,
int cy,
bool considerRevisits) {
421 auto* c =
grid_->cellByIndex(cx, cy);
422 if (!c)
return false;
430 if (considerRevisits && lambdaStillHasUnexploredNeighbors(cx, cy))
437 if (
auto* cS =
grid_->cellByIndex(cx, cy - 1); cS && *cS ==
CELL_FREE)
439 if (
auto* cN =
grid_->cellByIndex(cx, cy + 1); cN && *cN ==
CELL_FREE)
441 if (
auto* cE =
grid_->cellByIndex(cx + 1, cy); cE && *cE ==
CELL_FREE)
443 if (
auto* cW =
grid_->cellByIndex(cx - 1, cy); cW && *cW ==
CELL_FREE)
468 auto* c =
grid_->cellByIndex(cx, cy);
473 p.emplace_back(
grid_->idx2x(cx),
grid_->idx2y(cy));
475 bool cellDone =
false;
477 for (
int pass = 0; pass < 2 && !cellDone; pass++)
479 for (
const auto& dir : dirs)
481 const int ix = dir.first, iy = dir.second;
482 const bool isBorder =
483 lambdaCellIsBorder(cx + ix, cy + iy, pass == 1);
487 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS 498 if (!cellDone)
break;
505 const mrpt::math::TPolygon2D& rawGridContour,
506 const std::string& debugStr)
const 508 mrpt::opengl::COpenGLScene scene;
510 auto glGrid = mrpt::opengl::CTexturedPlane::Create();
511 glGrid->setPlaneCorners(
514 mrpt::math::CMatrixDouble mat;
515 grid_->getAsMatrix(mat);
517 mrpt::img::CImage im;
518 im.setFromMatrix(mat,
false );
520 glGrid->assignImage(im);
522 scene.insert(mrpt::opengl::stock_objects::CornerXYZSimple());
523 scene.insert(glGrid);
525 auto lambdaRenderPoly = [&scene](
526 const mrpt::math::TPolygon2D& p,
527 const mrpt::img::TColor& color,
double z) {
528 auto glPts = mrpt::opengl::CPointCloud::Create();
529 auto glPoly = mrpt::opengl::CSetOfLines::Create();
530 glPoly->setColor_u8(color);
531 glPts->setColor_u8(color);
532 glPts->setPointSize(4.0
f);
533 const auto N = p.size();
534 for (
size_t j = 0; j < N; j++)
536 const size_t j1 = (j + 1) % N;
537 const auto& p0 = p.at(j);
538 const auto& p1 = p.at(j1);
540 p0.x, p0.y, z + 1e-4 * j, p1.x, p1.y, z + 1e-4 * (j + 1));
541 glPts->insertPoint(p0.x, p0.y, z + 1e-4 * j);
543 scene.insert(glPoly);
547 lambdaRenderPoly(*
contour_, {0xff, 0x00, 0x00}, 0.10);
548 lambdaRenderPoly(rawGridContour, {0x00, 0xff, 0x00}, 0.05);
550 if (!debugStr.empty()) scene.getViewport()->addTextMessage(5, 5, debugStr);
553 scene.saveToFile(mrpt::format(
"collision_grid_%05i.3Dscene", i++));
557 size_t i,
const mrpt::math::TPolygon2D& p,
bool allowApproxEdges)
const 562 size_t im1 = i > 0 ? i - 1 : (p.size() - 1);
563 size_t ip1 = i == (p.size() - 1) ? 0 : i + 1;
565 const auto& pt_im1 = p[im1];
566 const auto& pt_ip1 = p[ip1];
567 const auto delta = pt_ip1 - pt_im1;
568 const size_t nSteps =
569 static_cast<size_t>(ceil(delta.norm() /
grid_->getResolution()));
570 const auto d = delta * (1.0 / nSteps);
571 for (
size_t k = 0; k < nSteps; k++)
573 const auto pt = pt_im1 +
d * k;
574 const auto* c =
grid_->cellByPos(pt.x, pt.y);
577 if (!allowApproxEdges)
590 const double originalArea = std::abs(mrpt::math::signedArea(p));
591 const double newArea = std::abs(mrpt::math::signedArea(rc.
next));
592 rc.
loss = newArea - originalArea;
594 if (allowApproxEdges) rc.
loss = -rc.
loss;
600 const mrpt::math::TPolygon2D& poly)
const 602 using namespace std::string_literals;
604 mrpt::math::TPolygon2D p = poly;
611 for (
int pass = 0; pass < 2; pass++)
615 std::optional<RemovalCandidate> best;
617 for (
size_t i = 0; i < p.size(); i++)
619 std::optional<RemovalCandidate> rc =
621 if (rc && (!best || rc->loss < best->loss)) best = *rc;
628 #ifdef DEBUG_DUMP_ALL_TEMPORARY_GRIDS 630 p, mrpt::format(
"pass #%i loss=%f", pass, best->loss));
std::optional< mrpt::math::TPolygon2D > contour_
std::optional< SimpleOccGrid > grid_
const mrpt::math::TPolygon2D & getContour() const
mrpt::math::TPolygon2D internalPrunePolygon(const mrpt::math::TPolygon2D &poly) const
constexpr uint8_t CELL_OCCUPIED
void internalGridFilterSpurious() const
geometry_msgs::TransformStamped t
void setShapeManual(const mrpt::math::TPolygon2D &contour, const float zMin, const float zMax)
constexpr uint8_t CELL_FREE
std::optional< RemovalCandidate > lossOfRemovingVertex(size_t i, const mrpt::math::TPolygon2D &p, bool allowApproxEdges) const
constexpr uint8_t CELL_VISITED
void computeShape() const
Computes contour_ from the contents in grid_.
void buildAddPoint(const mrpt::math::TPoint3Df &pt)
mrpt::math::TPolygon2D internalGridContour() const
mrpt::math::TPolygon2D next
void buildAddTriangle(const mrpt::opengl::TTriangle &t)
#define b2_maxPolygonVertices
void mergeWith(const Shape2p5 &s)
constexpr uint8_t CELL_UNDEFINED
void debugSaveGridTo3DSceneFile(const mrpt::math::TPolygon2D &rawGridContour, const std::string &debugStr={}) const
void internalGridFloodFill() const
void buildInit(const mrpt::math::TPoint2Df &bbMin, const mrpt::math::TPoint2Df &bbMax, int numCells=100)