| 174 | } |
| 175 | |
| 176 | void CandidatePathsGetter::GetBestCandidatePaths(vector<LinkPtr> const & allPaths, bool const isLastPoint, |
| 177 | uint32_t const requiredBearing, double const bearDistM, |
| 178 | m2::PointD const & startPoint, vector<Graph::EdgeVector> & candidates) |
| 179 | { |
| 180 | set<CandidatePath> candidatePaths; |
| 181 | set<CandidatePath> fakeEndingsCandidatePaths; |
| 182 | |
| 183 | BearingPointsSelector pointsSelector(bearDistM, isLastPoint); |
| 184 | for (auto const & l : allPaths) |
| 185 | { |
| 186 | auto const bearStartPoint = pointsSelector.GetStartPoint(l->GetStartEdge()); |
| 187 | auto const startPointsDistance = mercator::DistanceOnEarth(bearStartPoint, startPoint); |
| 188 | |
| 189 | // Number of edges counting from the last one to check bearing on. Accorfing to OpenLR spec |
| 190 | // we have to check bearing on a point that is no longer than 25 meters traveling down the path. |
| 191 | // But sometimes we may skip the best place to stop and generate a candidate. So we check several |
| 192 | // edges before the last one to avoid such a situation. Number of iterations is taken |
| 193 | // by intuition. |
| 194 | // Example: |
| 195 | // o -------- o { Partners segment. } |
| 196 | // o ------- o --- o { Our candidate. } |
| 197 | // ^ 25m |
| 198 | // ^ This one may be better than |
| 199 | // ^ this one. |
| 200 | // So we want to check them all. |
| 201 | uint32_t traceBackIterationsLeft = 3; |
| 202 | for (auto part = l; part; part = part->m_parent) |
| 203 | { |
| 204 | if (traceBackIterationsLeft == 0) |
| 205 | break; |
| 206 | |
| 207 | --traceBackIterationsLeft; |
| 208 | |
| 209 | auto const bearEndPoint = pointsSelector.GetEndPoint(part->m_edge, part->m_distanceM); |
| 210 | |
| 211 | auto const bearing = cpg::Bearing(bearStartPoint, bearEndPoint); |
| 212 | auto const bearingDiff = AbsDifference(bearing, requiredBearing); |
| 213 | auto const pathDistDiff = AbsDifference(part->m_distanceM, bearDistM); |
| 214 | |
| 215 | // TODO(mgsergio): Check bearing is within tolerance. Add to canidates if it is. |
| 216 | |
| 217 | if (part->m_hasFake) |
| 218 | fakeEndingsCandidatePaths.emplace(part, bearingDiff, pathDistDiff, startPointsDistance); |
| 219 | else |
| 220 | candidatePaths.emplace(part, bearingDiff, pathDistDiff, startPointsDistance); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | ASSERT(none_of(begin(candidatePaths), end(candidatePaths), mem_fn(&CandidatePath::HasFakeEndings)), ()); |
| 225 | ASSERT(fakeEndingsCandidatePaths.empty() || any_of(begin(fakeEndingsCandidatePaths), end(fakeEndingsCandidatePaths), |
| 226 | mem_fn(&CandidatePath::HasFakeEndings)), |
| 227 | ()); |
| 228 | |
| 229 | vector<CandidatePath> paths; |
| 230 | copy_n(begin(candidatePaths), min(static_cast<size_t>(kMaxCandidates), candidatePaths.size()), back_inserter(paths)); |
| 231 | |
| 232 | copy_n(begin(fakeEndingsCandidatePaths), |
| 233 | min(static_cast<size_t>(kMaxFakeCandidates), fakeEndingsCandidatePaths.size()), back_inserter(paths)); |
nothing calls this directly
no test coverage detected