Support for multi-segment routes. Needs to be further tested

This commit is contained in:
Dennis Luxen 2011-07-07 16:51:23 +00:00
parent ccf40b53eb
commit c60c3fcd3c
7 changed files with 681 additions and 712 deletions

View File

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

View File

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

View File

@ -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;
@ -46,11 +116,92 @@ template<class SearchEngineT>
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_ */

View File

@ -26,202 +26,43 @@ or see http://www.gnu.org/licenses/agpl.txt.
template<class SearchEngineT>
class GPXDescriptor : public BaseDescriptor<SearchEngineT>{
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 += ("<?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";
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";
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 += "<rtept lat=\"" + tmp + "\" ";
convertInternalLatLonToString(current.lon, tmp);
reply.content += "lon=\"" + tmp + "\">";
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>";
reply.content +="</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);
}
convertInternalLatLonToString(current.lat, tmp);
bodyString += "\n\t\t<rtept lat=\"" + tmp + "\" ";
convertInternalLatLonToString(current.lon, tmp);
bodyString += "lon=\"" + tmp + "\">\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<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>";
}
else {
reply.content += "\t<extensions>\n\t<rte>\n";
}
reply.content += "\t</rte>\n</gpx>";
reply.content += "</rte></gpx>";
}
private:
};
#endif /* GPX_DESCRIPTOR_H_ */

View File

@ -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> {
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);
}
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_ */

View File

@ -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");
//put start coord to linestring;
convertInternalCoordinateToString(phantomNodes->startCoord, tmp);
lineString += tmp;
reply.content += ("\t</Placemark>\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<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);
} 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 += "]]></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, ";
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 += "]]></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";
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 = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
reply.content += ("<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n");
reply.content += ("<Document>\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<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;
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 += "&#160;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 += "&#160;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";
}
reply.content += "\t</Placemark>\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 += 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_ */

View File

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