This commit is contained in:
DennisOSRM 2011-12-20 11:38:31 +01:00
commit 95d8d44259
8 changed files with 315 additions and 242 deletions

View File

@ -22,7 +22,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#define DOUGLASPEUCKER_H_ #define DOUGLASPEUCKER_H_
#include <cfloat> #include <cfloat>
#include <stack> #include "../DataStructures/SimpleStack.h"
/*This class object computes the bitvector of indicating generalized input points /*This class object computes the bitvector of indicating generalized input points
* according to the (Ramer-)Douglas-Peucker algorithm. * according to the (Ramer-)Douglas-Peucker algorithm.
@ -39,9 +39,9 @@ class DouglasPeucker {
private: private:
typedef std::pair<std::size_t, std::size_t> PairOfPoints; typedef std::pair<std::size_t, std::size_t> PairOfPoints;
//Stack to simulate the recursion //Stack to simulate the recursion
std::stack<PairOfPoints > recursionStack; SimpleStack<PairOfPoints > recursionStack;
double ComputeDistance(const _Coordinate& inputPoint, const _Coordinate& source, const _Coordinate& target) { double ComputeDistanceOfPointToLine(const _Coordinate& inputPoint, const _Coordinate& source, const _Coordinate& target) {
double r; double r;
const double x = (double)inputPoint.lat; const double x = (double)inputPoint.lat;
const double y = (double)inputPoint.lon; const double y = (double)inputPoint.lon;
@ -81,6 +81,7 @@ public:
std::size_t leftBorderOfRange = 0; std::size_t leftBorderOfRange = 0;
std::size_t rightBorderOfRange = 1; std::size_t rightBorderOfRange = 1;
//Sweep linerarily over array and identify those ranges that need to be checked //Sweep linerarily over array and identify those ranges that need to be checked
recursionStack.hint(inputVector.size());
do { do {
assert(inputVector[leftBorderOfRange].necessary); assert(inputVector[leftBorderOfRange].necessary);
assert(inputVector[inputVector.size()-1].necessary); assert(inputVector[inputVector.size()-1].necessary);
@ -104,7 +105,7 @@ public:
std::size_t indexOfFarthestElement = pair.second; std::size_t indexOfFarthestElement = pair.second;
//find index idx of element with maxDistance //find index idx of element with maxDistance
for(std::size_t i = pair.first+1; i < pair.second; ++i){ for(std::size_t i = pair.first+1; i < pair.second; ++i){
double distance = std::fabs(ComputeDistance(inputVector[i].location, inputVector[pair.first].location, inputVector[pair.second].location)); double distance = std::fabs(ComputeDistanceOfPointToLine(inputVector[i].location, inputVector[pair.first].location, inputVector[pair.second].location));
if(distance > DouglasPeuckerThresholds[zoomLevel] && distance > maxDistance) { if(distance > DouglasPeuckerThresholds[zoomLevel] && distance > maxDistance) {
indexOfFarthestElement = i; indexOfFarthestElement = i;
maxDistance = distance; maxDistance = distance;

View File

@ -24,28 +24,28 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <list> #include <list>
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
template<typename ValueT> template<typename KeyT, typename ValueT>
class LRUCache { class LRUCache {
private: private:
struct CacheEntry { struct CacheEntry {
CacheEntry(unsigned k, ValueT v) : key(k), value(v) {} CacheEntry(KeyT k, ValueT v) : key(k), value(v) {}
unsigned key; KeyT key;
ValueT value; ValueT value;
}; };
unsigned capacity; unsigned capacity;
std::list<CacheEntry> itemsInCache; std::list<CacheEntry> itemsInCache;
boost::unordered_map<unsigned, typename std::list<CacheEntry>::iterator > positionMap; boost::unordered_map<KeyT, typename std::list<CacheEntry>::iterator > positionMap;
public: public:
LRUCache(unsigned c) : capacity(c) {} LRUCache(unsigned c) : capacity(c) {}
bool Holds(unsigned key) { bool Holds(KeyT key) {
if(positionMap.find(key) != positionMap.end()) { if(positionMap.find(key) != positionMap.end()) {
return true; return true;
} }
return false; return false;
} }
void Insert(const unsigned key, ValueT value) { void Insert(const KeyT key, ValueT &value) {
itemsInCache.push_front(CacheEntry(key, value)); itemsInCache.push_front(CacheEntry(key, value));
positionMap.insert(std::make_pair(key, itemsInCache.begin())); positionMap.insert(std::make_pair(key, itemsInCache.begin()));
if(itemsInCache.size() > capacity) { if(itemsInCache.size() > capacity) {
@ -53,7 +53,7 @@ public:
itemsInCache.pop_back(); itemsInCache.pop_back();
} }
} }
bool Fetch(const unsigned key, ValueT& result) { bool Fetch(const KeyT key, ValueT& result) {
if(Holds(key)) { if(Holds(key)) {
CacheEntry e = *(positionMap.find(key)->second); CacheEntry e = *(positionMap.find(key)->second);
result = e.value; result = e.value;

View File

@ -147,13 +147,11 @@ public:
/** search for point on edge close to source */ /** search for point on edge close to source */
unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon); unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
std::vector<_GridEdge> candidates; std::vector<_GridEdge> candidates;
for(int j = -32768; j < (32768+1); j+=32768) { for(int j = -32768; j < (32768+1); j+=32768) {
for(int i = -1; i < 2; i++){ for(int i = -1; i < 2; i++){
GetContentsOfFileBucket(fileIndex+i+j, candidates); GetContentsOfFileBucket(fileIndex+i+j, candidates);
} }
} }
_GridEdge smallestEdge; _GridEdge smallestEdge;
_Coordinate tmp, newEndpoint; _Coordinate tmp, newEndpoint;
double dist = numeric_limits<double>::max(); double dist = numeric_limits<double>::max();
@ -179,7 +177,6 @@ public:
//INFO("b) " << candidate.edgeBasedNode << ", dist: " << tmpDist); //INFO("b) " << candidate.edgeBasedNode << ", dist: " << tmpDist);
} }
} }
// INFO("startcoord: " << smallestEdge.startCoord << ", tgtcoord" << smallestEdge.targetCoord << "result: " << newEndpoint); // INFO("startcoord: " << smallestEdge.startCoord << ", tgtcoord" << smallestEdge.targetCoord << "result: " << newEndpoint);
// INFO("length of old edge: " << LengthOfVector(smallestEdge.startCoord, smallestEdge.targetCoord)); // INFO("length of old edge: " << LengthOfVector(smallestEdge.startCoord, smallestEdge.targetCoord));
// INFO("Length of new edge: " << LengthOfVector(smallestEdge.startCoord, newEndpoint)); // INFO("Length of new edge: " << LengthOfVector(smallestEdge.startCoord, newEndpoint));
@ -253,16 +250,16 @@ public:
private: private:
void BuildCellIndexToFileIndexMap(const unsigned ramIndex, boost::unordered_map<unsigned ,unsigned >& cellMap){ inline void BuildCellIndexToFileIndexMap(const unsigned ramIndex, boost::unordered_map<unsigned ,unsigned >& cellMap){
unsigned lineBase = ramIndex/1024; unsigned lineBase = ramIndex/1024;
lineBase = lineBase*32*32768; lineBase = lineBase*32*32768;
unsigned columnBase = ramIndex%1024; unsigned columnBase = ramIndex%1024;
columnBase=columnBase*32; columnBase=columnBase*32;
for (int i = 0;i < 32;i++) { for (int i = 0;i < 32;++i) {
for (int j = 0;j < 32;j++) { for (int j = 0;j < 32;++j) {
unsigned fileIndex = lineBase + i * 32768 + columnBase + j; unsigned fileIndex = lineBase + i * 32768 + columnBase + j;
unsigned cellIndex = i * 32 + j; unsigned cellIndex = i * 32 + j;
cellMap.insert(std::make_pair(fileIndex, cellIndex)); cellMap[fileIndex] = cellIndex;
} }
} }
} }
@ -369,7 +366,7 @@ private:
return; return;
} }
std::vector<unsigned long> cellIndex(32*32); unsigned long cellIndex[32*32];
boost::unordered_map< unsigned, unsigned > cellMap(1024); boost::unordered_map< unsigned, unsigned > cellMap(1024);
BuildCellIndexToFileIndexMap(ramIndex, cellMap); BuildCellIndexToFileIndexMap(ramIndex, cellMap);
@ -382,8 +379,8 @@ private:
} }
localStream->seekg(startIndexInFile); localStream->seekg(startIndexInFile);
localStream->read((char*) &cellIndex[0], 32*32*sizeof(unsigned long)); localStream->read((char*) cellIndex, 32*32*sizeof(unsigned long));
assert(cellMap.find(fileIndex) != cellMap.end()); assert(cellMap.find(fileIndex) != cellMap.end());
if(cellIndex[cellMap.find(fileIndex)->second] == ULONG_MAX) { if(cellIndex[cellMap.find(fileIndex)->second] == ULONG_MAX) {
return; return;
} }
@ -397,7 +394,7 @@ private:
break; break;
result.push_back(gridEdge); result.push_back(gridEdge);
} while(true); } while(true);
} }
void AddEdge(_GridEdge edge) { void AddEdge(_GridEdge edge) {
std::vector<BresenhamPixel> indexList; std::vector<BresenhamPixel> indexList;

View File

@ -29,40 +29,38 @@ or see http://www.gnu.org/licenses/agpl.txt.
template<typename NodeT> template<typename NodeT>
struct NodeCoords { struct NodeCoords {
typedef unsigned key_type; //type of NodeID typedef unsigned key_type; //type of NodeID
typedef int value_type; //type of lat,lons typedef int value_type; //type of lat,lons
NodeCoords(int _lat, int _lon, NodeT _id) : lat(_lat), lon(_lon), id(_id) {} NodeCoords(int _lat, int _lon, NodeT _id) : lat(_lat), lon(_lon), id(_id) {}
NodeCoords() : lat(INT_MAX), lon(INT_MAX), id(UINT_MAX) {} NodeCoords() : lat(INT_MAX), lon(INT_MAX), id(UINT_MAX) {}
int lat; int lat;
int lon; int lon;
NodeT id; NodeT id;
static NodeCoords<NodeT> min_value() static NodeCoords<NodeT> min_value() {
{ return NodeCoords<NodeT>(-90*100000,-180*100000,numeric_limits<NodeT>::min());
return NodeCoords<NodeT>(-90*100000,-180*100000,numeric_limits<NodeT>::min()); }
} static NodeCoords<NodeT> max_value() {
static NodeCoords<NodeT> max_value() return NodeCoords<NodeT>(90*100000, 180*100000, numeric_limits<NodeT>::max());
{ }
return NodeCoords<NodeT>(90*100000, 180*100000, numeric_limits<NodeT>::max());
}
value_type operator[](size_t n) const { value_type operator[](size_t n) const {
switch(n) { switch(n) {
case 1: case 1:
return lat; return lat;
break; break;
case 0: case 0:
return lon; return lon;
break; break;
default: default:
assert(false); assert(false);
return UINT_MAX; return UINT_MAX;
break; break;
} }
assert(false); assert(false);
return UINT_MAX; return UINT_MAX;
} }
}; };
#endif //_NODE_COORDS_H #endif //_NODE_COORDS_H

View File

@ -31,46 +31,41 @@ or see http://www.gnu.org/licenses/agpl.txt.
class NodeInformationHelpDesk{ class NodeInformationHelpDesk{
public: public:
NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, unsigned _numberOfNodes) : numberOfNodes(_numberOfNodes) { NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned _numberOfNodes) : numberOfNodes(_numberOfNodes) {
readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput); readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
int2ExtNodeMap = new vector<_Coordinate>(); coordinateVector.reserve(numberOfNodes);
int2ExtNodeMap->reserve(numberOfNodes); assert(0 == coordinateVector.size());
assert(0 == int2ExtNodeMap->size());
} }
~NodeInformationHelpDesk() { ~NodeInformationHelpDesk() {
delete int2ExtNodeMap;
delete readOnlyGrid; delete readOnlyGrid;
} }
void initNNGrid(ifstream& in) { void initNNGrid(ifstream& in) {
while(!in.eof()) { while(!in.eof()) {
NodeInfo b; NodeInfo b;
in.read((char *)&b, sizeof(b)); in.read((char *)&b, sizeof(b));
int2ExtNodeMap->push_back(_Coordinate(b.lat, b.lon)); coordinateVector.push_back(_Coordinate(b.lat, b.lon));
} }
in.close(); in.close();
readOnlyGrid->OpenIndexFiles(); readOnlyGrid->OpenIndexFiles();
} }
inline int getLatitudeOfNode(const NodeID node) const { inline int getLatitudeOfNode(const NodeID node) const { return coordinateVector.at(node).lat; }
return int2ExtNodeMap->at(node).lat;
}
inline int getLongitudeOfNode(const NodeID node) const { return int2ExtNodeMap->at(node).lon; } inline int getLongitudeOfNode(const NodeID node) const { return coordinateVector.at(node).lon; }
NodeID getNumberOfNodes() const { return numberOfNodes; } inline NodeID getNumberOfNodes() const { return numberOfNodes; }
NodeID getNumberOfNodes2() const { return int2ExtNodeMap->size(); } inline NodeID getNumberOfNodes2() const { return coordinateVector.size(); }
inline void FindNearestNodeCoordForLatLon(const _Coordinate& coord, _Coordinate& result) { inline void FindNearestNodeCoordForLatLon(const _Coordinate& coord, _Coordinate& result) const {
readOnlyGrid->FindNearestCoordinateOnEdgeInNodeBasedGraph(coord, result); readOnlyGrid->FindNearestCoordinateOnEdgeInNodeBasedGraph(coord, result);
} }
bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode) { inline void FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode) const {
return readOnlyGrid->FindPhantomNodeForCoordinate(location, resultNode); readOnlyGrid->FindPhantomNodeForCoordinate(location, resultNode);
} }
inline bool FindRoutingStarts(const _Coordinate &start, const _Coordinate &target, PhantomNodes & phantomNodes) { inline void FindRoutingStarts(const _Coordinate &start, const _Coordinate &target, PhantomNodes & phantomNodes) const {
readOnlyGrid->FindRoutingStarts(start, target, phantomNodes); readOnlyGrid->FindRoutingStarts(start, target, phantomNodes);
return true;
} }
inline void FindNearestPointOnEdge(const _Coordinate & input, _Coordinate& output){ inline void FindNearestPointOnEdge(const _Coordinate & input, _Coordinate& output){
@ -78,7 +73,7 @@ public:
} }
private: private:
vector<_Coordinate> * int2ExtNodeMap; std::vector<_Coordinate> coordinateVector;
ReadOnlyGrid * readOnlyGrid; ReadOnlyGrid * readOnlyGrid;
unsigned numberOfNodes; unsigned numberOfNodes;
}; };

View File

@ -23,6 +23,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <climits> #include <climits>
#include <deque> #include <deque>
#include "SimpleStack.h"
#include <boost/thread.hpp> #include <boost/thread.hpp>
@ -36,7 +37,7 @@ struct _HeapData {
_HeapData( NodeID p ) : parent(p) { } _HeapData( NodeID p ) : parent(p) { }
}; };
typedef boost::thread_specific_ptr<BinaryHeap< NodeID, NodeID, int, _HeapData> > HeapPtr; typedef boost::thread_specific_ptr<BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> > > HeapPtr;
template<class EdgeData, class GraphT> template<class EdgeData, class GraphT>
class SearchEngine { class SearchEngine {
@ -57,13 +58,15 @@ public:
} }
inline void InitializeThreadLocalStorageIfNecessary() { inline void InitializeThreadLocalStorageIfNecessary() {
if(!_forwardHeap.get()) if(!_forwardHeap.get()) {
_forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData>(nodeHelpDesk->getNumberOfNodes())); _forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
}
else else
_forwardHeap->Clear(); _forwardHeap->Clear();
if(!_backwardHeap.get()) if(!_backwardHeap.get()) {
_backwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData>(nodeHelpDesk->getNumberOfNodes())); _backwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
}
else else
_backwardHeap->Clear(); _backwardHeap->Clear();
} }
@ -117,20 +120,16 @@ public:
pathNode = _backwardHeap->GetData(pathNode).parent; pathNode = _backwardHeap->GetData(pathNode).parent;
packedPath.push_back(pathNode); packedPath.push_back(pathNode);
} }
for(deque<NodeID>::size_type i = 0;i < packedPath.size() - 1;i++){ _UnpackPath(packedPath, path);
_UnpackEdge(packedPath[i], packedPath[i + 1], path);
}
return _upperbound; return _upperbound;
} }
inline bool FindRoutingStarts(const _Coordinate & start, const _Coordinate & target, PhantomNodes & routingStarts) const { inline void FindRoutingStarts(const _Coordinate & start, const _Coordinate & target, PhantomNodes & routingStarts) const {
nodeHelpDesk->FindRoutingStarts(start, target, routingStarts); nodeHelpDesk->FindRoutingStarts(start, target, routingStarts);
return true;
} }
inline bool FindPhantomNodeForCoordinate(const _Coordinate & location, PhantomNode & result) const { inline void FindPhantomNodeForCoordinate(const _Coordinate & location, PhantomNode & result) const {
return nodeHelpDesk->FindPhantomNodeForCoordinate(location, result); nodeHelpDesk->FindPhantomNodeForCoordinate(location, result);
} }
inline NodeID GetNameIDForOriginDestinationNodeID(NodeID s, NodeID t) const { inline NodeID GetNameIDForOriginDestinationNodeID(NodeID s, NodeID t) const {
@ -226,41 +225,52 @@ private:
} }
} }
inline bool _UnpackEdge(const NodeID source, const NodeID target, std::vector<_PathData> & path) const { inline void _UnpackPath(const std::deque<NodeID> & packedPath, std::vector<_PathData> & unpackedPath) const {
assert(source != target); const std::deque<NodeID>::size_type sizeOfPackedPath = packedPath.size();
//find edge first. SimpleStack<std::pair<NodeID, NodeID> > recursionStack(sizeOfPackedPath);
typename GraphT::EdgeIterator smallestEdge = SPECIAL_EDGEID;
int smallestWeight = INT_MAX; //We have to push the path in reverse order onto the stack because it's LIFO.
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(source);eit < _graph->EndEdges(source);eit++){ for(std::deque<NodeID>::size_type i = sizeOfPackedPath-1; i > 0; --i){
const int weight = _graph->GetEdgeData(eit).distance; recursionStack.push(std::make_pair(packedPath[i-1], packedPath[i]));
if(_graph->GetTarget(eit) == target && weight < smallestWeight && _graph->GetEdgeData(eit).forward){
smallestEdge = eit;
smallestWeight = weight;
}
} }
if(smallestEdge == SPECIAL_EDGEID){ std::pair<NodeID, NodeID> edge;
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(target);eit < _graph->EndEdges(target);eit++){ while(!recursionStack.empty()) {
edge = recursionStack.top();
recursionStack.pop();
typename GraphT::EdgeIterator smallestEdge = SPECIAL_EDGEID;
int smallestWeight = INT_MAX;
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(edge.first);eit < _graph->EndEdges(edge.first);++eit){
const int weight = _graph->GetEdgeData(eit).distance; const int weight = _graph->GetEdgeData(eit).distance;
if(_graph->GetTarget(eit) == source && weight < smallestWeight && _graph->GetEdgeData(eit).backward){ if(_graph->GetTarget(eit) == edge.second && weight < smallestWeight && _graph->GetEdgeData(eit).forward){
smallestEdge = eit; smallestEdge = eit;
smallestWeight = weight; smallestWeight = weight;
} }
} }
}
assert(smallestWeight != INT_MAX); if(smallestEdge == SPECIAL_EDGEID){
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(edge.second);eit < _graph->EndEdges(edge.second);++eit){
const int weight = _graph->GetEdgeData(eit).distance;
if(_graph->GetTarget(eit) == edge.first && weight < smallestWeight && _graph->GetEdgeData(eit).backward){
smallestEdge = eit;
smallestWeight = weight;
}
}
}
const EdgeData& ed = _graph->GetEdgeData(smallestEdge); assert(smallestWeight != INT_MAX);
if(ed.shortcut) {//unpack
const NodeID middle = ed.via; const EdgeData& ed = _graph->GetEdgeData(smallestEdge);
_UnpackEdge(source, middle, path); if(ed.shortcut) {//unpack
_UnpackEdge(middle, target, path); const NodeID middle = ed.via;
return false; //again, we need to this in reversed order
} else { recursionStack.push(std::make_pair(middle, edge.second));
assert(!ed.shortcut); recursionStack.push(std::make_pair(edge.first, middle));
path.push_back(_PathData(ed.via, ed.nameID, ed.turnInstruction, ed.distance) ); } else {
return true; assert(!ed.shortcut);
unpackedPath.push_back(_PathData(ed.via, ed.nameID, ed.turnInstruction, ed.distance) );
}
} }
} }
}; };

View File

@ -0,0 +1,71 @@
/*
open source routing machine
Copyright (C) Dennis Luxen, others 2010
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
or see http://www.gnu.org/licenses/agpl.txt.
*/
#ifndef SIMPLESTACK_H_
#define SIMPLESTACK_H_
#include <cassert>
#include <vector>
template<typename StackItemT, class ContainerT = std::vector<StackItemT> >
class SimpleStack {
private:
int last;
ContainerT arr;
public:
SimpleStack() : last(-1) {
}
SimpleStack(std::size_t size_hint) : last(-1) {
hint(size_hint);
}
inline void hint(std::size_t size_hint) {
arr.reserve(size_hint);
}
inline void push(StackItemT t) {
++last;
arr.push_back(t);
}
inline void pop() {
arr.pop_back();
--last;
}
inline StackItemT top() {
assert (last >= 0);
return arr[last];
}
inline int size() {
return last+1;
}
inline bool empty() {
return (-1 == last);
}
};
#endif /* SIMPLESTACK_H_ */

View File

@ -32,145 +32,146 @@ or see http://www.gnu.org/licenses/agpl.txt.
template<class SearchEngineT> template<class SearchEngineT>
class JSONDescriptor : public BaseDescriptor<SearchEngineT>{ class JSONDescriptor : public BaseDescriptor<SearchEngineT>{
private: private:
_DescriptorConfig config; _DescriptorConfig config;
_RouteSummary summary; _RouteSummary summary;
DescriptionFactory descriptionFactory; DescriptionFactory descriptionFactory;
std::string tmp; _Coordinate current;
_Coordinate current; struct {
struct { int startIndex;
int startIndex; int nameID;
int nameID; int leaveAtExit;
int leaveAtExit; } roundAbout;
} roundAbout;
public: public:
JSONDescriptor() {} JSONDescriptor() {}
void SetConfig(const _DescriptorConfig & c) { config = c; } void SetConfig(const _DescriptorConfig & c) { config = c; }
void Run(http::Reply & reply, RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine, unsigned durationOfTrip) { void Run(http::Reply & reply, RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine, const unsigned durationOfTrip) {
WriteHeaderToOutput(reply.content); WriteHeaderToOutput(reply.content);
if(durationOfTrip != INT_MAX && rawRoute.routeSegments.size() > 0) { if(durationOfTrip != INT_MAX && rawRoute.routeSegments.size() > 0) {
summary.startName = sEngine.GetEscapedNameForNameID(phantomNodes.startPhantom.nodeBasedEdgeNameID); summary.startName = sEngine.GetEscapedNameForNameID(phantomNodes.startPhantom.nodeBasedEdgeNameID);
descriptionFactory.SetStartSegment(phantomNodes.startPhantom); descriptionFactory.SetStartSegment(phantomNodes.startPhantom);
summary.destName = sEngine.GetEscapedNameForNameID(phantomNodes.targetPhantom.nodeBasedEdgeNameID); summary.destName = sEngine.GetEscapedNameForNameID(phantomNodes.targetPhantom.nodeBasedEdgeNameID);
reply.content += "0," reply.content += "0,"
"\"status_message\": \"Found route between points\","; "\"status_message\": \"Found route between points\",";
for(unsigned segmentIdx = 0; segmentIdx < rawRoute.routeSegments.size(); segmentIdx++) { for(unsigned segmentIdx = 0; segmentIdx < rawRoute.routeSegments.size(); ++segmentIdx) {
const std::vector< _PathData > & path = rawRoute.routeSegments[segmentIdx]; BOOST_FOREACH(_PathData & pathData, rawRoute.routeSegments[segmentIdx]) {
BOOST_FOREACH(_PathData pathData, path) { sEngine.GetCoordinatesForNodeID(pathData.node, current);
sEngine.GetCoordinatesForNodeID(pathData.node, current); descriptionFactory.AppendSegment(current, pathData );
descriptionFactory.AppendSegment(current, pathData ); }
} }
//TODO: Add via points descriptionFactory.SetEndSegment(phantomNodes.targetPhantom);
} } else {
descriptionFactory.SetEndSegment(phantomNodes.targetPhantom); //We do not need to do much, if there is no route ;-)
} else { reply.content += "207,"
//We do not need to do much, if there is no route ;-) "\"status_message\": \"Cannot find route between points\",";
reply.content += "207," }
"\"status_message\": \"Cannot find route between points\",";
}
summary.BuildDurationAndLengthStrings(descriptionFactory.Run(config.z), durationOfTrip); summary.BuildDurationAndLengthStrings(descriptionFactory.Run(config.z), durationOfTrip);
reply.content += "\"route_summary\": {" reply.content += "\"route_summary\": {"
"\"total_distance\":"; "\"total_distance\":";
reply.content += summary.lengthString; reply.content += summary.lengthString;
reply.content += "," reply.content += ","
"\"total_time\":"; "\"total_time\":";
reply.content += summary.durationString; reply.content += summary.durationString;
reply.content += "," reply.content += ","
"\"start_point\":\""; "\"start_point\":\"";
reply.content += summary.startName; reply.content += summary.startName;
reply.content += "\"," reply.content += "\","
"\"end_point\":\""; "\"end_point\":\"";
reply.content += summary.destName; reply.content += summary.destName;
reply.content += "\""; reply.content += "\"";
reply.content += "},"; reply.content += "},";
reply.content += "\"route_geometry\": "; reply.content += "\"route_geometry\": ";
if(config.geometry) { if(config.geometry) {
if(config.encodeGeometry) if(config.encodeGeometry)
descriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry); descriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry);
} else { } else {
reply.content += "[]"; reply.content += "[]";
} }
reply.content += "," reply.content += ","
"\"route_instructions\": ["; "\"route_instructions\": [";
if(config.instructions) { if(config.instructions) {
//Segment information has following format: //Segment information has following format:
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth] //["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
//Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5] //Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]
//See also: http://developers.cloudmade.com/wiki/navengine/JSON_format //See also: http://developers.cloudmade.com/wiki/navengine/JSON_format
unsigned prefixSumOfNecessarySegments = 0; unsigned prefixSumOfNecessarySegments = 0;
roundAbout.leaveAtExit = 0; roundAbout.leaveAtExit = 0;
roundAbout.nameID = 0; roundAbout.nameID = 0;
std::string tmpDist, tmpLength, tmp; std::string tmpDist, tmpLength, tmpDuration;
//Fetch data from Factory and generate a string from it. //Fetch data from Factory and generate a string from it.
BOOST_FOREACH(SegmentInformation segment, descriptionFactory.pathDescription) { BOOST_FOREACH(SegmentInformation & segment, descriptionFactory.pathDescription) {
if(TurnInstructions.TurnIsNecessary( segment.turnInstruction) ) { if(TurnInstructions.TurnIsNecessary( segment.turnInstruction) ) {
if(TurnInstructions.EnterRoundAbout == segment.turnInstruction) { if(TurnInstructions.EnterRoundAbout == segment.turnInstruction) {
roundAbout.nameID = segment.nameID; roundAbout.nameID = segment.nameID;
roundAbout.startIndex = prefixSumOfNecessarySegments; roundAbout.startIndex = prefixSumOfNecessarySegments;
} else { } else {
if(0 != prefixSumOfNecessarySegments) if(0 != prefixSumOfNecessarySegments)
reply.content += ","; reply.content += ",";
reply.content += "[\""; reply.content += "[\"";
if(TurnInstructions.LeaveRoundAbout == segment.turnInstruction) { if(TurnInstructions.LeaveRoundAbout == segment.turnInstruction) {
reply.content += TurnInstructions.TurnStrings[TurnInstructions.EnterRoundAbout]; reply.content += TurnInstructions.TurnStrings[TurnInstructions.EnterRoundAbout];
reply.content += " and leave at "; reply.content += " and leave at ";
reply.content += TurnInstructions.Ordinals[roundAbout.leaveAtExit+1]; reply.content += TurnInstructions.Ordinals[roundAbout.leaveAtExit+1];
reply.content += " exit"; reply.content += " exit";
roundAbout.leaveAtExit = 0; roundAbout.leaveAtExit = 0;
} else { } else {
reply.content += TurnInstructions.TurnStrings[segment.turnInstruction]; reply.content += TurnInstructions.TurnStrings[segment.turnInstruction];
} }
reply.content += "\",\""; reply.content += "\",\"";
reply.content += sEngine.GetEscapedNameForNameID(segment.nameID); reply.content += sEngine.GetEscapedNameForNameID(segment.nameID);
reply.content += "\","; reply.content += "\",";
intToString(segment.length, tmpDist); intToString(segment.length, tmpDist);
reply.content += tmpDist; reply.content += tmpDist;
reply.content += ","; reply.content += ",";
intToString(prefixSumOfNecessarySegments, tmpLength); intToString(prefixSumOfNecessarySegments, tmpLength);
reply.content += tmpLength; reply.content += tmpLength;
reply.content += ","; reply.content += ",";
intToString(segment.duration, tmp); intToString(segment.duration, tmpDuration);
reply.content += ",\""; reply.content += tmpDuration;
reply.content += tmpLength; reply.content += ",\"";
//TODO: fix heading reply.content += tmpLength;
reply.content += "\",\"NE\",22.5"; //TODO: fix heading
reply.content += "]"; reply.content += "\",\"NE\",22.5";
} reply.content += "]";
} else if(TurnInstructions.StayOnRoundAbout == segment.turnInstruction) { }
++roundAbout.leaveAtExit; } else if(TurnInstructions.StayOnRoundAbout == segment.turnInstruction) {
} ++roundAbout.leaveAtExit;
if(segment.necessary) }
++prefixSumOfNecessarySegments; if(segment.necessary)
} ++prefixSumOfNecessarySegments;
} }
reply.content += "],"; }
//list all viapoints so that the client may display it reply.content += "],";
reply.content += "\"via_points\":["; //list all viapoints so that the client may display it
for(unsigned segmentIdx = 1; (true == config.geometry) && (segmentIdx < rawRoute.segmentEndCoordinates.size()); segmentIdx++) { reply.content += "\"via_points\":[";
if(segmentIdx > 1) if(true == config.geometry) {
reply.content += ","; std::string tmp;
reply.content += "["; for(unsigned segmentIdx = 1; segmentIdx < rawRoute.segmentEndCoordinates.size(); ++segmentIdx) {
if(rawRoute.segmentEndCoordinates[segmentIdx].startPhantom.location.isSet()) if(segmentIdx > 1)
convertInternalReversedCoordinateToString(rawRoute.segmentEndCoordinates[segmentIdx].startPhantom.location, tmp); reply.content += ",";
else reply.content += "[";
convertInternalReversedCoordinateToString(rawRoute.rawViaNodeCoordinates[segmentIdx], tmp); if(rawRoute.segmentEndCoordinates[segmentIdx].startPhantom.location.isSet())
reply.content += tmp; convertInternalReversedCoordinateToString(rawRoute.segmentEndCoordinates[segmentIdx].startPhantom.location, tmp);
reply.content += "]"; else
} convertInternalReversedCoordinateToString(rawRoute.rawViaNodeCoordinates[segmentIdx], tmp);
reply.content += "]," reply.content += tmp;
"\"transactionId\": \"OSRM Routing Engine JSON Descriptor (v0.2)\""; reply.content += "]";
reply.content += "}"; }
} }
reply.content += "],"
"\"transactionId\": \"OSRM Routing Engine JSON Descriptor (v0.3)\"";
reply.content += "}";
}
void WriteHeaderToOutput(std::string & output) { inline void WriteHeaderToOutput(std::string & output) {
output += "{" output += "{"
"\"version\": 0.3," "\"version\": 0.3,"
"\"status\":"; "\"status\":";
} }
}; };
#endif /* JSON_DESCRIPTOR_H_ */ #endif /* JSON_DESCRIPTOR_H_ */