Merge pull request #1030 from DennisOSRM/features/json-generator

Distance tables and JSON generator
This commit is contained in:
Dennis Luxen 2014-05-21 14:10:03 +02:00
commit 2822382797
58 changed files with 3159 additions and 2512 deletions

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

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

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_ */

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:
@ -339,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";

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;
@ -722,7 +728,7 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u,
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;

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

View File

@ -117,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; }
@ -135,7 +148,7 @@ 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 NodeID node) const EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
{ {
return boost::irange(BeginEdges(node), EndEdges(node)); return boost::irange(BeginEdges(node), EndEdges(node));
} }

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

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;

View File

@ -1,6 +1,40 @@
/*
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)
@ -9,8 +43,12 @@ RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &gra
// and all end-nodes // and all end-nodes
for (auto &restriction : input_restrictions_list) for (auto &restriction : input_restrictions_list)
{ {
m_no_turn_via_node_set.insert(restriction.viaNode);
std::pair<NodeID, NodeID> restriction_source = std::pair<NodeID, NodeID> restriction_source =
std::make_pair(restriction.fromNode, restriction.viaNode); std::make_pair(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())
@ -70,7 +108,9 @@ void RestrictionMap::FixupArrivingTurnRestriction(const NodeID u, const NodeID v
const std::pair<NodeID, NodeID> restr_start = std::make_pair(x, u); const std::pair<NodeID, NodeID> restr_start = std::make_pair(x, u);
auto restriction_iterator = m_restriction_map.find(restr_start); 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);
@ -141,6 +181,7 @@ NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID
*/ */
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
{ {
// SimpleLogger().Write(logDEBUG) << "checking turn <" << u << "," << v << "," << w << ">";
BOOST_ASSERT(u != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(u != std::numeric_limits<unsigned>::max());
BOOST_ASSERT(v != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(v != std::numeric_limits<unsigned>::max());
BOOST_ASSERT(w != std::numeric_limits<unsigned>::max()); BOOST_ASSERT(w != std::numeric_limits<unsigned>::max());
@ -162,6 +203,5 @@ bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID u, const NodeID v, con
} }
} }
} }
return false; return false;
} }

View File

@ -30,17 +30,18 @@ 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>
/*!
* Makee it efficent to look up if an edge is the start + via node of a TurnRestriction. // Make it efficent to look up if an edge is the start + via node of a TurnRestriction
* Is needed by EdgeBasedGraphFactory. // EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
*/
class RestrictionMap class RestrictionMap
{ {
public: public:
@ -51,7 +52,7 @@ 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:
@ -65,7 +66,8 @@ 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_no_turn_via_node_set;
}; };
#endif #endif

View File

@ -30,6 +30,7 @@ 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"
template <class DataFacadeT> class SearchEngine template <class DataFacadeT> class SearchEngine
@ -41,10 +42,11 @@ 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)
{ {
} }

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

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

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

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

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

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

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_ */

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

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

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)

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

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

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

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

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:

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

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:

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> descriptor_table; {
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)
{
descriptor_table.emplace("json", 0); search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
descriptor_table.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 &route_parameters, http::Reply &reply)
{ const std::string GetDescriptor() const { return descriptor_string; }
// check number of parameters
if (2 > route_parameters.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(route_parameters.coordinates), reply = http::Reply::StockReply(http::Reply::badRequest);
end(route_parameters.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 : 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);
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 = (route_parameters.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 < route_parameters.hints.size() && DecodeObjectFromBase64(route_parameters.hints[i], phantom_node_vector[i]);
!route_parameters.hints[i].empty()) if (phantom_node_vector[i].isValid(facade->GetNumberOfNodes()))
{ {
DecodeObjectFromBase64(route_parameters.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],
route_parameters.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 ((route_parameters.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 (!route_parameters.jsonp_parameter.empty()) reply.status = http::Reply::ok;
{
reply.content.emplace_back(route_parameters.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 = descriptor_table.find(route_parameters.output_format); descriptor_config.instructions = route_parameters.print_instructions;
unsigned descriptor_type = (iter != descriptor_table.end() ? iter->second : 0); descriptor_config.geometry = route_parameters.geometry;
descriptor_config.encode_geometry = route_parameters.compression;
descriptor_config.zoom_level = route_parameters.zoom_level;
descriptor_config.instructions = route_parameters.print_instructions; std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
descriptor_config.geometry = route_parameters.geometry; switch (descriptor_type)
descriptor_config.encode_geometry = route_parameters.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 (!route_parameters.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 (!route_parameters.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 (!route_parameters.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_ */

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

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

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;

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)];

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

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

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

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";

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

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

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

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;

View File

@ -140,13 +140,8 @@ inline void AssertPathExists(const boost::filesystem::path &path)
{ {
if (!boost::filesystem::is_regular_file(path)) if (!boost::filesystem::is_regular_file(path))
{ {
SimpleLogger().Write(logDEBUG) << path << " check failed";
throw OSRMException(path.string() + " not found."); throw OSRMException(path.string() + " not found.");
} }
else
{
SimpleLogger().Write(logDEBUG) << path << " exists";
}
} }
#endif /* BOOST_FILE_SYSTEM_FIX_H */ #endif /* BOOST_FILE_SYSTEM_FIX_H */

View File

@ -28,767 +28,13 @@ 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>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <cmath> #include <cmath>
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;
}
/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/ /* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
template <class CoordinateT> template <class CoordinateT>
inline static double GetAngleBetweenThreeFixedPointCoordinates(const CoordinateT &A, inline static double GetAngleBetweenThreeFixedPointCoordinates(const CoordinateT &A,

View File

@ -28,8 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef INI_FILE_UTIL_H #ifndef INI_FILE_UTIL_H
#define INI_FILE_UTIL_H #define INI_FILE_UTIL_H
#include "SimpleLogger.h"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
#include <boost/regex.hpp>
#include <regex> #include <regex>
#include <string> #include <string>
@ -38,11 +41,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inline std::string ReadIniFileAndLowerContents(const boost::filesystem::path &path) inline std::string ReadIniFileAndLowerContents(const boost::filesystem::path &path)
{ {
boost::filesystem::fstream config_stream(path); boost::filesystem::fstream config_stream(path);
std::string input_str((std::istreambuf_iterator<char>(config_stream)), std::string ini_file_content((std::istreambuf_iterator<char>(config_stream)),
std::istreambuf_iterator<char>()); std::istreambuf_iterator<char>());
std::regex regex("^([^=]*)"); // match from start of line to '=' boost::regex regex( "^([^=]*)" ); //match from start of line to '='
std::string format("\\L$1\\E"); // replace with downcased substring std::string format( "\\L$1\\E" ); //replace with downcased substring
return std::regex_replace(input_str, regex, format); return boost::regex_replace( ini_file_content, regex, format );
} }
#endif // INI_FILE_UTIL_H #endif // INI_FILE_UTIL_H

View File

@ -28,16 +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>
inline double y2lat(const double a) inline float y2lat(const float 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 * log(tan(M_PI / 4.f + a * (M_PI / 180.f) / 2.f));
} }
#endif // MERCATOR_UTIL_H #endif // MERCATOR_UTIL_H

View File

@ -159,6 +159,7 @@ inline unsigned GenerateServerProgramOptions(const int argc,
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
Util/StdHashExtensions.h Normal file
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

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
Util/TrigonometryTables.h Normal file
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

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 |

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

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

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 |

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

View File

@ -35,7 +35,6 @@ Feature: Roundabout Instructions
| v | t | vd,tb | head,enter_roundabout-2,destination | | v | t | vd,tb | head,enter_roundabout-2,destination |
| v | u | vd,uc | head,enter_roundabout-3,destination | | v | u | vd,uc | head,enter_roundabout-3,destination |
@bug
Scenario: Testbot - Roundabout with oneway links Scenario: Testbot - Roundabout with oneway links
Given the node map Given the node map
| | | p | o | | | | | | p | o | | |
@ -74,4 +73,4 @@ Feature: Roundabout Instructions
| p | i | ph,ai | head,enter_roundabout-1,destination | | p | i | ph,ai | head,enter_roundabout-1,destination |
| p | k | ph,ck | head,enter_roundabout-2,destination | | p | k | ph,ck | head,enter_roundabout-2,destination |
| p | m | ph,em | head,enter_roundabout-3,destination | | p | m | ph,em | head,enter_roundabout-3,destination |
| p | o | ph,go | head,enter_roundabout-4,destination | | p | o | ph,go | head,enter_roundabout-4,destination |

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 |

View File

@ -438,6 +438,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 +451,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;