Merging develop branch into master for v0.3.4 release

This commit is contained in:
Dennis Luxen 2013-06-28 10:30:34 -04:00
commit 828b370ea1
74 changed files with 3021 additions and 1365 deletions

6
.gitignore vendored
View File

@ -33,11 +33,9 @@ ehthumbs.db
Icon? Icon?
Thumbs.db Thumbs.db
# SCons related files # # build related files #
####################### #######################
SconsBuilder* /build/
.scon*
.build
# Eclipse related files # # Eclipse related files #
######################### #########################

View File

@ -30,7 +30,6 @@ class IteratorbasedCRC32 {
private: private:
typedef typename ContainerT::iterator ContainerT_iterator; typedef typename ContainerT::iterator ContainerT_iterator;
unsigned crc; unsigned crc;
unsigned slowcrc_table[1<<8];
typedef boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> my_crc_32_type; typedef boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> my_crc_32_type;
typedef unsigned (IteratorbasedCRC32::*CRC32CFunctionPtr)(char *str, unsigned len, unsigned crc); typedef unsigned (IteratorbasedCRC32::*CRC32CFunctionPtr)(char *str, unsigned len, unsigned crc);

111
CMakeLists.txt Normal file
View File

@ -0,0 +1,111 @@
cmake_minimum_required(VERSION 2.6)
project(OSRM)
include(FindPackageHandleStandardArgs)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(BOOST_COMPONENTS filesystem regex system thread)
file(GLOB ExtractorGlob Extractor/*.cpp)
set(ExtractorSources extractor.cpp ${ExtractorGlob})
add_executable(osrm-extract ${ExtractorSources})
file(GLOB PrepareGlob Contractor/*.cpp)
set(PrepareSources createHierarchy.cpp ${PrepareGlob})
add_executable(osrm-prepare ${PrepareSources})
file(GLOB RoutedGlob Server/DataStructures/*.cpp Descriptors/*.cpp DataStructures/SearchEngine*.cpp)
set(RoutedSources routed.cpp ${RoutedGlob})
add_executable(osrm-routed ${RoutedSources})
set_target_properties(osrm-routed PROPERTIES COMPILE_FLAGS -DROUTED)
# Check the release mode
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
set(CMAKE_BUILD_TYPE Release)
endif(NOT CMAKE_BUILD_TYPE MATCHES Debug)
if(CMAKE_BUILD_TYPE MATCHES Debug)
message(STATUS "Configuring OSRM in debug mode")
endif(CMAKE_BUILD_TYPE MATCHES Debug)
if(CMAKE_BUILD_TYPE MATCHES Release)
message(STATUS "Configuring OSRM in release mode")
endif(CMAKE_BUILD_TYPE MATCHES Release)
#Configuring compilers
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# using Clang
set(CMAKE_CXX_FLAGS "-Wall -Wno-unknown-pragmas -Wno-unneeded-internal-declaration")
message(STATUS "OpenMP parallelization not available using clang++")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# using GCC
set(CMAKE_CXX_FLAGS "-Wall -fopenmp -pedantic")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
# using Intel C++
set(CMAKE_CXX_FLAGS "-static-intel -wd10237 -Wall -openmp -ipo")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
endif()
if(APPLE)
SET(CMAKE_OSX_ARCHITECTURES "x86_64")
message("Set Architecture to x64 on OS X")
endif()
#Check Boost
set(BOOST_MIN_VERSION "1.44.0")
find_package( Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED )
if (NOT Boost_FOUND)
message(FATAL_ERROR "Fatal error: Boost (version >= 1.44.0) required.\n")
endif (NOT Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries( osrm-extract ${Boost_LIBRARIES} )
target_link_libraries( osrm-prepare ${Boost_LIBRARIES} )
target_link_libraries( osrm-routed ${Boost_LIBRARIES} )
find_package ( BZip2 REQUIRED )
include_directories(${BZIP_INCLUDE_DIRS})
target_link_libraries (osrm-extract ${BZIP2_LIBRARIES})
find_package( ZLIB REQUIRED )
target_link_libraries (osrm-extract ${ZLIB_LIBRARY})
target_link_libraries (osrm-routed ${ZLIB_LIBRARY})
find_package( Threads REQUIRED )
target_link_libraries (osrm-extract ${Threads_LIBRARY})
find_package( Lua51 REQUIRED )
include_directories(${LUA_INCLUDE_DIR})
target_link_libraries( osrm-extract ${LUA_LIBRARY} )
target_link_libraries( osrm-prepare ${LUA_LIBRARY} )
find_package( LibXml2 REQUIRED )
include_directories(${LIBXML2_INCLUDE_DIR})
target_link_libraries (osrm-extract ${LIBXML2_LIBRARIES})
find_package( Luabind REQUIRED )
include_directories(${LUABIND_INCLUDE_DIR})
target_link_libraries (osrm-extract ${LUABIND_LIBRARY})
target_link_libraries (osrm-prepare ${LUABIND_LIBRARY})
find_package( Protobuf REQUIRED )
include_directories(${PROTOBUF_INCLUDE_DIRS})
target_link_libraries (osrm-extract ${PROTOBUF_LIBRARY})
target_link_libraries (osrm-prepare ${PROTOBUF_LIBRARY})
find_package( STXXL REQUIRED )
include_directories(${STXXL_INCLUDE_DIR})
target_link_libraries (osrm-extract ${STXXL_LIBRARY})
target_link_libraries (osrm-prepare ${STXXL_LIBRARY})
find_package( OSMPBF REQUIRED )
include_directories(${OSMPBF_INCLUDE_DIR})
target_link_libraries (osrm-extract ${OSMPBF_LIBRARY})
target_link_libraries (osrm-prepare ${OSMPBF_LIBRARY})
if(WITH_TOOLS)
message("-- Activating OSRM internal tools")
find_package( GDAL )
if(GDAL_FOUND)
add_executable(osrm-components Tools/componentAnalysis.cpp)
include_directories(${GDAL_INCLUDE_DIR})
target_link_libraries( osrm-components ${GDAL_LIBRARIES} )
target_link_libraries( osrm-components ${Boost_LIBRARIES} )
endif(GDAL_FOUND)
endif(WITH_TOOLS)

View File

@ -20,17 +20,6 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef CONTRACTOR_H_INCLUDED #ifndef CONTRACTOR_H_INCLUDED
#define CONTRACTOR_H_INCLUDED #define CONTRACTOR_H_INCLUDED
#include <algorithm>
#include <limits>
#include <vector>
#include <cfloat>
#include <ctime>
#include <boost/foreach.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include "TemporaryStorage.h" #include "TemporaryStorage.h"
#include "../DataStructures/BinaryHeap.h" #include "../DataStructures/BinaryHeap.h"
@ -42,6 +31,19 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "../Util/OpenMPWrapper.h" #include "../Util/OpenMPWrapper.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include <boost/assert.hpp>
#include <boost/foreach.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <cfloat>
#include <ctime>
#include <algorithm>
#include <limits>
#include <vector>
class Contractor { class Contractor {
private: private:
@ -119,7 +121,7 @@ public:
newEdge.target = diter->target(); newEdge.target = diter->target();
newEdge.data = _ContractorEdgeData( (std::max)((int)diter->weight(), 1 ), 1, diter->id(), false, diter->isForward(), diter->isBackward()); newEdge.data = _ContractorEdgeData( (std::max)((int)diter->weight(), 1 ), 1, diter->id(), false, diter->isForward(), diter->isBackward());
assert( newEdge.data.distance > 0 ); BOOST_ASSERT_MSG( newEdge.data.distance > 0, "edge distance < 1" );
#ifndef NDEBUG #ifndef NDEBUG
if ( newEdge.data.distance > 24 * 60 * 60 * 10 ) { if ( newEdge.data.distance > 24 * 60 * 60 * 10 ) {
WARN("Edge weight large -> " << newEdge.data.distance); WARN("Edge weight large -> " << newEdge.data.distance);
@ -232,8 +234,9 @@ public:
//initialize the variables //initialize the variables
#pragma omp parallel for schedule ( guided ) #pragma omp parallel for schedule ( guided )
for ( int x = 0; x < ( int ) numberOfNodes; ++x ) for ( int x = 0; x < ( int ) numberOfNodes; ++x ) {
remainingNodes[x].id = x; remainingNodes[x].id = x;
}
std::cout << "initializing elimination PQ ..." << std::flush; std::cout << "initializing elimination PQ ..." << std::flush;
#pragma omp parallel #pragma omp parallel
@ -247,7 +250,7 @@ public:
std::cout << "ok" << std::endl << "preprocessing " << numberOfNodes << " nodes ..." << std::flush; std::cout << "ok" << std::endl << "preprocessing " << numberOfNodes << " nodes ..." << std::flush;
bool flushedContractor = false; bool flushedContractor = false;
while ( numberOfContractedNodes < numberOfNodes ) { while ( numberOfNodes > 2 && numberOfContractedNodes < numberOfNodes ) {
if(!flushedContractor && (numberOfContractedNodes > (numberOfNodes*0.65) ) ){ if(!flushedContractor && (numberOfContractedNodes > (numberOfNodes*0.65) ) ){
DeallocatingVector<_ContractorEdge> newSetOfEdges; //this one is not explicitely cleared since it goes out of scope anywa DeallocatingVector<_ContractorEdge> newSetOfEdges; //this one is not explicitely cleared since it goes out of scope anywa
std::cout << " [flush " << numberOfContractedNodes << " nodes] " << std::flush; std::cout << " [flush " << numberOfContractedNodes << " nodes] " << std::flush;
@ -282,7 +285,6 @@ public:
//walk over all nodes //walk over all nodes
for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) { for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) {
//INFO("Restructuring node " << i << "|" << _graph->GetNumberOfNodes());
const NodeID start = i; const NodeID start = i;
for(_DynamicGraph::EdgeIterator currentEdge = _graph->BeginEdges(start); currentEdge < _graph->EndEdges(start); ++currentEdge) { for(_DynamicGraph::EdgeIterator currentEdge = _graph->BeginEdges(start); currentEdge < _graph->EndEdges(start); ++currentEdge) {
_DynamicGraph::EdgeData & data = _graph->GetEdgeData(currentEdge); _DynamicGraph::EdgeData & data = _graph->GetEdgeData(currentEdge);
@ -301,8 +303,14 @@ public:
newEdge.target = newNodeIDFromOldNodeIDMap[target]; newEdge.target = newNodeIDFromOldNodeIDMap[target];
newEdge.data = data; newEdge.data = data;
newEdge.data.originalViaNodeID = true; newEdge.data.originalViaNodeID = true;
assert(UINT_MAX != newNodeIDFromOldNodeIDMap[start] ); BOOST_ASSERT_MSG(
assert(UINT_MAX != newNodeIDFromOldNodeIDMap[target]); UINT_MAX != newNodeIDFromOldNodeIDMap[start],
"new start id not resolveable"
);
BOOST_ASSERT_MSG(
UINT_MAX != newNodeIDFromOldNodeIDMap[target],
"new target id not resolveable"
);
newSetOfEdges.push_back(newEdge); newSetOfEdges.push_back(newEdge);
} }
} }
@ -311,8 +319,6 @@ public:
tempStorage.seek(temporaryStorageSlotID, initialFilePosition); tempStorage.seek(temporaryStorageSlotID, initialFilePosition);
tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned)); tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned));
// INFO("Flushed " << numberOfTemporaryEdges << " edges to disk");
//Delete map from old NodeIDs to new ones. //Delete map from old NodeIDs to new ones.
std::vector<NodeID>().swap(newNodeIDFromOldNodeIDMap); std::vector<NodeID>().swap(newNodeIDFromOldNodeIDMap);
@ -438,38 +444,48 @@ public:
Percent p (_graph->GetNumberOfNodes()); Percent p (_graph->GetNumberOfNodes());
INFO("Getting edges of minimized graph"); INFO("Getting edges of minimized graph");
NodeID numberOfNodes = _graph->GetNumberOfNodes(); NodeID numberOfNodes = _graph->GetNumberOfNodes();
if(oldNodeIDFromNewNodeIDMap.size()) { if(_graph->GetNumberOfNodes()) {
for ( NodeID node = 0; node < numberOfNodes; ++node ) { for ( NodeID node = 0; node < numberOfNodes; ++node ) {
p.printStatus(node); p.printStatus(node);
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge < endEdges; ++edge ) { for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge < endEdges; ++edge ) {
const NodeID target = _graph->GetTarget( edge ); const NodeID target = _graph->GetTarget( edge );
const _DynamicGraph::EdgeData& data = _graph->GetEdgeData( edge ); const _DynamicGraph::EdgeData& data = _graph->GetEdgeData( edge );
Edge newEdge; Edge newEdge;
newEdge.source = oldNodeIDFromNewNodeIDMap[node]; if(0 != oldNodeIDFromNewNodeIDMap.size()) {
newEdge.target = oldNodeIDFromNewNodeIDMap[target]; newEdge.source = oldNodeIDFromNewNodeIDMap[node];
assert(UINT_MAX != newEdge.source); newEdge.target = oldNodeIDFromNewNodeIDMap[target];
assert(UINT_MAX != newEdge.target); } else {
newEdge.source = node;
newEdge.target = target;
}
BOOST_ASSERT_MSG(
UINT_MAX != newEdge.source,
"Source id invalid"
);
BOOST_ASSERT_MSG(
UINT_MAX != newEdge.target,
"Target id invalid"
);
newEdge.data.distance = data.distance; newEdge.data.distance = data.distance;
newEdge.data.shortcut = data.shortcut; newEdge.data.shortcut = data.shortcut;
if(!data.originalViaNodeID) if(!data.originalViaNodeID && oldNodeIDFromNewNodeIDMap.size()) {
newEdge.data.id = oldNodeIDFromNewNodeIDMap[data.id]; newEdge.data.id = oldNodeIDFromNewNodeIDMap[data.id];
else } else {
newEdge.data.id = data.id; newEdge.data.id = data.id;
}
assert(newEdge.data.id != UINT_MAX); BOOST_ASSERT_MSG(
newEdge.data.id <= INT_MAX, //2^31
"edge id invalid"
);
newEdge.data.forward = data.forward; newEdge.data.forward = data.forward;
newEdge.data.backward = data.backward; newEdge.data.backward = data.backward;
edges.push_back( newEdge ); edges.push_back( newEdge );
} }
} }
} }
INFO("Renumbered edges of minimized graph, freeing space");
_graph.reset(); _graph.reset();
std::vector<NodeID>().swap(oldNodeIDFromNewNodeIDMap); std::vector<NodeID>().swap(oldNodeIDFromNewNodeIDMap);
INFO("Loading temporary edges");
// std::ifstream temporaryEdgeStorage(temporaryEdgeStorageFilename.c_str(), std::ios::binary);
TemporaryStorage & tempStorage = TemporaryStorage::GetInstance(); TemporaryStorage & tempStorage = TemporaryStorage::GetInstance();
//Also get the edges from temporary storage //Also get the edges from temporary storage
unsigned numberOfTemporaryEdges = 0; unsigned numberOfTemporaryEdges = 0;
@ -494,7 +510,6 @@ public:
edges.push_back( newEdge ); edges.push_back( newEdge );
} }
tempStorage.deallocateSlot(temporaryStorageSlotID); tempStorage.deallocateSlot(temporaryStorageSlotID);
INFO("Hierarchy has " << edges.size() << " edges");
} }
private: private:
@ -517,24 +532,27 @@ private:
if ( heap.GetData( node ).target ) { if ( heap.GetData( node ).target ) {
++targetsFound; ++targetsFound;
if ( targetsFound >= numTargets ) if ( targetsFound >= numTargets ) {
return; return;
}
} }
//iterate over all edges of node //iterate over all edges of node
for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) { for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) {
const _ContractorEdgeData& data = _graph->GetEdgeData( edge ); const _ContractorEdgeData& data = _graph->GetEdgeData( edge );
if ( !data.forward ) if ( !data.forward ){
continue; continue;
}
const NodeID to = _graph->GetTarget( edge ); const NodeID to = _graph->GetTarget( edge );
if(middleNode == to) if(middleNode == to) {
continue; continue;
}
const int toDistance = distance + data.distance; const int toDistance = distance + data.distance;
//New Node discovered -> Add to Heap + Node Info Storage //New Node discovered -> Add to Heap + Node Info Storage
if ( !heap.WasInserted( to ) ) if ( !heap.WasInserted( to ) ) {
heap.Insert( to, toDistance, _HeapData(currentHop, false) ); heap.Insert( to, toDistance, _HeapData(currentHop, false) );
}
//Found a shorter Path -> Update distance //Found a shorter Path -> Update distance
else if ( toDistance < heap.GetKey( to ) ) { else if ( toDistance < heap.GetKey( to ) ) {
heap.DecreaseKey( to, toDistance ); heap.DecreaseKey( to, toDistance );
@ -584,8 +602,9 @@ private:
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) { for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge ); const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
if ( !outData.forward ) if ( !outData.forward ) {
continue; continue;
}
const NodeID target = _graph->GetTarget( outEdge ); const NodeID target = _graph->GetTarget( outEdge );
const int pathDistance = inData.distance + outData.distance; const int pathDistance = inData.distance + outData.distance;
maxDistance = std::max( maxDistance, pathDistance ); maxDistance = std::max( maxDistance, pathDistance );
@ -595,15 +614,16 @@ private:
} }
} }
if( Simulate ) if( Simulate ) {
_Dijkstra( maxDistance, numTargets, 1000, data, node ); _Dijkstra( maxDistance, numTargets, 1000, data, node );
else } else {
_Dijkstra( maxDistance, numTargets, 2000, data, node ); _Dijkstra( maxDistance, numTargets, 2000, data, node );
}
for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) { for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge ); const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
if ( !outData.forward ) if ( !outData.forward ) {
continue; continue;
}
const NodeID target = _graph->GetTarget( outEdge ); const NodeID target = _graph->GetTarget( outEdge );
const int pathDistance = inData.distance + outData.distance; const int pathDistance = inData.distance + outData.distance;
const int distance = heap.GetKey( target ); const int distance = heap.GetKey( target );
@ -643,8 +663,9 @@ private:
found = true; found = true;
break; break;
} }
if ( !found ) if ( !found ) {
insertedEdges[insertedEdgesSize++] = insertedEdges[i]; insertedEdges[insertedEdgesSize++] = insertedEdges[i];
}
} }
insertedEdges.resize( insertedEdgesSize ); insertedEdges.resize( insertedEdgesSize );
} }

View File

@ -89,11 +89,14 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vector<NodeBasedEdg
} }
void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector< EdgeBasedEdge >& outputEdgeList ) { void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector< EdgeBasedEdge >& outputEdgeList ) {
GUARANTEE(0 == outputEdgeList.size(), "Vector passed to EdgeBasedGraphFactory::GetEdgeBasedEdges(..) is not empty"); BOOST_ASSERT_MSG(
0 == outputEdgeList.size(),
"Vector is not empty"
);
edgeBasedEdges.swap(outputEdgeList); edgeBasedEdges.swap(outputEdgeList);
} }
void EdgeBasedGraphFactory::GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode> & nodes) { void EdgeBasedGraphFactory::GetEdgeBasedNodes( std::vector<EdgeBasedNode> & nodes) {
#ifndef NDEBUG #ifndef NDEBUG
BOOST_FOREACH(EdgeBasedNode & node, edgeBasedNodes){ BOOST_FOREACH(EdgeBasedNode & node, edgeBasedNodes){
assert(node.lat1 != INT_MAX); assert(node.lon1 != INT_MAX); assert(node.lat1 != INT_MAX); assert(node.lon1 != INT_MAX);
@ -282,7 +285,7 @@ void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename, lua_State
// turnInstruction |= TurnInstructions.AccessRestrictionFlag; // turnInstruction |= TurnInstructions.AccessRestrictionFlag;
// } // }
distance += penalty; distance += penalty;
//distance += heightPenalty; //distance += heightPenalty;
//distance += ComputeTurnPenalty(u, v, w); //distance += ComputeTurnPenalty(u, v, w);
@ -328,7 +331,7 @@ void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename, lua_State
TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, unsigned& penalty, lua_State *myLuaState) 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]); const double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]);
if( speedProfile.has_turn_penalty_function ) { if( speedProfile.has_turn_penalty_function ) {
try { try {
//call lua profile to compute turn penalty //call lua profile to compute turn penalty
@ -340,7 +343,7 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID
} else { } else {
penalty = 0; penalty = 0;
} }
if(u == w) { if(u == w) {
return TurnInstructions.UTurn; return TurnInstructions.UTurn;
} }

View File

@ -25,20 +25,6 @@
#ifndef EDGEBASEDGRAPHFACTORY_H_ #ifndef EDGEBASEDGRAPHFACTORY_H_
#define EDGEBASEDGRAPHFACTORY_H_ #define EDGEBASEDGRAPHFACTORY_H_
#include <algorithm>
#include <queue>
#include <vector>
#include <stxxl.h>
#include <cstdlib>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "../typedefs.h" #include "../typedefs.h"
#include "../DataStructures/DeallocatingVector.h" #include "../DataStructures/DeallocatingVector.h"
#include "../DataStructures/DynamicGraph.h" #include "../DataStructures/DynamicGraph.h"
@ -50,14 +36,22 @@
#include "../DataStructures/Percent.h" #include "../DataStructures/Percent.h"
#include "../DataStructures/TurnInstructions.h" #include "../DataStructures/TurnInstructions.h"
#include "../Util/BaseConfiguration.h" #include "../Util/BaseConfiguration.h"
#include "../Util/LuaUtil.h"
extern "C" { #include <stxxl.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include <luabind/luabind.hpp>
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
class EdgeBasedGraphFactory : boost::noncopyable { class EdgeBasedGraphFactory : boost::noncopyable {
public: public:
@ -65,9 +59,23 @@ public:
bool operator<(const EdgeBasedNode & other) const { bool operator<(const EdgeBasedNode & other) const {
return other.id < id; return other.id < id;
} }
bool operator==(const EdgeBasedNode & other) const { bool operator==(const EdgeBasedNode & other) const {
return id == other.id; return id == other.id;
} }
inline _Coordinate Centroid() const {
_Coordinate centroid;
//The coordinates of the midpoint are given by:
//x = (x1 + x2) /2 and y = (y1 + y2) /2.
centroid.lon = (std::min(lon1, lon2) + std::max(lon1, lon2))/2;
centroid.lat = (std::min(lat1, lat2) + std::max(lat1, lat2))/2;
return centroid;
}
inline bool isIgnored() const {
return ignoreInGrid;
}
NodeID id; NodeID id;
int lat1; int lat1;
int lat2; int lat2;
@ -127,7 +135,7 @@ private:
RestrictionMap _restrictionMap; RestrictionMap _restrictionMap;
DeallocatingVector<EdgeBasedEdge> edgeBasedEdges; DeallocatingVector<EdgeBasedEdge> edgeBasedEdges;
DeallocatingVector<EdgeBasedNode> edgeBasedNodes; std::vector<EdgeBasedNode> edgeBasedNodes;
NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const; NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const;
bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const; bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const;
@ -145,7 +153,7 @@ public:
void Run(const char * originalEdgeDataFilename, lua_State *myLuaState); void Run(const char * originalEdgeDataFilename, lua_State *myLuaState);
void GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges ); void GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges );
void GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode> & nodes); void GetEdgeBasedNodes( std::vector< EdgeBasedNode> & nodes);
void GetOriginalEdgeData( std::vector< OriginalEdgeData> & originalEdgeData); void GetOriginalEdgeData( std::vector< OriginalEdgeData> & originalEdgeData);
TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, unsigned& penalty, lua_State *myLuaState) const; TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, unsigned& penalty, lua_State *myLuaState) const;
unsigned GetNumberOfNodes() const; unsigned GetNumberOfNodes() const;

View File

@ -33,8 +33,8 @@
//This is one big workaround for latest boost renaming woes. //This is one big workaround for latest boost renaming woes.
#ifndef BOOST_FILESYSTEM_VERSION #if BOOST_FILESYSTEM_VERSION < 3
#warning Boost Installation with Filesystem3 (>=1.44) is required, activating workaround #warning Boost Installation with Filesystem3 missing, activating workaround
#include <cstdio> #include <cstdio>
namespace boost { namespace boost {
namespace filesystem { namespace filesystem {
@ -54,8 +54,9 @@ inline path unique_path(const path&) {
#endif #endif
#ifndef BOOST_FILESYSTEM_VERSION
#define BOOST_FILESYSTEM_VERSION 3 #define BOOST_FILESYSTEM_VERSION 3
#endif
/** /**
* This class implements a singleton file storage for temporary data. * This class implements a singleton file storage for temporary data.
* temporary slots can be accessed by other objects through an int * temporary slots can be accessed by other objects through an int
@ -89,8 +90,6 @@ private:
} }
void abort(boost::filesystem::filesystem_error& e); void abort(boost::filesystem::filesystem_error& e);
;
struct StreamData { struct StreamData {
bool writeMode; bool writeMode;
boost::filesystem::path pathToTemporaryFile; boost::filesystem::path pathToTemporaryFile;

View File

@ -21,7 +21,10 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef COORDINATE_H_ #ifndef COORDINATE_H_
#define COORDINATE_H_ #define COORDINATE_H_
#include <cassert>
#include <cmath>
#include <climits> #include <climits>
#include <iostream> #include <iostream>
struct _Coordinate { struct _Coordinate {
@ -102,5 +105,4 @@ inline double ApproximateDistanceByEuclid(const _Coordinate &c1, const _Coordina
return d; return d;
} }
#endif /* COORDINATE_H_ */ #endif /* COORDINATE_H_ */

View File

@ -21,18 +21,21 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef DYNAMICGRAPH_H_INCLUDED #ifndef DYNAMICGRAPH_H_INCLUDED
#define DYNAMICGRAPH_H_INCLUDED #define DYNAMICGRAPH_H_INCLUDED
#include <vector> #include "../DataStructures/DeallocatingVector.h"
#include <boost/assert.hpp>
#include <boost/integer.hpp>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <vector>
#include "../DataStructures/DeallocatingVector.h"
template< typename EdgeDataT> template< typename EdgeDataT>
class DynamicGraph { class DynamicGraph {
public: public:
typedef EdgeDataT EdgeData; typedef EdgeDataT EdgeData;
typedef unsigned NodeIterator; typedef uint32_t NodeIterator;
typedef unsigned EdgeIterator; typedef uint32_t EdgeIterator;
class InputEdge { class InputEdge {
public: public:
@ -47,16 +50,16 @@ class DynamicGraph {
}; };
//Constructs an empty graph with a given number of nodes. //Constructs an empty graph with a given number of nodes.
DynamicGraph( int nodes ) : m_numNodes(nodes), m_numEdges(0) { DynamicGraph( int32_t nodes ) : m_numNodes(nodes), m_numEdges(0) {
m_nodes.reserve( m_numNodes ); m_nodes.reserve( m_numNodes );
m_nodes.resize( m_numNodes ); m_nodes.resize( m_numNodes );
m_edges.reserve( m_numNodes * 1.1 ); m_edges.reserve( m_numNodes * 1.1 );
m_edges.resize( m_numNodes ); m_edges.resize( m_numNodes );
} }
template<class ContainerT> template<class ContainerT>
DynamicGraph( const int nodes, const ContainerT &graph ) DynamicGraph( const int32_t nodes, const ContainerT &graph ) {
{
m_numNodes = nodes; m_numNodes = nodes;
m_numEdges = ( EdgeIterator ) graph.size(); m_numEdges = ( EdgeIterator ) graph.size();
m_nodes.reserve( m_numNodes +1); m_nodes.reserve( m_numNodes +1);
@ -80,7 +83,10 @@ class DynamicGraph {
for ( EdgeIterator i = m_nodes[node].firstEdge, e = m_nodes[node].firstEdge + m_nodes[node].edges; i != e; ++i ) { for ( EdgeIterator i = m_nodes[node].firstEdge, e = m_nodes[node].firstEdge + m_nodes[node].edges; i != e; ++i ) {
m_edges[i].target = graph[edge].target; m_edges[i].target = graph[edge].target;
m_edges[i].data = graph[edge].data; m_edges[i].data = graph[edge].data;
GUARANTEE(graph[edge].data.distance > 0, "edge: " << edge << "(" << graph[edge].source << "," << graph[edge].target << ")=" << graph[edge].data.distance); BOOST_ASSERT_MSG(
graph[edge].data.distance > 0,
"edge distance invalid"
);
++edge; ++edge;
} }
} }
@ -88,17 +94,15 @@ class DynamicGraph {
~DynamicGraph(){ } ~DynamicGraph(){ }
unsigned GetNumberOfNodes() const uint32_t GetNumberOfNodes() const {
{
return m_numNodes; return m_numNodes;
} }
unsigned GetNumberOfEdges() const uint32_t GetNumberOfEdges() const {
{
return m_numEdges; return m_numEdges;
} }
unsigned GetOutDegree( const NodeIterator n ) const { uint32_t GetOutDegree( const NodeIterator n ) const {
return m_nodes[n].edges; return m_nodes[n].edges;
} }
@ -115,7 +119,6 @@ class DynamicGraph {
} }
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 ); return EdgeIterator( m_nodes[n].firstEdge );
} }
@ -133,7 +136,7 @@ class DynamicGraph {
m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges]; m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
} else { } else {
EdgeIterator newFirstEdge = ( EdgeIterator ) m_edges.size(); EdgeIterator newFirstEdge = ( EdgeIterator ) m_edges.size();
unsigned newSize = node.edges * 1.1 + 2; uint32_t newSize = node.edges * 1.1 + 2;
EdgeIterator requiredCapacity = newSize + m_edges.size(); EdgeIterator requiredCapacity = newSize + m_edges.size();
EdgeIterator oldCapacity = m_edges.capacity(); EdgeIterator oldCapacity = m_edges.capacity();
if ( requiredCapacity >= oldCapacity ) { if ( requiredCapacity >= oldCapacity ) {
@ -162,15 +165,15 @@ class DynamicGraph {
Node &node = m_nodes[source]; Node &node = m_nodes[source];
--m_numEdges; --m_numEdges;
--node.edges; --node.edges;
const unsigned last = node.firstEdge + node.edges; const uint32_t last = node.firstEdge + node.edges;
//swap with last edge //swap with last edge
m_edges[e] = m_edges[last]; m_edges[e] = m_edges[last];
makeDummy( last ); makeDummy( last );
} }
//removes all edges (source,target) //removes all edges (source,target)
int DeleteEdgesTo( const NodeIterator source, const NodeIterator target ) { int32_t DeleteEdgesTo( const NodeIterator source, const NodeIterator target ) {
int deleted = 0; int32_t deleted = 0;
for ( EdgeIterator i = BeginEdges( source ), iend = EndEdges( source ); i < iend - deleted; ++i ) { for ( EdgeIterator i = BeginEdges( source ), iend = EndEdges( source ); i < iend - deleted; ++i ) {
if ( m_edges[i].target == target ) { if ( m_edges[i].target == target ) {
do { do {
@ -200,11 +203,11 @@ class DynamicGraph {
protected: protected:
bool isDummy( EdgeIterator edge ) const { bool isDummy( const EdgeIterator edge ) const {
return m_edges[edge].target == (std::numeric_limits< NodeIterator >::max)(); return m_edges[edge].target == (std::numeric_limits< NodeIterator >::max)();
} }
void makeDummy( EdgeIterator edge ) { void makeDummy( const EdgeIterator edge ) {
m_edges[edge].target = (std::numeric_limits< NodeIterator >::max)(); m_edges[edge].target = (std::numeric_limits< NodeIterator >::max)();
} }
@ -212,7 +215,7 @@ class DynamicGraph {
//index of the first edge //index of the first edge
EdgeIterator firstEdge; EdgeIterator firstEdge;
//amount of edges //amount of edges
unsigned edges; uint32_t edges;
}; };
struct Edge { struct Edge {

View File

@ -0,0 +1,87 @@
/*
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 HILBERTVALUE_H_
#define HILBERTVALUE_H_
#include <boost/integer.hpp>
#include <boost/noncopyable.hpp>
// computes a 64 bit value that corresponds to the hilbert space filling curve
class HilbertCode : boost::noncopyable {
public:
static uint64_t GetHilbertNumberForCoordinate(
const _Coordinate & current_coordinate) {
unsigned location[2];
location[0] = current_coordinate.lat+( 90*100000);
location[1] = current_coordinate.lon+(180*100000);
TransposeCoordinate(location);
const uint64_t result = BitInterleaving(location[0], location[1]);
return result;
}
private:
static inline uint64_t BitInterleaving(const uint32_t a, const uint32_t b) {
uint64_t result = 0;
for(int8_t index = 31; index >= 0; --index){
result |= (a >> index) & 1;
result <<= 1;
result |= (b >> index) & 1;
if(0 != index){
result <<= 1;
}
}
return result;
}
static inline void TransposeCoordinate( uint32_t * X) {
uint32_t M = 1 << (32-1), P, Q, t;
int i;
// Inverse undo
for( Q = M; Q > 1; Q >>= 1 ) {
P=Q-1;
for( i = 0; i < 2; ++i ) {
if( X[i] & Q ) {
X[0] ^= P; // invert
} else {
t = (X[0]^X[i]) & P;
X[0] ^= t;
X[i] ^= t;
}
} // exchange
}
// Gray encode
for( i = 1; i < 2; ++i ) {
X[i] ^= X[i-1];
}
t=0;
for( Q = M; Q > 1; Q >>= 1 ) {
if( X[2-1] & Q ) {
t ^= Q-1;
}
} //check if this for loop is wrong
for( i = 0; i < 2; ++i ) {
X[i] ^= t;
}
}
};
#endif /* HILBERTVALUE_H_ */

View File

@ -21,34 +21,49 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef NODEINFORMATIONHELPDESK_H_ #ifndef NODEINFORMATIONHELPDESK_H_
#define NODEINFORMATIONHELPDESK_H_ #define NODEINFORMATIONHELPDESK_H_
#include "NodeCoords.h"
#include "PhantomNodes.h"
#include "QueryEdge.h"
#include "StaticRTree.h"
#include "../Contractor/EdgeBasedGraphFactory.h"
#include "../typedefs.h"
#include <boost/assert.hpp>
#include <boost/noncopyable.hpp>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <boost/noncopyable.hpp> typedef EdgeBasedGraphFactory::EdgeBasedNode RTreeLeaf;
#include "../typedefs.h"
#include "../DataStructures/QueryEdge.h"
#include "NNGrid.h"
#include "PhantomNodes.h"
#include "NodeCoords.h"
class NodeInformationHelpDesk : boost::noncopyable{ class NodeInformationHelpDesk : boost::noncopyable{
public: public:
NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned _numberOfNodes, const unsigned crc) : numberOfNodes(_numberOfNodes), checkSum(crc) { NodeInformationHelpDesk(
readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput); const char* ramIndexInput,
assert(0 == coordinateVector.size()); const char* fileIndexInput,
const unsigned number_of_nodes,
const unsigned crc) : number_of_nodes(number_of_nodes), checkSum(crc) {
read_only_rtree = new StaticRTree<RTreeLeaf>(
ramIndexInput,
fileIndexInput
);
BOOST_ASSERT_MSG(
0 == coordinateVector.size(),
"Coordinate vector not empty"
);
} }
//Todo: Shared memory mechanism //Todo: Shared memory mechanism
// NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned crc) : checkSum(crc) {
// readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
// }
~NodeInformationHelpDesk() { ~NodeInformationHelpDesk() {
delete readOnlyGrid; delete read_only_rtree;
} }
void initNNGrid(std::ifstream& nodesInstream, std::ifstream& edgesInStream) {
void initNNGrid(
std::ifstream& nodesInstream,
std::ifstream& edgesInStream
) {
DEBUG("Loading node data"); DEBUG("Loading node data");
NodeInfo b; NodeInfo b;
while(!nodesInstream.eof()) { while(!nodesInstream.eof()) {
@ -68,20 +83,15 @@ public:
OriginalEdgeData deserialized_originalEdgeData; OriginalEdgeData deserialized_originalEdgeData;
for(unsigned i = 0; i < numberOfOrigEdges; ++i) { for(unsigned i = 0; i < numberOfOrigEdges; ++i) {
edgesInStream.read((char*)&(deserialized_originalEdgeData), sizeof(OriginalEdgeData)); edgesInStream.read((char*)&(deserialized_originalEdgeData), sizeof(OriginalEdgeData));
origEdgeData_viaNode[i] = deserialized_originalEdgeData.viaNode; origEdgeData_viaNode[i] = deserialized_originalEdgeData.viaNode;
origEdgeData_nameID[i] = deserialized_originalEdgeData.nameID; origEdgeData_nameID[i] = deserialized_originalEdgeData.nameID;
origEdgeData_turnInstruction[i] = deserialized_originalEdgeData.turnInstruction; origEdgeData_turnInstruction[i] = deserialized_originalEdgeData.turnInstruction;
} }
edgesInStream.close(); edgesInStream.close();
DEBUG("Loaded " << numberOfOrigEdges << " orig edges"); DEBUG("Loaded " << numberOfOrigEdges << " orig edges");
DEBUG("Opening NN indices"); DEBUG("Opening NN indices");
readOnlyGrid->OpenIndexFiles();
} }
// void initNNGrid() {
// readOnlyGrid->OpenIndexFiles();
// }
inline int getLatitudeOfNode(const unsigned id) const { inline int getLatitudeOfNode(const unsigned id) const {
const NodeID node = origEdgeData_viaNode.at(id); const NodeID node = origEdgeData_viaNode.at(id);
return coordinateVector.at(node).lat; return coordinateVector.at(node).lat;
@ -100,24 +110,36 @@ public:
return origEdgeData_turnInstruction.at(id); return origEdgeData_turnInstruction.at(id);
} }
inline NodeID getNumberOfNodes() const { return numberOfNodes; } inline NodeID getNumberOfNodes() const {
inline NodeID getNumberOfNodes2() const { return coordinateVector.size(); } return number_of_nodes;
}
inline bool FindNearestNodeCoordForLatLon(const _Coordinate& coord, _Coordinate& result) const { inline NodeID getNumberOfNodes2() const {
return readOnlyGrid->FindNearestCoordinateOnEdgeInNodeBasedGraph(coord, result); return coordinateVector.size();
} }
inline bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode, const unsigned zoomLevel) { inline bool FindNearestNodeCoordForLatLon(
return readOnlyGrid->FindPhantomNodeForCoordinate(location, resultNode, zoomLevel); const _Coordinate& input_coordinate,
} _Coordinate& result,
const unsigned zoom_level = 18
) const {
PhantomNode resulting_phantom_node;
bool foundNode = FindPhantomNodeForCoordinate(input_coordinate, resulting_phantom_node, zoom_level);
result = resulting_phantom_node.location;
return foundNode;
}
inline void FindRoutingStarts(const _Coordinate &start, const _Coordinate &target, PhantomNodes & phantomNodes, const unsigned zoomLevel) const { inline bool FindPhantomNodeForCoordinate(
readOnlyGrid->FindRoutingStarts(start, target, phantomNodes, zoomLevel); const _Coordinate & input_coordinate,
} PhantomNode & resulting_phantom_node,
const unsigned zoom_level
inline void FindNearestPointOnEdge(const _Coordinate & input, _Coordinate& output){ ) const {
readOnlyGrid->FindNearestPointOnEdge(input, output); return read_only_rtree->FindPhantomNodeForCoordinate(
} input_coordinate,
resulting_phantom_node,
zoom_level
);
}
inline unsigned GetCheckSum() const { inline unsigned GetCheckSum() const {
return checkSum; return checkSum;
@ -129,8 +151,8 @@ private:
std::vector<unsigned> origEdgeData_nameID; std::vector<unsigned> origEdgeData_nameID;
std::vector<TurnInstruction> origEdgeData_turnInstruction; std::vector<TurnInstruction> origEdgeData_turnInstruction;
ReadOnlyGrid * readOnlyGrid; StaticRTree<EdgeBasedGraphFactory::EdgeBasedNode> * read_only_rtree;
const unsigned numberOfNodes; const unsigned number_of_nodes;
const unsigned checkSum; const unsigned checkSum;
}; };

View File

@ -0,0 +1,89 @@
/*
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 "SearchEngine.h"
SearchEngine::SearchEngine(
QueryGraph * g,
NodeInformationHelpDesk * nh,
std::vector<std::string> & n
) :
_queryData(g, nh, n),
shortestPath(_queryData),
alternativePaths(_queryData)
{}
SearchEngine::~SearchEngine() {}
void SearchEngine::GetCoordinatesForNodeID(
NodeID id,
_Coordinate& result
) const {
result.lat = _queryData.nodeHelpDesk->getLatitudeOfNode(id);
result.lon = _queryData.nodeHelpDesk->getLongitudeOfNode(id);
}
void SearchEngine::FindPhantomNodeForCoordinate(
const _Coordinate & location,
PhantomNode & result,
const unsigned zoomLevel
) const {
_queryData.nodeHelpDesk->FindPhantomNodeForCoordinate(
location,
result, zoomLevel
);
}
NodeID SearchEngine::GetNameIDForOriginDestinationNodeID(
const NodeID s,
const NodeID t
) const {
if(s == t){
return 0;
}
EdgeID e = _queryData.graph->FindEdge(s, t);
if(e == UINT_MAX) {
e = _queryData.graph->FindEdge( t, s );
}
if(UINT_MAX == e) {
return 0;
}
assert(e != UINT_MAX);
const QueryEdge::EdgeData ed = _queryData.graph->GetEdgeData(e);
return ed.id;
}
std::string SearchEngine::GetEscapedNameForNameID(const unsigned nameID) const {
bool is_name_invalid = (nameID >= _queryData.names.size() || nameID == 0);
if (is_name_invalid) {
return std::string("");
}
return HTMLEntitize(_queryData.names.at(nameID));
}
SearchEngineHeapPtr SearchEngineData::forwardHeap;
SearchEngineHeapPtr SearchEngineData::backwardHeap;
SearchEngineHeapPtr SearchEngineData::forwardHeap2;
SearchEngineHeapPtr SearchEngineData::backwardHeap2;
SearchEngineHeapPtr SearchEngineData::forwardHeap3;
SearchEngineHeapPtr SearchEngineData::backwardHeap3;

View File

@ -21,152 +21,48 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef SEARCHENGINE_H_ #ifndef SEARCHENGINE_H_
#define SEARCHENGINE_H_ #define SEARCHENGINE_H_
#include <climits> #include "Coordinate.h"
#include <deque>
#include "SimpleStack.h"
#include <boost/thread.hpp>
#include "BinaryHeap.h"
#include "NodeInformationHelpDesk.h" #include "NodeInformationHelpDesk.h"
#include "PhantomNodes.h" #include "PhantomNodes.h"
#include "QueryEdge.h"
#include "SearchEngineData.h"
#include "../RoutingAlgorithms/AlternativePathRouting.h" #include "../RoutingAlgorithms/AlternativePathRouting.h"
#include "../RoutingAlgorithms/BasicRoutingInterface.h"
#include "../RoutingAlgorithms/ShortestPathRouting.h" #include "../RoutingAlgorithms/ShortestPathRouting.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include "../typedefs.h" #include "../typedefs.h"
struct _HeapData { #include <climits>
NodeID parent; #include <string>
_HeapData( NodeID p ) : parent(p) { } #include <vector>
};
typedef BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> > QueryHeapType;
typedef boost::thread_specific_ptr<QueryHeapType> SearchEngineHeapPtr;
template<class EdgeData, class GraphT>
struct SearchEngineData {
typedef GraphT Graph;
typedef QueryHeapType QueryHeap;
SearchEngineData(GraphT * g, NodeInformationHelpDesk * nh, std::vector<std::string> & n) :graph(g), nodeHelpDesk(nh), names(n) {}
const GraphT * graph;
NodeInformationHelpDesk * nodeHelpDesk;
std::vector<std::string> & 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 QueryHeap(nodeHelpDesk->getNumberOfNodes()));
}
else
forwardHeap->Clear();
if(!backwardHeap.get()) {
backwardHeap.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
}
else
backwardHeap->Clear();
}
inline void InitializeOrClearSecondThreadLocalStorage() {
if(!forwardHeap2.get()) {
forwardHeap2.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
}
else
forwardHeap2->Clear();
if(!backwardHeap2.get()) {
backwardHeap2.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
}
else
backwardHeap2->Clear();
}
inline void InitializeOrClearThirdThreadLocalStorage() {
if(!forwardHeap3.get()) {
forwardHeap3.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
}
else
forwardHeap3->Clear();
if(!backwardHeap3.get()) {
backwardHeap3.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
}
else
backwardHeap3->Clear();
}
};
template<class EdgeData, class GraphT>
class SearchEngine { class SearchEngine {
private: private:
typedef SearchEngineData<EdgeData, GraphT> SearchEngineDataT; SearchEngineData _queryData;
SearchEngineDataT _queryData;
inline double absDouble(double input) { if(input < 0) return input*(-1); else return input;}
public: public:
ShortestPathRouting<SearchEngineDataT> shortestPath; ShortestPathRouting<SearchEngineData> shortestPath;
AlternativeRouting<SearchEngineDataT> alternativePaths; AlternativeRouting<SearchEngineData> alternativePaths;
SearchEngine(GraphT * g, NodeInformationHelpDesk * nh, std::vector<std::string> & n) : SearchEngine(
_queryData(g, nh, n), QueryGraph * g,
shortestPath(_queryData), NodeInformationHelpDesk * nh,
alternativePaths(_queryData) std::vector<std::string> & n
{} );
~SearchEngine() {} ~SearchEngine();
inline void GetCoordinatesForNodeID(NodeID id, _Coordinate& result) const { void GetCoordinatesForNodeID(NodeID id, _Coordinate& result) const;
result.lat = _queryData.nodeHelpDesk->getLatitudeOfNode(id);
result.lon = _queryData.nodeHelpDesk->getLongitudeOfNode(id);
}
inline void FindRoutingStarts(const _Coordinate & start, const _Coordinate & target, PhantomNodes & routingStarts) const { void FindPhantomNodeForCoordinate(
_queryData.nodeHelpDesk->FindRoutingStarts(start, target, routingStarts); const _Coordinate & location,
} PhantomNode & result,
unsigned zoomLevel
) const;
inline void FindPhantomNodeForCoordinate(const _Coordinate & location, PhantomNode & result, unsigned zoomLevel) const { NodeID GetNameIDForOriginDestinationNodeID(
_queryData.nodeHelpDesk->FindPhantomNodeForCoordinate(location, result, zoomLevel); const NodeID s, const NodeID t) const;
}
inline NodeID GetNameIDForOriginDestinationNodeID(const NodeID s, const NodeID t) const {
if(s == t)
return 0;
EdgeID e = _queryData.graph->FindEdge(s, t);
if(e == UINT_MAX)
e = _queryData.graph->FindEdge( t, s );
if(UINT_MAX == e) {
return 0;
}
assert(e != UINT_MAX);
const EdgeData ed = _queryData.graph->GetEdgeData(e);
return ed.via;
}
inline std::string GetEscapedNameForNameID(const unsigned nameID) const {
return ((nameID >= _queryData.names.size() || nameID == 0) ? std::string("") : HTMLEntitize(_queryData.names.at(nameID)));
}
inline std::string GetEscapedNameForEdgeBasedEdgeID(const unsigned edgeID) const {
const unsigned nameID = _queryData.graph->GetEdgeData(edgeID).nameID1;
return GetEscapedNameForNameID(nameID);
}
std::string GetEscapedNameForNameID(const unsigned nameID) const;
}; };
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::forwardHeap;
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::backwardHeap;
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::forwardHeap2;
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::backwardHeap2;
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::forwardHeap3;
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::backwardHeap3;
#endif /* SEARCHENGINE_H_ */ #endif /* SEARCHENGINE_H_ */

View File

@ -0,0 +1,60 @@
/*
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 "SearchEngineData.h"
void SearchEngineData::InitializeOrClearFirstThreadLocalStorage() {
if(!forwardHeap.get()) {
forwardHeap.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
} else {
forwardHeap->Clear();
}
if(!backwardHeap.get()) {
backwardHeap.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
} else {
backwardHeap->Clear();
}
}
void SearchEngineData::InitializeOrClearSecondThreadLocalStorage() {
if(!forwardHeap2.get()) {
forwardHeap2.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
} else {
forwardHeap2->Clear();
}
if(!backwardHeap2.get()) {
backwardHeap2.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
} else {
backwardHeap2->Clear();
}
}
void SearchEngineData::InitializeOrClearThirdThreadLocalStorage() {
if(!forwardHeap3.get()) {
forwardHeap3.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
} else {
forwardHeap3->Clear();
}
if(!backwardHeap3.get()) {
backwardHeap3.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
} else {
backwardHeap3->Clear();
}
}

View File

@ -0,0 +1,60 @@
/*
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 "BinaryHeap.h"
#include "QueryEdge.h"
#include "NodeInformationHelpDesk.h"
#include "StaticGraph.h"
#include "../typedefs.h"
#include <boost/thread.hpp>
#include <string>
#include <vector>
struct _HeapData {
NodeID parent;
_HeapData( NodeID p ) : parent(p) { }
};
typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
typedef BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> > QueryHeapType;
typedef boost::thread_specific_ptr<QueryHeapType> SearchEngineHeapPtr;
struct SearchEngineData {
typedef QueryGraph Graph;
typedef QueryHeapType QueryHeap;
SearchEngineData(QueryGraph * g, NodeInformationHelpDesk * nh, std::vector<std::string> & n) :graph(g), nodeHelpDesk(nh), names(n) {}
const QueryGraph * graph;
NodeInformationHelpDesk * nodeHelpDesk;
std::vector<std::string> & names;
static SearchEngineHeapPtr forwardHeap;
static SearchEngineHeapPtr backwardHeap;
static SearchEngineHeapPtr forwardHeap2;
static SearchEngineHeapPtr backwardHeap2;
static SearchEngineHeapPtr forwardHeap3;
static SearchEngineHeapPtr backwardHeap3;
void InitializeOrClearFirstThreadLocalStorage();
void InitializeOrClearSecondThreadLocalStorage();
void InitializeOrClearThirdThreadLocalStorage();
};

View File

@ -0,0 +1,909 @@
/*
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 STATICRTREE_H_
#define STATICRTREE_H_
#include "MercatorUtil.h"
#include "TimingUtil.h"
#include "Coordinate.h"
#include "PhantomNodes.h"
#include "DeallocatingVector.h"
#include "HilbertValue.h"
#include "../typedefs.h"
#include <boost/assert.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/minmax.hpp>
#include <boost/algorithm/minmax_element.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
#include <boost/noncopyable.hpp>
#include <boost/thread.hpp>
#include <cassert>
#include <cfloat>
#include <climits>
#include <algorithm>
#include <fstream>
#include <queue>
#include <vector>
//tuning parameters
const static uint32_t RTREE_BRANCHING_FACTOR = 50;
const static uint32_t RTREE_LEAF_NODE_SIZE = 1170;
// Implements a static, i.e. packed, R-tree
static boost::thread_specific_ptr<std::ifstream> thread_local_rtree_stream;
template<class DataT>
class StaticRTree : boost::noncopyable {
private:
struct RectangleInt2D {
RectangleInt2D() :
min_lon(INT_MAX),
max_lon(INT_MIN),
min_lat(INT_MAX),
max_lat(INT_MIN) {}
int32_t min_lon, max_lon;
int32_t min_lat, max_lat;
inline void InitializeMBRectangle(
const DataT * objects,
const uint32_t element_count
) {
for(uint32_t i = 0; i < element_count; ++i) {
min_lon = std::min(
min_lon, std::min(objects[i].lon1, objects[i].lon2)
);
max_lon = std::max(
max_lon, std::max(objects[i].lon1, objects[i].lon2)
);
min_lat = std::min(
min_lat, std::min(objects[i].lat1, objects[i].lat2)
);
max_lat = std::max(
max_lat, std::max(objects[i].lat1, objects[i].lat2)
);
}
}
inline void AugmentMBRectangle(const RectangleInt2D & other) {
min_lon = std::min(min_lon, other.min_lon);
max_lon = std::max(max_lon, other.max_lon);
min_lat = std::min(min_lat, other.min_lat);
max_lat = std::max(max_lat, other.max_lat);
}
inline _Coordinate Centroid() const {
_Coordinate centroid;
//The coordinates of the midpoints are given by:
//x = (x1 + x2) /2 and y = (y1 + y2) /2.
centroid.lon = (min_lon + max_lon)/2;
centroid.lat = (min_lat + max_lat)/2;
return centroid;
}
inline bool Intersects(const RectangleInt2D & other) const {
_Coordinate upper_left (other.max_lat, other.min_lon);
_Coordinate upper_right(other.max_lat, other.max_lon);
_Coordinate lower_right(other.min_lat, other.max_lon);
_Coordinate lower_left (other.min_lat, other.min_lon);
return (
Contains(upper_left)
|| Contains(upper_right)
|| Contains(lower_right)
|| Contains(lower_left)
);
}
inline double GetMinDist(const _Coordinate & location) const {
bool is_contained = Contains(location);
if (is_contained) {
return 0.0;
}
double min_dist = DBL_MAX;
min_dist = std::min(
min_dist,
ApproximateDistance(
location.lat,
location.lon,
max_lat,
min_lon
)
);
min_dist = std::min(
min_dist,
ApproximateDistance(
location.lat,
location.lon,
max_lat,
max_lon
)
);
min_dist = std::min(
min_dist,
ApproximateDistance(
location.lat,
location.lon,
min_lat,
max_lon
)
);
min_dist = std::min(
min_dist,
ApproximateDistance(
location.lat,
location.lon,
min_lat,
min_lon
)
);
return min_dist;
}
inline double GetMinMaxDist(const _Coordinate & location) const {
double min_max_dist = DBL_MAX;
//Get minmax distance to each of the four sides
_Coordinate upper_left (max_lat, min_lon);
_Coordinate upper_right(max_lat, max_lon);
_Coordinate lower_right(min_lat, max_lon);
_Coordinate lower_left (min_lat, min_lon);
min_max_dist = std::min(
min_max_dist,
std::max(
ApproximateDistance(location, upper_left ),
ApproximateDistance(location, upper_right)
)
);
min_max_dist = std::min(
min_max_dist,
std::max(
ApproximateDistance(location, upper_right),
ApproximateDistance(location, lower_right)
)
);
min_max_dist = std::min(
min_max_dist,
std::max(
ApproximateDistance(location, lower_right),
ApproximateDistance(location, lower_left )
)
);
min_max_dist = std::min(
min_max_dist,
std::max(
ApproximateDistance(location, lower_left ),
ApproximateDistance(location, upper_left )
)
);
return min_max_dist;
}
inline bool Contains(const _Coordinate & location) const {
bool lats_contained =
(location.lat > min_lat) && (location.lat < max_lat);
bool lons_contained =
(location.lon > min_lon) && (location.lon < max_lon);
return lats_contained && lons_contained;
}
inline friend std::ostream & operator<< ( std::ostream & out, const RectangleInt2D & rect ) {
out << rect.min_lat/100000. << "," << rect.min_lon/100000. << " " << rect.max_lat/100000. << "," << rect.max_lon/100000.;
return out;
}
};
typedef RectangleInt2D RectangleT;
struct WrappedInputElement {
explicit WrappedInputElement(const uint32_t _array_index, const uint64_t _hilbert_value) :
m_array_index(_array_index), m_hilbert_value(_hilbert_value) {}
WrappedInputElement() : m_array_index(UINT_MAX), m_hilbert_value(0) {}
uint32_t m_array_index;
uint64_t m_hilbert_value;
inline bool operator<(const WrappedInputElement & other) const {
return m_hilbert_value < other.m_hilbert_value;
}
};
struct LeafNode {
LeafNode() : object_count(0) {}
uint32_t object_count;
DataT objects[RTREE_LEAF_NODE_SIZE];
};
struct TreeNode {
TreeNode() : child_count(0), child_is_on_disk(false) {}
RectangleT minimum_bounding_rectangle;
uint32_t child_count:31;
bool child_is_on_disk:1;
uint32_t children[RTREE_BRANCHING_FACTOR];
};
struct QueryCandidate {
explicit QueryCandidate(const uint32_t n_id, const double dist) : node_id(n_id), min_dist(dist)/*, minmax_dist(DBL_MAX)*/ {}
QueryCandidate() : node_id(UINT_MAX), min_dist(DBL_MAX)/*, minmax_dist(DBL_MAX)*/ {}
uint32_t node_id;
double min_dist;
// double minmax_dist;
inline bool operator<(const QueryCandidate & other) const {
return min_dist < other.min_dist;
}
};
std::vector<TreeNode> m_search_tree;
uint64_t m_element_count;
std::string m_leaf_node_filename;
public:
//Construct a pack R-Tree from the input-list with Kamel-Faloutsos algorithm [1]
explicit StaticRTree(std::vector<DataT> & input_data_vector, const char * tree_node_filename, const char * leaf_node_filename) :
m_leaf_node_filename(leaf_node_filename) {
m_element_count = input_data_vector.size();
//remove elements that are flagged to be ignored
// boost::remove_erase_if(input_data_vector, boost::bind(&DataT::isIgnored, _1 ));
INFO("constructing r-tree of " << m_element_count << " elements");
// INFO("sizeof(LeafNode)=" << sizeof(LeafNode));
// INFO("sizeof(TreeNode)=" << sizeof(TreeNode));
// INFO("sizeof(WrappedInputElement)=" << sizeof(WrappedInputElement));
double time1 = get_timestamp();
std::vector<WrappedInputElement> input_wrapper_vector(input_data_vector.size());
//generate auxiliary vector of hilbert-values
#pragma omp parallel for schedule(guided)
for(uint64_t element_counter = 0; element_counter < m_element_count; ++element_counter) {
//INFO("ID: " << input_data_vector[element_counter].id);
input_wrapper_vector[element_counter].m_array_index = element_counter;
//Get Hilbert-Value for centroid in mercartor projection
DataT & current_element = input_data_vector[element_counter];
_Coordinate current_centroid = current_element.Centroid();
current_centroid.lat = 100000*lat2y(current_centroid.lat/100000.);
uint64_t current_hilbert_value = HilbertCode::GetHilbertNumberForCoordinate(current_centroid);
input_wrapper_vector[element_counter].m_hilbert_value = current_hilbert_value;
}
//INFO("finished wrapper setup");
//open leaf file
std::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
leaf_node_file.write((char*) &m_element_count, sizeof(uint64_t));
//sort the hilbert-value representatives
std::sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
// INFO("finished sorting");
std::vector<TreeNode> tree_nodes_in_level;
//pack M elements into leaf node and write to leaf file
uint64_t processed_objects_count = 0;
while(processed_objects_count < m_element_count) {
LeafNode current_leaf;
TreeNode current_node;
for(uint32_t current_element_index = 0; RTREE_LEAF_NODE_SIZE > current_element_index; ++current_element_index) {
if(m_element_count > (processed_objects_count + current_element_index)) {
// INFO("Checking element " << (processed_objects_count + current_element_index));
uint32_t index_of_next_object = input_wrapper_vector[processed_objects_count + current_element_index].m_array_index;
current_leaf.objects[current_element_index] = input_data_vector[index_of_next_object];
++current_leaf.object_count;
}
}
if(0 == processed_objects_count) {
for(uint32_t i = 0; i < current_leaf.object_count; ++i) {
//INFO("[" << i << "] id: " << current_leaf.objects[i].id << ", weight: " << current_leaf.objects[i].weight << ", " << current_leaf.objects[i].lat1/100000. << "," << current_leaf.objects[i].lon1/100000. << ";" << current_leaf.objects[i].lat2/100000. << "," << current_leaf.objects[i].lon2/100000.);
}
}
//generate tree node that resemble the objects in leaf and store it for next level
current_node.minimum_bounding_rectangle.InitializeMBRectangle(current_leaf.objects, current_leaf.object_count);
current_node.child_is_on_disk = true;
current_node.children[0] = tree_nodes_in_level.size();
tree_nodes_in_level.push_back(current_node);
//write leaf_node to leaf node file
leaf_node_file.write((char*)&current_leaf, sizeof(current_leaf));
processed_objects_count += current_leaf.object_count;
}
// INFO("wrote " << processed_objects_count << " leaf objects");
//close leaf file
leaf_node_file.close();
uint32_t processing_level = 0;
while(1 < tree_nodes_in_level.size()) {
// INFO("processing " << (uint32_t)tree_nodes_in_level.size() << " tree nodes in level " << processing_level);
std::vector<TreeNode> tree_nodes_in_next_level;
uint32_t processed_tree_nodes_in_level = 0;
while(processed_tree_nodes_in_level < tree_nodes_in_level.size()) {
TreeNode parent_node;
//pack RTREE_BRANCHING_FACTOR elements into tree_nodes each
for(uint32_t current_child_node_index = 0; RTREE_BRANCHING_FACTOR > current_child_node_index; ++current_child_node_index) {
if(processed_tree_nodes_in_level < tree_nodes_in_level.size()) {
TreeNode & current_child_node = tree_nodes_in_level[processed_tree_nodes_in_level];
//add tree node to parent entry
parent_node.children[current_child_node_index] = m_search_tree.size();
m_search_tree.push_back(current_child_node);
//augment MBR of parent
parent_node.minimum_bounding_rectangle.AugmentMBRectangle(current_child_node.minimum_bounding_rectangle);
//increase counters
++parent_node.child_count;
++processed_tree_nodes_in_level;
}
}
tree_nodes_in_next_level.push_back(parent_node);
// INFO("processed: " << processed_tree_nodes_in_level << ", generating " << (uint32_t)tree_nodes_in_next_level.size() << " parents");
}
tree_nodes_in_level.swap(tree_nodes_in_next_level);
++processing_level;
}
BOOST_ASSERT_MSG(1 == tree_nodes_in_level.size(), "tree broken, more than one root node");
//last remaining entry is the root node;
// INFO("root node has " << (uint32_t)tree_nodes_in_level[0].child_count << " children");
//store root node
m_search_tree.push_back(tree_nodes_in_level[0]);
//reverse and renumber tree to have root at index 0
std::reverse(m_search_tree.begin(), m_search_tree.end());
#pragma omp parallel for schedule(guided)
for(uint32_t i = 0; i < m_search_tree.size(); ++i) {
TreeNode & current_tree_node = m_search_tree[i];
for(uint32_t j = 0; j < current_tree_node.child_count; ++j) {
const uint32_t old_id = current_tree_node.children[j];
const uint32_t new_id = m_search_tree.size() - old_id - 1;
current_tree_node.children[j] = new_id;
}
}
//open tree file
std::ofstream tree_node_file(tree_node_filename, std::ios::binary);
uint32_t size_of_tree = m_search_tree.size();
BOOST_ASSERT_MSG(0 < size_of_tree, "tree empty");
tree_node_file.write((char *)&size_of_tree, sizeof(uint32_t));
tree_node_file.write((char *)&m_search_tree[0], sizeof(TreeNode)*size_of_tree);
//close tree node file.
tree_node_file.close();
double time2 = get_timestamp();
// INFO("written " << processed_objects_count << " leafs in " << sizeof(LeafNode)*(1+(unsigned)std::ceil(processed_objects_count/RTREE_LEAF_NODE_SIZE) )+sizeof(uint64_t) << " bytes");
// INFO("written search tree of " << size_of_tree << " tree nodes in " << sizeof(TreeNode)*size_of_tree+sizeof(uint32_t) << " bytes");
INFO("finished r-tree construction in " << (time2-time1) << " seconds");
//todo: test queries
/* INFO("first MBR:" << m_search_tree[0].minimum_bounding_rectangle);
DataT result;
time1 = get_timestamp();
bool found_nearest = NearestNeighbor(_Coordinate(50.191085,8.466479), result);
time2 = get_timestamp();
INFO("found nearest element to (50.191085,8.466479): " << (found_nearest ? "yes" : "no") << " in " << (time2-time1) << "s at (" << result.lat1/100000. << "," << result.lon1/100000. << " " << result.lat2/100000. << "," << result.lon2/100000. << ")");
time1 = get_timestamp();
found_nearest = NearestNeighbor(_Coordinate(50.23979, 8.51882), result);
time2 = get_timestamp();
INFO("found nearest element to (50.23979, 8.51882): " << (found_nearest ? "yes" : "no") << " in " << (time2-time1) << "s at (" << result.lat1/100000. << "," << result.lon1/100000. << " " << result.lat2/100000. << "," << result.lon2/100000. << ")");
time1 = get_timestamp();
found_nearest = NearestNeighbor(_Coordinate(49.0316,2.6937), result);
time2 = get_timestamp();
INFO("found nearest element to (49.0316,2.6937): " << (found_nearest ? "yes" : "no") << " in " << (time2-time1) << "s at (" << result.lat1/100000. << "," << result.lon1/100000. << " " << result.lat2/100000. << "," << result.lon2/100000. << ")");
*/
}
//Read-only operation for queries
explicit StaticRTree(
const char * node_filename,
const char * leaf_filename
) : m_leaf_node_filename(leaf_filename) {
//INFO("Loading nodes: " << node_filename);
//INFO("opening leafs: " << leaf_filename);
//open tree node file and load into RAM.
std::ifstream tree_node_file(node_filename, std::ios::binary);
uint32_t tree_size = 0;
tree_node_file.read((char*)&tree_size, sizeof(uint32_t));
//INFO("reading " << tree_size << " tree nodes in " << (sizeof(TreeNode)*tree_size) << " bytes");
m_search_tree.resize(tree_size);
tree_node_file.read((char*)&m_search_tree[0], sizeof(TreeNode)*tree_size);
tree_node_file.close();
//open leaf node file and store thread specific pointer
std::ifstream leaf_node_file(leaf_filename, std::ios::binary);
leaf_node_file.read((char*)&m_element_count, sizeof(uint64_t));
leaf_node_file.close();
//INFO( tree_size << " nodes in search tree");
//INFO( m_element_count << " elements in leafs");
}
/*
inline void FindKNearestPhantomNodesForCoordinate(
const _Coordinate & location,
const unsigned zoom_level,
const unsigned candidate_count,
std::vector<std::pair<PhantomNode, double> > & result_vector
) const {
bool ignore_tiny_components = (zoom_level <= 14);
DataT nearest_edge;
uint32_t io_count = 0;
uint32_t explored_tree_nodes_count = 0;
INFO("searching for coordinate " << input_coordinate);
double min_dist = DBL_MAX;
double min_max_dist = DBL_MAX;
bool found_a_nearest_edge = false;
_Coordinate nearest, current_start_coordinate, current_end_coordinate;
//initialize queue with root element
std::priority_queue<QueryCandidate> traversal_queue;
traversal_queue.push(QueryCandidate(0, m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate)));
BOOST_ASSERT_MSG(FLT_EPSILON > (0. - traversal_queue.top().min_dist), "Root element in NN Search has min dist != 0.");
while(!traversal_queue.empty()) {
const QueryCandidate current_query_node = traversal_queue.top(); traversal_queue.pop();
++explored_tree_nodes_count;
bool prune_downward = (current_query_node.min_dist >= min_max_dist);
bool prune_upward = (current_query_node.min_dist >= min_dist);
if( !prune_downward && !prune_upward ) { //downward pruning
TreeNode & current_tree_node = m_search_tree[current_query_node.node_id];
if (current_tree_node.child_is_on_disk) {
LeafNode current_leaf_node;
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
++io_count;
for(uint32_t i = 0; i < current_leaf_node.object_count; ++i) {
DataT & current_edge = current_leaf_node.objects[i];
if(ignore_tiny_components && current_edge.belongsToTinyComponent) {
continue;
}
double current_ratio = 0.;
double current_perpendicular_distance = ComputePerpendicularDistance(
input_coordinate,
_Coordinate(current_edge.lat1, current_edge.lon1),
_Coordinate(current_edge.lat2, current_edge.lon2),
nearest,
&current_ratio
);
if(
current_perpendicular_distance < min_dist
&& !DoubleEpsilonCompare(
current_perpendicular_distance,
min_dist
)
) { //found a new minimum
min_dist = current_perpendicular_distance;
result_phantom_node.edgeBasedNode = current_edge.id;
result_phantom_node.nodeBasedEdgeNameID = current_edge.nameID;
result_phantom_node.weight1 = current_edge.weight;
result_phantom_node.weight2 = INT_MAX;
result_phantom_node.location = nearest;
current_start_coordinate.lat = current_edge.lat1;
current_start_coordinate.lon = current_edge.lon1;
current_end_coordinate.lat = current_edge.lat2;
current_end_coordinate.lon = current_edge.lon2;
nearest_edge = current_edge;
found_a_nearest_edge = true;
} else if(
DoubleEpsilonCompare(current_perpendicular_distance, min_dist) &&
1 == abs(current_edge.id - result_phantom_node.edgeBasedNode )
&& CoordinatesAreEquivalent(
current_start_coordinate,
_Coordinate(
current_edge.lat1,
current_edge.lon1
),
_Coordinate(
current_edge.lat2,
current_edge.lon2
),
current_end_coordinate
)
) {
result_phantom_node.edgeBasedNode = std::min(current_edge.id, result_phantom_node.edgeBasedNode);
result_phantom_node.weight2 = current_edge.weight;
}
}
} else {
//traverse children, prune if global mindist is smaller than local one
for (uint32_t i = 0; i < current_tree_node.child_count; ++i) {
const int32_t child_id = current_tree_node.children[i];
TreeNode & child_tree_node = m_search_tree[child_id];
RectangleT & child_rectangle = child_tree_node.minimum_bounding_rectangle;
const double current_min_dist = child_rectangle.GetMinDist(input_coordinate);
const double current_min_max_dist = child_rectangle.GetMinMaxDist(input_coordinate);
if( current_min_max_dist < min_max_dist ) {
min_max_dist = current_min_max_dist;
}
if (current_min_dist > min_max_dist) {
continue;
}
if (current_min_dist > min_dist) { //upward pruning
continue;
}
traversal_queue.push(QueryCandidate(child_id, current_min_dist));
}
}
}
}
const double ratio = (found_a_nearest_edge ?
std::min(1., ApproximateDistance(_Coordinate(nearest_edge.lat1, nearest_edge.lon1),
result_phantom_node.location)/ApproximateDistance(_Coordinate(nearest_edge.lat1, nearest_edge.lon1), _Coordinate(nearest_edge.lat2, nearest_edge.lon2))
) : 0
);
result_phantom_node.weight1 *= ratio;
if(INT_MAX != result_phantom_node.weight2) {
result_phantom_node.weight2 *= (1.-ratio);
}
result_phantom_node.ratio = ratio;
//Hack to fix rounding errors and wandering via nodes.
if(std::abs(input_coordinate.lon - result_phantom_node.location.lon) == 1) {
result_phantom_node.location.lon = input_coordinate.lon;
}
if(std::abs(input_coordinate.lat - result_phantom_node.location.lat) == 1) {
result_phantom_node.location.lat = input_coordinate.lat;
}
INFO("mindist: " << min_dist << ", io's: " << io_count << ", nodes: " << explored_tree_nodes_count << ", loc: " << result_phantom_node.location << ", ratio: " << ratio << ", id: " << result_phantom_node.edgeBasedNode);
INFO("bidirected: " << (result_phantom_node.isBidirected() ? "yes" : "no") );
return found_a_nearest_edge;
}
*/
bool FindPhantomNodeForCoordinate(
const _Coordinate & input_coordinate,
PhantomNode & result_phantom_node,
const unsigned zoom_level
) {
bool ignore_tiny_components = (zoom_level <= 14);
DataT nearest_edge;
uint32_t io_count = 0;
uint32_t explored_tree_nodes_count = 0;
//INFO("searching for coordinate " << input_coordinate);
double min_dist = DBL_MAX;
double min_max_dist = DBL_MAX;
bool found_a_nearest_edge = false;
_Coordinate nearest, current_start_coordinate, current_end_coordinate;
//initialize queue with root element
std::priority_queue<QueryCandidate> traversal_queue;
double current_min_dist = m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate);
traversal_queue.push(
QueryCandidate(0, current_min_dist)
);
BOOST_ASSERT_MSG(
FLT_EPSILON > (0. - traversal_queue.top().min_dist),
"Root element in NN Search has min dist != 0."
);
while(!traversal_queue.empty()) {
const QueryCandidate current_query_node = traversal_queue.top(); traversal_queue.pop();
++explored_tree_nodes_count;
bool prune_downward = (current_query_node.min_dist >= min_max_dist);
bool prune_upward = (current_query_node.min_dist >= min_dist);
if( !prune_downward && !prune_upward ) { //downward pruning
TreeNode & current_tree_node = m_search_tree[current_query_node.node_id];
if (current_tree_node.child_is_on_disk) {
LeafNode current_leaf_node;
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
++io_count;
//INFO("checking " << current_leaf_node.object_count << " elements");
for(uint32_t i = 0; i < current_leaf_node.object_count; ++i) {
DataT & current_edge = current_leaf_node.objects[i];
if(ignore_tiny_components && current_edge.belongsToTinyComponent) {
continue;
}
if(current_edge.isIgnored()) {
continue;
}
double current_ratio = 0.;
double current_perpendicular_distance = ComputePerpendicularDistance(
input_coordinate,
_Coordinate(current_edge.lat1, current_edge.lon1),
_Coordinate(current_edge.lat2, current_edge.lon2),
nearest,
&current_ratio
);
//INFO("[" << current_edge.id << "] (" << current_edge.lat1/100000. << "," << current_edge.lon1/100000. << ")==(" << current_edge.lat2/100000. << "," << current_edge.lon2/100000. << ") at distance " << current_perpendicular_distance << " min dist: " << min_dist
// << ", ratio " << current_ratio
// );
if(
current_perpendicular_distance < min_dist
&& !DoubleEpsilonCompare(
current_perpendicular_distance,
min_dist
)
) { //found a new minimum
min_dist = current_perpendicular_distance;
result_phantom_node.edgeBasedNode = current_edge.id;
result_phantom_node.nodeBasedEdgeNameID = current_edge.nameID;
result_phantom_node.weight1 = current_edge.weight;
result_phantom_node.weight2 = INT_MAX;
result_phantom_node.location = nearest;
current_start_coordinate.lat = current_edge.lat1;
current_start_coordinate.lon = current_edge.lon1;
current_end_coordinate.lat = current_edge.lat2;
current_end_coordinate.lon = current_edge.lon2;
nearest_edge = current_edge;
found_a_nearest_edge = true;
} else if(
DoubleEpsilonCompare(current_perpendicular_distance, min_dist) &&
1 == abs(current_edge.id - result_phantom_node.edgeBasedNode )
&& CoordinatesAreEquivalent(
current_start_coordinate,
_Coordinate(
current_edge.lat1,
current_edge.lon1
),
_Coordinate(
current_edge.lat2,
current_edge.lon2
),
current_end_coordinate
)
) {
BOOST_ASSERT_MSG(current_edge.id != result_phantom_node.edgeBasedNode, "IDs not different");
//INFO("found bidirected edge on nodes " << current_edge.id << " and " << result_phantom_node.edgeBasedNode);
result_phantom_node.weight2 = current_edge.weight;
if(current_edge.id < result_phantom_node.edgeBasedNode) {
result_phantom_node.edgeBasedNode = current_edge.id;
std::swap(result_phantom_node.weight1, result_phantom_node.weight2);
std::swap(current_end_coordinate, current_start_coordinate);
// INFO("case 2");
}
//INFO("w1: " << result_phantom_node.weight1 << ", w2: " << result_phantom_node.weight2);
}
}
} else {
//traverse children, prune if global mindist is smaller than local one
for (uint32_t i = 0; i < current_tree_node.child_count; ++i) {
const int32_t child_id = current_tree_node.children[i];
TreeNode & child_tree_node = m_search_tree[child_id];
RectangleT & child_rectangle = child_tree_node.minimum_bounding_rectangle;
const double current_min_dist = child_rectangle.GetMinDist(input_coordinate);
const double current_min_max_dist = child_rectangle.GetMinMaxDist(input_coordinate);
if( current_min_max_dist < min_max_dist ) {
min_max_dist = current_min_max_dist;
}
if (current_min_dist > min_max_dist) {
continue;
}
if (current_min_dist > min_dist) { //upward pruning
continue;
}
traversal_queue.push(QueryCandidate(child_id, current_min_dist));
}
}
}
}
const double ratio = (found_a_nearest_edge ?
std::min(1., ApproximateDistance(current_start_coordinate,
result_phantom_node.location)/ApproximateDistance(current_start_coordinate, current_end_coordinate)
) : 0
);
result_phantom_node.weight1 *= ratio;
if(INT_MAX != result_phantom_node.weight2) {
result_phantom_node.weight2 *= (1.-ratio);
}
result_phantom_node.ratio = ratio;
//Hack to fix rounding errors and wandering via nodes.
if(std::abs(input_coordinate.lon - result_phantom_node.location.lon) == 1) {
result_phantom_node.location.lon = input_coordinate.lon;
}
if(std::abs(input_coordinate.lat - result_phantom_node.location.lat) == 1) {
result_phantom_node.location.lat = input_coordinate.lat;
}
// INFO("start: (" << nearest_edge.lat1 << "," << nearest_edge.lon1 << "), end: (" << nearest_edge.lat2 << "," << nearest_edge.lon2 << ")" );
// INFO("mindist: " << min_dist << ", io's: " << io_count << ", nodes: " << explored_tree_nodes_count << ", loc: " << result_phantom_node.location << ", ratio: " << ratio << ", id: " << result_phantom_node.edgeBasedNode);
// INFO("weight1: " << result_phantom_node.weight1 << ", weight2: " << result_phantom_node.weight2);
// INFO("bidirected: " << (result_phantom_node.isBidirected() ? "yes" : "no") );
// INFO("NameID: " << result_phantom_node.nodeBasedEdgeNameID);
return found_a_nearest_edge;
}
/*
//Nearest-Neighbor query with the Roussopoulos et al. algorithm [2]
inline bool NearestNeighbor(const _Coordinate & input_coordinate, DataT & result_element) {
uint32_t io_count = 0;
uint32_t explored_tree_nodes_count = 0;
INFO("searching for coordinate " << input_coordinate);
double min_dist = DBL_MAX;
double min_max_dist = DBL_MAX;
bool found_return_value = false;
//initialize queue with root element
std::priority_queue<QueryCandidate> traversal_queue;
traversal_queue.push(QueryCandidate(0, m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate)));
BOOST_ASSERT_MSG(FLT_EPSILON > (0. - traversal_queue.top().min_dist), "Root element in NN Search has min dist != 0.");
while(!traversal_queue.empty()) {
const QueryCandidate current_query_node = traversal_queue.top(); traversal_queue.pop();
++explored_tree_nodes_count;
// INFO("popped node " << current_query_node.node_id << " at distance " << current_query_node.min_dist);
bool prune_downward = (current_query_node.min_dist >= min_max_dist);
bool prune_upward = (current_query_node.min_dist >= min_dist);
// INFO(" up prune: " << (prune_upward ? "y" : "n" ));
// INFO(" down prune: " << (prune_downward ? "y" : "n" ));
if( prune_downward || prune_upward ) { //downward pruning
// INFO(" pruned node " << current_query_node.node_id << " because " << current_query_node.min_dist << "<" << min_max_dist);
} else {
TreeNode & current_tree_node = m_search_tree[current_query_node.node_id];
if (current_tree_node.child_is_on_disk) {
// INFO(" Fetching child from disk for id: " << current_query_node.node_id);
LeafNode current_leaf_node;
LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
++io_count;
double ratio = 0.;
_Coordinate nearest;
for(uint32_t i = 0; i < current_leaf_node.object_count; ++i) {
DataT & current_object = current_leaf_node.objects[i];
double current_perpendicular_distance = ComputePerpendicularDistance(
input_coordinate,
_Coordinate(current_object.lat1, current_object.lon1),
_Coordinate(current_object.lat2, current_object.lon2),
nearest,
&ratio
);
if(current_perpendicular_distance < min_dist && !DoubleEpsilonCompare(current_perpendicular_distance, min_dist)) { //found a new minimum
min_dist = current_perpendicular_distance;
result_element = current_object;
found_return_value = true;
}
}
} else {
//traverse children, prune if global mindist is smaller than local one
// INFO(" Checking " << current_tree_node.child_count << " children of node " << current_query_node.node_id);
for (uint32_t i = 0; i < current_tree_node.child_count; ++i) {
const int32_t child_id = current_tree_node.children[i];
TreeNode & child_tree_node = m_search_tree[child_id];
RectangleT & child_rectangle = child_tree_node.minimum_bounding_rectangle;
const double current_min_dist = child_rectangle.GetMinDist(input_coordinate);
const double current_min_max_dist = child_rectangle.GetMinMaxDist(input_coordinate);
if( current_min_max_dist < min_max_dist ) {
min_max_dist = current_min_max_dist;
}
if (current_min_dist > min_max_dist) {
continue;
}
if (current_min_dist > min_dist) { //upward pruning
continue;
}
// INFO(" pushing node " << child_id << " at distance " << current_min_dist);
traversal_queue.push(QueryCandidate(child_id, current_min_dist));
}
}
}
}
INFO("mindist: " << min_dist << ", io's: " << io_count << ", touched nodes: " << explored_tree_nodes_count);
return found_return_value;
}
*/
private:
inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode& result_node) {
if(!thread_local_rtree_stream.get() || !thread_local_rtree_stream->is_open()) {
thread_local_rtree_stream.reset(
new std::ifstream(
m_leaf_node_filename.c_str(),
std::ios::in | std::ios::binary
)
);
}
if(!thread_local_rtree_stream->good()) {
thread_local_rtree_stream->clear(std::ios::goodbit);
DEBUG("Resetting stale filestream");
}
uint64_t seek_pos = sizeof(uint64_t) + leaf_id*sizeof(LeafNode);
thread_local_rtree_stream->seekg(seek_pos);
thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode));
}
inline double ComputePerpendicularDistance(
const _Coordinate& inputPoint,
const _Coordinate& source,
const _Coordinate& target,
_Coordinate& nearest, double *r) const {
const double x = static_cast<double>(inputPoint.lat);
const double y = static_cast<double>(inputPoint.lon);
const double a = static_cast<double>(source.lat);
const double b = static_cast<double>(source.lon);
const double c = static_cast<double>(target.lat);
const double d = static_cast<double>(target.lon);
double p,q,mX,nY;
if(fabs(a-c) > FLT_EPSILON){
const double m = (d-b)/(c-a); // slope
// Projection of (x,y) on line joining (a,b) and (c,d)
p = ((x + (m*y)) + (m*m*a - m*b))/(1. + m*m);
q = b + m*(p - a);
} else {
p = c;
q = y;
}
nY = (d*p - c*q)/(a*d - b*c);
mX = (p - nY*a)/c;// These values are actually n/m+n and m/m+n , we need
// not calculate the explicit values of m an n as we
// are just interested in the ratio
if(std::isnan(mX)) {
*r = (target == inputPoint) ? 1. : 0.;
} else {
*r = mX;
}
if(*r<=0.){
nearest.lat = source.lat;
nearest.lon = source.lon;
return ((b - y)*(b - y) + (a - x)*(a - x));
// return std::sqrt(((b - y)*(b - y) + (a - x)*(a - x)));
} else if(*r >= 1.){
nearest.lat = target.lat;
nearest.lon = target.lon;
return ((d - y)*(d - y) + (c - x)*(c - x));
// return std::sqrt(((d - y)*(d - y) + (c - x)*(c - x)));
}
// point lies in between
nearest.lat = p;
nearest.lon = q;
// return std::sqrt((p-x)*(p-x) + (q-y)*(q-y));
return (p-x)*(p-x) + (q-y)*(q-y);
}
inline bool CoordinatesAreEquivalent(const _Coordinate & a, const _Coordinate & b, const _Coordinate & c, const _Coordinate & d) const {
return (a == b && c == d) || (a == c && b == d) || (a == d && b == c);
}
inline bool DoubleEpsilonCompare(const double d1, const double d2) const {
return (std::fabs(d1 - d2) < FLT_EPSILON);
}
};
//[1] "On Packing R-Trees"; I. Kamel, C. Faloutsos; 1993; DOI: 10.1145/170088.170403
//[2] "Nearest Neighbor Queries", N. Roussopulos et al; 1995; DOI: 10.1145/223784.223794
#endif /* STATICRTREE_H_ */

View File

@ -28,8 +28,9 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <vector> #include <vector>
#include "../typedefs.h" #include "../typedefs.h"
#include "../DataStructures/PhantomNodes.h"
#include "../DataStructures/HashTable.h" #include "../DataStructures/HashTable.h"
#include "../DataStructures/PhantomNodes.h"
#include "../DataStructures/SearchEngine.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include "../Plugins/RawRouteData.h" #include "../Plugins/RawRouteData.h"
@ -42,13 +43,12 @@ struct _DescriptorConfig {
unsigned short z; unsigned short z;
}; };
template<class SearchEngineT>
class BaseDescriptor { class BaseDescriptor {
public: public:
BaseDescriptor() { } BaseDescriptor() { }
//Maybe someone can explain the pure virtual destructor thing to me (dennis) //Maybe someone can explain the pure virtual destructor thing to me (dennis)
virtual ~BaseDescriptor() { } virtual ~BaseDescriptor() { }
virtual void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) = 0; virtual void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngine &sEngine) = 0;
virtual void SetConfig(const _DescriptorConfig & config) = 0; virtual void SetConfig(const _DescriptorConfig & config) = 0;
}; };

View File

@ -82,7 +82,7 @@ void DescriptionFactory::AppendUnencodedPolylineString(std::string &output) {
pc.printUnencodedString(pathDescription, output); pc.printUnencodedString(pathDescription, output);
} }
void DescriptionFactory::Run(const SearchEngineT &sEngine, const unsigned zoomLevel) { void DescriptionFactory::Run(const SearchEngine &sEngine, const unsigned zoomLevel) {
if(0 == pathDescription.size()) if(0 == pathDescription.size())
return; return;

View File

@ -27,7 +27,6 @@
#include "../Algorithms/DouglasPeucker.h" #include "../Algorithms/DouglasPeucker.h"
#include "../Algorithms/PolylineCompressor.h" #include "../Algorithms/PolylineCompressor.h"
#include "../DataStructures/Coordinate.h" #include "../DataStructures/Coordinate.h"
#include "../DataStructures/QueryEdge.h"
#include "../DataStructures/SearchEngine.h" #include "../DataStructures/SearchEngine.h"
#include "../DataStructures/SegmentInformation.h" #include "../DataStructures/SegmentInformation.h"
#include "../DataStructures/TurnInstructions.h" #include "../DataStructures/TurnInstructions.h"
@ -40,8 +39,6 @@ class DescriptionFactory {
PolylineCompressor pc; PolylineCompressor pc;
PhantomNode startPhantom, targetPhantom; PhantomNode startPhantom, targetPhantom;
typedef SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > SearchEngineT;
double DegreeToRadian(const double degree) const; double DegreeToRadian(const double degree) const;
double RadianToDegree(const double degree) const; double RadianToDegree(const double degree) const;
public: public:
@ -73,7 +70,7 @@ public:
void SetStartSegment(const PhantomNode & startPhantom); void SetStartSegment(const PhantomNode & startPhantom);
void SetEndSegment(const PhantomNode & startPhantom); void SetEndSegment(const PhantomNode & startPhantom);
void AppendEncodedPolylineString(std::string & output, bool isEncoded); void AppendEncodedPolylineString(std::string & output, bool isEncoded);
void Run(const SearchEngineT &sEngine, const unsigned zoomLevel); void Run(const SearchEngine &sEngine, const unsigned zoomLevel);
}; };
#endif /* DESCRIPTIONFACTORY_H_ */ #endif /* DESCRIPTIONFACTORY_H_ */

View File

@ -24,8 +24,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include "BaseDescriptor.h" #include "BaseDescriptor.h"
template<class SearchEngineT> class GPXDescriptor : public BaseDescriptor{
class GPXDescriptor : public BaseDescriptor<SearchEngineT>{
private: private:
_DescriptorConfig config; _DescriptorConfig config;
_Coordinate current; _Coordinate current;
@ -33,7 +32,7 @@ private:
std::string tmp; std::string tmp;
public: public:
void SetConfig(const _DescriptorConfig& c) { config = c; } void SetConfig(const _DescriptorConfig& c) { config = c; }
void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) { void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngine &sEngine) {
reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
reply.content += "<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" xmlns=\"http://www.topografix.com/GPX/1/1\" " reply.content += "<gpx creator=\"OSRM Routing Engine\" version=\"1.1\" xmlns=\"http://www.topografix.com/GPX/1/1\" "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "

View File

@ -34,8 +34,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "../Util/Azimuth.h" #include "../Util/Azimuth.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
template<class SearchEngineT> class JSONDescriptor : public BaseDescriptor{
class JSONDescriptor : public BaseDescriptor<SearchEngineT>{
private: private:
_DescriptorConfig config; _DescriptorConfig config;
DescriptionFactory descriptionFactory; DescriptionFactory descriptionFactory;
@ -68,7 +67,7 @@ public:
JSONDescriptor() : numberOfEnteredRestrictedAreas(0) {} JSONDescriptor() : numberOfEnteredRestrictedAreas(0) {}
void SetConfig(const _DescriptorConfig & c) { config = c; } void SetConfig(const _DescriptorConfig & c) { config = c; }
void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) { void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngine &sEngine) {
WriteHeaderToOutput(reply.content); WriteHeaderToOutput(reply.content);
@ -246,7 +245,7 @@ public:
reply.content += "}"; reply.content += "}";
} }
void GetRouteNames(std::vector<Segment> & shortestSegments, std::vector<Segment> & alternativeSegments, const SearchEngineT &sEngine, RouteNames & routeNames) { void GetRouteNames(std::vector<Segment> & shortestSegments, std::vector<Segment> & alternativeSegments, const SearchEngine &sEngine, RouteNames & routeNames) {
/*** extract names for both alternatives ***/ /*** extract names for both alternatives ***/
Segment shortestSegment1, shortestSegment2; Segment shortestSegment1, shortestSegment2;
@ -304,7 +303,7 @@ public:
"\"status\":"; "\"status\":";
} }
inline void BuildTextualDescription(DescriptionFactory & descriptionFactory, http::Reply & reply, const int lengthOfRoute, const SearchEngineT &sEngine, std::vector<Segment> & segmentVector) { inline void BuildTextualDescription(DescriptionFactory & descriptionFactory, http::Reply & reply, const int lengthOfRoute, const SearchEngine &sEngine, std::vector<Segment> & segmentVector) {
//Segment information has following format: //Segment information has following format:
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth] //["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
//Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5] //Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]

View File

@ -257,8 +257,8 @@ void ExtractionContainers::PrepareData(const std::string & outputFileName, const
fout.write((char*)&edgeIT->ignoreInGrid, sizeof(bool)); fout.write((char*)&edgeIT->ignoreInGrid, sizeof(bool));
fout.write((char*)&edgeIT->isAccessRestricted, sizeof(bool)); fout.write((char*)&edgeIT->isAccessRestricted, sizeof(bool));
fout.write((char*)&edgeIT->isContraFlow, sizeof(bool)); fout.write((char*)&edgeIT->isContraFlow, sizeof(bool));
++usedEdgeCounter;
} }
++usedEdgeCounter;
++edgeIT; ++edgeIT;
} }
} }

View File

@ -21,12 +21,12 @@
#ifndef EXTRACTIONCONTAINERS_H_ #ifndef EXTRACTIONCONTAINERS_H_
#define EXTRACTIONCONTAINERS_H_ #define EXTRACTIONCONTAINERS_H_
#include <boost/foreach.hpp>
#include <stxxl.h>
#include "ExtractorStructs.h" #include "ExtractorStructs.h"
#include "../DataStructures/TimingUtil.h" #include "../DataStructures/TimingUtil.h"
#include <boost/foreach.hpp>
#include <stxxl.h>
class ExtractionContainers { class ExtractionContainers {
public: public:
typedef stxxl::vector<NodeID> STXXLNodeIDVector; typedef stxxl::vector<NodeID> STXXLNodeIDVector;

View File

@ -76,7 +76,7 @@ inline bool PBFParser::ReadHeader() {
else if ( "DenseNodes" == feature ) { else if ( "DenseNodes" == feature ) {
supported = true; supported = true;
} }
if ( !supported ) { if ( !supported ) {
std::cerr << "[error] required feature not supported: " << feature.data() << std::endl; std::cerr << "[error] required feature not supported: " << feature.data() << std::endl;
return false; return false;
@ -155,22 +155,19 @@ inline bool PBFParser::Parse() {
inline void PBFParser::parseDenseNode(_ThreadData * threadData) { inline void PBFParser::parseDenseNode(_ThreadData * threadData) {
const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense(); const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense();
int denseTagIndex = 0; int denseTagIndex = 0;
int m_lastDenseID = 0; int64_t m_lastDenseID = 0;
int m_lastDenseLatitude = 0; int64_t m_lastDenseLatitude = 0;
int m_lastDenseLongitude = 0; int64_t m_lastDenseLongitude = 0;
ImportNode n;
std::vector<ImportNode> extracted_nodes_vector;
const int number_of_nodes = dense.id_size(); const int number_of_nodes = dense.id_size();
extracted_nodes_vector.reserve(number_of_nodes); std::vector<ImportNode> extracted_nodes_vector(number_of_nodes);
for(int i = 0; i < number_of_nodes; ++i) { for(int i = 0; i < number_of_nodes; ++i) {
n.Clear();
m_lastDenseID += dense.id( i ); m_lastDenseID += dense.id( i );
m_lastDenseLatitude += dense.lat( i ); m_lastDenseLatitude += dense.lat( i );
m_lastDenseLongitude += dense.lon( i ); m_lastDenseLongitude += dense.lon( i );
n.id = m_lastDenseID; extracted_nodes_vector[i].id = m_lastDenseID;
n.lat = 100000*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lat_offset() ) / NANO; extracted_nodes_vector[i].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; extracted_nodes_vector[i].lon = 100000*( ( double ) m_lastDenseLongitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lon_offset() ) / NANO;
while (denseTagIndex < dense.keys_vals_size()) { while (denseTagIndex < dense.keys_vals_size()) {
const int tagValue = dense.keys_vals( denseTagIndex ); const int tagValue = dense.keys_vals( denseTagIndex );
if( 0==tagValue ) { if( 0==tagValue ) {
@ -180,10 +177,9 @@ inline void PBFParser::parseDenseNode(_ThreadData * threadData) {
const int keyValue = dense.keys_vals ( denseTagIndex+1 ); const int keyValue = dense.keys_vals ( denseTagIndex+1 );
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue).data(); const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue).data();
const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue).data(); const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue).data();
n.keyVals.Add(key, value); extracted_nodes_vector[i].keyVals.Add(key, value);
denseTagIndex += 2; denseTagIndex += 2;
} }
extracted_nodes_vector.push_back(n);
} }
#pragma omp parallel for schedule ( guided ) #pragma omp parallel for schedule ( guided )
@ -292,37 +288,33 @@ inline void PBFParser::parseRelation(_ThreadData * threadData) {
} }
inline void PBFParser::parseWay(_ThreadData * threadData) { inline void PBFParser::parseWay(_ThreadData * threadData) {
ExtractionWay w;
std::vector<ExtractionWay> waysToParse;
const int number_of_ways = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size(); const int number_of_ways = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size();
waysToParse.reserve(number_of_ways); std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
for(int i = 0; i < number_of_ways; ++i) { for(int i = 0; i < number_of_ways; ++i) {
w.Clear();
const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i ); const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i );
w.id = inputWay.id(); parsed_way_vector[i].id = inputWay.id();
unsigned pathNode(0); unsigned pathNode(0);
const int number_of_referenced_nodes = inputWay.refs_size(); const int number_of_referenced_nodes = inputWay.refs_size();
for(int i = 0; i < number_of_referenced_nodes; ++i) { for(int j = 0; j < number_of_referenced_nodes; ++j) {
pathNode += inputWay.refs(i); pathNode += inputWay.refs(j);
w.path.push_back(pathNode); parsed_way_vector[i].path.push_back(pathNode);
} }
assert(inputWay.keys_size() == inputWay.vals_size()); assert(inputWay.keys_size() == inputWay.vals_size());
const int number_of_keys = inputWay.keys_size(); const int number_of_keys = inputWay.keys_size();
for(int i = 0; i < number_of_keys; ++i) { for(int j = 0; j < number_of_keys; ++j) {
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(i)); const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(j));
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(i)); const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(j));
w.keyVals.Add(key, val); parsed_way_vector[i].keyVals.Add(key, val);
} }
waysToParse.push_back(w);
} }
#pragma omp parallel for schedule ( guided ) #pragma omp parallel for schedule ( guided )
for(int i = 0; i < number_of_ways; ++i) { for(int i = 0; i < number_of_ways; ++i) {
ExtractionWay & w = waysToParse[i]; ExtractionWay & w = parsed_way_vector[i];
ParseWayInLua( w, scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()) ); ParseWayInLua( w, scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()) );
} }
BOOST_FOREACH(ExtractionWay & w, waysToParse) { BOOST_FOREACH(ExtractionWay & w, parsed_way_vector) {
extractor_callbacks->wayFunction(w); extractor_callbacks->wayFunction(w);
} }
} }
@ -423,7 +415,7 @@ inline bool PBFParser::readBlob(std::fstream& stream, _ThreadData * threadData)
if(stream.eof()) { if(stream.eof()) {
return false; return false;
} }
const int size = threadData->PBFBlobHeader.datasize(); const int size = threadData->PBFBlobHeader.datasize();
if ( size < 0 || size > MAX_BLOB_SIZE ) { if ( size < 0 || size > MAX_BLOB_SIZE ) {
std::cerr << "[error] invalid Blob size:" << size << std::endl; std::cerr << "[error] invalid Blob size:" << size << std::endl;

View File

@ -1,17 +1,17 @@
/* /*
open source routing machine open source routing machine
Copyright (C) Dennis Luxen, others 2010 Copyright (C) Dennis Luxen, others 2010
This program is free software; you can redistribute it and/or modify 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 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 the Free Software Foundation; either version 3 of the License, or
any later version. any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -21,6 +21,13 @@
#ifndef PBFPARSER_H_ #ifndef PBFPARSER_H_
#define PBFPARSER_H_ #define PBFPARSER_H_
#include "../DataStructures/HashTable.h"
#include "../DataStructures/ConcurrentQueue.h"
#include "../Util/MachineInfo.h"
#include "../Util/OpenMPWrapper.h"
#include "../typedefs.h"
#include "BaseParser.h"
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp> #include <boost/make_shared.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
@ -30,44 +37,38 @@
#include <zlib.h> #include <zlib.h>
#include "../typedefs.h"
#include "../DataStructures/HashTable.h"
#include "../DataStructures/ConcurrentQueue.h"
#include "../Util/MachineInfo.h"
#include "../Util/OpenMPWrapper.h"
#include "BaseParser.h"
class PBFParser : public BaseParser { class PBFParser : public BaseParser {
enum EntityType { enum EntityType {
TypeNode = 1, TypeNode = 1,
TypeWay = 2, TypeWay = 2,
TypeRelation = 4, TypeRelation = 4,
TypeDenseNode = 8 TypeDenseNode = 8
} ; } ;
struct _ThreadData { struct _ThreadData {
int currentGroupID; int currentGroupID;
int currentEntityID; int currentEntityID;
short entityTypeIndicator; short entityTypeIndicator;
OSMPBF::BlobHeader PBFBlobHeader; OSMPBF::BlobHeader PBFBlobHeader;
OSMPBF::Blob PBFBlob; OSMPBF::Blob PBFBlob;
OSMPBF::HeaderBlock PBFHeaderBlock; OSMPBF::HeaderBlock PBFHeaderBlock;
OSMPBF::PrimitiveBlock PBFprimitiveBlock; OSMPBF::PrimitiveBlock PBFprimitiveBlock;
std::vector<char> charBuffer; std::vector<char> charBuffer;
}; };
public: public:
PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se); PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se);
virtual ~PBFParser(); virtual ~PBFParser();
inline bool ReadHeader(); inline bool ReadHeader();
inline bool Parse(); inline bool Parse();
private: private:
inline void ReadData(); inline void ReadData();
inline void ParseData(); inline void ParseData();
@ -75,7 +76,7 @@ private:
inline void parseNode(_ThreadData * ); inline void parseNode(_ThreadData * );
inline void parseRelation(_ThreadData * threadData); inline void parseRelation(_ThreadData * threadData);
inline void parseWay(_ThreadData * threadData); inline void parseWay(_ThreadData * threadData);
inline void loadGroup(_ThreadData * threadData); inline void loadGroup(_ThreadData * threadData);
inline void loadBlock(_ThreadData * threadData); inline void loadBlock(_ThreadData * threadData);
inline bool readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData); inline bool readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData);
@ -83,17 +84,17 @@ private:
inline bool unpackLZMA(std::fstream &, _ThreadData * ); inline bool unpackLZMA(std::fstream &, _ThreadData * );
inline bool readBlob(std::fstream& stream, _ThreadData * threadData) ; inline bool readBlob(std::fstream& stream, _ThreadData * threadData) ;
inline bool readNextBlock(std::fstream& stream, _ThreadData * threadData); inline bool readNextBlock(std::fstream& stream, _ThreadData * threadData);
static const int NANO = 1000 * 1000 * 1000; static const int NANO = 1000 * 1000 * 1000;
static const int MAX_BLOB_HEADER_SIZE = 64 * 1024; static const int MAX_BLOB_HEADER_SIZE = 64 * 1024;
static const int MAX_BLOB_SIZE = 32 * 1024 * 1024; static const int MAX_BLOB_SIZE = 32 * 1024 * 1024;
#ifndef NDEBUG #ifndef NDEBUG
/* counting the number of read blocks and groups */ /* counting the number of read blocks and groups */
unsigned groupCount; unsigned groupCount;
unsigned blockCount; unsigned blockCount;
#endif #endif
std::fstream input; // the input stream to parse std::fstream input; // the input stream to parse
boost::shared_ptr<ConcurrentQueue < _ThreadData* > > threadDataQueue; boost::shared_ptr<ConcurrentQueue < _ThreadData* > > threadDataQueue;
}; };

View File

@ -21,13 +21,13 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef LOCATEPLUGIN_H_ #ifndef LOCATEPLUGIN_H_
#define LOCATEPLUGIN_H_ #define LOCATEPLUGIN_H_
#include <fstream>
#include "../Server/DataStructures/QueryObjectsStorage.h"
#include "BasePlugin.h" #include "BasePlugin.h"
#include "RouteParameters.h" #include "RouteParameters.h"
#include "../Util/StringUtil.h"
#include "../DataStructures/NodeInformationHelpDesk.h" #include "../DataStructures/NodeInformationHelpDesk.h"
#include "../Server/DataStructures/QueryObjectsStorage.h"
#include "../Util/StringUtil.h"
#include <fstream>
/* /*
* This Plugin locates the nearest node in the road network for a given coordinate. * This Plugin locates the nearest node in the road network for a given coordinate.

View File

@ -52,14 +52,14 @@ private:
StaticGraph<QueryEdge::EdgeData> * graph; StaticGraph<QueryEdge::EdgeData> * graph;
HashTable<std::string, unsigned> descriptorTable; HashTable<std::string, unsigned> descriptorTable;
std::string pluginDescriptorString; std::string pluginDescriptorString;
SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > * searchEngine; SearchEngine * searchEnginePtr;
public: public:
ViaRoutePlugin(QueryObjectsStorage * objects, std::string psd = "viaroute") : names(objects->names), pluginDescriptorString(psd) { ViaRoutePlugin(QueryObjectsStorage * objects, std::string psd = "viaroute") : names(objects->names), pluginDescriptorString(psd) {
nodeHelpDesk = objects->nodeHelpDesk; nodeHelpDesk = objects->nodeHelpDesk;
graph = objects->graph; graph = objects->graph;
searchEngine = new SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> >(graph, nodeHelpDesk, names); searchEnginePtr = new SearchEngine(graph, nodeHelpDesk, names);
descriptorTable.Set("", 0); //default descriptor descriptorTable.Set("", 0); //default descriptor
descriptorTable.Set("json", 0); descriptorTable.Set("json", 0);
@ -67,7 +67,7 @@ public:
} }
virtual ~ViaRoutePlugin() { virtual ~ViaRoutePlugin() {
delete searchEngine; delete searchEnginePtr;
} }
std::string GetDescriptor() const { return pluginDescriptorString; } std::string GetDescriptor() const { return pluginDescriptorString; }
@ -101,7 +101,7 @@ public:
} }
} }
// INFO("Brute force lookup of coordinate " << i); // INFO("Brute force lookup of coordinate " << i);
searchEngine->FindPhantomNodeForCoordinate( rawRoute.rawViaNodeCoordinates[i], phantomNodeVector[i], routeParameters.zoomLevel); searchEnginePtr->FindPhantomNodeForCoordinate( rawRoute.rawViaNodeCoordinates[i], phantomNodeVector[i], routeParameters.zoomLevel);
} }
for(unsigned i = 0; i < phantomNodeVector.size()-1; ++i) { for(unsigned i = 0; i < phantomNodeVector.size()-1; ++i) {
@ -112,10 +112,10 @@ public:
} }
if( ( routeParameters.alternateRoute ) && (1 == rawRoute.segmentEndCoordinates.size()) ) { if( ( routeParameters.alternateRoute ) && (1 == rawRoute.segmentEndCoordinates.size()) ) {
// INFO("Checking for alternative paths"); // INFO("Checking for alternative paths");
searchEngine->alternativePaths(rawRoute.segmentEndCoordinates[0], rawRoute); searchEnginePtr->alternativePaths(rawRoute.segmentEndCoordinates[0], rawRoute);
} else { } else {
searchEngine->shortestPath(rawRoute.segmentEndCoordinates, rawRoute); searchEnginePtr->shortestPath(rawRoute.segmentEndCoordinates, rawRoute);
} }
@ -125,7 +125,7 @@ public:
reply.status = http::Reply::ok; reply.status = http::Reply::ok;
//TODO: Move to member as smart pointer //TODO: Move to member as smart pointer
BaseDescriptor<SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > > * desc; BaseDescriptor * desc;
if("" != routeParameters.jsonpParameter) { if("" != routeParameters.jsonpParameter) {
reply.content += routeParameters.jsonpParameter; reply.content += routeParameters.jsonpParameter;
reply.content += "("; reply.content += "(";
@ -140,15 +140,15 @@ public:
switch(descriptorType){ switch(descriptorType){
case 0: case 0:
desc = new JSONDescriptor<SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > >(); desc = new JSONDescriptor();
break; break;
case 1: case 1:
desc = new GPXDescriptor<SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > >(); desc = new GPXDescriptor();
break; break;
default: default:
desc = new JSONDescriptor<SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > >(); desc = new JSONDescriptor();
break; break;
} }
@ -161,7 +161,7 @@ public:
// INFO("Number of segments: " << rawRoute.segmentEndCoordinates.size()); // INFO("Number of segments: " << rawRoute.segmentEndCoordinates.size());
desc->SetConfig(descriptorConfig); desc->SetConfig(descriptorConfig);
desc->Run(reply, rawRoute, phantomNodes, *searchEngine); desc->Run(reply, rawRoute, phantomNodes, *searchEnginePtr);
if("" != routeParameters.jsonpParameter) { if("" != routeParameters.jsonpParameter) {
reply.content += ")\n"; reply.content += ")\n";
} }

View File

@ -4,6 +4,7 @@ require 'digest/sha1'
require 'cucumber/rake/task' require 'cucumber/rake/task'
require 'sys/proctable' require 'sys/proctable'
BUILD_FOLDER = 'build'
DATA_FOLDER = 'sandbox' DATA_FOLDER = 'sandbox'
PROFILE = 'bicycle' PROFILE = 'bicycle'
OSRM_PORT = 5000 OSRM_PORT = 5000
@ -77,11 +78,13 @@ end
desc "Rebuild and run tests." desc "Rebuild and run tests."
task :default => [:build, :cucumber] task :default => [:build]
desc "Build using SConsstruct." desc "Build using CMake."
task :build do task :build do
system "scons" Dir.chdir BUILD_FOLDER do
system "make"
end
end end
desc "Setup config files." desc "Setup config files."
@ -99,8 +102,8 @@ desc "Download OSM data."
task :download => :setup do task :download => :setup do
Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}" Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}"
puts "Downloading..." puts "Downloading..."
puts "curl http://download.geofabrik.de/openstreetmap/europe/#{osm_data_country}.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf" puts "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
raise "Error while downloading data." unless system "curl http://download.geofabrik.de/openstreetmap/europe/#{osm_data_country}.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf" raise "Error while downloading data." unless system "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
if osm_data_area_bbox if osm_data_area_bbox
puts "Cropping and converting to protobuffer..." puts "Cropping and converting to protobuffer..."
raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true" raise "Error while cropping data." unless system "osmosis --read-pbf file=#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
@ -117,9 +120,9 @@ end
desc "Reprocess OSM data." desc "Reprocess OSM data."
task :process => :setup do task :process => :setup do
Dir.chdir DATA_FOLDER 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" raise "Error while extracting data." unless system "../#{BUILD_FOLDER}/osrm-extract #{osm_data_area_name}.osm.pbf #{PROFILES_FOLDER}/#{PROFILE}.lua"
puts 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" raise "Error while preparing data." unless system "../#{BUILD_FOLDER}/osrm-prepare #{osm_data_area_name}.osrm #{osm_data_area_name}.osrm.restrictions #{PROFILES_FOLDER}/#{PROFILE}.lua"
puts puts
end end
end end
@ -127,14 +130,14 @@ end
desc "Extract OSM data." desc "Extract OSM data."
task :extract => :setup do task :extract => :setup do
Dir.chdir DATA_FOLDER do Dir.chdir DATA_FOLDER do
raise "Error while extracting data." unless system "../osrm-extract #{osm_data_area_name}.osm.pbf ../profiles/#{PROFILE}.lua" raise "Error while extracting data." unless system "../#{BUILD_FOLDER}/osrm-extract #{osm_data_area_name}.osm.pbf ../profiles/#{PROFILE}.lua"
end end
end end
desc "Prepare OSM data." desc "Prepare OSM data."
task :prepare => :setup do task :prepare => :setup do
Dir.chdir DATA_FOLDER 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" raise "Error while preparing data." unless system "../#{BUILD_FOLDER}/osrm-prepare #{osm_data_area_name}.osrm #{osm_data_area_name}.osrm.restrictions ../profiles/#{PROFILE}.lua"
end end
end end
@ -154,7 +157,7 @@ desc "Run the routing server in the terminal. Press Ctrl-C to stop."
task :run => :setup do task :run => :setup do
Dir.chdir DATA_FOLDER do Dir.chdir DATA_FOLDER do
write_server_ini osm_data_area_name write_server_ini osm_data_area_name
system "../osrm-routed" system "../#{BUILD_FOLDER}/osrm-routed"
end end
end end
@ -163,7 +166,7 @@ task :up => :setup do
Dir.chdir DATA_FOLDER do Dir.chdir DATA_FOLDER do
abort("Already up.") if up? abort("Already up.") if up?
write_server_ini osm_data_area_name write_server_ini osm_data_area_name
pipe = IO.popen('../osrm-routed 1>>osrm-routed.log 2>>osrm-routed.log') pipe = IO.popen("../#{BUILD_FOLDER}/osrm-routed 1>>osrm-routed.log 2>>osrm-routed.log")
timeout = 5 timeout = 5
(timeout*10).times do (timeout*10).times do
begin begin

View File

@ -23,13 +23,15 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef BASICROUTINGINTERFACE_H_ #ifndef BASICROUTINGINTERFACE_H_
#define BASICROUTINGINTERFACE_H_ #define BASICROUTINGINTERFACE_H_
#include "../Plugins/RawRouteData.h"
#include "../Util/ContainerUtils.h"
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <cassert> #include <cassert>
#include <climits> #include <climits>
#include "../Plugins/RawRouteData.h" #include <stack>
#include "../Util/ContainerUtils.h"
template<class QueryDataT> template<class QueryDataT>
class BasicRoutingInterface : boost::noncopyable{ class BasicRoutingInterface : boost::noncopyable{
@ -42,6 +44,7 @@ public:
inline void RoutingStep(typename QueryDataT::QueryHeap & _forwardHeap, typename QueryDataT::QueryHeap & _backwardHeap, NodeID *middle, int *_upperbound, const int edgeBasedOffset, const bool forwardDirection) const { 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 NodeID node = _forwardHeap.DeleteMin();
const int distance = _forwardHeap.GetKey(node); const int distance = _forwardHeap.GetKey(node);
//INFO("Settled (" << _forwardHeap.GetData( node ).parent << "," << node << ")=" << distance);
if(_backwardHeap.WasInserted(node) ){ if(_backwardHeap.WasInserted(node) ){
const int newDistance = _backwardHeap.GetKey(node) + distance; const int newDistance = _backwardHeap.GetKey(node) + distance;
if(newDistance < *_upperbound ){ if(newDistance < *_upperbound ){

View File

@ -73,18 +73,24 @@ public:
//insert new starting nodes into forward heap, adjusted by previous distances. //insert new starting nodes into forward heap, adjusted by previous distances.
if(searchFrom1stStartNode) { if(searchFrom1stStartNode) {
forward_heap1.Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); forward_heap1.Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
INFO("fw1: " << phantomNodePair.startPhantom.edgeBasedNode << "´, w: " << -phantomNodePair.startPhantom.weight1);
forward_heap2.Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); forward_heap2.Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
} INFO("fw2: " << phantomNodePair.startPhantom.edgeBasedNode << "´, w: " << -phantomNodePair.startPhantom.weight1);
}
if(phantomNodePair.startPhantom.isBidirected() && searchFrom2ndStartNode) { if(phantomNodePair.startPhantom.isBidirected() && searchFrom2ndStartNode) {
forward_heap1.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);
INFO("fw1: " << phantomNodePair.startPhantom.edgeBasedNode+1 << "´, w: " << -phantomNodePair.startPhantom.weight2);
forward_heap2.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);
INFO("fw2: " << phantomNodePair.startPhantom.edgeBasedNode+1 << "´, w: " << -phantomNodePair.startPhantom.weight2);
} }
//insert new backward nodes into backward heap, unadjusted. //insert new backward nodes into backward heap, unadjusted.
reverse_heap1.Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode); reverse_heap1.Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode);
INFO("rv1: " << phantomNodePair.targetPhantom.edgeBasedNode << ", w;" << phantomNodePair.targetPhantom.weight1 );
if(phantomNodePair.targetPhantom.isBidirected() ) { if(phantomNodePair.targetPhantom.isBidirected() ) {
reverse_heap2.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);
} INFO("rv2: " << phantomNodePair.targetPhantom.edgeBasedNode+1 << ", w;" << phantomNodePair.targetPhantom.weight2 );
}
const int forward_offset = phantomNodePair.startPhantom.weight1 + (phantomNodePair.startPhantom.isBidirected() ? phantomNodePair.startPhantom.weight2 : 0); 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); const int reverse_offset = phantomNodePair.targetPhantom.weight1 + (phantomNodePair.targetPhantom.isBidirected() ? phantomNodePair.targetPhantom.weight2 : 0);

View File

@ -1,300 +0,0 @@
#Sconstruct
import os
import os.path
import string
import sys
from subprocess import call
def CheckBoost(context, version):
# Boost versions are in format major.minor.subminor
v_arr = version.split(".")
version_n = 0
if len(v_arr) > 0:
version_n += int(v_arr[0])*100000
if len(v_arr) > 1:
version_n += int(v_arr[1])*100
if len(v_arr) > 2:
version_n += int(v_arr[2])
context.Message('Checking for Boost version >= %s... ' % (version))
ret = context.TryRun("""
#include <boost/version.hpp>
int main()
{
return BOOST_VERSION >= %d ? 0 : 1;
}
""" % version_n, '.cpp')[0]
context.Result(ret)
return ret
def CheckProtobuf(context, version):
# Protobuf versions are in format major.minor.subminor
v_arr = version.split(".")
version_n = 0
if len(v_arr) > 0:
version_n += int(v_arr[0])*1000000
if len(v_arr) > 1:
version_n += int(v_arr[1])*1000
if len(v_arr) > 2:
version_n += int(v_arr[2])
context.Message('Checking for Protobuffer version >= %s... ' % (version))
ret = context.TryRun("""
#include <google/protobuf/stubs/common.h>
int main() {
return (GOOGLE_PROTOBUF_VERSION >= %d) ? 0 : 1;
}
""" % version_n, '.cpp')[0]
context.Result(ret)
return ret
# Adding various options to the SConstruct
AddOption('--cxx', dest='cxx', type='string', nargs=1, action='store', metavar='STRING', help='C++ Compiler')
AddOption('--stxxlroot', dest='stxxlroot', type='string', nargs=1, action='store', metavar='STRING', help='root directory of STXXL')
AddOption('--verbosity', dest='verbosity', type='string', nargs=1, action='store', metavar='STRING', help='make Scons talking')
AddOption('--buildconfiguration', dest='buildconfiguration', type='string', nargs=1, action='store', metavar='STRING', help='debug or release')
AddOption('--all-flags', dest='allflags', type='string', nargs=0, action='store', metavar='STRING', help='turn off -march optimization in release mode')
AddOption('--with-tools', dest='withtools', type='string', nargs=0, action='store', metavar='STRING', help='build tools for data analysis')
AddOption('--no-march', dest='nomarch', type='string', nargs=0, action='store', metavar='STRING', help='turn off native optimizations')
env = Environment( ENV = {'PATH' : os.environ['PATH']} ,COMPILER = GetOption('cxx'))
env["CC"] = os.getenv("CC") or env["CC"]
env["CXX"] = os.getenv("CXX") or env["CXX"]
env["ENV"].update(x for x in os.environ.items() if x[0].startswith("CCC_"))
try:
env['ENV']['TERM'] = os.environ['TERM']
except KeyError:
env['ENV']['TERM'] = 'none'
conf = Configure(env, custom_tests = { 'CheckBoost' : CheckBoost, 'CheckProtobuf' : CheckProtobuf })
if GetOption('cxx') is None:
#default Compiler
if sys.platform == 'darwin': #Mac OS X
env['CXX'] = 'clang++'
print 'Using default C++ Compiler: ', env['CXX'].strip()
else:
env.Replace(CXX = GetOption('cxx'))
print 'Using user supplied C++ Compiler: ', env['CXX']
if GetOption('allflags') is not None:
env.Append(CXXFLAGS = ["-Wextra", "-Wall", "-Wnon-virtual-dtor", "-Wundef", "-Wno-long-long", "-Woverloaded-virtual", "-Wfloat-equal", "-Wredundant-decls"])
if "clang" in env["CXX"]:
print "Warning building with clang removes OpenMP parallelization"
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', '-Wall'])
env.Append(LINKFLAGS = '-fopenmp')
if GetOption('buildconfiguration') == 'debug':
env.Append(CCFLAGS = ['-Wall', '-g3', '-rdynamic'])
else:
env.Append(CCFLAGS = ['-O3', '-DNDEBUG'])
if sys.platform == 'darwin': #Mac OS X
#os x default installations
env.Append(CPPPATH = ['/usr/include/libxml2'] )
env.Append(CPPPATH = ['/usr/X11/include']) #comes with os x
# env.Append(LIBPATH = ['/usr/X11/lib']) #needed for libpng
#assume stxxl and boost are installed via homebrew. call brew binary to get folder locations
import subprocess
stxxl_prefix = subprocess.check_output(["brew", "--prefix", "libstxxl"]).strip()
env.Append(CPPPATH = [stxxl_prefix+"/include"] )
env.Append(LIBPATH = [stxxl_prefix+"/lib"] )
boost_prefix = subprocess.check_output(["brew", "--prefix", "boost"]).strip()
env.Append(CPPPATH = [boost_prefix+"/include"] )
env.Append(LIBPATH = [boost_prefix+"/lib"] )
if not conf.CheckLibWithHeader('lua', 'lua.h', 'C'):
print "lua library not found. Exiting"
Exit(-1)
if not conf.CheckLibWithHeader('luabind', 'luabind/luabind.hpp', 'CXX'):
print "luabind library not found. Exiting"
Exit(-1)
elif sys.platform.startswith("freebsd"):
env.ParseConfig('pkg-config --cflags --libs protobuf')
env.Append(CPPPATH = ['/usr/local/include', '/usr/local/include/libxml2'])
env.Append(LIBPATH = ['/usr/local/lib'])
if GetOption('stxxlroot') is not None:
env.Append(CPPPATH = GetOption('stxxlroot')+'/include')
env.Append(LIBPATH = GetOption('stxxlroot')+'/lib')
print 'STXXLROOT = ', GetOption('stxxlroot')
elif sys.platform == 'win32':
#SCons really wants to use Microsoft compiler
print "Compiling is not yet supported on Windows"
Exit(-1)
else:
print "Default platform"
if GetOption('stxxlroot') is not None:
env.Append(CPPPATH = GetOption('stxxlroot')+'/include')
env.Append(LIBPATH = GetOption('stxxlroot')+'/lib')
print 'STXXLROOT = ', GetOption('stxxlroot')
env.Append(CPPPATH = ['/usr/include', '/usr/include/include', '/usr/include/libxml2/'])
if not conf.CheckLibWithHeader('pthread', 'pthread.h', 'CXX'):
print "pthread not found. Exiting"
Exit(-1)
if not conf.CheckLibWithHeader('luajit-5.1', 'luajit-2.0/lua.h', 'CXX'):
print "luajit library not found. Checking for interpreter"
env.ParseConfig('pkg-config --cflags --libs lua5.1')
env.ParseConfig('pkg-config --cflags --libs luabind')
#Check if architecture optimizations shall be turned off
if GetOption('buildconfiguration') != 'debug' and sys.platform != 'darwin' and GetOption('nomarch') is None:
env.Append(CCFLAGS = ['-march=native'])
if not conf.CheckHeader('omp.h'):
if "clang" not in env["CXX"]:
print "OpenMP not found, Exiting"
Exit(-1)
if not conf.CheckLibWithHeader('bz2', 'bzlib.h', 'CXX'):
print "bz2 library not found. Exiting"
Exit(-1)
if GetOption('withtools') is not None:
if not conf.CheckLibWithHeader('gdal', 'gdal/gdal.h', 'CXX'):
print "gdal library not found. Exiting"
Exit(-1)
if not conf.CheckLibWithHeader('osmpbf', 'osmpbf/osmpbf.h', 'CXX'):
print "osmpbf library not found. Exiting"
print "Either install libosmpbf-dev (Ubuntu) or use https://github.com/scrosby/OSM-binary"
Exit(-1)
if not conf.CheckLibWithHeader('protobuf', 'google/protobuf/descriptor.h', 'CXX'):
print "Google Protobuffer library not found. Exiting"
Exit(-1)
#check for protobuf 2.3.0
if not (conf.CheckProtobuf('2.3.0')):
print 'libprotobuf version >= 2.3.0 needed'
Exit(-1);
if not (env.Detect('protoc')):
print 'protobuffer compiler not found'
Exit(-1);
if not conf.CheckLibWithHeader('stxxl', 'stxxl.h', 'CXX'):
print "stxxl library not found. Exiting"
Exit(-1)
if not conf.CheckLibWithHeader('xml2', 'libxml/xmlreader.h', 'CXX'):
print "libxml2 library or header not found. Exiting"
Exit(-1)
if not conf.CheckLibWithHeader('z', 'zlib.h', 'CXX'):
print "zlib library or header not found. Exiting"
Exit(-1)
#Check BOOST installation
if not (conf.CheckBoost('1.44')):
print 'Boost version >= 1.44 needed'
Exit(-1);
if not conf.CheckLib('boost_system', language="C++"):
if not conf.CheckLib('boost_system-mt', language="C++"):
print "boost_system library not found. Exiting"
Exit(-1)
else:
print "using boost -mt"
env.Append(CCFLAGS = ' -lboost_system-mt')
env.Append(LINKFLAGS = ' -lboost_system-mt')
if not conf.CheckLibWithHeader('boost_thread', 'boost/thread.hpp', 'CXX'):
if not conf.CheckLibWithHeader('boost_thread-mt', 'boost/thread.hpp', 'CXX'):
print "boost thread library not found. Exiting"
Exit(-1)
else:
print "using boost -mt"
env.Append(CCFLAGS = ' -lboost_thread-mt')
env.Append(LINKFLAGS = ' -lboost_thread-mt')
if not conf.CheckLibWithHeader('boost_regex', 'boost/regex.hpp', 'CXX'):
if not conf.CheckLibWithHeader('boost_regex-mt', 'boost/regex.hpp', 'CXX'):
print "boost/regex.hpp not found. Exiting"
Exit(-1)
else:
print "using boost_regex -mt"
env.Append(CCFLAGS = ' -lboost_regex-mt')
env.Append(LINKFLAGS = ' -lboost_regex-mt')
if not conf.CheckLib('boost_filesystem', language="C++"):
if not conf.CheckLib('boost_filesystem-mt', language="C++"):
print "boost_filesystem library not found. Exiting"
Exit(-1)
else:
print "using boost -mt"
env.Append(CCFLAGS = ' -lboost_filesystem-mt')
env.Append(LINKFLAGS = ' -lboost_filesystem-mt')
if not conf.CheckCXXHeader('boost/archive/iterators/base64_from_binary.hpp'):
print "boost/archive/iterators/base64_from_binary.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/archive/iterators/binary_from_base64.hpp'):
print "boost/archive/iterators/binary_from_base64.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/archive/iterators/transform_width.hpp'):
print "boost/archive/iterators/transform_width.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/bind.hpp'):
print "boost/bind.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/circular_buffer.hpp'):
print "boost/circular_buffer.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/enable_shared_from_this.hpp'):
print "boost/bind.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/foreach.hpp'):
print "boost/foreach.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/lexical_cast.hpp'):
print "boost/foreach.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/logic/tribool.hpp'):
print "boost/foreach.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/math/tr1.hpp'):
print "boost/foreach.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/noncopyable.hpp'):
print "boost/noncopyable.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/property_tree/ptree.hpp'):
print "boost/property_tree/ptree.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/property_tree/ini_parser.hpp'):
print "boost/property_tree/ini_parser.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/shared_ptr.hpp'):
print "boost/shared_ptr.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/thread/mutex.hpp'):
print "boost/shared_ptr.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/thread/thread.hpp'):
print "boost/thread/thread.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/thread/condition.hpp'):
print "boost/thread/condition.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/thread/thread.hpp'):
print "boost/thread/thread.hpp not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/thread.hpp'):
print "boost thread header not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/tuple/tuple.hpp'):
print "boost thread header not found. Exiting"
Exit(-1)
if not conf.CheckCXXHeader('boost/unordered_map.hpp'):
print "boost thread header not found. Exiting"
Exit(-1)
#checks for intels thread building blocks library
#if not conf.CheckLibWithHeader('tbb', 'tbb/tbb.h', 'CXX'):
# print "Intel TBB library not found. Exiting"
# Exit(-1)
#if not conf.CheckCXXHeader('tbb/task_scheduler_init.h'):
# print "tbb/task_scheduler_init.h not found. Exiting"
# Exit(-1)
env.Program(target = 'osrm-extract', source = ["extractor.cpp", Glob('Util/*.cpp'), Glob('Extractor/*.cpp')])
env.Program(target = 'osrm-prepare', source = ["createHierarchy.cpp", Glob('Contractor/*.cpp'), Glob('Util/SRTMLookup/*.cpp'), Glob('Algorithms/*.cpp')])
env.Program(target = 'osrm-routed', source = ["routed.cpp", 'Descriptors/DescriptionFactory.cpp', Glob('ThirdParty/*.cc'), Glob('Server/DataStructures/*.cpp')], CCFLAGS = env['CCFLAGS'] + ['-DROUTED'])
if GetOption('withtools') is not None:
env.Program(target = 'Tools/osrm-component', source = ["Tools/componentAnalysis.cpp"])
env = conf.Finish()

View File

@ -21,8 +21,8 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef BASIC_DATASTRUCTURES_H #ifndef BASIC_DATASTRUCTURES_H
#define BASIC_DATASTRUCTURES_H #define BASIC_DATASTRUCTURES_H
#include <string> #include <string>
#include <sstream>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
@ -143,7 +143,11 @@ Reply Reply::stockReply(Reply::status_type status) {
rep.headers[0].name = "Access-Control-Allow-Origin"; rep.headers[0].name = "Access-Control-Allow-Origin";
rep.headers[0].value = "*"; rep.headers[0].value = "*";
rep.headers[1].name = "Content-Length"; rep.headers[1].name = "Content-Length";
rep.headers[1].value = boost::lexical_cast<std::string>(rep.content.size());
std::string s;
intToString(rep.content.size(), s);
rep.headers[1].value = s;
rep.headers[2].name = "Content-Type"; rep.headers[2].name = "Content-Type";
rep.headers[2].value = "text/html"; rep.headers[2].value = "text/html";
return rep; return rep;

View File

@ -22,14 +22,27 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "QueryObjectsStorage.h" #include "QueryObjectsStorage.h"
#include "../../Util/GraphLoader.h" #include "../../Util/GraphLoader.h"
QueryObjectsStorage::QueryObjectsStorage(std::string hsgrPath, std::string ramIndexPath, std::string fileIndexPath, std::string nodesPath, std::string edgesPath, std::string namesPath, std::string timestampPath) { QueryObjectsStorage::QueryObjectsStorage(
std::string hsgrPath,
std::string ramIndexPath,
std::string fileIndexPath,
std::string nodesPath,
std::string edgesPath,
std::string namesPath,
std::string timestampPath
) {
INFO("loading graph data"); INFO("loading graph data");
std::ifstream hsgrInStream(hsgrPath.c_str(), std::ios::binary); std::ifstream hsgrInStream(hsgrPath.c_str(), std::ios::binary);
if(!hsgrInStream) { ERR(hsgrPath << " not found"); } if(!hsgrInStream) { ERR(hsgrPath << " not found"); }
//Deserialize road network graph //Deserialize road network graph
std::vector< QueryGraph::_StrNode> nodeList; std::vector< QueryGraph::_StrNode> nodeList;
std::vector< QueryGraph::_StrEdge> edgeList; std::vector< QueryGraph::_StrEdge> edgeList;
const int n = readHSGRFromStream(hsgrInStream, nodeList, edgeList, &checkSum); const int n = readHSGRFromStream(
hsgrInStream,
nodeList,
edgeList,
&checkSum
);
INFO("Data checksum is " << checkSum); INFO("Data checksum is " << checkSum);
graph = new QueryGraph(nodeList, edgeList); graph = new QueryGraph(nodeList, edgeList);
@ -39,7 +52,7 @@ QueryObjectsStorage::QueryObjectsStorage(std::string hsgrPath, std::string ramIn
if(timestampPath.length()) { if(timestampPath.length()) {
INFO("Loading Timestamp"); INFO("Loading Timestamp");
std::ifstream timestampInStream(timestampPath.c_str()); std::ifstream timestampInStream(timestampPath.c_str());
if(!timestampInStream) { ERR(timestampPath << " not found"); } if(!timestampInStream) { WARN(timestampPath << " not found"); }
getline(timestampInStream, timestamp); getline(timestampInStream, timestamp);
timestampInStream.close(); timestampInStream.close();

View File

@ -25,7 +25,6 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <cctype> // std::tolower #include <cctype> // std::tolower
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include "APIGrammar.h" #include "APIGrammar.h"
@ -52,19 +51,20 @@ public:
void handle_request(const Request& req, Reply& rep){ void handle_request(const Request& req, Reply& rep){
//parse command //parse command
std::string request(req.uri);
{ //This block logs the current request to std out. should be moved to a logging component
time_t ltime;
struct tm *Tm;
ltime=time(NULL);
Tm=localtime(&ltime);
INFO((Tm->tm_mday < 10 ? "0" : "" ) << Tm->tm_mday << "-" << (Tm->tm_mon+1 < 10 ? "0" : "" ) << (Tm->tm_mon+1) << "-" << 1900+Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "" ) << Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "" ) << Tm->tm_min << ":" << (Tm->tm_sec < 10 ? "0" : "" ) << Tm->tm_sec << " " <<
req.endpoint.to_string() << " " << req.referrer << ( 0 == req.referrer.length() ? "- " :" ") << req.agent << ( 0 == req.agent.length() ? "- " :" ") << req.uri );
}
try { try {
std::string request(req.uri);
{ //This block logs the current request to std out. should be moved to a logging component
time_t ltime;
struct tm *Tm;
ltime=time(NULL);
Tm=localtime(&ltime);
INFO((Tm->tm_mday < 10 ? "0" : "" ) << Tm->tm_mday << "-" << (Tm->tm_mon+1 < 10 ? "0" : "" ) << (Tm->tm_mon+1) << "-" << 1900+Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "" ) << Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "" ) << Tm->tm_min << ":" << (Tm->tm_sec < 10 ? "0" : "" ) << Tm->tm_sec << " " <<
req.endpoint.to_string() << " " << req.referrer << ( 0 == req.referrer.length() ? "- " :" ") << req.agent << ( 0 == req.agent.length() ? "- " :" ") << req.uri );
}
RouteParameters routeParameters; RouteParameters routeParameters;
APIGrammar<std::string::iterator, RouteParameters> apiParser(&routeParameters); APIGrammar<std::string::iterator, RouteParameters> apiParser(&routeParameters);

View File

@ -21,6 +21,15 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef GRAPHLOADER_H #ifndef GRAPHLOADER_H
#define GRAPHLOADER_H #define GRAPHLOADER_H
#include "../DataStructures/ImportNode.h"
#include "../DataStructures/ImportEdge.h"
#include "../DataStructures/NodeCoords.h"
#include "../DataStructures/Restriction.h"
#include "../typedefs.h"
#include <boost/assert.hpp>
#include <boost/unordered_map.hpp>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
@ -30,19 +39,11 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <iomanip> #include <iomanip>
#include <vector> #include <vector>
#include <boost/unordered_map.hpp>
#include "../DataStructures/ImportNode.h"
#include "../DataStructures/ImportEdge.h"
#include "../DataStructures/NodeCoords.h"
#include "../DataStructures/Restriction.h"
#include "../typedefs.h"
typedef boost::unordered_map<NodeID, NodeID> ExternalNodeMap; typedef boost::unordered_map<NodeID, NodeID> ExternalNodeMap;
template<class EdgeT> template<class EdgeT>
struct _ExcessRemover { struct _ExcessRemover {
inline bool operator()( EdgeT & edge ) const { inline bool operator()( const EdgeT & edge ) const {
return edge.source() == UINT_MAX; return edge.source() == UINT_MAX;
} }
}; };
@ -116,9 +117,9 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &in, std::vector<EdgeT>& edgeL
in.read((char*)&isAccessRestricted, sizeof(bool)); in.read((char*)&isAccessRestricted, sizeof(bool));
in.read((char*)&isContraFlow, sizeof(bool)); in.read((char*)&isContraFlow, sizeof(bool));
GUARANTEE(length > 0, "loaded null length edge" ); BOOST_ASSERT_MSG(length > 0, "loaded null length edge" );
GUARANTEE(weight > 0, "loaded null weight"); BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
GUARANTEE(0<=dir && dir<=2, "loaded bogus direction"); BOOST_ASSERT_MSG(0<=dir && dir<=2, "loaded bogus direction");
bool forward = true; bool forward = true;
bool backward = true; bool backward = true;
@ -144,7 +145,9 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &in, std::vector<EdgeT>& edgeL
continue; continue;
} }
target = intNodeID->second; target = intNodeID->second;
GUARANTEE(source != UINT_MAX && target != UINT_MAX, "nonexisting source or target"); BOOST_ASSERT_MSG(source != UINT_MAX && target != UINT_MAX,
"nonexisting source or target"
);
if(source > target) { if(source > target) {
std::swap(source, target); std::swap(source, target);
@ -185,9 +188,9 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &in, std::vector<EdgeT>& edgeL
} }
} }
} }
std::vector<ImportEdge>::iterator newEnd = std::remove_if(edgeList.begin(), edgeList.end(), _ExcessRemover<EdgeT>()); typename std::vector<EdgeT>::iterator newEnd = std::remove_if(edgeList.begin(), edgeList.end(), _ExcessRemover<EdgeT>());
ext2IntNodeMap.clear(); ext2IntNodeMap.clear();
std::vector<ImportEdge>(edgeList.begin(), newEnd).swap(edgeList); //remove excess candidates. std::vector<EdgeT>(edgeList.begin(), newEnd).swap(edgeList); //remove excess candidates.
INFO("Graph loaded ok and has " << edgeList.size() << " edges"); INFO("Graph loaded ok and has " << edgeList.size() << " edges");
return n; return n;
} }
@ -299,7 +302,7 @@ NodeID readDTMPGraphFromStream(std::istream &in, std::vector<EdgeT>& edgeList, s
edgeList.push_back(inputEdge); edgeList.push_back(inputEdge);
} }
ext2IntNodeMap.clear(); ext2IntNodeMap.clear();
std::vector<ImportEdge>(edgeList.begin(), edgeList.end()).swap(edgeList); //remove excess candidates. std::vector<EdgeT>(edgeList.begin(), edgeList.end()).swap(edgeList); //remove excess candidates.
std::cout << "ok" << std::endl; std::cout << "ok" << std::endl;
return n; return n;
} }

View File

@ -18,14 +18,19 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
or see http://www.gnu.org/licenses/agpl.txt. or see http://www.gnu.org/licenses/agpl.txt.
*/ */
#ifndef LUAUTIL_H_ #ifndef LUAUTIL_H_
#define LUAUTIL_H_ #define LUAUTIL_H_
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include <boost/filesystem/convenience.hpp>
#include <luabind/luabind.hpp>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <boost/filesystem/convenience.hpp>
template<typename T> template<typename T>
void LUA_print(T number) { void LUA_print(T number) {

75
cmake/FindLuabind.cmake Normal file
View File

@ -0,0 +1,75 @@
# Locate Luabind library
# This module defines
# LUABIND_FOUND, if false, do not try to link to Luabind
# LUABIND_LIBRARIES
# LUABIND_INCLUDE_DIR, where to find luabind.hpp
#
# Note that the expected include convention is
# #include <luabind/luabind.hpp>
# and not
# #include <luabind.hpp>
IF( NOT LUABIND_FIND_QUIETLY )
MESSAGE(STATUS "Looking for Luabind...")
ENDIF()
FIND_PATH(LUABIND_INCLUDE_DIR luabind.hpp
HINTS
$ENV{LUABIND_DIR}
PATH_SUFFIXES luabind include/luabind include
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/opt/local # DarwinPorts
/opt
)
FIND_LIBRARY(LUABIND_LIBRARY
NAMES luabind
HINTS
$ENV{LUABIND_DIR}
PATH_SUFFIXES lib64 lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/opt/local
/opt
)
FIND_LIBRARY(LUABIND_LIBRARY_DBG
NAMES luabindd
HINTS
$ENV{LUABIND_DIR}
PATH_SUFFIXES lib64 lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/opt/local
/opt
)
IF(LUABIND_LIBRARY)
SET( LUABIND_LIBRARIES "${LUABIND_LIBRARY}" CACHE STRING "Luabind Libraries")
ENDIF(LUABIND_LIBRARY)
INCLUDE(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LUABIND_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Luabind DEFAULT_MSG LUABIND_LIBRARIES LUABIND_INCLUDE_DIR)
IF( NOT LUABIND_FIND_QUIETLY )
IF( LUABIND_FOUND )
MESSAGE(STATUS "Found Luabind: ${LUABIND_LIBRARY}" )
ENDIF()
IF( LUABIND_LIBRARY_DBG )
MESSAGE(STATUS "Luabind debug library availible: ${LUABIND_LIBRARY_DBG}")
ENDIF()
ENDIF()
MARK_AS_ADVANCED(LUABIND_INCLUDE_DIR LUABIND_LIBRARIES LUABIND_LIBRARY LUABIND_LIBRARY_DBG)

54
cmake/FindOSMPBF.cmake Normal file
View File

@ -0,0 +1,54 @@
# Locate OSMPBF library
# This module defines
# OSMPBF_FOUND, if false, do not try to link to OSMPBF
# OSMPBF_LIBRARIES
# OSMPBF_INCLUDE_DIR, where to find OSMPBF.hpp
#
# Note that the expected include convention is
# #include <osmpbf/osmpbf.h>
# and not
# #include <osmpbf.h>
IF( NOT OSMPBF_FIND_QUIETLY )
MESSAGE(STATUS "Looking for OSMPBF...")
ENDIF()
FIND_PATH(OSMPBF_INCLUDE_DIR osmpbf.h
HINTS
$ENV{OSMPBF_DIR}
PATH_SUFFIXES OSMPBF include/osmpbf include
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/opt/local # DarwinPorts
/opt
)
FIND_LIBRARY(OSMPBF_LIBRARY
NAMES osmpbf
HINTS
$ENV{OSMPBF_DIR}
PATH_SUFFIXES lib64 lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/opt/local
/opt
)
INCLUDE(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set OSMPBF_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OSMPBF DEFAULT_MSG OSMPBF_LIBRARY OSMPBF_INCLUDE_DIR)
IF( NOT OSMPBF_FIND_QUIETLY )
IF( OSMPBF_FOUND )
MESSAGE(STATUS "Found OSMPBF: ${OSMPBF_LIBRARY}" )
ENDIF()
ENDIF()
#MARK_AS_ADVANCED(OSMPBF_INCLUDE_DIR OSMPBF_LIBRARIES OSMPBF_LIBRARY OSMPBF_LIBRARY_DBG)

51
cmake/FindSTXXL.cmake Normal file
View File

@ -0,0 +1,51 @@
# Locate STXXL library
# This module defines
# STXXL_FOUND, if false, do not try to link to libstxxl
# STXXL_LIBRARY
# STXXL_INCLUDE_DIR, where to find stxxl.h
#
IF( NOT STXXL_FIND_QUIETLY )
MESSAGE(STATUS "Looking for STXXL...")
ENDIF()
FIND_PATH(STXXL_INCLUDE_DIR stxxl.h
HINTS
$ENV{STXXL_DIR}
PATH_SUFFIXES stxxl include/stxxl/stxxl include/stxxl include
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/opt/local # DarwinPorts
/opt
)
FIND_LIBRARY(STXXL_LIBRARY
NAMES stxxl
HINTS
$ENV{STXXL_DIR}
PATH_SUFFIXES lib64 lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/opt/local
/opt
)
INCLUDE(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set STXXL_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(STXXL DEFAULT_MSG STXXL_LIBRARY STXXL_INCLUDE_DIR)
IF( NOT STXXL_FIND_QUIETLY )
IF( STXXL_FOUND )
MESSAGE(STATUS "Found STXXL: ${STXXL_LIBRARY}" )
ENDIF()
ENDIF()
MARK_AS_ADVANCED(STXXL_INCLUDE_DIR STXXL_LIBRARY)

View File

@ -0,0 +1,123 @@
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
function(get_git_head_revision _refspecvar _hashvar)
set(GIT_PARENT_DIR "${CMAKE_SOURCE_DIR}")
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
# We have reached the root directory, we are not in git
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
return()
endif()
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
endwhile()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${GIT_DIR}/HEAD")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake"
@ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
endfunction()

View File

@ -18,15 +18,26 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
or see http://www.gnu.org/licenses/agpl.txt. or see http://www.gnu.org/licenses/agpl.txt.
*/ */
extern "C" { #include "Algorithms/IteratorBasedCRC32.h"
#include <lua.h> #include "Contractor/Contractor.h"
#include <lauxlib.h> #include "Contractor/EdgeBasedGraphFactory.h"
#include <lualib.h> #include "DataStructures/BinaryHeap.h"
} #include "DataStructures/DeallocatingVector.h"
#include <luabind/luabind.hpp> #include "DataStructures/QueryEdge.h"
#include "DataStructures/StaticGraph.h"
#include "DataStructures/StaticRTree.h"
#include "Util/BaseConfiguration.h"
#include "Util/GraphLoader.h"
#include "Util/InputFileUtil.h"
#include "Util/LuaUtil.h"
#include "Util/OpenMPWrapper.h"
#include "Util/StringUtil.h"
#include "typedefs.h"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <luabind/luabind.hpp>
#include <fstream> #include <fstream>
#include <istream> #include <istream>
#include <iostream> #include <iostream>
@ -34,21 +45,6 @@ extern "C" {
#include <string> #include <string>
#include <vector> #include <vector>
#include "Algorithms/IteratorBasedCRC32.h"
#include "Util/OpenMPWrapper.h"
#include "typedefs.h"
#include "Contractor/Contractor.h"
#include "Contractor/EdgeBasedGraphFactory.h"
#include "DataStructures/BinaryHeap.h"
#include "DataStructures/DeallocatingVector.h"
#include "DataStructures/NNGrid.h"
#include "DataStructures/QueryEdge.h"
#include "Util/BaseConfiguration.h"
#include "Util/GraphLoader.h"
#include "Util/InputFileUtil.h"
#include "Util/LuaUtil.h"
#include "Util/StringUtil.h"
typedef QueryEdge::EdgeData EdgeData; typedef QueryEdge::EdgeData EdgeData;
typedef DynamicGraph<EdgeData>::InputEdge InputEdge; typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
typedef StaticGraph<EdgeData>::InputEdge StaticEdge; typedef StaticGraph<EdgeData>::InputEdge StaticEdge;
@ -61,212 +57,220 @@ std::vector<NodeID> trafficLightNodes;
std::vector<ImportEdge> edgeList; std::vector<ImportEdge> edgeList;
int main (int argc, char *argv[]) { int main (int argc, char *argv[]) {
if(argc < 3) { try {
ERR("usage: " << std::endl << argv[0] << " <osrm-data> <osrm-restrictions> [<profile>]"); if(argc < 3) {
} ERR("usage: " << std::endl << argv[0] << " <osrm-data> <osrm-restrictions> [<profile>]");
double startupTime = get_timestamp();
unsigned numberOfThreads = omp_get_num_procs();
if(testDataFile("contractor.ini")) {
ContractorConfiguration contractorConfig("contractor.ini");
unsigned rawNumber = stringToInt(contractorConfig.GetParameter("Threads"));
if(rawNumber != 0 && rawNumber <= numberOfThreads)
numberOfThreads = rawNumber;
}
omp_set_num_threads(numberOfThreads);
INFO("Using restrictions from file: " << argv[2]);
std::ifstream restrictionsInstream(argv[2], std::ios::binary);
if(!restrictionsInstream.good()) {
ERR("Could not access <osrm-restrictions> files");
}
_Restriction restriction;
unsigned usableRestrictionsCounter(0);
restrictionsInstream.read((char*)&usableRestrictionsCounter, sizeof(unsigned));
inputRestrictions.resize(usableRestrictionsCounter);
restrictionsInstream.read((char *)&(inputRestrictions[0]), usableRestrictionsCounter*sizeof(_Restriction));
restrictionsInstream.close();
std::ifstream in;
in.open (argv[1], std::ifstream::in | std::ifstream::binary);
if (!in.is_open()) {
ERR("Cannot open " << argv[1]);
}
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") )) {
ERR("Need profile.lua to apply traffic signal penalty");
}
// Create a new lua state
lua_State *myLuaState = luaL_newstate();
// 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") );
if(0 != luaL_dofile(myLuaState, (argc > 3 ? argv[3] : "profile.lua") )) {
ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
}
EdgeBasedGraphFactory::SpeedProfileProperties speedProfile;
if(0 != luaL_dostring( myLuaState, "return traffic_signal_penalty\n")) {
ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
}
speedProfile.trafficSignalPenalty = 10*lua_tointeger(myLuaState, -1);
if(0 != luaL_dostring( myLuaState, "return u_turn_penalty\n")) {
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<ImportEdge> edgeList;
NodeID nodeBasedNodeNumber = readBinaryOSRMGraphFromStream(in, edgeList, bollardNodes, trafficLightNodes, &internalToExternalNodeMapping, inputRestrictions);
in.close();
INFO(inputRestrictions.size() << " restrictions, " << bollardNodes.size() << " bollard nodes, " << trafficLightNodes.size() << " traffic lights");
if(0 == edgeList.size())
ERR("The input data is broken. It is impossible to do any turns in this graph");
/***
* Building an edge-expanded graph from node-based input an turn restrictions
*/
INFO("Generating edge-expanded graph representation");
EdgeBasedGraphFactory * edgeBasedGraphFactory = new EdgeBasedGraphFactory (nodeBasedNodeNumber, edgeList, bollardNodes, trafficLightNodes, inputRestrictions, internalToExternalNodeMapping, speedProfile);
std::vector<ImportEdge>().swap(edgeList);
edgeBasedGraphFactory->Run(edgeOut.c_str(), myLuaState);
std::vector<_Restriction>().swap(inputRestrictions);
std::vector<NodeID>().swap(bollardNodes);
std::vector<NodeID>().swap(trafficLightNodes);
NodeID edgeBasedNodeNumber = edgeBasedGraphFactory->GetNumberOfNodes();
DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
edgeBasedGraphFactory->GetEdgeBasedEdges(edgeBasedEdgeList);
DeallocatingVector<EdgeBasedGraphFactory::EdgeBasedNode> nodeBasedEdgeList;
edgeBasedGraphFactory->GetEdgeBasedNodes(nodeBasedEdgeList);
delete edgeBasedGraphFactory;
/***
* Writing info on original (node-based) nodes
*/
INFO("writing node map ...");
std::ofstream mapOutFile(nodeOut.c_str(), std::ios::binary);
mapOutFile.write((char *)&(internalToExternalNodeMapping[0]), internalToExternalNodeMapping.size()*sizeof(NodeInfo));
mapOutFile.close();
std::vector<NodeInfo>().swap(internalToExternalNodeMapping);
double expansionHasFinishedTime = get_timestamp() - startupTime;
/***
* Building grid-like nearest-neighbor data structure
*/
INFO("building grid ...");
WritableGrid * writeableGrid = new WritableGrid();
writeableGrid->ConstructGrid(nodeBasedEdgeList, ramIndexOut.c_str(), fileIndexOut.c_str());
delete writeableGrid;
IteratorbasedCRC32<DeallocatingVector<EdgeBasedGraphFactory::EdgeBasedNode> > crc32;
unsigned crc32OfNodeBasedEdgeList = crc32(nodeBasedEdgeList.begin(), nodeBasedEdgeList.end() );
nodeBasedEdgeList.clear();
INFO("CRC32 based checksum is " << crc32OfNodeBasedEdgeList);
/***
* Contracting the edge-expanded graph
*/
INFO("initializing contractor");
Contractor* contractor = new Contractor( edgeBasedNodeNumber, edgeBasedEdgeList );
double contractionStartedTimestamp(get_timestamp());
contractor->Run();
INFO("Contraction took " << get_timestamp() - contractionStartedTimestamp << " sec");
DeallocatingVector< QueryEdge > contractedEdgeList;
contractor->GetEdges( contractedEdgeList );
delete contractor;
/***
* Sorting contracted edges in a way that the static query graph can read some in in-place.
*/
INFO("Building Node Array");
std::sort(contractedEdgeList.begin(), contractedEdgeList.end());
unsigned numberOfNodes = 0;
unsigned numberOfEdges = contractedEdgeList.size();
INFO("Serializing compacted graph");
std::ofstream edgeOutFile(graphOut.c_str(), std::ios::binary);
BOOST_FOREACH(const QueryEdge & edge, contractedEdgeList) {
if(edge.source > numberOfNodes) {
numberOfNodes = edge.source;
} }
if(edge.target > numberOfNodes) {
numberOfNodes = edge.target; double startupTime = get_timestamp();
unsigned numberOfThreads = omp_get_num_procs();
if(testDataFile("contractor.ini")) {
ContractorConfiguration contractorConfig("contractor.ini");
unsigned rawNumber = stringToInt(contractorConfig.GetParameter("Threads"));
if(rawNumber != 0 && rawNumber <= numberOfThreads)
numberOfThreads = rawNumber;
} }
} omp_set_num_threads(numberOfThreads);
numberOfNodes+=1;
std::vector< StaticGraph<EdgeData>::_StrNode > _nodes; INFO("Using restrictions from file: " << argv[2]);
_nodes.resize( numberOfNodes + 1 ); std::ifstream restrictionsInstream(argv[2], std::ios::binary);
if(!restrictionsInstream.good()) {
ERR("Could not access <osrm-restrictions> files");
}
_Restriction restriction;
unsigned usableRestrictionsCounter(0);
restrictionsInstream.read((char*)&usableRestrictionsCounter, sizeof(unsigned));
inputRestrictions.resize(usableRestrictionsCounter);
restrictionsInstream.read((char *)&(inputRestrictions[0]), usableRestrictionsCounter*sizeof(_Restriction));
restrictionsInstream.close();
StaticGraph<EdgeData>::EdgeIterator edge = 0; std::ifstream in;
StaticGraph<EdgeData>::EdgeIterator position = 0; in.open (argv[1], std::ifstream::in | std::ifstream::binary);
for ( StaticGraph<EdgeData>::NodeIterator node = 0; node <= numberOfNodes; ++node ) { if (!in.is_open()) {
StaticGraph<EdgeData>::EdgeIterator lastEdge = edge; ERR("Cannot open " << argv[1]);
while ( edge < numberOfEdges && contractedEdgeList[edge].source == node ) }
++edge;
_nodes[node].firstEdge = position; //=edge std::string nodeOut(argv[1]); nodeOut += ".nodes";
position += edge - lastEdge; //remove std::string edgeOut(argv[1]); edgeOut += ".edges";
} std::string graphOut(argv[1]); graphOut += ".hsgr";
++numberOfNodes; std::string rtree_nodes_path(argv[1]); rtree_nodes_path += ".ramIndex";
//Serialize numberOfNodes, nodes std::string rtree_leafs_path(argv[1]); rtree_leafs_path += ".fileIndex";
edgeOutFile.write((char*) &crc32OfNodeBasedEdgeList, sizeof(unsigned));
edgeOutFile.write((char*) &numberOfNodes, sizeof(unsigned)); /*** Setup Scripting Environment ***/
edgeOutFile.write((char*) &_nodes[0], sizeof(StaticGraph<EdgeData>::_StrNode)*(numberOfNodes)); if(!testDataFile( (argc > 3 ? argv[3] : "profile.lua") )) {
//Serialize number of Edges ERR("Need profile.lua to apply traffic signal penalty");
edgeOutFile.write((char*) &position, sizeof(unsigned)); }
--numberOfNodes;
edge = 0; // Create a new lua state
int usedEdgeCounter = 0; lua_State *myLuaState = luaL_newstate();
StaticGraph<EdgeData>::_StrEdge currentEdge;
for ( StaticGraph<EdgeData>::NodeIterator node = 0; node < numberOfNodes; ++node ) { // Connect LuaBind to this lua state
for ( StaticGraph<EdgeData>::EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) { luabind::open(myLuaState);
assert(node != contractedEdgeList[edge].target);
currentEdge.target = contractedEdgeList[edge].target; //open utility libraries string library;
currentEdge.data = contractedEdgeList[edge].data; luaL_openlibs(myLuaState);
if(currentEdge.data.distance <= 0) {
INFO("Edge: " << i << ",source: " << contractedEdgeList[edge].source << ", target: " << contractedEdgeList[edge].target << ", dist: " << currentEdge.data.distance); //adjust lua load path
ERR("Failed at edges of node " << node << " of " << numberOfNodes); 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") );
if(0 != luaL_dofile(myLuaState, (argc > 3 ? argv[3] : "profile.lua") )) {
ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
}
EdgeBasedGraphFactory::SpeedProfileProperties speedProfile;
if(0 != luaL_dostring( myLuaState, "return traffic_signal_penalty\n")) {
ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
}
speedProfile.trafficSignalPenalty = 10*lua_tointeger(myLuaState, -1);
if(0 != luaL_dostring( myLuaState, "return u_turn_penalty\n")) {
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<ImportEdge> edgeList;
NodeID nodeBasedNodeNumber = readBinaryOSRMGraphFromStream(in, edgeList, bollardNodes, trafficLightNodes, &internalToExternalNodeMapping, inputRestrictions);
in.close();
INFO(inputRestrictions.size() << " restrictions, " << bollardNodes.size() << " bollard nodes, " << trafficLightNodes.size() << " traffic lights");
if(0 == edgeList.size())
ERR("The input data is broken. It is impossible to do any turns in this graph");
/***
* Building an edge-expanded graph from node-based input an turn restrictions
*/
INFO("Generating edge-expanded graph representation");
EdgeBasedGraphFactory * edgeBasedGraphFactory = new EdgeBasedGraphFactory (nodeBasedNodeNumber, edgeList, bollardNodes, trafficLightNodes, inputRestrictions, internalToExternalNodeMapping, speedProfile);
std::vector<ImportEdge>().swap(edgeList);
edgeBasedGraphFactory->Run(edgeOut.c_str(), myLuaState);
std::vector<_Restriction>().swap(inputRestrictions);
std::vector<NodeID>().swap(bollardNodes);
std::vector<NodeID>().swap(trafficLightNodes);
NodeID edgeBasedNodeNumber = edgeBasedGraphFactory->GetNumberOfNodes();
DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
edgeBasedGraphFactory->GetEdgeBasedEdges(edgeBasedEdgeList);
std::vector<EdgeBasedGraphFactory::EdgeBasedNode> nodeBasedEdgeList;
edgeBasedGraphFactory->GetEdgeBasedNodes(nodeBasedEdgeList);
delete edgeBasedGraphFactory;
/***
* Writing info on original (node-based) nodes
*/
INFO("writing node map ...");
std::ofstream mapOutFile(nodeOut.c_str(), std::ios::binary);
mapOutFile.write((char *)&(internalToExternalNodeMapping[0]), internalToExternalNodeMapping.size()*sizeof(NodeInfo));
mapOutFile.close();
std::vector<NodeInfo>().swap(internalToExternalNodeMapping);
double expansionHasFinishedTime = get_timestamp() - startupTime;
/***
* Building grid-like nearest-neighbor data structure
*/
INFO("building r-tree ...");
StaticRTree<EdgeBasedGraphFactory::EdgeBasedNode> * rtree =
new StaticRTree<EdgeBasedGraphFactory::EdgeBasedNode>(
nodeBasedEdgeList,
rtree_nodes_path.c_str(),
rtree_leafs_path.c_str()
);
delete rtree;
IteratorbasedCRC32<std::vector<EdgeBasedGraphFactory::EdgeBasedNode> > crc32;
unsigned crc32OfNodeBasedEdgeList = crc32(nodeBasedEdgeList.begin(), nodeBasedEdgeList.end() );
nodeBasedEdgeList.clear();
INFO("CRC32 based checksum is " << crc32OfNodeBasedEdgeList);
/***
* Contracting the edge-expanded graph
*/
INFO("initializing contractor");
Contractor* contractor = new Contractor( edgeBasedNodeNumber, edgeBasedEdgeList );
double contractionStartedTimestamp(get_timestamp());
contractor->Run();
INFO("Contraction took " << get_timestamp() - contractionStartedTimestamp << " sec");
DeallocatingVector< QueryEdge > contractedEdgeList;
contractor->GetEdges( contractedEdgeList );
delete contractor;
/***
* Sorting contracted edges in a way that the static query graph can read some in in-place.
*/
INFO("Building Node Array");
std::sort(contractedEdgeList.begin(), contractedEdgeList.end());
unsigned numberOfNodes = 0;
unsigned numberOfEdges = contractedEdgeList.size();
INFO("Serializing compacted graph of " << numberOfEdges << " edges");
std::ofstream edgeOutFile(graphOut.c_str(), std::ios::binary);
BOOST_FOREACH(const QueryEdge & edge, contractedEdgeList) {
if(edge.source > numberOfNodes) {
numberOfNodes = edge.source;
}
if(edge.target > numberOfNodes) {
numberOfNodes = edge.target;
} }
//Serialize edges
edgeOutFile.write((char*) &currentEdge, sizeof(StaticGraph<EdgeData>::_StrEdge));
++edge;
++usedEdgeCounter;
} }
} numberOfNodes+=1;
double endTime = (get_timestamp() - startupTime);
INFO("Expansion : " << (nodeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< (edgeBasedNodeNumber/expansionHasFinishedTime) << " edges/sec");
INFO("Contraction: " << (edgeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< usedEdgeCounter/endTime << " edges/sec");
edgeOutFile.close(); std::vector< StaticGraph<EdgeData>::_StrNode > _nodes;
//cleanedEdgeList.clear(); _nodes.resize( numberOfNodes + 1 );
_nodes.clear();
INFO("finished preprocessing"); StaticGraph<EdgeData>::EdgeIterator edge = 0;
StaticGraph<EdgeData>::EdgeIterator position = 0;
for ( StaticGraph<EdgeData>::NodeIterator node = 0; node <= numberOfNodes; ++node ) {
StaticGraph<EdgeData>::EdgeIterator lastEdge = edge;
while ( edge < numberOfEdges && contractedEdgeList[edge].source == node )
++edge;
_nodes[node].firstEdge = position; //=edge
position += edge - lastEdge; //remove
}
++numberOfNodes;
//Serialize numberOfNodes, nodes
edgeOutFile.write((char*) &crc32OfNodeBasedEdgeList, sizeof(unsigned));
edgeOutFile.write((char*) &numberOfNodes, sizeof(unsigned));
edgeOutFile.write((char*) &_nodes[0], sizeof(StaticGraph<EdgeData>::_StrNode)*(numberOfNodes));
//Serialize number of Edges
edgeOutFile.write((char*) &position, sizeof(unsigned));
--numberOfNodes;
edge = 0;
int usedEdgeCounter = 0;
StaticGraph<EdgeData>::_StrEdge currentEdge;
for ( StaticGraph<EdgeData>::NodeIterator node = 0; node < numberOfNodes; ++node ) {
for ( StaticGraph<EdgeData>::EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) {
assert(node != contractedEdgeList[edge].target);
currentEdge.target = contractedEdgeList[edge].target;
currentEdge.data = contractedEdgeList[edge].data;
if(currentEdge.data.distance <= 0) {
INFO("Edge: " << i << ",source: " << contractedEdgeList[edge].source << ", target: " << contractedEdgeList[edge].target << ", dist: " << currentEdge.data.distance);
ERR("Failed at edges of node " << node << " of " << numberOfNodes);
}
//Serialize edges
edgeOutFile.write((char*) &currentEdge, sizeof(StaticGraph<EdgeData>::_StrEdge));
++edge;
++usedEdgeCounter;
}
}
double endTime = (get_timestamp() - startupTime);
INFO("Expansion : " << (nodeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< (edgeBasedNodeNumber/expansionHasFinishedTime) << " edges/sec");
INFO("Contraction: " << (edgeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< usedEdgeCounter/endTime << " edges/sec");
edgeOutFile.close();
//cleanedEdgeList.clear();
_nodes.clear();
INFO("finished preprocessing");
} catch (std::exception &e) {
ERR("Exception occured: " << e.what());
}
return 0; return 0;
} }

View File

@ -18,12 +18,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
or see http://www.gnu.org/licenses/agpl.txt. or see http://www.gnu.org/licenses/agpl.txt.
*/ */
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include "typedefs.h"
#include "Extractor/ExtractorCallbacks.h" #include "Extractor/ExtractorCallbacks.h"
#include "Extractor/ExtractionContainers.h" #include "Extractor/ExtractionContainers.h"
#include "Extractor/ScriptingEnvironment.h" #include "Extractor/ScriptingEnvironment.h"
@ -34,6 +28,13 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "Util/MachineInfo.h" #include "Util/MachineInfo.h"
#include "Util/OpenMPWrapper.h" #include "Util/OpenMPWrapper.h"
#include "Util/StringUtil.h" #include "Util/StringUtil.h"
#include "typedefs.h"
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
typedef BaseConfiguration ExtractorConfiguration; typedef BaseConfiguration ExtractorConfiguration;
@ -84,11 +85,11 @@ int main (int argc, char *argv[]) {
} }
unsigned amountOfRAM = 1; unsigned amountOfRAM = 1;
unsigned installedRAM = GetPhysicalmemory(); unsigned installedRAM = GetPhysicalmemory();
if(installedRAM < 2048264) { if(installedRAM < 2048264) {
WARN("Machine has less than 2GB RAM."); WARN("Machine has less than 2GB RAM.");
} }
StringMap stringMap; StringMap stringMap;
ExtractionContainers externalMemory; ExtractionContainers externalMemory;
@ -100,7 +101,7 @@ int main (int argc, char *argv[]) {
} else { } else {
parser = new XMLParser(argv[1], extractCallBacks, scriptingEnvironment); parser = new XMLParser(argv[1], extractCallBacks, scriptingEnvironment);
} }
if(!parser->ReadHeader()) { if(!parser->ReadHeader()) {
ERR("Parser not initialized!"); ERR("Parser not initialized!");
} }

View File

@ -41,14 +41,14 @@ Feature: Bike - Squares and other areas
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | b | | | a | b | xa |
| a | d | | | a | d | xa |
| b | c | | | b | c | xa |
| c | b | | | c | b | xa |
| c | d | | | c | d | xa |
| d | c | | | d | c | xa |
| d | a | | | d | a | xa |
| a | d | | | a | d | xa |
@parking @parking
Scenario: Bike - parking areas Scenario: Bike - parking areas
@ -100,4 +100,4 @@ Feature: Bike - Squares and other areas
| c | d | abcda | | c | d | abcda |
| d | c | abcda | | d | c | abcda |
| d | a | abcda | | d | a | abcda |
| a | d | abcda | | a | d | abcda |

View File

@ -0,0 +1,89 @@
@routing @bicycle @mode
Feature: Bike - Mode flag
Background:
Given the profile "bicycle"
@todo
Scenario: Bike - Mode when using a ferry
Given the node map
| a | b | |
| | c | d |
And the ways
| nodes | highway | route | duration |
| ab | primary | | |
| bc | | ferry | 0:01 |
| cd | primary | | |
When I route I should get
| from | to | route | turns | modes |
| a | d | ab,bc,cd | head,right,left, destination | bike,ferry,bike |
| d | a | cd,bc,ab | head,right,left, destination | bike,ferry,bike |
| c | a | bc,ab | head,left,destination | ferry,bike |
| d | b | cd,bc | head,right,destination | bike,ferry |
| a | c | ab,bc | head,right,destination | bike,ferry |
| b | d | bc,cd | head,left,destination | ferry,bike |
@todo
Scenario: Bike - Mode when pushing bike against oneways
Given the node map
| a | b | |
| | c | d |
And the ways
| nodes | highway | oneway |
| ab | primary | |
| bc | primary | yes |
| cd | primary | |
When I route I should get
| from | to | route | turns | modes |
| a | d | ab,bc,cd | head,right,left,destination | bike,push,bike |
| d | a | cd,bc,ab | head,right,left,destination | bike,push,bike |
| c | a | bc,ab | head,left,destination | push,bike |
| d | b | cd,bc | head,right,destination | bike,push |
| a | c | ab,bc | head,right,destination | bike,push |
| b | d | bc,cd | head,left,destination | push,bike |
@todo
Scenario: Bike - Mode when pushing on pedestrain streets
Given the node map
| a | b | |
| | c | d |
And the ways
| nodes | highway |
| ab | primary |
| bc | pedestrian |
| cd | primary |
When I route I should get
| from | to | route | turns | modes |
| a | d | ab,bc,cd | head,right,left,destination | bike,push,bike |
| d | a | cd,bc,ab | head,right,left,destination | bike,push,bike |
| c | a | bc,ab | head,left,destination | push,bike |
| d | b | cd,bc | head,right,destination | bike,push |
| a | c | ab,bc | head,right,destination | bike,push |
| b | d | bc,cd | head,left,destination | push,bike |
@todo
Scenario: Bike - Mode when pushing on pedestrain areas
Given the node map
| a | b | | |
| | c | d | f |
And the ways
| nodes | highway | area |
| ab | primary | |
| bcd | pedestrian | yes |
| df | primary | |
When I route I should get
| from | to | route | modes |
| a | f | ab,bcd,df | bike,push,bike |
| f | a | df,bcd,ab | bike,push,bike |
| d | a | bcd,ab | push,bike |
| f | b | df,bcd | bike,push |
| a | d | ab,bcd | bike,push |
| b | f | bcd,df | push,bike |

View File

@ -10,14 +10,15 @@ Feature: Bike - Street names in instructions
| | c | | | c |
And the ways And the ways
| nodes | name | | nodes | name |
| ab | My Way | | ab | My Way |
| bc | Your Way | | bc | Your Way |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | c | My Way,Your Way | | a | c | My Way,Your Way |
@unnamed
Scenario: Bike - Use way type to describe unnamed ways Scenario: Bike - Use way type to describe unnamed ways
Given the node map Given the node map
| a | b | c | d | | a | b | c | d |
@ -25,8 +26,24 @@ Feature: Bike - Street names in instructions
And the ways And the ways
| nodes | highway | name | | nodes | highway | name |
| ab | cycleway | | | ab | cycleway | |
| bcd | track | | | bcd | track | |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | d | cycleway,track | | a | d | {highway:cycleway},{highway:track} |
@area @names @todo
Scenario: Bike - name on streets overlapping an area
Given the node map
| x | a | b | y |
| | d | c | |
And the ways
| nodes | highway | area |
| xaby | residential | |
| abcda | residential | yes |
When I route I should get
| from | to | route |
| x | y | xaby |
| y | x | xaby |

View File

@ -112,3 +112,17 @@ Usually we can push bikes against oneways, but we use foot=no to prevent this in
| no | roundabout | | yes | x | | | no | roundabout | | yes | x | |
| no | roundabout | | no | x | | | no | roundabout | | no | x | |
| no | roundabout | | -1 | x | | | no | roundabout | | -1 | x | |
Scenario: Bike - Two consecutive oneways
Given the node map
| a | b | c |
And the ways
| nodes | oneway |
| ab | yes |
| bc | yes |
When I route I should get
| from | to | route |
| a | c | ab,bc |

View File

@ -85,3 +85,40 @@ Feature: Bike - Accessability of different way types
Then routability should be Then routability should be
| junction | forw | backw | | junction | forw | backw |
| roundabout | x | | | roundabout | x | |
Scenario: Bike - Instructions when pushing bike on oneways
Given the node map
| a | b | |
| | c | d |
And the ways
| nodes | highway | oneway |
| ab | primary | |
| bc | primary | yes |
| cd | primary | |
When I route I should get
| from | to | route | turns |
| a | d | ab,bc,cd | head,right,left,destination |
| d | a | cd,bc,ab | head,enter_contraflow,leave_contraflow,destination |
| c | a | bc,ab | head,leave_contraflow,destination |
| d | b | cd,bc | head,enter_contraflow,destination |
@todo
Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc.
Given the node map
| a | b | |
| | c | d |
And the ways
| nodes | highway |
| ab | primary |
| bc | footway |
| cd | primary |
When I route I should get
| from | to | route | turns |
| a | d | ab,bc,cd | head,right,left,destination |
| d | a | cd,bc,ab | head,enter_contraflow,leave_contraflow,destination |
| c | a | bc,ab | head,leave_contraflow,destination |
| d | b | cd,bc | head,enter_contraflow,destination |

View File

@ -0,0 +1,41 @@
@routing @bicycle @ref @name
Feature: Bike - Way ref
Background:
Given the profile "bicycle"
Scenario: Bike - Way with both name and ref
Given the node map
| a | b |
And the ways
| nodes | name | ref |
| ab | Utopia Drive | E7 |
When I route I should get
| from | to | route |
| a | b | Utopia Drive / E7 |
Scenario: Bike - Way with only ref
Given the node map
| a | b |
And the ways
| nodes | name | ref |
| ab | | E7 |
When I route I should get
| from | to | route |
| a | b | E7 |
Scenario: Bike - Way with only name
Given the node map
| a | b |
And the ways
| nodes | name |
| ab | Utopia Drive |
When I route I should get
| from | to | route |
| a | b | Utopia Drive |

View File

@ -31,7 +31,7 @@ Feature: Car - Max speed restrictions
When I route I should get When I route I should get
| from | to | route | time | | from | to | route | time |
| a | b | ab | 144s ~10% | | a | b | ab | 144s ~10% |
| b | c | bc | 63s ~10% | | b | c | bc | 42s ~10% |
Scenario: Car - Forward/backward maxspeed Scenario: Car - Forward/backward maxspeed
Given the shortcuts Given the shortcuts

View File

@ -56,4 +56,18 @@ Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tag
| primary | | -1 | -1 | | x | | primary | | -1 | -1 | | x |
| primary | roundabout | | yes | x | | | primary | roundabout | | yes | x | |
| primary | roundabout | | no | x | | | primary | roundabout | | no | x | |
| primary | roundabout | | -1 | x | | | primary | roundabout | | -1 | x | |
Scenario: Car - Two consecutive oneways
Given the node map
| a | b | c |
And the ways
| nodes | oneway |
| ab | yes |
| bc | yes |
When I route I should get
| from | to | route |
| a | c | ab,bc |

View File

@ -3,23 +3,24 @@ Feature: Car - Handle ferryshuttle train routes
Background: Background:
Given the profile "car" Given the profile "car"
Scenario: Car - Use a ferry route Scenario: Car - Use a ferry route
Given the node map Given the node map
| a | b | c | | | | a | b | c | | | |
| | | d | | | | | | d | | | |
| | | e | f | g | | | | e | f | g | h |
And the ways And the ways
| nodes | highway | route | bicycle | | nodes | highway | route | bicycle |
| abc | primary | | | | abc | primary | | |
| cde | | shuttle_train | yes | | cde | | shuttle_train | yes |
| ef | primary | | | | ef | primary | | |
| fg | | ferry_man | | | fg | | ferry_man | |
| gh | primary | | no |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | g | abc,cde,ef | | a | f | abc,cde,ef |
| b | f | abc,cde,ef | | b | f | abc,cde,ef |
| e | c | cde | | e | c | cde |
| e | b | cde,abc | | e | b | cde,abc |
@ -27,5 +28,6 @@ Feature: Car - Handle ferryshuttle train routes
| c | e | cde | | c | e | cde |
| c | f | cde,ef | | c | f | cde,ef |
| f | g | | | f | g | |
| g | h | gh |

View File

@ -18,12 +18,13 @@ Given /^the node map$/ do |table|
unless name.empty? unless name.empty?
raise "*** node invalid name '#{name}', must be single characters" unless name.size == 1 raise "*** node invalid name '#{name}', must be single characters" unless name.size == 1
raise "*** invalid node name '#{name}', must me alphanumeric" unless name.match /[a-z0-9]/ raise "*** invalid node name '#{name}', must me alphanumeric" unless name.match /[a-z0-9]/
raise "*** duplicate node '#{name}'" if name_node_hash[name] if name.match /[a-z]/
node = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+ci*@zoom, ORIGIN[1]-ri*@zoom raise "*** duplicate node '#{name}'" if name_node_hash[name]
node << { :name => name } add_osm_node name, *table_coord_to_lonlat(ci,ri)
node.uid = OSM_UID else
osm_db << node raise "*** duplicate node '#{name}'" if location_hash[name]
name_node_hash[name] = node add_location name, *table_coord_to_lonlat(ci,ri)
end
end end
end end
end end
@ -32,21 +33,18 @@ end
Given /^the node locations$/ do |table| Given /^the node locations$/ do |table|
table.hashes.each do |row| table.hashes.each do |row|
name = row['node'] name = row['node']
raise "*** node invalid name '#{name}', must be single characters" unless name.size == 1 raise "*** duplicate node '#{name}'" if find_node_by_name name
raise "*** invalid node name '#{name}', must me alphanumeric" unless name.match /[a-z0-9]/ if name.match /[a-z]/
raise "*** duplicate node '#{name}'" if name_node_hash[name] add_osm_node name, row['lon'].to_f, row['lat'].to_f
node = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, row['lon'].to_f, row['lat'].to_f else
node << { :name => name } add_location name, row['lon'].to_f, row['lat'].to_f
node.uid = OSM_UID end
osm_db << node
name_node_hash[name] = node
end end
end end
Given /^the nodes$/ do |table| Given /^the nodes$/ do |table|
table.hashes.each do |row| table.hashes.each do |row|
name = row.delete 'node' name = row.delete 'node'
raise "***invalid node name '#{c}', must be single characters" unless name.size == 1
node = find_node_by_name(name) node = find_node_by_name(name)
raise "*** unknown node '#{c}'" unless node raise "*** unknown node '#{c}'" unless node
node << row node << row
@ -61,8 +59,7 @@ Given /^the ways$/ do |table|
nodes = row.delete 'nodes' nodes = row.delete 'nodes'
raise "*** duplicate way '#{nodes}'" if name_way_hash[nodes] raise "*** duplicate way '#{nodes}'" if name_way_hash[nodes]
nodes.each_char do |c| nodes.each_char do |c|
raise "***invalid node name '#{c}', must be single characters" unless c.size == 1 raise "*** ways can only use names a-z, '#{name}'" unless c.match /[a-z]/
raise "*** ways cannot use numbered nodes, '#{name}'" unless c.match /[a-z]/
node = find_node_by_name(c) node = find_node_by_name(c)
raise "*** unknown node '#{c}'" unless node raise "*** unknown node '#{c}'" unless node
way << node way << node

View File

@ -3,10 +3,10 @@ When /^I request nearest I should get$/ do |table|
actual = [] actual = []
OSRMLauncher.new do OSRMLauncher.new do
table.hashes.each_with_index do |row,ri| table.hashes.each_with_index do |row,ri|
in_node = @name_node_hash[ row['in'] ] in_node = find_node_by_name row['in']
raise "*** unknown in-node '#{row['in']}" unless in_node raise "*** unknown in-node '#{row['in']}" unless in_node
out_node = @name_node_hash[ row['out'] ] out_node = find_node_by_name row['out']
raise "*** unknown out-node '#{row['out']}" unless out_node raise "*** unknown out-node '#{row['out']}" unless out_node
response = request_nearest("#{in_node.lat},#{in_node.lon}") response = request_nearest("#{in_node.lat},#{in_node.lon}")
@ -42,10 +42,10 @@ When /^I request nearest I should get$/ do |table|
table.routing_diff! actual table.routing_diff! actual
end end
When /^I route (\d+) times I should get$/ do |n,table| When /^I request nearest (\d+) times I should get$/ do |n,table|
ok = true ok = true
n.to_i.times do n.to_i.times do
ok = false unless step "I route I should get", table ok = false unless step "I request nearest I should get", table
end end
ok ok
end end

View File

@ -12,9 +12,13 @@ Then /^routability should be$/ do |table|
['forw','backw','bothw'].each do |direction| ['forw','backw','bothw'].each do |direction|
if table.headers.include? direction if table.headers.include? direction
if direction == 'forw' || direction == 'bothw' if direction == 'forw' || direction == 'bothw'
response = request_route("#{ORIGIN[1]},#{ORIGIN[0]+(1+WAY_SPACING*i)*@zoom}","#{ORIGIN[1]},#{ORIGIN[0]+(3+WAY_SPACING*i)*@zoom}") a = Location.new ORIGIN[0]+(1+WAY_SPACING*i)*@zoom, ORIGIN[1]
b = Location.new ORIGIN[0]+(3+WAY_SPACING*i)*@zoom, ORIGIN[1]
response = request_route [a,b]
elsif direction == 'backw' || direction == 'bothw' 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}") a = Location.new ORIGIN[0]+(3+WAY_SPACING*i)*@zoom, ORIGIN[1]
b = Location.new ORIGIN[0]+(1+WAY_SPACING*i)*@zoom, ORIGIN[1]
response = request_route [a,b]
end end
want = shortcuts_hash[row[direction]] || row[direction] #expand shortcuts want = shortcuts_hash[row[direction]] || row[direction] #expand shortcuts
got[direction] = route_status response got[direction] = route_status response
@ -22,7 +26,11 @@ Then /^routability should be$/ do |table|
if got[direction].empty? == false if got[direction].empty? == false
route = way_list json['route_instructions'] route = way_list json['route_instructions']
if route != "w#{i}" if route != "w#{i}"
got[direction] = "testing w#{i}, but got #{route}!?" if row[direction].empty? == true
got[direction] = want
else
got[direction] = "testing w#{i}, but got #{route}!?"
end
elsif want =~ /^\d+s/ elsif want =~ /^\d+s/
time = json['route_summary']['total_time'] time = json['route_summary']['total_time']
got[direction] = "#{time}s" got[direction] = "#{time}s"

View File

@ -3,11 +3,41 @@ When /^I route I should get$/ do |table|
actual = [] actual = []
OSRMLauncher.new do OSRMLauncher.new do
table.hashes.each_with_index do |row,ri| table.hashes.each_with_index do |row,ri|
from_node = @name_node_hash[ row['from'] ] waypoints = []
raise "*** unknown from-node '#{row['from']}" unless from_node if row['from'] and row['to']
to_node = @name_node_hash[ row['to'] ] node = find_node_by_name(row['from'])
raise "*** unknown to-node '#{row['to']}" unless to_node raise "*** unknown from-node '#{row['from']}" unless node
response = request_route("#{from_node.lat},#{from_node.lon}", "#{to_node.lat},#{to_node.lon}") waypoints << node
node = find_node_by_name(row['to'])
raise "*** unknown to-node '#{row['to']}" unless node
waypoints << node
got = {'from' => row['from'], 'to' => row['to'] }
elsif row['waypoints']
row['waypoints'].split(',').each do |n|
node = find_node_by_name(n.strip)
raise "*** unknown waypoint node '#{n.strip}" unless node
waypoints << node
end
got = {'waypoints' => row['waypoints'] }
else
raise "*** no waypoints"
end
params = {}
row.each_pair do |k,v|
if k =~ /param:(.*)/
if v=='(nil)'
params[$1]=nil
elsif v!=nil
params[$1]=v
end
got[k]=v
end
end
response = request_route(waypoints, params)
if response.code == "200" && response.body.empty? == false if response.code == "200" && response.body.empty? == false
json = JSON.parse response.body json = JSON.parse response.body
if json['status'] == 0 if json['status'] == 0
@ -15,10 +45,10 @@ When /^I route I should get$/ do |table|
bearings = bearing_list json['route_instructions'] bearings = bearing_list json['route_instructions']
compasses = compass_list json['route_instructions'] compasses = compass_list json['route_instructions']
turns = turn_list json['route_instructions'] turns = turn_list json['route_instructions']
modes = mode_list json['route_instructions']
end end
end end
got = {'from' => row['from'], 'to' => row['to'] }
if table.headers.include? 'start' if table.headers.include? 'start'
got['start'] = instructions ? json['route_summary']['start_point'] : nil got['start'] = instructions ? json['route_summary']['start_point'] : nil
end end
@ -46,6 +76,9 @@ When /^I route I should get$/ do |table|
if table.headers.include? 'turns' if table.headers.include? 'turns'
got['turns'] = turns got['turns'] = turns
end end
if table.headers.include? 'modes'
got['modes'] = modes
end
if table.headers.include? '#' # comment column if table.headers.include? '#' # comment column
got['#'] = row['#'] # copy value so it always match got['#'] = row['#'] # copy value so it always match
end end

View File

@ -14,9 +14,19 @@ DEFAULT_SPEEDPROFILE = 'bicycle'
WAY_SPACING = 100 WAY_SPACING = 100
DEFAULT_GRID_SIZE = 100 #meters DEFAULT_GRID_SIZE = 100 #meters
PROFILES_PATH = '../profiles' PROFILES_PATH = '../profiles'
BIN_PATH = '../build'
ORIGIN = [1,1] ORIGIN = [1,1]
class Location
attr_accessor :lon,:lat
def initialize lon,lat
@lat = lat
@lon = lon
end
end
def sanitized_scenario_title def sanitized_scenario_title
@sanitized_scenario_title ||= @scenario_title.gsub /[^0-9A-Za-z.\-]/, '_' @sanitized_scenario_title ||= @scenario_title.gsub /[^0-9A-Za-z.\-]/, '_'
end end
@ -32,10 +42,10 @@ def build_ways_from_table table
#add one unconnected way for each row #add one unconnected way for each row
table.hashes.each_with_index do |row,ri| table.hashes.each_with_index do |row,ri|
#NOTE: #NOTE:
#currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4 #currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4 edges
#this is relatated to the fact that a oneway deadend doesn't make a lot of sense #this is relatated to the fact that a oneway dead-end street doesn't make a lot of sense
#if we stack ways on different x coordinates, outability tests get messed up, because osrm might pick a neighboring way if the one test can't be used. #if we stack ways on different x coordinates, routability tests get messed up, because osrm might pick a neighboring way if the one test can't be used.
#instead we place all lines as a string on the same y coordinate. this prevents using neightboring ways. #instead we place all lines as a string on the same y coordinate. this prevents using neightboring ways.
#a few nodes... #a few nodes...
@ -110,8 +120,30 @@ def build_ways_from_table table
end end
end end
def table_coord_to_lonlat ci,ri
[ORIGIN[0]+ci*@zoom, ORIGIN[1]-ri*@zoom]
end
def add_osm_node name,lon,lat
node = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, lon, lat
node << { :name => name }
node.uid = OSM_UID
osm_db << node
name_node_hash[name] = node
end
def add_location name,lon,lat
location_hash[name] = Location.new(lon,lat)
end
def find_node_by_name s def find_node_by_name s
name_node_hash[s.to_s] raise "***invalid node name '#{s}', must be single characters" unless s.size == 1
raise "*** invalid node name '#{s}', must be alphanumeric" unless s.match /[a-z0-9]/
if s.match /[a-z]/
from_node = name_node_hash[ s.to_s ]
else
from_node = location_hash[ s.to_s ]
end
end end
def find_way_by_name s def find_way_by_name s
@ -135,6 +167,7 @@ end
def reset_osm def reset_osm
osm_db.clear osm_db.clear
name_node_hash.clear name_node_hash.clear
location_hash.clear
name_way_hash.clear name_way_hash.clear
@osm_str = nil @osm_str = nil
@osm_hash = nil @osm_hash = nil
@ -157,6 +190,10 @@ def name_node_hash
@name_node_hash ||= {} @name_node_hash ||= {}
end end
def location_hash
@location_hash ||= {}
end
def name_way_hash def name_way_hash
@name_way_hash ||= {} @name_way_hash ||= {}
end end
@ -213,7 +250,7 @@ def reprocess
unless extracted? unless extracted?
log_preprocess_info log_preprocess_info
log "== Extracting #{@osm_file}.osm...", :preprocess log "== Extracting #{@osm_file}.osm...", :preprocess
unless system "../osrm-extract #{@osm_file}.osm#{'.pbf' if use_pbf} 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE} #{PROFILES_PATH}/#{@profile}.lua" unless system "#{BIN_PATH}/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 log "*** Exited with code #{$?.exitstatus}.", :preprocess
raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}." raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}."
end end
@ -222,7 +259,7 @@ def reprocess
unless prepared? unless prepared?
log_preprocess_info log_preprocess_info
log "== Preparing #{@osm_file}.osm...", :preprocess 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_PATH}/#{@profile}.lua" unless system "#{BIN_PATH}/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 log "*** Exited with code #{$?.exitstatus}.", :preprocess
raise PrepareError.new $?.exitstatus, "osrm-prepare exited with code #{$?.exitstatus}." raise PrepareError.new $?.exitstatus, "osrm-prepare exited with code #{$?.exitstatus}."
end end

View File

@ -22,8 +22,8 @@ class FuzzyMatch
end end
def self.match_location got, want def self.match_location got, want
match( got[0], "#{want.lat} ~0.002%" ) && match( got[0], "#{want.lat} ~0.0025%" ) &&
match( got[1], "#{want.lon} ~0.002%" ) match( got[1], "#{want.lon} ~0.0025%" )
end end
end end

View File

@ -29,15 +29,15 @@ def lua_lib_hash
end end
def bin_extract_hash def bin_extract_hash
@@bin_extract_hash ||= hash_of_files '../osrm-extract' @@bin_extract_hash ||= hash_of_files "#{BIN_PATH}/osrm-extract"
end end
def bin_prepare_hash def bin_prepare_hash
@@bin_prepare_hash ||= hash_of_files '../osrm-prepare' @@bin_prepare_hash ||= hash_of_files "#{BIN_PATH}/osrm-prepare"
end end
def bin_routed_hash def bin_routed_hash
@@bin_routed_hash ||= hash_of_files '../osrm-routed' @@bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed"
end end
#combine state of data, profile and binaries into a hash that identifies the exact test scenario #combine state of data, profile and binaries into a hash that identifies the exact test scenario

View File

@ -48,7 +48,7 @@ class OSRMLauncher
def osrm_up def osrm_up
return if osrm_up? return if osrm_up?
@pid = Process.spawn(['../osrm-routed',''],:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE) @pid = Process.spawn(["#{BIN_PATH}/osrm-routed",''],:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
end end
def osrm_down def osrm_down

View File

@ -4,10 +4,19 @@ HOST = "http://localhost:#{OSRM_PORT}"
REQUEST_TIMEOUT = 1 REQUEST_TIMEOUT = 1
DESTINATION_REACHED = 15 #OSRM instruction code DESTINATION_REACHED = 15 #OSRM instruction code
class Hash
def to_param(namespace = nil)
collect do |key, value|
"#{key}=#{value}"
end.sort
end
end
def request_path path def request_path path, waypoints=[], options={}
@query = path locs = waypoints.compact.map { |w| "loc=#{w.lat},#{w.lon}" }
uri = URI.parse "#{HOST}/#{path}" params = (locs + options.to_param).join('&')
params = nil if params==""
uri = URI.parse ["#{HOST}/#{path}", params].compact.join('?')
Timeout.timeout(REQUEST_TIMEOUT) do Timeout.timeout(REQUEST_TIMEOUT) do
Net::HTTP.get_response uri Net::HTTP.get_response uri
end end
@ -17,8 +26,9 @@ rescue Timeout::Error
raise "*** osrm-routed did not respond." raise "*** osrm-routed did not respond."
end end
def request_route a,b def request_route waypoints, params={}
request_path "viaroute?loc=#{a}&loc=#{b}&output=json&instructions=true&alt=true" defaults = { 'output' => 'json', 'instructions' => true, 'alt' => false }
request_path "viaroute", waypoints, defaults.merge(params)
end end
def parse_response response def parse_response response
@ -108,9 +118,18 @@ def turn_list instructions
12 => :leave_roundabout, 12 => :leave_roundabout,
13 => :stay_roundabout, 13 => :stay_roundabout,
14 => :start_end_of_street, 14 => :start_end_of_street,
15 => :destination 15 => :destination,
16 => :enter_contraflow,
17 => :leave_contraflow
} }
instructions. instructions.
map { |r| types[r[0].to_i].to_s }. map { |r| types[r[0].to_i].to_s }.
join(',') join(',')
end end
def mode_list instructions
instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }.
map { |r| r[8] }.
map { |r| (r=="" || r==nil) ? '""' : r }.
join(',')
end

View File

@ -16,17 +16,17 @@ Feature: Handle bad data in a graceful manner
Scenario: Only dead-end oneways Scenario: Only dead-end oneways
Given the node map Given the node map
| a | b | c | | a | b | c | d | e |
Given the ways Given the ways
| nodes | oneway | | nodes | oneway |
| ab | yes | | abcde | yes |
| cb | yes |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | b | ab | | b | d | abcde |
@todo
Scenario: Start/end point at the same location Scenario: Start/end point at the same location
Given the node map Given the node map
| a | b | | a | b |
@ -58,27 +58,29 @@ Feature: Handle bad data in a graceful manner
| k | -78 | 0 | | k | -78 | 0 |
| l | -80 | 0 | | l | -80 | 0 |
| m | -82 | 0 | | m | -82 | 0 |
| n | -87 | 0 | # | n | -87 | 0 |
| o | -89 | 0 | # | o | -89 | 0 |
And the ways And the ways
| nodes | | nodes |
| ab | # | ab |
| bc | | bc |
| cd | | cd |
| de | | de |
| kl | | kl |
| lm | | lm |
| mn | # | mn |
| no | # | no |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | b | | # | a | b | cd |
| b | c | | # | b | c | cd |
| a | d | | # | a | d | cd |
| c | d | cd | # | c | d | cd |
| l | m | lm | | d | e | de |
| o | l | | # | k | l | kl |
| n | m | | # | l | m | lm |
| o | n | | # | o | l | lm |
# | n | m | lm |
# | o | n | lm |

View File

@ -0,0 +1,93 @@
@routing @bearing_param @todo
Feature: Bearing parameter
Background:
Given the profile "testbot"
And a grid size of 10 meters
Scenario: Testbot - Intial bearing in simple case
Given the node map
| a | |
| 0 | c |
| b | |
And the ways
| nodes |
| ac |
| bc |
When I route I should get
| from | to | param:bearing | route | bearing |
| 0 | c | 0 | bc | 45 |
| 0 | c | 45 | bc | 45 |
| 0 | c | 85 | bc | 45 |
| 0 | c | 95 | ac | 135 |
| 0 | c | 135 | ac | 135 |
| 0 | c | 180 | ac | 135 |
Scenario: Testbot - Initial bearing on split way
Given the node map
| d | | | | | 1 | | | | | c |
| a | | | | | 0 | | | | | b |
And the ways
| nodes | oneway |
| ab | yes |
| bc | yes |
| cd | yes |
| da | yes |
When I route I should get
| from | to | param:bearing | route | bearing |
| 0 | b | 10 | ab | 90 |
| 0 | b | 90 | ab | 90 |
| 0 | b | 170 | ab | 90 |
| 0 | b | 190 | cd,da,ab | 270 |
| 0 | b | 270 | cd,da,ab | 270 |
| 0 | b | 350 | cd,da,ab | 270 |
| 1 | d | 10 | cd | 90 |
| 1 | d | 90 | cd | 90 |
| 1 | d | 170 | cd | 90 |
| 1 | d | 190 | ab,bc,cd | 270 |
| 1 | d | 270 | ab,bc,cd | 270 |
| 1 | d | 350 | ab,bc,cd | 270 |
Scenario: Testbot - Initial bearing in all direction
Given the node map
| h | | | a | | | b |
| | | | | | | |
| | | p | i | j | | |
| g | | o | 0 | k | | c |
| | | n | m | l | | |
| | | | | | | |
| f | | | e | | | d |
And the ways
| nodes | oneway |
| ia | yes |
| jb | yes |
| kc | yes |
| ld | yes |
| me | yes |
| nf | yes |
| og | yes |
| ph | yes |
| ab | yes |
| bc | yes |
| cd | yes |
| de | yes |
| ef | yes |
| fg | yes |
| gh | yes |
| ha | yes |
When I route I should get
| from | to | param:bearing | route | bearing |
| 0 | a | 0 | ia | 0 |
| 0 | a | 45 | jb,bc,cd,de,ef,fg,gh,ha | 45 |
| 0 | a | 90 | kc,cd,de,ef,fg,gh,ha | 90 |
| 0 | a | 135 | ld,de,ef,fg,gh,ha | 135 |
| 0 | a | 180 | me,de,ef,fg,gh,ha | 180 |
| 0 | a | 225 | nf,ef,fg,gh,ha | 225 |
| 0 | a | 270 | og,gh,ha | 270 |
| 0 | a | 315 | pn,ha | 315 |

View File

@ -0,0 +1,23 @@
@routing @testbot @bug @todo
Feature: Testbot - Things that looks like bugs
Background:
Given the profile "testbot"
Scenario: Testbot - Triangle problem
Given the node map
| | | | d |
| a | b | c | |
| | | | e |
And the ways
| nodes | highway | oneway |
| abc | primary | |
| cd | primary | yes |
| ce | river | |
| de | primary | |
When I route I should get
| from | to | route |
| d | c | de,ce |
| e | d | de |

View File

@ -0,0 +1,38 @@
@routing @testbot @example
Feature: Testbot - Walkthrough
# A complete walk-through of how this data is processed can be found at:
# https://github.com/DennisOSRM/Project-OSRM/wiki/Processing-Flow
Background:
Given the profile "testbot"
Scenario: Testbot - Processing Flow
Given the node map
| | | | d |
| a | b | c | |
| | | | e |
And the ways
| nodes | highway | oneway |
| abc | primary | |
| cd | primary | yes |
| ce | river | |
| de | primary | |
When I route I should get
| from | to | route |
| a | b | abc |
| a | c | abc |
| a | d | abc,cd |
| a | e | abc,ce |
| b | a | abc |
| b | c | abc |
| b | d | abc,cd |
| b | e | abc,ce |
| d | a | de,ce,abc |
| d | b | de,ce,abc |
| d | e | de |
| e | a | ce,abc |
| e | b | ce,abc |
| e | c | ce |

View File

@ -0,0 +1,26 @@
@routing @testbot @mode
Feature: Testbot - Mode flag
Background:
Given the profile "testbot"
@todo
Scenario: Bike - Mode
Given the node map
| a | b | |
| | c | d |
And the ways
| nodes | highway | route | duration |
| ab | primary | | |
| bc | | ferry | 0:01 |
| cd | primary | | |
When I route I should get
| from | to | route | turns | modes |
| a | d | ab,bc,cd | head,right,left,destination | bot,ferry,bot |
| d | a | cd,bc,ab | head,right left,destination | bot,ferry,bot |
| c | a | bc,ab | head,left,destination | ferry,bot |
| d | b | cd,bc | head,right,destination | bot,ferry |
| a | c | ab,bc | head,right,destination | bot,ferry |
| b | d | bc,cd | head,left,destination | ferry,bot |

View File

@ -4,7 +4,7 @@ Testbot uses a signal penalty of 7s.
Background: Background:
Given the profile "testbot" Given the profile "testbot"
Scenario: Traffic signals should incur a delay, without changing distance Scenario: Traffic signals should incur a delay, without changing distance
Given the node map Given the node map
| a | b | c | | a | b | c |
@ -44,11 +44,8 @@ Testbot uses a signal penalty of 7s.
When I route I should get When I route I should get
| from | to | route | time | | from | to | route | time |
| a | b | abc | 10s +-1 |
| a | c | abc | 27s +-1 | | a | c | abc | 27s +-1 |
| d | e | def | 20s +-1 |
| d | f | def | 47s +-1 | | d | f | def | 47s +-1 |
| g | h | ghi | 30s +-1 |
| g | i | ghi | 67s +-1 | | g | i | ghi | 67s +-1 |
Scenario: Passing multiple traffic signals should incur a accumulated delay Scenario: Passing multiple traffic signals should incur a accumulated delay
@ -69,6 +66,7 @@ Testbot uses a signal penalty of 7s.
| from | to | route | time | | from | to | route | time |
| a | e | abcde | 61s +-1 | | a | e | abcde | 61s +-1 |
@todo
Scenario: Signal penalty should not depend on way type Scenario: Signal penalty should not depend on way type
Given the node map Given the node map
| a | b | c | | a | b | c |
@ -114,6 +112,7 @@ Testbot uses a signal penalty of 7s.
| from | to | route | time | | from | to | route | time |
| a | e | abcde | 61s +-1 | | a | e | abcde | 61s +-1 |
@todo
Scenario: Starting or ending at a traffic signal should not incur a delay Scenario: Starting or ending at a traffic signal should not incur a delay
Given the node map Given the node map
| a | b | c | | a | b | c |
@ -154,7 +153,7 @@ Testbot uses a signal penalty of 7s.
And the node map And the node map
| a | | b | | c | | a | | b | | c |
| | | d | | | | | | d | | |
And the nodes And the nodes
| node | highway | | node | highway |
| b | traffic_signals | | b | traffic_signals |
@ -163,7 +162,7 @@ Testbot uses a signal penalty of 7s.
| nodes | highway | | nodes | highway |
| abc | primary | | abc | primary |
| adc | primary | | adc | primary |
When I route I should get When I route I should get
| from | to | route | | from | to | route |
| a | c | adc | | a | c | adc |

View File

@ -98,7 +98,7 @@ Feature: Snap start/end point to the nearest way
| b | x | xb | | b | x | xb |
| c | x | xc | | c | x | xc |
Scenario: Find edges within 1km, but not 10km Scenario: Find edges within 1km, and the same from 10km
Given a grid size of 1000 meters Given a grid size of 1000 meters
Given the node map Given the node map
| p | | | | | | | | | | | i | | | | | | | | | | | j | | p | | | | | | | | | | | i | | | | | | | | | | | j |
@ -144,11 +144,11 @@ Feature: Snap start/end point to the nearest way
| x | 6 | xf | | x | 6 | xf |
| x | 7 | xg | | x | 7 | xg |
| x | 8 | xh | | x | 8 | xh |
| x | i | | | x | i | xa |
| x | j | | | x | j | xb |
| x | k | | | x | k | xc |
| x | l | | | x | l | xd |
| x | m | | | x | m | xe |
| x | n | | | x | n | xf |
| x | o | | | x | o | xg |
| x | p | | | x | p | xh |

View File

@ -0,0 +1,52 @@
@routing @testbot @via
Feature: Via points
Background:
Given the profile "testbot"
Scenario: Simple via point
Given the node map
| a | b | c |
And the ways
| nodes |
| abc |
When I route I should get
| waypoints | route |
| a,b,c | abc |
| c,b,a | abc |
Scenario: Via point at a dead end
Given the node map
| a | b | c |
| | d | |
And the ways
| nodes |
| abc |
| bd |
When I route I should get
| waypoints | route |
| a,d,c | abc,bd,bd,abc |
| c,d,a | abc,bd,bd,abc |
Scenario: Multiple via points
Given the node map
| a | | | | e | f | g | |
| | b | c | d | | | | h |
And the ways
| nodes |
| ae |
| ab |
| bcd |
| de |
| efg |
| gh |
| dh |
When I route I should get
| waypoints | route |
| a,c,f,h | ab,bcd,de,efg,gh |

View File

@ -1,219 +0,0 @@
-- Begin of globals
require("lib/access")
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 }
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,
["motorway_link"] = 75,
["trunk"] = 85,
["trunk_link"] = 70,
["primary"] = 65,
["primary_link"] = 60,
["secondary"] = 55,
["secondary_link"] = 50,
["tertiary"] = 40,
["tertiary_link"] = 30,
["unclassified"] = 25,
["residential"] = 25,
["living_street"] = 10,
["service"] = 15,
-- ["track"] = 5,
["ferry"] = 5,
["shuttle_train"] = 10,
["default"] = 50
}
take_minimum_of_speeds = false
obey_oneway = true
obey_bollards = true
use_restrictions = true
ignore_areas = true -- future feature
traffic_signal_penalty = 2
u_turn_penalty = 20
-- End of globals
function get_exceptions(vector)
for i,v in ipairs(restriction_exception_tags) do
vector:Add(v)
end
end
local function parse_maxspeed(source)
if source == nil then
return 0
end
local n = tonumber(source:match("%d*"))
if n == nil then
n = 0
end
if string.match(source, "mph") or string.match(source, "mp/h") then
n = (n*1609)/1000;
end
return math.abs(n)
end
function node_function (node)
local barrier = node.tags:Find ("barrier")
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
if traffic_signal == "traffic_signals" then
node.traffic_light = true;
end
-- parse access and barrier tags
if access and access ~= "" then
if access_tag_blacklist[access] then
node.bollard = true
end
elseif barrier and barrier ~= "" then
if barrier_whitelist[barrier] then
return
else
node.bollard = true
end
end
return 1
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")
local ref = way.tags:Find("ref")
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 = Access.find_access_tag(way, access_tags_hierachy)
-- Second, parse the way according to these properties
if ignore_areas and ("yes" == area) then
return 0
end
-- Check if we are allowed to access the way
if access_tag_blacklist[access] then
return 0
end
-- Set the name that will be used for instructions
if "" ~= ref then
way.name = ref
elseif "" ~= name then
way.name = name
-- else
-- way.name = highway -- if no name exists, use way type
end
if "roundabout" == junction then
way.roundabout = true;
end
-- Handling ferries and piers
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 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
maxspeed = math.huge
end
way.speed = math.min(speed_profile["default"], maxspeed)
end
-- Set access restriction flag if access is allowed under certain restrictions only
if access ~= "" and access_tag_restricted[access] then
way.is_access_restricted = true
end
-- Set access restriction flag if service is allowed under certain restrictions only
if service ~= "" and service_tag_restricted[service] then
way.is_access_restricted = true
end
-- Set direction according to tags on way
if obey_oneway then
if oneway == "no" or oneway == "0" or oneway == "false" then
way.direction = Way.bidirectional
elseif oneway == "-1" then
way.direction = Way.opposite
elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" or highway == "motorway_link" or highway == "motorway" then
way.direction = Way.oneway
else
way.direction = Way.bidirectional
end
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
way.ignore_in_grid = true
end
way.type = 1
return 1
end
-- These are wrappers to parse vectors of nodes and ways and thus to speed up any tracing JIT
function node_vector_function(vector)
for v in vector.nodes do
node_function(v)
end
end

View File

@ -65,6 +65,24 @@ route_speeds = {
["ferry"] = 5 ["ferry"] = 5
} }
surface_speeds = {
["cobblestone:flattened"] = 10,
["paving_stones"] = 10,
["compacted"] = 10,
["cobblestone"] = 6,
["unpaved"] = 6,
["fine_gravel"] = 6,
["gravel"] = 6,
["fine_gravel"] = 6,
["pebbelstone"] = 6,
["ground"] = 6,
["dirt"] = 6,
["earth"] = 6,
["grass"] = 6,
["mud"] = 3,
["sand"] = 3
}
take_minimum_of_speeds = true take_minimum_of_speeds = true
obey_oneway = true obey_oneway = true
obey_bollards = false obey_bollards = false
@ -158,16 +176,20 @@ function way_function (way)
local service = way.tags:Find("service") local service = way.tags:Find("service")
local area = way.tags:Find("area") local area = way.tags:Find("area")
local foot = way.tags:Find("foot") local foot = way.tags:Find("foot")
local surface = way.tags:Find("surface")
-- name -- name
if "" ~= ref then if "" ~= ref and "" ~= name then
way.name = ref way.name = name .. ' / ' .. ref
elseif "" ~= ref then
way.name = ref
elseif "" ~= name then elseif "" ~= name then
way.name = name way.name = name
else else
way.name = highway -- if no name exists, use way type way.name = "{highway:"..highway.."}" -- if no name exists, use way type
-- this encoding scheme is excepted to be a temporary solution
end end
-- speed -- speed
if route_speeds[route] then if route_speeds[route] then
-- ferries (doesn't cover routes tagged using relations) -- ferries (doesn't cover routes tagged using relations)
@ -285,6 +307,15 @@ function way_function (way)
elseif cycleway_right and cycleway_tags[cycleway_right] then elseif cycleway_right and cycleway_tags[cycleway_right] then
way.speed = bicycle_speeds["cycleway"] way.speed = bicycle_speeds["cycleway"]
end end
-- surfaces
if surface then
surface_speed = surface_speeds[surface]
if surface_speed then
way.speed = math.min(way.speed, surface_speed)
way.backward_speed = math.min(way.backward_speed, surface_speed)
end
end
-- maxspeed -- maxspeed
-- TODO: maxspeed of backward direction -- TODO: maxspeed of backward direction

View File

@ -11,10 +11,10 @@ service_tag_restricted = { ["parking_aisle"] = true }
ignore_in_grid = { ["ferry"] = true } ignore_in_grid = { ["ferry"] = true }
restriction_exception_tags = { "motorcar", "motor_vehicle", "vehicle" } restriction_exception_tags = { "motorcar", "motor_vehicle", "vehicle" }
speed_profile = { speed_profile = {
["motorway"] = 90, ["motorway"] = 90,
["motorway_link"] = 75, ["motorway_link"] = 75,
["trunk"] = 85, ["trunk"] = 85,
["trunk_link"] = 70, ["trunk_link"] = 70,
["primary"] = 65, ["primary"] = 65,
["primary_link"] = 60, ["primary_link"] = 60,
@ -43,7 +43,7 @@ u_turn_penalty = 20
-- End of globals -- End of globals
function get_exceptions(vector) function get_exceptions(vector)
for i,v in ipairs(restriction_exception_tags) do for i,v in ipairs(restriction_exception_tags) do
vector:Add(v) vector:Add(v)
end end
end end
@ -66,13 +66,13 @@ function node_function (node)
local barrier = node.tags:Find ("barrier") local barrier = node.tags:Find ("barrier")
local access = Access.find_access_tag(node, access_tags_hierachy) local access = Access.find_access_tag(node, access_tags_hierachy)
local traffic_signal = node.tags:Find("highway") local traffic_signal = node.tags:Find("highway")
--flag node if it carries a traffic light --flag node if it carries a traffic light
if traffic_signal == "traffic_signals" then if traffic_signal == "traffic_signals" then
node.traffic_light = true; node.traffic_light = true;
end end
-- parse access and barrier tags -- parse access and barrier tags
if access and access ~= "" then if access and access ~= "" then
if access_tag_blacklist[access] then if access_tag_blacklist[access] then
@ -90,35 +90,40 @@ end
function way_function (way) function way_function (way)
-- First, get the properties of each way that we come across -- we dont route over areas
local highway = way.tags:Find("highway") local area = way.tags:Find("area")
local name = way.tags:Find("name") if ignore_areas and ("yes" == area) then
local ref = way.tags:Find("ref") return 0
local junction = way.tags:Find("junction") end
local route = way.tags:Find("route")
local maxspeed = parse_maxspeed(way.tags:Find ( "maxspeed") ) -- check if oneway tag is unsupported
local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward")) local oneway = way.tags:Find("oneway")
local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward")) if "reversible" == oneway then
local barrier = way.tags:Find("barrier") return 0
local oneway = way.tags:Find("oneway") end
local cycleway = way.tags:Find("cycleway")
local duration = way.tags:Find("duration") -- Check if we are allowed to access the way
local service = way.tags:Find("service") local access = Access.find_access_tag(way, access_tags_hierachy)
local area = way.tags:Find("area") if access_tag_blacklist[access] then
local access = Access.find_access_tag(way, access_tags_hierachy) return 0
end
-- Second, parse the way according to these properties -- Second, parse the way according to these properties
local highway = way.tags:Find("highway")
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 maxspeed = parse_maxspeed(way.tags:Find ( "maxspeed") )
local maxspeed_forward = parse_maxspeed(way.tags:Find( "maxspeed:forward"))
local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward"))
local barrier = way.tags:Find("barrier")
local cycleway = way.tags:Find("cycleway")
local duration = way.tags:Find("duration")
local service = way.tags:Find("service")
if ignore_areas and ("yes" == area) then
return 0
end
-- Check if we are allowed to access the way
if access_tag_blacklist[access] then
return 0
end
-- Set the name that will be used for instructions -- Set the name that will be used for instructions
if "" ~= ref then if "" ~= ref then
way.name = ref way.name = ref
elseif "" ~= name then elseif "" ~= name then
@ -126,87 +131,82 @@ function way_function (way)
-- else -- else
-- way.name = highway -- if no name exists, use way type -- way.name = highway -- if no name exists, use way type
end end
if "roundabout" == junction then if "roundabout" == junction then
way.roundabout = true; way.roundabout = true;
end end
-- Handling ferries and piers -- Handling ferries and piers
if (speed_profile[route] ~= nil and speed_profile[route] > 0) then if (speed_profile[route] ~= nil and speed_profile[route] > 0) then
if durationIsValid(duration) then if durationIsValid(duration) then
way.duration = math.max( parseDuration(duration), 1 ); way.duration = math.max( parseDuration(duration), 1 );
end end
way.direction = Way.bidirectional way.direction = Way.bidirectional
if speed_profile[route] ~= nil then if speed_profile[route] ~= nil then
highway = route; highway = route;
end end
if tonumber(way.duration) < 0 then if tonumber(way.duration) < 0 then
way.speed = speed_profile[highway] way.speed = speed_profile[highway]
end end
end end
-- Set the avg speed on the way if it is accessible by road class -- 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 (speed_profile[highway] ~= nil and way.speed == -1 ) then
if maxspeed > speed_profile[highway] then if maxspeed > speed_profile[highway] then
way.speed = maxspeed way.speed = maxspeed
else else
if 0 == maxspeed then if 0 == maxspeed then
maxspeed = math.huge maxspeed = math.huge
end end
way.speed = math.min(speed_profile[highway], maxspeed) way.speed = math.min(speed_profile[highway], maxspeed)
end end
end end
-- Set the avg speed on ways that are marked accessible -- Set the avg speed on ways that are marked accessible
if "" ~= highway and access_tag_whitelist[access] and way.speed == -1 then if "" ~= highway and access_tag_whitelist[access] and way.speed == -1 then
if 0 == maxspeed then if 0 == maxspeed then
maxspeed = math.huge maxspeed = math.huge
end
way.speed = math.min(speed_profile["default"], maxspeed)
end end
way.speed = math.min(speed_profile["default"], maxspeed)
end
-- Set access restriction flag if access is allowed under certain restrictions only -- Set access restriction flag if access is allowed under certain restrictions only
if access ~= "" and access_tag_restricted[access] then if access ~= "" and access_tag_restricted[access] then
way.is_access_restricted = true way.is_access_restricted = true
end end
-- Set access restriction flag if service is allowed under certain restrictions only -- Set access restriction flag if service is allowed under certain restrictions only
if service ~= "" and service_tag_restricted[service] then if service ~= "" and service_tag_restricted[service] then
way.is_access_restricted = true way.is_access_restricted = true
end end
-- Set direction according to tags on way -- Set direction according to tags on way
if obey_oneway then way.direction = Way.bidirectional
if oneway == "no" or oneway == "0" or oneway == "false" then if obey_oneway then
way.direction = Way.bidirectional if oneway == "-1" then
elseif oneway == "-1" then
way.direction = Way.opposite way.direction = Way.opposite
elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" or highway == "motorway_link" or highway == "motorway" then elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" or highway == "motorway_link" or highway == "motorway" then
way.direction = Way.oneway way.direction = Way.oneway
else
way.direction = Way.bidirectional
end
else
way.direction = Way.bidirectional
end end
end
-- Override speed settings if explicit forward/backward maxspeeds are given -- Override speed settings if explicit forward/backward maxspeeds are given
if maxspeed_forward ~= nil and maxspeed_forward > 0 then if maxspeed_forward ~= nil and maxspeed_forward > 0 then
if Way.bidirectional == way.direction then if Way.bidirectional == way.direction then
way.backward_speed = way.speed 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 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 -- 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
if ignore_in_grid[highway] ~= nil and ignore_in_grid[highway] then
way.ignore_in_grid = true way.ignore_in_grid = true
end end
way.type = 1
way.type = 1
return 1 return 1
end end

View File

@ -3,7 +3,7 @@ local ipairs = ipairs
module "Access" module "Access"
function find_access_tag(source,access_tags_hierachy) function find_access_tag(source,access_tags_hierachy)
for i,v in ipairs(access_tags_hierachy) do for i,v in ipairs(access_tags_hierachy) do
local tag = source.tags:Find(v) local tag = source.tags:Find(v)
if tag ~= '' then if tag ~= '' then
return tag return tag

View File

@ -23,8 +23,9 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <iostream> #include <iostream>
#include <signal.h> #include <signal.h>
#include <boost/thread.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/date_time.hpp>
#include <boost/thread.hpp>
#include "Server/DataStructures/QueryObjectsStorage.h" #include "Server/DataStructures/QueryObjectsStorage.h"
#include "Server/ServerConfiguration.h" #include "Server/ServerConfiguration.h"
@ -64,7 +65,7 @@ BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
} }
#endif #endif
int main (int argc, char * argv[0]) { int main (int argc, char * argv[]) {
#ifdef __linux__ #ifdef __linux__
if(!mlockall(MCL_CURRENT | MCL_FUTURE)) if(!mlockall(MCL_CURRENT | MCL_FUTURE))
WARN("Process " << argv[0] << "could not be locked to RAM"); WARN("Process " << argv[0] << "could not be locked to RAM");
@ -138,7 +139,11 @@ int main (int argc, char * argv[0]) {
std::cout << "[server] initiating shutdown" << std::endl; std::cout << "[server] initiating shutdown" << std::endl;
s->Stop(); s->Stop();
std::cout << "[server] stopping threads" << std::endl; std::cout << "[server] stopping threads" << std::endl;
t.join();
if(!t.timed_join(boost::posix_time::seconds(2))) {
// INFO("Threads did not finish within 2 seconds. Hard abort!");
}
std::cout << "[server] freeing objects" << std::endl; std::cout << "[server] freeing objects" << std::endl;
delete s; delete s;
delete objects; delete objects;

View File

@ -35,16 +35,14 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <iostream> #include <iostream>
#define INFO(x) do {std::cout << "[info " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl;} while(0); #define INFO(x) do {std::cout << "[i " << __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 ERR(x) do {std::cerr << "[! " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl; std::exit(-1);} while(0);
#define WARN(x) do {std::cerr << "[warn " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl;} while(0); #define WARN(x) do {std::cerr << "[? " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl;} while(0);
#ifdef NDEBUG #ifdef NDEBUG
#define DEBUG(x) #define DEBUG(x)
#define GUARANTEE(x,y)
#else #else
#define DEBUG(x) do {std::cout << "[debug " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl;} while(0); #define DEBUG(x) do {std::cout << "[d " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl;} while(0);
#define GUARANTEE(x,y) do { {do{ if(false == (x)) { ERR(y) } } while(0);} } while(0);
#endif #endif
#ifndef M_PI #ifndef M_PI