diff --git a/DataStructures/ExtractorStructs.h b/DataStructures/ExtractorStructs.h index a8c48fbad..8a724fd46 100644 --- a/DataStructures/ExtractorStructs.h +++ b/DataStructures/ExtractorStructs.h @@ -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 ); } diff --git a/DataStructures/SearchEngine.h b/DataStructures/SearchEngine.h index 11843fb0b..fd9961be6 100644 --- a/DataStructures/SearchEngine.h +++ b/DataStructures/SearchEngine.h @@ -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 class SearchEngine { @@ -98,8 +98,7 @@ public: SearchEngine(GraphT * g, NodeHelperT * nh, vector * n = new vector()) : _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::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 } diff --git a/Plugins/BaseDescriptor.h b/Plugins/BaseDescriptor.h index f93614895..ba89616d4 100644 --- a/Plugins/BaseDescriptor.h +++ b/Plugins/BaseDescriptor.h @@ -22,9 +22,10 @@ or see http://www.gnu.org/licenses/agpl.txt. #define BASE_DESCRIPTOR_H_ #include +#include +#include #include #include -#include #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; @@ -46,11 +116,92 @@ template class BaseDescriptor { 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; - + //Maybe someone can explain the pure virtual destructor thing to me (dennis) + virtual ~BaseDescriptor() { } + 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_ */ diff --git a/Plugins/GPXDescriptor.h b/Plugins/GPXDescriptor.h index 56c743b30..b79fd1849 100644 --- a/Plugins/GPXDescriptor.h +++ b/Plugins/GPXDescriptor.h @@ -26,202 +26,43 @@ or see http://www.gnu.org/licenses/agpl.txt. template class GPXDescriptor : public BaseDescriptor{ private: - DescriptorConfig config; + _DescriptorConfig config; + string tmp; + _Coordinate current; 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 startLoc, endLoc, bodyString; - string direction = "East"; - reply.content += ("\n"); - reply.content += "\n"; + void SetConfig(const _DescriptorConfig& c) { config = c; } + void Run(http::Reply& reply, RawRouteData * route, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) { + reply.content += (""); + reply.content += ""; + reply.content += ""; + if(distance != UINT_MAX && route->routeSegments.size()) { - reply.content += ("\t\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\tstartCoord.lon, tmp); - bodyString += (" lon=\""+tmp+"\">"); - bodyString += ("\n\t\t\tStart 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 + "\">"; - 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"; + 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); - bodyString += direction; + convertInternalLatLonToString(current.lat, tmp); + reply.content += ""; - bodyString += ("\n\t\t\t\n\t\t\t\t"+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"+numberString.str() +"m\n"; - numberString.str(""); - bodyString+="\t\t\t\n\t\t"; + reply.content +=""; } - - 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); - } - - convertInternalLatLonToString(current.lat, tmp); - bodyString += "\n\t\t\n"; - - double angle = GetAngleBetweenTwoEdges(startOfSegment, current, next); - if(178 > angle || 182 < angle) { - convertInternalCoordinateToString(current, tmp); - lineString += tmp; - } - - 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\n\t\t\t\t"+numberString.str()+"m\n\t\t\t"; - numberString.str(""); - } else { - bodyString += "\t\t\t"; - 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 += "\n\t\t\t\n\t\t\t\t"; - 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\n"; - tempDist = 0; - prevType = type; - bodyString += "\t\t\t"; - } - bodyString +="\n\t\t"; - nameID = nextID; - previous = current; - type = nextType; } convertInternalLatLonToString(phantomNodes->targetCoord.lat, tmp); - bodyString += "\n\t\ttargetCoord.lon, tmp); - bodyString += "lon=\"" + tmp + "\">\n"; - bodyString += "\t\t\t"; - - nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2); - type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2); - bodyString += "follow road "; - - bodyString += sEngine->GetEscapedNameForNameID(nameID); - bodyString += "\n\t\t\t\n\t\t\t\t"; - - 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\n "; - string lat; string lon; - - bodyString += "\t\t\t\n\t\t"; - - - //put targetCoord to linestring - convertInternalCoordinateToString(phantomNodes->targetCoord, tmp); - lineString += tmp; - ostringstream s; - s << 10*(round(entireDistance/10.)); - reply.content += ("\t\t"+s.str()+"m\n"); - int travelTime = (distance/60) + 1; - s.str(""); - s << travelTime; - reply.content += ("\t\t\n"); - reply.content += ("\t\n\t\n"); - - if(config.geometry){ - reply.content +=(bodyString+"\n"); - } + reply.content += "lon=\"" + tmp + "\">"; } - else { - reply.content += "\t\n\t\n"; - } - reply.content += "\t\n"; + reply.content += ""; } -private: }; #endif /* GPX_DESCRIPTOR_H_ */ diff --git a/Plugins/JSONDescriptor.h b/Plugins/JSONDescriptor.h index ea481d97f..5b194178c 100644 --- a/Plugins/JSONDescriptor.h +++ b/Plugins/JSONDescriptor.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 JSONDescriptor : public BaseDescriptor { +class JSONDescriptor : public BaseDescriptor{ 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); - } - 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); - - position++; - startOfSegment = current; - } else { - omitted++; - } - 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 += "],"; - - string lat; string lon; - lastPlace = current; - routeInstructionString += "[\""; - - 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"; - } - lastAngle = angle; - tempDist = 0; - prevType = type; - distanceOfInstruction = 0; - durationOfInstruction = 0; - } - nameID = nextID; - previous = current; - type = nextType; + 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); } - 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 += "]"; + NodeID lastNodeID = UINT_MAX; + for(unsigned segmentIdx = 0; segmentIdx < rawRoute->routeSegments.size(); segmentIdx++) { + const std::vector< _PathData > & path = rawRoute->routeSegments[segmentIdx]; - string lat; string lon; + 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); + polyline.push_back(descriptorState.currentCoordinate); + descriptorState.geometryCounter++; + lastNodeID = (lastNodeID == rawRoute->segmentEndCoordinates[segmentIdx].startNode1 ? rawRoute->segmentEndCoordinates[segmentIdx].startNode2 : rawRoute->segmentEndCoordinates[segmentIdx].startNode1); - //put targetCoord to linestring + //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); + + 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; + } + } + 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(); + } + } + 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; + + 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); - else - config.pc.printUnencodedString(polyline, routeGeometryString); + if(config.encodeGeometry) + config.pc.printEncodedString(polyline, descriptorState.routeGeometryString); + else + 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_ */ diff --git a/Plugins/KMLDescriptor.h b/Plugins/KMLDescriptor.h index 5b79169bb..cba972eee 100644 --- a/Plugins/KMLDescriptor.h +++ b/Plugins/KMLDescriptor.h @@ -26,233 +26,224 @@ or see http://www.gnu.org/licenses/agpl.txt. template class KMLDescriptor : public BaseDescriptor{ 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 += ("\n"); - reply.content += ("\n"); - reply.content += ("\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\n"); - reply.content += ("\t\tsize() > 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 += ("]]>\n"); - - //put start coord to linestring; - convertInternalCoordinateToString(phantomNodes->startCoord, tmp); - lineString += tmp; - - reply.content += ("\t\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; - reply.content += "\t\n\t\t::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); - } else { - sEngine->getNodeInfo((it+1)->node, next); - nextID = sEngine->GetNameIDForOriginDestinationNodeID(it->node, (it+1)->node); - nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(it->node, (it+1)->node); + 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); - double angle = GetAngleBetweenTwoEdges(startOfSegment, current, next); - if(178 > angle || 182 < angle) { - convertInternalCoordinateToString(current, 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); - 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 "; + 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 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 += "]]>\n\t\tdrive 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"; - lastPlace = current; - // reply.content += "\n "; - // reply.content += ""; - // reply.content += lon; - // reply.content += ","; - // reply.content += lat; - // reply.content += ""; - reply.content += "\n\t\n"; - reply.content += "\t\n\t\t 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, "; + 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 { - reply.content += /*" (" << angle << ") */"turn sharp right, "; + assert(false); + } + } + + 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(); + } + } + descriptorState.distanceOfInstruction += ApproximateDistance(descriptorState.currentCoordinate, descriptorState.nextCoordinate); + lastNodeID = it->node; + if(it != path.begin()) { + descriptorState.previousCoordinate = descriptorState.currentCoordinate; + descriptorState.currentCoordinate = descriptorState.nextCoordinate; } - tempDist = 0; - prevType = type; } - 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 += "]]>\n\t\tdrive 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\n "; - string lat; string lon; - // convertLatLon(lastPlace.lon, lon); - // convertLatLon(lastPlace.lat, lat); - // reply.content += ""; - // reply.content += lon; - // reply.content += ","; - // reply.content += lat; - // reply.content += ""; - reply.content += "\t\n"; + descriptorState.currentNameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2); + descriptorState.nextCoordinate = phantomNodes->targetCoord; + appendCoordinateToString(descriptorState.currentCoordinate, descriptorState.routeGeometryString); - //put targetCoord to linestring - convertInternalCoordinateToString(phantomNodes->targetCoord, tmp); - lineString += tmp; - if(!config.geometry){ - - reply.content = ("\n"); - reply.content += ("\n"); - reply.content += ("\n"); + 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; } - - - reply.content += "\t\n" - "\t\t\n" - "\t\t" - "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)]]>" - "\n"; + //writing summary of route to reply + reply.content += "\n"; - if(config.geometry) { + reply.content += ""; + if(config.geometry) + reply.content += descriptorState.routeGeometryString; + reply.content += ""; + reply.content += ""; - reply.content += "\t\t\n" - "\t\t\t\n" - "\t\t\t\t"; - reply.content += lineString; - reply.content += "\n" - "\t\t\t\n" - "\t\t\n"; - } - reply.content += "\t\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 += ""; + reply.content += "Via Point 1"; + reply.content += ""; + reply.content += ""; + appendCoordinateToString(rawRoute->segmentEndCoordinates[segmentIdx].startCoord, reply.content); + reply.content += ""; + reply.content += ""; + reply.content += ""; + } } + reply.content += descriptorState.routeInstructionString; reply.content += "\n"; + 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 += ""; + } + } + + void appendInstructionLengthToString(unsigned length, std::string &output) { + if(config.instructions){ + output += "\n\tdrive for "; + intToString(10*(round(length/10.)), tmp); + output += tmp; + output += "m"; + output += "\n"; + } + } + + void WriteHeaderToOutput(std::string & output) { + output = ("\n\n\n"); + } }; #endif /* KML_DESCRIPTOR_H_ */ diff --git a/Plugins/RoutePlugin.h b/Plugins/RoutePlugin.h index 249a01bb9..7f437fe18 100644 --- a/Plugins/RoutePlugin.h +++ b/Plugins/RoutePlugin.h @@ -75,10 +75,10 @@ public: int lat2 = static_cast(100000.*atof(routeParameters.parameters[2].c_str())); int lon2 = static_cast(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 > > * 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; }