From e64e45015aa47bb449d1cf3348c850caa460670e Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Fri, 9 Dec 2011 17:43:50 +0100 Subject: [PATCH 01/17] Minor change: Removing dead code --- DataStructures/SearchEngine.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/DataStructures/SearchEngine.h b/DataStructures/SearchEngine.h index 8331347fd..a1fbcb8bf 100644 --- a/DataStructures/SearchEngine.h +++ b/DataStructures/SearchEngine.h @@ -75,20 +75,6 @@ public: InitializeThreadLocalStorageIfNecessary(); NodeID middle = ( NodeID ) UINT_MAX; -/* bool stOnSameEdge = false; - //Handling the special case that origin and destination are on same edge and that the order is correct. - if(phantomNodes.PhantomsAreOnSameNodeBasedEdge()){ - if(phantomNodes.startPhantom.isBidirected() && phantomNodes.targetPhantom.isBidirected()) { - int weight = std::abs(phantomNodes.startPhantom.weight1 - phantomNodes.targetPhantom.weight1); - return weight; - } else if(phantomNodes.startPhantom.weight1 <= phantomNodes.targetPhantom.weight1){ - int weight = std::abs(phantomNodes.startPhantom.weight1 - phantomNodes.targetPhantom.weight1); - return weight; - } else { - stOnSameEdge = true; - } - } -*/ //insert start and/or target node of start edge _forwardHeap->Insert(phantomNodes.startPhantom.edgeBasedNode, -phantomNodes.startPhantom.weight1, phantomNodes.startPhantom.edgeBasedNode); // INFO("a) forw insert " << phantomNodes.startPhantom.edgeBasedNode << ", weight: " << -phantomNodes.startPhantom.weight1); From 435efc9886a39aab2c22f483877d5dc71b9265ef Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 12:29:03 +0100 Subject: [PATCH 02/17] speedprofile.ini has new options --- speedprofile.ini | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/speedprofile.ini b/speedprofile.ini index 16f543119..a27aace43 100644 --- a/speedprofile.ini +++ b/speedprofile.ini @@ -1,6 +1,6 @@ [car] - motorway = 110 - motorway_link = 90 + motorway = 110 + motorway_link = 90 trunk = 90 trunk_link = 70 primary = 70 @@ -13,12 +13,13 @@ living_street = 10 service = 30 ferry = 5 - pier = 5 - barrier = bollard - obeyOneways = yes + pier = 5 + barrier = bollard + obeyOneways = yes useRestrictions = yes - accessTag = motorcar - + accessTag = motorcar + excludeFromGrid = ferry + defaultSpeed = 50 [bike] trunk = 16 trunk_link = 16 @@ -31,11 +32,13 @@ residential = 16 living_street = 16 service = 16 - track = 16 - cycleway = 16 - path = 16 - ferry = 5 - pier = 5 - obeyOneways = yes + track = 16 + cycleway = 16 + path = 16 + ferry = 5 + pier = 5 + obeyOneways = yes useRestrictions = no - accessTag = bicycle + accessTag = bicycle + excludeFromGrid = ferry + defaultSpeed = 5 From aa0ce0fb88307565d229c46f576fc08de5c7a771 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 13:49:38 +0100 Subject: [PATCH 03/17] Removed dead code --- DataStructures/NodeInformationHelpDesk.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/DataStructures/NodeInformationHelpDesk.h b/DataStructures/NodeInformationHelpDesk.h index a568c3670..f49dbec8f 100644 --- a/DataStructures/NodeInformationHelpDesk.h +++ b/DataStructures/NodeInformationHelpDesk.h @@ -73,10 +73,6 @@ public: return true; } - inline bool GetStartAndDestNodesOfEdge(const _Coordinate& coord, NodesOfEdge& nodesOfEdge) { - return readOnlyGrid->GetEdgeBasedStartNode(coord, nodesOfEdge); - } - inline void FindNearestPointOnEdge(const _Coordinate & input, _Coordinate& output){ readOnlyGrid->FindNearestPointOnEdge(input, output); } From e8699d4337a084cf35087a027855b79d17c80b0c Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 14:02:33 +0100 Subject: [PATCH 04/17] Removed dead code; streamlined IOs; #ifdef'ed debug code; replace google sparsehash by boost::unordered_map --- DataStructures/NNGrid.h | 113 ++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 73 deletions(-) diff --git a/DataStructures/NNGrid.h b/DataStructures/NNGrid.h index 04169cf6a..7191cbbb7 100644 --- a/DataStructures/NNGrid.h +++ b/DataStructures/NNGrid.h @@ -35,7 +35,7 @@ or see http://www.gnu.org/licenses/agpl.txt. #include #include -#include +#include #include "ExtractorStructs.h" #include "GridEdge.h" @@ -179,21 +179,15 @@ public: void OpenIndexFiles() { assert(ramInFile.is_open()); - - for(int i = 0; i < 1024*1024; ++i) { - unsigned temp; - ramInFile.read((char*)&temp, sizeof(unsigned)); - ramIndexTable[i] = temp; - } + ramInFile.read((char*)&ramIndexTable[0], sizeof(unsigned)*1024*1024); ramInFile.close(); } template void ConstructGrid(std::vector & edgeList, vector * int2ExtNodeMap, char * ramIndexOut, char * fileIndexOut) { Percent p(edgeList.size()); - for(NodeID i = 0; i < edgeList.size(); ++i) { + BOOST_FOREACH(EdgeT & edge, edgeList) { p.printIncrement(); - EdgeT & edge = edgeList[i]; int slat = 100000*lat2y(edge.lat1/100000.); int slon = edge.lon1; @@ -215,7 +209,9 @@ public: std::vector entriesInFileWithRAMSameIndex; unsigned indexInRamTable = entries->begin()->ramIndex; unsigned lastPositionInIndexFile = 0; +#ifndef NDEBUG unsigned numberOfUsedCells = 0; +#endif unsigned maxNumberOfRAMCellElements = 0; cout << "writing data ..." << flush; p.reinit(entries->size()); @@ -230,65 +226,40 @@ public: lastPositionInIndexFile += numberOfBytesInCell; entriesInFileWithRAMSameIndex.clear(); indexInRamTable = vt->ramIndex; +#ifndef NDEBUG numberOfUsedCells++; +#endif } entriesInFileWithRAMSameIndex.push_back(*vt); } /*unsigned numberOfBytesInCell = */FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile); ramIndexTable[indexInRamTable] = lastPositionInIndexFile; +#ifndef NDEBUG numberOfUsedCells++; +#endif entriesInFileWithRAMSameIndex.clear(); - + std::vector().swap(entriesInFileWithRAMSameIndex); assert(entriesInFileWithRAMSameIndex.size() == 0); + //close index file + indexOutFile.close(); + +#ifndef NDEBUG for(int i = 0; i < 1024*1024; ++i) { if(ramIndexTable[i] != UINT_MAX) { numberOfUsedCells--; } } assert(numberOfUsedCells == 0); - - //close index file - indexOutFile.close(); +#endif //Serialize RAM Index ofstream ramFile(ramIndexOut, std::ios::out | std::ios::binary | std::ios::trunc); //write 4 MB of index Table in RAM - for(int i = 0; i < 1024*1024; ++i) - ramFile.write((char *)&ramIndexTable[i], sizeof(unsigned) ); + ramFile.write((char *)&ramIndexTable[0], sizeof(unsigned)*1024*1024 ); //close ram index file ramFile.close(); } - bool GetEdgeBasedStartNode(const _Coordinate& coord, NodesOfEdge& nodesOfEdge) { - _Coordinate startCoord(100000*(lat2y(static_cast(coord.lat)/100000.)), coord.lon); - /** search for point on edge next to source */ - unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon); - std::vector<_GridEdge> candidates; - - for(int j = -32768; j < (32768+1); j+=32768) { - for(int i = -1; i < 2; i++){ - GetContentsOfFileBucket(fileIndex+i+j, candidates); - } - } - _Coordinate tmp; - double dist = numeric_limits::max(); - BOOST_FOREACH(_GridEdge candidate, candidates) { - double r = 0.; - double tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r); - if(tmpDist < dist) { - nodesOfEdge.edgeBasedNode = candidate.edgeBasedNode; - nodesOfEdge.ratio = r; - dist = tmpDist; - nodesOfEdge.projectedPoint.lat = round(100000*(y2lat(static_cast(tmp.lat)/100000.))); - nodesOfEdge.projectedPoint.lon = tmp.lon; - } - } - if(dist != (numeric_limits::max)()) { - return true; - } - return false; - } - bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode) { bool foundNode = false; _Coordinate startCoord(100000*(lat2y(static_cast(location.lat)/100000.)), location.lon); @@ -308,24 +279,23 @@ public: BOOST_FOREACH(_GridEdge candidate, candidates) { double r = 0.; double tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r); - if(DoubleEpsilonCompare(dist, tmpDist) && 1 == std::abs((int)candidate.edgeBasedNode-(int)resultNode.edgeBasedNode)) { - resultNode.weight2 = candidate.weight; -// INFO("b) " << candidate.edgeBasedNode << ", dist: " << tmpDist); - } if(tmpDist < dist && !DoubleEpsilonCompare(dist, tmpDist)) { -// INFO("a) " << candidate.edgeBasedNode << ", dist: " << tmpDist); - resultNode.Reset(); - resultNode.edgeBasedNode = candidate.edgeBasedNode; - resultNode.nodeBasedEdgeNameID = candidate.nameID; - resultNode.weight1 = candidate.weight; - dist = tmpDist; - resultNode.location.lat = round(100000*(y2lat(static_cast(tmp.lat)/100000.))); - resultNode.location.lon = tmp.lon; - foundNode = true; - smallestEdge = candidate; - newEndpoint = tmp; -// } else if(tmpDist < dist) { -// INFO("a) ignored " << candidate.edgeBasedNode << " at distance " << std::fabs(dist - tmpDist)); + //INFO("a) " << candidate.edgeBasedNode << ", dist: " << tmpDist); + resultNode.Reset(); + resultNode.edgeBasedNode = candidate.edgeBasedNode; + resultNode.nodeBasedEdgeNameID = candidate.nameID; + resultNode.weight1 = candidate.weight; + dist = tmpDist; + resultNode.location.lat = round(100000*(y2lat(static_cast(tmp.lat)/100000.))); + resultNode.location.lon = tmp.lon; + foundNode = true; + smallestEdge = candidate; + newEndpoint = tmp; + //} else if(tmpDist < dist) { + //INFO("a) ignored " << candidate.edgeBasedNode << " at distance " << std::fabs(dist - tmpDist)); + } else if(DoubleEpsilonCompare(dist, tmpDist) && 1 == std::abs((int)candidate.edgeBasedNode-(int)resultNode.edgeBasedNode)) { + resultNode.weight2 = candidate.weight; + //INFO("b) " << candidate.edgeBasedNode << ", dist: " << tmpDist); } } @@ -421,8 +391,7 @@ private: vector cellIndex; cellIndex.resize(32*32,UINT_MAX); - google::dense_hash_map< unsigned, unsigned > * cellMap = new google::dense_hash_map< unsigned, unsigned >(1024); - cellMap->set_empty_key(UINT_MAX); + boost::unordered_map< unsigned, unsigned > cellMap(1024); unsigned ramIndex = entriesWithSameRAMIndex.begin()->ramIndex; unsigned lineBase = ramIndex/1024; @@ -434,7 +403,7 @@ private: for(int j = 0; j < 32; j++) { unsigned fileIndex = lineBase + i*32768 + columnBase+j; unsigned cellIndex = i*32+j; - cellMap->insert(std::make_pair(fileIndex, cellIndex)); + cellMap.insert(std::make_pair(fileIndex, cellIndex)); } } @@ -451,13 +420,13 @@ private: unsigned fileIndex = entriesWithSameRAMIndex.begin()->fileIndex; for(std::vector::iterator it = entriesWithSameRAMIndex.begin(); it != uniqueEnd; it++) { - assert(cellMap->find(it->fileIndex) != cellMap->end() ); //asserting that file index belongs to cell index + assert(cellMap.find(it->fileIndex) != cellMap.end() ); //asserting that file index belongs to cell index if(it->fileIndex != fileIndex) { // start in cellIndex vermerken int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex; - int localCellIndex = cellMap->find(localFileIndex)->second; + int localCellIndex = cellMap.find(localFileIndex)->second; /*int localRamIndex = */GetRAMIndexFromFileIndex(localFileIndex); - assert(cellMap->find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap->end()); + assert(cellMap.find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap.end()); cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset; indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer); @@ -466,9 +435,9 @@ private: entriesWithSameFileIndex.push_back(data); fileIndex = it->fileIndex; } - assert(cellMap->find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap->end()); + assert(cellMap.find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap.end()); int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex; - int localCellIndex = cellMap->find(localFileIndex)->second; + int localCellIndex = cellMap.find(localFileIndex)->second; /*int localRamIndex = */GetRAMIndexFromFileIndex(localFileIndex); cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset; @@ -488,7 +457,6 @@ private: } delete tmpBuffer; - delete cellMap; return numberOfWrittenBytes; } @@ -530,8 +498,7 @@ private: std::vector cellIndex; cellIndex.resize(32*32); - google::dense_hash_map< unsigned, unsigned > cellMap(1024); - cellMap.set_empty_key(UINT_MAX); + boost::unordered_map< unsigned, unsigned > cellMap(1024); unsigned lineBase = ramIndex/1024; lineBase = lineBase*32*32768; From d07994bd734b373c40706a21663fe1c664aaac46 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 14:09:40 +0100 Subject: [PATCH 05/17] Replaced google sparsehash by boost unordered map --- DataStructures/BinaryHeap.h | 37 ++++--------------------------------- DataStructures/LRUCache.h | 9 ++++----- 2 files changed, 8 insertions(+), 38 deletions(-) diff --git a/DataStructures/BinaryHeap.h b/DataStructures/BinaryHeap.h index 00304f23a..c332eadc8 100644 --- a/DataStructures/BinaryHeap.h +++ b/DataStructures/BinaryHeap.h @@ -28,9 +28,7 @@ or see http://www.gnu.org/licenses/agpl.txt. #include #include #include -#include -#include -#include +#include template< typename NodeID, typename Key > class ArrayStorage { @@ -74,10 +72,10 @@ private: }; template< typename NodeID, typename Key > -class DenseStorage { +class UnorderedMapStorage { public: - DenseStorage( size_t size = 0 ) { nodes.set_empty_key(UINT_MAX); } + UnorderedMapStorage( size_t size = 0 ) { } Key &operator[]( NodeID node ) { return nodes[node]; @@ -88,34 +86,7 @@ public: } private: - google::dense_hash_map< NodeID, Key > nodes; -}; - -template< typename NodeID, typename Key > -class SparseStorage { -public: - - SparseStorage( size_t size = 0 ) { } - - Key &operator[]( NodeID node ) { - return nodes[node]; - } - - void Clear() { - nodes.clear(); - } - -private: - google::sparse_hash_map< NodeID, Key > nodes; -}; - -template< typename NodeID, typename Key > -class SparseTableStorage : public google::sparsetable { -public: - SparseTableStorage(size_t n) : google::sparsetable(n){ } - void Clear() { - google::sparsetable::clear(); - } + boost::unordered_map< NodeID, Key > nodes; }; template diff --git a/DataStructures/LRUCache.h b/DataStructures/LRUCache.h index c3b65d5e4..2bee8dd21 100644 --- a/DataStructures/LRUCache.h +++ b/DataStructures/LRUCache.h @@ -1,9 +1,10 @@ #include -#include #include #include #include +#include + template < class T > struct Countfn { unsigned long operator()( const T &x ) { return 1; } @@ -17,7 +18,7 @@ public: typedef std::vector< Key > Key_List; ///< List of keys typedef typename Key_List::iterator Key_List_Iter; ///< Main cache iterator typedef typename Key_List::const_iterator Key_List_cIter; ///< Main cache iterator (const) - typedef google::sparse_hash_map< Key, List_Iter > Map; ///< Index typedef + typedef boost::unordered_map< Key, List_Iter > Map; ///< Index typedef typedef std::pair< Key, List_Iter > Pair; ///< Pair of Map elements typedef typename Map::iterator Map_Iter; ///< Index iterator typedef typename Map::const_iterator Map_cIter; ///< Index iterator (const) @@ -29,9 +30,7 @@ private: unsigned long _curr_size; ///< Current abstract size of the cache public: - LRUCache( const unsigned long Size ) : _max_size( Size ), _curr_size( 0 ) { - _index.set_deleted_key(UINT_MAX); - } + LRUCache( const unsigned long Size ) : _max_size( Size ), _curr_size( 0 ) { } ~LRUCache() { clear(); } From 0906a0fe1cde4881e625a0ac44aed3d7cfa215e0 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 14:10:55 +0100 Subject: [PATCH 06/17] Web page is available at https://github.com/DennisOSRM/dennisosrm.github.com, so no need to store it twice --- Docs/Webpage/index.php | 11 - Docs/Webpage/main.html | 158 ---------- Docs/Webpage/osrm.css | 582 ----------------------------------- Docs/Webpage/osrm3.png | Bin 46921 -> 0 bytes Docs/Webpage/osrm3_small.png | Bin 10483 -> 0 bytes 5 files changed, 751 deletions(-) delete mode 100644 Docs/Webpage/index.php delete mode 100644 Docs/Webpage/main.html delete mode 100644 Docs/Webpage/osrm.css delete mode 100644 Docs/Webpage/osrm3.png delete mode 100644 Docs/Webpage/osrm3_small.png diff --git a/Docs/Webpage/index.php b/Docs/Webpage/index.php deleted file mode 100644 index ffa308f4a..000000000 --- a/Docs/Webpage/index.php +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/Docs/Webpage/main.html b/Docs/Webpage/main.html deleted file mode 100644 index 7afe1574e..000000000 --- a/Docs/Webpage/main.html +++ /dev/null @@ -1,158 +0,0 @@ - - - Open Source Routing Machine - - - - - -Logo -

The Open Source Routing Machine (OSRM) is a C++ implementation of a high-performance routing engine for shortest paths in road networks. -It combines sophisticated routing algorithms with the open and free road network data of the OpenStreetMap (OSM) project. -Shortest path computation on a continental sized network can take up to several seconds if it is done without a so-called speedup-technique. -OSRM is able to compute and output a shortest path between any origin and destination within a few miliseconds. -Since it is designed with OpenStreetMap compatibility in mind, OSM data files can be easily imported. -A demo installation is provided by our friends at Geofabrik. OSRM is under active development. -

- -

The key features of OSRM are: -

- -
    - -
  • High Performance Routing Algorithm
  • -
  • Easy import of OSM data files.
  • -
  • Written entirely in C++ and available under the GNU Affero General Public License for anyone to use.
  • -
  • Ability to handle continental sized networks.
  • -
  • Influenced by current and ongoing academic research. [more info] -
  • -
- - -
    -
  • General Instructions [html] -
  • -
  • Readme [html]
  • -
-
- -

Support

- -

Questions concerning use and development of the OSRM should be posted to the Help Forum.

- -

Bugs should be reported by filing a ticket in the Bug Tracker -

- -

License

- -

OSRM is free, open source, and available under the GNU Affero General Public License. -Companies with concerns about the AGPL should contact us to work something out.

- -

Platforms supported

- - - - - - - - - - - - - - - -
Operating Systems Compilers Third Party dependencies
- Linux (kernel >= 2.6.25)
- Mac OS X
- FreeBSD -
- g++ 4.2.3 (with warnings and unsupported)
- g++ 4.3+
- llvm-g++/dragonegg 2.8+
- Boost 1.37+
- sparsehash 1.4+
- libxml2 2.7+
- scons 1.20+
- stxxl 1.3.1+
- libprotobuf 2.30+ -
- -

Current version

- -

Version 0.1 (July 10, 2010) is a baseline release. It has basic features. Version 0.2 (March 2011) is much faster and resource friendly. While it is safe to use this version, the code in svn trunk is much more advanced.

- -

Major improvements in version 0.2

- - - - - - - - -
- -
    - -
  • Improved memory consumption
  • -
  • Much faster I/O thanks to binary intermediate data files
  • -
  • Origin and Destination can be on arbitrary points of any street segment
  • -
  • Support for PBF and BZ2 compressed OSM files
  • -
  • Support for http 1.1 gzip/deflate compression
  • -
  • Server can be bound to any IP/Port in the system
  • -
  • many, many bug fixes
  • -
  • many under-the-hood improvements
  • -
  • For a detailed list, please read the Timeline.
  • -
-
- - -
-

Links/Download

- - - - - - - - - - - - - - - - - - - - - - - -
- Current Stable Version Previous Stable Version Development Version (subversion)
- - Download: [sf.net page] - - [0.2] -tar.bz2/.gz (sf.net) [0.1] -tar.gz (sf.net) subversion checkout
- Subversion repository: - [see above] - [Browse] [Checkout] - [Browse] -[Checkout] -
- - \ No newline at end of file diff --git a/Docs/Webpage/osrm.css b/Docs/Webpage/osrm.css deleted file mode 100644 index 145d38cd5..000000000 --- a/Docs/Webpage/osrm.css +++ /dev/null @@ -1,582 +0,0 @@ -h2 { - padding: 3px; - background: #ffb20F; - color: #FFFFFF; - font-variant: normal; - font-weight: normal; - font-size: medium; - margin: 0px; -} - -body { background: #fff; color: #000; margin: 10px; padding: 0; } -body, th, td { - font: normal 13px Verdana,Arial,'Bitstream Vera Sans',Helvetica,sans-serif; -} -h1, h2, h3, h4 { - font-family: Arial,Verdana,'Bitstream Vera Sans',Helvetica,sans-serif; - font-weight: bold; - letter-spacing: -0.018em; - page-break-after: avoid; -} -h1 { font-size: 19px; margin: .15em 1em 0.5em 0 } -h2 { font-size: 16px } -h3 { font-size: 14px } -hr { border: none; border-top: 1px solid #ccb; margin: 2em 0 } -address { font-style: normal } -img { border: none } - -.underline { text-decoration: underline } -ol.loweralpha { list-style-type: lower-alpha } -ol.upperalpha { list-style-type: upper-alpha } -ol.lowerroman { list-style-type: lower-roman } -ol.upperroman { list-style-type: upper-roman } -ol.arabic { list-style-type: decimal } - -/* Link styles */ -:link, :visited { - text-decoration: none; - color: #b00; - border-bottom: 1px dotted #bbb; -} -:link:hover, :visited:hover { background-color: #eee; color: #555 } -h1 :link, h1 :visited ,h2 :link, h2 :visited, h3 :link, h3 :visited, -h4 :link, h4 :visited, h5 :link, h5 :visited, h6 :link, h6 :visited { - color: inherit; -} - -/* Heading anchors */ -.anchor:link, .anchor:visited { - border: none; - color: #d7d7d7; - font-size: .8em; - vertical-align: text-top; -} -* > .anchor:link, * > .anchor:visited { - visibility: hidden; -} -h1:hover .anchor, h2:hover .anchor, h3:hover .anchor, -h4:hover .anchor, h5:hover .anchor, h6:hover .anchor { - visibility: visible; -} - -@media screen { - a.ext-link .icon { - background: url(../extlink.gif) left center no-repeat; - padding-left: 16px; - } - a.mail-link .icon { - background: url(../envelope.png) left center no-repeat; - padding-left: 16px; - } -} - -/* Forms */ -input, textarea, select { margin: 2px } -input, select { vertical-align: middle } -input[type=button], input[type=submit], input[type=reset] { - background: #eee; - color: #222; - border: 1px outset #ccc; - padding: .1em .5em; -} -input[type=button]:hover, input[type=submit]:hover, input[type=reset]:hover { - background: #ccb; -} -input[type=button][disabled], input[type=submit][disabled], -input[type=reset][disabled] { - background: #f6f6f6; - border-style: solid; - color: #999; -} -input[type=text], input.textwidget, textarea { border: 1px solid #d7d7d7 } -input[type=text], input.textwidget { padding: .25em .5em } -input[type=text]:focus, input.textwidget:focus, textarea:focus { - border: 1px solid #886; -} -option { border-bottom: 1px dotted #d7d7d7 } -fieldset { border: 1px solid #d7d7d7; padding: .5em; margin: 1em 0 } -form p.hint, form span.hint { color: #666; font-size: 85%; font-style: italic; margin: .5em 0; - padding-left: 1em; -} -fieldset.iefix { - background: transparent; - border: none; - padding: 0; - margin: 0; -} -* html fieldset.iefix { width: 98% } -fieldset.iefix p { margin: 0 } -legend { color: #999; padding: 0 .25em; font-size: 90%; font-weight: bold } -label.disabled { color: #d7d7d7 } -.buttons { margin: .5em .5em .5em 0 } -.buttons form, .buttons form div { display: inline } -.buttons input { margin: 1em .5em .1em 0 } -.inlinebuttons input { - font-size: 70%; - border-width: 1px; - border-style: dotted; - margin: 0 .1em; - padding: 0.1em; - background: none; -} - -/* Header */ -#header hr { display: none } -#header h1 { margin: 1.5em 0 -1.5em; } -#header img { border: none; margin: 0 0 -3em } -#header :link, #header :visited, #header :link:hover, #header :visited:hover { - background: transparent; - color: #555; - margin-bottom: 2px; - border: none; -} -#header h1 :link:hover, #header h1 :visited:hover { color: #000 } - -/* Quick search */ -#search { - clear: both; - font-size: 10px; - height: 2.2em; - margin: 0 0 1em; - text-align: right; -} -#search input { font-size: 10px } -#search label { display: none } - -/* Navigation */ -.nav h2, .nav hr { display: none } -.nav ul { font-size: 10px; list-style: none; margin: 0; text-align: right } -.nav li { - border-right: 1px solid #d7d7d7; - display: inline; - padding: 0 .75em; - white-space: nowrap; -} -.nav li.last { border-right: none } - -/* Main navigation bar */ -#mainnav { - background: #f7f7f7 url(../topbar_gradient.png) 0 0; - border: 1px solid #000; - font: normal 10px verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif; - margin: .66em 0 .33em; - padding: .2em 0; -} -#mainnav li { border-right: none; padding: .25em 0 } -#mainnav :link, #mainnav :visited { - background: url(../dots.gif) 0 0 no-repeat; - border-right: 1px solid #fff; - border-bottom: none; - border-left: 1px solid #555; - color: #000; - padding: .2em 20px; -} -* html #mainnav :link, * html #mainnav :visited { background-position: 1px 0 } -#mainnav :link:hover, #mainnav :visited:hover { - background-color: #ccc; - border-right: 1px solid #ddd; -} -#mainnav .active :link, #mainnav .active :visited { - background: #333 url(../topbar_gradient2.png) 0 0 repeat-x; - border-top: none; - border-right: 1px solid #000; - color: #eee; - font-weight: bold; -} -#mainnav .active :link:hover, #mainnav .active :visited:hover { - border-right: 1px solid #000; -} - -/* Context-dependent navigation links */ -#ctxtnav { height: 1em } -#ctxtnav li ul { - background: #f7f7f7; - color: #ccc; - border: 1px solid; - padding: 0; - display: inline; - margin: 0; -} -#ctxtnav li li { padding: 0; } -#ctxtnav li li :link, #ctxtnav li li :visited { padding: 0 1em } -#ctxtnav li li :link:hover, #ctxtnav li li :visited:hover { - background: #bba; - color: #fff; -} - -/* Alternate links */ -#altlinks { clear: both; text-align: center } -#altlinks h3 { font-size: 12px; letter-spacing: normal; margin: 0 } -#altlinks ul { list-style: none; margin: 0; padding: 0 0 1em } -#altlinks li { - border-right: 1px solid #d7d7d7; - display: inline; - font-size: 11px; - line-height: 1.5; - padding: 0 1em; - white-space: nowrap; -} -#altlinks li.last { border-right: none } -#altlinks li :link, #altlinks li :visited { - background-repeat: no-repeat; - color: #666; - border: none; - padding: 0 0 2px; -} -#altlinks li a.ics { background-image: url(../ics.png); padding-left: 22px } -#altlinks li a.rss { background-image: url(../feed.png); padding-left: 20px } - -/* Footer */ -#footer { - clear: both; - color: #bbb; - font-size: 10px; - border-top: 1px solid; - height: 31px; - padding: .25em 0; -} -#footer :link, #footer :visited { color: #bbb; } -#footer hr { display: none } -#footer #tracpowered { border: 0; float: left } -#footer #tracpowered:hover { background: transparent } -#footer p { margin: 0 } -#footer p.left { - float: left; - margin-left: 1em; - padding: 0 1em; - border-left: 1px solid #d7d7d7; - border-right: 1px solid #d7d7d7; -} -#footer p.right { - float: right; - text-align: right; -} - -#content { padding-bottom: 2em; position: relative } - -#help { - clear: both; - color: #999; - font-size: 90%; - margin: 1em; - text-align: right; -} -#help :link, #help :visited { cursor: help } -#help hr { display: none } - -/* Page preferences form */ -#prefs { - background: #f7f7f0; - border: 1px outset #998; - float: right; - font-size: 9px; - padding: .8em; - position: relative; - margin: 0 1em 1em; -} -* html #prefs { width: 26em } /* Set width only for IE */ -#prefs input, #prefs select { font-size: 9px; vertical-align: middle } -#prefs fieldset { - background: transparent; - border: none; - margin: .5em; - padding: 0; -} -#prefs fieldset legend { - background: transparent; - color: #000; - font-size: 9px; - font-weight: normal; - margin: 0 0 0 -1.5em; - padding: 0; -} -#prefs .buttons { text-align: right } - -/* Version information (browser, wiki, attachments) */ -#info { - margin: 1em 0 0 0; - background: #f7f7f0; - border: 1px solid #d7d7d7; - border-collapse: collapse; - border-spacing: 0; - clear: both; - width: 100%; -} -#info th, #info td { font-size: 85%; padding: 2px .5em; vertical-align: top } -#info th { font-weight: bold; text-align: left; white-space: nowrap } -#info td.message { width: 100% } -#info .message ul { padding: 0; margin: 0 2em } -#info .message p { margin: 0; padding: 0 } - -/* Wiki */ -.wikipage { padding-left: 18px } -.wikipage h1, .wikipage h2, .wikipage h3 { margin-left: -18px } - -a.missing:link, a.missing:visited, a.missing, span.missing, -a.forbidden, span.forbidden { color: #998 } -a.missing:hover { color: #000 } -a.closed:link, a.closed:visited, span.closed { text-decoration: line-through } - -/* User-selectable styles for blocks */ -.important { - background: #fcb; - border: 1px dotted #d00; - color: #500; - padding: 0 .5em 0 .5em; - margin: .5em; -} - -dl.wiki dt { font-weight: bold } -dl.compact dt { float: left; padding-right: .5em } -dl.compact dd { margin: 0; padding: 0 } - -pre.wiki, pre.literal-block { - background: #f7f7f7; - border: 1px solid #d7d7d7; - margin: 1em 1.75em; - padding: .25em; - overflow: auto; -} - -blockquote.citation { - margin: -0.6em 0; - border-style: solid; - border-width: 0 0 0 2px; - padding-left: .5em; - border-color: #b44; -} -.citation blockquote.citation { border-color: #4b4; } -.citation .citation blockquote.citation { border-color: #44b; } -.citation .citation .citation blockquote.citation { border-color: #c55; } - -table.wiki { - border: 2px solid #ccc; - border-collapse: collapse; - border-spacing: 0; -} -table.wiki td { border: 1px solid #ccc; padding: .1em .25em; } - -.wikitoolbar { - border: solid #d7d7d7; - border-width: 1px 1px 1px 0; - height: 18px; - width: 234px; -} -.wikitoolbar :link, .wikitoolbar :visited { - background: transparent url(../edit_toolbar.png) no-repeat; - border: 1px solid #fff; - border-left-color: #d7d7d7; - cursor: default; - display: block; - float: left; - width: 24px; - height: 16px; -} -.wikitoolbar :link:hover, .wikitoolbar :visited:hover { - background-color: transparent; - border: 1px solid #fb2; -} -.wikitoolbar a#em { background-position: 0 0 } -.wikitoolbar a#strong { background-position: 0 -16px } -.wikitoolbar a#heading { background-position: 0 -32px } -.wikitoolbar a#link { background-position: 0 -48px } -.wikitoolbar a#code { background-position: 0 -64px } -.wikitoolbar a#hr { background-position: 0 -80px } -.wikitoolbar a#np { background-position: 0 -96px } -.wikitoolbar a#br { background-position: 0 -112px } -.wikitoolbar a#img { background-position: 0 -128px } - -/* Styles for the form for adding attachments. */ -#attachment .field { margin-top: 1.3em } -#attachment label { padding-left: .2em } -#attachment fieldset { margin-top: 2em } -#attachment fieldset .field { float: left; margin: 0 1em .5em 0 } -#attachment .options { float: left; padding: 0 0 1em 1em } -#attachment br { clear: left } -.attachment #preview { margin-top: 1em } - -/* Styles for the list of attachments. */ -#attachments { border: 1px outset #996; padding: 1em } -#attachments .attachments { margin-left: 2em; padding: 0 } -#attachments dt { display: list-item; list-style: square; } -#attachments dd { font-style: italic; margin-left: 0; padding-left: 0; } - -/* Styles for tabular listings such as those used for displaying directory - contents and report results. */ -table.listing { - clear: both; - border-bottom: 1px solid #d7d7d7; - border-collapse: collapse; - border-spacing: 0; - margin-top: 1em; - width: 100%; -} -table.listing th { text-align: left; padding: 0 1em .1em 0; font-size: 12px } -table.listing thead { background: #f7f7f0 } -table.listing thead th { - border: 1px solid #d7d7d7; - border-bottom-color: #999; - font-size: 11px; - font-weight: bold; - padding: 2px .5em; - vertical-align: bottom; -} -table.listing thead th :link:hover, table.listing thead th :visited:hover { - background-color: transparent; -} -table.listing thead th a { border: none; padding-right: 12px } -table.listing th.asc a, table.listing th.desc a { font-weight: bold } -table.listing th.asc a, table.listing th.desc a { - background-position: 100% 50%; - background-repeat: no-repeat; -} -table.listing th.asc a { background-image: url(../asc.png) } -table.listing th.desc a { background-image: url(../desc.png) } -table.listing tbody td, table.listing tbody th { - border: 1px dotted #ddd; - padding: .3em .5em; - vertical-align: top; -} -table.listing tbody td a:hover, table.listing tbody th a:hover { - background-color: transparent; -} -table.listing tbody tr { border-top: 1px solid #ddd } -table.listing tbody tr.even { background-color: #fcfcfc } -table.listing tbody tr.odd { background-color: #f7f7f7 } -table.listing tbody tr:hover { background: #eed !important } -table.listing tbody tr.focus { background: #ddf !important } - -/* Styles for the page history table - (extends the styles for "table.listing") */ -#fieldhist td { padding: 0 .5em } -#fieldhist td.date, #fieldhist td.diff, #fieldhist td.version, -#fieldhist td.author { - white-space: nowrap; -} -#fieldhist td.version { text-align: center } -#fieldhist td.comment { width: 100% } - -/* Auto-completion interface */ -.suggestions { background: #fff; border: 1px solid #886; color: #222; } -.suggestions ul { - font-family: sans-serif; - max-height: 20em; - min-height: 3em; - list-style: none; - margin: 0; - overflow: auto; - padding: 0; - width: 440px; -} -* html .suggestions ul { height: 10em; } -.suggestions li { background: #fff; cursor: pointer; padding: 2px 5px } -.suggestions li.selected { background: #b9b9b9 } - -/* Styles for the error page (and rst errors) */ -#content.error .message, div.system-message { - background: #fdc; - border: 2px solid #d00; - color: #500; - padding: .5em; - margin: 1em 0; -} -#content.error div.message pre, div.system-message pre { - margin-left: 1em; - overflow: hidden; - white-space: normal; -} -div.system-message p { margin: 0; } -div.system-message p.system-message-title { font-weight: bold; } - -#warning.system-message { background: #ffa; border: 2px solid #886; } -#warning.system-message li { list-style-type: square; } - -#notice.system-message { background: #bfb; border: 2px solid #484; } -#notice.system-message li { list-style-type: square; } - -#content.error form.newticket { display: inline; } -#content.error form.newticket textarea { display: none; } - -#content.error #systeminfo { margin: 1em; width: auto; } -#content.error #systeminfo th { font-weight: bold; text-align: right; } - -#content.error #traceback { margin-left: 1em; } -#content.error #traceback :link, #content.error #traceback :visited { - border: none; -} -#content.error #tbtoggle { font-size: 80%; } -#content.error #traceback div { margin-left: 1em; } -#content.error #traceback h3 { font-size: 95%; margin: .5em 0 0; } -#content.error #traceback :link var, #content.error #traceback :visited var { - font-family: monospace; - font-style: normal; - font-weight: bold; -} -#content.error #traceback span.file { color: #666; font-size: 85%; } -#content.error #traceback ul { list-style: none; margin: .5em 0; padding: 0; } -#content.error #traceback ol { - border: 1px dotted #d7d7d7; - color: #999; - font-size: 85%; - line-height: 1; - margin: .5em 0; -} -#content.error #traceback ol li { white-space: pre; } -#content.error #traceback ol li.current { background: #e6e6e6; color: #333; } -#content.error #traceback ol li code { color: #666; } -#content.error #traceback ol li.current code { color: #000; } -#content.error #traceback table { margin: .5em 0 1em; } -#content.error #traceback th, #content.error #traceback td { - font-size: 85%; padding: 1px; -} -#content.error #traceback th var { - font-family: monospace; - font-style: normal; -} -#content.error #traceback td code { white-space: pre; } -#content.error #traceback pre { font-size: 95%; } - -#content .paging { margin: 0 0 2em; padding: .5em 0 0; - font-size: 85%; line-height: 2em; text-align: center; -} -#content .paging .current { - padding: .1em .3em; - border: 1px solid #333; - background: #999; color: #fff; -} - -#content .paging :link, #content .paging :visited { - padding: .1em .3em; - border: 1px solid #666; - background: transparent; color: #666; -} -#content .paging :link:hover, #content .paging :visited:hover { - background: #999; color: #fff; border-color: #333; -} -#content .paging .previous a, -#content .paging .next a { - font-size: 150%; font-weight: bold; border: none; -} -#content .paging .previous a:hover, -#content .paging .next a:hover { - background: transparent; color: #666; -} - -#content h2 .numresults { color: #666; font-size: 90%; } - -/* Styles for search word highlighting */ -@media screen { - .searchword0 { background: #ff9 } - .searchword1 { background: #cfc } - .searchword2 { background: #cff } - .searchword3 { background: #ccf } - .searchword4 { background: #fcf } -} - -@media print { - #header, #altlinks, #footer, #help { display: none } - .nav, form, .buttons form, form .buttons, form .inlinebuttons { - display: none; - } - form.printableform { display: block } -} diff --git a/Docs/Webpage/osrm3.png b/Docs/Webpage/osrm3.png deleted file mode 100644 index a4f5c38a424b673800926258eaa206f624fcff6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46921 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/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 From e04ef5a03087ff858ddb1b2a0e296587ca128c71 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 14:12:36 +0100 Subject: [PATCH 07/17] Dropped google sparsehash dependency --- README.TXT | 1 - SConstruct | 3 --- 2 files changed, 4 deletions(-) diff --git a/README.TXT b/README.TXT index e909f5a65..2e09789bb 100644 --- a/README.TXT +++ b/README.TXT @@ -6,7 +6,6 @@ installing dependencies and running make should suffice. Make sure the following dependencies are installed: - Boost 1.41+ - - sparsehash 1.4+ - g++ 4.2+ - libxml2 2.7+ - scons 2.10+ diff --git a/SConstruct b/SConstruct index 0440fa32b..a87733504 100644 --- a/SConstruct +++ b/SConstruct @@ -101,9 +101,6 @@ if not conf.CheckLibWithHeader('z', 'zlib.h', 'CXX'): if not conf.CheckCXXHeader('stxxl.h'): print "Could not locate stxxl header. Exiting" Exit(-1) -if not conf.CheckCXXHeader('google/sparse_hash_map'): - print "Could not find Google Sparsehash library. Exiting" - Exit(-1) if not conf.CheckCXXHeader('boost/asio.hpp'): print "boost/asio.hpp not found. Exiting" Exit(-1) From 82c2e9978f4d72da5ebe30d112870c2f61514571 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 14:16:21 +0100 Subject: [PATCH 08/17] Fixed stopping condition of Dijkstra implementation. --- DataStructures/SearchEngine.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/DataStructures/SearchEngine.h b/DataStructures/SearchEngine.h index a1fbcb8bf..077367a49 100644 --- a/DataStructures/SearchEngine.h +++ b/DataStructures/SearchEngine.h @@ -90,18 +90,18 @@ public: // INFO("d) back insert " << phantomNodes.targetPhantom.edgeBasedNode+1 << ", weight: " << phantomNodes.targetPhantom.weight2); } int startOffset = (phantomNodes.startPhantom.isBidirected() ? std::max(phantomNodes.startPhantom.weight1, phantomNodes.startPhantom.weight2) : phantomNodes.startPhantom.weight1) ; - int targetOffset = 0;//(phantomNodes.targetPhantom.isBidirected() ? std::max(phantomNodes.targetPhantom.weight1, phantomNodes.targetPhantom.weight2) : phantomNodes.targetPhantom.weight1) ; + int targetOffset = (phantomNodes.targetPhantom.isBidirected() ? std::max(phantomNodes.targetPhantom.weight1, phantomNodes.targetPhantom.weight2) : phantomNodes.targetPhantom.weight1) ; while(_forwardHeap->Size() + _backwardHeap->Size() > 0){ if(_forwardHeap->Size() > 0){ - _RoutingStep(_forwardHeap, _backwardHeap, true, &middle, &_upperbound, startOffset); + _RoutingStep(_forwardHeap, _backwardHeap, true, &middle, &_upperbound, startOffset+targetOffset); } if(_backwardHeap->Size() > 0){ - _RoutingStep(_backwardHeap, _forwardHeap, false, &middle, &_upperbound, targetOffset); + _RoutingStep(_backwardHeap, _forwardHeap, false, &middle, &_upperbound, startOffset+targetOffset); } } -// INFO("-> dist " << _upperbound); + INFO("-> dist " << _upperbound); if ( _upperbound == INT_MAX ) { return _upperbound; } @@ -163,16 +163,16 @@ private: const int distance = _forwardHeap->GetKey(node); // INFO((forwardDirection ? "[forw]" : "[back]") << " settled node " << node << " at distance " << distance); if(_backwardHeap->WasInserted(node) ){ -// INFO((forwardDirection ? "[forw]" : "[back]") << " scanned node " << node << " in both directions"); - const int newDistance = _backwardHeap->GetKey(node) + distance; - if(newDistance < *_upperbound ){ - if(newDistance>=0 ) { -// INFO((forwardDirection ? "[forw]" : "[back]") << " settled node " << node << " is new middle at total distance " << newDistance); - *middle = node; - *_upperbound = newDistance; -// } else { -// INFO((forwardDirection ? "[forw]" : "[back]") << " ignored " << node << " as new middle at total distance " << newDistance); - } +// INFO((forwardDirection ? "[forw]" : "[back]") << " scanned node " << node << " in both directions"); + const int newDistance = _backwardHeap->GetKey(node) + distance; + if(newDistance < *_upperbound ){ + if(newDistance>=0 ) { +// INFO((forwardDirection ? "[forw]" : "[back]") << " -> node " << node << " is new middle at total distance " << newDistance); + *middle = node; + *_upperbound = newDistance; + } else { +// INFO((forwardDirection ? "[forw]" : "[back]") << " -> ignored " << node << " as new middle at total distance " << newDistance); + } } } From 6e74ac9bd2e5e456b59ec84779afbbe98c0d8818 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 14:57:59 +0100 Subject: [PATCH 09/17] Removed redundant information --- Docs/3rdparty.txt | 9 --------- README.TXT | 2 -- 2 files changed, 11 deletions(-) delete mode 100644 Docs/3rdparty.txt diff --git a/Docs/3rdparty.txt b/Docs/3rdparty.txt deleted file mode 100644 index 9fe556d1a..000000000 --- a/Docs/3rdparty.txt +++ /dev/null @@ -1,9 +0,0 @@ -Third Party Libraries: - -Scons 1.3+ -Boost 1.37+ -sparsehash 1.4+ -stxxl 1.3.1+ -libz2-dev 1.0.5+ -protobuffer 2.3.0+ -zlib 1.2.3.4+ \ No newline at end of file diff --git a/README.TXT b/README.TXT index 2e09789bb..c51dfec5b 100644 --- a/README.TXT +++ b/README.TXT @@ -51,8 +51,6 @@ lib\ bin (contains protoc.exe) include lib (contains libprotobuf.lib and libprotobuf-debug.lib) - sparsehash - src stxxl include lib (contains libstxxl.lib and libstxxl-debug.lib) From d7f8eafe2d8659731aa0eb181d04626cbd96d5d7 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 14:58:18 +0100 Subject: [PATCH 10/17] Removed google sparsehash --- extractor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/extractor.cpp b/extractor.cpp index 3695e33c5..e34037420 100644 --- a/extractor.cpp +++ b/extractor.cpp @@ -39,7 +39,6 @@ or see http://www.gnu.org/licenses/agpl.txt. #include #include #include -#include #include #include From 79a989e504e97b2d3b23be68e8aabe5f4571cd8a Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 15:13:15 +0100 Subject: [PATCH 11/17] ignored edge type, i.e. ferry connections, can now be excluded from nearest neighbor lookup --- Contractor/EdgeBasedGraphFactory.cpp | 4 ++-- DataStructures/ExtractorStructs.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Contractor/EdgeBasedGraphFactory.cpp b/Contractor/EdgeBasedGraphFactory.cpp index 47b5376a9..66a28abc7 100644 --- a/Contractor/EdgeBasedGraphFactory.cpp +++ b/Contractor/EdgeBasedGraphFactory.cpp @@ -126,7 +126,7 @@ void EdgeBasedGraphFactory::Run() { ++secondRestrictionIterator; } while(u == secondRestrictionIterator->fromNode); } - if(_nodeBasedGraph->EndEdges(v) == _nodeBasedGraph->BeginEdges(v) + 1 && _nodeBasedGraph->GetEdgeData(e1).type != 14 ) { + if(_nodeBasedGraph->EndEdges(v) == _nodeBasedGraph->BeginEdges(v) + 1 && _nodeBasedGraph->GetEdgeData(e1).type != INT_MAX) { EdgeBasedNode currentNode; currentNode.nameID = _nodeBasedGraph->GetEdgeData(e1).nameID; currentNode.lat1 = inputNodeInfoList[u].lat; @@ -186,7 +186,7 @@ void EdgeBasedGraphFactory::Run() { EdgeBasedEdge newEdge(edgeBasedSource, edgeBasedTarget, v, nameID, distance, true, false, turnInstruction); edgeBasedEdges.push_back(newEdge); - if(_nodeBasedGraph->GetEdgeData(e1).type != 14 ) { + if(_nodeBasedGraph->GetEdgeData(e1).type != INT_MAX ) { EdgeBasedNode currentNode; currentNode.nameID = _nodeBasedGraph->GetEdgeData(e1).nameID; diff --git a/DataStructures/ExtractorStructs.h b/DataStructures/ExtractorStructs.h index 5abfd67cd..5da724183 100644 --- a/DataStructures/ExtractorStructs.h +++ b/DataStructures/ExtractorStructs.h @@ -264,6 +264,9 @@ struct Settings { return speedProfile.at(param).first; } int GetHighwayTypeID(const std::string & param) const { + if(param == excludeFromGrid) { + return INT_MAX; + } if(speedProfile.find(param) == speedProfile.end()) { DEBUG("There is a bug with highway \"" << param << "\""); return -1; From 1fb97f00809eed55fd11be44768d33609f15da93 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 16:50:18 +0100 Subject: [PATCH 12/17] Disabling tc --- Contractor/EdgeBasedGraphFactory.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Contractor/EdgeBasedGraphFactory.cpp b/Contractor/EdgeBasedGraphFactory.cpp index 66a28abc7..adcc877d4 100644 --- a/Contractor/EdgeBasedGraphFactory.cpp +++ b/Contractor/EdgeBasedGraphFactory.cpp @@ -176,9 +176,9 @@ void EdgeBasedGraphFactory::Run() { } //incorporate turn costs, this is just a simple model and can (read: must) be extended - double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]); +// double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]); - unsigned distance = (int)( _nodeBasedGraph->GetEdgeData(e1).distance *(1+std::abs((angle-180.)/180.))); + unsigned distance = _nodeBasedGraph->GetEdgeData(e1).distance;//(int)( _nodeBasedGraph->GetEdgeData(e1).distance *(1+std::abs((angle-180.)/180.))); unsigned nameID = _nodeBasedGraph->GetEdgeData(e2).nameID; short turnInstruction = AnalyzeTurn(u, v, w); @@ -195,7 +195,7 @@ void EdgeBasedGraphFactory::Run() { currentNode.lat2 = inputNodeInfoList[v].lat; currentNode.lon2 = inputNodeInfoList[v].lon; currentNode.id = edgeBasedSource; - currentNode.weight = _nodeBasedGraph->GetEdgeData(e1).distance; + currentNode.weight = distance; edgeBasedNodes.push_back(currentNode); } } else { From b08104367e324f893cfc9fbbd2eeda7892ec416a Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 17:12:54 +0100 Subject: [PATCH 13/17] Minor change: Rearranging debug output --- DataStructures/NNGrid.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DataStructures/NNGrid.h b/DataStructures/NNGrid.h index 7191cbbb7..71f2c229f 100644 --- a/DataStructures/NNGrid.h +++ b/DataStructures/NNGrid.h @@ -310,12 +310,12 @@ public: double ratio = std::min(1., LengthOfVector(smallestEdge.startCoord, newEndpoint)/LengthOfVector(smallestEdge.startCoord, smallestEdge.targetCoord) ); assert(ratio >= 0 && ratio <=1); -// INFO("Old weight1: " << resultNode.weight1 << ", old weight2: " << resultNode.weight2); +// INFO("node: " << resultNode.edgeBasedNode << ", orig weight1: " << resultNode.weight1 << ", orig weight2: " << resultNode.weight2); resultNode.weight1 *= ratio; if(INT_MAX != resultNode.weight2) { - resultNode.weight2 *= (1.-ratio); -// INFO("New weight1: " << resultNode.weight1 << ", new weight2: " << resultNode.weight2); + resultNode.weight2 -= resultNode.weight1; } +// INFO("New weight1: " << resultNode.weight1 << ", new weight2: " << resultNode.weight2); // INFO("selected node: " << resultNode.edgeBasedNode << ", bidirected: " << (resultNode.isBidirected() ? "yes" : "no") << "\n--") return foundNode; } From 3a984668d60eb7d045e7249694411e0825ff4392 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 17:34:43 +0100 Subject: [PATCH 14/17] Fixing several of the flickering issues. --- DataStructures/SearchEngine.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/DataStructures/SearchEngine.h b/DataStructures/SearchEngine.h index 077367a49..f1d56771b 100644 --- a/DataStructures/SearchEngine.h +++ b/DataStructures/SearchEngine.h @@ -36,7 +36,7 @@ struct _HeapData { _HeapData( NodeID p ) : parent(p) { } }; -typedef boost::thread_specific_ptr > HeapPtr; +typedef boost::thread_specific_ptr > HeapPtr; template class SearchEngine { @@ -58,12 +58,12 @@ public: inline void InitializeThreadLocalStorageIfNecessary() { if(!_forwardHeap.get()) - _forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData >(nodeHelpDesk->getNumberOfNodes())); + _forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData>(nodeHelpDesk->getNumberOfNodes())); else _forwardHeap->Clear(); if(!_backwardHeap.get()) - _backwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData >(nodeHelpDesk->getNumberOfNodes())); + _backwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData>(nodeHelpDesk->getNumberOfNodes())); else _backwardHeap->Clear(); } @@ -89,19 +89,19 @@ public: _backwardHeap->Insert(phantomNodes.targetPhantom.edgeBasedNode+1, phantomNodes.targetPhantom.weight2, phantomNodes.targetPhantom.edgeBasedNode+1); // INFO("d) back insert " << phantomNodes.targetPhantom.edgeBasedNode+1 << ", weight: " << phantomNodes.targetPhantom.weight2); } - int startOffset = (phantomNodes.startPhantom.isBidirected() ? std::max(phantomNodes.startPhantom.weight1, phantomNodes.startPhantom.weight2) : phantomNodes.startPhantom.weight1) ; - int targetOffset = (phantomNodes.targetPhantom.isBidirected() ? std::max(phantomNodes.targetPhantom.weight1, phantomNodes.targetPhantom.weight2) : phantomNodes.targetPhantom.weight1) ; + int offset = (phantomNodes.startPhantom.isBidirected() ? std::max(phantomNodes.startPhantom.weight1, phantomNodes.startPhantom.weight2) : phantomNodes.startPhantom.weight1) ; + offset += (phantomNodes.targetPhantom.isBidirected() ? std::max(phantomNodes.targetPhantom.weight1, phantomNodes.targetPhantom.weight2) : phantomNodes.targetPhantom.weight1) ; while(_forwardHeap->Size() + _backwardHeap->Size() > 0){ if(_forwardHeap->Size() > 0){ - _RoutingStep(_forwardHeap, _backwardHeap, true, &middle, &_upperbound, startOffset+targetOffset); + _RoutingStep(_forwardHeap, _backwardHeap, true, &middle, &_upperbound, 2*offset); } if(_backwardHeap->Size() > 0){ - _RoutingStep(_backwardHeap, _forwardHeap, false, &middle, &_upperbound, startOffset+targetOffset); + _RoutingStep(_backwardHeap, _forwardHeap, false, &middle, &_upperbound, 2*offset); } } - INFO("-> dist " << _upperbound); +// INFO("-> dist " << _upperbound); if ( _upperbound == INT_MAX ) { return _upperbound; } @@ -158,7 +158,7 @@ public: return GetEscapedNameForNameID(nameID); } private: - inline void _RoutingStep(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const bool & forwardDirection, NodeID *middle, int *_upperbound, const int negativeOffset) const { + inline void _RoutingStep(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const bool & forwardDirection, NodeID *middle, int *_upperbound, const int edgeBasedOffset) const { const NodeID node = _forwardHeap->DeleteMin(); const int distance = _forwardHeap->GetKey(node); // INFO((forwardDirection ? "[forw]" : "[back]") << " settled node " << node << " at distance " << distance); @@ -176,7 +176,7 @@ private: } } - if(distance-negativeOffset > *_upperbound){ + if(distance-edgeBasedOffset > *_upperbound){ _forwardHeap->DeleteAll(); return; } @@ -217,7 +217,7 @@ private: } //Found a shorter Path -> Update distance else if ( toDistance < _forwardHeap->GetKey( to ) ) { -// INFO((forwardDirection ? "[forw]" : "[back]") << " decrease and scanning edge (" << node << "," << to << ") with distance " << toDistance << ", edge length: " << data.distance); +// INFO((forwardDirection ? "[forw]" : "[back]") << " decrease and scanning edge (" << node << "," << to << ") from " << _forwardHeap->GetKey(to) << "to " << toDistance << ", edge length: " << data.distance); _forwardHeap->GetData( to ).parent = node; _forwardHeap->DecreaseKey( to, toDistance ); //new parent From ec3bcb43a8b3dae0395019f3fc1bb59786c8cc53 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 18:26:33 +0100 Subject: [PATCH 15/17] Downsizing memory requirements by better struct packing --- Contractor/ContractionCleanup.h | 22 +++++++++------------- Contractor/Contractor.h | 19 +++++++++---------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/Contractor/ContractionCleanup.h b/Contractor/ContractionCleanup.h index e2b75e1ae..4283bb72c 100644 --- a/Contractor/ContractionCleanup.h +++ b/Contractor/ContractionCleanup.h @@ -40,11 +40,8 @@ private: parent = p; } }; -#ifdef _MANYCORES - typedef BinaryHeap< NodeID, NodeID, int, _HeapData, DenseStorage > _Heap; -#else typedef BinaryHeap< NodeID, NodeID, int, _CleanupHeapData > _Heap; -#endif + struct _ThreadData { _Heap* _heapForward; _Heap* _heapBackward; @@ -52,8 +49,7 @@ private: _heapBackward = new _Heap(nodes); _heapForward = new _Heap(nodes); } - ~_ThreadData() - { + ~_ThreadData() { delete _heapBackward; delete _heapForward; } @@ -65,13 +61,13 @@ public: NodeID source; NodeID target; struct EdgeData { - NodeID via; - unsigned nameID; - int distance; - bool shortcut; - bool forward; - bool backward; - short turnInstruction; + NodeID via; + unsigned nameID; + int distance; + short turnInstruction; + bool shortcut:1; + bool forward:1; + bool backward:1; } data; //sorts by source and other attributes diff --git a/Contractor/Contractor.h b/Contractor/Contractor.h index c8d9568e8..948cd264a 100644 --- a/Contractor/Contractor.h +++ b/Contractor/Contractor.h @@ -41,16 +41,15 @@ or see http://www.gnu.org/licenses/agpl.txt. class Contractor { private: - struct _EdgeBasedContractorEdgeData { - unsigned distance; - unsigned originalEdges; - unsigned via; - unsigned nameID; - bool shortcut; - bool forward; - bool backward; - short turnInstruction; + unsigned distance; + unsigned originalEdges; + unsigned via; + unsigned nameID; + short turnInstruction; + bool shortcut:1; + bool forward:1; + bool backward:1; } data; struct _HeapData { @@ -107,7 +106,7 @@ public: edge.data.distance = (std::max)((int)i->weight(), 1 ); assert( edge.data.distance > 0 ); -#ifndef NDEBUG +#ifdef NDEBUG if ( edge.data.distance > 24 * 60 * 60 * 10 ) { std::cout << "Edge Weight too large -> May lead to invalid CH" << std::endl; continue; From 7c85b2f85a868d920c17db8c803350c84b0c3101 Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 18:42:07 +0100 Subject: [PATCH 16/17] Threshold for Douglas-Peucker fixed --- Algorithms/DouglasPeucker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Algorithms/DouglasPeucker.h b/Algorithms/DouglasPeucker.h index 31424f727..66e1aba15 100644 --- a/Algorithms/DouglasPeucker.h +++ b/Algorithms/DouglasPeucker.h @@ -32,7 +32,7 @@ or see http://www.gnu.org/licenses/agpl.txt. * Note: points may also be pre-selected*/ //These thresholds are more or less heuristically chosen. -static double DouglasPeuckerThresholds[19] = { 10240000., 512., 2560000., 1280000., 640000., 320000., 160000., 80000., 40000., 20000., 10000., 5000., 2400., 1200., 200, 16, 6, 3., 1. }; +static double DouglasPeuckerThresholds[19] = { 10240000., 5120000., 2560000., 1280000., 640000., 320000., 160000., 80000., 40000., 20000., 10000., 5000., 2400., 1200., 200, 16, 6, 3., 1. }; template class DouglasPeucker { From e081cf1c3d33e63fbc10a4c2d30d3755d9a6be3c Mon Sep 17 00:00:00 2001 From: DennisOSRM Date: Sat, 10 Dec 2011 18:43:37 +0100 Subject: [PATCH 17/17] Fixing inverted #ifdef --- DataStructures/NNGrid.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DataStructures/NNGrid.h b/DataStructures/NNGrid.h index 71f2c229f..0e301787a 100644 --- a/DataStructures/NNGrid.h +++ b/DataStructures/NNGrid.h @@ -209,7 +209,7 @@ public: std::vector entriesInFileWithRAMSameIndex; unsigned indexInRamTable = entries->begin()->ramIndex; unsigned lastPositionInIndexFile = 0; -#ifndef NDEBUG +#ifdef NDEBUG unsigned numberOfUsedCells = 0; #endif unsigned maxNumberOfRAMCellElements = 0; @@ -226,7 +226,7 @@ public: lastPositionInIndexFile += numberOfBytesInCell; entriesInFileWithRAMSameIndex.clear(); indexInRamTable = vt->ramIndex; -#ifndef NDEBUG +#ifdef NDEBUG numberOfUsedCells++; #endif } @@ -234,7 +234,7 @@ public: } /*unsigned numberOfBytesInCell = */FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile); ramIndexTable[indexInRamTable] = lastPositionInIndexFile; -#ifndef NDEBUG +#ifdef NDEBUG numberOfUsedCells++; #endif entriesInFileWithRAMSameIndex.clear(); @@ -244,7 +244,7 @@ public: indexOutFile.close(); -#ifndef NDEBUG +#ifdef NDEBUG for(int i = 0; i < 1024*1024; ++i) { if(ramIndexTable[i] != UINT_MAX) { numberOfUsedCells--;