Support for multi-segment routes. Needs to be further tested
This commit is contained in:
parent
ccf40b53eb
commit
c60c3fcd3c
@ -346,21 +346,6 @@ inline double ApproximateDistance( const int lat1, const int lon1, const int lat
|
||||
return EARTH_RADIUS_IN_METERS * distanceArc;
|
||||
}
|
||||
|
||||
/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
|
||||
double GetAngleBetweenTwoEdges(const _Coordinate& A, const _Coordinate& C, const _Coordinate& B) {
|
||||
int v1x = A.lon - C.lon;
|
||||
int v1y = A.lat - C.lat;
|
||||
int v2x = B.lon - C.lon;
|
||||
int v2y = B.lat - C.lat;
|
||||
|
||||
double angle = (atan2(v2y,v2x) - atan2(v1y,v1x) )*180/M_PI;
|
||||
while(angle < 0)
|
||||
angle += 360;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
||||
inline double ApproximateDistance(const _Coordinate &c1, const _Coordinate &c2) {
|
||||
return ApproximateDistance( c1.lat, c1.lon, c2.lat, c2.lon );
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ struct _InsertedNodes {
|
||||
};
|
||||
|
||||
|
||||
typedef BinaryHeap< NodeID, int, int, _HeapData, DenseStorage< NodeID, unsigned > > _Heap;
|
||||
typedef BinaryHeap< NodeID, int, int, _HeapData/*, ArrayS< NodeID, unsigned >*/ > _Heap;
|
||||
|
||||
template<typename EdgeData, typename GraphT, typename NodeHelperT = NodeInformationHelpDesk>
|
||||
class SearchEngine {
|
||||
@ -98,8 +98,7 @@ public:
|
||||
SearchEngine(GraphT * g, NodeHelperT * nh, vector<string> * n = new vector<string>()) : _graph(g), nodeHelpDesk(nh), _names(n) {}
|
||||
~SearchEngine() {}
|
||||
|
||||
inline const void getNodeInfo(NodeID id, _Coordinate& result) const
|
||||
{
|
||||
inline const void getCoordinatesForNodeID(NodeID id, _Coordinate& result) const {
|
||||
result.lat = nodeHelpDesk->getLatitudeOfNode(id);
|
||||
result.lon = nodeHelpDesk->getLongitudeOfNode(id);
|
||||
}
|
||||
@ -108,7 +107,7 @@ public:
|
||||
return nodeHelpDesk->getNumberOfNodes();
|
||||
}
|
||||
|
||||
unsigned int ComputeRoute(PhantomNodes * phantomNodes, vector<_PathData > * path, _Coordinate& startCoord, _Coordinate& targetCoord) {
|
||||
unsigned int ComputeRoute(PhantomNodes * phantomNodes, vector<_PathData > * path) {
|
||||
|
||||
bool onSameEdge = false;
|
||||
bool onSameEdgeReversed = false;
|
||||
@ -122,7 +121,7 @@ public:
|
||||
NodeID middle = ( NodeID ) 0;
|
||||
unsigned int _upperbound = std::numeric_limits<unsigned int>::max();
|
||||
|
||||
if(phantomNodes->startNode1 == UINT_MAX || phantomNodes->startNode2 == UINT_MAX)
|
||||
if(phantomNodes->startNode1 == UINT_MAX || phantomNodes->targetNode1 == UINT_MAX || phantomNodes->startNode2 == UINT_MAX || phantomNodes->targetNode2 == UINT_MAX)
|
||||
return _upperbound;
|
||||
|
||||
if( (phantomNodes->startNode1 == phantomNodes->targetNode1 && phantomNodes->startNode2 == phantomNodes->targetNode2 ) ||
|
||||
@ -210,12 +209,13 @@ public:
|
||||
|
||||
while(_forwardHeap.Size() + _backwardHeap.Size() > 0) {
|
||||
if ( _forwardHeap.Size() > 0 ) {
|
||||
_RoutingStep( &_forwardHeap, &_backwardHeap, true, &middle, &_upperbound );
|
||||
_RoutingStep( _forwardHeap, _backwardHeap, true, &middle, &_upperbound );
|
||||
}
|
||||
if ( _backwardHeap.Size() > 0 ) {
|
||||
_RoutingStep( &_backwardHeap, &_forwardHeap, false, &middle, &_upperbound );
|
||||
_RoutingStep( _backwardHeap, _forwardHeap, false, &middle, &_upperbound );
|
||||
}
|
||||
}
|
||||
|
||||
// std::cout << "[debug] computing distance took " << get_timestamp() - time << std::endl;
|
||||
// time = get_timestamp();
|
||||
|
||||
@ -245,7 +245,6 @@ public:
|
||||
}
|
||||
|
||||
packedPath.clear();
|
||||
// std::cout << "[debug] unpacking path took " << get_timestamp() - time << std::endl;
|
||||
|
||||
return _upperbound/10;
|
||||
}
|
||||
@ -304,8 +303,7 @@ public:
|
||||
|
||||
}
|
||||
|
||||
inline bool FindRoutingStarts(const _Coordinate start, const _Coordinate target, PhantomNodes * routingStarts)
|
||||
{
|
||||
inline bool FindRoutingStarts(const _Coordinate &start, const _Coordinate &target, PhantomNodes * routingStarts) {
|
||||
nodeHelpDesk->FindRoutingStarts(start, target, routingStarts);
|
||||
return true;
|
||||
}
|
||||
@ -334,6 +332,12 @@ public:
|
||||
return (nameID >= _names->size() ? _names->at(0) : _names->at(nameID) );
|
||||
}
|
||||
|
||||
inline std::string GetEscapedNameForOriginDestinationNodeID(NodeID s, NodeID t) const {
|
||||
NodeID nameID = GetNameIDForOriginDestinationNodeID(s, t);
|
||||
return ( GetEscapedNameForNameID(nameID) );
|
||||
}
|
||||
|
||||
|
||||
inline std::string GetEscapedNameForNameID(const NodeID nameID) const {
|
||||
return ( (nameID >= _names->size() || nameID == 0) ? std::string("") : HTMLEntitize(_names->at(nameID)) );
|
||||
}
|
||||
@ -353,63 +357,84 @@ public:
|
||||
}
|
||||
private:
|
||||
|
||||
inline void _RoutingStep(_Heap * _forwardHeap, _Heap *_backwardHeap, const bool& forwardDirection, NodeID * middle, unsigned int * _upperbound) {
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
const unsigned int distance = _forwardHeap->GetKey( node );
|
||||
if ( _backwardHeap->WasInserted( node ) ) {
|
||||
const unsigned int newDistance = _backwardHeap->GetKey( node ) + distance;
|
||||
inline void _RoutingStep(_Heap& _forwardHeap, _Heap &_backwardHeap, const bool& forwardDirection, NodeID * middle, unsigned int * _upperbound) {
|
||||
const NodeID node = _forwardHeap.DeleteMin();
|
||||
const unsigned int distance = _forwardHeap.GetKey( node );
|
||||
if ( _backwardHeap.WasInserted( node ) ) {
|
||||
const unsigned int newDistance = _backwardHeap.GetKey( node ) + distance;
|
||||
if ( newDistance < *_upperbound ) {
|
||||
*middle = node;
|
||||
*_upperbound = newDistance;
|
||||
}
|
||||
}
|
||||
if ( distance > *_upperbound ) {
|
||||
_forwardHeap->DeleteAll();
|
||||
_forwardHeap.DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for ( typename GraphT::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
||||
const EdgeData& ed = _graph->GetEdgeData(edge);
|
||||
//const EdgeData& ed = _graph->GetEdgeData(edge);
|
||||
// if(!ed.shortcut)
|
||||
// continue;
|
||||
const NodeID to = _graph->GetTarget(edge);
|
||||
const EdgeWeight edgeWeight = ed.distance;
|
||||
const EdgeWeight edgeWeight = _graph->GetEdgeData(edge).distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
//const int toDistance = distance + edgeWeight;
|
||||
|
||||
//Stalling
|
||||
if(_forwardHeap->WasInserted( to )) {
|
||||
if(!forwardDirection ? ed.forward : ed.backward) {
|
||||
if(_forwardHeap->GetKey( to ) + edgeWeight < distance) {
|
||||
// std::cout << "[stalled] node " << node << std::endl;
|
||||
bool backwardDirectionFlag = (!forwardDirection) ? _graph->GetEdgeData(edge).forward : _graph->GetEdgeData(edge).backward;
|
||||
if(_forwardHeap.WasInserted( to )) {
|
||||
if(backwardDirectionFlag) {
|
||||
if(_forwardHeap.GetKey( to ) + edgeWeight < distance) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( typename GraphT::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
||||
const NodeID to = _graph->GetTarget(edge);
|
||||
const EdgeWeight edgeWeight = _graph->GetEdgeData(edge).distance;
|
||||
|
||||
if(forwardDirection ? ed.forward : ed.backward ) {
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
|
||||
bool forwardDirectionFlag = (forwardDirection ? _graph->GetEdgeData(edge).forward : _graph->GetEdgeData(edge).backward );
|
||||
if(forwardDirectionFlag) {
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !_forwardHeap->WasInserted( to ) ) {
|
||||
_forwardHeap->Insert( to, toDistance, node );
|
||||
if ( !_forwardHeap.WasInserted( to ) ) {
|
||||
_forwardHeap.Insert( to, toDistance, node );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < _forwardHeap->GetKey( to ) ) {
|
||||
_forwardHeap->GetData( to ).parent = node;
|
||||
_forwardHeap->DecreaseKey( to, toDistance );
|
||||
else if ( toDistance < _forwardHeap.GetKey( to ) ) {
|
||||
_forwardHeap.GetData( to ).parent = node;
|
||||
_forwardHeap.DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
}
|
||||
}
|
||||
// if(forwardDirection ? ed.forward : ed.backward ) {
|
||||
// //New Node discovered -> Add to Heap + Node Info Storage
|
||||
// if ( !_forwardHeap->WasInserted( to ) ) {
|
||||
// _forwardHeap->Insert( to, toDistance, node );
|
||||
// }
|
||||
// //Found a shorter Path -> Update distance
|
||||
// else if ( toDistance < _forwardHeap->GetKey( to ) ) {
|
||||
// _forwardHeap->GetData( to ).parent = node;
|
||||
// _forwardHeap->DecreaseKey( to, toDistance );
|
||||
// //new parent
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
inline void _RoutingStepWithStats( _Heap * _forwardHeap, _Heap *_backwardHeap, const bool& forwardDirection, NodeID * middle, unsigned int * _upperbound, _Statistics& stats) {
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
inline void _RoutingStepWithStats( _Heap& _forwardHeap, _Heap &_backwardHeap, const bool& forwardDirection, NodeID * middle, unsigned int * _upperbound, _Statistics& stats) {
|
||||
const NodeID node = _forwardHeap.DeleteMin();
|
||||
stats.deleteMins++;
|
||||
const unsigned int distance = _forwardHeap->GetKey( node );
|
||||
if ( _backwardHeap->WasInserted( node ) ) {
|
||||
const unsigned int newDistance = _backwardHeap->GetKey( node ) + distance;
|
||||
const unsigned int distance = _forwardHeap.GetKey( node );
|
||||
if ( _backwardHeap.WasInserted( node ) ) {
|
||||
const unsigned int newDistance = _backwardHeap.GetKey( node ) + distance;
|
||||
if ( newDistance < *_upperbound ) {
|
||||
*middle = node;
|
||||
*_upperbound = newDistance;
|
||||
@ -417,7 +442,7 @@ private:
|
||||
}
|
||||
if ( distance > *_upperbound ) {
|
||||
stats.meetingNodes++;
|
||||
_forwardHeap->DeleteAll();
|
||||
_forwardHeap.DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -431,9 +456,9 @@ private:
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
//Stalling
|
||||
if(_forwardHeap->WasInserted( to )) {
|
||||
if(_forwardHeap.WasInserted( to )) {
|
||||
if(!forwardDirection ? ed.forward : ed.backward) {
|
||||
if(_forwardHeap->GetKey( to ) + edgeWeight < distance) {
|
||||
if(_forwardHeap.GetKey( to ) + edgeWeight < distance) {
|
||||
stats.stalledNodes++;
|
||||
return;
|
||||
}
|
||||
@ -442,14 +467,14 @@ private:
|
||||
|
||||
if(forwardDirection ? ed.forward : ed.backward ) {
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !_forwardHeap->WasInserted( to ) ) {
|
||||
_forwardHeap->Insert( to, toDistance, node );
|
||||
if ( !_forwardHeap.WasInserted( to ) ) {
|
||||
_forwardHeap.Insert( to, toDistance, node );
|
||||
stats.insertedNodes++;
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < _forwardHeap->GetKey( to ) ) {
|
||||
_forwardHeap->GetData( to ).parent = node;
|
||||
_forwardHeap->DecreaseKey( to, toDistance );
|
||||
else if ( toDistance < _forwardHeap.GetKey( to ) ) {
|
||||
_forwardHeap.GetData( to ).parent = node;
|
||||
_forwardHeap.DecreaseKey( to, toDistance );
|
||||
stats.decreasedNodes++;
|
||||
//new parent
|
||||
}
|
||||
|
@ -22,9 +22,10 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
#define BASE_DESCRIPTOR_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../DataStructures/ExtractorStructs.h"
|
||||
@ -32,8 +33,77 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
#include "../DataStructures/PolylineCompressor.h"
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
struct DescriptorConfig {
|
||||
DescriptorConfig() : instructions(true), geometry(true), encodeGeometry(false), z(18) {}
|
||||
#include "RawRouteData.h"
|
||||
|
||||
static double areaThresholds[19] = { 5000, 5000, 5000, 5000, 5000, 2500, 2000, 1500, 800, 400, 250, 150, 100, 75, 25, 20, 10, 5, 0 };
|
||||
|
||||
/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
|
||||
static double GetAngleBetweenTwoEdges(const _Coordinate& A, const _Coordinate& C, const _Coordinate& B) {
|
||||
int v1x = A.lon - C.lon;
|
||||
int v1y = A.lat - C.lat;
|
||||
int v2x = B.lon - C.lon;
|
||||
int v2y = B.lat - C.lat;
|
||||
|
||||
double angle = (atan2(v2y,v2x) - atan2(v1y,v1x) )*180/M_PI;
|
||||
while(angle < 0)
|
||||
angle += 360;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
struct RouteSummary {
|
||||
std::string lengthString;
|
||||
std::string durationString;
|
||||
std::string startName;
|
||||
std::string destName;
|
||||
RouteSummary() : lengthString("0"), durationString("0"), startName("unknown street"), destName("unknown street") {}
|
||||
void BuildDurationAndLengthStrings(double distance, unsigned time) {
|
||||
//compute distance/duration for route summary
|
||||
std::ostringstream s;
|
||||
s << 10*(round(distance/10.));
|
||||
lengthString = s.str();
|
||||
int travelTime = 60*(time/60.) + 1;
|
||||
s.str("");
|
||||
s << travelTime;
|
||||
durationString = s.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct DirectionOfInstruction {
|
||||
std::string direction;
|
||||
std::string shortDirection;
|
||||
};
|
||||
|
||||
struct DescriptorState {
|
||||
_Coordinate currentCoordinate, nextCoordinate, previousCoordinate, tmpCoord, startOfSegmentCoordinate;
|
||||
std::string routeGeometryString;
|
||||
std::string routeInstructionString;
|
||||
unsigned lastNameID, currentNameID, geometryCounter, startIndexOfGeometry;
|
||||
double entireDistance, distanceOfInstruction, durationOfInstruction;
|
||||
|
||||
DescriptorState() : lastNameID(0), currentNameID(0), geometryCounter(0), startIndexOfGeometry(0), entireDistance(0.), distanceOfInstruction(0.), durationOfInstruction(0.) {};
|
||||
double GetAngleBetweenCoordinates() const {
|
||||
return GetAngleBetweenTwoEdges(previousCoordinate, currentCoordinate, nextCoordinate);
|
||||
}
|
||||
bool CurrentAndPreviousNameIDsEqual() const {
|
||||
return lastNameID == currentNameID;
|
||||
}
|
||||
void SetStartOfSegment() {
|
||||
startOfSegmentCoordinate = nextCoordinate;
|
||||
entireDistance += distanceOfInstruction;
|
||||
lastNameID = currentNameID;
|
||||
distanceOfInstruction = 0;
|
||||
startIndexOfGeometry = geometryCounter-1;
|
||||
}
|
||||
void PrintCoordinates() {
|
||||
#ifdef DEBUG
|
||||
std::cout << "prev: " << previousCoordinate << ", curr: " << currentCoordinate << ", next: " << nextCoordinate << std::endl;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
struct _DescriptorConfig {
|
||||
_DescriptorConfig() : instructions(true), geometry(true), encodeGeometry(false), z(18) {}
|
||||
bool instructions;
|
||||
bool geometry;
|
||||
bool encodeGeometry;
|
||||
@ -48,9 +118,90 @@ public:
|
||||
BaseDescriptor() { }
|
||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BaseDescriptor() { }
|
||||
virtual void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) = 0;
|
||||
virtual void SetConfig(const DescriptorConfig config) = 0;
|
||||
|
||||
virtual void Run(http::Reply& reply, RawRouteData * route, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) = 0;
|
||||
virtual void SetConfig(const _DescriptorConfig & config) = 0;
|
||||
};
|
||||
|
||||
static inline void getDirectionOfInstruction(double angle, DirectionOfInstruction & dirInst) {
|
||||
if(angle >= 23 && angle < 67) {
|
||||
dirInst.direction = "southeast";
|
||||
dirInst.shortDirection = "SE";
|
||||
return;
|
||||
}
|
||||
if(angle >= 67 && angle < 113) {
|
||||
dirInst.direction = "south";
|
||||
dirInst.shortDirection = "S";
|
||||
return;
|
||||
}
|
||||
if(angle >= 113 && angle < 158) {
|
||||
dirInst.direction = "southwest";
|
||||
dirInst.shortDirection = "SW";
|
||||
return;
|
||||
}
|
||||
if(angle >= 158 && angle < 202) {
|
||||
dirInst.direction = "west";
|
||||
dirInst.shortDirection = "W";
|
||||
return;
|
||||
}
|
||||
if(angle >= 202 && angle < 248) {
|
||||
dirInst.direction = "northwest";
|
||||
dirInst.shortDirection = "NW";
|
||||
return;
|
||||
}
|
||||
if(angle >= 248 && angle < 292) {
|
||||
dirInst.direction = "north";
|
||||
dirInst.shortDirection = "N";
|
||||
return;
|
||||
}
|
||||
if(angle >= 292 && angle < 336) {
|
||||
dirInst.direction = "northeast";
|
||||
dirInst.shortDirection = "NE";
|
||||
return;
|
||||
}
|
||||
dirInst.direction = "East";
|
||||
dirInst.shortDirection = "E";
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void getTurnDirectionOfInstruction(double angle, std::string & output) {
|
||||
if(angle >= 23 && angle < 67) {
|
||||
output = "Turn sharp right";
|
||||
// cout << "angle " << angle << "-> " << output << endl;
|
||||
return;
|
||||
}
|
||||
if (angle >= 67 && angle < 113) {
|
||||
output = "Turn right";
|
||||
// cout << "angle " << angle << "-> " << output << endl;
|
||||
return;
|
||||
}
|
||||
if (angle >= 113 && angle < 158) {
|
||||
output = "Bear right";
|
||||
// cout << "angle " << angle << "-> " << output << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (angle >= 158 && angle < 202) {
|
||||
output = "Continue";
|
||||
// cout << "angle " << angle << "-> " << output << endl;
|
||||
return;
|
||||
}
|
||||
if (angle >= 202 && angle < 248) {
|
||||
output = "Bear left";
|
||||
// cout << "angle " << angle << "-> " << output << endl;
|
||||
return;
|
||||
}
|
||||
if (angle >= 248 && angle < 292) {
|
||||
output = "Turn left";
|
||||
// cout << "angle " << angle << "-> " << output << endl;
|
||||
return;
|
||||
}
|
||||
if (angle >= 292 && angle < 336) {
|
||||
output = "Turn sharp left";
|
||||
// cout << "angle " << angle << "-> " << output << endl;
|
||||
return;
|
||||
}
|
||||
output = "U-Turn";
|
||||
// cout << "angle " << angle << "-> " << output << endl;
|
||||
}
|
||||
|
||||
#endif /* BASE_DESCRIPTOR_H_ */
|
||||
|
@ -26,202 +26,43 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
template<class SearchEngineT>
|
||||
class GPXDescriptor : public BaseDescriptor<SearchEngineT>{
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
public:
|
||||
void SetConfig(const DescriptorConfig c) { config = c; }
|
||||
void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) {
|
||||
_DescriptorConfig config;
|
||||
string tmp;
|
||||
string lineString;
|
||||
string startName;
|
||||
string targetName;
|
||||
double entireDistance = 0;
|
||||
string startLoc, endLoc, bodyString;
|
||||
string direction = "East";
|
||||
reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
reply.content += "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\"\n";
|
||||
reply.content += "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
|
||||
reply.content +="xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd\">\n";
|
||||
_Coordinate current;
|
||||
public:
|
||||
void SetConfig(const _DescriptorConfig& c) { config = c; }
|
||||
void Run(http::Reply& reply, RawRouteData * route, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) {
|
||||
reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content += "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd\">";
|
||||
reply.content += "<rte>";
|
||||
if(distance != UINT_MAX && route->routeSegments.size()) {
|
||||
|
||||
reply.content += ("\t<extensions>\n");
|
||||
|
||||
if(distance != UINT_MAX) {
|
||||
unsigned streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
startName = sEngine->GetEscapedNameForNameID(streetID);
|
||||
streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
targetName = sEngine->GetEscapedNameForNameID(streetID);
|
||||
convertInternalLatLonToString(phantomNodes->startCoord.lat, tmp);
|
||||
bodyString += ("\t\t<rtept lat=\""+tmp+"\"");
|
||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||
convertInternalLatLonToString(phantomNodes->startCoord.lon, tmp);
|
||||
bodyString += (" lon=\""+tmp+"\">");
|
||||
bodyString += ("\n\t\t\t<desc>Start from ");
|
||||
bodyString += startName;
|
||||
bodyString += (" and head ");
|
||||
_Coordinate tmpCoord;
|
||||
if(path->size() > 0)
|
||||
sEngine->getNodeInfo(path->begin()->node, tmpCoord);
|
||||
else
|
||||
tmpCoord = phantomNodes->targetCoord;
|
||||
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
||||
|
||||
int angle = round(GetAngleBetweenTwoEdges(_Coordinate(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon), tmpCoord, _Coordinate(tmpCoord.lat, tmpCoord.lon-1000)));
|
||||
if(angle >= 23 && angle < 67)
|
||||
direction = "South-East";
|
||||
if(angle >= 67 && angle < 113)
|
||||
direction = "South";
|
||||
if(angle >= 113 && angle < 158)
|
||||
direction = "South-West";
|
||||
if(angle >= 158 && angle < 202)
|
||||
direction = "West";
|
||||
if(angle >= 202 && angle < 248)
|
||||
direction = "North-West";
|
||||
if(angle >= 248 && angle < 292)
|
||||
direction = "North";
|
||||
if(angle >= 292 && angle < 336)
|
||||
direction = "North-East";
|
||||
|
||||
bodyString += direction;
|
||||
|
||||
bodyString += ("</desc>\n\t\t\t<extensions>\n\t\t\t\t<direction>"+direction+"</direction>\n");
|
||||
|
||||
_Coordinate previous(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon);
|
||||
_Coordinate next, current, lastPlace, startOfSegment;
|
||||
stringstream numberString;
|
||||
|
||||
double tempDist = 0;
|
||||
double lengthOfInstruction = 0;
|
||||
NodeID nextID = UINT_MAX;
|
||||
NodeID nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
short type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
lastPlace.lat = phantomNodes->startCoord.lat;
|
||||
lastPlace.lon = phantomNodes->startCoord.lon;
|
||||
short nextType = SHRT_MAX;
|
||||
short prevType = SHRT_MAX;
|
||||
|
||||
for(vector< _PathData >::iterator it = path->begin(); it != path->end(); it++) {
|
||||
sEngine->getNodeInfo(it->node, current);
|
||||
startOfSegment = previous;
|
||||
if(it==path->begin()){
|
||||
|
||||
tempDist += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon);
|
||||
numberString << 10*(round(tempDist/10.));;
|
||||
bodyString+="\t\t\t\t<distance>"+numberString.str() +"m</distance>\n";
|
||||
numberString.str("");
|
||||
bodyString+="\t\t\t</extensions>\n\t\t</rtept>";
|
||||
}
|
||||
|
||||
if(it==path->end()-1){
|
||||
next = _Coordinate(phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon);
|
||||
nextID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
} else {
|
||||
sEngine->getNodeInfo((it+1)->node, next);
|
||||
nextID = sEngine->GetNameIDForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
}
|
||||
for(unsigned segmentIdx = 0; segmentIdx < route->routeSegments.size(); segmentIdx++) {
|
||||
const std::vector< _PathData > & path = route->routeSegments[segmentIdx];
|
||||
if( ! path.size() )
|
||||
continue;
|
||||
for(vector< _PathData >::const_iterator it = path.begin(); it != path.end(); it++) {
|
||||
sEngine->getCoordinatesForNodeID(it->node, current);
|
||||
|
||||
convertInternalLatLonToString(current.lat, tmp);
|
||||
bodyString += "\n\t\t<rtept lat=\"" + tmp + "\" ";
|
||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||
convertInternalLatLonToString(current.lon, tmp);
|
||||
bodyString += "lon=\"" + tmp + "\">\n";
|
||||
reply.content += "lon=\"" + tmp + "\">";
|
||||
|
||||
double angle = GetAngleBetweenTwoEdges(startOfSegment, current, next);
|
||||
if(178 > angle || 182 < angle) {
|
||||
convertInternalCoordinateToString(current, tmp);
|
||||
lineString += tmp;
|
||||
reply.content +="</rtept>";
|
||||
}
|
||||
|
||||
if(nextID == nameID) {
|
||||
int temp = ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon);
|
||||
tempDist += temp;
|
||||
numberString << 10*(round(temp/10.));
|
||||
bodyString += "\t\t\t<extensions>\n\t\t\t\t<distance>"+numberString.str()+"m</distance>\n\t\t\t</extensions>";
|
||||
numberString.str("");
|
||||
} else {
|
||||
bodyString += "\t\t\t<desc>";
|
||||
if(type == 0 && prevType != 0)
|
||||
bodyString += "enter motorway and ";
|
||||
if(type != 0 && prevType == 0 )
|
||||
bodyString += "leave motorway and ";
|
||||
|
||||
bodyString += "follow road ";
|
||||
if(nameID != 0)
|
||||
bodyString += sEngine->GetEscapedNameForNameID(nameID);
|
||||
lastPlace = current;
|
||||
if(angle > 160 && angle < 200) {
|
||||
bodyString += /* " (" << angle << ")*/"drive ahead, ";
|
||||
} else if (angle > 290 && angle <= 360) {
|
||||
bodyString += /*" (" << angle << ")*/ "turn sharp left, ";
|
||||
} else if (angle > 230 && angle <= 290) {
|
||||
bodyString += /*" (" << angle << ")*/ "turn left, ";
|
||||
} else if (angle > 200 && angle <= 230) {
|
||||
bodyString += /*" (" << angle << ") */"bear left, ";
|
||||
} else if (angle > 130 && angle <= 160) {
|
||||
bodyString += /*" (" << angle << ") */"bear right, ";
|
||||
} else if (angle > 70 && angle <= 130) {
|
||||
bodyString += /*" (" << angle << ") */"turn right, ";
|
||||
} else {
|
||||
bodyString += /*" (" << angle << ") */"turn sharp right, ";
|
||||
}
|
||||
bodyString += "</desc>\n\t\t\t<extensions>\n\t\t\t\t<distance>";
|
||||
lengthOfInstruction = ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon)+tempDist;
|
||||
entireDistance += lengthOfInstruction;
|
||||
numberString << 10*(round(lengthOfInstruction/10.));;
|
||||
bodyString += numberString.str();
|
||||
numberString.str("");
|
||||
bodyString += "m</distance>\n";
|
||||
tempDist = 0;
|
||||
prevType = type;
|
||||
bodyString += "\t\t\t</extensions>";
|
||||
}
|
||||
bodyString +="\n\t\t</rtept>";
|
||||
nameID = nextID;
|
||||
previous = current;
|
||||
type = nextType;
|
||||
}
|
||||
convertInternalLatLonToString(phantomNodes->targetCoord.lat, tmp);
|
||||
bodyString += "\n\t\t<rtept lat=\"" + tmp + "\" ";
|
||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||
convertInternalLatLonToString(phantomNodes->targetCoord.lon, tmp);
|
||||
bodyString += "lon=\"" + tmp + "\">\n";
|
||||
bodyString += "\t\t\t<desc>";
|
||||
|
||||
nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
bodyString += "follow road ";
|
||||
|
||||
bodyString += sEngine->GetEscapedNameForNameID(nameID);
|
||||
bodyString += "</desc>\n\t\t\t<extensions>\n\t\t\t\t<distance>";
|
||||
|
||||
lengthOfInstruction = ApproximateDistance(previous.lat, previous.lon, phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon) + tempDist;
|
||||
entireDistance += lengthOfInstruction;
|
||||
numberString << 10*(round(lengthOfInstruction/10.));
|
||||
bodyString += numberString.str();
|
||||
numberString.str("");
|
||||
bodyString += "m</distance>\n ";
|
||||
string lat; string lon;
|
||||
|
||||
bodyString += "\t\t\t</extensions>\n\t\t</rtept>";
|
||||
|
||||
|
||||
//put targetCoord to linestring
|
||||
convertInternalCoordinateToString(phantomNodes->targetCoord, tmp);
|
||||
lineString += tmp;
|
||||
ostringstream s;
|
||||
s << 10*(round(entireDistance/10.));
|
||||
reply.content += ("\t\t<distance>"+s.str()+"m</distance>\n");
|
||||
int travelTime = (distance/60) + 1;
|
||||
s.str("");
|
||||
s << travelTime;
|
||||
reply.content += ("\t\t<time>"+s.str()+"</time>\n");
|
||||
reply.content += ("\t</extensions>\n\t<rte>\n");
|
||||
|
||||
if(config.geometry){
|
||||
reply.content +=(bodyString+"\n");
|
||||
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
||||
}
|
||||
reply.content += "</rte></gpx>";
|
||||
}
|
||||
else {
|
||||
reply.content += "\t<extensions>\n\t<rte>\n";
|
||||
}
|
||||
reply.content += "\t</rte>\n</gpx>";
|
||||
}
|
||||
private:
|
||||
};
|
||||
#endif /* GPX_DESCRIPTOR_H_ */
|
||||
|
@ -18,294 +18,268 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef JSON_DESCRIPTOR_H_
|
||||
#define JSON_DESCRIPTOR_H_
|
||||
|
||||
#include "BaseDescriptor.h"
|
||||
#include "../DataStructures/PolylineCompressor.h"
|
||||
|
||||
#ifndef JSONDESCRIPTOR_H_
|
||||
#define JSONDESCRIPTOR_H_
|
||||
|
||||
static double areaThresholds[19] = { 5000, 5000, 5000, 5000, 5000, 2500, 2000, 1500, 800, 400, 250, 150, 100, 75, 25, 20, 10, 5, 0 };
|
||||
|
||||
template<class SearchEngineT>
|
||||
class JSONDescriptor : public BaseDescriptor<SearchEngineT>{
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
_DescriptorConfig config;
|
||||
RouteSummary summary;
|
||||
DirectionOfInstruction directionOfInstruction;
|
||||
DescriptorState descriptorState;
|
||||
std::string tmp;
|
||||
vector<_Coordinate> polyline;
|
||||
|
||||
public:
|
||||
JSONDescriptor() {}
|
||||
void SetConfig(const DescriptorConfig c) {
|
||||
config = c;
|
||||
}
|
||||
void SetConfig(const _DescriptorConfig & c) { config = c; }
|
||||
|
||||
void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) {
|
||||
string tmp;
|
||||
string routeGeometryString;
|
||||
string routeSummaryString;
|
||||
string routeInstructionString;
|
||||
string startPointName;
|
||||
string endPointName;
|
||||
string direction = "East";
|
||||
string shortDirection = "E";
|
||||
int lastPosition = 0;
|
||||
int position = 0;
|
||||
unsigned durationOfInstruction = 0;
|
||||
double lastAngle = 0.;
|
||||
void Run(http::Reply & reply, RawRouteData *rawRoute, PhantomNodes *phantomNodes, SearchEngineT *sEngine, unsigned distance) {
|
||||
WriteHeaderToOutput(reply.content);
|
||||
|
||||
unsigned painted = 0;
|
||||
unsigned omitted = 0;
|
||||
//We do not need to do much, if there is no route ;-)
|
||||
if(distance != UINT_MAX && rawRoute->routeSegments.size() > 0) {
|
||||
reply.content += "0,"
|
||||
"\"status_message\": \"Found route between points\",";
|
||||
|
||||
reply.content += ("{");
|
||||
reply.content += ("\"version\":0.3,");
|
||||
|
||||
if(distance != UINT_MAX) {
|
||||
reply.content += ("\"status\":0,");
|
||||
reply.content += ("\"status_message\":");
|
||||
reply.content += "\"Found route between points\",";
|
||||
unsigned streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
startPointName = (0 == streetID ? "Unnamed origin street" : sEngine->GetEscapedNameForNameID(streetID) );
|
||||
streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
endPointName = (0 == streetID ? "Unnamed destination street" : sEngine->GetEscapedNameForNameID(streetID) );
|
||||
|
||||
routeInstructionString += "[\"Head ";
|
||||
_Coordinate tmpCoord;
|
||||
if(path->size() > 0)
|
||||
sEngine->getNodeInfo(path->begin()->node, tmpCoord);
|
||||
else
|
||||
tmpCoord = phantomNodes->targetCoord;
|
||||
|
||||
double angle = GetAngleBetweenTwoEdges(_Coordinate(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon), tmpCoord, _Coordinate(tmpCoord.lat, tmpCoord.lon-1000));
|
||||
if(angle >= 23 && angle < 67) {
|
||||
direction = "southeast";
|
||||
shortDirection = "SE";
|
||||
}
|
||||
if(angle >= 67 && angle < 113) {
|
||||
direction = "south";
|
||||
shortDirection = "S";
|
||||
}
|
||||
if(angle >= 113 && angle < 158) {
|
||||
direction = "southwest";
|
||||
shortDirection = "SW";
|
||||
}
|
||||
if(angle >= 158 && angle < 202) {
|
||||
direction = "west";
|
||||
shortDirection = "W";
|
||||
}
|
||||
if(angle >= 202 && angle < 248) {
|
||||
direction = "northwest";
|
||||
shortDirection = "NW";
|
||||
}
|
||||
if(angle >= 248 && angle < 292) {
|
||||
direction = "north";
|
||||
shortDirection = "N";
|
||||
}
|
||||
if(angle >= 292 && angle < 336) {
|
||||
direction = "northeast";
|
||||
shortDirection = "NE";
|
||||
}
|
||||
|
||||
routeInstructionString += direction;
|
||||
|
||||
//put start coord to linestring;
|
||||
//Put first segment of route into geometry
|
||||
polyline.push_back(phantomNodes->startCoord);
|
||||
descriptorState.geometryCounter++;
|
||||
descriptorState.startOfSegmentCoordinate = phantomNodes->startCoord;
|
||||
//Generate initial instruction for start of route (order of NodeIDs does not matter, its the same name anyway)
|
||||
summary.startName = sEngine->GetEscapedNameForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
descriptorState.lastNameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode2, phantomNodes->startNode1);
|
||||
|
||||
_Coordinate previous(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon);
|
||||
_Coordinate next, current, lastPlace, startOfSegment;
|
||||
stringstream numberString;
|
||||
stringstream intNumberString;
|
||||
//If we have a route, i.e. start and dest not on same edge, than get it
|
||||
if(rawRoute->routeSegments[0].size() > 0)
|
||||
sEngine->getCoordinatesForNodeID(rawRoute->routeSegments[0].begin()->node, descriptorState.tmpCoord);
|
||||
else
|
||||
descriptorState.tmpCoord = phantomNodes->targetCoord;
|
||||
|
||||
double tempDist = 0;
|
||||
double entireDistance = 0;
|
||||
double distanceOfInstruction = 0;
|
||||
NodeID nextID = UINT_MAX;
|
||||
NodeID nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
short type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
lastPlace.lat = phantomNodes->startCoord.lat;
|
||||
lastPlace.lon = phantomNodes->startCoord.lon;
|
||||
short nextType = SHRT_MAX;
|
||||
short prevType = SHRT_MAX;
|
||||
for(vector< _PathData >::iterator it = path->begin(); it != path->end(); it++) {
|
||||
sEngine->getNodeInfo(it->node, current);
|
||||
startOfSegment = previous;
|
||||
descriptorState.previousCoordinate = phantomNodes->startCoord;
|
||||
descriptorState.currentCoordinate = descriptorState.tmpCoord;
|
||||
descriptorState.distanceOfInstruction += ApproximateDistance(descriptorState.previousCoordinate, descriptorState.currentCoordinate);
|
||||
|
||||
if(it==path->end()-1){
|
||||
next = _Coordinate(phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon);
|
||||
nextID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
durationOfInstruction += sEngine->GetWeightForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
} else {
|
||||
sEngine->getNodeInfo((it+1)->node, next);
|
||||
nextID = sEngine->GetNameIDForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
durationOfInstruction += sEngine->GetWeightForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
if(config.instructions) {
|
||||
//Get Heading
|
||||
double angle = GetAngleBetweenTwoEdges(_Coordinate(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon), descriptorState.tmpCoord, _Coordinate(descriptorState.tmpCoord.lat, descriptorState.tmpCoord.lon-1000));
|
||||
getDirectionOfInstruction(angle, directionOfInstruction);
|
||||
appendInstructionNameToString(summary.startName, directionOfInstruction.direction, descriptorState.routeInstructionString, true);
|
||||
}
|
||||
double angle = GetAngleBetweenTwoEdges(startOfSegment, current, next);
|
||||
double area = fabs(0.5*( startOfSegment.lon*(current.lat - next.lat) + current.lon*(next.lat - startOfSegment.lat) + next.lon*(startOfSegment.lat - current.lat) ) );
|
||||
// std::cout << "Area for: " << area << std::endl;
|
||||
if(area > areaThresholds[config.z] || 19 == config.z) {
|
||||
painted++;
|
||||
polyline.push_back(current);
|
||||
NodeID lastNodeID = UINT_MAX;
|
||||
for(unsigned segmentIdx = 0; segmentIdx < rawRoute->routeSegments.size(); segmentIdx++) {
|
||||
const std::vector< _PathData > & path = rawRoute->routeSegments[segmentIdx];
|
||||
|
||||
position++;
|
||||
startOfSegment = current;
|
||||
} else {
|
||||
omitted++;
|
||||
if ( UINT_MAX == lastNodeID) {
|
||||
lastNodeID = (phantomNodes->startNode1 == (*path.begin()).node ? phantomNodes->startNode2 : phantomNodes->startNode1);
|
||||
}
|
||||
if(nextID == nameID) {
|
||||
double _dist = ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon);
|
||||
tempDist += _dist;
|
||||
entireDistance += _dist;
|
||||
} else {
|
||||
if(type == 0 && prevType != 0)
|
||||
routeInstructionString += ",enter motorway, ";
|
||||
if(type != 0 && prevType == 0 )
|
||||
routeInstructionString += ",leave motorway, ";
|
||||
routeInstructionString += "\", \"";
|
||||
if(nameID != 0)
|
||||
routeInstructionString += sEngine->GetEscapedNameForNameID(nameID);
|
||||
routeInstructionString += "\",";
|
||||
double _dist = ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon);
|
||||
distanceOfInstruction += _dist + tempDist;
|
||||
entireDistance += _dist;
|
||||
intNumberString.str("");
|
||||
intNumberString << 10*(round(distanceOfInstruction/10.));;
|
||||
routeInstructionString += intNumberString.str();
|
||||
routeInstructionString += ",";
|
||||
intNumberString.str("");
|
||||
intNumberString << lastPosition;
|
||||
lastPosition = position;
|
||||
routeInstructionString += intNumberString.str();
|
||||
routeInstructionString += ",";
|
||||
intNumberString.str("");
|
||||
intNumberString << durationOfInstruction/10;
|
||||
routeInstructionString += intNumberString.str();
|
||||
routeInstructionString += ",\"";
|
||||
intNumberString.str("");
|
||||
intNumberString << 10*(round(distanceOfInstruction/10.));
|
||||
routeInstructionString += intNumberString.str();
|
||||
routeInstructionString += "m\",\"";
|
||||
routeInstructionString += shortDirection;
|
||||
routeInstructionString += "\",";
|
||||
numberString.str("");
|
||||
numberString << fixed << setprecision(2) << lastAngle;
|
||||
routeInstructionString += numberString.str();
|
||||
routeInstructionString += "],";
|
||||
//Check, if there is overlap between current and previous route segment
|
||||
//if not, than we are fine and can route over this edge without paying any special attention.
|
||||
if(lastNodeID == (*path.begin()).node) {
|
||||
// appendCoordinateToString(descriptorState.currentCoordinate, descriptorState.routeGeometryString);
|
||||
polyline.push_back(descriptorState.currentCoordinate);
|
||||
descriptorState.geometryCounter++;
|
||||
lastNodeID = (lastNodeID == rawRoute->segmentEndCoordinates[segmentIdx].startNode1 ? rawRoute->segmentEndCoordinates[segmentIdx].startNode2 : rawRoute->segmentEndCoordinates[segmentIdx].startNode1);
|
||||
|
||||
string lat; string lon;
|
||||
lastPlace = current;
|
||||
routeInstructionString += "[\"";
|
||||
//output of the via nodes coordinates
|
||||
polyline.push_back(rawRoute->segmentEndCoordinates[segmentIdx].startCoord);
|
||||
descriptorState.geometryCounter++;
|
||||
descriptorState.currentNameID = sEngine->GetNameIDForOriginDestinationNodeID(rawRoute->segmentEndCoordinates[segmentIdx].startNode1, rawRoute->segmentEndCoordinates[segmentIdx].startNode2);
|
||||
//Make a special announement to do a U-Turn.
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
descriptorState.routeInstructionString += ",";
|
||||
descriptorState.distanceOfInstruction = ApproximateDistance(descriptorState.currentCoordinate, rawRoute->segmentEndCoordinates[segmentIdx].startCoord);
|
||||
getTurnDirectionOfInstruction(descriptorState.GetAngleBetweenCoordinates(), tmp);
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
descriptorState.routeInstructionString += ",";
|
||||
tmp = "U-turn at via point";
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
double tmpDistance = descriptorState.distanceOfInstruction;
|
||||
descriptorState.SetStartOfSegment(); //Set start of segment but save distance information.
|
||||
descriptorState.distanceOfInstruction = tmpDistance;
|
||||
} else if(segmentIdx > 0) { //We are going straight through an edge which is carrying the via point.
|
||||
assert(segmentIdx != 0);
|
||||
//routeInstructionString += "reaching via node: ";
|
||||
descriptorState.nextCoordinate = rawRoute->segmentEndCoordinates[segmentIdx].startCoord;
|
||||
descriptorState.currentNameID = sEngine->GetNameIDForOriginDestinationNodeID(rawRoute->segmentEndCoordinates[segmentIdx].startNode1, rawRoute->segmentEndCoordinates[segmentIdx].startNode2);
|
||||
|
||||
if(angle > 160 && angle < 200) {
|
||||
routeInstructionString += /* " (" << angle << ")*/"Continue";
|
||||
} else if (angle > 290 && angle <= 360) {
|
||||
routeInstructionString += /*" (" << angle << ")*/ "Turn sharp left";
|
||||
} else if (angle > 230 && angle <= 290) {
|
||||
routeInstructionString += /*" (" << angle << ")*/ "Turn left";
|
||||
} else if (angle > 200 && angle <= 230) {
|
||||
routeInstructionString += /*" (" << angle << ") */"Bear left";
|
||||
} else if (angle > 130 && angle <= 160) {
|
||||
routeInstructionString += /*" (" << angle << ") */"Bear right";
|
||||
} else if (angle > 70 && angle <= 130) {
|
||||
routeInstructionString += /*" (" << angle << ") */"Turn right";
|
||||
} else {
|
||||
routeInstructionString += /*" (" << angle << ") */"Turn sharp right";
|
||||
polyline.push_back(descriptorState.currentCoordinate);
|
||||
descriptorState.geometryCounter++;
|
||||
polyline.push_back(rawRoute->segmentEndCoordinates[segmentIdx].startCoord);
|
||||
descriptorState.geometryCounter++;
|
||||
if(config.instructions) {
|
||||
double turnAngle = descriptorState.GetAngleBetweenCoordinates();
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
descriptorState.SetStartOfSegment();
|
||||
descriptorState.routeInstructionString += ",";
|
||||
getTurnDirectionOfInstruction(turnAngle, tmp);
|
||||
tmp += " and reach via point";
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
|
||||
//instruction to continue on the segment
|
||||
appendInstructionLengthToString(ApproximateDistance(descriptorState.currentCoordinate, descriptorState.nextCoordinate), descriptorState.routeInstructionString);
|
||||
descriptorState.routeInstructionString += ",";
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), "Continue on", descriptorState.routeInstructionString);
|
||||
|
||||
//note the new segment starting coordinates
|
||||
descriptorState.SetStartOfSegment();
|
||||
descriptorState.previousCoordinate = descriptorState.currentCoordinate;
|
||||
descriptorState.currentCoordinate = descriptorState.nextCoordinate;
|
||||
}
|
||||
lastAngle = angle;
|
||||
tempDist = 0;
|
||||
prevType = type;
|
||||
distanceOfInstruction = 0;
|
||||
durationOfInstruction = 0;
|
||||
}
|
||||
nameID = nextID;
|
||||
previous = current;
|
||||
type = nextType;
|
||||
for(vector< _PathData >::const_iterator it = path.begin(); it != path.end(); it++) {
|
||||
sEngine->getCoordinatesForNodeID(it->node, descriptorState.nextCoordinate);
|
||||
descriptorState.currentNameID = sEngine->GetNameIDForOriginDestinationNodeID(lastNodeID, it->node);
|
||||
|
||||
double area = fabs(0.5*( descriptorState.startOfSegmentCoordinate.lon*(descriptorState.nextCoordinate.lat - descriptorState.currentCoordinate.lat) + descriptorState.nextCoordinate.lon*(descriptorState.currentCoordinate.lat - descriptorState.startOfSegmentCoordinate.lat) + descriptorState.currentCoordinate.lon*(descriptorState.startOfSegmentCoordinate.lat - descriptorState.nextCoordinate.lat) ) );
|
||||
//if route is generalization does not skip this point, add it to description
|
||||
if( it==path.end()-1 || config.z == 19 || area >= areaThresholds[config.z] || (false == descriptorState.CurrentAndPreviousNameIDsEqual()) ) {
|
||||
//mark the beginning of the segment thats announced
|
||||
// appendCoordinateToString(descriptorState.currentCoordinate, descriptorState.routeGeometryString);
|
||||
polyline.push_back(descriptorState.currentCoordinate);
|
||||
descriptorState.geometryCounter++;
|
||||
if( ( false == descriptorState.CurrentAndPreviousNameIDsEqual() ) && config.instructions) {
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
descriptorState.routeInstructionString += ",";
|
||||
getTurnDirectionOfInstruction(descriptorState.GetAngleBetweenCoordinates(), tmp);
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
|
||||
//note the new segment starting coordinates
|
||||
descriptorState.SetStartOfSegment();
|
||||
}
|
||||
nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
durationOfInstruction += sEngine->GetWeightForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
routeInstructionString += "\", \"";
|
||||
routeInstructionString += sEngine->GetEscapedNameForNameID(nameID);
|
||||
routeInstructionString += "\",";
|
||||
distanceOfInstruction = ApproximateDistance(previous.lat, previous.lon, phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon) + tempDist;
|
||||
entireDistance += distanceOfInstruction;
|
||||
intNumberString.str("");
|
||||
intNumberString << 10*(round(distanceOfInstruction/10.));;
|
||||
routeInstructionString += intNumberString.str();
|
||||
routeInstructionString += ",";
|
||||
numberString.str("");
|
||||
numberString << lastPosition;
|
||||
routeInstructionString += numberString.str();
|
||||
routeInstructionString += ",";
|
||||
intNumberString.str("");
|
||||
intNumberString << durationOfInstruction/10;
|
||||
routeInstructionString += intNumberString.str();
|
||||
routeInstructionString += ",\"";
|
||||
intNumberString.str("");
|
||||
intNumberString << 10*(round(distanceOfInstruction/10.));;
|
||||
routeInstructionString += intNumberString.str();
|
||||
routeInstructionString += "m\",\"";
|
||||
routeInstructionString += shortDirection;
|
||||
routeInstructionString += "\",";
|
||||
numberString.str("");
|
||||
numberString << fixed << setprecision(2) << lastAngle;
|
||||
routeInstructionString += numberString.str();
|
||||
routeInstructionString += "]";
|
||||
}
|
||||
descriptorState.distanceOfInstruction += ApproximateDistance(descriptorState.currentCoordinate, descriptorState.nextCoordinate);
|
||||
lastNodeID = it->node;
|
||||
if(it != path.begin()) {
|
||||
descriptorState.previousCoordinate = descriptorState.currentCoordinate;
|
||||
descriptorState.currentCoordinate = descriptorState.nextCoordinate;
|
||||
}
|
||||
}
|
||||
}
|
||||
descriptorState.currentNameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
descriptorState.nextCoordinate = phantomNodes->targetCoord;
|
||||
|
||||
string lat; string lon;
|
||||
|
||||
//put targetCoord to linestring
|
||||
if((false == descriptorState.CurrentAndPreviousNameIDsEqual()) && config.instructions) {
|
||||
polyline.push_back(descriptorState.currentCoordinate);
|
||||
descriptorState.geometryCounter++;
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
descriptorState.routeInstructionString += ",";
|
||||
getTurnDirectionOfInstruction(descriptorState.GetAngleBetweenCoordinates(), tmp);
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
descriptorState.distanceOfInstruction = 0;
|
||||
descriptorState.SetStartOfSegment();
|
||||
}
|
||||
summary.destName = sEngine->GetEscapedNameForNameID(descriptorState.currentNameID);
|
||||
descriptorState.distanceOfInstruction += ApproximateDistance(descriptorState.currentCoordinate, descriptorState.nextCoordinate);
|
||||
polyline.push_back(phantomNodes->targetCoord);
|
||||
position++;
|
||||
descriptorState.geometryCounter++;
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
summary.BuildDurationAndLengthStrings(descriptorState.entireDistance, distance);
|
||||
|
||||
//give complete distance in meters;
|
||||
ostringstream s;
|
||||
s << 10*(round(entireDistance/10.));
|
||||
routeSummaryString += "\"total_distance\":";
|
||||
routeSummaryString += s.str();
|
||||
|
||||
routeSummaryString += ",\"total_time\":";
|
||||
//give travel time in minutes
|
||||
int travelTime = distance;
|
||||
s.str("");
|
||||
s << travelTime;
|
||||
routeSummaryString += s.str();
|
||||
routeSummaryString += ",\"start_point\":\"";
|
||||
routeSummaryString += startPointName;
|
||||
routeSummaryString += "\",\"end_point\":\"";
|
||||
routeSummaryString += endPointName;
|
||||
routeSummaryString += "\"";
|
||||
} else {
|
||||
reply.content += ("\"status\":207,");
|
||||
reply.content += ("\"status_message\":");
|
||||
reply.content += "\"Cannot find route between points\",";
|
||||
routeSummaryString += "\"total_distance\":0";
|
||||
routeSummaryString += ",\"total_time\":0";
|
||||
routeSummaryString += ",\"start_point\":\"";
|
||||
routeSummaryString += "\",\"end_point\":\"";
|
||||
routeSummaryString += "\"";
|
||||
//no route found
|
||||
reply.content += "207,"
|
||||
"\"status_message\": \"Cannot find route between points\",";
|
||||
}
|
||||
reply.content += "\"route_summary\": {";
|
||||
reply.content += routeSummaryString;
|
||||
|
||||
reply.content += "\"route_summary\": {"
|
||||
"\"total_distance\":";
|
||||
reply.content += summary.lengthString;
|
||||
reply.content += ","
|
||||
"\"total_time\":";
|
||||
reply.content += summary.durationString;
|
||||
reply.content += ","
|
||||
"\"start_point\":\"";
|
||||
reply.content += summary.startName;
|
||||
reply.content += "\","
|
||||
"\"end_point\":\"";
|
||||
reply.content += summary.destName;
|
||||
reply.content += "\"";
|
||||
reply.content += "},";
|
||||
reply.content += "\"route_geometry\": ";
|
||||
if(config.geometry) {
|
||||
if(config.encodeGeometry)
|
||||
config.pc.printEncodedString(polyline, routeGeometryString);
|
||||
config.pc.printEncodedString(polyline, descriptorState.routeGeometryString);
|
||||
else
|
||||
config.pc.printUnencodedString(polyline, routeGeometryString);
|
||||
config.pc.printUnencodedString(polyline, descriptorState.routeGeometryString);
|
||||
|
||||
reply.content += routeGeometryString;
|
||||
reply.content += descriptorState.routeGeometryString;
|
||||
} else {
|
||||
reply.content += "[]";
|
||||
}
|
||||
reply.content += ",";
|
||||
reply.content += "\"route_instructions\": [";
|
||||
if(config.instructions) {
|
||||
reply.content += routeInstructionString;
|
||||
}
|
||||
|
||||
reply.content += ","
|
||||
"\"route_instructions\": [";
|
||||
if(config.instructions)
|
||||
reply.content += descriptorState.routeInstructionString;
|
||||
reply.content += "],";
|
||||
reply.content += "\"transactionId\": \"OSRM Routing Engine JSON Descriptor (beta)\"";
|
||||
//list all viapoints so that the client may display it
|
||||
reply.content += "\"via_points\":[";
|
||||
for(unsigned segmentIdx = 1; (true == config.geometry) && (segmentIdx < rawRoute->segmentEndCoordinates.size()); segmentIdx++) {
|
||||
if(segmentIdx > 1)
|
||||
reply.content += ",";
|
||||
reply.content += "[";
|
||||
convertInternalReversedCoordinateToString(rawRoute->segmentEndCoordinates[segmentIdx].startCoord, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += "]";
|
||||
}
|
||||
reply.content += "],"
|
||||
"\"transactionId\": \"OSRM Routing Engine JSON Descriptor (v0.2)\"";
|
||||
reply.content += "}";
|
||||
//std::cout << "zoom: " << config.z << ", threshold: " << areaThresholds[config.z] << ", painted: " << painted << ", omitted: " << omitted << std::endl;
|
||||
// std::cout << reply.content << std::endl;
|
||||
}
|
||||
private:
|
||||
void appendInstructionNameToString(const std::string & nameOfStreet, const std::string & instructionOrDirection, std::string &output, bool firstAdvice = false) {
|
||||
output += "[";
|
||||
if(config.instructions) {
|
||||
output += "\"";
|
||||
if(firstAdvice) {
|
||||
output += "Head ";
|
||||
}
|
||||
output += instructionOrDirection;
|
||||
output += "\",\"";
|
||||
output += nameOfStreet;
|
||||
output += "\",";
|
||||
}
|
||||
}
|
||||
|
||||
void appendInstructionLengthToString(unsigned length, std::string &output) {
|
||||
if(config.instructions){
|
||||
std::string tmpDistance;
|
||||
intToString(10*(round(length/10.)), tmpDistance);
|
||||
output += tmpDistance;
|
||||
output += ",";
|
||||
intToString(descriptorState.startIndexOfGeometry, tmp);
|
||||
output += tmp;
|
||||
output += ",";
|
||||
intToString(descriptorState.durationOfInstruction, tmp);
|
||||
output += tmp;
|
||||
output += ",";
|
||||
output += "\"";
|
||||
output += tmpDistance;
|
||||
output += "\",";
|
||||
double angle = descriptorState.GetAngleBetweenCoordinates();
|
||||
DirectionOfInstruction direction;
|
||||
getDirectionOfInstruction(angle, direction);
|
||||
output += "\"";
|
||||
output += direction.shortDirection;
|
||||
output += "\",";
|
||||
std::stringstream numberString;
|
||||
numberString << fixed << setprecision(2) << angle;
|
||||
output += numberString.str();
|
||||
}
|
||||
output += "]";
|
||||
}
|
||||
|
||||
void WriteHeaderToOutput(std::string & output) {
|
||||
output += "{"
|
||||
"\"version\": 0.3,"
|
||||
"\"status\":";
|
||||
}
|
||||
};
|
||||
#endif /* JSONDESCRIPTOR_H_ */
|
||||
#endif /* JSON_DESCRIPTOR_H_ */
|
||||
|
@ -26,233 +26,224 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
template<class SearchEngineT>
|
||||
class KMLDescriptor : public BaseDescriptor<SearchEngineT>{
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
_DescriptorConfig config;
|
||||
RouteSummary summary;
|
||||
DirectionOfInstruction directionOfInstruction;
|
||||
DescriptorState descriptorState;
|
||||
std::string tmp;
|
||||
|
||||
public:
|
||||
void SetConfig(const DescriptorConfig c) { config = c; }
|
||||
void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) {
|
||||
string tmp;
|
||||
string lineString;
|
||||
string startName;
|
||||
string targetName;
|
||||
double entireDistance = 0;
|
||||
string direction = "East";
|
||||
reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
reply.content += ("<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n");
|
||||
reply.content += ("<Document>\n");
|
||||
KMLDescriptor() {}
|
||||
void SetConfig(const _DescriptorConfig & c) { config = c; }
|
||||
|
||||
if(distance != UINT_MAX) {
|
||||
unsigned streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
startName = sEngine->GetEscapedNameForNameID(streetID);
|
||||
streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
targetName = sEngine->GetEscapedNameForNameID(streetID);
|
||||
void Run(http::Reply & reply, RawRouteData *rawRoute, PhantomNodes *phantomNodes, SearchEngineT *sEngine, unsigned distance) {
|
||||
WriteHeaderToOutput(reply.content);
|
||||
|
||||
reply.content += ("\t<Placemark>\n");
|
||||
reply.content += ("\t\t<name><![CDATA[Start from ");
|
||||
reply.content += startName;
|
||||
reply.content += (" direction ");
|
||||
_Coordinate tmpCoord;
|
||||
if(path->size() > 0)
|
||||
sEngine->getNodeInfo(path->begin()->node, tmpCoord);
|
||||
//We do not need to do much, if there is no route ;-)
|
||||
if(distance != UINT_MAX && rawRoute->routeSegments.size() > 0) {
|
||||
|
||||
//Put first segment of route into geometry
|
||||
appendCoordinateToString(phantomNodes->startCoord, descriptorState.routeGeometryString);
|
||||
descriptorState.startOfSegmentCoordinate = phantomNodes->startCoord;
|
||||
//Generate initial instruction for start of route (order of NodeIDs does not matter, its the same name anyway)
|
||||
summary.startName = sEngine->GetEscapedNameForOriginDestinationNodeID(phantomNodes->startNode2, phantomNodes->startNode1);
|
||||
descriptorState.lastNameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode2, phantomNodes->startNode1);
|
||||
|
||||
//If we have a route, i.e. start and dest not on same edge, than get it
|
||||
if(rawRoute->routeSegments[0].size() > 0)
|
||||
sEngine->getCoordinatesForNodeID(rawRoute->routeSegments[0].begin()->node, descriptorState.tmpCoord);
|
||||
else
|
||||
tmpCoord = phantomNodes->targetCoord;
|
||||
descriptorState.tmpCoord = phantomNodes->targetCoord;
|
||||
|
||||
int angle = round(GetAngleBetweenTwoEdges(_Coordinate(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon), tmpCoord, _Coordinate(tmpCoord.lat, tmpCoord.lon-1000)));
|
||||
if(angle >= 23 && angle < 67)
|
||||
direction = "South-East";
|
||||
if(angle >= 67 && angle < 113)
|
||||
direction = "South";
|
||||
if(angle >= 113 && angle < 158)
|
||||
direction = "South-West";
|
||||
if(angle >= 158 && angle < 202)
|
||||
direction = "West";
|
||||
if(angle >= 202 && angle < 248)
|
||||
direction = "North-West";
|
||||
if(angle >= 248 && angle < 292)
|
||||
direction = "North";
|
||||
if(angle >= 292 && angle < 336)
|
||||
direction = "North-East";
|
||||
descriptorState.previousCoordinate = phantomNodes->startCoord;
|
||||
descriptorState.currentCoordinate = descriptorState.tmpCoord;
|
||||
descriptorState.distanceOfInstruction += ApproximateDistance(descriptorState.previousCoordinate, descriptorState.currentCoordinate);
|
||||
|
||||
reply.content += direction;
|
||||
if(config.instructions) {
|
||||
//Get Heading
|
||||
double angle = GetAngleBetweenTwoEdges(_Coordinate(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon), descriptorState.tmpCoord, _Coordinate(descriptorState.tmpCoord.lat, descriptorState.tmpCoord.lon-1000));
|
||||
getDirectionOfInstruction(angle, directionOfInstruction);
|
||||
appendInstructionNameToString(summary.startName, directionOfInstruction.direction, descriptorState.routeInstructionString, true);
|
||||
}
|
||||
NodeID lastNodeID = UINT_MAX;
|
||||
for(unsigned segmentIdx = 0; segmentIdx < rawRoute->routeSegments.size(); segmentIdx++) {
|
||||
const std::vector< _PathData > & path = rawRoute->routeSegments[segmentIdx];
|
||||
if( ! path.size() )
|
||||
continue;
|
||||
|
||||
reply.content += ("]]></name>\n");
|
||||
if ( UINT_MAX == lastNodeID) {
|
||||
lastNodeID = (phantomNodes->startNode1 == (*path.begin()).node ? phantomNodes->startNode2 : phantomNodes->startNode1);
|
||||
}
|
||||
//Check, if there is overlap between current and previous route segment
|
||||
//if not, than we are fine and can route over this edge without paying any special attention.
|
||||
if(lastNodeID == (*path.begin()).node) {
|
||||
appendCoordinateToString(descriptorState.currentCoordinate, descriptorState.routeGeometryString);
|
||||
lastNodeID = (lastNodeID == rawRoute->segmentEndCoordinates[segmentIdx].startNode1 ? rawRoute->segmentEndCoordinates[segmentIdx].startNode2 : rawRoute->segmentEndCoordinates[segmentIdx].startNode1);
|
||||
|
||||
//put start coord to linestring;
|
||||
convertInternalCoordinateToString(phantomNodes->startCoord, tmp);
|
||||
lineString += tmp;
|
||||
//output of the via nodes coordinates
|
||||
appendCoordinateToString(rawRoute->segmentEndCoordinates[segmentIdx].startCoord, descriptorState.routeGeometryString);
|
||||
descriptorState.currentNameID = sEngine->GetNameIDForOriginDestinationNodeID(rawRoute->segmentEndCoordinates[segmentIdx].startNode1, rawRoute->segmentEndCoordinates[segmentIdx].startNode2);
|
||||
//Make a special announement to do a U-Turn.
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
|
||||
reply.content += ("\t</Placemark>\n");
|
||||
_Coordinate previous(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon);
|
||||
_Coordinate next, current, lastPlace, startOfSegment;
|
||||
stringstream numberString;
|
||||
descriptorState.distanceOfInstruction = ApproximateDistance(descriptorState.currentCoordinate, rawRoute->segmentEndCoordinates[segmentIdx].startCoord);
|
||||
getTurnDirectionOfInstruction(descriptorState.GetAngleBetweenCoordinates(), tmp);
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
tmp = "U-turn at via point";
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
double tmpDistance = descriptorState.distanceOfInstruction;
|
||||
descriptorState.SetStartOfSegment(); //Set start of segment but save distance information.
|
||||
descriptorState.distanceOfInstruction = tmpDistance;
|
||||
} else if(segmentIdx > 0) { //We are going straight through an edge which is carrying the via point.
|
||||
assert(segmentIdx != 0);
|
||||
//routeInstructionString += "\nreaching via node: \n";
|
||||
descriptorState.nextCoordinate = rawRoute->segmentEndCoordinates[segmentIdx].startCoord;
|
||||
descriptorState.currentNameID = sEngine->GetNameIDForOriginDestinationNodeID(rawRoute->segmentEndCoordinates[segmentIdx].startNode1, rawRoute->segmentEndCoordinates[segmentIdx].startNode2);
|
||||
appendCoordinateToString(descriptorState.currentCoordinate, descriptorState.routeGeometryString);
|
||||
appendCoordinateToString(rawRoute->segmentEndCoordinates[segmentIdx].startCoord, descriptorState.routeGeometryString);
|
||||
if(config.instructions) {
|
||||
double turnAngle = descriptorState.GetAngleBetweenCoordinates();
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
|
||||
double tempDist = 0;
|
||||
double lengthOfInstruction = 0;
|
||||
NodeID nextID = UINT_MAX;
|
||||
NodeID nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
short type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
lastPlace.lat = phantomNodes->startCoord.lat;
|
||||
lastPlace.lon = phantomNodes->startCoord.lon;
|
||||
short nextType = SHRT_MAX;
|
||||
short prevType = SHRT_MAX;
|
||||
reply.content += "\t<Placemark>\n\t\t<name><![CDATA[";
|
||||
for(vector< _PathData >::iterator it = path->begin(); it != path->end(); it++) {
|
||||
sEngine->getNodeInfo(it->node, current);
|
||||
startOfSegment = previous;
|
||||
if(it==path->end()-1){
|
||||
next = _Coordinate(phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon);
|
||||
nextID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
getTurnDirectionOfInstruction(turnAngle, tmp);
|
||||
tmp += " and reach via point";
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
|
||||
//instruction to continue on the segment
|
||||
appendInstructionLengthToString(ApproximateDistance(descriptorState.currentCoordinate, descriptorState.nextCoordinate), descriptorState.routeInstructionString);
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), "Continue on", descriptorState.routeInstructionString);
|
||||
|
||||
//note the new segment starting coordinates
|
||||
descriptorState.SetStartOfSegment();
|
||||
descriptorState.previousCoordinate = descriptorState.currentCoordinate;
|
||||
descriptorState.currentCoordinate = descriptorState.nextCoordinate;
|
||||
} else {
|
||||
sEngine->getNodeInfo((it+1)->node, next);
|
||||
nextID = sEngine->GetNameIDForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
double angle = GetAngleBetweenTwoEdges(startOfSegment, current, next);
|
||||
if(178 > angle || 182 < angle) {
|
||||
convertInternalCoordinateToString(current, tmp);
|
||||
lineString += tmp;
|
||||
for(vector< _PathData >::const_iterator it = path.begin(); it != path.end(); it++) {
|
||||
sEngine->getCoordinatesForNodeID(it->node, descriptorState.nextCoordinate);
|
||||
descriptorState.currentNameID = sEngine->GetNameIDForOriginDestinationNodeID(lastNodeID, it->node);
|
||||
|
||||
double area = fabs(0.5*( descriptorState.startOfSegmentCoordinate.lon*(descriptorState.nextCoordinate.lat - descriptorState.currentCoordinate.lat) + descriptorState.nextCoordinate.lon*(descriptorState.currentCoordinate.lat - descriptorState.startOfSegmentCoordinate.lat) + descriptorState.currentCoordinate.lon*(descriptorState.startOfSegmentCoordinate.lat - descriptorState.nextCoordinate.lat) ) );
|
||||
//if route is generalization does not skip this point, add it to description
|
||||
if( it==path.end()-1 || config.z == 19 || area >= areaThresholds[config.z] || (false == descriptorState.CurrentAndPreviousNameIDsEqual()) ) {
|
||||
//mark the beginning of the segment thats announced
|
||||
appendCoordinateToString(descriptorState.currentCoordinate, descriptorState.routeGeometryString);
|
||||
if( ( false == descriptorState.CurrentAndPreviousNameIDsEqual() ) && config.instructions) {
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
getTurnDirectionOfInstruction(descriptorState.GetAngleBetweenCoordinates(), tmp);
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
|
||||
//note the new segment starting coordinates
|
||||
descriptorState.SetStartOfSegment();
|
||||
}
|
||||
|
||||
if(nextID == nameID) {
|
||||
tempDist += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon);
|
||||
} else {
|
||||
if(type == 0 && prevType != 0)
|
||||
reply.content += "enter motorway and ";
|
||||
if(type != 0 && prevType == 0 )
|
||||
reply.content += "leave motorway and ";
|
||||
|
||||
//double angle = GetAngleBetweenTwoEdges(previous, current, next);
|
||||
reply.content += "follow road ";
|
||||
if(nameID != 0)
|
||||
reply.content += sEngine->GetEscapedNameForNameID(nameID);
|
||||
/*
|
||||
reply.content += " (type: ";
|
||||
numberString << type;
|
||||
reply.content += numberString.str();
|
||||
numberString.str("");
|
||||
reply.content += ", id: ";
|
||||
numberString << nameID;
|
||||
reply.content += numberString.str();
|
||||
numberString.str("");
|
||||
reply.content += ")";
|
||||
*/
|
||||
reply.content += "]]></name>\n\t\t<description>drive for ";
|
||||
lengthOfInstruction = ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon)+tempDist;
|
||||
entireDistance += lengthOfInstruction;
|
||||
numberString << 10*(round(lengthOfInstruction/10.));;
|
||||
reply.content += numberString.str();
|
||||
numberString.str("");
|
||||
reply.content += "m</description>";
|
||||
lastPlace = current;
|
||||
// reply.content += "\n <Point>";
|
||||
// reply.content += "<Coordinates>";
|
||||
// reply.content += lon;
|
||||
// reply.content += ",";
|
||||
// reply.content += lat;
|
||||
// reply.content += "</Coordinates></Point>";
|
||||
reply.content += "\n\t</Placemark>\n";
|
||||
reply.content += "\t<Placemark>\n\t\t<name><![CDATA[";
|
||||
if(angle > 160 && angle < 200) {
|
||||
reply.content += /* " (" << angle << ")*/"drive ahead, ";
|
||||
} else if (angle > 290 && angle <= 360) {
|
||||
reply.content += /*" (" << angle << ")*/ "turn sharp left, ";
|
||||
} else if (angle > 230 && angle <= 290) {
|
||||
reply.content += /*" (" << angle << ")*/ "turn left, ";
|
||||
} else if (angle > 200 && angle <= 230) {
|
||||
reply.content += /*" (" << angle << ") */"bear left, ";
|
||||
} else if (angle > 130 && angle <= 160) {
|
||||
reply.content += /*" (" << angle << ") */"bear right, ";
|
||||
} else if (angle > 70 && angle <= 130) {
|
||||
reply.content += /*" (" << angle << ") */"turn right, ";
|
||||
} else {
|
||||
reply.content += /*" (" << angle << ") */"turn sharp right, ";
|
||||
}
|
||||
tempDist = 0;
|
||||
prevType = type;
|
||||
descriptorState.distanceOfInstruction += ApproximateDistance(descriptorState.currentCoordinate, descriptorState.nextCoordinate);
|
||||
lastNodeID = it->node;
|
||||
if(it != path.begin()) {
|
||||
descriptorState.previousCoordinate = descriptorState.currentCoordinate;
|
||||
descriptorState.currentCoordinate = descriptorState.nextCoordinate;
|
||||
}
|
||||
nameID = nextID;
|
||||
previous = current;
|
||||
type = nextType;
|
||||
}
|
||||
nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
reply.content += "follow road ";
|
||||
reply.content += sEngine->GetEscapedNameForNameID(nameID);
|
||||
// reply.content += " (type: ";
|
||||
// numberString << type;
|
||||
// reply.content += numberString.str();
|
||||
// numberString.str("");
|
||||
// reply.content += ", id: ";
|
||||
// numberString << nameID;
|
||||
// reply.content += numberString.str();
|
||||
// numberString.str(")");
|
||||
reply.content += "]]></name>\n\t\t<description>drive for ";
|
||||
lengthOfInstruction = ApproximateDistance(previous.lat, previous.lon, phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon) + tempDist;
|
||||
entireDistance += lengthOfInstruction;
|
||||
numberString << 10*(round(lengthOfInstruction/10.));
|
||||
reply.content += numberString.str();
|
||||
numberString.str("");
|
||||
reply.content += "m</description>\n ";
|
||||
string lat; string lon;
|
||||
// convertLatLon(lastPlace.lon, lon);
|
||||
// convertLatLon(lastPlace.lat, lat);
|
||||
// reply.content += "<Point><Coordinates>";
|
||||
// reply.content += lon;
|
||||
// reply.content += ",";
|
||||
// reply.content += lat;
|
||||
// reply.content += "</Coordinates></Point>";
|
||||
reply.content += "\t</Placemark>\n";
|
||||
|
||||
//put targetCoord to linestring
|
||||
convertInternalCoordinateToString(phantomNodes->targetCoord, tmp);
|
||||
lineString += tmp;
|
||||
if(!config.geometry){
|
||||
|
||||
reply.content = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
reply.content += ("<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n");
|
||||
reply.content += ("<Document>\n");
|
||||
}
|
||||
descriptorState.currentNameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
descriptorState.nextCoordinate = phantomNodes->targetCoord;
|
||||
appendCoordinateToString(descriptorState.currentCoordinate, descriptorState.routeGeometryString);
|
||||
|
||||
|
||||
reply.content += "\t<Placemark>\n"
|
||||
"\t\t<name><![CDATA[Route from ";
|
||||
reply.content += startName;
|
||||
reply.content += " to ";
|
||||
reply.content += targetName;
|
||||
reply.content += "]]></name>\n"
|
||||
"\t\t<description>"
|
||||
"<![CDATA[Distance: ";
|
||||
|
||||
//give complete distance in meters;
|
||||
if((false == descriptorState.CurrentAndPreviousNameIDsEqual()) && config.instructions) {
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
getTurnDirectionOfInstruction(descriptorState.GetAngleBetweenCoordinates(), tmp);
|
||||
appendInstructionNameToString(sEngine->GetEscapedNameForNameID(descriptorState.currentNameID), tmp, descriptorState.routeInstructionString);
|
||||
descriptorState.distanceOfInstruction = 0;
|
||||
}
|
||||
summary.destName = sEngine->GetEscapedNameForNameID(descriptorState.currentNameID);
|
||||
descriptorState.distanceOfInstruction += ApproximateDistance(descriptorState.currentCoordinate, descriptorState.nextCoordinate);
|
||||
appendCoordinateToString(phantomNodes->targetCoord, descriptorState.routeGeometryString);
|
||||
appendInstructionLengthToString(descriptorState.distanceOfInstruction, descriptorState.routeInstructionString);
|
||||
descriptorState.SetStartOfSegment();
|
||||
//compute distance/duration for route summary
|
||||
ostringstream s;
|
||||
s << 10*(round(entireDistance/10.));
|
||||
reply.content += s.str();
|
||||
reply.content += " m (ca. ";
|
||||
|
||||
//give travel time in minutes
|
||||
s << 10*(round(descriptorState.entireDistance/10.));
|
||||
summary.lengthString = s.str();
|
||||
int travelTime = (distance/60) + 1;
|
||||
s.str("");
|
||||
s << travelTime;
|
||||
reply.content += s.str();
|
||||
summary.durationString = s.str();
|
||||
|
||||
reply.content += " minutes)]]>"
|
||||
"</description>\n";
|
||||
//writing summary of route to reply
|
||||
reply.content += "<Placemark><name><![CDATA[Route from ";
|
||||
reply.content += summary.startName;
|
||||
reply.content += " to ";
|
||||
reply.content += summary.destName;
|
||||
reply.content += "]]></name><description><![CDATA[Distance: ";
|
||||
reply.content += summary.lengthString;
|
||||
reply.content += " m (approx. ";
|
||||
reply.content += summary.durationString;
|
||||
reply.content += " minutes)]]></description>\n";
|
||||
|
||||
if(config.geometry) {
|
||||
reply.content += "<GeometryCollection><LineString><coordinates>";
|
||||
if(config.geometry)
|
||||
reply.content += descriptorState.routeGeometryString;
|
||||
reply.content += "</coordinates></LineString></GeometryCollection>";
|
||||
reply.content += "</Placemark>";
|
||||
|
||||
reply.content += "\t\t<GeometryCollection>\n"
|
||||
"\t\t\t<LineString>\n"
|
||||
"\t\t\t\t<coordinates>";
|
||||
reply.content += lineString;
|
||||
reply.content += "</coordinates>\n"
|
||||
"\t\t\t</LineString>\n"
|
||||
"\t\t</GeometryCollection>\n";
|
||||
//list all viapoints so that the client may display it
|
||||
std::cout << "number of segment endpoints in route: " << rawRoute->segmentEndCoordinates.size() << std::endl;
|
||||
for(unsigned segmentIdx = 1; (true == config.geometry) && (segmentIdx < rawRoute->segmentEndCoordinates.size()); segmentIdx++) {
|
||||
reply.content += "<Placemark>";
|
||||
reply.content += "<name>Via Point 1</name>";
|
||||
reply.content += "<Point>";
|
||||
reply.content += "<coordinates>";
|
||||
appendCoordinateToString(rawRoute->segmentEndCoordinates[segmentIdx].startCoord, reply.content);
|
||||
reply.content += "</coordinates>";
|
||||
reply.content += "</Point>";
|
||||
reply.content += "</Placemark>";
|
||||
}
|
||||
reply.content += "\t</Placemark>\n";
|
||||
}
|
||||
reply.content += descriptorState.routeInstructionString;
|
||||
reply.content += "</Document>\n</kml>";
|
||||
std::cout << descriptorState.routeInstructionString << std::endl;
|
||||
}
|
||||
private:
|
||||
void appendCoordinateToString(const _Coordinate coordinate, std::string & output) {
|
||||
if(config.geometry) {
|
||||
convertInternalCoordinateToString(coordinate, tmp);
|
||||
output += tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void appendInstructionNameToString(const std::string & nameOfStreet, const std::string & instructionOrDirection, std::string &output, bool firstAdvice = false) {
|
||||
if(config.instructions) {
|
||||
output += "<placemark><name><![CDATA[";
|
||||
if(firstAdvice) {
|
||||
output += "Head on ";
|
||||
output += nameOfStreet;
|
||||
output += " direction ";
|
||||
output += instructionOrDirection;
|
||||
} else {
|
||||
output += instructionOrDirection;
|
||||
output += " on ";
|
||||
output += nameOfStreet;
|
||||
}
|
||||
output += "]]></name>";
|
||||
}
|
||||
}
|
||||
|
||||
void appendInstructionLengthToString(unsigned length, std::string &output) {
|
||||
if(config.instructions){
|
||||
output += "\n\t<description>drive for ";
|
||||
intToString(10*(round(length/10.)), tmp);
|
||||
output += tmp;
|
||||
output += "m</description></placemark>";
|
||||
output += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void WriteHeaderToOutput(std::string & output) {
|
||||
output = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n<Document>\n");
|
||||
}
|
||||
};
|
||||
#endif /* KML_DESCRIPTOR_H_ */
|
||||
|
@ -75,10 +75,10 @@ public:
|
||||
int lat2 = static_cast<int>(100000.*atof(routeParameters.parameters[2].c_str()));
|
||||
int lon2 = static_cast<int>(100000.*atof(routeParameters.parameters[3].c_str()));
|
||||
|
||||
bool geometry(true);
|
||||
_DescriptorConfig descriptorConfig;
|
||||
|
||||
if("false" == routeParameters.options["geometry"]) {
|
||||
geometry = false;
|
||||
descriptorConfig.geometry = false;
|
||||
}
|
||||
|
||||
if(lat1>90*100000 || lat1 <-90*100000 || lon1>180*100000 || lon1 <-180*100000) {
|
||||
@ -95,9 +95,11 @@ public:
|
||||
_Coordinate targetCoord(lat2, lon2);
|
||||
|
||||
vector< _PathData > * path = new vector< _PathData >();
|
||||
RawRouteData * rawRoute = new RawRouteData(0);
|
||||
PhantomNodes * phantomNodes = new PhantomNodes();
|
||||
sEngine->FindRoutingStarts(startCoord, targetCoord, phantomNodes);
|
||||
unsigned int distance = sEngine->ComputeRoute(phantomNodes, path, startCoord, targetCoord);
|
||||
unsigned int distance = sEngine->ComputeRoute(phantomNodes, path);
|
||||
rawRoute->routeSegments.push_back(*path);
|
||||
reply.status = http::Reply::ok;
|
||||
BaseDescriptor<SearchEngine<EdgeData, StaticGraph<EdgeData> > > * desc;
|
||||
std::string JSONParameter = routeParameters.options.Find("jsonp");
|
||||
@ -105,7 +107,6 @@ public:
|
||||
reply.content += JSONParameter;
|
||||
reply.content += "(\n";
|
||||
}
|
||||
DescriptorConfig descriptorConfig;
|
||||
unsigned descriptorType = descriptorTable[routeParameters.options.Find("output")];
|
||||
unsigned short zoom = 18;
|
||||
if(routeParameters.options.Find("z") != ""){
|
||||
@ -144,7 +145,7 @@ public:
|
||||
break;
|
||||
}
|
||||
desc->SetConfig(descriptorConfig);
|
||||
desc->Run(reply, path, phantomNodes, sEngine, distance);
|
||||
desc->Run(reply, rawRoute, phantomNodes, sEngine, distance);
|
||||
if("" != JSONParameter) {
|
||||
reply.content += ")\n";
|
||||
}
|
||||
@ -194,6 +195,7 @@ public:
|
||||
|
||||
delete desc;
|
||||
delete path;
|
||||
delete rawRoute;
|
||||
delete phantomNodes;
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user