| 1260 | |
| 1261 | template <class FnT> |
| 1262 | void Geocoder::CentersFilter::ClusterizeStreets(std::vector<uint32_t> & streets, Geocoder const & geocoder, |
| 1263 | FnT && fn) const |
| 1264 | { |
| 1265 | std::vector<std::tuple<double, m2::PointD, uint32_t>> loadedStreets; |
| 1266 | loadedStreets.reserve(streets.size()); |
| 1267 | |
| 1268 | // Calculate {distance, center, feature id}. |
| 1269 | for (uint32_t fid : streets) |
| 1270 | { |
| 1271 | m2::PointD ftCenter; |
| 1272 | if (geocoder.m_context->GetCenter(fid, ftCenter)) |
| 1273 | { |
| 1274 | double minDist = std::numeric_limits<double>::max(); |
| 1275 | for (auto const & c : m_centers) |
| 1276 | minDist = std::min(minDist, ftCenter.Length(c)); |
| 1277 | loadedStreets.emplace_back(minDist, ftCenter, fid); |
| 1278 | } |
| 1279 | else |
| 1280 | { |
| 1281 | // In general, we don't have centers for newly created features, but editor doesn't support streets now. |
| 1282 | ASSERT(false, ("Street feature without table's center")); |
| 1283 | } |
| 1284 | } |
| 1285 | |
| 1286 | // Sort by distance. |
| 1287 | std::sort(loadedStreets.begin(), loadedStreets.end(), |
| 1288 | [](auto const & t1, auto const & t2) { return std::get<0>(t1) < std::get<0>(t2); }); |
| 1289 | |
| 1290 | buffer_vector<m2::RectD, 2> rects(m_centers.size()); |
| 1291 | for (size_t i = 0; i < rects.size(); ++i) |
| 1292 | { |
| 1293 | rects[i] = mercator::RectByCenterXYAndSizeInMeters(m_centers[i], |
| 1294 | geocoder.m_params.m_filteringParams.m_streetSearchRadiusM); |
| 1295 | } |
| 1296 | |
| 1297 | // Find the first (after m_maxStreetsCount) street that is out of the rect's bounds |
| 1298 | size_t count = std::min(loadedStreets.size(), geocoder.m_params.m_filteringParams.m_maxStreetsCount); |
| 1299 | for (; count < loadedStreets.size(); ++count) |
| 1300 | { |
| 1301 | bool const outside = |
| 1302 | std::all_of(rects.begin(), rects.end(), [pt = std::get<1>(loadedStreets[count])](m2::RectD const & rect) |
| 1303 | { return !rect.IsPointInside(pt); }); |
| 1304 | if (outside) |
| 1305 | break; |
| 1306 | } |
| 1307 | |
| 1308 | // Emit results. |
| 1309 | streets.clear(); |
| 1310 | if (count == 0) |
| 1311 | return; |
| 1312 | |
| 1313 | double firstDist = std::get<0>(loadedStreets[0]); |
| 1314 | for (size_t i = 0; i < count; ++i) |
| 1315 | { |
| 1316 | double const currDist = std::get<0>(loadedStreets[i]); |
| 1317 | if (currDist - firstDist > geocoder.m_params.m_filteringParams.m_streetClusterRadiusMercator) |
| 1318 | { |
| 1319 | std::sort(streets.begin(), streets.end()); |
no test coverage detected