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:
authorMaxim Pimenov <m@maps.me>2018-07-27 15:09:39 +0300
committerVladimir Byko-Ianko <bykoianko@gmail.com>2018-08-01 13:45:25 +0300
commit2bc35257235bd3e4a6c6ba94f44d3eea8ad6a8fd (patch)
tree69e9ba2d4d8730cf56a1aebb0e6721faaee0bb05 /geometry
parent159e70c4f76754f884b97f11d869ee0bd4bd338b (diff)
[geometry] Functors instead of factories in simplification.hpp.
Diffstat (limited to 'geometry')
-rw-r--r--geometry/geometry_tests/simplification_test.cpp45
-rw-r--r--geometry/parametrized_segment.hpp21
-rw-r--r--geometry/simplification.hpp41
3 files changed, 55 insertions, 52 deletions
diff --git a/geometry/geometry_tests/simplification_test.cpp b/geometry/geometry_tests/simplification_test.cpp
index 81748256aa..b9e26aea69 100644
--- a/geometry/geometry_tests/simplification_test.cpp
+++ b/geometry/geometry_tests/simplification_test.cpp
@@ -19,18 +19,10 @@ using namespace std;
namespace
{
-struct DistanceFact
-{
- m2::ParametrizedSegment<m2::PointD> operator()(m2::PointD const & p0, m2::PointD const & p1) const
- {
- return m2::ParametrizedSegment<m2::PointD>(p0, p1);
- }
-};
-
using P = m2::PointD;
+using DistanceFn = m2::SquaredDistanceFromSegmentToPoint<P>;
using PointOutput = BackInsertFunctor<vector<m2::PointD>>;
-typedef void (*SimplifyFn)(m2::PointD const *, m2::PointD const *, double, DistanceFact,
- PointOutput);
+typedef void (*SimplifyFn)(m2::PointD const *, m2::PointD const *, double, DistanceFn, PointOutput);
struct LargePolylineTestData
{
@@ -46,7 +38,7 @@ void TestSimplificationSmoke(SimplifyFn simplifyFn)
m2::PointD const points[] = {P(0.0, 1.0), P(2.2, 3.6), P(3.2, 3.6)};
double const epsilon = 0.1;
vector<m2::PointD> result, expectedResult(points, points + 3);
- simplifyFn(points, points + 3, epsilon, DistanceFact(), MakeBackInsertFunctor(result));
+ simplifyFn(points, points + 3, epsilon, DistanceFn(), MakeBackInsertFunctor(result));
TEST_EQUAL(result, expectedResult, (epsilon));
}
@@ -56,7 +48,7 @@ void TestSimplificationOfLine(SimplifyFn simplifyFn)
for (double epsilon = numeric_limits<double>::denorm_min(); epsilon < 1000; epsilon *= 2)
{
vector<m2::PointD> result, expectedResult(points, points + 2);
- simplifyFn(points, points + 2, epsilon, DistanceFact(), MakeBackInsertFunctor(result));
+ simplifyFn(points, points + 2, epsilon, DistanceFn(), MakeBackInsertFunctor(result));
TEST_EQUAL(result, expectedResult, (epsilon));
}
}
@@ -66,7 +58,7 @@ void TestSimplificationOfPoly(m2::PointD const * points, size_t count, SimplifyF
for (double epsilon = 0.00001; epsilon < 0.11; epsilon *= 10)
{
vector<m2::PointD> result;
- simplifyFn(points, points + count, epsilon, DistanceFact(), MakeBackInsertFunctor(result));
+ simplifyFn(points, points + count, epsilon, DistanceFn(), MakeBackInsertFunctor(result));
// LOG(LINFO, ("eps:", epsilon, "size:", result.size()));
TEST_GREATER(result.size(), 1, ());
@@ -76,24 +68,23 @@ void TestSimplificationOfPoly(m2::PointD const * points, size_t count, SimplifyF
}
}
-void SimplifyNearOptimal10(m2::PointD const * f, m2::PointD const * l, double e,
- DistanceFact distFact, PointOutput out)
+void SimplifyNearOptimal10(m2::PointD const * f, m2::PointD const * l, double e, DistanceFn distFn,
+ PointOutput out)
{
- SimplifyNearOptimal(10, f, l, e, distFact, out);
+ SimplifyNearOptimal(10, f, l, e, distFn, out);
}
-void SimplifyNearOptimal20(m2::PointD const * f, m2::PointD const * l, double e,
- DistanceFact distFact, PointOutput out)
+void SimplifyNearOptimal20(m2::PointD const * f, m2::PointD const * l, double e, DistanceFn distFn,
+ PointOutput out)
{
- SimplifyNearOptimal(20, f, l, e, distFact, out);
+ SimplifyNearOptimal(20, f, l, e, distFn, out);
}
void CheckDPStrict(P const * arr, size_t n, double eps, size_t expectedCount)
{
vector<P> vec;
- DistanceFact distFact;
- SimplifyDP(arr, arr + n, eps, distFact,
- AccumulateSkipSmallTrg<DistanceFact, P>(distFact, vec, eps));
+ DistanceFn distFn;
+ SimplifyDP(arr, arr + n, eps, distFn, AccumulateSkipSmallTrg<DistanceFn, P>(distFn, vec, eps));
TEST_GREATER(vec.size(), 1, ());
TEST_EQUAL(arr[0], vec.front(), ());
@@ -106,8 +97,8 @@ void CheckDPStrict(P const * arr, size_t n, double eps, size_t expectedCount)
for (size_t i = 2; i < vec.size(); ++i)
{
- auto const d = DistanceFact()(vec[i - 2], vec[i]);
- TEST_GREATER_OR_EQUAL(d.SquaredDistanceToPoint(vec[i - 1]), eps, ());
+ auto const d = DistanceFn();
+ TEST_GREATER_OR_EQUAL(d(vec[i - 2], vec[i], vec[i - 1]), eps, ());
}
}
} // namespace
@@ -118,14 +109,14 @@ UNIT_TEST(Simplification_TestDataIsCorrect)
// LOG(LINFO, ("Polyline test size:", LargePolylineTestData::m_Size));
}
-UNIT_TEST(Simplification_DP_Smoke) { TestSimplificationSmoke(&SimplifyDP<DistanceFact>); }
+UNIT_TEST(Simplification_DP_Smoke) { TestSimplificationSmoke(&SimplifyDP<DistanceFn>); }
-UNIT_TEST(Simplification_DP_Line) { TestSimplificationOfLine(&SimplifyDP<DistanceFact>); }
+UNIT_TEST(Simplification_DP_Line) { TestSimplificationOfLine(&SimplifyDP<DistanceFn>); }
UNIT_TEST(Simplification_DP_Polyline)
{
TestSimplificationOfPoly(LargePolylineTestData::m_Data, LargePolylineTestData::m_Size,
- &SimplifyDP<DistanceFact>);
+ &SimplifyDP<DistanceFn>);
}
UNIT_TEST(Simplification_Opt_Smoke) { TestSimplificationSmoke(&SimplifyNearOptimal10); }
diff --git a/geometry/parametrized_segment.hpp b/geometry/parametrized_segment.hpp
index b684659171..b79e9cc913 100644
--- a/geometry/parametrized_segment.hpp
+++ b/geometry/parametrized_segment.hpp
@@ -1,5 +1,3 @@
-// todo(@m) Do we need helpers like ClosestPointTo(p0, p1)?
-
#pragma once
#include "geometry/point2d.hpp"
@@ -16,12 +14,12 @@ namespace m2
// The parametrization is of the form
// p(t) = p0 + t * dir.
// Other conditions:
-// dir is normalized (p1 - p0)
+// dir is the normalized (p1 - p0) vector.
// length(dir) = 1.
// p(0) = p0.
// p(T) = p1 with T = length(p1 - p0).
//
-// The points with t in [0, T] correspond to the points of the segment.
+// The points with t in [0, T] are the points of the segment.
template <typename Point>
class ParametrizedSegment
{
@@ -78,4 +76,19 @@ public:
m2::PointD m_d;
double m_length;
};
+
+// This functor is here only for backward compatibility. It is not obvious
+// when looking at a call site whether x should be the first or the last parameter to the fuction.
+// For readability, consider creating a parametrized segment and using its methods instead
+// of using this functor.
+template <typename Point>
+struct SquaredDistanceFromSegmentToPoint
+{
+ // Returns squared distance from the segment [a, b] to the point x.
+ double operator()(Point const & a, Point const & b, Point const & x) const
+ {
+ ParametrizedSegment<Point> segment(a, b);
+ return segment.SquaredDistanceToPoint(x);
+ }
+};
} // namespace m2
diff --git a/geometry/simplification.hpp b/geometry/simplification.hpp
index f04ad3ac54..95e63b68ae 100644
--- a/geometry/simplification.hpp
+++ b/geometry/simplification.hpp
@@ -20,17 +20,16 @@ namespace impl
{
///@name This functions take input range NOT like STL does: [first, last].
//@{
-template <typename SegmentFact, typename Iter>
-std::pair<double, Iter> MaxDistance(Iter first, Iter last, SegmentFact & segFact)
+template <typename DistanceFn, typename Iter>
+std::pair<double, Iter> MaxDistance(Iter first, Iter last, DistanceFn & distFn)
{
std::pair<double, Iter> res(0.0, last);
if (std::distance(first, last) <= 1)
return res;
- auto const segment = segFact(m2::PointD(*first), m2::PointD(*last));
for (Iter i = first + 1; i != last; ++i)
{
- double const d = segment.SquaredDistanceToPoint(m2::PointD(*i));
+ double const d = distFn(m2::PointD(*first), m2::PointD(*last), m2::PointD(*i));
if (res.first < d)
{
res.first = d;
@@ -42,18 +41,18 @@ std::pair<double, Iter> MaxDistance(Iter first, Iter last, SegmentFact & segFact
}
// Actual SimplifyDP implementation.
-template <typename SegmentFact, typename Iter, typename Out>
-void SimplifyDP(Iter first, Iter last, double epsilon, SegmentFact & segFact, Out & out)
+template <typename DistanceFn, typename Iter, typename Out>
+void SimplifyDP(Iter first, Iter last, double epsilon, DistanceFn & distFn, Out & out)
{
- std::pair<double, Iter> maxDist = impl::MaxDistance(first, last, segFact);
+ std::pair<double, Iter> maxDist = impl::MaxDistance(first, last, distFn);
if (maxDist.second == last || maxDist.first < epsilon)
{
out(*last);
}
else
{
- impl::SimplifyDP(first, maxDist.second, epsilon, segFact, out);
- impl::SimplifyDP(maxDist.second, last, epsilon, segFact, out);
+ impl::SimplifyDP(first, maxDist.second, epsilon, distFn, out);
+ impl::SimplifyDP(maxDist.second, last, epsilon, distFn, out);
}
}
//@}
@@ -72,13 +71,13 @@ struct SimplifyOptimalRes
// Douglas-Peucker algorithm for STL-like range [beg, end).
// Iteratively includes the point with max distance from the current simplification.
// Average O(n log n), worst case O(n^2).
-template <typename SegmentFact, typename Iter, typename Out>
-void SimplifyDP(Iter beg, Iter end, double epsilon, SegmentFact segFact, Out out)
+template <typename DistanceFn, typename Iter, typename Out>
+void SimplifyDP(Iter beg, Iter end, double epsilon, DistanceFn distFn, Out out)
{
if (beg != end)
{
out(*beg);
- impl::SimplifyDP(beg, end - 1, epsilon, segFact, out);
+ impl::SimplifyDP(beg, end - 1, epsilon, distFn, out);
}
}
@@ -88,9 +87,9 @@ void SimplifyDP(Iter beg, Iter end, double epsilon, SegmentFact segFact, Out out
// which limits the number of points to try, that produce error > epsilon.
// Essentially, it's a trade-off between optimality and performance.
// Values around 20 - 200 are reasonable.
-template <typename SegmentFact, typename Iter, typename Out>
+template <typename DistanceFn, typename Iter, typename Out>
void SimplifyNearOptimal(int kMaxFalseLookAhead, Iter beg, Iter end, double epsilon,
- SegmentFact segFact, Out out)
+ DistanceFn distFn, Out out)
{
int32_t const n = static_cast<int32_t>(end - beg);
if (n <= 2)
@@ -109,7 +108,7 @@ void SimplifyNearOptimal(int kMaxFalseLookAhead, Iter beg, Iter end, double epsi
uint32_t const newPointCount = F[j].m_PointCount + 1;
if (newPointCount < F[i].m_PointCount)
{
- if (impl::MaxDistance(beg + i, beg + j, segFact).first < epsilon)
+ if (impl::MaxDistance(beg + i, beg + j, distFn).first < epsilon)
{
F[i].m_NextPoint = j;
F[i].m_PointCount = newPointCount;
@@ -128,12 +127,12 @@ void SimplifyNearOptimal(int kMaxFalseLookAhead, Iter beg, Iter end, double epsi
// Additional points filter to use in simplification.
// SimplifyDP can produce points that define degenerate triangle.
-template <class SegmentFact, class Point>
+template <class DistanceFn, class Point>
class AccumulateSkipSmallTrg
{
public:
- AccumulateSkipSmallTrg(SegmentFact & segFact, std::vector<Point> & vec, double eps)
- : m_segFact(segFact), m_vec(vec), m_eps(eps)
+ AccumulateSkipSmallTrg(DistanceFn & distFn, std::vector<Point> & vec, double eps)
+ : m_distFn(distFn), m_vec(vec), m_eps(eps)
{
}
@@ -143,8 +142,8 @@ public:
size_t count;
while ((count = m_vec.size()) >= 2)
{
- auto const segment = m_segFact(m2::PointD(m_vec[count - 2]), m2::PointD(p));
- if (segment.SquaredDistanceToPoint(m2::PointD(m_vec[count - 1])) < m_eps)
+ if (m_distFn(m2::PointD(m_vec[count - 2]), m2::PointD(p), m2::PointD(m_vec[count - 1])) <
+ m_eps)
m_vec.pop_back();
else
break;
@@ -154,7 +153,7 @@ public:
}
private:
- SegmentFact & m_segFact;
+ DistanceFn & m_distFn;
std::vector<Point> & m_vec;
double m_eps;
};