implements output generation through a dedicated JSON container:
- JSON syntax is not scattered over several files, but one place - Reduces code duplication - breaking changes: - new property in json(p) formatted response: "found_alternative": True/False - returned filenames now response.js(on) or route.gpx - /hello plugin returns JSON now
This commit is contained in:
parent
acab77f4f8
commit
a80815d57a
@ -26,6 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "PolylineCompressor.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output)
|
||||
const
|
||||
@ -39,9 +40,9 @@ void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std
|
||||
numbers[i] = ~(numbers[i]);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < end; ++i)
|
||||
for (const int number: numbers)
|
||||
{
|
||||
encodeNumber(numbers[i], output);
|
||||
encodeNumber(number, output);
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,37 +67,36 @@ void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output)
|
||||
}
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const
|
||||
JSON::String PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline) const
|
||||
{
|
||||
std::string output;
|
||||
std::vector<int> delta_numbers;
|
||||
output += "\"";
|
||||
if (!polyline.empty())
|
||||
{
|
||||
FixedPointCoordinate last_coordinate = polyline[0].location;
|
||||
delta_numbers.emplace_back(last_coordinate.lat);
|
||||
delta_numbers.emplace_back(last_coordinate.lon);
|
||||
for (unsigned i = 1; i < polyline.size(); ++i)
|
||||
for (const auto & segment : polyline)
|
||||
{
|
||||
if (polyline[i].necessary)
|
||||
if (segment.necessary)
|
||||
{
|
||||
int lat_diff = polyline[i].location.lat - last_coordinate.lat;
|
||||
int lon_diff = polyline[i].location.lon - last_coordinate.lon;
|
||||
int lat_diff = segment.location.lat - last_coordinate.lat;
|
||||
int lon_diff = segment.location.lon - last_coordinate.lon;
|
||||
delta_numbers.emplace_back(lat_diff);
|
||||
delta_numbers.emplace_back(lon_diff);
|
||||
last_coordinate = polyline[i].location;
|
||||
last_coordinate = segment.location;
|
||||
}
|
||||
}
|
||||
encodeVectorSignedNumber(delta_numbers, output);
|
||||
}
|
||||
output += "\"";
|
||||
JSON::String return_value(output);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const
|
||||
JSON::String PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordinate> &polyline) const
|
||||
{
|
||||
std::string output;
|
||||
std::vector<int> delta_numbers(2 * polyline.size());
|
||||
output += "\"";
|
||||
if (!polyline.empty())
|
||||
{
|
||||
delta_numbers[0] = polyline[0].lat;
|
||||
@ -110,53 +110,40 @@ void PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordina
|
||||
}
|
||||
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 += "[";
|
||||
std::string tmp;
|
||||
for (unsigned i = 0; i < polyline.size(); i++)
|
||||
JSON::Array json_geometry_array;
|
||||
for( const auto & coordinate : polyline)
|
||||
{
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lat, tmp);
|
||||
output += "[";
|
||||
std::string tmp, output;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
|
||||
output += (tmp + ",");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
|
||||
output += tmp;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if (i < polyline.size() - 1)
|
||||
{
|
||||
output += ",";
|
||||
}
|
||||
json_geometry_array.values.push_back(output);
|
||||
}
|
||||
output += "]";
|
||||
return json_geometry_array;
|
||||
}
|
||||
|
||||
void PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const
|
||||
JSON::Array PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
|
||||
{
|
||||
output += "[";
|
||||
std::string tmp;
|
||||
for (unsigned i = 0; i < polyline.size(); i++)
|
||||
JSON::Array json_geometry_array;
|
||||
for( const auto & segment : polyline)
|
||||
{
|
||||
if (!polyline[i].necessary)
|
||||
if (segment.necessary)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lat, tmp);
|
||||
output += "[";
|
||||
output += tmp;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lon, tmp);
|
||||
output += ", ";
|
||||
output += tmp;
|
||||
output += "]";
|
||||
if (i < polyline.size() - 1)
|
||||
{
|
||||
output += ",";
|
||||
std::string tmp, output;
|
||||
FixedPointCoordinate::convertInternalLatLonToString(segment.location.lat, tmp);
|
||||
output += (tmp + ",");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(segment.location.lon, tmp);
|
||||
output += tmp;
|
||||
json_geometry_array.values.push_back(output);
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
return json_geometry_array;
|
||||
}
|
||||
|
@ -28,8 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef POLYLINECOMPRESSOR_H_
|
||||
#define POLYLINECOMPRESSOR_H_
|
||||
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -42,17 +42,13 @@ class PolylineCompressor
|
||||
void encodeNumber(int number_to_encode, std::string &output) const;
|
||||
|
||||
public:
|
||||
void printEncodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const;
|
||||
JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
|
||||
void printEncodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const;
|
||||
JSON::String printEncodedString(const std::vector<FixedPointCoordinate> &polyline) const;
|
||||
|
||||
void printUnencodedString(const std::vector<FixedPointCoordinate> &polyline,
|
||||
std::string &output) const;
|
||||
JSON::Array printUnencodedString(const std::vector<FixedPointCoordinate> &polyline) const;
|
||||
|
||||
void printUnencodedString(const std::vector<SegmentInformation> &polyline,
|
||||
std::string &output) const;
|
||||
JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
};
|
||||
|
||||
#endif /* POLYLINECOMPRESSOR_H_ */
|
||||
|
237
DataStructures/JSONContainer.h
Normal file
237
DataStructures/JSONContainer.h
Normal 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
|
@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "SearchEngineData.h"
|
||||
#include "../RoutingAlgorithms/AlternativePathRouting.h"
|
||||
#include "../RoutingAlgorithms/ManyToManyRouting.h"
|
||||
#include "../RoutingAlgorithms/ShortestPathRouting.h"
|
||||
|
||||
template <class DataFacadeT> class SearchEngine
|
||||
@ -41,10 +42,11 @@ template <class DataFacadeT> class SearchEngine
|
||||
public:
|
||||
ShortestPathRouting<DataFacadeT> shortest_path;
|
||||
AlternativeRouting<DataFacadeT> alternative_path;
|
||||
ManyToManyRouting<DataFacadeT> distance_table;
|
||||
|
||||
explicit SearchEngine(DataFacadeT *facade)
|
||||
: facade(facade), shortest_path(facade, engine_working_data),
|
||||
alternative_path(facade, engine_working_data)
|
||||
alternative_path(facade, engine_working_data), distance_table(facade, engine_working_data)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ struct DescriptorConfig
|
||||
template <class DataFacadeT> class BaseDescriptor
|
||||
{
|
||||
public:
|
||||
BaseDescriptor() {}
|
||||
BaseDescriptor() {} //TODO: initialize facade here.
|
||||
// Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BaseDescriptor() {}
|
||||
virtual void Run(const RawRouteData &raw_route,
|
||||
|
@ -94,38 +94,23 @@ void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded,
|
||||
std::vector<std::string> &output)
|
||||
JSON::Value DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded)
|
||||
{
|
||||
std::string temp;
|
||||
if (return_encoded)
|
||||
{
|
||||
polyline_compressor.printEncodedString(path_description, temp);
|
||||
return polyline_compressor.printEncodedString(path_description);
|
||||
}
|
||||
else
|
||||
{
|
||||
polyline_compressor.printUnencodedString(path_description, temp);
|
||||
}
|
||||
output.emplace_back(temp);
|
||||
return polyline_compressor.printUnencodedString(path_description);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendEncodedPolylineString(std::vector<std::string> &output) const
|
||||
JSON::Value DescriptionFactory::AppendUnencodedPolylineString() const
|
||||
{
|
||||
std::string temp;
|
||||
polyline_compressor.printEncodedString(path_description, temp);
|
||||
output.emplace_back(temp);
|
||||
}
|
||||
|
||||
void DescriptionFactory::AppendUnencodedPolylineString(std::vector<std::string> &output) const
|
||||
{
|
||||
std::string temp;
|
||||
polyline_compressor.printUnencodedString(path_description, temp);
|
||||
output.emplace_back(temp);
|
||||
return polyline_compressor.printUnencodedString(path_description);
|
||||
}
|
||||
|
||||
void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
|
||||
{
|
||||
summary.startName = start_phantom.name_id;
|
||||
summary.destName = target_phantom.name_id;
|
||||
summary.source_name_id = start_phantom.name_id;
|
||||
summary.target_name_id = target_phantom.name_id;
|
||||
summary.BuildDurationAndLengthStrings(distance, time);
|
||||
}
|
||||
|
@ -57,18 +57,17 @@ class DescriptionFactory
|
||||
public:
|
||||
struct RouteSummary
|
||||
{
|
||||
std::string lengthString;
|
||||
std::string durationString;
|
||||
unsigned startName;
|
||||
unsigned destName;
|
||||
RouteSummary() : lengthString("0"), durationString("0"), startName(0), destName(0) {}
|
||||
unsigned distance;
|
||||
EdgeWeight duration;
|
||||
unsigned source_name_id;
|
||||
unsigned target_name_id;
|
||||
RouteSummary() : distance(0), duration(0), source_name_id(0), target_name_id(0) {}
|
||||
|
||||
void BuildDurationAndLengthStrings(const double distance, const unsigned time)
|
||||
void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
|
||||
{
|
||||
// compute distance/duration for route summary
|
||||
intToString(round(distance), lengthString);
|
||||
int travel_time = round(time / 10.);
|
||||
intToString(std::max(travel_time, 1), durationString);
|
||||
distance = round(raw_distance);
|
||||
duration = round(raw_duration / 10.);
|
||||
}
|
||||
} summary;
|
||||
|
||||
@ -79,13 +78,12 @@ class DescriptionFactory
|
||||
DescriptionFactory();
|
||||
virtual ~DescriptionFactory();
|
||||
double GetBearing(const FixedPointCoordinate &C, const FixedPointCoordinate &B) const;
|
||||
void AppendEncodedPolylineString(std::vector<std::string> &output) const;
|
||||
void AppendUnencodedPolylineString(std::vector<std::string> &output) const;
|
||||
JSON::Value AppendUnencodedPolylineString() const;
|
||||
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
|
||||
void BuildRouteSummary(const double distance, const unsigned time);
|
||||
void SetStartSegment(const PhantomNode &start_phantom);
|
||||
void SetEndSegment(const PhantomNode &start_phantom);
|
||||
void AppendEncodedPolylineString(const bool return_encoded, std::vector<std::string> &output);
|
||||
JSON::Value AppendEncodedPolylineString(const bool return_encoded);
|
||||
|
||||
template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel)
|
||||
{
|
||||
@ -198,7 +196,7 @@ class DescriptionFactory
|
||||
{
|
||||
if (path_description[i].necessary)
|
||||
{
|
||||
double angle =
|
||||
const double angle =
|
||||
GetBearing(path_description[i].location, path_description[i + 1].location);
|
||||
path_description[i].bearing = angle * 10;
|
||||
}
|
||||
|
@ -36,7 +36,24 @@ template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFac
|
||||
DescriptorConfig config;
|
||||
FixedPointCoordinate current;
|
||||
|
||||
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:
|
||||
void SetConfig(const DescriptorConfig &c) { config = c; }
|
||||
@ -47,51 +64,37 @@ template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFac
|
||||
DataFacadeT *facade,
|
||||
http::Reply &reply)
|
||||
{
|
||||
reply.content.emplace_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content.emplace_back("<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
|
||||
"xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
||||
"\">");
|
||||
reply.content.emplace_back("<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
|
||||
" OpenStreetMap contributors (ODbL)</license></copyright>"
|
||||
"</metadata>");
|
||||
reply.content.emplace_back("<rte>");
|
||||
bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
|
||||
(!raw_route.unpacked_path_segments.front().empty());
|
||||
std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
|
||||
"xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
||||
"\">"
|
||||
"<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
|
||||
" OpenStreetMap contributors (ODbL)</license></copyright>"
|
||||
"</metadata>"
|
||||
"<rte>");
|
||||
reply.content.insert(reply.content.end(), header.begin(), header.end());
|
||||
const bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
|
||||
(!raw_route.unpacked_path_segments.front().empty());
|
||||
if (found_route)
|
||||
{
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.source_phantom.location.lat, tmp);
|
||||
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.source_phantom.location.lon, tmp);
|
||||
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
|
||||
AddRoutePoint(phantom_node_list.source_phantom.location, reply.content);
|
||||
|
||||
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
|
||||
{
|
||||
for (const PathData &path_data : path_data_vector)
|
||||
{
|
||||
FixedPointCoordinate current_coordinate =
|
||||
const FixedPointCoordinate current_coordinate =
|
||||
facade->GetCoordinateOfNode(path_data.node);
|
||||
|
||||
FixedPointCoordinate::convertInternalLatLonToString(current_coordinate.lat,
|
||||
tmp);
|
||||
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(current_coordinate.lon,
|
||||
tmp);
|
||||
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
|
||||
AddRoutePoint(current_coordinate, reply.content);
|
||||
}
|
||||
}
|
||||
// Add the via point or the end coordinate
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.target_phantom.location.lat, tmp);
|
||||
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(
|
||||
phantom_node_list.target_phantom.location.lon, tmp);
|
||||
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
|
||||
AddRoutePoint(phantom_node_list.target_phantom.location, reply.content);
|
||||
|
||||
}
|
||||
reply.content.emplace_back("</rte></gpx>");
|
||||
std::string footer("</rte></gpx>");
|
||||
reply.content.insert(reply.content.end(), footer.begin(), footer.end());
|
||||
}
|
||||
};
|
||||
#endif // GPX_DESCRIPTOR_H
|
||||
|
@ -31,10 +31,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "BaseDescriptor.h"
|
||||
#include "DescriptionFactory.h"
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../DataStructures/SegmentInformation.h"
|
||||
#include "../DataStructures/TurnInstructions.h"
|
||||
#include "../Util/Azimuth.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -45,7 +47,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
|
||||
DataFacadeT *facade;
|
||||
DescriptorConfig config;
|
||||
DescriptionFactory description_factory;
|
||||
DescriptionFactory alternate_descriptionFactory;
|
||||
DescriptionFactory alternate_description_factory;
|
||||
FixedPointCoordinate current;
|
||||
unsigned entered_restricted_area_count;
|
||||
struct RoundAbout
|
||||
@ -106,14 +108,15 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
|
||||
DataFacadeT *f,
|
||||
http::Reply &reply)
|
||||
{
|
||||
JSON::Object json_result;
|
||||
facade = f;
|
||||
reply.content.emplace_back("{\"status\":");
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
// We do not need to do much, if there is no route ;-)
|
||||
reply.content.emplace_back(
|
||||
"207,\"status_message\": \"Cannot find route between points\"}");
|
||||
json_result.values["status"] = 207;
|
||||
json_result.values["status_message"] = "Cannot find route between points";
|
||||
JSON::render(reply.content, json_result);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -127,8 +130,8 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
|
||||
raw_route.segment_end_coordinates.size());
|
||||
|
||||
description_factory.SetStartSegment(phantom_nodes.source_phantom);
|
||||
reply.content.emplace_back("0,"
|
||||
"\"status_message\": \"Found route between points\",");
|
||||
json_result.values["status"] = 0;
|
||||
json_result.values["status_message"] = "Found route between points";
|
||||
|
||||
// for each unpacked segment add the leg to the description
|
||||
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
|
||||
@ -141,200 +144,151 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
|
||||
description_factory.SetEndSegment(phantom_nodes.target_phantom);
|
||||
description_factory.Run(facade, config.zoom_level);
|
||||
|
||||
reply.content.emplace_back("\"route_geometry\": ");
|
||||
if (config.geometry)
|
||||
{
|
||||
description_factory.AppendEncodedPolylineString(config.encode_geometry, reply.content);
|
||||
JSON::Value route_geometry = description_factory.AppendEncodedPolylineString(config.encode_geometry);
|
||||
json_result.values["route_geometry"] = route_geometry;
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.content.emplace_back("[]");
|
||||
}
|
||||
|
||||
reply.content.emplace_back(",\"route_instructions\": [");
|
||||
if (config.instructions)
|
||||
{
|
||||
JSON::Array json_route_instructions;
|
||||
BuildTextualDescription(description_factory,
|
||||
reply,
|
||||
json_route_instructions,
|
||||
raw_route.shortest_path_length,
|
||||
facade,
|
||||
shortest_path_segments);
|
||||
json_result.values["route_instructions"] = json_route_instructions;
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
description_factory.BuildRouteSummary(description_factory.entireLength,
|
||||
raw_route.shortest_path_length);
|
||||
JSON::Object json_route_summary;
|
||||
json_route_summary.values["total_distance"] = description_factory.summary.distance;
|
||||
json_route_summary.values["total_time"] = description_factory.summary.duration;
|
||||
json_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(description_factory.summary.source_name_id);
|
||||
json_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(description_factory.summary.target_name_id);
|
||||
json_result.values["route_summary"] = json_route_summary;
|
||||
|
||||
reply.content.emplace_back("\"route_summary\":");
|
||||
reply.content.emplace_back("{");
|
||||
reply.content.emplace_back("\"total_distance\":");
|
||||
reply.content.emplace_back(description_factory.summary.lengthString);
|
||||
reply.content.emplace_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.emplace_back(description_factory.summary.durationString);
|
||||
reply.content.emplace_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.startName));
|
||||
reply.content.emplace_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.destName));
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back("}");
|
||||
reply.content.emplace_back(",");
|
||||
// Get Names for both routes
|
||||
RouteNames route_names;
|
||||
JSON::Array json_route_names;
|
||||
GetRouteNames(shortest_path_segments, alternative_path_segments, facade, route_names);
|
||||
json_route_names.values.push_back(route_names.shortest_path_name_1);
|
||||
json_route_names.values.push_back(route_names.shortest_path_name_2);
|
||||
json_result.values["route_name"] = json_route_names;
|
||||
|
||||
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
|
||||
|
||||
JSON::Array json_via_points_array;
|
||||
JSON::Array json_first_coordinate;
|
||||
json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lat/COORDINATE_PRECISION);
|
||||
json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lon/COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_first_coordinate);
|
||||
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
|
||||
{
|
||||
std::string tmp;
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(nodes.target_phantom.location.lat/COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(nodes.target_phantom.location.lon/COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_coordinate);
|
||||
}
|
||||
json_result.values["via_points"] = json_via_points_array;
|
||||
|
||||
JSON::Array json_via_indices_array;
|
||||
json_via_indices_array.values.insert(json_via_indices_array.values.end(), shortest_leg_end_indices.begin(), shortest_leg_end_indices.end());
|
||||
json_result.values["via_indices"] = json_via_indices_array;
|
||||
|
||||
// only one alternative route is computed at this time, so this is hardcoded
|
||||
if (raw_route.alternative_path_length != INVALID_EDGE_WEIGHT)
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
alternate_descriptionFactory.SetStartSegment(phantom_nodes.source_phantom);
|
||||
json_result.values["found_alternative"] = JSON::True();
|
||||
alternate_description_factory.SetStartSegment(phantom_nodes.source_phantom);
|
||||
// Get all the coordinates for the computed route
|
||||
for (const PathData &path_data : raw_route.unpacked_alternative)
|
||||
{
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
alternate_descriptionFactory.AppendSegment(current, path_data);
|
||||
alternate_description_factory.AppendSegment(current, path_data);
|
||||
}
|
||||
}
|
||||
alternate_descriptionFactory.Run(facade, config.zoom_level);
|
||||
alternate_description_factory.Run(facade, config.zoom_level);
|
||||
|
||||
// //give an array of alternative routes
|
||||
reply.content.emplace_back("\"alternative_geometries\": [");
|
||||
if (config.geometry && INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
// Generate the linestrings for each alternative
|
||||
alternate_descriptionFactory.AppendEncodedPolylineString(config.encode_geometry,
|
||||
reply.content);
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"alternative_instructions\":[");
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
reply.content.emplace_back("[");
|
||||
// Generate instructions for each alternative
|
||||
if (config.geometry)
|
||||
{
|
||||
JSON::Value alternate_geometry_string = alternate_description_factory.AppendEncodedPolylineString(config.encode_geometry);
|
||||
JSON::Array json_alternate_geometries_array;
|
||||
json_alternate_geometries_array.values.push_back(alternate_geometry_string);
|
||||
json_result.values["alternative_geometries"] = json_alternate_geometries_array;
|
||||
}
|
||||
// Generate instructions for each alternative (simulated here)
|
||||
JSON::Array json_alt_instructions;
|
||||
JSON::Array json_current_alt_instructions;
|
||||
if (config.instructions)
|
||||
{
|
||||
BuildTextualDescription(alternate_descriptionFactory,
|
||||
reply,
|
||||
BuildTextualDescription(alternate_description_factory,
|
||||
json_current_alt_instructions,
|
||||
raw_route.alternative_path_length,
|
||||
facade,
|
||||
alternative_path_segments);
|
||||
json_alt_instructions.values.push_back(json_current_alt_instructions);
|
||||
json_result.values["alternative_instructions"] = json_alt_instructions;
|
||||
}
|
||||
reply.content.emplace_back("]");
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"alternative_summaries\":[");
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
// Generate route summary (length, duration) for each alternative
|
||||
alternate_descriptionFactory.BuildRouteSummary(
|
||||
alternate_descriptionFactory.entireLength, raw_route.alternative_path_length);
|
||||
reply.content.emplace_back("{");
|
||||
reply.content.emplace_back("\"total_distance\":");
|
||||
reply.content.emplace_back(alternate_descriptionFactory.summary.lengthString);
|
||||
reply.content.emplace_back(","
|
||||
"\"total_time\":");
|
||||
reply.content.emplace_back(alternate_descriptionFactory.summary.durationString);
|
||||
reply.content.emplace_back(","
|
||||
"\"start_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.startName));
|
||||
reply.content.emplace_back("\","
|
||||
"\"end_point\":\"");
|
||||
reply.content.emplace_back(
|
||||
facade->GetEscapedNameForNameID(description_factory.summary.destName));
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back("}");
|
||||
}
|
||||
reply.content.emplace_back("],");
|
||||
alternate_description_factory.BuildRouteSummary(
|
||||
alternate_description_factory.entireLength, raw_route.alternative_path_length);
|
||||
|
||||
// //Get Names for both routes
|
||||
RouteNames routeNames;
|
||||
GetRouteNames(shortest_path_segments, alternative_path_segments, facade, routeNames);
|
||||
JSON::Object json_alternate_route_summary;
|
||||
JSON::Array json_alternate_route_summary_array;
|
||||
json_alternate_route_summary.values["total_distance"] = alternate_description_factory.summary.distance;
|
||||
json_alternate_route_summary.values["total_time"] = alternate_description_factory.summary.duration;
|
||||
json_alternate_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(alternate_description_factory.summary.source_name_id);
|
||||
json_alternate_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(alternate_description_factory.summary.target_name_id);
|
||||
json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
|
||||
json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
|
||||
|
||||
reply.content.emplace_back("\"route_name\":[\"");
|
||||
reply.content.emplace_back(routeNames.shortest_path_name_1);
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(routeNames.shortest_path_name_2);
|
||||
reply.content.emplace_back("\"],"
|
||||
"\"alternative_names\":[");
|
||||
reply.content.emplace_back("[\"");
|
||||
reply.content.emplace_back(routeNames.alternative_path_name_1);
|
||||
reply.content.emplace_back("\",\"");
|
||||
reply.content.emplace_back(routeNames.alternative_path_name_2);
|
||||
reply.content.emplace_back("\"]");
|
||||
reply.content.emplace_back("],");
|
||||
// list all viapoints so that the client may display it
|
||||
reply.content.emplace_back("\"via_points\":[");
|
||||
JSON::Array json_altenative_indices_array;
|
||||
json_altenative_indices_array.values.push_back(0);
|
||||
json_altenative_indices_array.values.push_back(alternate_description_factory.path_description.size());
|
||||
json_result.values["alternative_indices"] = json_altenative_indices_array;
|
||||
|
||||
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
|
||||
JSON::Array json_alternate_names_array;
|
||||
JSON::Array json_alternate_names;
|
||||
json_alternate_names.values.push_back(route_names.alternative_path_name_1);
|
||||
json_alternate_names.values.push_back(route_names.alternative_path_name_2);
|
||||
json_alternate_names_array.values.push_back(json_alternate_names);
|
||||
json_result.values["alternative_names"] = json_alternate_names_array;
|
||||
|
||||
std::string tmp;
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(
|
||||
raw_route.segment_end_coordinates.front().source_phantom.location, tmp);
|
||||
reply.content.emplace_back("[");
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back("]");
|
||||
|
||||
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
|
||||
{
|
||||
tmp.clear();
|
||||
FixedPointCoordinate::convertInternalReversedCoordinateToString(
|
||||
nodes.target_phantom.location, tmp);
|
||||
reply.content.emplace_back(",[");
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back("]");
|
||||
} else {
|
||||
json_result.values["found_alternative"] = JSON::False();
|
||||
}
|
||||
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"via_indices\":[");
|
||||
for (const unsigned index : shortest_leg_end_indices)
|
||||
{
|
||||
tmp.clear();
|
||||
intToString(index, tmp);
|
||||
reply.content.emplace_back(tmp);
|
||||
if (index != shortest_leg_end_indices.back())
|
||||
{
|
||||
reply.content.emplace_back(",");
|
||||
}
|
||||
}
|
||||
reply.content.emplace_back("],\"alternative_indices\":[");
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
reply.content.emplace_back("0,");
|
||||
tmp.clear();
|
||||
intToString(alternate_descriptionFactory.path_description.size(), tmp);
|
||||
reply.content.emplace_back(tmp);
|
||||
}
|
||||
|
||||
reply.content.emplace_back("],");
|
||||
reply.content.emplace_back("\"hint_data\": {");
|
||||
reply.content.emplace_back("\"checksum\":");
|
||||
intToString(raw_route.check_sum, tmp);
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back(", \"locations\": [");
|
||||
|
||||
JSON::Object json_hint_object;
|
||||
json_hint_object.values["checksum"] = raw_route.check_sum;
|
||||
JSON::Array json_location_hint_array;
|
||||
std::string hint;
|
||||
for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i)
|
||||
{
|
||||
reply.content.emplace_back("\"");
|
||||
EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
|
||||
reply.content.emplace_back(hint);
|
||||
reply.content.emplace_back("\", ");
|
||||
json_location_hint_array.values.push_back(hint);
|
||||
}
|
||||
EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back(hint);
|
||||
reply.content.emplace_back("\"]");
|
||||
reply.content.emplace_back("}}");
|
||||
json_location_hint_array.values.push_back(hint);
|
||||
json_hint_object.values["locations"] = json_location_hint_array;
|
||||
json_result.values["hint_data"] = json_hint_object;
|
||||
|
||||
// render the content to the output array
|
||||
TIMER_START(route_render);
|
||||
JSON::render(reply.content, json_result);
|
||||
TIMER_STOP(route_render);
|
||||
JSON::render(SimpleLogger().Write(), json_result);
|
||||
SimpleLogger().Write(logDEBUG) << "rendering took: " << TIMER_MSEC(route_render);
|
||||
}
|
||||
|
||||
// TODO: break into function object with several functions, i.e. simplify
|
||||
// construct routes names
|
||||
void GetRouteNames(std::vector<Segment> &shortest_path_segments,
|
||||
std::vector<Segment> &alternative_path_segments,
|
||||
const DataFacadeT *facade,
|
||||
RouteNames &routeNames)
|
||||
RouteNames &route_names)
|
||||
{
|
||||
Segment shortest_segment_1, shortest_segment_2;
|
||||
Segment alternativeSegment1, alternative_segment_2;
|
||||
Segment alternative_segment_1, alternative_segment_2;
|
||||
|
||||
auto length_comperator = [](Segment a, Segment b)
|
||||
{ return a.length < b.length; };
|
||||
@ -351,28 +305,28 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
|
||||
std::sort(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(),
|
||||
length_comperator);
|
||||
alternativeSegment1 = alternative_path_segments[0];
|
||||
alternative_segment_1 = alternative_path_segments[0];
|
||||
}
|
||||
std::vector<Segment> shortestDifference(shortest_path_segments.size());
|
||||
std::vector<Segment> alternativeDifference(alternative_path_segments.size());
|
||||
std::vector<Segment> shortest_path_set_difference(shortest_path_segments.size());
|
||||
std::vector<Segment> 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(),
|
||||
shortestDifference.begin(),
|
||||
shortest_path_set_difference.begin(),
|
||||
length_comperator);
|
||||
int size_of_difference = shortestDifference.size();
|
||||
int size_of_difference = shortest_path_set_difference.size();
|
||||
if (size_of_difference)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < size_of_difference &&
|
||||
shortestDifference[i].name_id == shortest_path_segments[0].name_id)
|
||||
shortest_path_set_difference[i].name_id == shortest_path_segments[0].name_id)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
if (i < size_of_difference)
|
||||
{
|
||||
shortest_segment_2 = shortestDifference[i];
|
||||
shortest_segment_2 = shortest_path_set_difference[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,50 +334,51 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
|
||||
alternative_path_segments.end(),
|
||||
shortest_path_segments.begin(),
|
||||
shortest_path_segments.end(),
|
||||
alternativeDifference.begin(),
|
||||
alternative_path_set_difference.begin(),
|
||||
name_id_comperator);
|
||||
size_of_difference = alternativeDifference.size();
|
||||
size_of_difference = alternative_path_set_difference.size();
|
||||
if (size_of_difference)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < size_of_difference &&
|
||||
alternativeDifference[i].name_id == alternative_path_segments[0].name_id)
|
||||
alternative_path_set_difference[i].name_id == alternative_path_segments[0].name_id)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
if (i < size_of_difference)
|
||||
{
|
||||
alternative_segment_2 = alternativeDifference[i];
|
||||
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 (alternativeSegment1.position > alternative_segment_2.position)
|
||||
std::swap(alternativeSegment1, alternative_segment_2);
|
||||
|
||||
routeNames.shortest_path_name_1 =
|
||||
}
|
||||
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);
|
||||
routeNames.shortest_path_name_2 =
|
||||
route_names.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 =
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: reorder parameters
|
||||
inline void BuildTextualDescription(DescriptionFactory &description_factory,
|
||||
http::Reply &reply,
|
||||
JSON::Array & json_instruction_array,
|
||||
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]
|
||||
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
unsigned necessary_segments_running_index = 0;
|
||||
round_about.leave_at_exit = 0;
|
||||
round_about.name_id = 0;
|
||||
@ -432,6 +387,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
|
||||
// Fetch data from Factory and generate a string from it.
|
||||
for (const SegmentInformation &segment : description_factory.path_description)
|
||||
{
|
||||
JSON::Array json_instruction_row;
|
||||
TurnInstruction current_instruction = segment.turn_instruction;
|
||||
entered_restricted_area_count += (current_instruction != segment.turn_instruction);
|
||||
if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
|
||||
@ -443,50 +399,35 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
|
||||
}
|
||||
else
|
||||
{
|
||||
if (necessary_segments_running_index)
|
||||
{
|
||||
reply.content.emplace_back(",");
|
||||
}
|
||||
reply.content.emplace_back("[\"");
|
||||
std::string current_turn_instruction;
|
||||
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);
|
||||
temp_instruction = IntToString(as_integer(TurnInstruction::EnterRoundAbout));
|
||||
current_turn_instruction += temp_instruction;
|
||||
current_turn_instruction += "-";
|
||||
temp_instruction = IntToString(round_about.leave_at_exit + 1);
|
||||
current_turn_instruction += temp_instruction;
|
||||
round_about.leave_at_exit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
intToString(as_integer(current_instruction), temp_instruction);
|
||||
reply.content.emplace_back(temp_instruction);
|
||||
temp_instruction = IntToString(as_integer(current_instruction));
|
||||
current_turn_instruction += temp_instruction;
|
||||
}
|
||||
json_instruction_row.values.push_back(current_turn_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\",\"");
|
||||
json_instruction_row.values.push_back(facade->GetEscapedNameForNameID(segment.name_id));
|
||||
json_instruction_row.values.push_back(std::round(segment.length));
|
||||
json_instruction_row.values.push_back(necessary_segments_running_index);
|
||||
json_instruction_row.values.push_back(round(segment.duration / 10));
|
||||
json_instruction_row.values.push_back(IntToString(segment.length)+"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("]");
|
||||
json_instruction_row.values.push_back(Azimuth::Get(bearing_value));
|
||||
json_instruction_row.values.push_back(bearing_value);
|
||||
|
||||
route_segments_list.emplace_back(
|
||||
Segment(segment.name_id, segment.length, route_segments_list.size()));
|
||||
segment.name_id, segment.length, route_segments_list.size());
|
||||
json_instruction_array.values.push_back(json_instruction_row);
|
||||
}
|
||||
}
|
||||
else if (TurnInstruction::StayOnRoundAbout == current_instruction)
|
||||
@ -498,25 +439,21 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
|
||||
++necessary_segments_running_index;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: check if this in an invariant
|
||||
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("]");
|
||||
JSON::Array json_last_instruction_row;
|
||||
temp_instruction = IntToString(as_integer(TurnInstruction::ReachedYourDestination));
|
||||
json_last_instruction_row.values.push_back(temp_instruction);
|
||||
json_last_instruction_row.values.push_back("");
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
|
||||
json_last_instruction_row.values.push_back(0);
|
||||
json_last_instruction_row.values.push_back("0m");
|
||||
json_last_instruction_row.values.push_back(Azimuth::Get(0.0));
|
||||
json_last_instruction_row.values.push_back(0.);
|
||||
json_instruction_array.values.push_back(json_last_instruction_row);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ class Reply
|
||||
std::vector<Header> headers;
|
||||
std::vector<boost::asio::const_buffer> toBuffers();
|
||||
std::vector<boost::asio::const_buffer> HeaderstoBuffers();
|
||||
std::vector<std::string> content;
|
||||
std::vector<char> content;
|
||||
static Reply StockReply(status_type status);
|
||||
void setSize(const unsigned size);
|
||||
void SetUncompressedSize();
|
||||
|
@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "OSRM_impl.h"
|
||||
#include "OSRM.h"
|
||||
|
||||
#include "../Plugins/DistanceTablePlugin.h"
|
||||
#include "../Plugins/HelloWorldPlugin.h"
|
||||
#include "../Plugins/LocatePlugin.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.
|
||||
RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new HelloWorldPlugin());
|
||||
RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
|
||||
|
153
Plugins/DistanceTablePlugin.h
Normal file
153
Plugins/DistanceTablePlugin.h
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
|
||||
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 "../Descriptors/GPXDescriptor.h"
|
||||
#include "../Descriptors/JSONDescriptor.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../Util/TimingUtil.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class 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)
|
||||
{
|
||||
SimpleLogger().Write() << "running DT plugin";
|
||||
|
||||
// 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(); }))
|
||||
{
|
||||
SimpleLogger().Write() << "invalid coordinate";
|
||||
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
|
||||
{
|
||||
raw_route.raw_via_node_coordinates.emplace_back(coordinate);
|
||||
SimpleLogger().Write() << "adding coordinate " << 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(25, max_locations);
|
||||
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()))
|
||||
{
|
||||
SimpleLogger().Write() << "decoded phantom node for " << phantom_node_vector[i].location;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
SimpleLogger().Write() << "looking up coordinate in tree";
|
||||
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);
|
||||
SimpleLogger().Write() << "table computation took " << TIMER_MSEC(distance_table) << "ms";
|
||||
|
||||
if (!result_table)
|
||||
{
|
||||
SimpleLogger().Write() << "computation failed";
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
SimpleLogger().Write() << "computation successful";
|
||||
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
|
@ -25,10 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HELLOWORLDPLUGIN_H_
|
||||
#define HELLOWORLDPLUGIN_H_
|
||||
#ifndef HELLO_WORLD_PLUGIN_H
|
||||
#define HELLO_WORLD_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <string>
|
||||
@ -46,70 +47,58 @@ class HelloWorldPlugin : public BasePlugin
|
||||
void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
|
||||
{
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("<html><head><title>Hello World Demonstration "
|
||||
"Document</title></head><body><h1>Hello, World!</h1>");
|
||||
reply.content.emplace_back("<pre>");
|
||||
reply.content.emplace_back("zoom level: ");
|
||||
intToString(routeParameters.zoom_level, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\nchecksum: ");
|
||||
intToString(routeParameters.check_sum, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\ninstructions: ");
|
||||
reply.content.emplace_back((routeParameters.print_instructions ? "yes" : "no"));
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\ngeometry: ");
|
||||
reply.content.emplace_back((routeParameters.geometry ? "yes" : "no"));
|
||||
reply.content.emplace_back("\ncompression: ");
|
||||
reply.content.emplace_back((routeParameters.compression ? "yes" : "no"));
|
||||
reply.content.emplace_back("\noutput format: ");
|
||||
reply.content.emplace_back(routeParameters.output_format);
|
||||
reply.content.emplace_back("\njson parameter: ");
|
||||
reply.content.emplace_back(routeParameters.jsonp_parameter);
|
||||
reply.content.emplace_back("\nlanguage: ");
|
||||
reply.content.emplace_back(routeParameters.language);
|
||||
reply.content.emplace_back("\nNumber of locations: ");
|
||||
intToString(routeParameters.coordinates.size(), temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\n");
|
||||
|
||||
JSON::Object json_result;
|
||||
std::string temp_string;
|
||||
json_result.values["title"] = "Hello World";
|
||||
|
||||
temp_string = IntToString(routeParameters.zoom_level);
|
||||
json_result.values["zoom_level"] = temp_string;
|
||||
|
||||
temp_string = 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;
|
||||
for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
|
||||
{
|
||||
reply.content.emplace_back(" [");
|
||||
intToString(counter, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("] ");
|
||||
doubleToString(coordinate.lat / COORDINATE_PRECISION, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back(",");
|
||||
doubleToString(coordinate.lon / COORDINATE_PRECISION, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\n");
|
||||
JSON::Object json_location;
|
||||
JSON::Array json_coordinates;
|
||||
|
||||
json_coordinates.values.push_back(coordinate.lat / COORDINATE_PRECISION);
|
||||
json_coordinates.values.push_back(coordinate.lon / COORDINATE_PRECISION);
|
||||
json_location.values[IntToString(counter)] = json_coordinates;
|
||||
json_locations.values.push_back(json_location);
|
||||
++counter;
|
||||
}
|
||||
json_result.values["locations"] = json_locations;
|
||||
json_result.values["hint_count"] = routeParameters.hints.size();
|
||||
|
||||
reply.content.emplace_back("Number of hints: ");
|
||||
intToString(routeParameters.hints.size(), temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("\n");
|
||||
|
||||
JSON::Array json_hints;
|
||||
counter = 0;
|
||||
for (const std::string ¤t_string : routeParameters.hints)
|
||||
for (const std::string ¤t_hint : routeParameters.hints)
|
||||
{
|
||||
reply.content.emplace_back(" [");
|
||||
intToString(counter, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
reply.content.emplace_back("] ");
|
||||
reply.content.emplace_back(current_string);
|
||||
reply.content.emplace_back("\n");
|
||||
// JSON::String json_hint_string = current_hint;
|
||||
json_hints.values.push_back(current_hint);
|
||||
++counter;
|
||||
}
|
||||
reply.content.emplace_back("</pre></body></html>");
|
||||
json_result.values["hints"] = json_hints;
|
||||
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* HELLOWORLDPLUGIN_H_ */
|
||||
#endif // HELLO_WORLD_PLUGIN_H
|
||||
|
@ -29,10 +29,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define LOCATE_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
// locates the nearest node in the road network for a given coordinate.
|
||||
#include <string>
|
||||
|
||||
// locates the nearest node in the road network for a given coordinate.
|
||||
template <class DataFacadeT> class LocatePlugin : public BasePlugin
|
||||
{
|
||||
public:
|
||||
@ -42,70 +44,36 @@ template <class DataFacadeT> class LocatePlugin : public BasePlugin
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
// check number of parameters
|
||||
if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid())
|
||||
if (route_parameters.coordinates.empty())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
// check if queried location is sane
|
||||
if (!route_parameters.coordinates.front().isValid())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
// query to helpdesk
|
||||
JSON::Object json_result;
|
||||
FixedPointCoordinate result;
|
||||
std::string tmp;
|
||||
// json
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("{");
|
||||
if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(),
|
||||
result))
|
||||
{
|
||||
reply.content.emplace_back("\"status\":207,");
|
||||
reply.content.emplace_back("\"mapped_coordinate\":[]");
|
||||
json_result.values["status"] = 207;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write coordinate to stream
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("\"status\":0,");
|
||||
reply.content.emplace_back("\"mapped_coordinate\":");
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.lat, tmp);
|
||||
reply.content.emplace_back("[");
|
||||
reply.content.emplace_back(tmp);
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.lon, tmp);
|
||||
reply.content.emplace_back(",");
|
||||
reply.content.emplace_back(tmp);
|
||||
reply.content.emplace_back("]");
|
||||
json_result.values["status"] = 0;
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(result.lat/COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(result.lon/COORDINATE_PRECISION);
|
||||
json_result.values["mapped_coordinate"] = json_coordinate;
|
||||
}
|
||||
reply.content.emplace_back("}");
|
||||
reply.headers.resize(3);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
return;
|
||||
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -29,10 +29,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define NEAREST_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../DataStructures/PhantomNodes.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
|
||||
@ -43,8 +44,6 @@ template <class DataFacadeT> class NearestPlugin : public BasePlugin
|
||||
public:
|
||||
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest")
|
||||
{
|
||||
descriptor_table.emplace("", 0); // default descriptor
|
||||
descriptor_table.emplace("json", 1);
|
||||
}
|
||||
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
@ -57,81 +56,40 @@ template <class DataFacadeT> class NearestPlugin : public BasePlugin
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
// check if queried location is sane
|
||||
if (!route_parameters.coordinates.front().isValid())
|
||||
{
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
PhantomNode result;
|
||||
PhantomNode phantom_node;
|
||||
facade->FindPhantomNodeForCoordinate(
|
||||
route_parameters.coordinates.front(), result, route_parameters.zoom_level);
|
||||
route_parameters.coordinates.front(), phantom_node, route_parameters.zoom_level);
|
||||
|
||||
// json
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
JSON::Object json_result;
|
||||
if (!phantom_node.isValid())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("{\"status\":");
|
||||
if (SPECIAL_NODEID != result.forward_node_id)
|
||||
{
|
||||
reply.content.emplace_back("0,");
|
||||
json_result.values["status"] = 207;
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.content.emplace_back("207,");
|
||||
reply.status = http::Reply::ok;
|
||||
json_result.values["status"] = 0;
|
||||
JSON::Array json_coordinate;
|
||||
json_coordinate.values.push_back(phantom_node.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)
|
||||
{
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.location.lat, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
FixedPointCoordinate::convertInternalLatLonToString(result.location.lon, temp_string);
|
||||
reply.content.emplace_back(",");
|
||||
reply.content.emplace_back(temp_string);
|
||||
}
|
||||
reply.content.emplace_back("],\"name\":\"");
|
||||
if (SPECIAL_NODEID != result.forward_node_id)
|
||||
{
|
||||
facade->GetName(result.name_id, temp_string);
|
||||
reply.content.emplace_back(temp_string);
|
||||
}
|
||||
reply.content.emplace_back("\"}");
|
||||
reply.headers.resize(3);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"location.json\"";
|
||||
}
|
||||
reply.headers[0].name = "Content-Length";
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, temp_string);
|
||||
reply.headers[0].value = temp_string;
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
std::unordered_map<std::string, unsigned> descriptor_table;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
|
@ -28,8 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef TIMESTAMP_PLUGIN_H
|
||||
#define TIMESTAMP_PLUGIN_H
|
||||
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
template <class DataFacadeT> class TimestampPlugin : public BasePlugin
|
||||
{
|
||||
public:
|
||||
@ -40,46 +43,12 @@ template <class DataFacadeT> class TimestampPlugin : public BasePlugin
|
||||
const std::string GetDescriptor() const { return descriptor_string; }
|
||||
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
|
||||
{
|
||||
std::string tmp;
|
||||
|
||||
// json
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.emplace_back("{");
|
||||
reply.content.emplace_back("\"status\":");
|
||||
reply.content.emplace_back("0,");
|
||||
reply.content.emplace_back("\"timestamp\":\"");
|
||||
reply.content.emplace_back(facade->GetTimestamp());
|
||||
reply.content.emplace_back("\"");
|
||||
reply.content.emplace_back("}");
|
||||
reply.headers.resize(3);
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")");
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "text/javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.js\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/x-javascript";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"timestamp.json\"";
|
||||
}
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
intToString(content_length, tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
JSON::Object json_result;
|
||||
json_result.values["status"] = 0;
|
||||
const std::string timestamp = facade->GetTimestamp();
|
||||
json_result.values["timestamp"] = timestamp;
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -25,12 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIAROUTEPLUGIN_H_
|
||||
#define VIAROUTEPLUGIN_H_
|
||||
#ifndef VIA_ROUTE_PLUGIN_H
|
||||
#define VIA_ROUTE_PLUGIN_H
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include "../Algorithms/ObjectToBase64.h"
|
||||
|
||||
#include "../DataStructures/QueryEdge.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
#include "../Descriptors/BaseDescriptor.h"
|
||||
@ -60,6 +61,7 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
|
||||
|
||||
descriptor_table.emplace("json", 0);
|
||||
descriptor_table.emplace("gpx", 1);
|
||||
// descriptor_table.emplace("geojson", 2);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() {}
|
||||
@ -119,7 +121,9 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
|
||||
raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
||||
}
|
||||
|
||||
if ((route_parameters.alternate_route) && (1 == raw_route.segment_end_coordinates.size()))
|
||||
const bool is_alternate_requested = route_parameters.alternate_route;
|
||||
const bool is_only_one_segment = (1 == raw_route.segment_end_coordinates.size());
|
||||
if (is_alternate_requested && is_only_one_segment)
|
||||
{
|
||||
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
|
||||
raw_route);
|
||||
@ -135,12 +139,6 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(route_parameters.jsonp_parameter);
|
||||
reply.content.emplace_back("(");
|
||||
}
|
||||
|
||||
DescriptorConfig descriptor_config;
|
||||
|
||||
auto iter = descriptor_table.find(route_parameters.output_format);
|
||||
@ -160,6 +158,9 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
|
||||
case 1:
|
||||
descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>();
|
||||
break;
|
||||
// case 2:
|
||||
// descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
|
||||
// break;
|
||||
default:
|
||||
descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
|
||||
break;
|
||||
@ -170,67 +171,6 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
|
||||
phantom_nodes.target_phantom = raw_route.segment_end_coordinates.back().target_phantom;
|
||||
descriptor->SetConfig(descriptor_config);
|
||||
descriptor->Run(raw_route, phantom_nodes, facade, reply);
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
reply.content.emplace_back(")\n");
|
||||
}
|
||||
reply.headers.resize(3);
|
||||
reply.headers[0].name = "Content-Length";
|
||||
|
||||
unsigned content_length = 0;
|
||||
for (const std::string &snippet : reply.content)
|
||||
{
|
||||
content_length += snippet.length();
|
||||
}
|
||||
std::string tmp_string;
|
||||
intToString(content_length, tmp_string);
|
||||
reply.headers[0].value = tmp_string;
|
||||
|
||||
switch (descriptor_type)
|
||||
{
|
||||
case 0:
|
||||
if (!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:
|
||||
@ -238,4 +178,4 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif /* VIAROUTEPLUGIN_H_ */
|
||||
#endif // VIA_ROUTE_PLUGIN_H
|
||||
|
@ -78,6 +78,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
|
||||
{
|
||||
if (phantom_node_pair.PhantomNodesHaveEqualLocation())
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
246
RoutingAlgorithms/ManyToManyRouting.h
Normal file
246
RoutingAlgorithms/ManyToManyRouting.h
Normal 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 ¤t_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
|
@ -55,6 +55,7 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
|
||||
{
|
||||
if (phantom_node_pair.AtLeastOnePhantomNodeIsInvalid())
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ struct APIGrammar : qi::grammar<Iterator>
|
||||
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
|
||||
output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
|
||||
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
|
||||
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
|
||||
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
|
||||
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
|
||||
|
@ -81,6 +81,7 @@ void Connection::handle_read(const boost::system::error_code &e, std::size_t byt
|
||||
Header compression_header;
|
||||
std::vector<char> compressed_output;
|
||||
std::vector<boost::asio::const_buffer> output_buffer;
|
||||
|
||||
switch (compression_type)
|
||||
{
|
||||
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,
|
||||
std::vector<char> &compressed_data)
|
||||
{
|
||||
@ -171,16 +172,10 @@ void Connection::compressBufferCollection(std::vector<std::string> uncompressed_
|
||||
}
|
||||
|
||||
BOOST_ASSERT(compressed_data.empty());
|
||||
boost::iostreams::filtering_ostream compressing_stream;
|
||||
|
||||
compressing_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
|
||||
compressing_stream.push(boost::iostreams::back_inserter(compressed_data));
|
||||
|
||||
for (const std::string &line : uncompressed_data)
|
||||
{
|
||||
compressing_stream << line;
|
||||
}
|
||||
|
||||
compressing_stream.reset();
|
||||
boost::iostreams::filtering_ostream gzip_stream;
|
||||
gzip_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
|
||||
gzip_stream.push(boost::iostreams::back_inserter(compressed_data));
|
||||
gzip_stream.write(&uncompressed_data[0], uncompressed_data.size());
|
||||
boost::iostreams::close(gzip_stream);
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ class Connection : public std::enable_shared_from_this<Connection>
|
||||
/// Handle completion of a write operation.
|
||||
void handle_write(const boost::system::error_code &e);
|
||||
|
||||
void compressBufferCollection(std::vector<std::string> uncompressed_data,
|
||||
void compressBufferCollection(std::vector<char> uncompressed_data,
|
||||
CompressionType compression_type,
|
||||
std::vector<char> &compressed_data);
|
||||
|
||||
|
@ -38,7 +38,7 @@ void Reply::setSize(const unsigned size)
|
||||
{
|
||||
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()
|
||||
{
|
||||
unsigned uncompressed_size = 0;
|
||||
for (const std::string ¤t_line : content)
|
||||
{
|
||||
uncompressed_size += current_line.size();
|
||||
}
|
||||
uncompressed_size = content.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));
|
||||
for (const std::string &line : content)
|
||||
{
|
||||
buffers.push_back(boost::asio::buffer(line));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(content));
|
||||
return buffers;
|
||||
}
|
||||
|
||||
@ -94,14 +88,15 @@ Reply Reply::StockReply(Reply::status_type status)
|
||||
Reply rep;
|
||||
rep.status = status;
|
||||
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[0].name = "Access-Control-Allow-Origin";
|
||||
rep.headers[0].value = "*";
|
||||
rep.headers[1].name = "Content-Length";
|
||||
|
||||
std::string size_string;
|
||||
intToString(rep.content.size(), size_string);
|
||||
std::string size_string = IntToString(rep.content.size());
|
||||
|
||||
rep.headers[1].value = size_string;
|
||||
rep.headers[2].name = "Content-Type";
|
||||
|
@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "RequestHandler.h"
|
||||
#include "Http/Request.h"
|
||||
|
||||
#include "../DataStructures/JSONContainer.h"
|
||||
#include "../Library/OSRM.h"
|
||||
#include "../Util/SimpleLogger.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
@ -85,18 +86,51 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
|
||||
reply = http::Reply::StockReply(http::Reply::badRequest);
|
||||
reply.content.clear();
|
||||
const int position = std::distance(request.begin(), it);
|
||||
reply.content.push_back(
|
||||
"{\"status\":400,\"status_message\":\"Query string malformed close to position ");
|
||||
std::string tmp_position_string;
|
||||
intToString(position, tmp_position_string);
|
||||
reply.content.push_back(tmp_position_string);
|
||||
reply.content.push_back("\"}");
|
||||
JSON::Object json_result;
|
||||
json_result.values["status"] = 400;
|
||||
std::string tmp_position_string = IntToString(position);
|
||||
std::string message = ("Query string malformed close to position " + IntToString(position));
|
||||
json_result.values["status_message"] = message;
|
||||
JSON::render(reply.content, json_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// parsing done, lets call the right plugin to handle the request
|
||||
BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
|
||||
|
||||
if (!route_parameters.jsonp_parameter.empty())
|
||||
{
|
||||
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
@ -41,12 +41,8 @@ struct ServerFactory
|
||||
ServerFactory(const ServerFactory &) = delete;
|
||||
static Server *CreateServer(std::string &ip_address, int ip_port, int threads)
|
||||
{
|
||||
|
||||
SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
|
||||
|
||||
std::string port_stream;
|
||||
intToString(ip_port, port_stream);
|
||||
|
||||
std::string port_stream = IntToString(ip_port);
|
||||
return new Server(ip_address, port_stream, std::min(omp_get_num_procs(), threads));
|
||||
}
|
||||
};
|
||||
|
@ -110,10 +110,10 @@ int main(int argc, const char *argv[])
|
||||
// attention: super-inefficient hack below:
|
||||
|
||||
std::stringstream my_stream;
|
||||
for (const std::string &line : osrm_reply.content)
|
||||
for (const auto &element : osrm_reply.content)
|
||||
{
|
||||
std::cout << line;
|
||||
my_stream << line;
|
||||
std::cout << element;
|
||||
my_stream << element;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
|
@ -80,11 +80,12 @@ auto as_integer(Enumeration const 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);
|
||||
boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value);
|
||||
return 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;
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user