Use iterators for DouglasPeucker

This commit is contained in:
Patrick Niklaus 2014-08-24 23:47:56 +02:00
parent 651c07c724
commit 7d425aa76f
3 changed files with 31 additions and 29 deletions

View File

@ -106,37 +106,38 @@ DouglasPeucker::DouglasPeucker()
{ {
} }
void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level) void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level)
{ {
// check if input data is invalid // check if input data is invalid
BOOST_ASSERT_MSG(!input_geometry.empty(), "geometry invalid"); BOOST_ASSERT_MSG(begin != end, "geometry invalid");
if (input_geometry.size() < 2) unsigned size = std::distance(begin, end);
if (size < 2)
{ {
return; return;
} }
input_geometry.front().necessary = true; begin->necessary = true;
input_geometry.back().necessary = true; std::prev(end)->necessary = true;
{ {
BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level"); BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
unsigned left_border = 0; RandomAccessIt left_border = begin;
unsigned right_border = 1; RandomAccessIt right_border = std::next(begin);
// Sweep over array and identify those ranges that need to be checked // Sweep over array and identify those ranges that need to be checked
do do
{ {
// traverse list until new border element found // traverse list until new border element found
if (input_geometry[right_border].necessary) if (right_border->necessary)
{ {
// sanity checks // sanity checks
BOOST_ASSERT(input_geometry[left_border].necessary); BOOST_ASSERT(left_border->necessary);
BOOST_ASSERT(input_geometry[right_border].necessary); BOOST_ASSERT(right_border->necessary);
recursion_stack.emplace(left_border, right_border); recursion_stack.emplace(left_border, right_border);
left_border = right_border; left_border = right_border;
} }
++right_border; ++right_border;
} while (right_border < input_geometry.size()); } while (right_border != end);
} }
// mark locations as 'necessary' by divide-and-conquer // mark locations as 'necessary' by divide-and-conquer
@ -146,24 +147,23 @@ void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const
const GeometryRange pair = recursion_stack.top(); const GeometryRange pair = recursion_stack.top();
recursion_stack.pop(); recursion_stack.pop();
// sanity checks // sanity checks
BOOST_ASSERT_MSG(input_geometry[pair.first].necessary, "left border mus be necessary"); BOOST_ASSERT_MSG(pair.first->necessary, "left border mus be necessary");
BOOST_ASSERT_MSG(input_geometry[pair.second].necessary, "right border must be necessary"); BOOST_ASSERT_MSG(pair.second->necessary, "right border must be necessary");
BOOST_ASSERT_MSG(pair.second < input_geometry.size(), "right border outside of geometry"); BOOST_ASSERT_MSG(std::distance(pair.second, end) > 0, "right border outside of geometry");
BOOST_ASSERT_MSG(pair.first < pair.second, "left border on the wrong side"); BOOST_ASSERT_MSG(std::distance(pair.first, pair.second) >= 0, "left border on the wrong side");
int max_int_distance = 0; int max_int_distance = 0;
unsigned farthest_entry_index = pair.second; auto farthest_entry_it = pair.second;
const CoordinatePairCalculator dist_calc(input_geometry[pair.first].location, const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location);
input_geometry[pair.second].location);
// sweep over range to find the maximum // sweep over range to find the maximum
for (const auto i : osrm::irange(pair.first + 1, pair.second)) for (auto it = std::next(pair.first); it != pair.second; ++it)
{ {
const int distance = dist_calc(input_geometry[i].location); const int distance = dist_calc(it->location);
// found new feasible maximum? // found new feasible maximum?
if (distance > max_int_distance && distance > douglas_peucker_thresholds[zoom_level]) if (distance > max_int_distance && distance > douglas_peucker_thresholds[zoom_level])
{ {
farthest_entry_index = i; farthest_entry_it = it;
max_int_distance = distance; max_int_distance = distance;
} }
} }
@ -172,14 +172,14 @@ void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const
if (max_int_distance > douglas_peucker_thresholds[zoom_level]) if (max_int_distance > douglas_peucker_thresholds[zoom_level])
{ {
// mark idx as necessary // mark idx as necessary
input_geometry[farthest_entry_index].necessary = true; farthest_entry_it->necessary = true;
if (1 < (farthest_entry_index - pair.first)) if (1 < std::distance(pair.first, farthest_entry_it))
{ {
recursion_stack.emplace(pair.first, farthest_entry_index); recursion_stack.emplace(pair.first, farthest_entry_it);
} }
if (1 < (pair.second - farthest_entry_index)) if (1 < std::distance(pair.second, farthest_entry_it))
{ {
recursion_stack.emplace(farthest_entry_index, pair.second); recursion_stack.emplace(farthest_entry_it, pair.second);
} }
} }
} }

View File

@ -43,16 +43,18 @@ struct SegmentInformation;
class DouglasPeucker class DouglasPeucker
{ {
public:
using RandomAccessIt = std::vector<SegmentInformation>::iterator;
private: private:
std::vector<int> douglas_peucker_thresholds; std::vector<int> douglas_peucker_thresholds;
using GeometryRange = std::pair<unsigned, unsigned>; using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>;
// Stack to simulate the recursion // Stack to simulate the recursion
std::stack<GeometryRange> recursion_stack; std::stack<GeometryRange> recursion_stack;
public: public:
DouglasPeucker(); DouglasPeucker();
void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level); void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level);
}; };
#endif /* DOUGLASPEUCKER_H_ */ #endif /* DOUGLASPEUCKER_H_ */

View File

@ -190,7 +190,7 @@ class DescriptionFactory
} }
// Generalize poly line // Generalize poly line
polyline_generalizer.Run(path_description, zoomLevel); polyline_generalizer.Run(path_description.begin(), path_description.end(), zoomLevel);
// fix what needs to be fixed else // fix what needs to be fixed else
unsigned necessary_pieces = 0; // a running index that counts the necessary pieces unsigned necessary_pieces = 0; // a running index that counts the necessary pieces