Compare commits

...

62 Commits

Author SHA1 Message Date
Dennis Luxen 7d7cce5c72 add better and more precise comments to Restrictionmap 2014-05-22 14:53:53 +02:00
Dennis Luxen 0c66f84555 add static assertions to SearchEngine 2014-05-22 14:41:27 +02:00
Dennis Luxen 044e41c079 make temporary variables const 2014-05-22 14:41:02 +02:00
Dennis Luxen 8dc631e13c pull math functions from std namespace 2014-05-22 14:22:10 +02:00
Dennis Luxen d93b4feb99 add some static asserts to guard against memory usage regressions 2014-05-22 12:41:25 +02:00
Dennis Luxen 0b873f590c fix typo in error message 2014-05-22 12:24:34 +02:00
Dennis Luxen f52d637f58 do less work when compressing geometries 2014-05-22 11:41:32 +02:00
Dennis Luxen d1fdc7061f fix signed/unsigned comparison 2014-05-21 14:23:09 +02:00
Dennis Luxen 2822382797 Merge pull request #1030 from DennisOSRM/features/json-generator
Distance tables and JSON generator
2014-05-21 14:10:03 +02:00
Dennis Luxen 35c9021bdf reduce debug verbosity in RestrictionMap 2014-05-21 12:39:52 +02:00
Dennis Luxen 493b13364f move geographical distance computation to floats 2014-05-21 12:33:54 +02:00
Dennis Luxen a8ff3231a8 reduce debug verbosity 2014-05-21 12:33:14 +02:00
Dennis Luxen c2a750a690 use 100 locations at max for dist table 2014-05-21 12:29:45 +02:00
Dennis Luxen 6a9541833a add a leg to roundabout to remove edge case 2014-05-21 10:47:34 +02:00
Dennis Luxen 9117b45899 move more distance calculations to float 2014-05-21 10:03:30 +02:00
Dennis Luxen 812cf36d52 use floats instead of doubles for distance computations 2014-05-20 19:29:09 +02:00
Dennis Luxen 4aa7420d6a remove unneeded includes 2014-05-20 18:54:03 +02:00
Dennis Luxen 1802839a22 add approximator for perpendicular distance 2014-05-20 16:23:47 +02:00
Dennis Luxen 9a2d701e2e fix issue #1025:
- add function to count directed outgoing edges
- generate correct instruction for staying on a roundabout
- move test from @bug namespace to the general one
2014-05-20 15:40:14 +02:00
Dennis Luxen 69ad3f3365 add curly braces to one line if 2014-05-20 15:37:18 +02:00
Dennis Luxen d53eb881c2 revert to old boost based regex as GCC does not properly implement it prior to GCC 4.90 2014-05-20 14:33:03 +02:00
Dennis Luxen e28e45f38e remove unused variable 2014-05-20 14:33:03 +02:00
Dennis Luxen bf6ca22b00 fix #1021, always check if files exist 2014-05-20 14:33:03 +02:00
Dennis Luxen b8acbae3e8 fix #1021, always check if files exist 2014-05-20 14:33:03 +02:00
Dennis Luxen 4ec9f2c00f fix #1021, always check if files exist 2014-05-20 14:33:03 +02:00
Dennis Luxen 4fc329a1eb remove superflous way in test setup 2014-05-20 14:33:02 +02:00
Dennis Luxen 0574a60bc2 replace boost::unordered_map, move hash function for pairs into its own header 2014-05-20 14:33:02 +02:00
Dennis Luxen e490c4afed use consistent typedef'ed types 2014-05-20 14:33:02 +02:00
Dennis Luxen d028a30f87 fixes issue #1019:
- fix ignored turn restriction on chains of degree-2 nodes
- add a cucumber test to test for potential regressions
2014-05-20 14:33:02 +02:00
Dennis Luxen 75a2d4d00a minor code refactoring, wip 2014-05-20 14:33:02 +02:00
Dennis Luxen a122a1e8c7 remove comment 2014-05-20 14:33:02 +02:00
Dennis Luxen 8fe09c85b6 move atan2 lookup into trig header 2014-05-20 14:33:02 +02:00
Dennis Luxen bc951de2a5 use trig functions from std namespace 2014-05-20 14:33:01 +02:00
Dennis Luxen c970cd13cc flip bearings by 180 2014-05-20 14:33:01 +02:00
Dennis Luxen 8983c0f927 move GetBearing(.) function into FixedPointCoordinate 2014-05-20 14:33:01 +02:00
Dennis Luxen a47467f29b store facade ptr in c'tor, save a param in sub-sequent function calls 2014-05-20 14:33:01 +02:00
Dennis Luxen ef206eb4d9 clean up code a bit 2014-05-20 14:33:01 +02:00
Dennis Luxen da5eec1c5f refactor route name extraction into its own class, fix name extraction 2014-05-20 14:33:01 +02:00
Dennis Luxen a69b3535a5 fix typo 2014-05-20 14:33:01 +02:00
Dennis Luxen f4c23f3259 fix comparison 2014-05-20 14:33:01 +02:00
Dennis Luxen e36e9fd629 make comparsion explicitly unsigned 2014-05-20 14:33:00 +02:00
Dennis Luxen d2f19353ed remove some debug output 2014-05-20 14:33:00 +02:00
Dennis Luxen 2d498cb88b adapt JSON parsing in tests to allow for omitted fields 2014-05-20 14:33:00 +02:00
Dennis Luxen a80815d57a implements output generation through a dedicated JSON container:
- JSON syntax is not scattered over several files, but one place
- Reduces code duplication
- breaking changes:
  - new property in json(p) formatted response: "found_alternative": True/False
  - returned filenames now response.js(on) or route.gpx
  - /hello plugin returns JSON now
2014-05-20 14:33:00 +02:00
Dennis Luxen acab77f4f8 add simple isValid() function to PhantomNodes 2014-05-20 14:33:00 +02:00
Emil Tin bddad0c57c add test for roundabout with oneone links 2014-05-20 13:27:32 +02:00
Dennis Luxen 3968349480 deactivate LTO on debug build 2014-05-16 15:00:31 +02:00
Dennis Luxen 3ae17761b3 rename variables 2014-05-14 08:54:36 +02:00
Dennis Luxen 9a28bdbf76 reorder some includes 2014-05-14 08:53:26 +02:00
Dennis Luxen e769821e0f use range based for loops to traverse graphs 2014-05-13 16:56:30 +02:00
Dennis Luxen 9b68821f05 move common code into its own header 2014-05-13 13:30:52 +02:00
Dennis Luxen b2adb22b2d remove whitespace 2014-05-13 12:41:40 +02:00
Dennis Luxen 981941edf4 leave early to reduce scope nesting 2014-05-13 12:22:42 +02:00
Dennis Luxen 111dea89a9 use std::abs instead of hand-rolled substitute 2014-05-13 12:22:14 +02:00
Dennis Luxen 2720f4de9c add parantheses to fix compiler warning 2014-05-13 10:22:54 +02:00
Dennis Luxen 21645643b0 minor reformatting 2014-05-13 10:20:39 +02:00
Dennis Luxen c6a07acd90 use std::packaged_task and std::future to simulate boost::thread::timed_join() 2014-05-13 10:03:37 +02:00
Dennis Luxen 1816e6607e remove boost::thread from Server 2014-05-13 10:02:36 +02:00
Dennis Luxen 37dd05a9b5 Merge branch 'TheMarex-atan-perf' into develop 2014-05-13 10:00:45 +02:00
Patrick Niklaus 529997de9b Add atan based on lookup table. Again 6% improvement. 2014-05-13 02:20:33 +02:00
Patrick Niklaus 4f37270300 Simple fix that improves runtime of edge based egde generation by 26% 2014-05-13 01:00:24 +02:00
Dennis Luxen faf9c96442 fix regression in debug build 2014-05-12 18:09:25 +02:00
79 changed files with 3678 additions and 2174 deletions
+1 -1
View File
@@ -94,7 +94,7 @@ template <typename GraphT> class BFSComponentExplorer
const NodeID to_node_of_only_restriction = const NodeID to_node_of_only_restriction =
m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v); 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); const NodeID w = m_graph.GetTarget(e2);
+11 -1
View File
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "DouglasPeucker.h" #include "DouglasPeucker.h"
#include "../DataStructures/SegmentInformation.h" #include "../DataStructures/SegmentInformation.h"
#include "../Util/SimpleLogger.h"
#include <boost/assert.hpp> #include <boost/assert.hpp>
@@ -62,12 +63,17 @@ DouglasPeucker::DouglasPeucker()
void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level) void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
{ {
input_geometry.front().necessary = true;
input_geometry.back().necessary = true;
BOOST_ASSERT_MSG(!input_geometry.empty(), "geometry invalid"); BOOST_ASSERT_MSG(!input_geometry.empty(), "geometry invalid");
if (input_geometry.size() <= 2) if (input_geometry.size() < 2)
{ {
return; return;
} }
SimpleLogger().Write() << "input_geometry.size()=" << input_geometry.size();
{ {
BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level"); BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
unsigned left_border = 0; unsigned left_border = 0;
@@ -75,6 +81,10 @@ void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const
// Sweep over array and identify those ranges that need to be checked // Sweep over array and identify those ranges that need to be checked
do do
{ {
if (!input_geometry[left_border].necessary)
{
SimpleLogger().Write() << "broken interval [" << left_border << "," << right_border << "]";
}
BOOST_ASSERT_MSG(input_geometry[left_border].necessary, BOOST_ASSERT_MSG(input_geometry[left_border].necessary,
"left border must be necessary"); "left border must be necessary");
BOOST_ASSERT_MSG(input_geometry.back().necessary, "right border must be necessary"); BOOST_ASSERT_MSG(input_geometry.back().necessary, "right border must be necessary");
+142
View File
@@ -0,0 +1,142 @@
/*
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
{
RouteNames operator()(std::vector<SegmentT> &shortest_path_segments,
std::vector<SegmentT> &alternative_path_segments,
const DataFacadeT *facade)
{
RouteNames route_names;
SegmentT shortest_segment_1, shortest_segment_2;
SegmentT alternative_segment_1, alternative_segment_2;
auto length_comperator = [](SegmentT a, SegmentT b)
{ return a.length > b.length; };
auto name_id_comperator = [](SegmentT a, SegmentT b)
{ return a.name_id < b.name_id; };
if (shortest_path_segments.empty())
{
return route_names;
}
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);
alternative_segment_1 = alternative_path_segments[0];
}
std::vector<SegmentT> shortest_path_set_difference(shortest_path_segments.size());
std::vector<SegmentT> alternative_path_set_difference(alternative_path_segments.size());
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);
int size_of_difference = shortest_path_set_difference.size();
if (size_of_difference)
{
int i = 0;
while (i < size_of_difference &&
shortest_path_set_difference[i].name_id == shortest_path_segments[0].name_id)
{
++i;
}
if (i < size_of_difference)
{
shortest_segment_2 = shortest_path_set_difference[i];
}
}
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);
size_of_difference = alternative_path_set_difference.size();
if (size_of_difference)
{
int i = 0;
while (i < size_of_difference &&
alternative_path_set_difference[i].name_id ==
alternative_path_segments[0].name_id)
{
++i;
}
if (i < size_of_difference)
{
alternative_segment_2 = alternative_path_set_difference[i];
}
}
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);
}
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
+39 -50
View File
@@ -26,6 +26,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "PolylineCompressor.h" #include "PolylineCompressor.h"
#include "../Util/StringUtil.h"
//TODO: return vector of start indices for each leg
void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output)
const const
@@ -39,9 +42,9 @@ void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std
numbers[i] = ~(numbers[i]); numbers[i] = ~(numbers[i]);
} }
} }
for (unsigned i = 0; i < end; ++i) for (const int number: numbers)
{ {
encodeNumber(numbers[i], output); encodeNumber(number, output);
} }
} }
@@ -66,37 +69,36 @@ void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output)
} }
} }
void PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline, JSON::String PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline) const
std::string &output) const
{ {
std::string output;
std::vector<int> delta_numbers; std::vector<int> delta_numbers;
output += "\"";
if (!polyline.empty()) if (!polyline.empty())
{ {
FixedPointCoordinate last_coordinate = polyline[0].location; FixedPointCoordinate last_coordinate = polyline[0].location;
delta_numbers.emplace_back(last_coordinate.lat); delta_numbers.emplace_back(last_coordinate.lat);
delta_numbers.emplace_back(last_coordinate.lon); delta_numbers.emplace_back(last_coordinate.lon);
for (unsigned i = 1; i < polyline.size(); ++i) for (const auto & segment : polyline)
{ {
if (polyline[i].necessary) if (segment.necessary)
{ {
int lat_diff = polyline[i].location.lat - last_coordinate.lat; int lat_diff = segment.location.lat - last_coordinate.lat;
int lon_diff = polyline[i].location.lon - last_coordinate.lon; int lon_diff = segment.location.lon - last_coordinate.lon;
delta_numbers.emplace_back(lat_diff); delta_numbers.emplace_back(lat_diff);
delta_numbers.emplace_back(lon_diff); delta_numbers.emplace_back(lon_diff);
last_coordinate = polyline[i].location; last_coordinate = segment.location;
} }
} }
encodeVectorSignedNumber(delta_numbers, output); encodeVectorSignedNumber(delta_numbers, output);
} }
output += "\""; JSON::String return_value(output);
return return_value;
} }
void PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordinate> &polyline, JSON::String PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordinate> &polyline) const
std::string &output) const
{ {
std::string output;
std::vector<int> delta_numbers(2 * polyline.size()); std::vector<int> delta_numbers(2 * polyline.size());
output += "\"";
if (!polyline.empty()) if (!polyline.empty())
{ {
delta_numbers[0] = polyline[0].lat; delta_numbers[0] = polyline[0].lat;
@@ -110,53 +112,40 @@ void PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordina
} }
encodeVectorSignedNumber(delta_numbers, output); encodeVectorSignedNumber(delta_numbers, output);
} }
output += "\""; JSON::String return_value(output);
return return_value;
} }
void PolylineCompressor::printUnencodedString(const std::vector<FixedPointCoordinate> &polyline,
std::string &output) const JSON::Array PolylineCompressor::printUnencodedString(const std::vector<FixedPointCoordinate> &polyline) const
{ {
output += "["; JSON::Array json_geometry_array;
std::string tmp; for( const auto & coordinate : polyline)
for (unsigned i = 0; i < polyline.size(); i++)
{ {
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lat, tmp); std::string tmp, output;
output += "["; FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
output += (tmp + ",");
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
output += tmp; output += tmp;
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lon, tmp); json_geometry_array.values.push_back(output);
output += ", ";
output += tmp;
output += "]";
if (i < polyline.size() - 1)
{
output += ",";
}
} }
output += "]"; return json_geometry_array;
} }
void PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline, JSON::Array PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
std::string &output) const
{ {
output += "["; JSON::Array json_geometry_array;
std::string tmp; for( const auto & segment : polyline)
for (unsigned i = 0; i < polyline.size(); i++)
{ {
if (!polyline[i].necessary) if (segment.necessary)
{ {
continue; std::string tmp, output;
} FixedPointCoordinate::convertInternalLatLonToString(segment.location.lat, tmp);
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lat, tmp); output += (tmp + ",");
output += "["; FixedPointCoordinate::convertInternalLatLonToString(segment.location.lon, tmp);
output += tmp; output += tmp;
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lon, tmp); json_geometry_array.values.push_back(output);
output += ", ";
output += tmp;
output += "]";
if (i < polyline.size() - 1)
{
output += ",";
} }
} }
output += "]"; return json_geometry_array;
} }
+5 -9
View File
@@ -28,8 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef POLYLINECOMPRESSOR_H_ #ifndef POLYLINECOMPRESSOR_H_
#define POLYLINECOMPRESSOR_H_ #define POLYLINECOMPRESSOR_H_
#include "../DataStructures/JSONContainer.h"
#include "../DataStructures/SegmentInformation.h" #include "../DataStructures/SegmentInformation.h"
#include "../Util/StringUtil.h"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -42,17 +42,13 @@ class PolylineCompressor
void encodeNumber(int number_to_encode, std::string &output) const; void encodeNumber(int number_to_encode, std::string &output) const;
public: public:
void printEncodedString(const std::vector<SegmentInformation> &polyline, JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
std::string &output) const;
void printEncodedString(const std::vector<FixedPointCoordinate> &polyline, JSON::String printEncodedString(const std::vector<FixedPointCoordinate> &polyline) const;
std::string &output) const;
void printUnencodedString(const std::vector<FixedPointCoordinate> &polyline, JSON::Array printUnencodedString(const std::vector<FixedPointCoordinate> &polyline) const;
std::string &output) const;
void printUnencodedString(const std::vector<SegmentInformation> &polyline, JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
std::string &output) const;
}; };
#endif /* POLYLINECOMPRESSOR_H_ */ #endif /* POLYLINECOMPRESSOR_H_ */
+14 -23
View File
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../DataStructures/TurnInstructions.h" #include "../DataStructures/TurnInstructions.h"
#include "../Util/SimpleLogger.h" #include "../Util/SimpleLogger.h"
#include "../Util/StdHashExtensions.h"
#include <osrm/Coordinate.h> #include <osrm/Coordinate.h>
@@ -60,17 +61,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_set> #include <unordered_set>
#include <vector> #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 class TarjanSCC
{ {
private: private:
@@ -283,8 +273,7 @@ class TarjanSCC
++index; ++index;
// Traverse outgoing edges // Traverse outgoing edges
EdgeID end_edge = m_node_based_graph->EndEdges(v); for (auto e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
for (auto e2 = m_node_based_graph->BeginEdges(v); e2 < end_edge; ++e2)
{ {
const TarjanDynamicGraph::NodeIterator vprime = const TarjanDynamicGraph::NodeIterator vprime =
m_node_based_graph->GetTarget(e2); m_node_based_graph->GetTarget(e2);
@@ -340,14 +329,17 @@ class TarjanSCC
<< " many components, marking small components"; << " many components, marking small components";
// TODO/C++11: prime candidate for lambda function // TODO/C++11: prime candidate for lambda function
unsigned size_one_counter = 0; // unsigned size_one_counter = 0;
for (unsigned i = 0, end = component_size_vector.size(); i < end; ++i) // for (unsigned i = 0, end = component_size_vector.size(); i < end; ++i)
{ // {
if (1 == component_size_vector[i]) // if (1 == component_size_vector[i])
{ // {
++size_one_counter; // ++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"; SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1";
@@ -357,8 +349,7 @@ class TarjanSCC
for (NodeID u = 0; u < last_u_node; ++u) for (NodeID u = 0; u < last_u_node; ++u)
{ {
p.printIncrement(); p.printIncrement();
EdgeID last_edge = m_node_based_graph->EndEdges(u); for (auto e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
for (auto e1 = m_node_based_graph->BeginEdges(u); e1 < last_edge; ++e1)
{ {
if (!m_node_based_graph->GetEdgeData(e1).reversedEdge) if (!m_node_based_graph->GetEdgeData(e1).reversedEdge)
{ {
+15 -16
View File
@@ -86,7 +86,21 @@ if(CMAKE_BUILD_TYPE MATCHES Debug)
endif() endif()
endif() endif()
if(CMAKE_BUILD_TYPE MATCHES Release) 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() endif()
# Configuring compilers # Configuring compilers
@@ -104,21 +118,6 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++ # using Visual Studio C++
endif() 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) # disable partitioning of LTO process when possible (fixes Debian issues)
set(LTO_PARTITION_FLAGS "") set(LTO_PARTITION_FLAGS "")
CHECK_CXX_COMPILER_FLAG("-flto-partition=none" HAS_LTO_PARTITION_FLAG) CHECK_CXX_COMPILER_FLAG("-flto-partition=none" HAS_LTO_PARTITION_FLAG)
+10 -23
View File
@@ -340,10 +340,7 @@ class Contractor
for (unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i) for (unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i)
{ {
const NodeID start = i; const NodeID start = i;
auto last_edge = contractor_graph->EndEdges(start); for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(start))
for (auto current_edge = contractor_graph->BeginEdges(start);
current_edge < last_edge;
++current_edge)
{ {
ContractorGraph::EdgeData &data = ContractorGraph::EdgeData &data =
contractor_graph->GetEdgeData(current_edge); contractor_graph->GetEdgeData(current_edge);
@@ -531,8 +528,7 @@ class Contractor
for (NodeID node = 0; node < number_of_nodes; ++node) for (NodeID node = 0; node < number_of_nodes; ++node)
{ {
p.printStatus(node); p.printStatus(node);
auto endEdges = contractor_graph->EndEdges(node); for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
for (auto edge = contractor_graph->BeginEdges(node); edge < endEdges; ++edge)
{ {
const NodeID target = contractor_graph->GetTarget(edge); const NodeID target = contractor_graph->GetTarget(edge);
const ContractorGraph::EdgeData &data = contractor_graph->GetEdgeData(edge); const ContractorGraph::EdgeData &data = contractor_graph->GetEdgeData(edge);
@@ -634,8 +630,7 @@ class Contractor
} }
// iterate over all edges of node // iterate over all edges of node
auto end_edges = contractor_graph->EndEdges(node); for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
for (auto edge = contractor_graph->BeginEdges(node); edge != end_edges; ++edge)
{ {
const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge); const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
if (!data.forward) if (!data.forward)
@@ -698,8 +693,7 @@ class Contractor
int inserted_edges_size = data->inserted_edges.size(); int inserted_edges_size = data->inserted_edges.size();
std::vector<ContractorEdge> &inserted_edges = data->inserted_edges; std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
auto end_in_edges = contractor_graph->EndEdges(node); for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
for (auto in_edge = contractor_graph->BeginEdges(node); in_edge != end_in_edges; ++in_edge)
{ {
const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge); const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
const NodeID source = contractor_graph->GetTarget(in_edge); const NodeID source = contractor_graph->GetTarget(in_edge);
@@ -719,9 +713,7 @@ class Contractor
int max_distance = 0; int max_distance = 0;
unsigned number_of_targets = 0; unsigned number_of_targets = 0;
auto end_out_edges = contractor_graph->EndEdges(node); for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
for (auto out_edge = contractor_graph->BeginEdges(node); out_edge != end_out_edges;
++out_edge)
{ {
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge); const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
if (!out_data.forward) if (!out_data.forward)
@@ -746,10 +738,7 @@ class Contractor
{ {
Dijkstra(max_distance, number_of_targets, 2000, data, node); Dijkstra(max_distance, number_of_targets, 2000, data, node);
} }
for (auto out_edge = contractor_graph->BeginEdges(node), for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
endOutEdges = contractor_graph->EndEdges(node);
out_edge != endOutEdges;
++out_edge)
{ {
const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge); const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
if (!out_data.forward) if (!out_data.forward)
@@ -835,7 +824,7 @@ class Contractor
neighbours.clear(); neighbours.clear();
// find all neighbours // 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); const NodeID u = contractor_graph->GetTarget(e);
if (u != node) if (u != node)
@@ -862,8 +851,7 @@ class Contractor
neighbours.clear(); neighbours.clear();
// find all neighbours // find all neighbours
auto end_edges = contractor_graph->EndEdges(node); for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
for (auto e = contractor_graph->BeginEdges(node); e < end_edges; ++e)
{ {
const NodeID u = contractor_graph->GetTarget(e); const NodeID u = contractor_graph->GetTarget(e);
if (u == node) if (u == node)
@@ -895,7 +883,7 @@ class Contractor
std::vector<NodeID> &neighbours = data->neighbours; std::vector<NodeID> &neighbours = data->neighbours;
neighbours.clear(); 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); const NodeID target = contractor_graph->GetTarget(e);
if (node == target) if (node == target)
@@ -924,8 +912,7 @@ class Contractor
// examine all neighbours that are at most 2 hops away // examine all neighbours that are at most 2 hops away
for (const NodeID u : neighbours) for (const NodeID u : neighbours)
{ {
auto end_edges = contractor_graph->EndEdges(u); for (auto e : contractor_graph->GetAdjacentEdgeRange(u))
for (auto e = contractor_graph->BeginEdges(u); e < end_edges; ++e)
{ {
const NodeID target = contractor_graph->GetTarget(e); const NodeID target = contractor_graph->GetTarget(e);
if (node == target) if (node == target)
+20 -27
View File
@@ -305,6 +305,12 @@ void EdgeBasedGraphFactory::CompressGeometry()
continue; continue;
} }
// check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
if (m_restriction_map->IsNodeAViaNode(v))
{
continue;
}
const bool reverse_edge_order = const bool reverse_edge_order =
!(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(v)).forward); !(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; const EdgeID forward_e2 = m_node_based_graph->BeginEdges(v) + reverse_edge_order;
@@ -438,9 +444,7 @@ void EdgeBasedGraphFactory::RenumberEdges()
for (NodeID current_node = 0; current_node < m_node_based_graph->GetNumberOfNodes(); for (NodeID current_node = 0; current_node < m_node_based_graph->GetNumberOfNodes();
++current_node) ++current_node)
{ {
for (EdgeID current_edge = m_node_based_graph->BeginEdges(current_node); for (EdgeID current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
current_edge < m_node_based_graph->EndEdges(current_node);
++current_edge)
{ {
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge); EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
if (!edge_data.forward) if (!edge_data.forward)
@@ -483,10 +487,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
BOOST_ASSERT(u != SPECIAL_NODEID); BOOST_ASSERT(u != SPECIAL_NODEID);
BOOST_ASSERT(u < m_node_based_graph->GetNumberOfNodes()); BOOST_ASSERT(u < m_node_based_graph->GetNumberOfNodes());
p.printIncrement(); p.printIncrement();
for (EdgeID e1 = m_node_based_graph->BeginEdges(u), for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
last_edge = m_node_based_graph->EndEdges(u);
e1 < last_edge;
++e1)
{ {
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1); const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
if (edge_data.edgeBasedNodeID == SPECIAL_NODEID) if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
@@ -552,10 +553,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u) for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
{ {
for (EdgeID e1 = m_node_based_graph->BeginEdges(u), for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
last_edge_u = m_node_based_graph->EndEdges(u);
e1 < last_edge_u;
++e1)
{ {
if (!m_node_based_graph->GetEdgeData(e1).forward) if (!m_node_based_graph->GetEdgeData(e1).forward)
{ {
@@ -568,10 +566,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
m_restriction_map->CheckForEmanatingIsOnlyTurn(u, v); m_restriction_map->CheckForEmanatingIsOnlyTurn(u, v);
const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end()); const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
for (EdgeID e2 = m_node_based_graph->BeginEdges(v), for (EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
last_edge_v = m_node_based_graph->EndEdges(v);
e2 < last_edge_v;
++e2)
{ {
if (!m_node_based_graph->GetEdgeData(e2).forward) if (!m_node_based_graph->GetEdgeData(e2).forward)
{ {
@@ -628,8 +623,10 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
{ {
distance += speed_profile.trafficSignalPenalty; distance += speed_profile.trafficSignalPenalty;
} }
const int turn_penalty = GetTurnPenalty(u, v, w, lua_state); const double angle = GetAngleBetweenThreeFixedPointCoordinates(
TurnInstruction turn_instruction = AnalyzeTurn(u, v, w); 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) if (turn_instruction == TurnInstruction::UTurn)
{ {
distance += speed_profile.uTurnPenalty; distance += speed_profile.uTurnPenalty;
@@ -686,13 +683,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edg
SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter << " turns over barriers"; SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
} }
int EdgeBasedGraphFactory::GetTurnPenalty(const NodeID u, int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
const NodeID v,
const NodeID w,
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) if (speed_profile.has_turn_penalty_function)
{ {
@@ -706,7 +698,10 @@ int EdgeBasedGraphFactory::GetTurnPenalty(const NodeID u,
return 0; 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 const
{ {
if (u == w) if (u == w)
@@ -733,7 +728,7 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID
if (data1.roundabout && data2.roundabout) if (data1.roundabout && data2.roundabout)
{ {
// Is a turn possible? If yes, we stay on the 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. // No turn possible.
return TurnInstruction::NoTurn; return TurnInstruction::NoTurn;
@@ -771,8 +766,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); return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
} }
+2 -2
View File
@@ -76,9 +76,9 @@ class EdgeBasedGraphFactory
void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes); 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; unsigned GetNumberOfEdgeBasedNodes() const;
+380 -331
View File
@@ -1,331 +1,380 @@
/* /*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution. other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 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 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <osrm/Coordinate.h> #include <osrm/Coordinate.h>
#include "../Util/MercatorUtil.h" #include "../Util/MercatorUtil.h"
#include "../Util/SimpleLogger.h" #include "../Util/SimpleLogger.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include "../Util/TrigonometryTables.h"
#include <boost/assert.hpp>
#include <boost/assert.hpp>
#ifndef NDEBUG
#include <bitset> #ifndef NDEBUG
#endif #include <bitset>
#include <iostream> #endif
#include <limits> #include <iostream>
#include <limits>
FixedPointCoordinate::FixedPointCoordinate()
: lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min()) FixedPointCoordinate::FixedPointCoordinate()
{ : lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min())
} {
}
FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon)
{ FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon)
#ifndef NDEBUG {
if (0 != (std::abs(lat) >> 30)) #ifndef NDEBUG
{ if (0 != (std::abs(lat) >> 30))
std::bitset<32> y(lat); {
SimpleLogger().Write(logDEBUG) << "broken lat: " << lat << ", bits: " << y; std::bitset<32> y(lat);
} SimpleLogger().Write(logDEBUG) << "broken lat: " << lat << ", bits: " << y;
if (0 != (std::abs(lon) >> 30)) }
{ if (0 != (std::abs(lon) >> 30))
std::bitset<32> x(lon); {
SimpleLogger().Write(logDEBUG) << "broken lon: " << lon << ", bits: " << x; std::bitset<32> x(lon);
} SimpleLogger().Write(logDEBUG) << "broken lon: " << lon << ", bits: " << x;
#endif }
} #endif
}
void FixedPointCoordinate::Reset()
{ void FixedPointCoordinate::Reset()
lat = std::numeric_limits<int>::min(); {
lon = std::numeric_limits<int>::min(); lat = std::numeric_limits<int>::min();
} lon = std::numeric_limits<int>::min();
bool FixedPointCoordinate::isSet() const }
{ bool FixedPointCoordinate::isSet() const
return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon); {
} return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon);
bool FixedPointCoordinate::isValid() const }
{ bool FixedPointCoordinate::isValid() const
if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION || {
lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION) if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
{ lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
return false; {
} return false;
return true; }
} return true;
bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const }
{ bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const
return lat == other.lat && lon == other.lon; {
} return lat == other.lat && lon == other.lon;
}
double FixedPointCoordinate::ApproximateDistance(const int lat1,
const int lon1, double FixedPointCoordinate::ApproximateDistance(const int lat1,
const int lat2, const int lon1,
const int lon2) const int lat2,
{ const int lon2)
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min()); {
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min()); BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min()); BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min()); BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
double RAD = 0.017453292519943295769236907684886; BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
double lt1 = lat1 / COORDINATE_PRECISION; double RAD = 0.017453292519943295769236907684886;
double ln1 = lon1 / COORDINATE_PRECISION; double lt1 = lat1 / COORDINATE_PRECISION;
double lt2 = lat2 / COORDINATE_PRECISION; double ln1 = lon1 / COORDINATE_PRECISION;
double ln2 = lon2 / COORDINATE_PRECISION; double lt2 = lat2 / COORDINATE_PRECISION;
double dlat1 = lt1 * (RAD); double ln2 = lon2 / COORDINATE_PRECISION;
double dlat1 = lt1 * (RAD);
double dlong1 = ln1 * (RAD);
double dlat2 = lt2 * (RAD); double dlong1 = ln1 * (RAD);
double dlong2 = ln2 * (RAD); double dlat2 = lt2 * (RAD);
double dlong2 = ln2 * (RAD);
double dLong = dlong1 - dlong2;
double dLat = dlat1 - dlat2; 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)); double aHarv = pow(sin(dLat / 2.0), 2.0) + cos(dlat1) * cos(dlat2) * pow(sin(dLong / 2.), 2);
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi) double cHarv = 2. * atan2(sqrt(aHarv), sqrt(1.0 - aHarv));
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles) // earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
const double earth = 6372797.560856; // The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
return earth * cHarv; const double earth = 6372797.560856;
} return earth * cHarv;
}
double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &c1,
const FixedPointCoordinate &c2) double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &c1,
{ const FixedPointCoordinate &c2)
return ApproximateDistance(c1.lat, c1.lon, c2.lat, c2.lon); {
} return ApproximateDistance(c1.lat, c1.lon, c2.lat, c2.lon);
}
double FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
const FixedPointCoordinate &c2) float FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
{ const FixedPointCoordinate &c2)
return ApproximateEuclideanDistance(c1.lat, c1.lon, c2.lat, c2.lon); {
} return ApproximateEuclideanDistance(c1.lat, c1.lon, c2.lat, c2.lon);
}
double FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
const int lon1, float FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
const int lat2, const int lon1,
const int lon2) const int lat2,
{ const int lon2)
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min()); {
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min()); BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min()); BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
BOOST_ASSERT(lon2 != 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 float RAD = 0.017453292519943295769236907684886;
const double float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD; const float float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
const double float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD; const float float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
const double float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD; const float float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
const float 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 float x = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.);
const double earth_radius = 6372797.560856; const float y = (float_lat2 - float_lat1);
return sqrt(x * x + y * y) * earth_radius; const float 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, float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &point,
const FixedPointCoordinate &segA, const FixedPointCoordinate &segA,
const FixedPointCoordinate &segB) const FixedPointCoordinate &segB)
{ {
const double x = lat2y(point.lat / COORDINATE_PRECISION); const float x = lat2y(point.lat / COORDINATE_PRECISION);
const double y = point.lon / COORDINATE_PRECISION; const float y = point.lon / COORDINATE_PRECISION;
const double a = lat2y(segA.lat / COORDINATE_PRECISION); const float a = lat2y(segA.lat / COORDINATE_PRECISION);
const double b = segA.lon / COORDINATE_PRECISION; const float b = segA.lon / COORDINATE_PRECISION;
const double c = lat2y(segB.lat / COORDINATE_PRECISION); const float c = lat2y(segB.lat / COORDINATE_PRECISION);
const double d = segB.lon / COORDINATE_PRECISION; const float d = segB.lon / COORDINATE_PRECISION;
double p, q, nY; float p, q, nY;
if (std::abs(a - c) > std::numeric_limits<double>::epsilon()) if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
{ {
const double m = (d - b) / (c - a); // slope const float m = (d - b) / (c - a); // slope
// Projection of (x,y) on line joining (a,b) and (c,d) // Projection of (x,y) on line joining (a,b) and (c,d)
p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m); p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m);
q = b + m * (p - a); q = b + m * (p - a);
} }
else else
{ {
p = c; p = c;
q = y; q = y;
} }
nY = (d * p - c * q) / (a * d - b * c); nY = (d * p - c * q) / (a * d - b * c);
// discretize the result to coordinate precision. it's a hack! // discretize the result to coordinate precision. it's a hack!
if (std::abs(nY) < (1. / COORDINATE_PRECISION)) if (std::abs(nY) < (1. / COORDINATE_PRECISION))
{ {
nY = 0.; nY = 0.;
} }
double r = (p - nY * a) / c; float r = (p - nY * a) / c;
if (std::isnan(r)) if (std::isnan(r))
{ {
r = ((segB.lat == point.lat) && (segB.lon == point.lon)) ? 1. : 0.; r = ((segB.lat == point.lat) && (segB.lon == point.lon)) ? 1. : 0.;
} }
else if (std::abs(r) <= std::numeric_limits<double>::epsilon()) else if (std::abs(r) <= std::numeric_limits<float>::epsilon())
{ {
r = 0.; r = 0.;
} }
else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon()) else if (std::abs(r - 1.) <= std::numeric_limits<float>::epsilon())
{ {
r = 1.; r = 1.;
} }
FixedPointCoordinate nearest_location; FixedPointCoordinate nearest_location;
BOOST_ASSERT(!std::isnan(r)); BOOST_ASSERT(!std::isnan(r));
if (r <= 0.) if (r <= 0.)
{ // point is "left" of edge { // point is "left" of edge
nearest_location.lat = segA.lat; nearest_location.lat = segA.lat;
nearest_location.lon = segA.lon; nearest_location.lon = segA.lon;
} }
else if (r >= 1.) else if (r >= 1.)
{ // point is "right" of edge { // point is "right" of edge
nearest_location.lat = segB.lat; nearest_location.lat = segB.lat;
nearest_location.lon = segB.lon; nearest_location.lon = segB.lon;
} }
else else
{ // point lies in between { // point lies in between
nearest_location.lat = y2lat(p) * COORDINATE_PRECISION; nearest_location.lat = y2lat(p) * COORDINATE_PRECISION;
nearest_location.lon = q * COORDINATE_PRECISION; nearest_location.lon = q * COORDINATE_PRECISION;
} }
BOOST_ASSERT(nearest_location.isValid()); BOOST_ASSERT(nearest_location.isValid());
const double approximated_distance = const float approximated_distance =
FixedPointCoordinate::ApproximateDistance(point, nearest_location); FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
BOOST_ASSERT(0. <= approximated_distance); BOOST_ASSERT(0. <= approximated_distance);
return approximated_distance; return approximated_distance;
} }
double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &coord_a, float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &coord_a,
const FixedPointCoordinate &coord_b, const FixedPointCoordinate &coord_b,
const FixedPointCoordinate &query_location, const FixedPointCoordinate &query_location,
FixedPointCoordinate &nearest_location, FixedPointCoordinate &nearest_location,
double &r) float &r)
{ {
BOOST_ASSERT(query_location.isValid()); BOOST_ASSERT(query_location.isValid());
const double x = lat2y(query_location.lat / COORDINATE_PRECISION); const float x = lat2y(query_location.lat / COORDINATE_PRECISION);
const double y = query_location.lon / COORDINATE_PRECISION; const float y = query_location.lon / COORDINATE_PRECISION;
const double a = lat2y(coord_a.lat / COORDINATE_PRECISION); const float a = lat2y(coord_a.lat / COORDINATE_PRECISION);
const double b = coord_a.lon / COORDINATE_PRECISION; const float b = coord_a.lon / COORDINATE_PRECISION;
const double c = lat2y(coord_b.lat / COORDINATE_PRECISION); const float c = lat2y(coord_b.lat / COORDINATE_PRECISION);
const double d = coord_b.lon / COORDINATE_PRECISION; const float d = coord_b.lon / COORDINATE_PRECISION;
double p, q /*,mX*/, nY; float p, q /*,mX*/, nY;
if (std::abs(a - c) > std::numeric_limits<double>::epsilon()) if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
{ {
const double m = (d - b) / (c - a); // slope const float m = (d - b) / (c - a); // slope
// Projection of (x,y) on line joining (a,b) and (c,d) // Projection of (x,y) on line joining (a,b) and (c,d)
p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m); p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m);
q = b + m * (p - a); q = b + m * (p - a);
} }
else else
{ {
p = c; p = c;
q = y; q = y;
} }
nY = (d * p - c * q) / (a * d - b * c); nY = (d * p - c * q) / (a * d - b * c);
// discretize the result to coordinate precision. it's a hack! // discretize the result to coordinate precision. it's a hack!
if (std::abs(nY) < (1. / COORDINATE_PRECISION)) if (std::abs(nY) < (1. / COORDINATE_PRECISION))
{ {
nY = 0.; nY = 0.;
} }
r = (p - nY * a) / c; // These values are actually n/m+n and m/m+n , we need 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 // not calculate the explicit values of m an n as we
// are just interested in the ratio // are just interested in the ratio
if (std::isnan(r)) if (std::isnan(r))
{ {
r = ((coord_b.lat == query_location.lat) && (coord_b.lon == query_location.lon)) ? 1. : 0.; 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()) else if (std::abs(r) <= std::numeric_limits<float>::epsilon())
{ {
r = 0.; r = 0.;
} }
else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon()) else if (std::abs(r - 1.) <= std::numeric_limits<float>::epsilon())
{ {
r = 1.; r = 1.;
} }
BOOST_ASSERT(!std::isnan(r)); BOOST_ASSERT(!std::isnan(r));
if (r <= 0.) if (r <= 0.)
{ {
nearest_location.lat = coord_a.lat; nearest_location = coord_a;
nearest_location.lon = coord_a.lon; }
} else if (r >= 1.)
else if (r >= 1.) {
{ nearest_location = coord_b;
nearest_location.lat = coord_b.lat; }
nearest_location.lon = coord_b.lon; else
} {
else // point lies in between
{ nearest_location.lat = y2lat(p) * COORDINATE_PRECISION;
// point lies in between nearest_location.lon = q * COORDINATE_PRECISION;
nearest_location.lat = y2lat(p) * COORDINATE_PRECISION; }
nearest_location.lon = q * COORDINATE_PRECISION; BOOST_ASSERT(nearest_location.isValid());
}
BOOST_ASSERT(nearest_location.isValid()); // TODO: Replace with euclidean approximation when k-NN search is done
// const float approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance(
// TODO: Replace with euclidean approximation when k-NN search is done const float approximated_distance =
// const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance( FixedPointCoordinate::ApproximateEuclideanDistance(query_location, nearest_location);
const double approximated_distance = BOOST_ASSERT(0. <= approximated_distance);
FixedPointCoordinate::ApproximateDistance(query_location, nearest_location); return approximated_distance;
BOOST_ASSERT(0. <= approximated_distance); }
return approximated_distance;
} void FixedPointCoordinate::convertInternalLatLonToString(const int value, std::string &output)
{
void FixedPointCoordinate::convertInternalLatLonToString(const int value, std::string &output) char buffer[12];
{ buffer[11] = 0; // zero termination
char buffer[12]; output = printInt<11, 6>(buffer, value);
buffer[11] = 0; // zero termination }
output = printInt<11, 6>(buffer, value);
} void FixedPointCoordinate::convertInternalCoordinateToString(const FixedPointCoordinate &coord,
std::string &output)
void FixedPointCoordinate::convertInternalCoordinateToString(const FixedPointCoordinate &coord, {
std::string &output) std::string tmp;
{ tmp.reserve(23);
std::string tmp; convertInternalLatLonToString(coord.lon, tmp);
tmp.reserve(23); output = tmp;
convertInternalLatLonToString(coord.lon, tmp); output += ",";
output = tmp; convertInternalLatLonToString(coord.lat, tmp);
output += ","; output += tmp;
convertInternalLatLonToString(coord.lat, tmp); }
output += tmp;
} void
FixedPointCoordinate::convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord,
void std::string &output)
FixedPointCoordinate::convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord, {
std::string &output) std::string tmp;
{ tmp.reserve(23);
std::string tmp; convertInternalLatLonToString(coord.lat, tmp);
tmp.reserve(23); output = tmp;
convertInternalLatLonToString(coord.lat, tmp); output += ",";
output = tmp; convertInternalLatLonToString(coord.lon, tmp);
output += ","; output += tmp;
convertInternalLatLonToString(coord.lon, tmp); }
output += tmp;
} void FixedPointCoordinate::Output(std::ostream &out) const
{
void FixedPointCoordinate::Output(std::ostream &out) const out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")";
{ }
out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")";
} float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B)
{
const float delta_long = DegreeToRadian(B.lon / COORDINATE_PRECISION - A.lon / COORDINATE_PRECISION);
const float lat1 = DegreeToRadian(A.lat / COORDINATE_PRECISION);
const float lat2 = DegreeToRadian(B.lat / COORDINATE_PRECISION);
const float y = sin(delta_long) * cos(lat2);
const float x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_long);
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 delta_long = 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 = std::sin(delta_long) * std::cos(lat2);
const float x = std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(delta_long);
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::DegreeToRadian(const float degree)
{
return degree * (M_PI / 180.f);
}
float FixedPointCoordinate::RadianToDegree(const float radian)
{
return radian * (180.f / M_PI);
}
+20
View File
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../DataStructures/DeallocatingVector.h" #include "../DataStructures/DeallocatingVector.h"
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/range/irange.hpp>
#include <cstdint> #include <cstdint>
@@ -41,6 +42,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
template <typename EdgeDataT> class DynamicGraph template <typename EdgeDataT> class DynamicGraph
{ {
public: public:
typedef decltype(boost::irange(0u,0u)) EdgeRange;
typedef EdgeDataT EdgeData; typedef EdgeDataT EdgeData;
typedef unsigned NodeIterator; typedef unsigned NodeIterator;
typedef unsigned EdgeIterator; typedef unsigned EdgeIterator;
@@ -115,6 +117,19 @@ template <typename EdgeDataT> class DynamicGraph
unsigned GetOutDegree(const NodeIterator n) const { return m_nodes[n].edges; } 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); } 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; } void SetTarget(const EdgeIterator e, const NodeIterator n) { m_edges[e].target = n; }
@@ -133,6 +148,11 @@ template <typename EdgeDataT> class DynamicGraph
return EdgeIterator(m_nodes[n].firstEdge + m_nodes[n].edges); 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 // adds an edge. Invalidates edge iterators for the source node
EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data) EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
{ {
+237
View File
@@ -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
+1
View File
@@ -49,6 +49,7 @@ typedef DynamicGraph<NodeBasedEdgeData> NodeBasedDynamicGraph;
inline std::shared_ptr<NodeBasedDynamicGraph> inline std::shared_ptr<NodeBasedDynamicGraph>
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list) NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
{ {
static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
std::sort(input_edge_list.begin(), input_edge_list.end()); std::sort(input_edge_list.begin(), input_edge_list.end());
// TODO: remove duplicate edges // TODO: remove duplicate edges
+6
View File
@@ -115,6 +115,12 @@ struct PhantomNode
); );
} }
bool isValid() const
{
return location.isValid() &&
(name_id != std::numeric_limits<unsigned>::max());
}
bool operator==(const PhantomNode & other) const bool operator==(const PhantomNode & other) const
{ {
return location == other.location; return location == other.location;
+99 -52
View File
@@ -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 "RestrictionMap.h"
#include "NodeBasedGraph.h" #include "NodeBasedGraph.h"
#include "../Util/SimpleLogger.h"
bool RestrictionMap::IsNodeAViaNode(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, RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
const std::vector<TurnRestriction> &input_restrictions_list) const std::vector<TurnRestriction> &input_restrictions_list)
: m_count(0), m_graph(graph) : m_count(0), m_graph(graph)
{ {
// decompose restirction consisting of a start, via and end note into a start-edge // decompose restriction consisting of a start, via and end node into a
// and all end-nodes // a pair of starting edge and a list of all end nodes
for (auto &restriction : input_restrictions_list) for (auto &restriction : input_restrictions_list)
{ {
std::pair<NodeID, NodeID> restriction_source = m_restriction_start_nodes.insert(restriction.fromNode);
std::make_pair(restriction.fromNode, restriction.viaNode); m_no_turn_via_node_set.insert(restriction.viaNode);
std::pair<NodeID, NodeID> restriction_source = {restriction.fromNode, restriction.viaNode};
unsigned index; unsigned index;
auto restriction_iter = m_restriction_map.find(restriction_source); auto restriction_iter = m_restriction_map.find(restriction_source);
if (restriction_iter == m_restriction_map.end()) if (restriction_iter == m_restriction_map.end())
@@ -36,27 +73,26 @@ RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &gra
} }
++m_count; ++m_count;
m_restriction_bucket_list.at(index) 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
* 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) void RestrictionMap::FixupArrivingTurnRestriction(const NodeID u, const NodeID v, const NodeID w)
{ {
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(u != SPECIAL_NODEID);
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(v != SPECIAL_NODEID);
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(w != SPECIAL_NODEID);
// find all possible start edges if (!RestrictionStartsAtNode(u))
// it is more efficent to get a (small) list of potential start edges {
// than iterating over all buckets 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; std::vector<NodeID> predecessors;
for (EdgeID current_edge_id = m_graph->BeginEdges(u); current_edge_id < m_graph->EndEdges(u); for (const EdgeID current_edge_id : m_graph->GetAdjacentEdgeRange(u))
++current_edge_id)
{ {
const EdgeData &edge_data = m_graph->GetEdgeData(current_edge_id); const EdgeData &edge_data = m_graph->GetEdgeData(current_edge_id);
const NodeID target = m_graph->GetTarget(current_edge_id); const NodeID target = m_graph->GetTarget(current_edge_id);
@@ -68,10 +104,11 @@ void RestrictionMap::FixupArrivingTurnRestriction(const NodeID u, const NodeID v
for (const NodeID x : predecessors) for (const NodeID x : predecessors)
{ {
const std::pair<NodeID, NodeID> restr_start = std::make_pair(x, u); auto restriction_iterator = m_restriction_map.find({x, u});
auto restriction_iterator = m_restriction_map.find(restr_start);
if (restriction_iterator == m_restriction_map.end()) if (restriction_iterator == m_restriction_map.end())
{
continue; continue;
}
const unsigned index = restriction_iterator->second; const unsigned index = restriction_iterator->second;
auto &bucket = m_restriction_bucket_list.at(index); auto &bucket = m_restriction_bucket_list.at(index);
@@ -85,18 +122,19 @@ void RestrictionMap::FixupArrivingTurnRestriction(const NodeID u, const NodeID v
} }
} }
/** // Replaces start edge (v, w) with (u, w). Only start node changes.
* 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) void RestrictionMap::FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w)
{ {
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(u != SPECIAL_NODEID);
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(v != SPECIAL_NODEID);
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(w != SPECIAL_NODEID);
const std::pair<NodeID, NodeID> old_start = std::make_pair(v, w); if (!RestrictionStartsAtNode(u))
{
return;
}
auto restriction_iterator = m_restriction_map.find(old_start); const auto restriction_iterator = m_restriction_map.find({v, w});
if (restriction_iterator != m_restriction_map.end()) if (restriction_iterator != m_restriction_map.end())
{ {
const unsigned index = restriction_iterator->second; const unsigned index = restriction_iterator->second;
@@ -104,23 +142,24 @@ void RestrictionMap::FixupStartingTurnRestriction(const NodeID u, const NodeID v
m_restriction_map.erase(restriction_iterator); m_restriction_map.erase(restriction_iterator);
// insert new restriction start (u,w) (point to index) // insert new restriction start (u,w) (point to index)
const std::pair<NodeID, NodeID> new_start = std::make_pair(u, w); RestrictionSource new_source = {u, w};
m_restriction_map.insert(std::make_pair(new_start, index)); m_restriction_map.emplace(new_source, index);
} }
} }
/* // Check if edge (u, v) is the start of any turn restriction.
* Check if the edge (u, v) is contained in any turn restriction. // If so returns id of first target node.
* If so returns id of first target node.
*/
NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const
{ {
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(u != SPECIAL_NODEID);
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(v != SPECIAL_NODEID);
const std::pair<NodeID, NodeID> restriction_source = std::make_pair(u, v); if (!RestrictionStartsAtNode(u))
auto restriction_iter = m_restriction_map.find(restriction_source); {
return SPECIAL_NODEID;
}
auto restriction_iter = m_restriction_map.find({u, v});
if (restriction_iter != m_restriction_map.end()) if (restriction_iter != m_restriction_map.end())
{ {
const unsigned index = restriction_iter->second; const unsigned index = restriction_iter->second;
@@ -133,36 +172,44 @@ NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID
} }
} }
} }
return SPECIAL_NODEID;
return std::numeric_limits<unsigned>::max();
} }
/** // Checks if turn <u,v,w> is actually a turn restriction.
* 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 bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const
{ {
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(u != SPECIAL_NODEID);
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(v != SPECIAL_NODEID);
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(w != SPECIAL_NODEID);
const std::pair<NodeID, NodeID> restriction_source = std::make_pair(u, v); if (!RestrictionStartsAtNode(u))
auto restriction_iter = m_restriction_map.find(restriction_source); {
return false;
}
auto restriction_iter = m_restriction_map.find({u, v});
if (restriction_iter != m_restriction_map.end()) if (restriction_iter != m_restriction_map.end())
{ {
const unsigned index = restriction_iter->second; const unsigned index = restriction_iter->second;
auto &bucket = m_restriction_bucket_list.at(index); const auto &bucket = m_restriction_bucket_list.at(index);
for (const RestrictionTarget &restriction_target : bucket) for (const RestrictionTarget &restriction_target : bucket)
{ {
if ((w == restriction_target.first) && // target found if ((w == restriction_target.first) && // target found
(!restriction_target.second) // and not an only_-restr. (!restriction_target.second)) // and not an only_-restr.
)
{ {
return true; return true;
} }
} }
} }
return false; return false;
} }
// check of node is the start of any restriction
bool RestrictionMap::RestrictionStartsAtNode(const NodeID node) const
{
if (m_restriction_start_nodes.find(node) == m_restriction_start_nodes.end())
{
return false;
}
return true;
}
+11 -8
View File
@@ -30,17 +30,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory> #include <memory>
#include "../typedefs.h"
#include "DynamicGraph.h" #include "DynamicGraph.h"
#include "Restriction.h" #include "Restriction.h"
#include "NodeBasedGraph.h" #include "NodeBasedGraph.h"
#include "../Util/StdHashExtensions.h"
#include "../typedefs.h"
#include <boost/unordered_map.hpp> #include <unordered_map>
#include <unordered_set>
/*! // Efficent look up if an edge is the start + via node of a TurnRestriction
* Makee it efficent to 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
* Is needed by EdgeBasedGraphFactory.
*/
class RestrictionMap class RestrictionMap
{ {
public: public:
@@ -51,10 +51,11 @@ class RestrictionMap
void FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w); void FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const; NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const;
bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const; bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const;
bool IsNodeAViaNode(const NodeID node) const;
unsigned size() { return m_count; } unsigned size() { return m_count; }
private: private:
bool RestrictionStartsAtNode(const NodeID node) const;
typedef std::pair<NodeID, NodeID> RestrictionSource; typedef std::pair<NodeID, NodeID> RestrictionSource;
typedef std::pair<NodeID, bool> RestrictionTarget; typedef std::pair<NodeID, bool> RestrictionTarget;
typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector; typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
@@ -65,7 +66,9 @@ class RestrictionMap
//! index -> list of (target, isOnly) //! index -> list of (target, isOnly)
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list; std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
//! maps (start, via) -> bucket index //! 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 #endif
+2 -2
View File
@@ -76,7 +76,7 @@ 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); const int lat = COORDINATE_PRECISION * boost::fusion::at_c<0>(transmitted_coordinates);
int lon = COORDINATE_PRECISION * boost::fusion::at_c<1>(transmitted_coordinates); const int lon = COORDINATE_PRECISION * boost::fusion::at_c<1>(transmitted_coordinates);
coordinates.emplace_back(lat, lon); coordinates.emplace_back(lat, lon);
} }
+7 -1
View File
@@ -30,8 +30,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "SearchEngineData.h" #include "SearchEngineData.h"
#include "../RoutingAlgorithms/AlternativePathRouting.h" #include "../RoutingAlgorithms/AlternativePathRouting.h"
#include "../RoutingAlgorithms/ManyToManyRouting.h"
#include "../RoutingAlgorithms/ShortestPathRouting.h" #include "../RoutingAlgorithms/ShortestPathRouting.h"
#include <type_traits>
template <class DataFacadeT> class SearchEngine template <class DataFacadeT> class SearchEngine
{ {
private: private:
@@ -41,11 +44,14 @@ template <class DataFacadeT> class SearchEngine
public: public:
ShortestPathRouting<DataFacadeT> shortest_path; ShortestPathRouting<DataFacadeT> shortest_path;
AlternativeRouting<DataFacadeT> alternative_path; AlternativeRouting<DataFacadeT> alternative_path;
ManyToManyRouting<DataFacadeT> distance_table;
explicit SearchEngine(DataFacadeT *facade) explicit SearchEngine(DataFacadeT *facade)
: facade(facade), shortest_path(facade, engine_working_data), : 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>(), "don't instantiate with ptr type");
static_assert(std::is_object<DataFacadeT>(), "don't instantiate with void, function, or reference");
} }
~SearchEngine() {} ~SearchEngine() {}
+23 -13
View File
@@ -33,6 +33,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../Util/SimpleLogger.h" #include "../Util/SimpleLogger.h"
#include "../typedefs.h" #include "../typedefs.h"
#include <boost/range/irange.hpp>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <vector> #include <vector>
@@ -40,6 +42,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
{ {
public: public:
typedef decltype(boost::irange(0u,0u)) EdgeRange;
typedef NodeID NodeIterator; typedef NodeID NodeIterator;
typedef NodeID EdgeIterator; typedef NodeID EdgeIterator;
typedef EdgeDataT EdgeData; typedef EdgeDataT EdgeData;
@@ -62,7 +65,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
struct NodeArrayEntry struct NodeArrayEntry
{ {
// index of the first edge // index of the first edge
EdgeIterator firstEdge; EdgeIterator first_edge;
}; };
struct EdgeArrayEntry struct EdgeArrayEntry
@@ -71,6 +74,11 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
EdgeDataT data; EdgeDataT data;
}; };
EdgeRange GetAdjacentEdgeRange(const NodeID node) const
{
return boost::irange(BeginEdges(node), EndEdges(node));
}
StaticGraph(const int nodes, std::vector<InputEdge> &graph) StaticGraph(const int nodes, std::vector<InputEdge> &graph)
{ {
std::sort(graph.begin(), graph.end()); std::sort(graph.begin(), graph.end());
@@ -81,18 +89,20 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
EdgeIterator position = 0; EdgeIterator position = 0;
for (NodeIterator node = 0; node <= number_of_nodes; ++node) 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) while (edge < number_of_edges && graph[edge].source == node)
{
++edge; ++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_array.resize(position); //(edge)
edge = 0; edge = 0;
for (NodeIterator node = 0; node < number_of_nodes; ++node) for (NodeIterator node = 0; node < number_of_nodes; ++node)
{ {
EdgeIterator e = node_array[node + 1].firstEdge; EdgeIterator e = node_array[node + 1].first_edge;
for (EdgeIterator i = node_array[node].firstEdge; i != e; ++i) for (EdgeIterator i = node_array[node].first_edge; i != e; ++i)
{ {
edge_array[i].target = graph[edge].target; edge_array[i].target = graph[edge].target;
edge_array[i].data = graph[edge].data; edge_array[i].data = graph[edge].data;
@@ -115,10 +125,10 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
Percent p(GetNumberOfNodes()); Percent p(GetNumberOfNodes());
for (unsigned u = 0; u < GetNumberOfNodes(); ++u) 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); const unsigned v = GetTarget(eid);
EdgeData &data = GetEdgeData(eid); const EdgeData &data = GetEdgeData(eid);
if (data.shortcut) if (data.shortcut)
{ {
const EdgeID first_edge_id = FindEdgeInEitherDirection(u, data.id); const EdgeID first_edge_id = FindEdgeInEitherDirection(u, data.id);
@@ -144,7 +154,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
#endif #endif
} }
unsigned GetNumberOfNodes() const { return number_of_nodes; } unsigned GetNumberOfNodes() const { return number_of_nodes -1; }
unsigned GetNumberOfEdges() const { return number_of_edges; } unsigned GetNumberOfEdges() const { return number_of_edges; }
@@ -161,12 +171,12 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
EdgeIterator BeginEdges(const NodeIterator n) const 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 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 // searches for a specific edge
@@ -174,7 +184,7 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
{ {
EdgeIterator smallest_edge = SPECIAL_EDGEID; EdgeIterator smallest_edge = SPECIAL_EDGEID;
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT; 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 NodeID target = GetTarget(edge);
const EdgeWeight weight = GetEdgeData(edge).distance; const EdgeWeight weight = GetEdgeData(edge).distance;
+29 -28
View File
@@ -128,7 +128,7 @@ class StaticRTree
Contains(lower_left)); Contains(lower_left));
} }
inline double GetMinDist(const FixedPointCoordinate &location) const inline float GetMinDist(const FixedPointCoordinate &location) const
{ {
bool is_contained = Contains(location); bool is_contained = Contains(location);
if (is_contained) if (is_contained)
@@ -136,7 +136,7 @@ class StaticRTree
return 0.; return 0.;
} }
double min_dist = std::numeric_limits<double>::max(); float min_dist = std::numeric_limits<float>::max();
min_dist = std::min(min_dist, min_dist = std::min(min_dist,
FixedPointCoordinate::ApproximateEuclideanDistance( FixedPointCoordinate::ApproximateEuclideanDistance(
location.lat, location.lon, max_lat, min_lon)); location.lat, location.lon, max_lat, min_lon));
@@ -152,9 +152,9 @@ class StaticRTree
return min_dist; 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 // Get minmax distance to each of the four sides
FixedPointCoordinate upper_left(max_lat, min_lon); FixedPointCoordinate upper_left(max_lat, min_lon);
FixedPointCoordinate upper_right(max_lat, max_lon); FixedPointCoordinate upper_right(max_lat, max_lon);
@@ -240,13 +240,13 @@ class StaticRTree
struct QueryCandidate struct QueryCandidate
{ {
explicit QueryCandidate(const uint32_t n_id, const double dist) explicit QueryCandidate(const uint32_t n_id, const float dist)
: node_id(n_id), min_dist(dist) : node_id(n_id), min_dist(dist)
{ {
} }
QueryCandidate() : node_id(UINT_MAX), min_dist(std::numeric_limits<double>::max()) {} QueryCandidate() : node_id(UINT_MAX), min_dist(std::numeric_limits<float>::max()) {}
uint32_t node_id; uint32_t node_id;
double min_dist; float min_dist;
inline bool operator<(const QueryCandidate &other) const inline bool operator<(const QueryCandidate &other) const
{ {
return min_dist < other.min_dist; return min_dist < other.min_dist;
@@ -490,13 +490,13 @@ class StaticRTree
{ {
bool ignore_tiny_components = (zoom_level <= 14); bool ignore_tiny_components = (zoom_level <= 14);
DataT nearest_edge; DataT nearest_edge;
double min_dist = std::numeric_limits<double>::max(); float min_dist = std::numeric_limits<float>::max();
double min_max_dist = std::numeric_limits<double>::max(); float min_max_dist = std::numeric_limits<float>::max();
bool found_a_nearest_edge = false; bool found_a_nearest_edge = false;
// initialize queue with root element // initialize queue with root element
std::priority_queue<QueryCandidate> traversal_queue; std::priority_queue<QueryCandidate> traversal_queue;
double current_min_dist = float current_min_dist =
m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate); m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
traversal_queue.emplace(0, current_min_dist); traversal_queue.emplace(0, current_min_dist);
@@ -522,7 +522,7 @@ class StaticRTree
continue; continue;
} }
double current_minimum_distance = float current_minimum_distance =
FixedPointCoordinate::ApproximateEuclideanDistance( FixedPointCoordinate::ApproximateEuclideanDistance(
input_coordinate.lat, input_coordinate.lat,
input_coordinate.lon, input_coordinate.lon,
@@ -563,9 +563,9 @@ class StaticRTree
const TreeNode &child_tree_node = m_search_tree[child_id]; const TreeNode &child_tree_node = m_search_tree[child_id];
const RectangleT &child_rectangle = const RectangleT &child_rectangle =
child_tree_node.minimum_bounding_rectangle; child_tree_node.minimum_bounding_rectangle;
const double current_min_dist = const float current_min_dist =
child_rectangle.GetMinDist(input_coordinate); child_rectangle.GetMinDist(input_coordinate);
const double current_min_max_dist = const float current_min_max_dist =
child_rectangle.GetMinMaxDist(input_coordinate); child_rectangle.GetMinMaxDist(input_coordinate);
if (current_min_max_dist < min_max_dist) if (current_min_max_dist < min_max_dist)
{ {
@@ -597,19 +597,19 @@ class StaticRTree
const bool ignore_tiny_components = (zoom_level <= 14); const bool ignore_tiny_components = (zoom_level <= 14);
DataT nearest_edge; DataT nearest_edge;
double min_dist = std::numeric_limits<double>::max(); float min_dist = std::numeric_limits<float>::max();
double min_max_dist = std::numeric_limits<double>::max(); float min_max_dist = std::numeric_limits<float>::max();
bool found_a_nearest_edge = false; bool found_a_nearest_edge = false;
FixedPointCoordinate nearest, current_start_coordinate, current_end_coordinate; FixedPointCoordinate nearest, current_start_coordinate, current_end_coordinate;
// initialize queue with root element // initialize queue with root element
std::priority_queue<QueryCandidate> traversal_queue; std::priority_queue<QueryCandidate> traversal_queue;
double current_min_dist = float current_min_dist =
m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate); m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
traversal_queue.emplace(0, current_min_dist); traversal_queue.emplace(0, current_min_dist);
BOOST_ASSERT_MSG(std::numeric_limits<double>::epsilon() > BOOST_ASSERT_MSG(std::numeric_limits<float>::epsilon() >
(0. - traversal_queue.top().min_dist), (0. - traversal_queue.top().min_dist),
"Root element in NN Search has min dist != 0."); "Root element in NN Search has min dist != 0.");
@@ -635,8 +635,8 @@ class StaticRTree
continue; continue;
} }
double current_ratio = 0.; float current_ratio = 0.;
const double current_perpendicular_distance = const float current_perpendicular_distance =
FixedPointCoordinate::ComputePerpendicularDistance( FixedPointCoordinate::ComputePerpendicularDistance(
m_coordinate_list->at(current_edge.u), m_coordinate_list->at(current_edge.u),
m_coordinate_list->at(current_edge.v), m_coordinate_list->at(current_edge.v),
@@ -647,7 +647,7 @@ class StaticRTree
BOOST_ASSERT(0. <= current_perpendicular_distance); BOOST_ASSERT(0. <= current_perpendicular_distance);
if ((current_perpendicular_distance < min_dist) && if ((current_perpendicular_distance < min_dist) &&
!DoubleEpsilonCompare(current_perpendicular_distance, min_dist)) !EpsilonCompare(current_perpendicular_distance, min_dist))
{ // found a new minimum { // found a new minimum
min_dist = current_perpendicular_distance; min_dist = current_perpendicular_distance;
// TODO: use assignment c'tor in PhantomNode // TODO: use assignment c'tor in PhantomNode
@@ -685,9 +685,9 @@ class StaticRTree
const int32_t child_id = current_tree_node.children[i]; const int32_t child_id = current_tree_node.children[i];
TreeNode &child_tree_node = m_search_tree[child_id]; TreeNode &child_tree_node = m_search_tree[child_id];
RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle; RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
const double current_min_dist = const float current_min_dist =
child_rectangle.GetMinDist(input_coordinate); child_rectangle.GetMinDist(input_coordinate);
const double current_min_max_dist = const float current_min_max_dist =
child_rectangle.GetMinMaxDist(input_coordinate); child_rectangle.GetMinMaxDist(input_coordinate);
if (current_min_max_dist < min_max_dist) if (current_min_max_dist < min_max_dist)
{ {
@@ -717,18 +717,18 @@ class StaticRTree
result_phantom_node.location.lat = input_coordinate.lat; result_phantom_node.location.lat = input_coordinate.lat;
} }
double ratio = 0.; float ratio = 0.f;
if (found_a_nearest_edge) if (found_a_nearest_edge)
{ {
const double distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance( const float distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
current_start_coordinate, result_phantom_node.location); current_start_coordinate, result_phantom_node.location);
const double distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance( const float distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
current_start_coordinate, current_end_coordinate); current_start_coordinate, current_end_coordinate);
ratio = distance_1 / distance_2; ratio = distance_1 / distance_2;
ratio = std::min(1., ratio); ratio = std::min(1.f, ratio);
if (SPECIAL_NODEID != result_phantom_node.forward_node_id) if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
{ {
@@ -768,9 +768,10 @@ class StaticRTree
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c); 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());
} }
}; };
+2
View File
@@ -80,7 +80,9 @@ struct TurnInstructionsClass
static inline bool TurnIsNecessary(const TurnInstruction turn_instruction) static inline bool TurnIsNecessary(const TurnInstruction turn_instruction)
{ {
if (TurnInstruction::NoTurn == turn_instruction || TurnInstruction::StayOnRoundAbout == turn_instruction) if (TurnInstruction::NoTurn == turn_instruction || TurnInstruction::StayOnRoundAbout == turn_instruction)
{
return false; return false;
}
return true; return true;
} }
}; };
-1
View File
@@ -56,7 +56,6 @@ template <class DataFacadeT> class BaseDescriptor
virtual ~BaseDescriptor() {} virtual ~BaseDescriptor() {}
virtual void Run(const RawRouteData &raw_route, virtual void Run(const RawRouteData &raw_route,
const PhantomNodes &phantom_nodes, const PhantomNodes &phantom_nodes,
DataFacadeT *facade,
http::Reply &reply) = 0; http::Reply &reply) = 0;
virtual void SetConfig(const DescriptorConfig &config) = 0; virtual void SetConfig(const DescriptorConfig &config) = 0;
}; };
+14 -65
View File
@@ -29,41 +29,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
DescriptionFactory::DescriptionFactory() : entireLength(0) {} DescriptionFactory::DescriptionFactory() : entireLength(0) {}
DescriptionFactory::~DescriptionFactory() {}
inline double DescriptionFactory::DegreeToRadian(const double degree) const
{
return degree * (M_PI / 180.);
}
inline double DescriptionFactory::RadianToDegree(const double radian) const
{
return radian * (180. / M_PI);
}
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)
{ {
start_phantom = source; start_phantom = source;
@@ -83,49 +48,33 @@ void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
if ((1 == path_description.size()) && (path_description.back().location == coordinate)) if ((1 == path_description.size()) && (path_description.back().location == coordinate))
{ {
path_description.back().name_id = path_point.name_id; path_description.back().name_id = path_point.name_id;
return;
} }
else
{ path_description.emplace_back(coordinate,
path_description.emplace_back(coordinate, path_point.name_id,
path_point.name_id, path_point.segment_duration,
path_point.segment_duration, 0,
0, path_point.turn_instruction);
path_point.turn_instruction);
}
} }
void DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded, JSON::Value DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded)
std::vector<std::string> &output)
{ {
std::string temp;
if (return_encoded) if (return_encoded)
{ {
polyline_compressor.printEncodedString(path_description, temp); return polyline_compressor.printEncodedString(path_description);
} }
else return polyline_compressor.printUnencodedString(path_description);
{
polyline_compressor.printUnencodedString(path_description, temp);
}
output.emplace_back(temp);
} }
void DescriptionFactory::AppendEncodedPolylineString(std::vector<std::string> &output) const JSON::Value DescriptionFactory::AppendUnencodedPolylineString() const
{ {
std::string temp; return polyline_compressor.printUnencodedString(path_description);
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);
} }
void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time) void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
{ {
summary.startName = start_phantom.name_id; summary.source_name_id = start_phantom.name_id;
summary.destName = target_phantom.name_id; summary.target_name_id = target_phantom.name_id;
summary.BuildDurationAndLengthStrings(distance, time); summary.BuildDurationAndLengthStrings(distance, time);
} }
+15 -20
View File
@@ -57,18 +57,17 @@ class DescriptionFactory
public: public:
struct RouteSummary struct RouteSummary
{ {
std::string lengthString; unsigned distance;
std::string durationString; EdgeWeight duration;
unsigned startName; unsigned source_name_id;
unsigned destName; unsigned target_name_id;
RouteSummary() : lengthString("0"), durationString("0"), startName(0), destName(0) {} 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 // compute distance/duration for route summary
intToString(round(distance), lengthString); distance = round(raw_distance);
int travel_time = round(time / 10.); duration = round(raw_duration / 10.);
intToString(std::max(travel_time, 1), durationString);
} }
} summary; } summary;
@@ -77,15 +76,12 @@ class DescriptionFactory
// I know, declaring this public is considered bad. I'm lazy // I know, declaring this public is considered bad. I'm lazy
std::vector<SegmentInformation> path_description; std::vector<SegmentInformation> path_description;
DescriptionFactory(); DescriptionFactory();
virtual ~DescriptionFactory(); JSON::Value AppendUnencodedPolylineString() const;
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 AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
void BuildRouteSummary(const double distance, const unsigned time); void BuildRouteSummary(const double distance, const unsigned time);
void SetStartSegment(const PhantomNode &start_phantom); void SetStartSegment(const PhantomNode &start_phantom);
void SetEndSegment(const PhantomNode &start_phantom); void SetEndSegment(const PhantomNode &start_phantom);
void AppendEncodedPolylineString(const bool return_encoded, std::vector<std::string> &output); JSON::Value AppendEncodedPolylineString(const bool return_encoded);
template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel) template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel)
{ {
@@ -179,14 +175,14 @@ class DescriptionFactory
target_phantom.name_id = (path_description.end() - 2)->name_id; 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) if (path_description.size() > 2)
{ {
path_description.erase(path_description.begin()); path_description.erase(path_description.begin());
path_description[0].turn_instruction = TurnInstruction::HeadOn; path_description.front().turn_instruction = TurnInstruction::HeadOn;
path_description[0].necessary = true; path_description.front().necessary = true;
start_phantom.name_id = path_description[0].name_id; start_phantom.name_id = path_description.front().name_id;
} }
} }
@@ -198,8 +194,7 @@ class DescriptionFactory
{ {
if (path_description[i].necessary) if (path_description[i].necessary)
{ {
double angle = const double angle = path_description[i+1].location.GetBearing(path_description[i].location);
GetBearing(path_description[i].location, path_description[i + 1].location);
path_description[i].bearing = angle * 10; path_description[i].bearing = angle * 10;
} }
} }
+41 -36
View File
@@ -35,63 +35,68 @@ template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFac
private: private:
DescriptorConfig config; DescriptorConfig config;
FixedPointCoordinate current; 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: public:
GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
void SetConfig(const DescriptorConfig &c) { config = c; } void SetConfig(const DescriptorConfig &c) { config = c; }
// TODO: reorder parameters // TODO: reorder parameters
void Run(const RawRouteData &raw_route, void Run(const RawRouteData &raw_route,
const PhantomNodes &phantom_node_list, const PhantomNodes &phantom_node_list,
DataFacadeT *facade,
http::Reply &reply) http::Reply &reply)
{ {
reply.content.emplace_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
reply.content.emplace_back("<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" " "<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
"xmlns=\"http://www.topografix.com/GPX/1/1\" " "xmlns=\"http://www.topografix.com/GPX/1/1\" "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd" "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
"\">"); "\">"
reply.content.emplace_back("<metadata><copyright author=\"Project OSRM\"><license>Data (c)" "<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
" OpenStreetMap contributors (ODbL)</license></copyright>" " OpenStreetMap contributors (ODbL)</license></copyright>"
"</metadata>"); "</metadata>"
reply.content.emplace_back("<rte>"); "<rte>");
bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) && reply.content.insert(reply.content.end(), header.begin(), header.end());
(!raw_route.unpacked_path_segments.front().empty()); const bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
(!raw_route.unpacked_path_segments.front().empty());
if (found_route) if (found_route)
{ {
FixedPointCoordinate::convertInternalLatLonToString( AddRoutePoint(phantom_node_list.source_phantom.location, reply.content);
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>");
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments) for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
{ {
for (const PathData &path_data : path_data_vector) for (const PathData &path_data : path_data_vector)
{ {
FixedPointCoordinate current_coordinate = const FixedPointCoordinate current_coordinate =
facade->GetCoordinateOfNode(path_data.node); facade->GetCoordinateOfNode(path_data.node);
AddRoutePoint(current_coordinate, reply.content);
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>");
} }
} }
// Add the via point or the end coordinate AddRoutePoint(phantom_node_list.target_phantom.location, reply.content);
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>");
} }
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 #endif // GPX_DESCRIPTOR_H
+356 -524
View File
@@ -1,524 +1,356 @@
/* /*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution. other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 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 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef JSON_DESCRIPTOR_H_ #ifndef JSON_DESCRIPTOR_H_
#define JSON_DESCRIPTOR_H_ #define JSON_DESCRIPTOR_H_
#include "BaseDescriptor.h" #include "BaseDescriptor.h"
#include "DescriptionFactory.h" #include "DescriptionFactory.h"
#include "../Algorithms/ObjectToBase64.h" #include "../Algorithms/ObjectToBase64.h"
#include "../DataStructures/SegmentInformation.h" #include "../Algorithms/ExtractRouteNames.h"
#include "../DataStructures/TurnInstructions.h" #include "../DataStructures/JSONContainer.h"
#include "../Util/Azimuth.h" #include "../DataStructures/SegmentInformation.h"
#include "../Util/StringUtil.h" #include "../DataStructures/TurnInstructions.h"
#include "../Util/Azimuth.h"
#include <algorithm> #include "../Util/StringUtil.h"
#include "../Util/TimingUtil.h"
template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFacadeT>
{ #include <algorithm>
private:
// TODO: initalize in c'tor template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFacadeT>
DataFacadeT *facade; {
DescriptorConfig config; private:
DescriptionFactory description_factory; DataFacadeT *facade;
DescriptionFactory alternate_descriptionFactory; DescriptorConfig config;
FixedPointCoordinate current; DescriptionFactory description_factory, alternate_description_factory;
unsigned entered_restricted_area_count; FixedPointCoordinate current;
struct RoundAbout unsigned entered_restricted_area_count;
{ struct RoundAbout
RoundAbout() : start_index(INT_MAX), name_id(INT_MAX), leave_at_exit(INT_MAX) {} {
int start_index; RoundAbout() : start_index(INT_MAX), name_id(INT_MAX), leave_at_exit(INT_MAX) {}
int name_id; int start_index;
int leave_at_exit; int name_id;
} round_about; int leave_at_exit;
} round_about;
struct Segment
{ struct Segment
Segment() : name_id(-1), length(-1), position(-1) {} {
Segment(int n, int l, int p) : name_id(n), length(l), position(p) {} Segment() : name_id(-1), length(-1), position(-1) {}
int name_id; Segment(int n, int l, int p) : name_id(n), length(l), position(p) {}
int length; int name_id;
int position; int length;
}; int position;
std::vector<Segment> shortest_path_segments, alternative_path_segments; };
std::vector<unsigned> shortest_leg_end_indices, alternative_leg_end_indices; std::vector<Segment> shortest_path_segments, alternative_path_segments;
std::vector<unsigned> shortest_leg_end_indices, alternative_leg_end_indices;
struct RouteNames ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
{
std::string shortest_path_name_1;
std::string shortest_path_name_2; public:
std::string alternative_path_name_1; JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0)
std::string alternative_path_name_2; {
}; shortest_leg_end_indices.emplace_back(0);
alternative_leg_end_indices.emplace_back(0);
public: }
JSONDescriptor() : facade(nullptr), entered_restricted_area_count(0)
{ void SetConfig(const DescriptorConfig &c) { config = c; }
shortest_leg_end_indices.emplace_back(0);
alternative_leg_end_indices.emplace_back(0); unsigned DescribeLeg(const std::vector<PathData> route_leg, const PhantomNodes &leg_phantoms)
} {
unsigned added_element_count = 0;
void SetConfig(const DescriptorConfig &c) { config = c; } // Get all the coordinates for the computed route
FixedPointCoordinate current_coordinate;
unsigned DescribeLeg(const std::vector<PathData> route_leg, const PhantomNodes &leg_phantoms) for (const PathData &path_data : route_leg)
{ {
unsigned added_element_count = 0; current_coordinate = facade->GetCoordinateOfNode(path_data.node);
// Get all the coordinates for the computed route description_factory.AppendSegment(current_coordinate, path_data);
FixedPointCoordinate current_coordinate; ++added_element_count;
for (const PathData &path_data : route_leg) }
{ ++added_element_count;
current_coordinate = facade->GetCoordinateOfNode(path_data.node); BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
description_factory.AppendSegment(current_coordinate, path_data); return added_element_count;
++added_element_count; }
}
++added_element_count; void Run(const RawRouteData &raw_route,
BOOST_ASSERT((route_leg.size() + 1) == added_element_count); const PhantomNodes &phantom_nodes,
return added_element_count; http::Reply &reply)
} {
JSON::Object json_result;
void Run(const RawRouteData &raw_route,
const PhantomNodes &phantom_nodes, if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
// TODO: move facade initalization to c'tor {
DataFacadeT *f, // We do not need to do much, if there is no route ;-)
http::Reply &reply) json_result.values["status"] = 207;
{ json_result.values["status_message"] = "Cannot find route between points";
facade = f; JSON::render(reply.content, json_result);
reply.content.emplace_back("{\"status\":"); return;
}
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
{ // check if first segment is non-zero
// We do not need to do much, if there is no route ;-) std::string road_name =
reply.content.emplace_back( facade->GetEscapedNameForNameID(phantom_nodes.source_phantom.name_id);
"207,\"status_message\": \"Cannot find route between points\"}");
return; BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
} raw_route.segment_end_coordinates.size());
SimpleLogger().Write(logDEBUG) << "distance: " << raw_route.shortest_path_length; description_factory.SetStartSegment(phantom_nodes.source_phantom);
json_result.values["status"] = 0;
// check if first segment is non-zero json_result.values["status_message"] = "Found route between points";
std::string road_name =
facade->GetEscapedNameForNameID(phantom_nodes.source_phantom.name_id); // for each unpacked segment add the leg to the description
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
BOOST_ASSERT(raw_route.unpacked_path_segments.size() == {
raw_route.segment_end_coordinates.size()); const int added_segments = DescribeLeg(raw_route.unpacked_path_segments[i],
raw_route.segment_end_coordinates[i]);
description_factory.SetStartSegment(phantom_nodes.source_phantom); BOOST_ASSERT(0 < added_segments);
reply.content.emplace_back("0," shortest_leg_end_indices.emplace_back(added_segments + shortest_leg_end_indices.back());
"\"status_message\": \"Found route between points\","); }
description_factory.SetEndSegment(phantom_nodes.target_phantom);
// for each unpacked segment add the leg to the description description_factory.Run(facade, config.zoom_level);
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
{ if (config.geometry)
const int added_segments = DescribeLeg(raw_route.unpacked_path_segments[i], {
raw_route.segment_end_coordinates[i]); JSON::Value route_geometry = description_factory.AppendEncodedPolylineString(config.encode_geometry);
BOOST_ASSERT(0 < added_segments); json_result.values["route_geometry"] = route_geometry;
shortest_leg_end_indices.emplace_back(added_segments + shortest_leg_end_indices.back()); }
} if (config.instructions)
description_factory.SetEndSegment(phantom_nodes.target_phantom); {
description_factory.Run(facade, config.zoom_level); JSON::Array json_route_instructions;
BuildTextualDescription(description_factory,
reply.content.emplace_back("\"route_geometry\": "); json_route_instructions,
if (config.geometry) raw_route.shortest_path_length,
{ shortest_path_segments);
description_factory.AppendEncodedPolylineString(config.encode_geometry, reply.content); json_result.values["route_instructions"] = json_route_instructions;
} }
else description_factory.BuildRouteSummary(description_factory.entireLength,
{ raw_route.shortest_path_length);
reply.content.emplace_back("[]"); 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;
reply.content.emplace_back(",\"route_instructions\": ["); json_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(description_factory.summary.source_name_id);
if (config.instructions) json_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(description_factory.summary.target_name_id);
{ json_result.values["route_summary"] = json_route_summary;
BuildTextualDescription(description_factory,
reply, BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
raw_route.shortest_path_length,
facade, JSON::Array json_via_points_array;
shortest_path_segments); JSON::Array json_first_coordinate;
} json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lat/COORDINATE_PRECISION);
reply.content.emplace_back("],"); json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lon/COORDINATE_PRECISION);
description_factory.BuildRouteSummary(description_factory.entireLength, json_via_points_array.values.push_back(json_first_coordinate);
raw_route.shortest_path_length); for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
{
reply.content.emplace_back("\"route_summary\":"); std::string tmp;
reply.content.emplace_back("{"); JSON::Array json_coordinate;
reply.content.emplace_back("\"total_distance\":"); json_coordinate.values.push_back(nodes.target_phantom.location.lat/COORDINATE_PRECISION);
reply.content.emplace_back(description_factory.summary.lengthString); json_coordinate.values.push_back(nodes.target_phantom.location.lon/COORDINATE_PRECISION);
reply.content.emplace_back("," json_via_points_array.values.push_back(json_coordinate);
"\"total_time\":"); }
reply.content.emplace_back(description_factory.summary.durationString); json_result.values["via_points"] = json_via_points_array;
reply.content.emplace_back(","
"\"start_point\":\""); JSON::Array json_via_indices_array;
reply.content.emplace_back( json_via_indices_array.values.insert(json_via_indices_array.values.end(), shortest_leg_end_indices.begin(), shortest_leg_end_indices.end());
facade->GetEscapedNameForNameID(description_factory.summary.startName)); json_result.values["via_indices"] = json_via_indices_array;
reply.content.emplace_back("\","
"\"end_point\":\""); // only one alternative route is computed at this time, so this is hardcoded
reply.content.emplace_back( if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
facade->GetEscapedNameForNameID(description_factory.summary.destName)); {
reply.content.emplace_back("\""); json_result.values["found_alternative"] = JSON::True();
reply.content.emplace_back("}"); alternate_description_factory.SetStartSegment(phantom_nodes.source_phantom);
reply.content.emplace_back(","); // Get all the coordinates for the computed route
for (const PathData &path_data : raw_route.unpacked_alternative)
// only one alternative route is computed at this time, so this is hardcoded {
if (raw_route.alternative_path_length != INVALID_EDGE_WEIGHT) current = facade->GetCoordinateOfNode(path_data.node);
{ alternate_description_factory.AppendSegment(current, path_data);
alternate_descriptionFactory.SetStartSegment(phantom_nodes.source_phantom); }
// Get all the coordinates for the computed route alternate_description_factory.Run(facade, config.zoom_level);
for (const PathData &path_data : raw_route.unpacked_alternative)
{ if (config.geometry)
current = facade->GetCoordinateOfNode(path_data.node); {
alternate_descriptionFactory.AppendSegment(current, path_data); 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);
alternate_descriptionFactory.Run(facade, config.zoom_level); json_result.values["alternative_geometries"] = json_alternate_geometries_array;
}
// //give an array of alternative routes // Generate instructions for each alternative (simulated here)
reply.content.emplace_back("\"alternative_geometries\": ["); JSON::Array json_alt_instructions;
if (config.geometry && INVALID_EDGE_WEIGHT != raw_route.alternative_path_length) JSON::Array json_current_alt_instructions;
{ if (config.instructions)
// Generate the linestrings for each alternative {
alternate_descriptionFactory.AppendEncodedPolylineString(config.encode_geometry, BuildTextualDescription(alternate_description_factory,
reply.content); json_current_alt_instructions,
} raw_route.alternative_path_length,
reply.content.emplace_back("],"); alternative_path_segments);
reply.content.emplace_back("\"alternative_instructions\":["); json_alt_instructions.values.push_back(json_current_alt_instructions);
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length) json_result.values["alternative_instructions"] = json_alt_instructions;
{ }
reply.content.emplace_back("["); alternate_description_factory.BuildRouteSummary(
// Generate instructions for each alternative alternate_description_factory.entireLength, raw_route.alternative_path_length);
if (config.instructions)
{ JSON::Object json_alternate_route_summary;
BuildTextualDescription(alternate_descriptionFactory, JSON::Array json_alternate_route_summary_array;
reply, json_alternate_route_summary.values["total_distance"] = alternate_description_factory.summary.distance;
raw_route.alternative_path_length, json_alternate_route_summary.values["total_time"] = alternate_description_factory.summary.duration;
facade, json_alternate_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(alternate_description_factory.summary.source_name_id);
alternative_path_segments); 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);
reply.content.emplace_back("]"); json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
}
reply.content.emplace_back("],"); JSON::Array json_altenative_indices_array;
reply.content.emplace_back("\"alternative_summaries\":["); json_altenative_indices_array.values.push_back(0);
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length) json_altenative_indices_array.values.push_back(alternate_description_factory.path_description.size());
{ json_result.values["alternative_indices"] = json_altenative_indices_array;
// Generate route summary (length, duration) for each alternative } else {
alternate_descriptionFactory.BuildRouteSummary( json_result.values["found_alternative"] = JSON::False();
alternate_descriptionFactory.entireLength, raw_route.alternative_path_length); }
reply.content.emplace_back("{");
reply.content.emplace_back("\"total_distance\":"); // Get Names for both routes
reply.content.emplace_back(alternate_descriptionFactory.summary.lengthString); RouteNames route_names = GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
reply.content.emplace_back("," JSON::Array json_route_names;
"\"total_time\":"); json_route_names.values.push_back(route_names.shortest_path_name_1);
reply.content.emplace_back(alternate_descriptionFactory.summary.durationString); json_route_names.values.push_back(route_names.shortest_path_name_2);
reply.content.emplace_back("," json_result.values["route_name"] = json_route_names;
"\"start_point\":\"");
reply.content.emplace_back( if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
facade->GetEscapedNameForNameID(description_factory.summary.startName)); {
reply.content.emplace_back("\"," JSON::Array json_alternate_names_array;
"\"end_point\":\""); JSON::Array json_alternate_names;
reply.content.emplace_back( json_alternate_names.values.push_back(route_names.alternative_path_name_1);
facade->GetEscapedNameForNameID(description_factory.summary.destName)); json_alternate_names.values.push_back(route_names.alternative_path_name_2);
reply.content.emplace_back("\""); json_alternate_names_array.values.push_back(json_alternate_names);
reply.content.emplace_back("}"); json_result.values["alternative_names"] = json_alternate_names_array;
} }
reply.content.emplace_back("],");
JSON::Object json_hint_object;
// //Get Names for both routes json_hint_object.values["checksum"] = raw_route.check_sum;
RouteNames routeNames; JSON::Array json_location_hint_array;
GetRouteNames(shortest_path_segments, alternative_path_segments, facade, routeNames); std::string hint;
for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i)
reply.content.emplace_back("\"route_name\":[\""); {
reply.content.emplace_back(routeNames.shortest_path_name_1); EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
reply.content.emplace_back("\",\""); json_location_hint_array.values.push_back(hint);
reply.content.emplace_back(routeNames.shortest_path_name_2); }
reply.content.emplace_back("\"]," EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
"\"alternative_names\":["); json_location_hint_array.values.push_back(hint);
reply.content.emplace_back("[\""); json_hint_object.values["locations"] = json_location_hint_array;
reply.content.emplace_back(routeNames.alternative_path_name_1); json_result.values["hint_data"] = json_hint_object;
reply.content.emplace_back("\",\"");
reply.content.emplace_back(routeNames.alternative_path_name_2); // render the content to the output array
reply.content.emplace_back("\"]"); TIMER_START(route_render);
reply.content.emplace_back("],"); JSON::render(reply.content, json_result);
// list all viapoints so that the client may display it TIMER_STOP(route_render);
reply.content.emplace_back("\"via_points\":["); SimpleLogger().Write(logDEBUG) << "rendering took: " << TIMER_MSEC(route_render);
}
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
// TODO: reorder parameters
std::string tmp; inline void BuildTextualDescription(DescriptionFactory &description_factory,
FixedPointCoordinate::convertInternalReversedCoordinateToString( JSON::Array & json_instruction_array,
raw_route.segment_end_coordinates.front().source_phantom.location, tmp); const int route_length,
reply.content.emplace_back("["); std::vector<Segment> &route_segments_list)
reply.content.emplace_back(tmp); {
reply.content.emplace_back("]"); // Segment information has following format:
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates) unsigned necessary_segments_running_index = 0;
{ round_about.leave_at_exit = 0;
tmp.clear(); round_about.name_id = 0;
FixedPointCoordinate::convertInternalReversedCoordinateToString( std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
nodes.target_phantom.location, tmp);
reply.content.emplace_back(",["); // Fetch data from Factory and generate a string from it.
reply.content.emplace_back(tmp); for (const SegmentInformation &segment : description_factory.path_description)
reply.content.emplace_back("]"); {
} JSON::Array json_instruction_row;
TurnInstruction current_instruction = segment.turn_instruction;
reply.content.emplace_back("],"); entered_restricted_area_count += (current_instruction != segment.turn_instruction);
reply.content.emplace_back("\"via_indices\":["); if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
for (const unsigned index : shortest_leg_end_indices) {
{ if (TurnInstruction::EnterRoundAbout == current_instruction)
tmp.clear(); {
intToString(index, tmp); round_about.name_id = segment.name_id;
reply.content.emplace_back(tmp); round_about.start_index = necessary_segments_running_index;
if (index != shortest_leg_end_indices.back()) }
{ else
reply.content.emplace_back(","); {
} std::string current_turn_instruction;
} if (TurnInstruction::LeaveRoundAbout == current_instruction)
reply.content.emplace_back("],\"alternative_indices\":["); {
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length) temp_instruction = IntToString(as_integer(TurnInstruction::EnterRoundAbout));
{ current_turn_instruction += temp_instruction;
reply.content.emplace_back("0,"); current_turn_instruction += "-";
tmp.clear(); temp_instruction = IntToString(round_about.leave_at_exit + 1);
intToString(alternate_descriptionFactory.path_description.size(), tmp); current_turn_instruction += temp_instruction;
reply.content.emplace_back(tmp); round_about.leave_at_exit = 0;
} }
else
reply.content.emplace_back("],"); {
reply.content.emplace_back("\"hint_data\": {"); temp_instruction = IntToString(as_integer(current_instruction));
reply.content.emplace_back("\"checksum\":"); current_turn_instruction += temp_instruction;
intToString(raw_route.check_sum, tmp); }
reply.content.emplace_back(tmp); json_instruction_row.values.push_back(current_turn_instruction);
reply.content.emplace_back(", \"locations\": [");
json_instruction_row.values.push_back(facade->GetEscapedNameForNameID(segment.name_id));
std::string hint; json_instruction_row.values.push_back(std::round(segment.length));
for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i) json_instruction_row.values.push_back(necessary_segments_running_index);
{ json_instruction_row.values.push_back(round(segment.duration / 10));
reply.content.emplace_back("\""); json_instruction_row.values.push_back(IntToString(segment.length)+"m");
EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint); int bearing_value = round(segment.bearing / 10.);
reply.content.emplace_back(hint); json_instruction_row.values.push_back(Azimuth::Get(bearing_value));
reply.content.emplace_back("\", "); json_instruction_row.values.push_back(bearing_value);
}
EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint); route_segments_list.emplace_back(
reply.content.emplace_back("\""); segment.name_id, segment.length, route_segments_list.size());
reply.content.emplace_back(hint); json_instruction_array.values.push_back(json_instruction_row);
reply.content.emplace_back("\"]"); }
reply.content.emplace_back("}}"); }
} else if (TurnInstruction::StayOnRoundAbout == current_instruction)
{
// construct routes names ++round_about.leave_at_exit;
void GetRouteNames(std::vector<Segment> &shortest_path_segments, }
std::vector<Segment> &alternative_path_segments, if (segment.necessary)
const DataFacadeT *facade, {
RouteNames &routeNames) ++necessary_segments_running_index;
{ }
Segment shortest_segment_1, shortest_segment_2; }
Segment alternativeSegment1, alternative_segment_2;
//TODO: check if this in an invariant
auto length_comperator = [](Segment a, Segment b) if (INVALID_EDGE_WEIGHT != route_length)
{ return a.length < b.length; }; {
auto name_id_comperator = [](Segment a, Segment b) JSON::Array json_last_instruction_row;
{ return a.name_id < b.name_id; }; temp_instruction = IntToString(as_integer(TurnInstruction::ReachedYourDestination));
json_last_instruction_row.values.push_back(temp_instruction);
if (!shortest_path_segments.empty()) json_last_instruction_row.values.push_back("");
{ json_last_instruction_row.values.push_back(0);
std::sort( json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator); json_last_instruction_row.values.push_back(0);
shortest_segment_1 = shortest_path_segments[0]; json_last_instruction_row.values.push_back("0m");
if (!alternative_path_segments.empty()) json_last_instruction_row.values.push_back(Azimuth::Get(0.0));
{ json_last_instruction_row.values.push_back(0.);
std::sort(alternative_path_segments.begin(), json_instruction_array.values.push_back(json_last_instruction_row);
alternative_path_segments.end(), }
length_comperator); }
alternativeSegment1 = alternative_path_segments[0]; };
}
std::vector<Segment> shortestDifference(shortest_path_segments.size()); #endif /* JSON_DESCRIPTOR_H_ */
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_ */
+1
View File
@@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp> #include <boost/algorithm/string/regex.hpp>
#include <boost/ref.hpp>
#include <boost/regex.hpp> #include <boost/regex.hpp>
BaseParser::BaseParser(ExtractorCallbacks *extractor_callbacks, BaseParser::BaseParser(ExtractorCallbacks *extractor_callbacks,
+7 -6
View File
@@ -217,14 +217,15 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary); 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 *)&uuid, sizeof(UUID));
restrictions_out_stream.write((char *)&number_of_useable_restrictions, sizeof(unsigned)); restrictions_out_stream.write((char *)&number_of_useable_restrictions, sizeof(unsigned));
for (restrictions_iterator = restrictions_list.begin(); // for (restrictions_iterator = restrictions_list.begin();
restrictions_iterator != restrictions_list.end(); // restrictions_iterator != restrictions_list.end();
++restrictions_iterator) // ++restrictions_iterator)
for(const auto & restriction_container : restrictions_list)
{ {
if (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.fromNode && if (std::numeric_limits<unsigned>::max() != restriction_container.restriction.fromNode &&
std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.toNode) 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)); sizeof(TurnRestriction));
} }
} }
+86 -84
View File
@@ -63,102 +63,104 @@ bool ExtractorCallbacks::ProcessRestriction(const InputRestrictionContainer &res
/** warning: caller needs to take care of synchronization! */ /** warning: caller needs to take care of synchronization! */
void ExtractorCallbacks::ProcessWay(ExtractionWay &parsed_way) 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 { // Only true if the way is specified by the speed profile
if (std::numeric_limits<unsigned>::max() == parsed_way.id) return;
{ }
SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << parsed_way.id
<< " of size " << parsed_way.path.size();
return;
}
if (0 < parsed_way.duration) if (std::numeric_limits<unsigned>::max() == parsed_way.id)
{ {
// TODO: iterate all way segments and set duration corresponding to the length of each SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << parsed_way.id
// segment << " of size " << parsed_way.path.size();
parsed_way.speed = parsed_way.duration / (parsed_way.path.size() - 1); return;
} }
if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.speed)) if (0 < parsed_way.duration)
{ {
SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id; // TODO: iterate all way segments and set duration corresponding to the length of each
return; // segment
} parsed_way.speed = parsed_way.duration / (parsed_way.path.size() - 1);
}
// Get the unique identifier for the street name if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.speed))
const auto &string_map_iterator = string_map.find(parsed_way.name); {
if (string_map.end() == string_map_iterator) SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id;
{ return;
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) // 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_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)
{ {
std::reverse(parsed_way.path.begin(), parsed_way.path.end()); external_memory.all_edges_list.push_back(
parsed_way.direction = ExtractionWay::oneway; 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));
} }
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( external_memory.way_start_end_id_list.push_back(
WayIDStartAndEndEdge(parsed_way.id, WayIDStartAndEndEdge(parsed_way.id,
parsed_way.path[0], parsed_way.path[0],
parsed_way.path[1], parsed_way.path[1],
parsed_way.path[parsed_way.path.size() - 2], parsed_way.path[parsed_way.path.size() - 2],
parsed_way.path.back())); 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()));
}
} }
} }
-2
View File
@@ -42,8 +42,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <osrm/Coordinate.h> #include <osrm/Coordinate.h>
#include <boost/ref.hpp>
#include <zlib.h> #include <zlib.h>
#include <functional> #include <functional>
+111 -111
View File
@@ -40,8 +40,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <osrm/Coordinate.h> #include <osrm/Coordinate.h>
#include <boost/ref.hpp>
XMLParser::XMLParser(const char *filename, ExtractorCallbacks *ec, ScriptingEnvironment &se) XMLParser::XMLParser(const char *filename, ExtractorCallbacks *ec, ScriptingEnvironment &se)
: BaseParser(ec, se) : BaseParser(ec, se)
{ {
@@ -103,8 +101,8 @@ InputRestrictionContainer XMLParser::ReadXMLRestriction()
const int depth = xmlTextReaderDepth(inputReader); const int depth = xmlTextReaderDepth(inputReader);
while (xmlTextReaderRead(inputReader) == 1) while (xmlTextReaderRead(inputReader) == 1)
{ {
const int childType = xmlTextReaderNodeType(inputReader); const int child_type = xmlTextReaderNodeType(inputReader);
if (childType != 1 && childType != 15) if (child_type != 1 && child_type != 15)
{ {
continue; continue;
} }
@@ -114,13 +112,13 @@ InputRestrictionContainer XMLParser::ReadXMLRestriction()
{ {
continue; continue;
} }
if (depth == childDepth && childType == 15 && if (depth == childDepth && child_type == 15 &&
xmlStrEqual(childName, (const xmlChar *)"relation") == 1) xmlStrEqual(childName, (const xmlChar *)"relation") == 1)
{ {
xmlFree(childName); xmlFree(childName);
break; break;
} }
if (childType != 1) if (child_type != 1)
{ {
xmlFree(childName); xmlFree(childName);
continue; continue;
@@ -204,67 +202,68 @@ InputRestrictionContainer XMLParser::ReadXMLRestriction()
ExtractionWay XMLParser::ReadXMLWay() ExtractionWay XMLParser::ReadXMLWay()
{ {
ExtractionWay way; ExtractionWay way;
if (xmlTextReaderIsEmptyElement(inputReader) != 1) if (xmlTextReaderIsEmptyElement(inputReader) == 1)
{ {
const int depth = xmlTextReaderDepth(inputReader); return way;
while (xmlTextReaderRead(inputReader) == 1) }
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); continue;
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);
} }
const int childDepth = xmlTextReaderDepth(inputReader);
xmlChar *childName = xmlTextReaderName(inputReader);
if (childName == NULL)
{
continue;
}
if (depth == childDepth && child_type == 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 (child_type != 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);
} }
return way; return way;
} }
@@ -292,56 +291,57 @@ ImportNode XMLParser::ReadXMLNode()
xmlFree(attribute); xmlFree(attribute);
} }
if (xmlTextReaderIsEmptyElement(inputReader) != 1) if (xmlTextReaderIsEmptyElement(inputReader) == 1)
{ {
const int depth = xmlTextReaderDepth(inputReader); return node;
while (xmlTextReaderRead(inputReader) == 1) }
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); continue;
// 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);
} }
const int childDepth = xmlTextReaderDepth(inputReader);
xmlChar *childName = xmlTextReaderName(inputReader);
if (childName == NULL)
{
continue;
}
if (depth == childDepth && child_type == 15 &&
xmlStrEqual(childName, (const xmlChar *)"node") == 1)
{
xmlFree(childName);
break;
}
if (child_type != 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);
} }
return node; return node;
} }
+18 -8
View File
@@ -28,9 +28,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef FIXED_POINT_COORDINATE_H_ #ifndef FIXED_POINT_COORDINATE_H_
#define FIXED_POINT_COORDINATE_H_ #define FIXED_POINT_COORDINATE_H_
#include <functional>
#include <iosfwd> //for std::ostream #include <iosfwd> //for std::ostream
constexpr double COORDINATE_PRECISION = 1000000.; constexpr float COORDINATE_PRECISION = 1000000.;
struct FixedPointCoordinate struct FixedPointCoordinate
{ {
@@ -50,11 +51,13 @@ struct FixedPointCoordinate
static double ApproximateDistance(const FixedPointCoordinate &c1, static double ApproximateDistance(const FixedPointCoordinate &c1,
const FixedPointCoordinate &c2); const FixedPointCoordinate &c2);
static double ApproximateEuclideanDistance(const FixedPointCoordinate &c1, static float ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
const FixedPointCoordinate &c2); const FixedPointCoordinate &c2);
static double static float ApproximateEuclideanDistance(const int lat1, const int lon1, const int lat2, const int lon2);
ApproximateEuclideanDistance(const int lat1, const int lon1, const int lat2, const int lon2);
static float ApproximateSquaredEuclideanDistance(const FixedPointCoordinate &c1,
const FixedPointCoordinate &c2);
static void convertInternalLatLonToString(const int value, std::string &output); static void convertInternalLatLonToString(const int value, std::string &output);
@@ -64,17 +67,24 @@ struct FixedPointCoordinate
static void convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord, static void convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord,
std::string &output); std::string &output);
static double ComputePerpendicularDistance(const FixedPointCoordinate &point, static float ComputePerpendicularDistance(const FixedPointCoordinate &point,
const FixedPointCoordinate &segA, const FixedPointCoordinate &segA,
const FixedPointCoordinate &segB); const FixedPointCoordinate &segB);
static double ComputePerpendicularDistance(const FixedPointCoordinate &coord_a, static float ComputePerpendicularDistance(const FixedPointCoordinate &coord_a,
const FixedPointCoordinate &coord_b, const FixedPointCoordinate &coord_b,
const FixedPointCoordinate &query_location, const FixedPointCoordinate &query_location,
FixedPointCoordinate &nearest_location, FixedPointCoordinate &nearest_location,
double &r); float &r);
static float GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B);
float GetBearing(const FixedPointCoordinate &other) const;
void Output(std::ostream &out) 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 &o, FixedPointCoordinate const &c)
+1 -1
View File
@@ -58,7 +58,7 @@ class Reply
std::vector<Header> headers; 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<boost::asio::const_buffer> HeaderstoBuffers();
std::vector<std::string> content; std::vector<char> content;
static Reply StockReply(status_type status); static Reply StockReply(status_type status);
void setSize(const unsigned size); void setSize(const unsigned size);
void SetUncompressedSize(); void SetUncompressedSize();
+2
View File
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "OSRM_impl.h" #include "OSRM_impl.h"
#include "OSRM.h" #include "OSRM.h"
#include "../Plugins/DistanceTablePlugin.h"
#include "../Plugins/HelloWorldPlugin.h" #include "../Plugins/HelloWorldPlugin.h"
#include "../Plugins/LocatePlugin.h" #include "../Plugins/LocatePlugin.h"
#include "../Plugins/NearestPlugin.h" #include "../Plugins/NearestPlugin.h"
@@ -55,6 +56,7 @@ OSRM_impl::OSRM_impl(const ServerPaths &server_paths, const bool use_shared_memo
} }
// The following plugins handle all requests. // The following plugins handle all requests.
RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new HelloWorldPlugin()); RegisterPlugin(new HelloWorldPlugin());
RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade)); RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade)); RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
+141
View File
@@ -0,0 +1,141 @@
/*
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(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);
unsigned max_locations = std::min((std::size_t)100, raw_route.raw_via_node_coordinates.size());
for (unsigned i = 0; i < max_locations; ++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);
BOOST_ASSERT(phantom_node_vector[i].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 = 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
+41 -52
View File
@@ -25,10 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef HELLOWORLDPLUGIN_H_ #ifndef HELLO_WORLD_PLUGIN_H
#define HELLOWORLDPLUGIN_H_ #define HELLO_WORLD_PLUGIN_H
#include "BasePlugin.h" #include "BasePlugin.h"
#include "../DataStructures/JSONContainer.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include <string> #include <string>
@@ -46,70 +47,58 @@ class HelloWorldPlugin : public BasePlugin
void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
{ {
reply.status = http::Reply::ok; 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 = IntToString(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 = IntToString(routeParameters.coordinates.size());
json_result.values["location_count"] = temp_string;
JSON::Array json_locations;
unsigned counter = 0; unsigned counter = 0;
for (const FixedPointCoordinate &coordinate : routeParameters.coordinates) for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
{ {
reply.content.emplace_back(" ["); JSON::Object json_location;
intToString(counter, temp_string); JSON::Array json_coordinates;
reply.content.emplace_back(temp_string);
reply.content.emplace_back("] "); json_coordinates.values.push_back(coordinate.lat / COORDINATE_PRECISION);
doubleToString(coordinate.lat / COORDINATE_PRECISION, temp_string); json_coordinates.values.push_back(coordinate.lon / COORDINATE_PRECISION);
reply.content.emplace_back(temp_string); json_location.values[IntToString(counter)] = json_coordinates;
reply.content.emplace_back(","); json_locations.values.push_back(json_location);
doubleToString(coordinate.lon / COORDINATE_PRECISION, temp_string);
reply.content.emplace_back(temp_string);
reply.content.emplace_back("\n");
++counter; ++counter;
} }
json_result.values["locations"] = json_locations;
json_result.values["hint_count"] = routeParameters.hints.size();
reply.content.emplace_back("Number of hints: "); JSON::Array json_hints;
intToString(routeParameters.hints.size(), temp_string);
reply.content.emplace_back(temp_string);
reply.content.emplace_back("\n");
counter = 0; counter = 0;
for (const std::string &current_string : routeParameters.hints) for (const std::string &current_hint : routeParameters.hints)
{ {
reply.content.emplace_back(" ["); // JSON::String json_hint_string = current_hint;
intToString(counter, temp_string); json_hints.values.push_back(current_hint);
reply.content.emplace_back(temp_string);
reply.content.emplace_back("] ");
reply.content.emplace_back(current_string);
reply.content.emplace_back("\n");
++counter; ++counter;
} }
reply.content.emplace_back("</pre></body></html>"); json_result.values["hints"] = json_hints;
JSON::render(reply.content, json_result);
} }
private: private:
std::string descriptor_string; std::string descriptor_string;
}; };
#endif /* HELLOWORLDPLUGIN_H_ */ #endif // HELLO_WORLD_PLUGIN_H
+14 -51
View File
@@ -29,10 +29,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define LOCATE_PLUGIN_H #define LOCATE_PLUGIN_H
#include "BasePlugin.h" #include "BasePlugin.h"
#include "../DataStructures/JSONContainer.h"
#include "../Util/StringUtil.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 template <class DataFacadeT> class LocatePlugin : public BasePlugin
{ {
public: public:
@@ -42,70 +44,31 @@ template <class DataFacadeT> class LocatePlugin : public BasePlugin
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
{ {
// check number of parameters // 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); reply = http::Reply::StockReply(http::Reply::badRequest);
return; return;
} }
// query to helpdesk JSON::Object json_result;
FixedPointCoordinate 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(), if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(),
result)) result))
{ {
reply.content.emplace_back("\"status\":207,"); json_result.values["status"] = 207;
reply.content.emplace_back("\"mapped_coordinate\":[]");
} }
else else
{ {
// Write coordinate to stream
reply.status = http::Reply::ok; reply.status = http::Reply::ok;
reply.content.emplace_back("\"status\":0,"); json_result.values["status"] = 0;
reply.content.emplace_back("\"mapped_coordinate\":"); JSON::Array json_coordinate;
FixedPointCoordinate::convertInternalLatLonToString(result.lat, tmp); json_coordinate.values.push_back(result.lat/COORDINATE_PRECISION);
reply.content.emplace_back("["); json_coordinate.values.push_back(result.lon/COORDINATE_PRECISION);
reply.content.emplace_back(tmp); json_result.values["mapped_coordinate"] = json_coordinate;
FixedPointCoordinate::convertInternalLatLonToString(result.lon, tmp);
reply.content.emplace_back(",");
reply.content.emplace_back(tmp);
reply.content.emplace_back("]");
} }
reply.content.emplace_back("}");
reply.headers.resize(3); JSON::render(reply.content, json_result);
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;
} }
private: private:
+19 -66
View File
@@ -29,10 +29,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define NEAREST_PLUGIN_H #define NEAREST_PLUGIN_H
#include "BasePlugin.h" #include "BasePlugin.h"
#include "../DataStructures/JSONContainer.h"
#include "../DataStructures/PhantomNodes.h" #include "../DataStructures/PhantomNodes.h"
#include "../Util/StringUtil.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. * This Plugin locates the nearest point on a street in the road network for a given coordinate.
@@ -43,8 +44,6 @@ template <class DataFacadeT> class NearestPlugin : public BasePlugin
public: public:
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest")
{ {
descriptor_table.emplace("", 0); // default descriptor
descriptor_table.emplace("json", 1);
} }
const std::string GetDescriptor() const { return descriptor_string; } const std::string GetDescriptor() const { return descriptor_string; }
@@ -52,86 +51,40 @@ template <class DataFacadeT> class NearestPlugin : public BasePlugin
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
{ {
// check number of parameters // check number of parameters
if (route_parameters.coordinates.empty()) if (route_parameters.coordinates.empty() ||
{ !route_parameters.coordinates.front().isValid())
reply = http::Reply::StockReply(http::Reply::badRequest);
return;
}
if (!route_parameters.coordinates.front().isValid())
{ {
reply = http::Reply::StockReply(http::Reply::badRequest); reply = http::Reply::StockReply(http::Reply::badRequest);
return; return;
} }
PhantomNode result; PhantomNode phantom_node;
facade->FindPhantomNodeForCoordinate( facade->FindPhantomNodeForCoordinate(
route_parameters.coordinates.front(), result, route_parameters.zoom_level); route_parameters.coordinates.front(), phantom_node, route_parameters.zoom_level);
// json JSON::Object json_result;
if (!phantom_node.isValid())
if (!route_parameters.jsonp_parameter.empty())
{ {
reply.content.emplace_back(route_parameters.jsonp_parameter); json_result.values["status"] = 207;
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,");
} }
else 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.location.lat/COORDINATE_PRECISION);
json_coordinate.values.push_back(phantom_node.location.lon/COORDINATE_PRECISION);
json_result.values["mapped_coordinate"] = json_coordinate;
std::string temp_string;
facade->GetName(phantom_node.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) JSON::render(reply.content, json_result);
{
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;
} }
private: private:
DataFacadeT *facade; DataFacadeT *facade;
std::unordered_map<std::string, unsigned> descriptor_table;
std::string descriptor_string; std::string descriptor_string;
}; };
+8 -39
View File
@@ -28,8 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TIMESTAMP_PLUGIN_H #ifndef TIMESTAMP_PLUGIN_H
#define TIMESTAMP_PLUGIN_H #define TIMESTAMP_PLUGIN_H
#include "../DataStructures/JSONContainer.h"
#include "BasePlugin.h" #include "BasePlugin.h"
#include <string>
template <class DataFacadeT> class TimestampPlugin : public BasePlugin template <class DataFacadeT> class TimestampPlugin : public BasePlugin
{ {
public: public:
@@ -40,46 +43,12 @@ template <class DataFacadeT> class TimestampPlugin : public BasePlugin
const std::string GetDescriptor() const { return descriptor_string; } const std::string GetDescriptor() const { return descriptor_string; }
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) 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.status = http::Reply::ok;
reply.content.emplace_back("{"); JSON::Object json_result;
reply.content.emplace_back("\"status\":"); json_result.values["status"] = 0;
reply.content.emplace_back("0,"); const std::string timestamp = facade->GetTimestamp();
reply.content.emplace_back("\"timestamp\":\""); json_result.values["timestamp"] = timestamp;
reply.content.emplace_back(facade->GetTimestamp()); JSON::render(reply.content, json_result);
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;
} }
private: private:
+182 -241
View File
@@ -1,241 +1,182 @@
/* /*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution. other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 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 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef VIAROUTEPLUGIN_H_ #ifndef VIA_ROUTE_PLUGIN_H
#define VIAROUTEPLUGIN_H_ #define VIA_ROUTE_PLUGIN_H
#include "BasePlugin.h" #include "BasePlugin.h"
#include "../Algorithms/ObjectToBase64.h" #include "../Algorithms/ObjectToBase64.h"
#include "../DataStructures/QueryEdge.h"
#include "../DataStructures/SearchEngine.h" #include "../DataStructures/QueryEdge.h"
#include "../Descriptors/BaseDescriptor.h" #include "../DataStructures/SearchEngine.h"
#include "../Descriptors/GPXDescriptor.h" #include "../Descriptors/BaseDescriptor.h"
#include "../Descriptors/JSONDescriptor.h" #include "../Descriptors/GPXDescriptor.h"
#include "../Util/SimpleLogger.h" #include "../Descriptors/JSONDescriptor.h"
#include "../Util/StringUtil.h" #include "../Util/SimpleLogger.h"
#include "../Util/StringUtil.h"
#include <cstdlib> #include "../Util/TimingUtil.h"
#include <algorithm> #include <cstdlib>
#include <memory>
#include <unordered_map> #include <algorithm>
#include <string> #include <memory>
#include <vector> #include <unordered_map>
#include <string>
template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin #include <vector>
{
private: template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
std::unordered_map<std::string, unsigned> descriptorTable; {
std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr; private:
std::unordered_map<std::string, unsigned> descriptor_table;
public: std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
{ public:
search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade); explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
{
descriptorTable.emplace("json", 0); search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
descriptorTable.emplace("gpx", 1);
} descriptor_table.emplace("json", 0);
descriptor_table.emplace("gpx", 1);
virtual ~ViaRoutePlugin() {} // descriptor_table.emplace("geojson", 2);
}
const std::string GetDescriptor() const { return descriptor_string; }
virtual ~ViaRoutePlugin() {}
void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
{ const std::string GetDescriptor() const { return descriptor_string; }
// check number of parameters
if (2 > routeParameters.coordinates.size()) void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
{ {
reply = http::Reply::StockReply(http::Reply::badRequest); // check number of parameters
return; if (2 > route_parameters.coordinates.size() ||
} std::any_of(begin(route_parameters.coordinates),
end(route_parameters.coordinates),
RawRouteData raw_route; [&](FixedPointCoordinate coordinate)
raw_route.check_sum = facade->GetCheckSum(); { return !coordinate.isValid(); }))
{
if (std::any_of(begin(routeParameters.coordinates), reply = http::Reply::StockReply(http::Reply::badRequest);
end(routeParameters.coordinates), return;
[&](FixedPointCoordinate coordinate) }
{ return !coordinate.isValid(); }))
{ RawRouteData raw_route;
reply = http::Reply::StockReply(http::Reply::badRequest); raw_route.check_sum = facade->GetCheckSum();
return; for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
} {
raw_route.raw_via_node_coordinates.emplace_back(coordinate);
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 = (route_parameters.check_sum == raw_route.check_sum);
std::vector<PhantomNode> phantom_node_vector(raw_route.raw_via_node_coordinates.size()); for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i)
const bool checksum_OK = (routeParameters.check_sum == raw_route.check_sum); {
if (checksum_OK && i < route_parameters.hints.size() &&
for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i) !route_parameters.hints[i].empty())
{ {
if (checksum_OK && i < routeParameters.hints.size() && DecodeObjectFromBase64(route_parameters.hints[i], phantom_node_vector[i]);
!routeParameters.hints[i].empty()) if (phantom_node_vector[i].isValid(facade->GetNumberOfNodes()))
{ {
DecodeObjectFromBase64(routeParameters.hints[i], phantom_node_vector[i]); continue;
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);
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)
{
PhantomNodes current_phantom_node_pair; current_phantom_node_pair.source_phantom = phantom_node_vector[i];
for (unsigned i = 0; i < phantom_node_vector.size() - 1; ++i) current_phantom_node_pair.target_phantom = phantom_node_vector[i + 1];
{ raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
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());
TIMER_START(routing);
if ((routeParameters.alternate_route) && (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(), search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
raw_route); raw_route);
} }
else else
{ {
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, raw_route); search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, raw_route);
} }
TIMER_STOP(routing);
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length) SimpleLogger().Write() << "routing took " << TIMER_MSEC(routing) << "ms";
{
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found"; if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
} {
reply.status = http::Reply::ok; SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
}
if (!routeParameters.jsonp_parameter.empty()) reply.status = http::Reply::ok;
{
reply.content.emplace_back(routeParameters.jsonp_parameter); DescriptorConfig descriptor_config;
reply.content.emplace_back("(");
} auto iter = descriptor_table.find(route_parameters.output_format);
unsigned descriptor_type = (iter != descriptor_table.end() ? iter->second : 0);
DescriptorConfig descriptor_config;
descriptor_config.zoom_level = route_parameters.zoom_level;
auto iter = descriptorTable.find(routeParameters.output_format); descriptor_config.instructions = route_parameters.print_instructions;
unsigned descriptor_type = (iter != descriptorTable.end() ? iter->second : 0); descriptor_config.geometry = route_parameters.geometry;
descriptor_config.encode_geometry = route_parameters.compression;
descriptor_config.zoom_level = routeParameters.zoom_level;
descriptor_config.instructions = routeParameters.print_instructions; std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
descriptor_config.geometry = routeParameters.geometry; switch (descriptor_type)
descriptor_config.encode_geometry = routeParameters.compression; {
// case 0:
std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor; // descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
switch (descriptor_type) // break;
{ case 1:
// case 0: descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(facade);
// descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(); break;
// break; // case 2:
case 1: // descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(); // break;
break; default:
default: descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(facade);
descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(); break;
break; }
}
PhantomNodes phantom_nodes;
PhantomNodes phantom_nodes; phantom_nodes.source_phantom = raw_route.segment_end_coordinates.front().source_phantom;
phantom_nodes.source_phantom = raw_route.segment_end_coordinates.front().source_phantom; phantom_nodes.target_phantom = raw_route.segment_end_coordinates.back().target_phantom;
phantom_nodes.target_phantom = raw_route.segment_end_coordinates.back().target_phantom; descriptor->SetConfig(descriptor_config);
descriptor->SetConfig(descriptor_config); TIMER_START(descriptor);
descriptor->Run(raw_route, phantom_nodes, facade, reply); descriptor->Run(raw_route, phantom_nodes, reply);
TIMER_STOP(descriptor);
if (!routeParameters.jsonp_parameter.empty()) SimpleLogger().Write() << "descriptor took " << TIMER_MSEC(descriptor) << "ms";
{ }
reply.content.emplace_back(")\n");
} private:
reply.headers.resize(3); std::string descriptor_string;
reply.headers[0].name = "Content-Length"; DataFacadeT *facade;
};
unsigned content_length = 0;
for (const std::string &snippet : reply.content) #endif // VIA_ROUTE_PLUGIN_H
{
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_ */
+2 -1
View File
@@ -78,6 +78,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
{ {
if (phantom_node_pair.PhantomNodesHaveEqualLocation()) if (phantom_node_pair.PhantomNodesHaveEqualLocation())
{ {
BOOST_ASSERT(false);
return; return;
} }
@@ -604,7 +605,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 EdgeData &data = facade->GetEdgeData(edge);
const bool edge_is_forward_directed = const bool edge_is_forward_directed =
+6 -16
View File
@@ -87,7 +87,7 @@ template <class DataFacadeT> class BasicRoutingInterface
} }
// Stalling // 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 EdgeData &data = facade->GetEdgeData(edge);
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward); 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); for (auto edge : facade->GetAdjacentEdgeRange(node))
edge < end_edge;
++edge)
{ {
const EdgeData &data = facade->GetEdgeData(edge); const EdgeData &data = facade->GetEdgeData(edge);
bool forward_directionFlag = (forward_direction ? data.forward : data.backward); bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
@@ -167,9 +165,7 @@ template <class DataFacadeT> class BasicRoutingInterface
// The above explanation unclear? Think! // The above explanation unclear? Think!
EdgeID smaller_edge_id = SPECIAL_EDGEID; EdgeID smaller_edge_id = SPECIAL_EDGEID;
int edge_weight = INT_MAX; int edge_weight = INT_MAX;
for (EdgeID edge_id = facade->BeginEdges(edge.first); for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
edge_id < facade->EndEdges(edge.first);
++edge_id)
{ {
const int weight = facade->GetEdgeData(edge_id).distance; const int weight = facade->GetEdgeData(edge_id).distance;
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) && if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
@@ -181,9 +177,7 @@ template <class DataFacadeT> class BasicRoutingInterface
} }
if (SPECIAL_EDGEID == smaller_edge_id) if (SPECIAL_EDGEID == smaller_edge_id)
{ {
for (EdgeID edge_id = facade->BeginEdges(edge.second); for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
edge_id < facade->EndEdges(edge.second);
++edge_id)
{ {
const int weight = facade->GetEdgeData(edge_id).distance; const int weight = facade->GetEdgeData(edge_id).distance;
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) && if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
@@ -323,9 +317,7 @@ template <class DataFacadeT> class BasicRoutingInterface
EdgeID smaller_edge_id = SPECIAL_EDGEID; EdgeID smaller_edge_id = SPECIAL_EDGEID;
int edge_weight = INT_MAX; int edge_weight = INT_MAX;
for (EdgeID edge_id = facade->BeginEdges(edge.first); for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
edge_id < facade->EndEdges(edge.first);
++edge_id)
{ {
const int weight = facade->GetEdgeData(edge_id).distance; const int weight = facade->GetEdgeData(edge_id).distance;
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) && if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
@@ -338,9 +330,7 @@ template <class DataFacadeT> class BasicRoutingInterface
if (SPECIAL_EDGEID == smaller_edge_id) if (SPECIAL_EDGEID == smaller_edge_id)
{ {
for (EdgeID edge_id = facade->BeginEdges(edge.second); for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
edge_id < facade->EndEdges(edge.second);
++edge_id)
{ {
const int weight = facade->GetEdgeData(edge_id).distance; const int weight = facade->GetEdgeData(edge_id).distance;
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) && if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
+246
View File
@@ -0,0 +1,246 @@
/*
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 std::vector<PhantomNode> &phantom_nodes_vector) const
{
const unsigned number_of_locations = phantom_nodes_vector.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 PhantomNode &phantom_node : phantom_nodes_vector)
{
query_heap.Clear();
// insert target(s) 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())
{
BackwardRoutingStep(target_id, query_heap, search_space_with_buckets);
}
++target_id;
}
// for each source do forward search
unsigned source_id = 0;
for (const PhantomNode &phantom_node : phantom_nodes_vector)
{
query_heap.Clear();
// 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 &current_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
if ((source_distance + target_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
+7 -5
View File
@@ -51,13 +51,15 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector, void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
RawRouteData &raw_route_data) const RawRouteData &raw_route_data) const
{ {
for (const PhantomNodes &phantom_node_pair : phantom_nodes_vector) if(std::any_of(begin(phantom_nodes_vector),
end(phantom_nodes_vector),
[](PhantomNodes phantom_node_pair)
{ return phantom_node_pair.AtLeastOnePhantomNodeIsInvalid(); }))
{ {
if (phantom_node_pair.AtLeastOnePhantomNodeIsInvalid()) BOOST_ASSERT(false);
{ return;
return;
}
} }
int distance1 = 0; int distance1 = 0;
int distance2 = 0; int distance2 = 0;
bool search_from_1st_node = true; bool search_from_1st_node = true;
+1 -1
View File
@@ -45,7 +45,7 @@ struct APIGrammar : qi::grammar<Iterator>
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)]; 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)]; 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)]; 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)]; 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)]; 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)]; cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
+7 -12
View File
@@ -81,6 +81,7 @@ void Connection::handle_read(const boost::system::error_code &e, std::size_t byt
Header compression_header; Header compression_header;
std::vector<char> compressed_output; std::vector<char> compressed_output;
std::vector<boost::asio::const_buffer> output_buffer; std::vector<boost::asio::const_buffer> output_buffer;
switch (compression_type) switch (compression_type)
{ {
case deflateRFC1951: case deflateRFC1951:
@@ -158,7 +159,7 @@ void Connection::handle_write(const boost::system::error_code &e)
} }
} }
void Connection::compressBufferCollection(std::vector<std::string> uncompressed_data, void Connection::compressBufferCollection(std::vector<char> uncompressed_data,
CompressionType compression_type, CompressionType compression_type,
std::vector<char> &compressed_data) std::vector<char> &compressed_data)
{ {
@@ -171,16 +172,10 @@ void Connection::compressBufferCollection(std::vector<std::string> uncompressed_
} }
BOOST_ASSERT(compressed_data.empty()); BOOST_ASSERT(compressed_data.empty());
boost::iostreams::filtering_ostream compressing_stream; boost::iostreams::filtering_ostream gzip_stream;
gzip_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
compressing_stream.push(boost::iostreams::gzip_compressor(compression_parameters)); gzip_stream.push(boost::iostreams::back_inserter(compressed_data));
compressing_stream.push(boost::iostreams::back_inserter(compressed_data)); gzip_stream.write(&uncompressed_data[0], uncompressed_data.size());
boost::iostreams::close(gzip_stream);
for (const std::string &line : uncompressed_data)
{
compressing_stream << line;
}
compressing_stream.reset();
} }
} }
+1 -1
View File
@@ -89,7 +89,7 @@ class Connection : public std::enable_shared_from_this<Connection>
/// Handle completion of a write operation. /// Handle completion of a write operation.
void handle_write(const boost::system::error_code &e); 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, CompressionType compression_type,
std::vector<char> &compressed_data); std::vector<char> &compressed_data);
+6
View File
@@ -38,10 +38,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../../Util/StringUtil.h" #include "../../Util/StringUtil.h"
#include "../../typedefs.h" #include "../../typedefs.h"
#include <boost/range/irange.hpp>
#include <osrm/Coordinate.h> #include <osrm/Coordinate.h>
#include <string> #include <string>
typedef decltype(boost::irange(0u,0u)) EdgeRange;
template <class EdgeDataT> class BaseDataFacade template <class EdgeDataT> class BaseDataFacade
{ {
public: public:
@@ -67,6 +71,8 @@ template <class EdgeDataT> class BaseDataFacade
virtual EdgeID EndEdges(const NodeID n) const = 0; virtual EdgeID EndEdges(const NodeID n) const = 0;
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
// searches for a specific edge // searches for a specific edge
virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0; virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
+13 -4
View File
@@ -79,13 +79,13 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
if (boost::filesystem::exists(timestamp_path)) if (boost::filesystem::exists(timestamp_path))
{ {
SimpleLogger().Write() << "Loading Timestamp"; SimpleLogger().Write() << "Loading Timestamp";
boost::filesystem::ifstream timestampInStream(timestamp_path); boost::filesystem::ifstream timestamp_stream(timestamp_path);
if (!timestampInStream) if (!timestamp_stream)
{ {
SimpleLogger().Write(logWARNING) << timestamp_path << " not found"; SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
} }
getline(timestampInStream, m_timestamp); getline(timestamp_stream, m_timestamp);
timestampInStream.close(); timestamp_stream.close();
} }
if (m_timestamp.empty()) if (m_timestamp.empty())
{ {
@@ -279,16 +279,23 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
// load data // load data
SimpleLogger().Write() << "loading graph data"; SimpleLogger().Write() << "loading graph data";
AssertPathExists(hsgr_path);
LoadGraph(hsgr_path); LoadGraph(hsgr_path);
SimpleLogger().Write() << "loading egde information"; SimpleLogger().Write() << "loading egde information";
AssertPathExists(nodes_data_path);
AssertPathExists(edges_data_path);
LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path); LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
SimpleLogger().Write() << "loading geometries"; SimpleLogger().Write() << "loading geometries";
AssertPathExists(geometries_path);
LoadGeometries(geometries_path); LoadGeometries(geometries_path);
SimpleLogger().Write() << "loading r-tree"; SimpleLogger().Write() << "loading r-tree";
AssertPathExists(ram_index_path);
AssertPathExists(file_index_path);
LoadRTree(ram_index_path, file_index_path); LoadRTree(ram_index_path, file_index_path);
SimpleLogger().Write() << "loading timestamp"; SimpleLogger().Write() << "loading timestamp";
LoadTimestamp(timestamp_path); LoadTimestamp(timestamp_path);
SimpleLogger().Write() << "loading street names"; SimpleLogger().Write() << "loading street names";
AssertPathExists(names_data_path);
LoadStreetNames(names_data_path); LoadStreetNames(names_data_path);
} }
@@ -309,6 +316,8 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); } 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 // searches for a specific edge
EdgeID FindEdge(const NodeID from, const NodeID to) const EdgeID FindEdge(const NodeID from, const NodeID to) const
{ {
+2
View File
@@ -254,6 +254,8 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); } 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 // searches for a specific edge
EdgeID FindEdge(const NodeID from, const NodeID to) const EdgeID FindEdge(const NodeID from, const NodeID to) const
{ {
+7 -12
View File
@@ -38,7 +38,7 @@ void Reply::setSize(const unsigned size)
{ {
if ("Content-Length" == h.name) if ("Content-Length" == h.name)
{ {
intToString(size, h.value); h.value = IntToString(size);
} }
} }
} }
@@ -47,10 +47,7 @@ void Reply::setSize(const unsigned size)
void Reply::SetUncompressedSize() void Reply::SetUncompressedSize()
{ {
unsigned uncompressed_size = 0; unsigned uncompressed_size = 0;
for (const std::string &current_line : content) uncompressed_size = content.size();
{
uncompressed_size += current_line.size();
}
setSize(uncompressed_size); setSize(uncompressed_size);
} }
@@ -66,10 +63,7 @@ std::vector<boost::asio::const_buffer> Reply::toBuffers()
buffers.push_back(boost::asio::buffer(crlf)); buffers.push_back(boost::asio::buffer(crlf));
} }
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(content));
{
buffers.push_back(boost::asio::buffer(line));
}
return buffers; return buffers;
} }
@@ -94,14 +88,15 @@ Reply Reply::StockReply(Reply::status_type status)
Reply rep; Reply rep;
rep.status = status; rep.status = status;
rep.content.clear(); rep.content.clear();
rep.content.push_back(rep.ToString(status));
const std::string status_string = rep.ToString(status);
rep.content.insert(rep.content.end(), status_string.begin(), status_string.end());
rep.headers.resize(3); rep.headers.resize(3);
rep.headers[0].name = "Access-Control-Allow-Origin"; rep.headers[0].name = "Access-Control-Allow-Origin";
rep.headers[0].value = "*"; rep.headers[0].value = "*";
rep.headers[1].name = "Content-Length"; rep.headers[1].name = "Content-Length";
std::string size_string; std::string size_string = IntToString(rep.content.size());
intToString(rep.content.size(), size_string);
rep.headers[1].value = size_string; rep.headers[1].value = size_string;
rep.headers[2].name = "Content-Type"; rep.headers[2].name = "Content-Type";
+40 -6
View File
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "RequestHandler.h" #include "RequestHandler.h"
#include "Http/Request.h" #include "Http/Request.h"
#include "../DataStructures/JSONContainer.h"
#include "../Library/OSRM.h" #include "../Library/OSRM.h"
#include "../Util/SimpleLogger.h" #include "../Util/SimpleLogger.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
@@ -85,18 +86,51 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
reply = http::Reply::StockReply(http::Reply::badRequest); reply = http::Reply::StockReply(http::Reply::badRequest);
reply.content.clear(); reply.content.clear();
const int position = std::distance(request.begin(), it); const int position = std::distance(request.begin(), it);
reply.content.push_back( JSON::Object json_result;
"{\"status\":400,\"status_message\":\"Query string malformed close to position "); json_result.values["status"] = 400;
std::string tmp_position_string; std::string tmp_position_string = IntToString(position);
intToString(position, tmp_position_string); std::string message = ("Query string malformed close to position " + IntToString(position));
reply.content.push_back(tmp_position_string); json_result.values["status_message"] = message;
reply.content.push_back("\"}"); JSON::render(reply.content, json_result);
} }
else else
{ {
// parsing done, lets call the right plugin to handle the request // parsing done, lets call the right plugin to handle the request
BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed"); BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
if (!route_parameters.jsonp_parameter.empty())
{
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); routing_machine->RunQuery(route_parameters, reply);
// set headers, still ugly and should be reworked
reply.headers.resize(3);
if ("gpx" == route_parameters.output_format)
{
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\"";
}
else if (!route_parameters.jsonp_parameter.empty())
{
reply.content.push_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=\"response.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=\"response.json\"";
}
reply.headers[0].name = "Content-Length";
reply.headers[0].value = IntToString(reply.content.size());
return; return;
} }
} }
+3 -3
View File
@@ -262,10 +262,10 @@ RequestParser::consume(Request &req, char input, http::CompressionType *compress
return boost::indeterminate; return boost::indeterminate;
} }
return false; return false;
case expecting_newline_3: default: // expecting_newline_3:
return (input == '\n'); return (input == '\n');
default: // default:
return false; // return false;
} }
} }
+6 -3
View File
@@ -33,10 +33,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <thread>
#include <vector> #include <vector>
class Server class Server
@@ -59,19 +59,22 @@ class Server
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error)); boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
} }
Server() = delete;
Server(const Server &) = delete; Server(const Server &) = delete;
void Run() 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) 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)); boost::bind(&boost::asio::io_service::run, &io_service));
threads.push_back(thread); threads.push_back(thread);
} }
for (unsigned i = 0; i < threads.size(); ++i) for (unsigned i = 0; i < threads.size(); ++i)
{
threads[i]->join(); threads[i]->join();
}
} }
void Stop() { io_service.stop(); } void Stop() { io_service.stop(); }
+1 -5
View File
@@ -41,12 +41,8 @@ struct ServerFactory
ServerFactory(const 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, int threads)
{ {
SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion(); SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
std::string port_stream = IntToString(ip_port);
std::string port_stream;
intToString(ip_port, port_stream);
return new Server(ip_address, port_stream, std::min(omp_get_num_procs(), threads)); return new Server(ip_address, port_stream, std::min(omp_get_num_procs(), threads));
} }
}; };
+3 -3
View File
@@ -110,10 +110,10 @@ int main(int argc, const char *argv[])
// attention: super-inefficient hack below: // attention: super-inefficient hack below:
std::stringstream my_stream; std::stringstream my_stream;
for (const std::string &line : osrm_reply.content) for (const auto &element : osrm_reply.content)
{ {
std::cout << line; std::cout << element;
my_stream << line; my_stream << element;
} }
std::cout << std::endl; std::cout << std::endl;
+9
View File
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define BOOST_FILE_SYSTEM_FIX_H #define BOOST_FILE_SYSTEM_FIX_H
#include "OSRMException.h" #include "OSRMException.h"
#include "SimpleLogger.h"
#include <boost/any.hpp> #include <boost/any.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
@@ -135,4 +136,12 @@ inline path unique_path(const path &) { return temp_directory_path(); }
#define BOOST_FILESYSTEM_VERSION 3 #define BOOST_FILESYSTEM_VERSION 3
#endif #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 */ #endif /* BOOST_FILE_SYSTEM_FIX_H */
+4 -1
View File
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef COMPUTE_ANGLE_H #ifndef COMPUTE_ANGLE_H
#define COMPUTE_ANGLE_H #define COMPUTE_ANGLE_H
#include "TrigonometryTables.h"
#include "../Util/MercatorUtil.h" #include "../Util/MercatorUtil.h"
#include <osrm/Coordinate.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 v2x = (B.lon - C.lon) / COORDINATE_PRECISION;
const double v2y = lat2y(B.lat / COORDINATE_PRECISION) - lat2y(C.lat / 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) while (angle < 0)
{
angle += 360; angle += 360;
}
return angle; return angle;
} }
+65 -121
View File
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BoostFileSystemFix.h" #include "BoostFileSystemFix.h"
#include "GitDescription.h" #include "GitDescription.h"
#include "IniFileUtil.h"
#include "OSRMException.h" #include "OSRMException.h"
#include "SimpleLogger.h" #include "SimpleLogger.h"
@@ -37,108 +38,54 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/any.hpp> #include <boost/any.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <boost/regex.hpp>
#include <string> #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 // 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)
{ {
// declare a group of options that will be allowed only on command line // declare a group of options that will be allowed only on command line
boost::program_options::options_description generic_options("Options"); boost::program_options::options_description generic_options("Options");
generic_options.add_options() generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
("version,v", "Show version") "config,c",
("help,h", "Show this help message") boost::program_options::value<boost::filesystem::path>(&paths["config"])
( ->default_value("server.ini"),
"config,c", "Path to a configuration file");
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 // declare a group of options that will be allowed both on command line
// as well as in a config file // as well as in a config file
boost::program_options::options_description config_options("Configuration"); boost::program_options::options_description config_options("Configuration");
config_options.add_options() config_options.add_options()(
( "hsgrdata",
"hsgrdata", boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]), ".hsgr file")("nodesdata",
".hsgr file" boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
) ".nodes file")(
( "edgesdata",
"nodesdata", boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]), ".edges file")("geometry",
".nodes file" boost::program_options::value<boost::filesystem::path>(&paths["geometry"]),
) ".geometry file")(
( "ramindex",
"edgesdata", boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]), ".ramIndex file")(
".edges file" "fileindex",
) boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
( ".fileIndex file")(
"geometry", "namesdata",
boost::program_options::value<boost::filesystem::path>(&paths["geometry"]), boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
".geometry file" ".names file")("timestamp",
) boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
( ".timestamp 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 // hidden options, will be allowed both on command line and in config
// file, but will not be shown to the user // file, but will not be shown to the user
boost::program_options::options_description hidden_options("Hidden options"); boost::program_options::options_description hidden_options("Hidden options");
hidden_options.add_options() hidden_options.add_options()(
( "base,b",
"base,b", boost::program_options::value<boost::filesystem::path>(&paths["base"]),
boost::program_options::value<boost::filesystem::path>(&paths["base"]), "base path to .osrm file");
"base path to .osrm file"
);
// positional option // positional option
boost::program_options::positional_options_description positional_options; boost::program_options::positional_options_description positional_options;
@@ -152,25 +99,24 @@ inline bool GenerateDataStoreOptions(const int argc, const char * argv[], Server
config_file_options.add(config_options).add(hidden_options); config_file_options.add(config_options).add(hidden_options);
boost::program_options::options_description visible_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); visible_options.add(generic_options).add(config_options);
// parse command line options // parse command line options
boost::program_options::variables_map option_variables; boost::program_options::variables_map option_variables;
boost::program_options::store boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
( .options(cmdline_options)
boost::program_options::command_line_parser(argc, argv).options(cmdline_options).positional(positional_options).run(), .positional(positional_options)
option_variables .run(),
); option_variables);
if(option_variables.count("version")) if (option_variables.count("version"))
{ {
SimpleLogger().Write() << g_GIT_DESCRIPTION; SimpleLogger().Write() << g_GIT_DESCRIPTION;
return false; return false;
} }
if(option_variables.count("help")) if (option_variables.count("help"))
{ {
SimpleLogger().Write() << visible_options; SimpleLogger().Write() << visible_options;
return false; return false;
@@ -178,22 +124,26 @@ inline bool GenerateDataStoreOptions(const int argc, const char * argv[], Server
boost::program_options::notify(option_variables); boost::program_options::notify(option_variables);
const bool parameter_present = const bool parameter_present = (paths.find("hsgrdata") != paths.end() &&
(paths.find("hsgrdata") != paths.end() && !paths.find("hsgrdata" )->second.string().empty()) || !paths.find("hsgrdata")->second.string().empty()) ||
(paths.find("nodesdata") != paths.end() && !paths.find("nodesdata")->second.string().empty()) || (paths.find("nodesdata") != paths.end() &&
(paths.find("edgesdata") != paths.end() && !paths.find("edgesdata")->second.string().empty()) || !paths.find("nodesdata")->second.string().empty()) ||
(paths.find("geometry") != paths.end() && !paths.find("geometry" )->second.string().empty()) || (paths.find("edgesdata") != paths.end() &&
(paths.find("ramindex") != paths.end() && !paths.find("ramindex" )->second.string().empty()) || !paths.find("edgesdata")->second.string().empty()) ||
(paths.find("fileindex") != paths.end() && !paths.find("fileindex")->second.string().empty()) || (paths.find("geometry") != paths.end() &&
(paths.find("timestamp") != paths.end() && !paths.find("timestamp")->second.string().empty()); !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 (parameter_present)
{ {
if ( if ((paths.find("config") != paths.end() &&
( paths.find("config") != paths.end() && boost::filesystem::is_regular_file(paths.find("config")->second)) ||
boost::filesystem::is_regular_file(paths.find("config")->second) option_variables.count("base"))
) || option_variables.count("base")
)
{ {
SimpleLogger().Write(logWARNING) << "conflicting parameters"; SimpleLogger().Write(logWARNING) << "conflicting parameters";
SimpleLogger().Write() << visible_options; SimpleLogger().Write() << visible_options;
@@ -203,26 +153,20 @@ inline bool GenerateDataStoreOptions(const int argc, const char * argv[], Server
// parse config file // parse config file
ServerPaths::iterator path_iterator = paths.find("config"); ServerPaths::iterator path_iterator = paths.find("config");
if ( if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
path_iterator != paths.end() && !option_variables.count("base"))
boost::filesystem::is_regular_file(path_iterator->second) &&
!option_variables.count("base")
)
{ {
SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string(); SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
std::string config_str; std::string ini_file_contents = ReadIniFileAndLowerContents(path_iterator->second);
PrepareConfigFile( path_iterator->second, config_str ); std::stringstream config_stream(ini_file_contents);
std::stringstream config_stream( config_str ); boost::program_options::store(parse_config_file(config_stream, config_file_options),
boost::program_options::store( option_variables);
parse_config_file(config_stream, config_file_options),
option_variables
);
boost::program_options::notify(option_variables); boost::program_options::notify(option_variables);
} }
else if (option_variables.count("base")) else if (option_variables.count("base"))
{ {
path_iterator = paths.find("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(); std::string base_string = path_iterator->second.string();
path_iterator = paths.find("hsgrdata"); path_iterator = paths.find("hsgrdata");
+2 -2
View File
@@ -64,7 +64,7 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
if (!uuid_loaded.TestGraphUtil(uuid_orig)) if (!uuid_loaded.TestGraphUtil(uuid_orig))
{ {
SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build." SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
"Reprocess to get rid of this warning."; "Reprocess to get rid of this warning.";
} }
@@ -287,7 +287,7 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
hsgr_input_stream.read((char *)&uuid_loaded, sizeof(UUID)); hsgr_input_stream.read((char *)&uuid_loaded, sizeof(UUID));
if (!uuid_loaded.TestGraphUtil(uuid_orig)) if (!uuid_loaded.TestGraphUtil(uuid_orig))
{ {
SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build. " SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
"Reprocess to get rid of this warning."; "Reprocess to get rid of this warning.";
} }
+51
View File
@@ -0,0 +1,51 @@
/*
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 INI_FILE_UTIL_H
#define INI_FILE_UTIL_H
#include "SimpleLogger.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/regex.hpp>
#include <regex>
#include <string>
// support old capitalized option names by down-casing them with a regex replace
inline std::string ReadIniFileAndLowerContents(const boost::filesystem::path &path)
{
boost::filesystem::fstream config_stream(path);
std::string ini_file_content((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
return boost::regex_replace( ini_file_content, regex, format );
}
#endif // INI_FILE_UTIL_H
+1
View File
@@ -36,6 +36,7 @@ extern "C" {
#include <boost/filesystem/convenience.hpp> #include <boost/filesystem/convenience.hpp>
#include <luabind/luabind.hpp> #include <luabind/luabind.hpp>
#include <iostream> #include <iostream>
#include <string> #include <string>
+6 -8
View File
@@ -28,20 +28,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MERCATOR_UTIL_H #ifndef MERCATOR_UTIL_H
#define MERCATOR_UTIL_H #define MERCATOR_UTIL_H
#include "SimpleLogger.h"
#include <cmath> #include <cmath>
#ifndef M_PI inline float y2lat(const float a)
#define M_PI 3.14159265358979323846
#endif
inline double y2lat(const double a)
{ {
return 180. / M_PI * (2. * atan(exp(a * M_PI / 180.)) - M_PI / 2.); return 180.f / M_PI * (2.f * std::atan(std::exp(a * M_PI / 180.f)) - M_PI / 2.f);
} }
inline double lat2y(const double a) inline float lat2y(const float a)
{ {
return 180. / M_PI * log(tan(M_PI / 4. + a * (M_PI / 180.) / 2.)); return 180.f / M_PI * std::log(std::tan(M_PI / 4.f + a * (M_PI / 180.f) / 2.f));
} }
#endif // MERCATOR_UTIL_H #endif // MERCATOR_UTIL_H
+4 -16
View File
@@ -29,34 +29,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define PROGAM_OPTIONS_H #define PROGAM_OPTIONS_H
#include "GitDescription.h" #include "GitDescription.h"
#include "IniFileUtil.h"
#include "OSRMException.h" #include "OSRMException.h"
#include "SimpleLogger.h" #include "SimpleLogger.h"
#include <osrm/ServerPaths.h> #include <osrm/ServerPaths.h>
#include <boost/any.hpp> #include <boost/any.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <fstream> #include <fstream>
#include <regex>
#include <string> #include <string>
const static unsigned INIT_OK_START_ENGINE = 0; const static unsigned INIT_OK_START_ENGINE = 0;
const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1; const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
const static unsigned INIT_FAILED = -1; const static unsigned INIT_FAILED = -1;
// support old capitalized option names by down-casing them with a regex replace
inline void PrepareConfigFile(const boost::filesystem::path &path, std::string &output)
{
std::ifstream config_stream(path.string().c_str());
std::string input_str((std::istreambuf_iterator<char>(config_stream)),
std::istreambuf_iterator<char>());
std::regex regex("^([^=]*)"); // match from start of line to '='
std::string format("\\L$1\\E"); // replace with downcased substring
output = std::regex_replace(input_str, regex, format);
}
// generate boost::program_options object for the routing part // generate boost::program_options object for the routing part
inline unsigned GenerateServerProgramOptions(const int argc, inline unsigned GenerateServerProgramOptions(const int argc,
const char *argv[], const char *argv[],
@@ -166,12 +154,12 @@ inline unsigned GenerateServerProgramOptions(const int argc,
!option_variables.count("base")) !option_variables.count("base"))
{ {
SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string(); SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
std::string config_str; std::string ini_file_contents = ReadIniFileAndLowerContents(path_iterator->second);
PrepareConfigFile(path_iterator->second, config_str); std::stringstream config_stream(ini_file_contents);
std::stringstream config_stream(config_str);
boost::program_options::store(parse_config_file(config_stream, config_file_options), boost::program_options::store(parse_config_file(config_stream, config_file_options),
option_variables); option_variables);
boost::program_options::notify(option_variables); boost::program_options::notify(option_variables);
return INIT_OK_START_ENGINE;
} }
if (1 > requested_num_threads) if (1 > requested_num_threads)
+46
View File
@@ -0,0 +1,46 @@
/*
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 STD_HASH_EXTENSIONS_H
#define STD_HASH_EXTENSIONS_H
#include "../typedefs.h"
#include <functional>
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);
}
};
}
#endif // STD_HASH_EXTENSIONS_H
+30 -5
View File
@@ -80,11 +80,12 @@ auto as_integer(Enumeration const value)
return static_cast<typename std::underlying_type<Enumeration>::type>(value); return static_cast<typename std::underlying_type<Enumeration>::type>(value);
} }
static inline void intToString(const int value, std::string &output) static inline std::string IntToString(const int value)
{ {
output.clear(); std::string output;
std::back_insert_iterator<std::string> sink(output); std::back_insert_iterator<std::string> sink(output);
boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value); boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value);
return output;
} }
static inline void int64ToString(const int64_t value, std::string &output) static inline void int64ToString(const int64_t value, std::string &output)
@@ -168,11 +169,35 @@ static inline double StringToDouble(const char *p)
return r; return r;
} }
static inline void doubleToString(const double value, std::string &output) template <typename T>
struct scientific_policy : boost::spirit::karma::real_policies<T>
{ {
output.clear(); // we want the numbers always to be in fixed format
static int floatfield(T n) { return boost::spirit::karma::real_policies<T>::fmtflags::fixed; }
static unsigned int precision(T) { return 6; }
};
typedef
boost::spirit::karma::real_generator<double, scientific_policy<double> >
science_type;
static inline std::string FixedDoubleToString(const double value)
{
std::string output;
std::back_insert_iterator<std::string> sink(output); std::back_insert_iterator<std::string> sink(output);
boost::spirit::karma::generate(sink, boost::spirit::karma::double_, value); boost::spirit::karma::generate(sink, science_type(), value);
if (output.size() >= 2 && output[output.size()-2] == '.' && output[output.size()-1] == '0')
{
output.resize(output.size()-2);
}
return output;
}
static inline std::string DoubleToString(const double value)
{
std::string output;
std::back_insert_iterator<std::string> sink(output);
boost::spirit::karma::generate(sink, value);
return output;
} }
static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string &output) static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string &output)
+789
View File
@@ -0,0 +1,789 @@
/*
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 TRIGONOMETRY_TABLES_H
#define TRIGONOMETRY_TABLES_H
#include <cmath>
#include <limits>
constexpr unsigned short atan_table[4096] = {
0x0000, 0x0014, 0x0028, 0x003d, 0x0051, 0x0065,
0x007a, 0x008e, 0x00a3, 0x00b7, 0x00cb, 0x00e0,
0x00f4, 0x0108, 0x011d, 0x0131, 0x0146, 0x015a,
0x016e, 0x0183, 0x0197, 0x01ab, 0x01c0, 0x01d4,
0x01e9, 0x01fd, 0x0211, 0x0226, 0x023a, 0x024e,
0x0263, 0x0277, 0x028c, 0x02a0, 0x02b4, 0x02c9,
0x02dd, 0x02f1, 0x0306, 0x031a, 0x032f, 0x0343,
0x0357, 0x036c, 0x0380, 0x0394, 0x03a9, 0x03bd,
0x03d2, 0x03e6, 0x03fa, 0x040f, 0x0423, 0x0437,
0x044c, 0x0460, 0x0475, 0x0489, 0x049d, 0x04b2,
0x04c6, 0x04da, 0x04ef, 0x0503, 0x0517, 0x052c,
0x0540, 0x0555, 0x0569, 0x057d, 0x0592, 0x05a6,
0x05ba, 0x05cf, 0x05e3, 0x05f8, 0x060c, 0x0620,
0x0635, 0x0649, 0x065d, 0x0672, 0x0686, 0x069b,
0x06af, 0x06c3, 0x06d8, 0x06ec, 0x0700, 0x0715,
0x0729, 0x073d, 0x0752, 0x0766, 0x077b, 0x078f,
0x07a3, 0x07b8, 0x07cc, 0x07e0, 0x07f5, 0x0809,
0x081d, 0x0832, 0x0846, 0x085b, 0x086f, 0x0883,
0x0898, 0x08ac, 0x08c0, 0x08d5, 0x08e9, 0x08fd,
0x0912, 0x0926, 0x093b, 0x094f, 0x0963, 0x0978,
0x098c, 0x09a0, 0x09b5, 0x09c9, 0x09dd, 0x09f2,
0x0a06, 0x0a1a, 0x0a2f, 0x0a43, 0x0a58, 0x0a6c,
0x0a80, 0x0a95, 0x0aa9, 0x0abd, 0x0ad2, 0x0ae6,
0x0afa, 0x0b0f, 0x0b23, 0x0b37, 0x0b4c, 0x0b60,
0x0b75, 0x0b89, 0x0b9d, 0x0bb2, 0x0bc6, 0x0bda,
0x0bef, 0x0c03, 0x0c17, 0x0c2c, 0x0c40, 0x0c54,
0x0c69, 0x0c7d, 0x0c91, 0x0ca6, 0x0cba, 0x0cce,
0x0ce3, 0x0cf7, 0x0d0b, 0x0d20, 0x0d34, 0x0d48,
0x0d5d, 0x0d71, 0x0d86, 0x0d9a, 0x0dae, 0x0dc3,
0x0dd7, 0x0deb, 0x0e00, 0x0e14, 0x0e28, 0x0e3d,
0x0e51, 0x0e65, 0x0e7a, 0x0e8e, 0x0ea2, 0x0eb7,
0x0ecb, 0x0edf, 0x0ef4, 0x0f08, 0x0f1c, 0x0f31,
0x0f45, 0x0f59, 0x0f6e, 0x0f82, 0x0f96, 0x0fab,
0x0fbf, 0x0fd3, 0x0fe8, 0x0ffc, 0x1010, 0x1025,
0x1039, 0x104d, 0x1062, 0x1076, 0x108a, 0x109e,
0x10b3, 0x10c7, 0x10db, 0x10f0, 0x1104, 0x1118,
0x112d, 0x1141, 0x1155, 0x116a, 0x117e, 0x1192,
0x11a7, 0x11bb, 0x11cf, 0x11e4, 0x11f8, 0x120c,
0x1221, 0x1235, 0x1249, 0x125d, 0x1272, 0x1286,
0x129a, 0x12af, 0x12c3, 0x12d7, 0x12ec, 0x1300,
0x1314, 0x1329, 0x133d, 0x1351, 0x1365, 0x137a,
0x138e, 0x13a2, 0x13b7, 0x13cb, 0x13df, 0x13f4,
0x1408, 0x141c, 0x1431, 0x1445, 0x1459, 0x146d,
0x1482, 0x1496, 0x14aa, 0x14bf, 0x14d3, 0x14e7,
0x14fb, 0x1510, 0x1524, 0x1538, 0x154d, 0x1561,
0x1575, 0x1589, 0x159e, 0x15b2, 0x15c6, 0x15db,
0x15ef, 0x1603, 0x1617, 0x162c, 0x1640, 0x1654,
0x1669, 0x167d, 0x1691, 0x16a5, 0x16ba, 0x16ce,
0x16e2, 0x16f7, 0x170b, 0x171f, 0x1733, 0x1748,
0x175c, 0x1770, 0x1784, 0x1799, 0x17ad, 0x17c1,
0x17d6, 0x17ea, 0x17fe, 0x1812, 0x1827, 0x183b,
0x184f, 0x1863, 0x1878, 0x188c, 0x18a0, 0x18b4,
0x18c9, 0x18dd, 0x18f1, 0x1905, 0x191a, 0x192e,
0x1942, 0x1957, 0x196b, 0x197f, 0x1993, 0x19a8,
0x19bc, 0x19d0, 0x19e4, 0x19f9, 0x1a0d, 0x1a21,
0x1a35, 0x1a49, 0x1a5e, 0x1a72, 0x1a86, 0x1a9a,
0x1aaf, 0x1ac3, 0x1ad7, 0x1aeb, 0x1b00, 0x1b14,
0x1b28, 0x1b3c, 0x1b51, 0x1b65, 0x1b79, 0x1b8d,
0x1ba2, 0x1bb6, 0x1bca, 0x1bde, 0x1bf2, 0x1c07,
0x1c1b, 0x1c2f, 0x1c43, 0x1c58, 0x1c6c, 0x1c80,
0x1c94, 0x1ca8, 0x1cbd, 0x1cd1, 0x1ce5, 0x1cf9,
0x1d0e, 0x1d22, 0x1d36, 0x1d4a, 0x1d5e, 0x1d73,
0x1d87, 0x1d9b, 0x1daf, 0x1dc3, 0x1dd8, 0x1dec,
0x1e00, 0x1e14, 0x1e28, 0x1e3d, 0x1e51, 0x1e65,
0x1e79, 0x1e8d, 0x1ea2, 0x1eb6, 0x1eca, 0x1ede,
0x1ef2, 0x1f07, 0x1f1b, 0x1f2f, 0x1f43, 0x1f57,
0x1f6c, 0x1f80, 0x1f94, 0x1fa8, 0x1fbc, 0x1fd1,
0x1fe5, 0x1ff9, 0x200d, 0x2021, 0x2035, 0x204a,
0x205e, 0x2072, 0x2086, 0x209a, 0x20ae, 0x20c3,
0x20d7, 0x20eb, 0x20ff, 0x2113, 0x2127, 0x213c,
0x2150, 0x2164, 0x2178, 0x218c, 0x21a0, 0x21b5,
0x21c9, 0x21dd, 0x21f1, 0x2205, 0x2219, 0x222e,
0x2242, 0x2256, 0x226a, 0x227e, 0x2292, 0x22a6,
0x22bb, 0x22cf, 0x22e3, 0x22f7, 0x230b, 0x231f,
0x2333, 0x2348, 0x235c, 0x2370, 0x2384, 0x2398,
0x23ac, 0x23c0, 0x23d5, 0x23e9, 0x23fd, 0x2411,
0x2425, 0x2439, 0x244d, 0x2461, 0x2476, 0x248a,
0x249e, 0x24b2, 0x24c6, 0x24da, 0x24ee, 0x2502,
0x2517, 0x252b, 0x253f, 0x2553, 0x2567, 0x257b,
0x258f, 0x25a3, 0x25b7, 0x25cb, 0x25e0, 0x25f4,
0x2608, 0x261c, 0x2630, 0x2644, 0x2658, 0x266c,
0x2680, 0x2694, 0x26a9, 0x26bd, 0x26d1, 0x26e5,
0x26f9, 0x270d, 0x2721, 0x2735, 0x2749, 0x275d,
0x2771, 0x2785, 0x279a, 0x27ae, 0x27c2, 0x27d6,
0x27ea, 0x27fe, 0x2812, 0x2826, 0x283a, 0x284e,
0x2862, 0x2876, 0x288a, 0x289e, 0x28b3, 0x28c7,
0x28db, 0x28ef, 0x2903, 0x2917, 0x292b, 0x293f,
0x2953, 0x2967, 0x297b, 0x298f, 0x29a3, 0x29b7,
0x29cb, 0x29df, 0x29f3, 0x2a07, 0x2a1b, 0x2a2f,
0x2a43, 0x2a58, 0x2a6c, 0x2a80, 0x2a94, 0x2aa8,
0x2abc, 0x2ad0, 0x2ae4, 0x2af8, 0x2b0c, 0x2b20,
0x2b34, 0x2b48, 0x2b5c, 0x2b70, 0x2b84, 0x2b98,
0x2bac, 0x2bc0, 0x2bd4, 0x2be8, 0x2bfc, 0x2c10,
0x2c24, 0x2c38, 0x2c4c, 0x2c60, 0x2c74, 0x2c88,
0x2c9c, 0x2cb0, 0x2cc4, 0x2cd8, 0x2cec, 0x2d00,
0x2d14, 0x2d28, 0x2d3c, 0x2d50, 0x2d64, 0x2d78,
0x2d8c, 0x2da0, 0x2db4, 0x2dc8, 0x2ddc, 0x2df0,
0x2e04, 0x2e18, 0x2e2c, 0x2e40, 0x2e54, 0x2e68,
0x2e7c, 0x2e90, 0x2ea3, 0x2eb7, 0x2ecb, 0x2edf,
0x2ef3, 0x2f07, 0x2f1b, 0x2f2f, 0x2f43, 0x2f57,
0x2f6b, 0x2f7f, 0x2f93, 0x2fa7, 0x2fbb, 0x2fcf,
0x2fe3, 0x2ff7, 0x300b, 0x301e, 0x3032, 0x3046,
0x305a, 0x306e, 0x3082, 0x3096, 0x30aa, 0x30be,
0x30d2, 0x30e6, 0x30fa, 0x310e, 0x3122, 0x3135,
0x3149, 0x315d, 0x3171, 0x3185, 0x3199, 0x31ad,
0x31c1, 0x31d5, 0x31e9, 0x31fd, 0x3210, 0x3224,
0x3238, 0x324c, 0x3260, 0x3274, 0x3288, 0x329c,
0x32b0, 0x32c3, 0x32d7, 0x32eb, 0x32ff, 0x3313,
0x3327, 0x333b, 0x334f, 0x3363, 0x3376, 0x338a,
0x339e, 0x33b2, 0x33c6, 0x33da, 0x33ee, 0x3401,
0x3415, 0x3429, 0x343d, 0x3451, 0x3465, 0x3479,
0x348c, 0x34a0, 0x34b4, 0x34c8, 0x34dc, 0x34f0,
0x3504, 0x3517, 0x352b, 0x353f, 0x3553, 0x3567,
0x357b, 0x358e, 0x35a2, 0x35b6, 0x35ca, 0x35de,
0x35f2, 0x3605, 0x3619, 0x362d, 0x3641, 0x3655,
0x3668, 0x367c, 0x3690, 0x36a4, 0x36b8, 0x36cb,
0x36df, 0x36f3, 0x3707, 0x371b, 0x372f, 0x3742,
0x3756, 0x376a, 0x377e, 0x3791, 0x37a5, 0x37b9,
0x37cd, 0x37e1, 0x37f4, 0x3808, 0x381c, 0x3830,
0x3844, 0x3857, 0x386b, 0x387f, 0x3893, 0x38a6,
0x38ba, 0x38ce, 0x38e2, 0x38f5, 0x3909, 0x391d,
0x3931, 0x3944, 0x3958, 0x396c, 0x3980, 0x3993,
0x39a7, 0x39bb, 0x39cf, 0x39e2, 0x39f6, 0x3a0a,
0x3a1e, 0x3a31, 0x3a45, 0x3a59, 0x3a6d, 0x3a80,
0x3a94, 0x3aa8, 0x3abb, 0x3acf, 0x3ae3, 0x3af7,
0x3b0a, 0x3b1e, 0x3b32, 0x3b45, 0x3b59, 0x3b6d,
0x3b81, 0x3b94, 0x3ba8, 0x3bbc, 0x3bcf, 0x3be3,
0x3bf7, 0x3c0b, 0x3c1e, 0x3c32, 0x3c46, 0x3c59,
0x3c6d, 0x3c81, 0x3c94, 0x3ca8, 0x3cbc, 0x3ccf,
0x3ce3, 0x3cf7, 0x3d0a, 0x3d1e, 0x3d32, 0x3d45,
0x3d59, 0x3d6d, 0x3d80, 0x3d94, 0x3da8, 0x3dbb,
0x3dcf, 0x3de3, 0x3df6, 0x3e0a, 0x3e1e, 0x3e31,
0x3e45, 0x3e59, 0x3e6c, 0x3e80, 0x3e93, 0x3ea7,
0x3ebb, 0x3ece, 0x3ee2, 0x3ef6, 0x3f09, 0x3f1d,
0x3f30, 0x3f44, 0x3f58, 0x3f6b, 0x3f7f, 0x3f93,
0x3fa6, 0x3fba, 0x3fcd, 0x3fe1, 0x3ff5, 0x4008,
0x401c, 0x402f, 0x4043, 0x4057, 0x406a, 0x407e,
0x4091, 0x40a5, 0x40b8, 0x40cc, 0x40e0, 0x40f3,
0x4107, 0x411a, 0x412e, 0x4142, 0x4155, 0x4169,
0x417c, 0x4190, 0x41a3, 0x41b7, 0x41ca, 0x41de,
0x41f2, 0x4205, 0x4219, 0x422c, 0x4240, 0x4253,
0x4267, 0x427a, 0x428e, 0x42a1, 0x42b5, 0x42c9,
0x42dc, 0x42f0, 0x4303, 0x4317, 0x432a, 0x433e,
0x4351, 0x4365, 0x4378, 0x438c, 0x439f, 0x43b3,
0x43c6, 0x43da, 0x43ed, 0x4401, 0x4414, 0x4428,
0x443b, 0x444f, 0x4462, 0x4476, 0x4489, 0x449d,
0x44b0, 0x44c4, 0x44d7, 0x44eb, 0x44fe, 0x4512,
0x4525, 0x4539, 0x454c, 0x4560, 0x4573, 0x4586,
0x459a, 0x45ad, 0x45c1, 0x45d4, 0x45e8, 0x45fb,
0x460f, 0x4622, 0x4636, 0x4649, 0x465c, 0x4670,
0x4683, 0x4697, 0x46aa, 0x46be, 0x46d1, 0x46e5,
0x46f8, 0x470b, 0x471f, 0x4732, 0x4746, 0x4759,
0x476c, 0x4780, 0x4793, 0x47a7, 0x47ba, 0x47cd,
0x47e1, 0x47f4, 0x4808, 0x481b, 0x482e, 0x4842,
0x4855, 0x4869, 0x487c, 0x488f, 0x48a3, 0x48b6,
0x48ca, 0x48dd, 0x48f0, 0x4904, 0x4917, 0x492a,
0x493e, 0x4951, 0x4965, 0x4978, 0x498b, 0x499f,
0x49b2, 0x49c5, 0x49d9, 0x49ec, 0x49ff, 0x4a13,
0x4a26, 0x4a39, 0x4a4d, 0x4a60, 0x4a73, 0x4a87,
0x4a9a, 0x4aad, 0x4ac1, 0x4ad4, 0x4ae7, 0x4afb,
0x4b0e, 0x4b21, 0x4b35, 0x4b48, 0x4b5b, 0x4b6f,
0x4b82, 0x4b95, 0x4ba8, 0x4bbc, 0x4bcf, 0x4be2,
0x4bf6, 0x4c09, 0x4c1c, 0x4c2f, 0x4c43, 0x4c56,
0x4c69, 0x4c7d, 0x4c90, 0x4ca3, 0x4cb6, 0x4cca,
0x4cdd, 0x4cf0, 0x4d03, 0x4d17, 0x4d2a, 0x4d3d,
0x4d50, 0x4d64, 0x4d77, 0x4d8a, 0x4d9d, 0x4db1,
0x4dc4, 0x4dd7, 0x4dea, 0x4dfe, 0x4e11, 0x4e24,
0x4e37, 0x4e4b, 0x4e5e, 0x4e71, 0x4e84, 0x4e97,
0x4eab, 0x4ebe, 0x4ed1, 0x4ee4, 0x4ef7, 0x4f0b,
0x4f1e, 0x4f31, 0x4f44, 0x4f57, 0x4f6b, 0x4f7e,
0x4f91, 0x4fa4, 0x4fb7, 0x4fcb, 0x4fde, 0x4ff1,
0x5004, 0x5017, 0x502a, 0x503e, 0x5051, 0x5064,
0x5077, 0x508a, 0x509d, 0x50b1, 0x50c4, 0x50d7,
0x50ea, 0x50fd, 0x5110, 0x5123, 0x5137, 0x514a,
0x515d, 0x5170, 0x5183, 0x5196, 0x51a9, 0x51bc,
0x51d0, 0x51e3, 0x51f6, 0x5209, 0x521c, 0x522f,
0x5242, 0x5255, 0x5268, 0x527c, 0x528f, 0x52a2,
0x52b5, 0x52c8, 0x52db, 0x52ee, 0x5301, 0x5314,
0x5327, 0x533a, 0x534e, 0x5361, 0x5374, 0x5387,
0x539a, 0x53ad, 0x53c0, 0x53d3, 0x53e6, 0x53f9,
0x540c, 0x541f, 0x5432, 0x5445, 0x5458, 0x546b,
0x547e, 0x5491, 0x54a5, 0x54b8, 0x54cb, 0x54de,
0x54f1, 0x5504, 0x5517, 0x552a, 0x553d, 0x5550,
0x5563, 0x5576, 0x5589, 0x559c, 0x55af, 0x55c2,
0x55d5, 0x55e8, 0x55fb, 0x560e, 0x5621, 0x5634,
0x5647, 0x565a, 0x566d, 0x5680, 0x5693, 0x56a6,
0x56b9, 0x56cb, 0x56de, 0x56f1, 0x5704, 0x5717,
0x572a, 0x573d, 0x5750, 0x5763, 0x5776, 0x5789,
0x579c, 0x57af, 0x57c2, 0x57d5, 0x57e8, 0x57fb,
0x580e, 0x5820, 0x5833, 0x5846, 0x5859, 0x586c,
0x587f, 0x5892, 0x58a5, 0x58b8, 0x58cb, 0x58de,
0x58f0, 0x5903, 0x5916, 0x5929, 0x593c, 0x594f,
0x5962, 0x5975, 0x5988, 0x599a, 0x59ad, 0x59c0,
0x59d3, 0x59e6, 0x59f9, 0x5a0c, 0x5a1f, 0x5a31,
0x5a44, 0x5a57, 0x5a6a, 0x5a7d, 0x5a90, 0x5aa2,
0x5ab5, 0x5ac8, 0x5adb, 0x5aee, 0x5b01, 0x5b13,
0x5b26, 0x5b39, 0x5b4c, 0x5b5f, 0x5b72, 0x5b84,
0x5b97, 0x5baa, 0x5bbd, 0x5bd0, 0x5be2, 0x5bf5,
0x5c08, 0x5c1b, 0x5c2e, 0x5c40, 0x5c53, 0x5c66,
0x5c79, 0x5c8c, 0x5c9e, 0x5cb1, 0x5cc4, 0x5cd7,
0x5ce9, 0x5cfc, 0x5d0f, 0x5d22, 0x5d34, 0x5d47,
0x5d5a, 0x5d6d, 0x5d7f, 0x5d92, 0x5da5, 0x5db8,
0x5dca, 0x5ddd, 0x5df0, 0x5e03, 0x5e15, 0x5e28,
0x5e3b, 0x5e4d, 0x5e60, 0x5e73, 0x5e86, 0x5e98,
0x5eab, 0x5ebe, 0x5ed0, 0x5ee3, 0x5ef6, 0x5f09,
0x5f1b, 0x5f2e, 0x5f41, 0x5f53, 0x5f66, 0x5f79,
0x5f8b, 0x5f9e, 0x5fb1, 0x5fc3, 0x5fd6, 0x5fe9,
0x5ffb, 0x600e, 0x6021, 0x6033, 0x6046, 0x6059,
0x606b, 0x607e, 0x6091, 0x60a3, 0x60b6, 0x60c8,
0x60db, 0x60ee, 0x6100, 0x6113, 0x6126, 0x6138,
0x614b, 0x615d, 0x6170, 0x6183, 0x6195, 0x61a8,
0x61ba, 0x61cd, 0x61e0, 0x61f2, 0x6205, 0x6217,
0x622a, 0x623d, 0x624f, 0x6262, 0x6274, 0x6287,
0x6299, 0x62ac, 0x62bf, 0x62d1, 0x62e4, 0x62f6,
0x6309, 0x631b, 0x632e, 0x6340, 0x6353, 0x6366,
0x6378, 0x638b, 0x639d, 0x63b0, 0x63c2, 0x63d5,
0x63e7, 0x63fa, 0x640c, 0x641f, 0x6431, 0x6444,
0x6456, 0x6469, 0x647b, 0x648e, 0x64a0, 0x64b3,
0x64c5, 0x64d8, 0x64ea, 0x64fd, 0x650f, 0x6522,
0x6534, 0x6547, 0x6559, 0x656c, 0x657e, 0x6591,
0x65a3, 0x65b5, 0x65c8, 0x65da, 0x65ed, 0x65ff,
0x6612, 0x6624, 0x6637, 0x6649, 0x665b, 0x666e,
0x6680, 0x6693, 0x66a5, 0x66b8, 0x66ca, 0x66dc,
0x66ef, 0x6701, 0x6714, 0x6726, 0x6738, 0x674b,
0x675d, 0x6770, 0x6782, 0x6794, 0x67a7, 0x67b9,
0x67cc, 0x67de, 0x67f0, 0x6803, 0x6815, 0x6827,
0x683a, 0x684c, 0x685e, 0x6871, 0x6883, 0x6896,
0x68a8, 0x68ba, 0x68cd, 0x68df, 0x68f1, 0x6904,
0x6916, 0x6928, 0x693b, 0x694d, 0x695f, 0x6972,
0x6984, 0x6996, 0x69a8, 0x69bb, 0x69cd, 0x69df,
0x69f2, 0x6a04, 0x6a16, 0x6a29, 0x6a3b, 0x6a4d,
0x6a5f, 0x6a72, 0x6a84, 0x6a96, 0x6aa9, 0x6abb,
0x6acd, 0x6adf, 0x6af2, 0x6b04, 0x6b16, 0x6b28,
0x6b3b, 0x6b4d, 0x6b5f, 0x6b71, 0x6b84, 0x6b96,
0x6ba8, 0x6bba, 0x6bcd, 0x6bdf, 0x6bf1, 0x6c03,
0x6c15, 0x6c28, 0x6c3a, 0x6c4c, 0x6c5e, 0x6c70,
0x6c83, 0x6c95, 0x6ca7, 0x6cb9, 0x6ccb, 0x6cde,
0x6cf0, 0x6d02, 0x6d14, 0x6d26, 0x6d39, 0x6d4b,
0x6d5d, 0x6d6f, 0x6d81, 0x6d93, 0x6da6, 0x6db8,
0x6dca, 0x6ddc, 0x6dee, 0x6e00, 0x6e12, 0x6e25,
0x6e37, 0x6e49, 0x6e5b, 0x6e6d, 0x6e7f, 0x6e91,
0x6ea3, 0x6eb6, 0x6ec8, 0x6eda, 0x6eec, 0x6efe,
0x6f10, 0x6f22, 0x6f34, 0x6f46, 0x6f58, 0x6f6b,
0x6f7d, 0x6f8f, 0x6fa1, 0x6fb3, 0x6fc5, 0x6fd7,
0x6fe9, 0x6ffb, 0x700d, 0x701f, 0x7031, 0x7043,
0x7055, 0x7068, 0x707a, 0x708c, 0x709e, 0x70b0,
0x70c2, 0x70d4, 0x70e6, 0x70f8, 0x710a, 0x711c,
0x712e, 0x7140, 0x7152, 0x7164, 0x7176, 0x7188,
0x719a, 0x71ac, 0x71be, 0x71d0, 0x71e2, 0x71f4,
0x7206, 0x7218, 0x722a, 0x723c, 0x724e, 0x7260,
0x7272, 0x7284, 0x7296, 0x72a8, 0x72ba, 0x72cc,
0x72dd, 0x72ef, 0x7301, 0x7313, 0x7325, 0x7337,
0x7349, 0x735b, 0x736d, 0x737f, 0x7391, 0x73a3,
0x73b5, 0x73c7, 0x73d8, 0x73ea, 0x73fc, 0x740e,
0x7420, 0x7432, 0x7444, 0x7456, 0x7468, 0x747a,
0x748b, 0x749d, 0x74af, 0x74c1, 0x74d3, 0x74e5,
0x74f7, 0x7509, 0x751a, 0x752c, 0x753e, 0x7550,
0x7562, 0x7574, 0x7585, 0x7597, 0x75a9, 0x75bb,
0x75cd, 0x75df, 0x75f0, 0x7602, 0x7614, 0x7626,
0x7638, 0x764a, 0x765b, 0x766d, 0x767f, 0x7691,
0x76a3, 0x76b4, 0x76c6, 0x76d8, 0x76ea, 0x76fb,
0x770d, 0x771f, 0x7731, 0x7743, 0x7754, 0x7766,
0x7778, 0x778a, 0x779b, 0x77ad, 0x77bf, 0x77d1,
0x77e2, 0x77f4, 0x7806, 0x7818, 0x7829, 0x783b,
0x784d, 0x785e, 0x7870, 0x7882, 0x7894, 0x78a5,
0x78b7, 0x78c9, 0x78da, 0x78ec, 0x78fe, 0x7910,
0x7921, 0x7933, 0x7945, 0x7956, 0x7968, 0x797a,
0x798b, 0x799d, 0x79af, 0x79c0, 0x79d2, 0x79e4,
0x79f5, 0x7a07, 0x7a19, 0x7a2a, 0x7a3c, 0x7a4e,
0x7a5f, 0x7a71, 0x7a82, 0x7a94, 0x7aa6, 0x7ab7,
0x7ac9, 0x7adb, 0x7aec, 0x7afe, 0x7b0f, 0x7b21,
0x7b33, 0x7b44, 0x7b56, 0x7b67, 0x7b79, 0x7b8b,
0x7b9c, 0x7bae, 0x7bbf, 0x7bd1, 0x7be2, 0x7bf4,
0x7c06, 0x7c17, 0x7c29, 0x7c3a, 0x7c4c, 0x7c5d,
0x7c6f, 0x7c81, 0x7c92, 0x7ca4, 0x7cb5, 0x7cc7,
0x7cd8, 0x7cea, 0x7cfb, 0x7d0d, 0x7d1e, 0x7d30,
0x7d41, 0x7d53, 0x7d64, 0x7d76, 0x7d87, 0x7d99,
0x7daa, 0x7dbc, 0x7dcd, 0x7ddf, 0x7df0, 0x7e02,
0x7e13, 0x7e25, 0x7e36, 0x7e48, 0x7e59, 0x7e6b,
0x7e7c, 0x7e8e, 0x7e9f, 0x7eb0, 0x7ec2, 0x7ed3,
0x7ee5, 0x7ef6, 0x7f08, 0x7f19, 0x7f2b, 0x7f3c,
0x7f4d, 0x7f5f, 0x7f70, 0x7f82, 0x7f93, 0x7fa4,
0x7fb6, 0x7fc7, 0x7fd9, 0x7fea, 0x7ffb, 0x800d,
0x801e, 0x8030, 0x8041, 0x8052, 0x8064, 0x8075,
0x8086, 0x8098, 0x80a9, 0x80bb, 0x80cc, 0x80dd,
0x80ef, 0x8100, 0x8111, 0x8123, 0x8134, 0x8145,
0x8157, 0x8168, 0x8179, 0x818b, 0x819c, 0x81ad,
0x81bf, 0x81d0, 0x81e1, 0x81f3, 0x8204, 0x8215,
0x8226, 0x8238, 0x8249, 0x825a, 0x826c, 0x827d,
0x828e, 0x829f, 0x82b1, 0x82c2, 0x82d3, 0x82e5,
0x82f6, 0x8307, 0x8318, 0x832a, 0x833b, 0x834c,
0x835d, 0x836f, 0x8380, 0x8391, 0x83a2, 0x83b3,
0x83c5, 0x83d6, 0x83e7, 0x83f8, 0x840a, 0x841b,
0x842c, 0x843d, 0x844e, 0x8460, 0x8471, 0x8482,
0x8493, 0x84a4, 0x84b6, 0x84c7, 0x84d8, 0x84e9,
0x84fa, 0x850b, 0x851d, 0x852e, 0x853f, 0x8550,
0x8561, 0x8572, 0x8584, 0x8595, 0x85a6, 0x85b7,
0x85c8, 0x85d9, 0x85ea, 0x85fb, 0x860d, 0x861e,
0x862f, 0x8640, 0x8651, 0x8662, 0x8673, 0x8684,
0x8695, 0x86a7, 0x86b8, 0x86c9, 0x86da, 0x86eb,
0x86fc, 0x870d, 0x871e, 0x872f, 0x8740, 0x8751,
0x8762, 0x8773, 0x8784, 0x8796, 0x87a7, 0x87b8,
0x87c9, 0x87da, 0x87eb, 0x87fc, 0x880d, 0x881e,
0x882f, 0x8840, 0x8851, 0x8862, 0x8873, 0x8884,
0x8895, 0x88a6, 0x88b7, 0x88c8, 0x88d9, 0x88ea,
0x88fb, 0x890c, 0x891d, 0x892e, 0x893f, 0x8950,
0x8961, 0x8972, 0x8983, 0x8994, 0x89a5, 0x89b6,
0x89c6, 0x89d7, 0x89e8, 0x89f9, 0x8a0a, 0x8a1b,
0x8a2c, 0x8a3d, 0x8a4e, 0x8a5f, 0x8a70, 0x8a81,
0x8a92, 0x8aa3, 0x8ab3, 0x8ac4, 0x8ad5, 0x8ae6,
0x8af7, 0x8b08, 0x8b19, 0x8b2a, 0x8b3b, 0x8b4b,
0x8b5c, 0x8b6d, 0x8b7e, 0x8b8f, 0x8ba0, 0x8bb1,
0x8bc1, 0x8bd2, 0x8be3, 0x8bf4, 0x8c05, 0x8c16,
0x8c27, 0x8c37, 0x8c48, 0x8c59, 0x8c6a, 0x8c7b,
0x8c8c, 0x8c9c, 0x8cad, 0x8cbe, 0x8ccf, 0x8ce0,
0x8cf0, 0x8d01, 0x8d12, 0x8d23, 0x8d34, 0x8d44,
0x8d55, 0x8d66, 0x8d77, 0x8d87, 0x8d98, 0x8da9,
0x8dba, 0x8dca, 0x8ddb, 0x8dec, 0x8dfd, 0x8e0d,
0x8e1e, 0x8e2f, 0x8e40, 0x8e50, 0x8e61, 0x8e72,
0x8e83, 0x8e93, 0x8ea4, 0x8eb5, 0x8ec5, 0x8ed6,
0x8ee7, 0x8ef8, 0x8f08, 0x8f19, 0x8f2a, 0x8f3a,
0x8f4b, 0x8f5c, 0x8f6c, 0x8f7d, 0x8f8e, 0x8f9e,
0x8faf, 0x8fc0, 0x8fd0, 0x8fe1, 0x8ff2, 0x9002,
0x9013, 0x9024, 0x9034, 0x9045, 0x9056, 0x9066,
0x9077, 0x9088, 0x9098, 0x90a9, 0x90b9, 0x90ca,
0x90db, 0x90eb, 0x90fc, 0x910c, 0x911d, 0x912e,
0x913e, 0x914f, 0x915f, 0x9170, 0x9181, 0x9191,
0x91a2, 0x91b2, 0x91c3, 0x91d3, 0x91e4, 0x91f5,
0x9205, 0x9216, 0x9226, 0x9237, 0x9247, 0x9258,
0x9268, 0x9279, 0x9289, 0x929a, 0x92aa, 0x92bb,
0x92cc, 0x92dc, 0x92ed, 0x92fd, 0x930e, 0x931e,
0x932f, 0x933f, 0x9350, 0x9360, 0x9370, 0x9381,
0x9391, 0x93a2, 0x93b2, 0x93c3, 0x93d3, 0x93e4,
0x93f4, 0x9405, 0x9415, 0x9426, 0x9436, 0x9447,
0x9457, 0x9467, 0x9478, 0x9488, 0x9499, 0x94a9,
0x94ba, 0x94ca, 0x94da, 0x94eb, 0x94fb, 0x950c,
0x951c, 0x952c, 0x953d, 0x954d, 0x955e, 0x956e,
0x957e, 0x958f, 0x959f, 0x95af, 0x95c0, 0x95d0,
0x95e1, 0x95f1, 0x9601, 0x9612, 0x9622, 0x9632,
0x9643, 0x9653, 0x9663, 0x9674, 0x9684, 0x9694,
0x96a5, 0x96b5, 0x96c5, 0x96d6, 0x96e6, 0x96f6,
0x9707, 0x9717, 0x9727, 0x9738, 0x9748, 0x9758,
0x9768, 0x9779, 0x9789, 0x9799, 0x97aa, 0x97ba,
0x97ca, 0x97da, 0x97eb, 0x97fb, 0x980b, 0x981b,
0x982c, 0x983c, 0x984c, 0x985c, 0x986d, 0x987d,
0x988d, 0x989d, 0x98ad, 0x98be, 0x98ce, 0x98de,
0x98ee, 0x98ff, 0x990f, 0x991f, 0x992f, 0x993f,
0x9950, 0x9960, 0x9970, 0x9980, 0x9990, 0x99a0,
0x99b1, 0x99c1, 0x99d1, 0x99e1, 0x99f1, 0x9a01,
0x9a12, 0x9a22, 0x9a32, 0x9a42, 0x9a52, 0x9a62,
0x9a72, 0x9a83, 0x9a93, 0x9aa3, 0x9ab3, 0x9ac3,
0x9ad3, 0x9ae3, 0x9af3, 0x9b04, 0x9b14, 0x9b24,
0x9b34, 0x9b44, 0x9b54, 0x9b64, 0x9b74, 0x9b84,
0x9b94, 0x9ba4, 0x9bb5, 0x9bc5, 0x9bd5, 0x9be5,
0x9bf5, 0x9c05, 0x9c15, 0x9c25, 0x9c35, 0x9c45,
0x9c55, 0x9c65, 0x9c75, 0x9c85, 0x9c95, 0x9ca5,
0x9cb5, 0x9cc5, 0x9cd5, 0x9ce5, 0x9cf5, 0x9d05,
0x9d15, 0x9d25, 0x9d35, 0x9d45, 0x9d55, 0x9d65,
0x9d75, 0x9d85, 0x9d95, 0x9da5, 0x9db5, 0x9dc5,
0x9dd5, 0x9de5, 0x9df5, 0x9e05, 0x9e15, 0x9e25,
0x9e35, 0x9e45, 0x9e55, 0x9e65, 0x9e74, 0x9e84,
0x9e94, 0x9ea4, 0x9eb4, 0x9ec4, 0x9ed4, 0x9ee4,
0x9ef4, 0x9f04, 0x9f14, 0x9f23, 0x9f33, 0x9f43,
0x9f53, 0x9f63, 0x9f73, 0x9f83, 0x9f93, 0x9fa3,
0x9fb2, 0x9fc2, 0x9fd2, 0x9fe2, 0x9ff2, 0xa002,
0xa012, 0xa021, 0xa031, 0xa041, 0xa051, 0xa061,
0xa071, 0xa080, 0xa090, 0xa0a0, 0xa0b0, 0xa0c0,
0xa0cf, 0xa0df, 0xa0ef, 0xa0ff, 0xa10f, 0xa11e,
0xa12e, 0xa13e, 0xa14e, 0xa15e, 0xa16d, 0xa17d,
0xa18d, 0xa19d, 0xa1ac, 0xa1bc, 0xa1cc, 0xa1dc,
0xa1eb, 0xa1fb, 0xa20b, 0xa21b, 0xa22a, 0xa23a,
0xa24a, 0xa25a, 0xa269, 0xa279, 0xa289, 0xa298,
0xa2a8, 0xa2b8, 0xa2c8, 0xa2d7, 0xa2e7, 0xa2f7,
0xa306, 0xa316, 0xa326, 0xa335, 0xa345, 0xa355,
0xa364, 0xa374, 0xa384, 0xa393, 0xa3a3, 0xa3b3,
0xa3c2, 0xa3d2, 0xa3e2, 0xa3f1, 0xa401, 0xa411,
0xa420, 0xa430, 0xa440, 0xa44f, 0xa45f, 0xa46e,
0xa47e, 0xa48e, 0xa49d, 0xa4ad, 0xa4bc, 0xa4cc,
0xa4dc, 0xa4eb, 0xa4fb, 0xa50a, 0xa51a, 0xa52a,
0xa539, 0xa549, 0xa558, 0xa568, 0xa577, 0xa587,
0xa597, 0xa5a6, 0xa5b6, 0xa5c5, 0xa5d5, 0xa5e4,
0xa5f4, 0xa603, 0xa613, 0xa622, 0xa632, 0xa641,
0xa651, 0xa660, 0xa670, 0xa67f, 0xa68f, 0xa69e,
0xa6ae, 0xa6bd, 0xa6cd, 0xa6dc, 0xa6ec, 0xa6fb,
0xa70b, 0xa71a, 0xa72a, 0xa739, 0xa749, 0xa758,
0xa768, 0xa777, 0xa787, 0xa796, 0xa7a5, 0xa7b5,
0xa7c4, 0xa7d4, 0xa7e3, 0xa7f3, 0xa802, 0xa812,
0xa821, 0xa830, 0xa840, 0xa84f, 0xa85f, 0xa86e,
0xa87d, 0xa88d, 0xa89c, 0xa8ac, 0xa8bb, 0xa8ca,
0xa8da, 0xa8e9, 0xa8f8, 0xa908, 0xa917, 0xa927,
0xa936, 0xa945, 0xa955, 0xa964, 0xa973, 0xa983,
0xa992, 0xa9a1, 0xa9b1, 0xa9c0, 0xa9cf, 0xa9df,
0xa9ee, 0xa9fd, 0xaa0d, 0xaa1c, 0xaa2b, 0xaa3b,
0xaa4a, 0xaa59, 0xaa69, 0xaa78, 0xaa87, 0xaa96,
0xaaa6, 0xaab5, 0xaac4, 0xaad4, 0xaae3, 0xaaf2,
0xab01, 0xab11, 0xab20, 0xab2f, 0xab3e, 0xab4e,
0xab5d, 0xab6c, 0xab7b, 0xab8b, 0xab9a, 0xaba9,
0xabb8, 0xabc7, 0xabd7, 0xabe6, 0xabf5, 0xac04,
0xac14, 0xac23, 0xac32, 0xac41, 0xac50, 0xac60,
0xac6f, 0xac7e, 0xac8d, 0xac9c, 0xacab, 0xacbb,
0xacca, 0xacd9, 0xace8, 0xacf7, 0xad06, 0xad16,
0xad25, 0xad34, 0xad43, 0xad52, 0xad61, 0xad70,
0xad80, 0xad8f, 0xad9e, 0xadad, 0xadbc, 0xadcb,
0xadda, 0xade9, 0xadf8, 0xae08, 0xae17, 0xae26,
0xae35, 0xae44, 0xae53, 0xae62, 0xae71, 0xae80,
0xae8f, 0xae9e, 0xaead, 0xaebd, 0xaecc, 0xaedb,
0xaeea, 0xaef9, 0xaf08, 0xaf17, 0xaf26, 0xaf35,
0xaf44, 0xaf53, 0xaf62, 0xaf71, 0xaf80, 0xaf8f,
0xaf9e, 0xafad, 0xafbc, 0xafcb, 0xafda, 0xafe9,
0xaff8, 0xb007, 0xb016, 0xb025, 0xb034, 0xb043,
0xb052, 0xb061, 0xb070, 0xb07f, 0xb08e, 0xb09d,
0xb0ac, 0xb0bb, 0xb0ca, 0xb0d9, 0xb0e8, 0xb0f6,
0xb105, 0xb114, 0xb123, 0xb132, 0xb141, 0xb150,
0xb15f, 0xb16e, 0xb17d, 0xb18c, 0xb19b, 0xb1aa,
0xb1b8, 0xb1c7, 0xb1d6, 0xb1e5, 0xb1f4, 0xb203,
0xb212, 0xb221, 0xb22f, 0xb23e, 0xb24d, 0xb25c,
0xb26b, 0xb27a, 0xb289, 0xb297, 0xb2a6, 0xb2b5,
0xb2c4, 0xb2d3, 0xb2e2, 0xb2f1, 0xb2ff, 0xb30e,
0xb31d, 0xb32c, 0xb33b, 0xb349, 0xb358, 0xb367,
0xb376, 0xb385, 0xb393, 0xb3a2, 0xb3b1, 0xb3c0,
0xb3cf, 0xb3dd, 0xb3ec, 0xb3fb, 0xb40a, 0xb418,
0xb427, 0xb436, 0xb445, 0xb453, 0xb462, 0xb471,
0xb480, 0xb48e, 0xb49d, 0xb4ac, 0xb4bb, 0xb4c9,
0xb4d8, 0xb4e7, 0xb4f6, 0xb504, 0xb513, 0xb522,
0xb530, 0xb53f, 0xb54e, 0xb55c, 0xb56b, 0xb57a,
0xb588, 0xb597, 0xb5a6, 0xb5b5, 0xb5c3, 0xb5d2,
0xb5e1, 0xb5ef, 0xb5fe, 0xb60d, 0xb61b, 0xb62a,
0xb638, 0xb647, 0xb656, 0xb664, 0xb673, 0xb682,
0xb690, 0xb69f, 0xb6ae, 0xb6bc, 0xb6cb, 0xb6d9,
0xb6e8, 0xb6f7, 0xb705, 0xb714, 0xb722, 0xb731,
0xb740, 0xb74e, 0xb75d, 0xb76b, 0xb77a, 0xb788,
0xb797, 0xb7a6, 0xb7b4, 0xb7c3, 0xb7d1, 0xb7e0,
0xb7ee, 0xb7fd, 0xb80b, 0xb81a, 0xb829, 0xb837,
0xb846, 0xb854, 0xb863, 0xb871, 0xb880, 0xb88e,
0xb89d, 0xb8ab, 0xb8ba, 0xb8c8, 0xb8d7, 0xb8e5,
0xb8f4, 0xb902, 0xb911, 0xb91f, 0xb92e, 0xb93c,
0xb94b, 0xb959, 0xb968, 0xb976, 0xb984, 0xb993,
0xb9a1, 0xb9b0, 0xb9be, 0xb9cd, 0xb9db, 0xb9ea,
0xb9f8, 0xba06, 0xba15, 0xba23, 0xba32, 0xba40,
0xba4f, 0xba5d, 0xba6b, 0xba7a, 0xba88, 0xba97,
0xbaa5, 0xbab3, 0xbac2, 0xbad0, 0xbade, 0xbaed,
0xbafb, 0xbb0a, 0xbb18, 0xbb26, 0xbb35, 0xbb43,
0xbb51, 0xbb60, 0xbb6e, 0xbb7c, 0xbb8b, 0xbb99,
0xbba8, 0xbbb6, 0xbbc4, 0xbbd3, 0xbbe1, 0xbbef,
0xbbfd, 0xbc0c, 0xbc1a, 0xbc28, 0xbc37, 0xbc45,
0xbc53, 0xbc62, 0xbc70, 0xbc7e, 0xbc8c, 0xbc9b,
0xbca9, 0xbcb7, 0xbcc6, 0xbcd4, 0xbce2, 0xbcf0,
0xbcff, 0xbd0d, 0xbd1b, 0xbd29, 0xbd38, 0xbd46,
0xbd54, 0xbd62, 0xbd71, 0xbd7f, 0xbd8d, 0xbd9b,
0xbdaa, 0xbdb8, 0xbdc6, 0xbdd4, 0xbde2, 0xbdf1,
0xbdff, 0xbe0d, 0xbe1b, 0xbe29, 0xbe38, 0xbe46,
0xbe54, 0xbe62, 0xbe70, 0xbe7f, 0xbe8d, 0xbe9b,
0xbea9, 0xbeb7, 0xbec5, 0xbed4, 0xbee2, 0xbef0,
0xbefe, 0xbf0c, 0xbf1a, 0xbf28, 0xbf37, 0xbf45,
0xbf53, 0xbf61, 0xbf6f, 0xbf7d, 0xbf8b, 0xbf99,
0xbfa7, 0xbfb6, 0xbfc4, 0xbfd2, 0xbfe0, 0xbfee,
0xbffc, 0xc00a, 0xc018, 0xc026, 0xc034, 0xc042,
0xc051, 0xc05f, 0xc06d, 0xc07b, 0xc089, 0xc097,
0xc0a5, 0xc0b3, 0xc0c1, 0xc0cf, 0xc0dd, 0xc0eb,
0xc0f9, 0xc107, 0xc115, 0xc123, 0xc131, 0xc13f,
0xc14d, 0xc15b, 0xc169, 0xc177, 0xc185, 0xc193,
0xc1a1, 0xc1af, 0xc1bd, 0xc1cb, 0xc1d9, 0xc1e7,
0xc1f5, 0xc203, 0xc211, 0xc21f, 0xc22d, 0xc23b,
0xc249, 0xc257, 0xc265, 0xc273, 0xc281, 0xc28f,
0xc29d, 0xc2ab, 0xc2b8, 0xc2c6, 0xc2d4, 0xc2e2,
0xc2f0, 0xc2fe, 0xc30c, 0xc31a, 0xc328, 0xc336,
0xc344, 0xc352, 0xc35f, 0xc36d, 0xc37b, 0xc389,
0xc397, 0xc3a5, 0xc3b3, 0xc3c1, 0xc3ce, 0xc3dc,
0xc3ea, 0xc3f8, 0xc406, 0xc414, 0xc422, 0xc42f,
0xc43d, 0xc44b, 0xc459, 0xc467, 0xc475, 0xc482,
0xc490, 0xc49e, 0xc4ac, 0xc4ba, 0xc4c7, 0xc4d5,
0xc4e3, 0xc4f1, 0xc4ff, 0xc50d, 0xc51a, 0xc528,
0xc536, 0xc544, 0xc551, 0xc55f, 0xc56d, 0xc57b,
0xc589, 0xc596, 0xc5a4, 0xc5b2, 0xc5c0, 0xc5cd,
0xc5db, 0xc5e9, 0xc5f7, 0xc604, 0xc612, 0xc620,
0xc62d, 0xc63b, 0xc649, 0xc657, 0xc664, 0xc672,
0xc680, 0xc68d, 0xc69b, 0xc6a9, 0xc6b7, 0xc6c4,
0xc6d2, 0xc6e0, 0xc6ed, 0xc6fb, 0xc709, 0xc716,
0xc724, 0xc732, 0xc73f, 0xc74d, 0xc75b, 0xc768,
0xc776, 0xc784, 0xc791, 0xc79f, 0xc7ad, 0xc7ba,
0xc7c8, 0xc7d6, 0xc7e3, 0xc7f1, 0xc7fe, 0xc80c,
0xc81a, 0xc827, 0xc835, 0xc842, 0xc850, 0xc85e,
0xc86b, 0xc879, 0xc886, 0xc894, 0xc8a2, 0xc8af,
0xc8bd, 0xc8ca, 0xc8d8, 0xc8e5, 0xc8f3, 0xc901,
0xc90e, 0xc91c, 0xc929, 0xc937, 0xc944, 0xc952,
0xc95f, 0xc96d, 0xc97b, 0xc988, 0xc996, 0xc9a3,
0xc9b1, 0xc9be, 0xc9cc, 0xc9d9, 0xc9e7, 0xc9f4,
0xca02, 0xca0f, 0xca1d, 0xca2a, 0xca38, 0xca45,
0xca53, 0xca60, 0xca6e, 0xca7b, 0xca89, 0xca96,
0xcaa4, 0xcab1, 0xcabe, 0xcacc, 0xcad9, 0xcae7,
0xcaf4, 0xcb02, 0xcb0f, 0xcb1d, 0xcb2a, 0xcb37,
0xcb45, 0xcb52, 0xcb60, 0xcb6d, 0xcb7b, 0xcb88,
0xcb95, 0xcba3, 0xcbb0, 0xcbbe, 0xcbcb, 0xcbd8,
0xcbe6, 0xcbf3, 0xcc01, 0xcc0e, 0xcc1b, 0xcc29,
0xcc36, 0xcc43, 0xcc51, 0xcc5e, 0xcc6c, 0xcc79,
0xcc86, 0xcc94, 0xcca1, 0xccae, 0xccbc, 0xccc9,
0xccd6, 0xcce4, 0xccf1, 0xccfe, 0xcd0c, 0xcd19,
0xcd26, 0xcd34, 0xcd41, 0xcd4e, 0xcd5b, 0xcd69,
0xcd76, 0xcd83, 0xcd91, 0xcd9e, 0xcdab, 0xcdb9,
0xcdc6, 0xcdd3, 0xcde0, 0xcdee, 0xcdfb, 0xce08,
0xce15, 0xce23, 0xce30, 0xce3d, 0xce4a, 0xce58,
0xce65, 0xce72, 0xce7f, 0xce8d, 0xce9a, 0xcea7,
0xceb4, 0xcec2, 0xcecf, 0xcedc, 0xcee9, 0xcef6,
0xcf04, 0xcf11, 0xcf1e, 0xcf2b, 0xcf38, 0xcf46,
0xcf53, 0xcf60, 0xcf6d, 0xcf7a, 0xcf87, 0xcf95,
0xcfa2, 0xcfaf, 0xcfbc, 0xcfc9, 0xcfd6, 0xcfe4,
0xcff1, 0xcffe, 0xd00b, 0xd018, 0xd025, 0xd032,
0xd040, 0xd04d, 0xd05a, 0xd067, 0xd074, 0xd081,
0xd08e, 0xd09b, 0xd0a9, 0xd0b6, 0xd0c3, 0xd0d0,
0xd0dd, 0xd0ea, 0xd0f7, 0xd104, 0xd111, 0xd11e,
0xd12b, 0xd139, 0xd146, 0xd153, 0xd160, 0xd16d,
0xd17a, 0xd187, 0xd194, 0xd1a1, 0xd1ae, 0xd1bb,
0xd1c8, 0xd1d5, 0xd1e2, 0xd1ef, 0xd1fc, 0xd209,
0xd216, 0xd223, 0xd230, 0xd23d, 0xd24a, 0xd257,
0xd264, 0xd271, 0xd27e, 0xd28b, 0xd298, 0xd2a5,
0xd2b2, 0xd2bf, 0xd2cc, 0xd2d9, 0xd2e6, 0xd2f3,
0xd300, 0xd30d, 0xd31a, 0xd327, 0xd334, 0xd341,
0xd34e, 0xd35b, 0xd368, 0xd375, 0xd382, 0xd38f,
0xd39c, 0xd3a8, 0xd3b5, 0xd3c2, 0xd3cf, 0xd3dc,
0xd3e9, 0xd3f6, 0xd403, 0xd410, 0xd41d, 0xd42a,
0xd436, 0xd443, 0xd450, 0xd45d, 0xd46a, 0xd477,
0xd484, 0xd491, 0xd49e, 0xd4aa, 0xd4b7, 0xd4c4,
0xd4d1, 0xd4de, 0xd4eb, 0xd4f8, 0xd504, 0xd511,
0xd51e, 0xd52b, 0xd538, 0xd545, 0xd551, 0xd55e,
0xd56b, 0xd578, 0xd585, 0xd591, 0xd59e, 0xd5ab,
0xd5b8, 0xd5c5, 0xd5d1, 0xd5de, 0xd5eb, 0xd5f8,
0xd605, 0xd611, 0xd61e, 0xd62b, 0xd638, 0xd645,
0xd651, 0xd65e, 0xd66b, 0xd678, 0xd684, 0xd691,
0xd69e, 0xd6ab, 0xd6b7, 0xd6c4, 0xd6d1, 0xd6de,
0xd6ea, 0xd6f7, 0xd704, 0xd710, 0xd71d, 0xd72a,
0xd737, 0xd743, 0xd750, 0xd75d, 0xd769, 0xd776,
0xd783, 0xd78f, 0xd79c, 0xd7a9, 0xd7b6, 0xd7c2,
0xd7cf, 0xd7dc, 0xd7e8, 0xd7f5, 0xd802, 0xd80e,
0xd81b, 0xd828, 0xd834, 0xd841, 0xd84e, 0xd85a,
0xd867, 0xd873, 0xd880, 0xd88d, 0xd899, 0xd8a6,
0xd8b3, 0xd8bf, 0xd8cc, 0xd8d8, 0xd8e5, 0xd8f2,
0xd8fe, 0xd90b, 0xd917, 0xd924, 0xd931, 0xd93d,
0xd94a, 0xd956, 0xd963, 0xd970, 0xd97c, 0xd989,
0xd995, 0xd9a2, 0xd9ae, 0xd9bb, 0xd9c8, 0xd9d4,
0xd9e1, 0xd9ed, 0xd9fa, 0xda06, 0xda13, 0xda1f,
0xda2c, 0xda38, 0xda45, 0xda51, 0xda5e, 0xda6a,
0xda77, 0xda84, 0xda90, 0xda9d, 0xdaa9, 0xdab6,
0xdac2, 0xdacf, 0xdadb, 0xdae7, 0xdaf4, 0xdb00,
0xdb0d, 0xdb19, 0xdb26, 0xdb32, 0xdb3f, 0xdb4b,
0xdb58, 0xdb64, 0xdb71, 0xdb7d, 0xdb8a, 0xdb96,
0xdba2, 0xdbaf, 0xdbbb, 0xdbc8, 0xdbd4, 0xdbe1,
0xdbed, 0xdbf9, 0xdc06, 0xdc12, 0xdc1f, 0xdc2b,
0xdc38, 0xdc44, 0xdc50, 0xdc5d, 0xdc69, 0xdc76,
0xdc82, 0xdc8e, 0xdc9b, 0xdca7, 0xdcb3, 0xdcc0,
0xdccc, 0xdcd9, 0xdce5, 0xdcf1, 0xdcfe, 0xdd0a,
0xdd16, 0xdd23, 0xdd2f, 0xdd3b, 0xdd48, 0xdd54,
0xdd60, 0xdd6d, 0xdd79, 0xdd85, 0xdd92, 0xdd9e,
0xddaa, 0xddb7, 0xddc3, 0xddcf, 0xdddc, 0xdde8,
0xddf4, 0xde01, 0xde0d, 0xde19, 0xde25, 0xde32,
0xde3e, 0xde4a, 0xde57, 0xde63, 0xde6f, 0xde7b,
0xde88, 0xde94, 0xdea0, 0xdeac, 0xdeb9, 0xdec5,
0xded1, 0xdedd, 0xdeea, 0xdef6, 0xdf02, 0xdf0e,
0xdf1b, 0xdf27, 0xdf33, 0xdf3f, 0xdf4c, 0xdf58,
0xdf64, 0xdf70, 0xdf7c, 0xdf89, 0xdf95, 0xdfa1,
0xdfad, 0xdfb9, 0xdfc6, 0xdfd2, 0xdfde, 0xdfea,
0xdff6, 0xe003, 0xe00f, 0xe01b, 0xe027, 0xe033,
0xe03f, 0xe04c, 0xe058, 0xe064, 0xe070, 0xe07c,
0xe088, 0xe094, 0xe0a1, 0xe0ad, 0xe0b9, 0xe0c5,
0xe0d1, 0xe0dd, 0xe0e9, 0xe0f5, 0xe102, 0xe10e,
0xe11a, 0xe126, 0xe132, 0xe13e, 0xe14a, 0xe156,
0xe162, 0xe16e, 0xe17b, 0xe187, 0xe193, 0xe19f,
0xe1ab, 0xe1b7, 0xe1c3, 0xe1cf, 0xe1db, 0xe1e7,
0xe1f3, 0xe1ff, 0xe20b, 0xe217, 0xe223, 0xe22f,
0xe23c, 0xe248, 0xe254, 0xe260, 0xe26c, 0xe278,
0xe284, 0xe290, 0xe29c, 0xe2a8, 0xe2b4, 0xe2c0,
0xe2cc, 0xe2d8, 0xe2e4, 0xe2f0, 0xe2fc, 0xe308,
0xe314, 0xe320, 0xe32c, 0xe338, 0xe344, 0xe350,
0xe35c, 0xe368, 0xe374, 0xe380, 0xe38b, 0xe397,
0xe3a3, 0xe3af, 0xe3bb, 0xe3c7, 0xe3d3, 0xe3df,
0xe3eb, 0xe3f7, 0xe403, 0xe40f, 0xe41b, 0xe427,
0xe433, 0xe43f, 0xe44a, 0xe456, 0xe462, 0xe46e,
0xe47a, 0xe486, 0xe492, 0xe49e, 0xe4aa, 0xe4b6,
0xe4c1, 0xe4cd, 0xe4d9, 0xe4e5, 0xe4f1, 0xe4fd,
0xe509, 0xe515, 0xe520, 0xe52c, 0xe538, 0xe544,
0xe550, 0xe55c, 0xe567, 0xe573, 0xe57f, 0xe58b,
0xe597, 0xe5a3, 0xe5af, 0xe5ba, 0xe5c6, 0xe5d2,
0xe5de, 0xe5ea, 0xe5f5, 0xe601, 0xe60d, 0xe619,
0xe625, 0xe630, 0xe63c, 0xe648, 0xe654, 0xe660,
0xe66b, 0xe677, 0xe683, 0xe68f, 0xe69a, 0xe6a6,
0xe6b2, 0xe6be, 0xe6ca, 0xe6d5, 0xe6e1, 0xe6ed,
0xe6f9, 0xe704, 0xe710, 0xe71c, 0xe727, 0xe733,
0xe73f, 0xe74b, 0xe756, 0xe762, 0xe76e, 0xe77a,
0xe785, 0xe791, 0xe79d, 0xe7a8, 0xe7b4, 0xe7c0,
0xe7cb, 0xe7d7, 0xe7e3, 0xe7ef, 0xe7fa, 0xe806,
0xe812, 0xe81d, 0xe829, 0xe835, 0xe840, 0xe84c,
0xe858, 0xe863, 0xe86f, 0xe87b, 0xe886, 0xe892,
0xe89e, 0xe8a9, 0xe8b5, 0xe8c0, 0xe8cc, 0xe8d8,
0xe8e3, 0xe8ef, 0xe8fb, 0xe906, 0xe912, 0xe91d,
0xe929, 0xe935, 0xe940, 0xe94c, 0xe958, 0xe963,
0xe96f, 0xe97a, 0xe986, 0xe991, 0xe99d, 0xe9a9,
0xe9b4, 0xe9c0, 0xe9cb, 0xe9d7, 0xe9e3, 0xe9ee,
0xe9fa, 0xea05, 0xea11, 0xea1c, 0xea28, 0xea33,
0xea3f, 0xea4a, 0xea56, 0xea62, 0xea6d, 0xea79,
0xea84, 0xea90, 0xea9b, 0xeaa7, 0xeab2, 0xeabe,
0xeac9, 0xead5, 0xeae0, 0xeaec, 0xeaf7, 0xeb03,
0xeb0e, 0xeb1a, 0xeb25, 0xeb31, 0xeb3c, 0xeb48,
0xeb53, 0xeb5f, 0xeb6a, 0xeb76, 0xeb81, 0xeb8d,
0xeb98, 0xeba3, 0xebaf, 0xebba, 0xebc6, 0xebd1,
0xebdd, 0xebe8, 0xebf4, 0xebff, 0xec0a, 0xec16,
0xec21, 0xec2d, 0xec38, 0xec44, 0xec4f, 0xec5a,
0xec66, 0xec71, 0xec7d, 0xec88, 0xec93, 0xec9f,
0xecaa, 0xecb6, 0xecc1, 0xeccc, 0xecd8, 0xece3,
0xecef, 0xecfa, 0xed05, 0xed11, 0xed1c, 0xed27,
0xed33, 0xed3e, 0xed4a, 0xed55, 0xed60, 0xed6c,
0xed77, 0xed82, 0xed8e, 0xed99, 0xeda4, 0xedb0,
0xedbb, 0xedc6, 0xedd2, 0xeddd, 0xede8, 0xedf4,
0xedff, 0xee0a, 0xee15, 0xee21, 0xee2c, 0xee37,
0xee43, 0xee4e, 0xee59, 0xee65, 0xee70, 0xee7b,
0xee86, 0xee92, 0xee9d, 0xeea8, 0xeeb3, 0xeebf,
0xeeca, 0xeed5, 0xeee1, 0xeeec, 0xeef7, 0xef02,
0xef0e, 0xef19, 0xef24, 0xef2f, 0xef3a, 0xef46,
0xef51, 0xef5c, 0xef67, 0xef73, 0xef7e, 0xef89,
0xef94, 0xef9f, 0xefab, 0xefb6, 0xefc1, 0xefcc,
0xefd7, 0xefe3, 0xefee, 0xeff9, 0xf004, 0xf00f,
0xf01b, 0xf026, 0xf031, 0xf03c, 0xf047, 0xf052,
0xf05e, 0xf069, 0xf074, 0xf07f, 0xf08a, 0xf095,
0xf0a1, 0xf0ac, 0xf0b7, 0xf0c2, 0xf0cd, 0xf0d8,
0xf0e3, 0xf0ef, 0xf0fa, 0xf105, 0xf110, 0xf11b,
0xf126, 0xf131, 0xf13c, 0xf147, 0xf153, 0xf15e,
0xf169, 0xf174, 0xf17f, 0xf18a, 0xf195, 0xf1a0,
0xf1ab, 0xf1b6, 0xf1c2, 0xf1cd, 0xf1d8, 0xf1e3,
0xf1ee, 0xf1f9, 0xf204, 0xf20f, 0xf21a, 0xf225,
0xf230, 0xf23b, 0xf246, 0xf251, 0xf25c, 0xf267,
0xf272, 0xf27d, 0xf288, 0xf293, 0xf29f, 0xf2aa,
0xf2b5, 0xf2c0, 0xf2cb, 0xf2d6, 0xf2e1, 0xf2ec,
0xf2f7, 0xf302, 0xf30d, 0xf318, 0xf323, 0xf32e,
0xf339, 0xf344, 0xf34f, 0xf35a, 0xf364, 0xf36f,
0xf37a, 0xf385, 0xf390, 0xf39b, 0xf3a6, 0xf3b1,
0xf3bc, 0xf3c7, 0xf3d2, 0xf3dd, 0xf3e8, 0xf3f3,
0xf3fe, 0xf409, 0xf414, 0xf41f, 0xf42a, 0xf435,
0xf43f, 0xf44a, 0xf455, 0xf460, 0xf46b, 0xf476,
0xf481, 0xf48c, 0xf497, 0xf4a2, 0xf4ad, 0xf4b7,
0xf4c2, 0xf4cd, 0xf4d8, 0xf4e3, 0xf4ee, 0xf4f9,
0xf504, 0xf50f, 0xf519, 0xf524, 0xf52f, 0xf53a,
0xf545, 0xf550, 0xf55b, 0xf565, 0xf570, 0xf57b,
0xf586, 0xf591, 0xf59c, 0xf5a6, 0xf5b1, 0xf5bc,
0xf5c7, 0xf5d2, 0xf5dd, 0xf5e7, 0xf5f2, 0xf5fd,
0xf608, 0xf613, 0xf61d, 0xf628, 0xf633, 0xf63e,
0xf649, 0xf653, 0xf65e, 0xf669, 0xf674, 0xf67f,
0xf689, 0xf694, 0xf69f, 0xf6aa, 0xf6b4, 0xf6bf,
0xf6ca, 0xf6d5, 0xf6e0, 0xf6ea, 0xf6f5, 0xf700,
0xf70b, 0xf715, 0xf720, 0xf72b, 0xf736, 0xf740,
0xf74b, 0xf756, 0xf760, 0xf76b, 0xf776, 0xf781,
0xf78b, 0xf796, 0xf7a1, 0xf7ab, 0xf7b6, 0xf7c1,
0xf7cc, 0xf7d6, 0xf7e1, 0xf7ec, 0xf7f6, 0xf801,
0xf80c, 0xf816, 0xf821, 0xf82c, 0xf836, 0xf841,
0xf84c, 0xf856, 0xf861, 0xf86c, 0xf876, 0xf881,
0xf88c, 0xf896, 0xf8a1, 0xf8ac, 0xf8b6, 0xf8c1,
0xf8cc, 0xf8d6, 0xf8e1, 0xf8ec, 0xf8f6, 0xf901,
0xf90b, 0xf916, 0xf921, 0xf92b, 0xf936, 0xf941,
0xf94b, 0xf956, 0xf960, 0xf96b, 0xf976, 0xf980,
0xf98b, 0xf995, 0xf9a0, 0xf9aa, 0xf9b5, 0xf9c0,
0xf9ca, 0xf9d5, 0xf9df, 0xf9ea, 0xf9f4, 0xf9ff,
0xfa0a, 0xfa14, 0xfa1f, 0xfa29, 0xfa34, 0xfa3e,
0xfa49, 0xfa53, 0xfa5e, 0xfa69, 0xfa73, 0xfa7e,
0xfa88, 0xfa93, 0xfa9d, 0xfaa8, 0xfab2, 0xfabd,
0xfac7, 0xfad2, 0xfadc, 0xfae7, 0xfaf1, 0xfafc,
0xfb06, 0xfb11, 0xfb1b, 0xfb26, 0xfb30, 0xfb3b,
0xfb45, 0xfb50, 0xfb5a, 0xfb65, 0xfb6f, 0xfb7a,
0xfb84, 0xfb8f, 0xfb99, 0xfba4, 0xfbae, 0xfbb8,
0xfbc3, 0xfbcd, 0xfbd8, 0xfbe2, 0xfbed, 0xfbf7,
0xfc02, 0xfc0c, 0xfc16, 0xfc21, 0xfc2b, 0xfc36,
0xfc40, 0xfc4b, 0xfc55, 0xfc5f, 0xfc6a, 0xfc74,
0xfc7f, 0xfc89, 0xfc93, 0xfc9e, 0xfca8, 0xfcb3,
0xfcbd, 0xfcc7, 0xfcd2, 0xfcdc, 0xfce7, 0xfcf1,
0xfcfb, 0xfd06, 0xfd10, 0xfd1a, 0xfd25, 0xfd2f,
0xfd3a, 0xfd44, 0xfd4e, 0xfd59, 0xfd63, 0xfd6d,
0xfd78, 0xfd82, 0xfd8c, 0xfd97, 0xfda1, 0xfdab,
0xfdb6, 0xfdc0, 0xfdca, 0xfdd5, 0xfddf, 0xfde9,
0xfdf4, 0xfdfe, 0xfe08, 0xfe13, 0xfe1d, 0xfe27,
0xfe32, 0xfe3c, 0xfe46, 0xfe50, 0xfe5b, 0xfe65,
0xfe6f, 0xfe7a, 0xfe84, 0xfe8e, 0xfe98, 0xfea3,
0xfead, 0xfeb7, 0xfec1, 0xfecc, 0xfed6, 0xfee0,
0xfeeb, 0xfef5, 0xfeff, 0xff09, 0xff14, 0xff1e,
0xff28, 0xff32, 0xff3c, 0xff47, 0xff51, 0xff5b,
0xff65, 0xff70, 0xff7a, 0xff84, 0xff8e, 0xff98,
0xffa3, 0xffad, 0xffb7, 0xffc1, 0xffcc, 0xffd6,
0xffe0, 0xffea, 0xfff4, 0xffff
};
// max value is pi/4
constexpr double SCALING_FACTOR = 4. / M_PI * 0xFFFF;
inline double atan2_lookup(double y, double x)
{
if (std::abs(x) < std::numeric_limits<double>::epsilon())
{
if (y >= 0.)
{
return M_PI / 2.;
}
else
{
return -M_PI / 2.;
}
}
unsigned octant = 0;
if (x < 0.)
{
octant = 1;
x = -x;
}
if (y < 0.)
{
octant |= 2;
y = -y;
}
double t = y / x;
if (t > 1.0)
{
octant |= 4;
t = 1.0 / t;
}
double angle = atan_table[(unsigned)(t * 4095)] / SCALING_FACTOR;
switch (octant)
{
case 0:
break;
case 1:
angle = M_PI - angle;
break;
case 2:
angle = -angle;
break;
case 3:
angle = -M_PI + angle;
break;
case 4:
angle = M_PI / 2.0 - angle;
break;
case 5:
angle = M_PI / 2.0 + angle;
break;
case 6:
angle = -M_PI / 2.0 + angle;
break;
case 7:
angle = -M_PI / 2.0 - angle;
break;
}
return angle;
}
#endif // TRIGONOMETRY_TABLES_H
+2 -4
View File
@@ -42,7 +42,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cstdlib> #include <cstdlib>
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@@ -131,9 +130,8 @@ int main(int argc, char *argv[])
if (boost::filesystem::is_regular_file(config_file_path)) if (boost::filesystem::is_regular_file(config_file_path))
{ {
SimpleLogger().Write() << "Reading options from: " << config_file_path.string(); SimpleLogger().Write() << "Reading options from: " << config_file_path.string();
std::string config_str; std::string ini_file_contents = ReadIniFileAndLowerContents(config_file_path);
PrepareConfigFile(config_file_path.c_str(), config_str); std::stringstream config_stream(ini_file_contents);
std::stringstream config_stream(config_str);
boost::program_options::store(parse_config_file(config_stream, config_file_options), boost::program_options::store(parse_config_file(config_stream, config_file_options),
option_variables); option_variables);
boost::program_options::notify(option_variables); boost::program_options::notify(option_variables);
+29 -1
View File
@@ -30,6 +30,34 @@ Feature: Car - Turn restrictions
| s | n | sj,nj | | s | n | sj,nj |
| s | e | sj,ej | | s | e | sj,ej |
@no_turning
Scenario: Car - No straight on
Given the node map
| a | b | j | d | e |
| v | | | | z |
| | w | x | y | |
And the ways
| nodes | oneway |
| ab | no |
| bj | no |
| jd | no |
| de | no |
| av | yes |
| vw | yes |
| wx | yes |
| xy | yes |
| yz | yes |
| ze | yes |
And the relations
| type | way:from | way:to | node:via | restriction |
| restriction | bj | jd | j | no_straight_on |
When I route I should get
| from | to | route |
| a | e | av,vw,wx,xy,yz,ze |
@no_turning @no_turning
Scenario: Car - No right turn Scenario: Car - No right turn
Given the node map Given the node map
@@ -248,4 +276,4 @@ Feature: Car - Turn restrictions
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| s | a | sj,aj | | s | a | sj,aj |
| s | b | sj,bj | | s | b | sj,bj |
+1 -1
View File
@@ -15,5 +15,5 @@ Feature: osrm-routed command line options: invalid options
When I run "osrm-routed over-the-rainbow.osrm" When I run "osrm-routed over-the-rainbow.osrm"
Then stdout should contain "over-the-rainbow.osrm" Then stdout should contain "over-the-rainbow.osrm"
And stderr should contain "exception" And stderr should contain "exception"
And stderr should contain "does not exist" And stderr should contain "not found"
And it should exit with code 1 And it should exit with code 1
+36 -32
View File
@@ -93,10 +93,12 @@ def route_status response
end end
def extract_instruction_list instructions, index, postfix=nil def extract_instruction_list instructions, index, postfix=nil
instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }. if instructions
map { |r| r[index] }. instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }.
map { |r| (r=="" || r==nil) ? '""' : "#{r}#{postfix}" }. map { |r| r[index] }.
join(',') map { |r| (r=="" || r==nil) ? '""' : "#{r}#{postfix}" }.
join(',')
end
end end
def way_list instructions def way_list instructions
@@ -112,33 +114,35 @@ def bearing_list instructions
end end
def turn_list instructions def turn_list instructions
types = { if instructions
0 => :none, types = {
1 => :straight, 0 => :none,
2 => :slight_right, 1 => :straight,
3 => :right, 2 => :slight_right,
4 => :sharp_right, 3 => :right,
5 => :u_turn, 4 => :sharp_right,
6 => :sharp_left, 5 => :u_turn,
7 => :left, 6 => :sharp_left,
8 => :slight_left, 7 => :left,
9 => :via, 8 => :slight_left,
10 => :head, 9 => :via,
11 => :enter_roundabout, 10 => :head,
12 => :leave_roundabout, 11 => :enter_roundabout,
13 => :stay_roundabout, 12 => :leave_roundabout,
14 => :start_end_of_street, 13 => :stay_roundabout,
15 => :destination, 14 => :start_end_of_street,
16 => :enter_contraflow, 15 => :destination,
17 => :leave_contraflow 16 => :enter_contraflow,
} 17 => :leave_contraflow
# replace instructions codes with strings }
# "11-3" (enter roundabout and leave a 3rd exit) gets converted to "enter_roundabout-3" # replace instructions codes with strings
instructions.map do |r| # "11-3" (enter roundabout and leave a 3rd exit) gets converted to "enter_roundabout-3"
r[0].to_s.gsub(/^\d*/) do |match| instructions.map do |r|
types[match.to_i].to_s r[0].to_s.gsub(/^\d*/) do |match|
end types[match.to_i].to_s
end.join(',') end
end.join(',')
end
end end
def mode_list instructions def mode_list instructions
@@ -151,4 +155,4 @@ end
def distance_list instructions def distance_list instructions
extract_instruction_list instructions, 2, "m" extract_instruction_list instructions, 2, "m"
end end
+7 -5
View File
@@ -6,10 +6,11 @@ Feature: Testbot - oneways
Scenario: Routing on a oneway roundabout Scenario: Routing on a oneway roundabout
Given the node map Given the node map
| | d | c | | | x | | | v | | |
| e | | | b | | | | d | c | | |
| f | | | a | | | e | | | b | |
| | g | h | | | | f | | | a | |
| | | g | h | | |
And the ways And the ways
| nodes | oneway | | nodes | oneway |
@@ -21,6 +22,7 @@ Feature: Testbot - oneways
| fg | yes | | fg | yes |
| gh | yes | | gh | yes |
| ha | yes | | ha | yes |
| vx | yes |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
@@ -39,4 +41,4 @@ Feature: Testbot - oneways
| f | e | fg,gh,ha,ab,bc,cd,de | | f | e | fg,gh,ha,ab,bc,cd,de |
| g | f | gh,ha,ab,bc,cd,de,ef | | g | f | gh,ha,ab,bc,cd,de,ef |
| h | g | ha,ab,bc,cd,de,ef,fg | | h | g | ha,ab,bc,cd,de,ef,fg |
| a | h | ab,bc,cd,de,ef,fg,gh | | a | h | ab,bc,cd,de,ef,fg,gh |
+1 -1
View File
@@ -29,7 +29,7 @@ Feature: Projection to nearest point on road
| a | d | abc | NE | 45 | 1000m +-7 | | a | d | abc | NE | 45 | 1000m +-7 |
| d | a | abc | SW | 225 | 1000m +-7 | | d | a | abc | SW | 225 | 1000m +-7 |
| c | d | abc | SW | 225 | 1000m +-7 | | c | d | abc | SW | 225 | 1000m +-7 |
| d | c | abc | NE | 45 +-1 | 1000m +-7 | | d | c | abc | NE | 45 +-2 | 1000m +-7 |
Scenario: Projection onto way at high latitudes, no distance Scenario: Projection onto way at high latitudes, no distance
When I route I should get When I route I should get
+76
View File
@@ -0,0 +1,76 @@
@routing @testbot @roundabout @instruction
Feature: Roundabout Instructions
Background:
Given the profile "testbot"
Scenario: Testbot - Roundabout
Given the node map
| | | v | | |
| | | d | | |
| s | a | | c | u |
| | | b | | |
| | | t | | |
And the ways
| nodes | junction |
| sa | |
| tb | |
| uc | |
| vd | |
| abcda | roundabout |
When I route I should get
| from | to | route | turns |
| s | t | sa,tb | head,enter_roundabout-1,destination |
| s | u | sa,uc | head,enter_roundabout-2,destination |
| s | v | sa,vd | head,enter_roundabout-3,destination |
| t | u | tb,uc | head,enter_roundabout-1,destination |
| t | v | tb,vd | head,enter_roundabout-2,destination |
| t | s | tb,sa | head,enter_roundabout-3,destination |
| u | v | uc,vd | head,enter_roundabout-1,destination |
| u | s | uc,sa | head,enter_roundabout-2,destination |
| u | t | uc,tb | head,enter_roundabout-3,destination |
| v | s | vd,sa | head,enter_roundabout-1,destination |
| v | t | vd,tb | head,enter_roundabout-2,destination |
| v | u | vd,uc | head,enter_roundabout-3,destination |
Scenario: Testbot - Roundabout with oneway links
Given the node map
| | | p | o | | |
| | | h | g | | |
| i | a | | | f | n |
| j | b | | | e | m |
| | | c | d | | |
| | | k | l | | |
And the ways
| nodes | junction | oneway |
| ai | | yes |
| jb | | yes |
| ck | | yes |
| ld | | yes |
| em | | yes |
| nf | | yes |
| go | | yes |
| ph | | yes |
| abcdefgha | roundabout | |
When I route I should get
| from | to | route | turns |
| j | k | jb,ck | head,enter_roundabout-1,destination |
| j | m | jb,em | head,enter_roundabout-2,destination |
| j | o | jb,go | head,enter_roundabout-3,destination |
| j | i | jb,ai | head,enter_roundabout-4,destination |
| l | m | ld,em | head,enter_roundabout-1,destination |
| l | o | ld,go | head,enter_roundabout-2,destination |
| l | i | ld,ai | head,enter_roundabout-3,destination |
| l | k | ld,ck | head,enter_roundabout-4,destination |
| n | o | nf,go | head,enter_roundabout-1,destination |
| n | i | nf,ai | head,enter_roundabout-2,destination |
| n | k | nf,ck | head,enter_roundabout-3,destination |
| n | m | nf,em | head,enter_roundabout-4,destination |
| p | i | ph,ai | head,enter_roundabout-1,destination |
| p | k | ph,ck | head,enter_roundabout-2,destination |
| p | m | ph,em | head,enter_roundabout-3,destination |
| p | o | ph,go | head,enter_roundabout-4,destination |
+2 -2
View File
@@ -27,7 +27,7 @@ Feature: Status messages
| nodes | | nodes |
| ab | | ab |
| cd | | cd |
When I route I should get When I route I should get
| from | to | route | status | message | | from | to | route | status | message |
| a | b | ab | 0 | Found route between points | | a | b | ab | 0 | Found route between points |
@@ -64,4 +64,4 @@ Feature: Status messages
| viaroute/loc=1,1&loc=1,1 | 400 | Query string malformed close to position 9 | | viaroute/loc=1,1&loc=1,1 | 400 | Query string malformed close to position 9 |
| viaroute/loc=1,1&loc=1,1,1 | 400 | Query string malformed close to position 9 | | viaroute/loc=1,1&loc=1,1,1 | 400 | Query string malformed close to position 9 |
| viaroute/loc=1,1&loc=x | 400 | Query string malformed close to position 9 | | viaroute/loc=1,1&loc=x | 400 | Query string malformed close to position 9 |
| viaroute/loc=1,1&loc=x,y | 400 | Query string malformed close to position 9 | | viaroute/loc=1,1&loc=x,y | 400 | Query string malformed close to position 9 |
+12 -5
View File
@@ -252,6 +252,8 @@ int main(int argc, char *argv[])
speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function"); speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
static_assert(sizeof(ImportEdge) == 20,
"changing ImportEdge type has influence on memory consumption!");
std::vector<ImportEdge> edge_list; std::vector<ImportEdge> edge_list;
NodeID number_of_node_based_nodes = NodeID number_of_node_based_nodes =
readBinaryOSRMGraphFromStream(in, readBinaryOSRMGraphFromStream(in,
@@ -303,6 +305,9 @@ int main(int argc, char *argv[])
unsigned number_of_edge_based_nodes = edge_based_graph_factor->GetNumberOfEdgeBasedNodes(); unsigned number_of_edge_based_nodes = edge_based_graph_factor->GetNumberOfEdgeBasedNodes();
BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList; DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
static_assert(sizeof(EdgeBasedEdge) == 16,
"changing ImportEdge type has influence on memory consumption!");
edge_based_graph_factor->GetEdgeBasedEdges(edgeBasedEdgeList); edge_based_graph_factor->GetEdgeBasedEdges(edgeBasedEdgeList);
std::vector<EdgeBasedNode> node_based_edge_list; std::vector<EdgeBasedNode> node_based_edge_list;
edge_based_graph_factor->GetEdgeBasedNodes(node_based_edge_list); edge_based_graph_factor->GetEdgeBasedNodes(node_based_edge_list);
@@ -392,24 +397,24 @@ int main(int argc, char *argv[])
SimpleLogger().Write() << "Building node array"; SimpleLogger().Write() << "Building node array";
StaticGraph<EdgeData>::EdgeIterator edge = 0; StaticGraph<EdgeData>::EdgeIterator edge = 0;
StaticGraph<EdgeData>::EdgeIterator position = 0; StaticGraph<EdgeData>::EdgeIterator position = 0;
StaticGraph<EdgeData>::EdgeIterator lastEdge = edge; StaticGraph<EdgeData>::EdgeIterator last_edge = edge;
for (StaticGraph<EdgeData>::NodeIterator node = 0; node < max_used_node_id; ++node) for (StaticGraph<EdgeData>::NodeIterator node = 0; node < max_used_node_id; ++node)
{ {
lastEdge = edge; last_edge = edge;
while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node)) while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
{ {
++edge; ++edge;
} }
node_array[node].firstEdge = position; //=edge node_array[node].first_edge = position; //=edge
position += edge - lastEdge; // remove position += edge - last_edge; // remove
} }
for (unsigned sentinel_counter = max_used_node_id; sentinel_counter != node_array.size(); for (unsigned sentinel_counter = max_used_node_id; sentinel_counter != node_array.size();
++sentinel_counter) ++sentinel_counter)
{ {
// sentinel element, guarded against underflow // sentinel element, guarded against underflow
node_array[sentinel_counter].firstEdge = contracted_edge_count; node_array[sentinel_counter].first_edge = contracted_edge_count;
} }
unsigned node_array_size = node_array.size(); unsigned node_array_size = node_array.size();
@@ -438,6 +443,7 @@ int main(int argc, char *argv[])
// every target needs to be valid // every target needs to be valid
BOOST_ASSERT(current_edge.target < max_used_node_id); BOOST_ASSERT(current_edge.target < max_used_node_id);
#ifndef NDEBUG
if (current_edge.data.distance <= 0) if (current_edge.data.distance <= 0)
{ {
SimpleLogger().Write(logWARNING) SimpleLogger().Write(logWARNING)
@@ -450,6 +456,7 @@ int main(int argc, char *argv[])
<< node_array.size() - 1; << node_array.size() - 1;
return 1; return 1;
} }
#endif
hsgr_output_stream.write((char *)&current_edge, hsgr_output_stream.write((char *)&current_edge,
sizeof(StaticGraph<EdgeData>::EdgeArrayEntry)); sizeof(StaticGraph<EdgeData>::EdgeArrayEntry));
++number_of_used_edges; ++number_of_used_edges;
+6 -1
View File
@@ -55,6 +55,7 @@ function way_function (way)
local maxspeed = tonumber(way.tags:Find ( "maxspeed")) local maxspeed = tonumber(way.tags:Find ( "maxspeed"))
local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward")) local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward"))
local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward")) local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward"))
local junction = way.tags:Find("junction")
way.name = name way.name = name
@@ -96,12 +97,16 @@ function way_function (way)
way.direction = Way.bidirectional way.direction = Way.bidirectional
elseif oneway == "-1" then elseif oneway == "-1" then
way.direction = Way.opposite way.direction = Way.opposite
elseif oneway == "yes" or oneway == "1" or oneway == "true" then elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then
way.direction = Way.oneway way.direction = Way.oneway
else else
way.direction = Way.bidirectional way.direction = Way.bidirectional
end end
if junction == 'roundabout' then
way.roundabout = true
end
way.type = 1 way.type = 1
return 1 return 1
end end
+15 -3
View File
@@ -36,12 +36,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
#include <boost/thread.hpp> // for timed join. #include <cstdlib>
#include <signal.h> #include <signal.h>
#include <chrono>
#include <functional> #include <functional>
#include <future>
#include <iostream> #include <iostream>
#include <thread>
#ifdef _WIN32 #ifdef _WIN32
boost::function0<void> console_ctrl_function; boost::function0<void> console_ctrl_function;
@@ -139,7 +142,9 @@ int main(int argc, const char *argv[])
} }
else else
{ {
boost::thread server_thread(std::bind(&Server::Run, routing_server)); std::packaged_task<void()> server_task(std::bind(&Server::Run, routing_server));
auto future = server_task.get_future();
std::thread server_thread(std::move(server_task));
#ifndef _WIN32 #ifndef _WIN32
sigset_t wait_mask; sigset_t wait_mask;
@@ -162,9 +167,16 @@ int main(int argc, const char *argv[])
routing_server->Stop(); routing_server->Stop();
SimpleLogger().Write() << "stopping threads"; SimpleLogger().Write() << "stopping threads";
if (!server_thread.timed_join(boost::posix_time::seconds(2))) auto status = future.wait_for(std::chrono::seconds(2));
if (status != std::future_status::ready)
{ {
SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!"; SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
server_task.reset(); // just kill it
}
else
{
server_thread.join();
} }
} }