diff options
author | Sergey Magidovich <mgsergio@mapswithme.com> | 2016-02-13 19:04:32 +0300 |
---|---|---|
committer | Sergey Yershov <yershov@corp.mail.ru> | 2016-03-23 16:20:48 +0300 |
commit | fdaa9d6cf6496e0cf6b42ee864b90e7df778ce9c (patch) | |
tree | b1ba1e94089da588a6eaa13d6a123484ae5c430b /geometry | |
parent | 138798419bd017ea5236b5e24f43149b1881a35c (diff) |
Code review and refactoring of geometry/algorithm.
Diffstat (limited to 'geometry')
-rw-r--r-- | geometry/algorithm.cpp | 2 | ||||
-rw-r--r-- | geometry/algorithm.hpp | 67 | ||||
-rw-r--r-- | geometry/geometry_tests/algorithm_test.cpp | 35 |
3 files changed, 82 insertions, 22 deletions
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)); } } |