Compare commits
347 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f85b30d4a | |||
| e4c398aa23 | |||
| f9417555d0 | |||
| 5d3123b97f | |||
| 25080aaf1d | |||
| 05ac4b5ab6 | |||
| 07e13e2499 | |||
| 2d9645b9b0 | |||
| 65ccbedab2 | |||
| 631567864b | |||
| 39d479128c | |||
| 4c0b315c07 | |||
| 264e83a1f3 | |||
| 2b2ed50721 | |||
| 31fbf99109 | |||
| 63381ad221 | |||
| 6ee2d1103e | |||
| bee18dba54 | |||
| 481e445e8a | |||
| 129f7b7441 | |||
| d6bc3c5175 | |||
| de7c56c6bc | |||
| 0c59ecfa14 | |||
| f67241a3cb | |||
| 3b2893944c | |||
| dd7d6df4c6 | |||
| efbda436f3 | |||
| 2064934939 | |||
| b36cf7c450 | |||
| a24dd3dee2 | |||
| 7b22f08869 | |||
| 840929754a | |||
| 51fd332806 | |||
| 4d7e0f6b79 | |||
| b74a573ec5 | |||
| 5faf88afdb | |||
| 5e1110930e | |||
| f11adf5f80 | |||
| 40a71e09a6 | |||
| 1231847a3c | |||
| b06a73e893 | |||
| f99f194927 | |||
| eac7d07ef6 | |||
| 60d70a9f4c | |||
| c944783590 | |||
| 8104a8aea1 | |||
| a4db678895 | |||
| da33d02461 | |||
| 9b4071006e | |||
| b3cdd5b3bf | |||
| 93e53ec612 | |||
| ea8319e2b9 | |||
| 2fae253c62 | |||
| e204b257ad | |||
| dd83d8ed61 | |||
| 61f3d85af1 | |||
| 804e515847 | |||
| 35977b6c7f | |||
| 23f1d3d83b | |||
| b8ea935424 | |||
| 7c0866f626 | |||
| 0f2062b739 | |||
| e91454eeee | |||
| 58134200df | |||
| f6bab21928 | |||
| 011910811b | |||
| bbc0ba147a | |||
| 922a4331db | |||
| 8f7f1e2683 | |||
| 1980cc007f | |||
| 39611f7477 | |||
| e3d659576f | |||
| 46d4670b74 | |||
| 15ca6d5ca9 | |||
| 58f23cda4a | |||
| a58d8420a2 | |||
| 96f834fb81 | |||
| 86617eccb1 | |||
| f2936d1c2d | |||
| 0fc8e04ab5 | |||
| a65e2d3115 | |||
| ca6e25b11c | |||
| 3ec6a6f5bc | |||
| c12fae47e7 | |||
| 604d2c698b | |||
| 5d14016366 | |||
| b112becbba | |||
| e68a09fb3c | |||
| 30e9b4513a | |||
| 671b14dac0 | |||
| 82e99988e8 | |||
| 313a7ed7fa | |||
| cf3365574e | |||
| 0e1f6f50ea | |||
| 5b6518d4a9 | |||
| c009dce591 | |||
| 40e2d7932b | |||
| e29b7a6eae | |||
| a3e9cbc000 | |||
| aedcc2ff40 | |||
| 4c17aeb180 | |||
| ef60ae652c | |||
| 1d62ed028e | |||
| 50bf7694c2 | |||
| 807f1d7c1c | |||
| 7a7d0c09d9 | |||
| f90ce77da4 | |||
| d27ac27bc7 | |||
| 44c6a64bf4 | |||
| 2d6eae9391 | |||
| ba440550a6 | |||
| 8e24fee9da | |||
| 1148652101 | |||
| ed01eeaeb3 | |||
| 096f187d6f | |||
| fa35eb1959 | |||
| 8d89d30c74 | |||
| f1bde40939 | |||
| 4e7ccaa298 | |||
| d0284991ed | |||
| c4998990e5 | |||
| 42d3ee9b94 | |||
| be5c3e41e1 | |||
| 3282d410c4 | |||
| 75303c95f8 | |||
| 0209272831 | |||
| 0e16c4ed97 | |||
| e49720f34a | |||
| 8aee371d81 | |||
| 71c4f81b59 | |||
| 3127fafc88 | |||
| 4e6bdf28cc | |||
| 621a5a86a0 | |||
| d80c8cbd2f | |||
| 686f1aeeb2 | |||
| e27a69bab7 | |||
| 4ee2e1d049 | |||
| 2102648102 | |||
| 8611e40172 | |||
| 7d5b88fff8 | |||
| cfd9aa31a9 | |||
| 62aea4c321 | |||
| f75fcb3041 | |||
| 971c557d85 | |||
| ea05aa225e | |||
| 56cdabff6a | |||
| 15f62e680a | |||
| 0af4e16c21 | |||
| c7b90bac1a | |||
| 4b81331d53 | |||
| 47ab0cbf62 | |||
| f5b079b8e7 | |||
| 21c4691d40 | |||
| 3726706608 | |||
| 28a53aa147 | |||
| 2ad572490c | |||
| 0ed9caf969 | |||
| 63ee376f71 | |||
| 67bcb98a84 | |||
| 9cd91ae99c | |||
| d111a0e5e6 | |||
| 11d4c04cea | |||
| 01773c2a00 | |||
| 1079bf7843 | |||
| 05bcfd2c1c | |||
| 5357a6a4fd | |||
| b6787b0014 | |||
| a32116d24c | |||
| a03b698e5a | |||
| fa0c5db18c | |||
| bc063ded7a | |||
| 846505cbc8 | |||
| 964118d1d6 | |||
| c43b67ea2e | |||
| f68af08931 | |||
| cdd5a41965 | |||
| e13ee59af3 | |||
| 9eb183e01d | |||
| 1163417722 | |||
| 3edc48cda5 | |||
| 2c01425ee5 | |||
| ed9c72814f | |||
| adbbe2b097 | |||
| 7335e0809a | |||
| 75dabb75e2 | |||
| 15adcd24be | |||
| e98ba99331 | |||
| 11459d38d0 | |||
| baf4ea2e8c | |||
| 6a29168c14 | |||
| a4689c7a27 | |||
| 8fda5a187b | |||
| 7b78270f4b | |||
| afd3599a9c | |||
| 4bc8562cd0 | |||
| 11fed4c06c | |||
| 9416a983c6 | |||
| 8108c6320d | |||
| b40b931568 | |||
| 282f70ea91 | |||
| a671f63a3e | |||
| f3ad14cb7f | |||
| 21eb5b661d | |||
| 87fe073118 | |||
| 507dadebf4 | |||
| 7dac8c621c | |||
| 19f4ebf3c5 | |||
| c21b40bebc | |||
| 0766c3c62d | |||
| cc40eb709c | |||
| 3625308585 | |||
| df3a7676eb | |||
| 8f6077e973 | |||
| e6689144c4 | |||
| a67de410bf | |||
| 54ec1a89de | |||
| 4b5f744c6f | |||
| df978345d7 | |||
| facc07c60d | |||
| 2f203ac22c | |||
| cc864191b8 | |||
| 547455245e | |||
| b0d7449bb4 | |||
| aed04c7d55 | |||
| bb5973f2fd | |||
| f801fd1f0d | |||
| 44ca12ead6 | |||
| 9c48389f74 | |||
| acefb5a5f3 | |||
| 3d691a3aec | |||
| 38ebdbb563 | |||
| 1090325c31 | |||
| f8ba4b9312 | |||
| 49a1dfff60 | |||
| 5f4d342d45 | |||
| e1c1f79068 | |||
| a716fa252f | |||
| 0b12e4d8be | |||
| 6ad6c94355 | |||
| 78270c8155 | |||
| 4573ae21e6 | |||
| 0ab6220635 | |||
| 3b51976b96 | |||
| c35211b2f6 | |||
| f62515e13b | |||
| 7f2daf8926 | |||
| 0325861ef3 | |||
| 37f8285a6e | |||
| d3906cffdc | |||
| bee1c77efe | |||
| 7250a82286 | |||
| 984457f9c6 | |||
| 5db23f7e46 | |||
| f4f49b2b46 | |||
| 58b35f6e2d | |||
| b51ad16756 | |||
| d790bda7d2 | |||
| 15ce232f61 | |||
| d999a47600 | |||
| 644286111f | |||
| 917b1cbd6c | |||
| 6d1b585212 | |||
| 6ca35a6264 | |||
| 0290b1b4e0 | |||
| 1d86bf3e56 | |||
| 3fd8ab8d3a | |||
| d240ae3b03 | |||
| b875765c52 | |||
| 2bdec31219 | |||
| a9eebdb1fa | |||
| b25f3a9e91 | |||
| 06f3375a97 | |||
| 5057ae920c | |||
| 6a03f13d55 | |||
| 20cbfd95d6 | |||
| 885dbe1e65 | |||
| 7d7cce5c72 | |||
| 0c66f84555 | |||
| 044e41c079 | |||
| 8dc631e13c | |||
| d93b4feb99 | |||
| 0b873f590c | |||
| f52d637f58 | |||
| e2daf5c2fc | |||
| bef113001a | |||
| f0b403bc2e | |||
| a21fb5fc89 | |||
| bbc0424563 | |||
| f487845e9d | |||
| 77641a9fce | |||
| 56d93eb18b | |||
| da1fd96d4e | |||
| d1fdc7061f | |||
| 2822382797 | |||
| 35c9021bdf | |||
| 493b13364f | |||
| a8ff3231a8 | |||
| c2a750a690 | |||
| 6a9541833a | |||
| 9117b45899 | |||
| 812cf36d52 | |||
| 4aa7420d6a | |||
| 1802839a22 | |||
| 9a2d701e2e | |||
| 69ad3f3365 | |||
| d53eb881c2 | |||
| e28e45f38e | |||
| bf6ca22b00 | |||
| b8acbae3e8 | |||
| 4ec9f2c00f | |||
| 4fc329a1eb | |||
| 0574a60bc2 | |||
| e490c4afed | |||
| d028a30f87 | |||
| 75a2d4d00a | |||
| a122a1e8c7 | |||
| 8fe09c85b6 | |||
| bc951de2a5 | |||
| c970cd13cc | |||
| 8983c0f927 | |||
| a47467f29b | |||
| ef206eb4d9 | |||
| da5eec1c5f | |||
| a69b3535a5 | |||
| f4c23f3259 | |||
| e36e9fd629 | |||
| d2f19353ed | |||
| 2d498cb88b | |||
| a80815d57a | |||
| acab77f4f8 | |||
| bddad0c57c | |||
| 3968349480 | |||
| 3ae17761b3 | |||
| 9a28bdbf76 | |||
| e769821e0f | |||
| 9b68821f05 | |||
| b2adb22b2d | |||
| 981941edf4 | |||
| 111dea89a9 | |||
| 2720f4de9c | |||
| 21645643b0 | |||
| c6a07acd90 | |||
| 1816e6607e | |||
| 37dd05a9b5 | |||
| 529997de9b | |||
| 4f37270300 | |||
| faf9c96442 |
+1
-1
@@ -36,7 +36,7 @@ Thumbs.db
|
||||
# build related files #
|
||||
#######################
|
||||
/build/
|
||||
/Util/UUID.cpp
|
||||
/Util/FingerPrint.cpp
|
||||
/Util/GitDescription.cpp
|
||||
|
||||
# Eclipse related files #
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ install:
|
||||
- sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:boost-latest/ppa
|
||||
- sudo apt-get update >/dev/null
|
||||
- sudo apt-get -q install libprotoc-dev libprotobuf7 libprotobuf-dev libosmpbf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev lua5.1 liblua5.1-0-dev rubygems
|
||||
- sudo apt-get -q install libprotoc-dev libprotobuf7 libprotobuf-dev libosmpbf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev lua5.1 liblua5.1-0-dev rubygems libtbb-dev
|
||||
- sudo apt-get -q install g++-4.7
|
||||
- sudo apt-get install libboost1.54-all-dev
|
||||
#luabind
|
||||
|
||||
@@ -72,6 +72,14 @@ template <typename GraphT> class BFSComponentExplorer
|
||||
NodeID node,
|
||||
unsigned current_component)
|
||||
{
|
||||
/*
|
||||
Graphical representation of variables:
|
||||
|
||||
u v w
|
||||
*---------->*---------->*
|
||||
e2
|
||||
*/
|
||||
|
||||
bfs_queue.emplace(node, node);
|
||||
// mark node as read
|
||||
m_component_index_list[node] = current_component;
|
||||
@@ -94,7 +102,7 @@ template <typename GraphT> class BFSComponentExplorer
|
||||
const NodeID to_node_of_only_restriction =
|
||||
m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
|
||||
|
||||
for (auto e2 = m_graph.BeginEdges(v); e2 < m_graph.EndEdges(v); ++e2)
|
||||
for (auto e2 : m_graph.GetAdjacentEdgeRange(v))
|
||||
{
|
||||
const NodeID w = m_graph.GetTarget(e2);
|
||||
|
||||
|
||||
@@ -29,45 +29,93 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "DouglasPeucker.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
struct CoordinatePairCalculator
|
||||
{
|
||||
CoordinatePairCalculator() = delete;
|
||||
CoordinatePairCalculator(const FixedPointCoordinate &coordinate_a,
|
||||
const FixedPointCoordinate &coordinate_b)
|
||||
{
|
||||
// initialize distance calculator with two fixed coordinates a, b
|
||||
const float RAD = 0.017453292519943295769236907684886f;
|
||||
first_lat = (coordinate_a.lat / COORDINATE_PRECISION) * RAD;
|
||||
first_lon = (coordinate_a.lon / COORDINATE_PRECISION) * RAD;
|
||||
second_lat = (coordinate_b.lat / COORDINATE_PRECISION) * RAD;
|
||||
second_lon = (coordinate_b.lon / COORDINATE_PRECISION) * RAD;
|
||||
}
|
||||
|
||||
int operator()(FixedPointCoordinate &other) const
|
||||
{
|
||||
// set third coordinate c
|
||||
const float RAD = 0.017453292519943295769236907684886f;
|
||||
const float earth_radius = 6372797.560856f;
|
||||
const float float_lat1 = (other.lat / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lon1 = (other.lon / COORDINATE_PRECISION) * RAD;
|
||||
|
||||
// compute distance (a,c)
|
||||
const float x_value_1 = (first_lon - float_lon1) * cos((float_lat1 + first_lat) / 2.f);
|
||||
const float y_value_1 = first_lat - float_lat1;
|
||||
const float dist1 = sqrt(std::pow(x_value_1, 2) + std::pow(y_value_1, 2)) * earth_radius;
|
||||
|
||||
// compute distance (b,c)
|
||||
const float x_value_2 = (second_lon - float_lon1) * cos((float_lat1 + second_lat) / 2.f);
|
||||
const float y_value_2 = second_lat - float_lat1;
|
||||
const float dist2 = sqrt(std::pow(x_value_2, 2) + std::pow(y_value_2, 2)) * earth_radius;
|
||||
|
||||
// return the minimum
|
||||
return static_cast<int>(std::min(dist1, dist2));
|
||||
}
|
||||
|
||||
float first_lat;
|
||||
float first_lon;
|
||||
float second_lat;
|
||||
float second_lon;
|
||||
};
|
||||
|
||||
DouglasPeucker::DouglasPeucker()
|
||||
: douglas_peucker_thresholds({262144., // z0
|
||||
131072., // z1
|
||||
65536., // z2
|
||||
32768., // z3
|
||||
16384., // z4
|
||||
8192., // z5
|
||||
4096., // z6
|
||||
2048., // z7
|
||||
960., // z8
|
||||
480., // z9
|
||||
240., // z10
|
||||
90., // z11
|
||||
50., // z12
|
||||
25., // z13
|
||||
15., // z14
|
||||
5., // z15
|
||||
.65, // z16
|
||||
.5, // z17
|
||||
.35 // z18
|
||||
: 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");
|
||||
if (input_geometry.size() <= 2)
|
||||
|
||||
if (input_geometry.size() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
input_geometry.front().necessary = true;
|
||||
input_geometry.back().necessary = true;
|
||||
|
||||
{
|
||||
BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
|
||||
unsigned left_border = 0;
|
||||
@@ -75,55 +123,60 @@ void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const
|
||||
// Sweep over array and identify those ranges that need to be checked
|
||||
do
|
||||
{
|
||||
BOOST_ASSERT_MSG(input_geometry[left_border].necessary,
|
||||
"left border must be necessary");
|
||||
BOOST_ASSERT_MSG(input_geometry.back().necessary, "right border must be necessary");
|
||||
|
||||
// traverse list until new border element found
|
||||
if (input_geometry[right_border].necessary)
|
||||
{
|
||||
// sanity checks
|
||||
BOOST_ASSERT(input_geometry[left_border].necessary);
|
||||
BOOST_ASSERT(input_geometry[right_border].necessary);
|
||||
recursion_stack.emplace(left_border, right_border);
|
||||
left_border = right_border;
|
||||
}
|
||||
++right_border;
|
||||
} while (right_border < input_geometry.size());
|
||||
}
|
||||
|
||||
// mark locations as 'necessary' by divide-and-conquer
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
// pop next element
|
||||
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");
|
||||
double max_distance = std::numeric_limits<double>::min();
|
||||
|
||||
unsigned farthest_element_index = pair.second;
|
||||
// find index idx of element with max_distance
|
||||
int max_int_distance = 0;
|
||||
unsigned farthest_entry_index = pair.second;
|
||||
const CoordinatePairCalculator DistCalc(input_geometry[pair.first].location,
|
||||
input_geometry[pair.second].location);
|
||||
|
||||
// sweep over range to find the maximum
|
||||
for (unsigned i = pair.first + 1; i < pair.second; ++i)
|
||||
{
|
||||
const double temp_dist = FixedPointCoordinate::ComputePerpendicularDistance(
|
||||
input_geometry[i].location,
|
||||
input_geometry[pair.first].location,
|
||||
input_geometry[pair.second].location);
|
||||
const double distance = std::abs(temp_dist);
|
||||
if (distance > douglas_peucker_thresholds[zoom_level] && distance > max_distance)
|
||||
const int distance = DistCalc(input_geometry[i].location);
|
||||
// found new feasible maximum?
|
||||
if (distance > max_int_distance && distance > douglas_peucker_thresholds[zoom_level])
|
||||
{
|
||||
farthest_element_index = i;
|
||||
max_distance = distance;
|
||||
farthest_entry_index = i;
|
||||
max_int_distance = distance;
|
||||
}
|
||||
}
|
||||
if (max_distance > douglas_peucker_thresholds[zoom_level])
|
||||
|
||||
// check if maximum violates a zoom level dependent threshold
|
||||
if (max_int_distance > douglas_peucker_thresholds[zoom_level])
|
||||
{
|
||||
// mark idx as necessary
|
||||
input_geometry[farthest_element_index].necessary = true;
|
||||
if (1 < (farthest_element_index - pair.first))
|
||||
input_geometry[farthest_entry_index].necessary = true;
|
||||
if (1 < (farthest_entry_index - pair.first))
|
||||
{
|
||||
recursion_stack.emplace(pair.first, farthest_element_index);
|
||||
recursion_stack.emplace(pair.first, farthest_entry_index);
|
||||
}
|
||||
if (1 < (pair.second - farthest_element_index))
|
||||
if (1 < (pair.second - farthest_entry_index))
|
||||
{
|
||||
recursion_stack.emplace(farthest_element_index, pair.second);
|
||||
recursion_stack.emplace(farthest_entry_index, pair.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define DOUGLASPEUCKER_H_
|
||||
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/* This class object computes the bitvector of indicating generalized input
|
||||
@@ -38,22 +39,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* bit indicating if the points is present in the generalization.
|
||||
* Note: points may also be pre-selected*/
|
||||
|
||||
struct FixedPointCoordinate;
|
||||
struct SegmentInformation;
|
||||
|
||||
class DouglasPeucker
|
||||
{
|
||||
private:
|
||||
std::vector<double> douglas_peucker_thresholds;
|
||||
std::vector<int> douglas_peucker_thresholds;
|
||||
|
||||
typedef std::pair<unsigned, unsigned> GeometryRange;
|
||||
// Stack to simulate the recursion
|
||||
std::stack<GeometryRange> recursion_stack;
|
||||
|
||||
double ComputeDistance(const FixedPointCoordinate &point,
|
||||
const FixedPointCoordinate &segA,
|
||||
const FixedPointCoordinate &segB) const;
|
||||
|
||||
public:
|
||||
DouglasPeucker();
|
||||
void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACT_ROUTE_NAMES_H
|
||||
#define EXTRACT_ROUTE_NAMES_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct RouteNames
|
||||
{
|
||||
std::string shortest_path_name_1;
|
||||
std::string shortest_path_name_2;
|
||||
std::string alternative_path_name_1;
|
||||
std::string alternative_path_name_2;
|
||||
};
|
||||
|
||||
// construct routes names
|
||||
template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
|
||||
{
|
||||
private:
|
||||
SegmentT PickNextLongestSegment(const std::vector<SegmentT> &segment_list,
|
||||
const unsigned blocked_name_id) const
|
||||
{
|
||||
SegmentT result_segment;
|
||||
result_segment.length = 0;
|
||||
|
||||
for (const SegmentT &segment : segment_list)
|
||||
{
|
||||
if (segment.name_id != blocked_name_id && segment.length > result_segment.length)
|
||||
{
|
||||
result_segment = segment;
|
||||
}
|
||||
}
|
||||
return result_segment;
|
||||
}
|
||||
|
||||
public:
|
||||
RouteNames operator()(std::vector<SegmentT> &shortest_path_segments,
|
||||
std::vector<SegmentT> &alternative_path_segments,
|
||||
const DataFacadeT *facade) const
|
||||
{
|
||||
RouteNames route_names;
|
||||
|
||||
SegmentT shortest_segment_1, shortest_segment_2;
|
||||
SegmentT alternative_segment_1, alternative_segment_2;
|
||||
|
||||
auto length_comperator = [](const SegmentT &a, const SegmentT &b)
|
||||
{ return a.length > b.length; };
|
||||
auto name_id_comperator = [](const SegmentT &a, const SegmentT &b)
|
||||
{ return a.name_id < b.name_id; };
|
||||
|
||||
if (shortest_path_segments.empty())
|
||||
{
|
||||
return route_names;
|
||||
}
|
||||
|
||||
// pick the longest segment for the shortest path.
|
||||
std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator);
|
||||
shortest_segment_1 = shortest_path_segments[0];
|
||||
if (!alternative_path_segments.empty())
|
||||
{
|
||||
std::sort(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
length_comperator);
|
||||
|
||||
// also pick the longest segment for the alternative path
|
||||
alternative_segment_1 = alternative_path_segments[0];
|
||||
}
|
||||
|
||||
// compute the set difference (for shortest path) depending on names between shortest and
|
||||
// alternative
|
||||
std::vector<SegmentT> shortest_path_set_difference(shortest_path_segments.size());
|
||||
std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), name_id_comperator);
|
||||
std::sort(alternative_path_segments.begin(), alternative_path_segments.end(), name_id_comperator);
|
||||
std::set_difference(shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
shortest_path_set_difference.begin(),
|
||||
name_id_comperator);
|
||||
|
||||
std::sort(shortest_path_set_difference.begin(),
|
||||
shortest_path_set_difference.end(),
|
||||
length_comperator);
|
||||
shortest_segment_2 =
|
||||
PickNextLongestSegment(shortest_path_set_difference, shortest_path_segments[0].name_id);
|
||||
|
||||
// compute the set difference (for alternative path) depending on names between shortest and
|
||||
// alternative
|
||||
// vectors are still sorted, no need to do again
|
||||
BOOST_ASSERT(std::is_sorted(shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
name_id_comperator));
|
||||
BOOST_ASSERT(std::is_sorted(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
name_id_comperator));
|
||||
|
||||
std::vector<SegmentT> alternative_path_set_difference(alternative_path_segments.size());
|
||||
std::set_difference(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
alternative_path_set_difference.begin(),
|
||||
name_id_comperator);
|
||||
|
||||
std::sort(alternative_path_set_difference.begin(),
|
||||
alternative_path_set_difference.end(),
|
||||
length_comperator);
|
||||
|
||||
if (!alternative_path_segments.empty())
|
||||
{
|
||||
alternative_segment_2 = PickNextLongestSegment(alternative_path_set_difference,
|
||||
alternative_path_segments[0].name_id);
|
||||
}
|
||||
|
||||
// move the segments into the order in which they occur.
|
||||
if (shortest_segment_1.position > shortest_segment_2.position)
|
||||
{
|
||||
std::swap(shortest_segment_1, shortest_segment_2);
|
||||
}
|
||||
if (alternative_segment_1.position > alternative_segment_2.position)
|
||||
{
|
||||
std::swap(alternative_segment_1, alternative_segment_2);
|
||||
}
|
||||
|
||||
// fetching names for the selected segments
|
||||
route_names.shortest_path_name_1 =
|
||||
facade->GetEscapedNameForNameID(shortest_segment_1.name_id);
|
||||
route_names.shortest_path_name_2 =
|
||||
facade->GetEscapedNameForNameID(shortest_segment_2.name_id);
|
||||
|
||||
route_names.alternative_path_name_1 =
|
||||
facade->GetEscapedNameForNameID(alternative_segment_1.name_id);
|
||||
route_names.alternative_path_name_2 =
|
||||
facade->GetEscapedNameForNameID(alternative_segment_2.name_id);
|
||||
|
||||
return route_names;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXTRACT_ROUTE_NAMES_H
|
||||
@@ -32,7 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#if defined(__x86_64__) && !defined(__MINGW64__)
|
||||
#include <cpuid.h>
|
||||
#else
|
||||
#include <boost/crc.hpp> // for boost::crc_32_type
|
||||
@@ -105,7 +105,7 @@ template <class ContainerT> class IteratorbasedCRC32
|
||||
{
|
||||
static const int SSE42_BIT = 0x00100000;
|
||||
const unsigned ecx = cpuid();
|
||||
const bool has_SSE42 = ecx & SSE42_BIT;
|
||||
const bool has_SSE42 = (ecx & SSE42_BIT) != 0;
|
||||
if (has_SSE42)
|
||||
{
|
||||
SimpleLogger().Write() << "using hardware based CRC32 computation";
|
||||
|
||||
@@ -26,11 +26,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "PolylineCompressor.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output)
|
||||
const
|
||||
{
|
||||
const unsigned end = numbers.size();
|
||||
const unsigned end = static_cast<unsigned>(numbers.size());
|
||||
for (unsigned i = 0; i < end; ++i)
|
||||
{
|
||||
numbers[i] <<= 1;
|
||||
@@ -39,9 +42,9 @@ void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std
|
||||
numbers[i] = ~(numbers[i]);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < end; ++i)
|
||||
for (const int number : numbers)
|
||||
{
|
||||
encodeNumber(numbers[i], output);
|
||||
encodeNumber(number, output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +52,7 @@ void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output)
|
||||
{
|
||||
while (number_to_encode >= 0x20)
|
||||
{
|
||||
int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
|
||||
const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
|
||||
output += static_cast<char>(next_value);
|
||||
if (92 == next_value)
|
||||
{
|
||||
@@ -66,97 +69,50 @@ void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output)
|
||||
}
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const
|
||||
JSON::String PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline)
|
||||
const
|
||||
{
|
||||
std::string output;
|
||||
std::vector<int> delta_numbers;
|
||||
output += "\"";
|
||||
if (!polyline.empty())
|
||||
{
|
||||
FixedPointCoordinate last_coordinate = polyline[0].location;
|
||||
delta_numbers.emplace_back(last_coordinate.lat);
|
||||
delta_numbers.emplace_back(last_coordinate.lon);
|
||||
for (unsigned i = 1; i < polyline.size(); ++i)
|
||||
// iterate after skipping the first, already handled, segment
|
||||
for (auto it = ++polyline.cbegin(); it != polyline.cend(); ++it)
|
||||
{
|
||||
if (polyline[i].necessary)
|
||||
const auto &segment = *it;
|
||||
if (segment.necessary)
|
||||
{
|
||||
int lat_diff = polyline[i].location.lat - last_coordinate.lat;
|
||||
int lon_diff = polyline[i].location.lon - last_coordinate.lon;
|
||||
int lat_diff = segment.location.lat - last_coordinate.lat;
|
||||
int lon_diff = segment.location.lon - last_coordinate.lon;
|
||||
delta_numbers.emplace_back(lat_diff);
|
||||
delta_numbers.emplace_back(lon_diff);
|
||||
last_coordinate = polyline[i].location;
|
||||
last_coordinate = segment.location;
|
||||
}
|
||||
}
|
||||
encodeVectorSignedNumber(delta_numbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
JSON::String return_value(output);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const
|
||||
JSON::Array
|
||||
PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
|
||||
{
|
||||
std::vector<int> delta_numbers(2 * polyline.size());
|
||||
output += "\"";
|
||||
if (!polyline.empty())
|
||||
JSON::Array json_geometry_array;
|
||||
for (const auto &segment : polyline)
|
||||
{
|
||||
delta_numbers[0] = polyline[0].lat;
|
||||
delta_numbers[1] = polyline[0].lon;
|
||||
for (unsigned i = 1; i < polyline.size(); ++i)
|
||||
if (segment.necessary)
|
||||
{
|
||||
int lat_diff = polyline[i].lat - polyline[i - 1].lat;
|
||||
int lon_diff = polyline[i].lon - polyline[i - 1].lon;
|
||||
delta_numbers[(2 * i)] = (lat_diff);
|
||||
delta_numbers[(2 * i) + 1] = (lon_diff);
|
||||
}
|
||||
encodeVectorSignedNumber(delta_numbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
}
|
||||
|
||||
void PolylineCompressor::printUnencodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const
|
||||
{
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for (unsigned i = 0; i < polyline.size(); i++)
|
||||
{
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if (i < polyline.size() - 1)
|
||||
{
|
||||
output += ",";
|
||||
std::string tmp, output;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(segment.location.lat, tmp);
|
||||
output += (tmp + ",");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(segment.location.lon, tmp);
|
||||
output += tmp;
|
||||
json_geometry_array.values.push_back(output);
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
|
||||
void PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const
|
||||
{
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for (unsigned i = 0; i < polyline.size(); i++)
|
||||
{
|
||||
if (!polyline[i].necessary)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if (i < polyline.size() - 1)
|
||||
{
|
||||
output += ",";
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
return json_geometry_array;
|
||||
}
|
||||
|
||||
@@ -28,8 +28,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef POLYLINECOMPRESSOR_H_
|
||||
#define POLYLINECOMPRESSOR_H_
|
||||
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
struct SegmentInformation;
|
||||
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -42,17 +43,9 @@ class PolylineCompressor
|
||||
void encodeNumber(int number_to_encode, std::string &output) const;
|
||||
|
||||
public:
|
||||
void printEncodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const;
|
||||
JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
|
||||
void printEncodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const;
|
||||
|
||||
void printUnencodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const;
|
||||
|
||||
void printUnencodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const;
|
||||
JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
};
|
||||
|
||||
#endif /* POLYLINECOMPRESSOR_H_ */
|
||||
|
||||
@@ -37,7 +37,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StdHashExtensions.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
@@ -60,17 +62,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<std::pair<NodeID, NodeID>>
|
||||
{
|
||||
size_t operator()(const std::pair<NodeID, NodeID> &pair) const
|
||||
{
|
||||
return std::hash<int>()(pair.first) ^ std::hash<int>()(pair.second);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class TarjanSCC
|
||||
{
|
||||
private:
|
||||
@@ -162,52 +153,48 @@ class TarjanSCC
|
||||
DeallocatingVector<TarjanEdge> edge_list;
|
||||
for (const NodeBasedEdge &input_edge : input_edges)
|
||||
{
|
||||
if (input_edge.source() == input_edge.target())
|
||||
if (input_edge.source == input_edge.target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TarjanEdge edge;
|
||||
if (input_edge.isForward())
|
||||
if (input_edge.forward)
|
||||
{
|
||||
edge.source = input_edge.source();
|
||||
edge.target = input_edge.target();
|
||||
edge.data.forward = input_edge.isForward();
|
||||
edge.data.backward = input_edge.isBackward();
|
||||
edge.source = input_edge.source;
|
||||
edge.target = input_edge.target;
|
||||
edge.data.forward = input_edge.forward;
|
||||
edge.data.backward = input_edge.backward;
|
||||
}
|
||||
else
|
||||
{
|
||||
edge.source = input_edge.target();
|
||||
edge.target = input_edge.source();
|
||||
edge.data.backward = input_edge.isForward();
|
||||
edge.data.forward = input_edge.isBackward();
|
||||
edge.source = input_edge.target;
|
||||
edge.target = input_edge.source;
|
||||
edge.data.backward = input_edge.forward;
|
||||
edge.data.forward = input_edge.backward;
|
||||
}
|
||||
|
||||
edge.data.distance = (std::max)((int)input_edge.weight(), 1);
|
||||
edge.data.distance = (std::max)((int)input_edge.weight, 1);
|
||||
BOOST_ASSERT(edge.data.distance > 0);
|
||||
edge.data.shortcut = false;
|
||||
// edge.data.roundabout = input_edge.isRoundabout();
|
||||
// edge.data.ignoreInGrid = input_edge.ignoreInGrid();
|
||||
edge.data.name_id = input_edge.name();
|
||||
edge.data.type = input_edge.type();
|
||||
// edge.data.isAccessRestricted = input_edge.isAccessRestricted();
|
||||
edge.data.name_id = input_edge.name_id;
|
||||
edge.data.type = input_edge.type;
|
||||
edge.data.reversedEdge = false;
|
||||
edge_list.push_back(edge);
|
||||
if (edge.data.backward)
|
||||
{
|
||||
std::swap(edge.source, edge.target);
|
||||
edge.data.forward = input_edge.isBackward();
|
||||
edge.data.backward = input_edge.isForward();
|
||||
edge.data.forward = input_edge.backward;
|
||||
edge.data.backward = input_edge.forward;
|
||||
edge.data.reversedEdge = true;
|
||||
edge_list.push_back(edge);
|
||||
}
|
||||
}
|
||||
std::vector<NodeBasedEdge>().swap(input_edges);
|
||||
input_edges.shrink_to_fit();
|
||||
BOOST_ASSERT_MSG(0 == input_edges.size() && 0 == input_edges.capacity(),
|
||||
"input edge vector not properly deallocated");
|
||||
|
||||
std::sort(edge_list.begin(), edge_list.end());
|
||||
|
||||
m_node_based_graph = std::make_shared<TarjanDynamicGraph>(number_of_nodes, edge_list);
|
||||
}
|
||||
|
||||
@@ -227,20 +214,20 @@ class TarjanSCC
|
||||
const char *pszDriverName = "ESRI Shapefile";
|
||||
OGRSFDriver *poDriver =
|
||||
OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName);
|
||||
if (NULL == poDriver)
|
||||
if (nullptr == poDriver)
|
||||
{
|
||||
throw OSRMException("ESRI Shapefile driver not available");
|
||||
}
|
||||
OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", NULL);
|
||||
OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr);
|
||||
|
||||
if (NULL == poDS)
|
||||
if (nullptr == poDS)
|
||||
{
|
||||
throw OSRMException("Creation of output file failed");
|
||||
}
|
||||
|
||||
OGRLayer *poLayer = poDS->CreateLayer("component", NULL, wkbLineString, NULL);
|
||||
OGRLayer *poLayer = poDS->CreateLayer("component", nullptr, wkbLineString, nullptr);
|
||||
|
||||
if (NULL == poLayer)
|
||||
if (nullptr == poLayer)
|
||||
{
|
||||
throw OSRMException("Layer creation failed.");
|
||||
}
|
||||
@@ -283,8 +270,7 @@ class TarjanSCC
|
||||
++index;
|
||||
|
||||
// Traverse outgoing edges
|
||||
EdgeID end_edge = m_node_based_graph->EndEdges(v);
|
||||
for (auto e2 = m_node_based_graph->BeginEdges(v); e2 < end_edge; ++e2)
|
||||
for (auto e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
|
||||
{
|
||||
const TarjanDynamicGraph::NodeIterator vprime =
|
||||
m_node_based_graph->GetTarget(e2);
|
||||
@@ -339,15 +325,9 @@ class TarjanSCC
|
||||
SimpleLogger().Write() << "identified: " << component_size_vector.size()
|
||||
<< " many components, marking small components";
|
||||
|
||||
// TODO/C++11: prime candidate for lambda function
|
||||
unsigned size_one_counter = 0;
|
||||
for (unsigned i = 0, end = component_size_vector.size(); i < end; ++i)
|
||||
{
|
||||
if (1 == component_size_vector[i])
|
||||
{
|
||||
++size_one_counter;
|
||||
}
|
||||
}
|
||||
unsigned size_one_counter = std::count_if(component_size_vector.begin(),
|
||||
component_size_vector.end(),
|
||||
[] (unsigned value) { return 1 == value;});
|
||||
|
||||
SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1";
|
||||
|
||||
@@ -357,8 +337,7 @@ class TarjanSCC
|
||||
for (NodeID u = 0; u < last_u_node; ++u)
|
||||
{
|
||||
p.printIncrement();
|
||||
EdgeID last_edge = m_node_based_graph->EndEdges(u);
|
||||
for (auto e1 = m_node_based_graph->BeginEdges(u); e1 < last_edge; ++e1)
|
||||
for (auto e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
|
||||
{
|
||||
if (!m_node_based_graph->GetEdgeData(e1).reversedEdge)
|
||||
{
|
||||
|
||||
+84
-60
@@ -8,8 +8,6 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
include(GetGitRevisionDescription)
|
||||
git_describe(GIT_DESCRIPTION)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
set(bitness 32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(bitness 64)
|
||||
@@ -18,18 +16,23 @@ else()
|
||||
message(WARNING "Building on a 32 bit system is unsupported")
|
||||
endif()
|
||||
|
||||
if (WIN32 AND MSVC_VERSION LESS 1800)
|
||||
message(FATAL_ERROR "Building with Microsoft compiler needs Visual Studio 2013 or later (Express version works too)")
|
||||
endif()
|
||||
|
||||
OPTION(WITH_TOOLS "Build ORSM tools" OFF)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Include/)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/UUID.cpp UUID.cpp.alwaysbuild
|
||||
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp FingerPrint.cpp.alwaysbuild
|
||||
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UUID-Config.cmake
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake
|
||||
DEPENDS
|
||||
${CMAKE_SOURCE_DIR}/Util/UUID.cpp.in
|
||||
${CMAKE_SOURCE_DIR}/cmake/UUID-Config.cmake
|
||||
COMMENT "Configuring UUID.cpp"
|
||||
${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp.in
|
||||
COMMENT "Configuring FingerPrint.cpp"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(UUIDConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/UUID.cpp)
|
||||
add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp)
|
||||
|
||||
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread)
|
||||
|
||||
@@ -38,6 +41,8 @@ configure_file(
|
||||
${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp
|
||||
)
|
||||
file(GLOB ExtractorGlob Extractor/*.cpp)
|
||||
file(GLOB ImporterGlob DataStructures/Import*.cpp)
|
||||
add_library(IMPORT STATIC ${ImporterGlob})
|
||||
set(ExtractorSources extractor.cpp ${ExtractorGlob})
|
||||
add_executable(osrm-extract ${ExtractorSources})
|
||||
|
||||
@@ -63,14 +68,12 @@ set(
|
||||
${HttpGlob}
|
||||
)
|
||||
add_library(COORDLIB STATIC ${CoordinateGlob})
|
||||
add_library(OSRM ${OSRMSources} Util/GitDescription.cpp Util/UUID.cpp)
|
||||
add_library(UUID STATIC Util/UUID.cpp)
|
||||
add_library(FINGERPRINT STATIC Util/FingerPrint.cpp)
|
||||
add_library(OSRM ${OSRMSources} Util/GitDescription.cpp Util/FingerPrint.cpp)
|
||||
add_library(GITDESCRIPTION STATIC Util/GitDescription.cpp)
|
||||
add_dependencies(UUID UUIDConfigure)
|
||||
add_dependencies(GITDESCRIPTION GIT_DESCRIPTION)
|
||||
add_dependencies(FINGERPRINT FingerPrintConfigure)
|
||||
|
||||
add_executable(osrm-routed routed.cpp ${ServerGlob})
|
||||
set_target_properties(osrm-routed PROPERTIES COMPILE_FLAGS -DROUTED)
|
||||
add_executable(osrm-datastore datastore.cpp)
|
||||
|
||||
# Check the release mode
|
||||
@@ -86,39 +89,48 @@ if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
message(STATUS "Configuring OSRM in release mode")
|
||||
message(STATUS "Configuring OSRM in release mode")
|
||||
# Check if LTO is available
|
||||
set(LTO_FLAGS "")
|
||||
CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
|
||||
if (HAS_LTO_FLAG)
|
||||
set(LTO_FLAGS "${LTO_FLAGS} -flto")
|
||||
|
||||
# Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
|
||||
NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
|
||||
message(STATUS "Using gcc specific binutils for LTO.")
|
||||
set(CMAKE_AR "/usr/bin/gcc-ar")
|
||||
set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
|
||||
endif()
|
||||
endif (HAS_LTO_FLAG)
|
||||
endif()
|
||||
|
||||
# Configuring compilers
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# using Clang
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wunreachable-code -Wno-unknown-pragmas -Wno-unneeded-internal-declaration -pedantic -fPIC")
|
||||
message(STATUS "OpenMP parallelization not available using clang++")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wunreachable-code -pedantic -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# using GCC
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fopenmp -pedantic -fPIC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -fPIC")
|
||||
if (WIN32) # using mingw
|
||||
add_definitions(-DM_PI=3.141592653589793238462643383) # define M_PI
|
||||
add_definitions(-DWIN32)
|
||||
SET(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
|
||||
SET(OPTIONAL_OMP_LIB gomp)
|
||||
endif()
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
# using Intel C++
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -openmp -ipo -fPIC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -ipo -fPIC")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-DNOMINMAX) # avoid min and max macros that can break compilation
|
||||
add_definitions(-D_USE_MATH_DEFINES) # define M_PI
|
||||
add_definitions(-D_WIN32_WINNT=0x0501)
|
||||
endif()
|
||||
|
||||
# Check if LTO is available
|
||||
set(LTO_FLAGS "")
|
||||
CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
|
||||
if (HAS_LTO_FLAG)
|
||||
set(LTO_FLAGS "${LTO_FLAGS} -flto")
|
||||
|
||||
# Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
|
||||
NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
|
||||
message(STATUS "Using gcc specific binutils for LTO.")
|
||||
set(CMAKE_AR "/usr/bin/gcc-ar")
|
||||
set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
|
||||
endif()
|
||||
endif (HAS_LTO_FLAG)
|
||||
|
||||
# disable partitioning of LTO process when possible (fixes Debian issues)
|
||||
set(LTO_PARTITION_FLAGS "")
|
||||
CHECK_CXX_COMPILER_FLAG("-flto-partition=none" HAS_LTO_PARTITION_FLAG)
|
||||
@@ -132,10 +144,9 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_P
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
|
||||
|
||||
# Activate C++11
|
||||
ADD_DEFINITIONS(
|
||||
-std=c++11 # Or -std=c++0x
|
||||
# Other flags
|
||||
)
|
||||
if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
ADD_DEFINITIONS(-std=c++11)
|
||||
endif()
|
||||
|
||||
# Configuring other platform dependencies
|
||||
if(APPLE)
|
||||
@@ -143,10 +154,6 @@ if(APPLE)
|
||||
message(STATUS "Set Architecture to x64 on OS X")
|
||||
exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION)
|
||||
string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION})
|
||||
# if(DARWIN_VERSION GREATER 12 AND NOT OSXLIBSTD)
|
||||
# message(STATUS "Activating -std=c++11 flag for >= OS X 10.9")
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
# endif()
|
||||
if(OSXLIBSTD)
|
||||
message(STATUS "linking against ${OSXLIBSTD}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=${OSXLIBSTD}")
|
||||
@@ -157,6 +164,7 @@ if(APPLE)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(osrm-prepare rt)
|
||||
target_link_libraries(osrm-datastore rt)
|
||||
target_link_libraries(OSRM rt)
|
||||
endif()
|
||||
@@ -170,13 +178,25 @@ endif()
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(OSRM ${Boost_LIBRARIES} COORDLIB)
|
||||
target_link_libraries(osrm-extract ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
target_link_libraries(osrm-prepare ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
target_link_libraries(osrm-routed ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION)
|
||||
target_link_libraries(osrm-datastore ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
target_link_libraries(osrm-extract ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB IMPORT)
|
||||
target_link_libraries(osrm-prepare ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB IMPORT)
|
||||
target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM FINGERPRINT GITDESCRIPTION)
|
||||
target_link_libraries(osrm-datastore ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT} ${OPTIONAL_OMP_LIB})
|
||||
target_link_libraries(osrm-datastore ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(OSRM ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
find_package(TBB REQUIRED)
|
||||
if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES})
|
||||
endif()
|
||||
target_link_libraries(osrm-datastore ${TBB_LIBRARIES})
|
||||
target_link_libraries(osrm-extract ${TBB_LIBRARIES})
|
||||
target_link_libraries(osrm-prepare ${TBB_LIBRARIES})
|
||||
target_link_libraries(osrm-routed ${TBB_LIBRARIES})
|
||||
include_directories(${TBB_INCLUDE_DIR})
|
||||
|
||||
find_package(Lua52)
|
||||
if(NOT LUA52_FOUND)
|
||||
@@ -190,6 +210,11 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package( Luabind REQUIRED )
|
||||
include_directories(${LUABIND_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
|
||||
|
||||
if( LUAJIT_FOUND )
|
||||
target_link_libraries(osrm-extract ${LUAJIT_LIBRARIES})
|
||||
target_link_libraries(osrm-prepare ${LUAJIT_LIBRARIES})
|
||||
@@ -203,11 +228,6 @@ find_package(LibXml2 REQUIRED)
|
||||
include_directories(${LIBXML2_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${LIBXML2_LIBRARIES})
|
||||
|
||||
find_package( Luabind REQUIRED )
|
||||
include_directories(${LUABIND_INCLUDE_DIR})
|
||||
target_link_libraries(osrm-extract ${LUABIND_LIBRARY})
|
||||
target_link_libraries(osrm-prepare ${LUABIND_LIBRARY})
|
||||
|
||||
find_package( STXXL REQUIRED )
|
||||
include_directories(${STXXL_INCLUDE_DIR})
|
||||
target_link_libraries(OSRM ${STXXL_LIBRARY})
|
||||
@@ -238,20 +258,24 @@ if(WITH_TOOLS)
|
||||
find_package(GDAL)
|
||||
if(GDAL_FOUND)
|
||||
add_executable(osrm-components Tools/components.cpp)
|
||||
target_link_libraries(osrm-components ${TBB_LIBRARIES} IMPORT)
|
||||
include_directories(${GDAL_INCLUDE_DIR})
|
||||
target_link_libraries(
|
||||
osrm-components
|
||||
${GDAL_LIBRARIES} ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB)
|
||||
${GDAL_LIBRARIES} ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB)
|
||||
else()
|
||||
message(FATAL_ERROR "libgdal and/or development headers not found")
|
||||
endif()
|
||||
add_executable(osrm-cli Tools/simpleclient.cpp)
|
||||
target_link_libraries(osrm-cli ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION)
|
||||
add_executable(osrm-io-benchmark Tools/io-benchmark.cpp)
|
||||
target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
add_executable(osrm-unlock-all Tools/unlock_all_mutexes.cpp)
|
||||
target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(osrm-unlock-all rt)
|
||||
endif()
|
||||
target_link_libraries(osrm-cli ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM FINGERPRINT GITDESCRIPTION)
|
||||
target_link_libraries(osrm-cli ${TBB_LIBRARIES})
|
||||
add_executable(osrm-io-benchmark Tools/io-benchmark.cpp)
|
||||
target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
add_executable(osrm-unlock-all Tools/unlock_all_mutexes.cpp)
|
||||
target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(osrm-unlock-all rt)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
file(GLOB InstallGlob Include/osrm/*.h Library/OSRM.h)
|
||||
|
||||
+168
-138
@@ -35,12 +35,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../DataStructures/Percent.h"
|
||||
#include "../DataStructures/XORFastHash.h"
|
||||
#include "../DataStructures/XORFastHashStorage.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <tbb/enumerable_thread_specific.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
@@ -125,6 +129,28 @@ class Contractor
|
||||
bool is_independent : 1;
|
||||
};
|
||||
|
||||
|
||||
struct ThreadDataContainer
|
||||
{
|
||||
ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes) {}
|
||||
|
||||
inline ContractorThreadData* getThreadData()
|
||||
{
|
||||
bool exists = false;
|
||||
auto& ref = data.local(exists);
|
||||
if (!exists)
|
||||
{
|
||||
ref = std::make_shared<ContractorThreadData>(number_of_nodes);
|
||||
}
|
||||
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
int number_of_nodes;
|
||||
typedef tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>> EnumerableThreadData;
|
||||
EnumerableThreadData data;
|
||||
};
|
||||
|
||||
public:
|
||||
template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
|
||||
{
|
||||
@@ -138,14 +164,15 @@ class Contractor
|
||||
ContractorEdge new_edge;
|
||||
while (diter != dend)
|
||||
{
|
||||
new_edge.source = diter->source();
|
||||
new_edge.target = diter->target();
|
||||
new_edge.data = ContractorEdgeData((std::max)((int)diter->weight(), 1),
|
||||
1,
|
||||
diter->id(),
|
||||
false,
|
||||
diter->isForward(),
|
||||
diter->isBackward());
|
||||
new_edge.source = diter->source;
|
||||
new_edge.target = diter->target;
|
||||
new_edge.data = { static_cast<unsigned int>(std::max(diter->weight, 1)),
|
||||
1,
|
||||
diter->edge_id,
|
||||
false,
|
||||
diter->forward,
|
||||
diter->backward};
|
||||
|
||||
BOOST_ASSERT_MSG(new_edge.data.distance > 0, "edge distance < 1");
|
||||
#ifndef NDEBUG
|
||||
if (new_edge.data.distance > 24 * 60 * 60 * 10)
|
||||
@@ -156,14 +183,15 @@ class Contractor
|
||||
#endif
|
||||
edges.push_back(new_edge);
|
||||
std::swap(new_edge.source, new_edge.target);
|
||||
new_edge.data.forward = diter->isBackward();
|
||||
new_edge.data.backward = diter->isForward();
|
||||
new_edge.data.forward = diter->backward;
|
||||
new_edge.data.backward = diter->forward;
|
||||
edges.push_back(new_edge);
|
||||
++diter;
|
||||
}
|
||||
// clear input vector and trim the current set of edges with the well-known swap trick
|
||||
// clear input vector
|
||||
edges.shrink_to_fit();
|
||||
input_edge_list.clear();
|
||||
sort(edges.begin(), edges.end());
|
||||
tbb::parallel_sort(edges.begin(), edges.end());
|
||||
NodeID edge = 0;
|
||||
for (NodeID i = 0; i < edges.size();)
|
||||
{
|
||||
@@ -262,39 +290,51 @@ class Contractor
|
||||
|
||||
void Run()
|
||||
{
|
||||
// for the preperation we can use a big grain size, which is much faster (probably cache)
|
||||
constexpr size_t InitGrainSize = 100000;
|
||||
constexpr size_t PQGrainSize = 100000;
|
||||
// auto_partitioner will automatically increase the blocksize if we have
|
||||
// a lot of data. It is *important* for the last loop iterations
|
||||
// (which have a very small dataset) that it is devisible.
|
||||
constexpr size_t IndependentGrainSize = 1;
|
||||
constexpr size_t ContractGrainSize = 1;
|
||||
constexpr size_t NeighboursGrainSize = 1;
|
||||
constexpr size_t DeleteGrainSize = 1;
|
||||
|
||||
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
Percent p(number_of_nodes);
|
||||
|
||||
const unsigned thread_count = omp_get_max_threads();
|
||||
std::vector<ContractorThreadData *> thread_data_list;
|
||||
for (unsigned thread_id = 0; thread_id < thread_count; ++thread_id)
|
||||
{
|
||||
thread_data_list.push_back(new ContractorThreadData(number_of_nodes));
|
||||
}
|
||||
std::cout << "Contractor is using " << thread_count << " threads" << std::endl;
|
||||
ThreadDataContainer thread_data_list(number_of_nodes);
|
||||
|
||||
NodeID number_of_contracted_nodes = 0;
|
||||
std::vector<RemainingNodeData> remaining_nodes(number_of_nodes);
|
||||
std::vector<float> node_priorities(number_of_nodes);
|
||||
std::vector<NodePriorityData> node_data(number_of_nodes);
|
||||
|
||||
// initialize priorities in parallel
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (int x = 0; x < (int)number_of_nodes; ++x)
|
||||
{
|
||||
remaining_nodes[x].id = x;
|
||||
}
|
||||
|
||||
// initialize priorities in parallel
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, InitGrainSize),
|
||||
[&remaining_nodes](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
for (int x = range.begin(); x != range.end(); ++x)
|
||||
{
|
||||
remaining_nodes[x].id = x;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
std::cout << "initializing elimination PQ ..." << std::flush;
|
||||
#pragma omp parallel
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list[omp_get_thread_num()];
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (int x = 0; x < (int)number_of_nodes; ++x)
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
|
||||
[this, &node_priorities, &node_data, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
node_priorities[x] = EvaluateNodePriority(data, &node_data[x], x);
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
for (int x = range.begin(); x != range.end(); ++x)
|
||||
{
|
||||
node_priorities[x] = this->EvaluateNodePriority(data, &node_data[x], x);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
std::cout << "ok" << std::endl << "preprocessing " << number_of_nodes << " nodes ..."
|
||||
<< std::flush;
|
||||
|
||||
@@ -309,11 +349,7 @@ class Contractor
|
||||
std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
|
||||
|
||||
// Delete old heap data to free memory that we need for the coming operations
|
||||
for (ContractorThreadData *data : thread_data_list)
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
thread_data_list.clear();
|
||||
thread_data_list.data.clear();
|
||||
|
||||
// Create new priority array
|
||||
std::vector<float> new_node_priority(remaining_nodes.size());
|
||||
@@ -339,11 +375,8 @@ class Contractor
|
||||
// walk over all nodes
|
||||
for (unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i)
|
||||
{
|
||||
const NodeID start = i;
|
||||
auto last_edge = contractor_graph->EndEdges(start);
|
||||
for (auto current_edge = contractor_graph->BeginEdges(start);
|
||||
current_edge < last_edge;
|
||||
++current_edge)
|
||||
const NodeID source = i;
|
||||
for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
|
||||
{
|
||||
ContractorGraph::EdgeData &data =
|
||||
contractor_graph->GetEdgeData(current_edge);
|
||||
@@ -352,7 +385,7 @@ class Contractor
|
||||
{
|
||||
// Save edges of this node w/o renumbering.
|
||||
temporary_storage.WriteToSlot(
|
||||
edge_storage_slot, (char *)&start, sizeof(NodeID));
|
||||
edge_storage_slot, (char *)&source, sizeof(NodeID));
|
||||
temporary_storage.WriteToSlot(
|
||||
edge_storage_slot, (char *)&target, sizeof(NodeID));
|
||||
temporary_storage.WriteToSlot(edge_storage_slot,
|
||||
@@ -365,12 +398,12 @@ class Contractor
|
||||
// node is not yet contracted.
|
||||
// add (renumbered) outgoing edges to new DynamicGraph.
|
||||
ContractorEdge new_edge;
|
||||
new_edge.source = new_node_id_from_orig_id_map[start];
|
||||
new_edge.source = new_node_id_from_orig_id_map[source];
|
||||
new_edge.target = new_node_id_from_orig_id_map[target];
|
||||
new_edge.data = data;
|
||||
new_edge.data.is_original_via_node_ID = true;
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[start],
|
||||
"new start id not resolveable");
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[source],
|
||||
"new source id not resolveable");
|
||||
BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[target],
|
||||
"new target id not resolveable");
|
||||
new_edge_set.push_back(new_edge);
|
||||
@@ -385,7 +418,8 @@ class Contractor
|
||||
// Replace old priorities array by new one
|
||||
node_priorities.swap(new_node_priority);
|
||||
// Delete old node_priorities vector
|
||||
std::vector<float>().swap(new_node_priority);
|
||||
new_node_priority.clear();
|
||||
new_node_priority.shrink_to_fit();
|
||||
// old Graph is removed
|
||||
contractor_graph.reset();
|
||||
|
||||
@@ -399,61 +433,69 @@ class Contractor
|
||||
|
||||
// INFO: MAKE SURE THIS IS THE LAST OPERATION OF THE FLUSH!
|
||||
// reinitialize heaps and ThreadData objects with appropriate size
|
||||
for (unsigned thread_id = 0; thread_id < thread_count; ++thread_id)
|
||||
{
|
||||
thread_data_list.push_back(
|
||||
new ContractorThreadData(contractor_graph->GetNumberOfNodes()));
|
||||
}
|
||||
thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
}
|
||||
|
||||
const int last = (int)remaining_nodes.size();
|
||||
#pragma omp parallel
|
||||
{
|
||||
// determine independent node set
|
||||
ContractorThreadData *const data = thread_data_list[omp_get_thread_num()];
|
||||
#pragma omp for schedule(guided)
|
||||
for (int i = 0; i < last; ++i)
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, last, IndependentGrainSize),
|
||||
[this, &node_priorities, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
const NodeID node = remaining_nodes[i].id;
|
||||
remaining_nodes[i].is_independent =
|
||||
IsNodeIndependent(node_priorities, data, node);
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
// determine independent node set
|
||||
for (int i = range.begin(); i != range.end(); ++i)
|
||||
{
|
||||
const NodeID node = remaining_nodes[i].id;
|
||||
remaining_nodes[i].is_independent =
|
||||
this->IsNodeIndependent(node_priorities, data, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const auto first = stable_partition(remaining_nodes.begin(),
|
||||
remaining_nodes.end(),
|
||||
[](RemainingNodeData node_data)
|
||||
{ return !node_data.is_independent; });
|
||||
const int first_independent_node = first - remaining_nodes.begin();
|
||||
// contract independent nodes
|
||||
#pragma omp parallel
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list[omp_get_thread_num()];
|
||||
#pragma omp for schedule(guided) nowait
|
||||
for (int position = first_independent_node; position < last; ++position)
|
||||
{
|
||||
NodeID x = remaining_nodes[position].id;
|
||||
ContractNode<false>(data, x);
|
||||
}
|
||||
const int first_independent_node = static_cast<int>(first - remaining_nodes.begin());
|
||||
|
||||
std::sort(data->inserted_edges.begin(), data->inserted_edges.end());
|
||||
}
|
||||
#pragma omp parallel
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list[omp_get_thread_num()];
|
||||
#pragma omp for schedule(guided) nowait
|
||||
for (int position = first_independent_node; position < last; ++position)
|
||||
// contract independent nodes
|
||||
tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, ContractGrainSize),
|
||||
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
NodeID x = remaining_nodes[position].id;
|
||||
DeleteIncomingEdges(data, x);
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
for (int position = range.begin(); position != range.end(); ++position)
|
||||
{
|
||||
const NodeID x = remaining_nodes[position].id;
|
||||
this->ContractNode<false>(data, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
// insert new edges
|
||||
for (unsigned thread_id = 0; thread_id < thread_count; ++thread_id)
|
||||
{
|
||||
ContractorThreadData &data = *thread_data_list[thread_id];
|
||||
for (const ContractorEdge &edge : data.inserted_edges)
|
||||
);
|
||||
// make sure we really sort each block
|
||||
tbb::parallel_for(thread_data_list.data.range(),
|
||||
[&](const ThreadDataContainer::EnumerableThreadData::range_type& range)
|
||||
{
|
||||
auto current_edge_ID = contractor_graph->FindEdge(edge.source, edge.target);
|
||||
for (auto& data : range)
|
||||
std::sort(data->inserted_edges.begin(),
|
||||
data->inserted_edges.end());
|
||||
}
|
||||
);
|
||||
tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, DeleteGrainSize),
|
||||
[this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
for (int position = range.begin(); position != range.end(); ++position)
|
||||
{
|
||||
const NodeID x = remaining_nodes[position].id;
|
||||
this->DeleteIncomingEdges(data, x);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// insert new edges
|
||||
for (auto& data : thread_data_list.data)
|
||||
{
|
||||
for (const ContractorEdge &edge : data->inserted_edges)
|
||||
{
|
||||
const EdgeID current_edge_ID = contractor_graph->FindEdge(edge.source, edge.target);
|
||||
if (current_edge_ID < contractor_graph->EndEdges(edge.source))
|
||||
{
|
||||
ContractorGraph::EdgeData ¤t_data =
|
||||
@@ -469,23 +511,25 @@ class Contractor
|
||||
}
|
||||
contractor_graph->InsertEdge(edge.source, edge.target, edge.data);
|
||||
}
|
||||
data.inserted_edges.clear();
|
||||
data->inserted_edges.clear();
|
||||
}
|
||||
// update priorities
|
||||
#pragma omp parallel
|
||||
{
|
||||
ContractorThreadData *data = thread_data_list[omp_get_thread_num()];
|
||||
#pragma omp for schedule(guided) nowait
|
||||
for (int position = first_independent_node; position < last; ++position)
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, NeighboursGrainSize),
|
||||
[this, &remaining_nodes, &node_priorities, &node_data, &thread_data_list](const tbb::blocked_range<int>& range)
|
||||
{
|
||||
NodeID x = remaining_nodes[position].id;
|
||||
UpdateNodeNeighbours(node_priorities, node_data, data, x);
|
||||
ContractorThreadData *data = thread_data_list.getThreadData();
|
||||
for (int position = range.begin(); position != range.end(); ++position)
|
||||
{
|
||||
NodeID x = remaining_nodes[position].id;
|
||||
this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// remove contracted nodes from the pool
|
||||
number_of_contracted_nodes += last - first_independent_node;
|
||||
remaining_nodes.resize(first_independent_node);
|
||||
std::vector<RemainingNodeData>(remaining_nodes).swap(remaining_nodes);
|
||||
remaining_nodes.shrink_to_fit();
|
||||
// unsigned maxdegree = 0;
|
||||
// unsigned avgdegree = 0;
|
||||
// unsigned mindegree = UINT_MAX;
|
||||
@@ -513,26 +557,22 @@ class Contractor
|
||||
|
||||
p.printStatus(number_of_contracted_nodes);
|
||||
}
|
||||
for (ContractorThreadData *data : thread_data_list)
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
thread_data_list.clear();
|
||||
|
||||
thread_data_list.data.clear();
|
||||
}
|
||||
|
||||
template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
|
||||
{
|
||||
Percent p(contractor_graph->GetNumberOfNodes());
|
||||
SimpleLogger().Write() << "Getting edges of minimized graph";
|
||||
NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
|
||||
if (contractor_graph->GetNumberOfNodes())
|
||||
{
|
||||
Edge new_edge;
|
||||
for (NodeID node = 0; node < number_of_nodes; ++node)
|
||||
{
|
||||
p.printStatus(node);
|
||||
auto endEdges = contractor_graph->EndEdges(node);
|
||||
for (auto edge = contractor_graph->BeginEdges(node); edge < endEdges; ++edge)
|
||||
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const NodeID target = contractor_graph->GetTarget(edge);
|
||||
const ContractorGraph::EdgeData &data = contractor_graph->GetEdgeData(edge);
|
||||
@@ -573,18 +613,18 @@ class Contractor
|
||||
BOOST_ASSERT(0 == orig_node_id_to_new_id_map.capacity());
|
||||
TemporaryStorage &temporary_storage = TemporaryStorage::GetInstance();
|
||||
// loads edges of graph before renumbering, no need for further numbering action.
|
||||
NodeID start;
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
ContractorGraph::EdgeData data;
|
||||
|
||||
Edge restored_edge;
|
||||
for (unsigned i = 0; i < temp_edge_counter; ++i)
|
||||
{
|
||||
temporary_storage.ReadFromSlot(edge_storage_slot, (char *)&start, sizeof(NodeID));
|
||||
temporary_storage.ReadFromSlot(edge_storage_slot, (char *)&source, sizeof(NodeID));
|
||||
temporary_storage.ReadFromSlot(edge_storage_slot, (char *)&target, sizeof(NodeID));
|
||||
temporary_storage.ReadFromSlot(
|
||||
edge_storage_slot, (char *)&data, sizeof(ContractorGraph::EdgeData));
|
||||
restored_edge.source = start;
|
||||
restored_edge.source = source;
|
||||
restored_edge.target = target;
|
||||
restored_edge.data.distance = data.distance;
|
||||
restored_edge.data.shortcut = data.shortcut;
|
||||
@@ -634,8 +674,7 @@ class Contractor
|
||||
}
|
||||
|
||||
// iterate over all edges of node
|
||||
auto end_edges = contractor_graph->EndEdges(node);
|
||||
for (auto edge = contractor_graph->BeginEdges(node); edge != end_edges; ++edge)
|
||||
for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
|
||||
if (!data.forward)
|
||||
@@ -677,14 +716,14 @@ class Contractor
|
||||
float result;
|
||||
if (0 == (stats.edges_deleted_count * stats.original_edges_deleted_count))
|
||||
{
|
||||
result = 1 * node_data->depth;
|
||||
result = 1.f * node_data->depth;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 2 * (((float)stats.edges_added_count) / stats.edges_deleted_count) +
|
||||
4 * (((float)stats.original_edges_added_count) /
|
||||
stats.original_edges_deleted_count) +
|
||||
1 * node_data->depth;
|
||||
result = 2.f * (((float)stats.edges_added_count) / stats.edges_deleted_count) +
|
||||
4.f * (((float)stats.original_edges_added_count) /
|
||||
stats.original_edges_deleted_count) +
|
||||
1.f * node_data->depth;
|
||||
}
|
||||
BOOST_ASSERT(result >= 0);
|
||||
return result;
|
||||
@@ -692,20 +731,19 @@ class Contractor
|
||||
|
||||
template <bool RUNSIMULATION>
|
||||
inline bool
|
||||
ContractNode(ContractorThreadData *data, NodeID node, ContractionStats *stats = NULL)
|
||||
ContractNode(ContractorThreadData *data, NodeID node, ContractionStats *stats = nullptr)
|
||||
{
|
||||
ContractorHeap &heap = data->heap;
|
||||
int inserted_edges_size = data->inserted_edges.size();
|
||||
std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
|
||||
|
||||
auto end_in_edges = contractor_graph->EndEdges(node);
|
||||
for (auto in_edge = contractor_graph->BeginEdges(node); in_edge != end_in_edges; ++in_edge)
|
||||
for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
|
||||
const NodeID source = contractor_graph->GetTarget(in_edge);
|
||||
if (RUNSIMULATION)
|
||||
{
|
||||
BOOST_ASSERT(stats != NULL);
|
||||
BOOST_ASSERT(stats != nullptr);
|
||||
++stats->edges_deleted_count;
|
||||
stats->original_edges_deleted_count += in_data.originalEdges;
|
||||
}
|
||||
@@ -719,9 +757,7 @@ class Contractor
|
||||
int max_distance = 0;
|
||||
unsigned number_of_targets = 0;
|
||||
|
||||
auto end_out_edges = contractor_graph->EndEdges(node);
|
||||
for (auto out_edge = contractor_graph->BeginEdges(node); out_edge != end_out_edges;
|
||||
++out_edge)
|
||||
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
|
||||
if (!out_data.forward)
|
||||
@@ -746,10 +782,7 @@ class Contractor
|
||||
{
|
||||
Dijkstra(max_distance, number_of_targets, 2000, data, node);
|
||||
}
|
||||
for (auto out_edge = contractor_graph->BeginEdges(node),
|
||||
endOutEdges = contractor_graph->EndEdges(node);
|
||||
out_edge != endOutEdges;
|
||||
++out_edge)
|
||||
for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
|
||||
if (!out_data.forward)
|
||||
@@ -763,7 +796,7 @@ class Contractor
|
||||
{
|
||||
if (RUNSIMULATION)
|
||||
{
|
||||
BOOST_ASSERT(stats != NULL);
|
||||
BOOST_ASSERT(stats != nullptr);
|
||||
stats->edges_added_count += 2;
|
||||
stats->original_edges_added_count +=
|
||||
2 * (out_data.originalEdges + in_data.originalEdges);
|
||||
@@ -780,7 +813,6 @@ class Contractor
|
||||
true,
|
||||
true,
|
||||
false);
|
||||
;
|
||||
inserted_edges.push_back(new_edge);
|
||||
std::swap(new_edge.source, new_edge.target);
|
||||
new_edge.data.forward = false;
|
||||
@@ -835,7 +867,7 @@ class Contractor
|
||||
neighbours.clear();
|
||||
|
||||
// find all neighbours
|
||||
for (auto e = contractor_graph->BeginEdges(node); e < contractor_graph->EndEdges(node); ++e)
|
||||
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const NodeID u = contractor_graph->GetTarget(e);
|
||||
if (u != node)
|
||||
@@ -862,8 +894,7 @@ class Contractor
|
||||
neighbours.clear();
|
||||
|
||||
// find all neighbours
|
||||
auto end_edges = contractor_graph->EndEdges(node);
|
||||
for (auto e = contractor_graph->BeginEdges(node); e < end_edges; ++e)
|
||||
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const NodeID u = contractor_graph->GetTarget(e);
|
||||
if (u == node)
|
||||
@@ -895,7 +926,7 @@ class Contractor
|
||||
std::vector<NodeID> &neighbours = data->neighbours;
|
||||
neighbours.clear();
|
||||
|
||||
for (auto e = contractor_graph->BeginEdges(node); e < contractor_graph->EndEdges(node); ++e)
|
||||
for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const NodeID target = contractor_graph->GetTarget(e);
|
||||
if (node == target)
|
||||
@@ -924,8 +955,7 @@ class Contractor
|
||||
// examine all neighbours that are at most 2 hops away
|
||||
for (const NodeID u : neighbours)
|
||||
{
|
||||
auto end_edges = contractor_graph->EndEdges(u);
|
||||
for (auto e = contractor_graph->BeginEdges(u); e < end_edges; ++e)
|
||||
for (auto e : contractor_graph->GetAdjacentEdgeRange(u))
|
||||
{
|
||||
const NodeID target = contractor_graph->GetTarget(e);
|
||||
if (node == target)
|
||||
|
||||
@@ -155,7 +155,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
|
||||
|
||||
const unsigned geometry_size = forward_geometry.size();
|
||||
BOOST_ASSERT(geometry_size > 1);
|
||||
NodeID current_edge_start_coordinate_id = u;
|
||||
NodeID current_edge_source_coordinate_id = u;
|
||||
|
||||
if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
|
||||
{
|
||||
@@ -169,15 +169,15 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
|
||||
// traverse arrays from start and end respectively
|
||||
for (unsigned i = 0; i < geometry_size; ++i)
|
||||
{
|
||||
BOOST_ASSERT(current_edge_start_coordinate_id ==
|
||||
BOOST_ASSERT(current_edge_source_coordinate_id ==
|
||||
reverse_geometry[geometry_size - 1 - i].first);
|
||||
const NodeID current_edge_target_coordinate_id = forward_geometry[i].first;
|
||||
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_start_coordinate_id);
|
||||
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
|
||||
|
||||
// build edges
|
||||
m_edge_based_node_list.emplace_back(forward_data.edgeBasedNodeID,
|
||||
reverse_data.edgeBasedNodeID,
|
||||
current_edge_start_coordinate_id,
|
||||
current_edge_source_coordinate_id,
|
||||
current_edge_target_coordinate_id,
|
||||
forward_data.nameID,
|
||||
forward_geometry[i].second,
|
||||
@@ -187,7 +187,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
|
||||
m_geometry_compressor.GetPositionForID(e1),
|
||||
i,
|
||||
belongs_to_tiny_cc);
|
||||
current_edge_start_coordinate_id = current_edge_target_coordinate_id;
|
||||
current_edge_source_coordinate_id = current_edge_target_coordinate_id;
|
||||
|
||||
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
|
||||
|
||||
@@ -198,7 +198,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
|
||||
v != m_edge_based_node_list.back().u);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(current_edge_start_coordinate_id == v);
|
||||
BOOST_ASSERT(current_edge_source_coordinate_id == v);
|
||||
BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
|
||||
}
|
||||
else
|
||||
@@ -244,6 +244,9 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool b
|
||||
void EdgeBasedGraphFactory::FlushVectorToStream(
|
||||
std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
|
||||
{
|
||||
if (original_edge_data_vector.empty()) {
|
||||
return;
|
||||
}
|
||||
edge_data_file.write((char *)&(original_edge_data_vector[0]),
|
||||
original_edge_data_vector.size() * sizeof(OriginalEdgeData));
|
||||
original_edge_data_vector.clear();
|
||||
@@ -273,10 +276,10 @@ void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
|
||||
m_geometry_compressor.SerializeInternalVector(geometry_filename);
|
||||
|
||||
SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
|
||||
SimpleLogger().Write() << "Geometry compression: " << TIMER_MSEC(geometry)*0.001 << "s";
|
||||
SimpleLogger().Write() << "Renumbering edges: " << TIMER_MSEC(renumber)*0.001 << "s";
|
||||
SimpleLogger().Write() << "Generating nodes: " << TIMER_MSEC(generate_nodes)*0.001 << "s";
|
||||
SimpleLogger().Write() << "Generating edges: " << TIMER_MSEC(generate_edges)*0.001 << "s";
|
||||
SimpleLogger().Write() << "Geometry compression: " << TIMER_SEC(geometry) << "s";
|
||||
SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
|
||||
SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
|
||||
SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::CompressGeometry()
|
||||
@@ -305,6 +308,12 @@ void EdgeBasedGraphFactory::CompressGeometry()
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
|
||||
if (m_restriction_map->IsViaNode(v))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool reverse_edge_order =
|
||||
!(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(v)).forward);
|
||||
const EdgeID forward_e2 = m_node_based_graph->BeginEdges(v) + reverse_edge_order;
|
||||
@@ -438,9 +447,7 @@ void EdgeBasedGraphFactory::RenumberEdges()
|
||||
for (NodeID current_node = 0; current_node < m_node_based_graph->GetNumberOfNodes();
|
||||
++current_node)
|
||||
{
|
||||
for (EdgeID current_edge = m_node_based_graph->BeginEdges(current_node);
|
||||
current_edge < m_node_based_graph->EndEdges(current_node);
|
||||
++current_edge)
|
||||
for (EdgeID current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
|
||||
{
|
||||
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
|
||||
if (!edge_data.forward)
|
||||
@@ -483,10 +490,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
||||
BOOST_ASSERT(u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(u < m_node_based_graph->GetNumberOfNodes());
|
||||
p.printIncrement();
|
||||
for (EdgeID e1 = m_node_based_graph->BeginEdges(u),
|
||||
last_edge = m_node_based_graph->EndEdges(u);
|
||||
e1 < last_edge;
|
||||
++e1)
|
||||
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
|
||||
{
|
||||
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
|
||||
if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
|
||||
@@ -552,10 +556,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
|
||||
|
||||
for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
|
||||
{
|
||||
for (EdgeID e1 = m_node_based_graph->BeginEdges(u),
|
||||
last_edge_u = m_node_based_graph->EndEdges(u);
|
||||
e1 < last_edge_u;
|
||||
++e1)
|
||||
for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
|
||||
{
|
||||
if (!m_node_based_graph->GetEdgeData(e1).forward)
|
||||
{
|
||||
@@ -568,10 +569,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
|
||||
m_restriction_map->CheckForEmanatingIsOnlyTurn(u, v);
|
||||
const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
|
||||
|
||||
for (EdgeID e2 = m_node_based_graph->BeginEdges(v),
|
||||
last_edge_v = m_node_based_graph->EndEdges(v);
|
||||
e2 < last_edge_v;
|
||||
++e2)
|
||||
for (EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
|
||||
{
|
||||
if (!m_node_based_graph->GetEdgeData(e2).forward)
|
||||
{
|
||||
@@ -610,6 +608,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
|
||||
(to_node_of_only_restriction == SPECIAL_NODEID) &&
|
||||
(w != to_node_of_only_restriction))
|
||||
{
|
||||
// We are at an only_-restriction but not at the right turn.
|
||||
++restricted_turns_counter;
|
||||
continue;
|
||||
}
|
||||
@@ -628,8 +627,10 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
|
||||
{
|
||||
distance += speed_profile.trafficSignalPenalty;
|
||||
}
|
||||
const int turn_penalty = GetTurnPenalty(u, v, w, lua_state);
|
||||
TurnInstruction turn_instruction = AnalyzeTurn(u, v, w);
|
||||
const double angle = GetAngleBetweenThreeFixedPointCoordinates(
|
||||
m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
|
||||
const int turn_penalty = GetTurnPenalty(angle, lua_state);
|
||||
TurnInstruction turn_instruction = AnalyzeTurn(u, v, w, angle);
|
||||
if (turn_instruction == TurnInstruction::UTurn)
|
||||
{
|
||||
distance += speed_profile.uTurnPenalty;
|
||||
@@ -686,13 +687,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
|
||||
SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
|
||||
}
|
||||
|
||||
int EdgeBasedGraphFactory::GetTurnPenalty(const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w,
|
||||
lua_State *lua_state) const
|
||||
int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
|
||||
{
|
||||
const double angle = GetAngleBetweenThreeFixedPointCoordinates(
|
||||
m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
|
||||
|
||||
if (speed_profile.has_turn_penalty_function)
|
||||
{
|
||||
@@ -706,7 +702,10 @@ int EdgeBasedGraphFactory::GetTurnPenalty(const NodeID u,
|
||||
return 0;
|
||||
}
|
||||
|
||||
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w)
|
||||
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u,
|
||||
const NodeID v,
|
||||
const NodeID w,
|
||||
double angle)
|
||||
const
|
||||
{
|
||||
if (u == w)
|
||||
@@ -733,7 +732,7 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID
|
||||
if (data1.roundabout && data2.roundabout)
|
||||
{
|
||||
// Is a turn possible? If yes, we stay on the roundabout!
|
||||
if (1 == m_node_based_graph->GetOutDegree(v))
|
||||
if (1 == m_node_based_graph->GetDirectedOutDegree(v))
|
||||
{
|
||||
// No turn possible.
|
||||
return TurnInstruction::NoTurn;
|
||||
@@ -771,8 +770,6 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID
|
||||
}
|
||||
}
|
||||
|
||||
const double angle = GetAngleBetweenThreeFixedPointCoordinates(
|
||||
m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
|
||||
return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
#include "../DataStructures/DynamicGraph.h"
|
||||
#include "../DataStructures/EdgeBasedNode.h"
|
||||
#include "../DataStructures/OriginalEdgeData.h"
|
||||
#include "../DataStructures/QueryNode.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../DataStructures/NodeBasedGraph.h"
|
||||
#include "../DataStructures/RestrictionMap.h"
|
||||
#include "GeometryCompressor.h"
|
||||
@@ -76,9 +74,9 @@ class EdgeBasedGraphFactory
|
||||
|
||||
void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
|
||||
|
||||
TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w) const;
|
||||
TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, double angle) const;
|
||||
|
||||
int GetTurnPenalty(const NodeID u, const NodeID v, const NodeID w, lua_State *lua_state) const;
|
||||
int GetTurnPenalty(double angle, lua_State *lua_state) const;
|
||||
|
||||
unsigned GetNumberOfEdgeBasedNodes() const;
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
int current_free_list_maximum = 0;
|
||||
int UniqueNumber() { return ++current_free_list_maximum; }
|
||||
int free_list_maximum = 0;
|
||||
int UniqueNumber() { return ++free_list_maximum; }
|
||||
|
||||
GeometryCompressor::GeometryCompressor()
|
||||
{
|
||||
@@ -49,14 +49,15 @@ void GeometryCompressor::IncreaseFreeList()
|
||||
m_compressed_geometries.resize(m_compressed_geometries.size() + 100);
|
||||
for (unsigned i = 100; i > 0; --i)
|
||||
{
|
||||
m_free_list.emplace_back(current_free_list_maximum);
|
||||
++current_free_list_maximum;
|
||||
m_free_list.emplace_back(free_list_maximum);
|
||||
++free_list_maximum;
|
||||
}
|
||||
}
|
||||
|
||||
bool GeometryCompressor::HasEntryForID(const EdgeID edge_id) const
|
||||
{
|
||||
return (m_edge_id_to_list_index_map.find(edge_id) != m_edge_id_to_list_index_map.end());
|
||||
auto iter = m_edge_id_to_list_index_map.find(edge_id);
|
||||
return iter != m_edge_id_to_list_index_map.end();
|
||||
}
|
||||
|
||||
unsigned GeometryCompressor::GetPositionForID(const EdgeID edge_id) const
|
||||
@@ -71,9 +72,9 @@ void GeometryCompressor::SerializeInternalVector(const std::string &path) const
|
||||
{
|
||||
|
||||
boost::filesystem::fstream geometry_out_stream(path, std::ios::binary | std::ios::out);
|
||||
const unsigned number_of_compressed_geometries = m_compressed_geometries.size() + 1;
|
||||
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != number_of_compressed_geometries);
|
||||
geometry_out_stream.write((char *)&number_of_compressed_geometries, sizeof(unsigned));
|
||||
const unsigned compressed_geometries = m_compressed_geometries.size() + 1;
|
||||
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != compressed_geometries);
|
||||
geometry_out_stream.write((char *)&compressed_geometries, sizeof(unsigned));
|
||||
|
||||
// write indices array
|
||||
unsigned prefix_sum_of_list_indices = 0;
|
||||
@@ -146,6 +147,7 @@ void GeometryCompressor::CompressEdge(const EdgeID edge_id_1,
|
||||
m_free_list.pop_back();
|
||||
}
|
||||
|
||||
// find bucket index
|
||||
const auto iter = m_edge_id_to_list_index_map.find(edge_id_1);
|
||||
BOOST_ASSERT(iter != m_edge_id_to_list_index_map.end());
|
||||
const unsigned edge_bucket_id1 = iter->second;
|
||||
@@ -197,23 +199,23 @@ void GeometryCompressor::PrintStatistics() const
|
||||
BOOST_ASSERT(0 == compressed_edges % 2);
|
||||
BOOST_ASSERT(m_compressed_geometries.size() + m_free_list.size() > 0);
|
||||
|
||||
uint64_t number_of_compressed_geometries = 0;
|
||||
uint64_t compressed_geometries = 0;
|
||||
uint64_t longest_chain_length = 0;
|
||||
for (const std::vector<CompressedNode> ¤t_vector : m_compressed_geometries)
|
||||
{
|
||||
number_of_compressed_geometries += current_vector.size();
|
||||
compressed_geometries += current_vector.size();
|
||||
longest_chain_length = std::max(longest_chain_length, (uint64_t)current_vector.size());
|
||||
}
|
||||
|
||||
SimpleLogger().Write() << "Geometry successfully removed:"
|
||||
"\n compressed edges: " << compressed_edges
|
||||
<< "\n compressed geometries: " << number_of_compressed_geometries
|
||||
<< "\n compressed geometries: " << compressed_geometries
|
||||
<< "\n longest chain length: " << longest_chain_length
|
||||
<< "\n cmpr ratio: "
|
||||
<< ((float)compressed_edges /
|
||||
std::max(number_of_compressed_geometries, (uint64_t)1))
|
||||
std::max(compressed_geometries, (uint64_t)1))
|
||||
<< "\n avg chain length: "
|
||||
<< (float)number_of_compressed_geometries /
|
||||
<< (float)compressed_geometries /
|
||||
std::max((uint64_t)1, compressed_edges);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "TemporaryStorage.h"
|
||||
|
||||
StreamData::StreamData()
|
||||
: write_mode(true), temp_path(boost::filesystem::unique_path(temp_directory.append(
|
||||
TemporaryFilePattern.begin(), TemporaryFilePattern.end()))),
|
||||
: write_mode(true),
|
||||
temp_path(boost::filesystem::unique_path(temp_directory / TemporaryFilePattern)),
|
||||
temp_file(new boost::filesystem::fstream(
|
||||
temp_path, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary)),
|
||||
readWriteMutex(std::make_shared<boost::mutex>())
|
||||
@@ -126,7 +126,7 @@ void TemporaryStorage::ReadFromSlot(const int slot_id, char *pointer, const std:
|
||||
BOOST_ASSERT(!data.write_mode);
|
||||
data.temp_file->read(pointer, size);
|
||||
}
|
||||
catch (boost::filesystem::filesystem_error &e) { Abort(e); }
|
||||
catch (boost::filesystem::filesystem_error &error) { Abort(error); }
|
||||
}
|
||||
|
||||
uint64_t TemporaryStorage::GetFreeBytesOnTemporaryDevice()
|
||||
@@ -134,19 +134,19 @@ uint64_t TemporaryStorage::GetFreeBytesOnTemporaryDevice()
|
||||
uint64_t value = -1;
|
||||
try
|
||||
{
|
||||
boost::filesystem::path p = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::space_info s = boost::filesystem::space(p);
|
||||
value = s.free;
|
||||
boost::filesystem::path path = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::space_info space_info = boost::filesystem::space(path);
|
||||
value = space_info.free;
|
||||
}
|
||||
catch (boost::filesystem::filesystem_error &e) { Abort(e); }
|
||||
catch (boost::filesystem::filesystem_error &error) { Abort(error); }
|
||||
return value;
|
||||
}
|
||||
|
||||
void TemporaryStorage::CheckIfTemporaryDeviceFull()
|
||||
{
|
||||
boost::filesystem::path p = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::space_info s = boost::filesystem::space(p);
|
||||
if ((1024 * 1024) > s.free)
|
||||
boost::filesystem::path path = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::space_info space_info = boost::filesystem::space(path);
|
||||
if ((1024 * 1024) > space_info.free)
|
||||
{
|
||||
throw OSRMException("temporary device is full");
|
||||
}
|
||||
@@ -165,8 +165,8 @@ boost::filesystem::fstream::pos_type TemporaryStorage::Tell(const int slot_id)
|
||||
return position;
|
||||
}
|
||||
|
||||
void TemporaryStorage::Abort(const boost::filesystem::filesystem_error &e)
|
||||
void TemporaryStorage::Abort(const boost::filesystem::filesystem_error &error)
|
||||
{
|
||||
RemoveAll();
|
||||
throw OSRMException(e.what());
|
||||
throw OSRMException(error.what());
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ template <typename Data> class ConcurrentQueue
|
||||
[this]
|
||||
{ return m_internal_queue.size() < m_internal_queue.capacity(); });
|
||||
m_internal_queue.push_back(data);
|
||||
m_mutex.unlock();
|
||||
m_not_empty.notify_one();
|
||||
}
|
||||
|
||||
@@ -60,7 +59,6 @@ template <typename Data> class ConcurrentQueue
|
||||
{ return !m_internal_queue.empty(); });
|
||||
popped_value = m_internal_queue.front();
|
||||
m_internal_queue.pop_front();
|
||||
m_mutex.unlock();
|
||||
m_not_full.notify_one();
|
||||
}
|
||||
|
||||
@@ -73,7 +71,6 @@ template <typename Data> class ConcurrentQueue
|
||||
}
|
||||
popped_value = m_internal_queue.front();
|
||||
m_internal_queue.pop_front();
|
||||
m_mutex.unlock();
|
||||
m_not_full.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
+446
-331
@@ -1,331 +1,446 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include "../Util/MercatorUtil.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <bitset>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
FixedPointCoordinate::FixedPointCoordinate()
|
||||
: lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min())
|
||||
{
|
||||
}
|
||||
|
||||
FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (0 != (std::abs(lat) >> 30))
|
||||
{
|
||||
std::bitset<32> y(lat);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lat: " << lat << ", bits: " << y;
|
||||
}
|
||||
if (0 != (std::abs(lon) >> 30))
|
||||
{
|
||||
std::bitset<32> x(lon);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lon: " << lon << ", bits: " << x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::Reset()
|
||||
{
|
||||
lat = std::numeric_limits<int>::min();
|
||||
lon = std::numeric_limits<int>::min();
|
||||
}
|
||||
bool FixedPointCoordinate::isSet() const
|
||||
{
|
||||
return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon);
|
||||
}
|
||||
bool FixedPointCoordinate::isValid() const
|
||||
{
|
||||
if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
|
||||
lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const
|
||||
{
|
||||
return lat == other.lat && lon == other.lon;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateDistance(const int lat1,
|
||||
const int lon1,
|
||||
const int lat2,
|
||||
const int lon2)
|
||||
{
|
||||
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
|
||||
double RAD = 0.017453292519943295769236907684886;
|
||||
double lt1 = lat1 / COORDINATE_PRECISION;
|
||||
double ln1 = lon1 / COORDINATE_PRECISION;
|
||||
double lt2 = lat2 / COORDINATE_PRECISION;
|
||||
double ln2 = lon2 / COORDINATE_PRECISION;
|
||||
double dlat1 = lt1 * (RAD);
|
||||
|
||||
double dlong1 = ln1 * (RAD);
|
||||
double dlat2 = lt2 * (RAD);
|
||||
double dlong2 = ln2 * (RAD);
|
||||
|
||||
double dLong = dlong1 - dlong2;
|
||||
double dLat = dlat1 - dlat2;
|
||||
|
||||
double aHarv = pow(sin(dLat / 2.0), 2.0) + cos(dlat1) * cos(dlat2) * pow(sin(dLong / 2.), 2);
|
||||
double cHarv = 2. * atan2(sqrt(aHarv), sqrt(1.0 - aHarv));
|
||||
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
|
||||
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
|
||||
const double earth = 6372797.560856;
|
||||
return earth * cHarv;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2)
|
||||
{
|
||||
return ApproximateDistance(c1.lat, c1.lon, c2.lat, c2.lon);
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2)
|
||||
{
|
||||
return ApproximateEuclideanDistance(c1.lat, c1.lon, c2.lat, c2.lon);
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
|
||||
const int lon1,
|
||||
const int lat2,
|
||||
const int lon2)
|
||||
{
|
||||
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
|
||||
|
||||
const double RAD = 0.017453292519943295769236907684886;
|
||||
const double float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
|
||||
const double float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
|
||||
const double float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
|
||||
const double float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
|
||||
|
||||
const double x = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.);
|
||||
const double y = (float_lat2 - float_lat1);
|
||||
const double earth_radius = 6372797.560856;
|
||||
return sqrt(x * x + y * y) * earth_radius;
|
||||
}
|
||||
|
||||
// Yuck! Code duplication. This function is also in EgdeBasedNode.h
|
||||
double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &point,
|
||||
const FixedPointCoordinate &segA,
|
||||
const FixedPointCoordinate &segB)
|
||||
{
|
||||
const double x = lat2y(point.lat / COORDINATE_PRECISION);
|
||||
const double y = point.lon / COORDINATE_PRECISION;
|
||||
const double a = lat2y(segA.lat / COORDINATE_PRECISION);
|
||||
const double b = segA.lon / COORDINATE_PRECISION;
|
||||
const double c = lat2y(segB.lat / COORDINATE_PRECISION);
|
||||
const double d = segB.lon / COORDINATE_PRECISION;
|
||||
double p, q, nY;
|
||||
if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
const double m = (d - b) / (c - a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m);
|
||||
q = b + m * (p - a);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
nY = (d * p - c * q) / (a * d - b * c);
|
||||
|
||||
// discretize the result to coordinate precision. it's a hack!
|
||||
if (std::abs(nY) < (1. / COORDINATE_PRECISION))
|
||||
{
|
||||
nY = 0.;
|
||||
}
|
||||
|
||||
double r = (p - nY * a) / c;
|
||||
if (std::isnan(r))
|
||||
{
|
||||
r = ((segB.lat == point.lat) && (segB.lon == point.lon)) ? 1. : 0.;
|
||||
}
|
||||
else if (std::abs(r) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
r = 0.;
|
||||
}
|
||||
else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
r = 1.;
|
||||
}
|
||||
FixedPointCoordinate nearest_location;
|
||||
BOOST_ASSERT(!std::isnan(r));
|
||||
if (r <= 0.)
|
||||
{ // point is "left" of edge
|
||||
nearest_location.lat = segA.lat;
|
||||
nearest_location.lon = segA.lon;
|
||||
}
|
||||
else if (r >= 1.)
|
||||
{ // point is "right" of edge
|
||||
nearest_location.lat = segB.lat;
|
||||
nearest_location.lon = segB.lon;
|
||||
}
|
||||
else
|
||||
{ // point lies in between
|
||||
nearest_location.lat = y2lat(p) * COORDINATE_PRECISION;
|
||||
nearest_location.lon = q * COORDINATE_PRECISION;
|
||||
}
|
||||
BOOST_ASSERT(nearest_location.isValid());
|
||||
const double approximated_distance =
|
||||
FixedPointCoordinate::ApproximateDistance(point, nearest_location);
|
||||
BOOST_ASSERT(0. <= approximated_distance);
|
||||
return approximated_distance;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &coord_a,
|
||||
const FixedPointCoordinate &coord_b,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
double &r)
|
||||
{
|
||||
BOOST_ASSERT(query_location.isValid());
|
||||
|
||||
const double x = lat2y(query_location.lat / COORDINATE_PRECISION);
|
||||
const double y = query_location.lon / COORDINATE_PRECISION;
|
||||
const double a = lat2y(coord_a.lat / COORDINATE_PRECISION);
|
||||
const double b = coord_a.lon / COORDINATE_PRECISION;
|
||||
const double c = lat2y(coord_b.lat / COORDINATE_PRECISION);
|
||||
const double d = coord_b.lon / COORDINATE_PRECISION;
|
||||
double p, q /*,mX*/, nY;
|
||||
if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
const double m = (d - b) / (c - a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m);
|
||||
q = b + m * (p - a);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
nY = (d * p - c * q) / (a * d - b * c);
|
||||
|
||||
// discretize the result to coordinate precision. it's a hack!
|
||||
if (std::abs(nY) < (1. / COORDINATE_PRECISION))
|
||||
{
|
||||
nY = 0.;
|
||||
}
|
||||
|
||||
r = (p - nY * a) / c; // These values are actually n/m+n and m/m+n , we need
|
||||
// not calculate the explicit values of m an n as we
|
||||
// are just interested in the ratio
|
||||
if (std::isnan(r))
|
||||
{
|
||||
r = ((coord_b.lat == query_location.lat) && (coord_b.lon == query_location.lon)) ? 1. : 0.;
|
||||
}
|
||||
else if (std::abs(r) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
r = 0.;
|
||||
}
|
||||
else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
r = 1.;
|
||||
}
|
||||
BOOST_ASSERT(!std::isnan(r));
|
||||
if (r <= 0.)
|
||||
{
|
||||
nearest_location.lat = coord_a.lat;
|
||||
nearest_location.lon = coord_a.lon;
|
||||
}
|
||||
else if (r >= 1.)
|
||||
{
|
||||
nearest_location.lat = coord_b.lat;
|
||||
nearest_location.lon = coord_b.lon;
|
||||
}
|
||||
else
|
||||
{
|
||||
// point lies in between
|
||||
nearest_location.lat = y2lat(p) * COORDINATE_PRECISION;
|
||||
nearest_location.lon = q * COORDINATE_PRECISION;
|
||||
}
|
||||
BOOST_ASSERT(nearest_location.isValid());
|
||||
|
||||
// TODO: Replace with euclidean approximation when k-NN search is done
|
||||
// const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
const double approximated_distance =
|
||||
FixedPointCoordinate::ApproximateDistance(query_location, nearest_location);
|
||||
BOOST_ASSERT(0. <= approximated_distance);
|
||||
return approximated_distance;
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::convertInternalLatLonToString(const int value, std::string &output)
|
||||
{
|
||||
char buffer[12];
|
||||
buffer[11] = 0; // zero termination
|
||||
output = printInt<11, 6>(buffer, value);
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::convertInternalCoordinateToString(const FixedPointCoordinate &coord,
|
||||
std::string &output)
|
||||
{
|
||||
std::string tmp;
|
||||
tmp.reserve(23);
|
||||
convertInternalLatLonToString(coord.lon, tmp);
|
||||
output = tmp;
|
||||
output += ",";
|
||||
convertInternalLatLonToString(coord.lat, tmp);
|
||||
output += tmp;
|
||||
}
|
||||
|
||||
void
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord,
|
||||
std::string &output)
|
||||
{
|
||||
std::string tmp;
|
||||
tmp.reserve(23);
|
||||
convertInternalLatLonToString(coord.lat, tmp);
|
||||
output = tmp;
|
||||
output += ",";
|
||||
convertInternalLatLonToString(coord.lon, tmp);
|
||||
output += tmp;
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::Output(std::ostream &out) const
|
||||
{
|
||||
out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")";
|
||||
}
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include "../Util/MercatorUtil.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <bitset>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
FixedPointCoordinate::FixedPointCoordinate()
|
||||
: lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min())
|
||||
{
|
||||
}
|
||||
|
||||
FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (0 != (std::abs(lat) >> 30))
|
||||
{
|
||||
std::bitset<32> y_coordinate_vector(lat);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lat: " << lat
|
||||
<< ", bits: " << y_coordinate_vector;
|
||||
}
|
||||
if (0 != (std::abs(lon) >> 30))
|
||||
{
|
||||
std::bitset<32> x_coordinate_vector(lon);
|
||||
SimpleLogger().Write(logDEBUG) << "broken lon: " << lon
|
||||
<< ", bits: " << x_coordinate_vector;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::Reset()
|
||||
{
|
||||
lat = std::numeric_limits<int>::min();
|
||||
lon = std::numeric_limits<int>::min();
|
||||
}
|
||||
bool FixedPointCoordinate::isSet() const
|
||||
{
|
||||
return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon);
|
||||
}
|
||||
bool FixedPointCoordinate::isValid() const
|
||||
{
|
||||
if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
|
||||
lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const
|
||||
{
|
||||
return lat == other.lat && lon == other.lon;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateDistance(const int lat1,
|
||||
const int lon1,
|
||||
const int lat2,
|
||||
const int lon2)
|
||||
{
|
||||
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
|
||||
double RAD = 0.017453292519943295769236907684886;
|
||||
double lt1 = lat1 / COORDINATE_PRECISION;
|
||||
double ln1 = lon1 / COORDINATE_PRECISION;
|
||||
double lt2 = lat2 / COORDINATE_PRECISION;
|
||||
double ln2 = lon2 / COORDINATE_PRECISION;
|
||||
double dlat1 = lt1 * (RAD);
|
||||
|
||||
double dlong1 = ln1 * (RAD);
|
||||
double dlat2 = lt2 * (RAD);
|
||||
double dlong2 = ln2 * (RAD);
|
||||
|
||||
double dLong = dlong1 - dlong2;
|
||||
double dLat = dlat1 - dlat2;
|
||||
|
||||
double aHarv = pow(sin(dLat / 2.0), 2.0) + cos(dlat1) * cos(dlat2) * pow(sin(dLong / 2.), 2);
|
||||
double cHarv = 2. * atan2(sqrt(aHarv), sqrt(1.0 - aHarv));
|
||||
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
|
||||
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
|
||||
const double earth = 6372797.560856;
|
||||
return earth * cHarv;
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &coordinate_1,
|
||||
const FixedPointCoordinate &coordinate_2)
|
||||
{
|
||||
return ApproximateDistance(
|
||||
coordinate_1.lat, coordinate_1.lon, coordinate_2.lat, coordinate_2.lon);
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &coordinate_1,
|
||||
const FixedPointCoordinate &coordinate_2)
|
||||
{
|
||||
return ApproximateEuclideanDistance(
|
||||
coordinate_1.lat, coordinate_1.lon, coordinate_2.lat, coordinate_2.lon);
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
|
||||
const int lon1,
|
||||
const int lat2,
|
||||
const int lon2)
|
||||
{
|
||||
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
|
||||
|
||||
const float RAD = 0.017453292519943295769236907684886f;
|
||||
const float float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
|
||||
|
||||
const float x_value = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.f);
|
||||
const float y_value = float_lat2 - float_lat1;
|
||||
const float earth_radius = 6372797.560856f;
|
||||
return sqrt(x_value * x_value + y_value * y_value) * earth_radius;
|
||||
}
|
||||
|
||||
float
|
||||
FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &source_coordinate,
|
||||
const FixedPointCoordinate &target_coordinate,
|
||||
const FixedPointCoordinate &point)
|
||||
{
|
||||
// initialize values
|
||||
const float x_value = lat2y(point.lat / COORDINATE_PRECISION);
|
||||
const float y_value = point.lon / COORDINATE_PRECISION;
|
||||
const float a = lat2y(source_coordinate.lat / COORDINATE_PRECISION);
|
||||
const float b = source_coordinate.lon / COORDINATE_PRECISION;
|
||||
const float c = lat2y(target_coordinate.lat / COORDINATE_PRECISION);
|
||||
const float d = target_coordinate.lon / COORDINATE_PRECISION;
|
||||
float p, q;
|
||||
if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
const float slope = (d - b) / (c - a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x_value + (slope * y_value)) + (slope * slope * a - slope * b)) /
|
||||
(1.f + slope * slope);
|
||||
q = b + slope * (p - a);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = c;
|
||||
q = y_value;
|
||||
}
|
||||
|
||||
float nY = (d * p - c * q) / (a * d - b * c);
|
||||
// discretize the result to coordinate precision. it's a hack!
|
||||
if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
|
||||
{
|
||||
nY = 0.f;
|
||||
}
|
||||
|
||||
// compute ratio
|
||||
float ratio = (p - nY * a) / c;
|
||||
if (std::isnan(ratio))
|
||||
{
|
||||
ratio = (target_coordinate == point ? 1.f : 0.f);
|
||||
}
|
||||
else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
ratio = 0.f;
|
||||
}
|
||||
else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
ratio = 1.f;
|
||||
}
|
||||
|
||||
//compute the nearest location
|
||||
FixedPointCoordinate nearest_location;
|
||||
BOOST_ASSERT(!std::isnan(ratio));
|
||||
if (ratio <= 0.f)
|
||||
{ // point is "left" of edge
|
||||
nearest_location = source_coordinate;
|
||||
}
|
||||
else if (ratio >= 1.f)
|
||||
{ // point is "right" of edge
|
||||
nearest_location = target_coordinate;
|
||||
}
|
||||
else
|
||||
{ // point lies in between
|
||||
nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
|
||||
nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
|
||||
}
|
||||
BOOST_ASSERT(nearest_location.isValid());
|
||||
return FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio)
|
||||
{
|
||||
BOOST_ASSERT(query_location.isValid());
|
||||
|
||||
// initialize values
|
||||
const float x = lat2y(query_location.lat / COORDINATE_PRECISION);
|
||||
const float y = query_location.lon / COORDINATE_PRECISION;
|
||||
const float a = lat2y(segment_source.lat / COORDINATE_PRECISION);
|
||||
const float b = segment_source.lon / COORDINATE_PRECISION;
|
||||
const float c = lat2y(segment_target.lat / COORDINATE_PRECISION);
|
||||
const float d = segment_target.lon / COORDINATE_PRECISION;
|
||||
float p, q /*,mX*/, nY;
|
||||
if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
const float m = (d - b) / (c - a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x + (m * y)) + (m * m * a - m * b)) / (1.f + m * m);
|
||||
q = b + m * (p - a);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
nY = (d * p - c * q) / (a * d - b * c);
|
||||
|
||||
// discretize the result to coordinate precision. it's a hack!
|
||||
if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
|
||||
{
|
||||
nY = 0.f;
|
||||
}
|
||||
|
||||
// compute ratio
|
||||
ratio = (p - nY * a) / c; // These values are actually n/m+n and m/m+n , we need
|
||||
// not calculate the explicit values of m an n as we
|
||||
// are just interested in the ratio
|
||||
if (std::isnan(ratio))
|
||||
{
|
||||
ratio = (segment_target == query_location ? 1.f : 0.f);
|
||||
}
|
||||
else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
ratio = 0.;
|
||||
}
|
||||
else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
ratio = 1.f;
|
||||
}
|
||||
|
||||
// compute nearest location
|
||||
BOOST_ASSERT(!std::isnan(ratio));
|
||||
if (ratio <= 0.f)
|
||||
{
|
||||
nearest_location = segment_source;
|
||||
}
|
||||
else if (ratio >= 1.)
|
||||
{
|
||||
nearest_location = segment_target;
|
||||
}
|
||||
else
|
||||
{
|
||||
// point lies in between
|
||||
nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
|
||||
nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
|
||||
}
|
||||
BOOST_ASSERT(nearest_location.isValid());
|
||||
|
||||
const float approximate_distance =
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(query_location, nearest_location);
|
||||
BOOST_ASSERT(0. <= approximate_distance);
|
||||
return approximate_distance;
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::convertInternalLatLonToString(const int value, std::string &output)
|
||||
{
|
||||
char buffer[12];
|
||||
buffer[11] = 0; // zero termination
|
||||
output = printInt<11, 6>(buffer, value);
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::convertInternalCoordinateToString(const FixedPointCoordinate &coord,
|
||||
std::string &output)
|
||||
{
|
||||
std::string tmp;
|
||||
tmp.reserve(23);
|
||||
convertInternalLatLonToString(coord.lon, tmp);
|
||||
output = tmp;
|
||||
output += ",";
|
||||
convertInternalLatLonToString(coord.lat, tmp);
|
||||
output += tmp;
|
||||
}
|
||||
|
||||
void
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord,
|
||||
std::string &output)
|
||||
{
|
||||
std::string tmp;
|
||||
tmp.reserve(23);
|
||||
convertInternalLatLonToString(coord.lat, tmp);
|
||||
output = tmp;
|
||||
output += ",";
|
||||
convertInternalLatLonToString(coord.lon, tmp);
|
||||
output += tmp;
|
||||
}
|
||||
|
||||
void FixedPointCoordinate::Output(std::ostream &out) const
|
||||
{
|
||||
out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")";
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate)
|
||||
{
|
||||
const float lon_diff = second_coordinate.lon / COORDINATE_PRECISION - first_coordinate.lon / COORDINATE_PRECISION;
|
||||
const float lon_delta = DegreeToRadian(lon_diff);
|
||||
const float lat1 = DegreeToRadian(first_coordinate.lat / COORDINATE_PRECISION);
|
||||
const float lat2 = DegreeToRadian(second_coordinate.lat / COORDINATE_PRECISION);
|
||||
const float y = sin(lon_delta) * cos(lat2);
|
||||
const float x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon_delta);
|
||||
float result = RadianToDegree(std::atan2(y, x));
|
||||
while (result < 0.f)
|
||||
{
|
||||
result += 360.f;
|
||||
}
|
||||
|
||||
while (result >= 360.f)
|
||||
{
|
||||
result -= 360.f;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &other) const
|
||||
{
|
||||
const float lon_delta =
|
||||
DegreeToRadian(lon / COORDINATE_PRECISION - other.lon / COORDINATE_PRECISION);
|
||||
const float lat1 = DegreeToRadian(other.lat / COORDINATE_PRECISION);
|
||||
const float lat2 = DegreeToRadian(lat / COORDINATE_PRECISION);
|
||||
const float y_value = std::sin(lon_delta) * std::cos(lat2);
|
||||
const float x_value =
|
||||
std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
|
||||
float result = RadianToDegree(std::atan2(y_value, x_value));
|
||||
|
||||
while (result < 0.f)
|
||||
{
|
||||
result += 360.f;
|
||||
}
|
||||
|
||||
while (result >= 360.f)
|
||||
{
|
||||
result -= 360.f;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float FixedPointCoordinate::DegreeToRadian(const float degree) { return degree * (static_cast<float>(M_PI) / 180.f); }
|
||||
|
||||
float FixedPointCoordinate::RadianToDegree(const float radian) { return radian * (180.f * static_cast<float>(M_1_PI)); }
|
||||
|
||||
// This distance computation does integer arithmetic only and is a lot faster than
|
||||
// the other distance function which are numerically correct('ish).
|
||||
// It preserves some order among the elements that make it useful for certain purposes
|
||||
int FixedPointCoordinate::OrderedPerpendicularDistanceApproximation(
|
||||
const FixedPointCoordinate &input_point,
|
||||
const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target)
|
||||
{
|
||||
// initialize values
|
||||
const float x = lat2y(input_point.lat / COORDINATE_PRECISION);
|
||||
const float y = input_point.lon / COORDINATE_PRECISION;
|
||||
const float a = lat2y(segment_source.lat / COORDINATE_PRECISION);
|
||||
const float b = segment_source.lon / COORDINATE_PRECISION;
|
||||
const float c = lat2y(segment_target.lat / COORDINATE_PRECISION);
|
||||
const float d = segment_target.lon / COORDINATE_PRECISION;
|
||||
|
||||
float p, q;
|
||||
if (a == c)
|
||||
{
|
||||
p = c;
|
||||
q = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float m = (d - b) / (c - a); // slope
|
||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
||||
p = ((x + (m * y)) + (m * m * a - m * b)) / (1.f + m * m);
|
||||
q = b + m * (p - a);
|
||||
}
|
||||
|
||||
const float nY = (d * p - c * q) / (a * d - b * c);
|
||||
float ratio = (p - nY * a) / c; // These values are actually n/m+n and m/m+n , we need
|
||||
// not calculate the explicit values of m an n as we
|
||||
// are just interested in the ratio
|
||||
if (std::isnan(ratio))
|
||||
{
|
||||
ratio = (segment_target == input_point) ? 1.f : 0.f;
|
||||
}
|
||||
|
||||
// compute target quasi-location
|
||||
int dx, dy;
|
||||
if (ratio < 0.f)
|
||||
{
|
||||
dx = input_point.lon - segment_source.lon;
|
||||
dy = input_point.lat - segment_source.lat;
|
||||
}
|
||||
else if (ratio > 1.f)
|
||||
{
|
||||
dx = input_point.lon - segment_target.lon;
|
||||
dy = input_point.lat - segment_target.lat;
|
||||
}
|
||||
else
|
||||
{
|
||||
// point lies in between
|
||||
dx = input_point.lon - static_cast<int>(q * COORDINATE_PRECISION);
|
||||
dy = input_point.lat - static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
|
||||
}
|
||||
|
||||
// return an approximation in the plane
|
||||
return static_cast<int>(sqrt(dx * dx + dy * dy));
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ class DeallocatingVector
|
||||
{
|
||||
const std::size_t number_of_necessary_buckets = 1 + (new_size / bucketSizeC);
|
||||
|
||||
for (unsigned i = number_of_necessary_buckets; i < bucket_list.size(); ++i)
|
||||
for (std::size_t i = number_of_necessary_buckets; i < bucket_list.size(); ++i)
|
||||
{
|
||||
delete[] bucket_list[i];
|
||||
}
|
||||
|
||||
@@ -31,16 +31,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../DataStructures/DeallocatingVector.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/range/irange.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
|
||||
template <typename EdgeDataT> class DynamicGraph
|
||||
{
|
||||
public:
|
||||
typedef decltype(boost::irange(0u,0u)) EdgeRange;
|
||||
typedef EdgeDataT EdgeData;
|
||||
typedef unsigned NodeIterator;
|
||||
typedef unsigned EdgeIterator;
|
||||
@@ -89,7 +92,7 @@ template <typename EdgeDataT> class DynamicGraph
|
||||
position += m_nodes[node].edges;
|
||||
}
|
||||
m_nodes.back().firstEdge = position;
|
||||
m_edges.reserve(position * 1.1);
|
||||
m_edges.reserve(static_cast<std::size_t>(position * 1.1));
|
||||
m_edges.resize(position);
|
||||
edge = 0;
|
||||
for (NodeIterator node = 0; node < m_numNodes; ++node)
|
||||
@@ -115,6 +118,19 @@ template <typename EdgeDataT> class DynamicGraph
|
||||
|
||||
unsigned GetOutDegree(const NodeIterator n) const { return m_nodes[n].edges; }
|
||||
|
||||
unsigned GetDirectedOutDegree(const NodeIterator n) const
|
||||
{
|
||||
unsigned degree = 0;
|
||||
for(EdgeIterator edge = BeginEdges(n); edge < EndEdges(n); ++edge)
|
||||
{
|
||||
if (GetEdgeData(edge).forward)
|
||||
{
|
||||
++degree;
|
||||
}
|
||||
}
|
||||
return degree;
|
||||
}
|
||||
|
||||
NodeIterator GetTarget(const EdgeIterator e) const { return NodeIterator(m_edges[e].target); }
|
||||
|
||||
void SetTarget(const EdgeIterator e, const NodeIterator n) { m_edges[e].target = n; }
|
||||
@@ -133,6 +149,11 @@ template <typename EdgeDataT> class DynamicGraph
|
||||
return EdgeIterator(m_nodes[n].firstEdge + m_nodes[n].edges);
|
||||
}
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
|
||||
{
|
||||
return boost::irange(BeginEdges(node), EndEdges(node));
|
||||
}
|
||||
|
||||
// adds an edge. Invalidates edge iterators for the source node
|
||||
EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
|
||||
{
|
||||
@@ -178,7 +199,6 @@ template <typename EdgeDataT> class DynamicGraph
|
||||
void DeleteEdge(const NodeIterator source, const EdgeIterator e)
|
||||
{
|
||||
Node &node = m_nodes[source];
|
||||
#pragma omp atomic
|
||||
--m_numEdges;
|
||||
--node.edges;
|
||||
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != node.edges);
|
||||
@@ -206,7 +226,6 @@ template <typename EdgeDataT> class DynamicGraph
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp atomic
|
||||
m_numEdges -= deleted;
|
||||
m_nodes[source].edges -= deleted;
|
||||
|
||||
@@ -252,7 +271,7 @@ template <typename EdgeDataT> class DynamicGraph
|
||||
};
|
||||
|
||||
NodeIterator m_numNodes;
|
||||
EdgeIterator m_numEdges;
|
||||
std::atomic_uint m_numEdges;
|
||||
|
||||
std::vector<Node> m_nodes;
|
||||
DeallocatingVector<Edge> m_edges;
|
||||
|
||||
+26
-13
@@ -28,37 +28,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef HASH_TABLE_H
|
||||
#define HASH_TABLE_H
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
template <typename Key, typename Value> class HashTable : public std::unordered_map<Key, Value>
|
||||
template <typename Key, typename Value>
|
||||
class HashTable
|
||||
{
|
||||
private:
|
||||
typedef std::unordered_map<Key, Value> super;
|
||||
typedef std::pair<Key, Value> KeyValPair;
|
||||
std::vector<KeyValPair> table;
|
||||
|
||||
public:
|
||||
HashTable() : super() {}
|
||||
HashTable() {}
|
||||
|
||||
explicit HashTable(const unsigned size) : super(size) {}
|
||||
inline void Add(Key const &key, Value const &value)
|
||||
{
|
||||
table.emplace_back(std::move(key), std::move(value));
|
||||
}
|
||||
|
||||
inline void Add(Key const &key, Value const &value) { super::emplace(key, value); }
|
||||
inline void Clear()
|
||||
{
|
||||
table.clear();
|
||||
}
|
||||
|
||||
inline const Value Find(Key const &key) const
|
||||
{
|
||||
auto iter = super::find(key);
|
||||
if (iter == super::end())
|
||||
for (const auto &key_val_pair : table)
|
||||
{
|
||||
return Value();
|
||||
if (key_val_pair.first == key)
|
||||
{
|
||||
return key_val_pair.second;
|
||||
}
|
||||
}
|
||||
return iter->second;
|
||||
return Value();
|
||||
}
|
||||
|
||||
inline const bool Holds(Key const &key) const
|
||||
{
|
||||
if (super::find(key) == super::end())
|
||||
for (const auto &key_val_pair : table)
|
||||
{
|
||||
return false;
|
||||
if (key_val_pair.first == key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
uint64_t HilbertCode::operator()(const FixedPointCoordinate ¤t_coordinate) const
|
||||
{
|
||||
unsigned location[2];
|
||||
location[0] = current_coordinate.lat + (90 * COORDINATE_PRECISION);
|
||||
location[1] = current_coordinate.lon + (180 * COORDINATE_PRECISION);
|
||||
location[0] = current_coordinate.lat + static_cast<int>(90 * COORDINATE_PRECISION);
|
||||
location[1] = current_coordinate.lon + static_cast<int>(180 * COORDINATE_PRECISION);
|
||||
|
||||
TransposeCoordinate(location);
|
||||
return BitInterleaving(location[0], location[1]);
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ImportEdge.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
|
||||
{
|
||||
if (source == other.source)
|
||||
{
|
||||
if (target == other.target)
|
||||
{
|
||||
if (weight == other.weight)
|
||||
{
|
||||
return forward && backward && ((!other.forward) || (!other.backward));
|
||||
}
|
||||
return weight < other.weight;
|
||||
}
|
||||
return target < other.target;
|
||||
}
|
||||
return source < other.source;
|
||||
}
|
||||
|
||||
NodeBasedEdge::NodeBasedEdge(NodeID source,
|
||||
NodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
bool forward,
|
||||
bool backward,
|
||||
short type,
|
||||
bool roundabout,
|
||||
bool in_tiny_cc,
|
||||
bool access_restricted,
|
||||
bool contra_flow,
|
||||
bool is_split)
|
||||
: source(source), target(target), name_id(name_id), weight(weight), type(type),
|
||||
forward(forward), backward(backward), roundabout(roundabout), in_tiny_cc(in_tiny_cc),
|
||||
access_restricted(access_restricted), contra_flow(contra_flow), is_split(is_split)
|
||||
{
|
||||
BOOST_ASSERT_MSG(type > 0, "negative edge type");
|
||||
}
|
||||
|
||||
bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
|
||||
{
|
||||
if (source == other.source)
|
||||
{
|
||||
if (target == other.target)
|
||||
{
|
||||
if (weight == other.weight)
|
||||
{
|
||||
return forward && backward && ((!other.forward) || (!other.backward));
|
||||
}
|
||||
return weight < other.weight;
|
||||
}
|
||||
return target < other.target;
|
||||
}
|
||||
return source < other.source;
|
||||
}
|
||||
|
||||
template <class EdgeT>
|
||||
EdgeBasedEdge::EdgeBasedEdge(const EdgeT &other)
|
||||
: source(other.source), target(other.target), edge_id(other.data.via),
|
||||
weight(other.data.distance), forward(other.data.forward), backward(other.data.backward)
|
||||
{
|
||||
}
|
||||
|
||||
/** Default constructor. target and weight are set to 0.*/
|
||||
EdgeBasedEdge::EdgeBasedEdge()
|
||||
: source(0), target(0), edge_id(0), weight(0), forward(false), backward(false)
|
||||
{
|
||||
}
|
||||
|
||||
EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
|
||||
const NodeID target,
|
||||
const NodeID edge_id,
|
||||
const EdgeWeight weight,
|
||||
const bool forward,
|
||||
const bool backward)
|
||||
: source(source), target(target), edge_id(edge_id), weight(weight), forward(forward),
|
||||
backward(backward)
|
||||
{
|
||||
}
|
||||
+40
-126
@@ -28,149 +28,63 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef IMPORT_EDGE_H
|
||||
#define IMPORT_EDGE_H
|
||||
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
class NodeBasedEdge
|
||||
struct NodeBasedEdge
|
||||
{
|
||||
bool operator<(const NodeBasedEdge &e) const;
|
||||
|
||||
public:
|
||||
bool operator<(const NodeBasedEdge &e) const
|
||||
{
|
||||
if (source() == e.source())
|
||||
{
|
||||
if (target() == e.target())
|
||||
{
|
||||
if (weight() == e.weight())
|
||||
{
|
||||
return (isForward() && isBackward() && ((!e.isForward()) || (!e.isBackward())));
|
||||
}
|
||||
return (weight() < e.weight());
|
||||
}
|
||||
return (target() < e.target());
|
||||
}
|
||||
return (source() < e.source());
|
||||
}
|
||||
explicit NodeBasedEdge(NodeID source,
|
||||
NodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
bool forward,
|
||||
bool backward,
|
||||
short type,
|
||||
bool roundabout,
|
||||
bool in_tiny_cc,
|
||||
bool access_restricted,
|
||||
bool contra_flow,
|
||||
bool is_split);
|
||||
|
||||
explicit NodeBasedEdge(NodeID s,
|
||||
NodeID t,
|
||||
NodeID n,
|
||||
EdgeWeight w,
|
||||
bool f,
|
||||
bool b,
|
||||
short ty,
|
||||
bool ra,
|
||||
bool ig,
|
||||
bool ar,
|
||||
bool cf,
|
||||
bool is_split)
|
||||
: _source(s), _target(t), _name(n), _weight(w), _type(ty), forward(f), backward(b),
|
||||
_roundabout(ra), _ignoreInGrid(ig), _accessRestricted(ar), _contraFlow(cf),
|
||||
is_split(is_split)
|
||||
{
|
||||
if (ty < 0)
|
||||
{
|
||||
throw OSRMException("negative edge type");
|
||||
}
|
||||
}
|
||||
|
||||
NodeID target() const { return _target; }
|
||||
NodeID source() const { return _source; }
|
||||
NodeID name() const { return _name; }
|
||||
EdgeWeight weight() const { return _weight; }
|
||||
short type() const
|
||||
{
|
||||
BOOST_ASSERT_MSG(_type >= 0, "type of ImportEdge invalid");
|
||||
return _type;
|
||||
}
|
||||
bool isBackward() const { return backward; }
|
||||
bool isForward() const { return forward; }
|
||||
bool isLocatable() const { return _type != 14; }
|
||||
bool isRoundabout() const { return _roundabout; }
|
||||
bool ignoreInGrid() const { return _ignoreInGrid; }
|
||||
bool isAccessRestricted() const { return _accessRestricted; }
|
||||
bool isContraFlow() const { return _contraFlow; }
|
||||
bool IsSplit() const { return is_split; }
|
||||
|
||||
// TODO: names need to be fixed.
|
||||
NodeID _source;
|
||||
NodeID _target;
|
||||
NodeID _name;
|
||||
EdgeWeight _weight;
|
||||
short _type;
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
NodeID name_id;
|
||||
EdgeWeight weight;
|
||||
short type;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool _roundabout : 1;
|
||||
bool _ignoreInGrid : 1;
|
||||
bool _accessRestricted : 1;
|
||||
bool _contraFlow : 1;
|
||||
bool roundabout : 1;
|
||||
bool in_tiny_cc : 1;
|
||||
bool access_restricted : 1;
|
||||
bool contra_flow : 1;
|
||||
bool is_split : 1;
|
||||
|
||||
private:
|
||||
NodeBasedEdge() {}
|
||||
NodeBasedEdge() = delete;
|
||||
};
|
||||
|
||||
class EdgeBasedEdge
|
||||
struct EdgeBasedEdge
|
||||
{
|
||||
|
||||
public:
|
||||
bool operator<(const EdgeBasedEdge &e) const
|
||||
{
|
||||
if (source() == e.source())
|
||||
{
|
||||
if (target() == e.target())
|
||||
{
|
||||
if (weight() == e.weight())
|
||||
{
|
||||
return (isForward() && isBackward() && ((!e.isForward()) || (!e.isBackward())));
|
||||
}
|
||||
return (weight() < e.weight());
|
||||
}
|
||||
return (target() < e.target());
|
||||
}
|
||||
return (source() < e.source());
|
||||
}
|
||||
bool operator<(const EdgeBasedEdge &e) const;
|
||||
|
||||
template <class EdgeT>
|
||||
explicit EdgeBasedEdge(const EdgeT &myEdge)
|
||||
: m_source(myEdge.source), m_target(myEdge.target), m_edgeID(myEdge.data.via),
|
||||
m_weight(myEdge.data.distance), m_forward(myEdge.data.forward),
|
||||
m_backward(myEdge.data.backward)
|
||||
{
|
||||
}
|
||||
template <class EdgeT> explicit EdgeBasedEdge(const EdgeT &myEdge);
|
||||
|
||||
/** Default constructor. target and weight are set to 0.*/
|
||||
EdgeBasedEdge()
|
||||
: m_source(0), m_target(0), m_edgeID(0), m_weight(0), m_forward(false), m_backward(false)
|
||||
{
|
||||
}
|
||||
EdgeBasedEdge();
|
||||
|
||||
explicit EdgeBasedEdge(const NodeID s,
|
||||
const NodeID t,
|
||||
const NodeID v,
|
||||
const EdgeWeight w,
|
||||
const bool f,
|
||||
const bool b)
|
||||
: m_source(s), m_target(t), m_edgeID(v), m_weight(w), m_forward(f), m_backward(b)
|
||||
{
|
||||
}
|
||||
|
||||
NodeID target() const { return m_target; }
|
||||
NodeID source() const { return m_source; }
|
||||
EdgeWeight weight() const { return m_weight; }
|
||||
NodeID id() const { return m_edgeID; }
|
||||
bool isBackward() const { return m_backward; }
|
||||
bool isForward() const { return m_forward; }
|
||||
|
||||
private:
|
||||
NodeID m_source;
|
||||
NodeID m_target;
|
||||
NodeID m_edgeID;
|
||||
EdgeWeight m_weight : 30;
|
||||
bool m_forward : 1;
|
||||
bool m_backward : 1;
|
||||
explicit EdgeBasedEdge(const NodeID source,
|
||||
const NodeID target,
|
||||
const NodeID edge_id,
|
||||
const EdgeWeight weight,
|
||||
const bool forward,
|
||||
const bool backward);
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
NodeID edge_id;
|
||||
EdgeWeight weight : 30;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
};
|
||||
|
||||
typedef NodeBasedEdge ImportEdge;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "ImportNode.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
ExternalMemoryNode::ExternalMemoryNode(
|
||||
int lat, int lon, unsigned int node_id, bool bollard, bool traffic_light)
|
||||
: NodeInfo(lat, lon, node_id), bollard(bollard), trafficLight(traffic_light)
|
||||
{
|
||||
}
|
||||
|
||||
ExternalMemoryNode::ExternalMemoryNode() : bollard(false), trafficLight(false)
|
||||
{
|
||||
}
|
||||
|
||||
ExternalMemoryNode ExternalMemoryNode::min_value()
|
||||
{
|
||||
return ExternalMemoryNode(0, 0, 0, false, false);
|
||||
}
|
||||
|
||||
ExternalMemoryNode ExternalMemoryNode::max_value()
|
||||
{
|
||||
return ExternalMemoryNode(std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<unsigned>::max(),
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
void ImportNode::Clear()
|
||||
{
|
||||
keyVals.Clear();
|
||||
lat = 0;
|
||||
lon = 0;
|
||||
node_id = 0;
|
||||
bollard = false;
|
||||
trafficLight = false;
|
||||
}
|
||||
@@ -31,30 +31,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "QueryNode.h"
|
||||
#include "../DataStructures/HashTable.h"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
struct ExternalMemoryNode : NodeInfo
|
||||
{
|
||||
ExternalMemoryNode(int lat, int lon, unsigned int id, bool bollard, bool traffic_light)
|
||||
: NodeInfo(lat, lon, id), bollard(bollard), trafficLight(traffic_light)
|
||||
{
|
||||
}
|
||||
ExternalMemoryNode(int lat, int lon, unsigned int id, bool bollard, bool traffic_light);
|
||||
|
||||
ExternalMemoryNode() : bollard(false), trafficLight(false) {}
|
||||
ExternalMemoryNode();
|
||||
|
||||
static ExternalMemoryNode min_value() { return ExternalMemoryNode(0, 0, 0, false, false); }
|
||||
static ExternalMemoryNode min_value();
|
||||
|
||||
static ExternalMemoryNode max_value()
|
||||
{
|
||||
return ExternalMemoryNode(std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<unsigned>::max(),
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
NodeID key() const { return id; }
|
||||
static ExternalMemoryNode max_value();
|
||||
|
||||
bool bollard;
|
||||
bool trafficLight;
|
||||
@@ -64,15 +51,7 @@ struct ImportNode : public ExternalMemoryNode
|
||||
{
|
||||
HashTable<std::string, std::string> keyVals;
|
||||
|
||||
inline void Clear()
|
||||
{
|
||||
keyVals.clear();
|
||||
lat = 0;
|
||||
lon = 0;
|
||||
id = 0;
|
||||
bollard = false;
|
||||
trafficLight = false;
|
||||
}
|
||||
inline void Clear();
|
||||
};
|
||||
|
||||
#endif /* IMPORTNODE_H_ */
|
||||
|
||||
@@ -44,8 +44,8 @@ struct BZ2Context
|
||||
|
||||
int readFromBz2Stream(void *pointer, char *buffer, int len)
|
||||
{
|
||||
void *unusedTmpVoid = NULL;
|
||||
char *unusedTmp = NULL;
|
||||
void *unusedTmpVoid = nullptr;
|
||||
char *unusedTmp = nullptr;
|
||||
BZ2Context *context = (BZ2Context *)pointer;
|
||||
int read = 0;
|
||||
while (0 == read &&
|
||||
@@ -76,7 +76,7 @@ int readFromBz2Stream(void *pointer, char *buffer, int len)
|
||||
{
|
||||
context->bz2 = BZ2_bzReadOpen(
|
||||
&context->error, context->file, 0, 0, context->unused, context->nUnused);
|
||||
BOOST_ASSERT_MSG(NULL != context->bz2, "Could not open file");
|
||||
BOOST_ASSERT_MSG(nullptr != context->bz2, "Could not open file");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -107,12 +107,12 @@ xmlTextReaderPtr inputReaderFactory(const char *name)
|
||||
int error;
|
||||
context->bz2 =
|
||||
BZ2_bzReadOpen(&error, context->file, 0, 0, context->unused, context->nUnused);
|
||||
if (context->bz2 == NULL || context->file == NULL)
|
||||
if (context->bz2 == nullptr || context->file == nullptr)
|
||||
{
|
||||
delete context;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return xmlReaderForIO(readFromBz2Stream, closeBz2Stream, (void *)context, NULL, NULL, 0);
|
||||
return xmlReaderForIO(readFromBz2Stream, closeBz2Stream, (void *)context, nullptr, nullptr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// based on https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
|
||||
|
||||
#ifndef JSON_CONTAINER_H
|
||||
#define JSON_CONTAINER_H
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace JSON
|
||||
{
|
||||
|
||||
struct String;
|
||||
struct Number;
|
||||
struct Object;
|
||||
struct Array;
|
||||
struct True;
|
||||
struct False;
|
||||
struct Null;
|
||||
|
||||
typedef boost::variant<boost::recursive_wrapper<String>,
|
||||
boost::recursive_wrapper<Number>,
|
||||
boost::recursive_wrapper<Object>,
|
||||
boost::recursive_wrapper<Array>,
|
||||
boost::recursive_wrapper<True>,
|
||||
boost::recursive_wrapper<False>,
|
||||
boost::recursive_wrapper<Null> > Value;
|
||||
|
||||
struct String
|
||||
{
|
||||
String() {}
|
||||
String(const char *value) : value(value) {}
|
||||
String(const std::string &value) : value(value) {}
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct Number
|
||||
{
|
||||
Number() {}
|
||||
Number(double value) : value(value) {}
|
||||
double value;
|
||||
};
|
||||
|
||||
struct Object
|
||||
{
|
||||
std::unordered_map<std::string, Value> values;
|
||||
};
|
||||
|
||||
struct Array
|
||||
{
|
||||
std::vector<Value> values;
|
||||
};
|
||||
|
||||
struct True
|
||||
{
|
||||
};
|
||||
|
||||
struct False
|
||||
{
|
||||
};
|
||||
|
||||
struct Null
|
||||
{
|
||||
};
|
||||
|
||||
struct Renderer : boost::static_visitor<>
|
||||
{
|
||||
Renderer(std::ostream &_out) : out(_out) {}
|
||||
|
||||
void operator()(const String &string) const { out << "\"" << string.value << "\""; }
|
||||
|
||||
void operator()(const Number &number) const
|
||||
{
|
||||
out.precision(10);
|
||||
out << number.value;
|
||||
}
|
||||
|
||||
void operator()(const Object &object) const
|
||||
{
|
||||
out << "{";
|
||||
auto iterator = object.values.begin();
|
||||
while (iterator != object.values.end())
|
||||
{
|
||||
out << "\"" << (*iterator).first << "\":";
|
||||
boost::apply_visitor(Renderer(out), (*iterator).second);
|
||||
if (++iterator != object.values.end())
|
||||
{
|
||||
out << ",";
|
||||
}
|
||||
}
|
||||
out << "}";
|
||||
}
|
||||
|
||||
void operator()(const Array &array) const
|
||||
{
|
||||
out << "[";
|
||||
std::vector<Value>::const_iterator iterator;
|
||||
iterator = array.values.begin();
|
||||
while (iterator != array.values.end())
|
||||
{
|
||||
boost::apply_visitor(Renderer(out), *iterator);
|
||||
if (++iterator != array.values.end())
|
||||
{
|
||||
out << ",";
|
||||
}
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
|
||||
void operator()(const True &) const { out << "true"; }
|
||||
|
||||
void operator()(const False &) const { out << "false"; }
|
||||
|
||||
void operator()(const Null &) const { out << "null"; }
|
||||
|
||||
private:
|
||||
std::ostream &out;
|
||||
};
|
||||
|
||||
struct ArrayRenderer : boost::static_visitor<>
|
||||
{
|
||||
ArrayRenderer(std::vector<char> &_out) : out(_out) {}
|
||||
|
||||
void operator()(const String &string) const {
|
||||
out.push_back('\"');
|
||||
out.insert(out.end(), string.value.begin(), string.value.end());
|
||||
out.push_back('\"');
|
||||
}
|
||||
|
||||
void operator()(const Number &number) const
|
||||
{
|
||||
const std::string number_string = FixedDoubleToString(number.value);
|
||||
out.insert(out.end(), number_string.begin(), number_string.end());
|
||||
}
|
||||
|
||||
void operator()(const Object &object) const
|
||||
{
|
||||
out.push_back('{');
|
||||
auto iterator = object.values.begin();
|
||||
while (iterator != object.values.end())
|
||||
{
|
||||
out.push_back('\"');
|
||||
out.insert(out.end(), (*iterator).first.begin(), (*iterator).first.end());
|
||||
out.push_back('\"');
|
||||
out.push_back(':');
|
||||
|
||||
boost::apply_visitor(ArrayRenderer(out), (*iterator).second);
|
||||
if (++iterator != object.values.end())
|
||||
{
|
||||
out.push_back(',');
|
||||
}
|
||||
}
|
||||
out.push_back('}');
|
||||
}
|
||||
|
||||
void operator()(const Array &array) const
|
||||
{
|
||||
out.push_back('[');
|
||||
std::vector<Value>::const_iterator iterator;
|
||||
iterator = array.values.begin();
|
||||
while (iterator != array.values.end())
|
||||
{
|
||||
boost::apply_visitor(ArrayRenderer(out), *iterator);
|
||||
if (++iterator != array.values.end())
|
||||
{
|
||||
out.push_back(',');
|
||||
}
|
||||
}
|
||||
out.push_back(']');
|
||||
}
|
||||
|
||||
void operator()(const True &) const {
|
||||
const std::string temp("true");
|
||||
out.insert(out.end(), temp.begin(), temp.end());
|
||||
}
|
||||
|
||||
void operator()(const False &) const {
|
||||
const std::string temp("false");
|
||||
out.insert(out.end(), temp.begin(), temp.end());
|
||||
}
|
||||
|
||||
void operator()(const Null &) const {
|
||||
const std::string temp("null");
|
||||
out.insert(out.end(), temp.begin(), temp.end());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<char> &out;
|
||||
};
|
||||
|
||||
inline void render(std::ostream &out, const Object &object)
|
||||
{
|
||||
Value value = object;
|
||||
boost::apply_visitor(Renderer(out), value);
|
||||
}
|
||||
|
||||
inline void render(std::vector<char> &out, const Object &object)
|
||||
{
|
||||
Value value = object;
|
||||
boost::apply_visitor(ArrayRenderer(out), value);
|
||||
}
|
||||
|
||||
} // namespace JSON
|
||||
|
||||
#endif // JSON_CONTAINER_H
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#include "DynamicGraph.h"
|
||||
#include "ImportEdge.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -49,27 +52,26 @@ typedef DynamicGraph<NodeBasedEdgeData> NodeBasedDynamicGraph;
|
||||
inline std::shared_ptr<NodeBasedDynamicGraph>
|
||||
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
|
||||
{
|
||||
std::sort(input_edge_list.begin(), input_edge_list.end());
|
||||
static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
|
||||
// tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
|
||||
|
||||
// TODO: remove duplicate edges
|
||||
DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
|
||||
NodeBasedDynamicGraph::InputEdge edge;
|
||||
for (const ImportEdge &import_edge : input_edge_list)
|
||||
{
|
||||
// TODO: give ImportEdge a proper c'tor to use emplace_back's below
|
||||
if (!import_edge.isForward())
|
||||
if (import_edge.forward)
|
||||
{
|
||||
edge.source = import_edge.target();
|
||||
edge.target = import_edge.source();
|
||||
edge.data.backward = import_edge.isForward();
|
||||
edge.data.forward = import_edge.isBackward();
|
||||
edge.source = import_edge.source;
|
||||
edge.target = import_edge.target;
|
||||
edge.data.forward = import_edge.forward;
|
||||
edge.data.backward = import_edge.backward;
|
||||
}
|
||||
else
|
||||
{
|
||||
edge.source = import_edge.source();
|
||||
edge.target = import_edge.target();
|
||||
edge.data.forward = import_edge.isForward();
|
||||
edge.data.backward = import_edge.isBackward();
|
||||
edge.source = import_edge.target;
|
||||
edge.target = import_edge.source;
|
||||
edge.data.backward = import_edge.forward;
|
||||
edge.data.forward = import_edge.backward;
|
||||
}
|
||||
|
||||
if (edge.source == edge.target)
|
||||
@@ -77,18 +79,18 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
|
||||
continue;
|
||||
}
|
||||
|
||||
edge.data.distance = (std::max)((int)import_edge.weight(), 1);
|
||||
edge.data.distance = (std::max)((int)import_edge.weight, 1);
|
||||
BOOST_ASSERT(edge.data.distance > 0);
|
||||
edge.data.shortcut = false;
|
||||
edge.data.roundabout = import_edge.isRoundabout();
|
||||
edge.data.ignore_in_grid = import_edge.ignoreInGrid();
|
||||
edge.data.nameID = import_edge.name();
|
||||
edge.data.type = import_edge.type();
|
||||
edge.data.isAccessRestricted = import_edge.isAccessRestricted();
|
||||
edge.data.contraFlow = import_edge.isContraFlow();
|
||||
edge.data.roundabout = import_edge.roundabout;
|
||||
edge.data.ignore_in_grid = import_edge.in_tiny_cc;
|
||||
edge.data.nameID = import_edge.name_id;
|
||||
edge.data.type = import_edge.type;
|
||||
edge.data.isAccessRestricted = import_edge.access_restricted;
|
||||
edge.data.contraFlow = import_edge.contra_flow;
|
||||
edges_list.push_back(edge);
|
||||
|
||||
if (!import_edge.IsSplit())
|
||||
if (!import_edge.is_split)
|
||||
{
|
||||
using std::swap; // enable ADL
|
||||
swap(edge.source, edge.target);
|
||||
@@ -97,12 +99,67 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicate edges
|
||||
std::sort(edges_list.begin(), edges_list.end());
|
||||
NodeID edge_count = 0;
|
||||
for (NodeID i = 0; i < edges_list.size(); )
|
||||
{
|
||||
const NodeID source = edges_list[i].source;
|
||||
const NodeID target = edges_list[i].target;
|
||||
// remove eigenloops
|
||||
if (source == target)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
NodeBasedDynamicGraph::InputEdge forward_edge;
|
||||
NodeBasedDynamicGraph::InputEdge reverse_edge;
|
||||
forward_edge = reverse_edge = edges_list[i];
|
||||
forward_edge.data.forward = reverse_edge.data.backward = true;
|
||||
forward_edge.data.backward = reverse_edge.data.forward = false;
|
||||
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
|
||||
forward_edge.data.distance = reverse_edge.data.distance =
|
||||
std::numeric_limits<int>::max();
|
||||
// remove parallel edges
|
||||
while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
|
||||
{
|
||||
if (edges_list[i].data.forward)
|
||||
{
|
||||
forward_edge.data.distance =
|
||||
std::min(edges_list[i].data.distance, forward_edge.data.distance);
|
||||
}
|
||||
if (edges_list[i].data.backward)
|
||||
{
|
||||
reverse_edge.data.distance =
|
||||
std::min(edges_list[i].data.distance, reverse_edge.data.distance);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
// merge edges (s,t) and (t,s) into bidirectional edge
|
||||
if (forward_edge.data.distance == reverse_edge.data.distance)
|
||||
{
|
||||
if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
|
||||
{
|
||||
forward_edge.data.backward = true;
|
||||
edges_list[edge_count++] = forward_edge;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // insert seperate edges
|
||||
if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
|
||||
{
|
||||
edges_list[edge_count++] = forward_edge;
|
||||
}
|
||||
if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
|
||||
{
|
||||
edges_list[edge_count++] = reverse_edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
edges_list.resize(edge_count);
|
||||
SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size();
|
||||
|
||||
auto graph = std::make_shared<NodeBasedDynamicGraph>(number_of_nodes, edges_list);
|
||||
|
||||
edges_list.clear();
|
||||
BOOST_ASSERT(0 == edges_list.size());
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef PERCENT_H
|
||||
#define PERCENT_H
|
||||
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include <iostream>
|
||||
#include <atomic>
|
||||
|
||||
class Percent
|
||||
{
|
||||
@@ -61,20 +61,18 @@ class Percent
|
||||
|
||||
void printIncrement()
|
||||
{
|
||||
#pragma omp atomic
|
||||
++m_current_value;
|
||||
printStatus(m_current_value);
|
||||
}
|
||||
|
||||
void printAddition(const unsigned addition)
|
||||
{
|
||||
#pragma omp atomic
|
||||
m_current_value += addition;
|
||||
printStatus(m_current_value);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned m_current_value;
|
||||
std::atomic_uint m_current_value;
|
||||
unsigned m_max_value;
|
||||
unsigned m_percent_interval;
|
||||
unsigned m_next_threshold;
|
||||
|
||||
@@ -32,8 +32,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct PhantomNode
|
||||
{
|
||||
PhantomNode(NodeID forward_node_id, NodeID reverse_node_id, unsigned name_id,
|
||||
int forward_weight, int reverse_weight, int forward_offset, int reverse_offset,
|
||||
unsigned packed_geometry_id, FixedPointCoordinate &location,
|
||||
unsigned short fwd_segment_position) :
|
||||
forward_node_id(forward_node_id),
|
||||
reverse_node_id(reverse_node_id),
|
||||
name_id(name_id),
|
||||
forward_weight(forward_weight),
|
||||
reverse_weight(reverse_weight),
|
||||
forward_offset(forward_offset),
|
||||
reverse_offset(reverse_offset),
|
||||
packed_geometry_id(packed_geometry_id),
|
||||
location(location),
|
||||
fwd_segment_position(fwd_segment_position)
|
||||
{ }
|
||||
|
||||
PhantomNode() :
|
||||
forward_node_id(SPECIAL_NODEID),
|
||||
reverse_node_id(SPECIAL_NODEID),
|
||||
@@ -77,17 +95,6 @@ struct PhantomNode
|
||||
return result;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
forward_node_id = SPECIAL_NODEID;
|
||||
name_id = SPECIAL_NODEID;
|
||||
forward_weight = INVALID_EDGE_WEIGHT;
|
||||
reverse_weight = INVALID_EDGE_WEIGHT;
|
||||
forward_offset = 0;
|
||||
reverse_offset = 0;
|
||||
location.Reset();
|
||||
}
|
||||
|
||||
bool isBidirected() const
|
||||
{
|
||||
return (forward_node_id != SPECIAL_NODEID) &&
|
||||
@@ -115,38 +122,30 @@ struct PhantomNode
|
||||
);
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return location.isValid() &&
|
||||
(name_id != std::numeric_limits<unsigned>::max());
|
||||
}
|
||||
|
||||
bool operator==(const PhantomNode & other) const
|
||||
{
|
||||
return location == other.location;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<std::vector<PhantomNode>> PhantomNodeArray;
|
||||
|
||||
struct PhantomNodeLists
|
||||
{
|
||||
std::vector<PhantomNode> source_phantom_list;
|
||||
std::vector<PhantomNode> target_phantom_list;
|
||||
};
|
||||
|
||||
struct PhantomNodes
|
||||
{
|
||||
PhantomNode source_phantom;
|
||||
PhantomNode target_phantom;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
source_phantom.Reset();
|
||||
target_phantom.Reset();
|
||||
}
|
||||
|
||||
bool PhantomsAreOnSameNodeBasedEdge() const
|
||||
{
|
||||
return (source_phantom.forward_node_id == target_phantom.forward_node_id);
|
||||
}
|
||||
|
||||
bool AtLeastOnePhantomNodeIsInvalid() const
|
||||
{
|
||||
return ((source_phantom.forward_node_id == SPECIAL_NODEID) && (source_phantom.reverse_node_id == SPECIAL_NODEID)) ||
|
||||
((target_phantom.forward_node_id == SPECIAL_NODEID) && (target_phantom.reverse_node_id == SPECIAL_NODEID));
|
||||
}
|
||||
|
||||
bool PhantomNodesHaveEqualLocation() const
|
||||
{
|
||||
return source_phantom == target_phantom;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn)
|
||||
|
||||
@@ -41,28 +41,28 @@ struct NodeInfo
|
||||
typedef NodeID key_type; // type of NodeID
|
||||
typedef int value_type; // type of lat,lons
|
||||
|
||||
NodeInfo(int lat, int lon, NodeID id) : lat(lat), lon(lon), id(id) {}
|
||||
explicit NodeInfo(int lat, int lon, NodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
|
||||
NodeInfo()
|
||||
: lat(std::numeric_limits<int>::max()), lon(std::numeric_limits<int>::max()),
|
||||
id(std::numeric_limits<unsigned>::max())
|
||||
node_id(std::numeric_limits<unsigned>::max())
|
||||
{
|
||||
}
|
||||
|
||||
int lat;
|
||||
int lon;
|
||||
NodeID id;
|
||||
NodeID node_id;
|
||||
|
||||
static NodeInfo min_value()
|
||||
{
|
||||
return NodeInfo(-90 * COORDINATE_PRECISION,
|
||||
-180 * COORDINATE_PRECISION,
|
||||
return NodeInfo(static_cast<int>(-90 * COORDINATE_PRECISION),
|
||||
static_cast<int>(-180 * COORDINATE_PRECISION),
|
||||
std::numeric_limits<NodeID>::min());
|
||||
}
|
||||
|
||||
static NodeInfo max_value()
|
||||
{
|
||||
return NodeInfo(90 * COORDINATE_PRECISION,
|
||||
180 * COORDINATE_PRECISION,
|
||||
return NodeInfo(static_cast<int>(90 * COORDINATE_PRECISION),
|
||||
static_cast<int>(180 * COORDINATE_PRECISION),
|
||||
std::numeric_limits<NodeID>::max());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
#ifndef __RANGE_TABLE_H__
|
||||
#define __RANGE_TABLE_H__
|
||||
|
||||
#include "SharedMemoryFactory.h"
|
||||
#include "SharedMemoryVectorWrapper.h"
|
||||
|
||||
#include <boost/range/irange.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
/*
|
||||
* These pre-declarations are needed because parsing C++ is hard
|
||||
* and otherwise the compiler gets confused.
|
||||
*/
|
||||
|
||||
template<unsigned BLOCK_SIZE=16, bool USE_SHARED_MEMORY = false> class RangeTable;
|
||||
|
||||
template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
|
||||
std::ostream& operator<<(std::ostream &out, const RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table);
|
||||
|
||||
template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
|
||||
std::istream& operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table);
|
||||
|
||||
/**
|
||||
* Stores adjacent ranges in a compressed format.
|
||||
*
|
||||
* Maximum supported length of a range is 255.
|
||||
*
|
||||
* Note: BLOCK_SIZE is the number of differential encodoed values.
|
||||
* But each block consists of an absolute value and BLOCK_SIZE differential values.
|
||||
* So the effective block size is sizeof(unsigned) + BLOCK_SIZE.
|
||||
*/
|
||||
template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
|
||||
class RangeTable
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::array<unsigned char, BLOCK_SIZE> BlockT;
|
||||
typedef typename ShM<BlockT, USE_SHARED_MEMORY>::vector BlockContainerT;
|
||||
typedef typename ShM<unsigned, USE_SHARED_MEMORY>::vector OffsetContainerT;
|
||||
typedef decltype(boost::irange(0u,0u)) RangeT;
|
||||
|
||||
friend std::ostream& operator<< <>(std::ostream &out, const RangeTable &table);
|
||||
friend std::istream& operator>> <>(std::istream &in, RangeTable &table);
|
||||
|
||||
RangeTable() : sum_lengths(0) {}
|
||||
|
||||
// for loading from shared memory
|
||||
explicit RangeTable(OffsetContainerT& external_offsets, BlockContainerT& external_blocks, const unsigned sum_lengths)
|
||||
: sum_lengths(sum_lengths)
|
||||
{
|
||||
block_offsets.swap(external_offsets);
|
||||
diff_blocks.swap(external_blocks);
|
||||
}
|
||||
|
||||
// construct table from length vector
|
||||
explicit RangeTable(const std::vector<unsigned>& lengths)
|
||||
{
|
||||
const unsigned number_of_blocks = [&lengths]() {
|
||||
unsigned num = (lengths.size() + 1) / (BLOCK_SIZE + 1);
|
||||
if ((lengths.size() + 1) % (BLOCK_SIZE + 1) != 0)
|
||||
{
|
||||
num += 1;
|
||||
}
|
||||
return num;
|
||||
}();
|
||||
|
||||
block_offsets.reserve(number_of_blocks);
|
||||
diff_blocks.reserve(number_of_blocks);
|
||||
|
||||
unsigned last_length = 0;
|
||||
unsigned lengths_prefix_sum = 0;
|
||||
unsigned block_idx = 0;
|
||||
unsigned block_counter = 0;
|
||||
BlockT block;
|
||||
unsigned block_sum = 0;
|
||||
for (const unsigned l : lengths)
|
||||
{
|
||||
// first entry of a block: encode absolute offset
|
||||
if (block_idx == 0)
|
||||
{
|
||||
block_offsets.push_back(lengths_prefix_sum);
|
||||
block_sum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
block[block_idx - 1] = last_length;
|
||||
block_sum += last_length;
|
||||
}
|
||||
|
||||
BOOST_ASSERT((block_idx == 0 && block_offsets[block_counter] == lengths_prefix_sum)
|
||||
|| lengths_prefix_sum == (block_offsets[block_counter]+block_sum));
|
||||
|
||||
// block is full
|
||||
if (BLOCK_SIZE == block_idx)
|
||||
{
|
||||
diff_blocks.push_back(block);
|
||||
block_counter++;
|
||||
}
|
||||
|
||||
// we can only store strings with length 255
|
||||
BOOST_ASSERT(l <= 255);
|
||||
|
||||
lengths_prefix_sum += l;
|
||||
last_length = l;
|
||||
|
||||
block_idx = (block_idx + 1) % (BLOCK_SIZE + 1);
|
||||
}
|
||||
|
||||
// Last block can't be finished because we didn't add the sentinel
|
||||
BOOST_ASSERT (block_counter == (number_of_blocks - 1));
|
||||
|
||||
// one block missing: starts with guard value
|
||||
if (0 == block_idx)
|
||||
{
|
||||
// the last value is used as sentinel
|
||||
block_offsets.push_back(lengths_prefix_sum);
|
||||
block_idx = (block_idx + 1) % BLOCK_SIZE;
|
||||
}
|
||||
|
||||
while (0 != block_idx)
|
||||
{
|
||||
block[block_idx - 1] = last_length;
|
||||
last_length = 0;
|
||||
block_idx = (block_idx + 1) % (BLOCK_SIZE + 1);
|
||||
}
|
||||
diff_blocks.push_back(block);
|
||||
|
||||
BOOST_ASSERT(diff_blocks.size() == number_of_blocks && block_offsets.size() == number_of_blocks);
|
||||
|
||||
sum_lengths = lengths_prefix_sum;
|
||||
}
|
||||
|
||||
inline RangeT GetRange(const unsigned id) const
|
||||
{
|
||||
BOOST_ASSERT(id < block_offsets.size() + diff_blocks.size() * BLOCK_SIZE);
|
||||
// internal_idx 0 is implicitly stored in block_offsets[block_idx]
|
||||
const unsigned internal_idx = id % (BLOCK_SIZE + 1);
|
||||
const unsigned block_idx = id / (BLOCK_SIZE + 1);
|
||||
|
||||
BOOST_ASSERT(block_idx < diff_blocks.size());
|
||||
|
||||
unsigned begin_idx = 0;
|
||||
unsigned end_idx = 0;
|
||||
begin_idx = block_offsets[block_idx];
|
||||
const BlockT& block = diff_blocks[block_idx];
|
||||
if (internal_idx > 0)
|
||||
{
|
||||
begin_idx += PrefixSumAtIndex(internal_idx - 1, block);
|
||||
}
|
||||
|
||||
// next index inside current block
|
||||
if (internal_idx < BLOCK_SIZE)
|
||||
{
|
||||
// note internal_idx - 1 is the *current* index for uint8_blocks
|
||||
end_idx = begin_idx + block[internal_idx];
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(block_idx < block_offsets.size() - 1);
|
||||
end_idx = block_offsets[block_idx + 1];
|
||||
}
|
||||
|
||||
BOOST_ASSERT(begin_idx < sum_lengths && end_idx <= sum_lengths);
|
||||
BOOST_ASSERT(begin_idx <= end_idx);
|
||||
|
||||
return boost::irange(begin_idx, end_idx);
|
||||
}
|
||||
private:
|
||||
|
||||
inline unsigned PrefixSumAtIndex(int index, const BlockT& block) const;
|
||||
|
||||
// contains offset for each differential block
|
||||
OffsetContainerT block_offsets;
|
||||
// blocks of differential encoded offsets, should be aligned
|
||||
BlockContainerT diff_blocks;
|
||||
unsigned sum_lengths;
|
||||
};
|
||||
|
||||
template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
|
||||
unsigned RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY>::PrefixSumAtIndex(int index, const BlockT& block) const
|
||||
{
|
||||
// this loop looks inefficent, but a modern compiler
|
||||
// will emit nice SIMD here, at least for sensible block sizes. (I checked.)
|
||||
unsigned sum = 0;
|
||||
for (int i = 0; i <= index; ++i)
|
||||
{
|
||||
sum += block[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
|
||||
std::ostream& operator<<(std::ostream &out, const RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table)
|
||||
{
|
||||
// write number of block
|
||||
const unsigned number_of_blocks = table.diff_blocks.size();
|
||||
out.write((char *) &number_of_blocks, sizeof(unsigned));
|
||||
// write total length
|
||||
out.write((char *) &table.sum_lengths, sizeof(unsigned));
|
||||
// write block offsets
|
||||
out.write((char *) table.block_offsets.data(), sizeof(unsigned) * table.block_offsets.size());
|
||||
// write blocks
|
||||
out.write((char *) table.diff_blocks.data(), BLOCK_SIZE * table.diff_blocks.size());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
|
||||
std::istream& operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table)
|
||||
{
|
||||
// read number of block
|
||||
unsigned number_of_blocks;
|
||||
in.read((char *) &number_of_blocks, sizeof(unsigned));
|
||||
// read total length
|
||||
in.read((char *) &table.sum_lengths, sizeof(unsigned));
|
||||
|
||||
table.block_offsets.resize(number_of_blocks);
|
||||
table.diff_blocks.resize(number_of_blocks);
|
||||
|
||||
// read block offsets
|
||||
in.read((char *) table.block_offsets.data(), sizeof(unsigned) * number_of_blocks);
|
||||
// read blocks
|
||||
in.read((char *) table.diff_blocks.data(), BLOCK_SIZE * number_of_blocks);
|
||||
return in;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -34,26 +34,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct PathData
|
||||
{
|
||||
PathData()
|
||||
: node(std::numeric_limits<unsigned>::max()), name_id(std::numeric_limits<unsigned>::max()),
|
||||
segment_duration(std::numeric_limits<unsigned>::max()),
|
||||
: node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT),
|
||||
segment_duration(INVALID_EDGE_WEIGHT),
|
||||
turn_instruction(TurnInstruction::NoTurn)
|
||||
{
|
||||
}
|
||||
|
||||
PathData(NodeID node, unsigned name_id, TurnInstruction turn_instruction, unsigned segment_duration)
|
||||
PathData(NodeID node, unsigned name_id, TurnInstruction turn_instruction, EdgeWeight segment_duration)
|
||||
: node(node), name_id(name_id), segment_duration(segment_duration), turn_instruction(turn_instruction)
|
||||
{
|
||||
}
|
||||
NodeID node;
|
||||
unsigned name_id;
|
||||
unsigned segment_duration;
|
||||
EdgeWeight segment_duration;
|
||||
TurnInstruction turn_instruction;
|
||||
};
|
||||
|
||||
@@ -63,20 +61,18 @@ struct RawRouteData
|
||||
std::vector<PathData> unpacked_alternative;
|
||||
std::vector<PhantomNodes> segment_end_coordinates;
|
||||
std::vector<FixedPointCoordinate> raw_via_node_coordinates;
|
||||
std::vector<bool> source_traversed_in_reverse;
|
||||
std::vector<bool> target_traversed_in_reverse;
|
||||
std::vector<bool> alt_source_traversed_in_reverse;
|
||||
std::vector<bool> alt_target_traversed_in_reverse;
|
||||
unsigned check_sum;
|
||||
int shortest_path_length;
|
||||
int alternative_path_length;
|
||||
bool source_traversed_in_reverse;
|
||||
bool target_traversed_in_reverse;
|
||||
bool alt_source_traversed_in_reverse;
|
||||
bool alt_target_traversed_in_reverse;
|
||||
|
||||
RawRouteData()
|
||||
: check_sum(std::numeric_limits<unsigned>::max()),
|
||||
shortest_path_length(std::numeric_limits<int>::max()),
|
||||
alternative_path_length(std::numeric_limits<int>::max()),
|
||||
source_traversed_in_reverse(false), target_traversed_in_reverse(false),
|
||||
alt_source_traversed_in_reverse(false), alt_target_traversed_in_reverse(false)
|
||||
: check_sum(SPECIAL_NODEID),
|
||||
shortest_path_length(INVALID_EDGE_WEIGHT),
|
||||
alternative_path_length(INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,16 +1,53 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "RestrictionMap.h"
|
||||
#include "NodeBasedGraph.h"
|
||||
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
bool RestrictionMap::IsViaNode(const NodeID node) const
|
||||
{
|
||||
return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
|
||||
}
|
||||
|
||||
RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
|
||||
const std::vector<TurnRestriction> &input_restrictions_list)
|
||||
const std::vector<TurnRestriction> &restriction_list)
|
||||
: m_count(0), m_graph(graph)
|
||||
{
|
||||
// decompose restirction consisting of a start, via and end note into a start-edge
|
||||
// and all end-nodes
|
||||
for (auto &restriction : input_restrictions_list)
|
||||
// decompose restriction consisting of a start, via and end node into a
|
||||
// a pair of starting edge and a list of all end nodes
|
||||
for (auto &restriction : restriction_list)
|
||||
{
|
||||
std::pair<NodeID, NodeID> restriction_source =
|
||||
std::make_pair(restriction.fromNode, restriction.viaNode);
|
||||
m_restriction_start_nodes.insert(restriction.fromNode);
|
||||
m_no_turn_via_node_set.insert(restriction.viaNode);
|
||||
|
||||
RestrictionSource restriction_source = {restriction.fromNode, restriction.viaNode};
|
||||
|
||||
unsigned index;
|
||||
auto restriction_iter = m_restriction_map.find(restriction_source);
|
||||
if (restriction_iter == m_restriction_map.end())
|
||||
@@ -23,7 +60,7 @@ RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &gra
|
||||
{
|
||||
index = restriction_iter->second;
|
||||
// Map already contains an is_only_*-restriction
|
||||
if (m_restriction_bucket_list.at(index).begin()->second)
|
||||
if (m_restriction_bucket_list.at(index).begin()->is_only)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -36,133 +73,152 @@ RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &gra
|
||||
}
|
||||
++m_count;
|
||||
m_restriction_bucket_list.at(index)
|
||||
.push_back(std::make_pair(restriction.toNode, restriction.flags.isOnly));
|
||||
.emplace_back(restriction.toNode, restriction.flags.isOnly);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace end v with w in each turn restriction containing u as via node
|
||||
*
|
||||
* Note: We need access to node based graph.
|
||||
*/
|
||||
void RestrictionMap::FixupArrivingTurnRestriction(const NodeID u, const NodeID v, const NodeID w)
|
||||
// Replace end v with w in each turn restriction containing u as via node
|
||||
void RestrictionMap::FixupArrivingTurnRestriction(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w)
|
||||
{
|
||||
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
||||
|
||||
// find all possible start edges
|
||||
// it is more efficent to get a (small) list of potential start edges
|
||||
// than iterating over all buckets
|
||||
if (!IsViaNode(node_u))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// find all potential start edges. It is more efficent to get a (small) list
|
||||
// of potential start edges than iterating over all buckets
|
||||
std::vector<NodeID> predecessors;
|
||||
for (EdgeID current_edge_id = m_graph->BeginEdges(u); current_edge_id < m_graph->EndEdges(u);
|
||||
++current_edge_id)
|
||||
for (const EdgeID current_edge_id : m_graph->GetAdjacentEdgeRange(node_u))
|
||||
{
|
||||
const EdgeData &edge_data = m_graph->GetEdgeData(current_edge_id);
|
||||
const NodeID target = m_graph->GetTarget(current_edge_id);
|
||||
if (edge_data.backward && (v != target))
|
||||
if (edge_data.backward && (node_v != target))
|
||||
{
|
||||
predecessors.push_back(target);
|
||||
}
|
||||
}
|
||||
|
||||
for (const NodeID x : predecessors)
|
||||
for (const NodeID node_x : predecessors)
|
||||
{
|
||||
const std::pair<NodeID, NodeID> restr_start = std::make_pair(x, u);
|
||||
auto restriction_iterator = m_restriction_map.find(restr_start);
|
||||
const auto restriction_iterator = m_restriction_map.find({node_x, node_u});
|
||||
if (restriction_iterator == m_restriction_map.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const unsigned index = restriction_iterator->second;
|
||||
auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if (v == restriction_target.first)
|
||||
if (node_v == restriction_target.target_node)
|
||||
{
|
||||
restriction_target.first = w;
|
||||
restriction_target.target_node = node_w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the start edge (v, w) with (u, w), only start node changes.
|
||||
*/
|
||||
void RestrictionMap::FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w)
|
||||
// Replaces start edge (v, w) with (u, w). Only start node changes.
|
||||
void RestrictionMap::FixupStartingTurnRestriction(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w)
|
||||
{
|
||||
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
||||
|
||||
const std::pair<NodeID, NodeID> old_start = std::make_pair(v, w);
|
||||
if (!IsSourceNode(node_v))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto restriction_iterator = m_restriction_map.find(old_start);
|
||||
const auto restriction_iterator = m_restriction_map.find({node_v, node_w});
|
||||
if (restriction_iterator != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iterator->second;
|
||||
// remove old restriction start (v,w)
|
||||
m_restriction_map.erase(restriction_iterator);
|
||||
|
||||
// insert new restriction start (u,w) (point to index)
|
||||
const std::pair<NodeID, NodeID> new_start = std::make_pair(u, w);
|
||||
m_restriction_map.insert(std::make_pair(new_start, index));
|
||||
m_restriction_start_nodes.emplace(node_u);
|
||||
// insert new restriction start (u,w) (pointing to index)
|
||||
RestrictionSource new_source = {node_u, node_w};
|
||||
m_restriction_map.emplace(new_source, index);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the edge (u, v) is contained in any turn restriction.
|
||||
* If so returns id of first target node.
|
||||
*/
|
||||
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const
|
||||
// Check if edge (u, v) is the start of any turn restriction.
|
||||
// If so returns id of first target node.
|
||||
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
|
||||
{
|
||||
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
|
||||
const std::pair<NodeID, NodeID> restriction_source = std::make_pair(u, v);
|
||||
auto restriction_iter = m_restriction_map.find(restriction_source);
|
||||
|
||||
if (restriction_iter != m_restriction_map.end())
|
||||
if (!IsSourceNode(node_u))
|
||||
{
|
||||
const unsigned index = restriction_iter->second;
|
||||
auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (const RestrictionSource &restriction_target : bucket)
|
||||
{
|
||||
if (restriction_target.second)
|
||||
{
|
||||
return restriction_target.first;
|
||||
}
|
||||
}
|
||||
return SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the turn described by start u, via v and targed w is covert by any turn restriction.
|
||||
*/
|
||||
bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const
|
||||
{
|
||||
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max());
|
||||
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max());
|
||||
|
||||
const std::pair<NodeID, NodeID> restriction_source = std::make_pair(u, v);
|
||||
auto restriction_iter = m_restriction_map.find(restriction_source);
|
||||
|
||||
auto restriction_iter = m_restriction_map.find({node_u, node_v});
|
||||
if (restriction_iter != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iter->second;
|
||||
auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (const RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if ((w == restriction_target.first) && // target found
|
||||
(!restriction_target.second) // and not an only_-restr.
|
||||
if (restriction_target.is_only)
|
||||
{
|
||||
return restriction_target.target_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
// Checks if turn <u,v,w> is actually a turn restriction.
|
||||
bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w) const
|
||||
{
|
||||
// return false;
|
||||
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
||||
|
||||
if (!IsSourceNode(node_u))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto restriction_iter = m_restriction_map.find({node_u, node_v});
|
||||
if (restriction_iter != m_restriction_map.end())
|
||||
{
|
||||
const unsigned index = restriction_iter->second;
|
||||
const auto &bucket = m_restriction_bucket_list.at(index);
|
||||
for (const RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if ((node_w == restriction_target.target_node) && // target found
|
||||
(!restriction_target.is_only) // and not an only_-restr.
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check of node is the start of any restriction
|
||||
bool RestrictionMap::IsSourceNode(const NodeID node) const
|
||||
{
|
||||
if (m_restriction_start_nodes.find(node) == m_restriction_start_nodes.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,17 +30,68 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "DynamicGraph.h"
|
||||
#include "Restriction.h"
|
||||
#include "NodeBasedGraph.h"
|
||||
#include "../Util/StdHashExtensions.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
/*!
|
||||
* Makee it efficent to look up if an edge is the start + via node of a TurnRestriction.
|
||||
* Is needed by EdgeBasedGraphFactory.
|
||||
*/
|
||||
struct RestrictionSource
|
||||
{
|
||||
NodeID start_node;
|
||||
NodeID via_node;
|
||||
|
||||
RestrictionSource(NodeID start, NodeID via) : start_node(start), via_node(via)
|
||||
{
|
||||
}
|
||||
|
||||
friend inline bool operator==(const RestrictionSource &lhs, const RestrictionSource &rhs)
|
||||
{
|
||||
return (lhs.start_node == rhs.start_node && lhs.via_node == rhs.via_node);
|
||||
}
|
||||
};
|
||||
|
||||
struct RestrictionTarget
|
||||
{
|
||||
NodeID target_node;
|
||||
bool is_only;
|
||||
|
||||
explicit RestrictionTarget(NodeID target, bool only) : target_node(target), is_only(only)
|
||||
{
|
||||
}
|
||||
|
||||
friend inline bool operator==(const RestrictionTarget &lhs, const RestrictionTarget &rhs)
|
||||
{
|
||||
return (lhs.target_node == rhs.target_node && lhs.is_only == rhs.is_only);
|
||||
}
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<RestrictionSource>
|
||||
{
|
||||
size_t operator()(const RestrictionSource &r_source) const
|
||||
{
|
||||
return hash_val(r_source.start_node, r_source.via_node);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct hash<RestrictionTarget>
|
||||
{
|
||||
size_t operator()(const RestrictionTarget &r_target) const
|
||||
{
|
||||
return hash_val(r_target.target_node, r_target.is_only);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Efficent look up if an edge is the start + via node of a TurnRestriction
|
||||
EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
|
||||
*/
|
||||
class RestrictionMap
|
||||
{
|
||||
public:
|
||||
@@ -51,12 +102,14 @@ class RestrictionMap
|
||||
void FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
|
||||
NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const;
|
||||
bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const;
|
||||
|
||||
unsigned size() { return m_count; }
|
||||
bool IsViaNode(const NodeID node) const;
|
||||
unsigned size()
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::pair<NodeID, NodeID> RestrictionSource;
|
||||
typedef std::pair<NodeID, bool> RestrictionTarget;
|
||||
bool IsSourceNode(const NodeID node) const;
|
||||
typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
|
||||
typedef NodeBasedDynamicGraph::EdgeData EdgeData;
|
||||
|
||||
@@ -65,7 +118,9 @@ class RestrictionMap
|
||||
//! index -> list of (target, isOnly)
|
||||
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
|
||||
//! maps (start, via) -> bucket index
|
||||
boost::unordered_map<RestrictionSource, unsigned> m_restriction_map;
|
||||
std::unordered_map<RestrictionSource, unsigned> m_restriction_map;
|
||||
std::unordered_set<NodeID> m_restriction_start_nodes;
|
||||
std::unordered_set<NodeID> m_no_turn_via_node_set;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -57,7 +57,10 @@ void RouteParameters::setService(const std::string &service_string) { service =
|
||||
|
||||
void RouteParameters::setOutputFormat(const std::string &format) { output_format = format; }
|
||||
|
||||
void RouteParameters::setJSONpParameter(const std::string ¶meter) { jsonp_parameter = parameter; }
|
||||
void RouteParameters::setJSONpParameter(const std::string ¶meter)
|
||||
{
|
||||
jsonp_parameter = parameter;
|
||||
}
|
||||
|
||||
void RouteParameters::addHint(const std::string &hint)
|
||||
{
|
||||
@@ -68,15 +71,19 @@ void RouteParameters::addHint(const std::string &hint)
|
||||
}
|
||||
}
|
||||
|
||||
void RouteParameters::setLanguage(const std::string &language_string) { language = language_string; }
|
||||
void RouteParameters::setLanguage(const std::string &language_string)
|
||||
{
|
||||
language = language_string;
|
||||
}
|
||||
|
||||
void RouteParameters::setGeometryFlag(const bool flag) { geometry = flag; }
|
||||
|
||||
void RouteParameters::setCompressionFlag(const bool flag) { compression = flag; }
|
||||
|
||||
void RouteParameters::addCoordinate(const boost::fusion::vector<double, double> &transmitted_coordinates)
|
||||
void
|
||||
RouteParameters::addCoordinate(const boost::fusion::vector<double, double> &transmitted_coordinates)
|
||||
{
|
||||
int lat = COORDINATE_PRECISION * boost::fusion::at_c<0>(transmitted_coordinates);
|
||||
int lon = COORDINATE_PRECISION * boost::fusion::at_c<1>(transmitted_coordinates);
|
||||
coordinates.emplace_back(lat, lon);
|
||||
coordinates.emplace_back(
|
||||
static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(transmitted_coordinates)),
|
||||
static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(transmitted_coordinates)));
|
||||
}
|
||||
|
||||
@@ -30,8 +30,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "SearchEngineData.h"
|
||||
#include "../RoutingAlgorithms/AlternativePathRouting.h"
|
||||
#include "../RoutingAlgorithms/ManyToManyRouting.h"
|
||||
#include "../RoutingAlgorithms/ShortestPathRouting.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
template <class DataFacadeT> class SearchEngine
|
||||
{
|
||||
private:
|
||||
@@ -41,11 +44,14 @@ template <class DataFacadeT> class SearchEngine
|
||||
public:
|
||||
ShortestPathRouting<DataFacadeT> shortest_path;
|
||||
AlternativeRouting<DataFacadeT> alternative_path;
|
||||
ManyToManyRouting<DataFacadeT> distance_table;
|
||||
|
||||
explicit SearchEngine(DataFacadeT *facade)
|
||||
: facade(facade), shortest_path(facade, engine_working_data),
|
||||
alternative_path(facade, engine_working_data)
|
||||
alternative_path(facade, engine_working_data), distance_table(facade, engine_working_data)
|
||||
{
|
||||
static_assert(!std::is_pointer<DataFacadeT>::value, "don't instantiate with ptr type");
|
||||
static_assert(std::is_object<DataFacadeT>::value, "don't instantiate with void, function, or reference");
|
||||
}
|
||||
|
||||
~SearchEngine() {}
|
||||
|
||||
@@ -27,6 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "SearchEngineData.h"
|
||||
|
||||
#include "BinaryHeap.h"
|
||||
|
||||
void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
|
||||
{
|
||||
if (forwardHeap.get())
|
||||
|
||||
@@ -28,15 +28,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef SEARCH_ENGINE_DATA_H
|
||||
#define SEARCH_ENGINE_DATA_H
|
||||
|
||||
#include "BinaryHeap.h"
|
||||
#include "QueryEdge.h"
|
||||
#include "StaticGraph.h"
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include "BinaryHeap.h"
|
||||
|
||||
struct HeapData
|
||||
{
|
||||
|
||||
@@ -39,30 +39,32 @@ struct SegmentInformation
|
||||
{
|
||||
FixedPointCoordinate location;
|
||||
NodeID name_id;
|
||||
unsigned duration;
|
||||
double length;
|
||||
EdgeWeight duration;
|
||||
float length;
|
||||
short bearing; // more than enough [0..3600] fits into 12 bits
|
||||
TurnInstruction turn_instruction;
|
||||
bool necessary;
|
||||
bool necessary:1;
|
||||
bool is_via_location:1;
|
||||
|
||||
explicit SegmentInformation(const FixedPointCoordinate &location,
|
||||
const NodeID name_id,
|
||||
const unsigned duration,
|
||||
const double length,
|
||||
const EdgeWeight duration,
|
||||
const float length,
|
||||
const TurnInstruction turn_instruction,
|
||||
const bool necessary)
|
||||
const bool necessary,
|
||||
const bool is_via_location)
|
||||
: location(location), name_id(name_id), duration(duration), length(length), bearing(0),
|
||||
turn_instruction(turn_instruction), necessary(necessary)
|
||||
turn_instruction(turn_instruction), necessary(necessary), is_via_location(is_via_location)
|
||||
{
|
||||
}
|
||||
|
||||
explicit SegmentInformation(const FixedPointCoordinate &location,
|
||||
const NodeID name_id,
|
||||
const unsigned duration,
|
||||
const double length,
|
||||
const EdgeWeight duration,
|
||||
const float length,
|
||||
const TurnInstruction turn_instruction)
|
||||
: location(location), name_id(name_id), duration(duration), length(length), bearing(0),
|
||||
turn_instruction(turn_instruction), necessary(turn_instruction != TurnInstruction::NoTurn)
|
||||
turn_instruction(turn_instruction), necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,7 +34,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
#ifndef WIN32
|
||||
#include <boost/interprocess/xsi_shared_memory.hpp>
|
||||
#else
|
||||
#include <boost/interprocess/shared_memory_object.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/ipc.h>
|
||||
@@ -57,6 +61,7 @@ struct OSRMLockFile
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef WIN32
|
||||
class SharedMemory
|
||||
{
|
||||
|
||||
@@ -189,6 +194,138 @@ class SharedMemory
|
||||
boost::interprocess::mapped_region region;
|
||||
shm_remove remover;
|
||||
};
|
||||
#else
|
||||
// Windows - specific code
|
||||
class SharedMemory : boost::noncopyable
|
||||
{
|
||||
// Remove shared memory on destruction
|
||||
class shm_remove : boost::noncopyable
|
||||
{
|
||||
private:
|
||||
char *m_shmid;
|
||||
bool m_initialized;
|
||||
|
||||
public:
|
||||
void SetID(char *shmid)
|
||||
{
|
||||
m_shmid = shmid;
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
shm_remove() : m_shmid("undefined"), m_initialized(false) {}
|
||||
|
||||
~shm_remove()
|
||||
{
|
||||
if (m_initialized)
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
|
||||
if (!boost::interprocess::shared_memory_object::remove(m_shmid))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
void *Ptr() const { return region.get_address(); }
|
||||
|
||||
SharedMemory(const boost::filesystem::path &lock_file,
|
||||
const int id,
|
||||
const uint64_t size = 0,
|
||||
bool read_write = false,
|
||||
bool remove_prev = true)
|
||||
{
|
||||
sprintf(key, "%s.%d", "osrm.lock", id);
|
||||
if (0 == size)
|
||||
{ // read_only
|
||||
shm = boost::interprocess::shared_memory_object(
|
||||
boost::interprocess::open_only,
|
||||
key,
|
||||
read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
|
||||
region = boost::interprocess::mapped_region(
|
||||
shm, read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
|
||||
}
|
||||
else
|
||||
{ // writeable pointer
|
||||
// remove previously allocated mem
|
||||
if (remove_prev)
|
||||
{
|
||||
Remove(key);
|
||||
}
|
||||
shm = boost::interprocess::shared_memory_object(
|
||||
boost::interprocess::open_or_create, key, boost::interprocess::read_write);
|
||||
shm.truncate(size);
|
||||
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
|
||||
|
||||
remover.SetID(key);
|
||||
SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size << " bytes";
|
||||
}
|
||||
}
|
||||
|
||||
static bool RegionExists(const int id)
|
||||
{
|
||||
bool result = true;
|
||||
try
|
||||
{
|
||||
char k[500];
|
||||
build_key(id, k);
|
||||
result = RegionExists(k);
|
||||
}
|
||||
catch (...) { result = false; }
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool Remove(const int id)
|
||||
{
|
||||
char k[500];
|
||||
build_key(id, k);
|
||||
return Remove(k);
|
||||
}
|
||||
|
||||
private:
|
||||
static void build_key(int id, char *key)
|
||||
{
|
||||
OSRMLockFile lock_file;
|
||||
sprintf(key, "%s.%d", "osrm.lock", id);
|
||||
}
|
||||
|
||||
static bool RegionExists(const char *key)
|
||||
{
|
||||
bool result = true;
|
||||
try
|
||||
{
|
||||
boost::interprocess::shared_memory_object shm(
|
||||
boost::interprocess::open_only, key, boost::interprocess::read_write);
|
||||
}
|
||||
catch (...) { result = false; }
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool Remove(char *key)
|
||||
{
|
||||
bool ret = false;
|
||||
try
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
|
||||
ret = boost::interprocess::shared_memory_object::remove(key);
|
||||
}
|
||||
catch (const boost::interprocess::interprocess_exception &e)
|
||||
{
|
||||
if (e.get_error_code() != boost::interprocess::not_found_error)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char key[500];
|
||||
boost::interprocess::shared_memory_object shm;
|
||||
boost::interprocess::mapped_region region;
|
||||
shm_remove remover;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
|
||||
{
|
||||
|
||||
@@ -128,8 +128,8 @@ template <> class SharedMemoryWrapper<bool>
|
||||
|
||||
bool at(const std::size_t index) const
|
||||
{
|
||||
const unsigned bucket = index / 32;
|
||||
const unsigned offset = index % 32;
|
||||
const std::size_t bucket = index / 32;
|
||||
const unsigned offset = static_cast<unsigned>(index % 32);
|
||||
return m_ptr[bucket] & (1 << offset);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/range/irange.hpp>
|
||||
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
@@ -40,6 +45,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
|
||||
{
|
||||
public:
|
||||
typedef decltype(boost::irange(0u,0u)) EdgeRange;
|
||||
typedef NodeID NodeIterator;
|
||||
typedef NodeID EdgeIterator;
|
||||
typedef EdgeDataT EdgeData;
|
||||
@@ -62,7 +68,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
|
||||
struct NodeArrayEntry
|
||||
{
|
||||
// index of the first edge
|
||||
EdgeIterator firstEdge;
|
||||
EdgeIterator first_edge;
|
||||
};
|
||||
|
||||
struct EdgeArrayEntry
|
||||
@@ -71,9 +77,14 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
|
||||
EdgeDataT data;
|
||||
};
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const
|
||||
{
|
||||
return boost::irange(BeginEdges(node), EndEdges(node));
|
||||
}
|
||||
|
||||
StaticGraph(const int nodes, std::vector<InputEdge> &graph)
|
||||
{
|
||||
std::sort(graph.begin(), graph.end());
|
||||
tbb::parallel_sort(graph.begin(), graph.end());
|
||||
number_of_nodes = nodes;
|
||||
number_of_edges = (EdgeIterator)graph.size();
|
||||
node_array.resize(number_of_nodes + 1);
|
||||
@@ -81,22 +92,24 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
|
||||
EdgeIterator position = 0;
|
||||
for (NodeIterator node = 0; node <= number_of_nodes; ++node)
|
||||
{
|
||||
EdgeIterator lastEdge = edge;
|
||||
EdgeIterator last_edge = edge;
|
||||
while (edge < number_of_edges && graph[edge].source == node)
|
||||
{
|
||||
++edge;
|
||||
node_array[node].firstEdge = position; //=edge
|
||||
position += edge - lastEdge; // remove
|
||||
}
|
||||
node_array[node].first_edge = position; //=edge
|
||||
position += edge - last_edge; // remove
|
||||
}
|
||||
edge_array.resize(position); //(edge)
|
||||
edge = 0;
|
||||
for (NodeIterator node = 0; node < number_of_nodes; ++node)
|
||||
{
|
||||
EdgeIterator e = node_array[node + 1].firstEdge;
|
||||
for (EdgeIterator i = node_array[node].firstEdge; i != e; ++i)
|
||||
EdgeIterator e = node_array[node + 1].first_edge;
|
||||
for (EdgeIterator i = node_array[node].first_edge; i != e; ++i)
|
||||
{
|
||||
edge_array[i].target = graph[edge].target;
|
||||
edge_array[i].data = graph[edge].data;
|
||||
assert(edge_array[i].data.distance > 0);
|
||||
BOOST_ASSERT(edge_array[i].data.distance > 0);
|
||||
edge++;
|
||||
}
|
||||
}
|
||||
@@ -115,28 +128,29 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
|
||||
Percent p(GetNumberOfNodes());
|
||||
for (unsigned u = 0; u < GetNumberOfNodes(); ++u)
|
||||
{
|
||||
for (unsigned eid = BeginEdges(u); eid < EndEdges(u); ++eid)
|
||||
for (auto eid : GetAdjacentEdgeRange(u))
|
||||
{
|
||||
unsigned v = GetTarget(eid);
|
||||
EdgeData &data = GetEdgeData(eid);
|
||||
if (data.shortcut)
|
||||
const EdgeData &data = GetEdgeData(eid);
|
||||
if (!data.shortcut)
|
||||
{
|
||||
const EdgeID first_edge_id = FindEdgeInEitherDirection(u, data.id);
|
||||
if (SPECIAL_EDGEID == first_edge_id)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "cannot find first segment of edge ("
|
||||
<< u << "," << data.id << "," << v
|
||||
<< "), eid: " << eid;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
const EdgeID second_edge_id = FindEdgeInEitherDirection(data.id, v);
|
||||
if (SPECIAL_EDGEID == second_edge_id)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "cannot find second segment of edge ("
|
||||
<< u << "," << data.id << "," << v
|
||||
<< "), eid: " << eid;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const unsigned v = GetTarget(eid);
|
||||
const EdgeID first_edge_id = FindEdgeInEitherDirection(u, data.id);
|
||||
if (SPECIAL_EDGEID == first_edge_id)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "cannot find first segment of edge ("
|
||||
<< u << "," << data.id << "," << v
|
||||
<< "), eid: " << eid;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
const EdgeID second_edge_id = FindEdgeInEitherDirection(data.id, v);
|
||||
if (SPECIAL_EDGEID == second_edge_id)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "cannot find second segment of edge ("
|
||||
<< u << "," << data.id << "," << v
|
||||
<< "), eid: " << eid;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
}
|
||||
p.printIncrement();
|
||||
@@ -144,7 +158,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned GetNumberOfNodes() const { return number_of_nodes; }
|
||||
unsigned GetNumberOfNodes() const { return number_of_nodes -1; }
|
||||
|
||||
unsigned GetNumberOfEdges() const { return number_of_edges; }
|
||||
|
||||
@@ -161,12 +175,12 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
|
||||
|
||||
EdgeIterator BeginEdges(const NodeIterator n) const
|
||||
{
|
||||
return EdgeIterator(node_array.at(n).firstEdge);
|
||||
return EdgeIterator(node_array.at(n).first_edge);
|
||||
}
|
||||
|
||||
EdgeIterator EndEdges(const NodeIterator n) const
|
||||
{
|
||||
return EdgeIterator(node_array.at(n + 1).firstEdge);
|
||||
return EdgeIterator(node_array.at(n + 1).first_edge);
|
||||
}
|
||||
|
||||
// searches for a specific edge
|
||||
@@ -174,7 +188,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
|
||||
{
|
||||
EdgeIterator smallest_edge = SPECIAL_EDGEID;
|
||||
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
|
||||
for (EdgeIterator edge = BeginEdges(from); edge < EndEdges(from); edge++)
|
||||
for (auto edge : GetAdjacentEdgeRange(from))
|
||||
{
|
||||
const NodeID target = GetTarget(edge);
|
||||
const EdgeWeight weight = GetEdgeData(edge).distance;
|
||||
|
||||
+447
-191
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../Util/MercatorUtil.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
@@ -45,12 +46,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
@@ -64,7 +67,7 @@ const static uint32_t RTREE_LEAF_NODE_SIZE = 1024;
|
||||
static boost::thread_specific_ptr<boost::filesystem::ifstream> thread_local_rtree_stream;
|
||||
|
||||
// Implements a static, i.e. packed, R-tree
|
||||
template <class DataT,
|
||||
template <class EdgeDataT,
|
||||
class CoordinateListT = std::vector<FixedPointCoordinate>,
|
||||
bool UseSharedMemory = false>
|
||||
class StaticRTree
|
||||
@@ -77,7 +80,7 @@ class StaticRTree
|
||||
int32_t min_lon, max_lon;
|
||||
int32_t min_lat, max_lat;
|
||||
|
||||
inline void InitializeMBRectangle(const std::array<DataT, RTREE_LEAF_NODE_SIZE> &objects,
|
||||
inline void InitializeMBRectangle(const std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> &objects,
|
||||
const uint32_t element_count,
|
||||
const std::vector<NodeInfo> &coordinate_list)
|
||||
{
|
||||
@@ -97,14 +100,22 @@ class StaticRTree
|
||||
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 AugmentMBRectangle(const RectangleInt2D &other)
|
||||
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
|
||||
@@ -128,15 +139,15 @@ class StaticRTree
|
||||
Contains(lower_left));
|
||||
}
|
||||
|
||||
inline double GetMinDist(const FixedPointCoordinate &location) const
|
||||
inline float GetMinDist(const FixedPointCoordinate &location) const
|
||||
{
|
||||
bool is_contained = Contains(location);
|
||||
const bool is_contained = Contains(location);
|
||||
if (is_contained)
|
||||
{
|
||||
return 0.;
|
||||
}
|
||||
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
float min_dist = std::numeric_limits<float>::max();
|
||||
min_dist = std::min(min_dist,
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
location.lat, location.lon, max_lat, min_lon));
|
||||
@@ -152,9 +163,9 @@ class StaticRTree
|
||||
return min_dist;
|
||||
}
|
||||
|
||||
inline double GetMinMaxDist(const FixedPointCoordinate &location) const
|
||||
inline float GetMinMaxDist(const FixedPointCoordinate &location) const
|
||||
{
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
float min_max_dist = std::numeric_limits<float>::max();
|
||||
// Get minmax distance to each of the four sides
|
||||
FixedPointCoordinate upper_left(max_lat, min_lon);
|
||||
FixedPointCoordinate upper_right(max_lat, max_lon);
|
||||
@@ -215,15 +226,15 @@ class StaticRTree
|
||||
private:
|
||||
struct WrappedInputElement
|
||||
{
|
||||
explicit WrappedInputElement(const uint32_t _array_index, const uint64_t _hilbert_value)
|
||||
: m_array_index(_array_index), m_hilbert_value(_hilbert_value)
|
||||
explicit WrappedInputElement(const uint64_t _hilbert_value, const uint32_t _array_index)
|
||||
: m_hilbert_value(_hilbert_value), m_array_index(_array_index)
|
||||
{
|
||||
}
|
||||
|
||||
WrappedInputElement() : m_array_index(UINT_MAX), m_hilbert_value(0) {}
|
||||
WrappedInputElement() : m_hilbert_value(0), m_array_index(UINT_MAX) {}
|
||||
|
||||
uint32_t m_array_index;
|
||||
uint64_t m_hilbert_value;
|
||||
uint32_t m_array_index;
|
||||
|
||||
inline bool operator<(const WrappedInputElement &other) const
|
||||
{
|
||||
@@ -235,24 +246,60 @@ class StaticRTree
|
||||
{
|
||||
LeafNode() : object_count(0) {}
|
||||
uint32_t object_count;
|
||||
std::array<DataT, RTREE_LEAF_NODE_SIZE> objects;
|
||||
std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> objects;
|
||||
};
|
||||
|
||||
struct QueryCandidate
|
||||
{
|
||||
explicit QueryCandidate(const uint32_t n_id, const double dist)
|
||||
: node_id(n_id), min_dist(dist)
|
||||
explicit QueryCandidate(const float dist, const uint32_t n_id)
|
||||
: min_dist(dist), node_id(n_id)
|
||||
{
|
||||
}
|
||||
QueryCandidate() : node_id(UINT_MAX), min_dist(std::numeric_limits<double>::max()) {}
|
||||
QueryCandidate() : min_dist(std::numeric_limits<float>::max()), node_id(UINT_MAX) {}
|
||||
float min_dist;
|
||||
uint32_t node_id;
|
||||
double min_dist;
|
||||
inline bool operator<(const QueryCandidate &other) const
|
||||
{
|
||||
return min_dist < other.min_dist;
|
||||
// Attn: this is reversed order. std::pq is a max pq!
|
||||
return other.min_dist < min_dist;
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::variant<TreeNode, EdgeDataT> IncrementalQueryNodeType;
|
||||
struct IncrementalQueryCandidate
|
||||
{
|
||||
explicit IncrementalQueryCandidate(const float dist, const IncrementalQueryNodeType &node)
|
||||
: min_dist(dist), node(node)
|
||||
{
|
||||
}
|
||||
|
||||
IncrementalQueryCandidate() : min_dist(std::numeric_limits<float>::max()) {}
|
||||
|
||||
inline bool operator<(const IncrementalQueryCandidate &other) const
|
||||
{
|
||||
// Attn: this is reversed order. std::pq is a max pq!
|
||||
return other.min_dist < min_dist;
|
||||
}
|
||||
|
||||
inline bool RepresentsTreeNode() const
|
||||
{
|
||||
return boost::apply_visitor(decide_type_visitor(), node);
|
||||
}
|
||||
|
||||
float min_dist;
|
||||
IncrementalQueryNodeType node;
|
||||
|
||||
private:
|
||||
class decide_type_visitor : public boost::static_visitor<bool>
|
||||
{
|
||||
public:
|
||||
bool operator()(const TreeNode &) const { return true; }
|
||||
|
||||
template<typename AnotherType>
|
||||
bool operator()(const AnotherType &) const { return false; }
|
||||
};
|
||||
};
|
||||
|
||||
typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
|
||||
uint64_t m_element_count;
|
||||
const std::string m_leaf_node_filename;
|
||||
@@ -263,7 +310,7 @@ class StaticRTree
|
||||
StaticRTree(const StaticRTree &) = delete;
|
||||
|
||||
// Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
|
||||
explicit StaticRTree(std::vector<DataT> &input_data_vector,
|
||||
explicit StaticRTree(std::vector<EdgeDataT> &input_data_vector,
|
||||
const std::string tree_node_filename,
|
||||
const std::string leaf_node_filename,
|
||||
const std::vector<NodeInfo> &coordinate_list)
|
||||
@@ -273,36 +320,44 @@ class StaticRTree
|
||||
<< " edge elements build on-top of " << coordinate_list.size()
|
||||
<< " coordinates";
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> time0 = std::chrono::steady_clock::now();
|
||||
TIMER_START(construction);
|
||||
std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
|
||||
|
||||
HilbertCode get_hilbert_number;
|
||||
|
||||
// generate auxiliary vector of hilbert-values
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (uint64_t element_counter = 0; element_counter < m_element_count; ++element_counter)
|
||||
{
|
||||
input_wrapper_vector[element_counter].m_array_index = element_counter;
|
||||
// Get Hilbert-Value for centroid in mercartor projection
|
||||
DataT const ¤t_element = input_data_vector[element_counter];
|
||||
FixedPointCoordinate current_centroid =
|
||||
DataT::Centroid(FixedPointCoordinate(coordinate_list.at(current_element.u).lat,
|
||||
coordinate_list.at(current_element.u).lon),
|
||||
FixedPointCoordinate(coordinate_list.at(current_element.v).lat,
|
||||
coordinate_list.at(current_element.v).lon));
|
||||
current_centroid.lat =
|
||||
COORDINATE_PRECISION * lat2y(current_centroid.lat / COORDINATE_PRECISION);
|
||||
// generate auxiliary vector of hilbert-values
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<uint64_t>(0, m_element_count),
|
||||
[&input_data_vector, &input_wrapper_vector, &get_hilbert_number, &coordinate_list](
|
||||
const tbb::blocked_range<uint64_t> &range)
|
||||
{
|
||||
for (uint64_t element_counter = range.begin(); element_counter != range.end();
|
||||
++element_counter)
|
||||
{
|
||||
WrappedInputElement ¤t_wrapper = input_wrapper_vector[element_counter];
|
||||
current_wrapper.m_array_index = element_counter;
|
||||
|
||||
uint64_t current_hilbert_value = get_hilbert_number(current_centroid);
|
||||
input_wrapper_vector[element_counter].m_hilbert_value = current_hilbert_value;
|
||||
}
|
||||
EdgeDataT const ¤t_element = input_data_vector[element_counter];
|
||||
|
||||
// Get Hilbert-Value for centroid in mercartor projection
|
||||
FixedPointCoordinate current_centroid = EdgeDataT::Centroid(
|
||||
FixedPointCoordinate(coordinate_list.at(current_element.u).lat,
|
||||
coordinate_list.at(current_element.u).lon),
|
||||
FixedPointCoordinate(coordinate_list.at(current_element.v).lat,
|
||||
coordinate_list.at(current_element.v).lon));
|
||||
current_centroid.lat =
|
||||
COORDINATE_PRECISION * lat2y(current_centroid.lat / COORDINATE_PRECISION);
|
||||
|
||||
current_wrapper.m_hilbert_value = get_hilbert_number(current_centroid);
|
||||
}
|
||||
});
|
||||
|
||||
// open leaf file
|
||||
boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
|
||||
leaf_node_file.write((char *)&m_element_count, sizeof(uint64_t));
|
||||
|
||||
// sort the hilbert-value representatives
|
||||
std::sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
|
||||
tbb::parallel_sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
|
||||
std::vector<TreeNode> tree_nodes_in_level;
|
||||
|
||||
// pack M elements into leaf node and write to leaf file
|
||||
@@ -363,8 +418,8 @@ class StaticRTree
|
||||
// add tree node to parent entry
|
||||
parent_node.children[current_child_node_index] = m_search_tree.size();
|
||||
m_search_tree.emplace_back(current_child_node);
|
||||
// augment MBR of parent
|
||||
parent_node.minimum_bounding_rectangle.AugmentMBRectangle(
|
||||
// merge MBRs
|
||||
parent_node.minimum_bounding_rectangle.MergeBoundingBoxes(
|
||||
current_child_node.minimum_bounding_rectangle);
|
||||
// increase counters
|
||||
++parent_node.child_count;
|
||||
@@ -383,17 +438,21 @@ class StaticRTree
|
||||
// reverse and renumber tree to have root at index 0
|
||||
std::reverse(m_search_tree.begin(), m_search_tree.end());
|
||||
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (uint32_t i = 0; i < m_search_tree.size(); ++i)
|
||||
{
|
||||
TreeNode ¤t_tree_node = m_search_tree[i];
|
||||
for (uint32_t j = 0; j < current_tree_node.child_count; ++j)
|
||||
uint32_t search_tree_size = m_search_tree.size();
|
||||
tbb::parallel_for(tbb::blocked_range<uint32_t>(0, search_tree_size),
|
||||
[this, &search_tree_size](const tbb::blocked_range<uint32_t> &range)
|
||||
{
|
||||
for (uint32_t i = range.begin(); i != range.end(); ++i)
|
||||
{
|
||||
const uint32_t old_id = current_tree_node.children[j];
|
||||
const uint32_t new_id = m_search_tree.size() - old_id - 1;
|
||||
current_tree_node.children[j] = new_id;
|
||||
TreeNode ¤t_tree_node = this->m_search_tree[i];
|
||||
for (uint32_t j = 0; j < current_tree_node.child_count; ++j)
|
||||
{
|
||||
const uint32_t old_id = current_tree_node.children[j];
|
||||
const uint32_t new_id = search_tree_size - old_id - 1;
|
||||
current_tree_node.children[j] = new_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// open tree file
|
||||
boost::filesystem::ofstream tree_node_file(tree_node_filename, std::ios::binary);
|
||||
@@ -404,9 +463,9 @@ class StaticRTree
|
||||
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode) * size_of_tree);
|
||||
// close tree node file.
|
||||
tree_node_file.close();
|
||||
std::chrono::time_point<std::chrono::steady_clock> time1 = std::chrono::steady_clock::now();
|
||||
std::chrono::duration<double> elapsed_seconds = time1 - time0;
|
||||
SimpleLogger().Write() << "finished r-tree construction in " << (elapsed_seconds.count())
|
||||
|
||||
TIMER_STOP(construction);
|
||||
SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
|
||||
<< " seconds";
|
||||
}
|
||||
|
||||
@@ -433,7 +492,10 @@ class StaticRTree
|
||||
tree_node_file.read((char *)&tree_size, sizeof(uint32_t));
|
||||
|
||||
m_search_tree.resize(tree_size);
|
||||
tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size);
|
||||
if (tree_size > 0)
|
||||
{
|
||||
tree_node_file.read((char *)&m_search_tree[0], sizeof(TreeNode) * tree_size);
|
||||
}
|
||||
tree_node_file.close();
|
||||
// open leaf node file and store thread specific pointer
|
||||
if (!boost::filesystem::exists(leaf_file))
|
||||
@@ -489,16 +551,13 @@ class StaticRTree
|
||||
const unsigned zoom_level)
|
||||
{
|
||||
bool ignore_tiny_components = (zoom_level <= 14);
|
||||
DataT nearest_edge;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
bool found_a_nearest_edge = false;
|
||||
|
||||
float min_dist = std::numeric_limits<float>::max();
|
||||
float min_max_dist = std::numeric_limits<float>::max();
|
||||
|
||||
// initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
double current_min_dist =
|
||||
m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
|
||||
traversal_queue.emplace(0, current_min_dist);
|
||||
traversal_queue.emplace(0.f, 0);
|
||||
|
||||
while (!traversal_queue.empty())
|
||||
{
|
||||
@@ -516,13 +575,13 @@ class StaticRTree
|
||||
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
|
||||
for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
|
||||
{
|
||||
DataT const ¤t_edge = current_leaf_node.objects[i];
|
||||
EdgeDataT const ¤t_edge = current_leaf_node.objects[i];
|
||||
if (ignore_tiny_components && current_edge.is_in_tiny_cc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double current_minimum_distance =
|
||||
float current_minimum_distance =
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
input_coordinate.lat,
|
||||
input_coordinate.lon,
|
||||
@@ -532,9 +591,7 @@ class StaticRTree
|
||||
{
|
||||
// found a new minimum
|
||||
min_dist = current_minimum_distance;
|
||||
result_coordinate.lat = m_coordinate_list->at(current_edge.u).lat;
|
||||
result_coordinate.lon = m_coordinate_list->at(current_edge.u).lon;
|
||||
found_a_nearest_edge = true;
|
||||
result_coordinate = m_coordinate_list->at(current_edge.u);
|
||||
}
|
||||
|
||||
current_minimum_distance =
|
||||
@@ -548,95 +605,282 @@ class StaticRTree
|
||||
{
|
||||
// found a new minimum
|
||||
min_dist = current_minimum_distance;
|
||||
result_coordinate.lat = m_coordinate_list->at(current_edge.v).lat;
|
||||
result_coordinate.lon = m_coordinate_list->at(current_edge.v).lon;
|
||||
found_a_nearest_edge = true;
|
||||
result_coordinate = m_coordinate_list->at(current_edge.v);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// traverse children, prune if global mindist is smaller than local one
|
||||
min_max_dist = ExploreTreeNode(current_tree_node,
|
||||
input_coordinate,
|
||||
min_dist,
|
||||
min_max_dist,
|
||||
traversal_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result_coordinate.isValid();
|
||||
}
|
||||
|
||||
// implementation of the Hjaltason/Samet query [3], a BFS traversal of the tree
|
||||
bool
|
||||
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
std::vector<PhantomNode> &result_phantom_node_vector,
|
||||
const unsigned zoom_level,
|
||||
const unsigned number_of_results,
|
||||
const unsigned max_checked_segments = 4*RTREE_LEAF_NODE_SIZE)
|
||||
{
|
||||
// TIMER_START(samet);
|
||||
// SimpleLogger().Write(logDEBUG) << "searching for " << number_of_results << " results";
|
||||
std::vector<float> min_found_distances(number_of_results, std::numeric_limits<float>::max());
|
||||
|
||||
unsigned dequeues = 0;
|
||||
unsigned inspected_mbrs = 0;
|
||||
unsigned loaded_leafs = 0;
|
||||
unsigned inspected_segments = 0;
|
||||
unsigned pruned_elements = 0;
|
||||
unsigned ignored_segments = 0;
|
||||
unsigned ignored_mbrs = 0;
|
||||
|
||||
unsigned number_of_results_found_in_big_cc = 0;
|
||||
unsigned number_of_results_found_in_tiny_cc = 0;
|
||||
|
||||
// initialize queue with root element
|
||||
std::priority_queue<IncrementalQueryCandidate> traversal_queue;
|
||||
traversal_queue.emplace(0.f, m_search_tree[0]);
|
||||
|
||||
while (!traversal_queue.empty())
|
||||
{
|
||||
const IncrementalQueryCandidate current_query_node = traversal_queue.top();
|
||||
traversal_queue.pop();
|
||||
|
||||
++dequeues;
|
||||
|
||||
const float current_min_dist = min_found_distances[number_of_results-1];
|
||||
|
||||
if (current_query_node.min_dist > current_min_dist)
|
||||
{
|
||||
++pruned_elements;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current_query_node.RepresentsTreeNode())
|
||||
{
|
||||
const TreeNode & current_tree_node = boost::get<TreeNode>(current_query_node.node);
|
||||
if (current_tree_node.child_is_on_disk)
|
||||
{
|
||||
++loaded_leafs;
|
||||
// SimpleLogger().Write(logDEBUG) << "loading leaf: " << current_tree_node.children[0] << " w/ mbr [" <<
|
||||
// current_tree_node.minimum_bounding_rectangle.min_lat/COORDINATE_PRECISION << "," <<
|
||||
// current_tree_node.minimum_bounding_rectangle.min_lon/COORDINATE_PRECISION << "," <<
|
||||
// current_tree_node.minimum_bounding_rectangle.max_lat/COORDINATE_PRECISION << "-" <<
|
||||
// current_tree_node.minimum_bounding_rectangle.max_lon/COORDINATE_PRECISION << "]";
|
||||
|
||||
LeafNode current_leaf_node;
|
||||
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
|
||||
// Add all objects from leaf into queue
|
||||
for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
|
||||
{
|
||||
const auto ¤t_edge = current_leaf_node.objects[i];
|
||||
const float current_perpendicular_distance =
|
||||
FixedPointCoordinate::ComputePerpendicularDistance(
|
||||
m_coordinate_list->at(current_edge.u),
|
||||
m_coordinate_list->at(current_edge.v),
|
||||
input_coordinate);
|
||||
// distance must be non-negative
|
||||
BOOST_ASSERT(0. <= current_perpendicular_distance);
|
||||
|
||||
if (current_perpendicular_distance < current_min_dist)
|
||||
{
|
||||
traversal_queue.emplace(current_perpendicular_distance, current_edge);
|
||||
}
|
||||
else
|
||||
{
|
||||
++ignored_segments;
|
||||
}
|
||||
}
|
||||
// SimpleLogger().Write(logDEBUG) << "added " << current_leaf_node.object_count << " roads into queue of " << traversal_queue.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
++inspected_mbrs;
|
||||
// explore inner node
|
||||
// SimpleLogger().Write(logDEBUG) << "explore inner node w/ mbr [" <<
|
||||
// current_tree_node.minimum_bounding_rectangle.min_lat/COORDINATE_PRECISION << "," <<
|
||||
// current_tree_node.minimum_bounding_rectangle.min_lon/COORDINATE_PRECISION << "," <<
|
||||
// current_tree_node.minimum_bounding_rectangle.max_lat/COORDINATE_PRECISION << "-" <<
|
||||
// current_tree_node.minimum_bounding_rectangle.max_lon/COORDINATE_PRECISION << "," << "]";
|
||||
|
||||
// for each child mbr
|
||||
for (uint32_t i = 0; i < current_tree_node.child_count; ++i)
|
||||
{
|
||||
const int32_t child_id = current_tree_node.children[i];
|
||||
const TreeNode &child_tree_node = m_search_tree[child_id];
|
||||
const RectangleT &child_rectangle =
|
||||
child_tree_node.minimum_bounding_rectangle;
|
||||
const double current_min_dist =
|
||||
child_rectangle.GetMinDist(input_coordinate);
|
||||
const double current_min_max_dist =
|
||||
child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
if (current_min_max_dist < min_max_dist)
|
||||
const RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
||||
const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate);
|
||||
|
||||
// TODO - enough elements found, i.e. nearest distance > maximum distance?
|
||||
// ie. some measure of 'confidence of accuracy'
|
||||
|
||||
// check if it needs to be explored by mindist
|
||||
if (lower_bound_to_element < current_min_dist)
|
||||
{
|
||||
min_max_dist = current_min_max_dist;
|
||||
traversal_queue.emplace(lower_bound_to_element, child_tree_node);
|
||||
}
|
||||
if (current_min_dist > min_max_dist)
|
||||
else
|
||||
{
|
||||
continue;
|
||||
++ignored_mbrs;
|
||||
}
|
||||
if (current_min_dist > min_dist)
|
||||
{ // upward pruning
|
||||
continue;
|
||||
}
|
||||
traversal_queue.emplace(child_id, current_min_dist);
|
||||
}
|
||||
// SimpleLogger().Write(logDEBUG) << "added " << current_tree_node.child_count << " mbrs into queue of " << traversal_queue.size();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++inspected_segments;
|
||||
// inspecting an actual road segment
|
||||
const EdgeDataT & current_segment = boost::get<EdgeDataT>(current_query_node.node);
|
||||
|
||||
// don't collect too many results from small components
|
||||
if (number_of_results_found_in_big_cc == number_of_results && !current_segment.is_in_tiny_cc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't collect too many results from big components
|
||||
if (number_of_results_found_in_tiny_cc == number_of_results && current_segment.is_in_tiny_cc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if it is smaller than what we had before
|
||||
float current_ratio = 0.;
|
||||
FixedPointCoordinate foot_point_coordinate_on_segment;
|
||||
const float current_perpendicular_distance =
|
||||
FixedPointCoordinate::ComputePerpendicularDistance(
|
||||
m_coordinate_list->at(current_segment.u),
|
||||
m_coordinate_list->at(current_segment.v),
|
||||
input_coordinate,
|
||||
foot_point_coordinate_on_segment,
|
||||
current_ratio);
|
||||
|
||||
BOOST_ASSERT(0. <= current_perpendicular_distance);
|
||||
|
||||
if ((current_perpendicular_distance < current_min_dist) &&
|
||||
!EpsilonCompare(current_perpendicular_distance, current_min_dist))
|
||||
{
|
||||
// store phantom node in result vector
|
||||
result_phantom_node_vector.emplace_back(
|
||||
current_segment.forward_edge_based_node_id,
|
||||
current_segment.reverse_edge_based_node_id,
|
||||
current_segment.name_id,
|
||||
current_segment.forward_weight,
|
||||
current_segment.reverse_weight,
|
||||
current_segment.forward_offset,
|
||||
current_segment.reverse_offset,
|
||||
current_segment.packed_geometry_id,
|
||||
foot_point_coordinate_on_segment,
|
||||
current_segment.fwd_segment_position);
|
||||
|
||||
// Hack to fix rounding errors and wandering via nodes.
|
||||
FixUpRoundingIssue(input_coordinate, result_phantom_node_vector.back());
|
||||
|
||||
// set forward and reverse weights on the phantom node
|
||||
SetForwardAndReverseWeightsOnPhantomNode(current_segment,
|
||||
result_phantom_node_vector.back());
|
||||
|
||||
// do we have results only in a small scc
|
||||
if (current_segment.is_in_tiny_cc)
|
||||
{
|
||||
++number_of_results_found_in_tiny_cc;
|
||||
}
|
||||
else
|
||||
{
|
||||
// found an element in a large component
|
||||
min_found_distances[number_of_results_found_in_big_cc] = current_perpendicular_distance;
|
||||
++number_of_results_found_in_big_cc;
|
||||
// SimpleLogger().Write(logDEBUG) << std::setprecision(8) << foot_point_coordinate_on_segment << " at " << current_perpendicular_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add indicator to prune if maxdist > threshold
|
||||
if (number_of_results == number_of_results_found_in_big_cc || inspected_segments >= max_checked_segments)
|
||||
{
|
||||
// SimpleLogger().Write(logDEBUG) << "flushing queue of " << traversal_queue.size() << " elements";
|
||||
// work-around for traversal_queue.clear();
|
||||
traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
|
||||
}
|
||||
}
|
||||
|
||||
return found_a_nearest_edge;
|
||||
// for (const PhantomNode& result_node : result_phantom_node_vector)
|
||||
// {
|
||||
// SimpleLogger().Write(logDEBUG) << std::setprecision(8) << "found location " << result_node.forward_node_id << " at " << result_node.location;
|
||||
// }
|
||||
// SimpleLogger().Write(logDEBUG) << "dequeues: " << dequeues;
|
||||
// SimpleLogger().Write(logDEBUG) << "inspected_mbrs: " << inspected_mbrs;
|
||||
// SimpleLogger().Write(logDEBUG) << "loaded_leafs: " << loaded_leafs;
|
||||
// SimpleLogger().Write(logDEBUG) << "inspected_segments: " << inspected_segments;
|
||||
// SimpleLogger().Write(logDEBUG) << "pruned_elements: " << pruned_elements;
|
||||
// SimpleLogger().Write(logDEBUG) << "ignored_segments: " << ignored_segments;
|
||||
// SimpleLogger().Write(logDEBUG) << "ignored_mbrs: " << ignored_mbrs;
|
||||
|
||||
// SimpleLogger().Write(logDEBUG) << "number_of_results_found_in_big_cc: " << number_of_results_found_in_big_cc;
|
||||
// SimpleLogger().Write(logDEBUG) << "number_of_results_found_in_tiny_cc: " << number_of_results_found_in_tiny_cc;
|
||||
// TIMER_STOP(samet);
|
||||
// SimpleLogger().Write() << "query took " << TIMER_MSEC(samet) << "ms";
|
||||
|
||||
// if we found an element in either category, then we are good
|
||||
return !result_phantom_node_vector.empty();
|
||||
}
|
||||
|
||||
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &result_phantom_node,
|
||||
const unsigned zoom_level)
|
||||
{
|
||||
// SimpleLogger().Write() << "searching for coordinate " << input_coordinate;
|
||||
|
||||
std::vector<PhantomNode> result_phantom_node_vector;
|
||||
IncrementalFindPhantomNodeForCoordinate(input_coordinate, result_phantom_node_vector, zoom_level, 2);
|
||||
// if (!result_phantom_node_vector.empty())
|
||||
// {
|
||||
// result_phantom_node = result_phantom_node_vector.front();
|
||||
// }
|
||||
// return !result_phantom_node_vector.empty();
|
||||
|
||||
const bool ignore_tiny_components = (zoom_level <= 14);
|
||||
DataT nearest_edge;
|
||||
EdgeDataT nearest_edge;
|
||||
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
double min_max_dist = std::numeric_limits<double>::max();
|
||||
bool found_a_nearest_edge = false;
|
||||
float min_dist = std::numeric_limits<float>::max();
|
||||
float min_max_dist = std::numeric_limits<float>::max();
|
||||
|
||||
FixedPointCoordinate nearest, current_start_coordinate, current_end_coordinate;
|
||||
|
||||
// initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
double current_min_dist =
|
||||
m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
|
||||
traversal_queue.emplace(0, current_min_dist);
|
||||
traversal_queue.emplace(0.f, 0);
|
||||
|
||||
BOOST_ASSERT_MSG(std::numeric_limits<double>::epsilon() >
|
||||
(0. - traversal_queue.top().min_dist),
|
||||
"Root element in NN Search has min dist != 0.");
|
||||
|
||||
LeafNode current_leaf_node;
|
||||
while (!traversal_queue.empty())
|
||||
{
|
||||
const QueryCandidate current_query_node = traversal_queue.top();
|
||||
traversal_queue.pop();
|
||||
|
||||
const bool prune_downward = (current_query_node.min_dist >= min_max_dist);
|
||||
const bool prune_upward = (current_query_node.min_dist >= min_dist);
|
||||
const bool prune_downward = (current_query_node.min_dist > min_max_dist);
|
||||
const bool prune_upward = (current_query_node.min_dist > min_dist);
|
||||
if (!prune_downward && !prune_upward)
|
||||
{ // downward pruning
|
||||
const TreeNode ¤t_tree_node = m_search_tree[current_query_node.node_id];
|
||||
if (current_tree_node.child_is_on_disk)
|
||||
{
|
||||
LeafNode current_leaf_node;
|
||||
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
|
||||
for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
|
||||
{
|
||||
DataT ¤t_edge = current_leaf_node.objects[i];
|
||||
const EdgeDataT ¤t_edge = current_leaf_node.objects[i];
|
||||
if (ignore_tiny_components && current_edge.is_in_tiny_cc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double current_ratio = 0.;
|
||||
const double current_perpendicular_distance =
|
||||
float current_ratio = 0.;
|
||||
FixedPointCoordinate nearest;
|
||||
const float current_perpendicular_distance =
|
||||
FixedPointCoordinate::ComputePerpendicularDistance(
|
||||
m_coordinate_list->at(current_edge.u),
|
||||
m_coordinate_list->at(current_edge.v),
|
||||
@@ -647,102 +891,110 @@ class StaticRTree
|
||||
BOOST_ASSERT(0. <= current_perpendicular_distance);
|
||||
|
||||
if ((current_perpendicular_distance < min_dist) &&
|
||||
!DoubleEpsilonCompare(current_perpendicular_distance, min_dist))
|
||||
!EpsilonCompare(current_perpendicular_distance, min_dist))
|
||||
{ // found a new minimum
|
||||
min_dist = current_perpendicular_distance;
|
||||
// TODO: use assignment c'tor in PhantomNode
|
||||
result_phantom_node.forward_node_id =
|
||||
current_edge.forward_edge_based_node_id;
|
||||
result_phantom_node.reverse_node_id =
|
||||
current_edge.reverse_edge_based_node_id;
|
||||
result_phantom_node.name_id = current_edge.name_id;
|
||||
result_phantom_node.forward_weight = current_edge.forward_weight;
|
||||
result_phantom_node.reverse_weight = current_edge.reverse_weight;
|
||||
result_phantom_node.forward_offset = current_edge.forward_offset;
|
||||
result_phantom_node.reverse_offset = current_edge.reverse_offset;
|
||||
result_phantom_node.packed_geometry_id =
|
||||
current_edge.packed_geometry_id;
|
||||
result_phantom_node.fwd_segment_position =
|
||||
current_edge.fwd_segment_position;
|
||||
|
||||
result_phantom_node.location = nearest;
|
||||
current_start_coordinate.lat =
|
||||
m_coordinate_list->at(current_edge.u).lat;
|
||||
current_start_coordinate.lon =
|
||||
m_coordinate_list->at(current_edge.u).lon;
|
||||
current_end_coordinate.lat = m_coordinate_list->at(current_edge.v).lat;
|
||||
current_end_coordinate.lon = m_coordinate_list->at(current_edge.v).lon;
|
||||
result_phantom_node = {current_edge.forward_edge_based_node_id,
|
||||
current_edge.reverse_edge_based_node_id,
|
||||
current_edge.name_id,
|
||||
current_edge.forward_weight,
|
||||
current_edge.reverse_weight,
|
||||
current_edge.forward_offset,
|
||||
current_edge.reverse_offset,
|
||||
current_edge.packed_geometry_id,
|
||||
nearest,
|
||||
current_edge.fwd_segment_position};
|
||||
nearest_edge = current_edge;
|
||||
found_a_nearest_edge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// traverse children, prune if global mindist is smaller than local one
|
||||
for (uint32_t i = 0; i < current_tree_node.child_count; ++i)
|
||||
{
|
||||
const int32_t child_id = current_tree_node.children[i];
|
||||
TreeNode &child_tree_node = m_search_tree[child_id];
|
||||
RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
||||
const double current_min_dist =
|
||||
child_rectangle.GetMinDist(input_coordinate);
|
||||
const double current_min_max_dist =
|
||||
child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
if (current_min_max_dist < min_max_dist)
|
||||
{
|
||||
min_max_dist = current_min_max_dist;
|
||||
}
|
||||
if (current_min_dist > min_max_dist)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (current_min_dist > min_dist)
|
||||
{ // upward pruning
|
||||
continue;
|
||||
}
|
||||
traversal_queue.emplace(child_id, current_min_dist);
|
||||
}
|
||||
min_max_dist = ExploreTreeNode(current_tree_node,
|
||||
input_coordinate,
|
||||
min_dist,
|
||||
min_max_dist,
|
||||
traversal_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hack to fix rounding errors and wandering via nodes.
|
||||
if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon))
|
||||
if (result_phantom_node.location.isValid())
|
||||
{
|
||||
result_phantom_node.location.lon = input_coordinate.lon;
|
||||
// Hack to fix rounding errors and wandering via nodes.
|
||||
FixUpRoundingIssue(input_coordinate, result_phantom_node);
|
||||
|
||||
// set forward and reverse weights on the phantom node
|
||||
SetForwardAndReverseWeightsOnPhantomNode(nearest_edge, result_phantom_node);
|
||||
}
|
||||
if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat))
|
||||
{
|
||||
result_phantom_node.location.lat = input_coordinate.lat;
|
||||
}
|
||||
|
||||
double ratio = 0.;
|
||||
|
||||
if (found_a_nearest_edge)
|
||||
{
|
||||
const double distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
current_start_coordinate, result_phantom_node.location);
|
||||
|
||||
const double distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
current_start_coordinate, current_end_coordinate);
|
||||
|
||||
ratio = distance_1 / distance_2;
|
||||
ratio = std::min(1., ratio);
|
||||
|
||||
if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
|
||||
{
|
||||
result_phantom_node.forward_weight *= ratio;
|
||||
}
|
||||
if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
|
||||
{
|
||||
result_phantom_node.reverse_weight *= (1. - ratio);
|
||||
}
|
||||
}
|
||||
return found_a_nearest_edge;
|
||||
return result_phantom_node.location.isValid();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline void SetForwardAndReverseWeightsOnPhantomNode(const EdgeDataT & nearest_edge,
|
||||
PhantomNode &result_phantom_node) const
|
||||
{
|
||||
const float distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
m_coordinate_list->at(nearest_edge.u), result_phantom_node.location);
|
||||
const float distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
|
||||
m_coordinate_list->at(nearest_edge.u), m_coordinate_list->at(nearest_edge.v));
|
||||
const float ratio = std::min(1.f, distance_1 / distance_2);
|
||||
|
||||
if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
|
||||
{
|
||||
result_phantom_node.forward_weight *= ratio;
|
||||
}
|
||||
if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
|
||||
{
|
||||
result_phantom_node.reverse_weight *= (1.f - ratio);
|
||||
}
|
||||
}
|
||||
|
||||
// fixup locations if too close to inputs
|
||||
inline void FixUpRoundingIssue(const FixedPointCoordinate &input_coordinate,
|
||||
PhantomNode &result_phantom_node) const
|
||||
{
|
||||
if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon))
|
||||
{
|
||||
result_phantom_node.location.lon = input_coordinate.lon;
|
||||
}
|
||||
if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat))
|
||||
{
|
||||
result_phantom_node.location.lat = input_coordinate.lat;
|
||||
}
|
||||
}
|
||||
|
||||
template <class QueueT>
|
||||
inline float ExploreTreeNode(const TreeNode &parent,
|
||||
const FixedPointCoordinate &input_coordinate,
|
||||
const float min_dist,
|
||||
const float min_max_dist,
|
||||
QueueT &traversal_queue)
|
||||
{
|
||||
float new_min_max_dist = min_max_dist;
|
||||
// traverse children, prune if global mindist is smaller than local one
|
||||
for (uint32_t i = 0; i < parent.child_count; ++i)
|
||||
{
|
||||
const int32_t child_id = parent.children[i];
|
||||
const TreeNode &child_tree_node = m_search_tree[child_id];
|
||||
const RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
|
||||
const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate);
|
||||
const float upper_bound_to_element = child_rectangle.GetMinMaxDist(input_coordinate);
|
||||
new_min_max_dist = std::min(new_min_max_dist, upper_bound_to_element);
|
||||
if (lower_bound_to_element > new_min_max_dist)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (lower_bound_to_element > min_dist)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
traversal_queue.emplace(lower_bound_to_element, child_id);
|
||||
}
|
||||
return new_min_max_dist;
|
||||
}
|
||||
|
||||
inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode &result_node)
|
||||
{
|
||||
if (!thread_local_rtree_stream.get() || !thread_local_rtree_stream->is_open())
|
||||
@@ -755,9 +1007,12 @@ class StaticRTree
|
||||
thread_local_rtree_stream->clear(std::ios::goodbit);
|
||||
SimpleLogger().Write(logDEBUG) << "Resetting stale filestream";
|
||||
}
|
||||
uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
|
||||
const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
|
||||
thread_local_rtree_stream->seekg(seek_pos);
|
||||
BOOST_ASSERT_MSG(thread_local_rtree_stream->good(),
|
||||
"Seeking to position in leaf file failed.");
|
||||
thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode));
|
||||
BOOST_ASSERT_MSG(thread_local_rtree_stream->good(), "Reading from leaf file failed.");
|
||||
}
|
||||
|
||||
inline bool EdgesAreEquivalent(const FixedPointCoordinate &a,
|
||||
@@ -768,13 +1023,14 @@ class StaticRTree
|
||||
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
|
||||
}
|
||||
|
||||
inline bool DoubleEpsilonCompare(const double d1, const double d2) const
|
||||
template <typename FloatT> inline bool EpsilonCompare(const FloatT d1, const FloatT d2) const
|
||||
{
|
||||
return (std::abs(d1 - d2) < std::numeric_limits<double>::epsilon());
|
||||
return (std::abs(d1 - d2) < std::numeric_limits<FloatT>::epsilon());
|
||||
}
|
||||
};
|
||||
|
||||
//[1] "On Packing R-Trees"; I. Kamel, C. Faloutsos; 1993; DOI: 10.1145/170088.170403
|
||||
//[2] "Nearest Neighbor Queries", N. Roussopulos et al; 1995; DOI: 10.1145/223784.223794
|
||||
|
||||
//[3] "Distance Browsing in Spatial Databases"; G. Hjaltason, H. Samet; 1999; ACM Trans. DB Sys
|
||||
// Vol.24 No.2, pp.265-318
|
||||
#endif // STATICRTREE_H
|
||||
|
||||
@@ -80,7 +80,9 @@ struct TurnInstructionsClass
|
||||
static inline bool TurnIsNecessary(const TurnInstruction turn_instruction)
|
||||
{
|
||||
if (TurnInstruction::NoTurn == turn_instruction || TurnInstruction::StayOnRoundAbout == turn_instruction)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -54,10 +54,7 @@ template <class DataFacadeT> class BaseDescriptor
|
||||
BaseDescriptor() {}
|
||||
// Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BaseDescriptor() {}
|
||||
virtual void Run(const RawRouteData &raw_route,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
DataFacadeT *facade,
|
||||
http::Reply &reply) = 0;
|
||||
virtual void Run(const RawRouteData &raw_route, http::Reply &reply) = 0;
|
||||
virtual void SetConfig(const DescriptorConfig &config) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -27,54 +27,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "DescriptionFactory.h"
|
||||
|
||||
DescriptionFactory::DescriptionFactory() : entireLength(0) {}
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
DescriptionFactory::~DescriptionFactory() {}
|
||||
#include "../typedefs.h"
|
||||
#include "../Algorithms/PolylineCompressor.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
|
||||
inline double DescriptionFactory::DegreeToRadian(const double degree) const
|
||||
{
|
||||
return degree * (M_PI / 180.);
|
||||
}
|
||||
DescriptionFactory::DescriptionFactory() : entireLength(0) { via_indices.push_back(0); }
|
||||
|
||||
inline double DescriptionFactory::RadianToDegree(const double radian) const
|
||||
{
|
||||
return radian * (180. / M_PI);
|
||||
}
|
||||
std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }
|
||||
|
||||
double DescriptionFactory::GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B)
|
||||
const
|
||||
{
|
||||
double delta_long = DegreeToRadian(B.lon / COORDINATE_PRECISION - A.lon / COORDINATE_PRECISION);
|
||||
|
||||
const double lat1 = DegreeToRadian(A.lat / COORDINATE_PRECISION);
|
||||
const double lat2 = DegreeToRadian(B.lat / COORDINATE_PRECISION);
|
||||
|
||||
const double y = sin(delta_long) * cos(lat2);
|
||||
const double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_long);
|
||||
double result = RadianToDegree(atan2(y, x));
|
||||
while (result < 0.)
|
||||
{
|
||||
result += 360.;
|
||||
}
|
||||
|
||||
while (result >= 360.)
|
||||
{
|
||||
result -= 360.;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetStartSegment(const PhantomNode &source)
|
||||
void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool traversed_in_reverse)
|
||||
{
|
||||
start_phantom = source;
|
||||
AppendSegment(source.location, PathData(0, source.name_id, TurnInstruction::HeadOn, source.forward_weight));
|
||||
const EdgeWeight segment_duration =
|
||||
(traversed_in_reverse ? source.reverse_weight : source.forward_weight);
|
||||
AppendSegment(source.location,
|
||||
PathData(0, source.name_id, TurnInstruction::HeadOn, segment_duration));
|
||||
BOOST_ASSERT(path_description.back().duration == segment_duration);
|
||||
}
|
||||
|
||||
void DescriptionFactory::SetEndSegment(const PhantomNode &target)
|
||||
void DescriptionFactory::SetEndSegment(const PhantomNode &target, const bool traversed_in_reverse)
|
||||
{
|
||||
target_phantom = target;
|
||||
const EdgeWeight segment_duration =
|
||||
(traversed_in_reverse ? target.reverse_weight : target.forward_weight);
|
||||
path_description.emplace_back(
|
||||
target.location, target.name_id, 0, target.reverse_weight, TurnInstruction::NoTurn, true);
|
||||
target.location, target.name_id, segment_duration, 0.f, TurnInstruction::NoTurn, true, true);
|
||||
BOOST_ASSERT(path_description.back().duration == segment_duration);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
|
||||
@@ -83,49 +66,28 @@ void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
|
||||
if ((1 == path_description.size()) && (path_description.back().location == coordinate))
|
||||
{
|
||||
path_description.back().name_id = path_point.name_id;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
path_description.emplace_back(coordinate,
|
||||
path_point.name_id,
|
||||
path_point.segment_duration,
|
||||
0,
|
||||
path_point.turn_instruction);
|
||||
}
|
||||
|
||||
path_description.emplace_back(coordinate,
|
||||
path_point.name_id,
|
||||
path_point.segment_duration,
|
||||
0,
|
||||
path_point.turn_instruction);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded,
|
||||
std::vector<std::string> &output)
|
||||
JSON::Value DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded)
|
||||
{
|
||||
std::string temp;
|
||||
if (return_encoded)
|
||||
{
|
||||
polyline_compressor.printEncodedString(path_description, temp);
|
||||
return polyline_compressor.printEncodedString(path_description);
|
||||
}
|
||||
else
|
||||
{
|
||||
polyline_compressor.printUnencodedString(path_description, temp);
|
||||
}
|
||||
output.emplace_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(std::vector<std::string> &output) const
|
||||
{
|
||||
std::string temp;
|
||||
polyline_compressor.printEncodedString(path_description, temp);
|
||||
output.emplace_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendUnencodedPolylineString(std::vector<std::string> &output) const
|
||||
{
|
||||
std::string temp;
|
||||
polyline_compressor.printUnencodedString(path_description, temp);
|
||||
output.emplace_back(temp);
|
||||
return polyline_compressor.printUnencodedString(path_description);
|
||||
}
|
||||
|
||||
void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
|
||||
{
|
||||
summary.startName = start_phantom.name_id;
|
||||
summary.destName = target_phantom.name_id;
|
||||
summary.source_name_id = start_phantom.name_id;
|
||||
summary.target_name_id = target_phantom.name_id;
|
||||
summary.BuildDurationAndLengthStrings(distance, time);
|
||||
}
|
||||
|
||||
@@ -31,10 +31,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../Algorithms/DouglasPeucker.h"
|
||||
#include "../Algorithms/PolylineCompressor.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../DataStructures/RawRouteData.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
@@ -42,6 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
struct PathData;
|
||||
/* This class is fed with all way segments in consecutive order
|
||||
* and produces the description plus the encoded polyline */
|
||||
|
||||
@@ -54,21 +53,22 @@ class DescriptionFactory
|
||||
double DegreeToRadian(const double degree) const;
|
||||
double RadianToDegree(const double degree) const;
|
||||
|
||||
std::vector<unsigned> via_indices;
|
||||
|
||||
public:
|
||||
struct RouteSummary
|
||||
{
|
||||
std::string lengthString;
|
||||
std::string durationString;
|
||||
unsigned startName;
|
||||
unsigned destName;
|
||||
RouteSummary() : lengthString("0"), durationString("0"), startName(0), destName(0) {}
|
||||
unsigned distance;
|
||||
EdgeWeight duration;
|
||||
unsigned source_name_id;
|
||||
unsigned target_name_id;
|
||||
RouteSummary() : distance(0), duration(0), source_name_id(0), target_name_id(0) {}
|
||||
|
||||
void BuildDurationAndLengthStrings(const double distance, const unsigned time)
|
||||
void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
|
||||
{
|
||||
// compute distance/duration for route summary
|
||||
intToString(round(distance), lengthString);
|
||||
int travel_time = round(time / 10.);
|
||||
intToString(std::max(travel_time, 1), durationString);
|
||||
distance = static_cast<unsigned>(round(raw_distance));
|
||||
duration = static_cast<unsigned>(round(raw_duration / 10.));
|
||||
}
|
||||
} summary;
|
||||
|
||||
@@ -77,15 +77,12 @@ class DescriptionFactory
|
||||
// I know, declaring this public is considered bad. I'm lazy
|
||||
std::vector<SegmentInformation> path_description;
|
||||
DescriptionFactory();
|
||||
virtual ~DescriptionFactory();
|
||||
double GetBearing(const FixedPointCoordinate &C, const FixedPointCoordinate &B) const;
|
||||
void AppendEncodedPolylineString(std::vector<std::string> &output) const;
|
||||
void AppendUnencodedPolylineString(std::vector<std::string> &output) const;
|
||||
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
|
||||
void BuildRouteSummary(const double distance, const unsigned time);
|
||||
void SetStartSegment(const PhantomNode &start_phantom);
|
||||
void SetEndSegment(const PhantomNode &start_phantom);
|
||||
void AppendEncodedPolylineString(const bool return_encoded, std::vector<std::string> &output);
|
||||
void SetStartSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
|
||||
void SetEndSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
|
||||
JSON::Value AppendEncodedPolylineString(const bool return_encoded);
|
||||
std::vector<unsigned> const & GetViaIndices() const;
|
||||
|
||||
template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel)
|
||||
{
|
||||
@@ -147,7 +144,7 @@ class DescriptionFactory
|
||||
// string0 = string1;
|
||||
// }
|
||||
|
||||
double segment_length = 0.;
|
||||
float segment_length = 0.;
|
||||
unsigned segment_duration = 0;
|
||||
unsigned segment_start_index = 0;
|
||||
|
||||
@@ -179,14 +176,14 @@ class DescriptionFactory
|
||||
target_phantom.name_id = (path_description.end() - 2)->name_id;
|
||||
}
|
||||
}
|
||||
if (std::numeric_limits<double>::epsilon() > path_description[0].length)
|
||||
if (std::numeric_limits<double>::epsilon() > path_description.front().length)
|
||||
{
|
||||
if (path_description.size() > 2)
|
||||
{
|
||||
path_description.erase(path_description.begin());
|
||||
path_description[0].turn_instruction = TurnInstruction::HeadOn;
|
||||
path_description[0].necessary = true;
|
||||
start_phantom.name_id = path_description[0].name_id;
|
||||
path_description.front().turn_instruction = TurnInstruction::HeadOn;
|
||||
path_description.front().necessary = true;
|
||||
start_phantom.name_id = path_description.front().name_id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,15 +191,23 @@ class DescriptionFactory
|
||||
polyline_generalizer.Run(path_description, zoomLevel);
|
||||
|
||||
// fix what needs to be fixed else
|
||||
unsigned necessary_pieces = 0; // a running index that counts the necessary pieces
|
||||
for (unsigned i = 0; i < path_description.size() - 1 && path_description.size() >= 2; ++i)
|
||||
{
|
||||
if (path_description[i].necessary)
|
||||
{
|
||||
double angle =
|
||||
GetBearing(path_description[i].location, path_description[i + 1].location);
|
||||
path_description[i].bearing = angle * 10;
|
||||
++necessary_pieces;
|
||||
if (path_description[i].is_via_location)
|
||||
{ //mark the end of a leg
|
||||
via_indices.push_back(necessary_pieces);
|
||||
}
|
||||
const double angle = path_description[i+1].location.GetBearing(path_description[i].location);
|
||||
path_description[i].bearing = static_cast<unsigned>(angle * 10);
|
||||
}
|
||||
}
|
||||
via_indices.push_back(necessary_pieces+1);
|
||||
BOOST_ASSERT(via_indices.size() >= 2);
|
||||
// BOOST_ASSERT(0 != necessary_pieces || path_description.empty());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
+42
-39
@@ -35,63 +35,66 @@ template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFac
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
FixedPointCoordinate current;
|
||||
DataFacadeT * facade;
|
||||
|
||||
std::string tmp;
|
||||
void AddRoutePoint(const FixedPointCoordinate & coordinate, std::vector<char> & output)
|
||||
{
|
||||
const std::string route_point_head = "<rtept lat=\"";
|
||||
const std::string route_point_middle = " lon=\"";
|
||||
const std::string route_point_tail = "\"></rtept>";
|
||||
|
||||
std::string tmp;
|
||||
|
||||
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
|
||||
output.insert(output.end(), route_point_head.begin(), route_point_head.end());
|
||||
output.insert(output.end(), tmp.begin(), tmp.end());
|
||||
output.push_back('\"');
|
||||
|
||||
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
|
||||
output.insert(output.end(), route_point_middle.begin(), route_point_middle.end());
|
||||
output.insert(output.end(), tmp.begin(), tmp.end());
|
||||
output.insert(output.end(), route_point_tail.begin(), route_point_tail.end());
|
||||
}
|
||||
|
||||
public:
|
||||
GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
|
||||
|
||||
void SetConfig(const DescriptorConfig &c) { config = c; }
|
||||
|
||||
// TODO: reorder parameters
|
||||
void Run(const RawRouteData &raw_route,
|
||||
const PhantomNodes &phantom_node_list,
|
||||
DataFacadeT *facade,
|
||||
http::Reply &reply)
|
||||
void Run(const RawRouteData &raw_route, http::Reply &reply)
|
||||
{
|
||||
reply.content.emplace_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content.emplace_back("<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
|
||||
"xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
||||
"\">");
|
||||
reply.content.emplace_back("<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
|
||||
" OpenStreetMap contributors (ODbL)</license></copyright>"
|
||||
"</metadata>");
|
||||
reply.content.emplace_back("<rte>");
|
||||
bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
|
||||
(!raw_route.unpacked_path_segments.front().empty());
|
||||
std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
|
||||
"xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
||||
"\">"
|
||||
"<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
|
||||
" OpenStreetMap contributors (ODbL)</license></copyright>"
|
||||
"</metadata>"
|
||||
"<rte>");
|
||||
reply.content.insert(reply.content.end(), header.begin(), header.end());
|
||||
const bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
|
||||
(!raw_route.unpacked_path_segments.front().empty());
|
||||
if (found_route)
|
||||
{
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.source_phantom.location.lat, tmp);
|
||||
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.source_phantom.location.lon, tmp);
|
||||
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
|
||||
AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location, reply.content);
|
||||
|
||||
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
|
||||
{
|
||||
for (const PathData &path_data : path_data_vector)
|
||||
{
|
||||
FixedPointCoordinate current_coordinate =
|
||||
const FixedPointCoordinate current_coordinate =
|
||||
facade->GetCoordinateOfNode(path_data.node);
|
||||
|
||||
FixedPointCoordinate::convertInternalLatLonToString(current_coordinate.lat,
|
||||
tmp);
|
||||
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(current_coordinate.lon,
|
||||
tmp);
|
||||
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
|
||||
AddRoutePoint(current_coordinate, reply.content);
|
||||
}
|
||||
}
|
||||
// Add the via point or the end coordinate
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.target_phantom.location.lat, tmp);
|
||||
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.target_phantom.location.lon, tmp);
|
||||
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
|
||||
AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location, reply.content);
|
||||
|
||||
}
|
||||
reply.content.emplace_back("</rte></gpx>");
|
||||
std::string footer("</rte></gpx>");
|
||||
reply.content.insert(reply.content.end(), footer.begin(), footer.end());
|
||||
}
|
||||
};
|
||||
#endif // GPX_DESCRIPTOR_H
|
||||
|
||||
+385
-524
@@ -1,524 +1,385 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef JSON_DESCRIPTOR_H_
|
||||
#define JSON_DESCRIPTOR_H_
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
#include "DescriptionFactory.h"
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/Azimuth.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
// TODO: initalize in c'tor
|
||||
DataFacadeT *facade;
|
||||
DescriptorConfig config;
|
||||
DescriptionFactory description_factory;
|
||||
DescriptionFactory alternate_descriptionFactory;
|
||||
FixedPointCoordinate current;
|
||||
unsigned entered_restricted_area_count;
|
||||
struct RoundAbout
|
||||
{
|
||||
RoundAbout() : start_index(INT_MAX), name_id(INT_MAX), leave_at_exit(INT_MAX) {}
|
||||
int start_index;
|
||||
int name_id;
|
||||
int leave_at_exit;
|
||||
} round_about;
|
||||
|
||||
struct Segment
|
||||
{
|
||||
Segment() : name_id(-1), length(-1), position(-1) {}
|
||||
Segment(int n, int l, int p) : name_id(n), length(l), position(p) {}
|
||||
int name_id;
|
||||
int length;
|
||||
int position;
|
||||
};
|
||||
std::vector<Segment> shortest_path_segments, alternative_path_segments;
|
||||
std::vector<unsigned> shortest_leg_end_indices, alternative_leg_end_indices;
|
||||
|
||||
struct RouteNames
|
||||
{
|
||||
std::string shortest_path_name_1;
|
||||
std::string shortest_path_name_2;
|
||||
std::string alternative_path_name_1;
|
||||
std::string alternative_path_name_2;
|
||||
};
|
||||
|
||||
public:
|
||||
JSONDescriptor() : facade(nullptr), entered_restricted_area_count(0)
|
||||
{
|
||||
shortest_leg_end_indices.emplace_back(0);
|
||||
alternative_leg_end_indices.emplace_back(0);
|
||||
}
|
||||
|
||||
void SetConfig(const DescriptorConfig &c) { config = c; }
|
||||
|
||||
unsigned DescribeLeg(const std::vector<PathData> route_leg, const PhantomNodes &leg_phantoms)
|
||||
{
|
||||
unsigned added_element_count = 0;
|
||||
// Get all the coordinates for the computed route
|
||||
FixedPointCoordinate current_coordinate;
|
||||
for (const PathData &path_data : route_leg)
|
||||
{
|
||||
current_coordinate = facade->GetCoordinateOfNode(path_data.node);
|
||||
description_factory.AppendSegment(current_coordinate, path_data);
|
||||
++added_element_count;
|
||||
}
|
||||
++added_element_count;
|
||||
BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
|
||||
return added_element_count;
|
||||
}
|
||||
|
||||
void Run(const RawRouteData &raw_route,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
// TODO: move facade initalization to c'tor
|
||||
DataFacadeT *f,
|
||||
http::Reply &reply)
|
||||
{
|
||||
facade = f;
|
||||
reply.content.emplace_back("{\"status\":");
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
// We do not need to do much, if there is no route ;-)
|
||||
reply.content.emplace_back(
|
||||
"207,\"status_message\": \"Cannot find route between points\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "distance: " << raw_route.shortest_path_length;
|
||||
|
||||
// check if first segment is non-zero
|
||||
std::string road_name =
|
||||
facade->GetEscapedNameForNameID(phantom_nodes.source_phantom.name_id);
|
||||
|
||||
BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
|
||||
raw_route.segment_end_coordinates.size());
|
||||
|
||||
description_factory.SetStartSegment(phantom_nodes.source_phantom);
|
||||
reply.content.emplace_back("0,"
|
||||
"\"status_message\": \"Found route between points\",");
|
||||
|
||||
// for each unpacked segment add the leg to the description
|
||||
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
|
||||
{
|
||||
const int added_segments = DescribeLeg(raw_route.unpacked_path_segments[i],
|
||||
raw_route.segment_end_coordinates[i]);
|
||||
BOOST_ASSERT(0 < added_segments);
|
||||
shortest_leg_end_indices.emplace_back(added_segments + shortest_leg_end_indices.back());
|
||||
}
|
||||
description_factory.SetEndSegment(phantom_nodes.target_phantom);
|
||||
description_factory.Run(facade, config.zoom_level);
|
||||
|
||||
reply.content.emplace_back("\"route_geometry\": ");
|
||||
if (config.geometry)
|
||||
{
|
||||
description_factory.AppendEncodedPolylineString(config.encode_geometry, reply.content);
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.content.emplace_back("[]");
|
||||
}
|
||||
|
||||
reply.content.emplace_back(",\"route_instructions\": [");
|
||||
if (config.instructions)
|
||||
{
|
||||
BuildTextualDescription(description_factory,
|
||||
reply,
|
||||
raw_route.shortest_path_length,
|
||||
facade,
|
||||
shortest_path_segments);
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
description_factory.BuildRouteSummary(description_factory.entireLength,
|
||||
raw_route.shortest_path_length);
|
||||
|
||||
reply.content.emplace_back("\"route_summary\":");
|
||||
reply.content.emplace_back("{");
|
||||
reply.content.emplace_back("\"total_distance\":");
|
||||
reply.content.emplace_back(description_factory.summary.lengthString);
|
||||
reply.content.emplace_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.emplace_back(description_factory.summary.durationString);
|
||||
reply.content.emplace_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.startName));
|
||||
reply.content.emplace_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.destName));
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back("}");
|
||||
reply.content.emplace_back(",");
|
||||
|
||||
// only one alternative route is computed at this time, so this is hardcoded
|
||||
if (raw_route.alternative_path_length != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
alternate_descriptionFactory.SetStartSegment(phantom_nodes.source_phantom);
|
||||
// Get all the coordinates for the computed route
|
||||
for (const PathData &path_data : raw_route.unpacked_alternative)
|
||||
{
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
alternate_descriptionFactory.AppendSegment(current, path_data);
|
||||
}
|
||||
}
|
||||
alternate_descriptionFactory.Run(facade, config.zoom_level);
|
||||
|
||||
// //give an array of alternative routes
|
||||
reply.content.emplace_back("\"alternative_geometries\": [");
|
||||
if (config.geometry && INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
// Generate the linestrings for each alternative
|
||||
alternate_descriptionFactory.AppendEncodedPolylineString(config.encode_geometry,
|
||||
reply.content);
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"alternative_instructions\":[");
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
reply.content.emplace_back("[");
|
||||
// Generate instructions for each alternative
|
||||
if (config.instructions)
|
||||
{
|
||||
BuildTextualDescription(alternate_descriptionFactory,
|
||||
reply,
|
||||
raw_route.alternative_path_length,
|
||||
facade,
|
||||
alternative_path_segments);
|
||||
}
|
||||
reply.content.emplace_back("]");
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"alternative_summaries\":[");
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
// Generate route summary (length, duration) for each alternative
|
||||
alternate_descriptionFactory.BuildRouteSummary(
|
||||
alternate_descriptionFactory.entireLength, raw_route.alternative_path_length);
|
||||
reply.content.emplace_back("{");
|
||||
reply.content.emplace_back("\"total_distance\":");
|
||||
reply.content.emplace_back(alternate_descriptionFactory.summary.lengthString);
|
||||
reply.content.emplace_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.emplace_back(alternate_descriptionFactory.summary.durationString);
|
||||
reply.content.emplace_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.startName));
|
||||
reply.content.emplace_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.destName));
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back("}");
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
|
||||
// //Get Names for both routes
|
||||
RouteNames routeNames;
|
||||
GetRouteNames(shortest_path_segments, alternative_path_segments, facade, routeNames);
|
||||
|
||||
reply.content.emplace_back("\"route_name\":[\"");
|
||||
reply.content.emplace_back(routeNames.shortest_path_name_1);
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(routeNames.shortest_path_name_2);
|
||||
reply.content.emplace_back("\"],"
|
||||
"\"alternative_names\":[");
|
||||
reply.content.emplace_back("[\"");
|
||||
reply.content.emplace_back(routeNames.alternative_path_name_1);
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(routeNames.alternative_path_name_2);
|
||||
reply.content.emplace_back("\"]");
|
||||
reply.content.emplace_back("],");
|
||||
// list all viapoints so that the client may display it
|
||||
reply.content.emplace_back("\"via_points\":[");
|
||||
|
||||
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
|
||||
|
||||
std::string tmp;
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.location, tmp);
|
||||
reply.content.emplace_back("[");
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back("]");
|
||||
|
||||
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
|
||||
{
|
||||
tmp.clear();
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(
|
||||
nodes.target_phantom.location, tmp);
|
||||
reply.content.emplace_back(",[");
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back("]");
|
||||
}
|
||||
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"via_indices\":[");
|
||||
for (const unsigned index : shortest_leg_end_indices)
|
||||
{
|
||||
tmp.clear();
|
||||
intToString(index, tmp);
|
||||
reply.content.emplace_back(tmp);
|
||||
if (index != shortest_leg_end_indices.back())
|
||||
{
|
||||
reply.content.emplace_back(",");
|
||||
}
|
||||
}
|
||||
reply.content.emplace_back("],\"alternative_indices\":[");
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
reply.content.emplace_back("0,");
|
||||
tmp.clear();
|
||||
intToString(alternate_descriptionFactory.path_description.size(), tmp);
|
||||
reply.content.emplace_back(tmp);
|
||||
}
|
||||
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"hint_data\": {");
|
||||
reply.content.emplace_back("\"checksum\":");
|
||||
intToString(raw_route.check_sum, tmp);
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back(", \"locations\": [");
|
||||
|
||||
std::string hint;
|
||||
for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i)
|
||||
{
|
||||
reply.content.emplace_back("\"");
|
||||
EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
|
||||
reply.content.emplace_back(hint);
|
||||
reply.content.emplace_back("\", ");
|
||||
}
|
||||
EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back(hint);
|
||||
reply.content.emplace_back("\"]");
|
||||
reply.content.emplace_back("}}");
|
||||
}
|
||||
|
||||
// construct routes names
|
||||
void GetRouteNames(std::vector<Segment> &shortest_path_segments,
|
||||
std::vector<Segment> &alternative_path_segments,
|
||||
const DataFacadeT *facade,
|
||||
RouteNames &routeNames)
|
||||
{
|
||||
Segment shortest_segment_1, shortest_segment_2;
|
||||
Segment alternativeSegment1, alternative_segment_2;
|
||||
|
||||
auto length_comperator = [](Segment a, Segment b)
|
||||
{ return a.length < b.length; };
|
||||
auto name_id_comperator = [](Segment a, Segment b)
|
||||
{ return a.name_id < b.name_id; };
|
||||
|
||||
if (!shortest_path_segments.empty())
|
||||
{
|
||||
std::sort(
|
||||
shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator);
|
||||
shortest_segment_1 = shortest_path_segments[0];
|
||||
if (!alternative_path_segments.empty())
|
||||
{
|
||||
std::sort(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
length_comperator);
|
||||
alternativeSegment1 = alternative_path_segments[0];
|
||||
}
|
||||
std::vector<Segment> shortestDifference(shortest_path_segments.size());
|
||||
std::vector<Segment> alternativeDifference(alternative_path_segments.size());
|
||||
std::set_difference(shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
shortestDifference.begin(),
|
||||
length_comperator);
|
||||
int size_of_difference = shortestDifference.size();
|
||||
if (size_of_difference)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < size_of_difference &&
|
||||
shortestDifference[i].name_id == shortest_path_segments[0].name_id)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
if (i < size_of_difference)
|
||||
{
|
||||
shortest_segment_2 = shortestDifference[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::set_difference(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
alternativeDifference.begin(),
|
||||
name_id_comperator);
|
||||
size_of_difference = alternativeDifference.size();
|
||||
if (size_of_difference)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < size_of_difference &&
|
||||
alternativeDifference[i].name_id == alternative_path_segments[0].name_id)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
if (i < size_of_difference)
|
||||
{
|
||||
alternative_segment_2 = alternativeDifference[i];
|
||||
}
|
||||
}
|
||||
if (shortest_segment_1.position > shortest_segment_2.position)
|
||||
std::swap(shortest_segment_1, shortest_segment_2);
|
||||
|
||||
if (alternativeSegment1.position > alternative_segment_2.position)
|
||||
std::swap(alternativeSegment1, alternative_segment_2);
|
||||
|
||||
routeNames.shortest_path_name_1 =
|
||||
facade->GetEscapedNameForNameID(shortest_segment_1.name_id);
|
||||
routeNames.shortest_path_name_2 =
|
||||
facade->GetEscapedNameForNameID(shortest_segment_2.name_id);
|
||||
|
||||
routeNames.alternative_path_name_1 =
|
||||
facade->GetEscapedNameForNameID(alternativeSegment1.name_id);
|
||||
routeNames.alternative_path_name_2 =
|
||||
facade->GetEscapedNameForNameID(alternative_segment_2.name_id);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: reorder parameters
|
||||
inline void BuildTextualDescription(DescriptionFactory &description_factory,
|
||||
http::Reply &reply,
|
||||
const int route_length,
|
||||
const DataFacadeT *facade,
|
||||
std::vector<Segment> &route_segments_list)
|
||||
{
|
||||
// Segment information has following format:
|
||||
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
// Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]
|
||||
unsigned necessary_segments_running_index = 0;
|
||||
round_about.leave_at_exit = 0;
|
||||
round_about.name_id = 0;
|
||||
std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
|
||||
|
||||
// Fetch data from Factory and generate a string from it.
|
||||
for (const SegmentInformation &segment : description_factory.path_description)
|
||||
{
|
||||
TurnInstruction current_instruction = segment.turn_instruction;
|
||||
entered_restricted_area_count += (current_instruction != segment.turn_instruction);
|
||||
if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
|
||||
{
|
||||
if (TurnInstruction::EnterRoundAbout == current_instruction)
|
||||
{
|
||||
round_about.name_id = segment.name_id;
|
||||
round_about.start_index = necessary_segments_running_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (necessary_segments_running_index)
|
||||
{
|
||||
reply.content.emplace_back(",");
|
||||
}
|
||||
reply.content.emplace_back("[\"");
|
||||
if (TurnInstruction::LeaveRoundAbout == current_instruction)
|
||||
{
|
||||
intToString(as_integer(TurnInstruction::EnterRoundAbout), temp_instruction);
|
||||
reply.content.emplace_back(temp_instruction);
|
||||
reply.content.emplace_back("-");
|
||||
intToString(round_about.leave_at_exit + 1, temp_instruction);
|
||||
reply.content.emplace_back(temp_instruction);
|
||||
round_about.leave_at_exit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
intToString(as_integer(current_instruction), temp_instruction);
|
||||
reply.content.emplace_back(temp_instruction);
|
||||
}
|
||||
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(facade->GetEscapedNameForNameID(segment.name_id));
|
||||
reply.content.emplace_back("\",");
|
||||
intToString(segment.length, temp_dist);
|
||||
reply.content.emplace_back(temp_dist);
|
||||
reply.content.emplace_back(",");
|
||||
intToString(necessary_segments_running_index, temp_length);
|
||||
reply.content.emplace_back(temp_length);
|
||||
reply.content.emplace_back(",");
|
||||
intToString(round(segment.duration / 10.), temp_duration);
|
||||
reply.content.emplace_back(temp_duration);
|
||||
reply.content.emplace_back(",\"");
|
||||
intToString(segment.length, temp_length);
|
||||
reply.content.emplace_back(temp_length);
|
||||
reply.content.emplace_back("m\",\"");
|
||||
int bearing_value = round(segment.bearing / 10.);
|
||||
reply.content.emplace_back(Azimuth::Get(bearing_value));
|
||||
reply.content.emplace_back("\",");
|
||||
intToString(bearing_value, temp_bearing);
|
||||
reply.content.emplace_back(temp_bearing);
|
||||
reply.content.emplace_back("]");
|
||||
|
||||
route_segments_list.emplace_back(
|
||||
Segment(segment.name_id, segment.length, route_segments_list.size()));
|
||||
}
|
||||
}
|
||||
else if (TurnInstruction::StayOnRoundAbout == current_instruction)
|
||||
{
|
||||
++round_about.leave_at_exit;
|
||||
}
|
||||
if (segment.necessary)
|
||||
{
|
||||
++necessary_segments_running_index;
|
||||
}
|
||||
}
|
||||
if (INVALID_EDGE_WEIGHT != route_length)
|
||||
{
|
||||
reply.content.emplace_back(",[\"");
|
||||
intToString(as_integer(TurnInstruction::ReachedYourDestination), temp_instruction);
|
||||
reply.content.emplace_back(temp_instruction);
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back("\",");
|
||||
reply.content.emplace_back("0");
|
||||
reply.content.emplace_back(",");
|
||||
intToString(necessary_segments_running_index - 1, temp_length);
|
||||
reply.content.emplace_back(temp_length);
|
||||
reply.content.emplace_back(",");
|
||||
reply.content.emplace_back("0");
|
||||
reply.content.emplace_back(",\"");
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(Azimuth::Get(0.0));
|
||||
reply.content.emplace_back("\",");
|
||||
reply.content.emplace_back("0.0");
|
||||
reply.content.emplace_back("]");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* JSON_DESCRIPTOR_H_ */
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef JSON_DESCRIPTOR_H_
|
||||
#define JSON_DESCRIPTOR_H_
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
#include "DescriptionFactory.h"
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../Algorithms/ExtractRouteNames.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/Azimuth.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
DescriptorConfig config;
|
||||
DescriptionFactory description_factory, alternate_description_factory;
|
||||
FixedPointCoordinate current;
|
||||
unsigned entered_restricted_area_count;
|
||||
struct RoundAbout
|
||||
{
|
||||
RoundAbout() : start_index(INT_MAX), name_id(INVALID_NAMEID), leave_at_exit(INT_MAX) {}
|
||||
int start_index;
|
||||
unsigned name_id;
|
||||
int leave_at_exit;
|
||||
} round_about;
|
||||
|
||||
struct Segment
|
||||
{
|
||||
Segment() : name_id(INVALID_NAMEID), length(-1), position(0) {}
|
||||
Segment(unsigned n, int l, unsigned p) : name_id(n), length(l), position(p) {}
|
||||
unsigned name_id;
|
||||
int length;
|
||||
unsigned position;
|
||||
};
|
||||
std::vector<Segment> shortest_path_segments, alternative_path_segments;
|
||||
ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
|
||||
|
||||
public:
|
||||
JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0) {}
|
||||
|
||||
void SetConfig(const DescriptorConfig &c) { config = c; }
|
||||
|
||||
unsigned DescribeLeg(const std::vector<PathData> route_leg,
|
||||
const PhantomNodes &leg_phantoms,
|
||||
const bool target_traversed_in_reverse)
|
||||
{
|
||||
unsigned added_element_count = 0;
|
||||
// Get all the coordinates for the computed route
|
||||
FixedPointCoordinate current_coordinate;
|
||||
for (const PathData &path_data : route_leg)
|
||||
{
|
||||
current_coordinate = facade->GetCoordinateOfNode(path_data.node);
|
||||
description_factory.AppendSegment(current_coordinate, path_data);
|
||||
++added_element_count;
|
||||
}
|
||||
description_factory.SetEndSegment(leg_phantoms.target_phantom, target_traversed_in_reverse);
|
||||
++added_element_count;
|
||||
BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
|
||||
return added_element_count;
|
||||
}
|
||||
|
||||
void Run(const RawRouteData &raw_route, http::Reply &reply)
|
||||
{
|
||||
JSON::Object json_result;
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
// We do not need to do much, if there is no route ;-)
|
||||
json_result.values["status"] = 207;
|
||||
json_result.values["status_message"] = "Cannot find route between points";
|
||||
JSON::render(reply.content, json_result);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if first segment is non-zero
|
||||
std::string road_name = facade->GetEscapedNameForNameID(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.name_id);
|
||||
|
||||
BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
|
||||
raw_route.segment_end_coordinates.size());
|
||||
|
||||
description_factory.SetStartSegment(
|
||||
raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.source_traversed_in_reverse.front());
|
||||
json_result.values["status"] = 0;
|
||||
json_result.values["status_message"] = "Found route between points";
|
||||
|
||||
// for each unpacked segment add the leg to the description
|
||||
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
const int added_segments =
|
||||
#endif
|
||||
DescribeLeg(raw_route.unpacked_path_segments[i],
|
||||
raw_route.segment_end_coordinates[i],
|
||||
raw_route.target_traversed_in_reverse[i]);
|
||||
BOOST_ASSERT(0 < added_segments);
|
||||
}
|
||||
description_factory.Run(facade, config.zoom_level);
|
||||
|
||||
if (config.geometry)
|
||||
{
|
||||
JSON::Value route_geometry =
|
||||
description_factory.AppendEncodedPolylineString(config.encode_geometry);
|
||||
json_result.values["route_geometry"] = route_geometry;
|
||||
}
|
||||
if (config.instructions)
|
||||
{
|
||||
JSON::Array json_route_instructions;
|
||||
BuildTextualDescription(description_factory,
|
||||
json_route_instructions,
|
||||
raw_route.shortest_path_length,
|
||||
shortest_path_segments);
|
||||
json_result.values["route_instructions"] = json_route_instructions;
|
||||
}
|
||||
description_factory.BuildRouteSummary(description_factory.entireLength,
|
||||
raw_route.shortest_path_length);
|
||||
JSON::Object json_route_summary;
|
||||
json_route_summary.values["total_distance"] = description_factory.summary.distance;
|
||||
json_route_summary.values["total_time"] = description_factory.summary.duration;
|
||||
json_route_summary.values["start_point"] =
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.source_name_id);
|
||||
json_route_summary.values["end_point"] =
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.target_name_id);
|
||||
json_result.values["route_summary"] = json_route_summary;
|
||||
|
||||
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
|
||||
|
||||
JSON::Array json_via_points_array;
|
||||
JSON::Array json_first_coordinate;
|
||||
json_first_coordinate.values.push_back(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.location.lat /
|
||||
COORDINATE_PRECISION);
|
||||
json_first_coordinate.values.push_back(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.location.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_first_coordinate);
|
||||
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
|
||||
{
|
||||
std::string tmp;
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(nodes.target_phantom.location.lat /
|
||||
COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(nodes.target_phantom.location.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_coordinate);
|
||||
}
|
||||
json_result.values["via_points"] = json_via_points_array;
|
||||
|
||||
JSON::Array json_via_indices_array;
|
||||
|
||||
std::vector<unsigned> const &shortest_leg_end_indices = description_factory.GetViaIndices();
|
||||
json_via_indices_array.values.insert(json_via_indices_array.values.end(),
|
||||
shortest_leg_end_indices.begin(),
|
||||
shortest_leg_end_indices.end());
|
||||
json_result.values["via_indices"] = json_via_indices_array;
|
||||
|
||||
// only one alternative route is computed at this time, so this is hardcoded
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
json_result.values["found_alternative"] = JSON::True();
|
||||
BOOST_ASSERT(!raw_route.alt_source_traversed_in_reverse.empty());
|
||||
alternate_description_factory.SetStartSegment(
|
||||
raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.alt_source_traversed_in_reverse.front());
|
||||
// Get all the coordinates for the computed route
|
||||
for (const PathData &path_data : raw_route.unpacked_alternative)
|
||||
{
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
alternate_description_factory.AppendSegment(current, path_data);
|
||||
}
|
||||
alternate_description_factory.Run(facade, config.zoom_level);
|
||||
|
||||
if (config.geometry)
|
||||
{
|
||||
JSON::Value alternate_geometry_string =
|
||||
alternate_description_factory.AppendEncodedPolylineString(
|
||||
config.encode_geometry);
|
||||
JSON::Array json_alternate_geometries_array;
|
||||
json_alternate_geometries_array.values.push_back(alternate_geometry_string);
|
||||
json_result.values["alternative_geometries"] = json_alternate_geometries_array;
|
||||
}
|
||||
// Generate instructions for each alternative (simulated here)
|
||||
JSON::Array json_alt_instructions;
|
||||
JSON::Array json_current_alt_instructions;
|
||||
if (config.instructions)
|
||||
{
|
||||
BuildTextualDescription(alternate_description_factory,
|
||||
json_current_alt_instructions,
|
||||
raw_route.alternative_path_length,
|
||||
alternative_path_segments);
|
||||
json_alt_instructions.values.push_back(json_current_alt_instructions);
|
||||
json_result.values["alternative_instructions"] = json_alt_instructions;
|
||||
}
|
||||
alternate_description_factory.BuildRouteSummary(
|
||||
alternate_description_factory.entireLength, raw_route.alternative_path_length);
|
||||
|
||||
JSON::Object json_alternate_route_summary;
|
||||
JSON::Array json_alternate_route_summary_array;
|
||||
json_alternate_route_summary.values["total_distance"] =
|
||||
alternate_description_factory.summary.distance;
|
||||
json_alternate_route_summary.values["total_time"] =
|
||||
alternate_description_factory.summary.duration;
|
||||
json_alternate_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(
|
||||
alternate_description_factory.summary.source_name_id);
|
||||
json_alternate_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(
|
||||
alternate_description_factory.summary.target_name_id);
|
||||
json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
|
||||
json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
|
||||
|
||||
std::vector<unsigned> const &alternate_leg_end_indices =
|
||||
alternate_description_factory.GetViaIndices();
|
||||
JSON::Array json_altenative_indices_array;
|
||||
json_altenative_indices_array.values.insert(json_altenative_indices_array.values.end(),
|
||||
alternate_leg_end_indices.begin(),
|
||||
alternate_leg_end_indices.end());
|
||||
json_result.values["alternative_indices"] = json_altenative_indices_array;
|
||||
}
|
||||
else
|
||||
{
|
||||
json_result.values["found_alternative"] = JSON::False();
|
||||
}
|
||||
|
||||
// Get Names for both routes
|
||||
RouteNames route_names =
|
||||
GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
|
||||
JSON::Array json_route_names;
|
||||
json_route_names.values.push_back(route_names.shortest_path_name_1);
|
||||
json_route_names.values.push_back(route_names.shortest_path_name_2);
|
||||
json_result.values["route_name"] = json_route_names;
|
||||
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
JSON::Array json_alternate_names_array;
|
||||
JSON::Array json_alternate_names;
|
||||
json_alternate_names.values.push_back(route_names.alternative_path_name_1);
|
||||
json_alternate_names.values.push_back(route_names.alternative_path_name_2);
|
||||
json_alternate_names_array.values.push_back(json_alternate_names);
|
||||
json_result.values["alternative_names"] = json_alternate_names_array;
|
||||
}
|
||||
|
||||
JSON::Object json_hint_object;
|
||||
json_hint_object.values["checksum"] = raw_route.check_sum;
|
||||
JSON::Array json_location_hint_array;
|
||||
std::string hint;
|
||||
for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i)
|
||||
{
|
||||
EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
|
||||
json_location_hint_array.values.push_back(hint);
|
||||
}
|
||||
EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
|
||||
json_location_hint_array.values.push_back(hint);
|
||||
json_hint_object.values["locations"] = json_location_hint_array;
|
||||
json_result.values["hint_data"] = json_hint_object;
|
||||
|
||||
// render the content to the output array
|
||||
TIMER_START(route_render);
|
||||
JSON::render(reply.content, json_result);
|
||||
TIMER_STOP(route_render);
|
||||
SimpleLogger().Write(logDEBUG) << "rendering took: " << TIMER_MSEC(route_render);
|
||||
}
|
||||
|
||||
// TODO: reorder parameters
|
||||
inline void BuildTextualDescription(DescriptionFactory &description_factory,
|
||||
JSON::Array &json_instruction_array,
|
||||
const int route_length,
|
||||
std::vector<Segment> &route_segments_list)
|
||||
{
|
||||
// Segment information has following format:
|
||||
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
unsigned necessary_segments_running_index = 1;
|
||||
round_about.leave_at_exit = 0;
|
||||
round_about.name_id = 0;
|
||||
std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
|
||||
|
||||
// Fetch data from Factory and generate a string from it.
|
||||
for (const SegmentInformation &segment : description_factory.path_description)
|
||||
{
|
||||
JSON::Array json_instruction_row;
|
||||
TurnInstruction current_instruction = segment.turn_instruction;
|
||||
entered_restricted_area_count += (current_instruction != segment.turn_instruction);
|
||||
if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
|
||||
{
|
||||
if (TurnInstruction::EnterRoundAbout == current_instruction)
|
||||
{
|
||||
round_about.name_id = segment.name_id;
|
||||
round_about.start_index = necessary_segments_running_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string current_turn_instruction;
|
||||
if (TurnInstruction::LeaveRoundAbout == current_instruction)
|
||||
{
|
||||
temp_instruction =
|
||||
IntToString(as_integer(TurnInstruction::EnterRoundAbout));
|
||||
current_turn_instruction += temp_instruction;
|
||||
current_turn_instruction += "-";
|
||||
temp_instruction = IntToString(round_about.leave_at_exit + 1);
|
||||
current_turn_instruction += temp_instruction;
|
||||
round_about.leave_at_exit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_instruction = IntToString(as_integer(current_instruction));
|
||||
current_turn_instruction += temp_instruction;
|
||||
}
|
||||
json_instruction_row.values.push_back(current_turn_instruction);
|
||||
|
||||
json_instruction_row.values.push_back(
|
||||
facade->GetEscapedNameForNameID(segment.name_id));
|
||||
json_instruction_row.values.push_back(std::round(segment.length));
|
||||
json_instruction_row.values.push_back(necessary_segments_running_index);
|
||||
json_instruction_row.values.push_back(round(segment.duration / 10));
|
||||
json_instruction_row.values.push_back(
|
||||
UintToString(static_cast<unsigned>(segment.length)) + "m");
|
||||
const double bearing_value = (segment.bearing / 10.) ;
|
||||
json_instruction_row.values.push_back(Azimuth::Get(bearing_value));
|
||||
json_instruction_row.values.push_back(static_cast<unsigned>(round(bearing_value)));
|
||||
|
||||
route_segments_list.emplace_back(
|
||||
segment.name_id, segment.length, route_segments_list.size());
|
||||
json_instruction_array.values.push_back(json_instruction_row);
|
||||
}
|
||||
}
|
||||
else if (TurnInstruction::StayOnRoundAbout == current_instruction)
|
||||
{
|
||||
++round_about.leave_at_exit;
|
||||
}
|
||||
if (segment.necessary)
|
||||
{
|
||||
++necessary_segments_running_index;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: check if this in an invariant
|
||||
if (INVALID_EDGE_WEIGHT != route_length)
|
||||
{
|
||||
JSON::Array json_last_instruction_row;
|
||||
temp_instruction = IntToString(as_integer(TurnInstruction::ReachedYourDestination));
|
||||
json_last_instruction_row.values.push_back(temp_instruction);
|
||||
json_last_instruction_row.values.push_back("");
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back("0m");
|
||||
json_last_instruction_row.values.push_back(Azimuth::Get(0.0));
|
||||
json_last_instruction_row.values.push_back(0.);
|
||||
json_instruction_array.values.push_back(json_last_instruction_row);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* JSON_DESCRIPTOR_H_ */
|
||||
|
||||
@@ -36,12 +36,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/regex.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
BaseParser::BaseParser(ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment)
|
||||
: extractor_callbacks(extractor_callbacks),
|
||||
lua_state(scripting_environment.getLuaStateForThreadID(0)),
|
||||
lua_state(scripting_environment.getLuaState()),
|
||||
scripting_environment(scripting_environment), use_turn_restrictions(true)
|
||||
{
|
||||
ReadUseRestrictionsSetting();
|
||||
|
||||
@@ -29,6 +29,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "ExtractionWay.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
#include "../DataStructures/RangeTable.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -63,49 +65,46 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
|
||||
{
|
||||
unsigned number_of_used_nodes = 0;
|
||||
unsigned number_of_used_edges = 0;
|
||||
std::chrono::time_point<std::chrono::steady_clock> time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
|
||||
TIMER_START(sorting_used_nodes);
|
||||
stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
|
||||
std::chrono::time_point<std::chrono::steady_clock> time2 = std::chrono::steady_clock::now();
|
||||
std::chrono::duration<double> elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(sorting_used_nodes);
|
||||
std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush;
|
||||
TIMER_START(erasing_dups);
|
||||
auto new_end = std::unique(used_node_id_list.begin(), used_node_id_list.end());
|
||||
used_node_id_list.resize(new_end - used_node_id_list.begin());
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(erasing_dups);
|
||||
std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
|
||||
TIMER_START(sorting_nodes);
|
||||
stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), CmpNodeByID(), stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(sorting_nodes);
|
||||
std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] Sorting used ways ... " << std::flush;
|
||||
TIMER_START(sort_ways);
|
||||
stxxl::sort(
|
||||
way_start_end_id_list.begin(), way_start_end_id_list.end(), CmpWayByID(), stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(sort_ways);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Sorting restrictions. by from... " << std::flush;
|
||||
TIMER_START(sort_restrictions);
|
||||
stxxl::sort(restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByFrom(),
|
||||
stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(sort_restrictions);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
|
||||
TIMER_START(fix_restriction_starts);
|
||||
auto restrictions_iterator = restrictions_list.begin();
|
||||
auto way_start_and_end_iterator = way_start_end_id_list.begin();
|
||||
|
||||
@@ -149,24 +148,21 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
|
||||
++restrictions_iterator;
|
||||
}
|
||||
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
TIMER_STOP(fix_restriction_starts);
|
||||
std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
|
||||
TIMER_START(sort_restrictions_to);
|
||||
stxxl::sort(restrictions_list.begin(),
|
||||
restrictions_list.end(),
|
||||
CmpRestrictionContainerByTo(),
|
||||
stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(sort_restrictions_to);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
unsigned number_of_useable_restrictions = 0;
|
||||
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
|
||||
TIMER_START(fix_restriction_ends);
|
||||
restrictions_iterator = restrictions_list.begin();
|
||||
way_start_and_end_iterator = way_start_end_id_list.begin();
|
||||
while (way_start_and_end_iterator != way_start_end_id_list.end() &&
|
||||
@@ -207,24 +203,22 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
|
||||
}
|
||||
++restrictions_iterator;
|
||||
}
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(fix_restriction_ends);
|
||||
std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
|
||||
|
||||
SimpleLogger().Write() << "usable restrictions: " << number_of_useable_restrictions;
|
||||
// serialize restrictions
|
||||
std::ofstream restrictions_out_stream;
|
||||
restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary);
|
||||
restrictions_out_stream.write((char *)&uuid, sizeof(UUID));
|
||||
restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
|
||||
restrictions_out_stream.write((char *)&number_of_useable_restrictions, sizeof(unsigned));
|
||||
for (restrictions_iterator = restrictions_list.begin();
|
||||
restrictions_iterator != restrictions_list.end();
|
||||
++restrictions_iterator)
|
||||
|
||||
for(const auto & restriction_container : restrictions_list)
|
||||
{
|
||||
if (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.fromNode &&
|
||||
std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.toNode)
|
||||
if (std::numeric_limits<unsigned>::max() != restriction_container.restriction.fromNode &&
|
||||
std::numeric_limits<unsigned>::max() != restriction_container.restriction.toNode)
|
||||
{
|
||||
restrictions_out_stream.write((char *)&(restrictions_iterator->restriction),
|
||||
restrictions_out_stream.write((char *)&(restriction_container.restriction),
|
||||
sizeof(TurnRestriction));
|
||||
}
|
||||
}
|
||||
@@ -232,27 +226,26 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
|
||||
|
||||
std::ofstream file_out_stream;
|
||||
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
|
||||
file_out_stream.write((char *)&uuid, sizeof(UUID));
|
||||
file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
|
||||
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
|
||||
|
||||
TIMER_START(write_nodes);
|
||||
// identify all used nodes by a merging step of two sorted lists
|
||||
auto node_iterator = all_nodes_list.begin();
|
||||
auto node_id_iterator = used_node_id_list.begin();
|
||||
while (node_id_iterator != used_node_id_list.end() && node_iterator != all_nodes_list.end())
|
||||
{
|
||||
if (*node_id_iterator < node_iterator->id)
|
||||
if (*node_id_iterator < node_iterator->node_id)
|
||||
{
|
||||
++node_id_iterator;
|
||||
continue;
|
||||
}
|
||||
if (*node_id_iterator > node_iterator->id)
|
||||
if (*node_id_iterator > node_iterator->node_id)
|
||||
{
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(*node_id_iterator == node_iterator->id);
|
||||
BOOST_ASSERT(*node_id_iterator == node_iterator->node_id);
|
||||
|
||||
file_out_stream.write((char *)&(*node_iterator), sizeof(ExternalMemoryNode));
|
||||
|
||||
@@ -261,82 +254,78 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
|
||||
++node_iterator;
|
||||
}
|
||||
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(write_nodes);
|
||||
std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] setting number of nodes ... " << std::flush;
|
||||
std::ios::pos_type previous_file_position = file_out_stream.tellp();
|
||||
file_out_stream.seekp(std::ios::beg + sizeof(UUID));
|
||||
file_out_stream.seekp(std::ios::beg + sizeof(FingerPrint));
|
||||
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
||||
file_out_stream.seekp(previous_file_position);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
// Sort edges by start.
|
||||
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
|
||||
TIMER_START(sort_edges_by_start);
|
||||
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(sort_edges_by_start);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] Setting start coords ... " << std::flush;
|
||||
TIMER_START(set_start_coords);
|
||||
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
|
||||
// Traverse list of edges and nodes in parallel and set start coord
|
||||
node_iterator = all_nodes_list.begin();
|
||||
auto edge_iterator = all_edges_list.begin();
|
||||
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
|
||||
{
|
||||
if (edge_iterator->start < node_iterator->id)
|
||||
if (edge_iterator->start < node_iterator->node_id)
|
||||
{
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if (edge_iterator->start > node_iterator->id)
|
||||
if (edge_iterator->start > node_iterator->node_id)
|
||||
{
|
||||
node_iterator++;
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(edge_iterator->start == node_iterator->id);
|
||||
BOOST_ASSERT(edge_iterator->start == node_iterator->node_id);
|
||||
edge_iterator->source_coordinate.lat = node_iterator->lat;
|
||||
edge_iterator->source_coordinate.lon = node_iterator->lon;
|
||||
++edge_iterator;
|
||||
}
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(set_start_coords);
|
||||
std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
// Sort Edges by target
|
||||
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
|
||||
TIMER_START(sort_edges_by_target);
|
||||
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByTargetID(), stxxl_memory);
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(sort_edges_by_target);
|
||||
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
|
||||
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
std::cout << "[extractor] Setting target coords ... " << std::flush;
|
||||
TIMER_START(set_target_coords);
|
||||
// Traverse list of edges and nodes in parallel and set target coord
|
||||
node_iterator = all_nodes_list.begin();
|
||||
edge_iterator = all_edges_list.begin();
|
||||
|
||||
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
|
||||
{
|
||||
if (edge_iterator->target < node_iterator->id)
|
||||
if (edge_iterator->target < node_iterator->node_id)
|
||||
{
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if (edge_iterator->target > node_iterator->id)
|
||||
if (edge_iterator->target > node_iterator->node_id)
|
||||
{
|
||||
++node_iterator;
|
||||
continue;
|
||||
}
|
||||
BOOST_ASSERT(edge_iterator->target == node_iterator->id);
|
||||
BOOST_ASSERT(edge_iterator->target == node_iterator->node_id);
|
||||
if (edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min() &&
|
||||
edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
|
||||
{
|
||||
@@ -393,9 +382,8 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
|
||||
}
|
||||
++edge_iterator;
|
||||
}
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(set_target_coords);
|
||||
std::cout << "ok, after " << TIMER_SEC(set_target_coords) << "s" << std::endl;
|
||||
|
||||
std::cout << "[extractor] setting number of edges ... " << std::flush;
|
||||
|
||||
@@ -403,45 +391,35 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
|
||||
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
|
||||
file_out_stream.close();
|
||||
std::cout << "ok" << std::endl;
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << "[extractor] writing street name index ... " << std::flush;
|
||||
TIMER_START(write_name_index);
|
||||
std::string name_file_streamName = (output_file_name + ".names");
|
||||
boost::filesystem::ofstream name_file_stream(name_file_streamName, std::ios::binary);
|
||||
|
||||
// write number of names
|
||||
const unsigned number_of_names = name_list.size() + 1;
|
||||
name_file_stream.write((char *)&(number_of_names), sizeof(unsigned));
|
||||
|
||||
// compute total number of chars
|
||||
unsigned total_number_of_chars = 0;
|
||||
unsigned total_length = 0;
|
||||
std::vector<unsigned> name_lengths;
|
||||
for (const std::string &temp_string : name_list)
|
||||
{
|
||||
total_number_of_chars += temp_string.length();
|
||||
const unsigned string_length = std::min(static_cast<unsigned>(temp_string.length()), 255u);
|
||||
name_lengths.push_back(string_length);
|
||||
total_length += string_length;
|
||||
}
|
||||
// write total number of chars
|
||||
name_file_stream.write((char *)&(total_number_of_chars), sizeof(unsigned));
|
||||
// write prefixe sums
|
||||
unsigned name_lengths_prefix_sum = 0;
|
||||
for (const std::string &temp_string : name_list)
|
||||
{
|
||||
name_file_stream.write((char *)&(name_lengths_prefix_sum), sizeof(unsigned));
|
||||
name_lengths_prefix_sum += temp_string.length();
|
||||
}
|
||||
// duplicate on purpose!
|
||||
name_file_stream.write((char *)&(name_lengths_prefix_sum), sizeof(unsigned));
|
||||
|
||||
RangeTable<> table(name_lengths);
|
||||
name_file_stream << table;
|
||||
|
||||
name_file_stream.write((char*) &total_length, sizeof(unsigned));
|
||||
// write all chars consecutively
|
||||
for (const std::string &temp_string : name_list)
|
||||
{
|
||||
const unsigned string_length = temp_string.length();
|
||||
const unsigned string_length = std::min(static_cast<unsigned>(temp_string.length()), 255u);
|
||||
name_file_stream.write(temp_string.c_str(), string_length);
|
||||
}
|
||||
|
||||
name_file_stream.close();
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
elapsed_seconds = time2 - time1;
|
||||
std::cout << "ok, after " << elapsed_seconds.count() << "s" << std::endl;
|
||||
TIMER_STOP(write_name_index);
|
||||
std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
|
||||
|
||||
SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes and "
|
||||
<< number_of_used_edges << " edges";
|
||||
|
||||
@@ -31,13 +31,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "InternalExtractorEdge.h"
|
||||
#include "ExtractorStructs.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/UUID.h"
|
||||
#include "../Util/FingerPrint.h"
|
||||
|
||||
#include <stxxl/vector>
|
||||
|
||||
class ExtractionContainers
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
constexpr static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? std::numeric_limits<int>::max() : std::numeric_limits<unsigned>::max());
|
||||
#else
|
||||
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
|
||||
#endif
|
||||
public:
|
||||
typedef stxxl::vector<NodeID> STXXLNodeIDVector;
|
||||
typedef stxxl::vector<ExternalMemoryNode> STXXLNodeVector;
|
||||
@@ -52,7 +56,7 @@ class ExtractionContainers
|
||||
STXXLStringVector name_list;
|
||||
STXXLRestrictionsVector restrictions_list;
|
||||
STXXLWayIDStartEndVector way_start_end_id_list;
|
||||
const UUID uuid;
|
||||
const FingerPrint fingerprint;
|
||||
|
||||
ExtractionContainers();
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ inline bool durationIsValid(const std::string &s)
|
||||
|
||||
std::vector<std::string> result;
|
||||
boost::algorithm::split_regex(result, s, boost::regex(":"));
|
||||
bool matched = regex_match(s, e);
|
||||
const bool matched = regex_match(s, e);
|
||||
return matched;
|
||||
}
|
||||
|
||||
@@ -63,23 +63,23 @@ inline unsigned parseDuration(const std::string &s)
|
||||
|
||||
std::vector<std::string> result;
|
||||
boost::algorithm::split_regex(result, s, boost::regex(":"));
|
||||
bool matched = regex_match(s, e);
|
||||
const bool matched = regex_match(s, e);
|
||||
if (matched)
|
||||
{
|
||||
if (1 == result.size())
|
||||
{
|
||||
minutes = stringToInt(result[0]);
|
||||
minutes = StringToUint(result[0]);
|
||||
}
|
||||
if (2 == result.size())
|
||||
{
|
||||
minutes = stringToInt(result[1]);
|
||||
hours = stringToInt(result[0]);
|
||||
minutes = StringToUint(result[1]);
|
||||
hours = StringToUint(result[0]);
|
||||
}
|
||||
if (3 == result.size())
|
||||
{
|
||||
seconds = stringToInt(result[2]);
|
||||
minutes = stringToInt(result[1]);
|
||||
hours = stringToInt(result[0]);
|
||||
seconds = StringToUint(result[2]);
|
||||
minutes = StringToUint(result[1]);
|
||||
hours = StringToUint(result[0]);
|
||||
}
|
||||
return 10 * (3600 * hours + 60 * minutes + seconds);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ struct ExtractionWay
|
||||
id = SPECIAL_NODEID;
|
||||
nameID = INVALID_NAMEID;
|
||||
path.clear();
|
||||
keyVals.clear();
|
||||
keyVals.Clear();
|
||||
direction = ExtractionWay::notSure;
|
||||
speed = -1;
|
||||
backward_speed = -1;
|
||||
|
||||
@@ -63,102 +63,109 @@ bool ExtractorCallbacks::ProcessRestriction(const InputRestrictionContainer &res
|
||||
/** warning: caller needs to take care of synchronization! */
|
||||
void ExtractorCallbacks::ProcessWay(ExtractionWay &parsed_way)
|
||||
{
|
||||
if ((0 < parsed_way.speed) || (0 < parsed_way.duration))
|
||||
if ((0 >= parsed_way.speed) && (0 >= parsed_way.duration))
|
||||
{ // Only true if the way is specified by the speed profile
|
||||
if (std::numeric_limits<unsigned>::max() == parsed_way.id)
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << parsed_way.id
|
||||
<< " of size " << parsed_way.path.size();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 < parsed_way.duration)
|
||||
{
|
||||
// TODO: iterate all way segments and set duration corresponding to the length of each
|
||||
// segment
|
||||
parsed_way.speed = parsed_way.duration / (parsed_way.path.size() - 1);
|
||||
}
|
||||
if (parsed_way.path.size() <= 1)
|
||||
{ // safe-guard against broken data
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.speed))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id;
|
||||
return;
|
||||
}
|
||||
if (std::numeric_limits<unsigned>::max() == parsed_way.id)
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << parsed_way.id
|
||||
<< " of size " << parsed_way.path.size();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the unique identifier for the street name
|
||||
const auto &string_map_iterator = string_map.find(parsed_way.name);
|
||||
if (string_map.end() == string_map_iterator)
|
||||
{
|
||||
parsed_way.nameID = external_memory.name_list.size();
|
||||
external_memory.name_list.push_back(parsed_way.name);
|
||||
string_map.insert(std::make_pair(parsed_way.name, parsed_way.nameID));
|
||||
}
|
||||
else
|
||||
{
|
||||
parsed_way.nameID = string_map_iterator->second;
|
||||
}
|
||||
if (0 < parsed_way.duration)
|
||||
{
|
||||
// TODO: iterate all way segments and set duration corresponding to the length of each
|
||||
// segment
|
||||
parsed_way.speed = parsed_way.duration / (parsed_way.path.size() - 1);
|
||||
}
|
||||
|
||||
if (ExtractionWay::opposite == parsed_way.direction)
|
||||
if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.speed))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the unique identifier for the street name
|
||||
const auto &string_map_iterator = string_map.find(parsed_way.name);
|
||||
if (string_map.end() == string_map_iterator)
|
||||
{
|
||||
parsed_way.nameID = external_memory.name_list.size();
|
||||
external_memory.name_list.push_back(parsed_way.name);
|
||||
string_map.insert(std::make_pair(parsed_way.name, parsed_way.nameID));
|
||||
}
|
||||
else
|
||||
{
|
||||
parsed_way.nameID = string_map_iterator->second;
|
||||
}
|
||||
|
||||
if (ExtractionWay::opposite == parsed_way.direction)
|
||||
{
|
||||
std::reverse(parsed_way.path.begin(), parsed_way.path.end());
|
||||
parsed_way.direction = ExtractionWay::oneway;
|
||||
}
|
||||
|
||||
const bool split_edge =
|
||||
(parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed);
|
||||
|
||||
for (unsigned n = 0; n < (parsed_way.path.size() - 1); ++n)
|
||||
{
|
||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||
parsed_way.path[n],
|
||||
parsed_way.path[n + 1],
|
||||
parsed_way.type,
|
||||
(split_edge ? ExtractionWay::oneway : parsed_way.direction),
|
||||
parsed_way.speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
false,
|
||||
split_edge));
|
||||
external_memory.used_node_id_list.push_back(parsed_way.path[n]);
|
||||
}
|
||||
external_memory.used_node_id_list.push_back(parsed_way.path.back());
|
||||
|
||||
// The following information is needed to identify start and end segments of restrictions
|
||||
external_memory.way_start_end_id_list.push_back(
|
||||
WayIDStartAndEndEdge(parsed_way.id,
|
||||
parsed_way.path[0],
|
||||
parsed_way.path[1],
|
||||
parsed_way.path[parsed_way.path.size() - 2],
|
||||
parsed_way.path.back()));
|
||||
|
||||
if (split_edge)
|
||||
{ // Only true if the way should be split
|
||||
std::reverse(parsed_way.path.begin(), parsed_way.path.end());
|
||||
for (std::vector<NodeID>::size_type n = 0; n < parsed_way.path.size() - 1; ++n)
|
||||
{
|
||||
std::reverse(parsed_way.path.begin(), parsed_way.path.end());
|
||||
parsed_way.direction = ExtractionWay::oneway;
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(parsed_way.path[n],
|
||||
parsed_way.path[n + 1],
|
||||
parsed_way.type,
|
||||
ExtractionWay::oneway,
|
||||
parsed_way.backward_speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
(ExtractionWay::oneway == parsed_way.direction),
|
||||
split_edge));
|
||||
}
|
||||
|
||||
const bool split_bidirectional_edge =
|
||||
(parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed);
|
||||
|
||||
for (unsigned n = 0; n < parsed_way.path.size() - 1; ++n)
|
||||
{
|
||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||
parsed_way.path[n],
|
||||
parsed_way.path[n + 1],
|
||||
parsed_way.type,
|
||||
(split_bidirectional_edge ? ExtractionWay::oneway : parsed_way.direction),
|
||||
parsed_way.speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
false,
|
||||
split_bidirectional_edge));
|
||||
external_memory.used_node_id_list.push_back(parsed_way.path[n]);
|
||||
}
|
||||
external_memory.used_node_id_list.push_back(parsed_way.path.back());
|
||||
|
||||
// The following information is needed to identify start and end segments of restrictions
|
||||
external_memory.way_start_end_id_list.push_back(
|
||||
WayIDStartAndEndEdge(parsed_way.id,
|
||||
parsed_way.path[0],
|
||||
parsed_way.path[1],
|
||||
parsed_way.path[parsed_way.path.size() - 2],
|
||||
parsed_way.path.back()));
|
||||
|
||||
if (split_bidirectional_edge)
|
||||
{ // Only true if the way should be split
|
||||
std::reverse(parsed_way.path.begin(), parsed_way.path.end());
|
||||
for (std::vector<NodeID>::size_type n = 0; n < parsed_way.path.size() - 1; ++n)
|
||||
{
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(parsed_way.path[n],
|
||||
parsed_way.path[n + 1],
|
||||
parsed_way.type,
|
||||
ExtractionWay::oneway,
|
||||
parsed_way.backward_speed,
|
||||
parsed_way.nameID,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.ignoreInGrid,
|
||||
(0 < parsed_way.duration),
|
||||
parsed_way.isAccessRestricted,
|
||||
(ExtractionWay::oneway == parsed_way.direction),
|
||||
split_bidirectional_edge));
|
||||
}
|
||||
external_memory.way_start_end_id_list.push_back(
|
||||
WayIDStartAndEndEdge(parsed_way.id,
|
||||
parsed_way.path[0],
|
||||
parsed_way.path[1],
|
||||
parsed_way.path[parsed_way.path.size() - 2],
|
||||
parsed_way.path.back()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ struct CmpWayByID
|
||||
struct Cmp
|
||||
{
|
||||
typedef NodeID value_type;
|
||||
bool operator()(const NodeID a, const NodeID b) const { return a < b; }
|
||||
bool operator()(const NodeID left, const NodeID right) const { return left < right; }
|
||||
value_type max_value() { return 0xffffffff; }
|
||||
value_type min_value() { return 0x0; }
|
||||
};
|
||||
@@ -103,9 +103,9 @@ struct Cmp
|
||||
struct CmpNodeByID
|
||||
{
|
||||
typedef ExternalMemoryNode value_type;
|
||||
bool operator()(const ExternalMemoryNode &a, const ExternalMemoryNode &b) const
|
||||
bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const
|
||||
{
|
||||
return a.id < b.id;
|
||||
return left.node_id < right.node_id;
|
||||
}
|
||||
value_type max_value() { return ExternalMemoryNode::max_value(); }
|
||||
value_type min_value() { return ExternalMemoryNode::min_value(); }
|
||||
|
||||
+115
-91
@@ -35,14 +35,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
#include "../Util/MachineInfo.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/ref.hpp>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
@@ -52,9 +54,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
PBFParser::PBFParser(const char *fileName,
|
||||
ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment)
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
unsigned num_threads)
|
||||
: BaseParser(extractor_callbacks, scripting_environment)
|
||||
{
|
||||
if (0 == num_threads)
|
||||
{
|
||||
num_parser_threads = tbb::task_scheduler_init::default_num_threads();
|
||||
}
|
||||
else
|
||||
{
|
||||
num_parser_threads = num_threads;
|
||||
}
|
||||
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
// TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk?
|
||||
// NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free.
|
||||
@@ -103,7 +115,7 @@ inline bool PBFParser::ReadHeader()
|
||||
if (readBlob(input, &init_data))
|
||||
{
|
||||
if (!init_data.PBFHeaderBlock.ParseFromArray(&(init_data.charBuffer[0]),
|
||||
init_data.charBuffer.size()))
|
||||
static_cast<int>(init_data.charBuffer.size())))
|
||||
{
|
||||
std::cerr << "[error] Header not parseable!" << std::endl;
|
||||
return false;
|
||||
@@ -161,6 +173,8 @@ inline void PBFParser::ReadData()
|
||||
|
||||
inline void PBFParser::ParseData()
|
||||
{
|
||||
tbb::task_scheduler_init init(num_parser_threads);
|
||||
|
||||
while (true)
|
||||
{
|
||||
ParserThreadData *thread_data;
|
||||
@@ -233,17 +247,17 @@ inline void PBFParser::parseDenseNode(ParserThreadData *thread_data)
|
||||
m_lastDenseID += dense.id(i);
|
||||
m_lastDenseLatitude += dense.lat(i);
|
||||
m_lastDenseLongitude += dense.lon(i);
|
||||
extracted_nodes_vector[i].id = m_lastDenseID;
|
||||
extracted_nodes_vector[i].lat =
|
||||
extracted_nodes_vector[i].node_id = static_cast<NodeID>(m_lastDenseID);
|
||||
extracted_nodes_vector[i].lat = static_cast<int>(
|
||||
COORDINATE_PRECISION *
|
||||
((double)m_lastDenseLatitude * thread_data->PBFprimitiveBlock.granularity() +
|
||||
thread_data->PBFprimitiveBlock.lat_offset()) /
|
||||
NANO;
|
||||
extracted_nodes_vector[i].lon =
|
||||
NANO);
|
||||
extracted_nodes_vector[i].lon = static_cast<int>(
|
||||
COORDINATE_PRECISION *
|
||||
((double)m_lastDenseLongitude * thread_data->PBFprimitiveBlock.granularity() +
|
||||
thread_data->PBFprimitiveBlock.lon_offset()) /
|
||||
NANO;
|
||||
NANO);
|
||||
while (denseTagIndex < dense.keys_vals_size())
|
||||
{
|
||||
const int tagValue = dense.keys_vals(denseTagIndex);
|
||||
@@ -255,20 +269,21 @@ inline void PBFParser::parseDenseNode(ParserThreadData *thread_data)
|
||||
const int keyValue = dense.keys_vals(denseTagIndex + 1);
|
||||
const std::string &key = thread_data->PBFprimitiveBlock.stringtable().s(tagValue);
|
||||
const std::string &value = thread_data->PBFprimitiveBlock.stringtable().s(keyValue);
|
||||
extracted_nodes_vector[i].keyVals.emplace(key, value);
|
||||
extracted_nodes_vector[i].keyVals.Add(std::move(key), std::move(value));
|
||||
denseTagIndex += 2;
|
||||
}
|
||||
}
|
||||
#pragma omp parallel
|
||||
{
|
||||
const int thread_num = omp_get_thread_num();
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (int i = 0; i < number_of_nodes; ++i)
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, extracted_nodes_vector.size()),
|
||||
[this, &extracted_nodes_vector](const tbb::blocked_range<size_t> &range)
|
||||
{
|
||||
lua_State *lua_state = this->scripting_environment.getLuaState();
|
||||
for (size_t i = range.begin(); i != range.end(); ++i)
|
||||
{
|
||||
ImportNode &import_node = extracted_nodes_vector[i];
|
||||
ParseNodeInLua(import_node, scripting_environment.getLuaStateForThreadID(thread_num));
|
||||
ParseNodeInLua(import_node, lua_state);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const ImportNode &import_node : extracted_nodes_vector)
|
||||
{
|
||||
@@ -297,8 +312,8 @@ inline void PBFParser::parseRelation(ParserThreadData *thread_data)
|
||||
std::string except_tag_string;
|
||||
const OSMPBF::Relation &inputRelation =
|
||||
thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).relations(i);
|
||||
bool isRestriction = false;
|
||||
bool isOnlyRestriction = false;
|
||||
bool is_restriction = false;
|
||||
bool is_only_restriction = false;
|
||||
for (int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k)
|
||||
{
|
||||
const std::string &key =
|
||||
@@ -309,7 +324,7 @@ inline void PBFParser::parseRelation(ParserThreadData *thread_data)
|
||||
{
|
||||
if ("restriction" == val)
|
||||
{
|
||||
isRestriction = true;
|
||||
is_restriction = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -318,7 +333,7 @@ inline void PBFParser::parseRelation(ParserThreadData *thread_data)
|
||||
}
|
||||
if (("restriction" == key) && (val.find("only_") == 0))
|
||||
{
|
||||
isOnlyRestriction = true;
|
||||
is_only_restriction = true;
|
||||
}
|
||||
if ("except" == key)
|
||||
{
|
||||
@@ -326,22 +341,22 @@ inline void PBFParser::parseRelation(ParserThreadData *thread_data)
|
||||
}
|
||||
}
|
||||
|
||||
if (isRestriction && ShouldIgnoreRestriction(except_tag_string))
|
||||
if (is_restriction && ShouldIgnoreRestriction(except_tag_string))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isRestriction)
|
||||
if (is_restriction)
|
||||
{
|
||||
int64_t lastRef = 0;
|
||||
InputRestrictionContainer currentRestrictionContainer(isOnlyRestriction);
|
||||
int64_t last_ref = 0;
|
||||
InputRestrictionContainer current_restriction_container(is_only_restriction);
|
||||
for (int rolesIndex = 0, last_role = inputRelation.roles_sid_size();
|
||||
rolesIndex < last_role;
|
||||
++rolesIndex)
|
||||
{
|
||||
const std::string &role = thread_data->PBFprimitiveBlock.stringtable().s(
|
||||
inputRelation.roles_sid(rolesIndex));
|
||||
lastRef += inputRelation.memids(rolesIndex);
|
||||
last_ref += inputRelation.memids(rolesIndex);
|
||||
|
||||
if (!("from" == role || "to" == role || "via" == role))
|
||||
{
|
||||
@@ -355,41 +370,46 @@ inline void PBFParser::parseRelation(ParserThreadData *thread_data)
|
||||
{ // Only via should be a node
|
||||
continue;
|
||||
}
|
||||
assert("via" == role);
|
||||
if (std::numeric_limits<unsigned>::max() != currentRestrictionContainer.viaNode)
|
||||
BOOST_ASSERT("via" == role);
|
||||
if (std::numeric_limits<unsigned>::max() !=
|
||||
current_restriction_container.viaNode)
|
||||
{
|
||||
currentRestrictionContainer.viaNode = std::numeric_limits<unsigned>::max();
|
||||
current_restriction_container.viaNode =
|
||||
std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
assert(std::numeric_limits<unsigned>::max() == currentRestrictionContainer.viaNode);
|
||||
currentRestrictionContainer.restriction.viaNode = lastRef;
|
||||
BOOST_ASSERT(std::numeric_limits<unsigned>::max() ==
|
||||
current_restriction_container.viaNode);
|
||||
current_restriction_container.restriction.viaNode =
|
||||
static_cast<NodeID>(last_ref);
|
||||
break;
|
||||
case 1: // way
|
||||
assert("from" == role || "to" == role || "via" == role);
|
||||
BOOST_ASSERT("from" == role || "to" == role || "via" == role);
|
||||
if ("from" == role)
|
||||
{
|
||||
currentRestrictionContainer.fromWay = lastRef;
|
||||
current_restriction_container.fromWay = static_cast<EdgeID>(last_ref);
|
||||
}
|
||||
if ("to" == role)
|
||||
{
|
||||
currentRestrictionContainer.toWay = lastRef;
|
||||
current_restriction_container.toWay = static_cast<EdgeID>(last_ref);
|
||||
}
|
||||
if ("via" == role)
|
||||
{
|
||||
assert(currentRestrictionContainer.restriction.toNode == std::numeric_limits<unsigned>::max());
|
||||
currentRestrictionContainer.viaNode = lastRef;
|
||||
BOOST_ASSERT(current_restriction_container.restriction.toNode ==
|
||||
std::numeric_limits<unsigned>::max());
|
||||
current_restriction_container.viaNode = static_cast<NodeID>(last_ref);
|
||||
}
|
||||
break;
|
||||
case 2: // relation, not used. relations relating to relations are evil.
|
||||
continue;
|
||||
assert(false);
|
||||
BOOST_ASSERT(false);
|
||||
break;
|
||||
|
||||
default: // should not happen
|
||||
assert(false);
|
||||
BOOST_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!extractor_callbacks->ProcessRestriction(currentRestrictionContainer))
|
||||
if (!extractor_callbacks->ProcessRestriction(current_restriction_container))
|
||||
{
|
||||
std::cerr << "[PBFParser] relation not parsed" << std::endl;
|
||||
}
|
||||
@@ -404,38 +424,42 @@ inline void PBFParser::parseWay(ParserThreadData *thread_data)
|
||||
std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
|
||||
for (int i = 0; i < number_of_ways; ++i)
|
||||
{
|
||||
const OSMPBF::Way &inputWay =
|
||||
const OSMPBF::Way &input_way =
|
||||
thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways(i);
|
||||
parsed_way_vector[i].id = inputWay.id();
|
||||
unsigned pathNode(0);
|
||||
const int number_of_referenced_nodes = inputWay.refs_size();
|
||||
for (int j = 0; j < number_of_referenced_nodes; ++j)
|
||||
parsed_way_vector[i].id = static_cast<EdgeID>(input_way.id());
|
||||
unsigned node_id_in_path = 0;
|
||||
const auto number_of_referenced_nodes = input_way.refs_size();
|
||||
for (auto j = 0; j < number_of_referenced_nodes; ++j)
|
||||
{
|
||||
pathNode += inputWay.refs(j);
|
||||
parsed_way_vector[i].path.push_back(pathNode);
|
||||
node_id_in_path += static_cast<NodeID>(input_way.refs(j));
|
||||
parsed_way_vector[i].path.push_back(node_id_in_path);
|
||||
}
|
||||
assert(inputWay.keys_size() == inputWay.vals_size());
|
||||
const int number_of_keys = inputWay.keys_size();
|
||||
for (int j = 0; j < number_of_keys; ++j)
|
||||
BOOST_ASSERT(input_way.keys_size() == input_way.vals_size());
|
||||
const auto number_of_keys = input_way.keys_size();
|
||||
for (auto j = 0; j < number_of_keys; ++j)
|
||||
{
|
||||
const std::string &key =
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(inputWay.keys(j));
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(input_way.keys(j));
|
||||
const std::string &val =
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(inputWay.vals(j));
|
||||
parsed_way_vector[i].keyVals.emplace(key, val);
|
||||
thread_data->PBFprimitiveBlock.stringtable().s(input_way.vals(j));
|
||||
parsed_way_vector[i].keyVals.Add(std::move(key), std::move(val));
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp parallel for schedule(guided)
|
||||
for (int i = 0; i < number_of_ways; ++i)
|
||||
{
|
||||
ExtractionWay &extraction_way = parsed_way_vector[i];
|
||||
if (2 <= extraction_way.path.size())
|
||||
// TODO: investigate if schedule guided will be handled by tbb automatically
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, parsed_way_vector.size()),
|
||||
[this, &parsed_way_vector](const tbb::blocked_range<size_t> &range)
|
||||
{
|
||||
lua_State *lua_state = this->scripting_environment.getLuaState();
|
||||
for (size_t i = range.begin(); i != range.end(); i++)
|
||||
{
|
||||
ParseWayInLua(extraction_way,
|
||||
scripting_environment.getLuaStateForThreadID(omp_get_thread_num()));
|
||||
ExtractionWay &extraction_way = parsed_way_vector[i];
|
||||
if (2 <= extraction_way.path.size())
|
||||
{
|
||||
ParseWayInLua(extraction_way, lua_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (ExtractionWay &extraction_way : parsed_way_vector)
|
||||
{
|
||||
@@ -470,9 +494,9 @@ inline void PBFParser::loadGroup(ParserThreadData *thread_data)
|
||||
if (group.has_dense())
|
||||
{
|
||||
thread_data->entityTypeIndicator = TypeDenseNode;
|
||||
assert(0 != group.dense().id_size());
|
||||
BOOST_ASSERT(0 != group.dense().id_size());
|
||||
}
|
||||
assert(thread_data->entityTypeIndicator != TypeDummy);
|
||||
BOOST_ASSERT(thread_data->entityTypeIndicator != TypeDummy);
|
||||
}
|
||||
|
||||
inline void PBFParser::loadBlock(ParserThreadData *thread_data)
|
||||
@@ -503,51 +527,51 @@ inline bool PBFParser::readPBFBlobHeader(std::fstream &stream, ParserThreadData
|
||||
return dataSuccessfullyParsed;
|
||||
}
|
||||
|
||||
inline bool PBFParser::unpackZLIB(std::fstream &, ParserThreadData *thread_data)
|
||||
inline bool PBFParser::unpackZLIB(ParserThreadData *thread_data)
|
||||
{
|
||||
unsigned rawSize = thread_data->PBFBlob.raw_size();
|
||||
char *unpackedDataArray = new char[rawSize];
|
||||
z_stream compressedDataStream;
|
||||
compressedDataStream.next_in = (unsigned char *)thread_data->PBFBlob.zlib_data().data();
|
||||
compressedDataStream.avail_in = thread_data->PBFBlob.zlib_data().size();
|
||||
compressedDataStream.next_out = (unsigned char *)unpackedDataArray;
|
||||
compressedDataStream.avail_out = rawSize;
|
||||
compressedDataStream.zalloc = Z_NULL;
|
||||
compressedDataStream.zfree = Z_NULL;
|
||||
compressedDataStream.opaque = Z_NULL;
|
||||
int ret = inflateInit(&compressedDataStream);
|
||||
if (ret != Z_OK)
|
||||
auto raw_size = thread_data->PBFBlob.raw_size();
|
||||
char *unpacked_data_array = new char[raw_size];
|
||||
z_stream compressed_data_stream;
|
||||
compressed_data_stream.next_in = (unsigned char *)thread_data->PBFBlob.zlib_data().data();
|
||||
compressed_data_stream.avail_in = thread_data->PBFBlob.zlib_data().size();
|
||||
compressed_data_stream.next_out = (unsigned char *)unpacked_data_array;
|
||||
compressed_data_stream.avail_out = raw_size;
|
||||
compressed_data_stream.zalloc = Z_NULL;
|
||||
compressed_data_stream.zfree = Z_NULL;
|
||||
compressed_data_stream.opaque = Z_NULL;
|
||||
int return_code = inflateInit(&compressed_data_stream);
|
||||
if (return_code != Z_OK)
|
||||
{
|
||||
std::cerr << "[error] failed to init zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
delete[] unpacked_data_array;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflate(&compressedDataStream, Z_FINISH);
|
||||
if (ret != Z_STREAM_END)
|
||||
return_code = inflate(&compressed_data_stream, Z_FINISH);
|
||||
if (return_code != Z_STREAM_END)
|
||||
{
|
||||
std::cerr << "[error] failed to inflate zlib stream" << std::endl;
|
||||
std::cerr << "[error] Error type: " << ret << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
std::cerr << "[error] Error type: " << return_code << std::endl;
|
||||
delete[] unpacked_data_array;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = inflateEnd(&compressedDataStream);
|
||||
if (ret != Z_OK)
|
||||
return_code = inflateEnd(&compressed_data_stream);
|
||||
if (return_code != Z_OK)
|
||||
{
|
||||
std::cerr << "[error] failed to deinit zlib stream" << std::endl;
|
||||
delete[] unpackedDataArray;
|
||||
delete[] unpacked_data_array;
|
||||
return false;
|
||||
}
|
||||
|
||||
thread_data->charBuffer.clear();
|
||||
thread_data->charBuffer.resize(rawSize);
|
||||
std::copy(unpackedDataArray, unpackedDataArray + rawSize, thread_data->charBuffer.begin());
|
||||
delete[] unpackedDataArray;
|
||||
thread_data->charBuffer.resize(raw_size);
|
||||
std::copy(unpacked_data_array, unpacked_data_array + raw_size, thread_data->charBuffer.begin());
|
||||
delete[] unpacked_data_array;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool PBFParser::unpackLZMA(std::fstream &, ParserThreadData *) { return false; }
|
||||
inline bool PBFParser::unpackLZMA(ParserThreadData *) { return false; }
|
||||
|
||||
inline bool PBFParser::readBlob(std::fstream &stream, ParserThreadData *thread_data)
|
||||
{
|
||||
@@ -582,7 +606,7 @@ inline bool PBFParser::readBlob(std::fstream &stream, ParserThreadData *thread_d
|
||||
}
|
||||
else if (thread_data->PBFBlob.has_zlib_data())
|
||||
{
|
||||
if (!unpackZLIB(stream, thread_data))
|
||||
if (!unpackZLIB(thread_data))
|
||||
{
|
||||
std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
|
||||
delete[] data;
|
||||
@@ -591,7 +615,7 @@ inline bool PBFParser::readBlob(std::fstream &stream, ParserThreadData *thread_d
|
||||
}
|
||||
else if (thread_data->PBFBlob.has_lzma_data())
|
||||
{
|
||||
if (!unpackLZMA(stream, thread_data))
|
||||
if (!unpackLZMA(thread_data))
|
||||
{
|
||||
std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl;
|
||||
}
|
||||
@@ -631,7 +655,7 @@ bool PBFParser::readNextBlock(std::fstream &stream, ParserThreadData *thread_dat
|
||||
}
|
||||
|
||||
if (!thread_data->PBFprimitiveBlock.ParseFromArray(&(thread_data->charBuffer[0]),
|
||||
thread_data->charBuffer.size()))
|
||||
thread_data->charBuffer.size()))
|
||||
{
|
||||
std::cerr << "failed to parse PrimitiveBlock" << std::endl;
|
||||
return false;
|
||||
|
||||
@@ -63,7 +63,10 @@ class PBFParser : public BaseParser
|
||||
};
|
||||
|
||||
public:
|
||||
PBFParser(const char *file_name, ExtractorCallbacks *extractor_callbacks, ScriptingEnvironment &scripting_environment);
|
||||
PBFParser(const char *file_name,
|
||||
ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
unsigned num_parser_threads = 0);
|
||||
virtual ~PBFParser();
|
||||
|
||||
inline bool ReadHeader();
|
||||
@@ -80,8 +83,8 @@ class PBFParser : public BaseParser
|
||||
inline void loadGroup(ParserThreadData *thread_data);
|
||||
inline void loadBlock(ParserThreadData *thread_data);
|
||||
inline bool readPBFBlobHeader(std::fstream &stream, ParserThreadData *thread_data);
|
||||
inline bool unpackZLIB(std::fstream &stream, ParserThreadData *thread_data);
|
||||
inline bool unpackLZMA(std::fstream &stream, ParserThreadData *thread_data);
|
||||
inline bool unpackZLIB(ParserThreadData *thread_data);
|
||||
inline bool unpackLZMA(ParserThreadData *thread_data);
|
||||
inline bool readBlob(std::fstream &stream, ParserThreadData *thread_data);
|
||||
inline bool readNextBlock(std::fstream &stream, ParserThreadData *thread_data);
|
||||
|
||||
@@ -94,6 +97,7 @@ class PBFParser : public BaseParser
|
||||
|
||||
std::fstream input; // the input stream to parse
|
||||
std::shared_ptr<ConcurrentQueue<ParserThreadData *>> thread_data_queue;
|
||||
unsigned num_parser_threads;
|
||||
};
|
||||
|
||||
#endif /* PBFPARSER_H_ */
|
||||
|
||||
@@ -31,94 +31,91 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "ExtractionWay.h"
|
||||
#include "../DataStructures/ImportNode.h"
|
||||
#include "../Util/LuaUtil.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
ScriptingEnvironment::ScriptingEnvironment() {}
|
||||
ScriptingEnvironment::ScriptingEnvironment(const char *file_name)
|
||||
: file_name(file_name)
|
||||
{
|
||||
SimpleLogger().Write() << "Using script " << file_name;
|
||||
|
||||
// Create a new lua state
|
||||
for (int i = 0; i < omp_get_max_threads(); ++i)
|
||||
{
|
||||
lua_state_vector.push_back(luaL_newstate());
|
||||
}
|
||||
|
||||
// Connect LuaBind to this lua state for all threads
|
||||
#pragma omp parallel
|
||||
{
|
||||
lua_State *lua_state = getLuaStateForThreadID(omp_get_thread_num());
|
||||
luabind::open(lua_state);
|
||||
// open utility libraries string library;
|
||||
luaL_openlibs(lua_state);
|
||||
|
||||
luaAddScriptFolderToLoadPath(lua_state, file_name);
|
||||
|
||||
// Add our function to the state's global scope
|
||||
luabind::module(lua_state)[
|
||||
luabind::def("print", LUA_print<std::string>),
|
||||
luabind::def("durationIsValid", durationIsValid),
|
||||
luabind::def("parseDuration", parseDuration)
|
||||
];
|
||||
|
||||
luabind::module(lua_state)[luabind::class_<HashTable<std::string, std::string>>("keyVals")
|
||||
.def("Add", &HashTable<std::string, std::string>::Add)
|
||||
.def("Find", &HashTable<std::string, std::string>::Find)
|
||||
.def("Holds", &HashTable<std::string, std::string>::Holds)];
|
||||
|
||||
luabind::module(lua_state)[luabind::class_<ImportNode>("Node")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readwrite("lat", &ImportNode::lat)
|
||||
.def_readwrite("lon", &ImportNode::lon)
|
||||
.def_readonly("id", &ImportNode::id)
|
||||
.def_readwrite("bollard", &ImportNode::bollard)
|
||||
.def_readwrite("traffic_light", &ImportNode::trafficLight)
|
||||
.def_readwrite("tags", &ImportNode::keyVals)];
|
||||
|
||||
luabind::module(lua_state)
|
||||
[luabind::class_<ExtractionWay>("Way")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readonly("id", &ExtractionWay::id)
|
||||
.def_readwrite("name", &ExtractionWay::name)
|
||||
.def_readwrite("speed", &ExtractionWay::speed)
|
||||
.def_readwrite("backward_speed", &ExtractionWay::backward_speed)
|
||||
.def_readwrite("duration", &ExtractionWay::duration)
|
||||
.def_readwrite("type", &ExtractionWay::type)
|
||||
.def_readwrite("access", &ExtractionWay::access)
|
||||
.def_readwrite("roundabout", &ExtractionWay::roundabout)
|
||||
.def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted)
|
||||
.def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid)
|
||||
.def_readwrite("tags", &ExtractionWay::keyVals)
|
||||
.def_readwrite("direction", &ExtractionWay::direction)
|
||||
.enum_("constants")[
|
||||
luabind::value("notSure", 0),
|
||||
luabind::value("oneway", 1),
|
||||
luabind::value("bidirectional", 2),
|
||||
luabind::value("opposite", 3)
|
||||
]];
|
||||
|
||||
// fails on c++11/OS X 10.9
|
||||
luabind::module(lua_state)[luabind::class_<std::vector<std::string>>("vector").def(
|
||||
"Add",
|
||||
static_cast<void (std::vector<std::string>::*)(const std::string &)>(
|
||||
&std::vector<std::string>::push_back))];
|
||||
|
||||
if (0 != luaL_dofile(lua_state, file_name))
|
||||
{
|
||||
throw OSRMException("ERROR occured in scripting block");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptingEnvironment::~ScriptingEnvironment()
|
||||
void ScriptingEnvironment::initLuaState(lua_State* lua_state)
|
||||
{
|
||||
for (unsigned i = 0; i < lua_state_vector.size(); ++i)
|
||||
luabind::open(lua_state);
|
||||
// open utility libraries string library;
|
||||
luaL_openlibs(lua_state);
|
||||
|
||||
luaAddScriptFolderToLoadPath(lua_state, file_name.c_str());
|
||||
|
||||
// Add our function to the state's global scope
|
||||
luabind::module(lua_state)[
|
||||
luabind::def("print", LUA_print<std::string>),
|
||||
luabind::def("durationIsValid", durationIsValid),
|
||||
luabind::def("parseDuration", parseDuration)
|
||||
];
|
||||
|
||||
luabind::module(lua_state)[luabind::class_<HashTable<std::string, std::string>>("keyVals")
|
||||
.def("Add", &HashTable<std::string, std::string>::Add)
|
||||
.def("Find", &HashTable<std::string, std::string>::Find)
|
||||
.def("Holds", &HashTable<std::string, std::string>::Holds)];
|
||||
|
||||
luabind::module(lua_state)[luabind::class_<ImportNode>("Node")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readwrite("lat", &ImportNode::lat)
|
||||
.def_readwrite("lon", &ImportNode::lon)
|
||||
.def_readonly("id", &ImportNode::node_id)
|
||||
.def_readwrite("bollard", &ImportNode::bollard)
|
||||
.def_readwrite("traffic_light", &ImportNode::trafficLight)
|
||||
.def_readwrite("tags", &ImportNode::keyVals)];
|
||||
|
||||
luabind::module(lua_state)
|
||||
[luabind::class_<ExtractionWay>("Way")
|
||||
.def(luabind::constructor<>())
|
||||
.def_readonly("id", &ExtractionWay::id)
|
||||
.def_readwrite("name", &ExtractionWay::name)
|
||||
.def_readwrite("speed", &ExtractionWay::speed)
|
||||
.def_readwrite("backward_speed", &ExtractionWay::backward_speed)
|
||||
.def_readwrite("duration", &ExtractionWay::duration)
|
||||
.def_readwrite("type", &ExtractionWay::type)
|
||||
.def_readwrite("access", &ExtractionWay::access)
|
||||
.def_readwrite("roundabout", &ExtractionWay::roundabout)
|
||||
.def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted)
|
||||
.def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid)
|
||||
.def_readwrite("tags", &ExtractionWay::keyVals)
|
||||
.def_readwrite("direction", &ExtractionWay::direction)
|
||||
.enum_("constants")[
|
||||
luabind::value("notSure", 0),
|
||||
luabind::value("oneway", 1),
|
||||
luabind::value("bidirectional", 2),
|
||||
luabind::value("opposite", 3)
|
||||
]];
|
||||
|
||||
// fails on c++11/OS X 10.9
|
||||
luabind::module(lua_state)[luabind::class_<std::vector<std::string>>("vector").def(
|
||||
"Add",
|
||||
static_cast<void (std::vector<std::string>::*)(const std::string &)>(
|
||||
&std::vector<std::string>::push_back))];
|
||||
|
||||
if (0 != luaL_dofile(lua_state, file_name.c_str()))
|
||||
{
|
||||
// lua_state_vector[i];
|
||||
throw OSRMException("ERROR occured in scripting block");
|
||||
}
|
||||
}
|
||||
|
||||
lua_State *ScriptingEnvironment::getLuaStateForThreadID(const int id) { return lua_state_vector[id]; }
|
||||
lua_State *ScriptingEnvironment::getLuaState()
|
||||
{
|
||||
bool initialized = false;
|
||||
auto& ref = script_contexts.local(initialized);
|
||||
if (!initialized)
|
||||
{
|
||||
std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
|
||||
ref = state;
|
||||
initLuaState(ref.get());
|
||||
}
|
||||
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef SCRIPTINGENVIRONMENT_H_
|
||||
#define SCRIPTINGENVIRONMENT_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <tbb/enumerable_thread_specific.h>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
@@ -37,11 +39,14 @@ class ScriptingEnvironment
|
||||
public:
|
||||
ScriptingEnvironment();
|
||||
explicit ScriptingEnvironment(const char *file_name);
|
||||
virtual ~ScriptingEnvironment();
|
||||
|
||||
lua_State *getLuaStateForThreadID(const int);
|
||||
lua_State *getLuaState();
|
||||
|
||||
std::vector<lua_State *> lua_state_vector;
|
||||
private:
|
||||
void initLuaState(lua_State* lua_state);
|
||||
|
||||
std::string file_name;
|
||||
tbb::enumerable_thread_specific<std::shared_ptr<lua_State>> script_contexts;
|
||||
};
|
||||
|
||||
#endif /* SCRIPTINGENVIRONMENT_H_ */
|
||||
|
||||
+220
-214
@@ -40,15 +40,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
XMLParser::XMLParser(const char *filename, ExtractorCallbacks *ec, ScriptingEnvironment &se)
|
||||
: BaseParser(ec, se)
|
||||
XMLParser::XMLParser(const char *filename,
|
||||
ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment)
|
||||
: BaseParser(extractor_callbacks, scripting_environment)
|
||||
{
|
||||
inputReader = inputReaderFactory(filename);
|
||||
}
|
||||
|
||||
bool XMLParser::ReadHeader() { return (xmlTextReaderRead(inputReader) == 1); }
|
||||
bool XMLParser::ReadHeader() { return xmlTextReaderRead(inputReader) == 1; }
|
||||
bool XMLParser::Parse()
|
||||
{
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
@@ -62,16 +62,16 @@ bool XMLParser::Parse()
|
||||
}
|
||||
|
||||
xmlChar *currentName = xmlTextReaderName(inputReader);
|
||||
if (currentName == NULL)
|
||||
if (currentName == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(currentName, (const xmlChar *)"node") == 1)
|
||||
{
|
||||
ImportNode n = ReadXMLNode();
|
||||
ParseNodeInLua(n, lua_state);
|
||||
extractor_callbacks->ProcessNode(n);
|
||||
ImportNode current_node = ReadXMLNode();
|
||||
ParseNodeInLua(current_node, lua_state);
|
||||
extractor_callbacks->ProcessNode(current_node);
|
||||
}
|
||||
|
||||
if (xmlStrEqual(currentName, (const xmlChar *)"way") == 1)
|
||||
@@ -82,8 +82,9 @@ bool XMLParser::Parse()
|
||||
}
|
||||
if (use_turn_restrictions && xmlStrEqual(currentName, (const xmlChar *)"relation") == 1)
|
||||
{
|
||||
InputRestrictionContainer r = ReadXMLRestriction();
|
||||
if ((UINT_MAX != r.fromWay) && !extractor_callbacks->ProcessRestriction(r))
|
||||
InputRestrictionContainer current_restriction = ReadXMLRestriction();
|
||||
if ((UINT_MAX != current_restriction.fromWay) &&
|
||||
!extractor_callbacks->ProcessRestriction(current_restriction))
|
||||
{
|
||||
std::cerr << "[XMLParser] restriction not parsed" << std::endl;
|
||||
}
|
||||
@@ -95,103 +96,106 @@ bool XMLParser::Parse()
|
||||
|
||||
InputRestrictionContainer XMLParser::ReadXMLRestriction()
|
||||
{
|
||||
|
||||
InputRestrictionContainer restriction;
|
||||
std::string except_tag_string;
|
||||
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) != 1)
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) == 1)
|
||||
{
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
return restriction;
|
||||
}
|
||||
|
||||
std::string except_tag_string;
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int child_type = xmlTextReaderNodeType(inputReader);
|
||||
if (child_type != 1 && child_type != 15)
|
||||
{
|
||||
const int childType = xmlTextReaderNodeType(inputReader);
|
||||
if (childType != 1 && childType != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *childName = xmlTextReaderName(inputReader);
|
||||
if (childName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (depth == childDepth && childType == 15 &&
|
||||
xmlStrEqual(childName, (const xmlChar *)"relation") == 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
break;
|
||||
}
|
||||
if (childType != 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (k != NULL && value != NULL)
|
||||
{
|
||||
if (xmlStrEqual(k, (const xmlChar *)"restriction") &&
|
||||
(0 == std::string((const char *)value).find("only_")))
|
||||
{
|
||||
restriction.restriction.flags.isOnly = true;
|
||||
}
|
||||
if (xmlStrEqual(k, (const xmlChar *)"except"))
|
||||
{
|
||||
except_tag_string = (const char *)value;
|
||||
}
|
||||
}
|
||||
|
||||
if (k != NULL)
|
||||
{
|
||||
xmlFree(k);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(childName, (const xmlChar *)"member") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != NULL)
|
||||
{
|
||||
xmlChar *role = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"role");
|
||||
xmlChar *type = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"type");
|
||||
|
||||
if (xmlStrEqual(role, (const xmlChar *)"to") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"way"))
|
||||
{
|
||||
restriction.toWay = stringToUint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"from") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"way"))
|
||||
{
|
||||
restriction.fromWay = stringToUint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"via") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"node"))
|
||||
{
|
||||
restriction.restriction.viaNode = stringToUint((const char *)ref);
|
||||
}
|
||||
|
||||
if (NULL != type)
|
||||
{
|
||||
xmlFree(type);
|
||||
}
|
||||
if (NULL != role)
|
||||
{
|
||||
xmlFree(role);
|
||||
}
|
||||
if (NULL != ref)
|
||||
{
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
const int child_depth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *child_name = xmlTextReaderName(inputReader);
|
||||
if (child_name == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (depth == child_depth && child_type == 15 &&
|
||||
xmlStrEqual(child_name, (const xmlChar *)"relation") == 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
break;
|
||||
}
|
||||
if (child_type != 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (key != nullptr && value != nullptr)
|
||||
{
|
||||
if (xmlStrEqual(key, (const xmlChar *)"restriction") &&
|
||||
StringStartsWith((const char *)value, "only_"))
|
||||
{
|
||||
restriction.restriction.flags.isOnly = true;
|
||||
}
|
||||
if (xmlStrEqual(key, (const xmlChar *)"except"))
|
||||
{
|
||||
except_tag_string = (const char *)value;
|
||||
}
|
||||
}
|
||||
|
||||
if (key != nullptr)
|
||||
{
|
||||
xmlFree(key);
|
||||
}
|
||||
if (value != nullptr)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(child_name, (const xmlChar *)"member") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != nullptr)
|
||||
{
|
||||
xmlChar *role = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"role");
|
||||
xmlChar *type = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"type");
|
||||
|
||||
if (xmlStrEqual(role, (const xmlChar *)"to") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"way"))
|
||||
{
|
||||
restriction.toWay = StringToUint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"from") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"way"))
|
||||
{
|
||||
restriction.fromWay = StringToUint((const char *)ref);
|
||||
}
|
||||
if (xmlStrEqual(role, (const xmlChar *)"via") &&
|
||||
xmlStrEqual(type, (const xmlChar *)"node"))
|
||||
{
|
||||
restriction.restriction.viaNode = StringToUint((const char *)ref);
|
||||
}
|
||||
|
||||
if (nullptr != type)
|
||||
{
|
||||
xmlFree(type);
|
||||
}
|
||||
if (nullptr != role)
|
||||
{
|
||||
xmlFree(role);
|
||||
}
|
||||
if (nullptr != ref)
|
||||
{
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlFree(child_name);
|
||||
}
|
||||
|
||||
if (ShouldIgnoreRestriction(except_tag_string))
|
||||
@@ -204,67 +208,68 @@ InputRestrictionContainer XMLParser::ReadXMLRestriction()
|
||||
ExtractionWay XMLParser::ReadXMLWay()
|
||||
{
|
||||
ExtractionWay way;
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) != 1)
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) == 1)
|
||||
{
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
return way;
|
||||
}
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int child_type = xmlTextReaderNodeType(inputReader);
|
||||
if (child_type != 1 && child_type != 15)
|
||||
{
|
||||
const int childType = xmlTextReaderNodeType(inputReader);
|
||||
if (childType != 1 && childType != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *childName = xmlTextReaderName(inputReader);
|
||||
if (childName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == childDepth && childType == 15 &&
|
||||
xmlStrEqual(childName, (const xmlChar *)"way") == 1)
|
||||
{
|
||||
xmlChar *id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
|
||||
way.id = stringToUint((char *)id);
|
||||
xmlFree(id);
|
||||
xmlFree(childName);
|
||||
break;
|
||||
}
|
||||
if (childType != 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
|
||||
if (k != NULL && value != NULL)
|
||||
{
|
||||
way.keyVals.Add(std::string((char *)k), std::string((char *)value));
|
||||
}
|
||||
if (k != NULL)
|
||||
{
|
||||
xmlFree(k);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(childName, (const xmlChar *)"nd") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != NULL)
|
||||
{
|
||||
way.path.push_back(stringToUint((const char *)ref));
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
const int child_depth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *child_name = xmlTextReaderName(inputReader);
|
||||
if (child_name == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == child_depth && child_type == 15 &&
|
||||
xmlStrEqual(child_name, (const xmlChar *)"way") == 1)
|
||||
{
|
||||
xmlChar *node_id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
|
||||
way.id = StringToUint((char *)node_id);
|
||||
xmlFree(node_id);
|
||||
xmlFree(child_name);
|
||||
break;
|
||||
}
|
||||
if (child_type != 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
|
||||
if (key != nullptr && value != nullptr)
|
||||
{
|
||||
way.keyVals.Add(std::string((char *)key), std::string((char *)value));
|
||||
}
|
||||
if (key != nullptr)
|
||||
{
|
||||
xmlFree(key);
|
||||
}
|
||||
if (value != nullptr)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
else if (xmlStrEqual(child_name, (const xmlChar *)"nd") == 1)
|
||||
{
|
||||
xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
|
||||
if (ref != nullptr)
|
||||
{
|
||||
way.path.push_back(StringToUint((const char *)ref));
|
||||
xmlFree(ref);
|
||||
}
|
||||
}
|
||||
xmlFree(child_name);
|
||||
}
|
||||
return way;
|
||||
}
|
||||
@@ -274,74 +279,75 @@ ImportNode XMLParser::ReadXMLNode()
|
||||
ImportNode node;
|
||||
|
||||
xmlChar *attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lat");
|
||||
if (attribute != NULL)
|
||||
if (attribute != nullptr)
|
||||
{
|
||||
node.lat = COORDINATE_PRECISION * StringToDouble((const char *)attribute);
|
||||
node.lat = static_cast<int>(COORDINATE_PRECISION * StringToDouble((const char *)attribute));
|
||||
xmlFree(attribute);
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lon");
|
||||
if (attribute != NULL)
|
||||
if (attribute != nullptr)
|
||||
{
|
||||
node.lon = COORDINATE_PRECISION * StringToDouble((const char *)attribute);
|
||||
node.lon = static_cast<int>(COORDINATE_PRECISION * StringToDouble((const char *)attribute));
|
||||
xmlFree(attribute);
|
||||
}
|
||||
attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
|
||||
if (attribute != NULL)
|
||||
if (attribute != nullptr)
|
||||
{
|
||||
node.id = stringToUint((const char *)attribute);
|
||||
node.node_id = StringToUint((const char *)attribute);
|
||||
xmlFree(attribute);
|
||||
}
|
||||
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) != 1)
|
||||
if (xmlTextReaderIsEmptyElement(inputReader) == 1)
|
||||
{
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
return node;
|
||||
}
|
||||
const int depth = xmlTextReaderDepth(inputReader);
|
||||
while (xmlTextReaderRead(inputReader) == 1)
|
||||
{
|
||||
const int child_type = xmlTextReaderNodeType(inputReader);
|
||||
// 1 = Element, 15 = EndElement
|
||||
if (child_type != 1 && child_type != 15)
|
||||
{
|
||||
const int childType = xmlTextReaderNodeType(inputReader);
|
||||
// 1 = Element, 15 = EndElement
|
||||
if (childType != 1 && childType != 15)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int childDepth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *childName = xmlTextReaderName(inputReader);
|
||||
if (childName == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == childDepth && childType == 15 &&
|
||||
xmlStrEqual(childName, (const xmlChar *)"node") == 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
break;
|
||||
}
|
||||
if (childType != 1)
|
||||
{
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(childName, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *k = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (k != NULL && value != NULL)
|
||||
{
|
||||
node.keyVals.emplace(std::string((char *)(k)), std::string((char *)(value)));
|
||||
}
|
||||
if (k != NULL)
|
||||
{
|
||||
xmlFree(k);
|
||||
}
|
||||
if (value != NULL)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
|
||||
xmlFree(childName);
|
||||
continue;
|
||||
}
|
||||
const int child_depth = xmlTextReaderDepth(inputReader);
|
||||
xmlChar *child_name = xmlTextReaderName(inputReader);
|
||||
if (child_name == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depth == child_depth && child_type == 15 &&
|
||||
xmlStrEqual(child_name, (const xmlChar *)"node") == 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
break;
|
||||
}
|
||||
if (child_type != 1)
|
||||
{
|
||||
xmlFree(child_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
|
||||
{
|
||||
xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
|
||||
xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
|
||||
if (key != nullptr && value != nullptr)
|
||||
{
|
||||
node.keyVals.Add(std::string((char *)(key)), std::string((char *)(value)));
|
||||
}
|
||||
if (key != nullptr)
|
||||
{
|
||||
xmlFree(key);
|
||||
}
|
||||
if (value != nullptr)
|
||||
{
|
||||
xmlFree(value);
|
||||
}
|
||||
}
|
||||
|
||||
xmlFree(child_name);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -28,15 +28,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef XMLPARSER_H_
|
||||
#define XMLPARSER_H_
|
||||
|
||||
#include "ExtractorCallbacks.h"
|
||||
#include "BaseParser.h"
|
||||
#include "../DataStructures/Restriction.h"
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
class ExtractorCallbacks;
|
||||
|
||||
class XMLParser : public BaseParser
|
||||
{
|
||||
public:
|
||||
XMLParser(const char *filename, ExtractorCallbacks *ec, ScriptingEnvironment &se);
|
||||
XMLParser(const char *filename,
|
||||
ExtractorCallbacks *extractor_callbacks,
|
||||
ScriptingEnvironment &scripting_environment);
|
||||
bool ReadHeader();
|
||||
bool Parse();
|
||||
|
||||
|
||||
+39
-20
@@ -28,9 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef FIXED_POINT_COORDINATE_H_
|
||||
#define FIXED_POINT_COORDINATE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <iosfwd> //for std::ostream
|
||||
#include <string>
|
||||
|
||||
constexpr double COORDINATE_PRECISION = 1000000.;
|
||||
const float COORDINATE_PRECISION = 1000000.f;
|
||||
|
||||
struct FixedPointCoordinate
|
||||
{
|
||||
@@ -47,40 +49,57 @@ struct FixedPointCoordinate
|
||||
static double
|
||||
ApproximateDistance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
static double ApproximateDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2);
|
||||
static double ApproximateDistance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
static double ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2);
|
||||
static float ApproximateEuclideanDistance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
static double
|
||||
ApproximateEuclideanDistance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
static float ApproximateEuclideanDistance(const int lat1,
|
||||
const int lon1,
|
||||
const int lat2,
|
||||
const int lon2);
|
||||
|
||||
static float ApproximateSquaredEuclideanDistance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
static void convertInternalLatLonToString(const int value, std::string &output);
|
||||
|
||||
static void convertInternalCoordinateToString(const FixedPointCoordinate &coord,
|
||||
static void convertInternalCoordinateToString(const FixedPointCoordinate &coordinate,
|
||||
std::string &output);
|
||||
|
||||
static void convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord,
|
||||
static void convertInternalReversedCoordinateToString(const FixedPointCoordinate &coordinate,
|
||||
std::string &output);
|
||||
|
||||
static double ComputePerpendicularDistance(const FixedPointCoordinate &point,
|
||||
const FixedPointCoordinate &segA,
|
||||
const FixedPointCoordinate &segB);
|
||||
static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location);
|
||||
|
||||
static double ComputePerpendicularDistance(const FixedPointCoordinate &coord_a,
|
||||
const FixedPointCoordinate &coord_b,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
double &r);
|
||||
static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio);
|
||||
|
||||
static int OrderedPerpendicularDistanceApproximation(const FixedPointCoordinate& segment_source,
|
||||
const FixedPointCoordinate& segment_target,
|
||||
const FixedPointCoordinate& query_location);
|
||||
|
||||
|
||||
static float GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B);
|
||||
|
||||
float GetBearing(const FixedPointCoordinate &other) const;
|
||||
|
||||
void Output(std::ostream &out) const;
|
||||
|
||||
static float DegreeToRadian(const float degree);
|
||||
static float RadianToDegree(const float radian);
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &o, FixedPointCoordinate const &c)
|
||||
inline std::ostream &operator<<(std::ostream &out_stream, FixedPointCoordinate const &coordinate)
|
||||
{
|
||||
c.Output(o);
|
||||
return o;
|
||||
coordinate.Output(out_stream);
|
||||
return out_stream;
|
||||
}
|
||||
|
||||
#endif /* FIXED_POINT_COORDINATE_H_ */
|
||||
|
||||
@@ -29,18 +29,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define HTTP_HEADER_H
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace http
|
||||
{
|
||||
struct Header
|
||||
{
|
||||
std::string name;
|
||||
std::string value;
|
||||
Header& operator=(const Header& other) = default;
|
||||
Header(const std::string & name, const std::string & value) : name(name), value(value) {}
|
||||
Header(const Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
name.clear();
|
||||
value.clear();
|
||||
}
|
||||
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -56,11 +56,11 @@ class Reply
|
||||
internalServerError = 500 } status;
|
||||
|
||||
std::vector<Header> headers;
|
||||
std::vector<boost::asio::const_buffer> toBuffers();
|
||||
std::vector<boost::asio::const_buffer> ToBuffers();
|
||||
std::vector<boost::asio::const_buffer> HeaderstoBuffers();
|
||||
std::vector<std::string> content;
|
||||
std::vector<char> content;
|
||||
static Reply StockReply(status_type status);
|
||||
void setSize(const unsigned size);
|
||||
void SetSize(const unsigned size);
|
||||
void SetUncompressedSize();
|
||||
|
||||
Reply();
|
||||
|
||||
+18
-1
@@ -25,21 +25,36 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
namespace boost { namespace interprocess { class named_mutex; } }
|
||||
|
||||
#include "OSRM_impl.h"
|
||||
#include "OSRM.h"
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
#include <osrm/RouteParameters.h>
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include "../Plugins/BasePlugin.h"
|
||||
#include "../Plugins/DistanceTablePlugin.h"
|
||||
#include "../Plugins/HelloWorldPlugin.h"
|
||||
#include "../Plugins/LocatePlugin.h"
|
||||
#include "../Plugins/NearestPlugin.h"
|
||||
#include "../Plugins/TimestampPlugin.h"
|
||||
#include "../Plugins/ViaRoutePlugin.h"
|
||||
|
||||
#include "../Server/DataStructures/BaseDataFacade.h"
|
||||
#include "../Server/DataStructures/InternalDataFacade.h"
|
||||
#include "../Server/DataStructures/SharedBarriers.h"
|
||||
#include "../Server/DataStructures/SharedDataFacade.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/interprocess/sync/named_condition.hpp>
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
OSRM_impl::OSRM_impl(const ServerPaths &server_paths, const bool use_shared_memory)
|
||||
: use_shared_memory(use_shared_memory)
|
||||
@@ -55,6 +70,7 @@ OSRM_impl::OSRM_impl(const ServerPaths &server_paths, const bool use_shared_memo
|
||||
}
|
||||
|
||||
// The following plugins handle all requests.
|
||||
RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new HelloWorldPlugin());
|
||||
RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
@@ -64,6 +80,7 @@ OSRM_impl::OSRM_impl(const ServerPaths &server_paths, const bool use_shared_memo
|
||||
|
||||
OSRM_impl::~OSRM_impl()
|
||||
{
|
||||
delete query_data_facade;
|
||||
for (PluginMap::value_type &plugin_pointer : plugin_map)
|
||||
{
|
||||
delete plugin_pointer.second;
|
||||
|
||||
+4
-4
@@ -28,13 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef OSRM_IMPL_H
|
||||
#define OSRM_IMPL_H
|
||||
|
||||
#include <osrm/Reply.h>
|
||||
#include <osrm/RouteParameters.h>
|
||||
class BasePlugin;
|
||||
namespace http { class Reply; }
|
||||
struct RouteParameters;
|
||||
|
||||
#include <osrm/ServerPaths.h>
|
||||
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../Plugins/BasePlugin.h"
|
||||
#include "../Util/ProgramOptions.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DISTANCE_TABLE_PLUGIN_H
|
||||
#define DISTANCE_TABLE_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
#include "../Descriptors/BaseDescriptor.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class DistanceTablePlugin : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
|
||||
public:
|
||||
explicit DistanceTablePlugin(DataFacadeT *facade) : descriptor_string("table"), facade(facade)
|
||||
{
|
||||
search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
|
||||
}
|
||||
|
||||
virtual ~DistanceTablePlugin() {}
|
||||
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
// check number of parameters
|
||||
if (2 > route_parameters.coordinates.size())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
RawRouteData raw_route;
|
||||
raw_route.check_sum = facade->GetCheckSum();
|
||||
|
||||
if (std::any_of(begin(route_parameters.coordinates),
|
||||
end(route_parameters.coordinates),
|
||||
[&](FixedPointCoordinate coordinate)
|
||||
{ return !coordinate.isValid(); }))
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
|
||||
{
|
||||
raw_route.raw_via_node_coordinates.emplace_back(std::move(coordinate));
|
||||
}
|
||||
|
||||
const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
|
||||
unsigned max_locations =
|
||||
std::min(100u, static_cast<unsigned>(raw_route.raw_via_node_coordinates.size()));
|
||||
PhantomNodeArray phantom_node_vector(max_locations);
|
||||
for (unsigned i = 0; i < max_locations; ++i)
|
||||
{
|
||||
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||
!route_parameters.hints[i].empty())
|
||||
{
|
||||
PhantomNode current_phantom_node;
|
||||
DecodeObjectFromBase64(route_parameters.hints[i], current_phantom_node);
|
||||
if (current_phantom_node.isValid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
phantom_node_vector[i].emplace_back(std::move(current_phantom_node));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
facade->IncrementalFindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
|
||||
phantom_node_vector[i],
|
||||
route_parameters.zoom_level,
|
||||
1);
|
||||
|
||||
BOOST_ASSERT(phantom_node_vector[i].front().isValid(facade->GetNumberOfNodes()));
|
||||
}
|
||||
|
||||
// TIMER_START(distance_table);
|
||||
std::shared_ptr<std::vector<EdgeWeight>> result_table =
|
||||
search_engine_ptr->distance_table(phantom_node_vector);
|
||||
// TIMER_STOP(distance_table);
|
||||
|
||||
if (!result_table)
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
JSON::Object json_object;
|
||||
JSON::Array json_array;
|
||||
const unsigned number_of_locations = static_cast<unsigned>(phantom_node_vector.size());
|
||||
for (unsigned row = 0; row < number_of_locations; ++row)
|
||||
{
|
||||
JSON::Array json_row;
|
||||
auto row_begin_iterator = result_table->begin() + (row * number_of_locations);
|
||||
auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_locations);
|
||||
json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator);
|
||||
json_array.values.push_back(json_row);
|
||||
}
|
||||
json_object.values["distance_table"] = json_array;
|
||||
JSON::render(reply.content, json_object);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif // DISTANCE_TABLE_PLUGIN_H
|
||||
+40
-52
@@ -25,10 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HELLOWORLDPLUGIN_H_
|
||||
#define HELLOWORLDPLUGIN_H_
|
||||
#ifndef HELLO_WORLD_PLUGIN_H
|
||||
#define HELLO_WORLD_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
@@ -46,70 +47,57 @@ class HelloWorldPlugin : public BasePlugin
|
||||
void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
|
||||
{
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("<html><head><title>Hello World Demonstration "
|
||||
"Document</title></head><body><h1>Hello, World!</h1>");
|
||||
reply.content.emplace_back("<pre>");
|
||||
reply.content.emplace_back("zoom level: ");
|
||||
intToString(routeParameters.zoom_level, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\nchecksum: ");
|
||||
intToString(routeParameters.check_sum, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\ninstructions: ");
|
||||
reply.content.emplace_back((routeParameters.print_instructions ? "yes" : "no"));
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\ngeometry: ");
|
||||
reply.content.emplace_back((routeParameters.geometry ? "yes" : "no"));
|
||||
reply.content.emplace_back("\ncompression: ");
|
||||
reply.content.emplace_back((routeParameters.compression ? "yes" : "no"));
|
||||
reply.content.emplace_back("\noutput format: ");
|
||||
reply.content.emplace_back(routeParameters.output_format);
|
||||
reply.content.emplace_back("\njson parameter: ");
|
||||
reply.content.emplace_back(routeParameters.jsonp_parameter);
|
||||
reply.content.emplace_back("\nlanguage: ");
|
||||
reply.content.emplace_back(routeParameters.language);
|
||||
reply.content.emplace_back("\nNumber of locations: ");
|
||||
intToString(routeParameters.coordinates.size(), temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\n");
|
||||
|
||||
JSON::Object json_result;
|
||||
std::string temp_string;
|
||||
json_result.values["title"] = "Hello World";
|
||||
|
||||
temp_string = IntToString(routeParameters.zoom_level);
|
||||
json_result.values["zoom_level"] = temp_string;
|
||||
|
||||
temp_string = UintToString(routeParameters.check_sum);
|
||||
json_result.values["check_sum"] = temp_string;
|
||||
json_result.values["instructions"] = (routeParameters.print_instructions ? "yes" : "no");
|
||||
json_result.values["geometry"] = (routeParameters.geometry ? "yes" : "no");
|
||||
json_result.values["compression"] = (routeParameters.compression ? "yes" : "no");
|
||||
json_result.values["output_format"] = (!routeParameters.output_format.empty() ? "yes" : "no");
|
||||
|
||||
json_result.values["jsonp_parameter"] = (!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
|
||||
json_result.values["language"] = (!routeParameters.language.empty() ? "yes" : "no");
|
||||
|
||||
temp_string = UintToString(static_cast<unsigned>(routeParameters.coordinates.size()));
|
||||
json_result.values["location_count"] = temp_string;
|
||||
|
||||
JSON::Array json_locations;
|
||||
unsigned counter = 0;
|
||||
for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
|
||||
{
|
||||
reply.content.emplace_back(" [");
|
||||
intToString(counter, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("] ");
|
||||
doubleToString(coordinate.lat / COORDINATE_PRECISION, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back(",");
|
||||
doubleToString(coordinate.lon / COORDINATE_PRECISION, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\n");
|
||||
JSON::Object json_location;
|
||||
JSON::Array json_coordinates;
|
||||
|
||||
json_coordinates.values.push_back(coordinate.lat / COORDINATE_PRECISION);
|
||||
json_coordinates.values.push_back(coordinate.lon / COORDINATE_PRECISION);
|
||||
json_location.values[UintToString(counter)] = json_coordinates;
|
||||
json_locations.values.push_back(json_location);
|
||||
++counter;
|
||||
}
|
||||
json_result.values["locations"] = json_locations;
|
||||
json_result.values["hint_count"] = routeParameters.hints.size();
|
||||
|
||||
reply.content.emplace_back("Number of hints: ");
|
||||
intToString(routeParameters.hints.size(), temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\n");
|
||||
|
||||
JSON::Array json_hints;
|
||||
counter = 0;
|
||||
for (const std::string ¤t_string : routeParameters.hints)
|
||||
for (const std::string ¤t_hint : routeParameters.hints)
|
||||
{
|
||||
reply.content.emplace_back(" [");
|
||||
intToString(counter, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("] ");
|
||||
reply.content.emplace_back(current_string);
|
||||
reply.content.emplace_back("\n");
|
||||
json_hints.values.push_back(current_hint);
|
||||
++counter;
|
||||
}
|
||||
reply.content.emplace_back("</pre></body></html>");
|
||||
json_result.values["hints"] = json_hints;
|
||||
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* HELLOWORLDPLUGIN_H_ */
|
||||
#endif // HELLO_WORLD_PLUGIN_H
|
||||
|
||||
+14
-51
@@ -29,10 +29,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define LOCATE_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
// locates the nearest node in the road network for a given coordinate.
|
||||
#include <string>
|
||||
|
||||
// locates the nearest node in the road network for a given coordinate.
|
||||
template <class DataFacadeT> class LocatePlugin : public BasePlugin
|
||||
{
|
||||
public:
|
||||
@@ -42,70 +44,31 @@ template <class DataFacadeT> class LocatePlugin : public BasePlugin
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
// check number of parameters
|
||||
if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid())
|
||||
if (route_parameters.coordinates.empty() ||
|
||||
!route_parameters.coordinates.front().isValid())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
// query to helpdesk
|
||||
JSON::Object json_result;
|
||||
FixedPointCoordinate result;
|
||||
std::string tmp;
|
||||
// json
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("{");
|
||||
if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(),
|
||||
result))
|
||||
{
|
||||
reply.content.emplace_back("\"status\":207,");
|
||||
reply.content.emplace_back("\"mapped_coordinate\":[]");
|
||||
json_result.values["status"] = 207;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write coordinate to stream
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("\"status\":0,");
|
||||
reply.content.emplace_back("\"mapped_coordinate\":");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.lat, tmp);
|
||||
reply.content.emplace_back("[");
|
||||
reply.content.emplace_back(tmp);
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.lon, tmp);
|
||||
reply.content.emplace_back(",");
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back("]");
|
||||
json_result.values["status"] = 0;
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(result.lat/COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(result.lon/COORDINATE_PRECISION);
|
||||
json_result.values["mapped_coordinate"] = json_coordinate;
|
||||
}
|
||||
reply.content.emplace_back("}");
|
||||
reply.headers.resize(3);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
return;
|
||||
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
+24
-71
@@ -29,10 +29,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define NEAREST_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
|
||||
@@ -41,97 +41,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
template <class DataFacadeT> class NearestPlugin : public BasePlugin
|
||||
{
|
||||
public:
|
||||
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest")
|
||||
{
|
||||
descriptor_table.emplace("", 0); // default descriptor
|
||||
descriptor_table.emplace("json", 1);
|
||||
}
|
||||
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") {}
|
||||
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
// check number of parameters
|
||||
if (route_parameters.coordinates.empty())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
if (!route_parameters.coordinates.front().isValid())
|
||||
if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
PhantomNode result;
|
||||
facade->FindPhantomNodeForCoordinate(
|
||||
route_parameters.coordinates.front(), result, route_parameters.zoom_level);
|
||||
std::vector<PhantomNode> phantom_node_vector;
|
||||
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates.front(),
|
||||
phantom_node_vector,
|
||||
route_parameters.zoom_level,
|
||||
1);
|
||||
|
||||
// json
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
JSON::Object json_result;
|
||||
if (phantom_node_vector.empty() || !phantom_node_vector.front().isValid())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("{\"status\":");
|
||||
if (SPECIAL_NODEID != result.forward_node_id)
|
||||
{
|
||||
reply.content.emplace_back("0,");
|
||||
json_result.values["status"] = 207;
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.content.emplace_back("207,");
|
||||
reply.status = http::Reply::ok;
|
||||
json_result.values["status"] = 0;
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(phantom_node_vector.front().location.lat /
|
||||
COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(phantom_node_vector.front().location.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_result.values["mapped_coordinate"] = json_coordinate;
|
||||
std::string temp_string;
|
||||
facade->GetName(phantom_node_vector.front().name_id, temp_string);
|
||||
json_result.values["name"] = temp_string;
|
||||
}
|
||||
reply.content.emplace_back("\"mapped_coordinate\":[");
|
||||
std::string temp_string;
|
||||
|
||||
if (SPECIAL_NODEID != result.forward_node_id)
|
||||
{
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.location.lat, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.location.lon, temp_string);
|
||||
reply.content.emplace_back(",");
|
||||
reply.content.emplace_back(temp_string);
|
||||
}
|
||||
reply.content.emplace_back("],\"name\":\"");
|
||||
if (SPECIAL_NODEID != result.forward_node_id)
|
||||
{
|
||||
facade->GetName(result.name_id, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
}
|
||||
reply.content.emplace_back("\"}");
|
||||
reply.headers.resize(3);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, temp_string);
|
||||
reply.headers[0].value = temp_string;
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
std::unordered_map<std::string, unsigned> descriptor_table;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
|
||||
@@ -28,8 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef TIMESTAMP_PLUGIN_H
|
||||
#define TIMESTAMP_PLUGIN_H
|
||||
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
template <class DataFacadeT> class TimestampPlugin : public BasePlugin
|
||||
{
|
||||
public:
|
||||
@@ -40,46 +43,12 @@ template <class DataFacadeT> class TimestampPlugin : public BasePlugin
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
std::string tmp;
|
||||
|
||||
// json
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("{");
|
||||
reply.content.emplace_back("\"status\":");
|
||||
reply.content.emplace_back("0,");
|
||||
reply.content.emplace_back("\"timestamp\":\"");
|
||||
reply.content.emplace_back(facade->GetTimestamp());
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back("}");
|
||||
reply.headers.resize(3);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.json\"";
|
||||
}
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
JSON::Object json_result;
|
||||
json_result.values["status"] = 0;
|
||||
const std::string timestamp = facade->GetTimestamp();
|
||||
json_result.values["timestamp"] = timestamp;
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
+173
-241
@@ -1,241 +1,173 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIAROUTEPLUGIN_H_
|
||||
#define VIAROUTEPLUGIN_H_
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
#include "../Descriptors/BaseDescriptor.h"
|
||||
#include "../Descriptors/GPXDescriptor.h"
|
||||
#include "../Descriptors/JSONDescriptor.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::unordered_map<std::string, unsigned> descriptorTable;
|
||||
std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
|
||||
public:
|
||||
explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
|
||||
{
|
||||
search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
|
||||
|
||||
descriptorTable.emplace("json", 0);
|
||||
descriptorTable.emplace("gpx", 1);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() {}
|
||||
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
|
||||
{
|
||||
// check number of parameters
|
||||
if (2 > routeParameters.coordinates.size())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
RawRouteData raw_route;
|
||||
raw_route.check_sum = facade->GetCheckSum();
|
||||
|
||||
if (std::any_of(begin(routeParameters.coordinates),
|
||||
end(routeParameters.coordinates),
|
||||
[&](FixedPointCoordinate coordinate)
|
||||
{ return !coordinate.isValid(); }))
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
|
||||
{
|
||||
raw_route.raw_via_node_coordinates.emplace_back(coordinate);
|
||||
}
|
||||
|
||||
std::vector<PhantomNode> phantom_node_vector(raw_route.raw_via_node_coordinates.size());
|
||||
const bool checksum_OK = (routeParameters.check_sum == raw_route.check_sum);
|
||||
|
||||
for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i)
|
||||
{
|
||||
if (checksum_OK && i < routeParameters.hints.size() &&
|
||||
!routeParameters.hints[i].empty())
|
||||
{
|
||||
DecodeObjectFromBase64(routeParameters.hints[i], phantom_node_vector[i]);
|
||||
if (phantom_node_vector[i].isValid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
facade->FindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
|
||||
phantom_node_vector[i],
|
||||
routeParameters.zoom_level);
|
||||
}
|
||||
|
||||
PhantomNodes current_phantom_node_pair;
|
||||
for (unsigned i = 0; i < phantom_node_vector.size() - 1; ++i)
|
||||
{
|
||||
current_phantom_node_pair.source_phantom = phantom_node_vector[i];
|
||||
current_phantom_node_pair.target_phantom = phantom_node_vector[i + 1];
|
||||
raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
||||
}
|
||||
|
||||
if ((routeParameters.alternate_route) && (1 == raw_route.segment_end_coordinates.size()))
|
||||
{
|
||||
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
|
||||
raw_route);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, raw_route);
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
|
||||
if (!routeParameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(routeParameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
|
||||
DescriptorConfig descriptor_config;
|
||||
|
||||
auto iter = descriptorTable.find(routeParameters.output_format);
|
||||
unsigned descriptor_type = (iter != descriptorTable.end() ? iter->second : 0);
|
||||
|
||||
descriptor_config.zoom_level = routeParameters.zoom_level;
|
||||
descriptor_config.instructions = routeParameters.print_instructions;
|
||||
descriptor_config.geometry = routeParameters.geometry;
|
||||
descriptor_config.encode_geometry = routeParameters.compression;
|
||||
|
||||
std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
|
||||
switch (descriptor_type)
|
||||
{
|
||||
// case 0:
|
||||
// descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
|
||||
// break;
|
||||
case 1:
|
||||
descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>();
|
||||
break;
|
||||
default:
|
||||
descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
|
||||
break;
|
||||
}
|
||||
|
||||
PhantomNodes phantom_nodes;
|
||||
phantom_nodes.source_phantom = raw_route.segment_end_coordinates.front().source_phantom;
|
||||
phantom_nodes.target_phantom = raw_route.segment_end_coordinates.back().target_phantom;
|
||||
descriptor->SetConfig(descriptor_config);
|
||||
descriptor->Run(raw_route, phantom_nodes, facade, reply);
|
||||
|
||||
if (!routeParameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")\n");
|
||||
}
|
||||
reply.headers.resize(3);
|
||||
reply.headers[0].name = "Content-Length";
|
||||
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
std::string tmp_string;
|
||||
intToString(content_length, tmp_string);
|
||||
reply.headers[0].value = tmp_string;
|
||||
|
||||
switch (descriptor_type)
|
||||
{
|
||||
case 0:
|
||||
if (!routeParameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.json\"";
|
||||
}
|
||||
|
||||
break;
|
||||
case 1:
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/gpx+xml; charset=UTF-8";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.gpx\"";
|
||||
|
||||
break;
|
||||
default:
|
||||
if (!routeParameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.json\"";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif /* VIAROUTEPLUGIN_H_ */
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIA_ROUTE_PLUGIN_H
|
||||
#define VIA_ROUTE_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
#include "../Descriptors/BaseDescriptor.h"
|
||||
#include "../Descriptors/GPXDescriptor.h"
|
||||
#include "../Descriptors/JSONDescriptor.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::unordered_map<std::string, unsigned> descriptor_table;
|
||||
std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
|
||||
public:
|
||||
explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
|
||||
{
|
||||
search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
|
||||
|
||||
descriptor_table.emplace("json", 0);
|
||||
descriptor_table.emplace("gpx", 1);
|
||||
// descriptor_table.emplace("geojson", 2);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() {}
|
||||
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
// check number of parameters
|
||||
if (2 > route_parameters.coordinates.size() ||
|
||||
std::any_of(begin(route_parameters.coordinates),
|
||||
end(route_parameters.coordinates),
|
||||
[&](FixedPointCoordinate coordinate)
|
||||
{ return !coordinate.isValid(); }))
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
RawRouteData raw_route;
|
||||
raw_route.check_sum = facade->GetCheckSum();
|
||||
for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
|
||||
{
|
||||
raw_route.raw_via_node_coordinates.emplace_back(coordinate);
|
||||
}
|
||||
|
||||
std::vector<PhantomNode> phantom_node_vector(raw_route.raw_via_node_coordinates.size());
|
||||
const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
|
||||
|
||||
for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i)
|
||||
{
|
||||
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||
!route_parameters.hints[i].empty())
|
||||
{
|
||||
DecodeObjectFromBase64(route_parameters.hints[i], phantom_node_vector[i]);
|
||||
if (phantom_node_vector[i].isValid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
facade->FindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
|
||||
phantom_node_vector[i],
|
||||
route_parameters.zoom_level);
|
||||
}
|
||||
|
||||
PhantomNodes current_phantom_node_pair;
|
||||
for (unsigned i = 0; i < phantom_node_vector.size() - 1; ++i)
|
||||
{
|
||||
current_phantom_node_pair.source_phantom = phantom_node_vector[i];
|
||||
current_phantom_node_pair.target_phantom = phantom_node_vector[i + 1];
|
||||
raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
||||
}
|
||||
|
||||
const bool is_alternate_requested = route_parameters.alternate_route;
|
||||
const bool is_only_one_segment = (1 == raw_route.segment_end_coordinates.size());
|
||||
if (is_alternate_requested && is_only_one_segment)
|
||||
{
|
||||
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
|
||||
raw_route);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, raw_route);
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
|
||||
DescriptorConfig descriptor_config;
|
||||
|
||||
auto iter = descriptor_table.find(route_parameters.output_format);
|
||||
unsigned descriptor_type = (iter != descriptor_table.end() ? iter->second : 0);
|
||||
|
||||
descriptor_config.zoom_level = route_parameters.zoom_level;
|
||||
descriptor_config.instructions = route_parameters.print_instructions;
|
||||
descriptor_config.geometry = route_parameters.geometry;
|
||||
descriptor_config.encode_geometry = route_parameters.compression;
|
||||
|
||||
std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
|
||||
switch (descriptor_type)
|
||||
{
|
||||
// case 0:
|
||||
// descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
|
||||
// break;
|
||||
case 1:
|
||||
descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(facade);
|
||||
break;
|
||||
// case 2:
|
||||
// descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
|
||||
// break;
|
||||
default:
|
||||
descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(facade);
|
||||
break;
|
||||
}
|
||||
|
||||
descriptor->SetConfig(descriptor_config);
|
||||
descriptor->Run(raw_route, reply);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif // VIA_ROUTE_PLUGIN_H
|
||||
|
||||
@@ -76,11 +76,6 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
|
||||
void operator()(const PhantomNodes &phantom_node_pair, RawRouteData &raw_route_data)
|
||||
{
|
||||
if (phantom_node_pair.PhantomNodesHaveEqualLocation())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<NodeID> alternative_path;
|
||||
std::vector<NodeID> via_node_candidate_list;
|
||||
std::vector<SearchSpaceEdge> forward_search_space;
|
||||
@@ -271,8 +266,8 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
int length_of_via_path = 0, sharing_of_via_path = 0;
|
||||
ComputeLengthAndSharingOfViaPath(
|
||||
node, &length_of_via_path, &sharing_of_via_path, packed_shortest_path);
|
||||
const int maximum_allowed_sharing =
|
||||
upper_bound_to_shortest_path_distance * VIAPATH_GAMMA;
|
||||
const int maximum_allowed_sharing = static_cast<int>(
|
||||
upper_bound_to_shortest_path_distance * VIAPATH_GAMMA);
|
||||
if (sharing_of_via_path <= maximum_allowed_sharing &&
|
||||
length_of_via_path <= upper_bound_to_shortest_path_distance * (1 + VIAPATH_EPSILON))
|
||||
{
|
||||
@@ -307,10 +302,10 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
{
|
||||
BOOST_ASSERT(!packed_shortest_path.empty());
|
||||
raw_route_data.unpacked_path_segments.resize(1);
|
||||
raw_route_data.source_traversed_in_reverse =
|
||||
(packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_node_id);
|
||||
raw_route_data.target_traversed_in_reverse =
|
||||
(packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_node_id);
|
||||
raw_route_data.source_traversed_in_reverse.push_back(
|
||||
(packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_node_id));
|
||||
raw_route_data.target_traversed_in_reverse.push_back(
|
||||
(packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_node_id));
|
||||
|
||||
super::UnpackPath(
|
||||
// -- packed input
|
||||
@@ -334,16 +329,18 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
v_t_middle,
|
||||
packed_alternate_path);
|
||||
|
||||
raw_route_data.source_traversed_in_reverse =
|
||||
(packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_node_id);
|
||||
raw_route_data.target_traversed_in_reverse =
|
||||
(packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id);
|
||||
raw_route_data.alt_source_traversed_in_reverse.push_back(
|
||||
(packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_node_id));
|
||||
raw_route_data.alt_target_traversed_in_reverse.push_back(
|
||||
(packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id));
|
||||
|
||||
// unpack the alternate path
|
||||
super::UnpackPath(
|
||||
packed_alternate_path, phantom_node_pair, raw_route_data.unpacked_alternative);
|
||||
|
||||
raw_route_data.alternative_path_length = length_of_via_path;
|
||||
} else {
|
||||
BOOST_ASSERT(raw_route_data.alternative_path_length == INVALID_EDGE_WEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,7 +576,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
{
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int distance = forward_heap.GetKey(node);
|
||||
const int scaled_distance = distance / (1. + VIAPATH_EPSILON);
|
||||
const int scaled_distance = static_cast<int>(distance / (1. + VIAPATH_EPSILON));
|
||||
if ((INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_distance) &&
|
||||
(scaled_distance > *upper_bound_to_shortest_path_distance))
|
||||
{
|
||||
@@ -604,7 +601,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
}
|
||||
}
|
||||
|
||||
for (EdgeID edge = facade->BeginEdges(node); edge < facade->EndEdges(node); ++edge)
|
||||
for (auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
const bool edge_is_forward_directed =
|
||||
@@ -641,7 +638,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
QueryHeap &new_forward_heap,
|
||||
QueryHeap &new_reverse_heap,
|
||||
const RankedCandidateNode &candidate,
|
||||
const int lengthOfShortestPath,
|
||||
const int length_of_shortest_path,
|
||||
int *length_of_via_path,
|
||||
NodeID *s_v_middle,
|
||||
NodeID *v_t_middle) const
|
||||
@@ -706,12 +703,12 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const int T_threshold = VIAPATH_EPSILON * lengthOfShortestPath;
|
||||
const int T_threshold = static_cast<int>(VIAPATH_EPSILON * length_of_shortest_path);
|
||||
int unpacked_until_distance = 0;
|
||||
|
||||
std::stack<SearchSpaceEdge> unpack_stack;
|
||||
// Traverse path s-->v
|
||||
for (unsigned i = packed_s_v_path.size() - 1; (i > 0) && unpack_stack.empty(); --i)
|
||||
for (std::size_t i = packed_s_v_path.size() - 1; (i > 0) && unpack_stack.empty(); --i)
|
||||
{
|
||||
const EdgeID current_edge_id =
|
||||
facade->FindEdgeInEitherDirection(packed_s_v_path[i - 1], packed_s_v_path[i]);
|
||||
@@ -772,11 +769,12 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
int t_test_path_length = unpacked_until_distance;
|
||||
unpacked_until_distance = 0;
|
||||
// Traverse path s-->v
|
||||
for (unsigned i = 0, packed_path_length = packed_v_t_path.size() - 1;
|
||||
BOOST_ASSERT(!packed_v_t_path.empty());
|
||||
for (unsigned i = 0, packed_path_length = static_cast<unsigned>(packed_v_t_path.size() - 1);
|
||||
(i < packed_path_length) && unpack_stack.empty();
|
||||
++i)
|
||||
{
|
||||
EdgeID edgeID =
|
||||
const EdgeID edgeID =
|
||||
facade->FindEdgeInEitherDirection(packed_v_t_path[i], packed_v_t_path[i + 1]);
|
||||
int length_of_current_edge = facade->GetEdgeData(edgeID).distance;
|
||||
if (length_of_current_edge + unpacked_until_distance >= T_threshold)
|
||||
@@ -841,7 +839,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
|
||||
forward_heap3.Insert(s_P, 0, s_P);
|
||||
reverse_heap3.Insert(t_P, 0, t_P);
|
||||
// exploration from s and t until deletemin/(1+epsilon) > _lengthOfShortestPath
|
||||
// exploration from s and t until deletemin/(1+epsilon) > _lengt_oO_sShortest_path
|
||||
while ((forward_heap3.Size() + reverse_heap3.Size()) > 0)
|
||||
{
|
||||
if (!forward_heap3.Empty())
|
||||
|
||||
@@ -87,7 +87,7 @@ template <class DataFacadeT> class BasicRoutingInterface
|
||||
}
|
||||
|
||||
// Stalling
|
||||
for (EdgeID edge = facade->BeginEdges(node); edge < facade->EndEdges(node); ++edge)
|
||||
for (auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
|
||||
@@ -108,9 +108,7 @@ template <class DataFacadeT> class BasicRoutingInterface
|
||||
}
|
||||
}
|
||||
|
||||
for (EdgeID edge = facade->BeginEdges(node), end_edge = facade->EndEdges(node);
|
||||
edge < end_edge;
|
||||
++edge)
|
||||
for (auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
|
||||
@@ -148,7 +146,7 @@ template <class DataFacadeT> class BasicRoutingInterface
|
||||
const bool target_traversed_in_reverse =
|
||||
(packed_path.back() != phantom_node_pair.target_phantom.forward_node_id);
|
||||
|
||||
const unsigned packed_path_size = packed_path.size();
|
||||
const unsigned packed_path_size = static_cast<unsigned>(packed_path.size());
|
||||
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
||||
|
||||
// We have to push the path in reverse order onto the stack because it's LIFO.
|
||||
@@ -160,6 +158,13 @@ template <class DataFacadeT> class BasicRoutingInterface
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
/*
|
||||
Graphical representation of variables:
|
||||
|
||||
edge.first edge.second
|
||||
*------------------>*
|
||||
edge_id
|
||||
*/
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
@@ -167,9 +172,7 @@ template <class DataFacadeT> class BasicRoutingInterface
|
||||
// The above explanation unclear? Think!
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = INT_MAX;
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.first);
|
||||
edge_id < facade->EndEdges(edge.first);
|
||||
++edge_id)
|
||||
for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
@@ -179,11 +182,17 @@ template <class DataFacadeT> class BasicRoutingInterface
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Graphical representation of variables:
|
||||
|
||||
edge.first edge.second
|
||||
*<------------------*
|
||||
edge_id
|
||||
*/
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.second);
|
||||
edge_id < facade->EndEdges(edge.second);
|
||||
++edge_id)
|
||||
for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
@@ -237,8 +246,7 @@ template <class DataFacadeT> class BasicRoutingInterface
|
||||
BOOST_ASSERT(start_index <= end_index);
|
||||
for (int i = start_index; i < end_index; ++i)
|
||||
{
|
||||
unpacked_path.emplace_back(PathData{
|
||||
id_vector[i], name_index, TurnInstruction::NoTurn, 0});
|
||||
unpacked_path.emplace_back(id_vector[i], name_index, TurnInstruction::NoTurn, 0);
|
||||
}
|
||||
unpacked_path.back().turn_instruction = turn_instruction;
|
||||
unpacked_path.back().segment_duration = ed.distance;
|
||||
@@ -323,9 +331,7 @@ template <class DataFacadeT> class BasicRoutingInterface
|
||||
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = INT_MAX;
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.first);
|
||||
edge_id < facade->EndEdges(edge.first);
|
||||
++edge_id)
|
||||
for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
@@ -338,9 +344,7 @@ template <class DataFacadeT> class BasicRoutingInterface
|
||||
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
for (EdgeID edge_id = facade->BeginEdges(edge.second);
|
||||
edge_id < facade->EndEdges(edge.second);
|
||||
++edge_id)
|
||||
for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MANY_TO_MANY_ROUTING_H
|
||||
#define MANY_TO_MANY_ROUTING_H
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
#include "../DataStructures/SearchEngineData.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class ManyToManyRouting : public BasicRoutingInterface<DataFacadeT>
|
||||
{
|
||||
typedef BasicRoutingInterface<DataFacadeT> super;
|
||||
typedef SearchEngineData::QueryHeap QueryHeap;
|
||||
SearchEngineData &engine_working_data;
|
||||
|
||||
struct NodeBucket
|
||||
{
|
||||
unsigned target_id; // essentially a row in the distance matrix
|
||||
EdgeWeight distance;
|
||||
NodeBucket(const unsigned target_id, const EdgeWeight distance)
|
||||
: target_id(target_id), distance(distance)
|
||||
{
|
||||
}
|
||||
};
|
||||
typedef std::unordered_map<NodeID, std::vector<NodeBucket>> SearchSpaceWithBuckets;
|
||||
|
||||
public:
|
||||
ManyToManyRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||
: super(facade), engine_working_data(engine_working_data)
|
||||
{
|
||||
}
|
||||
|
||||
~ManyToManyRouting() {}
|
||||
|
||||
std::shared_ptr<std::vector<EdgeWeight>> operator()(const PhantomNodeArray &phantom_nodes_array)
|
||||
const
|
||||
{
|
||||
const unsigned number_of_locations = static_cast<unsigned>(phantom_nodes_array.size());
|
||||
std::shared_ptr<std::vector<EdgeWeight>> result_table =
|
||||
std::make_shared<std::vector<EdgeWeight>>(number_of_locations * number_of_locations,
|
||||
std::numeric_limits<EdgeWeight>::max());
|
||||
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
|
||||
QueryHeap &query_heap = *(engine_working_data.forwardHeap);
|
||||
|
||||
SearchSpaceWithBuckets search_space_with_buckets;
|
||||
|
||||
unsigned target_id = 0;
|
||||
for (const std::vector<PhantomNode> &phantom_node_vector : phantom_nodes_array)
|
||||
{
|
||||
query_heap.Clear();
|
||||
// insert target(s) at distance 0
|
||||
|
||||
for (const PhantomNode &phantom_node : phantom_node_vector)
|
||||
{
|
||||
if (SPECIAL_NODEID != phantom_node.forward_node_id)
|
||||
{
|
||||
query_heap.Insert(phantom_node.forward_node_id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.forward_node_id);
|
||||
}
|
||||
if (SPECIAL_NODEID != phantom_node.reverse_node_id)
|
||||
{
|
||||
query_heap.Insert(phantom_node.reverse_node_id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.reverse_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
BackwardRoutingStep(target_id, query_heap, search_space_with_buckets);
|
||||
}
|
||||
++target_id;
|
||||
}
|
||||
|
||||
// for each source do forward search
|
||||
unsigned source_id = 0;
|
||||
for (const std::vector<PhantomNode> &phantom_node_vector : phantom_nodes_array)
|
||||
{
|
||||
query_heap.Clear();
|
||||
for (const PhantomNode &phantom_node : phantom_node_vector)
|
||||
{
|
||||
// insert sources at distance 0
|
||||
if (SPECIAL_NODEID != phantom_node.forward_node_id)
|
||||
{
|
||||
query_heap.Insert(phantom_node.forward_node_id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.forward_node_id);
|
||||
}
|
||||
if (SPECIAL_NODEID != phantom_node.reverse_node_id)
|
||||
{
|
||||
query_heap.Insert(phantom_node.reverse_node_id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.reverse_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
ForwardRoutingStep(source_id,
|
||||
number_of_locations,
|
||||
query_heap,
|
||||
search_space_with_buckets,
|
||||
result_table);
|
||||
}
|
||||
|
||||
++source_id;
|
||||
}
|
||||
BOOST_ASSERT(source_id == target_id);
|
||||
return result_table;
|
||||
}
|
||||
|
||||
void ForwardRoutingStep(const unsigned source_id,
|
||||
const unsigned number_of_locations,
|
||||
QueryHeap &query_heap,
|
||||
const SearchSpaceWithBuckets &search_space_with_buckets,
|
||||
std::shared_ptr<std::vector<EdgeWeight>> result_table) const
|
||||
{
|
||||
const NodeID node = query_heap.DeleteMin();
|
||||
const int source_distance = query_heap.GetKey(node);
|
||||
|
||||
// check if each encountered node has an entry
|
||||
const auto bucket_iterator = search_space_with_buckets.find(node);
|
||||
// iterate bucket if there exists one
|
||||
if (bucket_iterator != search_space_with_buckets.end())
|
||||
{
|
||||
const std::vector<NodeBucket> &bucket_list = bucket_iterator->second;
|
||||
for (const NodeBucket ¤t_bucket : bucket_list)
|
||||
{
|
||||
// get target id from bucket entry
|
||||
const unsigned target_id = current_bucket.target_id;
|
||||
const int target_distance = current_bucket.distance;
|
||||
const EdgeWeight current_distance =
|
||||
(*result_table)[source_id * number_of_locations + target_id];
|
||||
// check if new distance is better
|
||||
const EdgeWeight new_distance = source_distance + target_distance;
|
||||
if (new_distance >= 0 && new_distance < current_distance)
|
||||
{
|
||||
(*result_table)[source_id * number_of_locations + target_id] =
|
||||
(source_distance + target_distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StallAtNode<true>(node, source_distance, query_heap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
RelaxOutgoingEdges<true>(node, source_distance, query_heap);
|
||||
}
|
||||
|
||||
void BackwardRoutingStep(const unsigned target_id,
|
||||
QueryHeap &query_heap,
|
||||
SearchSpaceWithBuckets &search_space_with_buckets) const
|
||||
{
|
||||
const NodeID node = query_heap.DeleteMin();
|
||||
const int target_distance = query_heap.GetKey(node);
|
||||
|
||||
// store settled nodes in search space bucket
|
||||
search_space_with_buckets[node].emplace_back(target_id, target_distance);
|
||||
|
||||
if (StallAtNode<false>(node, target_distance, query_heap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RelaxOutgoingEdges<false>(node, target_distance, query_heap);
|
||||
}
|
||||
|
||||
template <bool forward_direction>
|
||||
inline void
|
||||
RelaxOutgoingEdges(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap) const
|
||||
{
|
||||
for (auto edge : super::facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = super::facade->GetEdgeData(edge);
|
||||
const bool direction_flag = (forward_direction ? data.forward : data.backward);
|
||||
if (direction_flag)
|
||||
{
|
||||
const NodeID to = super::facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
const int to_distance = distance + edge_weight;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!query_heap.WasInserted(to))
|
||||
{
|
||||
query_heap.Insert(to, to_distance, node);
|
||||
}
|
||||
// Found a shorter Path -> Update distance
|
||||
else if (to_distance < query_heap.GetKey(to))
|
||||
{
|
||||
// new parent
|
||||
query_heap.GetData(to).parent = node;
|
||||
query_heap.DecreaseKey(to, to_distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stalling
|
||||
template <bool forward_direction>
|
||||
inline bool StallAtNode(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap)
|
||||
const
|
||||
{
|
||||
for (auto edge : super::facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = super::facade->GetEdgeData(edge);
|
||||
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
|
||||
if (reverse_flag)
|
||||
{
|
||||
const NodeID to = super::facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
if (query_heap.WasInserted(to))
|
||||
{
|
||||
if (query_heap.GetKey(to) + edge_weight < distance)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -51,13 +51,6 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
|
||||
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
RawRouteData &raw_route_data) const
|
||||
{
|
||||
for (const PhantomNodes &phantom_node_pair : phantom_nodes_vector)
|
||||
{
|
||||
if (phantom_node_pair.AtLeastOnePhantomNodeIsInvalid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
int distance1 = 0;
|
||||
int distance2 = 0;
|
||||
bool search_from_1st_node = true;
|
||||
@@ -174,6 +167,9 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
|
||||
raw_route_data.alternative_path_length = INVALID_EDGE_WEIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
search_from_1st_node = true;
|
||||
search_from_2nd_node = true;
|
||||
if (SPECIAL_NODEID == middle1)
|
||||
{
|
||||
search_from_1st_node = false;
|
||||
@@ -242,7 +238,7 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
|
||||
}
|
||||
}
|
||||
|
||||
// remove one path if both legs end at the same segment
|
||||
// remove the shorter path if both legs end at the same segment
|
||||
if (0 < current_leg)
|
||||
{
|
||||
const NodeID start_id_of_leg1 = temporary_packed_leg1.front();
|
||||
@@ -296,13 +292,6 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
|
||||
}
|
||||
raw_route_data.unpacked_path_segments.resize(packed_legs1.size());
|
||||
|
||||
raw_route_data.source_traversed_in_reverse =
|
||||
(packed_legs1.front().front() !=
|
||||
phantom_nodes_vector.front().source_phantom.forward_node_id);
|
||||
raw_route_data.target_traversed_in_reverse =
|
||||
(packed_legs1.back().back() !=
|
||||
phantom_nodes_vector.back().target_phantom.forward_node_id);
|
||||
|
||||
for (unsigned i = 0; i < packed_legs1.size(); ++i)
|
||||
{
|
||||
BOOST_ASSERT(!phantom_nodes_vector.empty());
|
||||
@@ -316,6 +305,11 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
|
||||
unpack_phantom_node_pair,
|
||||
// -- unpacked output
|
||||
raw_route_data.unpacked_path_segments[i]);
|
||||
|
||||
raw_route_data.source_traversed_in_reverse.push_back(
|
||||
(packed_legs1[i].front() != phantom_nodes_vector[i].source_phantom.forward_node_id));
|
||||
raw_route_data.target_traversed_in_reverse.push_back(
|
||||
(packed_legs1[i].back() != phantom_nodes_vector[i].target_phantom.forward_node_id));
|
||||
}
|
||||
raw_route_data.shortest_path_length = std::min(distance1, distance2);
|
||||
}
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ struct APIGrammar : qi::grammar<Iterator>
|
||||
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
|
||||
output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
|
||||
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
|
||||
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
|
||||
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
|
||||
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
|
||||
|
||||
+84
-96
@@ -41,13 +41,10 @@ namespace http
|
||||
{
|
||||
|
||||
Connection::Connection(boost::asio::io_service &io_service, RequestHandler &handler)
|
||||
: strand(io_service), TCP_socket(io_service), request_handler(handler),
|
||||
request_parser(new RequestParser())
|
||||
: strand(io_service), TCP_socket(io_service), request_handler(handler)
|
||||
{
|
||||
}
|
||||
|
||||
Connection::~Connection() { delete request_parser; }
|
||||
|
||||
boost::asio::ip::tcp::socket &Connection::socket() { return TCP_socket; }
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
@@ -61,126 +58,117 @@ void Connection::start()
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
|
||||
void Connection::handle_read(const boost::system::error_code &e, std::size_t bytes_transferred)
|
||||
void Connection::handle_read(const boost::system::error_code &error, std::size_t bytes_transferred)
|
||||
{
|
||||
if (!e)
|
||||
if (error)
|
||||
{
|
||||
CompressionType compression_type(noCompression);
|
||||
boost::tribool result;
|
||||
boost::tie(result, boost::tuples::ignore) =
|
||||
request_parser->Parse(request,
|
||||
incoming_data_buffer.data(),
|
||||
incoming_data_buffer.data() + bytes_transferred,
|
||||
&compression_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
request.endpoint = TCP_socket.remote_endpoint().address();
|
||||
request_handler.handle_request(request, reply);
|
||||
// no error detected, let's parse the request
|
||||
CompressionType compression_type(noCompression);
|
||||
boost::tribool result;
|
||||
boost::tie(result, boost::tuples::ignore) =
|
||||
request_parser.Parse(request,
|
||||
incoming_data_buffer.data(),
|
||||
incoming_data_buffer.data() + bytes_transferred,
|
||||
&compression_type);
|
||||
|
||||
Header compression_header;
|
||||
std::vector<char> compressed_output;
|
||||
std::vector<boost::asio::const_buffer> output_buffer;
|
||||
switch (compression_type)
|
||||
{
|
||||
case deflateRFC1951:
|
||||
compression_header.name = "Content-Encoding";
|
||||
compression_header.value = "deflate";
|
||||
reply.headers.insert(reply.headers.begin(), compression_header);
|
||||
compressBufferCollection(reply.content, compression_type, compressed_output);
|
||||
reply.setSize(compressed_output.size());
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
break;
|
||||
case gzipRFC1952:
|
||||
compression_header.name = "Content-Encoding";
|
||||
compression_header.value = "gzip";
|
||||
reply.headers.insert(reply.headers.begin(), compression_header);
|
||||
compressBufferCollection(reply.content, compression_type, compressed_output);
|
||||
reply.setSize(compressed_output.size());
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
break;
|
||||
case noCompression:
|
||||
reply.SetUncompressedSize();
|
||||
output_buffer = reply.toBuffers();
|
||||
boost::asio::async_write(
|
||||
TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!result)
|
||||
{
|
||||
reply = Reply::StockReply(Reply::badRequest);
|
||||
// the request has been parsed
|
||||
if (result)
|
||||
{
|
||||
request.endpoint = TCP_socket.remote_endpoint().address();
|
||||
request_handler.handle_request(request, reply);
|
||||
|
||||
boost::asio::async_write(TCP_socket,
|
||||
reply.toBuffers(),
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
}
|
||||
else
|
||||
// Header compression_header;
|
||||
std::vector<char> compressed_output;
|
||||
std::vector<boost::asio::const_buffer> output_buffer;
|
||||
|
||||
// compress the result w/ gzip/deflate if requested
|
||||
switch (compression_type)
|
||||
{
|
||||
TCP_socket.async_read_some(
|
||||
boost::asio::buffer(incoming_data_buffer),
|
||||
strand.wrap(boost::bind(&Connection::handle_read,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
case deflateRFC1951:
|
||||
// use deflate for compression
|
||||
reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "deflate"});
|
||||
CompressBufferCollection(reply.content, compression_type, compressed_output);
|
||||
reply.SetSize(static_cast<unsigned>(compressed_output.size()));
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
||||
break;
|
||||
case gzipRFC1952:
|
||||
// use gzip for compression
|
||||
reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "gzip"});
|
||||
CompressBufferCollection(reply.content, compression_type, compressed_output);
|
||||
reply.SetSize(static_cast<unsigned>(compressed_output.size()));
|
||||
output_buffer = reply.HeaderstoBuffers();
|
||||
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
||||
break;
|
||||
case noCompression:
|
||||
// don't use any compression
|
||||
reply.SetUncompressedSize();
|
||||
output_buffer = reply.ToBuffers();
|
||||
break;
|
||||
}
|
||||
// write result to stream
|
||||
boost::asio::async_write(TCP_socket,
|
||||
output_buffer,
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
}
|
||||
else if (!result)
|
||||
{ // request is not parseable
|
||||
reply = Reply::StockReply(Reply::badRequest);
|
||||
|
||||
boost::asio::async_write(TCP_socket,
|
||||
reply.ToBuffers(),
|
||||
strand.wrap(boost::bind(&Connection::handle_write,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't have a result yet, so continue reading
|
||||
TCP_socket.async_read_some(
|
||||
boost::asio::buffer(incoming_data_buffer),
|
||||
strand.wrap(boost::bind(&Connection::handle_read,
|
||||
this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle completion of a write operation.
|
||||
void Connection::handle_write(const boost::system::error_code &e)
|
||||
void Connection::handle_write(const boost::system::error_code &error)
|
||||
{
|
||||
if (!e)
|
||||
if (!error)
|
||||
{
|
||||
// Initiate graceful connection closure.
|
||||
boost::system::error_code ignoredEC;
|
||||
TCP_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignoredEC);
|
||||
boost::system::error_code ignore_error;
|
||||
TCP_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_error);
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::compressBufferCollection(std::vector<std::string> uncompressed_data,
|
||||
void Connection::CompressBufferCollection(std::vector<char> uncompressed_data,
|
||||
CompressionType compression_type,
|
||||
std::vector<char> &compressed_data)
|
||||
{
|
||||
boost::iostreams::gzip_params compression_parameters;
|
||||
|
||||
// there's a trade-off between speed and size. speed wins
|
||||
compression_parameters.level = boost::iostreams::zlib::best_speed;
|
||||
// check which compression flavor is used
|
||||
if (deflateRFC1951 == compression_type)
|
||||
{
|
||||
compression_parameters.noheader = true;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(compressed_data.empty());
|
||||
boost::iostreams::filtering_ostream compressing_stream;
|
||||
|
||||
compressing_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
|
||||
compressing_stream.push(boost::iostreams::back_inserter(compressed_data));
|
||||
|
||||
for (const std::string &line : uncompressed_data)
|
||||
{
|
||||
compressing_stream << line;
|
||||
}
|
||||
|
||||
compressing_stream.reset();
|
||||
// plug data into boost's compression stream
|
||||
boost::iostreams::filtering_ostream gzip_stream;
|
||||
gzip_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
|
||||
gzip_stream.push(boost::iostreams::back_inserter(compressed_data));
|
||||
gzip_stream.write(&uncompressed_data[0], uncompressed_data.size());
|
||||
boost::iostreams::close(gzip_stream);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include "RequestParser.h"
|
||||
#include "Http/CompressionType.h"
|
||||
#include "Http/Request.h"
|
||||
|
||||
@@ -68,15 +69,13 @@ class RequestHandler;
|
||||
namespace http
|
||||
{
|
||||
|
||||
class RequestParser;
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
class Connection : public std::enable_shared_from_this<Connection>
|
||||
{
|
||||
public:
|
||||
explicit Connection(boost::asio::io_service &io_service, RequestHandler &handler);
|
||||
Connection(const Connection &) = delete;
|
||||
~Connection();
|
||||
Connection() = delete;
|
||||
|
||||
boost::asio::ip::tcp::socket &socket();
|
||||
|
||||
@@ -89,7 +88,7 @@ class Connection : public std::enable_shared_from_this<Connection>
|
||||
/// Handle completion of a write operation.
|
||||
void handle_write(const boost::system::error_code &e);
|
||||
|
||||
void compressBufferCollection(std::vector<std::string> uncompressed_data,
|
||||
void CompressBufferCollection(std::vector<char> uncompressed_data,
|
||||
CompressionType compression_type,
|
||||
std::vector<char> &compressed_data);
|
||||
|
||||
@@ -98,7 +97,7 @@ class Connection : public std::enable_shared_from_this<Connection>
|
||||
RequestHandler &request_handler;
|
||||
boost::array<char, 8192> incoming_data_buffer;
|
||||
Request request;
|
||||
RequestParser *request_parser;
|
||||
RequestParser request_parser;
|
||||
Reply reply;
|
||||
};
|
||||
|
||||
|
||||
@@ -38,10 +38,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../../Util/StringUtil.h"
|
||||
#include "../../typedefs.h"
|
||||
|
||||
#include <boost/range/irange.hpp>
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef decltype(boost::irange(0u,0u)) EdgeRange;
|
||||
|
||||
template <class EdgeDataT> class BaseDataFacade
|
||||
{
|
||||
public:
|
||||
@@ -67,6 +71,8 @@ template <class EdgeDataT> class BaseDataFacade
|
||||
|
||||
virtual EdgeID EndEdges(const NodeID n) const = 0;
|
||||
|
||||
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
|
||||
|
||||
// searches for a specific edge
|
||||
virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
|
||||
|
||||
@@ -95,6 +101,11 @@ template <class EdgeDataT> class BaseDataFacade
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) const = 0;
|
||||
|
||||
virtual bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
std::vector<PhantomNode> &resulting_phantom_node_vector,
|
||||
const unsigned zoom_level,
|
||||
const unsigned number_of_results) const = 0;
|
||||
|
||||
virtual unsigned GetCheckSum() const = 0;
|
||||
|
||||
virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
|
||||
|
||||
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../../DataStructures/SharedMemoryVectorWrapper.h"
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../DataStructures/RangeTable.h"
|
||||
#include "../../Util/BoostFileSystemFix.h"
|
||||
#include "../../Util/GraphLoader.h"
|
||||
#include "../../Util/ProgramOptions.h"
|
||||
@@ -66,26 +67,26 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
|
||||
ShM<unsigned, false>::vector m_name_ID_list;
|
||||
ShM<TurnInstruction, false>::vector m_turn_instruction_list;
|
||||
ShM<char, false>::vector m_names_char_list;
|
||||
ShM<unsigned, false>::vector m_name_begin_indices;
|
||||
ShM<bool, false>::vector m_egde_is_compressed;
|
||||
ShM<unsigned, false>::vector m_geometry_indices;
|
||||
ShM<unsigned, false>::vector m_geometry_list;
|
||||
|
||||
std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>>
|
||||
m_static_rtree;
|
||||
RangeTable<16, false> m_name_table;
|
||||
|
||||
void LoadTimestamp(const boost::filesystem::path ×tamp_path)
|
||||
{
|
||||
if (boost::filesystem::exists(timestamp_path))
|
||||
{
|
||||
SimpleLogger().Write() << "Loading Timestamp";
|
||||
boost::filesystem::ifstream timestampInStream(timestamp_path);
|
||||
if (!timestampInStream)
|
||||
boost::filesystem::ifstream timestamp_stream(timestamp_path);
|
||||
if (!timestamp_stream)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
|
||||
}
|
||||
getline(timestampInStream, m_timestamp);
|
||||
timestampInStream.close();
|
||||
getline(timestamp_stream, m_timestamp);
|
||||
timestamp_stream.close();
|
||||
}
|
||||
if (m_timestamp.empty())
|
||||
{
|
||||
@@ -165,23 +166,29 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
|
||||
|
||||
void LoadGeometries(const boost::filesystem::path &geometry_file)
|
||||
{
|
||||
std::ifstream geometry_stream(geometry_file.c_str(), std::ios::binary);
|
||||
std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
|
||||
unsigned number_of_indices = 0;
|
||||
unsigned number_of_compressed_geometries = 0;
|
||||
|
||||
geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
|
||||
|
||||
m_geometry_indices.resize(number_of_indices);
|
||||
geometry_stream.read((char *)&(m_geometry_indices[0]),
|
||||
number_of_indices * sizeof(unsigned));
|
||||
if (number_of_indices > 0)
|
||||
{
|
||||
geometry_stream.read((char *)&(m_geometry_indices[0]),
|
||||
number_of_indices * sizeof(unsigned));
|
||||
}
|
||||
|
||||
geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
|
||||
|
||||
BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
|
||||
m_geometry_list.resize(number_of_compressed_geometries);
|
||||
|
||||
geometry_stream.read((char *)&(m_geometry_list[0]),
|
||||
number_of_compressed_geometries * sizeof(unsigned));
|
||||
if (number_of_compressed_geometries > 0)
|
||||
{
|
||||
geometry_stream.read((char *)&(m_geometry_list[0]),
|
||||
number_of_compressed_geometries * sizeof(unsigned));
|
||||
}
|
||||
geometry_stream.close();
|
||||
}
|
||||
|
||||
@@ -197,19 +204,18 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
|
||||
void LoadStreetNames(const boost::filesystem::path &names_file)
|
||||
{
|
||||
boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
|
||||
unsigned number_of_names = 0;
|
||||
|
||||
name_stream >> m_name_table;
|
||||
|
||||
unsigned number_of_chars = 0;
|
||||
name_stream.read((char *)&number_of_names, sizeof(unsigned));
|
||||
name_stream.read((char *)&number_of_chars, sizeof(unsigned));
|
||||
BOOST_ASSERT_MSG(0 != number_of_names, "name file broken");
|
||||
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
|
||||
|
||||
m_name_begin_indices.resize(number_of_names);
|
||||
name_stream.read((char *)&m_name_begin_indices[0], number_of_names * sizeof(unsigned));
|
||||
|
||||
m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
|
||||
name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
|
||||
BOOST_ASSERT_MSG(0 != m_names_char_list.size(), "could not load any names");
|
||||
if (0 == m_names_char_list.size())
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "list of street names is empty";
|
||||
}
|
||||
name_stream.close();
|
||||
}
|
||||
|
||||
@@ -279,16 +285,23 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
|
||||
|
||||
// load data
|
||||
SimpleLogger().Write() << "loading graph data";
|
||||
AssertPathExists(hsgr_path);
|
||||
LoadGraph(hsgr_path);
|
||||
SimpleLogger().Write() << "loading egde information";
|
||||
AssertPathExists(nodes_data_path);
|
||||
AssertPathExists(edges_data_path);
|
||||
LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
|
||||
SimpleLogger().Write() << "loading geometries";
|
||||
AssertPathExists(geometries_path);
|
||||
LoadGeometries(geometries_path);
|
||||
SimpleLogger().Write() << "loading r-tree";
|
||||
AssertPathExists(ram_index_path);
|
||||
AssertPathExists(file_index_path);
|
||||
LoadRTree(ram_index_path, file_index_path);
|
||||
SimpleLogger().Write() << "loading timestamp";
|
||||
LoadTimestamp(timestamp_path);
|
||||
SimpleLogger().Write() << "loading street names";
|
||||
AssertPathExists(names_data_path);
|
||||
LoadStreetNames(names_data_path);
|
||||
}
|
||||
|
||||
@@ -309,6 +322,11 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
|
||||
|
||||
EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const
|
||||
{
|
||||
return m_query_graph->GetAdjacentEdgeRange(node);
|
||||
};
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeID FindEdge(const NodeID from, const NodeID to) const
|
||||
{
|
||||
@@ -350,9 +368,18 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) const
|
||||
{
|
||||
const bool found = m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
return m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node, zoom_level);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool
|
||||
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
std::vector<PhantomNode> &resulting_phantom_node_vector,
|
||||
const unsigned zoom_level,
|
||||
const unsigned number_of_results) const
|
||||
{
|
||||
return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const { return m_check_sum; }
|
||||
@@ -369,18 +396,16 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
|
||||
result = "";
|
||||
return;
|
||||
}
|
||||
BOOST_ASSERT_MSG(name_id < m_name_begin_indices.size(), "name id too high");
|
||||
const unsigned begin_index = m_name_begin_indices[name_id];
|
||||
const unsigned end_index = m_name_begin_indices[name_id + 1];
|
||||
BOOST_ASSERT_MSG(begin_index < m_names_char_list.size(), "begin index of name too high");
|
||||
BOOST_ASSERT_MSG(end_index < m_names_char_list.size(), "end index of name too high");
|
||||
auto range = m_name_table.GetRange(name_id);
|
||||
|
||||
BOOST_ASSERT_MSG(begin_index <= end_index, "string ends before begin");
|
||||
result.clear();
|
||||
result.resize(end_index - begin_index);
|
||||
std::copy(m_names_char_list.begin() + begin_index,
|
||||
m_names_char_list.begin() + end_index,
|
||||
result.begin());
|
||||
if (range.begin() != range.end())
|
||||
{
|
||||
result.resize(range.back() - range.front() + 1);
|
||||
std::copy(m_names_char_list.begin() + range.front(),
|
||||
m_names_char_list.begin() + range.back() + 1,
|
||||
result.begin());
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const
|
||||
|
||||
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "BaseDataFacade.h"
|
||||
#include "SharedDataType.h"
|
||||
|
||||
#include "../../DataStructures/RangeTable.h"
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../Util/BoostFileSystemFix.h"
|
||||
@@ -51,6 +52,7 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
|
||||
typedef StaticGraph<EdgeData, true> QueryGraph;
|
||||
typedef typename StaticGraph<EdgeData, true>::NodeArrayEntry GraphNode;
|
||||
typedef typename StaticGraph<EdgeData, true>::EdgeArrayEntry GraphEdge;
|
||||
typedef typename RangeTable<16, true>::BlockT NameIndexBlock;
|
||||
typedef typename QueryGraph::InputEdge InputEdge;
|
||||
typedef typename super::RTreeLeaf RTreeLeaf;
|
||||
typedef typename StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode
|
||||
@@ -84,101 +86,126 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
|
||||
std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>
|
||||
m_static_rtree;
|
||||
|
||||
std::shared_ptr<RangeTable<16, true>> m_name_table;
|
||||
|
||||
void LoadChecksum()
|
||||
{
|
||||
m_check_sum =
|
||||
*data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::HSGR_CHECKSUM);
|
||||
SimpleLogger().Write() << "set checksum: " << m_check_sum;
|
||||
}
|
||||
|
||||
void LoadTimestamp()
|
||||
{
|
||||
char *timestamp_ptr = shared_memory + data_layout->GetTimeStampOffset();
|
||||
m_timestamp.resize(data_layout->timestamp_length);
|
||||
std::copy(
|
||||
timestamp_ptr, timestamp_ptr + data_layout->timestamp_length, m_timestamp.begin());
|
||||
char *timestamp_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::TIMESTAMP);
|
||||
m_timestamp.resize(data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP));
|
||||
std::copy(timestamp_ptr,
|
||||
timestamp_ptr + data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP),
|
||||
m_timestamp.begin());
|
||||
}
|
||||
|
||||
void LoadRTree(const boost::filesystem::path &file_index_path)
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
RTreeNode *tree_ptr = (RTreeNode *)(shared_memory + data_layout->GetRSearchTreeOffset());
|
||||
RTreeNode *tree_ptr =
|
||||
data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
|
||||
m_static_rtree =
|
||||
std::make_shared<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>(
|
||||
tree_ptr, data_layout->r_search_tree_size, file_index_path, m_coordinate_list);
|
||||
tree_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
|
||||
file_index_path,
|
||||
m_coordinate_list);
|
||||
}
|
||||
|
||||
void LoadGraph()
|
||||
{
|
||||
m_number_of_nodes = data_layout->graph_node_list_size;
|
||||
m_number_of_nodes = data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST];
|
||||
GraphNode *graph_nodes_ptr =
|
||||
(GraphNode *)(shared_memory + data_layout->GetGraphNodeListOffset());
|
||||
data_layout->GetBlockPtr<GraphNode>(shared_memory, SharedDataLayout::GRAPH_NODE_LIST);
|
||||
|
||||
GraphEdge *graph_edges_ptr =
|
||||
(GraphEdge *)(shared_memory + data_layout->GetGraphEdgeListOffset());
|
||||
data_layout->GetBlockPtr<GraphEdge>(shared_memory, SharedDataLayout::GRAPH_EDGE_LIST);
|
||||
|
||||
typename ShM<GraphNode, true>::vector node_list(graph_nodes_ptr,
|
||||
data_layout->graph_node_list_size);
|
||||
typename ShM<GraphEdge, true>::vector edge_list(graph_edges_ptr,
|
||||
data_layout->graph_edge_list_size);
|
||||
typename ShM<GraphNode, true>::vector node_list(
|
||||
graph_nodes_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST]);
|
||||
typename ShM<GraphEdge, true>::vector edge_list(
|
||||
graph_edges_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_EDGE_LIST]);
|
||||
m_query_graph.reset(new QueryGraph(node_list, edge_list));
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation()
|
||||
{
|
||||
|
||||
FixedPointCoordinate *coordinate_list_ptr =
|
||||
(FixedPointCoordinate *)(shared_memory + data_layout->GetCoordinateListOffset());
|
||||
FixedPointCoordinate *coordinate_list_ptr = data_layout->GetBlockPtr<FixedPointCoordinate>(
|
||||
shared_memory, SharedDataLayout::COORDINATE_LIST);
|
||||
m_coordinate_list = std::make_shared<ShM<FixedPointCoordinate, true>::vector>(
|
||||
coordinate_list_ptr, data_layout->coordinate_list_size);
|
||||
coordinate_list_ptr, data_layout->num_entries[SharedDataLayout::COORDINATE_LIST]);
|
||||
|
||||
TurnInstruction *turn_instruction_list_ptr =
|
||||
(TurnInstruction *)(shared_memory + data_layout->GetTurnInstructionListOffset());
|
||||
TurnInstruction *turn_instruction_list_ptr = data_layout->GetBlockPtr<TurnInstruction>(
|
||||
shared_memory, SharedDataLayout::TURN_INSTRUCTION);
|
||||
typename ShM<TurnInstruction, true>::vector turn_instruction_list(
|
||||
turn_instruction_list_ptr, data_layout->turn_instruction_list_size);
|
||||
turn_instruction_list_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::TURN_INSTRUCTION]);
|
||||
m_turn_instruction_list.swap(turn_instruction_list);
|
||||
|
||||
unsigned *name_id_list_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetNameIDListOffset());
|
||||
typename ShM<unsigned, true>::vector name_id_list(name_id_list_ptr,
|
||||
data_layout->name_id_list_size);
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_ID_LIST);
|
||||
typename ShM<unsigned, true>::vector name_id_list(
|
||||
name_id_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_ID_LIST]);
|
||||
m_name_ID_list.swap(name_id_list);
|
||||
}
|
||||
|
||||
void LoadViaNodeList()
|
||||
{
|
||||
NodeID *via_node_list_ptr = (NodeID *)(shared_memory + data_layout->GetViaNodeListOffset());
|
||||
typename ShM<NodeID, true>::vector via_node_list(via_node_list_ptr,
|
||||
data_layout->via_node_list_size);
|
||||
NodeID *via_node_list_ptr =
|
||||
data_layout->GetBlockPtr<NodeID>(shared_memory, SharedDataLayout::VIA_NODE_LIST);
|
||||
typename ShM<NodeID, true>::vector via_node_list(
|
||||
via_node_list_ptr, data_layout->num_entries[SharedDataLayout::VIA_NODE_LIST]);
|
||||
m_via_node_list.swap(via_node_list);
|
||||
}
|
||||
|
||||
void LoadNames()
|
||||
{
|
||||
unsigned *street_names_index_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetNameIndexOffset());
|
||||
typename ShM<unsigned, true>::vector name_begin_indices(street_names_index_ptr,
|
||||
data_layout->name_index_list_size);
|
||||
m_name_begin_indices.swap(name_begin_indices);
|
||||
unsigned *offsets_ptr =
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_OFFSETS);
|
||||
NameIndexBlock *blocks_ptr =
|
||||
data_layout->GetBlockPtr<NameIndexBlock>(shared_memory, SharedDataLayout::NAME_BLOCKS);
|
||||
typename ShM<unsigned, true>::vector name_offsets(
|
||||
offsets_ptr, data_layout->num_entries[SharedDataLayout::NAME_OFFSETS]);
|
||||
typename ShM<NameIndexBlock, true>::vector name_blocks(
|
||||
blocks_ptr, data_layout->num_entries[SharedDataLayout::NAME_BLOCKS]);
|
||||
|
||||
char *names_list_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::NAME_CHAR_LIST);
|
||||
typename ShM<char, true>::vector names_char_list(
|
||||
names_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_CHAR_LIST]);
|
||||
m_name_table = std::make_shared<RangeTable<16, true>>(
|
||||
name_offsets, name_blocks, names_char_list.size());
|
||||
|
||||
char *names_list_ptr = (char *)(shared_memory + data_layout->GetNameListOffset());
|
||||
typename ShM<char, true>::vector names_char_list(names_list_ptr,
|
||||
data_layout->name_char_list_size);
|
||||
m_names_char_list.swap(names_char_list);
|
||||
}
|
||||
|
||||
void LoadGeometries()
|
||||
{
|
||||
unsigned *geometries_compressed_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetGeometriesIndicatorOffset());
|
||||
typename ShM<bool, true>::vector egde_is_compressed(geometries_compressed_ptr,
|
||||
data_layout->geometries_indicators);
|
||||
unsigned *geometries_compressed_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
shared_memory, SharedDataLayout::GEOMETRIES_INDICATORS);
|
||||
typename ShM<bool, true>::vector egde_is_compressed(
|
||||
geometries_compressed_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDICATORS]);
|
||||
m_egde_is_compressed.swap(egde_is_compressed);
|
||||
|
||||
unsigned *geometries_index_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetGeometriesIndexListOffset());
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_INDEX);
|
||||
typename ShM<unsigned, true>::vector geometry_begin_indices(
|
||||
geometries_index_ptr, data_layout->geometries_index_list_size);
|
||||
geometries_index_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDEX]);
|
||||
m_geometry_indices.swap(geometry_begin_indices);
|
||||
|
||||
unsigned *geometries_list_ptr =
|
||||
(unsigned *)(shared_memory + data_layout->GetGeometryListOffset());
|
||||
typename ShM<unsigned, true>::vector geometry_list(geometries_list_ptr,
|
||||
data_layout->geometries_list_size);
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_LIST);
|
||||
typename ShM<unsigned, true>::vector geometry_list(
|
||||
geometries_list_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_LIST]);
|
||||
m_geometry_list.swap(geometry_list);
|
||||
}
|
||||
|
||||
@@ -213,20 +240,29 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
|
||||
m_layout_memory.reset(SharedMemoryFactory::Get(CURRENT_LAYOUT));
|
||||
|
||||
data_layout = (SharedDataLayout *)(m_layout_memory->Ptr());
|
||||
boost::filesystem::path ram_index_path(data_layout->ram_index_file_name);
|
||||
if (!boost::filesystem::exists(ram_index_path))
|
||||
{
|
||||
throw OSRMException("no leaf index file given. "
|
||||
"Is any data loaded into shared memory?");
|
||||
}
|
||||
|
||||
m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
|
||||
shared_memory = (char *)(m_large_memory->Ptr());
|
||||
|
||||
std::ofstream out("debug.bin");
|
||||
out.write(shared_memory, data_layout->GetSizeOfLayout());
|
||||
out.close();
|
||||
|
||||
const char *file_index_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
|
||||
boost::filesystem::path file_index_path(file_index_ptr);
|
||||
if (!boost::filesystem::exists(file_index_path))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
|
||||
throw OSRMException("Could not load leaf index file."
|
||||
"Is any data loaded into shared memory?");
|
||||
}
|
||||
|
||||
LoadGraph();
|
||||
LoadChecksum();
|
||||
LoadNodeAndEdgeInformation();
|
||||
LoadGeometries();
|
||||
LoadRTree(ram_index_path);
|
||||
LoadRTree(file_index_path);
|
||||
LoadTimestamp();
|
||||
LoadViaNodeList();
|
||||
LoadNames();
|
||||
@@ -254,6 +290,11 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
|
||||
|
||||
EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const
|
||||
{
|
||||
return m_query_graph->GetAdjacentEdgeRange(node);
|
||||
};
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeID FindEdge(const NodeID from, const NodeID to) const
|
||||
{
|
||||
@@ -311,9 +352,18 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
|
||||
PhantomNode &resulting_phantom_node,
|
||||
const unsigned zoom_level) const
|
||||
{
|
||||
const bool found = m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
return m_static_rtree->FindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node, zoom_level);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool
|
||||
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
|
||||
std::vector<PhantomNode> &resulting_phantom_node_vector,
|
||||
const unsigned zoom_level,
|
||||
const unsigned number_of_results) const
|
||||
{
|
||||
return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
|
||||
input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const { return m_check_sum; }
|
||||
@@ -330,18 +380,16 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
|
||||
result = "";
|
||||
return;
|
||||
}
|
||||
BOOST_ASSERT_MSG(name_id < m_name_begin_indices.size(), "name id too high");
|
||||
const unsigned begin_index = m_name_begin_indices[name_id];
|
||||
const unsigned end_index = m_name_begin_indices[name_id + 1];
|
||||
BOOST_ASSERT_MSG(begin_index <= m_names_char_list.size(), "begin index of name too high");
|
||||
BOOST_ASSERT_MSG(end_index <= m_names_char_list.size(), "end index of name too high");
|
||||
auto range = m_name_table->GetRange(name_id);
|
||||
|
||||
BOOST_ASSERT_MSG(begin_index <= end_index, "string ends before begin");
|
||||
result.clear();
|
||||
result.resize(end_index - begin_index);
|
||||
std::copy(m_names_char_list.begin() + begin_index,
|
||||
m_names_char_list.begin() + end_index,
|
||||
result.begin());
|
||||
if (range.begin() != range.end())
|
||||
{
|
||||
result.resize(range.back() - range.front() + 1);
|
||||
std::copy(m_names_char_list.begin() + range.front(),
|
||||
m_names_char_list.begin() + range.back() + 1,
|
||||
result.begin());
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const { return m_timestamp; }
|
||||
|
||||
@@ -28,229 +28,146 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef SHARED_DATA_TYPE_H_
|
||||
#define SHARED_DATA_TYPE_H_
|
||||
|
||||
#include "BaseDataFacade.h"
|
||||
|
||||
#include "../../DataStructures/QueryEdge.h"
|
||||
#include "../../DataStructures/StaticGraph.h"
|
||||
#include "../../DataStructures/StaticRTree.h"
|
||||
#include "../../DataStructures/TurnInstructions.h"
|
||||
|
||||
#include "../../typedefs.h"
|
||||
|
||||
#include <osrm/Coordinate.h>
|
||||
#include "../../Util/OSRMException.h"
|
||||
#include "../../Util/SimpleLogger.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
typedef BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf RTreeLeaf;
|
||||
typedef StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode RTreeNode;
|
||||
typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
|
||||
#include <array>
|
||||
|
||||
// Added at the start and end of each block as sanity check
|
||||
constexpr char CANARY[] = "OSRM";
|
||||
|
||||
struct SharedDataLayout
|
||||
{
|
||||
uint64_t name_index_list_size;
|
||||
uint64_t name_char_list_size;
|
||||
uint64_t name_id_list_size;
|
||||
uint64_t via_node_list_size;
|
||||
uint64_t graph_node_list_size;
|
||||
uint64_t graph_edge_list_size;
|
||||
uint64_t coordinate_list_size;
|
||||
uint64_t turn_instruction_list_size;
|
||||
uint64_t r_search_tree_size;
|
||||
uint64_t geometries_index_list_size;
|
||||
uint64_t geometries_list_size;
|
||||
uint64_t geometries_indicators;
|
||||
enum BlockID {
|
||||
NAME_OFFSETS = 0,
|
||||
NAME_BLOCKS,
|
||||
NAME_CHAR_LIST,
|
||||
NAME_ID_LIST,
|
||||
VIA_NODE_LIST,
|
||||
GRAPH_NODE_LIST,
|
||||
GRAPH_EDGE_LIST,
|
||||
COORDINATE_LIST,
|
||||
TURN_INSTRUCTION,
|
||||
R_SEARCH_TREE,
|
||||
GEOMETRIES_INDEX,
|
||||
GEOMETRIES_LIST,
|
||||
GEOMETRIES_INDICATORS,
|
||||
HSGR_CHECKSUM,
|
||||
TIMESTAMP,
|
||||
FILE_INDEX_PATH,
|
||||
NUM_BLOCKS
|
||||
};
|
||||
|
||||
unsigned checksum;
|
||||
unsigned timestamp_length;
|
||||
|
||||
char ram_index_file_name[1024];
|
||||
std::array<uint64_t, NUM_BLOCKS> num_entries;
|
||||
std::array<uint64_t, NUM_BLOCKS> entry_size;
|
||||
|
||||
SharedDataLayout()
|
||||
: name_index_list_size(0), name_char_list_size(0), name_id_list_size(0),
|
||||
via_node_list_size(0), graph_node_list_size(0), graph_edge_list_size(0),
|
||||
coordinate_list_size(0), turn_instruction_list_size(0), r_search_tree_size(0),
|
||||
geometries_index_list_size(0), geometries_list_size(0), geometries_indicators(0),
|
||||
checksum(0), timestamp_length(0)
|
||||
|
||||
: num_entries()
|
||||
, entry_size()
|
||||
{
|
||||
ram_index_file_name[0] = '\0';
|
||||
}
|
||||
|
||||
void PrintInformation() const
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "-";
|
||||
SimpleLogger().Write(logDEBUG) << "name_index_list_size: " << name_index_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "name_char_list_size: " << name_char_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "name_id_list_size: " << name_id_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "via_node_list_size: " << via_node_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "graph_node_list_size: " << graph_node_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "graph_edge_list_size: " << graph_edge_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "timestamp_length: " << timestamp_length;
|
||||
SimpleLogger().Write(logDEBUG) << "coordinate_list_size: " << coordinate_list_size;
|
||||
SimpleLogger().Write(logDEBUG)
|
||||
<< "turn_instruction_list_size: " << turn_instruction_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "r_search_tree_size: " << r_search_tree_size;
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_indicators: " << geometries_indicators
|
||||
<< "/" << ((geometries_indicators / 8) + 1);
|
||||
SimpleLogger().Write(logDEBUG)
|
||||
<< "geometries_index_list_size: " << geometries_index_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_list_size: " << geometries_list_size;
|
||||
SimpleLogger().Write(logDEBUG) << "sizeof(checksum): " << sizeof(checksum);
|
||||
SimpleLogger().Write(logDEBUG) << "ram index file name: " << ram_index_file_name;
|
||||
SimpleLogger().Write(logDEBUG) << "name_offsets_size: " << num_entries[NAME_OFFSETS];
|
||||
SimpleLogger().Write(logDEBUG) << "name_blocks_size: " << num_entries[NAME_BLOCKS];
|
||||
SimpleLogger().Write(logDEBUG) << "name_char_list_size: " << num_entries[NAME_CHAR_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "name_id_list_size: " << num_entries[NAME_ID_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "via_node_list_size: " << num_entries[VIA_NODE_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "graph_node_list_size: " << num_entries[GRAPH_NODE_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "graph_edge_list_size: " << num_entries[GRAPH_EDGE_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "timestamp_length: " << num_entries[TIMESTAMP];
|
||||
SimpleLogger().Write(logDEBUG) << "coordinate_list_size: " << num_entries[COORDINATE_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "turn_instruction_list_size: " << num_entries[TURN_INSTRUCTION];
|
||||
SimpleLogger().Write(logDEBUG) << "r_search_tree_size: " << num_entries[R_SEARCH_TREE];
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_indicators: " << num_entries[GEOMETRIES_INDICATORS]
|
||||
<< "/" << ((num_entries[GEOMETRIES_INDICATORS] / 8) + 1);
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_index_list_size: " << num_entries[GEOMETRIES_INDEX];
|
||||
SimpleLogger().Write(logDEBUG) << "geometries_list_size: " << num_entries[GEOMETRIES_LIST];
|
||||
SimpleLogger().Write(logDEBUG) << "sizeof(checksum): " << entry_size[HSGR_CHECKSUM];
|
||||
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_OFFSETS " << ": " << GetBlockSize(NAME_OFFSETS );
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_BLOCKS " << ": " << GetBlockSize(NAME_BLOCKS );
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_CHAR_LIST " << ": " << GetBlockSize(NAME_CHAR_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_ID_LIST " << ": " << GetBlockSize(NAME_ID_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "VIA_NODE_LIST " << ": " << GetBlockSize(VIA_NODE_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "GRAPH_NODE_LIST " << ": " << GetBlockSize(GRAPH_NODE_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "GRAPH_EDGE_LIST " << ": " << GetBlockSize(GRAPH_EDGE_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "COORDINATE_LIST " << ": " << GetBlockSize(COORDINATE_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "TURN_INSTRUCTION " << ": " << GetBlockSize(TURN_INSTRUCTION );
|
||||
SimpleLogger().Write(logDEBUG) << "R_SEARCH_TREE " << ": " << GetBlockSize(R_SEARCH_TREE );
|
||||
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDEX " << ": " << GetBlockSize(GEOMETRIES_INDEX );
|
||||
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_LIST " << ": " << GetBlockSize(GEOMETRIES_LIST );
|
||||
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDICATORS" << ": " << GetBlockSize(GEOMETRIES_INDICATORS);
|
||||
SimpleLogger().Write(logDEBUG) << "HSGR_CHECKSUM " << ": " << GetBlockSize(HSGR_CHECKSUM );
|
||||
SimpleLogger().Write(logDEBUG) << "TIMESTAMP " << ": " << GetBlockSize(TIMESTAMP );
|
||||
SimpleLogger().Write(logDEBUG) << "FILE_INDEX_PATH " << ": " << GetBlockSize(FILE_INDEX_PATH );
|
||||
}
|
||||
|
||||
uint64_t GetSizeOfLayout() const
|
||||
template<typename T>
|
||||
inline void SetBlockSize(BlockID bid, uint64_t entries)
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode)) +
|
||||
(geometries_indicators / 32 + 1) * sizeof(unsigned) +
|
||||
(geometries_index_list_size * sizeof(unsigned)) +
|
||||
(geometries_list_size * sizeof(unsigned)) + sizeof(checksum) + 1024 * sizeof(char);
|
||||
num_entries[bid] = entries;
|
||||
entry_size[bid] = sizeof(T);
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockSize(BlockID bid) const
|
||||
{
|
||||
// special encoding
|
||||
if (bid == GEOMETRIES_INDICATORS)
|
||||
{
|
||||
return (num_entries[GEOMETRIES_INDICATORS]/32 + 1) * entry_size[GEOMETRIES_INDICATORS];
|
||||
}
|
||||
|
||||
return num_entries[bid] * entry_size[bid];
|
||||
}
|
||||
|
||||
inline uint64_t GetSizeOfLayout() const
|
||||
{
|
||||
return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS*2*sizeof(CANARY);
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockOffset(BlockID bid) const
|
||||
{
|
||||
uint64_t result = sizeof(CANARY);
|
||||
for (auto i = 0; i < bid; i++)
|
||||
{
|
||||
result += GetBlockSize((BlockID) i) + 2*sizeof(CANARY);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t GetNameIndexOffset() const { return 0; }
|
||||
uint64_t GetNameListOffset() const
|
||||
template<typename T, bool WRITE_CANARY=false>
|
||||
inline T* GetBlockPtr(char* shared_memory, BlockID bid)
|
||||
{
|
||||
uint64_t result = (name_index_list_size * sizeof(unsigned));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetNameIDListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetViaNodeListOffset() const
|
||||
{
|
||||
uint64_t result = (name_index_list_size * sizeof(unsigned)) +
|
||||
(name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetGraphNodeListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetGraphEdgeListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetTimeStampOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetCoordinateListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetTurnInstructionListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetRSearchTreeOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetGeometriesIndicatorOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode));
|
||||
return result;
|
||||
}
|
||||
T* ptr = (T*)(shared_memory + GetBlockOffset(bid));
|
||||
if (WRITE_CANARY)
|
||||
{
|
||||
char* start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
|
||||
char* end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
|
||||
std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
|
||||
std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
char* start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
|
||||
char* end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
|
||||
bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
|
||||
bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
|
||||
if (!start_canary_alive)
|
||||
{
|
||||
throw OSRMException("Start canary of block corrupted.");
|
||||
}
|
||||
if (!end_canary_alive)
|
||||
{
|
||||
throw OSRMException("End canary of block corrupted.");
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t GetGeometriesIndexListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode)) +
|
||||
(geometries_indicators / 32 + 1) * sizeof(unsigned);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t GetGeometryListOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode)) +
|
||||
(geometries_indicators / 32 + 1) * sizeof(unsigned) +
|
||||
(geometries_index_list_size * sizeof(unsigned));
|
||||
return result;
|
||||
}
|
||||
uint64_t GetChecksumOffset() const
|
||||
{
|
||||
uint64_t result =
|
||||
(name_index_list_size * sizeof(unsigned)) + (name_char_list_size * sizeof(char)) +
|
||||
(name_id_list_size * sizeof(unsigned)) + (via_node_list_size * sizeof(NodeID)) +
|
||||
(graph_node_list_size * sizeof(QueryGraph::NodeArrayEntry)) +
|
||||
(graph_edge_list_size * sizeof(QueryGraph::EdgeArrayEntry)) +
|
||||
(timestamp_length * sizeof(char)) +
|
||||
(coordinate_list_size * sizeof(FixedPointCoordinate)) +
|
||||
(turn_instruction_list_size * sizeof(TurnInstructionsClass)) +
|
||||
(r_search_tree_size * sizeof(RTreeNode)) +
|
||||
(geometries_indicators / 32 + 1) * sizeof(unsigned) +
|
||||
(geometries_index_list_size * sizeof(unsigned)) +
|
||||
(geometries_list_size * sizeof(unsigned));
|
||||
return result;
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+15
-31
@@ -32,29 +32,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
namespace http
|
||||
{
|
||||
|
||||
void Reply::setSize(const unsigned size)
|
||||
void Reply::SetSize(const unsigned size)
|
||||
{
|
||||
for (Header &h : headers)
|
||||
{
|
||||
if ("Content-Length" == h.name)
|
||||
{
|
||||
intToString(size, h.value);
|
||||
h.value = UintToString(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the size of the uncompressed output.
|
||||
void Reply::SetUncompressedSize()
|
||||
{
|
||||
unsigned uncompressed_size = 0;
|
||||
for (const std::string ¤t_line : content)
|
||||
{
|
||||
uncompressed_size += current_line.size();
|
||||
}
|
||||
setSize(uncompressed_size);
|
||||
}
|
||||
void Reply::SetUncompressedSize() { SetSize(static_cast<unsigned>(content.size())); }
|
||||
|
||||
std::vector<boost::asio::const_buffer> Reply::toBuffers()
|
||||
std::vector<boost::asio::const_buffer> Reply::ToBuffers()
|
||||
{
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.push_back(ToBuffer(status));
|
||||
@@ -66,10 +58,7 @@ std::vector<boost::asio::const_buffer> Reply::toBuffers()
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(crlf));
|
||||
for (const std::string &line : content)
|
||||
{
|
||||
buffers.push_back(boost::asio::buffer(line));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(content));
|
||||
return buffers;
|
||||
}
|
||||
|
||||
@@ -91,22 +80,17 @@ std::vector<boost::asio::const_buffer> Reply::HeaderstoBuffers()
|
||||
|
||||
Reply Reply::StockReply(Reply::status_type status)
|
||||
{
|
||||
Reply rep;
|
||||
rep.status = status;
|
||||
rep.content.clear();
|
||||
rep.content.push_back(rep.ToString(status));
|
||||
rep.headers.resize(3);
|
||||
rep.headers[0].name = "Access-Control-Allow-Origin";
|
||||
rep.headers[0].value = "*";
|
||||
rep.headers[1].name = "Content-Length";
|
||||
Reply reply;
|
||||
reply.status = status;
|
||||
reply.content.clear();
|
||||
|
||||
std::string size_string;
|
||||
intToString(rep.content.size(), size_string);
|
||||
|
||||
rep.headers[1].value = size_string;
|
||||
rep.headers[2].name = "Content-Type";
|
||||
rep.headers[2].value = "text/html";
|
||||
return rep;
|
||||
const std::string status_string = reply.ToString(status);
|
||||
reply.content.insert(reply.content.end(), status_string.begin(), status_string.end());
|
||||
reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
|
||||
reply.headers.emplace_back("Content-Length",
|
||||
UintToString(static_cast<unsigned>(reply.content.size())));
|
||||
reply.headers.emplace_back("Content-Type", "text/html");
|
||||
return reply;
|
||||
}
|
||||
|
||||
std::string Reply::ToString(Reply::status_type status)
|
||||
|
||||
+45
-15
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "RequestHandler.h"
|
||||
#include "Http/Request.h"
|
||||
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../Library/OSRM.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
@@ -65,6 +66,7 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
|
||||
ltime = time(nullptr);
|
||||
Tm = localtime(<ime);
|
||||
|
||||
// log timestamp
|
||||
SimpleLogger().Write() << (Tm->tm_mday < 10 ? "0" : "") << Tm->tm_mday << "-"
|
||||
<< (Tm->tm_mon + 1 < 10 ? "0" : "") << (Tm->tm_mon + 1) << "-"
|
||||
<< 1900 + Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "")
|
||||
@@ -77,27 +79,55 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
|
||||
RouteParameters route_parameters;
|
||||
APIGrammarParser api_parser(&route_parameters);
|
||||
|
||||
auto it = request.begin();
|
||||
const bool result = boost::spirit::qi::parse(it, request.end(), api_parser);
|
||||
auto iter = request.begin();
|
||||
const bool result = boost::spirit::qi::parse(iter, request.end(), api_parser);
|
||||
|
||||
if (!result || (it != request.end()))
|
||||
// check if the was an error with the request
|
||||
if (!result || (iter != request.end()))
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
reply.content.clear();
|
||||
const int position = std::distance(request.begin(), it);
|
||||
reply.content.push_back(
|
||||
"{\"status\":400,\"status_message\":\"Query string malformed close to position ");
|
||||
std::string tmp_position_string;
|
||||
intToString(position, tmp_position_string);
|
||||
reply.content.push_back(tmp_position_string);
|
||||
reply.content.push_back("\"}");
|
||||
const unsigned position = static_cast<unsigned>(std::distance(request.begin(), iter));
|
||||
JSON::Object json_result;
|
||||
json_result.values["status"] = 400;
|
||||
std::string message = "Query string malformed close to position ";
|
||||
message += UintToString(position);
|
||||
json_result.values["status_message"] = message;
|
||||
JSON::render(reply.content, json_result);
|
||||
return;
|
||||
}
|
||||
|
||||
// parsing done, lets call the right plugin to handle the request
|
||||
BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{ // prepend response with jsonp parameter
|
||||
const std::string json_p = (route_parameters.jsonp_parameter + "(");
|
||||
reply.content.insert(reply.content.end(), json_p.begin(), json_p.end());
|
||||
}
|
||||
routing_machine->RunQuery(route_parameters, reply);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{ // append brace to jsonp response
|
||||
reply.content.push_back(')');
|
||||
}
|
||||
|
||||
// set headers
|
||||
reply.headers.emplace_back("Content-Length",
|
||||
UintToString(static_cast<unsigned>(reply.content.size())));
|
||||
if ("gpx" == route_parameters.output_format)
|
||||
{ // gpx file
|
||||
reply.headers.emplace_back("Content-Type", "application/gpx+xml; charset=UTF-8");
|
||||
reply.headers.emplace_back("Content-Disposition", "attachment; filename=\"route.gpx\"");
|
||||
}
|
||||
else if (route_parameters.jsonp_parameter.empty())
|
||||
{ // json file
|
||||
reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
|
||||
reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.json\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
// parsing done, lets call the right plugin to handle the request
|
||||
BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
|
||||
routing_machine->RunQuery(route_parameters, reply);
|
||||
return;
|
||||
{ // jsonp
|
||||
reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
|
||||
reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.js\"");
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
|
||||
@@ -31,16 +31,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
namespace http
|
||||
{
|
||||
|
||||
RequestParser::RequestParser() : state_(method_start) {}
|
||||
RequestParser::RequestParser() : state_(method_start), header({"", ""}) {}
|
||||
|
||||
void RequestParser::Reset() { state_ = method_start; }
|
||||
|
||||
boost::tuple<boost::tribool, char *>
|
||||
RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType *compressionType)
|
||||
RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType *compression_type)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
boost::tribool result = consume(req, *begin++, compressionType);
|
||||
boost::tribool result = consume(req, *begin++, compression_type);
|
||||
if (result || !result)
|
||||
{
|
||||
return boost::make_tuple(result, begin);
|
||||
@@ -51,7 +51,7 @@ RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType
|
||||
}
|
||||
|
||||
boost::tribool
|
||||
RequestParser::consume(Request &req, char input, http::CompressionType *compressionType)
|
||||
RequestParser::consume(Request &req, char input, http::CompressionType *compression_type)
|
||||
{
|
||||
switch (state_)
|
||||
{
|
||||
@@ -177,11 +177,11 @@ RequestParser::consume(Request &req, char input, http::CompressionType *compress
|
||||
/* giving gzip precedence over deflate */
|
||||
if (header.value.find("deflate") != std::string::npos)
|
||||
{
|
||||
*compressionType = deflateRFC1951;
|
||||
*compression_type = deflateRFC1951;
|
||||
}
|
||||
if (header.value.find("gzip") != std::string::npos)
|
||||
{
|
||||
*compressionType = gzipRFC1952;
|
||||
*compression_type = gzipRFC1952;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,10 +262,10 @@ RequestParser::consume(Request &req, char input, http::CompressionType *compress
|
||||
return boost::indeterminate;
|
||||
}
|
||||
return false;
|
||||
case expecting_newline_3:
|
||||
default: // expecting_newline_3:
|
||||
return (input == '\n');
|
||||
default:
|
||||
return false;
|
||||
// default:
|
||||
// return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-5
@@ -28,26 +28,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include "Connection.h"
|
||||
#include "RequestHandler.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
explicit Server(const std::string &address, const std::string &port, unsigned thread_pool_size)
|
||||
explicit Server(const std::string &address, const int port, const unsigned thread_pool_size)
|
||||
: thread_pool_size(thread_pool_size), acceptor(io_service),
|
||||
new_connection(new http::Connection(io_service, request_handler)), request_handler()
|
||||
{
|
||||
const std::string port_string = IntToString(port);
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_service);
|
||||
boost::asio::ip::tcp::resolver::query query(address, port);
|
||||
boost::asio::ip::tcp::resolver::query query(address, port_string);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
|
||||
acceptor.open(endpoint.protocol());
|
||||
@@ -59,19 +63,22 @@ class Server
|
||||
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
Server() = delete;
|
||||
Server(const Server &) = delete;
|
||||
|
||||
void Run()
|
||||
{
|
||||
std::vector<std::shared_ptr<boost::thread>> threads;
|
||||
std::vector<std::shared_ptr<std::thread>> threads;
|
||||
for (unsigned i = 0; i < thread_pool_size; ++i)
|
||||
{
|
||||
std::shared_ptr<boost::thread> thread = std::make_shared<boost::thread>(
|
||||
std::shared_ptr<std::thread> thread = std::make_shared<std::thread>(
|
||||
boost::bind(&boost::asio::io_service::run, &io_service));
|
||||
threads.push_back(thread);
|
||||
}
|
||||
for (unsigned i = 0; i < threads.size(); ++i)
|
||||
{
|
||||
threads[i]->join();
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() { io_service.stop(); }
|
||||
|
||||
@@ -29,9 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define SERVER_FACTORY_H
|
||||
|
||||
#include "Server.h"
|
||||
#include "../Util/OpenMPWrapper.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
@@ -39,15 +37,12 @@ struct ServerFactory
|
||||
{
|
||||
ServerFactory() = delete;
|
||||
ServerFactory(const ServerFactory &) = delete;
|
||||
static Server *CreateServer(std::string &ip_address, int ip_port, int threads)
|
||||
static Server *CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
|
||||
{
|
||||
|
||||
SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
|
||||
|
||||
std::string port_stream;
|
||||
intToString(ip_port, port_stream);
|
||||
|
||||
return new Server(ip_address, port_stream, std::min(omp_get_num_procs(), threads));
|
||||
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
|
||||
const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
|
||||
return new Server(ip_address, ip_port, real_num_threads);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+10
-7
@@ -33,7 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../Util/GraphLoader.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/UUID.h"
|
||||
#include "../Util/FingerPrint.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
@@ -61,11 +61,11 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
|
||||
std::ifstream restriction_ifstream(argv[2], std::ios::binary);
|
||||
const UUID uuid_orig;
|
||||
UUID uuid_loaded;
|
||||
restriction_ifstream.read((char *)&uuid_loaded, sizeof(UUID));
|
||||
const FingerPrint fingerprint_orig;
|
||||
FingerPrint fingerprint_loaded;
|
||||
restriction_ifstream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
|
||||
|
||||
if (!uuid_loaded.TestGraphUtil(uuid_orig))
|
||||
if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
|
||||
"Reprocess to get rid of this warning.";
|
||||
@@ -79,8 +79,11 @@ int main(int argc, char *argv[])
|
||||
restriction_ifstream.read((char *)&usable_restriction_count, sizeof(uint32_t));
|
||||
restrictions_vector.resize(usable_restriction_count);
|
||||
|
||||
restriction_ifstream.read((char *)&(restrictions_vector[0]),
|
||||
usable_restriction_count * sizeof(TurnRestriction));
|
||||
if (usable_restriction_count>0)
|
||||
{
|
||||
restriction_ifstream.read((char *)&(restrictions_vector[0]),
|
||||
usable_restriction_count * sizeof(TurnRestriction));
|
||||
}
|
||||
restriction_ifstream.close();
|
||||
|
||||
std::ifstream input_stream;
|
||||
|
||||
+25
-23
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../Util/GitDescription.h"
|
||||
#include "../Util/OSRMException.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
@@ -78,6 +79,11 @@ int main(int argc, char *argv[])
|
||||
SimpleLogger().Write() << "Not supported on FreeBSD";
|
||||
return 0;
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
SimpleLogger().Write() << "Not supported on Windows";
|
||||
return 0;
|
||||
#else
|
||||
|
||||
|
||||
if (1 == argc)
|
||||
{
|
||||
@@ -100,17 +106,15 @@ int main(int argc, char *argv[])
|
||||
throw OSRMException("Data file already exists");
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> time1, time2;
|
||||
int *random_array = new int[number_of_elements];
|
||||
std::generate(random_array, random_array + number_of_elements, std::rand);
|
||||
#ifdef __APPLE__
|
||||
FILE *fd = fopen(test_path.string().c_str(), "w");
|
||||
fcntl(fileno(fd), F_NOCACHE, 1);
|
||||
fcntl(fileno(fd), F_RDAHEAD, 0);
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
TIMER_START(write_1gb);
|
||||
write(fileno(fd), (char *)random_array, number_of_elements * sizeof(unsigned));
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
;
|
||||
TIMER_STOP(write_1gb);
|
||||
fclose(fd);
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
@@ -120,21 +124,20 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
throw OSRMException("Could not open random data file");
|
||||
}
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
TIMER_START(write_1gb);
|
||||
int ret = write(f, random_array, number_of_elements * sizeof(unsigned));
|
||||
if (0 > ret)
|
||||
{
|
||||
throw OSRMException("could not write random data file");
|
||||
}
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
TIMER_STOP(write_1gb);
|
||||
close(f);
|
||||
#endif
|
||||
std::chrono::duration<double> elapsed_seconds = time2 - time1;
|
||||
delete[] random_array;
|
||||
SimpleLogger().Write(logDEBUG) << "writing raw 1GB took " << elapsed_seconds.count()
|
||||
<< "ms";
|
||||
SimpleLogger().Write(logDEBUG) << "writing raw 1GB took " << TIMER_SEC(write_1gb)
|
||||
<< "s";
|
||||
SimpleLogger().Write() << "raw write performance: " << std::setprecision(5)
|
||||
<< std::fixed << 1024 * 1024 / (elapsed_seconds.count())
|
||||
<< std::fixed << 1024 * 1024 / TIMER_SEC(write_1gb)
|
||||
<< "MB/sec";
|
||||
|
||||
SimpleLogger().Write(logDEBUG)
|
||||
@@ -148,7 +151,6 @@ int main(int argc, char *argv[])
|
||||
throw OSRMException("data file does not exist");
|
||||
}
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> time1, time2;
|
||||
// volatiles do not get optimized
|
||||
Statistics stats;
|
||||
|
||||
@@ -170,7 +172,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
char *raw_array = (char *)memalign(512, number_of_elements * sizeof(unsigned));
|
||||
#endif
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
TIMER_START(read_1gb);
|
||||
#ifdef __APPLE__
|
||||
read(fileno(fd), raw_array, number_of_elements * sizeof(unsigned));
|
||||
close(fileno(fd));
|
||||
@@ -184,13 +186,12 @@ int main(int argc, char *argv[])
|
||||
f = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
|
||||
SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
|
||||
#endif
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
TIMER_STOP(read_1gb);
|
||||
|
||||
std::chrono::duration<double> elapsed_seconds = time2 - time1;
|
||||
SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << elapsed_seconds.count()
|
||||
<< "ms";
|
||||
SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << TIMER_SEC(read_1gb)
|
||||
<< "s";
|
||||
SimpleLogger().Write() << "raw read performance: " << std::setprecision(5) << std::fixed
|
||||
<< 1024 * 1024 / (elapsed_seconds.count()) << "MB/sec";
|
||||
<< 1024 * 1024 / TIMER_SEC(read_1gb) << "MB/sec";
|
||||
|
||||
std::vector<double> timing_results_raw_random;
|
||||
SimpleLogger().Write(logDEBUG) << "running 1000 random I/Os of 4KB";
|
||||
@@ -207,7 +208,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned block_to_read = std::rand() % number_of_blocks;
|
||||
off_t current_offset = block_to_read * 4096;
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
TIMER_START(random_access);
|
||||
#ifdef __APPLE__
|
||||
int ret1 = fseek(fd, current_offset, SEEK_SET);
|
||||
int ret2 = read(fileno(fd), (char *)&single_block[0], 4096);
|
||||
@@ -222,7 +223,7 @@ int main(int argc, char *argv[])
|
||||
int ret1 = lseek(f, current_offset, SEEK_SET);
|
||||
int ret2 = read(f, (char *)single_block, 4096);
|
||||
#endif
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
TIMER_STOP(random_access);
|
||||
if (((off_t) - 1) == ret1)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
|
||||
@@ -235,7 +236,7 @@ int main(int argc, char *argv[])
|
||||
SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
|
||||
throw OSRMException("read error");
|
||||
}
|
||||
timing_results_raw_random.push_back(elapsed_seconds.count());
|
||||
timing_results_raw_random.push_back(TIMER_SEC(random_access));
|
||||
}
|
||||
|
||||
// Do statistics
|
||||
@@ -267,7 +268,7 @@ int main(int argc, char *argv[])
|
||||
for (unsigned i = 0; i < 1000; ++i)
|
||||
{
|
||||
off_t current_offset = i * 4096;
|
||||
time1 = std::chrono::steady_clock::now();
|
||||
TIMER_START(read_every_100);
|
||||
#ifdef __APPLE__
|
||||
int ret1 = fseek(fd, current_offset, SEEK_SET);
|
||||
int ret2 = read(fileno(fd), (char *)&single_block, 4096);
|
||||
@@ -283,7 +284,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
int ret2 = read(f, (char *)single_block, 4096);
|
||||
#endif
|
||||
time2 = std::chrono::steady_clock::now();
|
||||
TIMER_STOP(read_every_100);
|
||||
if (((off_t) - 1) == ret1)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
|
||||
@@ -296,7 +297,7 @@ int main(int argc, char *argv[])
|
||||
SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
|
||||
throw OSRMException("read error");
|
||||
}
|
||||
timing_results_raw_seq.push_back(elapsed_seconds.count());
|
||||
timing_results_raw_seq.push_back(TIMER_SEC(read_every_100));
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
fclose(fd);
|
||||
@@ -343,4 +344,5 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -110,10 +110,10 @@ int main(int argc, const char *argv[])
|
||||
// attention: super-inefficient hack below:
|
||||
|
||||
std::stringstream my_stream;
|
||||
for (const std::string &line : osrm_reply.content)
|
||||
for (const auto &element : osrm_reply.content)
|
||||
{
|
||||
std::cout << line;
|
||||
my_stream << line;
|
||||
std::cout << element;
|
||||
my_stream << element;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define BOOST_FILE_SYSTEM_FIX_H
|
||||
|
||||
#include "OSRMException.h"
|
||||
#include "SimpleLogger.h"
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -135,4 +136,12 @@ inline path unique_path(const path &) { return temp_directory_path(); }
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#endif
|
||||
|
||||
inline void AssertPathExists(const boost::filesystem::path &path)
|
||||
{
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
{
|
||||
throw OSRMException(path.string() + " not found.");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BOOST_FILE_SYSTEM_FIX_H */
|
||||
|
||||
+4
-1
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef COMPUTE_ANGLE_H
|
||||
#define COMPUTE_ANGLE_H
|
||||
|
||||
#include "TrigonometryTables.h"
|
||||
#include "../Util/MercatorUtil.h"
|
||||
#include <osrm/Coordinate.h>
|
||||
|
||||
@@ -45,9 +46,11 @@ inline static double GetAngleBetweenThreeFixedPointCoordinates(const CoordinateT
|
||||
const double v2x = (B.lon - C.lon) / COORDINATE_PRECISION;
|
||||
const double v2y = lat2y(B.lat / COORDINATE_PRECISION) - lat2y(C.lat / COORDINATE_PRECISION);
|
||||
|
||||
double angle = (atan2(v2y, v2x) - atan2(v1y, v1x)) * 180 / M_PI;
|
||||
double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180 / M_PI;
|
||||
while (angle < 0)
|
||||
{
|
||||
angle += 360;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
template <typename T> inline void sort_unique_resize(std::vector<T> &vector)
|
||||
{
|
||||
std::sort(vector.begin(), vector.end());
|
||||
unsigned number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
|
||||
const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
|
||||
vector.resize(number_of_unique_elements);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ template <typename T> inline void sort_unique_resize_shrink_vector(std::vector<T
|
||||
|
||||
template <typename T> inline void remove_consecutive_duplicates_from_vector(std::vector<T> &vector)
|
||||
{
|
||||
unsigned number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
|
||||
const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
|
||||
vector.resize(number_of_unique_elements);
|
||||
}
|
||||
|
||||
|
||||
+70
-121
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "BoostFileSystemFix.h"
|
||||
#include "GitDescription.h"
|
||||
#include "IniFileUtil.h"
|
||||
#include "OSRMException.h"
|
||||
#include "SimpleLogger.h"
|
||||
|
||||
@@ -37,108 +38,54 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
void AssertPathExists(const boost::filesystem::path& path)
|
||||
{
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << path << " check failed";
|
||||
throw OSRMException(path.string() + " not found.");
|
||||
} else {
|
||||
SimpleLogger().Write(logDEBUG) << path << " exists";
|
||||
}
|
||||
}
|
||||
|
||||
// support old capitalized option names by down-casing them with a regex replace
|
||||
inline void PrepareConfigFile(
|
||||
const boost::filesystem::path & path,
|
||||
std::string & output
|
||||
) {
|
||||
boost::filesystem::fstream config_stream(path);
|
||||
std::string input_str(
|
||||
(std::istreambuf_iterator<char>(config_stream)),
|
||||
std::istreambuf_iterator<char>()
|
||||
);
|
||||
boost::regex regex("^([^=]*)"); //match from start of line to '='
|
||||
std::string format("\\L$1\\E"); //replace with downcased substring
|
||||
output = boost::regex_replace( input_str, regex, format );
|
||||
}
|
||||
|
||||
// generate boost::program_options object for the routing part
|
||||
inline bool GenerateDataStoreOptions(const int argc, const char * argv[], ServerPaths & paths)
|
||||
inline bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &paths, bool & springclean)
|
||||
{
|
||||
// declare a group of options that will be allowed only on command line
|
||||
boost::program_options::options_description generic_options("Options");
|
||||
generic_options.add_options()
|
||||
("version,v", "Show version")
|
||||
("help,h", "Show this help message")
|
||||
(
|
||||
"config,c",
|
||||
boost::program_options::value<boost::filesystem::path>(
|
||||
&paths["config"]
|
||||
)->default_value("server.ini"),
|
||||
"Path to a configuration file"
|
||||
);
|
||||
generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")
|
||||
("springclean,s", "Remove all regions in shared memory")("config,c",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["config"])
|
||||
->default_value("server.ini"),
|
||||
"Path to a configuration file");
|
||||
|
||||
// declare a group of options that will be allowed both on command line
|
||||
// as well as in a config file
|
||||
boost::program_options::options_description config_options("Configuration");
|
||||
config_options.add_options()
|
||||
(
|
||||
"hsgrdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
|
||||
".hsgr file"
|
||||
)
|
||||
(
|
||||
"nodesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
|
||||
".nodes file"
|
||||
)
|
||||
(
|
||||
"edgesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
|
||||
".edges file"
|
||||
)
|
||||
(
|
||||
"geometry",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["geometry"]),
|
||||
".geometry file"
|
||||
)
|
||||
(
|
||||
"ramindex",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
|
||||
".ramIndex file"
|
||||
)
|
||||
(
|
||||
"fileindex",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
|
||||
".fileIndex file"
|
||||
)
|
||||
(
|
||||
"namesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
|
||||
".names file"
|
||||
)
|
||||
(
|
||||
"timestamp",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
|
||||
".timestamp file"
|
||||
);
|
||||
config_options.add_options()(
|
||||
"hsgrdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
|
||||
".hsgr file")("nodesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
|
||||
".nodes file")(
|
||||
"edgesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
|
||||
".edges file")("geometry",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["geometry"]),
|
||||
".geometry file")(
|
||||
"ramindex",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
|
||||
".ramIndex file")(
|
||||
"fileindex",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
|
||||
".fileIndex file")(
|
||||
"namesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
|
||||
".names file")("timestamp",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
|
||||
".timestamp file");
|
||||
|
||||
// hidden options, will be allowed both on command line and in config
|
||||
// file, but will not be shown to the user
|
||||
boost::program_options::options_description hidden_options("Hidden options");
|
||||
hidden_options.add_options()
|
||||
(
|
||||
"base,b",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["base"]),
|
||||
"base path to .osrm file"
|
||||
);
|
||||
hidden_options.add_options()(
|
||||
"base,b",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["base"]),
|
||||
"base path to .osrm file");
|
||||
|
||||
// positional option
|
||||
boost::program_options::positional_options_description positional_options;
|
||||
@@ -152,48 +99,56 @@ inline bool GenerateDataStoreOptions(const int argc, const char * argv[], Server
|
||||
config_file_options.add(config_options).add(hidden_options);
|
||||
|
||||
boost::program_options::options_description visible_options(
|
||||
boost::filesystem::basename(argv[0]) + " [<options>] <configuration>"
|
||||
);
|
||||
boost::filesystem::basename(argv[0]) + " [<options>] <configuration>");
|
||||
visible_options.add(generic_options).add(config_options);
|
||||
|
||||
// parse command line options
|
||||
boost::program_options::variables_map option_variables;
|
||||
boost::program_options::store
|
||||
(
|
||||
boost::program_options::command_line_parser(argc, argv).options(cmdline_options).positional(positional_options).run(),
|
||||
option_variables
|
||||
);
|
||||
boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
|
||||
.options(cmdline_options)
|
||||
.positional(positional_options)
|
||||
.run(),
|
||||
option_variables);
|
||||
|
||||
if(option_variables.count("version"))
|
||||
if (option_variables.count("version"))
|
||||
{
|
||||
SimpleLogger().Write() << g_GIT_DESCRIPTION;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(option_variables.count("help"))
|
||||
if (option_variables.count("help"))
|
||||
{
|
||||
SimpleLogger().Write() << visible_options;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (option_variables.count("springclean"))
|
||||
{
|
||||
springclean = true;
|
||||
return true;
|
||||
}
|
||||
boost::program_options::notify(option_variables);
|
||||
|
||||
const bool parameter_present =
|
||||
(paths.find("hsgrdata") != paths.end() && !paths.find("hsgrdata" )->second.string().empty()) ||
|
||||
(paths.find("nodesdata") != paths.end() && !paths.find("nodesdata")->second.string().empty()) ||
|
||||
(paths.find("edgesdata") != paths.end() && !paths.find("edgesdata")->second.string().empty()) ||
|
||||
(paths.find("geometry") != paths.end() && !paths.find("geometry" )->second.string().empty()) ||
|
||||
(paths.find("ramindex") != paths.end() && !paths.find("ramindex" )->second.string().empty()) ||
|
||||
(paths.find("fileindex") != paths.end() && !paths.find("fileindex")->second.string().empty()) ||
|
||||
(paths.find("timestamp") != paths.end() && !paths.find("timestamp")->second.string().empty());
|
||||
const bool parameter_present = (paths.find("hsgrdata") != paths.end() &&
|
||||
!paths.find("hsgrdata")->second.string().empty()) ||
|
||||
(paths.find("nodesdata") != paths.end() &&
|
||||
!paths.find("nodesdata")->second.string().empty()) ||
|
||||
(paths.find("edgesdata") != paths.end() &&
|
||||
!paths.find("edgesdata")->second.string().empty()) ||
|
||||
(paths.find("geometry") != paths.end() &&
|
||||
!paths.find("geometry")->second.string().empty()) ||
|
||||
(paths.find("ramindex") != paths.end() &&
|
||||
!paths.find("ramindex")->second.string().empty()) ||
|
||||
(paths.find("fileindex") != paths.end() &&
|
||||
!paths.find("fileindex")->second.string().empty()) ||
|
||||
(paths.find("timestamp") != paths.end() &&
|
||||
!paths.find("timestamp")->second.string().empty());
|
||||
|
||||
if (parameter_present)
|
||||
{
|
||||
if (
|
||||
( paths.find("config") != paths.end() &&
|
||||
boost::filesystem::is_regular_file(paths.find("config")->second)
|
||||
) || option_variables.count("base")
|
||||
)
|
||||
if ((paths.find("config") != paths.end() &&
|
||||
boost::filesystem::is_regular_file(paths.find("config")->second)) ||
|
||||
option_variables.count("base"))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "conflicting parameters";
|
||||
SimpleLogger().Write() << visible_options;
|
||||
@@ -203,26 +158,20 @@ inline bool GenerateDataStoreOptions(const int argc, const char * argv[], Server
|
||||
|
||||
// parse config file
|
||||
ServerPaths::iterator path_iterator = paths.find("config");
|
||||
if (
|
||||
path_iterator != paths.end() &&
|
||||
boost::filesystem::is_regular_file(path_iterator->second) &&
|
||||
!option_variables.count("base")
|
||||
)
|
||||
if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
|
||||
!option_variables.count("base"))
|
||||
{
|
||||
SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
|
||||
std::string config_str;
|
||||
PrepareConfigFile( path_iterator->second, config_str );
|
||||
std::stringstream config_stream( config_str );
|
||||
boost::program_options::store(
|
||||
parse_config_file(config_stream, config_file_options),
|
||||
option_variables
|
||||
);
|
||||
std::string ini_file_contents = ReadIniFileAndLowerContents(path_iterator->second);
|
||||
std::stringstream config_stream(ini_file_contents);
|
||||
boost::program_options::store(parse_config_file(config_stream, config_file_options),
|
||||
option_variables);
|
||||
boost::program_options::notify(option_variables);
|
||||
}
|
||||
else if (option_variables.count("base"))
|
||||
{
|
||||
path_iterator = paths.find("base");
|
||||
BOOST_ASSERT( paths.end() != path_iterator );
|
||||
BOOST_ASSERT(paths.end() != path_iterator);
|
||||
std::string base_string = path_iterator->second.string();
|
||||
|
||||
path_iterator = paths.find("hsgrdata");
|
||||
|
||||
@@ -25,18 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "UUID.h"
|
||||
#include "FingerPrint.h"
|
||||
|
||||
#include "OSRMException.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/uuid/uuid_generators.hpp> // generators
|
||||
#include <boost/uuid/uuid_io.hpp> // streaming operators etc.
|
||||
#include <boost/uuid/name_generator.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#cmakedefine01 HAS64BITS
|
||||
@@ -45,7 +42,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#cmakedefine MD5GRAPH "${MD5GRAPH}"
|
||||
#cmakedefine MD5OBJECTS "${MD5OBJECTS}"
|
||||
|
||||
UUID::UUID() : magic_number(1297240911)
|
||||
FingerPrint::FingerPrint() : magic_number(1297240911)
|
||||
{
|
||||
md5_prepare[32] = md5_tree[32] = md5_graph[32] = md5_objects[32] = '\0';
|
||||
|
||||
@@ -53,26 +50,26 @@ UUID::UUID() : magic_number(1297240911)
|
||||
std::string temp_string(__DATE__);
|
||||
temp_string += __TIME__;
|
||||
|
||||
std::copy(MD5PREPARE, MD5PREPARE + strlen(MD5PREPARE), md5_prepare);
|
||||
std::memcpy(md5_prepare, MD5PREPARE, strlen(MD5PREPARE));
|
||||
temp_string += md5_prepare;
|
||||
std::copy(MD5RTREE, MD5RTREE + 32, md5_tree);
|
||||
std::memcpy(md5_tree, MD5RTREE, 32);
|
||||
temp_string += md5_tree;
|
||||
std::copy(MD5GRAPH, MD5GRAPH + 32, md5_graph);
|
||||
std::memcpy(md5_graph, MD5GRAPH, 32);
|
||||
temp_string += md5_graph;
|
||||
std::copy(MD5OBJECTS, MD5OBJECTS + 32, md5_objects);
|
||||
std::memcpy(md5_objects, MD5OBJECTS, 32);
|
||||
temp_string += md5_objects;
|
||||
|
||||
named_uuid = gen(temp_string);
|
||||
has_64_bits = HAS64BITS;
|
||||
}
|
||||
|
||||
UUID::~UUID() {}
|
||||
FingerPrint::~FingerPrint() {}
|
||||
|
||||
const boost::uuids::uuid &UUID::GetUUID() const { return named_uuid; }
|
||||
const boost::uuids::uuid &FingerPrint::GetFingerPrint() const { return named_uuid; }
|
||||
|
||||
bool UUID::IsMagicNumberOK() const { return 1297240911 == magic_number; }
|
||||
bool FingerPrint::IsMagicNumberOK() const { return 1297240911 == magic_number; }
|
||||
|
||||
bool UUID::TestGraphUtil(const UUID &other) const
|
||||
bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
|
||||
{
|
||||
if (!other.IsMagicNumberOK())
|
||||
{
|
||||
@@ -81,7 +78,7 @@ bool UUID::TestGraphUtil(const UUID &other) const
|
||||
return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
|
||||
}
|
||||
|
||||
bool UUID::TestPrepare(const UUID &other) const
|
||||
bool FingerPrint::TestPrepare(const FingerPrint &other) const
|
||||
{
|
||||
if (!other.IsMagicNumberOK())
|
||||
{
|
||||
@@ -90,7 +87,7 @@ bool UUID::TestPrepare(const UUID &other) const
|
||||
return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
|
||||
}
|
||||
|
||||
bool UUID::TestRTree(const UUID &other) const
|
||||
bool FingerPrint::TestRTree(const FingerPrint &other) const
|
||||
{
|
||||
if (!other.IsMagicNumberOK())
|
||||
{
|
||||
@@ -99,7 +96,7 @@ bool UUID::TestRTree(const UUID &other) const
|
||||
return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
|
||||
}
|
||||
|
||||
bool UUID::TestQueryObjects(const UUID &other) const
|
||||
bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
|
||||
{
|
||||
if (!other.IsMagicNumberOK())
|
||||
{
|
||||
@@ -25,25 +25,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef UUID_H
|
||||
#define UUID_H
|
||||
#ifndef FINGERPRINT_H
|
||||
#define FINGERPRINT_H
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
|
||||
// implements a singleton, i.e. there is one and only one conviguration object
|
||||
class UUID
|
||||
class FingerPrint
|
||||
{
|
||||
public:
|
||||
UUID();
|
||||
UUID(const UUID&) = delete;
|
||||
~UUID();
|
||||
const boost::uuids::uuid &GetUUID() const;
|
||||
FingerPrint();
|
||||
FingerPrint(const FingerPrint&) = delete;
|
||||
~FingerPrint();
|
||||
const boost::uuids::uuid &GetFingerPrint() const;
|
||||
bool IsMagicNumberOK() const;
|
||||
bool TestGraphUtil(const UUID &other) const;
|
||||
bool TestPrepare(const UUID &other) const;
|
||||
bool TestRTree(const UUID &other) const;
|
||||
bool TestNodeInfo(const UUID &other) const;
|
||||
bool TestQueryObjects(const UUID &other) const;
|
||||
bool TestGraphUtil(const FingerPrint &other) const;
|
||||
bool TestPrepare(const FingerPrint &other) const;
|
||||
bool TestRTree(const FingerPrint &other) const;
|
||||
bool TestNodeInfo(const FingerPrint &other) const;
|
||||
bool TestQueryObjects(const FingerPrint &other) const;
|
||||
|
||||
private:
|
||||
const unsigned magic_number;
|
||||
@@ -57,4 +57,4 @@ class UUID
|
||||
bool has_64_bits;
|
||||
};
|
||||
|
||||
#endif /* UUID_H */
|
||||
#endif /* FingerPrint_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user