14 #include <mrpt/random/random_shuffle.h>
24 const mrpt::poses::CPose3D& localPose,
33 for (
const auto& glLayerKV : pcGlobal.
layers)
35 const auto& glLayerName = glLayerKV.first;
38 std::map<std::string, std::optional<double>> localLayers;
46 for (
const auto& kv : itGlob->second)
47 localLayers[kv.first] = kv.second;
52 localLayers[glLayerName] = {};
55 for (
const auto& localWeight : localLayers)
57 const auto& localLayerName = localWeight.first;
58 const bool hasWeight = localWeight.second.has_value();
61 auto itLocal = pcLocal.
layers.find(localLayerName);
62 if (itLocal == pcLocal.
layers.end())
69 "Local pointcloud layer '%s' not found matching global "
71 localLayerName.c_str(), glLayerName.c_str());
74 const mrpt::maps::CMetricMap::Ptr& glLayer = glLayerKV.second;
77 const mrpt::maps::CMetricMap::Ptr& lcLayerMap = itLocal->second;
82 "Local layer map must be a point cloud, but found type "
84 lcLayerMap->GetRuntimeClass()->className);
86 const size_t nBefore =
out.paired_pt2pt.size();
93 glLayerPts->kdtree_search_params.leaf_max_size !=
96 glLayerPts->kdtree_search_params.leaf_max_size =
98 glLayerPts->mark_as_modified();
104 *glLayer, *lcLayer, localPose, ms, glLayerName, localLayerName,
107 const size_t nAfter =
out.paired_pt2pt.size();
109 if (hasWeight && nAfter != nBefore)
111 const double w = localWeight.second.value();
112 out.point_weights.emplace_back(nAfter - nBefore, w);
124 if (params.has(
"pointLayerMatches"))
126 auto& p = params[
"pointLayerMatches"];
129 ASSERT_(p.isSequence());
135 for (
const auto& entry : p.asSequence())
137 ASSERT_(entry.isMap());
138 const auto& em = entry.asMap();
140 ASSERT_(em.count(
"global"));
141 ASSERT_(em.count(
"local"));
146 em.count(
"weight") != 0 ? em.at(
"weight").as<
double>() : 1.0;
162 "allowMatchAlreadyMatchedGlobalPoints",
165 if (
auto val = params.getOrDefault(
"kdtree_leaf_max_points", 0); val > 0)
169 "bounding_box_intersection_check_epsilon",
175 const mrpt::maps::CPointsMap& pcLocal,
176 const mrpt::poses::CPose3D& localPose,
const std::size_t maxLocalPoints,
177 const uint64_t localPointsSampleSeed)
182 const auto lambdaKeepBBox = [&](
float x,
float y,
float z)
184 mrpt::keep_max(r.localMax.x,
x);
185 mrpt::keep_max(r.localMax.y, y);
186 mrpt::keep_max(r.localMax.z, z);
188 mrpt::keep_min(r.localMin.x,
x);
189 mrpt::keep_min(r.localMin.y, y);
190 mrpt::keep_min(r.localMin.z, z);
193 const auto& lxs = pcLocal.getPointsBufferRef_x();
194 const auto& lys = pcLocal.getPointsBufferRef_y();
195 const auto& lzs = pcLocal.getPointsBufferRef_z();
197 const size_t nLocalPoints = pcLocal.size();
199 if (maxLocalPoints == 0 || nLocalPoints <= maxLocalPoints)
202 r.x_locals.resize(nLocalPoints);
203 r.y_locals.resize(nLocalPoints);
204 r.z_locals.resize(nLocalPoints);
206 for (
size_t i = 0; i < nLocalPoints; i++)
208 localPose.composePoint(
209 lxs[i], lys[i], lzs[i], r.x_locals[i], r.y_locals[i],
211 lambdaKeepBBox(r.x_locals[i], r.y_locals[i], r.z_locals[i]);
217 r.idxs.emplace(maxLocalPoints);
218 std::iota(r.idxs->begin(), r.idxs->end(), 0);
220 const unsigned int seed =
221 localPointsSampleSeed != 0
222 ? localPointsSampleSeed
223 : std::chrono::system_clock::now().time_since_epoch().count();
225 mrpt::random::partial_shuffle(
226 r.idxs->begin(), r.idxs->end(), std::default_random_engine(seed),
229 r.x_locals.resize(maxLocalPoints);
230 r.y_locals.resize(maxLocalPoints);
231 r.z_locals.resize(maxLocalPoints);
233 for (
size_t ri = 0; ri < maxLocalPoints; ri++)
235 const auto i = (*r.idxs)[ri];
236 localPose.composePoint(
237 lxs[i], lys[i], lzs[i], r.x_locals[ri], r.y_locals[ri],
239 lambdaKeepBBox(r.x_locals[ri], r.y_locals[ri], r.z_locals[ri]);