diff --git a/.gitignore b/.gitignore index d76967bc1..b8ca61d98 100644 --- a/.gitignore +++ b/.gitignore @@ -54,23 +54,23 @@ stxxl.errlog # compiled protobuffers # ######################### -DataStructures/pbf-proto/*.pb.h -DataStructures/pbf-proto/*.pb.cc +/DataStructures/pbf-proto/*.pb.h +/DataStructures/pbf-proto/*.pb.cc # External Libs # ################# -lib/ -win/lib +/lib/ +/win/lib # Visual Studio Temp + build Files # #################################### -win/*.user -win/*.ncb -win/*.suo -win/Debug/ -win/Release/ -win/bin/ -win/bin-debug/ +/win/*.user +/win/*.ncb +/win/*.suo +/win/Debug/ +/win/Release/ +/win/bin/ +/win/bin-debug/ /osrm-extract /osrm-routed /osrm-prepare @@ -78,6 +78,7 @@ win/bin-debug/ # Sandbox folder # ################### -sandbox/ +/sandbox/ -test/profile.lua \ No newline at end of file +/test/profile.lua +/profile.lua diff --git a/Algorithms/CRC32.h b/Algorithms/CRC32.h index d84a56808..6321030b7 100644 --- a/Algorithms/CRC32.h +++ b/Algorithms/CRC32.h @@ -27,7 +27,6 @@ class CRC32 { private: unsigned crc; - unsigned slowcrc_table[1<<8]; typedef boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> my_crc_32_type; typedef unsigned (CRC32::*CRC32CFunctionPtr)(char *str, unsigned len, unsigned crc); diff --git a/Algorithms/ObjectToBase64.h b/Algorithms/ObjectToBase64.h index fab161b21..8d69c0a8a 100644 --- a/Algorithms/ObjectToBase64.h +++ b/Algorithms/ObjectToBase64.h @@ -33,12 +33,12 @@ or see http://www.gnu.org/licenses/agpl.txt. typedef boost::archive::iterators::base64_from_binary< - boost::archive::iterators::transform_width + boost::archive::iterators::transform_width > base64_t; typedef boost::archive::iterators::transform_width< - boost::archive::iterators::binary_from_base64, 8, 6 + boost::archive::iterators::binary_from_base64, 8, 6 > binary_t; template @@ -54,7 +54,7 @@ static void EncodeObjectToBase64(const ToEncodeT & object, std::string& encoded) template static void DecodeObjectFromBase64(ToEncodeT & object, const std::string& _encoded) { try { - string encoded(_encoded); + std::string encoded(_encoded); //replace "-" with "+" and "_" with "/" replaceAll(encoded, "-", "+"); replaceAll(encoded, "_", "/"); diff --git a/Algorithms/StronglyConnectedComponents.h b/Algorithms/StronglyConnectedComponents.h index 148e35613..a83110034 100644 --- a/Algorithms/StronglyConnectedComponents.h +++ b/Algorithms/StronglyConnectedComponents.h @@ -52,21 +52,12 @@ private: unsigned edgeBasedNodeID; unsigned nameID:31; bool shortcut:1; + short type; + bool isAccessRestricted:1; bool forward:1; bool backward:1; bool roundabout:1; bool ignoreInGrid:1; - short type; - bool isAccessRestricted; - }; - - struct _EdgeBasedEdgeData { - int distance; - unsigned via; - unsigned nameID; - bool forward; - bool backward; - TurnInstruction turnInstruction; }; typedef DynamicGraph< _NodeBasedEdgeData > _NodeBasedDynamicGraph; diff --git a/Contractor/Contractor.h b/Contractor/Contractor.h index aad4123ac..b9059ca62 100644 --- a/Contractor/Contractor.h +++ b/Contractor/Contractor.h @@ -157,11 +157,13 @@ public: forwardEdge.data.distance = backwardEdge.data.distance = std::numeric_limits< int >::max(); //remove parallel edges while ( i < edges.size() && edges[i].source == source && edges[i].target == target ) { - if ( edges[i].data.forward ) + if ( edges[i].data.forward) { forwardEdge.data.distance = std::min( edges[i].data.distance, forwardEdge.data.distance ); - if ( edges[i].data.backward ) + } + if ( edges[i].data.backward) { backwardEdge.data.distance = std::min( edges[i].data.distance, backwardEdge.data.distance ); - i++; + } + ++i; } //merge edges (s,t) and (t,s) into bidirectional edge if ( forwardEdge.data.distance == backwardEdge.data.distance ) { @@ -242,7 +244,7 @@ public: nodePriority[x] = _Evaluate( data, &nodeData[x], x ); } } - std::cout << "ok" << std::endl << "preprocessing ..." << std::flush; + std::cout << "ok" << std::endl << "preprocessing " << numberOfNodes << " nodes ..." << std::flush; bool flushedContractor = false; while ( numberOfContractedNodes < numberOfNodes ) { @@ -274,7 +276,7 @@ public: TemporaryStorage & tempStorage = TemporaryStorage::GetInstance(); //Write dummy number of edges to temporary file // std::ofstream temporaryEdgeStorage(temporaryEdgeStorageFilename.c_str(), std::ios::binary); - long initialFilePosition = tempStorage.tell(temporaryStorageSlotID); + uint64_t initialFilePosition = tempStorage.tell(temporaryStorageSlotID); unsigned numberOfTemporaryEdges = 0; tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned)); diff --git a/Contractor/EdgeBasedGraphFactory.cpp b/Contractor/EdgeBasedGraphFactory.cpp index 994c4cc07..fce247d31 100644 --- a/Contractor/EdgeBasedGraphFactory.cpp +++ b/Contractor/EdgeBasedGraphFactory.cpp @@ -21,8 +21,8 @@ #include "EdgeBasedGraphFactory.h" template<> -EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vector & inputEdges, std::vector & bn, std::vector & tl, std::vector<_Restriction> & irs, std::vector & nI, SpeedProfileProperties sp) : inputNodeInfoList(nI), numberOfTurnRestrictions(irs.size()), speedProfile(sp) { - BOOST_FOREACH(_Restriction & restriction, irs) { +EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vector & inputEdges, std::vector & bn, std::vector & tl, std::vector<_Restriction> & irs, std::vector & nI, SpeedProfileProperties sp) : speedProfile(sp), inputNodeInfoList(nI), numberOfTurnRestrictions(irs.size()) { + BOOST_FOREACH(const _Restriction & restriction, irs) { std::pair restrictionSource = std::make_pair(restriction.fromNode, restriction.viaNode); unsigned index; RestrictionMap::iterator restrIter = _restrictionMap.find(restrictionSource); @@ -44,18 +44,12 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vector edges; - // edges.reserve( 2 * inputEdges.size() ); + _NodeBasedEdge edge; for ( std::vector< NodeBasedEdge >::const_iterator i = inputEdges.begin(); i != inputEdges.end(); ++i ) { - - _NodeBasedEdge edge; if(!i->isForward()) { edge.source = i->target(); edge.target = i->source(); @@ -67,9 +61,9 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vectorisForward(); edge.data.backward = i->isBackward(); } - if(edge.source == edge.target) - continue; - + if(edge.source == edge.target) { + continue; + } edge.data.distance = (std::max)((int)i->weight(), 1 ); assert( edge.data.distance > 0 ); edge.data.shortcut = false; @@ -79,6 +73,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vectortype(); edge.data.isAccessRestricted = i->isAccessRestricted(); edge.data.edgeBasedNodeID = edges.size(); + edge.data.contraFlow = i->isContraFlow(); edges.push_back( edge ); if( edge.data.backward ) { std::swap( edge.source, edge.target ); @@ -108,16 +103,12 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode nodes.swap(edgeBasedNodes); } -void EdgeBasedGraphFactory::GetOriginalEdgeData( std::vector< OriginalEdgeData> & oed) { - oed.swap(originalEdgeData); -} - NodeID EdgeBasedGraphFactory::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const { std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v); RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource); if (restrIter != _restrictionMap.end()) { unsigned index = restrIter->second; - BOOST_FOREACH(RestrictionSource restrictionTarget, _restrictionBucketVector.at(index)) { + BOOST_FOREACH(const RestrictionSource & restrictionTarget, _restrictionBucketVector.at(index)) { if(restrictionTarget.second) { return restrictionTarget.first; } @@ -159,7 +150,7 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode( edgeBasedNodes.push_back(currentNode); } -void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename) { +void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename, lua_State *myLuaState) { Percent p(_nodeBasedGraph->GetNumberOfNodes()); int numberOfSkippedTurns(0); int nodeBasedEdgeCounter(0); @@ -243,12 +234,16 @@ void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename) { std::vector().swap(vectorOfComponentSizes); std::vector().swap(componentsIndex); + std::vector original_edge_data_vector; + original_edge_data_vector.reserve(10000); + //Loop over all turns and generate new set of edges. //Three nested loop look super-linear, but we are dealing with a linear number of turns only. for(_NodeBasedDynamicGraph::NodeIterator u = 0; u < _nodeBasedGraph->GetNumberOfNodes(); ++u ) { for(_NodeBasedDynamicGraph::EdgeIterator e1 = _nodeBasedGraph->BeginEdges(u); e1 < _nodeBasedGraph->EndEdges(u); ++e1) { ++nodeBasedEdgeCounter; _NodeBasedDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1); + bool isBollardNode = (_barrierNodes.find(v) != _barrierNodes.end()); //EdgeWeight heightPenalty = ComputeHeightPenalty(u, v); NodeID onlyToNode = CheckForEmanatingIsOnlyTurn(u, v); for(_NodeBasedDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) { @@ -258,7 +253,7 @@ void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename) { ++numberOfSkippedTurns; continue; } - bool isBollardNode = (_barrierNodes.find(v) != _barrierNodes.end()); + if(u == w && 1 != _nodeBasedGraph->GetOutDegree(v) ) { continue; } @@ -278,30 +273,30 @@ void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename) { if(_trafficLights.find(v) != _trafficLights.end()) { distance += speedProfile.trafficSignalPenalty; } - TurnInstruction turnInstruction = AnalyzeTurn(u, v, w); + unsigned penalty = 0; + TurnInstruction turnInstruction = AnalyzeTurn(u, v, w, penalty, myLuaState); if(turnInstruction == TurnInstructions.UTurn) distance += speedProfile.uTurnPenalty; // if(!edgeData1.isAccessRestricted && edgeData2.isAccessRestricted) { // distance += TurnInstructions.AccessRestrictionPenalty; // turnInstruction |= TurnInstructions.AccessRestrictionFlag; // } - + distance += penalty; + //distance += heightPenalty; //distance += ComputeTurnPenalty(u, v, w); assert(edgeData1.edgeBasedNodeID != edgeData2.edgeBasedNodeID); - if(originalEdgeData.size() == originalEdgeData.capacity()-3) { - originalEdgeData.reserve(originalEdgeData.size()*1.2); - } OriginalEdgeData oed(v,edgeData2.nameID, turnInstruction); - EdgeBasedEdge newEdge(edgeData1.edgeBasedNodeID, edgeData2.edgeBasedNodeID, edgeBasedEdges.size(), distance, true, false ); - originalEdgeData.push_back(oed); - if(originalEdgeData.size() > 100000) { - originalEdgeDataOutFile.write((char*)&(originalEdgeData[0]), originalEdgeData.size()*sizeof(OriginalEdgeData)); - originalEdgeData.clear(); - } + original_edge_data_vector.push_back(oed); ++numberOfOriginalEdges; - ++nodeBasedEdgeCounter; + + if(original_edge_data_vector.size() > 100000) { + originalEdgeDataOutFile.write((char*)&(original_edge_data_vector[0]), original_edge_data_vector.size()*sizeof(OriginalEdgeData)); + original_edge_data_vector.clear(); + } + + EdgeBasedEdge newEdge(edgeData1.edgeBasedNodeID, edgeData2.edgeBasedNodeID, edgeBasedEdges.size(), distance, true, false ); edgeBasedEdges.push_back(newEdge); } else { ++numberOfSkippedTurns; @@ -311,8 +306,7 @@ void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename) { } p.printIncrement(); } - numberOfOriginalEdges += originalEdgeData.size(); - originalEdgeDataOutFile.write((char*)&(originalEdgeData[0]), originalEdgeData.size()*sizeof(OriginalEdgeData)); + originalEdgeDataOutFile.write((char*)&(original_edge_data_vector[0]), original_edge_data_vector.size()*sizeof(OriginalEdgeData)); originalEdgeDataOutFile.seekp(std::ios::beg); originalEdgeDataOutFile.write((char*)&numberOfOriginalEdges, sizeof(unsigned)); originalEdgeDataOutFile.close(); @@ -326,12 +320,27 @@ void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename) { // std::vector(edgeBasedNodes).swap(edgeBasedNodes); // INFO("size: " << edgeBasedNodes.size() << ", cap: " << edgeBasedNodes.capacity()); INFO("Node-based graph contains " << nodeBasedEdgeCounter << " edges"); + INFO("Edge-based graph contains " << edgeBasedEdges.size() << " edges"); // INFO("Edge-based graph contains " << edgeBasedEdges.size() << " edges, blowup is " << 2*((double)edgeBasedEdges.size()/(double)nodeBasedEdgeCounter)); INFO("Edge-based graph skipped " << numberOfSkippedTurns << " turns, defined by " << numberOfTurnRestrictions << " restrictions."); INFO("Generated " << edgeBasedNodes.size() << " edge based nodes"); } -TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w) const { +TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, unsigned& penalty, lua_State *myLuaState) const { + const double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]); + + if( speedProfile.has_turn_penalty_function ) { + try { + //call lua profile to compute turn penalty + penalty = luabind::call_function( myLuaState, "turn_function", 180-angle ); + } catch (const luabind::error &er) { + std::cerr << er.what() << std::endl; + //TODO handle lua errors + } + } else { + penalty = 0; + } + if(u == w) { return TurnInstructions.UTurn; } @@ -342,33 +351,42 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID _NodeBasedDynamicGraph::EdgeData & data1 = _nodeBasedGraph->GetEdgeData(edge1); _NodeBasedDynamicGraph::EdgeData & data2 = _nodeBasedGraph->GetEdgeData(edge2); + if(!data1.contraFlow && data2.contraFlow) { + return TurnInstructions.EnterAgainstAllowedDirection; + } + if(data1.contraFlow && !data2.contraFlow) { + return TurnInstructions.LeaveAgainstAllowedDirection; + } + //roundabouts need to be handled explicitely if(data1.roundabout && data2.roundabout) { //Is a turn possible? If yes, we stay on the roundabout! if( 1 == (_nodeBasedGraph->EndEdges(v) - _nodeBasedGraph->BeginEdges(v)) ) { //No turn possible. return TurnInstructions.NoTurn; - } else { - return TurnInstructions.StayOnRoundAbout; } + return TurnInstructions.StayOnRoundAbout; } //Does turn start or end on roundabout? if(data1.roundabout || data2.roundabout) { //We are entering the roundabout - if( (!data1.roundabout) && data2.roundabout) + if( (!data1.roundabout) && data2.roundabout) { return TurnInstructions.EnterRoundAbout; + } //We are leaving the roundabout - else if(data1.roundabout && (!data2.roundabout) ) + if(data1.roundabout && (!data2.roundabout) ) { return TurnInstructions.LeaveRoundAbout; + } } //If street names stay the same and if we are certain that it is not a roundabout, we skip it. - if( (data1.nameID == data2.nameID) && (0 != data1.nameID)) + if( (data1.nameID == data2.nameID) && (0 != data1.nameID)) { return TurnInstructions.NoTurn; - if( (data1.nameID == data2.nameID) && (0 == data1.nameID) && (_nodeBasedGraph->GetOutDegree(v) <= 2) ) + } + if( (data1.nameID == data2.nameID) && (0 == data1.nameID) && (_nodeBasedGraph->GetOutDegree(v) <= 2) ) { return TurnInstructions.NoTurn; + } - double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]); return TurnInstructions.GetTurnDirectionOfInstruction(angle); } @@ -379,12 +397,12 @@ unsigned EdgeBasedGraphFactory::GetNumberOfNodes() const { /* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/ template double EdgeBasedGraphFactory::GetAngleBetweenTwoEdges(const CoordinateT& A, const CoordinateT& C, const CoordinateT& B) const { - const int v1x = A.lon - C.lon; - const int v1y = A.lat - C.lat; - const int v2x = B.lon - C.lon; - const int v2y = B.lat - C.lat; + const double v1x = (A.lon - C.lon)/100000.; + const double v1y = lat2y(A.lat/100000.) - lat2y(C.lat/100000.); + const double v2x = (B.lon - C.lon)/100000.; + const double v2y = lat2y(B.lat/100000.) - lat2y(C.lat/100000.); - double angle = (atan2((double)v2y,v2x) - atan2((double)v1y,v1x) )*180/M_PI; + double angle = (atan2(v2y,v2x) - atan2(v1y,v1x) )*180/M_PI; while(angle < 0) angle += 360; return angle; diff --git a/Contractor/EdgeBasedGraphFactory.h b/Contractor/EdgeBasedGraphFactory.h index 62a119e81..e751a7169 100644 --- a/Contractor/EdgeBasedGraphFactory.h +++ b/Contractor/EdgeBasedGraphFactory.h @@ -34,8 +34,10 @@ #include #include #include +#include #include - +#include +#include #include "../typedefs.h" #include "../DataStructures/DeallocatingVector.h" @@ -43,39 +45,21 @@ #include "../Extractor/ExtractorStructs.h" #include "../DataStructures/HashTable.h" #include "../DataStructures/ImportEdge.h" +#include "../DataStructures/MercatorUtil.h" #include "../DataStructures/QueryEdge.h" #include "../DataStructures/Percent.h" #include "../DataStructures/TurnInstructions.h" #include "../Util/BaseConfiguration.h" -class EdgeBasedGraphFactory { -private: - struct _NodeBasedEdgeData { - int distance; - unsigned edgeBasedNodeID; - unsigned nameID:31; - bool shortcut:1; - bool forward:1; - bool backward:1; - bool roundabout:1; - bool ignoreInGrid:1; - short type; - bool isAccessRestricted; - }; +extern "C" { +#include +#include +#include +} +#include - struct _EdgeBasedEdgeData { - int distance; - unsigned via; - unsigned nameID; - bool forward; - bool backward; - TurnInstruction turnInstruction; - }; - typedef DynamicGraph< _NodeBasedEdgeData > _NodeBasedDynamicGraph; - typedef _NodeBasedDynamicGraph::InputEdge _NodeBasedEdge; - std::vector inputNodeInfoList; - unsigned numberOfTurnRestrictions; +class EdgeBasedGraphFactory : boost::noncopyable { public: struct EdgeBasedNode { bool operator<(const EdgeBasedNode & other) const { @@ -95,16 +79,45 @@ public: bool ignoreInGrid:1; }; - struct SpeedProfileProperties{ - SpeedProfileProperties() : trafficSignalPenalty(0), uTurnPenalty(0) {} + SpeedProfileProperties() : trafficSignalPenalty(0), uTurnPenalty(0), has_turn_penalty_function(false) {} int trafficSignalPenalty; int uTurnPenalty; + bool has_turn_penalty_function; } speedProfile; + private: + struct _NodeBasedEdgeData { + int distance; + unsigned edgeBasedNodeID; + unsigned nameID; + short type; + bool isAccessRestricted:1; + bool shortcut:1; + bool forward:1; + bool backward:1; + bool roundabout:1; + bool ignoreInGrid:1; + bool contraFlow:1; + }; + + struct _EdgeBasedEdgeData { + int distance; + unsigned via; + unsigned nameID; + bool forward; + bool backward; + TurnInstruction turnInstruction; + }; + + typedef DynamicGraph< _NodeBasedEdgeData > _NodeBasedDynamicGraph; + typedef _NodeBasedDynamicGraph::InputEdge _NodeBasedEdge; + std::vector inputNodeInfoList; + unsigned numberOfTurnRestrictions; + boost::shared_ptr<_NodeBasedDynamicGraph> _nodeBasedGraph; - boost::unordered_map _barrierNodes; - boost::unordered_map _trafficLights; + boost::unordered_set _barrierNodes; + boost::unordered_set _trafficLights; typedef std::pair RestrictionSource; typedef std::pair RestrictionTarget; @@ -113,10 +126,8 @@ private: std::vector _restrictionBucketVector; RestrictionMap _restrictionMap; - DeallocatingVector edgeBasedEdges; DeallocatingVector edgeBasedNodes; - std::vector originalEdgeData; NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const; bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const; @@ -127,18 +138,16 @@ private: bool belongsToTinyComponent); template double GetAngleBetweenTwoEdges(const CoordinateT& A, const CoordinateT& C, const CoordinateT& B) const; -// SRTMLookup srtmLookup; - public: template< class InputEdgeT > explicit EdgeBasedGraphFactory(int nodes, std::vector & inputEdges, std::vector & _bollardNodes, std::vector & trafficLights, std::vector<_Restriction> & inputRestrictions, std::vector & nI, SpeedProfileProperties speedProfile); - void Run(const char * originalEdgeDataFilename); + void Run(const char * originalEdgeDataFilename, lua_State *myLuaState); void GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges ); void GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode> & nodes); void GetOriginalEdgeData( std::vector< OriginalEdgeData> & originalEdgeData); - TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w) const; + TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, unsigned& penalty, lua_State *myLuaState) const; unsigned GetNumberOfNodes() const; }; diff --git a/DataStructures/BinaryHeap.h b/DataStructures/BinaryHeap.h index 85c14d456..f8b34704f 100644 --- a/DataStructures/BinaryHeap.h +++ b/DataStructures/BinaryHeap.h @@ -75,10 +75,13 @@ template< typename NodeID, typename Key > class UnorderedMapStorage { public: - UnorderedMapStorage( size_t ) { } + UnorderedMapStorage( size_t ) { + //hash table gets 1000 Buckets + nodes.rehash(1000); + } - Key &operator[]( NodeID node ) { - return nodes[node]; + Key &operator[]( const NodeID node ) { + return nodes[node]; } void Clear() { diff --git a/DataStructures/DeallocatingVector.h b/DataStructures/DeallocatingVector.h index 89502f7d4..89d8e2ce7 100644 --- a/DataStructures/DeallocatingVector.h +++ b/DataStructures/DeallocatingVector.h @@ -22,7 +22,6 @@ or see http://www.gnu.org/licenses/agpl.txt. #define DEALLOCATINGVECTOR_H_ #include -#include #include #if __cplusplus > 199711L @@ -32,7 +31,7 @@ or see http://www.gnu.org/licenses/agpl.txt. #endif -template +template class DeallocatingVectorIterator : public std::iterator { protected: @@ -42,12 +41,12 @@ protected: DeallocatingVectorIteratorState(); public: explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r) : mData(r.mData), mIndex(r.mIndex), mBucketList(r.mBucketList) {} - //explicit DeallocatingVectorIteratorState(const ElementT * ptr, const size_t idx, const std::vector & input_list) : mData(ptr), mIndex(idx), mBucketList(input_list) {} - explicit DeallocatingVectorIteratorState(const size_t idx, std::vector & input_list) : mData(DEALLOCATION_VECTOR_NULL_PTR), mIndex(idx), mBucketList(input_list) { + //explicit DeallocatingVectorIteratorState(const ElementT * ptr, const std::size_t idx, const std::vector & input_list) : mData(ptr), mIndex(idx), mBucketList(input_list) {} + explicit DeallocatingVectorIteratorState(const std::size_t idx, std::vector & input_list) : mData(DEALLOCATION_VECTOR_NULL_PTR), mIndex(idx), mBucketList(input_list) { setPointerForIndex(); } ElementT * mData; - size_t mIndex; + std::size_t mIndex; std::vector & mBucketList; inline void setPointerForIndex() { @@ -55,8 +54,8 @@ protected: mData = DEALLOCATION_VECTOR_NULL_PTR; return; } - size_t _bucket = mIndex/bucketSizeC; - size_t _index = mIndex%bucketSizeC; + std::size_t _bucket = mIndex/bucketSizeC; + std::size_t _index = mIndex%bucketSizeC; mData = &(mBucketList[_bucket][_index]); if(DeallocateC) { @@ -104,8 +103,8 @@ public: template DeallocatingVectorIterator(const DeallocatingVectorIterator & r) : mState(r.mState) {} - DeallocatingVectorIterator(size_t idx, std::vector & input_list) : mState(idx, input_list) {} - //DeallocatingVectorIterator(size_t idx, const std::vector & input_list) : mState(idx, input_list) {} + DeallocatingVectorIterator(std::size_t idx, std::vector & input_list) : mState(idx, input_list) {} + //DeallocatingVectorIterator(std::size_t idx, const std::vector & input_list) : mState(idx, input_list) {} DeallocatingVectorIterator(const DeallocatingVectorIteratorState & r) : mState(r) {} template @@ -185,10 +184,10 @@ public: } }; -template +template class DeallocatingVector { private: - size_t mCurrentSize; + std::size_t mCurrentSize; std::vector mBucketList; public: @@ -227,21 +226,21 @@ public: } inline void push_back(const ElementT & element) { - size_t _capacity = capacity(); + std::size_t _capacity = capacity(); if(mCurrentSize == _capacity) { mBucketList.push_back(new ElementT[bucketSizeC]); } - size_t _index = size()%bucketSizeC; + std::size_t _index = size()%bucketSizeC; mBucketList.back()[_index] = element; ++mCurrentSize; } - inline void reserve(const size_t) const { + inline void reserve(const std::size_t) const { //don't do anything } - inline void resize(const size_t new_size) { + inline void resize(const std::size_t new_size) { if(new_size > mCurrentSize) { while(capacity() < new_size) { mBucketList.push_back(new ElementT[bucketSizeC]); @@ -249,7 +248,7 @@ public: mCurrentSize = new_size; } if(new_size < mCurrentSize) { - size_t number_of_necessary_buckets = 1+(new_size / bucketSizeC); + std::size_t number_of_necessary_buckets = 1+(new_size / bucketSizeC); for(unsigned i = number_of_necessary_buckets; i < mBucketList.size(); ++i) { delete[] mBucketList[i]; @@ -259,16 +258,16 @@ public: } } - inline size_t size() const { + inline std::size_t size() const { return mCurrentSize; } - inline size_t capacity() const { + inline std::size_t capacity() const { return mBucketList.size() * bucketSizeC; } inline iterator begin() { - return iterator(static_cast(0), mBucketList); + return iterator(static_cast(0), mBucketList); } inline iterator end() { @@ -276,7 +275,7 @@ public: } inline deallocation_iterator dbegin() { - return deallocation_iterator(static_cast(0), mBucketList); + return deallocation_iterator(static_cast(0), mBucketList); } inline deallocation_iterator dend() { @@ -284,24 +283,36 @@ public: } inline const_iterator begin() const { - return const_iterator(static_cast(0), mBucketList); + return const_iterator(static_cast(0), mBucketList); } inline const_iterator end() const { return const_iterator(size(), mBucketList); } - inline ElementT & operator[](const size_t index) { - size_t _bucket = index / bucketSizeC; - size_t _index = index % bucketSizeC; + inline ElementT & operator[](const std::size_t index) { + std::size_t _bucket = index / bucketSizeC; + std::size_t _index = index % bucketSizeC; return (mBucketList[_bucket][_index]); } - const inline ElementT & operator[](const size_t index) const { - size_t _bucket = index / bucketSizeC; - size_t _index = index % bucketSizeC; + const inline ElementT & operator[](const std::size_t index) const { + std::size_t _bucket = index / bucketSizeC; + std::size_t _index = index % bucketSizeC; return (mBucketList[_bucket][_index]); } + + inline ElementT & back() { + std::size_t _bucket = mCurrentSize / bucketSizeC; + std::size_t _index = mCurrentSize % bucketSizeC; + return (mBucketList[_bucket][_index]); + } + + const inline ElementT & back() const { + std::size_t _bucket = mCurrentSize / bucketSizeC; + std::size_t _index = mCurrentSize % bucketSizeC; + return (mBucketList[_bucket][_index]); + } }; #endif /* DEALLOCATINGVECTOR_H_ */ diff --git a/DataStructures/DynamicGraph.h b/DataStructures/DynamicGraph.h index c2a54059d..6730babdf 100644 --- a/DataStructures/DynamicGraph.h +++ b/DataStructures/DynamicGraph.h @@ -59,8 +59,8 @@ class DynamicGraph { { m_numNodes = nodes; m_numEdges = ( EdgeIterator ) graph.size(); - m_nodes.reserve( m_numNodes ); - m_nodes.resize( m_numNodes ); + m_nodes.reserve( m_numNodes +1); + m_nodes.resize( m_numNodes +1); EdgeIterator edge = 0; EdgeIterator position = 0; for ( NodeIterator node = 0; node < m_numNodes; ++node ) { @@ -72,6 +72,7 @@ class DynamicGraph { m_nodes[node].edges = edge - lastEdge; position += m_nodes[node].edges; } + m_nodes.back().firstEdge = position; m_edges.reserve( position * 1.1 ); m_edges.resize( position ); edge = 0; @@ -97,40 +98,33 @@ class DynamicGraph { return m_numEdges; } - unsigned GetOutDegree( const NodeIterator &n ) const - { + unsigned GetOutDegree( const NodeIterator n ) const { return m_nodes[n].edges; } - NodeIterator GetTarget( const EdgeIterator &e ) const - { + NodeIterator GetTarget( const EdgeIterator e ) const { return NodeIterator( m_edges[e].target ); } - EdgeDataT &GetEdgeData( const EdgeIterator &e ) - { + EdgeDataT &GetEdgeData( const EdgeIterator e ) { return m_edges[e].data; } - const EdgeDataT &GetEdgeData( const EdgeIterator &e ) const - { + const EdgeDataT &GetEdgeData( const EdgeIterator e ) const { return m_edges[e].data; } - EdgeIterator BeginEdges( const NodeIterator &n ) const - { + EdgeIterator BeginEdges( const NodeIterator n ) const { //assert( EndEdges( n ) - EdgeIterator( _nodes[n].firstEdge ) <= 100 ); return EdgeIterator( m_nodes[n].firstEdge ); } - EdgeIterator EndEdges( const NodeIterator &n ) const - { + EdgeIterator EndEdges( const NodeIterator n ) const { return EdgeIterator( m_nodes[n].firstEdge + m_nodes[n].edges ); } //adds an edge. Invalidates edge iterators for the source node - EdgeIterator InsertEdge( const NodeIterator &from, const NodeIterator &to, const EdgeDataT &data ) - { + EdgeIterator InsertEdge( const NodeIterator from, const NodeIterator to, const EdgeDataT &data ) { Node &node = m_nodes[from]; EdgeIterator newFirstEdge = node.edges + node.firstEdge; if ( newFirstEdge >= m_edges.size() || !isDummy( newFirstEdge ) ) { @@ -164,7 +158,7 @@ class DynamicGraph { } //removes an edge. Invalidates edge iterators for the source node - void DeleteEdge( const NodeIterator source, const EdgeIterator &e ) { + void DeleteEdge( const NodeIterator source, const EdgeIterator e ) { Node &node = m_nodes[source]; --m_numEdges; --node.edges; @@ -175,8 +169,7 @@ class DynamicGraph { } //removes all edges (source,target) - int DeleteEdgesTo( const NodeIterator source, const NodeIterator target ) - { + int DeleteEdgesTo( const NodeIterator source, const NodeIterator target ) { int deleted = 0; for ( EdgeIterator i = BeginEdges( source ), iend = EndEdges( source ); i < iend - deleted; ++i ) { if ( m_edges[i].target == target ) { @@ -196,8 +189,7 @@ class DynamicGraph { } //searches for a specific edge - EdgeIterator FindEdge( const NodeIterator &from, const NodeIterator &to ) const - { + EdgeIterator FindEdge( const NodeIterator from, const NodeIterator to ) const { for ( EdgeIterator i = BeginEdges( from ), iend = EndEdges( from ); i != iend; ++i ) { if ( m_edges[i].target == to ) { return i; @@ -208,13 +200,11 @@ class DynamicGraph { protected: - bool isDummy( EdgeIterator edge ) const - { + bool isDummy( EdgeIterator edge ) const { return m_edges[edge].target == (std::numeric_limits< NodeIterator >::max)(); } - void makeDummy( EdgeIterator edge ) - { + void makeDummy( EdgeIterator edge ) { m_edges[edge].target = (std::numeric_limits< NodeIterator >::max)(); } @@ -233,9 +223,8 @@ class DynamicGraph { NodeIterator m_numNodes; EdgeIterator m_numEdges; - DeallocatingVector< Node > m_nodes; - DeallocatingVector< Edge > m_edges; - + std::vector< Node > m_nodes; + DeallocatingVector< Edge > m_edges; }; #endif // DYNAMICGRAPH_H_INCLUDED diff --git a/DataStructures/ImportEdge.h b/DataStructures/ImportEdge.h index a90cd474d..714560ccc 100644 --- a/DataStructures/ImportEdge.h +++ b/DataStructures/ImportEdge.h @@ -16,7 +16,7 @@ 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 EDGE_H #define EDGE_H @@ -40,12 +40,8 @@ public: return (source() < e.source()); } - /** Default constructor. target and weight are set to 0.*/ - NodeBasedEdge() : - _source(0), _target(0), _name(0), _weight(0), forward(0), backward(0), _type(0), _roundabout(false), _ignoreInGrid(false), _accessRestricted(false) { assert(false); } //shall not be used. - - explicit NodeBasedEdge(NodeID s, NodeID t, NodeID n, EdgeWeight w, bool f, bool b, short ty, bool ra, bool ig, bool ar) : - _source(s), _target(t), _name(n), _weight(w), forward(f), backward(b), _type(ty), _roundabout(ra), _ignoreInGrid(ig), _accessRestricted(ar) { if(ty < 0) {ERR("Type: " << ty);}; } + explicit NodeBasedEdge(NodeID s, NodeID t, NodeID n, EdgeWeight w, bool f, bool b, short ty, bool ra, bool ig, bool ar, bool cf) : + _source(s), _target(t), _name(n), _weight(w), forward(f), backward(b), _type(ty), _roundabout(ra), _ignoreInGrid(ig), _accessRestricted(ar), _contraFlow(cf) { if(ty < 0) {ERR("Type: " << ty);}; } NodeID target() const {return _target; } NodeID source() const {return _source; } @@ -59,6 +55,7 @@ public: bool isRoundabout() const { return _roundabout; } bool ignoreInGrid() const { return _ignoreInGrid; } bool isAccessRestricted() const { return _accessRestricted; } + bool isContraFlow() const { return _contraFlow; } NodeID _source; NodeID _target; @@ -70,6 +67,13 @@ public: bool _roundabout; bool _ignoreInGrid; bool _accessRestricted; + bool _contraFlow; + +private: + /** Default constructor. target and weight are set to 0.*/ + NodeBasedEdge() : + _source(0), _target(0), _name(0), _weight(0), forward(0), backward(0), _type(0), _roundabout(false), _ignoreInGrid(false), _accessRestricted(false), _contraFlow(false) { assert(false); } //shall not be used. + }; class EdgeBasedEdge { @@ -91,43 +95,46 @@ public: template EdgeBasedEdge(const EdgeT & myEdge ) : - _source(myEdge.source), - _target(myEdge.target), - _edgeID(myEdge.data.via), -// _nameID1(myEdge.data.nameID), - _weight(myEdge.data.distance), - _forward(myEdge.data.forward), - _backward(myEdge.data.backward)//, -// _turnInstruction(myEdge.data.turnInstruction) - { } + m_source(myEdge.source), + m_target(myEdge.target), + m_edgeID(myEdge.data.via), + m_weight(myEdge.data.distance), + m_forward(myEdge.data.forward), + m_backward(myEdge.data.backward) + { } /** Default constructor. target and weight are set to 0.*/ EdgeBasedEdge() : - _source(0), _target(0), _edgeID(0), _weight(0), _forward(false), _backward(false) { } + m_source(0), + m_target(0), + m_edgeID(0), + m_weight(0), + m_forward(false), + m_backward(false) + { } - explicit EdgeBasedEdge(NodeID s, NodeID t, NodeID v, EdgeWeight w, bool f, bool b) : - _source(s), _target(t), _edgeID(v), _weight(w), _forward(f), _backward(b){} + explicit EdgeBasedEdge(const NodeID s, const NodeID t, const NodeID v, const EdgeWeight w, const bool f, const bool b) : + m_source(s), + m_target(t), + m_edgeID(v), + m_weight(w), + m_forward(f), + m_backward(b) + {} - NodeID target() const {return _target; } - NodeID source() const {return _source; } - EdgeWeight weight() const {return _weight; } - NodeID id() const { return _edgeID; } - bool isBackward() const { return _backward; } - bool isForward() const { return _forward; } - - NodeID _source; - NodeID _target; - NodeID _edgeID; - EdgeWeight _weight:30; - bool _forward:1; - bool _backward:1; -}; - -struct MinimalEdgeData { -public: - EdgeWeight distance; - bool forward; - bool backward; + NodeID target() const {return m_target; } + NodeID source() const {return m_source; } + EdgeWeight weight() const {return m_weight; } + NodeID id() const { return m_edgeID; } + bool isBackward() const { return m_backward; } + bool isForward() const { return m_forward; } +private: + NodeID m_source; + NodeID m_target; + NodeID m_edgeID; + EdgeWeight m_weight:30; + bool m_forward:1; + bool m_backward:1; }; typedef NodeBasedEdge ImportEdge; diff --git a/DataStructures/InputReaderFactory.h b/DataStructures/InputReaderFactory.h index 552eb7370..f58232f79 100644 --- a/DataStructures/InputReaderFactory.h +++ b/DataStructures/InputReaderFactory.h @@ -43,21 +43,21 @@ int readFromBz2Stream( void* pointer, char* buffer, int len ) { return read; } else if(BZ_STREAM_END == context->error) { BZ2_bzReadGetUnused(&context->error, context->bz2, &unusedTmpVoid, &context->nUnused); - if(BZ_OK != context->error) { cerr << "Could not BZ2_bzReadGetUnused" << endl; exit(-1);}; + if(BZ_OK != context->error) {std::cerr << "Could not BZ2_bzReadGetUnused" <nUnused;i++) { context->unused[i] = unusedTmp[i]; } BZ2_bzReadClose(&context->error, context->bz2); - if(BZ_OK != context->error) { cerr << "Could not BZ2_bzReadClose" << endl; exit(-1);}; + if(BZ_OK != context->error) {std::cerr << "Could not BZ2_bzReadClose" <error = BZ_STREAM_END; // set to the stream end for next call to this function if(0 == context->nUnused && feof(context->file)) { return read; } else { context->bz2 = BZ2_bzReadOpen(&context->error, context->file, 0, 0, context->unused, context->nUnused); - if(NULL == context->bz2){ cerr << "Could not open file" << endl; exit(-1);}; + if(NULL == context->bz2){std::cerr << "Could not open file" <error = false; diff --git a/Extractor/LuaUtil.h b/DataStructures/MercatorUtil.h similarity index 71% rename from Extractor/LuaUtil.h rename to DataStructures/MercatorUtil.h index 7134f96e0..15bea275a 100644 --- a/Extractor/LuaUtil.h +++ b/DataStructures/MercatorUtil.h @@ -16,20 +16,23 @@ 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 MERCATORUTIL_H_ +#define MERCATORUTIL_H_ +#include -#ifndef LUAUTIL_H_ -#define LUAUTIL_H_ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif -#include - -template -void LUA_print(T number) { - std::cout << "[LUA] " << number << std::endl; +inline double y2lat(double a) { + return 180/M_PI * (2 * atan(exp(a*M_PI/180)) - M_PI/2); } +inline double lat2y(double a) { + return 180/M_PI * log(tan(M_PI/4+a*(M_PI/180)/2)); +} - -#endif /* LUAUTIL_H_ */ +#endif /* MERCATORUTIL_H_ */ diff --git a/DataStructures/NNGrid.h b/DataStructures/NNGrid.h index f84a0a45f..22cb4e2d4 100644 --- a/DataStructures/NNGrid.h +++ b/DataStructures/NNGrid.h @@ -21,10 +21,12 @@ or see http://www.gnu.org/licenses/agpl.txt. #ifndef NNGRID_H_ #define NNGRID_H_ -#include #include #include #include +#include + +#include #include #include #include @@ -42,12 +44,12 @@ or see http://www.gnu.org/licenses/agpl.txt. #include #include "DeallocatingVector.h" -//#include "ExtractorStructs.h" #include "GridEdge.h" #include "Percent.h" #include "PhantomNodes.h" -#include "Util.h" +#include "MercatorUtil.h" #include "StaticGraph.h" +#include "TimingUtil.h" #include "../Algorithms/Bresenham.h" namespace NNGrid{ @@ -58,7 +60,7 @@ template class NNGrid { public: NNGrid() /*: cellCache(500), fileCache(500)*/ { - ramIndexTable.resize((1024*1024), ULONG_MAX); + ramIndexTable.resize((1024*1024), std::numeric_limits::max()); } NNGrid(const char* rif, const char* _i) { @@ -66,7 +68,7 @@ public: ERR("Not available in Write mode"); } iif = std::string(_i); - ramIndexTable.resize((1024*1024), ULONG_MAX); + ramIndexTable.resize((1024*1024), std::numeric_limits::max()); ramInFile.open(rif, std::ios::in | std::ios::binary); if(!ramInFile) { ERR(rif << " not found"); } @@ -87,13 +89,13 @@ public: void OpenIndexFiles() { assert(ramInFile.is_open()); - ramInFile.read(static_cast(static_cast(&ramIndexTable[0]) ), sizeof(unsigned long)*1024*1024); + ramInFile.read(static_cast(static_cast(&ramIndexTable[0]) ), sizeof(uint64_t)*1024*1024); ramInFile.close(); } #ifndef ROUTED template - inline void ConstructGrid(DeallocatingVector & edgeList, char * ramIndexOut, char * fileIndexOut) { + inline void ConstructGrid(DeallocatingVector & edgeList, const char * ramIndexOut, const char * fileIndexOut) { //TODO: Implement this using STXXL-Streams Percent p(edgeList.size()); BOOST_FOREACH(EdgeT & edge, edgeList) { @@ -106,6 +108,9 @@ public: int tlon = edge.lon2; AddEdge( _GridEdge( edge.id, edge.nameID, edge.weight, _Coordinate(slat, slon), _Coordinate(tlat, tlon), edge.belongsToTinyComponent ) ); } + if( 0 == entries.size() ) { + ERR("No viable edges for nearest neighbor index. Aborting"); + } double timestamp = get_timestamp(); //create index file on disk, old one is over written indexOutFile.open(fileIndexOut, std::ios::out | std::ios::binary | std::ios::trunc); @@ -114,8 +119,8 @@ public: INFO("finished sorting after " << (get_timestamp() - timestamp) << "s"); std::vector entriesInFileWithRAMSameIndex; unsigned indexInRamTable = entries.begin()->ramIndex; - unsigned long lastPositionInIndexFile = 0; - cout << "writing data ..." << flush; + uint64_t lastPositionInIndexFile = 0; + std::cout << "writing data ..." << std::flush; p.reinit(entries.size()); boost::unordered_map< unsigned, unsigned > cellMap(1024); BOOST_FOREACH(GridEntry & gridEntry, entries) { @@ -143,9 +148,9 @@ public: indexOutFile.close(); //Serialize RAM Index - ofstream ramFile(ramIndexOut, std::ios::out | std::ios::binary | std::ios::trunc); + std::ofstream ramFile(ramIndexOut, std::ios::out | std::ios::binary | std::ios::trunc); //write 4 MB of index Table in RAM - ramFile.write((char *)&ramIndexTable[0], sizeof(unsigned long)*1024*1024 ); + ramFile.write((char *)&ramIndexTable[0], sizeof(uint64_t)*1024*1024 ); //close ram index file ramFile.close(); } @@ -174,10 +179,10 @@ public: // INFO("looked up " << candidates.size()); _GridEdge smallestEdge; _Coordinate tmp, edgeStartCoord, edgeEndCoord; - double dist = numeric_limits::max(); + double dist = std::numeric_limits::max(); double r, tmpDist; - BOOST_FOREACH(_GridEdge candidate, candidates) { + BOOST_FOREACH(const _GridEdge & candidate, candidates) { if(candidate.belongsToTinyComponent && ignoreTinyComponents) continue; r = 0.; @@ -216,7 +221,7 @@ public: // } // INFO("startCoord: " << smallestEdge.startCoord << "; targetCoord: " << smallestEdge.targetCoord << "; newEndpoint: " << resultNode.location); - double ratio = (foundNode ? std::min(1., ApproximateDistance(smallestEdge.startCoord, resultNode.location)/ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord)) : 0); + const double ratio = (foundNode ? std::min(1., ApproximateDistance(smallestEdge.startCoord, resultNode.location)/ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord)) : 0); resultNode.location.lat = round(100000.*(y2lat(static_cast(resultNode.location.lat)/100000.))); // INFO("Length of vector: " << ApproximateDistance(smallestEdge.startCoord, resultNode.location)/ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord)); //Hack to fix rounding errors and wandering via nodes. @@ -227,12 +232,13 @@ public: resultNode.weight1 *= ratio; if(INT_MAX != resultNode.weight2) { - resultNode.weight2 -= resultNode.weight1; + resultNode.weight2 *= (1.-ratio); } resultNode.ratio = ratio; -// INFO("New weight1: " << resultNode.weight1 << ", new weight2: " << resultNode.weight2 << ", ratio: " << ratio); // INFO("start: " << edgeStartCoord << ", end: " << edgeEndCoord); -// INFO("selected node: " << resultNode.edgeBasedNode << ", bidirected: " << (resultNode.isBidirected() ? "yes" : "no") << "\n--"); +// INFO("selected node: " << resultNode.edgeBasedNode << ", bidirected: " << (resultNode.isBidirected() ? "yes" : "no")); +// INFO("New weight1: " << resultNode.weight1 << ", new weight2: " << resultNode.weight2 << ", ratio: " << ratio); + // INFO("distance to input coordinate: " << ApproximateDistance(location, resultNode.location) << "\n--"); // double time2 = get_timestamp(); // INFO("NN-Lookup in " << 1000*(time2-time1) << "ms"); return foundNode; @@ -264,7 +270,7 @@ public: } _Coordinate tmp; double dist = (std::numeric_limits::max)(); - BOOST_FOREACH(_GridEdge candidate, candidates) { + BOOST_FOREACH(const _GridEdge & candidate, candidates) { double r = 0.; double tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r); if(tmpDist < dist) { @@ -310,17 +316,18 @@ private: cellMap.insert(insertionVector.begin(), insertionVector.end()); } - inline bool DoubleEpsilonCompare(const double d1, const double d2) { + inline bool DoubleEpsilonCompare(const double d1, const double d2) const { return (std::fabs(d1 - d2) < FLT_EPSILON); } - inline unsigned FillCell(std::vector& entriesWithSameRAMIndex, const unsigned long fileOffset, boost::unordered_map< unsigned, unsigned > & cellMap ) { +#ifndef ROUTED + inline unsigned FillCell(std::vector& entriesWithSameRAMIndex, const uint64_t fileOffset, boost::unordered_map< unsigned, unsigned > & cellMap ) { std::vector tmpBuffer(32*32*4096,0); - unsigned long indexIntoTmpBuffer = 0; + uint64_t indexIntoTmpBuffer = 0; unsigned numberOfWrittenBytes = 0; assert(indexOutFile.is_open()); - std::vector cellIndex(32*32,ULONG_MAX); + std::vector cellIndex(32*32,std::numeric_limits::max()); for(unsigned i = 0; i < entriesWithSameRAMIndex.size() -1; ++i) { assert(entriesWithSameRAMIndex[i].ramIndex== entriesWithSameRAMIndex[i+1].ramIndex); @@ -356,8 +363,8 @@ private: indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer); assert(entriesWithSameFileIndex.size() == 0); - indexOutFile.write(static_cast(static_cast(&cellIndex[0])),32*32*sizeof(unsigned long)); - numberOfWrittenBytes += 32*32*sizeof(unsigned long); + indexOutFile.write(static_cast(static_cast(&cellIndex[0])),32*32*sizeof(uint64_t)); + numberOfWrittenBytes += 32*32*sizeof(uint64_t); //write contents of tmpbuffer to disk indexOutFile.write(&tmpBuffer[0], indexIntoTmpBuffer*sizeof(char)); @@ -366,7 +373,7 @@ private: return numberOfWrittenBytes; } - inline unsigned FlushEntriesWithSameFileIndexToBuffer( std::vector &vectorWithSameFileIndex, std::vector & tmpBuffer, const unsigned long index) const { + inline unsigned FlushEntriesWithSameFileIndexToBuffer( std::vector &vectorWithSameFileIndex, std::vector & tmpBuffer, const uint64_t index) const { sort( vectorWithSameFileIndex.begin(), vectorWithSameFileIndex.end() ); vectorWithSameFileIndex.erase(unique(vectorWithSameFileIndex.begin(), vectorWithSameFileIndex.end()), vectorWithSameFileIndex.end()); const unsigned lengthOfBucket = vectorWithSameFileIndex.size(); @@ -391,11 +398,12 @@ private: vectorWithSameFileIndex.clear(); return counter; } +#endif inline void GetContentsOfFileBucketEnumerated(const unsigned fileIndex, std::vector<_GridEdge>& result) const { unsigned ramIndex = GetRAMIndexFromFileIndex(fileIndex); - unsigned long startIndexInFile = ramIndexTable[ramIndex]; - if(startIndexInFile == ULONG_MAX) { + uint64_t startIndexInFile = ramIndexTable[ramIndex]; + if(startIndexInFile == std::numeric_limits::max()) { return; } unsigned enumeratedIndex = GetCellIndexFromRAMAndFileIndex(ramIndex, fileIndex); @@ -409,14 +417,14 @@ private: } //only read the single necessary cell index - localStream->seekg(startIndexInFile+(enumeratedIndex*sizeof(unsigned long))); - unsigned long fetchedIndex = 0; - localStream->read(static_cast( static_cast(&fetchedIndex)), sizeof(unsigned long)); + localStream->seekg(startIndexInFile+(enumeratedIndex*sizeof(uint64_t))); + uint64_t fetchedIndex = 0; + localStream->read(static_cast( static_cast(&fetchedIndex)), sizeof(uint64_t)); - if(fetchedIndex == ULONG_MAX) { + if(fetchedIndex == std::numeric_limits::max()) { return; } - const unsigned long position = fetchedIndex + 32*32*sizeof(unsigned long) ; + const uint64_t position = fetchedIndex + 32*32*sizeof(uint64_t) ; unsigned lengthOfBucket; unsigned currentSizeOfResult = result.size(); @@ -428,12 +436,12 @@ private: inline void GetContentsOfFileBucket(const unsigned fileIndex, std::vector<_GridEdge>& result, boost::unordered_map< unsigned, unsigned> & cellMap) { unsigned ramIndex = GetRAMIndexFromFileIndex(fileIndex); - unsigned long startIndexInFile = ramIndexTable[ramIndex]; - if(startIndexInFile == ULONG_MAX) { + uint64_t startIndexInFile = ramIndexTable[ramIndex]; + if(startIndexInFile == std::numeric_limits::max()) { return; } - unsigned long cellIndex[32*32]; + uint64_t cellIndex[32*32]; cellMap.clear(); BuildCellIndexToFileIndexMap(ramIndex, cellMap); @@ -446,12 +454,12 @@ private: } localStream->seekg(startIndexInFile); - localStream->read(static_cast(static_cast( cellIndex)), 32*32*sizeof(unsigned long)); + localStream->read(static_cast(static_cast( cellIndex)), 32*32*sizeof(uint64_t)); assert(cellMap.find(fileIndex) != cellMap.end()); - if(cellIndex[cellMap[fileIndex]] == ULONG_MAX) { + if(cellIndex[cellMap[fileIndex]] == std::numeric_limits::max()) { return; } - const unsigned long position = cellIndex[cellMap[fileIndex]] + 32*32*sizeof(unsigned long) ; + const uint64_t position = cellIndex[cellMap[fileIndex]] + 32*32*sizeof(uint64_t) ; unsigned lengthOfBucket; unsigned currentSizeOfResult = result.size(); @@ -543,7 +551,7 @@ private: } } - inline unsigned GetFileIndexForLatLon(const int lt, const int ln) { + inline unsigned GetFileIndexForLatLon(const int lt, const int ln) const { double lat = lt/100000.; double lon = ln/100000.; @@ -574,14 +582,14 @@ private: return ramIndex; } - const static unsigned long END_OF_BUCKET_DELIMITER = UINT_MAX; + const static uint64_t END_OF_BUCKET_DELIMITER = boost::integer_traits::const_max; - std::ofstream indexOutFile; std::ifstream ramInFile; #ifndef ROUTED + std::ofstream indexOutFile; stxxl::vector entries; #endif - std::vector ramIndexTable; //8 MB for first level index in RAM + std::vector ramIndexTable; //8 MB for first level index in RAM std::string iif; // LRUCache > cellCache; // LRUCache > fileCache; diff --git a/DataStructures/NodeInformationHelpDesk.h b/DataStructures/NodeInformationHelpDesk.h index abf05b71a..029d30def 100644 --- a/DataStructures/NodeInformationHelpDesk.h +++ b/DataStructures/NodeInformationHelpDesk.h @@ -25,13 +25,15 @@ or see http://www.gnu.org/licenses/agpl.txt. #include #include +#include + #include "../typedefs.h" #include "../DataStructures/QueryEdge.h" #include "NNGrid.h" #include "PhantomNodes.h" #include "NodeCoords.h" -class NodeInformationHelpDesk{ +class NodeInformationHelpDesk : boost::noncopyable{ public: NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned _numberOfNodes, const unsigned crc) : numberOfNodes(_numberOfNodes), checkSum(crc) { readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput); @@ -59,34 +61,43 @@ public: DEBUG("Loading edge data"); unsigned numberOfOrigEdges(0); edgesInStream.read((char*)&numberOfOrigEdges, sizeof(unsigned)); - origEdgeData.resize(numberOfOrigEdges); - edgesInStream.read((char*)&(origEdgeData[0]), numberOfOrigEdges*sizeof(OriginalEdgeData)); + origEdgeData_viaNode.resize(numberOfOrigEdges); + origEdgeData_nameID.resize(numberOfOrigEdges); + origEdgeData_turnInstruction.resize(numberOfOrigEdges); + + OriginalEdgeData deserialized_originalEdgeData; + for(unsigned i = 0; i < numberOfOrigEdges; ++i) { + edgesInStream.read((char*)&(deserialized_originalEdgeData), sizeof(OriginalEdgeData)); + origEdgeData_viaNode[i] = deserialized_originalEdgeData.viaNode; + origEdgeData_nameID[i] = deserialized_originalEdgeData.nameID; + origEdgeData_turnInstruction[i] = deserialized_originalEdgeData.turnInstruction; + } edgesInStream.close(); DEBUG("Loaded " << numberOfOrigEdges << " orig edges"); DEBUG("Opening NN indices"); readOnlyGrid->OpenIndexFiles(); } - void initNNGrid() { - readOnlyGrid->OpenIndexFiles(); - } +// void initNNGrid() { +// readOnlyGrid->OpenIndexFiles(); +// } inline int getLatitudeOfNode(const unsigned id) const { - const NodeID node = origEdgeData.at(id).viaNode; + const NodeID node = origEdgeData_viaNode.at(id); return coordinateVector.at(node).lat; } inline int getLongitudeOfNode(const unsigned id) const { - const NodeID node = origEdgeData.at(id).viaNode; + const NodeID node = origEdgeData_viaNode.at(id); return coordinateVector.at(node).lon; } inline unsigned getNameIndexFromEdgeID(const unsigned id) const { - return origEdgeData.at(id).nameID; + return origEdgeData_nameID.at(id); } inline TurnInstruction getTurnInstructionFromEdgeID(const unsigned id) const { - return origEdgeData.at(id).turnInstruction; + return origEdgeData_turnInstruction.at(id); } inline NodeID getNumberOfNodes() const { return numberOfNodes; } @@ -96,7 +107,7 @@ public: return readOnlyGrid->FindNearestCoordinateOnEdgeInNodeBasedGraph(coord, result); } - inline bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode, const unsigned zoomLevel) const { + inline bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode, const unsigned zoomLevel) { return readOnlyGrid->FindPhantomNodeForCoordinate(location, resultNode, zoomLevel); } @@ -114,7 +125,9 @@ public: private: std::vector<_Coordinate> coordinateVector; - std::vector origEdgeData; + std::vector origEdgeData_viaNode; + std::vector origEdgeData_nameID; + std::vector origEdgeData_turnInstruction; ReadOnlyGrid * readOnlyGrid; const unsigned numberOfNodes; diff --git a/DataStructures/QueryEdge.h b/DataStructures/QueryEdge.h index 72cbf0f07..3a2aecb82 100644 --- a/DataStructures/QueryEdge.h +++ b/DataStructures/QueryEdge.h @@ -41,8 +41,8 @@ struct QueryEdge { NodeID target; struct EdgeData { NodeID id:31; - int distance:30; bool shortcut:1; + int distance:30; bool forward:1; bool backward:1; } data; diff --git a/DataStructures/SearchEngine.h b/DataStructures/SearchEngine.h index d0cf25191..505d3f905 100644 --- a/DataStructures/SearchEngine.h +++ b/DataStructures/SearchEngine.h @@ -42,32 +42,33 @@ struct _HeapData { _HeapData( NodeID p ) : parent(p) { } }; -typedef boost::thread_specific_ptr > > SearchEngineHeapPtr; +typedef BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage > QueryHeapType; +typedef boost::thread_specific_ptr SearchEngineHeapPtr; template struct SearchEngineData { - typedef SearchEngineHeapPtr HeapPtr; typedef GraphT Graph; - SearchEngineData(GraphT * g, NodeInformationHelpDesk * nh, std::vector & n) :graph(g), nodeHelpDesk(nh), names(n) {} + typedef QueryHeapType QueryHeap; + SearchEngineData(GraphT * g, NodeInformationHelpDesk * nh, std::vector & n) :graph(g), nodeHelpDesk(nh), names(n) {} const GraphT * graph; NodeInformationHelpDesk * nodeHelpDesk; - std::vector & names; - static HeapPtr forwardHeap; - static HeapPtr backwardHeap; - static HeapPtr forwardHeap2; - static HeapPtr backwardHeap2; - static HeapPtr forwardHeap3; - static HeapPtr backwardHeap3; + std::vector & names; + static SearchEngineHeapPtr forwardHeap; + static SearchEngineHeapPtr backwardHeap; + static SearchEngineHeapPtr forwardHeap2; + static SearchEngineHeapPtr backwardHeap2; + static SearchEngineHeapPtr forwardHeap3; + static SearchEngineHeapPtr backwardHeap3; inline void InitializeOrClearFirstThreadLocalStorage() { if(!forwardHeap.get()) { - forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage >(nodeHelpDesk->getNumberOfNodes())); + forwardHeap.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes())); } else forwardHeap->Clear(); if(!backwardHeap.get()) { - backwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage >(nodeHelpDesk->getNumberOfNodes())); + backwardHeap.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes())); } else backwardHeap->Clear(); @@ -75,13 +76,13 @@ struct SearchEngineData { inline void InitializeOrClearSecondThreadLocalStorage() { if(!forwardHeap2.get()) { - forwardHeap2.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage >(nodeHelpDesk->getNumberOfNodes())); + forwardHeap2.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes())); } else forwardHeap2->Clear(); if(!backwardHeap2.get()) { - backwardHeap2.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage >(nodeHelpDesk->getNumberOfNodes())); + backwardHeap2.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes())); } else backwardHeap2->Clear(); @@ -89,13 +90,13 @@ struct SearchEngineData { inline void InitializeOrClearThirdThreadLocalStorage() { if(!forwardHeap3.get()) { - forwardHeap3.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage >(nodeHelpDesk->getNumberOfNodes())); + forwardHeap3.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes())); } else forwardHeap3->Clear(); if(!backwardHeap3.get()) { - backwardHeap3.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage >(nodeHelpDesk->getNumberOfNodes())); + backwardHeap3.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes())); } else backwardHeap3->Clear(); @@ -113,7 +114,7 @@ public: ShortestPathRouting shortestPath; AlternativeRouting alternativePaths; - SearchEngine(GraphT * g, NodeInformationHelpDesk * nh, std::vector & n) : + SearchEngine(GraphT * g, NodeInformationHelpDesk * nh, std::vector & n) : _queryData(g, nh, n), shortestPath(_queryData), alternativePaths(_queryData) diff --git a/DataStructures/Util.h b/DataStructures/TimingUtil.h similarity index 68% rename from DataStructures/Util.h rename to DataStructures/TimingUtil.h index 8448e4ce6..6e980e26f 100644 --- a/DataStructures/Util.h +++ b/DataStructures/TimingUtil.h @@ -18,16 +18,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or see http://www.gnu.org/licenses/agpl.txt. */ -#ifndef TIMEUTIL_H_ -#define TIMEUTIL_H_ +#ifndef TIMINGUTIL_H_ +#define TIMINGUTIL_H_ #include -#include #include -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif #ifdef _WIN32 #include @@ -43,13 +39,6 @@ or see http://www.gnu.org/licenses/agpl.txt. #include #endif -#ifdef _WIN32 - #include -#else - #include -#endif -#include - /** Returns a timestamp (now) in seconds (incl. a fractional part). */ static inline double get_timestamp() { struct timeval tp; @@ -57,14 +46,5 @@ static inline double get_timestamp() { return double(tp.tv_sec) + tp.tv_usec / 1000000.; } -static inline double y2lat(double a) { return 180/M_PI * (2 * atan(exp(a*M_PI/180)) - M_PI/2); } -static inline double lat2y(double a) { return 180/M_PI * log(tan(M_PI/4+a*(M_PI/180)/2)); } -static inline unsigned boost_thread_id_hash(boost::thread::id const& id) { - std::stringstream ostr; - ostr << id; - std::tr1::hash h; - return h(ostr.str()); -} - -#endif /* TIMEUTIL_H_ */ +#endif /* TIMINGUTIL_H_ */ diff --git a/DataStructures/TurnInstructions.h b/DataStructures/TurnInstructions.h index 2e709831d..3284d9bbe 100644 --- a/DataStructures/TurnInstructions.h +++ b/DataStructures/TurnInstructions.h @@ -21,12 +21,12 @@ #ifndef TURNINSTRUCTIONS_H_ #define TURNINSTRUCTIONS_H_ -#include +#include typedef unsigned char TurnInstruction; //This is a hack until c++0x is available enough to use scoped enums -struct TurnInstructionsClass { +struct TurnInstructionsClass : boost::noncopyable { const static TurnInstruction NoTurn = 0; //Give no instruction at all const static TurnInstruction GoStraight = 1; //Tell user to go straight! @@ -44,48 +44,14 @@ struct TurnInstructionsClass { const static TurnInstruction StayOnRoundAbout = 13; const static TurnInstruction StartAtEndOfStreet = 14; const static TurnInstruction ReachedYourDestination = 15; + const static TurnInstruction EnterAgainstAllowedDirection = 16; + const static TurnInstruction LeaveAgainstAllowedDirection = 17; const static TurnInstruction AccessRestrictionFlag = 128; const static TurnInstruction InverseAccessRestrictionFlag = 0x7f; // ~128 does not work without a warning. const static int AccessRestrictionPenalty = 1 << 15; //unrelated to the bit set in the restriction flag -// std::string TurnStrings[16]; -// std::string Ordinals[12]; - - //This is a hack until c++0x is available enough to use initializer lists. -// TurnInstructionsClass(){ -// TurnStrings [0] = ""; -// TurnStrings [1] = "Continue"; -// TurnStrings [2] = "Turn slight right"; -// TurnStrings [3] = "Turn right"; -// TurnStrings [4] = "Turn sharp right"; -// TurnStrings [5] = "U-Turn"; -// TurnStrings [6] = "Turn sharp left"; -// TurnStrings [7] = "Turn left"; -// TurnStrings [8] = "Turn slight left"; -// TurnStrings [9] = "Reach via point"; -// TurnStrings[10] = "Head"; -// TurnStrings[11] = "Enter roundabout"; -// TurnStrings[12] = "Leave roundabout"; -// TurnStrings[13] = "Stay on roundabout"; -// TurnStrings[14] = "Start"; -// TurnStrings[15] = "You have reached your destination"; -// -// Ordinals[0] = "zeroth"; -// Ordinals[1] = "first"; -// Ordinals[2] = "second"; -// Ordinals[3] = "third"; -// Ordinals[4] = "fourth"; -// Ordinals[5] = "fifth"; -// Ordinals[6] = "sixth"; -// Ordinals[7] = "seventh"; -// Ordinals[8] = "eighth"; -// Ordinals[9] = "nineth"; -// Ordinals[10] = "tenth"; -// Ordinals[11] = "one of the too many"; -// }; - static inline TurnInstruction GetTurnDirectionOfInstruction( const double angle ) { if(angle >= 23 && angle < 67) { return TurnSharpRight; diff --git a/DataStructures/XORFastHash.h b/DataStructures/XORFastHash.h index e90de23df..c3c14702b 100644 --- a/DataStructures/XORFastHash.h +++ b/DataStructures/XORFastHash.h @@ -49,7 +49,7 @@ public: table1.resize(2 << 16); table2.resize(2 << 16); for(unsigned i = 0; i < (2 << 16); ++i) { - table1[i] = i; table2[i]; + table1[i] = i; table2[i] = i; } std::random_shuffle(table1.begin(), table1.end()); std::random_shuffle(table2.begin(), table2.end()); @@ -75,8 +75,8 @@ public: table3.resize(1 << 8); table4.resize(1 << 8); for(unsigned i = 0; i < (1 << 8); ++i) { - table1[i] = i; table2[i]; - table3[i] = i; table4[i]; + table1[i] = i; table2[i] = i; + table3[i] = i; table4[i] = i; } std::random_shuffle(table1.begin(), table1.end()); std::random_shuffle(table2.begin(), table2.end()); diff --git a/Descriptors/DescriptionFactory.h b/Descriptors/DescriptionFactory.h index e38fb10fb..52adc2713 100644 --- a/Descriptors/DescriptionFactory.h +++ b/Descriptors/DescriptionFactory.h @@ -53,13 +53,9 @@ public: _RouteSummary() : lengthString("0"), durationString("0"), startName(0), destName(0) {} void BuildDurationAndLengthStrings(const double distance, const unsigned time) { //compute distance/duration for route summary - std::ostringstream s; - s << round(distance); - lengthString = s.str(); + intToString(round(distance), lengthString); int travelTime = time/10 + 1; - s.str(""); - s << travelTime; - durationString = s.str(); + intToString(travelTime, durationString); } } summary; diff --git a/Descriptors/GPXDescriptor.h b/Descriptors/GPXDescriptor.h index 2b9021ba5..5096468fb 100644 --- a/Descriptors/GPXDescriptor.h +++ b/Descriptors/GPXDescriptor.h @@ -39,6 +39,7 @@ public: "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd" "\">"; + reply.content += "Data (c) OpenStreetMap contributors (ODbL)"; reply.content += ""; if(rawRoute.lengthOfShortestPath != INT_MAX && rawRoute.computedShortestPath.size()) { convertInternalLatLonToString(phantomNodes.startPhantom.location.lat, tmp); @@ -46,7 +47,7 @@ public: convertInternalLatLonToString(phantomNodes.startPhantom.location.lon, tmp); reply.content += "lon=\"" + tmp + "\">"; - BOOST_FOREACH(_PathData pathData, rawRoute.computedShortestPath) { + BOOST_FOREACH(const _PathData & pathData, rawRoute.computedShortestPath) { sEngine.GetCoordinatesForNodeID(pathData.node, current); convertInternalLatLonToString(current.lat, tmp); diff --git a/Descriptors/JSONDescriptor.h b/Descriptors/JSONDescriptor.h index 140cde9fe..72a011b55 100644 --- a/Descriptors/JSONDescriptor.h +++ b/Descriptors/JSONDescriptor.h @@ -246,7 +246,7 @@ public: reply.content += "}"; } - void GetRouteNames(std::vector & shortestSegments, std::vector & alternativeSegments, SearchEngineT &sEngine, RouteNames & routeNames) { + void GetRouteNames(std::vector & shortestSegments, std::vector & alternativeSegments, const SearchEngineT &sEngine, RouteNames & routeNames) { /*** extract names for both alternatives ***/ Segment shortestSegment1, shortestSegment2; @@ -262,23 +262,25 @@ public: std::vector shortestDifference(shortestSegments.size()); std::vector alternativeDifference(alternativeSegments.size()); std::set_difference(shortestSegments.begin(), shortestSegments.end(), alternativeSegments.begin(), alternativeSegments.end(), shortestDifference.begin(), boost::bind(&Segment::nameID, _1) < boost::bind(&Segment::nameID, _2) ); - if(0 < shortestDifference.size() ) { - unsigned i = 0; - while( i < shortestDifference.size() && shortestDifference[i].nameID == shortestSegments[0].nameID) { + int size_of_difference = shortestDifference.size(); + if(0 < size_of_difference ) { + int i = 0; + while( i < size_of_difference && shortestDifference[i].nameID == shortestSegments[0].nameID) { ++i; } - if(i < shortestDifference.size()) { + if(i < size_of_difference ) { shortestSegment2 = shortestDifference[i]; } } std::set_difference(alternativeSegments.begin(), alternativeSegments.end(), shortestSegments.begin(), shortestSegments.end(), alternativeDifference.begin(), boost::bind(&Segment::nameID, _1) < boost::bind(&Segment::nameID, _2) ); - if(0 < alternativeDifference.size() ) { - unsigned i = 0; - while( i < alternativeDifference.size() && alternativeDifference[i].nameID == alternativeSegments[0].nameID) { + size_of_difference = alternativeDifference.size(); + if(0 < size_of_difference ) { + int i = 0; + while( i < size_of_difference && alternativeDifference[i].nameID == alternativeSegments[0].nameID) { ++i; } - if(i < alternativeDifference.size()) { + if(i < size_of_difference ) { alternativeSegment2 = alternativeDifference[i]; } } @@ -292,7 +294,7 @@ public: routeNames.shortestPathName2 = sEngine.GetEscapedNameForNameID(shortestSegment2.nameID); routeNames.alternativePathName1 = sEngine.GetEscapedNameForNameID(alternativeSegment1.nameID); - routeNames.alternativePathName2 += sEngine.GetEscapedNameForNameID(alternativeSegment2.nameID); + routeNames.alternativePathName2 = sEngine.GetEscapedNameForNameID(alternativeSegment2.nameID); } } diff --git a/Extractor/BaseParser.cpp b/Extractor/BaseParser.cpp new file mode 100644 index 000000000..6981e9570 --- /dev/null +++ b/Extractor/BaseParser.cpp @@ -0,0 +1,116 @@ +/* +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. +*/ + +#include "BaseParser.h" + +BaseParser::BaseParser(ExtractorCallbacks* ec, ScriptingEnvironment& se) : +extractor_callbacks(ec), scriptingEnvironment(se), luaState(NULL), use_turn_restrictions(true) { + luaState = se.getLuaStateForThreadID(0); + ReadUseRestrictionsSetting(); + ReadRestrictionExceptions(); +} + +void BaseParser::ReadUseRestrictionsSetting() { + if( 0 != luaL_dostring( luaState, "return use_turn_restrictions\n") ) { + ERR(lua_tostring( luaState,-1)<< " occured in scripting block"); + } + if( lua_isboolean( luaState, -1) ) { + use_turn_restrictions = lua_toboolean(luaState, -1); + } + if( use_turn_restrictions ) { + INFO("Using turn restrictions" ); + } else { + INFO("Ignoring turn restrictions" ); + } +} + +void BaseParser::ReadRestrictionExceptions() { + if(lua_function_exists(luaState, "get_exceptions" )) { + //get list of turn restriction exceptions + try { + luabind::call_function( + luaState, + "get_exceptions", + boost::ref(restriction_exceptions) + ); + INFO("Found " << restriction_exceptions.size() << " exceptions to turn restriction"); + BOOST_FOREACH(std::string & str, restriction_exceptions) { + INFO(" " << str); + } + } catch (const luabind::error &er) { + lua_State* Ler=er.state(); + report_errors(Ler, -1); + ERR(er.what()); + } + } else { + INFO("Found no exceptions to turn restrictions"); + } +} + +void BaseParser::report_errors(lua_State *L, const int status) const { + if( 0!=status ) { + std::cerr << "-- " << lua_tostring(L, -1) << std::endl; + lua_pop(L, 1); // remove error message + } +} + +void BaseParser::ParseNodeInLua(ImportNode& n, lua_State* localLuaState) { + try { + luabind::call_function( localLuaState, "node_function", boost::ref(n) ); + } catch (const luabind::error &er) { + lua_State* Ler=er.state(); + report_errors(Ler, -1); + ERR(er.what()); + } +} + +void BaseParser::ParseWayInLua(ExtractionWay& w, lua_State* localLuaState) { + if(2 > w.path.size()) { + return; + } + try { + luabind::call_function( localLuaState, "way_function", boost::ref(w) ); + } catch (const luabind::error &er) { + lua_State* Ler=er.state(); + report_errors(Ler, -1); + ERR(er.what()); + } +} + +bool BaseParser::ShouldIgnoreRestriction(const std::string& except_tag_string) const { + //should this restriction be ignored? yes if there's an overlap between: + //a) the list of modes in the except tag of the restriction (except_tag_string), ex: except=bus;bicycle + //b) the lua profile defines a hierachy of modes, ex: [access, vehicle, bicycle] + + if( "" == except_tag_string ) { + return false; + } + + //Be warned, this is quadratic work here, but we assume that + //only a few exceptions are actually defined. + std::vector exceptions; + boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*")); + BOOST_FOREACH(std::string& str, exceptions) { + if( restriction_exceptions.end() != std::find(restriction_exceptions.begin(), restriction_exceptions.end(), str) ) { + return true; + } + } + return false; +} diff --git a/Extractor/BaseParser.h b/Extractor/BaseParser.h index f46b19fea..6a19efa07 100644 --- a/Extractor/BaseParser.h +++ b/Extractor/BaseParser.h @@ -27,23 +27,32 @@ extern "C" { #include } +#include + +#include "ExtractorCallbacks.h" #include "ScriptingEnvironment.h" -template -class BaseParser { +class BaseParser : boost::noncopyable { public: + BaseParser(ExtractorCallbacks* ec, ScriptingEnvironment& se); virtual ~BaseParser() {} - virtual bool Init() = 0; - virtual void RegisterCallbacks(ExternalMemoryT * externalMemory) = 0; - virtual void RegisterScriptingEnvironment(ScriptingEnvironment & _se) = 0; + virtual bool ReadHeader() = 0; virtual bool Parse() = 0; - void report_errors(lua_State *L, int status) { - if ( status!=0 ) { - std::cerr << "-- " << lua_tostring(L, -1) << std::endl; - lua_pop(L, 1); // remove error message - } - } + virtual void ParseNodeInLua(ImportNode& n, lua_State* luaStateForThread); + virtual void ParseWayInLua(ExtractionWay& n, lua_State* luaStateForThread); + virtual void report_errors(lua_State *L, const int status) const; + +protected: + virtual void ReadUseRestrictionsSetting(); + virtual void ReadRestrictionExceptions(); + virtual bool ShouldIgnoreRestriction(const std::string& except_tag_string) const; + + ExtractorCallbacks* extractor_callbacks; + ScriptingEnvironment& scriptingEnvironment; + lua_State* luaState; + std::vector restriction_exceptions; + bool use_turn_restrictions; }; diff --git a/Extractor/ExtractionContainers.cpp b/Extractor/ExtractionContainers.cpp index b4a2fe060..b2476bc86 100644 --- a/Extractor/ExtractionContainers.cpp +++ b/Extractor/ExtractionContainers.cpp @@ -27,31 +27,31 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const double time = get_timestamp(); boost::uint64_t memory_to_use = static_cast(amountOfRAM) * 1024 * 1024 * 1024; - cout << "[extractor] Sorting used nodes ... " << flush; + std::cout << "[extractor] Sorting used nodes ... " << std::flush; stxxl::sort(usedNodeIDs.begin(), usedNodeIDs.end(), Cmp(), memory_to_use); - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; time = get_timestamp(); - cout << "[extractor] Erasing duplicate nodes ... " << flush; - stxxl::vector::iterator NewEnd = unique ( usedNodeIDs.begin(),usedNodeIDs.end() ) ; + std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush; + stxxl::vector::iterator NewEnd = std::unique ( usedNodeIDs.begin(),usedNodeIDs.end() ) ; usedNodeIDs.resize ( NewEnd - usedNodeIDs.begin() ); - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; time = get_timestamp(); - cout << "[extractor] Sorting all nodes ... " << flush; + std::cout << "[extractor] Sorting all nodes ... " << std::flush; stxxl::sort(allNodes.begin(), allNodes.end(), CmpNodeByID(), memory_to_use); - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; time = get_timestamp(); - cout << "[extractor] Sorting used ways ... " << flush; + std::cout << "[extractor] Sorting used ways ... " << std::flush; stxxl::sort(wayStartEndVector.begin(), wayStartEndVector.end(), CmpWayByID(), memory_to_use); - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; - cout << "[extractor] Sorting restrctns. by from... " << flush; + std::cout << "[extractor] Sorting restrctns. by from... " << std::flush; stxxl::sort(restrictionsVector.begin(), restrictionsVector.end(), CmpRestrictionContainerByFrom(), memory_to_use); - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; - cout << "[extractor] Fixing restriction starts ... " << flush; + std::cout << "[extractor] Fixing restriction starts ... " << std::flush; STXXLRestrictionsVector::iterator restrictionsIT = restrictionsVector.begin(); STXXLWayIDStartEndVector::iterator wayStartAndEndEdgeIT = wayStartEndVector.begin(); @@ -79,16 +79,16 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const ++restrictionsIT; } - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; time = get_timestamp(); - cout << "[extractor] Sorting restrctns. by to ... " << flush; + std::cout << "[extractor] Sorting restrctns. by to ... " << std::flush; stxxl::sort(restrictionsVector.begin(), restrictionsVector.end(), CmpRestrictionContainerByTo(), memory_to_use); - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; time = get_timestamp(); unsigned usableRestrictionsCounter(0); - cout << "[extractor] Fixing restriction ends ... " << flush; + std::cout << "[extractor] Fixing restriction ends ... " << std::flush; restrictionsIT = restrictionsVector.begin(); wayStartAndEndEdgeIT = wayStartEndVector.begin(); while(wayStartAndEndEdgeIT != wayStartEndVector.end() && restrictionsIT != restrictionsVector.end()) { @@ -116,11 +116,11 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const } ++restrictionsIT; } - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; INFO("usable restrictions: " << usableRestrictionsCounter ); //serialize restrictions - ofstream restrictionsOutstream; - restrictionsOutstream.open(restrictionsFileName.c_str(), ios::binary); + std::ofstream restrictionsOutstream; + restrictionsOutstream.open(restrictionsFileName.c_str(), std::ios::binary); restrictionsOutstream.write((char*)&usableRestrictionsCounter, sizeof(unsigned)); for(restrictionsIT = restrictionsVector.begin(); restrictionsIT != restrictionsVector.end(); ++restrictionsIT) { if(UINT_MAX != restrictionsIT->restriction.fromNode && UINT_MAX != restrictionsIT->restriction.toNode) { @@ -129,11 +129,11 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const } restrictionsOutstream.close(); - ofstream fout; - fout.open(outputFileName.c_str(), ios::binary); + std::ofstream fout; + fout.open(outputFileName.c_str(), std::ios::binary); fout.write((char*)&usedNodeCounter, sizeof(unsigned)); time = get_timestamp(); - cout << "[extractor] Confirming/Writing used nodes ... " << flush; + std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush; STXXLNodeVector::iterator nodesIT = allNodes.begin(); STXXLNodeIDVector::iterator usedNodeIDsIT = usedNodeIDs.begin(); @@ -154,24 +154,24 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const } } - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; - cout << "[extractor] setting number of nodes ... " << flush; - ios::pos_type positionInFile = fout.tellp(); - fout.seekp(ios::beg); + std::cout << "[extractor] setting number of nodes ... " << std::flush; + std::ios::pos_type positionInFile = fout.tellp(); + fout.seekp(std::ios::beg); fout.write((char*)&usedNodeCounter, sizeof(unsigned)); fout.seekp(positionInFile); - cout << "ok" << endl; + std::cout << "ok" << std::endl; time = get_timestamp(); // Sort edges by start. - cout << "[extractor] Sorting edges by start ... " << flush; + std::cout << "[extractor] Sorting edges by start ... " << std::flush; stxxl::sort(allEdges.begin(), allEdges.end(), CmpEdgeByStartID(), memory_to_use); - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; time = get_timestamp(); - cout << "[extractor] Setting start coords ... " << flush; + std::cout << "[extractor] Setting start coords ... " << std::flush; fout.write((char*)&usedEdgeCounter, sizeof(unsigned)); // Traverse list of edges and nodes in parallel and set start coord nodesIT = allNodes.begin(); @@ -191,16 +191,16 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const ++edgeIT; } } - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; time = get_timestamp(); // Sort Edges by target - cout << "[extractor] Sorting edges by target ... " << flush; + std::cout << "[extractor] Sorting edges by target ... " << std::flush; stxxl::sort(allEdges.begin(), allEdges.end(), CmpEdgeByTargetID(), memory_to_use); - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; time = get_timestamp(); - cout << "[extractor] Setting target coords ... " << flush; + std::cout << "[extractor] Setting target coords ... " << std::flush; // Traverse list of edges and nodes in parallel and set target coord nodesIT = allNodes.begin(); edgeIT = allEdges.begin(); @@ -231,22 +231,22 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const fout.write((char*)&edgeIT->target, sizeof(unsigned)); fout.write((char*)&intDist, sizeof(int)); switch(edgeIT->direction) { - case _Way::notSure: + case ExtractionWay::notSure: fout.write((char*)&zero, sizeof(short)); break; - case _Way::oneway: + case ExtractionWay::oneway: fout.write((char*)&one, sizeof(short)); break; - case _Way::bidirectional: + case ExtractionWay::bidirectional: fout.write((char*)&zero, sizeof(short)); break; - case _Way::opposite: + case ExtractionWay::opposite: fout.write((char*)&one, sizeof(short)); break; default: - cerr << "[error] edge with no direction: " << edgeIT->direction << endl; - assert(false); + std::cerr << "[error] edge with no direction: " << edgeIT->direction << std::endl; + assert(false); break; } fout.write((char*)&intWeight, sizeof(int)); @@ -256,33 +256,34 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const fout.write((char*)&edgeIT->isRoundabout, sizeof(bool)); fout.write((char*)&edgeIT->ignoreInGrid, sizeof(bool)); fout.write((char*)&edgeIT->isAccessRestricted, sizeof(bool)); + fout.write((char*)&edgeIT->isContraFlow, sizeof(bool)); } ++usedEdgeCounter; ++edgeIT; } } - cout << "ok, after " << get_timestamp() - time << "s" << endl; - cout << "[extractor] setting number of edges ... " << flush; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; + std::cout << "[extractor] setting number of edges ... " << std::flush; fout.seekp(positionInFile); fout.write((char*)&usedEdgeCounter, sizeof(unsigned)); fout.close(); - cout << "ok" << endl; + std::cout << "ok" << std::endl; time = get_timestamp(); - cout << "[extractor] writing street name index ... " << flush; + std::cout << "[extractor] writing street name index ... " << std::flush; std::string nameOutFileName = (outputFileName + ".names"); - ofstream nameOutFile(nameOutFileName.c_str(), ios::binary); + std::ofstream nameOutFile(nameOutFileName.c_str(), std::ios::binary); unsigned sizeOfNameIndex = nameVector.size(); nameOutFile.write((char *)&(sizeOfNameIndex), sizeof(unsigned)); - BOOST_FOREACH(string str, nameVector) { + BOOST_FOREACH(const std::string & str, nameVector) { unsigned lengthOfRawString = strlen(str.c_str()); nameOutFile.write((char *)&(lengthOfRawString), sizeof(unsigned)); nameOutFile.write(str.c_str(), lengthOfRawString); } nameOutFile.close(); - cout << "ok, after " << get_timestamp() - time << "s" << endl; + std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl; // time = get_timestamp(); // cout << "[extractor] writing address list ... " << flush; @@ -298,8 +299,8 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const INFO("Processed " << usedNodeCounter << " nodes and " << usedEdgeCounter << " edges"); - } catch ( const exception& e ) { - cerr << "Caught Execption:" << e.what() << endl; + } catch ( const std::exception& e ) { + std::cerr << "Caught Execption:" << e.what() << std::endl; } } diff --git a/Extractor/ExtractionContainers.h b/Extractor/ExtractionContainers.h index b683e7153..abf718d5f 100644 --- a/Extractor/ExtractionContainers.h +++ b/Extractor/ExtractionContainers.h @@ -25,13 +25,13 @@ #include #include "ExtractorStructs.h" -#include "../DataStructures/Util.h" +#include "../DataStructures/TimingUtil.h" class ExtractionContainers { public: typedef stxxl::vector STXXLNodeIDVector; typedef stxxl::vector<_Node> STXXLNodeVector; - typedef stxxl::vector<_Edge> STXXLEdgeVector; + typedef stxxl::vector STXXLEdgeVector; typedef stxxl::vector STXXLStringVector; typedef stxxl::vector<_RawRestrictionContainer> STXXLRestrictionsVector; typedef stxxl::vector<_WayIDStartAndEndEdge> STXXLWayIDStartEndVector; diff --git a/Extractor/ExtractionHelperFunctions.h b/Extractor/ExtractionHelperFunctions.h index 08a1e14ef..6771939a9 100644 --- a/Extractor/ExtractionHelperFunctions.h +++ b/Extractor/ExtractionHelperFunctions.h @@ -28,12 +28,15 @@ or see http://www.gnu.org/licenses/agpl.txt. #include #include + #include "../Util/StringUtil.h" +namespace qi = boost::spirit::qi; + //TODO: Move into LUA inline bool durationIsValid(const std::string &s) { - boost::regex e ("((\\d|\\d\\d):)*(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl); + boost::regex e ("((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl); std::vector< std::string > result; boost::algorithm::split_regex( result, s, boost::regex( ":" ) ) ; @@ -42,17 +45,28 @@ inline bool durationIsValid(const std::string &s) { } inline unsigned parseDuration(const std::string &s) { - int hours = 0; - int minutes = 0; - boost::regex e ("((\\d|\\d\\d):)*(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl); + unsigned hours = 0; + unsigned minutes = 0; + unsigned seconds = 0; + boost::regex e ("((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl); std::vector< std::string > result; boost::algorithm::split_regex( result, s, boost::regex( ":" ) ) ; bool matched = regex_match(s, e); if(matched) { - hours = (result.size()== 2) ? stringToInt(result[0]) : 0; - minutes = (result.size()== 2) ? stringToInt(result[1]) : stringToInt(result[0]); - return 600*(hours*60+minutes); + if(1 == result.size()) { + minutes = stringToInt(result[0]); + } + if(2 == result.size()) { + minutes = stringToInt(result[1]); + hours = stringToInt(result[0]); + } + if(3 == result.size()) { + seconds = stringToInt(result[2]); + minutes = stringToInt(result[1]); + hours = stringToInt(result[0]); + } + return 10*(3600*hours+60*minutes+seconds); } return UINT_MAX; } @@ -66,5 +80,4 @@ inline int parseMaxspeed(std::string input) { //call-by-value on purpose. return n; } - #endif /* EXTRACTIONHELPERFUNCTIONS_H_ */ diff --git a/Extractor/ExtractorCallbacks.cpp b/Extractor/ExtractorCallbacks.cpp index 5423d8970..c8b5fc1aa 100644 --- a/Extractor/ExtractorCallbacks.cpp +++ b/Extractor/ExtractorCallbacks.cpp @@ -48,58 +48,95 @@ ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers * ext, StringMap * s stringMap = strMap; } -ExtractorCallbacks::~ExtractorCallbacks() { -} +ExtractorCallbacks::~ExtractorCallbacks() { } /** warning: caller needs to take care of synchronization! */ -bool ExtractorCallbacks::nodeFunction(_Node &n) { - if(n.lat <= 85*100000 && n.lat >= -85*100000) +void ExtractorCallbacks::nodeFunction(const _Node &n) { + if(n.lat <= 85*100000 && n.lat >= -85*100000) { externalMemory->allNodes.push_back(n); - return true; + } } -bool ExtractorCallbacks::restrictionFunction(_RawRestrictionContainer &r) { +bool ExtractorCallbacks::restrictionFunction(const _RawRestrictionContainer &r) { externalMemory->restrictionsVector.push_back(r); return true; } /** warning: caller needs to take care of synchronization! */ -bool ExtractorCallbacks::wayFunction(_Way &w) { - /*** Store name of way and split it into edge segments ***/ +void ExtractorCallbacks::wayFunction(ExtractionWay &parsed_way) { + if((0 < parsed_way.speed) || (0 < parsed_way.duration)) { //Only true if the way is specified by the speed profile + if(UINT_MAX == parsed_way.id){ + DEBUG("found bogus way with id: " << parsed_way.id << " of size " << parsed_way.path.size()); + return; + } - if ( w.speed > 0 ) { //Only true if the way is specified by the speed profile + if(0 < parsed_way.duration) { + //TODO: iterate all way segments and set duration corresponding to the length of each segment + parsed_way.speed = parsed_way.duration/(parsed_way.path.size()-1); + } + + if(FLT_EPSILON >= fabs(-1. - parsed_way.speed)){ + DEBUG("found way with bogus speed, id: " << parsed_way.id); + return; + } //Get the unique identifier for the street name - const StringMap::const_iterator strit = stringMap->find(w.name); - if(strit == stringMap->end()) { - w.nameID = externalMemory->nameVector.size(); - externalMemory->nameVector.push_back(w.name); - stringMap->insert(StringMap::value_type(w.name, w.nameID)); + const StringMap::const_iterator string_map_iterator = stringMap->find(parsed_way.name); + if(stringMap->end() == string_map_iterator) { + parsed_way.nameID = externalMemory->nameVector.size(); + externalMemory->nameVector.push_back(parsed_way.name); + stringMap->insert(std::make_pair(parsed_way.name, parsed_way.nameID)); } else { - w.nameID = strit->second; + parsed_way.nameID = string_map_iterator->second; } - if(fabs(-1. - w.speed) < FLT_EPSILON){ - WARN("found way with bogus speed, id: " << w.id); - return true; - } - if(w.id == UINT_MAX) { - WARN("found way with unknown type: " << w.id); - return true; + if(ExtractionWay::opposite == parsed_way.direction) { + std::reverse( parsed_way.path.begin(), parsed_way.path.end() ); + parsed_way.direction = ExtractionWay::oneway; } - if ( w.direction == _Way::opposite ){ - std::reverse( w.path.begin(), w.path.end() ); - } + const bool split_bidirectional_edge = (parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed); - for(vector< NodeID >::size_type n = 0; n < w.path.size()-1; ++n) { - externalMemory->allEdges.push_back(_Edge(w.path[n], w.path[n+1], w.type, w.direction, w.speed, w.nameID, w.roundabout, w.ignoreInGrid, w.isDurationSet, w.isAccessRestricted)); - externalMemory->usedNodeIDs.push_back(w.path[n]); + for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) { + externalMemory->allEdges.push_back( + InternalExtractorEdge(parsed_way.path[n], + parsed_way.path[n+1], + parsed_way.type, + (split_bidirectional_edge ? ExtractionWay::oneway : parsed_way.direction), + parsed_way.speed, + parsed_way.nameID, + parsed_way.roundabout, + parsed_way.ignoreInGrid, + (0 < parsed_way.duration), + parsed_way.isAccessRestricted + ) + ); + externalMemory->usedNodeIDs.push_back(parsed_way.path[n]); } - externalMemory->usedNodeIDs.push_back(w.path.back()); + externalMemory->usedNodeIDs.push_back(parsed_way.path.back()); //The following information is needed to identify start and end segments of restrictions - externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(w.id, w.path[0], w.path[1], w.path[w.path.size()-2], w.path[w.path.size()-1])); + externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back())); + + if(split_bidirectional_edge) { //Only true if the way should be split + std::reverse( parsed_way.path.begin(), parsed_way.path.end() ); + for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) { + externalMemory->allEdges.push_back( + InternalExtractorEdge(parsed_way.path[n], + parsed_way.path[n+1], + parsed_way.type, + ExtractionWay::oneway, + parsed_way.backward_speed, + parsed_way.nameID, + parsed_way.roundabout, + parsed_way.ignoreInGrid, + (0 < parsed_way.duration), + parsed_way.isAccessRestricted, + (ExtractionWay::oneway == parsed_way.direction) + ) + ); + } + externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back())); + } } - return true; } diff --git a/Extractor/ExtractorCallbacks.h b/Extractor/ExtractorCallbacks.h index 70f812ec2..4293d1330 100644 --- a/Extractor/ExtractorCallbacks.h +++ b/Extractor/ExtractorCallbacks.h @@ -45,12 +45,12 @@ public: ~ExtractorCallbacks(); /** warning: caller needs to take care of synchronization! */ - bool nodeFunction(_Node &n); + void nodeFunction(const _Node &n); - bool restrictionFunction(_RawRestrictionContainer &r); + bool restrictionFunction(const _RawRestrictionContainer &r); /** warning: caller needs to take care of synchronization! */ - bool wayFunction(_Way &w); + void wayFunction(ExtractionWay &w); }; diff --git a/Extractor/ExtractorStructs.h b/Extractor/ExtractorStructs.h index ebd40fc66..fe21da957 100644 --- a/Extractor/ExtractorStructs.h +++ b/Extractor/ExtractorStructs.h @@ -34,14 +34,14 @@ or see http://www.gnu.org/licenses/agpl.txt. #include "../DataStructures/ImportNode.h" #include "../DataStructures/NodeCoords.h" #include "../DataStructures/Restriction.h" -#include "../DataStructures/Util.h" +#include "../DataStructures/TimingUtil.h" #include "../typedefs.h" typedef boost::unordered_map StringMap; typedef boost::unordered_map > StringToIntPairMap; -struct _Way { - _Way() { +struct ExtractionWay { + ExtractionWay() { Clear(); } @@ -50,46 +50,52 @@ struct _Way { nameID = UINT_MAX; path.clear(); keyVals.EraseAll(); - direction = _Way::notSure; + direction = ExtractionWay::notSure; speed = -1; + backward_speed = -1; + duration = -1; type = -1; access = true; roundabout = false; - isDurationSet = false; isAccessRestricted = false; ignoreInGrid = false; } - enum { + enum Directions { notSure = 0, oneway, bidirectional, opposite - } direction; + }; + Directions direction; unsigned id; unsigned nameID; std::string name; double speed; + double backward_speed; + double duration; short type; bool access; bool roundabout; - bool isDurationSet; bool isAccessRestricted; bool ignoreInGrid; std::vector< NodeID > path; HashTable keyVals; }; -struct _Relation { - _Relation() : type(unknown){} +struct ExtractorRelation { + ExtractorRelation() : type(unknown){} enum { unknown = 0, ferry, turnRestriction } type; HashTable keyVals; }; -struct _Edge { - _Edge() : start(0), target(0), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false) {}; - _Edge(NodeID s, NodeID t) : start(s), target(t), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false) { } - _Edge(NodeID s, NodeID t, short tp, short d, double sp): start(s), target(t), type(tp), direction(d), speed(sp), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false) { } - _Edge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar) { +struct InternalExtractorEdge { + InternalExtractorEdge() : start(0), target(0), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) {}; + InternalExtractorEdge(NodeID s, NodeID t) : start(s), target(t), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) { } + InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp): start(s), target(t), type(tp), direction(d), speed(sp), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) { } + InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar), isContraFlow(false) { + assert(0 <= type); + } + InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar, bool icf): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar), isContraFlow(icf) { assert(0 <= type); } NodeID start; @@ -102,19 +108,21 @@ struct _Edge { bool ignoreInGrid; bool isDurationSet; bool isAccessRestricted; + bool isContraFlow; _Coordinate startCoord; _Coordinate targetCoord; - static _Edge min_value() { - return _Edge(0,0); + static InternalExtractorEdge min_value() { + return InternalExtractorEdge(0,0); } - static _Edge max_value() { - return _Edge((numeric_limits::max)(), (numeric_limits::max)()); + static InternalExtractorEdge max_value() { + return InternalExtractorEdge((std::numeric_limits::max)(), (std::numeric_limits::max)()); } - }; + + struct _WayIDStartAndEndEdge { unsigned wayID; NodeID firstStart; @@ -125,10 +133,10 @@ struct _WayIDStartAndEndEdge { _WayIDStartAndEndEdge(unsigned w, NodeID fs, NodeID ft, NodeID ls, NodeID lt) : wayID(w), firstStart(fs), firstTarget(ft), lastStart(ls), lastTarget(lt) {} static _WayIDStartAndEndEdge min_value() { - return _WayIDStartAndEndEdge((numeric_limits::min)(), (numeric_limits::min)(), (numeric_limits::min)(), (numeric_limits::min)(), (numeric_limits::min)()); + return _WayIDStartAndEndEdge((std::numeric_limits::min)(), (std::numeric_limits::min)(), (std::numeric_limits::min)(), (std::numeric_limits::min)(), (std::numeric_limits::min)()); } static _WayIDStartAndEndEdge max_value() { - return _WayIDStartAndEndEdge((numeric_limits::max)(), (numeric_limits::max)(), (numeric_limits::max)(), (numeric_limits::max)(), (numeric_limits::max)()); + return _WayIDStartAndEndEdge((std::numeric_limits::max)(), (std::numeric_limits::max)(), (std::numeric_limits::max)(), (std::numeric_limits::max)(), (std::numeric_limits::max)()); } }; @@ -171,38 +179,33 @@ struct CmpNodeByID : public std::binary_function<_Node, _Node, bool> { } }; -struct CmpEdgeByStartID : public std::binary_function<_Edge, _Edge, bool> -{ - typedef _Edge value_type; - bool operator () (const _Edge & a, const _Edge & b) const { +struct CmpEdgeByStartID : public std::binary_function { + typedef InternalExtractorEdge value_type; + bool operator () (const InternalExtractorEdge & a, const InternalExtractorEdge & b) const { return a.start < b.start; } value_type max_value() { - return _Edge::max_value(); + return InternalExtractorEdge::max_value(); } value_type min_value() { - return _Edge::min_value(); + return InternalExtractorEdge::min_value(); } }; -struct CmpEdgeByTargetID : public std::binary_function<_Edge, _Edge, bool> -{ - typedef _Edge value_type; - bool operator () (const _Edge & a, const _Edge & b) const - { +struct CmpEdgeByTargetID : public std::binary_function { + typedef InternalExtractorEdge value_type; + bool operator () (const InternalExtractorEdge & a, const InternalExtractorEdge & b) const { return a.target < b.target; } - value_type max_value() - { - return _Edge::max_value(); + value_type max_value() { + return InternalExtractorEdge::max_value(); } - value_type min_value() - { - return _Edge::min_value(); + value_type min_value() { + return InternalExtractorEdge::min_value(); } }; -inline string GetRandomString() { +inline std::string GetRandomString() { char s[128]; static const char alphanum[] = "0123456789" @@ -213,7 +216,7 @@ inline string GetRandomString() { s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; } s[127] = 0; - return string(s); + return std::string(s); } #endif /* EXTRACTORSTRUCTS_H_ */ diff --git a/Extractor/PBFParser.cpp b/Extractor/PBFParser.cpp new file mode 100644 index 000000000..2f343ca9f --- /dev/null +++ b/Extractor/PBFParser.cpp @@ -0,0 +1,490 @@ +/* + 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. + */ + +#include "PBFParser.h" + +PBFParser::PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se) : BaseParser( ec, se ) { + GOOGLE_PROTOBUF_VERIFY_VERSION; + //TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk? + //NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free. + threadDataQueue = boost::make_shared >( 2500 ); /* Max 2500 items in queue, hardcoded. */ + input.open(fileName, std::ios::in | std::ios::binary); + + if (!input) { + std::cerr << fileName << ": File not found." << std::endl; + } + +#ifndef NDEBUG + blockCount = 0; + groupCount = 0; +#endif +} + +PBFParser::~PBFParser() { + if(input.is_open()) { + input.close(); + } + + // Clean up any leftover ThreadData objects in the queue + _ThreadData* td; + while (threadDataQueue->try_pop(td)) { + delete td; + } + google::protobuf::ShutdownProtobufLibrary(); + +#ifndef NDEBUG + DEBUG("parsed " << blockCount << " blocks from pbf with " << groupCount << " groups"); +#endif +} + +inline bool PBFParser::ReadHeader() { + _ThreadData initData; + /** read Header */ + if(!readPBFBlobHeader(input, &initData)) { + return false; + } + + if(readBlob(input, &initData)) { + if(!initData.PBFHeaderBlock.ParseFromArray(&(initData.charBuffer[0]), initData.charBuffer.size() ) ) { + std::cerr << "[error] Header not parseable!" << std::endl; + return false; + } + + for(int i = 0, featureSize = initData.PBFHeaderBlock.required_features_size(); i < featureSize; ++i) { + const std::string& feature = initData.PBFHeaderBlock.required_features( i ); + bool supported = false; + if ( "OsmSchema-V0.6" == feature ) { + supported = true; + } + else if ( "DenseNodes" == feature ) { + supported = true; + } + + if ( !supported ) { + std::cerr << "[error] required feature not supported: " << feature.data() << std::endl; + return false; + } + } + } else { + std::cerr << "[error] blob not loaded!" << std::endl; + } + return true; +} + +inline void PBFParser::ReadData() { + bool keepRunning = true; + do { + _ThreadData *threadData = new _ThreadData(); + keepRunning = readNextBlock(input, threadData); + + if (keepRunning) { + threadDataQueue->push(threadData); + } else { + threadDataQueue->push(NULL); // No more data to read, parse stops when NULL encountered + delete threadData; + } + } while(keepRunning); +} + +inline void PBFParser::ParseData() { + while (true) { + _ThreadData *threadData; + threadDataQueue->wait_and_pop(threadData); + if( NULL==threadData ) { + INFO("Parse Data Thread Finished"); + threadDataQueue->push(NULL); // Signal end of data for other threads + break; + } + + loadBlock(threadData); + + for(int i = 0, groupSize = threadData->PBFprimitiveBlock.primitivegroup_size(); i < groupSize; ++i) { + threadData->currentGroupID = i; + loadGroup(threadData); + + if(threadData->entityTypeIndicator == TypeNode) { + parseNode(threadData); + } + if(threadData->entityTypeIndicator == TypeWay) { + parseWay(threadData); + } + if(threadData->entityTypeIndicator == TypeRelation) { + parseRelation(threadData); + } + if(threadData->entityTypeIndicator == TypeDenseNode) { + parseDenseNode(threadData); + } + } + + delete threadData; + threadData = NULL; + } +} + +inline bool PBFParser::Parse() { + // Start the read and parse threads + boost::thread readThread(boost::bind(&PBFParser::ReadData, this)); + + //Open several parse threads that are synchronized before call to + boost::thread parseThread(boost::bind(&PBFParser::ParseData, this)); + + // Wait for the threads to finish + readThread.join(); + parseThread.join(); + + return true; +} + +inline void PBFParser::parseDenseNode(_ThreadData * threadData) { + const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense(); + int denseTagIndex = 0; + int m_lastDenseID = 0; + int m_lastDenseLatitude = 0; + int m_lastDenseLongitude = 0; + + ImportNode n; + std::vector extracted_nodes_vector; + const int number_of_nodes = dense.id_size(); + extracted_nodes_vector.reserve(number_of_nodes); + for(int i = 0; i < number_of_nodes; ++i) { + n.Clear(); + m_lastDenseID += dense.id( i ); + m_lastDenseLatitude += dense.lat( i ); + m_lastDenseLongitude += dense.lon( i ); + n.id = m_lastDenseID; + n.lat = 100000*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lat_offset() ) / NANO; + n.lon = 100000*( ( double ) m_lastDenseLongitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lon_offset() ) / NANO; + while (denseTagIndex < dense.keys_vals_size()) { + const int tagValue = dense.keys_vals( denseTagIndex ); + if( 0==tagValue ) { + ++denseTagIndex; + break; + } + const int keyValue = dense.keys_vals ( denseTagIndex+1 ); + const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue).data(); + const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue).data(); + n.keyVals.Add(key, value); + denseTagIndex += 2; + } + extracted_nodes_vector.push_back(n); + } + +#pragma omp parallel for schedule ( guided ) + for(int i = 0; i < number_of_nodes; ++i) { + ImportNode &n = extracted_nodes_vector[i]; + ParseNodeInLua( n, scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()) ); + } + + BOOST_FOREACH(ImportNode &n, extracted_nodes_vector) { + extractor_callbacks->nodeFunction(n); + } +} + +inline void PBFParser::parseNode(_ThreadData * ) { + ERR("Parsing of simple nodes not supported. PBF should use dense nodes"); +} + +inline void PBFParser::parseRelation(_ThreadData * threadData) { + //TODO: leave early, if relation is not a restriction + //TODO: reuse rawRestriction container + if( !use_turn_restrictions ) { + return; + } + const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ); + for(int i = 0; i < group.relations_size(); ++i ) { + std::string except_tag_string; + const OSMPBF::Relation& inputRelation = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).relations(i); + bool isRestriction = false; + bool isOnlyRestriction = false; + for(int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k) { + const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k)); + const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k)); + if ("type" == key) { + if( "restriction" == val) { + isRestriction = true; + } else { + break; + } + } + if ("restriction" == key) { + if(val.find("only_") == 0) { + isOnlyRestriction = true; + } + } + if ("except" == key) { + except_tag_string = val; + } + } + + if( isRestriction && ShouldIgnoreRestriction(except_tag_string) ) { + continue; + } + + if(isRestriction) { + int64_t lastRef = 0; + _RawRestrictionContainer currentRestrictionContainer(isOnlyRestriction); + for(int rolesIndex = 0; rolesIndex < inputRelation.roles_sid_size(); ++rolesIndex) { + std::string role(threadData->PBFprimitiveBlock.stringtable().s( inputRelation.roles_sid( rolesIndex ) ).data()); + lastRef += inputRelation.memids(rolesIndex); + + if(!("from" == role || "to" == role || "via" == role)) { + continue; + } + + switch(inputRelation.types(rolesIndex)) { + case 0: //node + if("from" == role || "to" == role) { //Only via should be a node + continue; + } + assert("via" == role); + if(UINT_MAX != currentRestrictionContainer.viaNode) { + currentRestrictionContainer.viaNode = UINT_MAX; + } + assert(UINT_MAX == currentRestrictionContainer.viaNode); + currentRestrictionContainer.restriction.viaNode = lastRef; + break; + case 1: //way + assert("from" == role || "to" == role || "via" == role); + if("from" == role) { + currentRestrictionContainer.fromWay = lastRef; + } + if ("to" == role) { + currentRestrictionContainer.toWay = lastRef; + } + if ("via" == role) { + assert(currentRestrictionContainer.restriction.toNode == UINT_MAX); + currentRestrictionContainer.viaNode = lastRef; + } + break; + case 2: //relation, not used. relations relating to relations are evil. + continue; + assert(false); + break; + + default: //should not happen + //cout << "unknown"; + assert(false); + break; + } + } + if(!extractor_callbacks->restrictionFunction(currentRestrictionContainer)) { + std::cerr << "[PBFParser] relation not parsed" << std::endl; + } + } + } +} + +inline void PBFParser::parseWay(_ThreadData * threadData) { + ExtractionWay w; + std::vector waysToParse; + const int number_of_ways = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size(); + waysToParse.reserve(number_of_ways); + for(int i = 0; i < number_of_ways; ++i) { + w.Clear(); + const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i ); + w.id = inputWay.id(); + unsigned pathNode(0); + const int number_of_referenced_nodes = inputWay.refs_size(); + for(int i = 0; i < number_of_referenced_nodes; ++i) { + pathNode += inputWay.refs(i); + w.path.push_back(pathNode); + } + assert(inputWay.keys_size() == inputWay.vals_size()); + const int number_of_keys = inputWay.keys_size(); + for(int i = 0; i < number_of_keys; ++i) { + const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(i)); + const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(i)); + w.keyVals.Add(key, val); + } + waysToParse.push_back(w); + } + +#pragma omp parallel for schedule ( guided ) + for(int i = 0; i < number_of_ways; ++i) { + ExtractionWay & w = waysToParse[i]; + ParseWayInLua( w, scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()) ); + } + + BOOST_FOREACH(ExtractionWay & w, waysToParse) { + extractor_callbacks->wayFunction(w); + } +} + +inline void PBFParser::loadGroup(_ThreadData * threadData) { +#ifndef NDEBUG + ++groupCount; +#endif + + const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ); + threadData->entityTypeIndicator = 0; + if ( group.nodes_size() != 0 ) { + threadData->entityTypeIndicator = TypeNode; + } + if ( group.ways_size() != 0 ) { + threadData->entityTypeIndicator = TypeWay; + } + if ( group.relations_size() != 0 ) { + threadData->entityTypeIndicator = TypeRelation; + } + if ( group.has_dense() ) { + threadData->entityTypeIndicator = TypeDenseNode; + assert( group.dense().id_size() != 0 ); + } + assert( threadData->entityTypeIndicator != 0 ); +} + +inline void PBFParser::loadBlock(_ThreadData * threadData) { +#ifndef NDEBUG + ++blockCount; +#endif + threadData->currentGroupID = 0; + threadData->currentEntityID = 0; +} + +inline bool PBFParser::readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData) { + int size(0); + stream.read((char *)&size, sizeof(int)); + size = swapEndian(size); + if(stream.eof()) { + return false; + } + if ( size > MAX_BLOB_HEADER_SIZE || size < 0 ) { + return false; + } + char *data = new char[size]; + stream.read(data, size*sizeof(data[0])); + + bool dataSuccessfullyParsed = (threadData->PBFBlobHeader).ParseFromArray( data, size); + delete[] data; + return dataSuccessfullyParsed; +} + +inline bool PBFParser::unpackZLIB(std::fstream &, _ThreadData * threadData) { + unsigned rawSize = threadData->PBFBlob.raw_size(); + char* unpackedDataArray = new char[rawSize]; + z_stream compressedDataStream; + compressedDataStream.next_in = ( unsigned char* ) threadData->PBFBlob.zlib_data().data(); + compressedDataStream.avail_in = threadData->PBFBlob.zlib_data().size(); + compressedDataStream.next_out = ( unsigned char* ) unpackedDataArray; + compressedDataStream.avail_out = rawSize; + compressedDataStream.zalloc = Z_NULL; + compressedDataStream.zfree = Z_NULL; + compressedDataStream.opaque = Z_NULL; + int ret = inflateInit( &compressedDataStream ); + if ( ret != Z_OK ) { + std::cerr << "[error] failed to init zlib stream" << std::endl; + delete[] unpackedDataArray; + return false; + } + + ret = inflate( &compressedDataStream, Z_FINISH ); + if ( ret != Z_STREAM_END ) { + std::cerr << "[error] failed to inflate zlib stream" << std::endl; + std::cerr << "[error] Error type: " << ret << std::endl; + delete[] unpackedDataArray; + return false; + } + + ret = inflateEnd( &compressedDataStream ); + if ( ret != Z_OK ) { + std::cerr << "[error] failed to deinit zlib stream" << std::endl; + delete[] unpackedDataArray; + return false; + } + + threadData->charBuffer.clear(); threadData->charBuffer.resize(rawSize); + std::copy(unpackedDataArray, unpackedDataArray + rawSize, threadData->charBuffer.begin()); + delete[] unpackedDataArray; + return true; +} + +inline bool PBFParser::unpackLZMA(std::fstream &, _ThreadData * ) { + return false; +} + +inline bool PBFParser::readBlob(std::fstream& stream, _ThreadData * threadData) { + if(stream.eof()) { + return false; + } + + const int size = threadData->PBFBlobHeader.datasize(); + if ( size < 0 || size > MAX_BLOB_SIZE ) { + std::cerr << "[error] invalid Blob size:" << size << std::endl; + return false; + } + + char* data = new char[size]; + stream.read(data, sizeof(data[0])*size); + + if ( !threadData->PBFBlob.ParseFromArray( data, size ) ) { + std::cerr << "[error] failed to parse blob" << std::endl; + delete[] data; + return false; + } + + if ( threadData->PBFBlob.has_raw() ) { + const std::string& data = threadData->PBFBlob.raw(); + threadData->charBuffer.clear(); + threadData->charBuffer.resize( data.size() ); + std::copy(data.begin(), data.end(), threadData->charBuffer.begin()); + } else if ( threadData->PBFBlob.has_zlib_data() ) { + if ( !unpackZLIB(stream, threadData) ) { + std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl; + delete[] data; + return false; + } + } else if ( threadData->PBFBlob.has_lzma_data() ) { + if ( !unpackLZMA(stream, threadData) ) { + std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl; + } + delete[] data; + return false; + } else { + std::cerr << "[error] Blob contains no data" << std::endl; + delete[] data; + return false; + } + delete[] data; + return true; +} + +bool PBFParser::readNextBlock(std::fstream& stream, _ThreadData * threadData) { + if(stream.eof()) { + return false; + } + + if ( !readPBFBlobHeader(stream, threadData) ){ + return false; + } + + if ( threadData->PBFBlobHeader.type() != "OSMData" ) { + return false; + } + + if ( !readBlob(stream, threadData) ) { + return false; + } + + if ( !threadData->PBFprimitiveBlock.ParseFromArray( &(threadData->charBuffer[0]), threadData-> charBuffer.size() ) ) { + ERR("failed to parse PrimitiveBlock"); + return false; + } + return true; +} diff --git a/Extractor/PBFParser.h b/Extractor/PBFParser.h index 24f80c924..587fbc96c 100644 --- a/Extractor/PBFParser.h +++ b/Extractor/PBFParser.h @@ -1,600 +1,101 @@ /* - 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. + 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 PBFPARSER_H_ #define PBFPARSER_H_ -#include +#include #include #include -#include #include #include -#include "../typedefs.h" +#include -#include "BaseParser.h" -#include "ExtractorCallbacks.h" -#include "ExtractorStructs.h" -#include "ScriptingEnvironment.h" +#include "../typedefs.h" #include "../DataStructures/HashTable.h" #include "../DataStructures/ConcurrentQueue.h" +#include "../Util/MachineInfo.h" #include "../Util/OpenMPWrapper.h" -class PBFParser : public BaseParser { - -// typedef BaseParser super; +#include "BaseParser.h" +class PBFParser : public BaseParser { + enum EntityType { TypeNode = 1, TypeWay = 2, TypeRelation = 4, TypeDenseNode = 8 } ; - - enum Endianness { - LittleEndian = 1, - BigEndian = 2 - }; - + struct _ThreadData { int currentGroupID; int currentEntityID; short entityTypeIndicator; - + OSMPBF::BlobHeader PBFBlobHeader; OSMPBF::Blob PBFBlob; - + OSMPBF::HeaderBlock PBFHeaderBlock; OSMPBF::PrimitiveBlock PBFprimitiveBlock; - + std::vector charBuffer; }; - + public: - PBFParser(const char * fileName) : externalMemory(NULL){ - GOOGLE_PROTOBUF_VERIFY_VERSION; - //TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk? - //NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free. - threadDataQueue = boost::make_shared >( 2500 ); /* Max 2500 items in queue, hardcoded. */ - input.open(fileName, std::ios::in | std::ios::binary); - - if (!input) { - std::cerr << fileName << ": File not found." << std::endl; - } - -#ifndef NDEBUG - blockCount = 0; - groupCount = 0; -#endif - } - - void RegisterCallbacks(ExtractorCallbacks * em) { - externalMemory = em; - } - - //call by value, but who cares. It is done once. - void RegisterScriptingEnvironment(ScriptingEnvironment & _se) { - scriptingEnvironment = _se; - } - - ~PBFParser() { - if(input.is_open()) - input.close(); - - // Clean up any leftover ThreadData objects in the queue - _ThreadData* td; - while (threadDataQueue->try_pop(td)) { - delete td; - } - google::protobuf::ShutdownProtobufLibrary(); - -#ifndef NDEBUG - DEBUG("parsed " << blockCount << " blocks from pbf with " << groupCount << " groups"); -#endif - } - - inline bool Init() { - _ThreadData initData; - /** read Header */ - if(!readPBFBlobHeader(input, &initData)) { - return false; - } - - if(readBlob(input, &initData)) { - if(!initData.PBFHeaderBlock.ParseFromArray(&(initData.charBuffer[0]), initData.charBuffer.size() ) ) { - std::cerr << "[error] Header not parseable!" << std::endl; - return false; - } - - for(int i = 0, featureSize = initData.PBFHeaderBlock.required_features_size(); i < featureSize; ++i) { - const std::string& feature = initData.PBFHeaderBlock.required_features( i ); - bool supported = false; - if ( "OsmSchema-V0.6" == feature ) - supported = true; - else if ( "DenseNodes" == feature ) - supported = true; - - if ( !supported ) { - std::cerr << "[error] required feature not supported: " << feature.data() << std::endl; - return false; - } - } - } else { - std::cerr << "[error] blob not loaded!" << std::endl; - } - return true; - } - - inline void ReadData() { - bool keepRunning = true; - do { - _ThreadData *threadData = new _ThreadData(); - keepRunning = readNextBlock(input, threadData); - - if (keepRunning) - threadDataQueue->push(threadData); - else { - threadDataQueue->push(NULL); // No more data to read, parse stops when NULL encountered - delete threadData; - } - } while(keepRunning); - } - - inline void ParseData() { - while (1) { - _ThreadData *threadData; - threadDataQueue->wait_and_pop(threadData); - if (threadData == NULL) { - INFO("Parse Data Thread Finished"); - threadDataQueue->push(NULL); // Signal end of data for other threads - break; - } - - loadBlock(threadData); - - for(int i = 0, groupSize = threadData->PBFprimitiveBlock.primitivegroup_size(); i < groupSize; ++i) { - threadData->currentGroupID = i; - loadGroup(threadData); - - if(threadData->entityTypeIndicator == TypeNode) - parseNode(threadData); - if(threadData->entityTypeIndicator == TypeWay) - parseWay(threadData); - if(threadData->entityTypeIndicator == TypeRelation) - parseRelation(threadData); - if(threadData->entityTypeIndicator == TypeDenseNode) - parseDenseNode(threadData); - } - - delete threadData; - threadData = NULL; - } - } - - inline bool Parse() { - // Start the read and parse threads - boost::thread readThread(boost::bind(&PBFParser::ReadData, this)); - - //Open several parse threads that are synchronized before call to - boost::thread parseThread(boost::bind(&PBFParser::ParseData, this)); - - // Wait for the threads to finish - readThread.join(); - parseThread.join(); - - return true; - } - + PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se); + virtual ~PBFParser(); + + inline bool ReadHeader(); + inline bool Parse(); + private: - - inline void parseDenseNode(_ThreadData * threadData) { - const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense(); - int denseTagIndex = 0; - int m_lastDenseID = 0; - int m_lastDenseLatitude = 0; - int m_lastDenseLongitude = 0; - - ImportNode n; - std::vector nodesToParse; - for(int i = 0, idSize = dense.id_size(); i < idSize; ++i) { - n.Clear(); - m_lastDenseID += dense.id( i ); - m_lastDenseLatitude += dense.lat( i ); - m_lastDenseLongitude += dense.lon( i ); - n.id = m_lastDenseID; - n.lat = 100000*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() +threadData-> PBFprimitiveBlock.lat_offset() ) / NANO; - n.lon = 100000*( ( double ) m_lastDenseLongitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lon_offset() ) / NANO; - while (denseTagIndex < dense.keys_vals_size()) { - const int tagValue = dense.keys_vals( denseTagIndex ); - if(tagValue == 0) { - ++denseTagIndex; - break; - } - const int keyValue = dense.keys_vals ( denseTagIndex+1 ); - const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue).data(); - const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue).data(); - n.keyVals.Add(key, value); - denseTagIndex += 2; - } - nodesToParse.push_back(n); - } - - unsigned endi_nodes = nodesToParse.size(); -#pragma omp parallel for schedule ( guided ) - for(unsigned i = 0; i < endi_nodes; ++i) { - ImportNode &n = nodesToParse[i]; - /** Pass the unpacked node to the LUA call back **/ - try { - luabind::call_function( - scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()), - "node_function", - boost::ref(n) - ); - } catch (const luabind::error &er) { - lua_State* Ler=er.state(); - report_errors(Ler, -1); - ERR(er.what()); - } -// catch (...) { -// ERR("Unknown error occurred during PBF dense node parsing!"); -// } - } - - - BOOST_FOREACH(ImportNode &n, nodesToParse) { - if(!externalMemory->nodeFunction(n)) - std::cerr << "[PBFParser] dense node not parsed" << std::endl; - } - } - - inline void parseNode(_ThreadData * ) { - ERR("Parsing of simple nodes not supported. PBF should use dense nodes"); - } - - inline void parseRelation(_ThreadData * threadData) { - //TODO: leave early, if relatio is not a restriction - //TODO: reuse rawRestriction container - const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ); - for(int i = 0; i < group.relations_size(); ++i ) { - const OSMPBF::Relation& inputRelation = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).relations(i); - bool isRestriction = false; - bool isOnlyRestriction = false; - for(int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k) { - const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k)); - const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k)); - if ("type" == key) { - if( "restriction" == val) - isRestriction = true; - else - break; - } - if ("restriction" == key) { - if(val.find("only_") == 0) - isOnlyRestriction = true; - } - - } - if(isRestriction) { - long long lastRef = 0; - _RawRestrictionContainer currentRestrictionContainer(isOnlyRestriction); - for(int rolesIndex = 0; rolesIndex < inputRelation.roles_sid_size(); ++rolesIndex) { - std::string role(threadData->PBFprimitiveBlock.stringtable().s( inputRelation.roles_sid( rolesIndex ) ).data()); - lastRef += inputRelation.memids(rolesIndex); - - if(false == ("from" == role || "to" == role || "via" == role)) { - continue; - } - - switch(inputRelation.types(rolesIndex)) { - case 0: //node - if("from" == role || "to" == role) //Only via should be a node - continue; - assert("via" == role); - if(UINT_MAX != currentRestrictionContainer.viaNode) - currentRestrictionContainer.viaNode = UINT_MAX; - assert(UINT_MAX == currentRestrictionContainer.viaNode); - currentRestrictionContainer.restriction.viaNode = lastRef; - break; - case 1: //way - assert("from" == role || "to" == role || "via" == role); - if("from" == role) { - currentRestrictionContainer.fromWay = lastRef; - } - if ("to" == role) { - currentRestrictionContainer.toWay = lastRef; - } - if ("via" == role) { - assert(currentRestrictionContainer.restriction.toNode == UINT_MAX); - currentRestrictionContainer.viaNode = lastRef; - } - break; - case 2: //relation, not used. relations relating to relations are evil. - continue; - assert(false); - break; - - default: //should not happen - //cout << "unknown"; - assert(false); - break; - } - } - // if(UINT_MAX != currentRestriction.viaNode) { - // cout << "restr from " << currentRestriction.from << " via "; - // cout << "node " << currentRestriction.viaNode; - // cout << " to " << currentRestriction.to << endl; - // } - if(!externalMemory->restrictionFunction(currentRestrictionContainer)) - std::cerr << "[PBFParser] relation not parsed" << std::endl; - } - } - } - - inline void parseWay(_ThreadData * threadData) { - _Way w; - std::vector<_Way> waysToParse(threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size()); - for(int i = 0, ways_size = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size(); i < ways_size; ++i) { - w.Clear(); - const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i ); - w.id = inputWay.id(); - unsigned pathNode(0); - for(int i = 0; i < inputWay.refs_size(); ++i) { - pathNode += inputWay.refs(i); - w.path.push_back(pathNode); - } - assert(inputWay.keys_size() == inputWay.vals_size()); - for(int i = 0; i < inputWay.keys_size(); ++i) { - const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(i)); - const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(i)); - w.keyVals.Add(key, val); - } - - waysToParse.push_back(w); - } - - unsigned endi_ways = waysToParse.size(); -#pragma omp parallel for schedule ( guided ) - for(unsigned i = 0; i < endi_ways; ++i) { - _Way & w = waysToParse[i]; - /** Pass the unpacked way to the LUA call back **/ - try { - luabind::call_function( - scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()), - "way_function", - boost::ref(w), - w.path.size() - ); - - } catch (const luabind::error &er) { - lua_State* Ler=er.state(); - report_errors(Ler, -1); - ERR(er.what()); - } -// catch (...) { -// ERR("Unknown error!"); -// } - } - - BOOST_FOREACH(_Way & w, waysToParse) { - if(!externalMemory->wayFunction(w)) { - std::cerr << "[PBFParser] way not parsed" << std::endl; - } - } - } - - inline void loadGroup(_ThreadData * threadData) { -#ifndef NDEBUG - ++groupCount; -#endif - - const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ); - threadData->entityTypeIndicator = 0; - if ( group.nodes_size() != 0 ) { - threadData->entityTypeIndicator = TypeNode; - } - if ( group.ways_size() != 0 ) { - threadData->entityTypeIndicator = TypeWay; - } - if ( group.relations_size() != 0 ) { - threadData->entityTypeIndicator = TypeRelation; - } - if ( group.has_dense() ) { - threadData->entityTypeIndicator = TypeDenseNode; - assert( group.dense().id_size() != 0 ); - } - assert( threadData->entityTypeIndicator != 0 ); - } - - inline void loadBlock(_ThreadData * threadData) { -#ifndef NDEBUG - ++blockCount; -#endif - threadData->currentGroupID = 0; - threadData->currentEntityID = 0; - } - - /* Reverses Network Byte Order into something usable, compiles down to a bswap-mov combination */ - inline unsigned swapEndian(unsigned x) const { - if(getMachineEndianness() == LittleEndian) - return ( (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24) ); - return x; - } - - inline bool readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData) { - int size(0); - stream.read((char *)&size, sizeof(int)); - size = swapEndian(size); - if(stream.eof()) { - return false; - } - if ( size > MAX_BLOB_HEADER_SIZE || size < 0 ) { - return false; - } - char *data = new char[size]; - stream.read(data, size*sizeof(data[0])); - - bool dataSuccessfullyParsed = (threadData->PBFBlobHeader).ParseFromArray( data, size); - delete[] data; - return dataSuccessfullyParsed; - } - - inline bool unpackZLIB(std::fstream &, _ThreadData * threadData) { - unsigned rawSize = threadData->PBFBlob.raw_size(); - char* unpackedDataArray = new char[rawSize]; - z_stream compressedDataStream; - compressedDataStream.next_in = ( unsigned char* ) threadData->PBFBlob.zlib_data().data(); - compressedDataStream.avail_in = threadData->PBFBlob.zlib_data().size(); - compressedDataStream.next_out = ( unsigned char* ) unpackedDataArray; - compressedDataStream.avail_out = rawSize; - compressedDataStream.zalloc = Z_NULL; - compressedDataStream.zfree = Z_NULL; - compressedDataStream.opaque = Z_NULL; - int ret = inflateInit( &compressedDataStream ); - if ( ret != Z_OK ) { - std::cerr << "[error] failed to init zlib stream" << std::endl; - delete[] unpackedDataArray; - return false; - } - - ret = inflate( &compressedDataStream, Z_FINISH ); - if ( ret != Z_STREAM_END ) { - std::cerr << "[error] failed to inflate zlib stream" << std::endl; - std::cerr << "[error] Error type: " << ret << std::endl; - delete[] unpackedDataArray; - return false; - } - - ret = inflateEnd( &compressedDataStream ); - if ( ret != Z_OK ) { - std::cerr << "[error] failed to deinit zlib stream" << std::endl; - delete[] unpackedDataArray; - return false; - } - - threadData->charBuffer.clear(); threadData->charBuffer.resize(rawSize); - std::copy(unpackedDataArray, unpackedDataArray + rawSize, threadData->charBuffer.begin()); - delete[] unpackedDataArray; - return true; - } - - inline bool unpackLZMA(std::fstream &, _ThreadData * ) const { - return false; - } - - inline bool readBlob(std::fstream& stream, _ThreadData * threadData) { - if(stream.eof()) - return false; - - const int size = threadData->PBFBlobHeader.datasize(); - if ( size < 0 || size > MAX_BLOB_SIZE ) { - std::cerr << "[error] invalid Blob size:" << size << std::endl; - return false; - } - - char* data = new char[size]; - stream.read(data, sizeof(data[0])*size); - - if ( !threadData->PBFBlob.ParseFromArray( data, size ) ) { - std::cerr << "[error] failed to parse blob" << std::endl; - delete[] data; - return false; - } - - if ( threadData->PBFBlob.has_raw() ) { - const std::string& data = threadData->PBFBlob.raw(); - threadData->charBuffer.clear(); - threadData->charBuffer.resize( data.size() ); - std::copy(data.begin(), data.end(), threadData->charBuffer.begin()); - } else if ( threadData->PBFBlob.has_zlib_data() ) { - if ( !unpackZLIB(stream, threadData) ) { - std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl; - delete[] data; - return false; - } - } else if ( threadData->PBFBlob.has_lzma_data() ) { - if ( !unpackLZMA(stream, threadData) ) - std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl; - delete[] data; - return false; - } else { - std::cerr << "[error] Blob contains no data" << std::endl; - delete[] data; - return false; - } - delete[] data; - return true; - } - - inline bool readNextBlock(std::fstream& stream, _ThreadData * threadData) { - if(stream.eof()) { - return false; - } - - if ( !readPBFBlobHeader(stream, threadData) ){ - return false; - } - - if ( threadData->PBFBlobHeader.type() != "OSMData" ) { - return false; - } - - if ( !readBlob(stream, threadData) ) { - return false; - } - - if ( !threadData->PBFprimitiveBlock.ParseFromArray( &(threadData->charBuffer[0]), threadData-> charBuffer.size() ) ) { - ERR("failed to parse PrimitiveBlock"); - return false; - } - return true; - } - - //Is optimized to a single 'mov eax,1' on GCC, clang and icc using -O3 - inline Endianness getMachineEndianness() const { - int i(1); - char *p = (char *) &i; - if (1 == p[0]) - return LittleEndian; - return BigEndian; - } - + inline void ReadData(); + inline void ParseData(); + inline void parseDenseNode(_ThreadData * threadData); + inline void parseNode(_ThreadData * ); + inline void parseRelation(_ThreadData * threadData); + inline void parseWay(_ThreadData * threadData); + + inline void loadGroup(_ThreadData * threadData); + inline void loadBlock(_ThreadData * threadData); + inline bool readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData); + inline bool unpackZLIB(std::fstream &, _ThreadData * threadData); + inline bool unpackLZMA(std::fstream &, _ThreadData * ); + inline bool readBlob(std::fstream& stream, _ThreadData * threadData) ; + inline bool readNextBlock(std::fstream& stream, _ThreadData * threadData); + static const int NANO = 1000 * 1000 * 1000; static const int MAX_BLOB_HEADER_SIZE = 64 * 1024; static const int MAX_BLOB_SIZE = 32 * 1024 * 1024; - + #ifndef NDEBUG /* counting the number of read blocks and groups */ unsigned groupCount; unsigned blockCount; #endif - ExtractorCallbacks * externalMemory; - /* the input stream to parse */ - std::fstream input; - - /* ThreadData Queue */ + std::fstream input; // the input stream to parse boost::shared_ptr > threadDataQueue; - - ScriptingEnvironment scriptingEnvironment; }; #endif /* PBFPARSER_H_ */ diff --git a/Extractor/ScriptingEnvironment.cpp b/Extractor/ScriptingEnvironment.cpp index 01f183166..6bab21c5f 100644 --- a/Extractor/ScriptingEnvironment.cpp +++ b/Extractor/ScriptingEnvironment.cpp @@ -18,15 +18,7 @@ or see http://www.gnu.org/licenses/agpl.txt. */ -extern "C" { -#include -#include -#include -} - #include "ScriptingEnvironment.h" -#include "../typedefs.h" -#include "../Util/OpenMPWrapper.h" ScriptingEnvironment::ScriptingEnvironment() {} ScriptingEnvironment::ScriptingEnvironment(const char * fileName) { @@ -44,6 +36,8 @@ ScriptingEnvironment::ScriptingEnvironment(const char * fileName) { //open utility libraries string library; luaL_openlibs(myLuaState); + luaAddScriptFolderToLoadPath( myLuaState, fileName ); + // Add our function to the state's global scope luabind::module(myLuaState) [ luabind::def("print", LUA_print), @@ -51,15 +45,7 @@ ScriptingEnvironment::ScriptingEnvironment(const char * fileName) { luabind::def("durationIsValid", durationIsValid), luabind::def("parseDuration", parseDuration) ]; -//#pragma omp critical -// { -// if(0 != luaL_dostring( -// myLuaState, -// "print('Initializing LUA engine')\n" -// )) { -// ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block"); -// } -// } + luabind::module(myLuaState) [ luabind::class_ >("keyVals") .def("Add", &HashTable::Add) @@ -79,32 +65,32 @@ ScriptingEnvironment::ScriptingEnvironment(const char * fileName) { ]; luabind::module(myLuaState) [ - luabind::class_<_Way>("Way") + luabind::class_("Way") .def(luabind::constructor<>()) - .def_readwrite("name", &_Way::name) - .def_readwrite("speed", &_Way::speed) - .def_readwrite("type", &_Way::type) - .def_readwrite("access", &_Way::access) - .def_readwrite("roundabout", &_Way::roundabout) - .def_readwrite("is_duration_set", &_Way::isDurationSet) - .def_readwrite("is_access_restricted", &_Way::isAccessRestricted) - .def_readwrite("ignore_in_grid", &_Way::ignoreInGrid) - .def_readwrite("tags", &_Way::keyVals) - .def_readwrite("direction", &_Way::direction) + .def_readwrite("name", &ExtractionWay::name) + .def_readwrite("speed", &ExtractionWay::speed) + .def_readwrite("backward_speed", &ExtractionWay::backward_speed) + .def_readwrite("duration", &ExtractionWay::duration) + .def_readwrite("type", &ExtractionWay::type) + .def_readwrite("access", &ExtractionWay::access) + .def_readwrite("roundabout", &ExtractionWay::roundabout) + .def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted) + .def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid) + .def_readwrite("tags", &ExtractionWay::keyVals) + .def_readwrite("direction", &ExtractionWay::direction) .enum_("constants") - [ - luabind::value("notSure", 0), - luabind::value("oneway", 1), - luabind::value("bidirectional", 2), - luabind::value("opposite", 3) - ] - ]; + [ + luabind::value("notSure", 0), + luabind::value("oneway", 1), + luabind::value("bidirectional", 2), + luabind::value("opposite", 3) + ] + ]; + luabind::module(myLuaState) [ + luabind::class_ >("vector") + .def("Add", &std::vector::push_back) + ]; - // Now call our function in a lua script -//#pragma omp critical -// { -// INFO("Parsing speedprofile from " << fileName ); -// } if(0 != luaL_dofile(myLuaState, fileName) ) { ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block"); } diff --git a/Extractor/ScriptingEnvironment.h b/Extractor/ScriptingEnvironment.h index 05528d408..015ff2529 100644 --- a/Extractor/ScriptingEnvironment.h +++ b/Extractor/ScriptingEnvironment.h @@ -30,9 +30,11 @@ extern "C" { #include "ExtractionHelperFunctions.h" #include "ExtractorStructs.h" -#include "LuaUtil.h" +#include "../typedefs.h" #include "../DataStructures/ImportNode.h" +#include "../Util/LuaUtil.h" +#include "../Util/OpenMPWrapper.h" class ScriptingEnvironment { public: diff --git a/Extractor/XMLParser.cpp b/Extractor/XMLParser.cpp new file mode 100644 index 000000000..fa810a702 --- /dev/null +++ b/Extractor/XMLParser.cpp @@ -0,0 +1,276 @@ +/* + 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. + */ + +#include + +#include "XMLParser.h" + +#include "ExtractorStructs.h" +#include "../DataStructures/HashTable.h" +#include "../DataStructures/InputReaderFactory.h" + + +XMLParser::XMLParser(const char * filename, ExtractorCallbacks* ec, ScriptingEnvironment& se) : BaseParser(ec, se) { + WARN("Parsing plain .osm/.osm.bz2 is deprecated. Switch to .pbf"); + inputReader = inputReaderFactory(filename); +} + +bool XMLParser::ReadHeader() { + return (xmlTextReaderRead( inputReader ) == 1); +} +bool XMLParser::Parse() { + while ( xmlTextReaderRead( inputReader ) == 1 ) { + const int type = xmlTextReaderNodeType( inputReader ); + + //1 is Element + if ( type != 1 ) { + continue; + } + + xmlChar* currentName = xmlTextReaderName( inputReader ); + if ( currentName == NULL ) { + continue; + } + + if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) { + ImportNode n = _ReadXMLNode(); + ParseNodeInLua( n, luaState ); + extractor_callbacks->nodeFunction(n); +// if(!extractor_callbacks->nodeFunction(n)) +// std::cerr << "[XMLParser] dense node not parsed" << std::endl; + } + + if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) { + ExtractionWay way = _ReadXMLWay( ); + ParseWayInLua( way, luaState ); + extractor_callbacks->wayFunction(way); +// if(!extractor_callbacks->wayFunction(way)) +// std::cerr << "[PBFParser] way not parsed" << std::endl; + } + if( use_turn_restrictions ) { + if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) { + _RawRestrictionContainer r = _ReadXMLRestriction(); + if(r.fromWay != UINT_MAX) { + if(!extractor_callbacks->restrictionFunction(r)) { + std::cerr << "[XMLParser] restriction not parsed" << std::endl; + } + } + } + } + xmlFree( currentName ); + } + return true; +} + +_RawRestrictionContainer XMLParser::_ReadXMLRestriction() { + _RawRestrictionContainer restriction; + std::string except_tag_string; + + if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { + const int depth = xmlTextReaderDepth( inputReader );while ( xmlTextReaderRead( inputReader ) == 1 ) { + const int childType = xmlTextReaderNodeType( inputReader ); + if ( childType != 1 && childType != 15 ) { + continue; + } + const int childDepth = xmlTextReaderDepth( inputReader ); + xmlChar* childName = xmlTextReaderName( inputReader ); + if ( childName == NULL ) { + continue; + } + if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "relation" ) == 1 ) { + xmlFree( childName ); + break; + } + if ( childType != 1 ) { + xmlFree( childName ); + continue; + } + + if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { + xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" ); + xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" ); + if ( k != NULL && value != NULL ) { + if(xmlStrEqual(k, ( const xmlChar* ) "restriction" )){ + if(0 == std::string((const char *) value).find("only_")) { + restriction.restriction.flags.isOnly = true; + } + } + if ( xmlStrEqual(k, (const xmlChar *) "except") ) { + except_tag_string = (const char*) value; + } + } + + if ( k != NULL ) { + xmlFree( k ); + } + if ( value != NULL ) { + xmlFree( value ); + } + } else if ( xmlStrEqual( childName, ( const xmlChar* ) "member" ) == 1 ) { + xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" ); + if ( ref != NULL ) { + xmlChar * role = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "role" ); + xmlChar * type = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "type" ); + + if(xmlStrEqual(role, (const xmlChar *) "to") && xmlStrEqual(type, (const xmlChar *) "way")) { + restriction.toWay = atoi((const char*) ref); + } + if(xmlStrEqual(role, (const xmlChar *) "from") && xmlStrEqual(type, (const xmlChar *) "way")) { + restriction.fromWay = atoi((const char*) ref); + } + if(xmlStrEqual(role, (const xmlChar *) "via") && xmlStrEqual(type, (const xmlChar *) "node")) { + restriction.restriction.viaNode = atoi((const char*) ref); + } + + if(NULL != type) { + xmlFree( type ); + } + if(NULL != role) { + xmlFree( role ); + } + if(NULL != ref) { + xmlFree( ref ); + } + } + } + xmlFree( childName ); + } + } + + if( ShouldIgnoreRestriction(except_tag_string) ) { + restriction.fromWay = UINT_MAX; //workaround to ignore the restriction + } + return restriction; +} + +ExtractionWay XMLParser::_ReadXMLWay() { + ExtractionWay way; + if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { + const int depth = xmlTextReaderDepth( inputReader ); + while ( xmlTextReaderRead( inputReader ) == 1 ) { + const int childType = xmlTextReaderNodeType( inputReader ); + if ( childType != 1 && childType != 15 ) { + continue; + } + const int childDepth = xmlTextReaderDepth( inputReader ); + xmlChar* childName = xmlTextReaderName( inputReader ); + if ( childName == NULL ) { + continue; + } + + if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "way" ) == 1 ) { + xmlChar* id = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" ); + way.id = atoi((char*)id); + xmlFree(id); + xmlFree( childName ); + break; + } + if ( childType != 1 ) { + xmlFree( childName ); + continue; + } + + if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { + xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" ); + xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" ); + // cout << "->k=" << k << ", v=" << value << endl; + if ( k != NULL && value != NULL ) { + way.keyVals.Add(std::string( (char *) k ), std::string( (char *) value)); + } + if ( k != NULL ) { + xmlFree( k ); + } + if ( value != NULL ) { + xmlFree( value ); + } + } else if ( xmlStrEqual( childName, ( const xmlChar* ) "nd" ) == 1 ) { + xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" ); + if ( ref != NULL ) { + way.path.push_back( atoi(( const char* ) ref ) ); + xmlFree( ref ); + } + } + xmlFree( childName ); + } + } + return way; +} + +ImportNode XMLParser::_ReadXMLNode() { + ImportNode node; + + xmlChar* attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lat" ); + if ( attribute != NULL ) { + node.lat = static_cast(100000.*atof(( const char* ) attribute ) ); + xmlFree( attribute ); + } + attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lon" ); + if ( attribute != NULL ) { + node.lon = static_cast(100000.*atof(( const char* ) attribute )); + xmlFree( attribute ); + } + attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" ); + if ( attribute != NULL ) { + node.id = atoi(( const char* ) attribute ); + xmlFree( attribute ); + } + + if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { + const int depth = xmlTextReaderDepth( inputReader ); + while ( xmlTextReaderRead( inputReader ) == 1 ) { + const int childType = xmlTextReaderNodeType( inputReader ); + // 1 = Element, 15 = EndElement + if ( childType != 1 && childType != 15 ) { + continue; + } + const int childDepth = xmlTextReaderDepth( inputReader ); + xmlChar* childName = xmlTextReaderName( inputReader ); + if ( childName == NULL ) { + continue; + } + + if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "node" ) == 1 ) { + xmlFree( childName ); + break; + } + if ( childType != 1 ) { + xmlFree( childName ); + continue; + } + + if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { + xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" ); + xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" ); + if ( k != NULL && value != NULL ) { + node.keyVals.Add(std::string( reinterpret_cast(k) ), std::string( reinterpret_cast(value))); + } + if ( k != NULL ) { + xmlFree( k ); + } + if ( value != NULL ) { + xmlFree( value ); + } + } + + xmlFree( childName ); + } + } + return node; +} diff --git a/Extractor/XMLParser.h b/Extractor/XMLParser.h index c9d665dc3..a2af2fb86 100644 --- a/Extractor/XMLParser.h +++ b/Extractor/XMLParser.h @@ -1,308 +1,42 @@ /* - 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. + 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 XMLPARSER_H_ #define XMLPARSER_H_ -#include #include #include "../typedefs.h" #include "BaseParser.h" -#include "ExtractorStructs.h" -#include "ExtractorCallbacks.h" -#include "ScriptingEnvironment.h" -#include "../DataStructures/HashTable.h" -#include "../DataStructures/InputReaderFactory.h" -class XMLParser : public BaseParser { +class XMLParser : public BaseParser { public: - XMLParser(const char * filename) : externalMemory(NULL), myLuaState(NULL){ - WARN("Parsing plain .osm/.osm.bz2 is deprecated. Switch to .pbf"); - inputReader = inputReaderFactory(filename); - } - virtual ~XMLParser() {} - - void RegisterCallbacks(ExtractorCallbacks * em) { - externalMemory = em; - } - - void RegisterScriptingEnvironment(ScriptingEnvironment & _se) { - myLuaState = _se.getLuaStateForThreadID(0); - } - - bool Init() { - return (xmlTextReaderRead( inputReader ) == 1); - } - bool Parse() { - while ( xmlTextReaderRead( inputReader ) == 1 ) { - const int type = xmlTextReaderNodeType( inputReader ); - - //1 is Element - if ( type != 1 ) - continue; - - xmlChar* currentName = xmlTextReaderName( inputReader ); - if ( currentName == NULL ) - continue; - - if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) { - ImportNode n = _ReadXMLNode( ); - /** Pass the unpacked node to the LUA call back **/ - try { - luabind::call_function( - myLuaState, - "node_function", - boost::ref(n) - ); - if(!externalMemory->nodeFunction(n)) - std::cerr << "[XMLParser] dense node not parsed" << std::endl; - } catch (const luabind::error &er) { - cerr << er.what() << endl; - lua_State* Ler=er.state(); - report_errors(Ler, -1); - } catch (std::exception & e) { - ERR(e.what()); - } catch (...) { - ERR("Unknown error occurred during XML node parsing!"); - } - } - - if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) { - string name; - _Way way = _ReadXMLWay( ); - - /** Pass the unpacked way to the LUA call back **/ - try { - luabind::call_function( - myLuaState, - "way_function", - boost::ref(way), - way.path.size() - ); - if(!externalMemory->wayFunction(way)) { - std::cerr << "[PBFParser] way not parsed" << std::endl; - } - } catch (const luabind::error &er) { - cerr << er.what() << endl; - lua_State* Ler=er.state(); - report_errors(Ler, -1); - } catch (std::exception & e) { - ERR(e.what()); - } catch (...) { - ERR("Unknown error occurred during XML way parsing!"); - } - } - if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) { - _RawRestrictionContainer r = _ReadXMLRestriction(); - if(r.fromWay != UINT_MAX) { - if(!externalMemory->restrictionFunction(r)) { - std::cerr << "[XMLParser] restriction not parsed" << std::endl; - } - } - } - xmlFree( currentName ); - } - return true; - } - + XMLParser(const char* filename, ExtractorCallbacks* ec, ScriptingEnvironment& se); + bool ReadHeader(); + bool Parse(); + private: - _RawRestrictionContainer _ReadXMLRestriction ( ) { - _RawRestrictionContainer restriction; - - if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { - const int depth = xmlTextReaderDepth( inputReader );while ( xmlTextReaderRead( inputReader ) == 1 ) { - const int childType = xmlTextReaderNodeType( inputReader ); - if ( childType != 1 && childType != 15 ) - continue; - const int childDepth = xmlTextReaderDepth( inputReader ); - xmlChar* childName = xmlTextReaderName( inputReader ); - if ( childName == NULL ) - continue; - - if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "relation" ) == 1 ) { - xmlFree( childName ); - break; - } - if ( childType != 1 ) { - xmlFree( childName ); - continue; - } - - if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { - xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" ); - xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" ); - if ( k != NULL && value != NULL ) { - if(xmlStrEqual(k, ( const xmlChar* ) "restriction" )){ - if(0 == std::string((const char *) value).find("only_")) - restriction.restriction.flags.isOnly = true; - } - - } - if ( k != NULL ) - xmlFree( k ); - if ( value != NULL ) - xmlFree( value ); - } else if ( xmlStrEqual( childName, ( const xmlChar* ) "member" ) == 1 ) { - xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" ); - if ( ref != NULL ) { - xmlChar * role = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "role" ); - xmlChar * type = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "type" ); - if(xmlStrEqual(role, (const xmlChar *) "to") && xmlStrEqual(type, (const xmlChar *) "way")) { - restriction.toWay = atoi((const char*) ref); - } - if(xmlStrEqual(role, (const xmlChar *) "from") && xmlStrEqual(type, (const xmlChar *) "way")) { - restriction.fromWay = atoi((const char*) ref); - } - if(xmlStrEqual(role, (const xmlChar *) "via") && xmlStrEqual(type, (const xmlChar *) "node")) { - restriction.restriction.viaNode = atoi((const char*) ref); - } - - if(NULL != type) - xmlFree( type ); - if(NULL != role) - xmlFree( role ); - if(NULL != ref) - xmlFree( ref ); - } - } - xmlFree( childName ); - } - } - return restriction; - } - - _Way _ReadXMLWay( ) { - _Way way; - if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { - const int depth = xmlTextReaderDepth( inputReader ); - while ( xmlTextReaderRead( inputReader ) == 1 ) { - const int childType = xmlTextReaderNodeType( inputReader ); - if ( childType != 1 && childType != 15 ) - continue; - const int childDepth = xmlTextReaderDepth( inputReader ); - xmlChar* childName = xmlTextReaderName( inputReader ); - if ( childName == NULL ) - continue; - - if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "way" ) == 1 ) { - xmlChar* id = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" ); - way.id = atoi((char*)id); - xmlFree(id); - xmlFree( childName ); - break; - } - if ( childType != 1 ) { - xmlFree( childName ); - continue; - } - - if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { - xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" ); - xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" ); - // cout << "->k=" << k << ", v=" << value << endl; - if ( k != NULL && value != NULL ) { - - way.keyVals.Add(std::string( (char *) k ), std::string( (char *) value)); - } - if ( k != NULL ) - xmlFree( k ); - if ( value != NULL ) - xmlFree( value ); - } else if ( xmlStrEqual( childName, ( const xmlChar* ) "nd" ) == 1 ) { - xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" ); - if ( ref != NULL ) { - way.path.push_back( atoi(( const char* ) ref ) ); - xmlFree( ref ); - } - } - xmlFree( childName ); - } - } - return way; - } - - ImportNode _ReadXMLNode( ) { - ImportNode node; - - xmlChar* attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lat" ); - if ( attribute != NULL ) { - node.lat = static_cast(100000.*atof(( const char* ) attribute ) ); - xmlFree( attribute ); - } - attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lon" ); - if ( attribute != NULL ) { - node.lon = static_cast(100000.*atof(( const char* ) attribute )); - xmlFree( attribute ); - } - attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" ); - if ( attribute != NULL ) { - node.id = atoi(( const char* ) attribute ); - xmlFree( attribute ); - } - - if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) { - const int depth = xmlTextReaderDepth( inputReader ); - while ( xmlTextReaderRead( inputReader ) == 1 ) { - const int childType = xmlTextReaderNodeType( inputReader ); - // 1 = Element, 15 = EndElement - if ( childType != 1 && childType != 15 ) - continue; - const int childDepth = xmlTextReaderDepth( inputReader ); - xmlChar* childName = xmlTextReaderName( inputReader ); - if ( childName == NULL ) - continue; - - if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "node" ) == 1 ) { - xmlFree( childName ); - break; - } - if ( childType != 1 ) { - xmlFree( childName ); - continue; - } - - if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) { - xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" ); - xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" ); - if ( k != NULL && value != NULL ) { - node.keyVals.Add(std::string( reinterpret_cast(k) ), std::string( reinterpret_cast(value))); - } - if ( k != NULL ) - xmlFree( k ); - if ( value != NULL ) - xmlFree( value ); - } - - xmlFree( childName ); - } - } - return node; - } - /* Input Reader */ + _RawRestrictionContainer _ReadXMLRestriction(); + ExtractionWay _ReadXMLWay(); + ImportNode _ReadXMLNode(); xmlTextReaderPtr inputReader; - - //holds the callback functions and storage for our temporary data - ExtractorCallbacks * externalMemory; - - lua_State *myLuaState; }; #endif /* XMLPARSER_H_ */ diff --git a/Plugins/LocatePlugin.h b/Plugins/LocatePlugin.h index 39d83b345..c26e75fb6 100644 --- a/Plugins/LocatePlugin.h +++ b/Plugins/LocatePlugin.h @@ -52,12 +52,12 @@ public: //query to helpdesk _Coordinate result; - std::string JSONParameter, tmp; + std::string tmp; //json // JSONParameter = routeParameters.options.Find("jsonp"); if("" != routeParameters.jsonpParameter) { - reply.content += JSONParameter; + reply.content += routeParameters.jsonpParameter; reply.content += "("; } reply.status = http::Reply::ok; @@ -82,7 +82,7 @@ public: reply.content += ",\"transactionId\": \"OSRM Routing Engine JSON Locate (v0.3)\""; reply.content += ("}"); reply.headers.resize(3); - if("" != JSONParameter) { + if("" != routeParameters.jsonpParameter) { reply.content += ")"; reply.headers[1].name = "Content-Type"; reply.headers[1].value = "text/javascript"; diff --git a/Plugins/NearestPlugin.h b/Plugins/NearestPlugin.h index 53dc1bd51..c10230f6c 100644 --- a/Plugins/NearestPlugin.h +++ b/Plugins/NearestPlugin.h @@ -60,7 +60,6 @@ public: nodeHelpDesk->FindPhantomNodeForCoordinate(routeParameters.coordinates[0], result, routeParameters.zoomLevel); std::string tmp; - std::string JSONParameter; //json if("" != routeParameters.jsonpParameter) { @@ -93,7 +92,7 @@ public: reply.content += ",\"transactionId\":\"OSRM Routing Engine JSON Nearest (v0.3)\""; reply.content += ("}"); reply.headers.resize(3); - if("" != JSONParameter) { + if("" != routeParameters.jsonpParameter) { reply.content += ")"; reply.headers[1].name = "Content-Type"; reply.headers[1].value = "text/javascript"; diff --git a/Rakefile b/Rakefile index 727412797..a7c6ae809 100644 --- a/Rakefile +++ b/Rakefile @@ -7,6 +7,7 @@ require 'sys/proctable' DATA_FOLDER = 'sandbox' PROFILE = 'bicycle' OSRM_PORT = 5000 +PROFILES_FOLDER = '../profiles' Cucumber::Rake::Task.new do |t| t.cucumber_opts = %w{--format pretty} @@ -16,7 +17,7 @@ areas = { :kbh => { :country => 'denmark', :bbox => 'top=55.6972 left=12.5222 right=12.624 bottom=55.6376' }, :frd => { :country => 'denmark', :bbox => 'top=55.7007 left=12.4765 bottom=55.6576 right=12.5698' }, :regh => { :country => 'denmark', :bbox => 'top=56.164 left=11.792 bottom=55.403 right=12.731' }, - :dk => { :country => 'denmark', :bbox => nil }, + :denmark => { :country => 'denmark', :bbox => nil }, :skaane => { :country => 'sweden', :bbox => 'top=56.55 left=12.4 bottom=55.3 right=14.6' } } @@ -115,11 +116,25 @@ end desc "Reprocess OSM data." task :process => :setup do + Dir.chdir DATA_FOLDER do + raise "Error while extracting data." unless system "../osrm-extract #{osm_data_area_name}.osm.pbf #{PROFILES_FOLDER}/#{PROFILE}.lua" + puts + raise "Error while preparing data." unless system "../osrm-prepare #{osm_data_area_name}.osrm #{osm_data_area_name}.osrm.restrictions #{PROFILES_FOLDER}/#{PROFILE}.lua" + puts + end +end + +desc "Extract OSM data." +task :extract => :setup do Dir.chdir DATA_FOLDER do raise "Error while extracting data." unless system "../osrm-extract #{osm_data_area_name}.osm.pbf ../profiles/#{PROFILE}.lua" - puts + end +end + +desc "Prepare OSM data." +task :prepare => :setup do + Dir.chdir DATA_FOLDER do raise "Error while preparing data." unless system "../osrm-prepare #{osm_data_area_name}.osrm #{osm_data_area_name}.osrm.restrictions ../profiles/#{PROFILE}.lua" - puts end end diff --git a/RoutingAlgorithms/AlternativePathRouting.h b/RoutingAlgorithms/AlternativePathRouting.h index b55d1a9aa..4cd256b98 100644 --- a/RoutingAlgorithms/AlternativePathRouting.h +++ b/RoutingAlgorithms/AlternativePathRouting.h @@ -21,23 +21,25 @@ or see http://www.gnu.org/licenses/agpl.txt. #ifndef ALTERNATIVEROUTES_H_ #define ALTERNATIVEROUTES_H_ +#include +#include #include #include "BasicRoutingInterface.h" -const double VIAPATH_ALPHA = 0.25; -const double VIAPATH_EPSILON = 0.25; -const double VIAPATH_GAMMA = 0.80; +const double VIAPATH_ALPHA = 0.15; +const double VIAPATH_EPSILON = 0.10; //alternative at most 15% longer +const double VIAPATH_GAMMA = 0.75; //alternative shares at most 75% with the shortest. template -class AlternativeRouting : private BasicRoutingInterface{ +class AlternativeRouting : private BasicRoutingInterface { typedef BasicRoutingInterface super; - typedef std::pair PreselectedNode; - typedef typename QueryDataT::HeapPtr HeapPtr; - typedef std::pair UnpackEdge; + typedef typename QueryDataT::Graph SearchGraph; + typedef typename QueryDataT::QueryHeap QueryHeap; + typedef std::pair SearchSpaceEdge; struct RankedCandidateNode { - RankedCandidateNode(NodeID n, int l, int s) : node(n), length(l), sharing(s) {} + RankedCandidateNode(const NodeID n, const int l, const int s) : node(n), length(l), sharing(s) {} NodeID node; int length; int sharing; @@ -45,9 +47,12 @@ class AlternativeRouting : private BasicRoutingInterface{ return (2*length + sharing) < (2*other.length + other.sharing); } }; + + const SearchGraph * search_graph; + public: - AlternativeRouting(QueryDataT & qd) : super(qd) { } + AlternativeRouting(QueryDataT & qd) : super(qd), search_graph(qd.graph) { } ~AlternativeRouting() {} @@ -59,81 +64,115 @@ public: std::vector alternativePath; std::vector viaNodeCandidates; - std::vector packedShortestPath; - std::vector nodesThatPassPreselection; + std::vector forward_search_space; + std::vector reverse_search_space; - HeapPtr & forwardHeap = super::_queryData.forwardHeap; - HeapPtr & backwardHeap = super::_queryData.backwardHeap; - HeapPtr & forwardHeap2 = super::_queryData.forwardHeap2; - HeapPtr & backwardHeap2 = super::_queryData.backwardHeap2; - - //Initialize Queues + //Initialize Queues, semi-expensive because access to TSS invokes a system call super::_queryData.InitializeOrClearFirstThreadLocalStorage(); - int _upperBound = INT_MAX; - NodeID middle = UINT_MAX; - forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); + super::_queryData.InitializeOrClearSecondThreadLocalStorage(); + super::_queryData.InitializeOrClearThirdThreadLocalStorage(); + + QueryHeap & forward_heap1 = *(super::_queryData.forwardHeap); + QueryHeap & reverse_heap1 = *(super::_queryData.backwardHeap); + QueryHeap & forward_heap2 = *(super::_queryData.forwardHeap2); + QueryHeap & reverse_heap2 = *(super::_queryData.backwardHeap2); + + int upper_bound_to_shortest_path_distance = INT_MAX; + NodeID middle_node = UINT_MAX; + forward_heap1.Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); if(phantomNodePair.startPhantom.isBidirected() ) { - forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); + forward_heap1.Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); } - backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode); + reverse_heap1.Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode); if(phantomNodePair.targetPhantom.isBidirected() ) { - backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1); + reverse_heap1.Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1); } - const int offset = (phantomNodePair.startPhantom.isBidirected() ? std::max(phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.weight2) : phantomNodePair.startPhantom.weight1) - + (phantomNodePair.targetPhantom.isBidirected() ? std::max(phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.weight2) : phantomNodePair.targetPhantom.weight1); + const int forward_offset = phantomNodePair.startPhantom.weight1 + (phantomNodePair.startPhantom.isBidirected() ? phantomNodePair.startPhantom.weight2 : 0); + const int reverse_offset = phantomNodePair.targetPhantom.weight1 + (phantomNodePair.targetPhantom.isBidirected() ? phantomNodePair.targetPhantom.weight2 : 0); //exploration dijkstra from nodes s and t until deletemin/(1+epsilon) > _lengthOfShortestPath - while(forwardHeap->Size() + backwardHeap->Size() > 0){ - if(forwardHeap->Size() > 0){ - AlternativeRoutingStep(forwardHeap, backwardHeap, &middle, &_upperBound, 2*offset, true, viaNodeCandidates); + while(0 < (forward_heap1.Size() + reverse_heap1.Size())){ + if(0 < forward_heap1.Size()){ + AlternativeRoutingStep(forward_heap1, reverse_heap1, &middle_node, &upper_bound_to_shortest_path_distance, viaNodeCandidates, forward_search_space, forward_offset); } - if(backwardHeap->Size() > 0){ - AlternativeRoutingStep(backwardHeap, forwardHeap, &middle, &_upperBound, 2*offset, false, viaNodeCandidates); + if(0 < reverse_heap1.Size()){ + AlternativeRoutingStep(reverse_heap1, forward_heap1, &middle_node, &upper_bound_to_shortest_path_distance, viaNodeCandidates, reverse_search_space, reverse_offset); } } - std::sort(viaNodeCandidates.begin(), viaNodeCandidates.end()); - int size = std::unique(viaNodeCandidates.begin(), viaNodeCandidates.end())- viaNodeCandidates.begin(); - viaNodeCandidates.resize(size); + sort_unique_resize(viaNodeCandidates); - //save (packed) shortest path of shortest path and keep it for later use. - //we need it during the checks and dont want to recompute it always - super::RetrievePackedPathFromHeap(forwardHeap, backwardHeap, middle, packedShortestPath); + std::vector packed_forward_path; + std::vector packed_reverse_path; - //ch-pruning of via nodes in both search spaces + super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path); + super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path); + boost::unordered_map approximated_forward_sharing; + boost::unordered_map approximated_reverse_sharing; + + unsigned index_into_forward_path = 0; + //sweep over search space, compute forward sharing for each current edge (u,v) + BOOST_FOREACH(const SearchSpaceEdge & current_edge, forward_search_space) { + const NodeID u = current_edge.first; + const NodeID v = current_edge.second; + if(packed_forward_path.size() < index_into_forward_path && current_edge == forward_search_space[index_into_forward_path]) { + //current_edge is on shortest path => sharing(u):=queue.GetKey(u); + ++index_into_forward_path; + approximated_forward_sharing[v] = forward_heap1.GetKey(u); + } else { + //sharing (s) = sharing (t) + approximated_forward_sharing[v] = approximated_forward_sharing[u]; + } + } + + unsigned index_into_reverse_path = 0; + //sweep over search space, compute backward sharing + BOOST_FOREACH(const SearchSpaceEdge & current_edge, reverse_search_space) { + const NodeID u = current_edge.first; + const NodeID v = current_edge.second; + if(packed_reverse_path.size() < index_into_reverse_path && current_edge == reverse_search_space[index_into_reverse_path]) { + //current_edge is on shortest path => sharing(u):=queue.GetKey(u); + ++index_into_reverse_path; + approximated_reverse_sharing[v] = reverse_heap1.GetKey(u); + } else { + //sharing (s) = sharing (t) + approximated_reverse_sharing[v] = approximated_reverse_sharing[u]; + } + } + std::vector nodes_that_passed_preselection; BOOST_FOREACH(const NodeID node, viaNodeCandidates) { - if(node == middle) //subpath optimality tells us that this case is just the shortest path - continue; + int approximated_sharing = approximated_forward_sharing[node] + approximated_reverse_sharing[node]; + int approximated_length = forward_heap1.GetKey(node)+reverse_heap1.GetKey(node); + bool lengthPassed = (approximated_length < upper_bound_to_shortest_path_distance*(1+VIAPATH_EPSILON)); + bool sharingPassed = (approximated_sharing <= upper_bound_to_shortest_path_distance*VIAPATH_GAMMA); + bool stretchPassed = approximated_length - approximated_sharing < (1.+VIAPATH_EPSILON)*(upper_bound_to_shortest_path_distance-approximated_sharing); - int sharing = approximateAmountOfSharing(node, forwardHeap, backwardHeap, packedShortestPath); - int length1 = forwardHeap->GetKey(node); - int length2 = backwardHeap->GetKey(node); - bool lengthPassed = (length1+length2 < _upperBound*(1+VIAPATH_EPSILON)); - bool sharingPassed = (sharing <= _upperBound*VIAPATH_GAMMA); - bool stretchPassed = length1+length2 - sharing < (1.+VIAPATH_EPSILON)*(_upperBound-sharing); - - if(lengthPassed && sharingPassed && stretchPassed) - nodesThatPassPreselection.push_back(std::make_pair(node, length1+length2)); + if(lengthPassed && sharingPassed && stretchPassed) { + nodes_that_passed_preselection.push_back(node); + } } + std::vector & packedShortestPath = packed_forward_path; + std::reverse(packedShortestPath.begin(), packedShortestPath.end()); + packedShortestPath.push_back(middle_node); + packedShortestPath.insert(packedShortestPath.end(),packed_reverse_path.begin(), packed_reverse_path.end()); std::vector rankedCandidates; //prioritizing via nodes for deep inspection - BOOST_FOREACH(const PreselectedNode node, nodesThatPassPreselection) { + BOOST_FOREACH(const NodeID node, nodes_that_passed_preselection) { int lengthOfViaPath = 0, sharingOfViaPath = 0; - - computeLengthAndSharingOfViaPath(node, &lengthOfViaPath, &sharingOfViaPath, offset, packedShortestPath); - if(sharingOfViaPath <= VIAPATH_GAMMA*_upperBound) - rankedCandidates.push_back(RankedCandidateNode(node.first, lengthOfViaPath, sharingOfViaPath)); + computeLengthAndSharingOfViaPath(node, &lengthOfViaPath, &sharingOfViaPath, forward_offset+reverse_offset, packedShortestPath); + if(sharingOfViaPath <= upper_bound_to_shortest_path_distance*VIAPATH_GAMMA) { + rankedCandidates.push_back(RankedCandidateNode(node, lengthOfViaPath, sharingOfViaPath)); + } } - std::sort(rankedCandidates.begin(), rankedCandidates.end()); NodeID selectedViaNode = UINT_MAX; int lengthOfViaPath = INT_MAX; NodeID s_v_middle = UINT_MAX, v_t_middle = UINT_MAX; - BOOST_FOREACH(const RankedCandidateNode candidate, rankedCandidates){ - if(viaNodeCandidatePasses_T_Test(forwardHeap, backwardHeap, forwardHeap2, backwardHeap2, candidate, offset, _upperBound, &lengthOfViaPath, &s_v_middle, &v_t_middle)) { + BOOST_FOREACH(const RankedCandidateNode & candidate, rankedCandidates){ + if(viaNodeCandidatePasses_T_Test(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, candidate, forward_offset+reverse_offset, upper_bound_to_shortest_path_distance, &lengthOfViaPath, &s_v_middle, &v_t_middle)) { // select first admissable selectedViaNode = candidate.node; break; @@ -141,15 +180,15 @@ public: } //Unpack shortest path and alternative, if they exist - if(INT_MAX != _upperBound) { + if(INT_MAX != upper_bound_to_shortest_path_distance) { super::UnpackPath(packedShortestPath, rawRouteData.computedShortestPath); - rawRouteData.lengthOfShortestPath = _upperBound; + rawRouteData.lengthOfShortestPath = upper_bound_to_shortest_path_distance; } else { rawRouteData.lengthOfShortestPath = INT_MAX; } if(selectedViaNode != UINT_MAX) { - retrievePackedViaPath(forwardHeap, backwardHeap, forwardHeap2, backwardHeap2, s_v_middle, v_t_middle, rawRouteData.computedAlternativePath); + retrievePackedViaPath(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, s_v_middle, v_t_middle, rawRouteData.computedAlternativePath); rawRouteData.lengthOfAlternativePath = lengthOfViaPath; } else { rawRouteData.lengthOfAlternativePath = INT_MAX; @@ -158,7 +197,7 @@ public: private: //unpack by exploring search spaces from v - inline void retrievePackedViaPath(const HeapPtr & _forwardHeap1, const HeapPtr & _backwardHeap1, const HeapPtr & _forwardHeap2, const HeapPtr & _backwardHeap2, + inline void retrievePackedViaPath(QueryHeap & _forwardHeap1, QueryHeap & _backwardHeap1, QueryHeap & _forwardHeap2, QueryHeap & _backwardHeap2, const NodeID s_v_middle, const NodeID v_t_middle, std::vector<_PathData> & unpackedPath) { //unpack [s,v) std::vector packed_s_v_path, packed_v_t_path; @@ -170,16 +209,16 @@ private: super::UnpackPath(packed_s_v_path, unpackedPath); } - inline void computeLengthAndSharingOfViaPath(const PreselectedNode& node, int *lengthOfViaPath, int *sharingOfViaPath, - const int offset, const std::vector & packedShortestPath) { + inline void computeLengthAndSharingOfViaPath(const NodeID via_node, int *real_length_of_via_path, int *sharing_of_via_path, + const int offset, const std::vector & packed_shortest_path) { //compute and unpack and by exploring search spaces from v and intersecting against queues //only half-searches have to be done at this stage super::_queryData.InitializeOrClearSecondThreadLocalStorage(); - HeapPtr & existingForwardHeap = super::_queryData.forwardHeap; - HeapPtr & existingBackwardHeap = super::_queryData.backwardHeap; - HeapPtr & newForwardHeap = super::_queryData.forwardHeap2; - HeapPtr & newBackwardHeap = super::_queryData.backwardHeap2; + QueryHeap & existingForwardHeap = *super::_queryData.forwardHeap; + QueryHeap & existingBackwardHeap = *super::_queryData.backwardHeap; + QueryHeap & newForwardHeap = *super::_queryData.forwardHeap2; + QueryHeap & newBackwardHeap = *super::_queryData.backwardHeap2; std::vector < NodeID > packed_s_v_path; std::vector < NodeID > packed_v_t_path; @@ -189,18 +228,18 @@ private: NodeID s_v_middle = UINT_MAX; int upperBoundFor_s_v_Path = INT_MAX;//compute path by reusing forward search from s - newBackwardHeap->Insert(node.first, 0, node.first); - while (newBackwardHeap->Size() > 0) { + newBackwardHeap.Insert(via_node, 0, via_node); + while (0 < newBackwardHeap.Size()) { super::RoutingStep(newBackwardHeap, existingForwardHeap, &s_v_middle, &upperBoundFor_s_v_Path, 2 * offset, false); } //compute path by reusing backward search from node t NodeID v_t_middle = UINT_MAX; int upperBoundFor_v_t_Path = INT_MAX; - newForwardHeap->Insert(node.first, 0, node.first); - while (newForwardHeap->Size() > 0) { + newForwardHeap.Insert(via_node, 0, via_node); + while (0 < newForwardHeap.Size() ) { super::RoutingStep(newForwardHeap, existingBackwardHeap, &v_t_middle, &upperBoundFor_v_t_Path, 2 * offset, true); } - *lengthOfViaPath = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path; + *real_length_of_via_path = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path; if(UINT_MAX == s_v_middle || UINT_MAX == v_t_middle) return; @@ -211,35 +250,35 @@ private: //partial unpacking, compute sharing //First partially unpack s-->v until paths deviate, note length of common path. - for (unsigned i = 0, lengthOfPackedPath = std::min( packed_s_v_path.size(), packedShortestPath.size()) - 1; (i < lengthOfPackedPath); ++i) { - if (packed_s_v_path[i] == packedShortestPath[i] && packed_s_v_path[i + 1] == packedShortestPath[i + 1]) { - typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]); - *sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance; + for (unsigned i = 0, lengthOfPackedPath = std::min( packed_s_v_path.size(), packed_shortest_path.size()) - 1; (i < lengthOfPackedPath); ++i) { + if (packed_s_v_path[i] == packed_shortest_path[i] && packed_s_v_path[i + 1] == packed_shortest_path[i + 1]) { + typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]); + *sharing_of_via_path += search_graph->GetEdgeData(edgeID).distance; } else { - if (packed_s_v_path[i] == packedShortestPath[i]) { + if (packed_s_v_path[i] == packed_shortest_path[i]) { super::UnpackEdge(packed_s_v_path[i], packed_s_v_path[i+1], partiallyUnpackedViaPath); - super::UnpackEdge(packedShortestPath[i], packedShortestPath[i+1], partiallyUnpackedShortestPath); + super::UnpackEdge(packed_shortest_path[i], packed_shortest_path[i+1], partiallyUnpackedShortestPath); break; } } } //traverse partially unpacked edge and note common prefix for (int i = 0, lengthOfPackedPath = std::min( partiallyUnpackedViaPath.size(), partiallyUnpackedShortestPath.size()) - 1; (i < lengthOfPackedPath) && (partiallyUnpackedViaPath[i] == partiallyUnpackedShortestPath[i] && partiallyUnpackedViaPath[i+1] == partiallyUnpackedShortestPath[i+1]); ++i) { - typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(partiallyUnpackedViaPath[i], partiallyUnpackedViaPath[i+1]); - *sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance; + typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection(partiallyUnpackedViaPath[i], partiallyUnpackedViaPath[i+1]); + *sharing_of_via_path += search_graph->GetEdgeData(edgeID).distance; } //Second, partially unpack v-->t in reverse order until paths deviate and note lengths int viaPathIndex = packed_v_t_path.size() - 1; - int shortestPathIndex = packedShortestPath.size() - 1; + int shortestPathIndex = packed_shortest_path.size() - 1; for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex ) { - if (packed_v_t_path[viaPathIndex - 1] == packedShortestPath[shortestPathIndex - 1] && packed_v_t_path[viaPathIndex] == packedShortestPath[shortestPathIndex]) { - typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( packed_v_t_path[viaPathIndex - 1], packed_v_t_path[viaPathIndex]); - *sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance; + if (packed_v_t_path[viaPathIndex - 1] == packed_shortest_path[shortestPathIndex - 1] && packed_v_t_path[viaPathIndex] == packed_shortest_path[shortestPathIndex]) { + typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection( packed_v_t_path[viaPathIndex - 1], packed_v_t_path[viaPathIndex]); + *sharing_of_via_path += search_graph->GetEdgeData(edgeID).distance; } else { - if (packed_v_t_path[viaPathIndex] == packedShortestPath[shortestPathIndex]) { + if (packed_v_t_path[viaPathIndex] == packed_shortest_path[shortestPathIndex]) { super::UnpackEdge(packed_v_t_path[viaPathIndex-1], packed_v_t_path[viaPathIndex], partiallyUnpackedViaPath); - super::UnpackEdge(packedShortestPath[shortestPathIndex-1] , packedShortestPath[shortestPathIndex], partiallyUnpackedShortestPath); + super::UnpackEdge(packed_shortest_path[shortestPathIndex-1] , packed_shortest_path[shortestPathIndex], partiallyUnpackedShortestPath); break; } } @@ -249,16 +288,16 @@ private: shortestPathIndex = partiallyUnpackedShortestPath.size() - 1; for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex) { if (partiallyUnpackedViaPath[viaPathIndex - 1] == partiallyUnpackedShortestPath[shortestPathIndex - 1] && partiallyUnpackedViaPath[viaPathIndex] == partiallyUnpackedShortestPath[shortestPathIndex]) { - typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( partiallyUnpackedViaPath[viaPathIndex - 1], partiallyUnpackedViaPath[viaPathIndex]); - *sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance; + typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection( partiallyUnpackedViaPath[viaPathIndex - 1], partiallyUnpackedViaPath[viaPathIndex]); + *sharing_of_via_path += search_graph->GetEdgeData(edgeID).distance; } else { break; } } - //finished partial unpacking spree! Amount of sharing is stored to appropriate poiner variable + //finished partial unpacking spree! Amount of sharing is stored to appropriate pointer variable } - inline int approximateAmountOfSharing(const NodeID middleNodeIDOfAlternativePath, HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const std::vector & packedShortestPath) { + inline int approximateAmountOfSharing(const NodeID middleNodeIDOfAlternativePath, QueryHeap & _forwardHeap, QueryHeap & _backwardHeap, const std::vector & packedShortestPath) { std::vector packedAlternativePath; super::RetrievePackedPathFromHeap(_forwardHeap, _backwardHeap, middleNodeIDOfAlternativePath, packedAlternativePath); @@ -270,8 +309,8 @@ private: //compute forward sharing while( (packedAlternativePath[aindex] == packedShortestPath[aindex]) && (packedAlternativePath[aindex+1] == packedShortestPath[aindex+1]) ) { // INFO("retrieving edge (" << packedAlternativePath[aindex] << "," << packedAlternativePath[aindex+1] << ")"); - typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex+1]); - sharing += super::_queryData.graph->GetEdgeData(edgeID).distance; + typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex+1]); + sharing += search_graph->GetEdgeData(edgeID).distance; ++aindex; } @@ -279,55 +318,65 @@ private: int bindex = packedShortestPath.size()-1; //compute backward sharing while( aindex > 0 && bindex > 0 && (packedAlternativePath[aindex] == packedShortestPath[bindex]) && (packedAlternativePath[aindex-1] == packedShortestPath[bindex-1]) ) { - typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex-1]); - sharing += super::_queryData.graph->GetEdgeData(edgeID).distance; + typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex-1]); + sharing += search_graph->GetEdgeData(edgeID).distance; --aindex; --bindex; } return sharing; } - inline void AlternativeRoutingStep(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, NodeID *middle, int *_upperbound, const int edgeBasedOffset, const bool forwardDirection, std::vector& searchSpaceIntersection) const { - const NodeID node = _forwardHeap->DeleteMin(); + template + inline void AlternativeRoutingStep( + QueryHeap & _forward_heap, + QueryHeap & _reverse_heap, + NodeID *middle_node, + int *upper_bound_to_shortest_path_distance, + std::vector& searchSpaceIntersection, + std::vector & search_space, + const int edgeBasedOffset + ) const { + const NodeID node = _forward_heap.DeleteMin(); + const int distance = _forward_heap.GetKey(node); + int scaledDistance = (distance-edgeBasedOffset)/(1.+VIAPATH_EPSILON); + if(scaledDistance > *upper_bound_to_shortest_path_distance){ + _forward_heap.DeleteAll(); + return; + } - const int distance = _forwardHeap->GetKey(node); - if(_backwardHeap->WasInserted(node) ){ + search_space.push_back(std::make_pair(_forward_heap.GetData( node ).parent, node)); + + if(_reverse_heap.WasInserted(node) ){ searchSpaceIntersection.push_back(node); - const int newDistance = _backwardHeap->GetKey(node) + distance; - if(newDistance < *_upperbound ){ + const int newDistance = _reverse_heap.GetKey(node) + distance; + if(newDistance < *upper_bound_to_shortest_path_distance ){ if(newDistance>=0 ) { - *middle = node; - *_upperbound = newDistance; + *middle_node = node; + *upper_bound_to_shortest_path_distance = newDistance; } } } - int scaledDistance = (distance-edgeBasedOffset)/(1.+VIAPATH_EPSILON); - if(scaledDistance > *_upperbound){ - _forwardHeap->DeleteAll(); - return; - } - - for ( typename QueryDataT::Graph::EdgeIterator edge = super::_queryData.graph->BeginEdges( node ); edge < super::_queryData.graph->EndEdges(node); edge++ ) { - const typename QueryDataT::Graph::EdgeData & data = super::_queryData.graph->GetEdgeData(edge); + for ( typename SearchGraph::EdgeIterator edge = search_graph->BeginEdges( node ); edge < search_graph->EndEdges(node); edge++ ) { + const typename SearchGraph::EdgeData & data = search_graph->GetEdgeData(edge); bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward ); if(forwardDirectionFlag) { - const NodeID to = super::_queryData.graph->GetTarget(edge); + const NodeID to = search_graph->GetTarget(edge); const int edgeWeight = data.distance; assert( edgeWeight > 0 ); const int toDistance = distance + edgeWeight; //New Node discovered -> Add to Heap + Node Info Storage - if ( !_forwardHeap->WasInserted( to ) ) { - _forwardHeap->Insert( to, toDistance, node ); + if ( !_forward_heap.WasInserted( to ) ) { + _forward_heap.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 < _forward_heap.GetKey( to ) ) { + _forward_heap.GetData( to ).parent = node; + _forward_heap.DecreaseKey( to, toDistance ); //new parent } } @@ -335,16 +384,17 @@ private: } //conduct T-Test - inline bool viaNodeCandidatePasses_T_Test( HeapPtr& existingForwardHeap, HeapPtr& existingBackwardHeap, HeapPtr& newForwardHeap, HeapPtr& newBackwardHeap, const RankedCandidateNode& candidate, const int offset, const int lengthOfShortestPath, int * lengthOfViaPath, NodeID * s_v_middle, NodeID * v_t_middle) { + inline bool viaNodeCandidatePasses_T_Test( QueryHeap& existingForwardHeap, QueryHeap& existingBackwardHeap, QueryHeap& newForwardHeap, QueryHeap& newBackwardHeap, const RankedCandidateNode& candidate, const int offset, const int lengthOfShortestPath, int * lengthOfViaPath, NodeID * s_v_middle, NodeID * v_t_middle) { + newForwardHeap.Clear(); + newBackwardHeap.Clear(); std::vector < NodeID > packed_s_v_path; std::vector < NodeID > packed_v_t_path; - super::_queryData.InitializeOrClearSecondThreadLocalStorage(); *s_v_middle = UINT_MAX; int upperBoundFor_s_v_Path = INT_MAX; //compute path by reusing forward search from s - newBackwardHeap->Insert(candidate.node, 0, candidate.node); - while (newBackwardHeap->Size() > 0) { + newBackwardHeap.Insert(candidate.node, 0, candidate.node); + while (newBackwardHeap.Size() > 0) { super::RoutingStep(newBackwardHeap, existingForwardHeap, s_v_middle, &upperBoundFor_s_v_Path, 2*offset, false); } @@ -354,8 +404,8 @@ private: //compute path by reusing backward search from t *v_t_middle = UINT_MAX; int upperBoundFor_v_t_Path = INT_MAX; - newForwardHeap->Insert(candidate.node, 0, candidate.node); - while (newForwardHeap->Size() > 0) { + newForwardHeap.Insert(candidate.node, 0, candidate.node); + while (newForwardHeap.Size() > 0) { super::RoutingStep(newForwardHeap, existingBackwardHeap, v_t_middle, &upperBoundFor_v_t_Path, 2*offset, true); } @@ -369,14 +419,21 @@ private: super::RetrievePackedPathFromHeap(newForwardHeap, existingBackwardHeap, *v_t_middle, packed_v_t_path); NodeID s_P = *s_v_middle, t_P = *v_t_middle; + if(UINT_MAX == s_P) { + return false; + } + + if(UINT_MAX == t_P) { + return false; + } const int T_threshold = VIAPATH_EPSILON * lengthOfShortestPath; int unpackedUntilDistance = 0; - std::stack unpackStack; + std::stack unpackStack; //Traverse path s-->v for (unsigned i = packed_s_v_path.size() - 1; (i > 0) && unpackStack.empty(); --i) { - typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( packed_s_v_path[i - 1], packed_s_v_path[i]); - int lengthOfCurrentEdge = super::_queryData.graph->GetEdgeData(edgeID).distance; + typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection( packed_s_v_path[i - 1], packed_s_v_path[i]); + int lengthOfCurrentEdge = search_graph->GetEdgeData(edgeID).distance; if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) { unpackStack.push(std::make_pair(packed_s_v_path[i - 1], packed_s_v_path[i])); } else { @@ -386,17 +443,17 @@ private: } while (!unpackStack.empty()) { - const UnpackEdge viaPathEdge = unpackStack.top(); + const SearchSpaceEdge viaPathEdge = unpackStack.top(); unpackStack.pop(); - typename QueryDataT::Graph::EdgeIterator edgeIDInViaPath = super::_queryData.graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second); + typename SearchGraph::EdgeIterator edgeIDInViaPath = search_graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second); if(UINT_MAX == edgeIDInViaPath) return false; - typename QueryDataT::Graph::EdgeData currentEdgeData = super::_queryData.graph->GetEdgeData(edgeIDInViaPath); + typename SearchGraph::EdgeData currentEdgeData = search_graph->GetEdgeData(edgeIDInViaPath); bool IsViaEdgeShortCut = currentEdgeData.shortcut; if (IsViaEdgeShortCut) { const NodeID middleOfViaPath = currentEdgeData.id; - typename QueryDataT::Graph::EdgeIterator edgeIDOfSecondSegment = super::_queryData.graph->FindEdgeInEitherDirection(middleOfViaPath, viaPathEdge.second); - int lengthOfSecondSegment = super::_queryData.graph->GetEdgeData(edgeIDOfSecondSegment).distance; + typename SearchGraph::EdgeIterator edgeIDOfSecondSegment = search_graph->FindEdgeInEitherDirection(middleOfViaPath, viaPathEdge.second); + int lengthOfSecondSegment = search_graph->GetEdgeData(edgeIDOfSecondSegment).distance; //attention: !unpacking in reverse! //Check if second segment is the one to go over treshold? if yes add second segment to stack, else push first segment to stack and add distance of second one. if (unpackedUntilDistance + lengthOfSecondSegment >= T_threshold) { @@ -416,8 +473,8 @@ private: unpackedUntilDistance = 0; //Traverse path s-->v for (unsigned i = 0, lengthOfPackedPath = packed_v_t_path.size() - 1; (i < lengthOfPackedPath) && unpackStack.empty(); ++i) { - typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( packed_v_t_path[i], packed_v_t_path[i + 1]); - int lengthOfCurrentEdge = super::_queryData.graph->GetEdgeData(edgeID).distance; + typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection( packed_v_t_path[i], packed_v_t_path[i + 1]); + int lengthOfCurrentEdge = search_graph->GetEdgeData(edgeID).distance; if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) { unpackStack.push( std::make_pair(packed_v_t_path[i], packed_v_t_path[i + 1])); } else { @@ -427,17 +484,17 @@ private: } while (!unpackStack.empty()) { - const UnpackEdge viaPathEdge = unpackStack.top(); + const SearchSpaceEdge viaPathEdge = unpackStack.top(); unpackStack.pop(); - typename QueryDataT::Graph::EdgeIterator edgeIDInViaPath = super::_queryData.graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second); + typename SearchGraph::EdgeIterator edgeIDInViaPath = search_graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second); if(UINT_MAX == edgeIDInViaPath) return false; - typename QueryDataT::Graph::EdgeData currentEdgeData = super::_queryData.graph->GetEdgeData(edgeIDInViaPath); + typename SearchGraph::EdgeData currentEdgeData = search_graph->GetEdgeData(edgeIDInViaPath); const bool IsViaEdgeShortCut = currentEdgeData.shortcut; if (IsViaEdgeShortCut) { const NodeID middleOfViaPath = currentEdgeData.id; - typename QueryDataT::Graph::EdgeIterator edgeIDOfFirstSegment = super::_queryData.graph->FindEdgeInEitherDirection(viaPathEdge.first, middleOfViaPath); - int lengthOfFirstSegment = super::_queryData.graph->GetEdgeData( edgeIDOfFirstSegment).distance; + typename SearchGraph::EdgeIterator edgeIDOfFirstSegment = search_graph->FindEdgeInEitherDirection(viaPathEdge.first, middleOfViaPath); + int lengthOfFirstSegment = search_graph->GetEdgeData( edgeIDOfFirstSegment).distance; //Check if first segment is the one to go over treshold? if yes first segment to stack, else push second segment to stack and add distance of first one. if (unpackedUntilDistance + lengthOfFirstSegment >= T_threshold) { unpackStack.push( std::make_pair(viaPathEdge.first, middleOfViaPath)); @@ -454,20 +511,21 @@ private: lengthOfPathT_Test_Path += unpackedUntilDistance; //Run actual T-Test query and compare if distances equal. - HeapPtr& forwardHeap = super::_queryData.forwardHeap3; - HeapPtr& backwardHeap = super::_queryData.backwardHeap3; super::_queryData.InitializeOrClearThirdThreadLocalStorage(); + + QueryHeap& forward_heap3 = *super::_queryData.forwardHeap3; + QueryHeap& backward_heap3 = *super::_queryData.backwardHeap3; int _upperBound = INT_MAX; NodeID middle = UINT_MAX; - forwardHeap->Insert(s_P, 0, s_P); - backwardHeap->Insert(t_P, 0, t_P); + forward_heap3.Insert(s_P, 0, s_P); + backward_heap3.Insert(t_P, 0, t_P); //exploration from s and t until deletemin/(1+epsilon) > _lengthOfShortestPath - while (forwardHeap->Size() + backwardHeap->Size() > 0) { - if (forwardHeap->Size() > 0) { - super::RoutingStep(forwardHeap, backwardHeap, &middle, &_upperBound, offset, true); + while (forward_heap3.Size() + backward_heap3.Size() > 0) { + if (forward_heap3.Size() > 0) { + super::RoutingStep(forward_heap3, backward_heap3, &middle, &_upperBound, offset, true); } - if (backwardHeap->Size() > 0) { - super::RoutingStep(backwardHeap, forwardHeap, &middle, &_upperBound, offset, false); + if (backward_heap3.Size() > 0) { + super::RoutingStep(backward_heap3, forward_heap3, &middle, &_upperBound, offset, false); } } return (_upperBound <= lengthOfPathT_Test_Path); diff --git a/RoutingAlgorithms/BasicRoutingInterface.h b/RoutingAlgorithms/BasicRoutingInterface.h index bbe0474e4..f329c697b 100644 --- a/RoutingAlgorithms/BasicRoutingInterface.h +++ b/RoutingAlgorithms/BasicRoutingInterface.h @@ -23,43 +23,43 @@ or see http://www.gnu.org/licenses/agpl.txt. #ifndef BASICROUTINGINTERFACE_H_ #define BASICROUTINGINTERFACE_H_ +#include + #include #include #include "../Plugins/RawRouteData.h" +#include "../Util/ContainerUtils.h" template -class BasicRoutingInterface { +class BasicRoutingInterface : boost::noncopyable{ protected: QueryDataT & _queryData; public: BasicRoutingInterface(QueryDataT & qd) : _queryData(qd) { } virtual ~BasicRoutingInterface(){ }; - inline void RoutingStep(typename QueryDataT::HeapPtr & _forwardHeap, typename QueryDataT::HeapPtr & _backwardHeap, NodeID *middle, int *_upperbound, const int edgeBasedOffset, const bool forwardDirection) const { - const NodeID node = _forwardHeap->DeleteMin(); - const int distance = _forwardHeap->GetKey(node); -// INFO((forwardDirection ? "[forw]" : "[back]") << " settled node " << node << " at distance " << distance); - if(_backwardHeap->WasInserted(node) ){ -// INFO((forwardDirection ? "[forw]" : "[back]") << " scanned node " << node << " in both directions, upper bound: " << *_upperbound); - const int newDistance = _backwardHeap->GetKey(node) + distance; + inline void RoutingStep(typename QueryDataT::QueryHeap & _forwardHeap, typename QueryDataT::QueryHeap & _backwardHeap, NodeID *middle, int *_upperbound, const int edgeBasedOffset, const bool forwardDirection) const { + const NodeID node = _forwardHeap.DeleteMin(); + const int distance = _forwardHeap.GetKey(node); + if(_backwardHeap.WasInserted(node) ){ + const int newDistance = _backwardHeap.GetKey(node) + distance; if(newDistance < *_upperbound ){ if(newDistance>=0 ) { -// INFO((forwardDirection ? "[forw]" : "[back]") << " -> node " << node << " is new middle at total distance " << newDistance); *middle = node; *_upperbound = newDistance; } else { -// INFO((forwardDirection ? "[forw]" : "[back]") << " -> ignored " << node << " as new middle at total distance " << newDistance); } } } if(distance-edgeBasedOffset > *_upperbound){ - _forwardHeap->DeleteAll(); + _forwardHeap.DeleteAll(); return; } - for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); edge++ ) { + //Stalling + for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); ++edge ) { const typename QueryDataT::Graph::EdgeData & data = _queryData.graph->GetEdgeData(edge); bool backwardDirectionFlag = (!forwardDirection) ? data.forward : data.backward; if(backwardDirectionFlag) { @@ -68,16 +68,15 @@ public: assert( edgeWeight > 0 ); - //Stalling - if(_forwardHeap->WasInserted( to )) { - if(_forwardHeap->GetKey( to ) + edgeWeight < distance) { + if(_forwardHeap.WasInserted( to )) { + if(_forwardHeap.GetKey( to ) + edgeWeight < distance) { return; } } } } - for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); edge++ ) { + for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); ++edge ) { const typename QueryDataT::Graph::EdgeData & data = _queryData.graph->GetEdgeData(edge); bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward ); if(forwardDirectionFlag) { @@ -89,23 +88,20 @@ public: const int toDistance = distance + edgeWeight; //New Node discovered -> Add to Heap + Node Info Storage - if ( !_forwardHeap->WasInserted( to ) ) { - // INFO((forwardDirection ? "[forw]" : "[back]") << " scanning edge (" << node << "," << to << ") with distance " << toDistance << ", edge length: " << data.distance); - _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 ) ) { - // INFO((forwardDirection ? "[forw]" : "[back]") << " decrease and scanning edge (" << node << "," << to << ") from " << _forwardHeap->GetKey(to) << "to " << toDistance << ", edge length: " << data.distance); - _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 } } } } - inline void UnpackPath(std::vector & packedPath, std::vector<_PathData> & unpackedPath) const { - + inline void UnpackPath(const std::vector & packedPath, std::vector<_PathData> & unpackedPath) const { const unsigned sizeOfPackedPath = packedPath.size(); std::stack > recursionStack; @@ -118,15 +114,12 @@ public: while(!recursionStack.empty()) { edge = recursionStack.top(); recursionStack.pop(); -// INFO("Unpacking edge (" << edge.first << "," << edge.second << ")"); typename QueryDataT::Graph::EdgeIterator smallestEdge = SPECIAL_EDGEID; int smallestWeight = INT_MAX; for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.first);eit < _queryData.graph->EndEdges(edge.first);++eit){ const int weight = _queryData.graph->GetEdgeData(eit).distance; -// INFO("Checking edge (" << edge.first << "/" << _queryData.graph->GetTarget(eit) << ")"); if(_queryData.graph->GetTarget(eit) == edge.second && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).forward){ -// INFO("1smallest " << eit << ", " << weight); smallestEdge = eit; smallestWeight = weight; } @@ -135,9 +128,7 @@ public: if(smallestEdge == SPECIAL_EDGEID){ for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.second);eit < _queryData.graph->EndEdges(edge.second);++eit){ const int weight = _queryData.graph->GetEdgeData(eit).distance; -// INFO("Checking edge (" << edge.first << "/" << _queryData.graph->GetTarget(eit) << ")"); if(_queryData.graph->GetTarget(eit) == edge.first && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).backward){ -// INFO("2smallest " << eit << ", " << weight); smallestEdge = eit; smallestWeight = weight; } @@ -159,7 +150,6 @@ public: } inline void UnpackEdge(const NodeID s, const NodeID t, std::vector & unpackedPath) const { - std::stack > recursionStack; recursionStack.push(std::make_pair(s,t)); @@ -193,7 +183,6 @@ public: if(ed.shortcut) {//unpack const NodeID middle = ed.id; //again, we need to this in reversed order -// INFO("unpacking (" << middle << "," << edge.second << ") and (" << edge.first << "," << middle << ")"); recursionStack.push(std::make_pair(middle, edge.second)); recursionStack.push(std::make_pair(edge.first, middle)); } else { @@ -204,22 +193,29 @@ public: unpackedPath.push_back(t); } - inline void RetrievePackedPathFromHeap(const typename QueryDataT::HeapPtr & _fHeap, const typename QueryDataT::HeapPtr & _bHeap, const NodeID middle, std::vector& packedPath) { + inline void RetrievePackedPathFromHeap(typename QueryDataT::QueryHeap & _fHeap, typename QueryDataT::QueryHeap & _bHeap, const NodeID middle, std::vector& packedPath) const { NodeID pathNode = middle; - while(pathNode != _fHeap->GetData(pathNode).parent) { - pathNode = _fHeap->GetData(pathNode).parent; + while(pathNode != _fHeap.GetData(pathNode).parent) { + pathNode = _fHeap.GetData(pathNode).parent; packedPath.push_back(pathNode); } std::reverse(packedPath.begin(), packedPath.end()); - packedPath.push_back(middle); pathNode = middle; - while (pathNode != _bHeap->GetData(pathNode).parent){ - pathNode = _bHeap->GetData(pathNode).parent; + while (pathNode != _bHeap.GetData(pathNode).parent){ + pathNode = _bHeap.GetData(pathNode).parent; packedPath.push_back(pathNode); } } + + inline void RetrievePackedPathFromSingleHeap(typename QueryDataT::QueryHeap & search_heap, const NodeID middle, std::vector& packed_path) const { + NodeID pathNode = middle; + while(pathNode != search_heap.GetData(pathNode).parent) { + pathNode = search_heap.GetData(pathNode).parent; + packed_path.push_back(pathNode); + } + } }; diff --git a/RoutingAlgorithms/ShortestPathRouting.h b/RoutingAlgorithms/ShortestPathRouting.h index 6fc4c5996..66d374079 100644 --- a/RoutingAlgorithms/ShortestPathRouting.h +++ b/RoutingAlgorithms/ShortestPathRouting.h @@ -28,13 +28,14 @@ or see http://www.gnu.org/licenses/agpl.txt. template class ShortestPathRouting : public BasicRoutingInterface{ typedef BasicRoutingInterface super; + typedef typename QueryDataT::QueryHeap QueryHeap; public: - ShortestPathRouting(QueryDataT & qd) : super(qd) {} + ShortestPathRouting( QueryDataT & qd) : super(qd) {} ~ShortestPathRouting() {} - void operator()(std::vector & phantomNodesVector, RawRouteData & rawRouteData) { - BOOST_FOREACH(PhantomNodes & phantomNodePair, phantomNodesVector) { + void operator()(std::vector & phantomNodesVector, RawRouteData & rawRouteData) const { + BOOST_FOREACH(const PhantomNodes & phantomNodePair, phantomNodesVector) { if(!phantomNodePair.AtLeastOnePhantomNodeIsUINTMAX()) { rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX; return; @@ -43,125 +44,102 @@ public: int distance1 = 0; int distance2 = 0; - bool searchFrom1stStartNode(true); - bool searchFrom2ndStartNode(true); - NodeID middle1 = ( NodeID ) UINT_MAX; - NodeID middle2 = ( NodeID ) UINT_MAX; + bool searchFrom1stStartNode = true; + bool searchFrom2ndStartNode = true; + NodeID middle1 = UINT_MAX; + NodeID middle2 = UINT_MAX; std::vector packedPath1; std::vector packedPath2; - typename QueryDataT::HeapPtr & forwardHeap = super::_queryData.forwardHeap; - typename QueryDataT::HeapPtr & backwardHeap = super::_queryData.backwardHeap; - - typename QueryDataT::HeapPtr & forwardHeap2 = super::_queryData.forwardHeap2; - typename QueryDataT::HeapPtr & backwardHeap2 = super::_queryData.backwardHeap2; + super::_queryData.InitializeOrClearFirstThreadLocalStorage(); + super::_queryData.InitializeOrClearSecondThreadLocalStorage(); + super::_queryData.InitializeOrClearThirdThreadLocalStorage(); + QueryHeap & forward_heap1 = *(super::_queryData.forwardHeap); + QueryHeap & reverse_heap1 = *(super::_queryData.backwardHeap); + QueryHeap & forward_heap2 = *(super::_queryData.forwardHeap2); + QueryHeap & reverse_heap2 = *(super::_queryData.backwardHeap2); //Get distance to next pair of target nodes. - BOOST_FOREACH(PhantomNodes & phantomNodePair, phantomNodesVector) { - super::_queryData.InitializeOrClearFirstThreadLocalStorage(); - super::_queryData.InitializeOrClearSecondThreadLocalStorage(); - + BOOST_FOREACH(const PhantomNodes & phantomNodePair, phantomNodesVector) { + forward_heap1.Clear(); forward_heap2.Clear(); + reverse_heap1.Clear(); reverse_heap2.Clear(); int _localUpperbound1 = INT_MAX; int _localUpperbound2 = INT_MAX; + middle1 = UINT_MAX; + middle2 = UINT_MAX; + //insert new starting nodes into forward heap, adjusted by previous distances. if(searchFrom1stStartNode) { - forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); - forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); -// INFO("a 1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode << " with weight " << phantomNodePair.startPhantom.weight1); -// } else { -// INFO("Skipping first start node"); + forward_heap1.Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); + forward_heap2.Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); } if(phantomNodePair.startPhantom.isBidirected() && searchFrom2ndStartNode) { - forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); - forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); -// INFO("b 1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode+1 << " with weight " << -phantomNodePair.startPhantom.weight1); -// } else if(!searchFrom2ndStartNode) { -// INFO("Skipping second start node"); + forward_heap1.Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); + forward_heap2.Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); } -// backwardHeap->Clear(); -// backwardHeap2->Clear(); //insert new backward nodes into backward heap, unadjusted. - backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode); -// INFO("1) back insert " << phantomNodePair.targetPhantom.edgeBasedNode << " with weight " << phantomNodePair.targetPhantom.weight1); + reverse_heap1.Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode); if(phantomNodePair.targetPhantom.isBidirected() ) { -// INFO("2) back insert " << phantomNodePair.targetPhantom.edgeBasedNode+1 << " with weight " << phantomNodePair.targetPhantom.weight2); - backwardHeap2->Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1); + reverse_heap2.Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1); } - int offset = (phantomNodePair.startPhantom.isBidirected() ? std::max(phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.weight2) : phantomNodePair.startPhantom.weight1) ; - offset += (phantomNodePair.targetPhantom.isBidirected() ? std::max(phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.weight2) : phantomNodePair.targetPhantom.weight1) ; + const int forward_offset = phantomNodePair.startPhantom.weight1 + (phantomNodePair.startPhantom.isBidirected() ? phantomNodePair.startPhantom.weight2 : 0); + const int reverse_offset = phantomNodePair.targetPhantom.weight1 + (phantomNodePair.targetPhantom.isBidirected() ? phantomNodePair.targetPhantom.weight2 : 0); //run two-Target Dijkstra routing step. - while(forwardHeap->Size() + backwardHeap->Size() > 0){ - if(forwardHeap->Size() > 0){ - super::RoutingStep(forwardHeap, backwardHeap, &middle1, &_localUpperbound1, 2*offset, true); + while(0 < (forward_heap1.Size() + reverse_heap1.Size() )){ + if(0 < forward_heap1.Size()){ + super::RoutingStep(forward_heap1, reverse_heap1, &middle1, &_localUpperbound1, forward_offset, true); } - if(backwardHeap->Size() > 0){ - super::RoutingStep(backwardHeap, forwardHeap, &middle1, &_localUpperbound1, 2*offset, false); + if(0 < reverse_heap1.Size() ){ + super::RoutingStep(reverse_heap1, forward_heap1, &middle1, &_localUpperbound1, reverse_offset, false); } } - if(backwardHeap2->Size() > 0) { - while(forwardHeap2->Size() + backwardHeap2->Size() > 0){ - if(forwardHeap2->Size() > 0){ - super::RoutingStep(forwardHeap2, backwardHeap2, &middle2, &_localUpperbound2, 2*offset, true); + if(0 < reverse_heap2.Size()) { + while(0 < (forward_heap2.Size() + reverse_heap2.Size() )){ + if(0 < forward_heap2.Size()){ + super::RoutingStep(forward_heap2, reverse_heap2, &middle2, &_localUpperbound2, forward_offset, true); } - if(backwardHeap2->Size() > 0){ - super::RoutingStep(backwardHeap2, forwardHeap2, &middle2, &_localUpperbound2, 2*offset, false); + if(0 < reverse_heap2.Size()){ + super::RoutingStep(reverse_heap2, forward_heap2, &middle2, &_localUpperbound2, reverse_offset, false); } } } -// INFO("upperbound1: " << _localUpperbound1 << ", distance1: " << distance1); -// INFO("upperbound2: " << _localUpperbound2 << ", distance2: " << distance2); //No path found for both target nodes? - if(INT_MAX == _localUpperbound1 && INT_MAX == _localUpperbound2) { + if((INT_MAX == _localUpperbound1) && (INT_MAX == _localUpperbound2)) { rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX; return; } if(UINT_MAX == middle1) { searchFrom1stStartNode = false; -// INFO("Next Search will not start from 1st"); - } else { -// INFO("Next Search will start from 1st"); - searchFrom1stStartNode = true; } if(UINT_MAX == middle2) { searchFrom2ndStartNode = false; -// INFO("Next Search will not start from 2nd"); - } else { - searchFrom2ndStartNode = true; -// INFO("Next Search will start from 2nd"); } //Was at most one of the two paths not found? assert(!(INT_MAX == distance1 && INT_MAX == distance2)); -// INFO("middle1: " << middle1); - //Unpack paths if they exist std::vector temporaryPackedPath1; std::vector temporaryPackedPath2; if(INT_MAX != _localUpperbound1) { - super::RetrievePackedPathFromHeap(forwardHeap, backwardHeap, middle1, temporaryPackedPath1); -// INFO("temporaryPackedPath1 ends with " << *(temporaryPackedPath1.end()-1) ); + super::RetrievePackedPathFromHeap(forward_heap1, reverse_heap1, middle1, temporaryPackedPath1); } -// INFO("middle2: " << middle2); if(INT_MAX != _localUpperbound2) { - super::RetrievePackedPathFromHeap(forwardHeap2, backwardHeap2, middle2, temporaryPackedPath2); -// INFO("temporaryPackedPath2 ends with " << *(temporaryPackedPath2.end()-1) ); + super::RetrievePackedPathFromHeap(forward_heap2, reverse_heap2, middle2, temporaryPackedPath2); } //if one of the paths was not found, replace it with the other one. if(0 == temporaryPackedPath1.size()) { -// INFO("Deleting path 1"); temporaryPackedPath1.insert(temporaryPackedPath1.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end()); _localUpperbound1 = _localUpperbound2; } if(0 == temporaryPackedPath2.size()) { -// INFO("Deleting path 2"); temporaryPackedPath2.insert(temporaryPackedPath2.end(), temporaryPackedPath1.begin(), temporaryPackedPath1.end()); _localUpperbound2 = _localUpperbound1; } @@ -170,28 +148,21 @@ public: //Plug paths together, s.t. end of packed path is begin of temporary packed path if(0 < packedPath1.size() && 0 < packedPath2.size() ) { -// INFO("Both paths are non-empty"); if( *(temporaryPackedPath1.begin()) == *(temporaryPackedPath2.begin())) { -// INFO("both paths start with the same node:" << *(temporaryPackedPath1.begin())); //both new route segments start with the same node, thus one of the packedPath must go. assert( (packedPath1.size() == packedPath2.size() ) || (*(packedPath1.end()-1) != *(packedPath2.end()-1)) ); if( *(packedPath1.end()-1) == *(temporaryPackedPath1.begin())) { -// INFO("Deleting packedPath2 that ends with " << *(packedPath2.end()-1) << ", other ends with " << *(packedPath1.end()-1)); packedPath2.clear(); packedPath2.insert(packedPath2.end(), packedPath1.begin(), packedPath1.end()); distance2 = distance1; -// INFO("packedPath2 now ends with " << *(packedPath2.end()-1)); } else { -// INFO("Deleting path1 that ends with " << *(packedPath1.end()-1) << ", other ends with " << *(packedPath2.end()-1)); packedPath1.clear(); packedPath1.insert(packedPath1.end(), packedPath2.begin(), packedPath2.end()); distance1 = distance2; -// INFO("Path1 now ends with " << *(packedPath1.end()-1)); } } else { //packed paths 1 and 2 may need to switch. if(*(packedPath1.end()-1) != *(temporaryPackedPath1.begin())) { -// INFO("Switching"); packedPath1.swap(packedPath2); std::swap(distance1, distance2); } @@ -201,61 +172,24 @@ public: packedPath2.insert(packedPath2.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end()); if( (packedPath1.back() == packedPath2.back()) && phantomNodePair.targetPhantom.isBidirected() ) { -// INFO("both paths end in same direction on bidirected edge, make sure start only start with : " << packedPath1.back()); NodeID lastNodeID = packedPath2.back(); searchFrom1stStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode+1); searchFrom2ndStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode); -// INFO("Next search from node " << phantomNodePair.targetPhantom.edgeBasedNode << ": " << (searchFrom1stStartNode ? "yes" : "no") ); -// INFO("Next search from node " << phantomNodePair.targetPhantom.edgeBasedNode+1 << ": " << (searchFrom2ndStartNode ? "yes" : "no") ); } distance1 += _localUpperbound1; distance2 += _localUpperbound2; } -// INFO("length path1: " << distance1); -// INFO("length path2: " << distance2); - if(distance1 <= distance2){ - //remove consecutive duplicates -// std::cout << "unclean 1: "; -// for(unsigned i = 0; i < packedPath1.size(); ++i) -// std::cout << packedPath1[i] << " "; -// std::cout << std::endl; - -// std::cout << "cleaned 1: "; -// for(unsigned i = 0; i < packedPath1.size(); ++i) -// std::cout << packedPath1[i] << " "; -// std::cout << std::endl; -// super::UnpackPath(packedPath1, rawRouteData.computedShortestPath); - } else { + if(distance1 > distance2){ std::swap(packedPath1, packedPath2); -// std::cout << "unclean 2: "; -// for(unsigned i = 0; i < packedPath2.size(); ++i) -// std::cout << packedPath2[i] << " "; -// std::cout << std::endl; -// _RemoveConsecutiveDuplicatesFromContainer(packedPath2); -// std::cout << "cleaned 2: "; -// for(unsigned i = 0; i < packedPath2.size(); ++i) -// std::cout << packedPath2[i] << " "; -// std::cout << std::endl; -// super::UnpackPath(packedPath2, unpackedPath); } - _RemoveConsecutiveDuplicatesFromContainer(packedPath1); + remove_consecutive_duplicates_from_vector(packedPath1); super::UnpackPath(packedPath1, rawRouteData.computedShortestPath); rawRouteData.lengthOfShortestPath = std::min(distance1, distance2); -// INFO("Found via route with distance " << std::min(distance1, distance2)); return; } -private: - template - void _RemoveConsecutiveDuplicatesFromContainer(ContainerT & packedPath) { - //remove consecutive duplicates - typename ContainerT::iterator it; - // using default comparison: - it = std::unique(packedPath.begin(), packedPath.end()); - packedPath.resize(it - packedPath.begin()); - } }; #endif /* SHORTESTPATHROUTING_H_ */ diff --git a/SConstruct b/SConstruct index 2f09e53aa..83e70de89 100644 --- a/SConstruct +++ b/SConstruct @@ -87,7 +87,7 @@ if "clang" in env["CXX"]: if GetOption('allflags') is not None: env.Append(CXXFLAGS = ["-W#warnings", "-Wc++0x-compat", "-Waddress-of-temporary", "-Wambiguous-member-template", "-Warray-bounds", "-Watomic-properties", "-Wbind-to-temporary-copy", "-Wbuiltin-macro-redefined", "-Wc++-compat", "-Wc++0x-extensions", "-Wcomments", "-Wconditional-uninitialized", "-Wconstant-logical-operand", "-Wdeclaration-after-statement", "-Wdeprecated", "-Wdeprecated-implementations", "-Wdeprecated-writable-strings", "-Wduplicate-method-arg", "-Wempty-body", "-Wendif-labels", "-Wenum-compare", "-Wformat=2", "-Wfour-char-constants", "-Wgnu", "-Wincomplete-implementation", "-Winvalid-noreturn", "-Winvalid-offsetof", "-Winvalid-token-paste", "-Wlocal-type-template-args", "-Wmethod-signatures", "-Wmicrosoft", "-Wmissing-declarations", "-Wnon-pod-varargs", "-Wnonfragile-abi2", "-Wnull-dereference", "-Wout-of-line-declaration", "-Woverlength-strings", "-Wpacked", "-Wpointer-arith", "-Wpointer-sign", "-Wprotocol", "-Wreadonly-setter-attrs", "-Wselector", "-Wshift-overflow", "-Wshift-sign-overflow", "-Wstrict-selector-match", "-Wsuper-class-method-mismatch", "-Wtautological-compare", "-Wtypedef-redefinition", "-Wundeclared-selector", "-Wunnamed-type-template-args", "-Wunused-exception-parameter", "-Wunused-member-function", "-Wused-but-marked-unused", "-Wvariadic-macros"]) else: - env.Append(CCFLAGS = ['-minline-all-stringops', '-fopenmp']) + env.Append(CCFLAGS = ['-minline-all-stringops', '-fopenmp', '-Wall']) env.Append(LINKFLAGS = '-fopenmp') if GetOption('buildconfiguration') == 'debug': diff --git a/Server/APIGrammar.h b/Server/APIGrammar.h index b24a1b206..3b8794185 100644 --- a/Server/APIGrammar.h +++ b/Server/APIGrammar.h @@ -33,7 +33,7 @@ template struct APIGrammar : qi::grammar { APIGrammar(HandlerT * h) : APIGrammar::base_type(api_call), handler(h) { api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >> *(query); - query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | cmp | language | instruction | alt_route | old_API) ) ; + query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | cmp | language | instruction | geometry | alt_route | old_API) ) ; zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)]; output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)]; diff --git a/Server/BasicDatastructures.h b/Server/BasicDatastructures.h index c01d5d34a..71e3ac996 100644 --- a/Server/BasicDatastructures.h +++ b/Server/BasicDatastructures.h @@ -21,8 +21,11 @@ or see http://www.gnu.org/licenses/agpl.txt. #ifndef BASIC_DATASTRUCTURES_H #define BASIC_DATASTRUCTURES_H #include +#include #include +#include "../Util/StringUtil.h" + namespace http { const std::string okString = "HTTP/1.0 200 OK\r\n"; @@ -70,15 +73,13 @@ struct Reply { std::vector HeaderstoBuffers(); std::string content; static Reply stockReply(status_type status); - void setSize(unsigned size) { - for (std::size_t i = 0; i < headers.size(); ++i) { - Header& h = headers[i]; - if("Content-Length" == h.name) { - std::stringstream sizeString; - sizeString << size; - h.value = sizeString.str(); - } - } + void setSize(const unsigned size) { + BOOST_FOREACH ( Header& h, headers) { + if("Content-Length" == h.name) { + std::string sizeString; + intToString(size,h.value ); + } + } } }; @@ -138,11 +139,13 @@ Reply Reply::stockReply(Reply::status_type status) { Reply rep; rep.status = status; rep.content = ToString(status); - rep.headers.resize(2); - rep.headers[0].name = "Content-Length"; - rep.headers[0].value = boost::lexical_cast(rep.content.size()); - rep.headers[1].name = "Content-Type"; - rep.headers[1].value = "text/html"; + rep.headers.resize(3); + rep.headers[0].name = "Access-Control-Allow-Origin"; + rep.headers[0].value = "*"; + rep.headers[1].name = "Content-Length"; + rep.headers[1].value = boost::lexical_cast(rep.content.size()); + rep.headers[2].name = "Content-Type"; + rep.headers[2].value = "text/html"; return rep; } } // namespace http diff --git a/Server/Connection.h b/Server/Connection.h index ea1ebd933..5dd4b7913 100644 --- a/Server/Connection.h +++ b/Server/Connection.h @@ -30,7 +30,6 @@ or see http://www.gnu.org/licenses/agpl.txt. #include #include -#include "../DataStructures/Util.h" #include "BasicDatastructures.h" #include "RequestHandler.h" #include "RequestParser.h" diff --git a/Server/RequestHandler.h b/Server/RequestHandler.h index 35036a6ba..c801b7971 100644 --- a/Server/RequestHandler.h +++ b/Server/RequestHandler.h @@ -33,6 +33,7 @@ or see http://www.gnu.org/licenses/agpl.txt. #include "../DataStructures/HashTable.h" #include "../Plugins/BasePlugin.h" #include "../Plugins/RouteParameters.h" +#include "../Util/StringUtil.h" #include "../typedefs.h" namespace http { @@ -71,16 +72,17 @@ public: bool result = boost::spirit::qi::parse(it, request.end(), apiParser); // returns true if successful if (!result || (it != request.end()) ) { rep = http::Reply::stockReply(http::Reply::badRequest); - std::stringstream content; int position = std::distance(request.begin(), it); - content << "Input seems to be malformed close to position " << position << "
"; - content << "
";
-                content << req.uri << "
"; + std::string tmp_position_string; + intToString(position, tmp_position_string); + rep.content += "Input seems to be malformed close to position "; + rep.content += "
";
+                rep.content += request;
+                rep.content += tmp_position_string;
+                rep.content += "
"; for(unsigned i = 0, end = std::distance(request.begin(), it); i < end; ++i) - content << " "; - content << "^" << "
"; - content << "
"; - rep.content += content.str(); + rep.content += " "; + rep.content += "^
"; } else { //Finished parsing, lets call the right plugin to handle the request if(pluginMap.Holds(routeParameters.service)) { diff --git a/Util/ContainerUtils.h b/Util/ContainerUtils.h new file mode 100644 index 000000000..215e9885c --- /dev/null +++ b/Util/ContainerUtils.h @@ -0,0 +1,34 @@ +/* + * ContainerUtils.h + * + * Created on: 02.02.2013 + * Author: dennis + */ + +#ifndef CONTAINERUTILS_H_ +#define CONTAINERUTILS_H_ + +#include +#include + +template +inline void sort_unique_resize(std::vector & vector) { + std::sort(vector.begin(), vector.end()); + unsigned number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin(); + vector.resize(number_of_unique_elements); +} + +template +inline void sort_unique_resize_shrink_vector(std::vector & vector) { + sort_unique_resize(vector); + std::vector().swap(vector); +} + +template +inline void remove_consecutive_duplicates_from_vector(std::vector & vector) { + unsigned number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin(); + vector.resize(number_of_unique_elements); +} + + +#endif /* CONTAINERUTILS_H_ */ diff --git a/Util/GraphLoader.h b/Util/GraphLoader.h index ef04f8d8f..40bc98a9c 100644 --- a/Util/GraphLoader.h +++ b/Util/GraphLoader.h @@ -101,7 +101,7 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &in, std::vector& edgeL short type; NodeID nameID; int length; - bool isRoundabout, ignoreInGrid, isAccessRestricted; + bool isRoundabout, ignoreInGrid, isAccessRestricted, isContraFlow; for (EdgeID i=0; i& edgeL in.read((char*)&isRoundabout, sizeof(bool)); in.read((char*)&ignoreInGrid, sizeof(bool)); in.read((char*)&isAccessRestricted, sizeof(bool)); + in.read((char*)&isContraFlow, sizeof(bool)); GUARANTEE(length > 0, "loaded null length edge" ); GUARANTEE(weight > 0, "loaded null weight"); @@ -150,7 +151,7 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &in, std::vector& edgeL std::swap(forward, backward); } - EdgeT inputEdge(source, target, nameID, weight, forward, backward, type, isRoundabout, ignoreInGrid, isAccessRestricted ); + EdgeT inputEdge(source, target, nameID, weight, forward, backward, type, isRoundabout, ignoreInGrid, isAccessRestricted, isContraFlow ); edgeList.push_back(inputEdge); } std::sort(edgeList.begin(), edgeList.end()); @@ -169,14 +170,14 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &in, std::vector& edgeL edgeList[i]._source = UINT_MAX; } else { //edge i-1 is open in both directions, but edge i is smaller in one direction. Close edge i-1 in this direction - edgeList[i-1].forward = ~edgeList[i].isForward(); - edgeList[i-1].backward = ~edgeList[i].isBackward(); + edgeList[i-1].forward = !edgeList[i].isForward(); + edgeList[i-1].backward = !edgeList[i].isBackward(); } } else if (edgeFlagsAreSuperSet2) { if(edgeList[i-1].weight() <= edgeList[i].weight()) { //edge i-1 is smaller for one direction. edge i is open in both. close edge i in the other direction - edgeList[i].forward = ~edgeList[i-1].isForward(); - edgeList[i].backward = ~edgeList[i-1].isBackward(); + edgeList[i].forward = !edgeList[i-1].isForward(); + edgeList[i].backward = !edgeList[i-1].isBackward(); } else { //edge i is smaller and goes in both direction. Throw away edge i-1 edgeList[i-1]._source = UINT_MAX; diff --git a/Util/LuaUtil.h b/Util/LuaUtil.h new file mode 100644 index 000000000..fadf78d6f --- /dev/null +++ b/Util/LuaUtil.h @@ -0,0 +1,52 @@ +/* + 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 LUAUTIL_H_ +#define LUAUTIL_H_ + +#include +#include +#include + +template +void LUA_print(T number) { + std::cout << "[LUA] " << number << std::endl; +} + +// Check if the lua function is defined +inline bool lua_function_exists(lua_State* lua_state, const char* name) { + luabind::object g = luabind::globals(lua_state); + luabind::object func = g[name]; + return func && (luabind::type(func) == LUA_TFUNCTION); +} + +// Add the folder contain the script to the lua load path, so script can easily require() other lua scripts inside that folder, or subfolders. +// See http://lua-users.org/wiki/PackagePath for details on the package.path syntax. +inline void luaAddScriptFolderToLoadPath(lua_State* myLuaState, const char* fileName) { + const boost::filesystem::path profilePath( fileName ); + std::string folder = profilePath.parent_path().string(); + //TODO: This code is most probably not Windows safe since it uses UNIX'ish path delimiters + const std::string luaCode = "package.path = \"" + folder + "/?.lua;profiles/?.lua;\" .. package.path"; + luaL_dostring( myLuaState, luaCode.c_str() ); +} + +#endif /* LUAUTIL_H_ */ diff --git a/Util/MachineInfo.h b/Util/MachineInfo.h index 2849071a0..7c0f31c3b 100644 --- a/Util/MachineInfo.h +++ b/Util/MachineInfo.h @@ -30,8 +30,29 @@ extern "C" { #include #endif -/* Returns the physical memory size in kilobytes */ -unsigned GetPhysicalmemory(void){ +enum Endianness { + LittleEndian = 1, + BigEndian = 2 +}; + +//Function is optimized to a single 'mov eax,1' on GCC, clang and icc using -O3 +inline Endianness getMachineEndianness() { + int i(1); + char *p = (char *) &i; + if (1 == p[0]) + return LittleEndian; + return BigEndian; +} + +// Reverses Network Byte Order into something usable, compiles down to a bswap-mov combination +inline unsigned swapEndian(unsigned x) { + if(getMachineEndianness() == LittleEndian) + return ( (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24) ); + return x; +} + +// Returns the physical memory size in kilobytes +inline unsigned GetPhysicalmemory(void){ #if defined(SUN5) || defined(__linux__) return (sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)); @@ -61,4 +82,5 @@ unsigned GetPhysicalmemory(void){ #endif } -#endif +#endif // MACHINE_INFO_H + diff --git a/Util/StringUtil.h b/Util/StringUtil.h index 32e147c1f..b09ac166a 100644 --- a/Util/StringUtil.h +++ b/Util/StringUtil.h @@ -21,14 +21,14 @@ or see http://www.gnu.org/licenses/agpl.txt. #ifndef STRINGUTIL_H_ #define STRINGUTIL_H_ -#include -#include #include -#include +#include #include #include +#include + #include "../DataStructures/Coordinate.h" #include "../typedefs.h" @@ -80,6 +80,20 @@ static inline int stringToInt(const std::string& input) { return value; } +static inline void doubleToString(const double value, std::string & output){ + output.clear(); + std::back_insert_iterator sink(output); + boost::spirit::karma::generate(sink, boost::spirit::karma::double_, value); +} + +static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string & output){ + // The largest 32-bit integer is 4294967295, that is 10 chars + // On the safe side, add 1 for sign, and 1 for trailing zero + char buffer[12] ; + sprintf(buffer, "%g", value) ; + output = buffer ; +} + static inline void convertInternalLatLonToString(const int value, std::string & output) { char buffer[100]; buffer[10] = 0; // Nullterminierung @@ -106,70 +120,38 @@ static inline void convertInternalReversedCoordinateToString(const _Coordinate & output += " "; } -static inline void doubleToString(const double value, std::string & output){ - // The largest 32-bit integer is 4294967295, that is 10 chars - // On the safe side, add 1 for sign, and 1 for trailing zero - char buffer[12] ; - sprintf(buffer, "%f", value) ; - output = buffer ; -} - -static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string & output){ - // The largest 32-bit integer is 4294967295, that is 10 chars - // On the safe side, add 1 for sign, and 1 for trailing zero - char buffer[12] ; - sprintf(buffer, "%g", value) ; - output = buffer ; -} - -inline std::string & replaceAll(std::string &s, const std::string &sub, const std::string &other) { - assert(!sub.empty()); - size_t b = 0; - for (;;) { - b = s.find(sub, b); - if (b == s.npos) break; - s.replace(b, sub.size(), other); - b += other.size(); - } - return s; +inline void replaceAll(std::string &s, const std::string &sub, const std::string &other) { + boost::replace_all(s, sub, other); } inline void stringSplit(const std::string &s, const char delim, std::vector& result) { - std::stringstream ss(s); - std::string item; - while(std::getline(ss, item, delim)) { - if(item.size() > 0) - result.push_back(item); - } + boost::split(result, s, boost::is_any_of(std::string(&delim))); } - static std::string originals[] = {"&", "\"", "<", ">", "'", "[", "]", "\\"}; static std::string entities[] = {"&", """, "<", ">", "'", "&91;", "&93;", " \" }; -inline std::string HTMLEntitize( std::string result) { - for(unsigned i = 0; i < sizeof(originals)/sizeof(std::string); i++) { - result = replaceAll(result, originals[i], entities[i]); +inline std::string HTMLEntitize( const std::string & input) { + std::string result(input); + for(unsigned i = 0; i < sizeof(originals)/sizeof(std::string); ++i) { + replaceAll(result, originals[i], entities[i]); } return result; } -inline std::string HTMLDeEntitize( std::string result) { - for(unsigned i = 0; i < sizeof(originals)/sizeof(std::string); i++) { - result = replaceAll(result, entities[i], originals[i]); +inline std::string HTMLDeEntitize( std::string & result) { + for(unsigned i = 0; i < sizeof(originals)/sizeof(std::string); ++i) { + replaceAll(result, entities[i], originals[i]); } return result; } -inline bool StringStartsWith(std::string & input, std::string & prefix) { - return (input.find(prefix) == 0); +inline bool StringStartsWith(const std::string & input, const std::string & prefix) { + return boost::starts_with(input, prefix); } - -/* - * Function returns a 'random' filename in temporary directors. - * May not be platform independent. - */ +// Function returns a 'random' filename in temporary directors. +// May not be platform independent. inline void GetTemporaryFileName(std::string & filename) { char buffer[L_tmpnam]; char * retPointer = tmpnam (buffer); diff --git a/createHierarchy.cpp b/createHierarchy.cpp index 5d7f13d32..7156cef32 100644 --- a/createHierarchy.cpp +++ b/createHierarchy.cpp @@ -44,12 +44,11 @@ extern "C" { #include "DataStructures/NNGrid.h" #include "DataStructures/QueryEdge.h" #include "Util/BaseConfiguration.h" -#include "Util/InputFileUtil.h" #include "Util/GraphLoader.h" +#include "Util/InputFileUtil.h" +#include "Util/LuaUtil.h" #include "Util/StringUtil.h" -using namespace std; - typedef QueryEdge::EdgeData EdgeData; typedef DynamicGraph::InputEdge InputEdge; typedef StaticGraph::InputEdge StaticEdge; @@ -59,6 +58,7 @@ std::vector internalToExternalNodeMapping; std::vector<_Restriction> inputRestrictions; std::vector bollardNodes; std::vector trafficLightNodes; +std::vector edgeList; int main (int argc, char *argv[]) { if(argc < 3) { @@ -76,7 +76,7 @@ int main (int argc, char *argv[]) { omp_set_num_threads(numberOfThreads); INFO("Using restrictions from file: " << argv[2]); - std::ifstream restrictionsInstream(argv[2], ios::binary); + std::ifstream restrictionsInstream(argv[2], std::ios::binary); if(!restrictionsInstream.good()) { ERR("Could not access files"); } @@ -93,12 +93,11 @@ int main (int argc, char *argv[]) { ERR("Cannot open " << argv[1]); } - char nodeOut[1024]; strcpy(nodeOut, argv[1]); strcat(nodeOut, ".nodes"); - char edgeOut[1024]; strcpy(edgeOut, argv[1]); strcat(edgeOut, ".edges"); - char graphOut[1024]; strcpy(graphOut, argv[1]); strcat(graphOut, ".hsgr"); - char ramIndexOut[1024]; strcpy(ramIndexOut, argv[1]); strcat(ramIndexOut, ".ramIndex"); - char fileIndexOut[1024]; strcpy(fileIndexOut, argv[1]); strcat(fileIndexOut, ".fileIndex"); - char levelInfoOut[1024]; strcpy(levelInfoOut, argv[1]); strcat(levelInfoOut, ".levels"); + std::string nodeOut(argv[1]); nodeOut += ".nodes"; + std::string edgeOut(argv[1]); edgeOut += ".edges"; + std::string graphOut(argv[1]); graphOut += ".hsgr"; + std::string ramIndexOut(argv[1]); ramIndexOut += ".ramIndex"; + std::string fileIndexOut(argv[1]); fileIndexOut += ".fileIndex"; /*** Setup Scripting Environment ***/ if(!testDataFile( (argc > 3 ? argv[3] : "profile.lua") )) { @@ -111,6 +110,11 @@ int main (int argc, char *argv[]) { // Connect LuaBind to this lua state luabind::open(myLuaState); + //open utility libraries string library; + luaL_openlibs(myLuaState); + + //adjust lua load path + luaAddScriptFolderToLoadPath( myLuaState, (argc > 3 ? argv[3] : "profile.lua") ); // Now call our function in a lua script INFO("Parsing speedprofile from " << (argc > 3 ? argv[3] : "profile.lua") ); @@ -129,8 +133,9 @@ int main (int argc, char *argv[]) { ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block"); } speedProfile.uTurnPenalty = 10*lua_tointeger(myLuaState, -1); - - + + speedProfile.has_turn_penalty_function = lua_function_exists( myLuaState, "turn_function" ); + std::vector edgeList; NodeID nodeBasedNodeNumber = readBinaryOSRMGraphFromStream(in, edgeList, bollardNodes, trafficLightNodes, &internalToExternalNodeMapping, inputRestrictions); in.close(); @@ -146,34 +151,27 @@ int main (int argc, char *argv[]) { INFO("Generating edge-expanded graph representation"); EdgeBasedGraphFactory * edgeBasedGraphFactory = new EdgeBasedGraphFactory (nodeBasedNodeNumber, edgeList, bollardNodes, trafficLightNodes, inputRestrictions, internalToExternalNodeMapping, speedProfile); std::vector().swap(edgeList); - edgeBasedGraphFactory->Run(edgeOut); + edgeBasedGraphFactory->Run(edgeOut.c_str(), myLuaState); std::vector<_Restriction>().swap(inputRestrictions); std::vector().swap(bollardNodes); std::vector().swap(trafficLightNodes); NodeID edgeBasedNodeNumber = edgeBasedGraphFactory->GetNumberOfNodes(); DeallocatingVector edgeBasedEdgeList; edgeBasedGraphFactory->GetEdgeBasedEdges(edgeBasedEdgeList); + DeallocatingVector nodeBasedEdgeList; + edgeBasedGraphFactory->GetEdgeBasedNodes(nodeBasedEdgeList); + delete edgeBasedGraphFactory; /*** * Writing info on original (node-based) nodes */ INFO("writing node map ..."); - std::ofstream mapOutFile(nodeOut, std::ios::binary); + std::ofstream mapOutFile(nodeOut.c_str(), std::ios::binary); mapOutFile.write((char *)&(internalToExternalNodeMapping[0]), internalToExternalNodeMapping.size()*sizeof(NodeInfo)); mapOutFile.close(); std::vector().swap(internalToExternalNodeMapping); - /*** - * Writing info on original (node-based) edges - */ - INFO("writing info on original edges"); - std::vector originalEdgeData; - edgeBasedGraphFactory->GetOriginalEdgeData(originalEdgeData); - - DeallocatingVector nodeBasedEdgeList; - edgeBasedGraphFactory->GetEdgeBasedNodes(nodeBasedEdgeList); - delete edgeBasedGraphFactory; double expansionHasFinishedTime = get_timestamp() - startupTime; /*** @@ -182,7 +180,7 @@ int main (int argc, char *argv[]) { INFO("building grid ..."); WritableGrid * writeableGrid = new WritableGrid(); - writeableGrid->ConstructGrid(nodeBasedEdgeList, ramIndexOut, fileIndexOut); + writeableGrid->ConstructGrid(nodeBasedEdgeList, ramIndexOut.c_str(), fileIndexOut.c_str()); delete writeableGrid; IteratorbasedCRC32 > crc32; unsigned crc32OfNodeBasedEdgeList = crc32(nodeBasedEdgeList.begin(), nodeBasedEdgeList.end() ); @@ -208,13 +206,13 @@ int main (int argc, char *argv[]) { */ INFO("Building Node Array"); - sort(contractedEdgeList.begin(), contractedEdgeList.end()); + std::sort(contractedEdgeList.begin(), contractedEdgeList.end()); unsigned numberOfNodes = 0; unsigned numberOfEdges = contractedEdgeList.size(); INFO("Serializing compacted graph"); - ofstream edgeOutFile(graphOut, ios::binary); + std::ofstream edgeOutFile(graphOut.c_str(), std::ios::binary); - BOOST_FOREACH(QueryEdge & edge, contractedEdgeList) { + BOOST_FOREACH(const QueryEdge & edge, contractedEdgeList) { if(edge.source > numberOfNodes) { numberOfNodes = edge.source; } diff --git a/extractor.cpp b/extractor.cpp index c7b6decb2..4912c9b67 100644 --- a/extractor.cpp +++ b/extractor.cpp @@ -32,6 +32,7 @@ or see http://www.gnu.org/licenses/agpl.txt. #include "Util/BaseConfiguration.h" #include "Util/InputFileUtil.h" #include "Util/MachineInfo.h" +#include "Util/OpenMPWrapper.h" #include "Util/StringUtil.h" typedef BaseConfiguration ExtractorConfiguration; @@ -39,6 +40,8 @@ typedef BaseConfiguration ExtractorConfiguration; ExtractorCallbacks * extractCallBacks; int main (int argc, char *argv[]) { + double earliestTime = get_timestamp(); + if(argc < 2) { ERR("usage: \n" << argv[0] << " []"); } @@ -55,7 +58,6 @@ int main (int argc, char *argv[]) { } omp_set_num_threads(numberOfThreads); - INFO("extracting data from input file " << argv[1]); bool isPBF(false); std::string outputFileName(argv[1]); @@ -67,12 +69,12 @@ int main (int argc, char *argv[]) { isPBF = true; } } - if(pos!=string::npos) { + if(pos!=std::string::npos) { outputFileName.replace(pos, 8, ".osrm"); restrictionsFileName.replace(pos, 8, ".osrm.restrictions"); } else { pos=outputFileName.find(".osm"); - if(pos!=string::npos) { + if(pos!=std::string::npos) { outputFileName.replace(pos, 5, ".osrm"); restrictionsFileName.replace(pos, 5, ".osrm.restrictions"); } else { @@ -90,30 +92,30 @@ int main (int argc, char *argv[]) { StringMap stringMap; ExtractionContainers externalMemory; - stringMap[""] = 0; extractCallBacks = new ExtractorCallbacks(&externalMemory, &stringMap); - BaseParser * parser; + BaseParser* parser; if(isPBF) { - parser = new PBFParser(argv[1]); + parser = new PBFParser(argv[1], extractCallBacks, scriptingEnvironment); } else { - parser = new XMLParser(argv[1]); + parser = new XMLParser(argv[1], extractCallBacks, scriptingEnvironment); } - parser->RegisterCallbacks(extractCallBacks); - parser->RegisterScriptingEnvironment(scriptingEnvironment); - - if(!parser->Init()) + + if(!parser->ReadHeader()) { ERR("Parser not initialized!"); + } + INFO("Parsing in progress.."); double time = get_timestamp(); parser->Parse(); - INFO("parsing finished after " << get_timestamp() - time << " seconds"); + INFO("Parsing finished after " << get_timestamp() - time << " seconds"); externalMemory.PrepareData(outputFileName, restrictionsFileName, amountOfRAM); stringMap.clear(); delete parser; delete extractCallBacks; - INFO("finished"); + INFO("finished after " << get_timestamp() - earliestTime << "s"); + std::cout << "\nRun:\n" "./osrm-prepare " << outputFileName << " " << restrictionsFileName << std::endl; return 0; diff --git a/features/bicycle/access.feature b/features/bicycle/access.feature index 149a2743c..cb1fc0d0b 100644 --- a/features/bicycle/access.feature +++ b/features/bicycle/access.feature @@ -1,5 +1,5 @@ @routing @bicycle @access -Feature: Bike - Restricted access +Feature: Bike - Access tags on ways Reference: http://wiki.openstreetmap.org/wiki/Key:access Background: @@ -7,37 +7,95 @@ Reference: http://wiki.openstreetmap.org/wiki/Key:access Scenario: Bike - Access tag hierachy on ways Then routability should be - | access | vehicle | bicycle | bothw | - | | | | x | - | yes | | | x | - | no | | | | - | | yes | | x | - | | no | | | - | no | yes | | x | - | yes | no | | | - | | | yes | x | - | | | no | | - | no | | yes | x | - | yes | | no | | - | | no | yes | x | - | | yes | no | | + | highway | access | vehicle | bicycle | bothw | + | | | | | x | + | | yes | | | x | + | | no | | | | + | | | yes | | x | + | | | no | | | + | | no | yes | | x | + | | yes | no | | | + | | | | yes | x | + | | | | no | | + | | no | | yes | x | + | | yes | | no | | + | | | no | yes | x | + | | | yes | no | | + | runway | | | | | + | runway | yes | | | x | + | runway | no | | | | + | runway | | yes | | x | + | runway | | no | | | + | runway | no | yes | | x | + | runway | yes | no | | | + | runway | | | yes | x | + | runway | | | no | | + | runway | no | | yes | x | + | runway | yes | | no | | + | runway | | no | yes | x | + | runway | | yes | no | | - Scenario: Bike - Access tag hierachy on nodes - Then routability should be - | node/access | node/vehicle | node/bicycle | bothw | - | | | | x | - | yes | | | x | - | no | | | | - | | yes | | x | - | | no | | | - | no | yes | | x | - | yes | no | | | - | | | yes | x | - | | | no | | - | no | | yes | x | - | yes | | no | | - | | no | yes | x | - | | yes | no | | + @todo + Scenario: Bike - Access tag in forward direction + Then routability should be + | highway | access:forward | vehicle:forward | bicycle:forward | forw | backw | + | | | | | x | | + | | yes | | | x | | + | | no | | | | | + | | | yes | | x | | + | | | no | | | | + | | no | yes | | x | | + | | yes | no | | | | + | | | | yes | x | | + | | | | no | | | + | | no | | yes | x | | + | | yes | | no | | | + | | | no | yes | x | | + | | | yes | no | | | + | runway | | | | x | | + | runway | yes | | | x | | + | runway | no | | | | | + | runway | | yes | | x | | + | runway | | no | | | | + | runway | no | yes | | x | | + | runway | yes | no | | | | + | runway | | | yes | x | | + | runway | | | no | | | + | runway | no | | yes | x | | + | runway | yes | | no | | | + | runway | | no | yes | x | | + | runway | | yes | no | | | + + @todo + Scenario: Bike - Access tag in backward direction + Then routability should be + | highway | access:forward | vehicle:forward | bicycle:forward | forw | backw | + | | | | | | x | + | | yes | | | | x | + | | no | | | | | + | | | yes | | | x | + | | | no | | | | + | | no | yes | | | x | + | | yes | no | | | | + | | | | yes | | x | + | | | | no | | | + | | no | | yes | | x | + | | yes | | no | | | + | | | no | yes | | x | + | | | yes | no | | | + | runway | | | | | x | + | runway | yes | | | | x | + | runway | no | | | | | + | runway | | yes | | | x | + | runway | | no | | | | + | runway | no | yes | | | x | + | runway | yes | no | | | | + | runway | | | yes | | x | + | runway | | | no | | | + | runway | no | | yes | | x | + | runway | yes | | no | | | + | runway | | no | yes | | x | + | runway | | yes | no | | | Scenario: Bike - Overwriting implied acccess on ways Then routability should be @@ -51,18 +109,6 @@ Reference: http://wiki.openstreetmap.org/wiki/Key:access | runway | | yes | | x | | runway | | | yes | x | - Scenario: Bike - Overwriting implied acccess on nodes - Then routability should be - | highway | node/access | node/vehicle | node/bicycle | bothw | - | cycleway | | | | x | - | runway | | | | | - | cycleway | no | | | | - | cycleway | | no | | | - | cycleway | | | no | | - | runway | yes | | | | - | runway | | yes | | | - | runway | | | yes | | - Scenario: Bike - Access tags on ways Then routability should be | access | vehicle | bicycle | bothw | @@ -92,35 +138,6 @@ Reference: http://wiki.openstreetmap.org/wiki/Key:access | | | agricultural | | | | | forestery | | - Scenario: Bike - Access tags on nodes - Then routability should be - | node/access | node/vehicle | node/bicycle | bothw | - | | | | x | - | yes | | | x | - | permissive | | | x | - | designated | | | x | - | some_tag | | | x | - | no | | | | - | private | | | | - | agricultural | | | | - | forestery | | | | - | | yes | | x | - | | permissive | | x | - | | designated | | x | - | | some_tag | | x | - | | no | | | - | | private | | | - | | agricultural | | | - | | forestery | | | - | | | yes | x | - | | | permissive | x | - | | | designated | x | - | | | some_tag | x | - | | | no | | - | | | private | | - | | | agricultural | | - | | | forestery | | - Scenario: Bike - Access tags on both node and way Then routability should be | access | node/access | bothw | @@ -147,10 +164,10 @@ Reference: http://wiki.openstreetmap.org/wiki/Key:access Scenario: Bike - Ignore access tags for other modes Then routability should be - | highway | foot | motor_vehicle | moped | bothw | - | runway | yes | | | | + | highway | boat | motor_vehicle | moped | bothw | + | river | yes | | | | | cycleway | no | | | x | | runway | | yes | | | | cycleway | | no | | x | | runway | | | yes | | - | cycleway | | | no | x | \ No newline at end of file + | cycleway | | | no | x | diff --git a/features/bicycle/access_node.feature b/features/bicycle/access_node.feature new file mode 100644 index 000000000..eba808d52 --- /dev/null +++ b/features/bicycle/access_node.feature @@ -0,0 +1,64 @@ +@routing @bicycle @access +Feature: Bike - Access tags on nodes +Reference: http://wiki.openstreetmap.org/wiki/Key:access + + Background: + Given the profile "bicycle" + + Scenario: Bike - Access tag hierachy on nodes + Then routability should be + | node/access | node/vehicle | node/bicycle | bothw | + | | | | x | + | yes | | | x | + | no | | | | + | | yes | | x | + | | no | | | + | no | yes | | x | + | yes | no | | | + | | | yes | x | + | | | no | | + | no | | yes | x | + | yes | | no | | + | | no | yes | x | + | | yes | no | | + + Scenario: Bike - Overwriting implied acccess on nodes + Then routability should be + | highway | node/access | node/vehicle | node/bicycle | bothw | + | cycleway | | | | x | + | runway | | | | | + | cycleway | no | | | | + | cycleway | | no | | | + | cycleway | | | no | | + | runway | yes | | | | + | runway | | yes | | | + | runway | | | yes | | + + Scenario: Bike - Access tags on nodes + Then routability should be + | node/access | node/vehicle | node/bicycle | bothw | + | | | | x | + | yes | | | x | + | permissive | | | x | + | designated | | | x | + | some_tag | | | x | + | no | | | | + | private | | | | + | agricultural | | | | + | forestery | | | | + | | yes | | x | + | | permissive | | x | + | | designated | | x | + | | some_tag | | x | + | | no | | | + | | private | | | + | | agricultural | | | + | | forestery | | | + | | | yes | x | + | | | permissive | x | + | | | designated | x | + | | | some_tag | x | + | | | no | | + | | | private | | + | | | agricultural | | + | | | forestery | | \ No newline at end of file diff --git a/features/bicycle/cycleway.feature b/features/bicycle/cycleway.feature index bf42563ff..f26029453 100644 --- a/features/bicycle/cycleway.feature +++ b/features/bicycle/cycleway.feature @@ -29,16 +29,16 @@ Reference: http://wiki.openstreetmap.org/wiki/Key:cycleway Then routability should be | highway | cycleway | cycleway:left | cycleway:right | forw | backw | | primary | | | | x | x | - | pirmary | track | | | x | x | - | pirmary | opposite | | | x | x | - | pirmary | | track | | x | x | - | pirmary | | opposite | | x | x | - | pirmary | | | track | x | x | - | pirmary | | | opposite | x | x | - | pirmary | | track | track | x | x | - | pirmary | | opposite | opposite | x | x | - | pirmary | | track | opposite | x | x | - | pirmary | | opposite | track | x | x | + | primary | track | | | x | x | + | primary | opposite | | | x | x | + | primary | | track | | x | x | + | primary | | opposite | | x | x | + | primary | | | track | x | x | + | primary | | | opposite | x | x | + | primary | | track | track | x | x | + | primary | | opposite | opposite | x | x | + | primary | | track | opposite | x | x | + | primary | | opposite | track | x | x | Scenario: Bike - Left/right side cycleways on implied oneways Then routability should be diff --git a/features/bicycle/ferry.feature b/features/bicycle/ferry.feature index 762774cf1..5d67df7ea 100644 --- a/features/bicycle/ferry.feature +++ b/features/bicycle/ferry.feature @@ -58,79 +58,6 @@ Feature: Bike - Handle ferry routes | abcd | | ferry | yes | 1:00 | When I route I should get - | from | to | route | time | - | a | d | abcd | 3600s +-1 | - | d | a | abcd | 3600s +-1 | - - Scenario: Bike - Ferry duration, connected routes - Given the node map - | x | | | | | | | | y | - | | a | b | c | d | e | f | g | | - - And the ways - | nodes | highway | route | bicycle | duration | - | xa | primary | | | | - | yg | primary | | | | - | abcd | | ferry | yes | 0:30 | - | defg | | ferry | yes | 0:30 | - - When I route I should get - | from | to | route | time | - | a | g | abcd,defg | 3600s +-1 | - | g | a | defg,abcd | 3600s +-1 | - - Scenario: Bike - Prefer road when faster than ferry - Given the node map - | x | a | b | c | | - | | | | | d | - | y | g | f | e | | - - And the ways - | nodes | highway | route | bicycle | duration | - | xa | primary | | | | - | yg | primary | | | | - | xy | primary | | | | - | abcd | | ferry | yes | 0:01 | - | defg | | ferry | yes | 0:01 | - - When I route I should get - | from | to | route | time | - | a | g | xa,xy,yg | 60s +-25% | - | g | a | yg,xy,xa | 60s +-25% | - - Scenario: Bike - Long winding ferry route - Given the node map - | x | | b | | d | | f | | y | - | | a | | c | | e | | g | | - - And the ways - | nodes | highway | route | bicycle | duration | - | xa | primary | | | | - | yg | primary | | | | - | abcdefg | | ferry | yes | 6:30 | - - When I route I should get - | from | to | route | time | - | a | g | abcdefg | 23400s +-1 | - | g | a | abcdefg | 23400s +-1 | - - @todo - Scenario: Bike - Ferry duration, individual parts - Given the node map - | x | y | | z | | | v | - | a | b | | c | | | d | - - And the ways - | nodes | highway | route | bicycle | duration | - | xa | primary | | | | - | yb | primary | | | | - | zc | primary | | | | - | vd | primary | | | | - | abcd | | ferry | yes | 1:00 | - - When I route I should get - | from | to | route | time | - | a | d | abcd | 3600s +-1 | - | a | b | abcd | 600s +-1 | - | b | c | abcd | 1200s +-1 | - | c | d | abcd | 1800s +-1 | + | from | to | route | time | + | a | d | abcd | 3600s +-10 | + | d | a | abcd | 3600s +-10 | diff --git a/features/bicycle/maxspeed.feature b/features/bicycle/maxspeed.feature index 30d82b7e8..9924f5596 100644 --- a/features/bicycle/maxspeed.feature +++ b/features/bicycle/maxspeed.feature @@ -3,20 +3,39 @@ Feature: Bike - Max speed restrictions Background: Use specific speeds Given the profile "bicycle" - - Scenario: Bike - Respect maxspeeds when lower that way type speed - Given the node map - | a | b | c | - And the ways - | nodes | highway | maxspeed | - | ab | residential | | - | bc | residential | 10 | + Scenario: Bicycle - Respect maxspeeds when lower that way type speed + Then routability should be + | highway | maxspeed | bothw | + | residential | | 49s ~10% | + | residential | 10 | 72s ~10% | - When I route I should get - | from | to | route | time | - | a | b | ab | 20s ~5% | - | b | c | bc | 36s ~5% | + Scenario: Bicycle - Ignore maxspeed when higher than way speed + Then routability should be + | highway | maxspeed | bothw | + | residential | | 49s ~10% | + | residential | 80 | 49s ~10% | + + @todo + Scenario: Bicycle - Maxspeed formats + Then routability should be + | highway | maxspeed | bothw | + | residential | | 49s ~10% | + | residential | 5 | 144s ~10% | + | residential | 5mph | 90s ~10% | + | residential | 5 mph | 90s ~10% | + | residential | 5MPH | 90s ~10% | + | residential | 5 MPH | 90s ~10% | + | trunk | 5unknown | 49s ~10% | + | trunk | 5 unknown | 49s ~10% | + + @todo + Scenario: Bicycle - Maxspeed special tags + Then routability should be + | highway | maxspeed | bothw | + | residential | | 49s ~10% | + | residential | none | 49s ~10% | + | residential | signals | 49s ~10% | Scenario: Bike - Do not use maxspeed when higher that way type speed Given the node map @@ -29,5 +48,23 @@ Feature: Bike - Max speed restrictions When I route I should get | from | to | route | time | - | a | b | ab | 20s ~5% | - | b | c | bc | 20s ~5% | + | a | b | ab | 24s ~5% | + | b | c | bc | 24s ~5% | + + Scenario: Bike - Forward/backward maxspeed + Given the shortcuts + | key | value | + | bike | 49s ~10% | + | run | 73s ~10% | + | walk | 145s ~10% | + | snail | 720s ~10% | + + Then routability should be + | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw | + | | | | bike | bike | + | 10 | | | run | run | + | | 10 | | run | bike | + | | | 10 | bike | run | + | 1 | 10 | | run | snail | + | 1 | | 10 | snail | run | + | 1 | 5 | 10 | walk | run | diff --git a/features/bicycle/oneway.feature b/features/bicycle/oneway.feature index 4e6cb4f2d..6a9d3bf02 100644 --- a/features/bicycle/oneway.feature +++ b/features/bicycle/oneway.feature @@ -1,19 +1,20 @@ @routing @bicycle @oneway Feature: Bike - Oneway streets Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing +Usually we can push bikes against oneways, but we use foot=no to prevent this in these tests Background: Given the profile "bicycle" Scenario: Bike - Simple oneway Then routability should be - | highway | oneway | forw | backw | - | primary | yes | x | | + | highway | foot | oneway | forw | backw | + | primary | no | yes | x | | Scenario: Simple reverse oneway Then routability should be - | highway | oneway | forw | backw | - | primary | -1 | | x | + | highway | foot | oneway | forw | backw | + | primary | no | -1 | | x | Scenario: Bike - Around the Block Given the node map @@ -21,11 +22,11 @@ Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tag | d | c | And the ways - | nodes | oneway | - | ab | yes | - | bc | | - | cd | | - | da | | + | nodes | oneway | foot | + | ab | yes | no | + | bc | | no | + | cd | | no | + | da | | no | When I route I should get | from | to | route | @@ -34,80 +35,80 @@ Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tag Scenario: Bike - Handle various oneway tag values Then routability should be - | oneway | forw | backw | - | | x | x | - | nonsense | x | x | - | no | x | x | - | false | x | x | - | 0 | x | x | - | yes | x | | - | true | x | | - | 1 | x | | - | -1 | | x | + | foot | oneway | forw | backw | + | no | | x | x | + | no | nonsense | x | x | + | no | no | x | x | + | no | false | x | x | + | no | 0 | x | x | + | no | yes | x | | + | no | true | x | | + | no | 1 | x | | + | no | -1 | | x | Scenario: Bike - Implied oneways Then routability should be - | highway | bicycle | junction | forw | backw | - | | | | x | x | - | | | roundabout | x | | - | motorway | yes | | x | | - | motorway_link | yes | | x | | - | motorway | yes | roundabout | x | | - | motorway_link | yes | roundabout | x | | + | highway | foot | bicycle | junction | forw | backw | + | | no | | | x | x | + | | no | | roundabout | x | | + | motorway | no | yes | | x | | + | motorway_link | no | yes | | x | | + | motorway | no | yes | roundabout | x | | + | motorway_link | no | yes | roundabout | x | | Scenario: Bike - Overriding implied oneways Then routability should be - | highway | junction | oneway | forw | backw | - | primary | roundabout | no | x | x | - | primary | roundabout | yes | x | | - | motorway_link | | -1 | | | - | trunk_link | | -1 | | | - | primary | roundabout | -1 | | x | + | highway | foot | junction | oneway | forw | backw | + | primary | no | roundabout | no | x | x | + | primary | no | roundabout | yes | x | | + | motorway_link | no | | -1 | | | + | trunk_link | no | | -1 | | | + | primary | no | roundabout | -1 | | x | Scenario: Bike - Oneway:bicycle should override normal oneways tags Then routability should be - | oneway:bicycle | oneway | junction | forw | backw | - | yes | | | x | | - | yes | yes | | x | | - | yes | no | | x | | - | yes | -1 | | x | | - | yes | | roundabout | x | | - | no | | | x | x | - | no | yes | | x | x | - | no | no | | x | x | - | no | -1 | | x | x | - | no | | roundabout | x | x | - | -1 | | | | x | - | -1 | yes | | | x | - | -1 | no | | | x | - | -1 | -1 | | | x | - | -1 | | roundabout | | x | + | foot | oneway:bicycle | oneway | junction | forw | backw | + | no | yes | | | x | | + | no | yes | yes | | x | | + | no | yes | no | | x | | + | no | yes | -1 | | x | | + | no | yes | | roundabout | x | | + | no | no | | | x | x | + | no | no | yes | | x | x | + | no | no | no | | x | x | + | no | no | -1 | | x | x | + | no | no | | roundabout | x | x | + | no | -1 | | | | x | + | no | -1 | yes | | | x | + | no | -1 | no | | | x | + | no | -1 | -1 | | | x | + | no | -1 | | roundabout | | x | Scenario: Bike - Contra flow Then routability should be - | oneway | cycleway | forw | backw | - | yes | opposite | x | x | - | yes | opposite_track | x | x | - | yes | opposite_lane | x | x | - | -1 | opposite | x | x | - | -1 | opposite_track | x | x | - | -1 | opposite_lane | x | x | - | no | opposite | x | x | - | no | opposite_track | x | x | - | no | opposite_lane | x | x | + | foot | oneway | cycleway | forw | backw | + | no | yes | opposite | x | x | + | no | yes | opposite_track | x | x | + | no | yes | opposite_lane | x | x | + | no | -1 | opposite | x | x | + | no | -1 | opposite_track | x | x | + | no | -1 | opposite_lane | x | x | + | no | no | opposite | x | x | + | no | no | opposite_track | x | x | + | no | no | opposite_lane | x | x | Scenario: Bike - Should not be affected by car tags Then routability should be - | junction | oneway | oneway:car | forw | backw | - | | yes | yes | x | | - | | yes | no | x | | - | | yes | -1 | x | | - | | no | yes | x | x | - | | no | no | x | x | - | | no | -1 | x | x | - | | -1 | yes | | x | - | | -1 | no | | x | - | | -1 | -1 | | x | - | roundabout | | yes | x | | - | roundabout | | no | x | | - | roundabout | | -1 | x | | + | foot | junction | oneway | oneway:car | forw | backw | + | no | | yes | yes | x | | + | no | | yes | no | x | | + | no | | yes | -1 | x | | + | no | | no | yes | x | x | + | no | | no | no | x | x | + | no | | no | -1 | x | x | + | no | | -1 | yes | | x | + | no | | -1 | no | | x | + | no | | -1 | -1 | | x | + | no | roundabout | | yes | x | | + | no | roundabout | | no | x | | + | no | roundabout | | -1 | x | | diff --git a/features/bicycle/pushing.feature b/features/bicycle/pushing.feature new file mode 100644 index 000000000..169d340e3 --- /dev/null +++ b/features/bicycle/pushing.feature @@ -0,0 +1,87 @@ +@routing @bicycle @pushing +Feature: Bike - Accessability of different way types + + Background: + Given the profile "bicycle" + Given the shortcuts + | key | value | + | bike | 49s ~20% | + | foot | 121s ~20% | + + Scenario: Bike - Pushing bikes on pedestrian-only ways + Then routability should be + | highway | oneway | forw | backw | + | (nil) | | | | + | cycleway | | bike | bike | + | primary | | bike | bike | + | pedestrian | | foot | foot | + | footway | | foot | foot | + | primary | yes | bike | foot | + + Scenario: Bike - Pushing bikes against normal oneways + Then routability should be + | highway | oneway | forw | backw | + | (nil) | | | | + | primary | yes | bike | foot | + | pedestrian | yes | foot | foot | + + Scenario: Bike - Pushing bikes against reverse oneways + Then routability should be + | highway | oneway | forw | backw | + | (nil) | | | | + | primary | -1 | foot | bike | + | pedestrian | -1 | foot | foot | + + @square + Scenario: Bike - Push bikes on pedestrian areas + Given the node map + | x | | + | a | b | + | d | c | + + And the ways + | nodes | area | highway | + | xa | | primary | + | abcda | yes | pedestrian | + + When I route I should get + | from | to | route | + | a | b | abcda | + | a | d | abcda | + | b | c | abcda | + | c | b | abcda | + | c | d | abcda | + | d | c | abcda | + | d | a | abcda | + | a | d | abcda | + + Scenario: Bike - Pushing bikes on ways with foot=yes + Then routability should be + | highway | foot | bothw | + | motorway | | | + | motorway | yes | foot | + | runway | | | + | runway | yes | foot | + + @todo + Scenario: Bike - Pushing bikes on ways with foot=yes in one direction + Then routability should be + | highway | foot:forward | foot:backward | forw | backw | + | motorway | | | | | + | motorway | yes | | foot | | + | motorway | | yes | | foot | + + @construction + Scenario: Bike - Don't allow routing on ways still under construction + Then routability should be + | highway | foot | bicycle | bothw | + | primary | | | x | + | construction | | | | + | construction | yes | | | + | construction | | yes | | + + @roundabout + Scenario: Bike - Don't push bikes against oneway flow on roundabouts + Then routability should be + | junction | forw | backw | + | roundabout | x | | diff --git a/features/bicycle/restrictions.feature b/features/bicycle/restrictions.feature index 736c939aa..2d5fa40c5 100644 --- a/features/bicycle/restrictions.feature +++ b/features/bicycle/restrictions.feature @@ -1,9 +1,9 @@ @routing @bicycle @restrictions Feature: Bike - Turn restrictions - Handle turn restrictions as defined by http://wiki.openstreetmap.org/wiki/Relation:restriction + Ignore turn restrictions on bicycle, since you always become a temporary pedestrian. Note that if u-turns are allowed, turn restrictions can lead to suprising, but correct, routes. - Background: Use car routing + Background: Given the profile "bicycle" @no_turning @@ -14,11 +14,11 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | nodes | oneway | foot | + | sj | yes | no | + | nj | -1 | no | + | wj | -1 | no | + | ej | -1 | no | And the relations | type | way:from | way:to | node:via | restriction | @@ -26,7 +26,7 @@ Feature: Bike - Turn restrictions When I route I should get | from | to | route | - | s | w | | + | s | w | sj,wj | | s | n | sj,nj | | s | e | sj,ej | @@ -38,11 +38,11 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | nodes | oneway | foot | + | sj | yes | no | + | nj | -1 | no | + | wj | -1 | no | + | ej | -1 | no | And the relations | type | way:from | way:to | node:via | restriction | @@ -52,7 +52,7 @@ Feature: Bike - Turn restrictions | from | to | route | | s | w | sj,wj | | s | n | sj,nj | - | s | e | | + | s | e | sj,ej | @no_turning Scenario: Bike - No u-turn @@ -62,11 +62,11 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | nodes | oneway | foot | + | sj | yes | no | + | nj | -1 | no | + | wj | -1 | no | + | ej | -1 | no | And the relations | type | way:from | way:to | node:via | restriction | @@ -74,7 +74,7 @@ Feature: Bike - Turn restrictions When I route I should get | from | to | route | - | s | w | | + | s | w | sj,wj | | s | n | sj,nj | | s | e | sj,ej | @@ -86,11 +86,11 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | nodes | oneway | foot | + | sj | yes | no | + | nj | -1 | no | + | wj | -1 | no | + | ej | -1 | no | And the relations | type | way:from | way:to | node:via | restriction | @@ -98,7 +98,7 @@ Feature: Bike - Turn restrictions When I route I should get | from | to | route | - | s | w | | + | s | w | sj,wj | | s | n | sj,nj | | s | e | sj,ej | @@ -110,11 +110,11 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | nodes | oneway | foot | + | sj | yes | no | + | nj | -1 | no | + | wj | -1 | no | + | ej | -1 | no | And the relations | type | way:from | way:to | node:via | restriction | @@ -123,8 +123,8 @@ Feature: Bike - Turn restrictions When I route I should get | from | to | route | | s | w | sj,wj | - | s | n | | - | s | e | | + | s | n | sj,nj | + | s | e | sj,ej | @only_turning Scenario: Bike - Only right turn @@ -134,11 +134,11 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | nodes | oneway | foot | + | sj | yes | no | + | nj | -1 | no | + | wj | -1 | no | + | ej | -1 | no | And the relations | type | way:from | way:to | node:via | restriction | @@ -146,8 +146,8 @@ Feature: Bike - Turn restrictions When I route I should get | from | to | route | - | s | w | | - | s | n | | + | s | w | sj,wj | + | s | n | sj,nj | | s | e | sj,ej | @only_turning @@ -158,11 +158,11 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | nodes | oneway | foot | + | sj | yes | no | + | nj | -1 | no | + | wj | -1 | no | + | ej | -1 | no | And the relations | type | way:from | way:to | node:via | restriction | @@ -170,9 +170,9 @@ Feature: Bike - Turn restrictions When I route I should get | from | to | route | - | s | w | | + | s | w | sj,wj | | s | n | sj,nj | - | s | e | | + | s | e | sj,ej | @no_turning Scenario: Bike - Handle any only_* restriction @@ -182,11 +182,11 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | nj | -1 | - | wj | -1 | - | ej | -1 | + | nodes | oneway | foot | + | sj | yes | no | + | nj | -1 | no | + | wj | -1 | no | + | ej | -1 | no | And the relations | type | way:from | way:to | node:via | restriction | @@ -194,11 +194,11 @@ Feature: Bike - Turn restrictions When I route I should get | from | to | route | - | s | w | | + | s | w | sj,wj | | s | n | sj,nj | - | s | e | | + | s | e | sj,ej | - @except @todo + @except Scenario: Bike - Except tag and on no_ restrictions Given the node map | b | x | c | @@ -206,29 +206,29 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | xj | -1 | - | aj | -1 | - | bj | -1 | - | cj | -1 | - | dj | -1 | + | nodes | oneway | foot | + | sj | no | no | + | xj | -1 | no | + | aj | -1 | no | + | bj | no | no | + | cj | -1 | no | + | dj | -1 | no | And the relations | type | way:from | way:to | node:via | restriction | except | | restriction | sj | aj | j | no_left_turn | bicycle | | restriction | sj | bj | j | no_left_turn | | - | restriction | sj | cj | j | no_right_turn | bicycle | - | restriction | sj | dj | j | no_right_turn | | + | restriction | sj | cj | j | no_right_turn | | + | restriction | sj | dj | j | no_right_turn | bicycle | When I route I should get | from | to | route | | s | a | sj,aj | - | s | b | | - | s | c | | + | s | b | sj,bj | + | s | c | sj,cj | | s | d | sj,dj | - @except @todo + @except Scenario: Bike - Except tag and on only_ restrictions Given the node map | a | | b | @@ -236,10 +236,10 @@ Feature: Bike - Turn restrictions | | s | | And the ways - | nodes | oneway | - | sj | yes | - | aj | -1 | - | bj | -1 | + | nodes | oneway | foot | + | sj | yes | no | + | aj | no | no | + | bj | no | no | And the relations | type | way:from | way:to | node:via | restriction | except | @@ -249,3 +249,41 @@ Feature: Bike - Turn restrictions | from | to | route | | s | a | sj,aj | | s | b | sj,bj | + + @except + Scenario: Bike - Multiple except tag values + Given the node map + | s | j | a | + | | | b | + | | | c | + | | | d | + | | | e | + | | | f | + + And the ways + | nodes | oneway | foot | + | sj | yes | no | + | ja | yes | no | + | jb | yes | no | + | jc | yes | no | + | jd | yes | no | + | je | yes | no | + | jf | yes | no | + + And the relations + | type | way:from | way:to | node:via | restriction | except | + | restriction | sj | ja | j | no_straight_on | | + | restriction | sj | jb | j | no_straight_on | bicycle | + | restriction | sj | jc | j | no_straight_on | bus; bicycle | + | restriction | sj | jd | j | no_straight_on | bicycle; motocar | + | restriction | sj | je | j | no_straight_on | bus, bicycle | + | restriction | sj | jf | j | no_straight_on | bicycle, bus | + + When I route I should get + | from | to | route | + | s | a | sj,ja | + | s | b | sj,jb | + | s | c | sj,jc | + | s | d | sj,jd | + | s | e | sj,je | + | s | f | sj,jf | diff --git a/features/bicycle/train.feature b/features/bicycle/train.feature index 1b5699f16..a4af362b5 100644 --- a/features/bicycle/train.feature +++ b/features/bicycle/train.feature @@ -30,3 +30,10 @@ Bringing bikes on trains and subways | (nil) | some_tag | | | | (nil) | some_tag | no | | | (nil) | some_tag | yes | x | + + @construction + Scenario: Bike - Don't route on railways under construction + Then routability should be + | highway | railway | bicycle | bothw | + | primary | | | x | + | (nil) | construction | yes | | diff --git a/features/bicycle/turn_penalty.feature b/features/bicycle/turn_penalty.feature new file mode 100644 index 000000000..157cbf2d6 --- /dev/null +++ b/features/bicycle/turn_penalty.feature @@ -0,0 +1,33 @@ +@routing @bicycle @turn_penalty +Feature: Turn Penalties + + Background: + Given the profile "turnbot" + + Scenario: Bike - turns should incur a delay that depend on the angle + + Given the node map + | c | d | e | + | b | j | f | + | a | s | g | + + And the ways + | nodes | + | sj | + | ja | + | jb | + | jc | + | jd | + | je | + | jf | + | jg | + + When I route I should get + | from | to | route | time | distance | + | s | a | sj,ja | 39s +-1 | 242m +-1 | + | s | b | sj,jb | 30s +-1 | 200m +-1 | + | s | c | sj,jc | 29s +-1 | 242m +-1 | + | s | d | sj,jd | 20s +-1 | 200m +-1 | + | s | e | sj,je | 29s +-1 | 242m +-1 | + | s | f | sj,jf | 30s +-1 | 200m +-1 | + | s | g | sj,jg | 39s +-1 | 242m +-1 | \ No newline at end of file diff --git a/features/bicycle/way.feature b/features/bicycle/way.feature index ca157bd25..f5ad5bb87 100644 --- a/features/bicycle/way.feature +++ b/features/bicycle/way.feature @@ -4,32 +4,38 @@ Feature: Bike - Accessability of different way types Background: Given the profile "bicycle" - Scenario: Bike - Basic access + Scenario: Bike - Routability of way types Bikes are allowed on footways etc because you can pull your bike at a lower speed. - Given the profile "bicycle" + Pier is not allowed, since it's tagged using man_made=pier. Then routability should be - | highway | forw | - | (nil) | | - | motorway | | - | motorway_link | | - | trunk | | - | trunk_link | | - | primary | x | - | primary_link | x | - | secondary | x | - | secondary_link | x | - | tertiary | x | - | tertiary_link | x | - | residential | x | - | service | x | - | unclassified | x | - | living_street | x | - | road | x | - | track | x | - | path | x | - | footway | x | - | pedestrian | x | - | steps | x | - | pier | x | - | cycleway | x | - | bridleway | | + | highway | bothw | + | (nil) | | + | motorway | | + | motorway_link | | + | trunk | | + | trunk_link | | + | primary | x | + | primary_link | x | + | secondary | x | + | secondary_link | x | + | tertiary | x | + | tertiary_link | x | + | residential | x | + | service | x | + | unclassified | x | + | living_street | x | + | road | x | + | track | x | + | path | x | + | footway | x | + | pedestrian | x | + | steps | x | + | cycleway | x | + | bridleway | | + | pier | | + + Scenario: Bike - Routability of man_made structures + Then routability should be + | highway | man_made | bothw | + | (nil) | (nil) | | + | (nil) | pier | x | diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature index cc31c6c13..7da5088f4 100644 --- a/features/car/maxspeed.feature +++ b/features/car/maxspeed.feature @@ -10,16 +10,16 @@ Feature: Car - Max speed restrictions | a | b | c | And the ways - | nodes | highway | maxspeed | - | ab | trunk | | - | bc | trunk | 10 | + | nodes | highway | maxspeed | + | ab | trunk | | + | bc | trunk | 10 | When I route I should get | from | to | route | time | | a | b | ab | 42s ~10% | | b | c | bc | 360s ~10% | - Scenario: Car - Ignore maxspeed when higher than way speed + Scenario: Car - Do not ignore maxspeed when higher than way speed Given the node map | a | b | c | @@ -31,4 +31,24 @@ Feature: Car - Max speed restrictions When I route I should get | from | to | route | time | | a | b | ab | 144s ~10% | - | b | c | bc | 144s ~10% | + | b | c | bc | 63s ~10% | + + Scenario: Car - Forward/backward maxspeed + Given the shortcuts + | key | value | + | car | 12s ~10% | + | run | 73s ~10% | + | walk | 146s ~10% | + | snail | 720s ~10% | + + And a grid size of 100 meters + + Then routability should be + | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw | + | | | | car | car | + | 10 | | | run | run | + | | 10 | | run | car | + | | | 10 | car | run | + | 1 | 10 | | run | snail | + | 1 | | 10 | snail | run | + | 1 | 5 | 10 | walk | run | diff --git a/features/car/permissive.feature b/features/car/permissive.feature new file mode 100644 index 000000000..e69de29bb diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature index 1ee527395..91ba29865 100644 --- a/features/car/restrictions.feature +++ b/features/car/restrictions.feature @@ -198,8 +198,8 @@ Feature: Car - Turn restrictions | s | n | sj,nj | | s | e | | - @except @todo - Scenario: Bike - Except tag and on no_ restrictions + @except + Scenario: Car - Except tag and on no_ restrictions Given the node map | b | x | c | | a | j | d | @@ -207,19 +207,19 @@ Feature: Car - Turn restrictions And the ways | nodes | oneway | - | sj | yes | + | sj | no | | xj | -1 | | aj | -1 | - | bj | -1 | - | cj | -1 | + | bj | no | + | cj | no | | dj | -1 | And the relations | type | way:from | way:to | node:via | restriction | except | | restriction | sj | aj | j | no_left_turn | motorcar | | restriction | sj | bj | j | no_left_turn | | - | restriction | sj | cj | j | no_right_turn | motorcar | - | restriction | sj | dj | j | no_right_turn | | + | restriction | sj | cj | j | no_right_turn | | + | restriction | sj | dj | j | no_right_turn | motorcar | When I route I should get | from | to | route | @@ -228,8 +228,8 @@ Feature: Car - Turn restrictions | s | c | | | s | d | sj,dj | - @except @todo - Scenario: Bike - Except tag and on only_ restrictions + @except + Scenario: Car - Except tag and on only_ restrictions Given the node map | a | | b | | | j | | @@ -238,8 +238,8 @@ Feature: Car - Turn restrictions And the ways | nodes | oneway | | sj | yes | - | aj | -1 | - | bj | -1 | + | aj | no | + | bj | no | And the relations | type | way:from | way:to | node:via | restriction | except | diff --git a/features/car/shuttle_train.feature b/features/car/shuttle_train.feature new file mode 100644 index 000000000..ed2187c27 --- /dev/null +++ b/features/car/shuttle_train.feature @@ -0,0 +1,31 @@ +@routing @car @shuttle_train +Feature: Car - Handle ferryshuttle train routes + + Background: + Given the profile "car" + + Scenario: Car - Use a ferry route + Given the node map + | a | b | c | | | + | | | d | | | + | | | e | f | g | + + And the ways + | nodes | highway | route | bicycle | + | abc | primary | | | + | cde | | shuttle_train | yes | + | ef | primary | | | + | fg | | ferry_man | | + + When I route I should get + | from | to | route | + | a | g | abc,cde,ef | + | b | f | abc,cde,ef | + | e | c | cde | + | e | b | cde,abc | + | e | a | cde,abc | + | c | e | cde | + | c | f | cde,ef | + | f | g | | + + diff --git a/features/foot/maxspeed.feature b/features/foot/maxspeed.feature new file mode 100644 index 000000000..8a3571a04 --- /dev/null +++ b/features/foot/maxspeed.feature @@ -0,0 +1,20 @@ +@routing @maxspeed @foot +Feature: Foot - Ignore max speed restrictions + +Background: Use specific speeds + Given the profile "foot" + +@todo +Scenario: Foot - Ignore maxspeed + Then routability should be + | highway | maxspeed | bothw | + | residential | | 145s ~10% | + | residential | 1 | 145s ~10% | + | residential | 100 | 145s ~10% | + | residential | 1 | 145s ~10% | + | residential | 1mph | 145s ~10% | + | residential | 1 mph | 145s ~10% | + | residential | 1unknown | 145s ~10% | + | residential | 1 unknown | 145s ~10% | + | residential | none | 145s ~10% | + | residential | signals | 145s ~10% | diff --git a/features/nearest/pick.feature b/features/nearest/pick.feature new file mode 100644 index 000000000..f3bd76d76 --- /dev/null +++ b/features/nearest/pick.feature @@ -0,0 +1,56 @@ +@nearest +Feature: Locating Nearest node on a Way - pick closest way + + Background: + Given the profile "testbot" + + Scenario: Nearest - two ways crossing + Given the node map + | | 0 | c | 1 | | + | 7 | | n | | 2 | + | a | k | x | m | b | + | 6 | | l | | 3 | + | | 5 | d | 4 | | + + And the ways + | nodes | + | axb | + | cxd | + + When I request nearest I should get + | in | out | + | 0 | c | + | 1 | c | + | 2 | b | + | 3 | b | + | 4 | d | + | 5 | d | + | 6 | a | + | 7 | a | + | k | k | + | l | l | + | m | m | + | n | n | + + Scenario: Nearest - inside a triangle + Given the node map + | | | | | | c | | | | | | + | | | | | | | | | | | | + | | | | y | | | | z | | | | + | | | | | 0 | | 1 | | | | | + | | | | 2 | | 3 | | 4 | | | | + | a | | | x | | u | | w | | | b | + + And the ways + | nodes | + | ab | + | bc | + | ca | + + When I request nearest I should get + | in | out | + | 0 | y | + | 1 | z | + | 2 | x | + | 3 | u | + | 4 | w | \ No newline at end of file diff --git a/features/nearest/projection.feature b/features/nearest/projection.feature new file mode 100644 index 000000000..f33a19f81 --- /dev/null +++ b/features/nearest/projection.feature @@ -0,0 +1,105 @@ +@nearest +Feature: Locating Nearest node on a Way - basic projection onto way + + Background: + Given the profile "testbot" + + Scenario: Nearest - easy-west way + Given the node map + | 0 | 1 | 2 | 3 | 4 | + | | a | x | b | | + | 5 | 6 | 7 | 8 | 9 | + + And the ways + | nodes | + | ab | + + When I request nearest I should get + | in | out | + | 0 | a | + | 1 | a | + | 2 | x | + | 3 | b | + | 4 | b | + | 5 | a | + | 6 | a | + | 7 | x | + | 8 | b | + | 9 | b | + + Scenario: Nearest - north-south way + Given the node map + | 0 | | 5 | + | 1 | a | 6 | + | 2 | x | 7 | + | 3 | b | 8 | + | 4 | | 9 | + + And the ways + | nodes | + | ab | + + When I request nearest I should get + | in | out | + | 0 | a | + | 1 | a | + | 2 | x | + | 3 | b | + | 4 | b | + | 5 | a | + | 6 | a | + | 7 | x | + | 8 | b | + | 9 | b | + + Scenario: Nearest - diagonal 1 + Given the node map + | 8 | | 4 | | | | + | | a | | 5 | | | + | 0 | | x | | 6 | | + | | 1 | | y | | 7 | + | | | 2 | | b | | + | | | | 3 | | 9 | + + And the ways + | nodes | + | ab | + + When I request nearest I should get + | in | out | + | 0 | a | + | 1 | x | + | 2 | y | + | 3 | b | + | 4 | a | + | 5 | x | + | 6 | y | + | 7 | b | + | 8 | a | + | 9 | b | + + Scenario: Nearest - diagonal 2 + Given the node map + | | | | 3 | | 9 | + | | | 2 | | b | | + | | 1 | | y | | 7 | + | 0 | | x | | 6 | | + | | a | | 5 | | | + | 8 | | 4 | | | | + + And the ways + | nodes | + | ab | + + When I request nearest I should get + | in | out | + | 0 | a | + | 1 | x | + | 2 | y | + | 3 | b | + | 4 | a | + | 5 | x | + | 6 | y | + | 7 | b | + | 8 | a | + | 9 | b | diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb index fc34105fb..c16adaacb 100644 --- a/features/step_definitions/data.rb +++ b/features/step_definitions/data.rb @@ -6,6 +6,12 @@ Given /^a grid size of (\d+) meters$/ do |meters| set_grid_size meters end +Given /^the shortcuts$/ do |table| + table.hashes.each do |row| + shortcuts_hash[ row['key'] ] = row['value'] + end +end + Given /^the node map$/ do |table| table.raw.each_with_index do |row,ri| row.each_with_index do |name,ci| @@ -90,14 +96,18 @@ Given /^the relations$/ do |table| relation = OSM::Relation.new make_osm_id, OSM_USER, OSM_TIMESTAMP row.each_pair do |key,value| if key =~ /^node:(.*)/ - raise "***invalid relation node member '#{value}', must be single character" unless value.size == 1 - node = find_node_by_name(value) - raise "*** unknown relation node member '#{value}'" unless node - relation << OSM::Member.new( 'node', node.id, $1 ) + value.split(',').map { |v| v.strip }.each do |node_name| + raise "***invalid relation node member '#{node_name}', must be single character" unless node_name.size == 1 + node = find_node_by_name(node_name) + raise "*** unknown relation node member '#{node_name}'" unless node + relation << OSM::Member.new( 'node', node.id, $1 ) + end elsif key =~ /^way:(.*)/ - way = find_way_by_name(value) - raise "*** unknown relation way member '#{value}'" unless way - relation << OSM::Member.new( 'way', way.id, $1 ) + value.split(',').map { |v| v.strip }.each do |way_name| + way = find_way_by_name(way_name) + raise "*** unknown relation way member '#{way_name}'" unless way + relation << OSM::Member.new( 'way', way.id, $1 ) + end elsif key =~ /^(.*):(.*)/ raise "*** unknown relation member type '#{$1}', must be either 'node' or 'way'" else diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb new file mode 100644 index 000000000..303788b47 --- /dev/null +++ b/features/step_definitions/nearest.rb @@ -0,0 +1,51 @@ +When /^I request nearest I should get$/ do |table| + reprocess + actual = [] + OSRMLauncher.new do + table.hashes.each_with_index do |row,ri| + in_node = @name_node_hash[ row['in'] ] + raise "*** unknown in-node '#{row['in']}" unless in_node + + out_node = @name_node_hash[ row['out'] ] + raise "*** unknown out-node '#{row['out']}" unless out_node + + response = request_nearest("#{in_node.lat},#{in_node.lon}") + if response.code == "200" && response.body.empty? == false + json = JSON.parse response.body + if json['status'] == 0 + coord = json['mapped_coordinate'] + end + end + + got = {'in' => row['in'], 'out' => coord } + + ok = true + row.keys.each do |key| + if key=='out' + if FuzzyMatch.match_location coord, out_node + got[key] = row[key] + else + row[key] = "#{row[key]} [#{out_node.lat},#{out_node.lon}]" + ok = false + end + end + end + + unless ok + failed = { :attempt => 'nearest', :query => @query, :response => response } + log_fail row,got,[failed] + end + + actual << got + end + end + table.routing_diff! actual +end + +When /^I route (\d+) times I should get$/ do |n,table| + ok = true + n.to_i.times do + ok = false unless step "I route I should get", table + end + ok +end \ No newline at end of file diff --git a/features/step_definitions/routability.rb b/features/step_definitions/routability.rb index d949d01b9..0af027a98 100644 --- a/features/step_definitions/routability.rb +++ b/features/step_definitions/routability.rb @@ -16,18 +16,21 @@ Then /^routability should be$/ do |table| elsif direction == 'backw' || direction == 'bothw' response = request_route("#{ORIGIN[1]},#{ORIGIN[0]+(3+WAY_SPACING*i)*@zoom}","#{ORIGIN[1]},#{ORIGIN[0]+(1+WAY_SPACING*i)*@zoom}") end + want = shortcuts_hash[row[direction]] || row[direction] #expand shortcuts got[direction] = route_status response json = JSON.parse(response.body) if got[direction].empty? == false route = way_list json['route_instructions'] if route != "w#{i}" got[direction] = "testing w#{i}, but got #{route}!?" - elsif row[direction] =~ /\d+s/ + elsif want =~ /^\d+s/ time = json['route_summary']['total_time'] got[direction] = "#{time}s" end end - if got[direction] != row[direction] + if FuzzyMatch.match got[direction], want + got[direction] = row[direction] + else attempts << { :attempt => direction, :query => @query, :response => response } end end diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb index 32e6f60e5..7ef5ba756 100644 --- a/features/step_definitions/routing.rb +++ b/features/step_definitions/routing.rb @@ -46,34 +46,17 @@ When /^I route I should get$/ do |table| if table.headers.include? 'turns' got['turns'] = turns end + if table.headers.include? '#' # comment column + got['#'] = row['#'] # copy value so it always match + end end ok = true row.keys.each do |key| - if row[key].match /(.*)\s+~(.+)%$/ #percentage range: 100 ~5% - margin = 1 - $2.to_f*0.01 - from = $1.to_f*margin - to = $1.to_f/margin - if got[key].to_f >= from && got[key].to_f <= to - got[key] = row[key] - else - ok = false - end - elsif row[key].match /(.*)\s+\+\-(.+)$/ #absolute range: 100 +-5 - margin = $2.to_f - from = $1.to_f-margin - to = $1.to_f+margin - if got[key].to_f >= from && got[key].to_f <= to - got[key] = row[key] - else - ok = false - end - elsif row[key] =~ /^\/(.*)\/$/ #regex: /a,b,.*/ - if got[key] =~ /#{$1}/ - got[key] = row[key] - end + if FuzzyMatch.match got[key], row[key] + got[key] = row[key] else - ok = row[key] == got[key] + ok = false end end @@ -94,4 +77,4 @@ When /^I route (\d+) times I should get$/ do |n,table| ok = false unless step "I route I should get", table end ok -end \ No newline at end of file +end diff --git a/features/support/data.rb b/features/support/data.rb index 392265da4..ce6b995c1 100644 --- a/features/support/data.rb +++ b/features/support/data.rb @@ -13,7 +13,7 @@ OSM_TIMESTAMP = '2000-00-00T00:00:00Z' DEFAULT_SPEEDPROFILE = 'bicycle' WAY_SPACING = 100 DEFAULT_GRID_SIZE = 100 #meters - +PROFILES_PATH = '../profiles' ORIGIN = [1,1] @@ -71,8 +71,15 @@ def build_ways_from_table table way << node5 tags = row.dup - tags.delete 'forw' - tags.delete 'backw' + + # remove tags that describe expected test result + tags.reject! do |k,v| + k =~ /^forw\b/ || + k =~ /^backw\b/ || + k =~ /^bothw\b/ + end + + ##remove empty tags tags.reject! { |k,v| v=='' } # sort tag keys in the form of 'node/....' @@ -198,14 +205,15 @@ def write_timestamp end def reprocess + use_pbf = true Dir.chdir TEST_FOLDER do write_osm write_timestamp - convert_osm_to_pbf + convert_osm_to_pbf if use_pbf unless extracted? log_preprocess_info log "== Extracting #{@osm_file}.osm...", :preprocess - unless system "../osrm-extract #{@osm_file}.osm.pbf 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE} ../profiles/#{@profile}.lua" + unless system "../osrm-extract #{@osm_file}.osm#{'.pbf' if use_pbf} 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE} #{PROFILES_PATH}/#{@profile}.lua" log "*** Exited with code #{$?.exitstatus}.", :preprocess raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}." end @@ -214,7 +222,7 @@ def reprocess unless prepared? log_preprocess_info log "== Preparing #{@osm_file}.osm...", :preprocess - unless system "../osrm-prepare #{@osm_file}.osrm #{@osm_file}.osrm.restrictions 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE} ../profiles/#{@profile}.lua" + unless system "../osrm-prepare #{@osm_file}.osrm #{@osm_file}.osrm.restrictions 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE} #{PROFILES_PATH}/#{@profile}.lua" log "*** Exited with code #{$?.exitstatus}.", :preprocess raise PrepareError.new $?.exitstatus, "osrm-prepare exited with code #{$?.exitstatus}." end diff --git a/features/support/fuzzy.rb b/features/support/fuzzy.rb new file mode 100644 index 000000000..9138dcce5 --- /dev/null +++ b/features/support/fuzzy.rb @@ -0,0 +1,30 @@ + +class FuzzyMatch + + def self.match got, want + if got == want + return true + elsif want.match /(.*)\s+~(.+)%$/ #percentage range: 100 ~5% + margin = 1 - $2.to_f*0.01 + from = $1.to_f*margin + to = $1.to_f/margin + return got.to_f >= from && got.to_f <= to + elsif want.match /(.*)\s+\+\-(.+)$/ #absolute range: 100 +-5 + margin = $2.to_f + from = $1.to_f-margin + to = $1.to_f+margin + return got.to_f >= from && got.to_f <= to + elsif want =~ /^\/(.*)\/$/ #regex: /a,b,.*/ + return got =~ /#{$1}/ + else + return false + end + end + + def self.match_location got, want + match( got[0], "#{want.lat} ~0.002%" ) && + match( got[1], "#{want.lon} ~0.002%" ) + end + +end + diff --git a/features/support/hash.rb b/features/support/hash.rb index b4b2f762b..83e5f916d 100644 --- a/features/support/hash.rb +++ b/features/support/hash.rb @@ -1,39 +1,47 @@ require 'digest/sha1' -def hash_of_file path +def hash_of_files paths + paths = [paths] unless paths.is_a? Array hash = Digest::SHA1.new - open(path,'r') do |io| - while !io.eof - buf = io.readpartial 1024 - hash.update buf + for path in paths do + open(path,'r') do |io| + while !io.eof + buf = io.readpartial 1024 + hash.update buf + end end end return hash.hexdigest end + def profile_hash @@profile_hashes ||= {} - @@profile_hashes[@profile] ||= hash_of_file "../profiles/#{@profile}.lua" + @@profile_hashes[@profile] ||= hash_of_files "#{PROFILES_PATH}/#{@profile}.lua" end def osm_hash @osm_hash ||= Digest::SHA1.hexdigest osm_str end +def lua_lib_hash + @lua_lib_hash ||= hash_of_files Dir.glob("../profiles/lib/*.lua") +end + def bin_extract_hash - @@bin_extract_hash ||= hash_of_file '../osrm-extract' + @@bin_extract_hash ||= hash_of_files '../osrm-extract' end def bin_prepare_hash - @@bin_prepare_hash ||= hash_of_file '../osrm-prepare' + @@bin_prepare_hash ||= hash_of_files '../osrm-prepare' end def bin_routed_hash - @@bin_routed_hash ||= hash_of_file '../osrm-routed' + @@bin_routed_hash ||= hash_of_files '../osrm-routed' end #combine state of data, profile and binaries into a hash that identifies the exact test scenario def fingerprint - @fingerprint ||= Digest::SHA1.hexdigest "#{bin_extract_hash}-#{bin_prepare_hash}-#{bin_routed_hash}-#{profile_hash}-#{osm_hash}" + @fingerprint ||= Digest::SHA1.hexdigest "#{bin_extract_hash}-#{bin_prepare_hash}-#{bin_routed_hash}-#{profile_hash}-#{lua_lib_hash}-#{osm_hash}" end diff --git a/features/support/nearest.rb b/features/support/nearest.rb new file mode 100644 index 000000000..e37130735 --- /dev/null +++ b/features/support/nearest.rb @@ -0,0 +1,17 @@ +require 'net/http' + +def request_nearest_url path + @query = path + uri = URI.parse "#{HOST}/#{path}" + Timeout.timeout(REQUEST_TIMEOUT) do + Net::HTTP.get_response uri + end +rescue Errno::ECONNREFUSED => e + raise "*** osrm-routed is not running." +rescue Timeout::Error + raise "*** osrm-routed did not respond." +end + +def request_nearest a + request_nearest_url "nearest?loc=#{a}" +end diff --git a/features/support/shortcuts.rb b/features/support/shortcuts.rb new file mode 100644 index 000000000..20bc3c0fe --- /dev/null +++ b/features/support/shortcuts.rb @@ -0,0 +1,3 @@ +def shortcuts_hash + @shortcuts_hash ||= {} +end diff --git a/features/testbot/distance.feature b/features/testbot/distance.feature index ac1f38364..1fb436bc6 100644 --- a/features/testbot/distance.feature +++ b/features/testbot/distance.feature @@ -29,7 +29,7 @@ Feature: Distance calculation When I route I should get | from | to | route | distance | - | a | d | abcde | 300m +-8 | + | a | d | abcde | 300m +-2 | Scenario: Distance should equal sum of segments, rightwinded Given the node map @@ -43,7 +43,7 @@ Feature: Distance calculation When I route I should get | from | to | route | distance | - | a | d | abcde | 300m +-8 | + | a | d | abcde | 300m +-2 | Scenario: 10m distances Given a grid size of 10 meters diff --git a/features/testbot/duration.feature b/features/testbot/duration.feature new file mode 100644 index 000000000..ab6571ce5 --- /dev/null +++ b/features/testbot/duration.feature @@ -0,0 +1,42 @@ +@routing @testbot @routes @duration +Feature: Durations + + Background: + Given the profile "testbot" + + Scenario: Duration of ways + Given the node map + | a | b | | | | f | + | | | | e | | | + | | c | | | d | | + + And the ways + | nodes | highway | duration | + | ab | primary | 0:01 | + | bc | primary | 0:10 | + | cd | primary | 1:00 | + | de | primary | 10:00 | + | ef | primary | 01:02:03 | + + When I route I should get + | from | to | route | distance | time | + | a | b | ab | 100m +-1 | 60s +-1 | + | b | c | bc | 200m +-1 | 600s +-1 | + | c | d | cd | 300m +-1 | 3600s +-1 | + | d | e | de | 144m +-2 | 36000s +-1 | + | e | f | ef | 224m +-2 | 3723s +-1 | + + @todo + Scenario: Partial duration of ways + Given the node map + | a | b | | c | + + And the ways + | nodes | highway | duration | + | abc | primary | 0:01 | + + When I route I should get + | from | to | route | distance | time | + | a | c | abc | 300m +-1 | 60s +-1 | + | a | b | ab | 100m +-1 | 20s +-1 | + | b | c | bc | 200m +-1 | 40s +-1 | diff --git a/features/testbot/weight.feature b/features/testbot/fastest.feature similarity index 84% rename from features/testbot/weight.feature rename to features/testbot/fastest.feature index 0e3551ff2..572280cd7 100644 --- a/features/testbot/weight.feature +++ b/features/testbot/fastest.feature @@ -1,5 +1,5 @@ -@routing @weight -Feature: Choosing route based on length, speed, etc +@routing @fastest +Feature: Choosing fastest route Background: Given the profile "testbot" @@ -22,7 +22,7 @@ Feature: Choosing route based on length, speed, etc | x | y | xa,atb,by | | y | x | by,atb,xa | - Scenario: Pick the shortest travel time, even when it's longer + Scenario: Pick the fastest route, even when it's longer Given the node map | | p | | | a | s | b | diff --git a/features/testbot/ferry.feature b/features/testbot/ferry.feature index aadd083c0..7bd43534e 100644 --- a/features/testbot/ferry.feature +++ b/features/testbot/ferry.feature @@ -7,21 +7,61 @@ Feature: Testbot - Handle ferry routes Scenario: Testbot - Ferry duration, single node Given the node map | a | b | c | d | - | | | e | f | - | | | g | h | - | | | i | j | - + | e | f | g | h | + | i | j | k | l | + | m | n | o | p | + | q | r | s | t | + And the ways - | nodes | highway | route | bicycle | duration | - | ab | primary | | | | - | cd | primary | | | | - | ef | primary | | | | - | gh | primary | | | | - | ij | primary | | | | - | bc | | ferry | yes | 0:01 | - | be | | ferry | yes | 0:10 | - | bg | | ferry | yes | 1:00 | - | bi | | ferry | yes | 10:00 | + | nodes | highway | route | duration | + | ab | primary | | | + | cd | primary | | | + | ef | primary | | | + | gh | primary | | | + | ij | primary | | | + | kl | primary | | | + | mn | primary | | | + | op | primary | | | + | qr | primary | | | + | st | primary | | | + | bc | | ferry | 0:01 | + | fg | | ferry | 0:10 | + | jk | | ferry | 1:00 | + | no | | ferry | 24:00 | + | rs | | ferry | 96:00 | + + When I route I should get + | from | to | route | time | + | b | c | bc | 60s +-1 | + | f | g | fg | 600s +-1 | + | j | k | jk | 3600s +-1 | + | n | o | no | 86400s +-1 | + | r | s | rs | 345600s +-1 | + + @todo + Scenario: Testbot - Week long ferry routes + Given the node map + | a | b | c | d | + | e | f | g | h | + | i | j | k | l | + + And the ways + | nodes | highway | route | duration | + | ab | primary | | | + | cd | primary | | | + | ef | primary | | | + | gh | primary | | | + | ij | primary | | | + | kl | primary | | | + | bc | | ferry | 24:00 | + | fg | | ferry | 168:00 | + | jk | | ferry | 720:00 | + + When I route I should get + | from | to | route | time | + | b | c | bc | 86400s +-1 | + | f | g | fg | 604800s +-1 | + | j | k | jk | 259200s +-1 | Scenario: Testbot - Ferry duration, multiple nodes Given the node map @@ -29,33 +69,107 @@ Feature: Testbot - Handle ferry routes | | a | b | c | d | | And the ways - | nodes | highway | route | bicycle | duration | - | xa | primary | | | | - | yd | primary | | | | - | abcd | | ferry | yes | 1:00 | + | nodes | highway | route | duration | + | xa | primary | | | + | yd | primary | | | + | ad | | ferry | 1:00 | When I route I should get | from | to | route | time | - | a | d | abcd | 3600s +-1 | - | d | a | abcd | 3600s +-1 | + | a | d | ad | 3600s +-1 | + | d | a | ad | 3600s +-1 | @todo - Scenario: Bike - Ferry duration, individual parts + Scenario: Testbot - Ferry duration, individual parts, fast + Given a grid size of 10000 meters Given the node map | x | y | | z | | | v | | a | b | | c | | | d | And the ways - | nodes | highway | route | bicycle | duration | - | xa | primary | | | | - | yb | primary | | | | - | zc | primary | | | | - | vd | primary | | | | - | abcd | | ferry | yes | 1:00 | + | nodes | highway | route | duration | + | xa | primary | | | + | yb | primary | | | + | zc | primary | | | + | vd | primary | | | + | abcd | | ferry | 0:06 | When I route I should get - | from | to | route | time | - | a | d | abcd | 3600s +-1 | - | a | b | abcd | 600s +-1 | - | b | c | abcd | 1200s +-1 | - | c | d | abcd | 1800s +-1 | \ No newline at end of file + | from | to | route | time | + | a | d | abcd | 360s +-1 | + | a | b | abcd | 60s +-1 | + | b | c | abcd | 120s +-1 | + | c | d | abcd | 180s +-1 | + + @todo + Scenario: Testbot - Ferry duration, individual parts, slow + Given the node map + | x | y | | z | | | v | + | a | b | | c | | | d | + + And the ways + | nodes | highway | route | duration | + | xa | primary | | | + | yb | primary | | | + | zc | primary | | | + | vd | primary | | | + | abcd | | ferry | 1:00 | + + When I route I should get + | from | to | route | time | + | a | d | abcd | 3600s ~1% | + | a | b | abcd | 600s ~1% | + | b | c | abcd | 1200s ~1% | + | c | d | abcd | 1800s ~1% | + + Scenario: Testbot - Ferry duration, connected routes + Given the node map + | x | | | | d | | | | y | + | | a | b | c | | e | f | g | t | + + And the ways + | nodes | highway | route | duration | + | xa | primary | | | + | yg | primary | | | + | abcd | | ferry | 0:30 | + | defg | | ferry | 0:30 | + + When I route I should get + | from | to | route | time | + | a | g | abcd,defg | 3600s +-1 | + | g | a | defg,abcd | 3600s +-1 | + + Scenario: Testbot - Prefer road when faster than ferry + Given the node map + | x | a | b | c | | + | | | | | d | + | y | g | f | e | | + + And the ways + | nodes | highway | route | duration | + | xa | primary | | | + | yg | primary | | | + | xy | primary | | | + | abcd | | ferry | 0:01 | + | defg | | ferry | 0:01 | + + When I route I should get + | from | to | route | time | + | a | g | xa,xy,yg | 60s +-25% | + | g | a | yg,xy,xa | 60s +-25% | + + Scenario: Testbot - Long winding ferry route + Given the node map + | x | | b | | d | | f | | y | + | | a | | c | | e | | g | | + + And the ways + | nodes | highway | route | duration | + | xa | primary | | | + | yg | primary | | | + | abcdefg | | ferry | 6:30 | + + When I route I should get + | from | to | route | time | + | a | g | abcdefg | 23400s +-1 | + | g | a | abcdefg | 23400s +-1 | diff --git a/features/testbot/graph.feature b/features/testbot/graph.feature new file mode 100644 index 000000000..97a517119 --- /dev/null +++ b/features/testbot/graph.feature @@ -0,0 +1,22 @@ +@routing @graph +Feature: Basic Routing +Test the input data descibed on https://github.com/DennisOSRM/Project-OSRM/wiki/Graph-representation + + Background: + Given the profile "testbot" + + @smallest + Scenario: Graph transformation + Given the node map + | | | d | + | a | b | c | + | | | e | + + And the ways + | nodes | + | abc | + | dce | + + When I route I should get + | from | to | route | + | a | e | abc,dce | diff --git a/features/testbot/impedance.feature b/features/testbot/impedance.feature new file mode 100644 index 000000000..0e5362309 --- /dev/null +++ b/features/testbot/impedance.feature @@ -0,0 +1,96 @@ +@routing @testbot @impedance @todo +Feature: Setting impedance and speed separately +These tests assume that the speed is not factored into the impedance by OSRM internally. +Instead the speed can optionally be factored into the weiht in the lua profile. + +Note: With the default grid size of 100m, the diagonals has a length if 141.42m + + Background: + Given the profile "testbot" + + Scenario: Use impedance to pick route, even when longer/slower + Given the node map + | | s | | t | | u | | v | | + | a | | b | | c | | d | | e | + + And the ways + | nodes | impedance | + | ab | 1.3 | + | asb | 1 | + | bc | 1.5 | + | btc | 1 | + | cd | 0.015 | + | cud | 0.010 | + | de | 150000 | + | dve | 100000 | + + When I route I should get + | from | to | route | distance | + | a | b | ab | 200m +-1 | + | b | a | ab | 200m +-1 | + | b | c | btc | 282m +-1 | + | c | b | btc | 282m +-1 | + | c | d | cud | 282m +-1 | + | d | c | cud | 282m +-1 | + | d | e | dve | 282m +-1 | + | e | d | dve | 282m +-1 | + + Scenario: Weight should default to 1 + Given the node map + | | s | | t | | + | a | | b | | c | + + And the ways + | nodes | impedance | + | ab | 1.40 | + | asb | | + | bc | 1.42 | + | btc | | + + When I route I should get + | from | to | route | + | a | b | ab | + | b | a | ab | + | b | c | btc | + | c | b | btc | + + Scenario: Use both impedance and speed (multiplied) when picking route + OSRM should not factor speed into impedance internally. However, the profile can choose to do so, + and this test expect the testbot profile to do it. + Given the node map + | | s | | t | | + | a | | b | | c | + + And the ways + | nodes | impedance | highway | + | ab | 2.80 | primary | + | asb | 1 | secondary | + | bc | 2.84 | primary | + | btc | 1 | secondary | + + When I route I should get + | from | to | route | + | a | b | ab | + | b | a | ab | + | b | c | btc | + | c | b | btc | + + Scenario: Weight should influence neither speed nor travel time. + Given the node map + | a | b | c | + | t | | | + + And the ways + | nodes | + | ab | + | bc | + | at | + + When I route I should get + | from | to | route | distance | time | + | a | b | ab | 100m +-1 | 10s +-1 | + | b | a | ab | 100m +-1 | 10s +-1 | + | b | c | bc | 100m +-1 | 10s +-1 | + | c | b | bc | 100m +-1 | 10s +-1 | + | a | c | ab,bc | 200m +-1 | 20s +-1 | + | c | a | bc,ab | 200m +-1 | 20s +-1 | diff --git a/features/testbot/maxspeed.feature b/features/testbot/maxspeed.feature new file mode 100644 index 000000000..c6b210e48 --- /dev/null +++ b/features/testbot/maxspeed.feature @@ -0,0 +1,52 @@ +@routing @maxspeed @testbot +Feature: Car - Max speed restrictions + + Background: Use specific speeds + Given the profile "testbot" + + Scenario: Testbot - Respect maxspeeds when lower that way type speed + Given the node map + | a | b | c | d | + + And the ways + | nodes | maxspeed | + | ab | | + | bc | 24 | + | cd | 18 | + + When I route I should get + | from | to | route | time | + | a | b | ab | 10s +-1 | + | b | a | ab | 10s +-1 | + | b | c | bc | 15s +-1 | + | c | b | bc | 15s +-1 | + | c | d | cd | 20s +-1 | + | d | c | cd | 20s +-1 | + + Scenario: Testbot - Ignore maxspeed when higher than way speed + Given the node map + | a | b | c | + + And the ways + | nodes | maxspeed | + | ab | | + | bc | 200 | + + When I route I should get + | from | to | route | time | + | a | b | ab | 10s +-1 | + | b | a | ab | 10s +-1 | + | b | c | bc | 10s +-1 | + | c | b | bc | 10s +-1 | + + @opposite + Scenario: Testbot - Forward/backward maxspeed + Then routability should be + | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw | + | | | | 20s +-1 | 20s +-1 | + | 18 | | | 40s +-1 | 40s +-1 | + | | 18 | | 40s +-1 | 20s +-1 | + | | | 18 | 20s +-1 | 40s +-1 | + | 9 | 18 | | 40s +-1 | 80s +-1 | + | 9 | | 18 | 80s +-1 | 40s +-1 | + | 9 | 24 | 18 | 30s +-1 | 40s +-1 | \ No newline at end of file diff --git a/features/testbot/opposite.feature b/features/testbot/opposite.feature new file mode 100644 index 000000000..c242c97b1 --- /dev/null +++ b/features/testbot/opposite.feature @@ -0,0 +1,18 @@ +@routing @testbot @opposite +Feature: Separate settings for forward/backward direction + + Background: + Given the profile "testbot" + + Scenario: Testbot - Going against the flow + Given the node map + | a | b | c | d | + + And the ways + | nodes | highway | + | abcd | river | + + When I route I should get + | from | to | route | distance | time | + | a | d | abcd | 300 +- 1m | 30s | + | d | a | abcd | 300 +- 1m | 68s | \ No newline at end of file diff --git a/features/testbot/routes.feature b/features/testbot/routes.feature new file mode 100644 index 000000000..763b34793 --- /dev/null +++ b/features/testbot/routes.feature @@ -0,0 +1,35 @@ +@routing @testbot @routes @todo +Feature: OSM Route Relation + + Background: + Given the profile "testbot" + + Scenario: Prioritize ways that are part of route relations + This scenario assumes that the testbot uses an impedance of 0.5 for ways that are part of 'testbot' routes. + + Given the node map + | s | | | t | | | | + | a | | | b | | | c | + | | | | | | | | + | | | | u | | | v | + + And the ways + | nodes | + | ab | + | bc | + | as | + | stb | + | bu | + | uvc | + + And the relations + | type | route | way:route | + | route | testbot | as,stb | + | route | testbot | bu,uvc | + + When I route I should get + | from | to | route | distance | time | + | b | c | bc | 300m +-1 | 30s +-1 | + | c | b | bc | 300m +-1 | 30s +-1 | + | a | b | as,stb | 500m +-1 | 50s +-1 | + | b | a | stb,as | 500m +-1 | 50s +-1 | \ No newline at end of file diff --git a/features/testbot/turns.feature b/features/testbot/turns.feature index 34a0c9199..5a14c9e7b 100644 --- a/features/testbot/turns.feature +++ b/features/testbot/turns.feature @@ -97,19 +97,27 @@ Feature: Turn directions/codes | g | c | xg,xc | head,right,destination | | g | e | xg,xe | head,sharp_right,destination | - Scenario: Skadestuevej, København + Scenario: Turn instructions at high latitude https://github.com/DennisOSRM/Project-OSRM/issues/532 Given the node locations | node | lat | lon | - | a | 55.68679 | 12.52360 | - | b | 55.68745 | 12.52407 | - | c | 55.68720 | 12.52509 | + | a | 55.68740 | 12.52430 | + | b | 55.68745 | 12.52409 | + | c | 55.68711 | 12.52383 | + | x | -55.68740 | 12.52430 | + | y | -55.68745 | 12.52409 | + | z | -55.68711 | 12.52383 | And the ways | nodes | | ab | | bc | + | xy | + | yz | When I route I should get | from | to | route | turns | - | a | c | ab,bc | head,right,destination | + | a | c | ab,bc | head,left,destination | + | c | a | bc,ab | head,right,destination | + | x | z | xy,yz | head,right,destination | + | z | x | yz,xy | head,left,destination | diff --git a/profile.lua b/profile.lua index b2291c1b0..33a7247d6 100644 --- a/profile.lua +++ b/profile.lua @@ -1,13 +1,15 @@ -- Begin of globals +require("lib/access") -barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true} +barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true} access_tag_whitelist = { ["yes"] = true, ["motorcar"] = true, ["motor_vehicle"] = true, ["vehicle"] = true, ["permissive"] = true, ["designated"] = true } -access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestery"] = true } +access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true } access_tag_restricted = { ["destination"] = true, ["delivery"] = true } access_tags = { "motorcar", "motor_vehicle", "vehicle" } access_tags_hierachy = { "motorcar", "motor_vehicle", "vehicle", "access" } service_tag_restricted = { ["parking_aisle"] = true } ignore_in_grid = { ["ferry"] = true } +restriction_exception_tags = { "motorcar", "motor_vehicle", "vehicle" } speed_profile = { ["motorway"] = 90, @@ -26,6 +28,7 @@ speed_profile = { ["service"] = 15, -- ["track"] = 5, ["ferry"] = 5, + ["shuttle_train"] = 10, ["default"] = 50 } @@ -39,24 +42,9 @@ u_turn_penalty = 20 -- End of globals ---find first tag in access hierachy which is set -local function find_access_tag(source) - for i,v in ipairs(access_tags_hierachy) do - if source.tags:Holds(v) then - local tag = source.tags:Find(v) - if tag ~= '' then --and tag ~= "" then - return tag - end - end - end - return nil -end - -local function find_in_keyvals(keyvals, tag) - if keyvals:Holds(tag) then - return keyvals:Find(tag) - else - return nil +function get_exceptions(vector) + for i,v in ipairs(restriction_exception_tags) do + vector:Add(v) end end @@ -64,7 +52,7 @@ local function parse_maxspeed(source) if source == nil then return 0 end - local n = tonumber(source) + local n = tonumber(source:match("%d*")) if n == nil then n = 0 end @@ -76,7 +64,7 @@ end function node_function (node) local barrier = node.tags:Find ("barrier") - local access = find_access_tag(node) + local access = Access.find_access_tag(node, access_tags_hierachy) local traffic_signal = node.tags:Find("highway") --flag node if it carries a traffic light @@ -101,13 +89,7 @@ function node_function (node) end -function way_function (way, numberOfNodesInWay) - - -- A way must have two nodes or more - if(numberOfNodesInWay < 2) then - return 0; - end - +function way_function (way) -- First, get the properties of each way that we come across local highway = way.tags:Find("highway") local name = way.tags:Find("name") @@ -115,13 +97,15 @@ function way_function (way, numberOfNodesInWay) local junction = way.tags:Find("junction") local route = way.tags:Find("route") local maxspeed = parse_maxspeed(way.tags:Find ( "maxspeed") ) + local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward")) + local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward")) local barrier = way.tags:Find("barrier") local oneway = way.tags:Find("oneway") local cycleway = way.tags:Find("cycleway") local duration = way.tags:Find("duration") local service = way.tags:Find("service") local area = way.tags:Find("area") - local access = find_access_tag(way) + local access = Access.find_access_tag(way, access_tags_hierachy) -- Second, parse the way according to these properties @@ -148,29 +132,31 @@ function way_function (way, numberOfNodesInWay) end -- Handling ferries and piers - if (speed_profile[route] ~= nil and speed_profile[route] > 0) - then - if durationIsValid(duration) then - way.speed = math.max( parseDuration(duration) / math.max(1, numberOfNodesInWay-1) ); - way.is_duration_set = true - end - way.direction = Way.bidirectional - if speed_profile[route] ~= nil then - highway = route; - end - if not way.is_duration_set then - way.speed = speed_profile[highway] - end - end + if (speed_profile[route] ~= nil and speed_profile[route] > 0) then + if durationIsValid(duration) then + way.duration = math.max( parseDuration(duration), 1 ); + end + way.direction = Way.bidirectional + if speed_profile[route] ~= nil then + highway = route; + end + if tonumber(way.duration) < 0 then + way.speed = speed_profile[highway] + end + end -- Set the avg speed on the way if it is accessible by road class - if (speed_profile[highway] ~= nil and way.speed == -1 ) then - if 0 == maxspeed then - maxspeed = math.huge - end - way.speed = math.min(speed_profile[highway], maxspeed) + if (speed_profile[highway] ~= nil and way.speed == -1 ) then + if maxspeed > speed_profile[highway] then + way.speed = maxspeed + else + if 0 == maxspeed then + maxspeed = math.huge + end + way.speed = math.min(speed_profile[highway], maxspeed) end - + end + -- Set the avg speed on ways that are marked accessible if "" ~= highway and access_tag_whitelist[access] and way.speed == -1 then if 0 == maxspeed then @@ -203,7 +189,18 @@ function way_function (way, numberOfNodesInWay) else way.direction = Way.bidirectional end - + + -- Override speed settings if explicit forward/backward maxspeeds are given + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + if Way.bidirectional == way.direction then + way.backward_speed = way.speed + end + way.speed = maxspeed_forward + end + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + way.backward_speed = maxspeed_backward + end + -- Override general direction settings of there is a specific one for our mode of travel if ignore_in_grid[highway] ~= nil and ignore_in_grid[highway] then diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua index c27771b14..96c06b555 100644 --- a/profiles/bicycle.lua +++ b/profiles/bicycle.lua @@ -1,39 +1,41 @@ +require("lib/access") + -- Begin of globals -barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true} +barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true} access_tag_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true } access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestery"] = true } access_tag_restricted = { ["destination"] = true, ["delivery"] = true } access_tags_hierachy = { "bicycle", "vehicle", "access" } cycleway_tags = {["track"]=true,["lane"]=true,["opposite"]=true,["opposite_lane"]=true,["opposite_track"]=true,["share_busway"]=true,["sharrow"]=true,["shared"]=true } service_tag_restricted = { ["parking_aisle"] = true } +restriction_exception_tags = { "bicycle", "vehicle", "access" } -default_speed = 16 +default_speed = 15 -main_speeds = { - ["cycleway"] = 18, - ["primary"] = 17, - ["primary_link"] = 17, - ["secondary"] = 18, - ["secondary_link"] = 18, - ["tertiary"] = 18, - ["tertiary_link"] = 18, - ["residential"] = 18, - ["unclassified"] = 16, - ["living_street"] = 16, - ["road"] = 16, - ["service"] = 16, - ["track"] = 13, - ["path"] = 13, - ["footway"] = 12, - ["pedestrian"] = 12, - ["pier"] = 12, - ["steps"] = 2 +walking_speed = 6 + +bicycle_speeds = { + ["cycleway"] = default_speed, + ["primary"] = default_speed, + ["primary_link"] = default_speed, + ["secondary"] = default_speed, + ["secondary_link"] = default_speed, + ["tertiary"] = default_speed, + ["tertiary_link"] = default_speed, + ["residential"] = default_speed, + ["unclassified"] = default_speed, + ["living_street"] = default_speed, + ["road"] = default_speed, + ["service"] = default_speed, + ["track"] = 12, + ["path"] = 12 + --["footway"] = 12, + --["pedestrian"] = 12, } pedestrian_speeds = { - ["footway"] = 5, - ["pedestrian"] = 5, - ["pier"] = 5, + ["footway"] = walking_speed, + ["pedestrian"] = walking_speed, ["steps"] = 2 } @@ -47,7 +49,7 @@ railway_speeds = { } platform_speeds = { - ["platform"] = 5 + ["platform"] = walking_speed } amenity_speeds = { @@ -55,6 +57,10 @@ amenity_speeds = { ["parking_entrance"] = 10 } +man_made_speeds = { + ["pier"] = walking_speed +} + route_speeds = { ["ferry"] = 5 } @@ -64,25 +70,22 @@ obey_oneway = true obey_bollards = false use_restrictions = true ignore_areas = true -- future feature -traffic_signal_penalty = 2 +traffic_signal_penalty = 5 u_turn_penalty = 20 - +use_turn_restrictions = false +turn_penalty = 60 +turn_bias = 1.4 -- End of globals ---find first tag in access hierachy which is set -function find_access_tag(source) - for i,v in ipairs(access_tags_hierachy) do - local tag = source.tags:Find(v) - if tag ~= '' then --and tag ~= "" then - return tag - end +function get_exceptions(vector) + for i,v in ipairs(restriction_exception_tags) do + vector:Add(v) end - return nil end function node_function (node) local barrier = node.tags:Find ("barrier") - local access = find_access_tag(node) + local access = Access.find_access_tag(node, access_tags_hierachy) local traffic_signal = node.tags:Find("highway") -- flag node if it carries a traffic light @@ -91,7 +94,7 @@ function node_function (node) end -- parse access and barrier tags - if access and access ~= "" then + if access and access ~= "" then if access_tag_blacklist[access] then node.bollard = true else @@ -108,22 +111,43 @@ function node_function (node) return 1 end -function way_function (way, numberOfNodesInWay) - -- A way must have two nodes or more - if(numberOfNodesInWay < 2) then - return 0; - end - - -- First, get the properties of each way that we come across +function way_function (way) + -- initial routability check, filters out buildings, boundaries, etc local highway = way.tags:Find("highway") + local route = way.tags:Find("route") + local man_made = way.tags:Find("man_made") + local railway = way.tags:Find("railway") + local amenity = way.tags:Find("amenity") + local public_transport = way.tags:Find("public_transport") + if (not highway or highway == '') and + (not route or route == '') and + (not railway or railway=='') and + (not amenity or amenity=='') and + (not man_made or man_made=='') and + (not public_transport or public_transport=='') + then + return 0 + end + + -- don't route on ways or railways that are still under construction + if highway=='construction' or railway=='construction' then + return 0 + end + + -- access + local access = Access.find_access_tag(way, access_tags_hierachy) + if access_tag_blacklist[access] then + return 0 + end + + + -- other tags local name = way.tags:Find("name") local ref = way.tags:Find("ref") local junction = way.tags:Find("junction") - local route = way.tags:Find("route") - local railway = way.tags:Find("railway") - local public_transport = way.tags:Find("public_transport") local maxspeed = parseMaxspeed(way.tags:Find ( "maxspeed") ) - local man_made = way.tags:Find("man_made") + local maxspeed_forward = parseMaxspeed(way.tags:Find( "maxspeed:forward")) + local maxspeed_backward = parseMaxspeed(way.tags:Find( "maxspeed:backward")) local barrier = way.tags:Find("barrier") local oneway = way.tags:Find("oneway") local onewayClass = way.tags:Find("oneway:bicycle") @@ -133,23 +157,7 @@ function way_function (way, numberOfNodesInWay) local duration = way.tags:Find("duration") local service = way.tags:Find("service") local area = way.tags:Find("area") - local amenity = way.tags:Find("amenity") - local access = find_access_tag(way) - - -- initial routability check, filters out buildings, boundaries, etc - if (not highway or highway == '') and - (not route or route == '') and - (not railway or railway=='') and - (not amenity or amenity=='') and - (not public_transport or public_transport=='') - then - return 0 - end - - -- access - if access_tag_blacklist[access] then - return 0 - end + local foot = way.tags:Find("foot") -- name if "" ~= ref then @@ -160,13 +168,13 @@ function way_function (way, numberOfNodesInWay) way.name = highway -- if no name exists, use way type end + -- speed if route_speeds[route] then - -- ferries + -- ferries (doesn't cover routes tagged using relations) way.direction = Way.bidirectional way.ignore_in_grid = true if durationIsValid(duration) then - way.speed = math.max( parseDuration(duration) / math.max(1, numberOfNodesInWay-1) ) - way.is_duration_set = true + way.duration = math.max( 1, parseDuration(duration) ) else way.speed = route_speeds[route] end @@ -182,34 +190,32 @@ function way_function (way, numberOfNodesInWay) way.speed = railway_speeds[railway] way.direction = Way.bidirectional end - elseif pedestrian_speeds[highway] and main_speeds[highway] then - -- pedestrian areas - if access_tag_whitelist[access] then - way.speed = main_speeds[highway] -- biking - else - way.speed = pedestrian_speeds[highway] -- pushing bikes - end elseif amenity and amenity_speeds[amenity] then -- parking areas way.speed = amenity_speeds[amenity] - else + elseif bicycle_speeds[highway] then -- regular ways - if main_speeds[highway] then - way.speed = main_speeds[highway] - elseif main_speeds[man_made] then - way.speed = main_speeds[man_made] - elseif access_tag_whitelist[access] then - way.speed = default_speed - end - end - - -- maxspeed - if take_minimum_of_speeds then - if maxspeed and maxspeed>0 then - way.speed = math.min(way.speed, maxspeed) - end - end - + way.speed = bicycle_speeds[highway] + elseif access and access_tag_whitelist[access] then + -- unknown way, but valid access tag + way.speed = default_speed + else + -- biking not allowed, maybe we can push our bike? + -- essentially requires pedestrian profiling, for example foot=no mean we can't push a bike + -- TODO: if we can push, the way should be marked as pedestrion mode, but there's no way to do it yet from lua.. + if foot ~= 'no' then + if pedestrian_speeds[highway] then + -- pedestrian-only ways and areas + way.speed = pedestrian_speeds[highway] + elseif man_made and man_made_speeds[man_made] then + -- man made structures + way.speed = man_made_speeds[man_made] + elseif foot == 'yes' then + way.speed = walking_speed + end + end + end + -- direction way.direction = Way.bidirectional local impliedOneway = false @@ -252,15 +258,65 @@ function way_function (way, numberOfNodesInWay) way.direction = Way.oneway end + -- pushing bikes + if bicycle_speeds[highway] or pedestrian_speeds[highway] then + if foot ~= 'no' then + if junction ~= "roundabout" then + if way.direction == Way.oneway then + way.backward_speed = walking_speed + elseif way.direction == Way.opposite then + way.backward_speed = walking_speed + way.speed = way.speed + end + end + end + if way.backward_speed == way.speed then + -- TODO: no way yet to mark a way as pedestrian mode if forward/backward speeds are equal + way.direction = Way.bidirectional + end + end + + -- cycleways if cycleway and cycleway_tags[cycleway] then - way.speed = main_speeds["cycleway"] + way.speed = bicycle_speeds["cycleway"] elseif cycleway_left and cycleway_tags[cycleway_left] then - way.speed = main_speeds["cycleway"] + way.speed = bicycle_speeds["cycleway"] elseif cycleway_right and cycleway_tags[cycleway_right] then - way.speed = main_speeds["cycleway"] + way.speed = bicycle_speeds["cycleway"] end + -- maxspeed + -- TODO: maxspeed of backward direction + if take_minimum_of_speeds then + if maxspeed and maxspeed>0 then + way.speed = math.min(way.speed, maxspeed) + end + end + + -- Override speed settings if explicit forward/backward maxspeeds are given + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + if Way.bidirectional == way.direction then + way.backward_speed = way.speed + end + way.speed = maxspeed_forward + end + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + way.backward_speed = maxspeed_backward + end + + + way.type = 1 return 1 end + +function turn_function (angle) + -- compute turn penalty as angle^2, with a left/right bias + k = turn_penalty/(90.0*90.0) + if angle>=0 then + return angle*angle*k/turn_bias + else + return angle*angle*k*turn_bias + end +end diff --git a/profiles/car.lua b/profiles/car.lua index 1e2d6c379..33a7247d6 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -1,6 +1,7 @@ -- Begin of globals +require("lib/access") -barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true} +barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true} access_tag_whitelist = { ["yes"] = true, ["motorcar"] = true, ["motor_vehicle"] = true, ["vehicle"] = true, ["permissive"] = true, ["designated"] = true } access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true } access_tag_restricted = { ["destination"] = true, ["delivery"] = true } @@ -8,6 +9,7 @@ access_tags = { "motorcar", "motor_vehicle", "vehicle" } access_tags_hierachy = { "motorcar", "motor_vehicle", "vehicle", "access" } service_tag_restricted = { ["parking_aisle"] = true } ignore_in_grid = { ["ferry"] = true } +restriction_exception_tags = { "motorcar", "motor_vehicle", "vehicle" } speed_profile = { ["motorway"] = 90, @@ -26,6 +28,7 @@ speed_profile = { ["service"] = 15, -- ["track"] = 5, ["ferry"] = 5, + ["shuttle_train"] = 10, ["default"] = 50 } @@ -39,24 +42,9 @@ u_turn_penalty = 20 -- End of globals ---find first tag in access hierachy which is set -local function find_access_tag(source) - for i,v in ipairs(access_tags_hierachy) do - if source.tags:Holds(v) then - local tag = source.tags:Find(v) - if tag ~= '' then --and tag ~= "" then - return tag - end - end - end - return nil -end - -local function find_in_keyvals(keyvals, tag) - if keyvals:Holds(tag) then - return keyvals:Find(tag) - else - return nil +function get_exceptions(vector) + for i,v in ipairs(restriction_exception_tags) do + vector:Add(v) end end @@ -64,7 +52,7 @@ local function parse_maxspeed(source) if source == nil then return 0 end - local n = tonumber(source) + local n = tonumber(source:match("%d*")) if n == nil then n = 0 end @@ -76,7 +64,7 @@ end function node_function (node) local barrier = node.tags:Find ("barrier") - local access = find_access_tag(node) + local access = Access.find_access_tag(node, access_tags_hierachy) local traffic_signal = node.tags:Find("highway") --flag node if it carries a traffic light @@ -101,13 +89,7 @@ function node_function (node) end -function way_function (way, numberOfNodesInWay) - - -- A way must have two nodes or more - if(numberOfNodesInWay < 2) then - return 0; - end - +function way_function (way) -- First, get the properties of each way that we come across local highway = way.tags:Find("highway") local name = way.tags:Find("name") @@ -115,13 +97,15 @@ function way_function (way, numberOfNodesInWay) local junction = way.tags:Find("junction") local route = way.tags:Find("route") local maxspeed = parse_maxspeed(way.tags:Find ( "maxspeed") ) + local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward")) + local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward")) local barrier = way.tags:Find("barrier") local oneway = way.tags:Find("oneway") local cycleway = way.tags:Find("cycleway") local duration = way.tags:Find("duration") local service = way.tags:Find("service") local area = way.tags:Find("area") - local access = find_access_tag(way) + local access = Access.find_access_tag(way, access_tags_hierachy) -- Second, parse the way according to these properties @@ -148,29 +132,31 @@ function way_function (way, numberOfNodesInWay) end -- Handling ferries and piers - if (speed_profile[route] ~= nil and speed_profile[route] > 0) - then - if durationIsValid(duration) then - way.speed = math.max( parseDuration(duration) / math.max(1, numberOfNodesInWay-1) ); - way.is_duration_set = true - end - way.direction = Way.bidirectional - if speed_profile[route] ~= nil then - highway = route; - end - if not way.is_duration_set then - way.speed = speed_profile[highway] - end - end + if (speed_profile[route] ~= nil and speed_profile[route] > 0) then + if durationIsValid(duration) then + way.duration = math.max( parseDuration(duration), 1 ); + end + way.direction = Way.bidirectional + if speed_profile[route] ~= nil then + highway = route; + end + if tonumber(way.duration) < 0 then + way.speed = speed_profile[highway] + end + end -- Set the avg speed on the way if it is accessible by road class - if (speed_profile[highway] ~= nil and way.speed == -1 ) then - if 0 == maxspeed then - maxspeed = math.huge - end - way.speed = math.min(speed_profile[highway], maxspeed) + if (speed_profile[highway] ~= nil and way.speed == -1 ) then + if maxspeed > speed_profile[highway] then + way.speed = maxspeed + else + if 0 == maxspeed then + maxspeed = math.huge + end + way.speed = math.min(speed_profile[highway], maxspeed) end - + end + -- Set the avg speed on ways that are marked accessible if "" ~= highway and access_tag_whitelist[access] and way.speed == -1 then if 0 == maxspeed then @@ -203,7 +189,18 @@ function way_function (way, numberOfNodesInWay) else way.direction = Way.bidirectional end - + + -- Override speed settings if explicit forward/backward maxspeeds are given + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + if Way.bidirectional == way.direction then + way.backward_speed = way.speed + end + way.speed = maxspeed_forward + end + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + way.backward_speed = maxspeed_backward + end + -- Override general direction settings of there is a specific one for our mode of travel if ignore_in_grid[highway] ~= nil and ignore_in_grid[highway] then diff --git a/profiles/foot.lua b/profiles/foot.lua index 596917aa5..6a15fb2ea 100644 --- a/profiles/foot.lua +++ b/profiles/foot.lua @@ -9,6 +9,7 @@ access_tag_restricted = { ["destination"] = true, ["delivery"] = true } access_tags = { "foot" } service_tag_restricted = { ["parking_aisle"] = true } ignore_in_grid = { ["ferry"] = true } +restriction_exception_tags = { "foot" } speed_profile = { ["primary"] = 5, @@ -40,9 +41,15 @@ use_restrictions = false ignore_areas = true -- future feature traffic_signal_penalty = 2 u_turn_penalty = 2 - +use_turn_restrictions = false -- End of globals +function get_exceptions(vector) + for i,v in ipairs(restriction_exception_tags) do + vector:Add(v) + end +end + function node_function (node) local barrier = node.tags:Find ("barrier") local access = node.tags:Find ("access") @@ -68,13 +75,8 @@ function node_function (node) return 1 end -function way_function (way, numberOfNodesInWay) +function way_function (way) - -- A way must have two nodes or more - if(numberOfNodesInWay < 2) then - return 0; - end - -- First, get the properties of each way that we come across local highway = way.tags:Find("highway") local name = way.tags:Find("name") @@ -145,10 +147,7 @@ function way_function (way, numberOfNodesInWay) -- Set the avg speed on the way if it is accessible by road class if (speed_profile[highway] ~= nil and way.speed == -1 ) then - if (0 < maxspeed and not take_minimum_of_speeds) or (maxspeed == 0) then - maxspeed = math.huge - end - way.speed = math.min(speed_profile[highway], maxspeed) + way.speed = speed_profile[highway] end -- Set the avg speed on ways that are marked accessible diff --git a/profiles/lib/access.lua b/profiles/lib/access.lua new file mode 100644 index 000000000..a1e2fcf4d --- /dev/null +++ b/profiles/lib/access.lua @@ -0,0 +1,13 @@ +local ipairs = ipairs + +module "Access" + +function find_access_tag(source,access_tags_hierachy) + for i,v in ipairs(access_tags_hierachy) do + local tag = source.tags:Find(v) + if tag ~= '' then + return tag + end + end + return nil +end \ No newline at end of file diff --git a/profiles/testbot.lua b/profiles/testbot.lua index 3eb1ff339..f934fead5 100644 --- a/profiles/testbot.lua +++ b/profiles/testbot.lua @@ -23,6 +23,18 @@ ignore_areas = true -- future feature traffic_signal_penalty = 7 -- seconds u_turn_penalty = 20 +function limit_speed(speed, limits) + -- don't use ipairs(), since it stops at the first nil value + for i=1, #limits do + limit = limits[i] + if limit ~= nil and limit > 0 then + if limit < speed then + return limit -- stop at first speedlimit that's smaller than speed + end + end + end + return speed +end function node_function (node) local traffic_signal = node.tags:Find("highway") @@ -34,26 +46,50 @@ function node_function (node) return 1 end -function way_function (way, numberOfNodesInWay) - -- A way must have two nodes or more - if(numberOfNodesInWay < 2) then - return 0; - end - +function way_function (way) local highway = way.tags:Find("highway") local name = way.tags:Find("name") local oneway = way.tags:Find("oneway") local route = way.tags:Find("route") local duration = way.tags:Find("duration") + local maxspeed = tonumber(way.tags:Find ( "maxspeed")) + local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward")) + local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward")) way.name = name if route ~= nil and durationIsValid(duration) then - way.ignore_in_grid = true - way.speed = math.max( 1, parseDuration(duration) / math.max(1, numberOfNodesInWay-1) ) - way.is_duration_set = true + way.duration = math.max( 1, parseDuration(duration) ) else - way.speed = speed_profile[highway] or speed_profile['default'] + local speed_forw = speed_profile[highway] or speed_profile['default'] + local speed_back = speed_forw + + if highway == "river" then + local temp_speed = speed_forw; + speed_forw = temp_speed*1.5 + speed_back = temp_speed/1.5 + end + + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + speed_forw = maxspeed_forward + else + if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then + speed_forw = maxspeed + end + end + + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + speed_back = maxspeed_backward + else + if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then + speed_back = maxspeed + end + end + + way.speed = speed_forw + if speed_back ~= way_forw then + way.backward_speed = speed_back + end end if oneway == "no" or oneway == "0" or oneway == "false" then diff --git a/profiles/turnbot.lua b/profiles/turnbot.lua new file mode 100644 index 000000000..1a96966f1 --- /dev/null +++ b/profiles/turnbot.lua @@ -0,0 +1,8 @@ +-- Testbot, with turn penalty +-- Used for testing turn penalties + +require 'testbot' + +function turn_function (angle) + return 200*math.abs(angle)/180 -- penalty +end diff --git a/test/.stxxl b/test/.stxxl index d26050d7f..b1765e2c0 100644 --- a/test/.stxxl +++ b/test/.stxxl @@ -1 +1 @@ -disk=/tmp/stxxl,1,syscall +disk=/tmp/stxxl,10,syscall diff --git a/typedefs.h b/typedefs.h index 852e71ad6..32807130e 100644 --- a/typedefs.h +++ b/typedefs.h @@ -21,22 +21,20 @@ or see http://www.gnu.org/licenses/agpl.txt. #ifndef TYPEDEFS_H_ #define TYPEDEFS_H_ +#include +#include +#include + +// To fix long and long long woes +#include +#include + #ifdef __APPLE__ #include #endif -#include -#include -#include #include -using namespace std; - -#ifdef STXXL_VERBOSE_LEVEL -#undef STXXL_VERBOSE_LEVEL -#endif -#define STXXL_VERBOSE_LEVEL -100 - #define INFO(x) do {std::cout << "[info " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl;} while(0); #define ERR(x) do {std::cerr << "[error " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl; std::exit(-1);} while(0); #define WARN(x) do {std::cerr << "[warn " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl;} while(0); @@ -53,7 +51,7 @@ using namespace std; #define M_PI 3.14159265358979323846 #endif -//Necessary workaround for Windows as VS doesn't implement C99 +// Necessary workaround for Windows as VS doesn't implement C99 #ifdef _MSC_VER template digitT round(digitT x) { @@ -66,7 +64,7 @@ typedef unsigned int NodeID; typedef unsigned int EdgeID; typedef unsigned int EdgeWeight; -static const NodeID SPECIAL_NODEID = UINT_MAX; -static const EdgeID SPECIAL_EDGEID = UINT_MAX; +static const NodeID SPECIAL_NODEID = boost::integer_traits::const_max; +static const EdgeID SPECIAL_EDGEID = boost::integer_traits::const_max; #endif /* TYPEDEFS_H_ */