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:
Dennis Luxen 2014-05-16 16:09:40 +02:00
parent acab77f4f8
commit a80815d57a
28 changed files with 1092 additions and 675 deletions

View File

@ -26,6 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "PolylineCompressor.h" #include "PolylineCompressor.h"
#include "../Util/StringUtil.h"
void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output)
const const
@ -39,9 +40,9 @@ void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std
numbers[i] = ~(numbers[i]); numbers[i] = ~(numbers[i]);
} }
} }
for (unsigned i = 0; i < end; ++i) for (const int number: numbers)
{ {
encodeNumber(numbers[i], output); encodeNumber(number, output);
} }
} }
@ -66,37 +67,36 @@ void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output)
} }
} }
void PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline, JSON::String PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline) const
std::string &output) const
{ {
std::string output;
std::vector<int> delta_numbers; std::vector<int> delta_numbers;
output += "\"";
if (!polyline.empty()) if (!polyline.empty())
{ {
FixedPointCoordinate last_coordinate = polyline[0].location; FixedPointCoordinate last_coordinate = polyline[0].location;
delta_numbers.emplace_back(last_coordinate.lat); delta_numbers.emplace_back(last_coordinate.lat);
delta_numbers.emplace_back(last_coordinate.lon); delta_numbers.emplace_back(last_coordinate.lon);
for (unsigned i = 1; i < polyline.size(); ++i) for (const auto & segment : polyline)
{ {
if (polyline[i].necessary) if (segment.necessary)
{ {
int lat_diff = polyline[i].location.lat - last_coordinate.lat; int lat_diff = segment.location.lat - last_coordinate.lat;
int lon_diff = polyline[i].location.lon - last_coordinate.lon; int lon_diff = segment.location.lon - last_coordinate.lon;
delta_numbers.emplace_back(lat_diff); delta_numbers.emplace_back(lat_diff);
delta_numbers.emplace_back(lon_diff); delta_numbers.emplace_back(lon_diff);
last_coordinate = polyline[i].location; last_coordinate = segment.location;
} }
} }
encodeVectorSignedNumber(delta_numbers, output); encodeVectorSignedNumber(delta_numbers, output);
} }
output += "\""; JSON::String return_value(output);
return return_value;
} }
void PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordinate> &polyline, JSON::String PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordinate> &polyline) const
std::string &output) const
{ {
std::string output;
std::vector<int> delta_numbers(2 * polyline.size()); std::vector<int> delta_numbers(2 * polyline.size());
output += "\"";
if (!polyline.empty()) if (!polyline.empty())
{ {
delta_numbers[0] = polyline[0].lat; delta_numbers[0] = polyline[0].lat;
@ -110,53 +110,40 @@ void PolylineCompressor::printEncodedString(const std::vector<FixedPointCoordina
} }
encodeVectorSignedNumber(delta_numbers, output); encodeVectorSignedNumber(delta_numbers, output);
} }
output += "\""; JSON::String return_value(output);
return return_value;
} }
void PolylineCompressor::printUnencodedString(const std::vector<FixedPointCoordinate> &polyline,
std::string &output) const JSON::Array PolylineCompressor::printUnencodedString(const std::vector<FixedPointCoordinate> &polyline) const
{ {
output += "["; JSON::Array json_geometry_array;
std::string tmp; for( const auto & coordinate : polyline)
for (unsigned i = 0; i < polyline.size(); i++)
{ {
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lat, tmp); std::string tmp, output;
output += "["; FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
output += (tmp + ",");
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
output += tmp; output += tmp;
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lon, tmp); json_geometry_array.values.push_back(output);
output += ", ";
output += tmp;
output += "]";
if (i < polyline.size() - 1)
{
output += ",";
} }
} return json_geometry_array;
output += "]";
} }
void PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline, JSON::Array PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
std::string &output) const
{ {
output += "["; JSON::Array json_geometry_array;
std::string tmp; for( const auto & segment : polyline)
for (unsigned i = 0; i < polyline.size(); i++)
{ {
if (!polyline[i].necessary) if (segment.necessary)
{ {
continue; std::string tmp, output;
} FixedPointCoordinate::convertInternalLatLonToString(segment.location.lat, tmp);
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lat, tmp); output += (tmp + ",");
output += "["; FixedPointCoordinate::convertInternalLatLonToString(segment.location.lon, tmp);
output += tmp; output += tmp;
FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lon, tmp); json_geometry_array.values.push_back(output);
output += ", ";
output += tmp;
output += "]";
if (i < polyline.size() - 1)
{
output += ",";
} }
} }
output += "]"; return json_geometry_array;
} }

View File

@ -28,8 +28,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef POLYLINECOMPRESSOR_H_ #ifndef POLYLINECOMPRESSOR_H_
#define POLYLINECOMPRESSOR_H_ #define POLYLINECOMPRESSOR_H_
#include "../DataStructures/JSONContainer.h"
#include "../DataStructures/SegmentInformation.h" #include "../DataStructures/SegmentInformation.h"
#include "../Util/StringUtil.h"
#include <string> #include <string>
#include <vector> #include <vector>
@ -42,17 +42,13 @@ class PolylineCompressor
void encodeNumber(int number_to_encode, std::string &output) const; void encodeNumber(int number_to_encode, std::string &output) const;
public: public:
void printEncodedString(const std::vector<SegmentInformation> &polyline, JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
std::string &output) const;
void printEncodedString(const std::vector<FixedPointCoordinate> &polyline, JSON::String printEncodedString(const std::vector<FixedPointCoordinate> &polyline) const;
std::string &output) const;
void printUnencodedString(const std::vector<FixedPointCoordinate> &polyline, JSON::Array printUnencodedString(const std::vector<FixedPointCoordinate> &polyline) const;
std::string &output) const;
void printUnencodedString(const std::vector<SegmentInformation> &polyline, JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
std::string &output) const;
}; };
#endif /* POLYLINECOMPRESSOR_H_ */ #endif /* POLYLINECOMPRESSOR_H_ */

View File

@ -0,0 +1,237 @@
/*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// based on https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
#ifndef JSON_CONTAINER_H
#define JSON_CONTAINER_H
#include "../Util/StringUtil.h"
#include <boost/variant.hpp>
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
namespace JSON
{
struct String;
struct Number;
struct Object;
struct Array;
struct True;
struct False;
struct Null;
typedef boost::variant<boost::recursive_wrapper<String>,
boost::recursive_wrapper<Number>,
boost::recursive_wrapper<Object>,
boost::recursive_wrapper<Array>,
boost::recursive_wrapper<True>,
boost::recursive_wrapper<False>,
boost::recursive_wrapper<Null> > Value;
struct String
{
String() {}
String(const char *value) : value(value) {}
String(const std::string &value) : value(value) {}
std::string value;
};
struct Number
{
Number() {}
Number(double value) : value(value) {}
double value;
};
struct Object
{
std::unordered_map<std::string, Value> values;
};
struct Array
{
std::vector<Value> values;
};
struct True
{
};
struct False
{
};
struct Null
{
};
struct Renderer : boost::static_visitor<>
{
Renderer(std::ostream &_out) : out(_out) {}
void operator()(const String &string) const { out << "\"" << string.value << "\""; }
void operator()(const Number &number) const
{
out.precision(10);
out << number.value;
}
void operator()(const Object &object) const
{
out << "{";
auto iterator = object.values.begin();
while (iterator != object.values.end())
{
out << "\"" << (*iterator).first << "\":";
boost::apply_visitor(Renderer(out), (*iterator).second);
if (++iterator != object.values.end())
{
out << ",";
}
}
out << "}";
}
void operator()(const Array &array) const
{
out << "[";
std::vector<Value>::const_iterator iterator;
iterator = array.values.begin();
while (iterator != array.values.end())
{
boost::apply_visitor(Renderer(out), *iterator);
if (++iterator != array.values.end())
{
out << ",";
}
}
out << "]";
}
void operator()(const True &) const { out << "true"; }
void operator()(const False &) const { out << "false"; }
void operator()(const Null &) const { out << "null"; }
private:
std::ostream &out;
};
struct ArrayRenderer : boost::static_visitor<>
{
ArrayRenderer(std::vector<char> &_out) : out(_out) {}
void operator()(const String &string) const {
out.push_back('\"');
out.insert(out.end(), string.value.begin(), string.value.end());
out.push_back('\"');
}
void operator()(const Number &number) const
{
const std::string number_string = FixedDoubleToString(number.value);
out.insert(out.end(), number_string.begin(), number_string.end());
}
void operator()(const Object &object) const
{
out.push_back('{');
auto iterator = object.values.begin();
while (iterator != object.values.end())
{
out.push_back('\"');
out.insert(out.end(), (*iterator).first.begin(), (*iterator).first.end());
out.push_back('\"');
out.push_back(':');
boost::apply_visitor(ArrayRenderer(out), (*iterator).second);
if (++iterator != object.values.end())
{
out.push_back(',');
}
}
out.push_back('}');
}
void operator()(const Array &array) const
{
out.push_back('[');
std::vector<Value>::const_iterator iterator;
iterator = array.values.begin();
while (iterator != array.values.end())
{
boost::apply_visitor(ArrayRenderer(out), *iterator);
if (++iterator != array.values.end())
{
out.push_back(',');
}
}
out.push_back(']');
}
void operator()(const True &) const {
const std::string temp("true");
out.insert(out.end(), temp.begin(), temp.end());
}
void operator()(const False &) const {
const std::string temp("false");
out.insert(out.end(), temp.begin(), temp.end());
}
void operator()(const Null &) const {
const std::string temp("null");
out.insert(out.end(), temp.begin(), temp.end());
}
private:
std::vector<char> &out;
};
inline void render(std::ostream &out, const Object &object)
{
Value value = object;
boost::apply_visitor(Renderer(out), value);
}
inline void render(std::vector<char> &out, const Object &object)
{
Value value = object;
boost::apply_visitor(ArrayRenderer(out), value);
}
} // namespace JSON
#endif // JSON_CONTAINER_H

View File

@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "SearchEngineData.h" #include "SearchEngineData.h"
#include "../RoutingAlgorithms/AlternativePathRouting.h" #include "../RoutingAlgorithms/AlternativePathRouting.h"
#include "../RoutingAlgorithms/ManyToManyRouting.h"
#include "../RoutingAlgorithms/ShortestPathRouting.h" #include "../RoutingAlgorithms/ShortestPathRouting.h"
template <class DataFacadeT> class SearchEngine template <class DataFacadeT> class SearchEngine
@ -41,10 +42,11 @@ template <class DataFacadeT> class SearchEngine
public: public:
ShortestPathRouting<DataFacadeT> shortest_path; ShortestPathRouting<DataFacadeT> shortest_path;
AlternativeRouting<DataFacadeT> alternative_path; AlternativeRouting<DataFacadeT> alternative_path;
ManyToManyRouting<DataFacadeT> distance_table;
explicit SearchEngine(DataFacadeT *facade) explicit SearchEngine(DataFacadeT *facade)
: facade(facade), shortest_path(facade, engine_working_data), : facade(facade), shortest_path(facade, engine_working_data),
alternative_path(facade, engine_working_data) alternative_path(facade, engine_working_data), distance_table(facade, engine_working_data)
{ {
} }

View File

@ -51,7 +51,7 @@ struct DescriptorConfig
template <class DataFacadeT> class BaseDescriptor template <class DataFacadeT> class BaseDescriptor
{ {
public: public:
BaseDescriptor() {} BaseDescriptor() {} //TODO: initialize facade here.
// Maybe someone can explain the pure virtual destructor thing to me (dennis) // Maybe someone can explain the pure virtual destructor thing to me (dennis)
virtual ~BaseDescriptor() {} virtual ~BaseDescriptor() {}
virtual void Run(const RawRouteData &raw_route, virtual void Run(const RawRouteData &raw_route,

View File

@ -94,38 +94,23 @@ void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
} }
} }
void DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded, JSON::Value DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded)
std::vector<std::string> &output)
{ {
std::string temp;
if (return_encoded) if (return_encoded)
{ {
polyline_compressor.printEncodedString(path_description, temp); return polyline_compressor.printEncodedString(path_description);
} }
else return polyline_compressor.printUnencodedString(path_description);
{
polyline_compressor.printUnencodedString(path_description, temp);
}
output.emplace_back(temp);
} }
void DescriptionFactory::AppendEncodedPolylineString(std::vector<std::string> &output) const JSON::Value DescriptionFactory::AppendUnencodedPolylineString() const
{ {
std::string temp; return polyline_compressor.printUnencodedString(path_description);
polyline_compressor.printEncodedString(path_description, temp);
output.emplace_back(temp);
}
void DescriptionFactory::AppendUnencodedPolylineString(std::vector<std::string> &output) const
{
std::string temp;
polyline_compressor.printUnencodedString(path_description, temp);
output.emplace_back(temp);
} }
void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time) void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
{ {
summary.startName = start_phantom.name_id; summary.source_name_id = start_phantom.name_id;
summary.destName = target_phantom.name_id; summary.target_name_id = target_phantom.name_id;
summary.BuildDurationAndLengthStrings(distance, time); summary.BuildDurationAndLengthStrings(distance, time);
} }

View File

@ -57,18 +57,17 @@ class DescriptionFactory
public: public:
struct RouteSummary struct RouteSummary
{ {
std::string lengthString; unsigned distance;
std::string durationString; EdgeWeight duration;
unsigned startName; unsigned source_name_id;
unsigned destName; unsigned target_name_id;
RouteSummary() : lengthString("0"), durationString("0"), startName(0), destName(0) {} RouteSummary() : distance(0), duration(0), source_name_id(0), target_name_id(0) {}
void BuildDurationAndLengthStrings(const double distance, const unsigned time) void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
{ {
// compute distance/duration for route summary // compute distance/duration for route summary
intToString(round(distance), lengthString); distance = round(raw_distance);
int travel_time = round(time / 10.); duration = round(raw_duration / 10.);
intToString(std::max(travel_time, 1), durationString);
} }
} summary; } summary;
@ -79,13 +78,12 @@ class DescriptionFactory
DescriptionFactory(); DescriptionFactory();
virtual ~DescriptionFactory(); virtual ~DescriptionFactory();
double GetBearing(const FixedPointCoordinate &C, const FixedPointCoordinate &B) const; double GetBearing(const FixedPointCoordinate &C, const FixedPointCoordinate &B) const;
void AppendEncodedPolylineString(std::vector<std::string> &output) const; JSON::Value AppendUnencodedPolylineString() const;
void AppendUnencodedPolylineString(std::vector<std::string> &output) const;
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data); void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
void BuildRouteSummary(const double distance, const unsigned time); void BuildRouteSummary(const double distance, const unsigned time);
void SetStartSegment(const PhantomNode &start_phantom); void SetStartSegment(const PhantomNode &start_phantom);
void SetEndSegment(const PhantomNode &start_phantom); void SetEndSegment(const PhantomNode &start_phantom);
void AppendEncodedPolylineString(const bool return_encoded, std::vector<std::string> &output); JSON::Value AppendEncodedPolylineString(const bool return_encoded);
template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel) template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel)
{ {
@ -198,7 +196,7 @@ class DescriptionFactory
{ {
if (path_description[i].necessary) if (path_description[i].necessary)
{ {
double angle = const double angle =
GetBearing(path_description[i].location, path_description[i + 1].location); GetBearing(path_description[i].location, path_description[i + 1].location);
path_description[i].bearing = angle * 10; path_description[i].bearing = angle * 10;
} }

View File

@ -36,8 +36,25 @@ template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFac
DescriptorConfig config; DescriptorConfig config;
FixedPointCoordinate current; FixedPointCoordinate current;
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; std::string tmp;
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
output.insert(output.end(), route_point_head.begin(), route_point_head.end());
output.insert(output.end(), tmp.begin(), tmp.end());
output.push_back('\"');
FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
output.insert(output.end(), route_point_middle.begin(), route_point_middle.end());
output.insert(output.end(), tmp.begin(), tmp.end());
output.insert(output.end(), route_point_tail.begin(), route_point_tail.end());
}
public: public:
void SetConfig(const DescriptorConfig &c) { config = c; } void SetConfig(const DescriptorConfig &c) { config = c; }
@ -47,51 +64,37 @@ template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFac
DataFacadeT *facade, DataFacadeT *facade,
http::Reply &reply) http::Reply &reply)
{ {
reply.content.emplace_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
reply.content.emplace_back("<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" " "<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" "
"xmlns=\"http://www.topografix.com/GPX/1/1\" " "xmlns=\"http://www.topografix.com/GPX/1/1\" "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd" "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
"\">"); "\">"
reply.content.emplace_back("<metadata><copyright author=\"Project OSRM\"><license>Data (c)" "<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
" OpenStreetMap contributors (ODbL)</license></copyright>" " OpenStreetMap contributors (ODbL)</license></copyright>"
"</metadata>"); "</metadata>"
reply.content.emplace_back("<rte>"); "<rte>");
bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) && reply.content.insert(reply.content.end(), header.begin(), header.end());
const bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
(!raw_route.unpacked_path_segments.front().empty()); (!raw_route.unpacked_path_segments.front().empty());
if (found_route) if (found_route)
{ {
FixedPointCoordinate::convertInternalLatLonToString( AddRoutePoint(phantom_node_list.source_phantom.location, reply.content);
phantom_node_list.source_phantom.location.lat, tmp);
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
FixedPointCoordinate::convertInternalLatLonToString(
phantom_node_list.source_phantom.location.lon, tmp);
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments) for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
{ {
for (const PathData &path_data : path_data_vector) for (const PathData &path_data : path_data_vector)
{ {
FixedPointCoordinate current_coordinate = const FixedPointCoordinate current_coordinate =
facade->GetCoordinateOfNode(path_data.node); facade->GetCoordinateOfNode(path_data.node);
AddRoutePoint(current_coordinate, reply.content);
}
}
AddRoutePoint(phantom_node_list.target_phantom.location, reply.content);
FixedPointCoordinate::convertInternalLatLonToString(current_coordinate.lat,
tmp);
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
FixedPointCoordinate::convertInternalLatLonToString(current_coordinate.lon,
tmp);
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
} }
} std::string footer("</rte></gpx>");
// Add the via point or the end coordinate reply.content.insert(reply.content.end(), footer.begin(), footer.end());
FixedPointCoordinate::convertInternalLatLonToString(
phantom_node_list.target_phantom.location.lat, tmp);
reply.content.emplace_back("<rtept lat=\"" + tmp + "\" ");
FixedPointCoordinate::convertInternalLatLonToString(
phantom_node_list.target_phantom.location.lon, tmp);
reply.content.emplace_back("lon=\"" + tmp + "\"></rtept>");
}
reply.content.emplace_back("</rte></gpx>");
} }
}; };
#endif // GPX_DESCRIPTOR_H #endif // GPX_DESCRIPTOR_H

View File

@ -31,10 +31,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BaseDescriptor.h" #include "BaseDescriptor.h"
#include "DescriptionFactory.h" #include "DescriptionFactory.h"
#include "../Algorithms/ObjectToBase64.h" #include "../Algorithms/ObjectToBase64.h"
#include "../DataStructures/JSONContainer.h"
#include "../DataStructures/SegmentInformation.h" #include "../DataStructures/SegmentInformation.h"
#include "../DataStructures/TurnInstructions.h" #include "../DataStructures/TurnInstructions.h"
#include "../Util/Azimuth.h" #include "../Util/Azimuth.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include "../Util/TimingUtil.h"
#include <algorithm> #include <algorithm>
@ -45,7 +47,7 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
DataFacadeT *facade; DataFacadeT *facade;
DescriptorConfig config; DescriptorConfig config;
DescriptionFactory description_factory; DescriptionFactory description_factory;
DescriptionFactory alternate_descriptionFactory; DescriptionFactory alternate_description_factory;
FixedPointCoordinate current; FixedPointCoordinate current;
unsigned entered_restricted_area_count; unsigned entered_restricted_area_count;
struct RoundAbout struct RoundAbout
@ -106,14 +108,15 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
DataFacadeT *f, DataFacadeT *f,
http::Reply &reply) http::Reply &reply)
{ {
JSON::Object json_result;
facade = f; facade = f;
reply.content.emplace_back("{\"status\":");
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length) if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
{ {
// We do not need to do much, if there is no route ;-) // We do not need to do much, if there is no route ;-)
reply.content.emplace_back( json_result.values["status"] = 207;
"207,\"status_message\": \"Cannot find route between points\"}"); json_result.values["status_message"] = "Cannot find route between points";
JSON::render(reply.content, json_result);
return; return;
} }
@ -127,8 +130,8 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
raw_route.segment_end_coordinates.size()); raw_route.segment_end_coordinates.size());
description_factory.SetStartSegment(phantom_nodes.source_phantom); description_factory.SetStartSegment(phantom_nodes.source_phantom);
reply.content.emplace_back("0," json_result.values["status"] = 0;
"\"status_message\": \"Found route between points\","); json_result.values["status_message"] = "Found route between points";
// for each unpacked segment add the leg to the description // for each unpacked segment add the leg to the description
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i) 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.SetEndSegment(phantom_nodes.target_phantom);
description_factory.Run(facade, config.zoom_level); description_factory.Run(facade, config.zoom_level);
reply.content.emplace_back("\"route_geometry\": ");
if (config.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) if (config.instructions)
{ {
JSON::Array json_route_instructions;
BuildTextualDescription(description_factory, BuildTextualDescription(description_factory,
reply, json_route_instructions,
raw_route.shortest_path_length, raw_route.shortest_path_length,
facade, facade,
shortest_path_segments); shortest_path_segments);
json_result.values["route_instructions"] = json_route_instructions;
} }
reply.content.emplace_back("],");
description_factory.BuildRouteSummary(description_factory.entireLength, description_factory.BuildRouteSummary(description_factory.entireLength,
raw_route.shortest_path_length); 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\":"); // Get Names for both routes
reply.content.emplace_back("{"); RouteNames route_names;
reply.content.emplace_back("\"total_distance\":"); JSON::Array json_route_names;
reply.content.emplace_back(description_factory.summary.lengthString); GetRouteNames(shortest_path_segments, alternative_path_segments, facade, route_names);
reply.content.emplace_back("," json_route_names.values.push_back(route_names.shortest_path_name_1);
"\"total_time\":"); json_route_names.values.push_back(route_names.shortest_path_name_2);
reply.content.emplace_back(description_factory.summary.durationString); json_result.values["route_name"] = json_route_names;
reply.content.emplace_back(","
"\"start_point\":\""); BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
reply.content.emplace_back(
facade->GetEscapedNameForNameID(description_factory.summary.startName)); JSON::Array json_via_points_array;
reply.content.emplace_back("\"," JSON::Array json_first_coordinate;
"\"end_point\":\""); json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lat/COORDINATE_PRECISION);
reply.content.emplace_back( json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lon/COORDINATE_PRECISION);
facade->GetEscapedNameForNameID(description_factory.summary.destName)); json_via_points_array.values.push_back(json_first_coordinate);
reply.content.emplace_back("\""); for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
reply.content.emplace_back("}"); {
reply.content.emplace_back(","); 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 // 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 // Get all the coordinates for the computed route
for (const PathData &path_data : raw_route.unpacked_alternative) for (const PathData &path_data : raw_route.unpacked_alternative)
{ {
current = facade->GetCoordinateOfNode(path_data.node); current = facade->GetCoordinateOfNode(path_data.node);
alternate_descriptionFactory.AppendSegment(current, path_data); alternate_description_factory.AppendSegment(current, path_data);
} }
} alternate_description_factory.Run(facade, config.zoom_level);
alternate_descriptionFactory.Run(facade, config.zoom_level);
// //give an array of alternative routes if (config.geometry)
reply.content.emplace_back("\"alternative_geometries\": [");
if (config.geometry && INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
{ {
// Generate the linestrings for each alternative JSON::Value alternate_geometry_string = alternate_description_factory.AppendEncodedPolylineString(config.encode_geometry);
alternate_descriptionFactory.AppendEncodedPolylineString(config.encode_geometry, JSON::Array json_alternate_geometries_array;
reply.content); json_alternate_geometries_array.values.push_back(alternate_geometry_string);
json_result.values["alternative_geometries"] = json_alternate_geometries_array;
} }
reply.content.emplace_back("],"); // Generate instructions for each alternative (simulated here)
reply.content.emplace_back("\"alternative_instructions\":["); JSON::Array json_alt_instructions;
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length) JSON::Array json_current_alt_instructions;
{
reply.content.emplace_back("[");
// Generate instructions for each alternative
if (config.instructions) if (config.instructions)
{ {
BuildTextualDescription(alternate_descriptionFactory, BuildTextualDescription(alternate_description_factory,
reply, json_current_alt_instructions,
raw_route.alternative_path_length, raw_route.alternative_path_length,
facade, facade,
alternative_path_segments); 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("]"); alternate_description_factory.BuildRouteSummary(
} alternate_description_factory.entireLength, raw_route.alternative_path_length);
reply.content.emplace_back("],");
reply.content.emplace_back("\"alternative_summaries\":[");
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
{
// Generate route summary (length, duration) for each alternative
alternate_descriptionFactory.BuildRouteSummary(
alternate_descriptionFactory.entireLength, raw_route.alternative_path_length);
reply.content.emplace_back("{");
reply.content.emplace_back("\"total_distance\":");
reply.content.emplace_back(alternate_descriptionFactory.summary.lengthString);
reply.content.emplace_back(","
"\"total_time\":");
reply.content.emplace_back(alternate_descriptionFactory.summary.durationString);
reply.content.emplace_back(","
"\"start_point\":\"");
reply.content.emplace_back(
facade->GetEscapedNameForNameID(description_factory.summary.startName));
reply.content.emplace_back("\","
"\"end_point\":\"");
reply.content.emplace_back(
facade->GetEscapedNameForNameID(description_factory.summary.destName));
reply.content.emplace_back("\"");
reply.content.emplace_back("}");
}
reply.content.emplace_back("],");
// //Get Names for both routes JSON::Object json_alternate_route_summary;
RouteNames routeNames; JSON::Array json_alternate_route_summary_array;
GetRouteNames(shortest_path_segments, alternative_path_segments, facade, routeNames); 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\":[\""); JSON::Array json_altenative_indices_array;
reply.content.emplace_back(routeNames.shortest_path_name_1); json_altenative_indices_array.values.push_back(0);
reply.content.emplace_back("\",\""); json_altenative_indices_array.values.push_back(alternate_description_factory.path_description.size());
reply.content.emplace_back(routeNames.shortest_path_name_2); json_result.values["alternative_indices"] = json_altenative_indices_array;
reply.content.emplace_back("\"],"
"\"alternative_names\":[");
reply.content.emplace_back("[\"");
reply.content.emplace_back(routeNames.alternative_path_name_1);
reply.content.emplace_back("\",\"");
reply.content.emplace_back(routeNames.alternative_path_name_2);
reply.content.emplace_back("\"]");
reply.content.emplace_back("],");
// list all viapoints so that the client may display it
reply.content.emplace_back("\"via_points\":[");
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty()); 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; } else {
FixedPointCoordinate::convertInternalReversedCoordinateToString( json_result.values["found_alternative"] = JSON::False();
raw_route.segment_end_coordinates.front().source_phantom.location, tmp);
reply.content.emplace_back("[");
reply.content.emplace_back(tmp);
reply.content.emplace_back("]");
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
{
tmp.clear();
FixedPointCoordinate::convertInternalReversedCoordinateToString(
nodes.target_phantom.location, tmp);
reply.content.emplace_back(",[");
reply.content.emplace_back(tmp);
reply.content.emplace_back("]");
} }
reply.content.emplace_back("],"); JSON::Object json_hint_object;
reply.content.emplace_back("\"via_indices\":["); json_hint_object.values["checksum"] = raw_route.check_sum;
for (const unsigned index : shortest_leg_end_indices) JSON::Array json_location_hint_array;
{
tmp.clear();
intToString(index, tmp);
reply.content.emplace_back(tmp);
if (index != shortest_leg_end_indices.back())
{
reply.content.emplace_back(",");
}
}
reply.content.emplace_back("],\"alternative_indices\":[");
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
{
reply.content.emplace_back("0,");
tmp.clear();
intToString(alternate_descriptionFactory.path_description.size(), tmp);
reply.content.emplace_back(tmp);
}
reply.content.emplace_back("],");
reply.content.emplace_back("\"hint_data\": {");
reply.content.emplace_back("\"checksum\":");
intToString(raw_route.check_sum, tmp);
reply.content.emplace_back(tmp);
reply.content.emplace_back(", \"locations\": [");
std::string hint; std::string hint;
for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i) 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); EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
reply.content.emplace_back(hint); json_location_hint_array.values.push_back(hint);
reply.content.emplace_back("\", ");
} }
EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint); EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
reply.content.emplace_back("\""); json_location_hint_array.values.push_back(hint);
reply.content.emplace_back(hint); json_hint_object.values["locations"] = json_location_hint_array;
reply.content.emplace_back("\"]"); json_result.values["hint_data"] = json_hint_object;
reply.content.emplace_back("}}");
// 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 // construct routes names
void GetRouteNames(std::vector<Segment> &shortest_path_segments, void GetRouteNames(std::vector<Segment> &shortest_path_segments,
std::vector<Segment> &alternative_path_segments, std::vector<Segment> &alternative_path_segments,
const DataFacadeT *facade, const DataFacadeT *facade,
RouteNames &routeNames) RouteNames &route_names)
{ {
Segment shortest_segment_1, shortest_segment_2; 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) auto length_comperator = [](Segment a, Segment b)
{ return a.length < b.length; }; { return a.length < b.length; };
@ -351,28 +305,28 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
std::sort(alternative_path_segments.begin(), std::sort(alternative_path_segments.begin(),
alternative_path_segments.end(), alternative_path_segments.end(),
length_comperator); 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> shortest_path_set_difference(shortest_path_segments.size());
std::vector<Segment> alternativeDifference(alternative_path_segments.size()); std::vector<Segment> alternative_path_set_difference(alternative_path_segments.size());
std::set_difference(shortest_path_segments.begin(), std::set_difference(shortest_path_segments.begin(),
shortest_path_segments.end(), shortest_path_segments.end(),
alternative_path_segments.begin(), alternative_path_segments.begin(),
alternative_path_segments.end(), alternative_path_segments.end(),
shortestDifference.begin(), shortest_path_set_difference.begin(),
length_comperator); length_comperator);
int size_of_difference = shortestDifference.size(); int size_of_difference = shortest_path_set_difference.size();
if (size_of_difference) if (size_of_difference)
{ {
int i = 0; int i = 0;
while (i < size_of_difference && 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; ++i;
} }
if (i < size_of_difference) 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(), alternative_path_segments.end(),
shortest_path_segments.begin(), shortest_path_segments.begin(),
shortest_path_segments.end(), shortest_path_segments.end(),
alternativeDifference.begin(), alternative_path_set_difference.begin(),
name_id_comperator); name_id_comperator);
size_of_difference = alternativeDifference.size(); size_of_difference = alternative_path_set_difference.size();
if (size_of_difference) if (size_of_difference)
{ {
int i = 0; int i = 0;
while (i < size_of_difference && 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; ++i;
} }
if (i < size_of_difference) 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) if (shortest_segment_1.position > shortest_segment_2.position)
{
std::swap(shortest_segment_1, shortest_segment_2); std::swap(shortest_segment_1, shortest_segment_2);
}
if (alternativeSegment1.position > alternative_segment_2.position) if (alternative_segment_1.position > alternative_segment_2.position)
std::swap(alternativeSegment1, alternative_segment_2); {
std::swap(alternative_segment_1, alternative_segment_2);
routeNames.shortest_path_name_1 = }
route_names.shortest_path_name_1 =
facade->GetEscapedNameForNameID(shortest_segment_1.name_id); 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); facade->GetEscapedNameForNameID(shortest_segment_2.name_id);
routeNames.alternative_path_name_1 = route_names.alternative_path_name_1 =
facade->GetEscapedNameForNameID(alternativeSegment1.name_id); facade->GetEscapedNameForNameID(alternative_segment_1.name_id);
routeNames.alternative_path_name_2 = route_names.alternative_path_name_2 =
facade->GetEscapedNameForNameID(alternative_segment_2.name_id); facade->GetEscapedNameForNameID(alternative_segment_2.name_id);
} }
} }
// TODO: reorder parameters // TODO: reorder parameters
inline void BuildTextualDescription(DescriptionFactory &description_factory, inline void BuildTextualDescription(DescriptionFactory &description_factory,
http::Reply &reply, JSON::Array & json_instruction_array,
const int route_length, const int route_length,
const DataFacadeT *facade, const DataFacadeT *facade,
std::vector<Segment> &route_segments_list) std::vector<Segment> &route_segments_list)
{ {
// Segment information has following format: // Segment information has following format:
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth] //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
// Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]
unsigned necessary_segments_running_index = 0; unsigned necessary_segments_running_index = 0;
round_about.leave_at_exit = 0; round_about.leave_at_exit = 0;
round_about.name_id = 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. // Fetch data from Factory and generate a string from it.
for (const SegmentInformation &segment : description_factory.path_description) for (const SegmentInformation &segment : description_factory.path_description)
{ {
JSON::Array json_instruction_row;
TurnInstruction current_instruction = segment.turn_instruction; TurnInstruction current_instruction = segment.turn_instruction;
entered_restricted_area_count += (current_instruction != segment.turn_instruction); entered_restricted_area_count += (current_instruction != segment.turn_instruction);
if (TurnInstructionsClass::TurnIsNecessary(current_instruction)) if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
@ -443,50 +399,35 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
} }
else else
{ {
if (necessary_segments_running_index) std::string current_turn_instruction;
{
reply.content.emplace_back(",");
}
reply.content.emplace_back("[\"");
if (TurnInstruction::LeaveRoundAbout == current_instruction) if (TurnInstruction::LeaveRoundAbout == current_instruction)
{ {
intToString(as_integer(TurnInstruction::EnterRoundAbout), temp_instruction); temp_instruction = IntToString(as_integer(TurnInstruction::EnterRoundAbout));
reply.content.emplace_back(temp_instruction); current_turn_instruction += temp_instruction;
reply.content.emplace_back("-"); current_turn_instruction += "-";
intToString(round_about.leave_at_exit + 1, temp_instruction); temp_instruction = IntToString(round_about.leave_at_exit + 1);
reply.content.emplace_back(temp_instruction); current_turn_instruction += temp_instruction;
round_about.leave_at_exit = 0; round_about.leave_at_exit = 0;
} }
else else
{ {
intToString(as_integer(current_instruction), temp_instruction); temp_instruction = IntToString(as_integer(current_instruction));
reply.content.emplace_back(temp_instruction); current_turn_instruction += temp_instruction;
} }
json_instruction_row.values.push_back(current_turn_instruction);
reply.content.emplace_back("\",\""); json_instruction_row.values.push_back(facade->GetEscapedNameForNameID(segment.name_id));
reply.content.emplace_back(facade->GetEscapedNameForNameID(segment.name_id)); json_instruction_row.values.push_back(std::round(segment.length));
reply.content.emplace_back("\","); json_instruction_row.values.push_back(necessary_segments_running_index);
intToString(segment.length, temp_dist); json_instruction_row.values.push_back(round(segment.duration / 10));
reply.content.emplace_back(temp_dist); json_instruction_row.values.push_back(IntToString(segment.length)+"m");
reply.content.emplace_back(",");
intToString(necessary_segments_running_index, temp_length);
reply.content.emplace_back(temp_length);
reply.content.emplace_back(",");
intToString(round(segment.duration / 10.), temp_duration);
reply.content.emplace_back(temp_duration);
reply.content.emplace_back(",\"");
intToString(segment.length, temp_length);
reply.content.emplace_back(temp_length);
reply.content.emplace_back("m\",\"");
int bearing_value = round(segment.bearing / 10.); int bearing_value = round(segment.bearing / 10.);
reply.content.emplace_back(Azimuth::Get(bearing_value)); json_instruction_row.values.push_back(Azimuth::Get(bearing_value));
reply.content.emplace_back("\","); json_instruction_row.values.push_back(bearing_value);
intToString(bearing_value, temp_bearing);
reply.content.emplace_back(temp_bearing);
reply.content.emplace_back("]");
route_segments_list.emplace_back( 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) else if (TurnInstruction::StayOnRoundAbout == current_instruction)
@ -498,25 +439,21 @@ template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFa
++necessary_segments_running_index; ++necessary_segments_running_index;
} }
} }
//TODO: check if this in an invariant
if (INVALID_EDGE_WEIGHT != route_length) if (INVALID_EDGE_WEIGHT != route_length)
{ {
reply.content.emplace_back(",[\""); JSON::Array json_last_instruction_row;
intToString(as_integer(TurnInstruction::ReachedYourDestination), temp_instruction); temp_instruction = IntToString(as_integer(TurnInstruction::ReachedYourDestination));
reply.content.emplace_back(temp_instruction); json_last_instruction_row.values.push_back(temp_instruction);
reply.content.emplace_back("\",\""); json_last_instruction_row.values.push_back("");
reply.content.emplace_back("\","); json_last_instruction_row.values.push_back(0);
reply.content.emplace_back("0"); json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
reply.content.emplace_back(","); json_last_instruction_row.values.push_back(0);
intToString(necessary_segments_running_index - 1, temp_length); json_last_instruction_row.values.push_back("0m");
reply.content.emplace_back(temp_length); json_last_instruction_row.values.push_back(Azimuth::Get(0.0));
reply.content.emplace_back(","); json_last_instruction_row.values.push_back(0.);
reply.content.emplace_back("0"); json_instruction_array.values.push_back(json_last_instruction_row);
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("]");
} }
} }
}; };

View File

@ -58,7 +58,7 @@ class Reply
std::vector<Header> headers; std::vector<Header> headers;
std::vector<boost::asio::const_buffer> toBuffers(); std::vector<boost::asio::const_buffer> toBuffers();
std::vector<boost::asio::const_buffer> HeaderstoBuffers(); std::vector<boost::asio::const_buffer> HeaderstoBuffers();
std::vector<std::string> content; std::vector<char> content;
static Reply StockReply(status_type status); static Reply StockReply(status_type status);
void setSize(const unsigned size); void setSize(const unsigned size);
void SetUncompressedSize(); void SetUncompressedSize();

View File

@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "OSRM_impl.h" #include "OSRM_impl.h"
#include "OSRM.h" #include "OSRM.h"
#include "../Plugins/DistanceTablePlugin.h"
#include "../Plugins/HelloWorldPlugin.h" #include "../Plugins/HelloWorldPlugin.h"
#include "../Plugins/LocatePlugin.h" #include "../Plugins/LocatePlugin.h"
#include "../Plugins/NearestPlugin.h" #include "../Plugins/NearestPlugin.h"
@ -55,6 +56,7 @@ OSRM_impl::OSRM_impl(const ServerPaths &server_paths, const bool use_shared_memo
} }
// The following plugins handle all requests. // The following plugins handle all requests.
RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new HelloWorldPlugin()); RegisterPlugin(new HelloWorldPlugin());
RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade)); RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade)); RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));

View File

@ -0,0 +1,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

View File

@ -25,10 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef HELLOWORLDPLUGIN_H_ #ifndef HELLO_WORLD_PLUGIN_H
#define HELLOWORLDPLUGIN_H_ #define HELLO_WORLD_PLUGIN_H
#include "BasePlugin.h" #include "BasePlugin.h"
#include "../DataStructures/JSONContainer.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include <string> #include <string>
@ -46,70 +47,58 @@ class HelloWorldPlugin : public BasePlugin
void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
{ {
reply.status = http::Reply::ok; reply.status = http::Reply::ok;
reply.content.emplace_back("<html><head><title>Hello World Demonstration "
"Document</title></head><body><h1>Hello, World!</h1>");
reply.content.emplace_back("<pre>");
reply.content.emplace_back("zoom level: ");
intToString(routeParameters.zoom_level, temp_string);
reply.content.emplace_back(temp_string);
reply.content.emplace_back("\nchecksum: ");
intToString(routeParameters.check_sum, temp_string);
reply.content.emplace_back(temp_string);
reply.content.emplace_back("\ninstructions: ");
reply.content.emplace_back((routeParameters.print_instructions ? "yes" : "no"));
reply.content.emplace_back(temp_string);
reply.content.emplace_back("\ngeometry: ");
reply.content.emplace_back((routeParameters.geometry ? "yes" : "no"));
reply.content.emplace_back("\ncompression: ");
reply.content.emplace_back((routeParameters.compression ? "yes" : "no"));
reply.content.emplace_back("\noutput format: ");
reply.content.emplace_back(routeParameters.output_format);
reply.content.emplace_back("\njson parameter: ");
reply.content.emplace_back(routeParameters.jsonp_parameter);
reply.content.emplace_back("\nlanguage: ");
reply.content.emplace_back(routeParameters.language);
reply.content.emplace_back("\nNumber of locations: ");
intToString(routeParameters.coordinates.size(), temp_string);
reply.content.emplace_back(temp_string);
reply.content.emplace_back("\n");
JSON::Object json_result;
std::string temp_string;
json_result.values["title"] = "Hello World";
temp_string = IntToString(routeParameters.zoom_level);
json_result.values["zoom_level"] = temp_string;
temp_string = IntToString(routeParameters.check_sum);
json_result.values["check_sum"] = temp_string;
json_result.values["instructions"] = (routeParameters.print_instructions ? "yes" : "no");
json_result.values["geometry"] = (routeParameters.geometry ? "yes" : "no");
json_result.values["compression"] = (routeParameters.compression ? "yes" : "no");
json_result.values["output_format"] = (!routeParameters.output_format.empty() ? "yes" : "no");
json_result.values["jsonp_parameter"] = (!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
json_result.values["language"] = (!routeParameters.language.empty() ? "yes" : "no");
temp_string = IntToString(routeParameters.coordinates.size());
json_result.values["location_count"] = temp_string;
JSON::Array json_locations;
unsigned counter = 0; unsigned counter = 0;
for (const FixedPointCoordinate &coordinate : routeParameters.coordinates) for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
{ {
reply.content.emplace_back(" ["); JSON::Object json_location;
intToString(counter, temp_string); JSON::Array json_coordinates;
reply.content.emplace_back(temp_string);
reply.content.emplace_back("] "); json_coordinates.values.push_back(coordinate.lat / COORDINATE_PRECISION);
doubleToString(coordinate.lat / COORDINATE_PRECISION, temp_string); json_coordinates.values.push_back(coordinate.lon / COORDINATE_PRECISION);
reply.content.emplace_back(temp_string); json_location.values[IntToString(counter)] = json_coordinates;
reply.content.emplace_back(","); json_locations.values.push_back(json_location);
doubleToString(coordinate.lon / COORDINATE_PRECISION, temp_string);
reply.content.emplace_back(temp_string);
reply.content.emplace_back("\n");
++counter; ++counter;
} }
json_result.values["locations"] = json_locations;
json_result.values["hint_count"] = routeParameters.hints.size();
reply.content.emplace_back("Number of hints: "); JSON::Array json_hints;
intToString(routeParameters.hints.size(), temp_string);
reply.content.emplace_back(temp_string);
reply.content.emplace_back("\n");
counter = 0; counter = 0;
for (const std::string &current_string : routeParameters.hints) for (const std::string &current_hint : routeParameters.hints)
{ {
reply.content.emplace_back(" ["); // JSON::String json_hint_string = current_hint;
intToString(counter, temp_string); json_hints.values.push_back(current_hint);
reply.content.emplace_back(temp_string);
reply.content.emplace_back("] ");
reply.content.emplace_back(current_string);
reply.content.emplace_back("\n");
++counter; ++counter;
} }
reply.content.emplace_back("</pre></body></html>"); json_result.values["hints"] = json_hints;
JSON::render(reply.content, json_result);
} }
private: private:
std::string descriptor_string; std::string descriptor_string;
}; };
#endif /* HELLOWORLDPLUGIN_H_ */ #endif // HELLO_WORLD_PLUGIN_H

View File

@ -29,10 +29,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define LOCATE_PLUGIN_H #define LOCATE_PLUGIN_H
#include "BasePlugin.h" #include "BasePlugin.h"
#include "../DataStructures/JSONContainer.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
// locates the nearest node in the road network for a given coordinate. #include <string>
// locates the nearest node in the road network for a given coordinate.
template <class DataFacadeT> class LocatePlugin : public BasePlugin template <class DataFacadeT> class LocatePlugin : public BasePlugin
{ {
public: public:
@ -42,70 +44,36 @@ template <class DataFacadeT> class LocatePlugin : public BasePlugin
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
{ {
// check number of parameters // check number of parameters
if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid()) if (route_parameters.coordinates.empty())
{
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); reply = http::Reply::StockReply(http::Reply::badRequest);
return; return;
} }
// query to helpdesk JSON::Object json_result;
FixedPointCoordinate result; FixedPointCoordinate result;
std::string tmp;
// json
if (!route_parameters.jsonp_parameter.empty())
{
reply.content.emplace_back(route_parameters.jsonp_parameter);
reply.content.emplace_back("(");
}
reply.status = http::Reply::ok;
reply.content.emplace_back("{");
if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(), if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(),
result)) result))
{ {
reply.content.emplace_back("\"status\":207,"); json_result.values["status"] = 207;
reply.content.emplace_back("\"mapped_coordinate\":[]");
} }
else else
{ {
// Write coordinate to stream
reply.status = http::Reply::ok; reply.status = http::Reply::ok;
reply.content.emplace_back("\"status\":0,"); json_result.values["status"] = 0;
reply.content.emplace_back("\"mapped_coordinate\":"); JSON::Array json_coordinate;
FixedPointCoordinate::convertInternalLatLonToString(result.lat, tmp); json_coordinate.values.push_back(result.lat/COORDINATE_PRECISION);
reply.content.emplace_back("["); json_coordinate.values.push_back(result.lon/COORDINATE_PRECISION);
reply.content.emplace_back(tmp); json_result.values["mapped_coordinate"] = json_coordinate;
FixedPointCoordinate::convertInternalLatLonToString(result.lon, tmp);
reply.content.emplace_back(",");
reply.content.emplace_back(tmp);
reply.content.emplace_back("]");
} }
reply.content.emplace_back("}");
reply.headers.resize(3); JSON::render(reply.content, json_result);
if (!route_parameters.jsonp_parameter.empty())
{
reply.content.emplace_back(")");
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "text/javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"location.js\"";
}
else
{
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "application/x-javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"location.json\"";
}
reply.headers[0].name = "Content-Length";
unsigned content_length = 0;
for (const std::string &snippet : reply.content)
{
content_length += snippet.length();
}
intToString(content_length, tmp);
reply.headers[0].value = tmp;
return;
} }
private: private:

View File

@ -29,10 +29,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define NEAREST_PLUGIN_H #define NEAREST_PLUGIN_H
#include "BasePlugin.h" #include "BasePlugin.h"
#include "../DataStructures/JSONContainer.h"
#include "../DataStructures/PhantomNodes.h" #include "../DataStructures/PhantomNodes.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include <unordered_map> #include <string>
/* /*
* This Plugin locates the nearest point on a street in the road network for a given coordinate. * This Plugin locates the nearest point on a street in the road network for a given coordinate.
@ -43,8 +44,6 @@ template <class DataFacadeT> class NearestPlugin : public BasePlugin
public: public:
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest")
{ {
descriptor_table.emplace("", 0); // default descriptor
descriptor_table.emplace("json", 1);
} }
const std::string GetDescriptor() const { return descriptor_string; } const std::string GetDescriptor() const { return descriptor_string; }
@ -57,81 +56,40 @@ template <class DataFacadeT> class NearestPlugin : public BasePlugin
reply = http::Reply::StockReply(http::Reply::badRequest); reply = http::Reply::StockReply(http::Reply::badRequest);
return; return;
} }
// check if queried location is sane
if (!route_parameters.coordinates.front().isValid()) if (!route_parameters.coordinates.front().isValid())
{ {
reply = http::Reply::StockReply(http::Reply::badRequest); reply = http::Reply::StockReply(http::Reply::badRequest);
return; return;
} }
PhantomNode result; PhantomNode phantom_node;
facade->FindPhantomNodeForCoordinate( facade->FindPhantomNodeForCoordinate(
route_parameters.coordinates.front(), result, route_parameters.zoom_level); route_parameters.coordinates.front(), phantom_node, route_parameters.zoom_level);
// json JSON::Object json_result;
if (!phantom_node.isValid())
if (!route_parameters.jsonp_parameter.empty())
{ {
reply.content.emplace_back(route_parameters.jsonp_parameter); json_result.values["status"] = 207;
reply.content.emplace_back("(");
} }
else
{
reply.status = http::Reply::ok; reply.status = http::Reply::ok;
reply.content.emplace_back("{\"status\":"); json_result.values["status"] = 0;
if (SPECIAL_NODEID != result.forward_node_id) JSON::Array json_coordinate;
{ json_coordinate.values.push_back(phantom_node.location.lat/COORDINATE_PRECISION);
reply.content.emplace_back("0,"); json_coordinate.values.push_back(phantom_node.location.lon/COORDINATE_PRECISION);
} json_result.values["mapped_coordinate"] = json_coordinate;
else
{
reply.content.emplace_back("207,");
}
reply.content.emplace_back("\"mapped_coordinate\":[");
std::string temp_string; std::string temp_string;
facade->GetName(phantom_node.name_id, temp_string);
json_result.values["name"] = temp_string;
}
if (SPECIAL_NODEID != result.forward_node_id) JSON::render(reply.content, json_result);
{
FixedPointCoordinate::convertInternalLatLonToString(result.location.lat, temp_string);
reply.content.emplace_back(temp_string);
FixedPointCoordinate::convertInternalLatLonToString(result.location.lon, temp_string);
reply.content.emplace_back(",");
reply.content.emplace_back(temp_string);
}
reply.content.emplace_back("],\"name\":\"");
if (SPECIAL_NODEID != result.forward_node_id)
{
facade->GetName(result.name_id, temp_string);
reply.content.emplace_back(temp_string);
}
reply.content.emplace_back("\"}");
reply.headers.resize(3);
if (!route_parameters.jsonp_parameter.empty())
{
reply.content.emplace_back(")");
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "text/javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"location.js\"";
}
else
{
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "application/x-javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"location.json\"";
}
reply.headers[0].name = "Content-Length";
unsigned content_length = 0;
for (const std::string &snippet : reply.content)
{
content_length += snippet.length();
}
intToString(content_length, temp_string);
reply.headers[0].value = temp_string;
} }
private: private:
DataFacadeT *facade; DataFacadeT *facade;
std::unordered_map<std::string, unsigned> descriptor_table;
std::string descriptor_string; std::string descriptor_string;
}; };

View File

@ -28,8 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef TIMESTAMP_PLUGIN_H #ifndef TIMESTAMP_PLUGIN_H
#define TIMESTAMP_PLUGIN_H #define TIMESTAMP_PLUGIN_H
#include "../DataStructures/JSONContainer.h"
#include "BasePlugin.h" #include "BasePlugin.h"
#include <string>
template <class DataFacadeT> class TimestampPlugin : public BasePlugin template <class DataFacadeT> class TimestampPlugin : public BasePlugin
{ {
public: public:
@ -40,46 +43,12 @@ template <class DataFacadeT> class TimestampPlugin : public BasePlugin
const std::string GetDescriptor() const { return descriptor_string; } const std::string GetDescriptor() const { return descriptor_string; }
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
{ {
std::string tmp;
// json
if (!route_parameters.jsonp_parameter.empty())
{
reply.content.emplace_back(route_parameters.jsonp_parameter);
reply.content.emplace_back("(");
}
reply.status = http::Reply::ok; reply.status = http::Reply::ok;
reply.content.emplace_back("{"); JSON::Object json_result;
reply.content.emplace_back("\"status\":"); json_result.values["status"] = 0;
reply.content.emplace_back("0,"); const std::string timestamp = facade->GetTimestamp();
reply.content.emplace_back("\"timestamp\":\""); json_result.values["timestamp"] = timestamp;
reply.content.emplace_back(facade->GetTimestamp()); JSON::render(reply.content, json_result);
reply.content.emplace_back("\"");
reply.content.emplace_back("}");
reply.headers.resize(3);
if (!route_parameters.jsonp_parameter.empty())
{
reply.content.emplace_back(")");
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "text/javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"timestamp.js\"";
}
else
{
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "application/x-javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"timestamp.json\"";
}
unsigned content_length = 0;
for (const std::string &snippet : reply.content)
{
content_length += snippet.length();
}
intToString(content_length, tmp);
reply.headers[0].value = tmp;
} }
private: private:

View File

@ -25,12 +25,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef VIAROUTEPLUGIN_H_ #ifndef VIA_ROUTE_PLUGIN_H
#define VIAROUTEPLUGIN_H_ #define VIA_ROUTE_PLUGIN_H
#include "BasePlugin.h" #include "BasePlugin.h"
#include "../Algorithms/ObjectToBase64.h" #include "../Algorithms/ObjectToBase64.h"
#include "../DataStructures/QueryEdge.h" #include "../DataStructures/QueryEdge.h"
#include "../DataStructures/SearchEngine.h" #include "../DataStructures/SearchEngine.h"
#include "../Descriptors/BaseDescriptor.h" #include "../Descriptors/BaseDescriptor.h"
@ -60,6 +61,7 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
descriptor_table.emplace("json", 0); descriptor_table.emplace("json", 0);
descriptor_table.emplace("gpx", 1); descriptor_table.emplace("gpx", 1);
// descriptor_table.emplace("geojson", 2);
} }
virtual ~ViaRoutePlugin() {} virtual ~ViaRoutePlugin() {}
@ -119,7 +121,9 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair); 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(), search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
raw_route); raw_route);
@ -135,12 +139,6 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
} }
reply.status = http::Reply::ok; 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; DescriptorConfig descriptor_config;
auto iter = descriptor_table.find(route_parameters.output_format); auto iter = descriptor_table.find(route_parameters.output_format);
@ -160,6 +158,9 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
case 1: case 1:
descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(); descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>();
break; break;
// case 2:
// descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
// break;
default: default:
descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(); descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
break; break;
@ -170,67 +171,6 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
phantom_nodes.target_phantom = raw_route.segment_end_coordinates.back().target_phantom; phantom_nodes.target_phantom = raw_route.segment_end_coordinates.back().target_phantom;
descriptor->SetConfig(descriptor_config); descriptor->SetConfig(descriptor_config);
descriptor->Run(raw_route, phantom_nodes, facade, reply); 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: private:
@ -238,4 +178,4 @@ template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
DataFacadeT *facade; DataFacadeT *facade;
}; };
#endif /* VIAROUTEPLUGIN_H_ */ #endif // VIA_ROUTE_PLUGIN_H

View File

@ -78,6 +78,7 @@ template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInte
{ {
if (phantom_node_pair.PhantomNodesHaveEqualLocation()) if (phantom_node_pair.PhantomNodesHaveEqualLocation())
{ {
BOOST_ASSERT(false);
return; return;
} }

View File

@ -0,0 +1,246 @@
/*
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MANY_TO_MANY_ROUTING_H
#define MANY_TO_MANY_ROUTING_H
#include "BasicRoutingInterface.h"
#include "../DataStructures/SearchEngineData.h"
#include "../typedefs.h"
#include <boost/assert.hpp>
#include <limits>
#include <memory>
#include <unordered_map>
#include <vector>
template <class DataFacadeT> class ManyToManyRouting : public BasicRoutingInterface<DataFacadeT>
{
typedef BasicRoutingInterface<DataFacadeT> super;
typedef SearchEngineData::QueryHeap QueryHeap;
SearchEngineData &engine_working_data;
struct NodeBucket
{
unsigned target_id; // essentially a row in the distance matrix
EdgeWeight distance;
NodeBucket(const unsigned target_id, const EdgeWeight distance)
: target_id(target_id), distance(distance)
{
}
};
typedef std::unordered_map<NodeID, std::vector<NodeBucket>> SearchSpaceWithBuckets;
public:
ManyToManyRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
: super(facade), engine_working_data(engine_working_data)
{
}
~ManyToManyRouting() {}
std::shared_ptr<std::vector<EdgeWeight>>
operator()(const std::vector<PhantomNode> &phantom_nodes_vector) const
{
const unsigned number_of_locations = phantom_nodes_vector.size();
std::shared_ptr<std::vector<EdgeWeight>> result_table = std::make_shared<std::vector<EdgeWeight>>(
number_of_locations * number_of_locations, std::numeric_limits<EdgeWeight>::max());
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
super::facade->GetNumberOfNodes());
QueryHeap &query_heap = *(engine_working_data.forwardHeap);
SearchSpaceWithBuckets search_space_with_buckets;
unsigned target_id = 0;
for (const PhantomNode &phantom_node : phantom_nodes_vector)
{
query_heap.Clear();
// insert target(s) at distance 0
if (SPECIAL_NODEID != phantom_node.forward_node_id)
{
query_heap.Insert(phantom_node.forward_node_id, phantom_node.GetForwardWeightPlusOffset(), phantom_node.forward_node_id);
}
if (SPECIAL_NODEID != phantom_node.reverse_node_id)
{
query_heap.Insert(phantom_node.reverse_node_id, phantom_node.GetReverseWeightPlusOffset(), phantom_node.reverse_node_id);
}
// explore search space
while (!query_heap.Empty())
{
BackwardRoutingStep(target_id, query_heap, search_space_with_buckets);
}
++target_id;
}
// for each source do forward search
unsigned source_id = 0;
for (const PhantomNode &phantom_node : phantom_nodes_vector)
{
query_heap.Clear();
// insert sources at distance 0
if (SPECIAL_NODEID != phantom_node.forward_node_id)
{
query_heap.Insert(phantom_node.forward_node_id, -phantom_node.GetForwardWeightPlusOffset(), phantom_node.forward_node_id);
}
if (SPECIAL_NODEID != phantom_node.reverse_node_id)
{
query_heap.Insert(phantom_node.reverse_node_id, -phantom_node.GetReverseWeightPlusOffset(), phantom_node.reverse_node_id);
}
// explore search space
while (!query_heap.Empty())
{
ForwardRoutingStep(source_id,
number_of_locations,
query_heap,
search_space_with_buckets,
result_table);
}
++source_id;
}
BOOST_ASSERT(source_id == target_id);
return result_table;
}
void ForwardRoutingStep(const unsigned source_id,
const unsigned number_of_locations,
QueryHeap &query_heap,
const SearchSpaceWithBuckets &search_space_with_buckets,
std::shared_ptr<std::vector<EdgeWeight>> result_table) const
{
const NodeID node = query_heap.DeleteMin();
const int source_distance = query_heap.GetKey(node);
// check if each encountered node has an entry
const auto bucket_iterator = search_space_with_buckets.find(node);
// iterate bucket if there exists one
if (bucket_iterator != search_space_with_buckets.end())
{
const std::vector<NodeBucket> &bucket_list = bucket_iterator->second;
for (const NodeBucket &current_bucket : bucket_list)
{
// get target id from bucket entry
const unsigned target_id = current_bucket.target_id;
const unsigned target_distance = current_bucket.distance;
const EdgeWeight current_distance =
(*result_table)[source_id * number_of_locations + target_id];
// check if new distance is better
if ((source_distance + target_distance) < current_distance)
{
(*result_table)[source_id * number_of_locations + target_id] =
(source_distance + target_distance);
}
}
}
if (StallAtNode<true>(node, source_distance, query_heap))
{
return;
}
RelaxOutgoingEdges<true>(node, source_distance, query_heap);
}
void BackwardRoutingStep(const unsigned target_id,
QueryHeap &query_heap,
SearchSpaceWithBuckets &search_space_with_buckets) const
{
const NodeID node = query_heap.DeleteMin();
const int target_distance = query_heap.GetKey(node);
// store settled nodes in search space bucket
search_space_with_buckets[node].emplace_back(target_id, target_distance);
if (StallAtNode<false>(node, target_distance, query_heap))
{
return;
}
RelaxOutgoingEdges<false>(node, target_distance, query_heap);
}
template <bool forward_direction>
inline void
RelaxOutgoingEdges(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap) const
{
for (auto edge : super::facade->GetAdjacentEdgeRange(node))
{
const auto &data = super::facade->GetEdgeData(edge);
const bool direction_flag = (forward_direction ? data.forward : data.backward);
if (direction_flag)
{
const NodeID to = super::facade->GetTarget(edge);
const int edge_weight = data.distance;
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
const int to_distance = distance + edge_weight;
// New Node discovered -> Add to Heap + Node Info Storage
if (!query_heap.WasInserted(to))
{
query_heap.Insert(to, to_distance, node);
}
// Found a shorter Path -> Update distance
else if (to_distance < query_heap.GetKey(to))
{
// new parent
query_heap.GetData(to).parent = node;
query_heap.DecreaseKey(to, to_distance);
}
}
}
}
// Stalling
template <bool forward_direction>
inline bool StallAtNode(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap) const
{
for (auto edge : super::facade->GetAdjacentEdgeRange(node))
{
const auto &data = super::facade->GetEdgeData(edge);
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
if (reverse_flag)
{
const NodeID to = super::facade->GetTarget(edge);
const int edge_weight = data.distance;
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
if (query_heap.WasInserted(to))
{
if (query_heap.GetKey(to) + edge_weight < distance)
{
return true;
}
}
}
}
return false;
}
};
#endif

View File

@ -55,6 +55,7 @@ template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInte
{ {
if (phantom_node_pair.AtLeastOnePhantomNodeIsInvalid()) if (phantom_node_pair.AtLeastOnePhantomNodeIsInvalid())
{ {
BOOST_ASSERT(false);
return; return;
} }
} }

View File

@ -45,7 +45,7 @@ struct APIGrammar : qi::grammar<Iterator>
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)]; zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)]; output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)]; jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)]; checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)]; instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)]; geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)]; cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];

View File

@ -81,6 +81,7 @@ void Connection::handle_read(const boost::system::error_code &e, std::size_t byt
Header compression_header; Header compression_header;
std::vector<char> compressed_output; std::vector<char> compressed_output;
std::vector<boost::asio::const_buffer> output_buffer; std::vector<boost::asio::const_buffer> output_buffer;
switch (compression_type) switch (compression_type)
{ {
case deflateRFC1951: case deflateRFC1951:
@ -158,7 +159,7 @@ void Connection::handle_write(const boost::system::error_code &e)
} }
} }
void Connection::compressBufferCollection(std::vector<std::string> uncompressed_data, void Connection::compressBufferCollection(std::vector<char> uncompressed_data,
CompressionType compression_type, CompressionType compression_type,
std::vector<char> &compressed_data) std::vector<char> &compressed_data)
{ {
@ -171,16 +172,10 @@ void Connection::compressBufferCollection(std::vector<std::string> uncompressed_
} }
BOOST_ASSERT(compressed_data.empty()); BOOST_ASSERT(compressed_data.empty());
boost::iostreams::filtering_ostream compressing_stream; boost::iostreams::filtering_ostream gzip_stream;
gzip_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
compressing_stream.push(boost::iostreams::gzip_compressor(compression_parameters)); gzip_stream.push(boost::iostreams::back_inserter(compressed_data));
compressing_stream.push(boost::iostreams::back_inserter(compressed_data)); gzip_stream.write(&uncompressed_data[0], uncompressed_data.size());
boost::iostreams::close(gzip_stream);
for (const std::string &line : uncompressed_data)
{
compressing_stream << line;
}
compressing_stream.reset();
} }
} }

View File

@ -89,7 +89,7 @@ class Connection : public std::enable_shared_from_this<Connection>
/// Handle completion of a write operation. /// Handle completion of a write operation.
void handle_write(const boost::system::error_code &e); void handle_write(const boost::system::error_code &e);
void compressBufferCollection(std::vector<std::string> uncompressed_data, void compressBufferCollection(std::vector<char> uncompressed_data,
CompressionType compression_type, CompressionType compression_type,
std::vector<char> &compressed_data); std::vector<char> &compressed_data);

View File

@ -38,7 +38,7 @@ void Reply::setSize(const unsigned size)
{ {
if ("Content-Length" == h.name) if ("Content-Length" == h.name)
{ {
intToString(size, h.value); h.value = IntToString(size);
} }
} }
} }
@ -47,10 +47,7 @@ void Reply::setSize(const unsigned size)
void Reply::SetUncompressedSize() void Reply::SetUncompressedSize()
{ {
unsigned uncompressed_size = 0; unsigned uncompressed_size = 0;
for (const std::string &current_line : content) uncompressed_size = content.size();
{
uncompressed_size += current_line.size();
}
setSize(uncompressed_size); setSize(uncompressed_size);
} }
@ -66,10 +63,7 @@ std::vector<boost::asio::const_buffer> Reply::toBuffers()
buffers.push_back(boost::asio::buffer(crlf)); buffers.push_back(boost::asio::buffer(crlf));
} }
buffers.push_back(boost::asio::buffer(crlf)); buffers.push_back(boost::asio::buffer(crlf));
for (const std::string &line : content) buffers.push_back(boost::asio::buffer(content));
{
buffers.push_back(boost::asio::buffer(line));
}
return buffers; return buffers;
} }
@ -94,14 +88,15 @@ Reply Reply::StockReply(Reply::status_type status)
Reply rep; Reply rep;
rep.status = status; rep.status = status;
rep.content.clear(); rep.content.clear();
rep.content.push_back(rep.ToString(status));
const std::string status_string = rep.ToString(status);
rep.content.insert(rep.content.end(), status_string.begin(), status_string.end());
rep.headers.resize(3); rep.headers.resize(3);
rep.headers[0].name = "Access-Control-Allow-Origin"; rep.headers[0].name = "Access-Control-Allow-Origin";
rep.headers[0].value = "*"; rep.headers[0].value = "*";
rep.headers[1].name = "Content-Length"; rep.headers[1].name = "Content-Length";
std::string size_string; std::string size_string = IntToString(rep.content.size());
intToString(rep.content.size(), size_string);
rep.headers[1].value = size_string; rep.headers[1].value = size_string;
rep.headers[2].name = "Content-Type"; rep.headers[2].name = "Content-Type";

View File

@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "RequestHandler.h" #include "RequestHandler.h"
#include "Http/Request.h" #include "Http/Request.h"
#include "../DataStructures/JSONContainer.h"
#include "../Library/OSRM.h" #include "../Library/OSRM.h"
#include "../Util/SimpleLogger.h" #include "../Util/SimpleLogger.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
@ -85,18 +86,51 @@ void RequestHandler::handle_request(const http::Request &req, http::Reply &reply
reply = http::Reply::StockReply(http::Reply::badRequest); reply = http::Reply::StockReply(http::Reply::badRequest);
reply.content.clear(); reply.content.clear();
const int position = std::distance(request.begin(), it); const int position = std::distance(request.begin(), it);
reply.content.push_back( JSON::Object json_result;
"{\"status\":400,\"status_message\":\"Query string malformed close to position "); json_result.values["status"] = 400;
std::string tmp_position_string; std::string tmp_position_string = IntToString(position);
intToString(position, tmp_position_string); std::string message = ("Query string malformed close to position " + IntToString(position));
reply.content.push_back(tmp_position_string); json_result.values["status_message"] = message;
reply.content.push_back("\"}"); JSON::render(reply.content, json_result);
} }
else else
{ {
// parsing done, lets call the right plugin to handle the request // parsing done, lets call the right plugin to handle the request
BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed"); BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
if (!route_parameters.jsonp_parameter.empty())
{
const std::string json_p = (route_parameters.jsonp_parameter + "(");
reply.content.insert(reply.content.end(), json_p.begin(), json_p.end());
}
routing_machine->RunQuery(route_parameters, reply); routing_machine->RunQuery(route_parameters, reply);
// set headers, still ugly and should be reworked
reply.headers.resize(3);
if ("gpx" == route_parameters.output_format)
{
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "application/gpx+xml; charset=UTF-8";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"route.gpx\"";
}
else if (!route_parameters.jsonp_parameter.empty())
{
reply.content.push_back(')');
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "text/javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"response.js\"";
}
else
{
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "application/x-javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"response.json\"";
}
reply.headers[0].name = "Content-Length";
reply.headers[0].value = IntToString(reply.content.size());
return; return;
} }
} }

View File

@ -41,12 +41,8 @@ struct ServerFactory
ServerFactory(const ServerFactory &) = delete; ServerFactory(const ServerFactory &) = delete;
static Server *CreateServer(std::string &ip_address, int ip_port, int threads) static Server *CreateServer(std::string &ip_address, int ip_port, int threads)
{ {
SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion(); SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
std::string port_stream = IntToString(ip_port);
std::string port_stream;
intToString(ip_port, port_stream);
return new Server(ip_address, port_stream, std::min(omp_get_num_procs(), threads)); return new Server(ip_address, port_stream, std::min(omp_get_num_procs(), threads));
} }
}; };

View File

@ -110,10 +110,10 @@ int main(int argc, const char *argv[])
// attention: super-inefficient hack below: // attention: super-inefficient hack below:
std::stringstream my_stream; std::stringstream my_stream;
for (const std::string &line : osrm_reply.content) for (const auto &element : osrm_reply.content)
{ {
std::cout << line; std::cout << element;
my_stream << line; my_stream << element;
} }
std::cout << std::endl; std::cout << std::endl;

View File

@ -80,11 +80,12 @@ auto as_integer(Enumeration const value)
return static_cast<typename std::underlying_type<Enumeration>::type>(value); return static_cast<typename std::underlying_type<Enumeration>::type>(value);
} }
static inline void intToString(const int value, std::string &output) static inline std::string IntToString(const int value)
{ {
output.clear(); std::string output;
std::back_insert_iterator<std::string> sink(output); std::back_insert_iterator<std::string> sink(output);
boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value); boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value);
return output;
} }
static inline void int64ToString(const int64_t value, std::string &output) static inline void int64ToString(const int64_t value, std::string &output)
@ -168,11 +169,35 @@ static inline double StringToDouble(const char *p)
return r; return r;
} }
static inline void doubleToString(const double value, std::string &output) template <typename T>
struct scientific_policy : boost::spirit::karma::real_policies<T>
{ {
output.clear(); // we want the numbers always to be in fixed format
static int floatfield(T n) { return boost::spirit::karma::real_policies<T>::fmtflags::fixed; }
static unsigned int precision(T) { return 6; }
};
typedef
boost::spirit::karma::real_generator<double, scientific_policy<double> >
science_type;
static inline std::string FixedDoubleToString(const double value)
{
std::string output;
std::back_insert_iterator<std::string> sink(output); std::back_insert_iterator<std::string> sink(output);
boost::spirit::karma::generate(sink, boost::spirit::karma::double_, value); boost::spirit::karma::generate(sink, science_type(), value);
if (output.size() >= 2 && output[output.size()-2] == '.' && output[output.size()-1] == '0')
{
output.resize(output.size()-2);
}
return output;
}
static inline std::string DoubleToString(const double value)
{
std::string output;
std::back_insert_iterator<std::string> sink(output);
boost::spirit::karma::generate(sink, value);
return output;
} }
static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string &output) static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string &output)