Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/stl_iterator.hpp2
-rw-r--r--geometry/algorithm.cpp2
-rw-r--r--geometry/algorithm.hpp67
-rw-r--r--geometry/geometry_tests/algorithm_test.cpp35
-rw-r--r--indexer/edits_migration.cpp60
-rw-r--r--indexer/feature_algo.cpp4
-rw-r--r--std/type_traits.hpp6
7 files changed, 115 insertions, 61 deletions
diff --git a/base/stl_iterator.hpp b/base/stl_iterator.hpp
index f944f27d0d..153c6436fa 100644
--- a/base/stl_iterator.hpp
+++ b/base/stl_iterator.hpp
@@ -4,12 +4,10 @@
namespace detail
{
-
struct Dummy
{
template <class T> Dummy & operator=(T const &) { return *this; }
};
-
}
class CounterIterator :
diff --git a/geometry/algorithm.cpp b/geometry/algorithm.cpp
index 76ebe95f09..e2b57ae2c4 100644
--- a/geometry/algorithm.cpp
+++ b/geometry/algorithm.cpp
@@ -13,7 +13,7 @@ void CalculatePolyLineCenter::operator()(m2::PointD const & pt)
m_poly.emplace_back(pt, m_length);
}
-PointD CalculatePolyLineCenter::GetCenter() const
+PointD CalculatePolyLineCenter::GetResult() const
{
using TIter = vector<Value>::const_iterator;
diff --git a/geometry/algorithm.hpp b/geometry/algorithm.hpp
index 6513bd6885..962f51ed20 100644
--- a/geometry/algorithm.hpp
+++ b/geometry/algorithm.hpp
@@ -3,6 +3,8 @@
#include "geometry/point2d.hpp"
#include "geometry/rect2d.hpp"
+#include "std/type_traits.hpp"
+#include "std/array.hpp"
#include "std/vector.hpp"
namespace m2
@@ -16,7 +18,7 @@ public:
CalculatePolyLineCenter() : m_length(0.0) {}
void operator()(PointD const & pt);
- PointD GetCenter() const;
+ PointD GetResult() const;
private:
struct Value
@@ -40,7 +42,7 @@ public:
CalculatePointOnSurface(RectD const & rect);
void operator()(PointD const & p1, PointD const & p2, PointD const & p3);
- PointD GetCenter() const { return m_center; }
+ PointD GetResult() const { return m_center; }
private:
PointD m_rectCenter;
PointD m_center;
@@ -52,8 +54,67 @@ class CalculateBoundingBox
{
public:
void operator()(PointD const & p);
- RectD GetBoundingBox() const { return m_boundingBox; }
+ RectD GetResult() const { return m_boundingBox; }
private:
RectD m_boundingBox;
};
+
+namespace impl
+{
+template <typename TCalculator, typename TIterator>
+m2::PointD ApplyPointOnSurfaceCalculator(TIterator begin, TIterator end, TCalculator && calc)
+{
+ array<m2::PointD, 3> triangle;
+ while (begin != end)
+ {
+ for (auto i = 0; i < 3; ++i)
+ {
+ // Cannot use ASSERT_NOT_EQUAL, due to absence of an approbriate DebugPrint.
+ ASSERT(begin != end, ("Not enough points to calculate point on surface"));
+ triangle[i] = *begin++;
+ }
+ calc(triangle[0], triangle[1], triangle[2]);
+ }
+ return calc.GetResult();
+}
+
+template <typename TCalculator, typename TIterator>
+auto ApplyCalculator(TIterator begin, TIterator end, TCalculator && calc)
+ -> decltype(calc.GetResult())
+{
+ for (; begin != end; ++begin)
+ calc(*begin);
+ return calc.GetResult();
+}
+
+template <typename TCalculator, typename TIterator>
+auto SelectImplementation(TIterator begin, TIterator end, TCalculator && calc, true_type const &)
+ -> decltype(calc.GetResult())
+{
+ return impl::ApplyPointOnSurfaceCalculator(begin, end, forward<TCalculator>(calc));
+}
+
+template <typename TCalculator, typename TIterator>
+auto SelectImplementation(TIterator begin, TIterator end, TCalculator && calc, false_type const &)
+ -> decltype(calc.GetResult())
+{
+ return impl::ApplyCalculator(begin, end, forward<TCalculator>(calc));
+}
+} // namespace impl
+
+template <typename TCalculator, typename TIterator>
+auto ApplyCalculator(TIterator begin, TIterator end, TCalculator && calc)
+ -> decltype(calc.GetResult())
+{
+ return impl::SelectImplementation(begin, end, forward<TCalculator>(calc),
+ is_same<CalculatePointOnSurface,
+ typename remove_reference<TCalculator>::type>());
+}
+
+template <typename TCalculator, typename TCollection>
+auto ApplyCalculator(TCollection && collection, TCalculator && calc)
+ -> decltype(calc.GetResult())
+{
+ return ApplyCalculator(begin(collection), end(collection), forward<TCalculator>(calc));
+}
} // namespace m2
diff --git a/geometry/geometry_tests/algorithm_test.cpp b/geometry/geometry_tests/algorithm_test.cpp
index 3f349f9791..efde4580c5 100644
--- a/geometry/geometry_tests/algorithm_test.cpp
+++ b/geometry/geometry_tests/algorithm_test.cpp
@@ -14,28 +14,24 @@ namespace
{
PointD GetPolyLineCenter(vector<PointD> const & points)
{
- CalculatePolyLineCenter doCalc;
- for (auto const & p : points)
- doCalc(p);
- return doCalc.GetCenter();
+ return m2::ApplyCalculator(points, m2::CalculatePolyLineCenter());
}
RectD GetBoundingBox(vector<PointD> const & points)
{
- CalculateBoundingBox doCalc;
- for (auto const p : points)
- doCalc(p);
- return doCalc.GetBoundingBox();
+ return m2::ApplyCalculator(points, m2::CalculateBoundingBox());
}
PointD GetPointOnSurface(vector<PointD> const & points)
{
- ASSERT(!points.empty() && points.size() % 3 == 0, ());
- CalculatePointOnSurface doCalc(GetBoundingBox(points));
- for (auto i = 0; i < points.size() - 3; i += 3)
- doCalc(points[i], points[i + 1], points[i + 2]);
- return doCalc.GetCenter();
+ ASSERT(!points.empty() && points.size() % 3 == 0, ("points.size() =", points.size()));
+ auto const boundingBox = GetBoundingBox(points);
+ return m2::ApplyCalculator(points, m2::CalculatePointOnSurface(boundingBox));
+}
+bool PointsAlmostEqual(PointD const & p1, PointD const & p2)
+{
+ return p1.EqualDxDy(p2, 1e-7);
}
} // namespace
@@ -146,21 +142,24 @@ UNIT_TEST(CalculatePointOnSurface)
{
vector<PointD> const points {
{0, 0}, {1, 1}, {2, 0},
- {1, 1}, {2, 0}, {3, 1},
+ {1, 1}, {2, 0}, {3, 1}, // Center of this triangle is used as a result.
{2, 0}, {3, 1}, {4, 0},
{4, 0}, {3, 1}, {4, 2},
- {3, 1}, {4, 2}, {3, 3},
+ {3, 1}, {4, 2}, {3, 3}, // Or this.
{4, 2}, {3, 3}, {4, 4},
{3, 3}, {4, 4}, {2, 4},
- {3, 3}, {2, 4}, {1, 3},
+ {3, 3}, {2, 4}, {1, 3}, // Or this.
{1, 3}, {2, 4}, {0, 4},
{0, 4}, {1, 3}, {0, 2},
- {1, 3}, {0, 2}, {1, 1}, // Center of this triangle is used as a result.
+ {1, 3}, {0, 2}, {1, 1}, // Or this
{0, 2}, {1, 1}, {0, 0},
};
- TEST_EQUAL(GetPointOnSurface(points), PointD(2.0 / 3.0, 2), ());
+ auto const result = GetPointOnSurface(points);
+ TEST(PointsAlmostEqual(result, {10.0 / 3.0, 2}) || PointsAlmostEqual(result, {2, 2.0 / 3.0}) ||
+ PointsAlmostEqual(result, {2, 10.0 / 3.0}) || PointsAlmostEqual(result, {2.0 / 3.0, 2}),
+ ("result = ", result));
}
}
diff --git a/indexer/edits_migration.cpp b/indexer/edits_migration.cpp
index 92beaff9f0..f4f3fbb227 100644
--- a/indexer/edits_migration.cpp
+++ b/indexer/edits_migration.cpp
@@ -5,6 +5,7 @@
#include "indexer/feature.hpp"
#include "base/logging.hpp"
+#include "base/stl_iterator.hpp"
#include "std/algorithm.hpp"
#include "std/unique_ptr.hpp"
@@ -14,46 +15,37 @@ namespace
m2::PointD CalculateCenter(vector<m2::PointD> const & geometry)
{
ASSERT(!geometry.empty() && geometry.size() % 3 == 0,
- ("Invalid geometry should be handled in caller."));
+ ("Invalid geometry should be handled in caller. geometry.size() =", geometry.size()));
- m2::CalculateBoundingBox doCalcBox;
- for (auto const & p : geometry)
- doCalcBox(p);
-
- m2::CalculatePointOnSurface doCalcCenter(doCalcBox.GetBoundingBox());
- for (auto i = 0; i < geometry.size() - 3; i += 3)
- doCalcCenter(geometry[i], geometry[i + 1], geometry[i + 2]);
-
- return doCalcCenter.GetCenter();
+ auto const boundingBox = ApplyCalculator(begin(geometry), end(geometry),
+ m2::CalculateBoundingBox());
+ return ApplyCalculator(begin(geometry), end(geometry), m2::CalculatePointOnSurface(boundingBox));
}
-uint32_t GetGeometriesIntersectionCapacity(vector<m2::PointD> g1,
- vector<m2::PointD> g2)
+uint32_t GetGeometriesIntersectionSize(vector<m2::PointD> g1,
+ vector<m2::PointD> g2)
{
- struct Counter
- {
- Counter & operator++() { return *this; }
- Counter & operator*() { return *this; }
- Counter & operator=(m2::PointD const &)
- {
- ++m_count;
- return *this;
- }
- uint32_t m_count = 0;
- };
-
sort(begin(g1), end(g1));
sort(begin(g2), end(g2));
- Counter counter;
- set_intersection(begin(g1), end(g1),
- begin(g2), end(g2),
- counter, [](m2::PointD const & p1, m2::PointD const & p2)
- {
- // TODO(mgsergio): Use 1e-7 everyware instead of MercatotBounds::GetCellID2PointAbsEpsilon
- return p1 < p2 && !p1.EqualDxDy(p2, 1e-7);
- });
- return counter.m_count;
+ // The default comparison operator used in sort above (cmp1) and one that is
+ // used in set_itersection (cmp2) are compatible in that sence that
+ // cmp2(a, b) :- cmp1(a, b) and
+ // cmp1(a, b) :- cmp2(a, b) || a almost equal b.
+ // You can think of cmp2 as !(a >= b).
+ // But cmp2 is not transitive:
+ // i.e. !cmp(a, b) && !cmp(b, c) does NOT implies !cmp(a, c),
+ // |a, b| < eps, |b, c| < eps.
+ // This could lead to unexpected results in set_itersection (with greedy implementation),
+ // but we assume such situation is very unlikely.
+ return set_intersection(begin(g1), end(g1),
+ begin(g2), end(g2),
+ CounterIterator(), [](m2::PointD const & p1, m2::PointD const & p2)
+ {
+ // TODO(mgsergio): Use 1e-7 everyware instead of
+ // MercatotBounds::GetCellID2PointAbsEpsilon
+ return p1 < p2 && !p1.EqualDxDy(p2, 1e-7);
+ }).GetCount();
}
} // namespace
@@ -104,7 +96,7 @@ FeatureID MigrateWayFeatureIndex(osm::Editor::TForEachFeaturesNearByFn & forEach
return;
++count;
auto const ftGeometry = ft.GetTriangesAsPoints(FeatureType::BEST_GEOMETRY);
- auto matched = GetGeometriesIntersectionCapacity(ftGeometry, geometry);
+ auto matched = GetGeometriesIntersectionSize(ftGeometry, geometry);
auto const score = static_cast<double>(matched) / geometry.size();
if (score > bestScore)
{
diff --git a/indexer/feature_algo.cpp b/indexer/feature_algo.cpp
index 3112d37b0b..25d15e9e58 100644
--- a/indexer/feature_algo.cpp
+++ b/indexer/feature_algo.cpp
@@ -25,7 +25,7 @@ m2::PointD GetCenter(FeatureType const & f, int scale)
{
m2::CalculatePolyLineCenter doCalc;
f.ForEachPoint(doCalc, scale);
- return doCalc.GetCenter();
+ return doCalc.GetResult();
}
default:
@@ -33,7 +33,7 @@ m2::PointD GetCenter(FeatureType const & f, int scale)
ASSERT_EQUAL(type, GEOM_AREA, ());
m2::CalculatePointOnSurface doCalc(f.GetLimitRect(scale));
f.ForEachTriangle(doCalc, scale);
- return doCalc.GetCenter();
+ return doCalc.GetResult();
}
}
}
diff --git a/std/type_traits.hpp b/std/type_traits.hpp
index 00baf5531f..fcbe0f428c 100644
--- a/std/type_traits.hpp
+++ b/std/type_traits.hpp
@@ -18,10 +18,14 @@ using std::is_same;
using std::is_signed;
using std::is_standard_layout;
using std::is_unsigned;
+using std::is_void;
using std::make_signed;
using std::make_unsigned;
+using std::remove_reference;
using std::underlying_type;
-using std::is_void;
+
+using std::false_type;
+using std::true_type;
/// @todo clang on linux doesn't have is_trivially_copyable.
#ifndef OMIM_OS_LINUX