Merge branch 'revert-1240-revert-1217-sketch-upstream' into develop
This commit is contained in:
commit
8700007025
@ -83,62 +83,40 @@ struct CoordinatePairCalculator
|
||||
};
|
||||
}
|
||||
|
||||
DouglasPeucker::DouglasPeucker()
|
||||
: douglas_peucker_thresholds({
|
||||
512440, // z0
|
||||
256720, // z1
|
||||
122560, // z2
|
||||
56780, // z3
|
||||
28800, // z4
|
||||
14400, // z5
|
||||
7200, // z6
|
||||
3200, // z7
|
||||
2400, // z8
|
||||
1000, // z9
|
||||
600, // z10
|
||||
120, // z11
|
||||
60, // z12
|
||||
45, // z13
|
||||
36, // z14
|
||||
20, // z15
|
||||
8, // z16
|
||||
6, // z17
|
||||
4 // z18
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
|
||||
{
|
||||
// check if input data is invalid
|
||||
BOOST_ASSERT_MSG(!input_geometry.empty(), "geometry invalid");
|
||||
Run(std::begin(input_geometry), std::end(input_geometry), zoom_level);
|
||||
}
|
||||
|
||||
if (input_geometry.size() < 2)
|
||||
void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level)
|
||||
{
|
||||
unsigned size = std::distance(begin, end);
|
||||
if (size < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
input_geometry.front().necessary = true;
|
||||
input_geometry.back().necessary = true;
|
||||
begin->necessary = true;
|
||||
std::prev(end)->necessary = true;
|
||||
|
||||
{
|
||||
BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
|
||||
unsigned left_border = 0;
|
||||
unsigned right_border = 1;
|
||||
RandomAccessIt left_border = begin;
|
||||
RandomAccessIt right_border = std::next(begin);
|
||||
// Sweep over array and identify those ranges that need to be checked
|
||||
do
|
||||
{
|
||||
// traverse list until new border element found
|
||||
if (input_geometry[right_border].necessary)
|
||||
if (right_border->necessary)
|
||||
{
|
||||
// sanity checks
|
||||
BOOST_ASSERT(input_geometry[left_border].necessary);
|
||||
BOOST_ASSERT(input_geometry[right_border].necessary);
|
||||
BOOST_ASSERT(left_border->necessary);
|
||||
BOOST_ASSERT(right_border->necessary);
|
||||
recursion_stack.emplace(left_border, right_border);
|
||||
left_border = right_border;
|
||||
}
|
||||
++right_border;
|
||||
} while (right_border < input_geometry.size());
|
||||
} while (right_border != end);
|
||||
}
|
||||
|
||||
// mark locations as 'necessary' by divide-and-conquer
|
||||
@ -148,40 +126,40 @@ void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const
|
||||
const GeometryRange pair = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
// sanity checks
|
||||
BOOST_ASSERT_MSG(input_geometry[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 < input_geometry.size(), "right border outside of geometry");
|
||||
BOOST_ASSERT_MSG(pair.first < pair.second, "left border on the wrong side");
|
||||
BOOST_ASSERT_MSG(pair.first->necessary, "left border must be necessary");
|
||||
BOOST_ASSERT_MSG(pair.second->necessary, "right border must be necessary");
|
||||
BOOST_ASSERT_MSG(std::distance(pair.second, end) > 0, "right border outside of geometry");
|
||||
BOOST_ASSERT_MSG(std::distance(pair.first, pair.second) >= 0, "left border on the wrong side");
|
||||
|
||||
int max_int_distance = 0;
|
||||
unsigned farthest_entry_index = pair.second;
|
||||
const CoordinatePairCalculator dist_calc(input_geometry[pair.first].location,
|
||||
input_geometry[pair.second].location);
|
||||
auto farthest_entry_it = pair.second;
|
||||
const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location);
|
||||
|
||||
// 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?
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check if maximum violates a zoom level dependent threshold
|
||||
if (max_int_distance > douglas_peucker_thresholds[zoom_level])
|
||||
if (max_int_distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level])
|
||||
{
|
||||
// mark idx as necessary
|
||||
input_geometry[farthest_entry_index].necessary = true;
|
||||
if (1 < (farthest_entry_index - pair.first))
|
||||
farthest_entry_it->necessary = true;
|
||||
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(farthest_entry_it, pair.second))
|
||||
{
|
||||
recursion_stack.emplace(farthest_entry_index, pair.second);
|
||||
recursion_stack.emplace(farthest_entry_it, pair.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
/* This class object computes the bitvector of indicating generalized input
|
||||
* points according to the (Ramer-)Douglas-Peucker algorithm.
|
||||
@ -40,18 +41,39 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* Note: points may also be pre-selected*/
|
||||
|
||||
struct SegmentInformation;
|
||||
static const std::array<int, 19> DOUGLAS_PEUCKER_THRESHOLDS = {
|
||||
512440, // z0
|
||||
256720, // z1
|
||||
122560, // z2
|
||||
56780, // z3
|
||||
28800, // z4
|
||||
14400, // z5
|
||||
7200, // z6
|
||||
3200, // z7
|
||||
2400, // z8
|
||||
1000, // z9
|
||||
600, // z10
|
||||
120, // z11
|
||||
60, // z12
|
||||
45, // z13
|
||||
36, // z14
|
||||
20, // z15
|
||||
8, // z16
|
||||
6, // z17
|
||||
4 // z18
|
||||
};
|
||||
|
||||
class DouglasPeucker
|
||||
{
|
||||
private:
|
||||
std::vector<int> douglas_peucker_thresholds;
|
||||
public:
|
||||
using RandomAccessIt = std::vector<SegmentInformation>::iterator;
|
||||
|
||||
using GeometryRange = std::pair<unsigned, unsigned>;
|
||||
using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>;
|
||||
// Stack to simulate the recursion
|
||||
std::stack<GeometryRange> recursion_stack;
|
||||
|
||||
public:
|
||||
DouglasPeucker();
|
||||
void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level);
|
||||
void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,7 @@ add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp FingerPrint.c
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp)
|
||||
add_custom_target(tests DEPENDS datastructure-tests)
|
||||
add_custom_target(tests DEPENDS datastructure-tests algorithm-tests)
|
||||
add_custom_target(benchmarks DEPENDS rtree-bench)
|
||||
|
||||
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
|
||||
@ -72,6 +72,7 @@ file(GLOB AlgorithmGlob Algorithms/*.cpp)
|
||||
file(GLOB HttpGlob Server/Http/*.cpp)
|
||||
file(GLOB LibOSRMGlob Library/*.cpp)
|
||||
file(GLOB DataStructureTestsGlob UnitTests/DataStructures/*.cpp DataStructures/HilbertValue.cpp)
|
||||
file(GLOB AlgorithmTestsGlob UnitTests/Algorithms/*.cpp)
|
||||
|
||||
set(
|
||||
OSRMSources
|
||||
@ -93,6 +94,7 @@ add_executable(osrm-datastore datastore.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGE
|
||||
|
||||
# Unit tests
|
||||
add_executable(datastructure-tests EXCLUDE_FROM_ALL UnitTests/datastructure_tests.cpp ${DataStructureTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE>)
|
||||
add_executable(algorithm-tests EXCLUDE_FROM_ALL UnitTests/algorithm_tests.cpp ${AlgorithmTestsGlob} $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE>)
|
||||
|
||||
# Benchmarks
|
||||
add_executable(rtree-bench EXCLUDE_FROM_ALL Benchmarks/StaticRTreeBench.cpp $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE>)
|
||||
@ -195,6 +197,7 @@ target_link_libraries(osrm-prepare ${Boost_LIBRARIES})
|
||||
target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
|
||||
target_link_libraries(osrm-datastore ${Boost_LIBRARIES})
|
||||
target_link_libraries(datastructure-tests ${Boost_LIBRARIES})
|
||||
target_link_libraries(algorithm-tests ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
|
||||
target_link_libraries(rtree-bench ${Boost_LIBRARIES})
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
@ -203,6 +206,7 @@ target_link_libraries(osrm-datastore ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(osrm-prepare ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(OSRM ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(datastructure-tests ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(algorithm-tests ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(rtree-bench ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
find_package(TBB REQUIRED)
|
||||
@ -214,6 +218,7 @@ target_link_libraries(osrm-extract ${TBB_LIBRARIES})
|
||||
target_link_libraries(osrm-prepare ${TBB_LIBRARIES})
|
||||
target_link_libraries(osrm-routed ${TBB_LIBRARIES})
|
||||
target_link_libraries(datastructure-tests ${TBB_LIBRARIES})
|
||||
target_link_libraries(algorithm-tests ${TBB_LIBRARIES})
|
||||
target_link_libraries(rtree-bench ${TBB_LIBRARIES})
|
||||
include_directories(${TBB_INCLUDE_DIR})
|
||||
|
||||
|
172
DataStructures/Rectangle.h
Normal file
172
DataStructures/Rectangle.h
Normal file
@ -0,0 +1,172 @@
|
||||
#ifndef RECTANGLE_H
|
||||
#define RECTANGLE_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
// TODO: Make template type, add tests
|
||||
struct RectangleInt2D
|
||||
{
|
||||
RectangleInt2D() : min_lon(std::numeric_limits<int32_t>::max()),
|
||||
max_lon(std::numeric_limits<int32_t>::min()),
|
||||
min_lat(std::numeric_limits<int32_t>::max()),
|
||||
max_lat(std::numeric_limits<int32_t>::min()) {}
|
||||
|
||||
int32_t min_lon, max_lon;
|
||||
int32_t min_lat, max_lat;
|
||||
|
||||
inline void MergeBoundingBoxes(const RectangleInt2D &other)
|
||||
{
|
||||
min_lon = std::min(min_lon, other.min_lon);
|
||||
max_lon = std::max(max_lon, other.max_lon);
|
||||
min_lat = std::min(min_lat, other.min_lat);
|
||||
max_lat = std::max(max_lat, other.max_lat);
|
||||
BOOST_ASSERT(min_lat != std::numeric_limits<int32_t>::min());
|
||||
BOOST_ASSERT(min_lon != std::numeric_limits<int32_t>::min());
|
||||
BOOST_ASSERT(max_lat != std::numeric_limits<int32_t>::min());
|
||||
BOOST_ASSERT(max_lon != std::numeric_limits<int32_t>::min());
|
||||
}
|
||||
|
||||
inline FixedPointCoordinate Centroid() const
|
||||
{
|
||||
FixedPointCoordinate centroid;
|
||||
// The coordinates of the midpoints are given by:
|
||||
// x = (x1 + x2) /2 and y = (y1 + y2) /2.
|
||||
centroid.lon = (min_lon + max_lon) / 2;
|
||||
centroid.lat = (min_lat + max_lat) / 2;
|
||||
return centroid;
|
||||
}
|
||||
|
||||
inline bool Intersects(const RectangleInt2D &other) const
|
||||
{
|
||||
FixedPointCoordinate upper_left(other.max_lat, other.min_lon);
|
||||
FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_right(other.min_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_left(other.min_lat, other.min_lon);
|
||||
|
||||
return (Contains(upper_left) || Contains(upper_right) || Contains(lower_right) ||
|
||||
Contains(lower_left));
|
||||
}
|
||||
|
||||
inline float GetMinDist(const FixedPointCoordinate &location) const
|
||||
{
|
||||
const bool is_contained = Contains(location);
|
||||
if (is_contained)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
enum Direction
|
||||
{
|
||||
INVALID = 0,
|
||||
NORTH = 1,
|
||||
SOUTH = 2,
|
||||
EAST = 4,
|
||||
NORTH_EAST = 5,
|
||||
SOUTH_EAST = 6,
|
||||
WEST = 8,
|
||||
NORTH_WEST = 9,
|
||||
SOUTH_WEST = 10
|
||||
};
|
||||
|
||||
Direction d = INVALID;
|
||||
if (location.lat > max_lat)
|
||||
d = (Direction) (d | NORTH);
|
||||
else if (location.lat < min_lat)
|
||||
d = (Direction) (d | SOUTH);
|
||||
if (location.lon > max_lon)
|
||||
d = (Direction) (d | EAST);
|
||||
else if (location.lon < min_lon)
|
||||
d = (Direction) (d | WEST);
|
||||
|
||||
BOOST_ASSERT(d != INVALID);
|
||||
|
||||
float min_dist = std::numeric_limits<float>::max();
|
||||
switch (d)
|
||||
{
|
||||
case NORTH:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, location.lon));
|
||||
break;
|
||||
case SOUTH:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, location.lon));
|
||||
break;
|
||||
case WEST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, min_lon));
|
||||
break;
|
||||
case EAST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, max_lon));
|
||||
break;
|
||||
case NORTH_EAST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, max_lon));
|
||||
break;
|
||||
case NORTH_WEST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, min_lon));
|
||||
break;
|
||||
case SOUTH_EAST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, max_lon));
|
||||
break;
|
||||
case SOUTH_WEST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, min_lon));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(min_dist != std::numeric_limits<float>::max());
|
||||
|
||||
return min_dist;
|
||||
}
|
||||
|
||||
inline float GetMinMaxDist(const FixedPointCoordinate &location) const
|
||||
{
|
||||
float min_max_dist = std::numeric_limits<float>::max();
|
||||
// Get minmax distance to each of the four sides
|
||||
const FixedPointCoordinate upper_left(max_lat, min_lon);
|
||||
const FixedPointCoordinate upper_right(max_lat, max_lon);
|
||||
const FixedPointCoordinate lower_right(min_lat, max_lon);
|
||||
const FixedPointCoordinate lower_left(min_lat, min_lon);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right)));
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right)));
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left)));
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left)));
|
||||
return min_max_dist;
|
||||
}
|
||||
|
||||
inline bool Contains(const FixedPointCoordinate &location) const
|
||||
{
|
||||
const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat);
|
||||
const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon);
|
||||
return lats_contained && lons_contained;
|
||||
}
|
||||
|
||||
inline friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect)
|
||||
{
|
||||
out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION
|
||||
<< " " << rect.max_lat / COORDINATE_PRECISION << ","
|
||||
<< rect.max_lon / COORDINATE_PRECISION;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "HilbertValue.h"
|
||||
#include "phantom_node.hpp"
|
||||
#include "QueryNode.h"
|
||||
#include "Rectangle.h"
|
||||
#include "SharedMemoryFactory.h"
|
||||
#include "SharedMemoryVectorWrapper.h"
|
||||
|
||||
@ -70,190 +71,6 @@ template <class EdgeDataT,
|
||||
class StaticRTree
|
||||
{
|
||||
public:
|
||||
struct RectangleInt2D
|
||||
{
|
||||
RectangleInt2D() : min_lon(INT_MAX), max_lon(INT_MIN), min_lat(INT_MAX), max_lat(INT_MIN) {}
|
||||
|
||||
int32_t min_lon, max_lon;
|
||||
int32_t min_lat, max_lat;
|
||||
|
||||
inline void InitializeMBRectangle(const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
|
||||
const uint32_t element_count,
|
||||
const std::vector<NodeInfo> &coordinate_list)
|
||||
{
|
||||
for (uint32_t i = 0; i < element_count; ++i)
|
||||
{
|
||||
min_lon = std::min(min_lon,
|
||||
std::min(coordinate_list.at(objects[i].u).lon,
|
||||
coordinate_list.at(objects[i].v).lon));
|
||||
max_lon = std::max(max_lon,
|
||||
std::max(coordinate_list.at(objects[i].u).lon,
|
||||
coordinate_list.at(objects[i].v).lon));
|
||||
|
||||
min_lat = std::min(min_lat,
|
||||
std::min(coordinate_list.at(objects[i].u).lat,
|
||||
coordinate_list.at(objects[i].v).lat));
|
||||
max_lat = std::max(max_lat,
|
||||
std::max(coordinate_list.at(objects[i].u).lat,
|
||||
coordinate_list.at(objects[i].v).lat));
|
||||
}
|
||||
BOOST_ASSERT(min_lat != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(min_lon != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(max_lat != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(max_lon != std::numeric_limits<int>::min());
|
||||
}
|
||||
|
||||
inline void MergeBoundingBoxes(const RectangleInt2D &other)
|
||||
{
|
||||
min_lon = std::min(min_lon, other.min_lon);
|
||||
max_lon = std::max(max_lon, other.max_lon);
|
||||
min_lat = std::min(min_lat, other.min_lat);
|
||||
max_lat = std::max(max_lat, other.max_lat);
|
||||
BOOST_ASSERT(min_lat != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(min_lon != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(max_lat != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(max_lon != std::numeric_limits<int>::min());
|
||||
}
|
||||
|
||||
inline FixedPointCoordinate Centroid() const
|
||||
{
|
||||
FixedPointCoordinate centroid;
|
||||
// The coordinates of the midpoints are given by:
|
||||
// x = (x1 + x2) /2 and y = (y1 + y2) /2.
|
||||
centroid.lon = (min_lon + max_lon) / 2;
|
||||
centroid.lat = (min_lat + max_lat) / 2;
|
||||
return centroid;
|
||||
}
|
||||
|
||||
inline bool Intersects(const RectangleInt2D &other) const
|
||||
{
|
||||
FixedPointCoordinate upper_left(other.max_lat, other.min_lon);
|
||||
FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_right(other.min_lat, other.max_lon);
|
||||
FixedPointCoordinate lower_left(other.min_lat, other.min_lon);
|
||||
|
||||
return (Contains(upper_left) || Contains(upper_right) || Contains(lower_right) ||
|
||||
Contains(lower_left));
|
||||
}
|
||||
|
||||
inline float GetMinDist(const FixedPointCoordinate &location) const
|
||||
{
|
||||
const bool is_contained = Contains(location);
|
||||
if (is_contained)
|
||||
{
|
||||
return 0.;
|
||||
}
|
||||
|
||||
enum Direction
|
||||
{
|
||||
INVALID = 0,
|
||||
NORTH = 1,
|
||||
SOUTH = 2,
|
||||
EAST = 4,
|
||||
NORTH_EAST = 5,
|
||||
SOUTH_EAST = 6,
|
||||
WEST = 8,
|
||||
NORTH_WEST = 9,
|
||||
SOUTH_WEST = 10
|
||||
};
|
||||
|
||||
Direction d = INVALID;
|
||||
if (location.lat > max_lat)
|
||||
d = (Direction) (d | NORTH);
|
||||
else if (location.lat < min_lat)
|
||||
d = (Direction) (d | SOUTH);
|
||||
if (location.lon > max_lon)
|
||||
d = (Direction) (d | EAST);
|
||||
else if (location.lon < min_lon)
|
||||
d = (Direction) (d | WEST);
|
||||
|
||||
BOOST_ASSERT(d != INVALID);
|
||||
|
||||
float min_dist = std::numeric_limits<float>::max();
|
||||
switch (d)
|
||||
{
|
||||
case NORTH:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, location.lon));
|
||||
break;
|
||||
case SOUTH:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, location.lon));
|
||||
break;
|
||||
case WEST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, min_lon));
|
||||
break;
|
||||
case EAST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, max_lon));
|
||||
break;
|
||||
case NORTH_EAST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, max_lon));
|
||||
break;
|
||||
case NORTH_WEST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, min_lon));
|
||||
break;
|
||||
case SOUTH_EAST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, max_lon));
|
||||
break;
|
||||
case SOUTH_WEST:
|
||||
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, min_lon));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(min_dist != std::numeric_limits<float>::max());
|
||||
|
||||
return min_dist;
|
||||
}
|
||||
|
||||
inline float GetMinMaxDist(const FixedPointCoordinate &location) const
|
||||
{
|
||||
float min_max_dist = std::numeric_limits<float>::max();
|
||||
// Get minmax distance to each of the four sides
|
||||
const FixedPointCoordinate upper_left(max_lat, min_lon);
|
||||
const FixedPointCoordinate upper_right(max_lat, max_lon);
|
||||
const FixedPointCoordinate lower_right(min_lat, max_lon);
|
||||
const FixedPointCoordinate lower_left(min_lat, min_lon);
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right)));
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right)));
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left)));
|
||||
|
||||
min_max_dist = std::min(
|
||||
min_max_dist,
|
||||
std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left),
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left)));
|
||||
return min_max_dist;
|
||||
}
|
||||
|
||||
inline bool Contains(const FixedPointCoordinate &location) const
|
||||
{
|
||||
const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat);
|
||||
const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon);
|
||||
return lats_contained && lons_contained;
|
||||
}
|
||||
|
||||
inline friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect)
|
||||
{
|
||||
out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION
|
||||
<< " " << rect.max_lat / COORDINATE_PRECISION << ","
|
||||
<< rect.max_lon / COORDINATE_PRECISION;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
using RectangleT = RectangleInt2D;
|
||||
|
||||
struct TreeNode
|
||||
@ -412,7 +229,7 @@ class StaticRTree
|
||||
}
|
||||
|
||||
// generate tree node that resemble the objects in leaf and store it for next level
|
||||
current_node.minimum_bounding_rectangle.InitializeMBRectangle(
|
||||
InitializeMBRectangle(current_node.minimum_bounding_rectangle,
|
||||
current_leaf.objects, current_leaf.object_count, coordinate_list);
|
||||
current_node.child_is_on_disk = true;
|
||||
current_node.children[0] = tree_nodes_in_level.size();
|
||||
@ -1199,6 +1016,33 @@ class StaticRTree
|
||||
{
|
||||
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
|
||||
}
|
||||
|
||||
inline void InitializeMBRectangle(RectangleT& rectangle,
|
||||
const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
|
||||
const uint32_t element_count,
|
||||
const std::vector<NodeInfo> &coordinate_list)
|
||||
{
|
||||
for (uint32_t i = 0; i < element_count; ++i)
|
||||
{
|
||||
rectangle.min_lon = std::min(rectangle.min_lon,
|
||||
std::min(coordinate_list.at(objects[i].u).lon,
|
||||
coordinate_list.at(objects[i].v).lon));
|
||||
rectangle.max_lon = std::max(rectangle.max_lon,
|
||||
std::max(coordinate_list.at(objects[i].u).lon,
|
||||
coordinate_list.at(objects[i].v).lon));
|
||||
|
||||
rectangle.min_lat = std::min(rectangle.min_lat,
|
||||
std::min(coordinate_list.at(objects[i].u).lat,
|
||||
coordinate_list.at(objects[i].v).lat));
|
||||
rectangle.max_lat = std::max(rectangle.max_lat,
|
||||
std::max(coordinate_list.at(objects[i].u).lat,
|
||||
coordinate_list.at(objects[i].v).lat));
|
||||
}
|
||||
BOOST_ASSERT(rectangle.min_lat != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(rectangle.min_lon != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(rectangle.max_lat != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(rectangle.max_lon != std::numeric_limits<int>::min());
|
||||
}
|
||||
};
|
||||
|
||||
//[1] "On Packing R-Trees"; I. Kamel, C. Faloutsos; 1993; DOI: 10.1145/170088.170403
|
||||
|
@ -194,7 +194,7 @@ class DescriptionFactory
|
||||
}
|
||||
|
||||
// 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
|
||||
unsigned necessary_pieces = 0; // a running index that counts the necessary pieces
|
||||
|
83
UnitTests/Algorithms/DouglasPeuckerTest.cpp
Normal file
83
UnitTests/Algorithms/DouglasPeuckerTest.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
#include "../../Algorithms/DouglasPeucker.h"
|
||||
#include "../../DataStructures/SegmentInformation.h"
|
||||
#include "../../Include/osrm/Coordinate.h"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/test_case_template.hpp>
|
||||
#include <boost/mpl/list.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(douglas_peucker)
|
||||
|
||||
SegmentInformation getTestInfo(int lat, int lon, bool necessary)
|
||||
{
|
||||
return SegmentInformation(FixedPointCoordinate(lat, lon),
|
||||
0, 0, 0, TurnInstruction::HeadOn, necessary, false, 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(all_necessary_test)
|
||||
{
|
||||
/*
|
||||
* x
|
||||
* / \
|
||||
* x \
|
||||
* / \
|
||||
* x x
|
||||
*/
|
||||
std::vector<SegmentInformation> info = {
|
||||
getTestInfo(5, 5, true),
|
||||
getTestInfo(6, 6, true),
|
||||
getTestInfo(10, 10, true),
|
||||
getTestInfo(5, 15, true)
|
||||
};
|
||||
DouglasPeucker dp;
|
||||
for (unsigned z = 0; z < 20; z++)
|
||||
{
|
||||
dp.Run(info, z);
|
||||
for (const auto& i : info)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(i.necessary, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(remove_second_node_test)
|
||||
{
|
||||
DouglasPeucker dp;
|
||||
for (unsigned z = 0; z < 19; z++)
|
||||
{
|
||||
/*
|
||||
* x--x
|
||||
* | \
|
||||
* x-x x
|
||||
* |
|
||||
* x
|
||||
*/
|
||||
std::vector<SegmentInformation> info = {
|
||||
getTestInfo(5 * COORDINATE_PRECISION,
|
||||
5 * COORDINATE_PRECISION, true),
|
||||
getTestInfo(5 * COORDINATE_PRECISION,
|
||||
5 * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z], false),
|
||||
getTestInfo(10 * COORDINATE_PRECISION,
|
||||
10 * COORDINATE_PRECISION, false),
|
||||
getTestInfo(10 * COORDINATE_PRECISION,
|
||||
10 + COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z] * 2, false),
|
||||
getTestInfo(5 * COORDINATE_PRECISION,
|
||||
15 * COORDINATE_PRECISION, false),
|
||||
getTestInfo(5 * COORDINATE_PRECISION + DOUGLAS_PEUCKER_THRESHOLDS[z],
|
||||
15 * COORDINATE_PRECISION, true),
|
||||
};
|
||||
std::cout << "Threshold: " << DOUGLAS_PEUCKER_THRESHOLDS[z] << std::endl;
|
||||
dp.Run(info, z);
|
||||
std::cout << "z: " << z << std::endl;
|
||||
BOOST_CHECK_EQUAL(info[0].necessary, true);
|
||||
BOOST_CHECK_EQUAL(info[1].necessary, false);
|
||||
BOOST_CHECK_EQUAL(info[2].necessary, true);
|
||||
BOOST_CHECK_EQUAL(info[3].necessary, true);
|
||||
BOOST_CHECK_EQUAL(info[4].necessary, false);
|
||||
BOOST_CHECK_EQUAL(info[5].necessary, true);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
8
UnitTests/algorithm_tests.cpp
Normal file
8
UnitTests/algorithm_tests.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#define BOOST_TEST_MODULE algorithm tests
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
/*
|
||||
* This file will contain an automatically generated main function.
|
||||
*/
|
||||
|
@ -28,12 +28,53 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef TIMINGUTIL_H
|
||||
#define TIMINGUTIL_H
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
struct GlobalTimer
|
||||
{
|
||||
GlobalTimer() : time(0) {}
|
||||
std::atomic<uint64_t> time;
|
||||
};
|
||||
|
||||
class GlobalTimerFactory
|
||||
{
|
||||
public:
|
||||
static GlobalTimerFactory& get()
|
||||
{
|
||||
static GlobalTimerFactory instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
GlobalTimer& getGlobalTimer(const std::string& name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(map_mutex);
|
||||
return timer_map[name];
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex map_mutex;
|
||||
std::unordered_map<std::string, GlobalTimer> timer_map;
|
||||
};
|
||||
|
||||
#define GLOBAL_TIMER_AQUIRE(_X) auto& _X##_global_timer = GlobalTimerFactory::get().getGlobalTimer(#_X)
|
||||
#define GLOBAL_TIMER_RESET(_X) _X##_global_timer.time = 0
|
||||
#define GLOBAL_TIMER_START(_X) TIMER_START(_X)
|
||||
#define GLOBAL_TIMER_STOP(_X) TIMER_STOP(_X); _X##_global_timer.time += TIMER_NSEC(_X)
|
||||
#define GLOBAL_TIMER_NSEC(_X) static_cast<double>(_X##_global_timer.time)
|
||||
#define GLOBAL_TIMER_USEC(_X) (_X##_global_timer.time / 1000.0)
|
||||
#define GLOBAL_TIMER_MSEC(_X) (_X##_global_timer.time / 1000.0 / 1000.0)
|
||||
#define GLOBAL_TIMER_SEC(_X) (_X##_global_timer.time / 1000.0 / 1000.0 / 1000.0)
|
||||
|
||||
#define TIMER_START(_X) auto _X##_start = std::chrono::steady_clock::now(), _X##_stop = _X##_start
|
||||
#define TIMER_STOP(_X) _X##_stop = std::chrono::steady_clock::now()
|
||||
#define TIMER_MSEC(_X) std::chrono::duration_cast<std::chrono::milliseconds>(_X##_stop - _X##_start).count()
|
||||
#define TIMER_SEC(_X) (0.001*std::chrono::duration_cast<std::chrono::milliseconds>(_X##_stop - _X##_start).count())
|
||||
#define TIMER_NSEC(_X) std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count()
|
||||
#define TIMER_USEC(_X) std::chrono::duration_cast<std::chrono::microseconds>(_X##_stop - _X##_start).count()
|
||||
#define TIMER_MSEC(_X) (0.000001*std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count())
|
||||
#define TIMER_SEC(_X) (0.000001*std::chrono::duration_cast<std::chrono::microseconds>(_X##_stop - _X##_start).count())
|
||||
#define TIMER_MIN(_X) std::chrono::duration_cast<std::chrono::minutes>(_X##_stop - _X##_start).count()
|
||||
|
||||
#endif // TIMINGUTIL_H
|
||||
|
@ -722,7 +722,7 @@ constexpr unsigned short atan_table[4096] = {
|
||||
// max value is pi/4
|
||||
constexpr double SCALING_FACTOR = 4. / M_PI * 0xFFFF;
|
||||
|
||||
double atan2_lookup(double y, double x)
|
||||
inline double atan2_lookup(double y, double x)
|
||||
{
|
||||
if (std::abs(x) < std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user