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) {
183 mrpt::keep_max(r.localMax.x,
x);
184 mrpt::keep_max(r.localMax.y, y);
185 mrpt::keep_max(r.localMax.z, z);
187 mrpt::keep_min(r.localMin.x,
x);
188 mrpt::keep_min(r.localMin.y, y);
189 mrpt::keep_min(r.localMin.z, z);
192 const auto& lxs = pcLocal.getPointsBufferRef_x();
193 const auto& lys = pcLocal.getPointsBufferRef_y();
194 const auto& lzs = pcLocal.getPointsBufferRef_z();
196 const size_t nLocalPoints = pcLocal.size();
198 if (maxLocalPoints == 0 || nLocalPoints <= maxLocalPoints)
201 r.x_locals.resize(nLocalPoints);
202 r.y_locals.resize(nLocalPoints);
203 r.z_locals.resize(nLocalPoints);
205 for (
size_t i = 0; i < nLocalPoints; i++)
207 localPose.composePoint(
208 lxs[i], lys[i], lzs[i], r.x_locals[i], r.y_locals[i],
210 lambdaKeepBBox(r.x_locals[i], r.y_locals[i], r.z_locals[i]);
216 r.idxs.emplace(maxLocalPoints);
217 std::iota(r.idxs->begin(), r.idxs->end(), 0);
219 const unsigned int seed =
220 localPointsSampleSeed != 0
221 ? localPointsSampleSeed
222 : std::chrono::system_clock::now().time_since_epoch().count();
224 mrpt::random::partial_shuffle(
225 r.idxs->begin(), r.idxs->end(), std::default_random_engine(seed),
228 r.x_locals.resize(maxLocalPoints);
229 r.y_locals.resize(maxLocalPoints);
230 r.z_locals.resize(maxLocalPoints);
232 for (
size_t ri = 0; ri < maxLocalPoints; ri++)
234 const auto i = (*r.idxs)[ri];
235 localPose.composePoint(
236 lxs[i], lys[i], lzs[i], r.x_locals[ri], r.y_locals[ri],
238 lambdaKeepBBox(r.x_locals[ri], r.y_locals[ri], r.z_locals[ri]);