Make DouglasPeucker a free standing function
This commit is contained in:
parent
23cd4d5ed2
commit
c590596dbe
@ -4,7 +4,6 @@
|
|||||||
#include "guidance/segment_list.hpp"
|
#include "guidance/segment_list.hpp"
|
||||||
#include "guidance/textual_route_annotation.hpp"
|
#include "guidance/textual_route_annotation.hpp"
|
||||||
|
|
||||||
#include "engine/douglas_peucker.hpp"
|
|
||||||
#include "engine/internal_route_result.hpp"
|
#include "engine/internal_route_result.hpp"
|
||||||
#include "engine/object_encoder.hpp"
|
#include "engine/object_encoder.hpp"
|
||||||
#include "engine/phantom_node.hpp"
|
#include "engine/phantom_node.hpp"
|
||||||
@ -261,7 +260,8 @@ ApiResponseGenerator<DataFacadeT>::BuildRouteSegments(const Segments &segment_li
|
|||||||
(extractor::TurnInstruction::EnterRoundAbout != current_turn))
|
(extractor::TurnInstruction::EnterRoundAbout != current_turn))
|
||||||
{
|
{
|
||||||
|
|
||||||
detail::Segment seg = {segment.name_id, static_cast<int32_t>(segment.length),
|
detail::Segment seg = {segment.name_id,
|
||||||
|
static_cast<int32_t>(segment.length),
|
||||||
static_cast<std::size_t>(result.size())};
|
static_cast<std::size_t>(result.size())};
|
||||||
result.emplace_back(std::move(seg));
|
result.emplace_back(std::move(seg));
|
||||||
}
|
}
|
||||||
|
@ -3,24 +3,16 @@
|
|||||||
|
|
||||||
#include "engine/segment_information.hpp"
|
#include "engine/segment_information.hpp"
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <stack>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
namespace engine
|
namespace engine
|
||||||
{
|
{
|
||||||
|
namespace detail
|
||||||
/* This class object computes the bitvector of indicating generalized input
|
{
|
||||||
* points according to the (Ramer-)Douglas-Peucker algorithm.
|
const constexpr int DOUGLAS_PEUCKER_THRESHOLDS[19] = {
|
||||||
*
|
|
||||||
* Input is vector of pairs. Each pair consists of the point information and a
|
|
||||||
* bit indicating if the points is present in the generalization.
|
|
||||||
* Note: points may also be pre-selected*/
|
|
||||||
|
|
||||||
static const std::array<int, 19> DOUGLAS_PEUCKER_THRESHOLDS{{
|
|
||||||
512440, // z0
|
512440, // z0
|
||||||
256720, // z1
|
256720, // z1
|
||||||
122560, // z2
|
122560, // z2
|
||||||
@ -39,22 +31,28 @@ static const std::array<int, 19> DOUGLAS_PEUCKER_THRESHOLDS{{
|
|||||||
20, // z15
|
20, // z15
|
||||||
8, // z16
|
8, // z16
|
||||||
6, // z17
|
6, // z17
|
||||||
4 // z18
|
4, // z18
|
||||||
}};
|
|
||||||
|
|
||||||
class DouglasPeucker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using RandomAccessIt = std::vector<SegmentInformation>::iterator;
|
|
||||||
|
|
||||||
using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>;
|
|
||||||
// Stack to simulate the recursion
|
|
||||||
std::stack<GeometryRange> recursion_stack;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level);
|
|
||||||
void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const constexpr auto DOUGLAS_PEUCKER_THRESHOLDS_SIZE =
|
||||||
|
sizeof(DOUGLAS_PEUCKER_THRESHOLDS) / sizeof(*DOUGLAS_PEUCKER_THRESHOLDS);
|
||||||
|
} // ns detail
|
||||||
|
|
||||||
|
// These functions compute the bitvector of indicating generalized input
|
||||||
|
// points according to the (Ramer-)Douglas-Peucker algorithm.
|
||||||
|
//
|
||||||
|
// Input is vector of pairs. Each pair consists of the point information and a
|
||||||
|
// bit indicating if the points is present in the generalization.
|
||||||
|
// Note: points may also be pre-selected*/
|
||||||
|
void douglasPeucker(std::vector<SegmentInformation>::iterator begin,
|
||||||
|
std::vector<SegmentInformation>::iterator end,
|
||||||
|
const unsigned zoom_level);
|
||||||
|
|
||||||
|
// Convenience range-based function
|
||||||
|
inline void douglasPeucker(std::vector<SegmentInformation> &geometry, const unsigned zoom_level)
|
||||||
|
{
|
||||||
|
douglasPeucker(begin(geometry), end(geometry), zoom_level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,14 +272,13 @@ void SegmentList<DataFacadeT>::Finalize(const bool extract_alternative,
|
|||||||
|
|
||||||
if (allow_simplification)
|
if (allow_simplification)
|
||||||
{
|
{
|
||||||
DouglasPeucker polyline_generalizer;
|
douglasPeucker(segments, zoom_level);
|
||||||
polyline_generalizer.Run(segments.begin(), segments.end(), zoom_level);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t necessary_segments = 0; // a running index that counts the necessary pieces
|
std::uint32_t necessary_segments = 0; // a running index that counts the necessary pieces
|
||||||
via_indices.push_back(0);
|
via_indices.push_back(0);
|
||||||
const auto markNecessarySegments = [this, &necessary_segments](SegmentInformation &first,
|
const auto markNecessarySegments =
|
||||||
const SegmentInformation &second)
|
[this, &necessary_segments](SegmentInformation &first, const SegmentInformation &second)
|
||||||
{
|
{
|
||||||
if (!first.necessary)
|
if (!first.necessary)
|
||||||
return;
|
return;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
#include "engine/douglas_peucker.hpp"
|
#include "engine/douglas_peucker.hpp"
|
||||||
|
|
||||||
#include "engine/segment_information.hpp"
|
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include "osrm/coordinate.hpp"
|
#include "osrm/coordinate.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <stack>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
{
|
{
|
||||||
@ -59,13 +59,15 @@ struct CoordinatePairCalculator
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
|
void douglasPeucker(std::vector<SegmentInformation>::iterator begin,
|
||||||
|
std::vector<SegmentInformation>::iterator end,
|
||||||
|
const unsigned zoom_level)
|
||||||
{
|
{
|
||||||
Run(std::begin(input_geometry), std::end(input_geometry), zoom_level);
|
using Iter = decltype(begin);
|
||||||
}
|
using GeometryRange = std::pair<Iter, Iter>;
|
||||||
|
|
||||||
|
std::stack<GeometryRange> recursion_stack;
|
||||||
|
|
||||||
void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level)
|
|
||||||
{
|
|
||||||
const auto size = std::distance(begin, end);
|
const auto size = std::distance(begin, end);
|
||||||
if (size < 2)
|
if (size < 2)
|
||||||
{
|
{
|
||||||
@ -76,7 +78,8 @@ void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigne
|
|||||||
std::prev(end)->necessary = true;
|
std::prev(end)->necessary = true;
|
||||||
|
|
||||||
{
|
{
|
||||||
BOOST_ASSERT_MSG(zoom_level < DOUGLAS_PEUCKER_THRESHOLDS.size(), "unsupported zoom level");
|
BOOST_ASSERT_MSG(zoom_level < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE,
|
||||||
|
"unsupported zoom level");
|
||||||
auto left_border = begin;
|
auto left_border = begin;
|
||||||
auto right_border = std::next(begin);
|
auto 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
|
||||||
@ -117,7 +120,8 @@ void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigne
|
|||||||
{
|
{
|
||||||
const int distance = dist_calc(it->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 > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
|
||||||
{
|
{
|
||||||
farthest_entry_it = it;
|
farthest_entry_it = it;
|
||||||
max_int_distance = distance;
|
max_int_distance = distance;
|
||||||
@ -125,7 +129,7 @@ void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigne
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if maximum violates a zoom level dependent threshold
|
// check if maximum violates a zoom level dependent threshold
|
||||||
if (max_int_distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
|
if (max_int_distance > detail::DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
|
||||||
{
|
{
|
||||||
// mark idx as necessary
|
// mark idx as necessary
|
||||||
farthest_entry_it->necessary = true;
|
farthest_entry_it->necessary = true;
|
||||||
@ -140,5 +144,5 @@ void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // ns engine
|
||||||
}
|
} // ns osrm
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(douglas_peucker)
|
BOOST_AUTO_TEST_SUITE(douglas_peucker_simplification)
|
||||||
|
|
||||||
using namespace osrm;
|
using namespace osrm;
|
||||||
using namespace osrm::engine;
|
using namespace osrm::engine;
|
||||||
@ -22,18 +22,20 @@ SegmentInformation getTestInfo(int lat, int lon, bool necessary)
|
|||||||
BOOST_AUTO_TEST_CASE(all_necessary_test)
|
BOOST_AUTO_TEST_CASE(all_necessary_test)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* x
|
x
|
||||||
* / \
|
/ \
|
||||||
* x \
|
x \
|
||||||
* / \
|
/ \
|
||||||
* x x
|
x x
|
||||||
*/
|
/
|
||||||
std::vector<SegmentInformation> info = {getTestInfo(5, 5, true), getTestInfo(6, 6, true),
|
*/
|
||||||
getTestInfo(10, 10, true), getTestInfo(5, 15, true)};
|
std::vector<SegmentInformation> info = {getTestInfo(5, 5, true),
|
||||||
DouglasPeucker dp;
|
getTestInfo(6, 6, true),
|
||||||
for (unsigned z = 0; z < DOUGLAS_PEUCKER_THRESHOLDS.size(); z++)
|
getTestInfo(10, 10, true),
|
||||||
|
getTestInfo(5, 15, true)};
|
||||||
|
for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
|
||||||
{
|
{
|
||||||
dp.Run(info, z);
|
douglasPeucker(info, z);
|
||||||
for (const auto &i : info)
|
for (const auto &i : info)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_EQUAL(i.necessary, true);
|
BOOST_CHECK_EQUAL(i.necessary, true);
|
||||||
@ -43,29 +45,29 @@ BOOST_AUTO_TEST_CASE(all_necessary_test)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(remove_second_node_test)
|
BOOST_AUTO_TEST_CASE(remove_second_node_test)
|
||||||
{
|
{
|
||||||
DouglasPeucker dp;
|
for (unsigned z = 0; z < detail::DOUGLAS_PEUCKER_THRESHOLDS_SIZE; z++)
|
||||||
for (unsigned z = 0; z < DOUGLAS_PEUCKER_THRESHOLDS.size(); z++)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* x--x
|
x--x
|
||||||
* | \
|
| \
|
||||||
* x-x x
|
x-x x
|
||||||
* |
|
|
|
||||||
* x
|
x
|
||||||
*/
|
*/
|
||||||
std::vector<SegmentInformation> info = {
|
std::vector<SegmentInformation> info = {
|
||||||
getTestInfo(5 * COORDINATE_PRECISION, 5 * COORDINATE_PRECISION, true),
|
getTestInfo(5 * COORDINATE_PRECISION, 5 * COORDINATE_PRECISION, true),
|
||||||
getTestInfo(5 * COORDINATE_PRECISION,
|
getTestInfo(5 * COORDINATE_PRECISION,
|
||||||
5 * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z], false),
|
5 * COORDINATE_PRECISION + detail::DOUGLAS_PEUCKER_THRESHOLDS[z], false),
|
||||||
getTestInfo(10 * COORDINATE_PRECISION, 10 * COORDINATE_PRECISION, false),
|
getTestInfo(10 * COORDINATE_PRECISION, 10 * COORDINATE_PRECISION, false),
|
||||||
getTestInfo(10 * COORDINATE_PRECISION,
|
getTestInfo(10 * COORDINATE_PRECISION,
|
||||||
10 + COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z] * 2, false),
|
10 + COORDINATE_PRECISION + detail::DOUGLAS_PEUCKER_THRESHOLDS[z] * 2,
|
||||||
|
false),
|
||||||
getTestInfo(5 * COORDINATE_PRECISION, 15 * COORDINATE_PRECISION, false),
|
getTestInfo(5 * COORDINATE_PRECISION, 15 * COORDINATE_PRECISION, false),
|
||||||
getTestInfo(5 * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z],
|
getTestInfo(5 * COORDINATE_PRECISION + detail::DOUGLAS_PEUCKER_THRESHOLDS[z],
|
||||||
15 * COORDINATE_PRECISION, true),
|
15 * COORDINATE_PRECISION, true),
|
||||||
};
|
};
|
||||||
BOOST_TEST_MESSAGE("Threshold (" << z << "): " << DOUGLAS_PEUCKER_THRESHOLDS[z]);
|
BOOST_TEST_MESSAGE("Threshold (" << z << "): " << detail::DOUGLAS_PEUCKER_THRESHOLDS[z]);
|
||||||
dp.Run(info, z);
|
douglasPeucker(info, z);
|
||||||
BOOST_CHECK_EQUAL(info[0].necessary, true);
|
BOOST_CHECK_EQUAL(info[0].necessary, true);
|
||||||
BOOST_CHECK_EQUAL(info[1].necessary, false);
|
BOOST_CHECK_EQUAL(info[1].necessary, false);
|
||||||
BOOST_CHECK_EQUAL(info[2].necessary, true);
|
BOOST_CHECK_EQUAL(info[2].necessary, true);
|
||||||
|
Loading…
Reference in New Issue
Block a user