| 276 | } |
| 277 | |
| 278 | double ScoreTriangulatedGeometriesByPoints(std::vector<m2::PointD> const & lhs, std::vector<m2::PointD> const & rhs) |
| 279 | { |
| 280 | // The default comparison operator used in sort above (cmp1) and one that is |
| 281 | // used in set_itersection (cmp2) are compatible in that sence that |
| 282 | // cmp2(a, b) :- cmp1(a, b) and |
| 283 | // cmp1(a, b) :- cmp2(a, b) || a almost equal b. |
| 284 | // You can think of cmp2 as !(a >= b). |
| 285 | // But cmp2 is not transitive: |
| 286 | // i.e. !cmp(a, b) && !cmp(b, c) does NOT implies !cmp(a, c), |
| 287 | // |a, b| < eps, |b, c| < eps. |
| 288 | // This could lead to unexpected results in set_itersection (with greedy implementation), |
| 289 | // but we assume such situation is very unlikely. |
| 290 | auto const matched = set_intersection(begin(lhs), end(lhs), begin(rhs), end(rhs), CounterIterator(), |
| 291 | [](m2::PointD const & p1, m2::PointD const & p2) |
| 292 | { |
| 293 | return p1 < p2 && !p1.EqualDxDy(p2, mercator::kPointEqualityEps); |
| 294 | }).GetCount(); |
| 295 | |
| 296 | return static_cast<double>(matched) / static_cast<double>(lhs.size()); |
| 297 | } |
| 298 | } // namespace matcher |
no test coverage detected