14 #include <mrpt/io/CFileGZInputStream.h>
15 #include <mrpt/io/CFileGZOutputStream.h>
16 #include <mrpt/maps/CVoxelMap.h>
17 #include <mrpt/maps/CVoxelMapRGB.h>
18 #include <mrpt/math/CHistogram.h>
19 #include <mrpt/math/distributions.h>
20 #include <mrpt/opengl/CGridPlaneXY.h>
21 #include <mrpt/opengl/CPointCloud.h>
22 #include <mrpt/opengl/CPointCloudColoured.h>
23 #include <mrpt/opengl/CSetOfLines.h>
24 #include <mrpt/opengl/CSetOfObjects.h>
25 #include <mrpt/serialization/CArchive.h>
26 #include <mrpt/serialization/optional_serialization.h>
27 #include <mrpt/serialization/stl_serialization.h>
28 #include <mrpt/system/string_utils.h>
34 metric_map_t, mrpt::serialization::CSerializable,
mp2p_icp)
39 uint8_t metric_map_t::serializeGetVersion()
const {
return 3; }
40 void metric_map_t::serializeTo(mrpt::serialization::CArchive&
out)
const
45 for (
const auto& p :
planes)
out << p.plane << p.centroid;
48 for (
const auto& l :
lines)
out << l;
51 for (
const auto& l :
layers)
out << l.first << *l.second.get();
69 void metric_map_t::serializeFrom(
70 mrpt::serialization::CArchive& in, uint8_t version)
80 const auto nPls = in.ReadAs<uint32_t>();
82 for (
auto& pl :
planes) in >> pl.plane >> pl.centroid;
84 const auto nLins = in.ReadAs<uint32_t>();
86 for (
auto& l :
lines) in >> l;
88 const auto nPts = in.ReadAs<uint32_t>();
90 for (std::size_t i = 0; i < nPts; i++)
94 layers[name] = mrpt::ptr_cast<mrpt::maps::CMetricMap>::from(
98 if (version >= 1) { in >>
id >>
label; }
105 if (version >= 2 && in.ReadAs<
bool>())
108 in >> g.geo_coord.lat.decimal_value >>
109 g.geo_coord.lon.decimal_value >> g.geo_coord.height;
110 if (version >= 3) { in >> g.T_enu_to_map; }
111 else { in >> g.T_enu_to_map.mean; }
121 MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(version);
126 -> std::shared_ptr<mrpt::opengl::CSetOfObjects>
129 auto o = mrpt::opengl::CSetOfObjects::Create();
131 get_visualization_planes(*o, p.planes);
132 get_visualization_lines(*o, p.lines);
133 get_visualization_points(*o, p.points);
147 for (
const auto& plane :
planes)
150 mrpt::opengl::CGridPlaneXY::Create(-pw, pw, -pw, pw, .0, pf);
151 gl_pl->setColor_u8(p.
color);
152 mrpt::math::TPose3D planePose;
153 plane.plane.getAsPose3DForcingOrigin(plane.centroid, planePose);
154 gl_pl->setPose(planePose);
166 auto glLin = mrpt::opengl::CSetOfLines::Create();
167 glLin->setColor_u8(p.
color);
169 for (
size_t idxLine = 0; idxLine <
lines.size(); idxLine++)
171 const auto& line =
lines[idxLine];
173 const auto halfSeg = line.director * (0.5 * linLen);
174 glLin->appendLine(line.pBase - halfSeg, line.pBase + halfSeg);
193 const auto itPts =
layers.find(kv.first);
194 if (itPts ==
layers.end())
196 "Rendering parameters given for layer '%s' which does not "
197 "exist in this metric_map_t object",
206 for (
const auto& kv :
layers)
217 const mrpt::maps::CMetricMap::Ptr& map)
219 mrpt::maps::CPointsMap::Ptr pts;
221 auto voxelMap = std::dynamic_pointer_cast<mrpt::maps::CVoxelMap>(map);
222 auto voxelRGBMap = std::dynamic_pointer_cast<mrpt::maps::CVoxelMapRGB>(map);
223 if (voxelMap || voxelRGBMap)
228 if (voxelMap) pts = voxelMap->getOccupiedVoxels();
229 if (voxelRGBMap) pts = voxelRGBMap->getOccupiedVoxels();
236 voxelMap->renderingOptions.generateFreeVoxels =
239 else if (voxelRGBMap)
241 voxelRGBMap->renderingOptions.generateFreeVoxels =
246 map->getVisualizationInto(o);
250 else { pts = std::dynamic_pointer_cast<mrpt::maps::CPointsMap>(map); }
257 map->getVisualizationInto(o);
260 if (
auto glPtsCol = o.getByClass<mrpt::opengl::CPointCloudColoured>();
265 else if (
auto glPts = o.getByClass<mrpt::opengl::CPointCloud>(); glPts)
273 if (pts && pts->empty())
return;
278 auto glPts = mrpt::opengl::CPointCloudColoured::Create();
279 glPts->loadFromPointsMap(pts.get());
283 mrpt::math::TBoundingBoxf bb;
285 const bool hasToAutoFindBB =
286 (!p.
colorMode->colorMapMinCoord.has_value() ||
287 !p.
colorMode->colorMapMaxCoord.has_value());
289 if (hasToAutoFindBB) bb = pts->boundingBox();
291 ASSERT_(p.
colorMode->recolorizeByCoordinate.has_value());
293 const unsigned int coordIdx =
static_cast<unsigned int>(
294 p.
colorMode->recolorizeByCoordinate.value());
295 ASSERT_(coordIdx < 3);
297 float min = bb.min[coordIdx], max = bb.max[coordIdx];
299 if (hasToAutoFindBB &&
300 p.
colorMode->autoBoundingBoxOutliersPercentile.has_value())
302 const float confidenceInterval =
303 *p.
colorMode->autoBoundingBoxOutliersPercentile;
306 for (
int i = 0; i < 3; i++)
307 if (bb.max[i] == bb.min[i]) bb.max[i] = bb.min[i] + 0.1f;
310 constexpr
size_t nBins = 100;
312 std::array<mrpt::math::CHistogram, 3> hists = {
313 mrpt::math::CHistogram(bb.min.x, bb.max.x, nBins),
314 mrpt::math::CHistogram(bb.min.y, bb.max.y, nBins),
315 mrpt::math::CHistogram(bb.min.z, bb.max.z, nBins)};
317 const auto lambdaVisitPoints =
318 [&hists](
const mrpt::math::TPoint3Df&
pt)
320 for (
int i = 0; i < 3; i++) hists[i].
add(
pt[i]);
323 for (
size_t i = 0; i < pts->size(); i++)
325 mrpt::math::TPoint3Df
pt;
326 pts->getPoint(i,
pt.x,
pt.y,
pt.z);
327 lambdaVisitPoints(
pt);
331 std::vector<double> coords;
332 std::vector<double> hits;
334 hists[coordIdx].getHistogramNormalized(coords, hits);
335 mrpt::math::confidenceIntervalsFromHistogram(
336 coords, hits,
min, max, confidenceInterval);
340 const float coordMin = p.
colorMode->colorMapMinCoord.has_value()
344 const float coordMax = p.
colorMode->colorMapMaxCoord.has_value()
348 glPts->recolorizeByCoordinate(
349 coordMin, coordMax, coordIdx, p.
colorMode->colorMap);
356 auto glPts = mrpt::opengl::CPointCloud::Create();
357 glPts->loadFromPointsMap(pts.get());
360 glPts->setColor_u8(p.
color);
376 const std::optional<mrpt::math::TPose3D>& otherRelativePose)
378 mrpt::poses::CPose3D pose;
379 if (otherRelativePose.has_value())
380 pose = mrpt::poses::CPose3D(otherRelativePose.value());
383 if (otherRelativePose.has_value())
387 std::back_inserter(
lines),
388 [&](
const mrpt::math::TLine3D& l)
390 return mrpt::math::TLine3D::FromPointAndDirector(
391 pose.composePoint(l.pBase),
392 pose.rotateVector(l.getDirectorVector()));
399 std::back_inserter(
lines));
403 if (otherRelativePose.has_value())
407 std::back_inserter(
planes),
411 g.centroid = pose.composePoint(l.centroid);
415 THROW_EXCEPTION(
"To-do");
423 std::back_inserter(
planes));
427 for (
const auto& layer : otherPc.
layers)
429 const auto& name = layer.first;
430 const auto& otherMap = layer.second;
433 if (
layers.count(name) == 0)
436 layers[name] = std::dynamic_pointer_cast<mrpt::maps::CMetricMap>(
437 otherMap->duplicateGetSmartPtr());
439 if (otherRelativePose.has_value())
442 std::dynamic_pointer_cast<mrpt::maps::CPointsMap>(
447 pts->changeCoordinatesReference(pose);
452 "Merging with SE(3) transform only available for "
453 "metric maps of point cloud types.");
460 if (
auto pts = std::dynamic_pointer_cast<mrpt::maps::CPointsMap>(
464 pts->insertAnotherMap(
465 std::dynamic_pointer_cast<mrpt::maps::CPointsMap>(otherMap)
472 "Merging with SE(3) transform only available for "
473 "metric maps of point cloud types.");
492 for (
const auto& layer :
layers)
495 std::dynamic_pointer_cast<mrpt::maps::CPointsMap>(layer.second);
506 using namespace std::string_literals;
510 if (
id) ret +=
"id="s + std::to_string(*
id) +
" "s;
514 ret +=
"georeferenced: lat="s +
520 if (
empty())
return {ret +
"empty"s};
524 if (!ret.empty()) ret +=
", "s;
528 if (!
lines.empty()) retAppend(std::to_string(
lines.size()) +
" lines"s);
529 if (!
planes.empty()) retAppend(std::to_string(
planes.size()) +
" planes"s);
531 size_t nPts = 0, nVoxels = 0;
532 bool otherLayers =
false;
533 for (
const auto& layer :
layers)
535 ASSERT_(layer.second);
537 std::dynamic_pointer_cast<mrpt::maps::CPointsMap>(layer.second);
542 else if (
auto vxs = std::dynamic_pointer_cast<mrpt::maps::CVoxelMap>(
546 nVoxels += vxs->grid().activeCellsCount();
552 if (nPts != 0 || nVoxels != 0 || otherLayers)
555 mrpt::system::unitsFormat(
static_cast<double>(nPts), 2,
false) +
557 mrpt::system::unitsFormat(
static_cast<double>(nVoxels), 2,
false) +
558 " voxels in "s + std::to_string(
layers.size()) +
" layers ("s);
560 for (
const auto& layer :
layers)
563 "\""s + layer.first +
"\":"s + layer.second->asString() +
" "s;
573 auto f = mrpt::io::CFileGZOutputStream(fileName);
574 if (!
f.is_open())
return false;
576 auto arch = mrpt::serialization::archiveFrom(
f);
584 auto f = mrpt::io::CFileGZInputStream(fileName);
585 if (!
f.is_open())
return false;
587 auto arch = mrpt::serialization::archiveFrom(
f);
597 return shared_from_this();
599 catch (
const std::bad_weak_ptr&)
609 if (!ret) ret = std::make_shared<metric_map_t>(*
this);
617 return shared_from_this();
619 catch (
const std::bad_weak_ptr&)
629 if (!ret) ret = std::make_shared<metric_map_t>(*
this);
636 auto it =
layers.find(name);
638 THROW_EXCEPTION_FMT(
"Layer '%s' does not exist.", name.c_str());
640 const auto& ptr = it->second;
643 auto ret = std::dynamic_pointer_cast<mrpt::maps::CPointsMap>(ptr);
646 "Layer '%s' is not a point cloud (actual class:'%s').",
647 name.c_str(), ptr->GetRuntimeClass()->className);
653 const mrpt::maps::CMetricMap& map)
655 if (
auto ptsMap =
dynamic_cast<const mrpt::maps::CPointsMap*
>(&map); ptsMap)
659 if (
auto voxelMap =
dynamic_cast<const mrpt::maps::CVoxelMap*
>(&map);
662 return voxelMap->getOccupiedVoxels().get();
664 if (
auto voxelRGBMap =
dynamic_cast<const mrpt::maps::CVoxelMapRGB*
>(&map);
667 return voxelRGBMap->getOccupiedVoxels().get();
674 if (
auto ptsMap =
dynamic_cast<mrpt::maps::CPointsMap*
>(&map); ptsMap)
678 if (
auto voxelMap =
dynamic_cast<mrpt::maps::CVoxelMap*
>(&map); voxelMap)
680 return voxelMap->getOccupiedVoxels().get();
682 if (
auto voxelRGBMap =
dynamic_cast<mrpt::maps::CVoxelMapRGB*
>(&map);
685 return voxelRGBMap->getOccupiedVoxels().get();
691 const mrpt::maps::CMetricMap& map,
bool throwIfNotImplemented)
694 dynamic_cast<const mrpt::maps::NearestNeighborsCapable*
>(&map);
697 if (!throwIfNotImplemented)
return nullptr;
700 "The map of type '%s' does not implement the expected interface "
701 "mrpt::maps::NearestNeighborsCapable",
702 map.GetRuntimeClass()->className);