Merge branch 'revert-1240-revert-1217-sketch-upstream' into develop

This commit is contained in:
Dennis Luxen 2014-10-29 10:18:44 -04:00
commit 8700007025
10 changed files with 400 additions and 247 deletions

View File

@ -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);
}
}
}

View File

@ -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);
};

View File

@ -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
View 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

View File

@ -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

View File

@ -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

View 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()

View 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.
*/

View File

@ -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

View File

@ -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())
{