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?
Thumbs.db
# SCons related files #
# build related files #
#######################
SconsBuilder*
.scon*
.build
/build/
# Eclipse related files #
#########################

View File

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

View File

@ -89,11 +89,14 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vector<NodeBasedEdg
}
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);
}
void EdgeBasedGraphFactory::GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode> & nodes) {
void EdgeBasedGraphFactory::GetEdgeBasedNodes( std::vector<EdgeBasedNode> & nodes) {
#ifndef NDEBUG
BOOST_FOREACH(EdgeBasedNode & node, edgeBasedNodes){
assert(node.lat1 != INT_MAX); assert(node.lon1 != INT_MAX);

View File

@ -25,20 +25,6 @@
#ifndef 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 "../DataStructures/DeallocatingVector.h"
#include "../DataStructures/DynamicGraph.h"
@ -50,14 +36,22 @@
#include "../DataStructures/Percent.h"
#include "../DataStructures/TurnInstructions.h"
#include "../Util/BaseConfiguration.h"
#include "../Util/LuaUtil.h"
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include <luabind/luabind.hpp>
#include <stxxl.h>
#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 {
public:
@ -65,9 +59,23 @@ public:
bool operator<(const EdgeBasedNode & other) const {
return other.id < id;
}
bool operator==(const EdgeBasedNode & other) const {
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;
int lat1;
int lat2;
@ -127,7 +135,7 @@ private:
RestrictionMap _restrictionMap;
DeallocatingVector<EdgeBasedEdge> edgeBasedEdges;
DeallocatingVector<EdgeBasedNode> edgeBasedNodes;
std::vector<EdgeBasedNode> edgeBasedNodes;
NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) 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 GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges );
void GetEdgeBasedNodes( DeallocatingVector< EdgeBasedNode> & nodes);
void GetEdgeBasedNodes( std::vector< EdgeBasedNode> & nodes);
void GetOriginalEdgeData( std::vector< OriginalEdgeData> & originalEdgeData);
TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, unsigned& penalty, lua_State *myLuaState) const;
unsigned GetNumberOfNodes() const;

View File

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

View File

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

View File

@ -21,18 +21,21 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef DYNAMICGRAPH_H_INCLUDED
#define DYNAMICGRAPH_H_INCLUDED
#include <vector>
#include "../DataStructures/DeallocatingVector.h"
#include <boost/assert.hpp>
#include <boost/integer.hpp>
#include <algorithm>
#include <limits>
#include "../DataStructures/DeallocatingVector.h"
#include <vector>
template< typename EdgeDataT>
class DynamicGraph {
public:
typedef EdgeDataT EdgeData;
typedef unsigned NodeIterator;
typedef unsigned EdgeIterator;
typedef uint32_t NodeIterator;
typedef uint32_t EdgeIterator;
class InputEdge {
public:
@ -47,16 +50,16 @@ class DynamicGraph {
};
//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.resize( m_numNodes );
m_edges.reserve( m_numNodes * 1.1 );
m_edges.resize( m_numNodes );
}
template<class ContainerT>
DynamicGraph( const int nodes, const ContainerT &graph )
{
DynamicGraph( const int32_t nodes, const ContainerT &graph ) {
m_numNodes = nodes;
m_numEdges = ( EdgeIterator ) graph.size();
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 ) {
m_edges[i].target = graph[edge].target;
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;
}
}
@ -88,17 +94,15 @@ class DynamicGraph {
~DynamicGraph(){ }
unsigned GetNumberOfNodes() const
{
uint32_t GetNumberOfNodes() const {
return m_numNodes;
}
unsigned GetNumberOfEdges() const
{
uint32_t GetNumberOfEdges() const {
return m_numEdges;
}
unsigned GetOutDegree( const NodeIterator n ) const {
uint32_t GetOutDegree( const NodeIterator n ) const {
return m_nodes[n].edges;
}
@ -115,7 +119,6 @@ class DynamicGraph {
}
EdgeIterator BeginEdges( const NodeIterator n ) const {
//assert( EndEdges( n ) - EdgeIterator( _nodes[n].firstEdge ) <= 100 );
return EdgeIterator( m_nodes[n].firstEdge );
}
@ -133,7 +136,7 @@ class DynamicGraph {
m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
} else {
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 oldCapacity = m_edges.capacity();
if ( requiredCapacity >= oldCapacity ) {
@ -162,15 +165,15 @@ class DynamicGraph {
Node &node = m_nodes[source];
--m_numEdges;
--node.edges;
const unsigned last = node.firstEdge + node.edges;
const uint32_t last = node.firstEdge + node.edges;
//swap with last edge
m_edges[e] = m_edges[last];
makeDummy( last );
}
//removes all edges (source,target)
int DeleteEdgesTo( const NodeIterator source, const NodeIterator target ) {
int deleted = 0;
int32_t DeleteEdgesTo( const NodeIterator source, const NodeIterator target ) {
int32_t deleted = 0;
for ( EdgeIterator i = BeginEdges( source ), iend = EndEdges( source ); i < iend - deleted; ++i ) {
if ( m_edges[i].target == target ) {
do {
@ -200,11 +203,11 @@ class DynamicGraph {
protected:
bool isDummy( EdgeIterator edge ) const {
bool isDummy( const EdgeIterator edge ) const {
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)();
}
@ -212,7 +215,7 @@ class DynamicGraph {
//index of the first edge
EdgeIterator firstEdge;
//amount of edges
unsigned edges;
uint32_t edges;
};
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_
#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 <iostream>
#include <vector>
#include <boost/noncopyable.hpp>
#include "../typedefs.h"
#include "../DataStructures/QueryEdge.h"
#include "NNGrid.h"
#include "PhantomNodes.h"
#include "NodeCoords.h"
typedef EdgeBasedGraphFactory::EdgeBasedNode RTreeLeaf;
class NodeInformationHelpDesk : boost::noncopyable{
public:
NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned _numberOfNodes, const unsigned crc) : numberOfNodes(_numberOfNodes), checkSum(crc) {
readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
assert(0 == coordinateVector.size());
NodeInformationHelpDesk(
const char* ramIndexInput,
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
// NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput, const unsigned crc) : checkSum(crc) {
// readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
// }
~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");
NodeInfo b;
while(!nodesInstream.eof()) {
@ -75,13 +90,8 @@ public:
edgesInStream.close();
DEBUG("Loaded " << numberOfOrigEdges << " orig edges");
DEBUG("Opening NN indices");
readOnlyGrid->OpenIndexFiles();
}
// void initNNGrid() {
// readOnlyGrid->OpenIndexFiles();
// }
inline int getLatitudeOfNode(const unsigned id) const {
const NodeID node = origEdgeData_viaNode.at(id);
return coordinateVector.at(node).lat;
@ -100,23 +110,35 @@ public:
return origEdgeData_turnInstruction.at(id);
}
inline NodeID getNumberOfNodes() const { return numberOfNodes; }
inline NodeID getNumberOfNodes2() const { return coordinateVector.size(); }
inline bool FindNearestNodeCoordForLatLon(const _Coordinate& coord, _Coordinate& result) const {
return readOnlyGrid->FindNearestCoordinateOnEdgeInNodeBasedGraph(coord, result);
inline NodeID getNumberOfNodes() const {
return number_of_nodes;
}
inline bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode, const unsigned zoomLevel) {
return readOnlyGrid->FindPhantomNodeForCoordinate(location, resultNode, zoomLevel);
inline NodeID getNumberOfNodes2() const {
return coordinateVector.size();
}
inline void FindRoutingStarts(const _Coordinate &start, const _Coordinate &target, PhantomNodes & phantomNodes, const unsigned zoomLevel) const {
readOnlyGrid->FindRoutingStarts(start, target, phantomNodes, zoomLevel);
inline bool FindNearestNodeCoordForLatLon(
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 FindNearestPointOnEdge(const _Coordinate & input, _Coordinate& output){
readOnlyGrid->FindNearestPointOnEdge(input, output);
inline bool FindPhantomNodeForCoordinate(
const _Coordinate & input_coordinate,
PhantomNode & resulting_phantom_node,
const unsigned zoom_level
) const {
return read_only_rtree->FindPhantomNodeForCoordinate(
input_coordinate,
resulting_phantom_node,
zoom_level
);
}
inline unsigned GetCheckSum() const {
@ -129,8 +151,8 @@ private:
std::vector<unsigned> origEdgeData_nameID;
std::vector<TurnInstruction> origEdgeData_turnInstruction;
ReadOnlyGrid * readOnlyGrid;
const unsigned numberOfNodes;
StaticRTree<EdgeBasedGraphFactory::EdgeBasedNode> * read_only_rtree;
const unsigned number_of_nodes;
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_
#define SEARCHENGINE_H_
#include <climits>
#include <deque>
#include "SimpleStack.h"
#include <boost/thread.hpp>
#include "BinaryHeap.h"
#include "Coordinate.h"
#include "NodeInformationHelpDesk.h"
#include "PhantomNodes.h"
#include "QueryEdge.h"
#include "SearchEngineData.h"
#include "../RoutingAlgorithms/AlternativePathRouting.h"
#include "../RoutingAlgorithms/BasicRoutingInterface.h"
#include "../RoutingAlgorithms/ShortestPathRouting.h"
#include "../Util/StringUtil.h"
#include "../typedefs.h"
struct _HeapData {
NodeID parent;
_HeapData( NodeID p ) : parent(p) { }
};
#include <climits>
#include <string>
#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 {
private:
typedef SearchEngineData<EdgeData, GraphT> SearchEngineDataT;
SearchEngineDataT _queryData;
SearchEngineData _queryData;
inline double absDouble(double input) { if(input < 0) return input*(-1); else return input;}
public:
ShortestPathRouting<SearchEngineDataT> shortestPath;
AlternativeRouting<SearchEngineDataT> alternativePaths;
ShortestPathRouting<SearchEngineData> shortestPath;
AlternativeRouting<SearchEngineData> alternativePaths;
SearchEngine(GraphT * g, NodeInformationHelpDesk * nh, std::vector<std::string> & n) :
_queryData(g, nh, n),
shortestPath(_queryData),
alternativePaths(_queryData)
{}
~SearchEngine() {}
SearchEngine(
QueryGraph * g,
NodeInformationHelpDesk * nh,
std::vector<std::string> & n
);
~SearchEngine();
inline void GetCoordinatesForNodeID(NodeID id, _Coordinate& result) const {
result.lat = _queryData.nodeHelpDesk->getLatitudeOfNode(id);
result.lon = _queryData.nodeHelpDesk->getLongitudeOfNode(id);
}
void GetCoordinatesForNodeID(NodeID id, _Coordinate& result) const;
inline void FindRoutingStarts(const _Coordinate & start, const _Coordinate & target, PhantomNodes & routingStarts) const {
_queryData.nodeHelpDesk->FindRoutingStarts(start, target, routingStarts);
}
void FindPhantomNodeForCoordinate(
const _Coordinate & location,
PhantomNode & result,
unsigned zoomLevel
) const;
inline void FindPhantomNodeForCoordinate(const _Coordinate & location, PhantomNode & result, unsigned zoomLevel) const {
_queryData.nodeHelpDesk->FindPhantomNodeForCoordinate(location, result, zoomLevel);
}
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);
}
NodeID GetNameIDForOriginDestinationNodeID(
const NodeID s, const NodeID t) const;
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_ */

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 "../typedefs.h"
#include "../DataStructures/PhantomNodes.h"
#include "../DataStructures/HashTable.h"
#include "../DataStructures/PhantomNodes.h"
#include "../DataStructures/SearchEngine.h"
#include "../Util/StringUtil.h"
#include "../Plugins/RawRouteData.h"
@ -42,13 +43,12 @@ struct _DescriptorConfig {
unsigned short z;
};
template<class SearchEngineT>
class BaseDescriptor {
public:
BaseDescriptor() { }
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
virtual ~BaseDescriptor() { }
virtual void Run(http::Reply & reply, 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;
};

View File

@ -82,7 +82,7 @@ void DescriptionFactory::AppendUnencodedPolylineString(std::string &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())
return;

View File

@ -27,7 +27,6 @@
#include "../Algorithms/DouglasPeucker.h"
#include "../Algorithms/PolylineCompressor.h"
#include "../DataStructures/Coordinate.h"
#include "../DataStructures/QueryEdge.h"
#include "../DataStructures/SearchEngine.h"
#include "../DataStructures/SegmentInformation.h"
#include "../DataStructures/TurnInstructions.h"
@ -40,8 +39,6 @@ class DescriptionFactory {
PolylineCompressor pc;
PhantomNode startPhantom, targetPhantom;
typedef SearchEngine<QueryEdge::EdgeData, StaticGraph<QueryEdge::EdgeData> > SearchEngineT;
double DegreeToRadian(const double degree) const;
double RadianToDegree(const double degree) const;
public:
@ -73,7 +70,7 @@ public:
void SetStartSegment(const PhantomNode & startPhantom);
void SetEndSegment(const PhantomNode & startPhantom);
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_ */

View File

@ -24,8 +24,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <boost/foreach.hpp>
#include "BaseDescriptor.h"
template<class SearchEngineT>
class GPXDescriptor : public BaseDescriptor<SearchEngineT>{
class GPXDescriptor : public BaseDescriptor{
private:
_DescriptorConfig config;
_Coordinate current;
@ -33,7 +32,7 @@ private:
std::string tmp;
public:
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 += "<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\" "

View File

@ -34,8 +34,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "../Util/Azimuth.h"
#include "../Util/StringUtil.h"
template<class SearchEngineT>
class JSONDescriptor : public BaseDescriptor<SearchEngineT>{
class JSONDescriptor : public BaseDescriptor{
private:
_DescriptorConfig config;
DescriptionFactory descriptionFactory;
@ -68,7 +67,7 @@ public:
JSONDescriptor() : numberOfEnteredRestrictedAreas(0) {}
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);
@ -246,7 +245,7 @@ public:
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 ***/
Segment shortestSegment1, shortestSegment2;
@ -304,7 +303,7 @@ public:
"\"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:
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
//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->isAccessRestricted, sizeof(bool));
fout.write((char*)&edgeIT->isContraFlow, sizeof(bool));
}
++usedEdgeCounter;
}
++edgeIT;
}
}

View File

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

View File

@ -155,22 +155,19 @@ inline bool PBFParser::Parse() {
inline void PBFParser::parseDenseNode(_ThreadData * threadData) {
const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense();
int denseTagIndex = 0;
int m_lastDenseID = 0;
int m_lastDenseLatitude = 0;
int m_lastDenseLongitude = 0;
int64_t m_lastDenseID = 0;
int64_t m_lastDenseLatitude = 0;
int64_t m_lastDenseLongitude = 0;
ImportNode n;
std::vector<ImportNode> extracted_nodes_vector;
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) {
n.Clear();
m_lastDenseID += dense.id( i );
m_lastDenseLatitude += dense.lat( i );
m_lastDenseLongitude += dense.lon( i );
n.id = m_lastDenseID;
n.lat = 100000*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lat_offset() ) / NANO;
n.lon = 100000*( ( double ) m_lastDenseLongitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lon_offset() ) / NANO;
extracted_nodes_vector[i].id = m_lastDenseID;
extracted_nodes_vector[i].lat = 100000*( ( double ) m_lastDenseLatitude * threadData->PBFprimitiveBlock.granularity() + threadData->PBFprimitiveBlock.lat_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()) {
const int tagValue = dense.keys_vals( denseTagIndex );
if( 0==tagValue ) {
@ -180,10 +177,9 @@ inline void PBFParser::parseDenseNode(_ThreadData * threadData) {
const int keyValue = dense.keys_vals ( denseTagIndex+1 );
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue).data();
const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue).data();
n.keyVals.Add(key, value);
extracted_nodes_vector[i].keyVals.Add(key, value);
denseTagIndex += 2;
}
extracted_nodes_vector.push_back(n);
}
#pragma omp parallel for schedule ( guided )
@ -292,37 +288,33 @@ inline void PBFParser::parseRelation(_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();
waysToParse.reserve(number_of_ways);
std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
for(int i = 0; i < number_of_ways; ++i) {
w.Clear();
const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i );
w.id = inputWay.id();
parsed_way_vector[i].id = inputWay.id();
unsigned pathNode(0);
const int number_of_referenced_nodes = inputWay.refs_size();
for(int i = 0; i < number_of_referenced_nodes; ++i) {
pathNode += inputWay.refs(i);
w.path.push_back(pathNode);
for(int j = 0; j < number_of_referenced_nodes; ++j) {
pathNode += inputWay.refs(j);
parsed_way_vector[i].path.push_back(pathNode);
}
assert(inputWay.keys_size() == inputWay.vals_size());
const int number_of_keys = inputWay.keys_size();
for(int i = 0; i < number_of_keys; ++i) {
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(i));
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(i));
w.keyVals.Add(key, val);
for(int j = 0; j < number_of_keys; ++j) {
const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputWay.keys(j));
const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputWay.vals(j));
parsed_way_vector[i].keyVals.Add(key, val);
}
waysToParse.push_back(w);
}
#pragma omp parallel for schedule ( guided )
for(int i = 0; i < number_of_ways; ++i) {
ExtractionWay & w = waysToParse[i];
ExtractionWay & w = parsed_way_vector[i];
ParseWayInLua( w, scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()) );
}
BOOST_FOREACH(ExtractionWay & w, waysToParse) {
BOOST_FOREACH(ExtractionWay & w, parsed_way_vector) {
extractor_callbacks->wayFunction(w);
}
}

View File

@ -21,6 +21,13 @@
#ifndef 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/make_shared.hpp>
#include <boost/ref.hpp>
@ -30,13 +37,7 @@
#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 {

View File

@ -21,13 +21,13 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef LOCATEPLUGIN_H_
#define LOCATEPLUGIN_H_
#include <fstream>
#include "../Server/DataStructures/QueryObjectsStorage.h"
#include "BasePlugin.h"
#include "RouteParameters.h"
#include "../Util/StringUtil.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.

View File

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

View File

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

View File

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

View File

@ -73,17 +73,23 @@ public:
//insert new starting nodes into forward heap, adjusted by previous distances.
if(searchFrom1stStartNode) {
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);
INFO("fw2: " << phantomNodePair.startPhantom.edgeBasedNode << "´, w: " << -phantomNodePair.startPhantom.weight1);
}
if(phantomNodePair.startPhantom.isBidirected() && searchFrom2ndStartNode) {
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);
INFO("fw2: " << phantomNodePair.startPhantom.edgeBasedNode+1 << "´, w: " << -phantomNodePair.startPhantom.weight2);
}
//insert new backward nodes into backward heap, unadjusted.
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() ) {
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 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
#define BASIC_DATASTRUCTURES_H
#include <string>
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#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].value = "*";
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].value = "text/html";
return rep;

View File

@ -22,14 +22,27 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "QueryObjectsStorage.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");
std::ifstream hsgrInStream(hsgrPath.c_str(), std::ios::binary);
if(!hsgrInStream) { ERR(hsgrPath << " not found"); }
//Deserialize road network graph
std::vector< QueryGraph::_StrNode> nodeList;
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);
graph = new QueryGraph(nodeList, edgeList);
@ -39,7 +52,7 @@ QueryObjectsStorage::QueryObjectsStorage(std::string hsgrPath, std::string ramIn
if(timestampPath.length()) {
INFO("Loading Timestamp");
std::ifstream timestampInStream(timestampPath.c_str());
if(!timestampInStream) { ERR(timestampPath << " not found"); }
if(!timestampInStream) { WARN(timestampPath << " not found"); }
getline(timestampInStream, timestamp);
timestampInStream.close();

View File

@ -25,7 +25,6 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <cctype> // std::tolower
#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/noncopyable.hpp>
#include "APIGrammar.h"
@ -52,6 +51,7 @@ public:
void handle_request(const Request& req, Reply& rep){
//parse command
try {
std::string request(req.uri);
{ //This block logs the current request to std out. should be moved to a logging component
@ -64,7 +64,7 @@ public:
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 {
RouteParameters 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
#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 <cmath>
@ -30,19 +39,11 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <iomanip>
#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;
template<class EdgeT>
struct _ExcessRemover {
inline bool operator()( EdgeT & edge ) const {
inline bool operator()( const EdgeT & edge ) const {
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*)&isContraFlow, sizeof(bool));
GUARANTEE(length > 0, "loaded null length edge" );
GUARANTEE(weight > 0, "loaded null weight");
GUARANTEE(0<=dir && dir<=2, "loaded bogus direction");
BOOST_ASSERT_MSG(length > 0, "loaded null length edge" );
BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
BOOST_ASSERT_MSG(0<=dir && dir<=2, "loaded bogus direction");
bool forward = true;
bool backward = true;
@ -144,7 +145,9 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &in, std::vector<EdgeT>& edgeL
continue;
}
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) {
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();
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");
return n;
}
@ -299,7 +302,7 @@ NodeID readDTMPGraphFromStream(std::istream &in, std::vector<EdgeT>& edgeList, s
edgeList.push_back(inputEdge);
}
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;
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.
*/
#ifndef 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 <string>
#include <boost/filesystem/convenience.hpp>
template<typename T>
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.
*/
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include <luabind/luabind.hpp>
#include "Algorithms/IteratorBasedCRC32.h"
#include "Contractor/Contractor.h"
#include "Contractor/EdgeBasedGraphFactory.h"
#include "DataStructures/BinaryHeap.h"
#include "DataStructures/DeallocatingVector.h"
#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 <luabind/luabind.hpp>
#include <fstream>
#include <istream>
#include <iostream>
@ -34,21 +45,6 @@ extern "C" {
#include <string>
#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 DynamicGraph<EdgeData>::InputEdge InputEdge;
typedef StaticGraph<EdgeData>::InputEdge StaticEdge;
@ -61,6 +57,7 @@ std::vector<NodeID> trafficLightNodes;
std::vector<ImportEdge> edgeList;
int main (int argc, char *argv[]) {
try {
if(argc < 3) {
ERR("usage: " << std::endl << argv[0] << " <osrm-data> <osrm-restrictions> [<profile>]");
}
@ -96,8 +93,8 @@ int main (int argc, char *argv[]) {
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";
std::string rtree_nodes_path(argv[1]); rtree_nodes_path += ".ramIndex";
std::string rtree_leafs_path(argv[1]); rtree_leafs_path += ".fileIndex";
/*** Setup Scripting Environment ***/
if(!testDataFile( (argc > 3 ? argv[3] : "profile.lua") )) {
@ -158,7 +155,7 @@ int main (int argc, char *argv[]) {
NodeID edgeBasedNodeNumber = edgeBasedGraphFactory->GetNumberOfNodes();
DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
edgeBasedGraphFactory->GetEdgeBasedEdges(edgeBasedEdgeList);
DeallocatingVector<EdgeBasedGraphFactory::EdgeBasedNode> nodeBasedEdgeList;
std::vector<EdgeBasedGraphFactory::EdgeBasedNode> nodeBasedEdgeList;
edgeBasedGraphFactory->GetEdgeBasedNodes(nodeBasedEdgeList);
delete edgeBasedGraphFactory;
@ -178,11 +175,15 @@ int main (int argc, char *argv[]) {
* 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;
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);
@ -209,7 +210,7 @@ int main (int argc, char *argv[]) {
std::sort(contractedEdgeList.begin(), contractedEdgeList.end());
unsigned numberOfNodes = 0;
unsigned numberOfEdges = contractedEdgeList.size();
INFO("Serializing compacted graph");
INFO("Serializing compacted graph of " << numberOfEdges << " edges");
std::ofstream edgeOutFile(graphOut.c_str(), std::ios::binary);
BOOST_FOREACH(const QueryEdge & edge, contractedEdgeList) {
@ -268,5 +269,8 @@ int main (int argc, char *argv[]) {
//cleanedEdgeList.clear();
_nodes.clear();
INFO("finished preprocessing");
} catch (std::exception &e) {
ERR("Exception occured: " << e.what());
}
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.
*/
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include "typedefs.h"
#include "Extractor/ExtractorCallbacks.h"
#include "Extractor/ExtractionContainers.h"
#include "Extractor/ScriptingEnvironment.h"
@ -34,6 +28,13 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "Util/MachineInfo.h"
#include "Util/OpenMPWrapper.h"
#include "Util/StringUtil.h"
#include "typedefs.h"
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
typedef BaseConfiguration ExtractorConfiguration;

View File

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

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

@ -18,6 +18,7 @@ Feature: Bike - Street names in instructions
| from | to | route |
| a | c | My Way,Your Way |
@unnamed
Scenario: Bike - Use way type to describe unnamed ways
Given the node map
| a | b | c | d |
@ -29,4 +30,20 @@ Feature: Bike - Street names in instructions
When I route I should get
| 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 | | no | 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
| junction | forw | backw |
| 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
| from | to | route | time |
| a | b | ab | 144s ~10% |
| b | c | bc | 63s ~10% |
| b | c | bc | 42s ~10% |
Scenario: Car - Forward/backward maxspeed
Given the shortcuts

View File

@ -57,3 +57,17 @@ Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tag
| primary | roundabout | | yes | x | |
| primary | roundabout | | no | 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

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

View File

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

View File

@ -3,10 +3,10 @@ When /^I request nearest I should get$/ do |table|
actual = []
OSRMLauncher.new do
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
out_node = @name_node_hash[ row['out'] ]
out_node = find_node_by_name row['out']
raise "*** unknown out-node '#{row['out']}" unless out_node
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
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
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
ok
end

View File

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

View File

@ -3,11 +3,41 @@ When /^I route I should get$/ do |table|
actual = []
OSRMLauncher.new do
table.hashes.each_with_index do |row,ri|
from_node = @name_node_hash[ row['from'] ]
raise "*** unknown from-node '#{row['from']}" unless from_node
to_node = @name_node_hash[ row['to'] ]
raise "*** unknown to-node '#{row['to']}" unless to_node
response = request_route("#{from_node.lat},#{from_node.lon}", "#{to_node.lat},#{to_node.lon}")
waypoints = []
if row['from'] and row['to']
node = find_node_by_name(row['from'])
raise "*** unknown from-node '#{row['from']}" unless node
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
json = JSON.parse response.body
if json['status'] == 0
@ -15,10 +45,10 @@ When /^I route I should get$/ do |table|
bearings = bearing_list json['route_instructions']
compasses = compass_list json['route_instructions']
turns = turn_list json['route_instructions']
modes = mode_list json['route_instructions']
end
end
got = {'from' => row['from'], 'to' => row['to'] }
if table.headers.include? 'start'
got['start'] = instructions ? json['route_summary']['start_point'] : nil
end
@ -46,6 +76,9 @@ When /^I route I should get$/ do |table|
if table.headers.include? 'turns'
got['turns'] = turns
end
if table.headers.include? 'modes'
got['modes'] = modes
end
if table.headers.include? '#' # comment column
got['#'] = row['#'] # copy value so it always match
end

View File

@ -14,9 +14,19 @@ DEFAULT_SPEEDPROFILE = 'bicycle'
WAY_SPACING = 100
DEFAULT_GRID_SIZE = 100 #meters
PROFILES_PATH = '../profiles'
BIN_PATH = '../build'
ORIGIN = [1,1]
class Location
attr_accessor :lon,:lat
def initialize lon,lat
@lat = lat
@lon = lon
end
end
def sanitized_scenario_title
@sanitized_scenario_title ||= @scenario_title.gsub /[^0-9A-Za-z.\-]/, '_'
end
@ -32,10 +42,10 @@ def build_ways_from_table table
#add one unconnected way for each row
table.hashes.each_with_index do |row,ri|
#NOTE:
#currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4
#this is relatated to the fact that a oneway deadend doesn't make a lot of sense
#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 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.
#a few nodes...
@ -110,8 +120,30 @@ def build_ways_from_table table
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
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
def find_way_by_name s
@ -135,6 +167,7 @@ end
def reset_osm
osm_db.clear
name_node_hash.clear
location_hash.clear
name_way_hash.clear
@osm_str = nil
@osm_hash = nil
@ -157,6 +190,10 @@ def name_node_hash
@name_node_hash ||= {}
end
def location_hash
@location_hash ||= {}
end
def name_way_hash
@name_way_hash ||= {}
end
@ -213,7 +250,7 @@ def reprocess
unless extracted?
log_preprocess_info
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
raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}."
end
@ -222,7 +259,7 @@ def reprocess
unless prepared?
log_preprocess_info
log "== Preparing #{@osm_file}.osm...", :preprocess
unless system "../osrm-prepare #{@osm_file}.osrm #{@osm_file}.osrm.restrictions 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE} #{PROFILES_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
raise PrepareError.new $?.exitstatus, "osrm-prepare exited with code #{$?.exitstatus}."
end

View File

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

View File

@ -29,15 +29,15 @@ def lua_lib_hash
end
def bin_extract_hash
@@bin_extract_hash ||= hash_of_files '../osrm-extract'
@@bin_extract_hash ||= hash_of_files "#{BIN_PATH}/osrm-extract"
end
def bin_prepare_hash
@@bin_prepare_hash ||= hash_of_files '../osrm-prepare'
@@bin_prepare_hash ||= hash_of_files "#{BIN_PATH}/osrm-prepare"
end
def bin_routed_hash
@@bin_routed_hash ||= hash_of_files '../osrm-routed'
@@bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed"
end
#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
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
def osrm_down

View File

@ -4,10 +4,19 @@ HOST = "http://localhost:#{OSRM_PORT}"
REQUEST_TIMEOUT = 1
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
@query = path
uri = URI.parse "#{HOST}/#{path}"
def request_path path, waypoints=[], options={}
locs = waypoints.compact.map { |w| "loc=#{w.lat},#{w.lon}" }
params = (locs + options.to_param).join('&')
params = nil if params==""
uri = URI.parse ["#{HOST}/#{path}", params].compact.join('?')
Timeout.timeout(REQUEST_TIMEOUT) do
Net::HTTP.get_response uri
end
@ -17,8 +26,9 @@ rescue Timeout::Error
raise "*** osrm-routed did not respond."
end
def request_route a,b
request_path "viaroute?loc=#{a}&loc=#{b}&output=json&instructions=true&alt=true"
def request_route waypoints, params={}
defaults = { 'output' => 'json', 'instructions' => true, 'alt' => false }
request_path "viaroute", waypoints, defaults.merge(params)
end
def parse_response response
@ -108,9 +118,18 @@ def turn_list instructions
12 => :leave_roundabout,
13 => :stay_roundabout,
14 => :start_end_of_street,
15 => :destination
15 => :destination,
16 => :enter_contraflow,
17 => :leave_contraflow
}
instructions.
map { |r| types[r[0].to_i].to_s }.
join(',')
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
Given the node map
| a | b | c |
| a | b | c | d | e |
Given the ways
| nodes | oneway |
| ab | yes |
| cb | yes |
| abcde | yes |
When I route I should get
| from | to | route |
| a | b | ab |
| b | d | abcde |
@todo
Scenario: Start/end point at the same location
Given the node map
| a | b |
@ -58,27 +58,29 @@ Feature: Handle bad data in a graceful manner
| k | -78 | 0 |
| l | -80 | 0 |
| m | -82 | 0 |
| n | -87 | 0 |
| o | -89 | 0 |
# | n | -87 | 0 |
# | o | -89 | 0 |
And the ways
| nodes |
| ab |
# | ab |
| bc |
| cd |
| de |
| kl |
| lm |
| mn |
| no |
# | mn |
# | no |
When I route I should get
| from | to | route |
| a | b | |
| b | c | |
| a | d | |
| c | d | cd |
| l | m | lm |
| o | l | |
| n | m | |
| o | n | |
# | a | b | cd |
# | b | c | cd |
# | a | d | cd |
# | c | d | cd |
| d | e | de |
# | k | l | kl |
# | l | m | lm |
# | 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

@ -44,11 +44,8 @@ Testbot uses a signal penalty of 7s.
When I route I should get
| from | to | route | time |
| a | b | abc | 10s +-1 |
| a | c | abc | 27s +-1 |
| d | e | def | 20s +-1 |
| d | f | def | 47s +-1 |
| g | h | ghi | 30s +-1 |
| g | i | ghi | 67s +-1 |
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 |
| a | e | abcde | 61s +-1 |
@todo
Scenario: Signal penalty should not depend on way type
Given the node map
| a | b | c |
@ -114,6 +112,7 @@ Testbot uses a signal penalty of 7s.
| from | to | route | time |
| a | e | abcde | 61s +-1 |
@todo
Scenario: Starting or ending at a traffic signal should not incur a delay
Given the node map
| a | b | c |

View File

@ -98,7 +98,7 @@ Feature: Snap start/end point to the nearest way
| b | x | xb |
| 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 the node map
| p | | | | | | | | | | | i | | | | | | | | | | | j |
@ -144,11 +144,11 @@ Feature: Snap start/end point to the nearest way
| x | 6 | xf |
| x | 7 | xg |
| x | 8 | xh |
| x | i | |
| x | j | |
| x | k | |
| x | l | |
| x | m | |
| x | n | |
| x | o | |
| x | p | |
| x | i | xa |
| x | j | xb |
| x | k | xc |
| x | l | xd |
| x | m | xe |
| x | n | xf |
| x | o | xg |
| 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
}
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
obey_oneway = true
obey_bollards = false
@ -158,14 +176,18 @@ function way_function (way)
local service = way.tags:Find("service")
local area = way.tags:Find("area")
local foot = way.tags:Find("foot")
local surface = way.tags:Find("surface")
-- name
if "" ~= ref then
if "" ~= ref and "" ~= name then
way.name = name .. ' / ' .. ref
elseif "" ~= ref then
way.name = ref
elseif "" ~= name then
way.name = name
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
-- speed
@ -286,6 +308,15 @@ function way_function (way)
way.speed = bicycle_speeds["cycleway"]
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
-- TODO: maxspeed of backward direction
if take_minimum_of_speeds then

View File

@ -90,33 +90,38 @@ end
function way_function (way)
-- First, get the properties of each way that we come across
-- we dont route over areas
local area = way.tags:Find("area")
if ignore_areas and ("yes" == area) then
return 0
end
-- check if oneway tag is unsupported
local oneway = way.tags:Find("oneway")
if "reversible" == oneway then
return 0
end
-- Check if we are allowed to access the way
local access = Access.find_access_tag(way, access_tags_hierachy)
if access_tag_blacklist[access] then
return 0
end
-- 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 = tonumber(way.tags:Find( "maxspeed:forward"))
local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward"))
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 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
@ -176,18 +181,13 @@ function way_function (way)
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
if obey_oneway then
if 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
@ -202,10 +202,10 @@ function way_function (way)
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

View File

@ -23,8 +23,9 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include <iostream>
#include <signal.h>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time.hpp>
#include <boost/thread.hpp>
#include "Server/DataStructures/QueryObjectsStorage.h"
#include "Server/ServerConfiguration.h"
@ -64,7 +65,7 @@ BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
}
#endif
int main (int argc, char * argv[0]) {
int main (int argc, char * argv[]) {
#ifdef __linux__
if(!mlockall(MCL_CURRENT | MCL_FUTURE))
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;
s->Stop();
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;
delete s;
delete objects;

View File

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