[osrm] 02/05: Imported Upstream version 0.4.2
Andreas Tille
tille at debian.org
Thu Jul 10 14:50:42 UTC 2014
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository osrm.
commit 4afb219d8ecf1a77c5611958e4091603d0fd0604
Author: Andreas Tille <tille at debian.org>
Date: Thu Jul 10 16:43:58 2014 +0200
Imported Upstream version 0.4.2
---
.clang-format | 54 +
.gitignore | 12 +-
.travis.yml | 54 +
AUTHORS.TXT | 11 -
Algorithms/BFSComponentExplorer.h | 148 ++
Algorithms/Bresenham.h | 49 -
Algorithms/CRC32.cpp | 85 --
Algorithms/CRC32.h | 45 -
Algorithms/DouglasPeucker.cpp | 183 +++
Algorithms/DouglasPeucker.h | 149 +-
Algorithms/ExtractRouteNames.h | 169 +++
Algorithms/IteratorBasedCRC32.h | 185 ++-
Algorithms/ObjectToBase64.h | 100 +-
Algorithms/PolylineCompressor.cpp | 118 ++
Algorithms/PolylineCompressor.h | 151 +-
Algorithms/StronglyConnectedComponents.h | 628 ++++----
CMakeLists.txt | 344 ++++-
Contractor/ContractionCleanup.h | 261 ----
Contractor/Contractor.h | 1313 ++++++++++-------
Contractor/EdgeBasedGraphFactory.cpp | 1049 ++++++++-----
Contractor/EdgeBasedGraphFactory.h | 234 ++-
Contractor/GeometryCompressor.cpp | 227 +++
Contractor/GeometryCompressor.h | 65 +
Contractor/TemporaryStorage.cpp | 226 +--
Contractor/TemporaryStorage.h | 165 +--
DataStructures/BinaryHeap.h | 340 +++--
DataStructures/ConcurrentQueue.h | 120 +-
DataStructures/Coordinate.cpp | 446 ++++++
DataStructures/Coordinate.h | 108 --
DataStructures/DeallocatingVector.h | 487 +++---
DataStructures/DynamicGraph.h | 443 +++---
DataStructures/EdgeBasedNode.h | 90 ++
DataStructures/GridEdge.h | 82 --
DataStructures/HashTable.h | 125 +-
DataStructures/HilbertValue.cpp | 100 ++
DataStructures/HilbertValue.h | 104 +-
DataStructures/ImportEdge.cpp | 107 ++
DataStructures/ImportEdge.h | 218 ++-
DataStructures/ImportNode.cpp | 64 +
DataStructures/ImportNode.h | 71 +-
DataStructures/InputReaderFactory.h | 127 +-
DataStructures/JSONContainer.h | 237 +++
DataStructures/LRUCache.h | 87 +-
DataStructures/MercatorUtil.h | 38 -
DataStructures/NNGrid.h | 602 --------
DataStructures/NodeBasedGraph.h | 166 +++
DataStructures/NodeCoords.h | 69 -
DataStructures/NodeInformationHelpDesk.h | 159 --
DataStructures/OriginalEdgeData.h | 60 +
DataStructures/Percent.h | 127 +-
DataStructures/PhantomNodes.h | 225 ++-
DataStructures/QueryEdge.h | 94 +-
DataStructures/QueryNode.h | 85 ++
DataStructures/RangeTable.h | 231 +++
DataStructures/RawRouteData.h | 80 +
DataStructures/Restriction.h | 155 +-
DataStructures/RestrictionMap.cpp | 224 +++
DataStructures/RestrictionMap.h | 126 ++
DataStructures/RouteParameters.cpp | 89 ++
DataStructures/SearchEngine.cpp | 89 --
DataStructures/SearchEngine.h | 96 +-
DataStructures/SearchEngineData.cpp | 105 +-
DataStructures/SearchEngineData.h | 79 +-
DataStructures/SegmentInformation.h | 92 +-
DataStructures/SharedMemoryFactory.h | 370 +++++
DataStructures/SharedMemoryVectorWrapper.h | 156 ++
DataStructures/SimpleStack.h | 71 -
DataStructures/StaticGraph.h | 279 ++--
DataStructures/StaticKDTree.h | 245 +--
DataStructures/StaticRTree.h | 1557 +++++++++++---------
DataStructures/TimingUtil.h | 50 -
DataStructures/TurnInstructions.h | 132 +-
DataStructures/XORFastHash.h | 84 +-
DataStructures/XORFastHashStorage.h | 107 +-
Descriptors/BaseDescriptor.h | 94 +-
Descriptors/DescriptionFactory.cpp | 253 +---
Descriptors/DescriptionFactory.h | 233 ++-
Descriptors/GPXDescriptor.h | 141 +-
Descriptors/JSONDescriptor.h | 777 +++++-----
Extractor/BaseParser.cpp | 187 +--
Extractor/BaseParser.h | 82 +-
Extractor/ExtractionContainers.cpp | 566 ++++---
Extractor/ExtractionContainers.h | 96 +-
Extractor/ExtractionHelperFunctions.h | 122 +-
Extractor/ExtractionWay.h | 79 +
Extractor/ExtractorCallbacks.cpp | 255 ++--
Extractor/ExtractorCallbacks.h | 86 +-
Extractor/ExtractorStructs.h | 260 +---
Extractor/InternalExtractorEdge.h | 120 ++
Extractor/PBFParser.cpp | 1056 +++++++------
Extractor/PBFParser.h | 119 +-
Extractor/ScriptingEnvironment.cpp | 195 +--
Extractor/ScriptingEnvironment.h | 70 +-
Extractor/XMLParser.cpp | 583 ++++----
Extractor/XMLParser.h | 68 +-
Gemfile.lock | 30 +-
Include/osrm/Coordinate.h | 105 ++
Include/osrm/Header.h | 53 +
Include/osrm/Reply.h | 74 +
Include/osrm/RouteParameters.h | 83 ++
Include/osrm/ServerPaths.h | 38 +
LICENCE.TXT | 683 +--------
Library/OSRM.h | 52 +
Library/OSRM_impl.cpp | 167 +++
Library/OSRM_impl.h | 65 +
Plugins/BasePlugin.h | 63 +-
Plugins/DistanceTablePlugin.h | 146 ++
Plugins/HelloWorldPlugin.h | 135 +-
Plugins/LocatePlugin.h | 152 +-
Plugins/NearestPlugin.h | 171 +--
Plugins/PluginMapFactory.h | 34 -
Plugins/RawRouteData.h | 45 -
Plugins/RouteParameters.h | 107 --
Plugins/TimestampPlugin.h | 106 +-
Plugins/ViaRoutePlugin.h | 397 +++--
README.TXT => README.md | 17 +-
Rakefile | 62 +-
RoutingAlgorithms/AlternativePathRouting.h | 1129 +++++++++-----
RoutingAlgorithms/BasicRoutingInterface.h | 512 +++++--
RoutingAlgorithms/ManyToManyRouting.h | 264 ++++
RoutingAlgorithms/ShortestPathRouting.h | 399 +++--
Server/APIGrammar.h | 54 +-
Server/BasicDatastructures.h | 157 --
Server/Connection.cpp | 174 +++
Server/Connection.h | 247 ++--
Server/DataStructures/BaseDataFacade.h | 125 ++
Server/DataStructures/InternalDataFacade.h | 430 ++++++
Server/DataStructures/QueryObjectsStorage.cpp | 100 --
Server/DataStructures/QueryObjectsStorage.h | 47 -
Server/DataStructures/SharedBarriers.h | 60 +
Server/DataStructures/SharedDataFacade.h | 398 +++++
Server/DataStructures/SharedDataType.h | 190 +++
Server/Http/CompressionType.h | 41 +
Server/Http/Reply.cpp | 123 ++
Server/Http/Request.h | 48 +
Server/RequestHandler.cpp | 142 ++
Server/RequestHandler.h | 138 +-
Server/RequestParser.cpp | 306 ++++
Server/RequestParser.h | 345 +----
Server/Server.h | 166 ++-
Server/ServerConfiguration.h | 28 -
Server/ServerFactory.h | 107 +-
Tools/componentAnalysis.cpp | 102 --
Tools/components.cpp | 136 ++
Tools/io-benchmark.cpp | 348 +++++
Tools/simpleclient.cpp | 131 ++
Tools/unlock_all_mutexes.cpp | 52 +
Util/Azimuth.h | 79 +-
Util/BaseConfiguration.h | 107 --
Util/BoostFileSystemFix.h | 147 ++
Util/ComputeAngle.h | 57 +
Util/ContainerUtils.h | 71 +-
Util/DataStoreOptions.h | 284 ++++
Util/FingerPrint.cpp.in | 106 ++
Util/FingerPrint.h | 60 +
Util/GitDescription.cpp.in | 29 +
Util/GitDescription.h | 33 +
Util/GraphLoader.h | 533 +++----
Util/IniFileUtil.h | 49 +
Util/InputFileUtil.h | 46 -
Util/LinuxStackTrace.h | 156 --
Util/LuaUtil.h | 81 +-
Util/MachineInfo.h | 109 +-
Util/MercatorUtil.h | 43 +
Util/OSRMException.h | 46 +
Util/OpenMPWrapper.h | 34 -
Util/ProgramOptions.h | 270 ++++
Util/SimpleLogger.h | 158 ++
Util/StdHashExtensions.h | 73 +
Util/StringUtil.h | 353 +++--
Util/TimingUtil.h | 39 +
Util/TrigonometryTables.h | 790 ++++++++++
appveyor.yml | 67 +
cmake/CheckCXXCompilerFlag.cmake | 29 +
cmake/FindLua52.cmake | 82 ++
cmake/FindLuaJIT.cmake | 93 ++
cmake/FindLuabind.cmake | 4 +-
cmake/FindSTXXL.cmake | 2 +-
cmake/FindTBB.cmake | 283 ++++
cmake/FingerPrint-Config.cmake | 10 +
cmake/GetGitRevisionDescription.cmake.in | 38 +
cmake/cmake_options_script.py | 45 +
cmake/pkgconfig.in | 11 +
config/cucumber.yml | 8 +-
contractor.ini | 1 -
createHierarchy.cpp | 276 ----
datastore.cpp | 575 ++++++++
extractor.cpp | 339 +++--
extractor.ini | 2 -
features/bicycle/access.feature | 322 ++--
features/bicycle/access_node.feature | 116 +-
features/bicycle/area.feature | 186 +--
features/bicycle/barrier.feature | 68 +-
features/bicycle/cycleway.feature | 150 +-
features/bicycle/destination.feature | 134 +-
features/bicycle/ferry.feature | 120 +-
features/bicycle/maxspeed.feature | 130 +-
features/bicycle/mode.feature | 146 +-
features/bicycle/names.feature | 66 +-
features/bicycle/oneway.feature | 252 ++--
features/bicycle/pushing.feature | 200 +--
features/bicycle/ref.feature | 76 +-
features/bicycle/restrictions.feature | 574 ++++----
features/bicycle/roundabout.feature | 30 +
features/bicycle/stop_area.feature | 58 +-
features/bicycle/surface.feature | 40 +
features/bicycle/train.feature | 70 +-
features/bicycle/turn_penalty.feature | 42 +-
features/bicycle/way.feature | 73 +-
features/car/access.feature | 266 ++--
features/car/barrier.feature | 66 +-
features/car/destination.feature | 134 +-
features/car/ferry.feature | 48 +-
features/car/maxspeed.feature | 113 +-
features/car/names.feature | 56 +-
features/car/oneway.feature | 132 +-
features/car/restrictions.feature | 561 +++----
features/car/roundabout.feature | 30 +
features/car/shuttle_train.feature | 52 +-
features/car/speed.feature | 24 +
features/car/way.feature | 58 +-
features/foot/access.feature | 95 ++
features/foot/access_node.feature | 50 +
features/foot/area.feature | 103 ++
features/foot/barrier.feature | 39 +
features/foot/ferry.feature | 63 +
features/foot/maxspeed.feature | 31 +-
features/foot/names.feature | 33 +
features/foot/oneway.feature | 110 +-
features/foot/ref.feature | 41 +
features/foot/restrictions.feature | 288 ++++
features/foot/roundabout.feature | 34 +
features/foot/surface.feature | 15 +
features/foot/way.feature | 56 +-
features/investigate/weird.feature | 42 -
features/locate/locate.feature | 197 +++
features/nearest/pick.feature | 128 +-
features/nearest/projection.feature | 184 +--
features/options/extract/files.feature | 30 +
features/options/extract/help.feature | 47 +
features/options/extract/invalid.feature | 12 +
features/options/extract/version.feature | 22 +
features/options/prepare/files.feature | 30 +
features/options/prepare/help.feature | 50 +
features/options/prepare/invalid.feature | 12 +
features/options/prepare/version.feature | 22 +
features/options/routed/files.feature | 27 +
features/options/routed/help.feature | 77 +
features/options/routed/invalid.feature | 19 +
features/options/routed/version.feature | 22 +
features/step_definitions/data.rb | 59 +-
.../step_definitions/{nearest.rb => locate.rb} | 22 +-
features/step_definitions/nearest.rb | 12 +-
features/step_definitions/options.rb | 49 +
features/step_definitions/requests.rb | 25 +-
features/step_definitions/routability.rb | 99 +-
features/step_definitions/routing.rb | 153 +-
features/stress/launch.feature | 102 +-
features/support/config.rb | 18 -
features/support/cucumber.rb | 6 +-
features/support/data.rb | 160 +-
features/support/env.rb | 41 +-
features/support/exceptions.rb | 17 +-
features/support/file.rb | 42 +-
features/support/fuzzy.rb | 20 +-
features/support/hash.rb | 16 +-
features/support/hooks.rb | 21 +-
features/support/launch.rb | 44 +-
features/support/{nearest.rb => locate.rb} | 8 +-
features/support/log.rb | 35 +-
features/support/nearest.rb | 2 +-
features/support/osm_parser.rb | 18 +-
features/support/route.rb | 129 +-
features/support/run.rb | 18 +
features/testbot/bad.feature | 144 +-
features/testbot/basic.feature | 519 ++++---
features/testbot/bearing.feature | 348 +++--
features/testbot/bearing_param.feature | 170 +--
features/testbot/bug.feature | 23 -
features/testbot/bugs.feature | 5 +
features/testbot/distance.feature | 452 +++---
features/testbot/duration.feature | 66 +-
features/testbot/example.feature | 59 +-
features/testbot/fastest.feature | 62 +-
features/testbot/ferry.feature | 332 ++---
features/testbot/fixed.feature | 26 +
features/testbot/geometry.feature | 30 +
features/testbot/graph.feature | 37 +-
features/testbot/impedance.feature | 161 +-
features/testbot/loop.feature | 78 +
features/testbot/maxspeed.feature | 65 +-
features/testbot/mode.feature | 40 +-
features/testbot/oneway.feature | 44 +
features/testbot/opposite.feature | 32 +-
features/testbot/origin.feature | 128 +-
features/testbot/overlap.feature | 39 +
features/testbot/penalty.feature | 332 ++---
features/testbot/planetary.feature | 168 +--
features/testbot/projection.feature | 38 +
features/testbot/protobuffer.feature | 156 ++
features/testbot/roundabout.feature | 76 +
features/testbot/routes.feature | 58 +-
features/testbot/snap.feature | 306 ++--
features/testbot/speed.feature | 31 +
features/testbot/status.feature | 67 +
features/testbot/time.feature | 448 +++---
features/testbot/turns.feature | 220 +--
features/testbot/utf.feature | 34 +-
features/testbot/via.feature | 124 +-
features/timestamp/timestamp.feature | 19 +-
prepare.cpp | 523 +++++++
profile.lua | 1 +
profiles/bicycle.lua | 575 ++++----
profiles/car.lua | 289 ++--
profiles/examples/postgis.lua | 82 ++
profiles/foot.lua | 312 ++--
profiles/testbot.lua | 181 +--
routed.cpp | 270 ++--
server.ini | 11 -
test/contractor.ini | 1 -
test/extractor.ini | 1 -
typedefs.h | 82 +-
win/createHierarchy.vcproj | 459 ------
win/extractor.vcproj | 532 -------
win/getopt.c | 1260 ----------------
win/getopt.h | 189 ---
win/osrm.sln | 29 -
win/osrm.vsprops | 39 -
win/routed.vcproj | 459 ------
win/unistd.h | 30 -
330 files changed, 31598 insertions(+), 21819 deletions(-)
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..f5577f5
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,54 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+ConstructorInitializerIndentWidth: 4
+AlignEscapedNewlinesLeft: false
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: true
+AlwaysBreakTemplateDeclarations: false
+AlwaysBreakBeforeMultilineStrings: false
+BreakBeforeBinaryOperators: false
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BinPackParameters: false
+ColumnLimit: 100
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+DerivePointerBinding: false
+ExperimentalAutoDetectBinPacking: false
+IndentCaseLabels: false
+MaxEmptyLinesToKeep: 1
+KeepEmptyLinesAtTheStartOfBlocks: true
+NamespaceIndentation: None
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakString: 1000
+PenaltyBreakFirstLessLess: 120
+PenaltyExcessCharacter: 1000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerBindsToType: false
+SpacesBeforeTrailingComments: 1
+Cpp11BracedListStyle: true
+Standard: Cpp11
+IndentWidth: 4
+TabWidth: 8
+UseTab: Never
+BreakBeforeBraces: Allman
+IndentFunctionDeclarationAfterType: false
+SpacesInParentheses: false
+SpacesInAngles: false
+SpaceInEmptyParentheses: false
+SpacesInCStyleCastParentheses: false
+SpacesInContainerLiterals: true
+SpaceBeforeAssignmentOperators: true
+ContinuationIndentWidth: 4
+CommentPragmas: '^ IWYU pragma:'
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+SpaceBeforeParens: ControlStatements
+...
+
diff --git a/.gitignore b/.gitignore
index 2e6107a..5642924 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,8 @@ Thumbs.db
# build related files #
#######################
/build/
+/Util/FingerPrint.cpp
+/Util/GitDescription.cpp
# Eclipse related files #
#########################
@@ -70,8 +72,13 @@ stxxl.errlog
/win/bin/
/win/bin-debug/
/osrm-extract
+/osrm-io-benchmark
+/osrm-components
/osrm-routed
+/osrm-datastore
/osrm-prepare
+/osrm-unlock-all
+/osrm-cli
/nohup.out
# Sandbox folder #
@@ -79,4 +86,7 @@ stxxl.errlog
/sandbox/
/test/profile.lua
-/profile.lua
+
+# Deprecated config file #
+##########################
+/server.ini
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..8817e38
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,54 @@
+language: cpp
+compiler:
+ - gcc
+# - clang
+# Make sure CMake is installed
+install:
+ - sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test
+ - sudo add-apt-repository -y ppa:boost-latest/ppa
+ - sudo apt-get update >/dev/null
+ - sudo apt-get -q install libprotoc-dev libprotobuf7 libprotobuf-dev libosmpbf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev lua5.1 liblua5.1-0-dev rubygems libtbb-dev
+ - sudo apt-get -q install g++-4.7
+ - sudo apt-get install libboost1.54-all-dev
+ #luabind
+ - curl https://gist.githubusercontent.com/DennisOSRM/f2eb7b948e6fe1ae319e/raw/install-luabind.sh | sudo bash
+ #osmosis
+ - curl -s https://gist.githubusercontent.com/DennisOSRM/803a64a9178ec375069f/raw/ | sudo bash
+before_script:
+ - rvm use 1.9.3
+ - gem install bundler
+ - bundle install
+ - mkdir build
+ - cd build
+ - cmake .. $CMAKEOPTIONS
+script:
+ - make -j 2
+ - cd ..
+ - cucumber -p verify
+after_script:
+# - cd ..
+# - cucumber -p verify
+branches:
+ only:
+ - master
+ - develop
+cache:
+- bundler
+- apt
+env:
+ - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-4.7" OSRM_PORT=5000 OSRM_TIMEOUT=60
+ - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++-4.7" OSRM_PORT=5010 OSRM_TIMEOUT=60
+notifications:
+ irc:
+ channels:
+ - irc.oftc.net#osrm
+ on_success: change
+ on_failure: always
+ use_notice: true
+ skip_join: false
+
+ recipients:
+ - dennis at mapbox.com
+ email:
+ on_success: change
+ on_failure: always
diff --git a/AUTHORS.TXT b/AUTHORS.TXT
deleted file mode 100644
index 8268ebd..0000000
--- a/AUTHORS.TXT
+++ /dev/null
@@ -1,11 +0,0 @@
-The following people contributed code to the Open Source Routing Machine:
-
-Christian Vetter
-Dennis Luxen
-Ruslan Krenzler
-Frederik Ramm
-Bharath Vissapragada
-Pascal Neis
-Sasa Ivetic
-Emil Tin
-Henning Moll
diff --git a/Algorithms/BFSComponentExplorer.h b/Algorithms/BFSComponentExplorer.h
new file mode 100644
index 0000000..7bc7ecb
--- /dev/null
+++ b/Algorithms/BFSComponentExplorer.h
@@ -0,0 +1,148 @@
+#ifndef __BFS_COMPONENT_EXPLORER_H__
+#define __BFS_COMPONENT_EXPLORER_H__
+
+#include "../typedefs.h"
+#include "../DataStructures/DynamicGraph.h"
+#include "../DataStructures/RestrictionMap.h"
+
+#include <queue>
+#include <unordered_set>
+
+// Explores the components of the given graph while respecting turn restrictions
+// and barriers.
+template <typename GraphT> class BFSComponentExplorer
+{
+ public:
+ BFSComponentExplorer(const GraphT &dynamicGraph,
+ const RestrictionMap &restrictions,
+ const std::unordered_set<NodeID> &barrier_nodes)
+ : m_graph(dynamicGraph), m_restriction_map(restrictions), m_barrier_nodes(barrier_nodes)
+ {
+ BOOST_ASSERT(m_graph.GetNumberOfNodes() > 0);
+ }
+
+ /*!
+ * Returns the size of the component that the node belongs to.
+ */
+ inline unsigned int GetComponentSize(NodeID node)
+ {
+ BOOST_ASSERT(node < m_component_index_list.size());
+
+ return m_component_index_size[m_component_index_list[node]];
+ }
+
+ inline unsigned int GetNumberOfComponents() { return m_component_index_size.size(); }
+
+ /*!
+ * Computes the component sizes.
+ */
+ void run()
+ {
+ std::queue<std::pair<NodeID, NodeID>> bfs_queue;
+ unsigned current_component = 0;
+
+ BOOST_ASSERT(m_component_index_list.empty());
+ BOOST_ASSERT(m_component_index_size.empty());
+
+ unsigned num_nodes = m_graph.GetNumberOfNodes();
+
+ m_component_index_list.resize(num_nodes, std::numeric_limits<unsigned>::max());
+
+ BOOST_ASSERT(num_nodes > 0);
+
+ // put unexplorered node with parent pointer into queue
+ for (NodeID node = 0; node < num_nodes; ++node)
+ {
+ if (std::numeric_limits<unsigned>::max() == m_component_index_list[node])
+ {
+ unsigned size = ExploreComponent(bfs_queue, node, current_component);
+
+ // push size into vector
+ m_component_index_size.emplace_back(size);
+ ++current_component;
+ }
+ }
+ }
+
+ private:
+ /*!
+ * Explores the current component that starts at node using BFS.
+ */
+ inline unsigned ExploreComponent(std::queue<std::pair<NodeID, NodeID>> &bfs_queue,
+ NodeID node,
+ unsigned current_component)
+ {
+ /*
+ Graphical representation of variables:
+
+ u v w
+ *---------->*---------->*
+ e2
+ */
+
+ bfs_queue.emplace(node, node);
+ // mark node as read
+ m_component_index_list[node] = current_component;
+
+ unsigned current_component_size = 1;
+
+ while (!bfs_queue.empty())
+ {
+ // fetch element from BFS queue
+ std::pair<NodeID, NodeID> current_queue_item = bfs_queue.front();
+ bfs_queue.pop();
+
+ const NodeID v = current_queue_item.first; // current node
+ const NodeID u = current_queue_item.second; // parent
+ // increment size counter of current component
+ ++current_component_size;
+ const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
+ if (!is_barrier_node)
+ {
+ const NodeID to_node_of_only_restriction =
+ m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);
+
+ for (auto e2 : m_graph.GetAdjacentEdgeRange(v))
+ {
+ const NodeID w = m_graph.GetTarget(e2);
+
+ if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
+ w != to_node_of_only_restriction)
+ {
+ // At an only_-restriction but not at the right turn
+ continue;
+ }
+
+ if (u != w)
+ {
+ // only add an edge if turn is not a U-turn except
+ // when it is at the end of a dead-end street.
+ if (!m_restriction_map.CheckIfTurnIsRestricted(u, v, w))
+ {
+ // only add an edge if turn is not prohibited
+ if (std::numeric_limits<unsigned>::max() == m_component_index_list[w])
+ {
+ // insert next (node, parent) only if w has
+ // not yet been explored
+ // mark node as read
+ m_component_index_list[w] = current_component;
+ bfs_queue.emplace(w, v);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return current_component_size;
+ }
+
+ std::vector<unsigned> m_component_index_list;
+ std::vector<NodeID> m_component_index_size;
+
+ const GraphT &m_graph;
+ const RestrictionMap &m_restriction_map;
+ const std::unordered_set<NodeID> &m_barrier_nodes;
+};
+
+#endif
diff --git a/Algorithms/Bresenham.h b/Algorithms/Bresenham.h
deleted file mode 100644
index a4f7e61..0000000
--- a/Algorithms/Bresenham.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- 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 BRESENHAM_H_
-#define BRESENHAM_H_
-
-#include <cmath>
-#include <vector>
-typedef std::pair<unsigned, unsigned> BresenhamPixel;
-
-inline void Bresenham (int x0, int y0, int x1, int y1, std::vector<BresenhamPixel> &resultList) {
- int dx = std::abs(x1-x0);
- int dy = std::abs(y1-y0);
- int sx = (x0 < x1 ? 1 : -1);
- int sy = (y0 < y1 ? 1 : -1);
- int err = dx - dy;
- while(true) {
- resultList.push_back(std::make_pair(x0,y0));
- if(x0 == x1 && y0 == y1) break;
- int e2 = 2* err;
- if ( e2 > -dy) {
- err -= dy;
- x0 += sx;
- }
- if(e2 < dx) {
- err+= dx;
- y0 += sy;
- }
- }
-}
-
-#endif /* BRESENHAM_H_ */
diff --git a/Algorithms/CRC32.cpp b/Algorithms/CRC32.cpp
deleted file mode 100644
index d2f821c..0000000
--- a/Algorithms/CRC32.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- 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 "CRC32.h"
-
-CRC32::CRC32() : crc(0) {
- crcFunction = detectBestCRC32C();
-}
-
-unsigned CRC32::SoftwareBasedCRC32(char *str, unsigned len, unsigned ) {
- boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_Processor;
- CRC32_Processor.process_bytes( str, len);
- return CRC32_Processor.checksum();
-}
-
-unsigned CRC32::SSEBasedCRC32( char *str, unsigned len, unsigned crc) {
- unsigned q=len/sizeof(unsigned),
- r=len%sizeof(unsigned),
- *p=(unsigned*)str/*, crc*/;
-
- //crc=0;
- while (q--) {
- __asm__ __volatile__(
- ".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
- :"=S"(crc)
- :"0"(crc), "c"(*p)
- );
- ++p;
- }
-
- str=(char*)p;
- while (r--) {
- __asm__ __volatile__(
- ".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
- :"=S"(crc)
- :"0"(crc), "c"(*str)
- );
- ++str;
- }
- return crc;
-}
-
-CRC32::CRC32CFunctionPtr CRC32::detectBestCRC32C() {
- static const int SSE42_BIT = 20;
- unsigned ecx = cpuid(1);
- bool hasSSE42 = ecx & (1 << SSE42_BIT);
- if (hasSSE42) {
- std::cout << "using hardware base sse computation" << std::endl;
- return &CRC32::SSEBasedCRC32; //crc32 hardware accelarated;
- } else {
- std::cout << "using software base sse computation" << std::endl;
- return &CRC32::SoftwareBasedCRC32; //crc32cSlicingBy8;
- }
-}
-
-unsigned CRC32::cpuid(unsigned functionInput) {
- unsigned eax;
- unsigned ebx;
- unsigned ecx;
- unsigned edx;
- asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (functionInput));
- return ecx;
-}
-
-unsigned CRC32::operator()(char *str, unsigned len){
- crc =((*this).*(crcFunction))(str, len, crc);
- return crc;
-}
diff --git a/Algorithms/CRC32.h b/Algorithms/CRC32.h
deleted file mode 100644
index 6321030..0000000
--- a/Algorithms/CRC32.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- 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 CRC32_H_
-#define CRC32_H_
-
-#include <boost/crc.hpp> // for boost::crc_32_type
-#include <iostream>
-
-class CRC32 {
-private:
- unsigned crc;
-
- typedef boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> my_crc_32_type;
- typedef unsigned (CRC32::*CRC32CFunctionPtr)(char *str, unsigned len, unsigned crc);
-
- unsigned SoftwareBasedCRC32(char *str, unsigned len, unsigned crc);
- unsigned SSEBasedCRC32( char *str, unsigned len, unsigned crc);
- unsigned cpuid(unsigned functionInput);
- CRC32CFunctionPtr detectBestCRC32C();
- CRC32CFunctionPtr crcFunction;
-public:
- CRC32();
- unsigned operator()(char *str, unsigned len);
- virtual ~CRC32() {};
-};
-
-#endif /* CRC32_H_ */
diff --git a/Algorithms/DouglasPeucker.cpp b/Algorithms/DouglasPeucker.cpp
new file mode 100644
index 0000000..2e647fc
--- /dev/null
+++ b/Algorithms/DouglasPeucker.cpp
@@ -0,0 +1,183 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <osrm/Coordinate.h>
+
+#include "DouglasPeucker.h"
+#include "../DataStructures/SegmentInformation.h"
+#include "../Util/SimpleLogger.h"
+
+#include <boost/assert.hpp>
+
+#include <cmath>
+
+#include <algorithm>
+
+struct CoordinatePairCalculator
+{
+ CoordinatePairCalculator() = delete;
+ CoordinatePairCalculator(const FixedPointCoordinate &coordinate_a,
+ const FixedPointCoordinate &coordinate_b)
+ {
+ // initialize distance calculator with two fixed coordinates a, b
+ const float RAD = 0.017453292519943295769236907684886f;
+ first_lat = (coordinate_a.lat / COORDINATE_PRECISION) * RAD;
+ first_lon = (coordinate_a.lon / COORDINATE_PRECISION) * RAD;
+ second_lat = (coordinate_b.lat / COORDINATE_PRECISION) * RAD;
+ second_lon = (coordinate_b.lon / COORDINATE_PRECISION) * RAD;
+ }
+
+ int operator()(FixedPointCoordinate &other) const
+ {
+ // set third coordinate c
+ const float RAD = 0.017453292519943295769236907684886f;
+ const float earth_radius = 6372797.560856f;
+ const float float_lat1 = (other.lat / COORDINATE_PRECISION) * RAD;
+ const float float_lon1 = (other.lon / COORDINATE_PRECISION) * RAD;
+
+ // compute distance (a,c)
+ const float x_value_1 = (first_lon - float_lon1) * cos((float_lat1 + first_lat) / 2.f);
+ const float y_value_1 = first_lat - float_lat1;
+ const float dist1 = sqrt(std::pow(x_value_1, 2) + std::pow(y_value_1, 2)) * earth_radius;
+
+ // compute distance (b,c)
+ const float x_value_2 = (second_lon - float_lon1) * cos((float_lat1 + second_lat) / 2.f);
+ const float y_value_2 = second_lat - float_lat1;
+ const float dist2 = sqrt(std::pow(x_value_2, 2) + std::pow(y_value_2, 2)) * earth_radius;
+
+ // return the minimum
+ return static_cast<int>(std::min(dist1, dist2));
+ }
+
+ float first_lat;
+ float first_lon;
+ float second_lat;
+ float second_lon;
+};
+
+DouglasPeucker::DouglasPeucker()
+ : douglas_peucker_thresholds({512440, // z0
+ 256720, // z1
+ 122560, // z2
+ 56780, // z3
+ 28800, // z4
+ 14400, // z5
+ 7200, // z6
+ 3200, // z7
+ 2400, // z8
+ 1000, // z9
+ 600, // z10
+ 120, // z11
+ 60, // z12
+ 45, // z13
+ 36, // z14
+ 20, // z15
+ 8, // z16
+ 6, // z17
+ 4 // z18
+ })
+{
+}
+
+void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level)
+{
+ // check if input data is invalid
+ BOOST_ASSERT_MSG(!input_geometry.empty(), "geometry invalid");
+
+ if (input_geometry.size() < 2)
+ {
+ return;
+ }
+
+ input_geometry.front().necessary = true;
+ input_geometry.back().necessary = true;
+
+ {
+ BOOST_ASSERT_MSG(zoom_level < 19, "unsupported zoom level");
+ unsigned left_border = 0;
+ unsigned right_border = 1;
+ // Sweep over array and identify those ranges that need to be checked
+ do
+ {
+ // traverse list until new border element found
+ if (input_geometry[right_border].necessary)
+ {
+ // sanity checks
+ BOOST_ASSERT(input_geometry[left_border].necessary);
+ BOOST_ASSERT(input_geometry[right_border].necessary);
+ recursion_stack.emplace(left_border, right_border);
+ left_border = right_border;
+ }
+ ++right_border;
+ } while (right_border < input_geometry.size());
+ }
+
+ // mark locations as 'necessary' by divide-and-conquer
+ while (!recursion_stack.empty())
+ {
+ // pop next element
+ const GeometryRange pair = recursion_stack.top();
+ recursion_stack.pop();
+ // sanity checks
+ BOOST_ASSERT_MSG(input_geometry[pair.first].necessary, "left border mus be necessary");
+ BOOST_ASSERT_MSG(input_geometry[pair.second].necessary, "right border must be necessary");
+ BOOST_ASSERT_MSG(pair.second < input_geometry.size(), "right border outside of geometry");
+ BOOST_ASSERT_MSG(pair.first < pair.second, "left border on the wrong side");
+
+ int max_int_distance = 0;
+ unsigned farthest_entry_index = pair.second;
+ const CoordinatePairCalculator DistCalc(input_geometry[pair.first].location,
+ input_geometry[pair.second].location);
+
+ // sweep over range to find the maximum
+ for (unsigned i = pair.first + 1; i < pair.second; ++i)
+ {
+ const int distance = DistCalc(input_geometry[i].location);
+ // found new feasible maximum?
+ if (distance > max_int_distance && distance > douglas_peucker_thresholds[zoom_level])
+ {
+ farthest_entry_index = i;
+ max_int_distance = distance;
+ }
+ }
+
+ // check if maximum violates a zoom level dependent threshold
+ if (max_int_distance > douglas_peucker_thresholds[zoom_level])
+ {
+ // mark idx as necessary
+ input_geometry[farthest_entry_index].necessary = true;
+ if (1 < (farthest_entry_index - pair.first))
+ {
+ recursion_stack.emplace(pair.first, farthest_entry_index);
+ }
+ if (1 < (pair.second - farthest_entry_index))
+ {
+ recursion_stack.emplace(farthest_entry_index, pair.second);
+ }
+ }
+ }
+}
diff --git a/Algorithms/DouglasPeucker.h b/Algorithms/DouglasPeucker.h
index 47b0ce9..d0f295c 100644
--- a/Algorithms/DouglasPeucker.h
+++ b/Algorithms/DouglasPeucker.h
@@ -1,129 +1,58 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef DOUGLASPEUCKER_H_
#define DOUGLASPEUCKER_H_
-#include <cassert>
-#include <cmath>
-#include <cfloat>
#include <stack>
+#include <utility>
+#include <vector>
-#include "../DataStructures/Coordinate.h"
-
-/*This class object computes the bitvector of indicating generalized input points
- * according to the (Ramer-)Douglas-Peucker algorithm.
+/* This class object computes the bitvector of indicating generalized input
+ * points according to the (Ramer-)Douglas-Peucker algorithm.
*
- * Input is vector of pairs. Each pair consists of the point information and a bit
- * indicating if the points is present in the generalization.
+ * Input is vector of pairs. Each pair consists of the point information and a
+ * bit indicating if the points is present in the generalization.
* Note: points may also be pre-selected*/
-//These thresholds are more or less heuristically chosen.
-// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
-static double DouglasPeuckerThresholds[19] = { 32000000., 16240000., 80240000., 40240000., 20000000., 10000000., 500000., 240000., 120000., 60000., 30000., 19000., 5000., 2000., 200, 16, 6, 3. , 3. };
-
-template<class PointT>
-class DouglasPeucker {
-private:
- typedef std::pair<std::size_t, std::size_t> PairOfPoints;
- //Stack to simulate the recursion
- std::stack<PairOfPoints > recursionStack;
-
- /**
- * This distance computation does integer arithmetic only and is about twice as fast as
- * the other distance function. It is an approximation only, but works more or less ok.
- */
- template<class CoordT>
- inline int fastDistance(const CoordT& point, const CoordT& segA, const CoordT& segB) const {
- const int p2x = (segB.lon - segA.lat);
- const int p2y = (segB.lon - segA.lat);
- const int something = p2x*p2x + p2y*p2y;
- int u = (something < FLT_EPSILON ? 0 : ((point.lon - segA.lon) * p2x + (point.lat - segA.lat) * p2y) / something);
-
- if (u > 1)
- u = 1;
- else if (u < 0)
- u = 0;
-
- const int x = segA.lon + u * p2x;
- const int y = segA.lat + u * p2y;
-
- const int dx = x - point.lon;
- const int dy = y - point.lat;
-
- const int dist = (dx*dx + dy*dy);
-
- return dist;
- }
-
+struct SegmentInformation;
-public:
- void Run(std::vector<PointT> & inputVector, const unsigned zoomLevel) {
- {
- assert(zoomLevel < 19);
- assert(1 < inputVector.size());
- std::size_t leftBorderOfRange = 0;
- std::size_t rightBorderOfRange = 1;
- //Sweep linerarily over array and identify those ranges that need to be checked
-// recursionStack.hint(inputVector.size());
- do {
- assert(inputVector[leftBorderOfRange].necessary);
- assert(inputVector.back().necessary);
+class DouglasPeucker
+{
+ private:
+ std::vector<int> douglas_peucker_thresholds;
- if(inputVector[rightBorderOfRange].necessary) {
- recursionStack.push(std::make_pair(leftBorderOfRange, rightBorderOfRange));
- leftBorderOfRange = rightBorderOfRange;
- }
- ++rightBorderOfRange;
- } while( rightBorderOfRange < inputVector.size());
- }
- while(!recursionStack.empty()) {
- //pop next element
- const PairOfPoints pair = recursionStack.top();
- recursionStack.pop();
- assert(inputVector[pair.first].necessary);
- assert(inputVector[pair.second].necessary);
- assert(pair.second < inputVector.size());
- assert(pair.first < pair.second);
- int maxDistance = INT_MIN;
+ typedef std::pair<unsigned, unsigned> GeometryRange;
+ // Stack to simulate the recursion
+ std::stack<GeometryRange> recursion_stack;
- std::size_t indexOfFarthestElement = pair.second;
- //find index idx of element with maxDistance
- for(std::size_t i = pair.first+1; i < pair.second; ++i){
- const double distance = std::fabs(fastDistance(inputVector[i].location, inputVector[pair.first].location, inputVector[pair.second].location));
- if(distance > DouglasPeuckerThresholds[zoomLevel] && distance > maxDistance) {
- indexOfFarthestElement = i;
- maxDistance = distance;
- }
- }
- if (maxDistance > DouglasPeuckerThresholds[zoomLevel]) {
- // mark idx as necessary
- inputVector[indexOfFarthestElement].necessary = true;
- if (1 < indexOfFarthestElement - pair.first) {
- recursionStack.push(std::make_pair(pair.first, indexOfFarthestElement) );
- }
- if (1 < pair.second - indexOfFarthestElement)
- recursionStack.push(std::make_pair(indexOfFarthestElement, pair.second) );
- }
- }
- }
+ public:
+ DouglasPeucker();
+ void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
};
#endif /* DOUGLASPEUCKER_H_ */
diff --git a/Algorithms/ExtractRouteNames.h b/Algorithms/ExtractRouteNames.h
new file mode 100644
index 0000000..5c1b860
--- /dev/null
+++ b/Algorithms/ExtractRouteNames.h
@@ -0,0 +1,169 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef EXTRACT_ROUTE_NAMES_H
+#define EXTRACT_ROUTE_NAMES_H
+
+#include <boost/assert.hpp>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+struct RouteNames
+{
+ std::string shortest_path_name_1;
+ std::string shortest_path_name_2;
+ std::string alternative_path_name_1;
+ std::string alternative_path_name_2;
+};
+
+// construct routes names
+template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
+{
+ private:
+ SegmentT PickNextLongestSegment(const std::vector<SegmentT> &segment_list,
+ const unsigned blocked_name_id) const
+ {
+ SegmentT result_segment;
+ result_segment.length = 0;
+
+ for (const SegmentT &segment : segment_list)
+ {
+ if (segment.name_id != blocked_name_id && segment.length > result_segment.length)
+ {
+ result_segment = segment;
+ }
+ }
+ return result_segment;
+ }
+
+ public:
+ RouteNames operator()(std::vector<SegmentT> &shortest_path_segments,
+ std::vector<SegmentT> &alternative_path_segments,
+ const DataFacadeT *facade) const
+ {
+ RouteNames route_names;
+
+ SegmentT shortest_segment_1, shortest_segment_2;
+ SegmentT alternative_segment_1, alternative_segment_2;
+
+ auto length_comperator = [](const SegmentT &a, const SegmentT &b)
+ { return a.length > b.length; };
+ auto name_id_comperator = [](const SegmentT &a, const SegmentT &b)
+ { return a.name_id < b.name_id; };
+
+ if (shortest_path_segments.empty())
+ {
+ return route_names;
+ }
+
+ // pick the longest segment for the shortest path.
+ std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator);
+ shortest_segment_1 = shortest_path_segments[0];
+ if (!alternative_path_segments.empty())
+ {
+ std::sort(alternative_path_segments.begin(),
+ alternative_path_segments.end(),
+ length_comperator);
+
+ // also pick the longest segment for the alternative path
+ alternative_segment_1 = alternative_path_segments[0];
+ }
+
+ // compute the set difference (for shortest path) depending on names between shortest and
+ // alternative
+ std::vector<SegmentT> shortest_path_set_difference(shortest_path_segments.size());
+ std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), name_id_comperator);
+ std::sort(alternative_path_segments.begin(), alternative_path_segments.end(), name_id_comperator);
+ std::set_difference(shortest_path_segments.begin(),
+ shortest_path_segments.end(),
+ alternative_path_segments.begin(),
+ alternative_path_segments.end(),
+ shortest_path_set_difference.begin(),
+ name_id_comperator);
+
+ std::sort(shortest_path_set_difference.begin(),
+ shortest_path_set_difference.end(),
+ length_comperator);
+ shortest_segment_2 =
+ PickNextLongestSegment(shortest_path_set_difference, shortest_path_segments[0].name_id);
+
+ // compute the set difference (for alternative path) depending on names between shortest and
+ // alternative
+ // vectors are still sorted, no need to do again
+ BOOST_ASSERT(std::is_sorted(shortest_path_segments.begin(),
+ shortest_path_segments.end(),
+ name_id_comperator));
+ BOOST_ASSERT(std::is_sorted(alternative_path_segments.begin(),
+ alternative_path_segments.end(),
+ name_id_comperator));
+
+ std::vector<SegmentT> alternative_path_set_difference(alternative_path_segments.size());
+ std::set_difference(alternative_path_segments.begin(),
+ alternative_path_segments.end(),
+ shortest_path_segments.begin(),
+ shortest_path_segments.end(),
+ alternative_path_set_difference.begin(),
+ name_id_comperator);
+
+ std::sort(alternative_path_set_difference.begin(),
+ alternative_path_set_difference.end(),
+ length_comperator);
+
+ if (!alternative_path_segments.empty())
+ {
+ alternative_segment_2 = PickNextLongestSegment(alternative_path_set_difference,
+ alternative_path_segments[0].name_id);
+ }
+
+ // move the segments into the order in which they occur.
+ if (shortest_segment_1.position > shortest_segment_2.position)
+ {
+ std::swap(shortest_segment_1, shortest_segment_2);
+ }
+ if (alternative_segment_1.position > alternative_segment_2.position)
+ {
+ std::swap(alternative_segment_1, alternative_segment_2);
+ }
+
+ // fetching names for the selected segments
+ route_names.shortest_path_name_1 =
+ facade->GetEscapedNameForNameID(shortest_segment_1.name_id);
+ route_names.shortest_path_name_2 =
+ facade->GetEscapedNameForNameID(shortest_segment_2.name_id);
+
+ route_names.alternative_path_name_1 =
+ facade->GetEscapedNameForNameID(alternative_segment_1.name_id);
+ route_names.alternative_path_name_2 =
+ facade->GetEscapedNameForNameID(alternative_segment_2.name_id);
+
+ return route_names;
+ }
+};
+
+#endif // EXTRACT_ROUTE_NAMES_H
diff --git a/Algorithms/IteratorBasedCRC32.h b/Algorithms/IteratorBasedCRC32.h
index 5d4415c..84a404a 100644
--- a/Algorithms/IteratorBasedCRC32.h
+++ b/Algorithms/IteratorBasedCRC32.h
@@ -1,109 +1,144 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef ITERATORBASEDCRC32_H_
-#define ITERATORBASEDCRC32_H_
+*/
+
+#ifndef ITERATOR_BASED_CRC32_H
+#define ITERATOR_BASED_CRC32_H
+
+#include "../Util/SimpleLogger.h"
-#include <boost/crc.hpp> // for boost::crc_32_type
#include <iostream>
-template<class ContainerT>
-class IteratorbasedCRC32 {
-private:
- typedef typename ContainerT::iterator ContainerT_iterator;
+#if defined(__x86_64__) && !defined(__MINGW64__)
+#include <cpuid.h>
+#else
+#include <boost/crc.hpp> // for boost::crc_32_type
+
+inline void __get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
+{
+ *ecx = 0;
+}
+#endif
+
+template <class ContainerT> class IteratorbasedCRC32
+{
+ private:
+ typedef typename ContainerT::iterator IteratorType;
unsigned crc;
- typedef boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> my_crc_32_type;
- typedef unsigned (IteratorbasedCRC32::*CRC32CFunctionPtr)(char *str, unsigned len, unsigned crc);
-
- unsigned SoftwareBasedCRC32(char *str, unsigned len, unsigned ){
- boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_Processor;
- CRC32_Processor.process_bytes( str, len);
- return CRC32_Processor.checksum();
+ bool use_SSE42_CRC_function;
+
+#if !defined(__x86_64__)
+ boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_processor;
+#endif
+ unsigned SoftwareBasedCRC32(char *str, unsigned len)
+ {
+#if !defined(__x86_64__)
+ CRC32_processor.process_bytes(str, len);
+ return CRC32_processor.checksum();
+#else
+ return 0;
+#endif
}
- unsigned SSEBasedCRC32( char *str, unsigned len, unsigned crc){
- unsigned q=len/sizeof(unsigned),
- r=len%sizeof(unsigned),
- *p=(unsigned*)str/*, crc*/;
-
- //crc=0;
- while (q--) {
- __asm__ __volatile__(
- ".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
- :"=S"(crc)
- :"0"(crc), "c"(*p)
- );
+
+ // adapted from http://byteworm.com/2010/10/13/crc32/
+ unsigned SSE42BasedCRC32(char *str, unsigned len)
+ {
+#if defined(__x86_64__)
+ unsigned q = len / sizeof(unsigned);
+ unsigned r = len % sizeof(unsigned);
+ unsigned *p = (unsigned *)str;
+
+ // crc=0;
+ while (q--)
+ {
+ __asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
+ : "=S"(crc)
+ : "0"(crc), "c"(*p));
++p;
}
- str=(char*)p;
- while (r--) {
- __asm__ __volatile__(
- ".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
- :"=S"(crc)
- :"0"(crc), "c"(*str)
- );
+ str = (char *)p;
+ while (r--)
+ {
+ __asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
+ : "=S"(crc)
+ : "0"(crc), "c"(*str));
++str;
}
+#endif
return crc;
}
- unsigned cpuid(unsigned functionInput){
- unsigned eax;
- unsigned ebx;
- unsigned ecx;
- unsigned edx;
- asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (functionInput));
+ inline unsigned cpuid() const
+ {
+ unsigned eax = 0, ebx = 0, ecx = 0, edx = 0;
+ // on X64 this calls hardware cpuid(.) instr. otherwise a dummy impl.
+ __get_cpuid(1, &eax, &ebx, &ecx, &edx);
return ecx;
}
- CRC32CFunctionPtr detectBestCRC32C(){
- static const int SSE42_BIT = 20;
- unsigned ecx = cpuid(1);
- bool hasSSE42 = ecx & (1 << SSE42_BIT);
- if (hasSSE42) {
- std::cout << "using hardware base sse computation" << std::endl;
- return &IteratorbasedCRC32::SSEBasedCRC32; //crc32 hardware accelarated;
- } else {
- std::cout << "using software base sse computation" << std::endl;
- return &IteratorbasedCRC32::SoftwareBasedCRC32; //crc32cSlicingBy8;
+ bool DetectNativeCRC32Support()
+ {
+ static const int SSE42_BIT = 0x00100000;
+ const unsigned ecx = cpuid();
+ const bool has_SSE42 = (ecx & SSE42_BIT) != 0;
+ if (has_SSE42)
+ {
+ SimpleLogger().Write() << "using hardware based CRC32 computation";
}
- }
- CRC32CFunctionPtr crcFunction;
-public:
- IteratorbasedCRC32(): crc(0) {
- crcFunction = detectBestCRC32C();
+ else
+ {
+ SimpleLogger().Write() << "using software based CRC32 computation";
+ }
+ return has_SSE42;
}
- virtual ~IteratorbasedCRC32() {};
+ public:
+ IteratorbasedCRC32() : crc(0) { use_SSE42_CRC_function = DetectNativeCRC32Support(); }
- unsigned operator()( ContainerT_iterator iter, const ContainerT_iterator end) {
+ unsigned operator()(IteratorType iter, const IteratorType end)
+ {
unsigned crc = 0;
- while(iter != end) {
- char * data = reinterpret_cast<char*>(&(*iter) );
- crc =((*this).*(crcFunction))(data, sizeof(typename ContainerT::value_type*), crc);
+ while (iter != end)
+ {
+ char *data = reinterpret_cast<char *>(&(*iter));
+
+ if (use_SSE42_CRC_function)
+ {
+ crc = SSE42BasedCRC32(data, sizeof(typename ContainerT::value_type));
+ }
+ else
+ {
+ crc = SoftwareBasedCRC32(data, sizeof(typename ContainerT::value_type));
+ }
++iter;
}
return crc;
}
};
-#endif /* ITERATORBASEDCRC32_H_ */
+#endif /* ITERATOR_BASED_CRC32_H */
diff --git a/Algorithms/ObjectToBase64.h b/Algorithms/ObjectToBase64.h
index 8d69c0a..2599283 100644
--- a/Algorithms/ObjectToBase64.h
+++ b/Algorithms/ObjectToBase64.h
@@ -1,67 +1,99 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef OBJECTTOBASE64_H_
#define OBJECTTOBASE64_H_
+#include "../Util/StringUtil.h"
+
+#include <boost/assert.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
-#include <boost/foreach.hpp>
#include <algorithm>
#include <string>
-
-#include "../Util/StringUtil.h"
+#include <vector>
typedef
boost::archive::iterators::base64_from_binary<
- boost::archive::iterators::transform_width<std::string::const_iterator, 6, 8>
-> base64_t;
+ boost::archive::iterators::transform_width<const char *, 6, 8>
+ > base64_t;
typedef
boost::archive::iterators::transform_width<
- boost::archive::iterators::binary_from_base64<std::string::const_iterator>, 8, 6
+ boost::archive::iterators::binary_from_base64<
+ std::string::const_iterator>, 8, 6
> binary_t;
-template<class ToEncodeT>
-static void EncodeObjectToBase64(const ToEncodeT & object, std::string& encoded) {
- encoded.clear();
- char * pointerToOriginalObject = (char *)&object;
- encoded = std::string(base64_t(pointerToOriginalObject), base64_t(pointerToOriginalObject+sizeof(ToEncodeT)));
- //replace "+" with "-" and "/" with "_"
+template<class ObjectT>
+static void EncodeObjectToBase64(const ObjectT & object, std::string& encoded) {
+ const char * char_ptr_to_object = (const char *)&object;
+ std::vector<unsigned char> data(sizeof(object));
+ std::copy(
+ char_ptr_to_object,
+ char_ptr_to_object + sizeof(ObjectT),
+ data.begin()
+ );
+
+ unsigned char number_of_padded_chars = 0; // is in {0,1,2};
+ while(data.size() % 3 != 0) {
+ ++number_of_padded_chars;
+ data.push_back(0x00);
+ }
+
+ BOOST_ASSERT_MSG(
+ 0 == data.size() % 3,
+ "base64 input data size is not a multiple of 3!"
+ );
+ encoded.resize(sizeof(ObjectT));
+ encoded.assign(
+ base64_t( &data[0] ),
+ base64_t( &data[0] + (data.size() - number_of_padded_chars) )
+ );
replaceAll(encoded, "+", "-");
replaceAll(encoded, "/", "_");
}
-template<class ToEncodeT>
-static void DecodeObjectFromBase64(ToEncodeT & object, const std::string& _encoded) {
+template<class ObjectT>
+static void DecodeObjectFromBase64(const std::string& input, ObjectT & object) {
try {
- std::string encoded(_encoded);
+ std::string encoded(input);
//replace "-" with "+" and "_" with "/"
replaceAll(encoded, "-", "+");
replaceAll(encoded, "_", "/");
- char * pointerToDecodedObject = (char *)&object;
- std::string dec(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length() - 1));
- std::copy ( dec.begin(), dec.end(), pointerToDecodedObject );
- } catch(...) {}
+
+ std::copy (
+ binary_t( encoded.begin() ),
+ binary_t( encoded.begin() + encoded.length() - 1),
+ (char *)&object
+ );
+
+ } catch(...) { }
}
#endif /* OBJECTTOBASE64_H_ */
diff --git a/Algorithms/PolylineCompressor.cpp b/Algorithms/PolylineCompressor.cpp
new file mode 100644
index 0000000..a34f8c7
--- /dev/null
+++ b/Algorithms/PolylineCompressor.cpp
@@ -0,0 +1,118 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "PolylineCompressor.h"
+#include "../DataStructures/SegmentInformation.h"
+
+#include <osrm/Coordinate.h>
+
+void PolylineCompressor::encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output)
+ const
+{
+ const unsigned end = static_cast<unsigned>(numbers.size());
+ for (unsigned i = 0; i < end; ++i)
+ {
+ numbers[i] <<= 1;
+ if (numbers[i] < 0)
+ {
+ numbers[i] = ~(numbers[i]);
+ }
+ }
+ for (const int number : numbers)
+ {
+ encodeNumber(number, output);
+ }
+}
+
+void PolylineCompressor::encodeNumber(int number_to_encode, std::string &output) const
+{
+ while (number_to_encode >= 0x20)
+ {
+ const int next_value = (0x20 | (number_to_encode & 0x1f)) + 63;
+ output += static_cast<char>(next_value);
+ if (92 == next_value)
+ {
+ output += static_cast<char>(next_value);
+ }
+ number_to_encode >>= 5;
+ }
+
+ number_to_encode += 63;
+ output += static_cast<char>(number_to_encode);
+ if (92 == number_to_encode)
+ {
+ output += static_cast<char>(number_to_encode);
+ }
+}
+
+JSON::String PolylineCompressor::printEncodedString(const std::vector<SegmentInformation> &polyline)
+ const
+{
+ std::string output;
+ std::vector<int> delta_numbers;
+ if (!polyline.empty())
+ {
+ FixedPointCoordinate last_coordinate = polyline[0].location;
+ delta_numbers.emplace_back(last_coordinate.lat);
+ delta_numbers.emplace_back(last_coordinate.lon);
+ // iterate after skipping the first, already handled, segment
+ for (auto it = ++polyline.cbegin(); it != polyline.cend(); ++it)
+ {
+ const auto &segment = *it;
+ if (segment.necessary)
+ {
+ int lat_diff = segment.location.lat - last_coordinate.lat;
+ int lon_diff = segment.location.lon - last_coordinate.lon;
+ delta_numbers.emplace_back(lat_diff);
+ delta_numbers.emplace_back(lon_diff);
+ last_coordinate = segment.location;
+ }
+ }
+ encodeVectorSignedNumber(delta_numbers, output);
+ }
+ JSON::String return_value(output);
+ return return_value;
+}
+
+JSON::Array
+PolylineCompressor::printUnencodedString(const std::vector<SegmentInformation> &polyline) const
+{
+ JSON::Array json_geometry_array;
+ for (const auto &segment : polyline)
+ {
+ if (segment.necessary)
+ {
+ std::string tmp, output;
+ FixedPointCoordinate::convertInternalLatLonToString(segment.location.lat, tmp);
+ output += (tmp + ",");
+ FixedPointCoordinate::convertInternalLatLonToString(segment.location.lon, tmp);
+ output += tmp;
+ json_geometry_array.values.push_back(output);
+ }
+ }
+ return json_geometry_array;
+}
diff --git a/Algorithms/PolylineCompressor.h b/Algorithms/PolylineCompressor.h
index 7bb143b..5472bd8 100644
--- a/Algorithms/PolylineCompressor.h
+++ b/Algorithms/PolylineCompressor.h
@@ -1,134 +1,51 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef POLYLINECOMPRESSOR_H_
-#define POLYLINECOMPRESSOR_H_
-
-#include <string>
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//#include "../DataStructures/ExtractorStructs.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../Util/StringUtil.h"
+*/
-class PolylineCompressor {
-private:
- inline void encodeVectorSignedNumber(std::vector<int> & numbers, std::string & output) const {
- for(unsigned i = 0; i < numbers.size(); ++i) {
- numbers[i] <<= 1;
- if (numbers[i] < 0) {
- numbers[i] = ~(numbers[i]);
- }
- }
- for(unsigned i = 0; i < numbers.size(); ++i) {
- encodeNumber(numbers[i], output);
- }
- }
+#ifndef POLYLINECOMPRESSOR_H_
+#define POLYLINECOMPRESSOR_H_
- inline void encodeNumber(int numberToEncode, std::string & output) const {
- while (numberToEncode >= 0x20) {
- int nextValue = (0x20 | (numberToEncode & 0x1f)) + 63;
- output += (static_cast<char> (nextValue));
- if(92 == nextValue)
- output += (static_cast<char> (nextValue));
- numberToEncode >>= 5;
- }
+struct SegmentInformation;
- numberToEncode += 63;
- output += (static_cast<char> (numberToEncode));
- if(92 == numberToEncode)
- output += (static_cast<char> (numberToEncode));
- }
+#include "../DataStructures/JSONContainer.h"
-public:
- inline void printEncodedString(const std::vector<SegmentInformation>& polyline, std::string &output) const {
- std::vector<int> deltaNumbers;
- output += "\"";
- if(!polyline.empty()) {
- _Coordinate lastCoordinate = polyline[0].location;
- deltaNumbers.push_back( lastCoordinate.lat );
- deltaNumbers.push_back( lastCoordinate.lon );
- for(unsigned i = 1; i < polyline.size(); ++i) {
- if(!polyline[i].necessary)
- continue;
- deltaNumbers.push_back(polyline[i].location.lat - lastCoordinate.lat);
- deltaNumbers.push_back(polyline[i].location.lon - lastCoordinate.lon);
- lastCoordinate = polyline[i].location;
- }
- encodeVectorSignedNumber(deltaNumbers, output);
- }
- output += "\"";
+#include <string>
+#include <vector>
- }
+class PolylineCompressor
+{
+ private:
+ void encodeVectorSignedNumber(std::vector<int> &numbers, std::string &output) const;
- inline void printEncodedString(const std::vector<_Coordinate>& polyline, std::string &output) const {
- std::vector<int> deltaNumbers(2*polyline.size());
- output += "\"";
- if(!polyline.empty()) {
- deltaNumbers[0] = polyline[0].lat;
- deltaNumbers[1] = polyline[0].lon;
- for(unsigned i = 1; i < polyline.size(); ++i) {
- deltaNumbers[(2*i)] = (polyline[i].lat - polyline[i-1].lat);
- deltaNumbers[(2*i)+1] = (polyline[i].lon - polyline[i-1].lon);
- }
- encodeVectorSignedNumber(deltaNumbers, output);
- }
- output += "\"";
- }
+ void encodeNumber(int number_to_encode, std::string &output) const;
- inline void printUnencodedString(std::vector<_Coordinate> & polyline, std::string & output) const {
- output += "[";
- std::string tmp;
- for(unsigned i = 0; i < polyline.size(); i++) {
- convertInternalLatLonToString(polyline[i].lat, tmp);
- output += "[";
- output += tmp;
- convertInternalLatLonToString(polyline[i].lon, tmp);
- output += ", ";
- output += tmp;
- output += "]";
- if( i < polyline.size()-1 ) {
- output += ",";
- }
- }
- output += "]";
- }
+ public:
+ JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
- inline void printUnencodedString(std::vector<SegmentInformation> & polyline, std::string & output) const {
- output += "[";
- std::string tmp;
- for(unsigned i = 0; i < polyline.size(); i++) {
- if(!polyline[i].necessary)
- continue;
- convertInternalLatLonToString(polyline[i].location.lat, tmp);
- output += "[";
- output += tmp;
- convertInternalLatLonToString(polyline[i].location.lon, tmp);
- output += ", ";
- output += tmp;
- output += "]";
- if( i < polyline.size()-1 ) {
- output += ",";
- }
- }
- output += "]";
- }
+ JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
};
#endif /* POLYLINECOMPRESSOR_H_ */
diff --git a/Algorithms/StronglyConnectedComponents.h b/Algorithms/StronglyConnectedComponents.h
index a831100..e0c31f9 100644
--- a/Algorithms/StronglyConnectedComponents.h
+++ b/Algorithms/StronglyConnectedComponents.h
@@ -1,373 +1,447 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
#ifndef STRONGLYCONNECTEDCOMPONENTS_H_
#define STRONGLYCONNECTEDCOMPONENTS_H_
-#include <cassert>
-
-#include <stack>
-#include <vector>
-
-#include <boost/foreach.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/unordered_map.hpp>
-
-#include <gdal/gdal.h>
-#include <gdal/ogrsf_frmts.h>
-
+#include "../typedefs.h"
#include "../DataStructures/DeallocatingVector.h"
#include "../DataStructures/DynamicGraph.h"
#include "../DataStructures/ImportEdge.h"
-#include "../DataStructures/NodeCoords.h"
+#include "../DataStructures/QueryNode.h"
#include "../DataStructures/Percent.h"
#include "../DataStructures/Restriction.h"
#include "../DataStructures/TurnInstructions.h"
-// Strongly connected components using Tarjan's Algorithm
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/StdHashExtensions.h"
-class TarjanSCC {
-private:
- struct _NodeBasedEdgeData {
- int distance;
- unsigned edgeBasedNodeID;
- unsigned nameID:31;
- bool shortcut:1;
- short type;
- bool isAccessRestricted:1;
- bool forward:1;
- bool backward:1;
- bool roundabout:1;
- bool ignoreInGrid:1;
- };
+#include <osrm/Coordinate.h>
- typedef DynamicGraph< _NodeBasedEdgeData > _NodeBasedDynamicGraph;
- typedef _NodeBasedDynamicGraph::InputEdge _NodeBasedEdge;
- std::vector<NodeInfo> inputNodeInfoList;
- unsigned numberOfTurnRestrictions;
- boost::shared_ptr<_NodeBasedDynamicGraph> _nodeBasedGraph;
- boost::unordered_map<NodeID, bool> _barrierNodes;
- boost::unordered_map<NodeID, bool> _trafficLights;
+#include <boost/assert.hpp>
+#include <boost/filesystem.hpp>
- typedef std::pair<NodeID, NodeID> RestrictionSource;
- typedef std::pair<NodeID, bool> RestrictionTarget;
- typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
- typedef boost::unordered_map<RestrictionSource, unsigned > RestrictionMap;
- std::vector<EmanatingRestrictionsVector> _restrictionBucketVector;
- RestrictionMap _restrictionMap;
+#ifdef __APPLE__
+#include <gdal.h>
+#include <ogrsf_frmts.h>
+#else
+#include <gdal/gdal.h>
+#include <gdal/ogrsf_frmts.h>
+#endif
+#include <cstdint>
-public:
- struct EdgeBasedNode {
- bool operator<(const EdgeBasedNode & other) const {
- return other.id < id;
- }
- bool operator==(const EdgeBasedNode & other) const {
- return id == other.id;
- }
- NodeID id;
- int lat1;
- int lat2;
- int lon1;
- int lon2:31;
- bool belongsToTinyComponent:1;
- NodeID nameID;
- unsigned weight:31;
- bool ignoreInGrid:1;
- };
-
-private:
- DeallocatingVector<EdgeBasedNode> edgeBasedNodes;
+#include <memory>
+#include <stack>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
- struct TarjanNode {
- TarjanNode() : index(UINT_MAX), lowlink(UINT_MAX), onStack(false) {}
+class TarjanSCC
+{
+ private:
+ struct TarjanNode
+ {
+ TarjanNode() : index(UINT_MAX), low_link(UINT_MAX), on_stack(false) {}
unsigned index;
- unsigned lowlink;
- bool onStack;
+ unsigned low_link;
+ bool on_stack;
+ };
+
+ struct TarjanEdgeData
+ {
+ int distance;
+ unsigned name_id : 31;
+ bool shortcut : 1;
+ short type;
+ bool forward : 1;
+ bool backward : 1;
+ bool reversedEdge : 1;
};
- struct TarjanStackFrame {
- explicit TarjanStackFrame(NodeID _v, NodeID p) : v(_v), parent(p) {}
+ struct TarjanStackFrame
+ {
+ explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
NodeID v;
NodeID parent;
};
-public:
- TarjanSCC(int nodes, std::vector<NodeBasedEdge> & inputEdges, std::vector<NodeID> & bn, std::vector<NodeID> & tl, std::vector<_Restriction> & irs, std::vector<NodeInfo> & nI) : inputNodeInfoList(nI), numberOfTurnRestrictions(irs.size()) {
- BOOST_FOREACH(_Restriction & restriction, irs) {
- std::pair<NodeID, NodeID> restrictionSource = std::make_pair(restriction.fromNode, restriction.viaNode);
+
+ typedef DynamicGraph<TarjanEdgeData> TarjanDynamicGraph;
+ typedef TarjanDynamicGraph::InputEdge TarjanEdge;
+ typedef std::pair<NodeID, NodeID> RestrictionSource;
+ typedef std::pair<NodeID, bool> restriction_target;
+ typedef std::vector<restriction_target> EmanatingRestrictionsVector;
+ typedef std::unordered_map<RestrictionSource, unsigned> RestrictionMap;
+
+ std::vector<NodeInfo> m_coordinate_list;
+ std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
+ std::shared_ptr<TarjanDynamicGraph> m_node_based_graph;
+ std::unordered_set<NodeID> m_barrier_node_list;
+ std::unordered_set<NodeID> m_traffic_light_list;
+ unsigned m_restriction_counter;
+ RestrictionMap m_restriction_map;
+
+ public:
+ TarjanSCC(int number_of_nodes,
+ std::vector<NodeBasedEdge> &input_edges,
+ std::vector<NodeID> &bn,
+ std::vector<NodeID> &tl,
+ std::vector<TurnRestriction> &irs,
+ std::vector<NodeInfo> &nI)
+ : m_coordinate_list(nI), m_restriction_counter(irs.size())
+ {
+ for (const TurnRestriction &restriction : irs)
+ {
+ std::pair<NodeID, NodeID> restrictionSource = {restriction.fromNode,
+ restriction.viaNode};
unsigned index;
- RestrictionMap::iterator restrIter = _restrictionMap.find(restrictionSource);
- if(restrIter == _restrictionMap.end()) {
- index = _restrictionBucketVector.size();
- _restrictionBucketVector.resize(index+1);
- _restrictionMap[restrictionSource] = index;
- } else {
- index = restrIter->second;
- //Map already contains an is_only_*-restriction
- if(_restrictionBucketVector.at(index).begin()->second)
+ RestrictionMap::iterator restriction_iterator =
+ m_restriction_map.find(restrictionSource);
+ if (restriction_iterator == m_restriction_map.end())
+ {
+ index = m_restriction_bucket_list.size();
+ m_restriction_bucket_list.resize(index + 1);
+ m_restriction_map.emplace(restrictionSource, index);
+ }
+ else
+ {
+ index = restriction_iterator->second;
+ // Map already contains an is_only_*-restriction
+ if (m_restriction_bucket_list.at(index).begin()->second)
+ {
continue;
- else if(restriction.flags.isOnly){
- //We are going to insert an is_only_*-restriction. There can be only one.
- _restrictionBucketVector.at(index).clear();
+ }
+ else if (restriction.flags.isOnly)
+ {
+ // We are going to insert an is_only_*-restriction. There can be only one.
+ m_restriction_bucket_list.at(index).clear();
}
}
- _restrictionBucketVector.at(index).push_back(std::make_pair(restriction.toNode, restriction.flags.isOnly));
+ m_restriction_bucket_list.at(index)
+ .emplace_back(restriction.toNode, restriction.flags.isOnly);
}
- BOOST_FOREACH(NodeID id, bn) {
- _barrierNodes[id] = true;
- }
- BOOST_FOREACH(NodeID id, tl) {
- _trafficLights[id] = true;
- }
+ m_barrier_node_list.insert(bn.begin(), bn.end());
+ m_traffic_light_list.insert(tl.begin(), tl.end());
- DeallocatingVector< _NodeBasedEdge > edges;
- for ( std::vector< NodeBasedEdge >::const_iterator i = inputEdges.begin(); i != inputEdges.end(); ++i ) {
-
- _NodeBasedEdge edge;
- if(!i->isForward()) {
- edge.source = i->target();
- edge.target = i->source();
- edge.data.backward = i->isForward();
- edge.data.forward = i->isBackward();
- } else {
- edge.source = i->source();
- edge.target = i->target();
- edge.data.forward = i->isForward();
- edge.data.backward = i->isBackward();
- }
- if(edge.source == edge.target)
+ DeallocatingVector<TarjanEdge> edge_list;
+ for (const NodeBasedEdge &input_edge : input_edges)
+ {
+ if (input_edge.source == input_edge.target)
+ {
continue;
+ }
+
+ TarjanEdge edge;
+ if (input_edge.forward)
+ {
+ edge.source = input_edge.source;
+ edge.target = input_edge.target;
+ edge.data.forward = input_edge.forward;
+ edge.data.backward = input_edge.backward;
+ }
+ else
+ {
+ edge.source = input_edge.target;
+ edge.target = input_edge.source;
+ edge.data.backward = input_edge.forward;
+ edge.data.forward = input_edge.backward;
+ }
- edge.data.distance = (std::max)((int)i->weight(), 1 );
- assert( edge.data.distance > 0 );
+ edge.data.distance = (std::max)((int)input_edge.weight, 1);
+ BOOST_ASSERT(edge.data.distance > 0);
edge.data.shortcut = false;
- edge.data.roundabout = i->isRoundabout();
- edge.data.ignoreInGrid = i->ignoreInGrid();
- edge.data.nameID = i->name();
- edge.data.type = i->type();
- edge.data.isAccessRestricted = i->isAccessRestricted();
- edge.data.edgeBasedNodeID = edges.size();
- edges.push_back( edge );
- if( edge.data.backward ) {
- std::swap( edge.source, edge.target );
- edge.data.forward = i->isBackward();
- edge.data.backward = i->isForward();
- edge.data.edgeBasedNodeID = edges.size();
- edges.push_back( edge );
+ edge.data.name_id = input_edge.name_id;
+ edge.data.type = input_edge.type;
+ edge.data.reversedEdge = false;
+ edge_list.push_back(edge);
+ if (edge.data.backward)
+ {
+ std::swap(edge.source, edge.target);
+ edge.data.forward = input_edge.backward;
+ edge.data.backward = input_edge.forward;
+ edge.data.reversedEdge = true;
+ edge_list.push_back(edge);
}
}
- std::vector<NodeBasedEdge>().swap(inputEdges);
- std::sort( edges.begin(), edges.end() );
- _nodeBasedGraph = boost::make_shared<_NodeBasedDynamicGraph>( nodes, edges );
+ input_edges.shrink_to_fit();
+ BOOST_ASSERT_MSG(0 == input_edges.size() && 0 == input_edges.capacity(),
+ "input edge vector not properly deallocated");
+
+ std::sort(edge_list.begin(), edge_list.end());
+ m_node_based_graph = std::make_shared<TarjanDynamicGraph>(number_of_nodes, edge_list);
}
- void Run() {
- Percent p(_nodeBasedGraph->GetNumberOfNodes());
+ ~TarjanSCC() { m_node_based_graph.reset(); }
- const char *pszDriverName = "ESRI Shapefile";
- OGRSFDriver *poDriver;
+ void Run()
+ {
+ // remove files from previous run if exist
+ DeleteFileIfExists("component.dbf");
+ DeleteFileIfExists("component.shx");
+ DeleteFileIfExists("component.shp");
+
+ Percent p(m_node_based_graph->GetNumberOfNodes());
OGRRegisterAll();
- poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(
- pszDriverName );
- if( poDriver == NULL )
+ const char *pszDriverName = "ESRI Shapefile";
+ OGRSFDriver *poDriver =
+ OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName);
+ if (nullptr == poDriver)
{
- printf( "%s driver not available.\n", pszDriverName );
- exit( 1 );
+ throw OSRMException("ESRI Shapefile driver not available");
}
- OGRDataSource *poDS;
+ OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr);
- poDS = poDriver->CreateDataSource( "component.shp", NULL );
- if( poDS == NULL ) {
- printf( "Creation of output file failed.\n" );
- exit( 1 );
+ if (nullptr == poDS)
+ {
+ throw OSRMException("Creation of output file failed");
}
- OGRLayer *poLayer;
+ OGRLayer *poLayer = poDS->CreateLayer("component", nullptr, wkbLineString, nullptr);
- poLayer = poDS->CreateLayer( "component", NULL, wkbLineString, NULL );
- if( poLayer == NULL ) {
- printf( "Layer creation failed.\n" );
- exit( 1 );
+ if (nullptr == poLayer)
+ {
+ throw OSRMException("Layer creation failed.");
}
-
- //The following is a hack to distinguish between stuff that happens before the recursive call and stuff that happens after
- std::stack<std::pair<bool, TarjanStackFrame> > recursionStack; //true = stuff before, false = stuff after call
- std::stack<NodeID> tarjanStack;
- std::vector<unsigned> componentsIndex(_nodeBasedGraph->GetNumberOfNodes(), UINT_MAX);
- std::vector<NodeID> vectorOfComponentSizes;
- std::vector<TarjanNode> tarjanNodes(_nodeBasedGraph->GetNumberOfNodes());
- unsigned currentComponent = 0, sizeOfCurrentComponent = 0;
+ // The following is a hack to distinguish between stuff that happens
+ // before the recursive call and stuff that happens after
+ std::stack<std::pair<bool, TarjanStackFrame>> recursion_stack;
+ // true = stuff before, false = stuff after call
+ std::stack<NodeID> tarjan_stack;
+ std::vector<unsigned> components_index(m_node_based_graph->GetNumberOfNodes(), UINT_MAX);
+ std::vector<NodeID> component_size_vector;
+ std::vector<TarjanNode> tarjan_node_list(m_node_based_graph->GetNumberOfNodes());
+ unsigned component_index = 0, size_of_current_component = 0;
int index = 0;
- for(NodeID node = 0, endNodes = _nodeBasedGraph->GetNumberOfNodes(); node < endNodes; ++node) {
- if(UINT_MAX == componentsIndex[node]) {
- recursionStack.push(std::make_pair(true, TarjanStackFrame(node,node)) );
+ NodeID last_node = m_node_based_graph->GetNumberOfNodes();
+ for (NodeID node = 0; node < last_node; ++node)
+ {
+ if (UINT_MAX == components_index[node])
+ {
+ recursion_stack.emplace(true, TarjanStackFrame(node, node));
}
- while(!recursionStack.empty()) {
- bool beforeRecursion = recursionStack.top().first;
- TarjanStackFrame currentFrame = recursionStack.top().second;
+ while (!recursion_stack.empty())
+ {
+ const bool before_recursion = recursion_stack.top().first;
+ TarjanStackFrame currentFrame = recursion_stack.top().second;
NodeID v = currentFrame.v;
-// INFO("popping node " << v << (beforeRecursion ? " before " : " after ") << "recursion");
- recursionStack.pop();
-
- if(beforeRecursion) {
- //Mark frame to handle tail of recursion
- recursionStack.push(std::make_pair(false, currentFrame));
-
- //Mark essential information for SCC
- tarjanNodes[v].index = index;
- tarjanNodes[v].lowlink = index;
- tarjanStack.push(v);
- tarjanNodes[v].onStack = true;
+ recursion_stack.pop();
+
+ if (before_recursion)
+ {
+ // Mark frame to handle tail of recursion
+ recursion_stack.emplace(false, currentFrame);
+
+ // Mark essential information for SCC
+ tarjan_node_list[v].index = index;
+ tarjan_node_list[v].low_link = index;
+ tarjan_stack.push(v);
+ tarjan_node_list[v].on_stack = true;
++index;
-// INFO("pushing " << v << " onto tarjan stack, idx[" << v << "]=" << tarjanNodes[v].index << ", lowlink["<< v << "]=" << tarjanNodes[v].lowlink);
-
- //Traverse outgoing edges
- for(_NodeBasedDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) {
- _NodeBasedDynamicGraph::NodeIterator vprime = _nodeBasedGraph->GetTarget(e2);
-// INFO("traversing edge (" << v << "," << vprime << ")");
- if(UINT_MAX == tarjanNodes[vprime].index) {
-
- recursionStack.push(std::make_pair(true,TarjanStackFrame(vprime, v)));
- } else {
-// INFO("Node " << vprime << " is already explored");
- if(tarjanNodes[vprime].onStack) {
- unsigned newLowlink = std::min(tarjanNodes[v].lowlink, tarjanNodes[vprime].index);
-// INFO("Setting lowlink[" << v << "] from " << tarjanNodes[v].lowlink << " to " << newLowlink);
- tarjanNodes[v].lowlink = newLowlink;
-// } else {
-// INFO("But node " << vprime << " is not on stack");
+
+ // Traverse outgoing edges
+ for (auto e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
+ {
+ const TarjanDynamicGraph::NodeIterator vprime =
+ m_node_based_graph->GetTarget(e2);
+ if (UINT_MAX == tarjan_node_list[vprime].index)
+ {
+ recursion_stack.emplace(true, TarjanStackFrame(vprime, v));
+ }
+ else
+ {
+ if (tarjan_node_list[vprime].on_stack &&
+ tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
+ {
+ tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
}
}
}
- } else {
-
-// INFO("we are at the end of recursion and checking node " << v);
- { // setting lowlink in its own scope so it does not pollute namespace
- // NodeID parent = (UINT_MAX == tarjanNodes[v].parent ? v : tarjanNodes[v].parent );
-// INFO("parent=" << currentFrame.parent);
-// INFO("tarjanNodes[" << v << "].lowlink=" << tarjanNodes[v].lowlink << ", tarjanNodes[" << currentFrame.parent << "].lowlink=" << tarjanNodes[currentFrame.parent].lowlink);
- //Note the index shift by 1 compared to the recursive version
- tarjanNodes[currentFrame.parent].lowlink = std::min(tarjanNodes[currentFrame.parent].lowlink, tarjanNodes[v].lowlink);
-// INFO("Setting tarjanNodes[" << currentFrame.parent <<"].lowlink=" << tarjanNodes[currentFrame.parent].lowlink);
- }
-// INFO("tarjanNodes[" << v << "].lowlink=" << tarjanNodes[v].lowlink << ", tarjanNodes[" << v << "].index=" << tarjanNodes[v].index);
-
- //after recursion, lets do cycle checking
- //Check if we found a cycle. This is the bottom part of the recursion
- if(tarjanNodes[v].lowlink == tarjanNodes[v].index) {
+ }
+ else
+ {
+ tarjan_node_list[currentFrame.parent].low_link =
+ std::min(tarjan_node_list[currentFrame.parent].low_link,
+ tarjan_node_list[v].low_link);
+ // after recursion, lets do cycle checking
+ // Check if we found a cycle. This is the bottom part of the recursion
+ if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
+ {
NodeID vprime;
- do {
-// INFO("identified component " << currentComponent << ": " << tarjanStack.top());
- vprime = tarjanStack.top(); tarjanStack.pop();
- tarjanNodes[vprime].onStack = false;
- componentsIndex[vprime] = currentComponent;
- ++sizeOfCurrentComponent;
- } while( v != vprime);
- vectorOfComponentSizes.push_back(sizeOfCurrentComponent);
- if(sizeOfCurrentComponent > 1000)
- INFO("large component [" << currentComponent << "]=" << sizeOfCurrentComponent);
- ++currentComponent;
- sizeOfCurrentComponent = 0;
+ do
+ {
+ vprime = tarjan_stack.top();
+ tarjan_stack.pop();
+ tarjan_node_list[vprime].on_stack = false;
+ components_index[vprime] = component_index;
+ ++size_of_current_component;
+ } while (v != vprime);
+
+ component_size_vector.emplace_back(size_of_current_component);
+
+ if (size_of_current_component > 1000)
+ {
+ SimpleLogger().Write() << "large component [" << component_index
+ << "]=" << size_of_current_component;
+ }
+
+ ++component_index;
+ size_of_current_component = 0;
}
}
}
}
- INFO("identified: " << vectorOfComponentSizes.size() << " many components, marking small components");
+ SimpleLogger().Write() << "identified: " << component_size_vector.size()
+ << " many components, marking small components";
- int singleCounter = 0;
- for(unsigned i = 0; i < vectorOfComponentSizes.size(); ++i){
- if(1 == vectorOfComponentSizes[i])
- ++singleCounter;
- }
- INFO("identified " << singleCounter << " SCCs of size 1");
+ unsigned size_one_counter = std::count_if(component_size_vector.begin(),
+ component_size_vector.end(),
+ [] (unsigned value) { return 1 == value;});
- p.reinit(_nodeBasedGraph->GetNumberOfNodes());
- for(_NodeBasedDynamicGraph::NodeIterator u = 0; u < _nodeBasedGraph->GetNumberOfNodes(); ++u ) {
- for(_NodeBasedDynamicGraph::EdgeIterator e1 = _nodeBasedGraph->BeginEdges(u); e1 < _nodeBasedGraph->EndEdges(u); ++e1) {
- _NodeBasedDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1);
+ SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1";
- if(_nodeBasedGraph->GetEdgeData(e1).type != SHRT_MAX) {
- assert(e1 != UINT_MAX);
- assert(u != UINT_MAX);
- assert(v != UINT_MAX);
- //edges that end on bollard nodes may actually be in two distinct components
- if(std::min(vectorOfComponentSizes[componentsIndex[u]], vectorOfComponentSizes[componentsIndex[v]]) < 10) {
-
- //INFO("(" << inputNodeInfoList[u].lat/100000. << ";" << inputNodeInfoList[u].lon/100000. << ") -> (" << inputNodeInfoList[v].lat/100000. << ";" << inputNodeInfoList[v].lon/100000. << ")");
+ uint64_t total_network_distance = 0;
+ p.reinit(m_node_based_graph->GetNumberOfNodes());
+ NodeID last_u_node = m_node_based_graph->GetNumberOfNodes();
+ for (NodeID u = 0; u < last_u_node; ++u)
+ {
+ p.printIncrement();
+ for (auto e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
+ {
+ if (!m_node_based_graph->GetEdgeData(e1).reversedEdge)
+ {
+ continue;
+ }
+ const TarjanDynamicGraph::NodeIterator v = m_node_based_graph->GetTarget(e1);
+
+ total_network_distance +=
+ 100 * FixedPointCoordinate::ApproximateDistance(m_coordinate_list[u].lat,
+ m_coordinate_list[u].lon,
+ m_coordinate_list[v].lat,
+ m_coordinate_list[v].lon);
+
+ if (SHRT_MAX != m_node_based_graph->GetEdgeData(e1).type)
+ {
+ BOOST_ASSERT(e1 != UINT_MAX);
+ BOOST_ASSERT(u != UINT_MAX);
+ BOOST_ASSERT(v != UINT_MAX);
+
+ const unsigned size_of_containing_component =
+ std::min(component_size_vector[components_index[u]],
+ component_size_vector[components_index[v]]);
+
+ // edges that end on bollard nodes may actually be in two distinct components
+ if (size_of_containing_component < 10)
+ {
OGRLineString lineString;
- lineString.addPoint(inputNodeInfoList[u].lon/100000., inputNodeInfoList[u].lat/100000.);
- lineString.addPoint(inputNodeInfoList[v].lon/100000., inputNodeInfoList[v].lat/100000.);
+ lineString.addPoint(m_coordinate_list[u].lon / COORDINATE_PRECISION,
+ m_coordinate_list[u].lat / COORDINATE_PRECISION);
+ lineString.addPoint(m_coordinate_list[v].lon / COORDINATE_PRECISION,
+ m_coordinate_list[v].lat / COORDINATE_PRECISION);
- OGRFeature *poFeature;
- poFeature = OGRFeature::CreateFeature( poLayer->GetLayerDefn() );
- poFeature->SetGeometry( &lineString );
- if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
+ OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn());
+
+ poFeature->SetGeometry(&lineString);
+ if (OGRERR_NONE != poLayer->CreateFeature(poFeature))
{
- ERR( "Failed to create feature in shapefile.\n" );
+ throw OSRMException("Failed to create feature in shapefile.");
}
- OGRFeature::DestroyFeature( poFeature );
+ OGRFeature::DestroyFeature(poFeature);
}
}
}
}
- OGRDataSource::DestroyDataSource( poDS );
- std::vector<NodeID>().swap(vectorOfComponentSizes);
- std::vector<NodeID>().swap(componentsIndex);
+ OGRDataSource::DestroyDataSource(poDS);
+ std::vector<NodeID>().swap(component_size_vector);
+ BOOST_ASSERT_MSG(0 == component_size_vector.size() && 0 == component_size_vector.capacity(),
+ "component_size_vector not properly deallocated");
+
+ std::vector<NodeID>().swap(components_index);
+ BOOST_ASSERT_MSG(0 == components_index.size() && 0 == components_index.capacity(),
+ "icomponents_index not properly deallocated");
+ SimpleLogger().Write() << "total network distance: " << (uint64_t)total_network_distance /
+ 100 / 1000. << " km";
}
-private:
- unsigned CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const {
- std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v);
- RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource);
- if (restrIter != _restrictionMap.end()) {
- unsigned index = restrIter->second;
- BOOST_FOREACH(RestrictionSource restrictionTarget, _restrictionBucketVector.at(index)) {
- if(restrictionTarget.second) {
- return restrictionTarget.first;
+
+ private:
+ unsigned CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const
+ {
+ std::pair<NodeID, NodeID> restriction_source = {u, v};
+ RestrictionMap::const_iterator restriction_iterator =
+ m_restriction_map.find(restriction_source);
+ if (restriction_iterator != m_restriction_map.end())
+ {
+ const unsigned index = restriction_iterator->second;
+ for (const RestrictionSource &restriction_target : m_restriction_bucket_list.at(index))
+ {
+ if (restriction_target.second)
+ {
+ return restriction_target.first;
}
}
}
return UINT_MAX;
}
- bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const {
- //only add an edge if turn is not a U-turn except it is the end of dead-end street.
- std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v);
- RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource);
- if (restrIter != _restrictionMap.end()) {
- unsigned index = restrIter->second;
- BOOST_FOREACH(RestrictionTarget restrictionTarget, _restrictionBucketVector.at(index)) {
- if(w == restrictionTarget.first)
+
+ bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const
+ {
+ // only add an edge if turn is not a U-turn except it is the end of dead-end street.
+ std::pair<NodeID, NodeID> restriction_source = {u, v};
+ RestrictionMap::const_iterator restriction_iterator =
+ m_restriction_map.find(restriction_source);
+ if (restriction_iterator != m_restriction_map.end())
+ {
+ const unsigned index = restriction_iterator->second;
+ for (const restriction_target &restriction_target : m_restriction_bucket_list.at(index))
+ {
+ if (w == restriction_target.first)
+ {
return true;
+ }
}
}
return false;
}
+
+ void DeleteFileIfExists(const std::string &file_name) const
+ {
+ if (boost::filesystem::exists(file_name))
+ {
+ boost::filesystem::remove(file_name);
+ }
+ }
};
#endif /* STRONGLYCONNECTEDCOMPONENTS_H_ */
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3de4c4f..dc202c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,111 +1,307 @@
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8)
project(OSRM)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+include(CheckCXXCompilerFlag)
include(FindPackageHandleStandardArgs)
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
-set(BOOST_COMPONENTS filesystem regex system thread)
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+include(GetGitRevisionDescription)
+git_describe(GIT_DESCRIPTION)
+
+set(bitness 32)
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(bitness 64)
+ message(STATUS "Building on a 64 bit system")
+else()
+ message(WARNING "Building on a 32 bit system is unsupported")
+endif()
+
+if (WIN32 AND MSVC_VERSION LESS 1800)
+ message(FATAL_ERROR "Building with Microsoft compiler needs Visual Studio 2013 or later (Express version works too)")
+endif()
+
+OPTION(WITH_TOOLS "Build ORSM tools" OFF)
+
+include_directories(${CMAKE_SOURCE_DIR}/Include/)
+
+add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp FingerPrint.cpp.alwaysbuild
+ COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FingerPrint-Config.cmake
+ DEPENDS
+ ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp.in
+ COMMENT "Configuring FingerPrint.cpp"
+ VERBATIM)
+
+add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp)
+
+set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread)
+
+configure_file(
+ ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp.in
+ ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp
+)
file(GLOB ExtractorGlob Extractor/*.cpp)
+file(GLOB ImporterGlob DataStructures/Import*.cpp)
+add_library(IMPORT STATIC ${ImporterGlob})
set(ExtractorSources extractor.cpp ${ExtractorGlob})
add_executable(osrm-extract ${ExtractorSources})
-file(GLOB PrepareGlob Contractor/*.cpp)
-set(PrepareSources createHierarchy.cpp ${PrepareGlob})
+file(GLOB PrepareGlob Contractor/*.cpp DataStructures/HilbertValue.cpp DataStructures/RestrictionMap.cpp)
+set(PrepareSources prepare.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)
+file(GLOB ServerGlob Server/*.cpp)
+file(GLOB DescriptorGlob Descriptors/*.cpp)
+file(GLOB DatastructureGlob DataStructures/SearchEngineData.cpp DataStructures/RouteParameters.cpp)
+file(GLOB CoordinateGlob DataStructures/Coordinate.cpp)
+file(GLOB AlgorithmGlob Algorithms/*.cpp)
+file(GLOB HttpGlob Server/Http/*.cpp)
+file(GLOB LibOSRMGlob Library/*.cpp)
+
+set(
+ OSRMSources
+ ${LibOSRMGlob}
+ ${DescriptorGlob}
+ ${DatastructureGlob}
+ ${CoordinateGlob}
+ ${AlgorithmGlob}
+ ${HttpGlob}
+)
+add_library(COORDLIB STATIC ${CoordinateGlob})
+add_library(FINGERPRINT STATIC Util/FingerPrint.cpp)
+add_library(OSRM ${OSRMSources} Util/GitDescription.cpp Util/FingerPrint.cpp)
+add_library(GITDESCRIPTION STATIC Util/GitDescription.cpp)
+add_dependencies(FINGERPRINT FingerPrintConfigure)
+
+add_executable(osrm-routed routed.cpp ${ServerGlob})
+add_executable(osrm-datastore datastore.cpp)
# Check the release mode
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
- set(CMAKE_BUILD_TYPE Release)
-endif(NOT CMAKE_BUILD_TYPE MATCHES Debug)
+ set(CMAKE_BUILD_TYPE Release)
+endif()
if(CMAKE_BUILD_TYPE MATCHES Debug)
- message(STATUS "Configuring OSRM in debug mode")
-endif(CMAKE_BUILD_TYPE MATCHES Debug)
+ message(STATUS "Configuring OSRM in debug mode")
+ if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ message(STATUS "adding profiling flags")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline")
+ set(CMAKE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline")
+ endif()
+endif()
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++
+ message(STATUS "Configuring OSRM in release mode")
+ # Check if LTO is available
+ set(LTO_FLAGS "")
+ CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG)
+ if (HAS_LTO_FLAG)
+ set(LTO_FLAGS "${LTO_FLAGS} -flto")
+
+ # Since gcc 4.9 the LTO format is non-standart ('slim'), so we need to use the build-in tools
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
+ NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "4.9.0")
+ message(STATUS "Using gcc specific binutils for LTO.")
+ set(CMAKE_AR "/usr/bin/gcc-ar")
+ set(CMAKE_RANLIB "/usr/bin/gcc-ranlib")
+ endif()
+ endif (HAS_LTO_FLAG)
endif()
+# Configuring compilers
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ # using Clang
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wunreachable-code -pedantic -fPIC")
+elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ # using GCC
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -fPIC")
+ if (WIN32) # using mingw
+ add_definitions(-DM_PI=3.141592653589793238462643383) # define M_PI
+ add_definitions(-DWIN32)
+ SET(OPTIONAL_SOCKET_LIBS ws2_32 wsock32)
+ SET(OPTIONAL_OMP_LIB gomp)
+ endif()
+elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
+ # using Intel C++
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -ipo -fPIC")
+elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ # using Visual Studio C++
+ set(BOOST_COMPONENTS ${BOOST_COMPONENTS} date_time chrono zlib)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+ add_definitions(-DNOMINMAX) # avoid min and max macros that can break compilation
+ add_definitions(-D_USE_MATH_DEFINES) # define M_PI
+ add_definitions(-D_WIN32_WINNT=0x0501)
+endif()
+
+# disable partitioning of LTO process when possible (fixes Debian issues)
+set(LTO_PARTITION_FLAGS "")
+CHECK_CXX_COMPILER_FLAG("-flto-partition=none" HAS_LTO_PARTITION_FLAG)
+if (HAS_LTO_PARTITION_FLAG)
+ set(LTO_PARTITION_FLAGS "${LTO_PARTITION_FLAGS} -flto-partition=none")
+endif (HAS_LTO_PARTITION_FLAG)
+
+# Add Link-Time-Optimization flags, if supported (GCC >= 4.7) and enabled
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LTO_FLAGS}")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
+set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}")
+
+# Activate C++11
+if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ ADD_DEFINITIONS(-std=c++11)
+endif()
+
+# Configuring other platform dependencies
if(APPLE)
- SET(CMAKE_OSX_ARCHITECTURES "x86_64")
- message("Set Architecture to x64 on OS X")
+ set(CMAKE_OSX_ARCHITECTURES "x86_64")
+ message(STATUS "Set Architecture to x64 on OS X")
+ exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION)
+ string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION})
+ if(OSXLIBSTD)
+ message(STATUS "linking against ${OSXLIBSTD}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=${OSXLIBSTD}")
+ elseif(DARWIN_VERSION GREATER 12)
+ message(STATUS "linking against libc++")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ endif()
+endif()
+
+if(UNIX AND NOT APPLE)
+ target_link_libraries(osrm-prepare rt)
+ target_link_libraries(osrm-datastore rt)
+ target_link_libraries(OSRM rt)
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)
+set(BOOST_MIN_VERSION "1.49.0")
+find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED)
+if(NOT Boost_FOUND)
+ message(FATAL_ERROR "Fatal error: Boost (version >= 1.49.0) required.\n")
+endif()
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})
+target_link_libraries(OSRM ${Boost_LIBRARIES} COORDLIB)
+target_link_libraries(osrm-extract ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB IMPORT)
+target_link_libraries(osrm-prepare ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB IMPORT)
+target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM FINGERPRINT GITDESCRIPTION)
+target_link_libraries(osrm-datastore ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB)
-find_package( Threads REQUIRED )
-target_link_libraries (osrm-extract ${Threads_LIBRARY})
+find_package(Threads REQUIRED)
+target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT} ${OPTIONAL_OMP_LIB})
+target_link_libraries(osrm-datastore ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(OSRM ${CMAKE_THREAD_LIBS_INIT})
-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(TBB REQUIRED)
+if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
+ set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES})
+endif()
+target_link_libraries(osrm-datastore ${TBB_LIBRARIES})
+target_link_libraries(osrm-extract ${TBB_LIBRARIES})
+target_link_libraries(osrm-prepare ${TBB_LIBRARIES})
+target_link_libraries(osrm-routed ${TBB_LIBRARIES})
+include_directories(${TBB_INCLUDE_DIR})
-find_package( LibXml2 REQUIRED )
-include_directories(${LIBXML2_INCLUDE_DIR})
-target_link_libraries (osrm-extract ${LIBXML2_LIBRARIES})
+find_package(Lua52)
+if(NOT LUA52_FOUND)
+ find_package(Lua51 REQUIRED)
+ if(NOT APPLE)
+ find_package(LuaJIT 5.1)
+ endif()
+else()
+ if(NOT APPLE)
+ find_package(LuaJIT 5.2)
+ endif()
+endif()
find_package( Luabind REQUIRED )
include_directories(${LUABIND_INCLUDE_DIR})
-target_link_libraries (osrm-extract ${LUABIND_LIBRARY})
-target_link_libraries (osrm-prepare ${LUABIND_LIBRARY})
+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})
+if( LUAJIT_FOUND )
+ target_link_libraries(osrm-extract ${LUAJIT_LIBRARIES})
+ target_link_libraries(osrm-prepare ${LUAJIT_LIBRARIES})
+else()
+ target_link_libraries(osrm-extract ${LUA_LIBRARY})
+ target_link_libraries(osrm-prepare ${LUA_LIBRARY})
+endif()
+include_directories(${LUA_INCLUDE_DIR})
+
+find_package(LibXml2 REQUIRED)
+include_directories(${LIBXML2_INCLUDE_DIR})
+target_link_libraries(osrm-extract ${LIBXML2_LIBRARIES})
find_package( STXXL REQUIRED )
include_directories(${STXXL_INCLUDE_DIR})
-target_link_libraries (osrm-extract ${STXXL_LIBRARY})
-target_link_libraries (osrm-prepare ${STXXL_LIBRARY})
+target_link_libraries(OSRM ${STXXL_LIBRARY})
+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})
+target_link_libraries(osrm-extract ${OSMPBF_LIBRARY})
+target_link_libraries(osrm-prepare ${OSMPBF_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(BZip2 REQUIRED)
+include_directories(${BZIP_INCLUDE_DIRS})
+target_link_libraries(osrm-extract ${BZIP2_LIBRARIES})
+
+find_package(ZLIB REQUIRED)
+include_directories(${ZLIB_INCLUDE_DIRS})
+target_link_libraries(osrm-extract ${ZLIB_LIBRARY})
+target_link_libraries(osrm-routed ${ZLIB_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)
+ message(STATUS "Activating OSRM internal tools")
+ find_package(GDAL)
+ if(GDAL_FOUND)
+ add_executable(osrm-components Tools/components.cpp)
+ target_link_libraries(osrm-components ${TBB_LIBRARIES} IMPORT)
+ include_directories(${GDAL_INCLUDE_DIR})
+ target_link_libraries(
+ osrm-components
+ ${GDAL_LIBRARIES} ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB)
+ else()
+ message(FATAL_ERROR "libgdal and/or development headers not found")
+ endif()
+ add_executable(osrm-cli Tools/simpleclient.cpp)
+ target_link_libraries(osrm-cli ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM FINGERPRINT GITDESCRIPTION)
+ target_link_libraries(osrm-cli ${TBB_LIBRARIES})
+ add_executable(osrm-io-benchmark Tools/io-benchmark.cpp)
+ target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION)
+ add_executable(osrm-unlock-all Tools/unlock_all_mutexes.cpp)
+ target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION)
+ if(UNIX AND NOT APPLE)
+ target_link_libraries(osrm-unlock-all rt)
+ endif()
+endif()
+
+file(GLOB InstallGlob Include/osrm/*.h Library/OSRM.h)
+
+# Add RPATH info to executables so that when they are run after being installed
+# (i.e., from /usr/local/bin/) the linker can find library dependencies. For
+# more info see http://www.cmake.org/Wiki/CMake_RPATH_handling
+set_property(TARGET osrm-extract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
+set_property(TARGET osrm-prepare PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
+set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
+set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+install(FILES ${InstallGlob} DESTINATION include/osrm)
+install(TARGETS osrm-extract DESTINATION bin)
+install(TARGETS osrm-prepare DESTINATION bin)
+install(TARGETS osrm-datastore DESTINATION bin)
+install(TARGETS osrm-routed DESTINATION bin)
+install(TARGETS OSRM DESTINATION lib)
+list(GET Boost_LIBRARIES 1 BOOST_LIBRARY_FIRST)
+get_filename_component(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_FIRST}" PATH)
+set(BOOST_LIBRARY_LISTING "-L${BOOST_LIBRARY_LISTING}")
+foreach (lib ${Boost_LIBRARIES})
+ get_filename_component(BOOST_LIBRARY_NAME "${lib}" NAME_WE)
+ string(REPLACE "lib" "" BOOST_LIBRARY_NAME ${BOOST_LIBRARY_NAME})
+ set(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_LISTING} -l${BOOST_LIBRARY_NAME}")
+endforeach ()
+
+configure_file(${CMAKE_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY)
+install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig)
diff --git a/Contractor/ContractionCleanup.h b/Contractor/ContractionCleanup.h
deleted file mode 100644
index e42dad3..0000000
--- a/Contractor/ContractionCleanup.h
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- 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 CONTRACTIONCLEANUP_H_INCLUDED
-#define CONTRACTIONCLEANUP_H_INCLUDED
-
-#include <algorithm>
-#ifndef _WIN32
-#include <sys/time.h>
-#endif
-#include "Contractor.h"
-
-class ContractionCleanup {
-private:
-
- struct _CleanupHeapData {
- NodeID parent;
- _CleanupHeapData( NodeID p ) {
- parent = p;
- }
- };
- typedef BinaryHeap< NodeID, NodeID, int, _CleanupHeapData > _Heap;
-
- struct _ThreadData {
- _Heap* _heapForward;
- _Heap* _heapBackward;
- _ThreadData( NodeID nodes ) {
- _heapBackward = new _Heap(nodes);
- _heapForward = new _Heap(nodes);
- }
- ~_ThreadData() {
- delete _heapBackward;
- delete _heapForward;
- }
- };
-
-public:
-
- struct Edge {
- NodeID source;
- NodeID target;
- struct EdgeData {
- NodeID via;
- unsigned nameID;
- int distance;
- TurnInstruction turnInstruction;
- bool shortcut:1;
- bool forward:1;
- bool backward:1;
- } data;
- bool operator<( const Edge& right ) const {
- if ( source != right.source )
- return source < right.source;
- return target < right.target;
- }
-
- //sorts by source and other attributes
- static bool CompareBySource( const Edge& left, const Edge& right ) {
- if ( left.source != right.source )
- return left.source < right.source;
- int l = ( left.data.forward ? -1 : 0 ) + ( left.data.backward ? -1 : 0 );
- int r = ( right.data.forward ? -1 : 0 ) + ( right.data.backward ? -1 : 0 );
- if ( l != r )
- return l < r;
- if ( left.target != right.target )
- return left.target < right.target;
- return left.data.distance < right.data.distance;
- }
-
- bool operator== ( const Edge& right ) const {
- return ( source == right.source && target == right.target && data.distance == right.data.distance &&
- data.shortcut == right.data.shortcut && data.forward == right.data.forward && data.backward == right.data.backward
- && data.via == right.data.via && data.nameID == right.data.nameID
- );
- }
- };
-
- ContractionCleanup( int numNodes, const std::vector< Edge >& edges ) {
- _graph = edges;
- _numNodes = numNodes;
- }
-
- ~ContractionCleanup() {
-
- }
-
- void Run() {
- RemoveUselessShortcuts();
- }
-
- template< class EdgeT >
- void GetData( std::vector< EdgeT >& edges ) {
- for ( int edge = 0, endEdges = ( int ) _graph.size(); edge != endEdges; ++edge ) {
- if(_graph[edge].data.forward || _graph[edge].data.backward) {
- EdgeT newEdge;
- newEdge.source = _graph[edge].source;
- newEdge.target = _graph[edge].target;
- newEdge.data = _graph[edge].data;
- edges.push_back( newEdge );
- }
- }
- sort( edges.begin(), edges.end() );
- }
-
-private:
-
- double _Timestamp() {
- struct timeval tp;
- gettimeofday(&tp, NULL);
- return double(tp.tv_sec) + tp.tv_usec / 1000000.;
- }
-
- void BuildOutgoingGraph() {
- //sort edges by source
- sort( _graph.begin(), _graph.end(), Edge::CompareBySource );
- try {
- _firstEdge.resize( _numNodes + 1 );
- } catch(...) {
- ERR("Not enough RAM on machine");
- return;
- }
- _firstEdge[0] = 0;
- for ( NodeID i = 0, node = 0; i < ( NodeID ) _graph.size(); i++ ) {
- while ( _graph[i].source != node )
- _firstEdge[++node] = i;
- if ( i == ( NodeID ) _graph.size() - 1 )
- while ( node < _numNodes )
- _firstEdge[++node] = ( int ) _graph.size();
- }
- }
-
- void RemoveUselessShortcuts() {
- int maxThreads = omp_get_max_threads();
- std::vector < _ThreadData* > threadData;
- for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
- threadData.push_back( new _ThreadData( _numNodes ) );
- }
-
- INFO("Scanning for useless shortcuts");
- BuildOutgoingGraph();
-/*
- #pragma omp parallel for
- for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
- //only remove shortcuts
- if ( !_graph[i].data.shortcut )
- continue;
-
- if ( _graph[i].data.forward ) {
- int result = _ComputeDistance( _graph[i].source, _graph[i].target, threadData[omp_get_thread_num()] );
- if ( result < _graph[i].data.distance ) {
- _graph[i].data.forward = false;
- }
- }
- if ( _graph[i].data.backward ) {
- int result = _ComputeDistance( _graph[i].target, _graph[i].source, threadData[omp_get_thread_num()] );
- if ( result < _graph[i].data.distance ) {
- _graph[i].data.backward = false;
- }
- }
- }
-*/
- INFO("Removing edges");
- int useful = 0;
- for ( int i = 0; i < ( int ) _graph.size(); i++ ) {
- if ( !_graph[i].data.forward && !_graph[i].data.backward && _graph[i].data.shortcut ) {
- continue;
- }
- _graph[useful] = _graph[i];
- useful++;
- }
- INFO("Removed " << _graph.size() - useful << " useless shortcuts");
- _graph.resize( useful );
-
- for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
- delete threadData[threadNum];
- }
- }
-
- void _ComputeStep( _Heap* heapForward, _Heap* heapBackward, bool forwardDirection, NodeID* middle, int* targetDistance ) {
-
- const NodeID node = heapForward->DeleteMin();
- const int distance = heapForward->GetKey( node );
-
- if ( distance > *targetDistance ) {
- heapForward->DeleteAll();
- return;
- }
-
- if ( heapBackward->WasInserted( node ) ) {
- const int newDistance = heapBackward->GetKey( node ) + distance;
- if ( newDistance < *targetDistance ) {
- *middle = node;
- *targetDistance = newDistance;
- }
- }
-
- for ( int edge = _firstEdge[node], endEdges = _firstEdge[node + 1]; edge != endEdges; ++edge ) {
- const NodeID to = _graph[edge].target;
- const int edgeWeight = _graph[edge].data.distance;
- assert( edgeWeight > 0 );
- const int toDistance = distance + edgeWeight;
-
- if ( (forwardDirection ? _graph[edge].data.forward : _graph[edge].data.backward ) ) {
- //New Node discovered -> Add to Heap + Node Info Storage
- if ( !heapForward->WasInserted( to ) )
- heapForward->Insert( to, toDistance, node );
-
- //Found a shorter Path -> Update distance
- else if ( toDistance < heapForward->GetKey( to ) ) {
- heapForward->DecreaseKey( to, toDistance );
- //new parent
- heapForward->GetData( to ) = node;
- }
- }
- }
- }
-
- int _ComputeDistance( NodeID source, NodeID target, _ThreadData * data ) {
- data->_heapForward->Clear();
- data->_heapBackward->Clear();
- //insert source into heap
- data->_heapForward->Insert( source, 0, source );
- data->_heapBackward->Insert( target, 0, target );
-
- int targetDistance = std::numeric_limits< int >::max();
- NodeID middle = std::numeric_limits<NodeID>::max();
-
- while ( data->_heapForward->Size() + data->_heapBackward->Size() > 0 ) {
- if ( data->_heapForward->Size() > 0 ) {
- _ComputeStep( data->_heapForward, data->_heapBackward, true, &middle, &targetDistance );
- }
-
- if ( data->_heapBackward->Size() > 0 ) {
- _ComputeStep( data->_heapBackward, data->_heapForward, false, &middle, &targetDistance );
- }
- }
- return targetDistance;
- }
- NodeID _numNodes;
- std::vector< Edge > _graph;
- std::vector< unsigned > _firstEdge;
-};
-
-#endif // CONTRACTIONCLEANUP_H_INCLUDED
diff --git a/Contractor/Contractor.h b/Contractor/Contractor.h
index 35d2aa2..a879607 100644
--- a/Contractor/Contractor.h
+++ b/Contractor/Contractor.h
@@ -1,25 +1,32 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef CONTRACTOR_H_INCLUDED
-#define CONTRACTOR_H_INCLUDED
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef CONTRACTOR_H
+#define CONTRACTOR_H
#include "TemporaryStorage.h"
#include "../DataStructures/BinaryHeap.h"
@@ -28,396 +35,510 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "../DataStructures/Percent.h"
#include "../DataStructures/XORFastHash.h"
#include "../DataStructures/XORFastHashStorage.h"
-#include "../Util/OpenMPWrapper.h"
+#include "../Util/SimpleLogger.h"
#include "../Util/StringUtil.h"
+#include "../Util/TimingUtil.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 <tbb/enumerable_thread_specific.h>
+#include <tbb/parallel_for.h>
+#include <tbb/parallel_sort.h>
#include <algorithm>
#include <limits>
#include <vector>
-class Contractor {
+class Contractor
+{
-private:
- struct _ContractorEdgeData {
- _ContractorEdgeData() :
- distance(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0), originalViaNodeID(false) {}
- _ContractorEdgeData( unsigned _distance, unsigned _originalEdges, unsigned _id, bool _shortcut, bool _forward, bool _backward) :
- distance(_distance), id(_id), originalEdges(std::min((unsigned)1<<28, _originalEdges) ), shortcut(_shortcut), forward(_forward), backward(_backward), originalViaNodeID(false) {}
+ private:
+ struct ContractorEdgeData
+ {
+ ContractorEdgeData()
+ : distance(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0),
+ is_original_via_node_ID(false)
+ {
+ }
+ ContractorEdgeData(unsigned _distance,
+ unsigned _originalEdges,
+ unsigned _id,
+ bool _shortcut,
+ bool _forward,
+ bool _backward)
+ : distance(_distance), id(_id),
+ originalEdges(std::min((unsigned)1 << 28, _originalEdges)), shortcut(_shortcut),
+ forward(_forward), backward(_backward), is_original_via_node_ID(false)
+ {
+ }
unsigned distance;
unsigned id;
- unsigned originalEdges:28;
- bool shortcut:1;
- bool forward:1;
- bool backward:1;
- bool originalViaNodeID:1;
+ unsigned originalEdges : 28;
+ bool shortcut : 1;
+ bool forward : 1;
+ bool backward : 1;
+ bool is_original_via_node_ID : 1;
} data;
- struct _HeapData {
+ struct ContractorHeapData
+ {
short hop;
bool target;
- _HeapData() : hop(0), target(false) {}
- _HeapData( short h, bool t ) : hop(h), target(t) {}
+ ContractorHeapData() : hop(0), target(false) {}
+ ContractorHeapData(short h, bool t) : hop(h), target(t) {}
};
- typedef DynamicGraph< _ContractorEdgeData > _DynamicGraph;
- // typedef BinaryHeap< NodeID, NodeID, int, _HeapData, ArrayStorage<NodeID, NodeID> > _Heap;
- typedef BinaryHeap< NodeID, NodeID, int, _HeapData, XORFastHashStorage<NodeID, NodeID> > _Heap;
- typedef _DynamicGraph::InputEdge _ContractorEdge;
-
- struct _ThreadData {
- _Heap heap;
- std::vector< _ContractorEdge > insertedEdges;
- std::vector< NodeID > neighbours;
- _ThreadData( NodeID nodes ): heap( nodes ) { }
+ typedef DynamicGraph<ContractorEdgeData> ContractorGraph;
+ // typedef BinaryHeap< NodeID, NodeID, int, ContractorHeapData, ArrayStorage<NodeID, NodeID>
+ // > ContractorHeap;
+ typedef BinaryHeap<NodeID, NodeID, int, ContractorHeapData, XORFastHashStorage<NodeID, NodeID>>
+ ContractorHeap;
+ typedef ContractorGraph::InputEdge ContractorEdge;
+
+ struct ContractorThreadData
+ {
+ ContractorHeap heap;
+ std::vector<ContractorEdge> inserted_edges;
+ std::vector<NodeID> neighbours;
+ ContractorThreadData(NodeID nodes) : heap(nodes) {}
};
- struct _PriorityData {
+ struct NodePriorityData
+ {
int depth;
- _PriorityData() : depth(0) { }
+ NodePriorityData() : depth(0) {}
};
- struct _ContractionInformation {
- int edgesDeleted;
- int edgesAdded;
- int originalEdgesDeleted;
- int originalEdgesAdded;
- _ContractionInformation() : edgesDeleted(0), edgesAdded(0), originalEdgesDeleted(0), originalEdgesAdded(0) {}
+ struct ContractionStats
+ {
+ int edges_deleted_count;
+ int edges_added_count;
+ int original_edges_deleted_count;
+ int original_edges_added_count;
+ ContractionStats()
+ : edges_deleted_count(0), edges_added_count(0), original_edges_deleted_count(0),
+ original_edges_added_count(0)
+ {
+ }
};
- struct _RemainingNodeData {
- _RemainingNodeData() : id (0), isIndependent(false) {}
- NodeID id:31;
- bool isIndependent:1;
+ struct RemainingNodeData
+ {
+ RemainingNodeData() : id(0), is_independent(false) {}
+ NodeID id : 31;
+ bool is_independent : 1;
};
- struct _NodePartitionor {
- inline bool operator()(_RemainingNodeData & nodeData ) const {
- return !nodeData.isIndependent;
- }
- };
-public:
+ struct ThreadDataContainer
+ {
+ ThreadDataContainer(int number_of_nodes) : number_of_nodes(number_of_nodes) {}
+
+ inline ContractorThreadData* getThreadData()
+ {
+ bool exists = false;
+ auto& ref = data.local(exists);
+ if (!exists)
+ {
+ ref = std::make_shared<ContractorThreadData>(number_of_nodes);
+ }
+
+ return ref.get();
+ }
- template<class ContainerT >
- Contractor( int nodes, ContainerT& inputEdges) {
- std::vector< _ContractorEdge > edges;
- edges.reserve(inputEdges.size()*2);
+ int number_of_nodes;
+ typedef tbb::enumerable_thread_specific<std::shared_ptr<ContractorThreadData>> EnumerableThreadData;
+ EnumerableThreadData data;
+ };
- typename ContainerT::deallocation_iterator diter = inputEdges.dbegin();
- typename ContainerT::deallocation_iterator dend = inputEdges.dend();
+ public:
+ template <class ContainerT> Contractor(int nodes, ContainerT &input_edge_list)
+ {
+ std::vector<ContractorEdge> edges;
+ edges.reserve(input_edge_list.size() * 2);
+ temp_edge_counter = 0;
- _ContractorEdge newEdge;
- while(diter!=dend) {
- newEdge.source = diter->source();
- newEdge.target = diter->target();
- newEdge.data = _ContractorEdgeData( (std::max)((int)diter->weight(), 1 ), 1, diter->id(), false, diter->isForward(), diter->isBackward());
+ auto diter = input_edge_list.dbegin();
+ auto dend = input_edge_list.dend();
- BOOST_ASSERT_MSG( newEdge.data.distance > 0, "edge distance < 1" );
+ ContractorEdge new_edge;
+ while (diter != dend)
+ {
+ new_edge.source = diter->source;
+ new_edge.target = diter->target;
+ new_edge.data = { static_cast<unsigned int>(std::max(diter->weight, 1)),
+ 1,
+ diter->edge_id,
+ false,
+ diter->forward,
+ diter->backward};
+
+ BOOST_ASSERT_MSG(new_edge.data.distance > 0, "edge distance < 1");
#ifndef NDEBUG
- if ( newEdge.data.distance > 24 * 60 * 60 * 10 ) {
- WARN("Edge weight large -> " << newEdge.data.distance);
+ if (new_edge.data.distance > 24 * 60 * 60 * 10)
+ {
+ SimpleLogger().Write(logWARNING) << "Edge weight large -> "
+ << new_edge.data.distance;
}
#endif
- edges.push_back( newEdge );
- std::swap( newEdge.source, newEdge.target );
- newEdge.data.forward = diter->isBackward();
- newEdge.data.backward = diter->isForward();
- edges.push_back( newEdge );
+ edges.push_back(new_edge);
+ std::swap(new_edge.source, new_edge.target);
+ new_edge.data.forward = diter->backward;
+ new_edge.data.backward = diter->forward;
+ edges.push_back(new_edge);
++diter;
}
- //clear input vector and trim the current set of edges with the well-known swap trick
- inputEdges.clear();
- sort( edges.begin(), edges.end() );
+ // clear input vector
+ edges.shrink_to_fit();
+ input_edge_list.clear();
+ tbb::parallel_sort(edges.begin(), edges.end());
NodeID edge = 0;
- for ( NodeID i = 0; i < edges.size(); ) {
+ for (NodeID i = 0; i < edges.size();)
+ {
const NodeID source = edges[i].source;
const NodeID target = edges[i].target;
const NodeID id = edges[i].data.id;
- //remove eigenloops
- if ( source == target ) {
+ // remove eigenloops
+ if (source == target)
+ {
i++;
continue;
}
- _ContractorEdge forwardEdge;
- _ContractorEdge backwardEdge;
- forwardEdge.source = backwardEdge.source = source;
- forwardEdge.target = backwardEdge.target = target;
- forwardEdge.data.forward = backwardEdge.data.backward = true;
- forwardEdge.data.backward = backwardEdge.data.forward = false;
- forwardEdge.data.shortcut = backwardEdge.data.shortcut = false;
- forwardEdge.data.id = backwardEdge.data.id = id;
- forwardEdge.data.originalEdges = backwardEdge.data.originalEdges = 1;
- forwardEdge.data.distance = backwardEdge.data.distance = std::numeric_limits< int >::max();
- //remove parallel edges
- while ( i < edges.size() && edges[i].source == source && edges[i].target == target ) {
- if ( edges[i].data.forward) {
- forwardEdge.data.distance = std::min( edges[i].data.distance, forwardEdge.data.distance );
+ ContractorEdge forward_edge;
+ ContractorEdge reverse_edge;
+ forward_edge.source = reverse_edge.source = source;
+ forward_edge.target = reverse_edge.target = target;
+ forward_edge.data.forward = reverse_edge.data.backward = true;
+ forward_edge.data.backward = reverse_edge.data.forward = false;
+ forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
+ forward_edge.data.id = reverse_edge.data.id = id;
+ forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
+ forward_edge.data.distance = reverse_edge.data.distance =
+ std::numeric_limits<int>::max();
+ // remove parallel edges
+ while (i < edges.size() && edges[i].source == source && edges[i].target == target)
+ {
+ if (edges[i].data.forward)
+ {
+ forward_edge.data.distance =
+ std::min(edges[i].data.distance, forward_edge.data.distance);
}
- if ( edges[i].data.backward) {
- backwardEdge.data.distance = std::min( edges[i].data.distance, backwardEdge.data.distance );
+ if (edges[i].data.backward)
+ {
+ reverse_edge.data.distance =
+ std::min(edges[i].data.distance, reverse_edge.data.distance);
}
++i;
}
- //merge edges (s,t) and (t,s) into bidirectional edge
- if ( forwardEdge.data.distance == backwardEdge.data.distance ) {
- if ( (int)forwardEdge.data.distance != std::numeric_limits< int >::max() ) {
- forwardEdge.data.backward = true;
- edges[edge++] = forwardEdge;
+ // merge edges (s,t) and (t,s) into bidirectional edge
+ if (forward_edge.data.distance == reverse_edge.data.distance)
+ {
+ if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
+ {
+ forward_edge.data.backward = true;
+ edges[edge++] = forward_edge;
}
- } else { //insert seperate edges
- if ( ((int)forwardEdge.data.distance) != std::numeric_limits< int >::max() ) {
- edges[edge++] = forwardEdge;
+ }
+ else
+ { // insert seperate edges
+ if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
+ {
+ edges[edge++] = forward_edge;
}
- if ( (int)backwardEdge.data.distance != std::numeric_limits< int >::max() ) {
- edges[edge++] = backwardEdge;
+ if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
+ {
+ edges[edge++] = reverse_edge;
}
}
}
- std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size() << std::endl;
- edges.resize( edge );
- _graph = boost::make_shared<_DynamicGraph>( nodes, edges );
+ std::cout << "merged " << edges.size() - edge << " edges out of " << edges.size()
+ << std::endl;
+ edges.resize(edge);
+ contractor_graph = std::make_shared<ContractorGraph>(nodes, edges);
edges.clear();
- std::vector<_ContractorEdge>().swap(edges);
+ edges.shrink_to_fit();
+
+ BOOST_ASSERT(0 == edges.capacity());
// unsigned maxdegree = 0;
// NodeID highestNode = 0;
//
- // for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) {
- // unsigned degree = _graph->EndEdges(i) - _graph->BeginEdges(i);
+ // for(unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i) {
+ // unsigned degree = contractor_graph->EndEdges(i) -
+ // contractor_graph->BeginEdges(i);
// if(degree > maxdegree) {
// maxdegree = degree;
// highestNode = i;
// }
// }
//
- // INFO("edges at node with id " << highestNode << " has degree " << maxdegree);
- // for(unsigned i = _graph->BeginEdges(highestNode); i < _graph->EndEdges(highestNode); ++i) {
- // INFO(" ->(" << highestNode << "," << _graph->GetTarget(i) << "); via: " << _graph->GetEdgeData(i).via);
+ // SimpleLogger().Write() << "edges at node with id " << highestNode << " has degree
+ // " << maxdegree;
+ // for(unsigned i = contractor_graph->BeginEdges(highestNode); i <
+ // contractor_graph->EndEdges(highestNode); ++i) {
+ // SimpleLogger().Write() << " ->(" << highestNode << "," <<
+ // contractor_graph->GetTarget(i)
+ // << "); via: " << contractor_graph->GetEdgeData(i).via;
// }
- //Create temporary file
+ // Create temporary file
- // GetTemporaryFileName(temporaryEdgeStorageFilename);
- temporaryStorageSlotID = TemporaryStorage::GetInstance().allocateSlot();
+ edge_storage_slot = TemporaryStorage::GetInstance().AllocateSlot();
std::cout << "contractor finished initalization" << std::endl;
}
- ~Contractor() {
- //Delete temporary file
- // remove(temporaryEdgeStorageFilename.c_str());
- TemporaryStorage::GetInstance().deallocateSlot(temporaryStorageSlotID);
- }
+ ~Contractor() { TemporaryStorage::GetInstance().DeallocateSlot(edge_storage_slot); }
- void Run() {
- const NodeID numberOfNodes = _graph->GetNumberOfNodes();
- Percent p (numberOfNodes);
+ void Run()
+ {
+ // for the preperation we can use a big grain size, which is much faster (probably cache)
+ constexpr size_t InitGrainSize = 100000;
+ constexpr size_t PQGrainSize = 100000;
+ // auto_partitioner will automatically increase the blocksize if we have
+ // a lot of data. It is *important* for the last loop iterations
+ // (which have a very small dataset) that it is devisible.
+ constexpr size_t IndependentGrainSize = 1;
+ constexpr size_t ContractGrainSize = 1;
+ constexpr size_t NeighboursGrainSize = 1;
+ constexpr size_t DeleteGrainSize = 1;
- const unsigned maxThreads = omp_get_max_threads();
- std::vector < _ThreadData* > threadData;
- for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
- threadData.push_back( new _ThreadData( numberOfNodes ) );
- }
- std::cout << "Contractor is using " << maxThreads << " threads" << std::endl;
+ const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
+ Percent p(number_of_nodes);
- NodeID numberOfContractedNodes = 0;
- std::vector< _RemainingNodeData > remainingNodes( numberOfNodes );
- std::vector< float > nodePriority( numberOfNodes );
- std::vector< _PriorityData > nodeData( numberOfNodes );
+ ThreadDataContainer thread_data_list(number_of_nodes);
+
+ NodeID number_of_contracted_nodes = 0;
+ std::vector<RemainingNodeData> remaining_nodes(number_of_nodes);
+ std::vector<float> node_priorities(number_of_nodes);
+ std::vector<NodePriorityData> node_data(number_of_nodes);
+
+
+ // initialize priorities in parallel
+ tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, InitGrainSize),
+ [&remaining_nodes](const tbb::blocked_range<int>& range)
+ {
+ for (int x = range.begin(); x != range.end(); ++x)
+ {
+ remaining_nodes[x].id = x;
+ }
+ }
+ );
- //initialize the variables
-#pragma omp parallel for schedule ( guided )
- for ( int x = 0; x < ( int ) numberOfNodes; ++x ) {
- remainingNodes[x].id = x;
- }
std::cout << "initializing elimination PQ ..." << std::flush;
-#pragma omp parallel
- {
- _ThreadData* data = threadData[omp_get_thread_num()];
-#pragma omp parallel for schedule ( guided )
- for ( int x = 0; x < ( int ) numberOfNodes; ++x ) {
- nodePriority[x] = _Evaluate( data, &nodeData[x], x );
+ tbb::parallel_for(tbb::blocked_range<int>(0, number_of_nodes, PQGrainSize),
+ [this, &node_priorities, &node_data, &thread_data_list](const tbb::blocked_range<int>& range)
+ {
+ ContractorThreadData *data = thread_data_list.getThreadData();
+ for (int x = range.begin(); x != range.end(); ++x)
+ {
+ node_priorities[x] = this->EvaluateNodePriority(data, &node_data[x], x);
+ }
}
- }
- std::cout << "ok" << std::endl << "preprocessing " << numberOfNodes << " nodes ..." << std::flush;
-
- bool flushedContractor = false;
- 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;
-
- //Delete old heap data to free memory that we need for the coming operations
- BOOST_FOREACH(_ThreadData * data, threadData)
- delete data;
- threadData.clear();
-
-
- //Create new priority array
- std::vector<float> newNodePriority(remainingNodes.size());
- //this map gives the old IDs from the new ones, necessary to get a consistent graph at the end of contraction
- oldNodeIDFromNewNodeIDMap.resize(remainingNodes.size());
- //this map gives the new IDs from the old ones, necessary to remap targets from the remaining graph
- std::vector<NodeID> newNodeIDFromOldNodeIDMap(numberOfNodes, UINT_MAX);
-
- //build forward and backward renumbering map and remap ids in remainingNodes and Priorities.
- for(unsigned newNodeID = 0; newNodeID < remainingNodes.size(); ++newNodeID) {
- //create renumbering maps in both directions
- oldNodeIDFromNewNodeIDMap[newNodeID] = remainingNodes[newNodeID].id;
- newNodeIDFromOldNodeIDMap[remainingNodes[newNodeID].id] = newNodeID;
- newNodePriority[newNodeID] = nodePriority[remainingNodes[newNodeID].id];
- remainingNodes[newNodeID].id = newNodeID;
+ );
+ std::cout << "ok" << std::endl << "preprocessing " << number_of_nodes << " nodes ..."
+ << std::flush;
+
+ bool flushed_contractor = false;
+ while (number_of_nodes > 2 && number_of_contracted_nodes < number_of_nodes)
+ {
+ if (!flushed_contractor && (number_of_contracted_nodes > (number_of_nodes * 0.65)))
+ {
+ DeallocatingVector<ContractorEdge> new_edge_set; // this one is not explicitely
+ // cleared since it goes out of
+ // scope anywa
+ std::cout << " [flush " << number_of_contracted_nodes << " nodes] " << std::flush;
+
+ // Delete old heap data to free memory that we need for the coming operations
+ thread_data_list.data.clear();
+
+ // Create new priority array
+ std::vector<float> new_node_priority(remaining_nodes.size());
+ // this map gives the old IDs from the new ones, necessary to get a consistent graph
+ // at the end of contraction
+ orig_node_id_to_new_id_map.resize(remaining_nodes.size());
+ // this map gives the new IDs from the old ones, necessary to remap targets from the
+ // remaining graph
+ std::vector<NodeID> new_node_id_from_orig_id_map(number_of_nodes, UINT_MAX);
+
+ // build forward and backward renumbering map and remap ids in remaining_nodes and
+ // Priorities.
+ for (unsigned new_node_id = 0; new_node_id < remaining_nodes.size(); ++new_node_id)
+ {
+ // create renumbering maps in both directions
+ orig_node_id_to_new_id_map[new_node_id] = remaining_nodes[new_node_id].id;
+ new_node_id_from_orig_id_map[remaining_nodes[new_node_id].id] = new_node_id;
+ new_node_priority[new_node_id] =
+ node_priorities[remaining_nodes[new_node_id].id];
+ remaining_nodes[new_node_id].id = new_node_id;
}
- TemporaryStorage & tempStorage = TemporaryStorage::GetInstance();
- //Write dummy number of edges to temporary file
- // std::ofstream temporaryEdgeStorage(temporaryEdgeStorageFilename.c_str(), std::ios::binary);
- uint64_t initialFilePosition = tempStorage.tell(temporaryStorageSlotID);
- unsigned numberOfTemporaryEdges = 0;
- tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned));
-
- //walk over all nodes
- for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) {
- const NodeID start = i;
- for(_DynamicGraph::EdgeIterator currentEdge = _graph->BeginEdges(start); currentEdge < _graph->EndEdges(start); ++currentEdge) {
- _DynamicGraph::EdgeData & data = _graph->GetEdgeData(currentEdge);
- const NodeID target = _graph->GetTarget(currentEdge);
- if(UINT_MAX == newNodeIDFromOldNodeIDMap[i] ){
- //Save edges of this node w/o renumbering.
- tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&start, sizeof(NodeID));
- tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&target, sizeof(NodeID));
- tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&data, sizeof(_DynamicGraph::EdgeData));
- ++numberOfTemporaryEdges;
- }else {
- //node is not yet contracted.
- //add (renumbered) outgoing edges to new DynamicGraph.
- _ContractorEdge newEdge;
- newEdge.source = newNodeIDFromOldNodeIDMap[start];
- newEdge.target = newNodeIDFromOldNodeIDMap[target];
- newEdge.data = data;
- newEdge.data.originalViaNodeID = true;
- 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);
+ TemporaryStorage &temporary_storage = TemporaryStorage::GetInstance();
+ // walk over all nodes
+ for (unsigned i = 0; i < contractor_graph->GetNumberOfNodes(); ++i)
+ {
+ const NodeID source = i;
+ for (auto current_edge : contractor_graph->GetAdjacentEdgeRange(source))
+ {
+ ContractorGraph::EdgeData &data =
+ contractor_graph->GetEdgeData(current_edge);
+ const NodeID target = contractor_graph->GetTarget(current_edge);
+ if (UINT_MAX == new_node_id_from_orig_id_map[i])
+ {
+ // Save edges of this node w/o renumbering.
+ temporary_storage.WriteToSlot(
+ edge_storage_slot, (char *)&source, sizeof(NodeID));
+ temporary_storage.WriteToSlot(
+ edge_storage_slot, (char *)&target, sizeof(NodeID));
+ temporary_storage.WriteToSlot(edge_storage_slot,
+ (char *)&data,
+ sizeof(ContractorGraph::EdgeData));
+ ++temp_edge_counter;
+ }
+ else
+ {
+ // node is not yet contracted.
+ // add (renumbered) outgoing edges to new DynamicGraph.
+ ContractorEdge new_edge;
+ new_edge.source = new_node_id_from_orig_id_map[source];
+ new_edge.target = new_node_id_from_orig_id_map[target];
+ new_edge.data = data;
+ new_edge.data.is_original_via_node_ID = true;
+ BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[source],
+ "new source id not resolveable");
+ BOOST_ASSERT_MSG(UINT_MAX != new_node_id_from_orig_id_map[target],
+ "new target id not resolveable");
+ new_edge_set.push_back(new_edge);
}
}
}
- //Note the number of temporarily stored edges
- tempStorage.seek(temporaryStorageSlotID, initialFilePosition);
- tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned));
-
- //Delete map from old NodeIDs to new ones.
- std::vector<NodeID>().swap(newNodeIDFromOldNodeIDMap);
-
- //Replace old priorities array by new one
- nodePriority.swap(newNodePriority);
- //Delete old nodePriority vector
- std::vector<float>().swap(newNodePriority);
- //old Graph is removed
- _graph.reset();
-
- //create new graph
- std::sort(newSetOfEdges.begin(), newSetOfEdges.end());
- _graph = boost::make_shared<_DynamicGraph>(remainingNodes.size(), newSetOfEdges);
-
- newSetOfEdges.clear();
- flushedContractor = true;
-
- //INFO: MAKE SURE THIS IS THE LAST OPERATION OF THE FLUSH!
- //reinitialize heaps and ThreadData objects with appropriate size
- for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
- threadData.push_back( new _ThreadData( _graph->GetNumberOfNodes() ) );
- }
+
+ // Delete map from old NodeIDs to new ones.
+ new_node_id_from_orig_id_map.clear();
+ new_node_id_from_orig_id_map.shrink_to_fit();
+
+ // Replace old priorities array by new one
+ node_priorities.swap(new_node_priority);
+ // Delete old node_priorities vector
+ new_node_priority.clear();
+ new_node_priority.shrink_to_fit();
+ // old Graph is removed
+ contractor_graph.reset();
+
+ // create new graph
+ std::sort(new_edge_set.begin(), new_edge_set.end());
+ contractor_graph =
+ std::make_shared<ContractorGraph>(remaining_nodes.size(), new_edge_set);
+
+ new_edge_set.clear();
+ flushed_contractor = true;
+
+ // INFO: MAKE SURE THIS IS THE LAST OPERATION OF THE FLUSH!
+ // reinitialize heaps and ThreadData objects with appropriate size
+ thread_data_list.number_of_nodes = contractor_graph->GetNumberOfNodes();
}
- const int last = ( int ) remainingNodes.size();
-#pragma omp parallel
- {
- //determine independent node set
- _ThreadData* const data = threadData[omp_get_thread_num()];
-#pragma omp for schedule ( guided )
- for ( int i = 0; i < last; ++i ) {
- const NodeID node = remainingNodes[i].id;
- remainingNodes[i].isIndependent = _IsIndependent( nodePriority/*, nodeData*/, data, node );
+ const int last = (int)remaining_nodes.size();
+ tbb::parallel_for(tbb::blocked_range<int>(0, last, IndependentGrainSize),
+ [this, &node_priorities, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
+ {
+ ContractorThreadData *data = thread_data_list.getThreadData();
+ // determine independent node set
+ for (int i = range.begin(); i != range.end(); ++i)
+ {
+ const NodeID node = remaining_nodes[i].id;
+ remaining_nodes[i].is_independent =
+ this->IsNodeIndependent(node_priorities, data, node);
+ }
}
- }
- _NodePartitionor functor;
- const std::vector < _RemainingNodeData >::const_iterator first = stable_partition( remainingNodes.begin(), remainingNodes.end(), functor );
- const int firstIndependent = first - remainingNodes.begin();
- //contract independent nodes
-#pragma omp parallel
- {
- _ThreadData* data = threadData[omp_get_thread_num()];
-#pragma omp for schedule ( guided ) nowait
- for ( int position = firstIndependent ; position < last; ++position ) {
- NodeID x = remainingNodes[position].id;
- _Contract< false > ( data, x );
- //nodePriority[x] = -1;
+ );
+
+ const auto first = stable_partition(remaining_nodes.begin(),
+ remaining_nodes.end(),
+ [](RemainingNodeData node_data)
+ { return !node_data.is_independent; });
+ const int first_independent_node = static_cast<int>(first - remaining_nodes.begin());
+
+ // contract independent nodes
+ tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, ContractGrainSize),
+ [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
+ {
+ ContractorThreadData *data = thread_data_list.getThreadData();
+ for (int position = range.begin(); position != range.end(); ++position)
+ {
+ const NodeID x = remaining_nodes[position].id;
+ this->ContractNode<false>(data, x);
+ }
+ }
+ );
+ // make sure we really sort each block
+ tbb::parallel_for(thread_data_list.data.range(),
+ [&](const ThreadDataContainer::EnumerableThreadData::range_type& range)
+ {
+ for (auto& data : range)
+ std::sort(data->inserted_edges.begin(),
+ data->inserted_edges.end());
+ }
+ );
+ tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, DeleteGrainSize),
+ [this, &remaining_nodes, &thread_data_list](const tbb::blocked_range<int>& range)
+ {
+ ContractorThreadData *data = thread_data_list.getThreadData();
+ for (int position = range.begin(); position != range.end(); ++position)
+ {
+ const NodeID x = remaining_nodes[position].id;
+ this->DeleteIncomingEdges(data, x);
+ }
}
+ );
- std::sort( data->insertedEdges.begin(), data->insertedEdges.end() );
- }
-#pragma omp parallel
+ // insert new edges
+ for (auto& data : thread_data_list.data)
{
- _ThreadData* data = threadData[omp_get_thread_num()];
-#pragma omp for schedule ( guided ) nowait
- for ( int position = firstIndependent ; position < last; ++position ) {
- NodeID x = remainingNodes[position].id;
- _DeleteIncomingEdges( data, x );
- }
- }
- //insert new edges
- for ( unsigned threadNum = 0; threadNum < maxThreads; ++threadNum ) {
- _ThreadData& data = *threadData[threadNum];
- BOOST_FOREACH(const _ContractorEdge& edge, data.insertedEdges) {
- _DynamicGraph::EdgeIterator currentEdgeID = _graph->FindEdge(edge.source, edge.target);
- if(currentEdgeID < _graph->EndEdges(edge.source) ) {
- _DynamicGraph::EdgeData & currentEdgeData = _graph->GetEdgeData(currentEdgeID);
- if( currentEdgeData.shortcut
- && edge.data.forward == currentEdgeData.forward
- && edge.data.backward == currentEdgeData.backward ) {
- currentEdgeData.distance = std::min(currentEdgeData.distance, edge.data.distance);
+ for (const ContractorEdge &edge : data->inserted_edges)
+ {
+ const EdgeID current_edge_ID = contractor_graph->FindEdge(edge.source, edge.target);
+ if (current_edge_ID < contractor_graph->EndEdges(edge.source))
+ {
+ ContractorGraph::EdgeData ¤t_data =
+ contractor_graph->GetEdgeData(current_edge_ID);
+ if (current_data.shortcut && edge.data.forward == current_data.forward &&
+ edge.data.backward == current_data.backward &&
+ edge.data.distance < current_data.distance)
+ {
+ // found a duplicate edge with smaller weight, update it.
+ current_data = edge.data;
continue;
}
}
- _graph->InsertEdge( edge.source, edge.target, edge.data );
+ contractor_graph->InsertEdge(edge.source, edge.target, edge.data);
}
- data.insertedEdges.clear();
+ data->inserted_edges.clear();
}
- //update priorities
-#pragma omp parallel
- {
- _ThreadData* data = threadData[omp_get_thread_num()];
-#pragma omp for schedule ( guided ) nowait
- for ( int position = firstIndependent ; position < last; ++position ) {
- NodeID x = remainingNodes[position].id;
- _UpdateNeighbours( nodePriority, nodeData, data, x );
+
+ tbb::parallel_for(tbb::blocked_range<int>(first_independent_node, last, NeighboursGrainSize),
+ [this, &remaining_nodes, &node_priorities, &node_data, &thread_data_list](const tbb::blocked_range<int>& range)
+ {
+ ContractorThreadData *data = thread_data_list.getThreadData();
+ for (int position = range.begin(); position != range.end(); ++position)
+ {
+ NodeID x = remaining_nodes[position].id;
+ this->UpdateNodeNeighbours(node_priorities, node_data, data, x);
+ }
}
- }
- //remove contracted nodes from the pool
- numberOfContractedNodes += last - firstIndependent;
- remainingNodes.resize( firstIndependent );
- std::vector< _RemainingNodeData>( remainingNodes ).swap( remainingNodes );
+ );
+
+ // remove contracted nodes from the pool
+ number_of_contracted_nodes += last - first_independent_node;
+ remaining_nodes.resize(first_independent_node);
+ remaining_nodes.shrink_to_fit();
// unsigned maxdegree = 0;
// unsigned avgdegree = 0;
// unsigned mindegree = UINT_MAX;
// unsigned quaddegree = 0;
//
- // for(unsigned i = 0; i < remainingNodes.size(); ++i) {
- // unsigned degree = _graph->EndEdges(remainingNodes[i].first) - _graph->BeginEdges(remainingNodes[i].first);
+ // for(unsigned i = 0; i < remaining_nodes.size(); ++i) {
+ // unsigned degree = contractor_graph->EndEdges(remaining_nodes[i].first)
+ // -
+ // contractor_graph->BeginEdges(remaining_nodes[i].first);
// if(degree > maxdegree)
// maxdegree = degree;
// if(degree < mindegree)
@@ -427,331 +548,431 @@ public:
// quaddegree += (degree*degree);
// }
//
- // avgdegree /= std::max((unsigned)1,(unsigned)remainingNodes.size() );
- // quaddegree /= std::max((unsigned)1,(unsigned)remainingNodes.size() );
+ // avgdegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
+ // quaddegree /= std::max((unsigned)1,(unsigned)remaining_nodes.size() );
//
- // INFO("rest: " << remainingNodes.size() << ", max: " << maxdegree << ", min: " << mindegree << ", avg: " << avgdegree << ", quad: " << quaddegree);
+ // SimpleLogger().Write() << "rest: " << remaining_nodes.size() << ", max: "
+ // << maxdegree << ", min: " << mindegree << ", avg: " << avgdegree << ",
+ // quad: " << quaddegree;
- p.printStatus(numberOfContractedNodes);
+ p.printStatus(number_of_contracted_nodes);
}
- BOOST_FOREACH(_ThreadData * data, threadData)
- delete data;
- threadData.clear();
+
+ thread_data_list.data.clear();
}
- template< class Edge >
- inline void GetEdges( DeallocatingVector< Edge >& edges ) {
- Percent p (_graph->GetNumberOfNodes());
- INFO("Getting edges of minimized graph");
- NodeID numberOfNodes = _graph->GetNumberOfNodes();
- if(_graph->GetNumberOfNodes()) {
- for ( NodeID node = 0; node < numberOfNodes; ++node ) {
+ template <class Edge> inline void GetEdges(DeallocatingVector<Edge> &edges)
+ {
+ Percent p(contractor_graph->GetNumberOfNodes());
+ SimpleLogger().Write() << "Getting edges of minimized graph";
+ const NodeID number_of_nodes = contractor_graph->GetNumberOfNodes();
+ if (contractor_graph->GetNumberOfNodes())
+ {
+ Edge new_edge;
+ for (NodeID node = 0; node < number_of_nodes; ++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];
- } else {
- newEdge.source = node;
- newEdge.target = target;
+ for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
+ {
+ const NodeID target = contractor_graph->GetTarget(edge);
+ const ContractorGraph::EdgeData &data = contractor_graph->GetEdgeData(edge);
+ if (!orig_node_id_to_new_id_map.empty())
+ {
+ new_edge.source = orig_node_id_to_new_id_map[node];
+ new_edge.target = orig_node_id_to_new_id_map[target];
+ }
+ else
+ {
+ new_edge.source = node;
+ new_edge.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 && oldNodeIDFromNewNodeIDMap.size()) {
- newEdge.data.id = oldNodeIDFromNewNodeIDMap[data.id];
- } else {
- newEdge.data.id = data.id;
+ BOOST_ASSERT_MSG(UINT_MAX != new_edge.source, "Source id invalid");
+ BOOST_ASSERT_MSG(UINT_MAX != new_edge.target, "Target id invalid");
+ new_edge.data.distance = data.distance;
+ new_edge.data.shortcut = data.shortcut;
+ if (!data.is_original_via_node_ID && !orig_node_id_to_new_id_map.empty())
+ {
+ new_edge.data.id = orig_node_id_to_new_id_map[data.id];
}
- 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 );
+ else
+ {
+ new_edge.data.id = data.id;
+ }
+ BOOST_ASSERT_MSG(new_edge.data.id != INT_MAX, // 2^31
+ "edge id invalid");
+ new_edge.data.forward = data.forward;
+ new_edge.data.backward = data.backward;
+ edges.push_back(new_edge);
}
}
}
- _graph.reset();
- std::vector<NodeID>().swap(oldNodeIDFromNewNodeIDMap);
-
- TemporaryStorage & tempStorage = TemporaryStorage::GetInstance();
- //Also get the edges from temporary storage
- unsigned numberOfTemporaryEdges = 0;
- tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned));
- //loads edges of graph before renumbering, no need for further numbering action.
- NodeID start;
+ contractor_graph.reset();
+ orig_node_id_to_new_id_map.clear();
+ orig_node_id_to_new_id_map.shrink_to_fit();
+
+ BOOST_ASSERT(0 == orig_node_id_to_new_id_map.capacity());
+ TemporaryStorage &temporary_storage = TemporaryStorage::GetInstance();
+ // loads edges of graph before renumbering, no need for further numbering action.
+ NodeID source;
NodeID target;
- //edges.reserve(edges.size()+numberOfTemporaryEdges);
- _DynamicGraph::EdgeData data;
- for(unsigned i = 0; i < numberOfTemporaryEdges; ++i) {
- tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&start, sizeof(NodeID));
- tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&target, sizeof(NodeID));
- tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&data, sizeof(_DynamicGraph::EdgeData));
- Edge newEdge;
- newEdge.source = start;
- newEdge.target = target;
- newEdge.data.distance = data.distance;
- newEdge.data.shortcut = data.shortcut;
- newEdge.data.id = data.id;
- newEdge.data.forward = data.forward;
- newEdge.data.backward = data.backward;
- edges.push_back( newEdge );
+ ContractorGraph::EdgeData data;
+
+ Edge restored_edge;
+ for (unsigned i = 0; i < temp_edge_counter; ++i)
+ {
+ temporary_storage.ReadFromSlot(edge_storage_slot, (char *)&source, sizeof(NodeID));
+ temporary_storage.ReadFromSlot(edge_storage_slot, (char *)&target, sizeof(NodeID));
+ temporary_storage.ReadFromSlot(
+ edge_storage_slot, (char *)&data, sizeof(ContractorGraph::EdgeData));
+ restored_edge.source = source;
+ restored_edge.target = target;
+ restored_edge.data.distance = data.distance;
+ restored_edge.data.shortcut = data.shortcut;
+ restored_edge.data.id = data.id;
+ restored_edge.data.forward = data.forward;
+ restored_edge.data.backward = data.backward;
+ edges.push_back(restored_edge);
}
- tempStorage.deallocateSlot(temporaryStorageSlotID);
+ temporary_storage.DeallocateSlot(edge_storage_slot);
}
-private:
- inline void _Dijkstra( const int maxDistance, const unsigned numTargets, const int maxNodes, _ThreadData* const data, const NodeID middleNode ){
+ private:
+ inline void Dijkstra(const int max_distance,
+ const unsigned number_of_targets,
+ const int maxNodes,
+ ContractorThreadData *const data,
+ const NodeID middleNode)
+ {
- _Heap& heap = data->heap;
+ ContractorHeap &heap = data->heap;
int nodes = 0;
- unsigned targetsFound = 0;
- while ( heap.Size() > 0 ) {
+ unsigned number_of_targets_found = 0;
+ while (heap.Size() > 0)
+ {
const NodeID node = heap.DeleteMin();
- const int distance = heap.GetKey( node );
- const short currentHop = heap.GetData( node ).hop+1;
+ const int distance = heap.GetKey(node);
+ const short current_hop = heap.GetData(node).hop + 1;
- if ( ++nodes > maxNodes )
+ if (++nodes > maxNodes)
+ {
return;
- //Destination settled?
- if ( distance > maxDistance )
+ }
+ // Destination settled?
+ if (distance > max_distance)
+ {
return;
+ }
- if ( heap.GetData( node ).target ) {
- ++targetsFound;
- if ( targetsFound >= numTargets ) {
+ if (heap.GetData(node).target)
+ {
+ ++number_of_targets_found;
+ if (number_of_targets_found >= number_of_targets)
+ {
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 ){
+ // iterate over all edges of node
+ for (auto edge : contractor_graph->GetAdjacentEdgeRange(node))
+ {
+ const ContractorEdgeData &data = contractor_graph->GetEdgeData(edge);
+ if (!data.forward)
+ {
continue;
}
- const NodeID to = _graph->GetTarget( edge );
- if(middleNode == to) {
+ const NodeID to = contractor_graph->GetTarget(edge);
+ if (middleNode == to)
+ {
continue;
}
- const int toDistance = distance + data.distance;
+ const int to_distance = distance + data.distance;
- //New Node discovered -> Add to Heap + Node Info Storage
- if ( !heap.WasInserted( to ) ) {
- heap.Insert( to, toDistance, _HeapData(currentHop, false) );
+ // New Node discovered -> Add to Heap + Node Info Storage
+ if (!heap.WasInserted(to))
+ {
+ heap.Insert(to, to_distance, ContractorHeapData(current_hop, false));
}
- //Found a shorter Path -> Update distance
- else if ( toDistance < heap.GetKey( to ) ) {
- heap.DecreaseKey( to, toDistance );
- heap.GetData( to ).hop = currentHop;
+ // Found a shorter Path -> Update distance
+ else if (to_distance < heap.GetKey(to))
+ {
+ heap.DecreaseKey(to, to_distance);
+ heap.GetData(to).hop = current_hop;
}
}
}
}
- inline float _Evaluate( _ThreadData* const data, _PriorityData* const nodeData, const NodeID node){
- _ContractionInformation stats;
+ inline float EvaluateNodePriority(ContractorThreadData *const data,
+ NodePriorityData *const node_data,
+ const NodeID node)
+ {
+ ContractionStats stats;
- //perform simulated contraction
- _Contract< true> ( data, node, &stats );
+ // perform simulated contraction
+ ContractNode<true>(data, node, &stats);
// Result will contain the priority
float result;
- if ( 0 == (stats.edgesDeleted*stats.originalEdgesDeleted) )
- result = 1 * nodeData->depth;
+ if (0 == (stats.edges_deleted_count * stats.original_edges_deleted_count))
+ {
+ result = 1.f * node_data->depth;
+ }
else
- result = 2 * ((( float ) stats.edgesAdded ) / stats.edgesDeleted ) + 4 * ((( float ) stats.originalEdgesAdded ) / stats.originalEdgesDeleted ) + 1 * nodeData->depth;
- assert( result >= 0 );
+ {
+ result = 2.f * (((float)stats.edges_added_count) / stats.edges_deleted_count) +
+ 4.f * (((float)stats.original_edges_added_count) /
+ stats.original_edges_deleted_count) +
+ 1.f * node_data->depth;
+ }
+ BOOST_ASSERT(result >= 0);
return result;
}
- template< bool Simulate >
- inline bool _Contract( _ThreadData* data, NodeID node, _ContractionInformation* stats = NULL ) {
- _Heap& heap = data->heap;
- int insertedEdgesSize = data->insertedEdges.size();
- std::vector< _ContractorEdge >& insertedEdges = data->insertedEdges;
-
- for ( _DynamicGraph::EdgeIterator inEdge = _graph->BeginEdges( node ), endInEdges = _graph->EndEdges( node ); inEdge != endInEdges; ++inEdge ) {
- const _ContractorEdgeData& inData = _graph->GetEdgeData( inEdge );
- const NodeID source = _graph->GetTarget( inEdge );
- if ( Simulate ) {
- assert( stats != NULL );
- ++stats->edgesDeleted;
- stats->originalEdgesDeleted += inData.originalEdges;
+ template <bool RUNSIMULATION>
+ inline bool
+ ContractNode(ContractorThreadData *data, NodeID node, ContractionStats *stats = nullptr)
+ {
+ ContractorHeap &heap = data->heap;
+ int inserted_edges_size = data->inserted_edges.size();
+ std::vector<ContractorEdge> &inserted_edges = data->inserted_edges;
+
+ for (auto in_edge : contractor_graph->GetAdjacentEdgeRange(node))
+ {
+ const ContractorEdgeData &in_data = contractor_graph->GetEdgeData(in_edge);
+ const NodeID source = contractor_graph->GetTarget(in_edge);
+ if (RUNSIMULATION)
+ {
+ BOOST_ASSERT(stats != nullptr);
+ ++stats->edges_deleted_count;
+ stats->original_edges_deleted_count += in_data.originalEdges;
}
- if ( !inData.backward )
+ if (!in_data.backward)
+ {
continue;
+ }
heap.Clear();
- heap.Insert( source, 0, _HeapData() );
- int maxDistance = 0;
- unsigned numTargets = 0;
+ heap.Insert(source, 0, ContractorHeapData());
+ int max_distance = 0;
+ unsigned number_of_targets = 0;
- for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) {
- const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge );
- if ( !outData.forward ) {
+ for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
+ {
+ const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
+ if (!out_data.forward)
+ {
continue;
}
- const NodeID target = _graph->GetTarget( outEdge );
- const int pathDistance = inData.distance + outData.distance;
- maxDistance = std::max( maxDistance, pathDistance );
- if ( !heap.WasInserted( target ) ) {
- heap.Insert( target, INT_MAX, _HeapData( 0, true ) );
- ++numTargets;
+ const NodeID target = contractor_graph->GetTarget(out_edge);
+ const int path_distance = in_data.distance + out_data.distance;
+ max_distance = std::max(max_distance, path_distance);
+ if (!heap.WasInserted(target))
+ {
+ heap.Insert(target, INT_MAX, ContractorHeapData(0, true));
+ ++number_of_targets;
}
}
- if( Simulate ) {
- _Dijkstra( maxDistance, numTargets, 1000, data, node );
- } else {
- _Dijkstra( maxDistance, numTargets, 2000, data, node );
+ if (RUNSIMULATION)
+ {
+ Dijkstra(max_distance, number_of_targets, 1000, 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 ) {
+ else
+ {
+ Dijkstra(max_distance, number_of_targets, 2000, data, node);
+ }
+ for (auto out_edge : contractor_graph->GetAdjacentEdgeRange(node))
+ {
+ const ContractorEdgeData &out_data = contractor_graph->GetEdgeData(out_edge);
+ if (!out_data.forward)
+ {
continue;
}
- const NodeID target = _graph->GetTarget( outEdge );
- const int pathDistance = inData.distance + outData.distance;
- const int distance = heap.GetKey( target );
- if ( pathDistance < distance ) {
- if ( Simulate ) {
- assert( stats != NULL );
- stats->edgesAdded+=2;
- stats->originalEdgesAdded += 2* ( outData.originalEdges + inData.originalEdges );
- } else {
- _ContractorEdge newEdge;
- newEdge.source = source;
- newEdge.target = target;
- newEdge.data = _ContractorEdgeData( pathDistance, outData.originalEdges + inData.originalEdges, node/*, 0, inData.turnInstruction*/, true, true, false);;
- insertedEdges.push_back( newEdge );
- std::swap( newEdge.source, newEdge.target );
- newEdge.data.forward = false;
- newEdge.data.backward = true;
- insertedEdges.push_back( newEdge );
+ const NodeID target = contractor_graph->GetTarget(out_edge);
+ const int path_distance = in_data.distance + out_data.distance;
+ const int distance = heap.GetKey(target);
+ if (path_distance < distance)
+ {
+ if (RUNSIMULATION)
+ {
+ BOOST_ASSERT(stats != nullptr);
+ stats->edges_added_count += 2;
+ stats->original_edges_added_count +=
+ 2 * (out_data.originalEdges + in_data.originalEdges);
+ }
+ else
+ {
+ ContractorEdge new_edge;
+ new_edge.source = source;
+ new_edge.target = target;
+ new_edge.data =
+ ContractorEdgeData(path_distance,
+ out_data.originalEdges + in_data.originalEdges,
+ node /*, 0, in_data.turnInstruction*/,
+ true,
+ true,
+ false);
+ inserted_edges.push_back(new_edge);
+ std::swap(new_edge.source, new_edge.target);
+ new_edge.data.forward = false;
+ new_edge.data.backward = true;
+ inserted_edges.push_back(new_edge);
}
}
}
}
- if ( !Simulate ) {
- for ( int i = insertedEdgesSize, iend = insertedEdges.size(); i < iend; ++i ) {
+ if (!RUNSIMULATION)
+ {
+ int iend = inserted_edges.size();
+ for (int i = inserted_edges_size; i < iend; ++i)
+ {
bool found = false;
- for ( int other = i + 1 ; other < iend ; ++other ) {
- if ( insertedEdges[other].source != insertedEdges[i].source )
+ for (int other = i + 1; other < iend; ++other)
+ {
+ if (inserted_edges[other].source != inserted_edges[i].source)
+ {
continue;
- if ( insertedEdges[other].target != insertedEdges[i].target )
+ }
+ if (inserted_edges[other].target != inserted_edges[i].target)
+ {
continue;
- if ( insertedEdges[other].data.distance != insertedEdges[i].data.distance )
+ }
+ if (inserted_edges[other].data.distance != inserted_edges[i].data.distance)
+ {
continue;
- if ( insertedEdges[other].data.shortcut != insertedEdges[i].data.shortcut )
+ }
+ if (inserted_edges[other].data.shortcut != inserted_edges[i].data.shortcut)
+ {
continue;
- insertedEdges[other].data.forward |= insertedEdges[i].data.forward;
- insertedEdges[other].data.backward |= insertedEdges[i].data.backward;
+ }
+ inserted_edges[other].data.forward |= inserted_edges[i].data.forward;
+ inserted_edges[other].data.backward |= inserted_edges[i].data.backward;
found = true;
break;
}
- if ( !found ) {
- insertedEdges[insertedEdgesSize++] = insertedEdges[i];
+ if (!found)
+ {
+ inserted_edges[inserted_edges_size++] = inserted_edges[i];
}
}
- insertedEdges.resize( insertedEdgesSize );
+ inserted_edges.resize(inserted_edges_size);
}
return true;
}
- inline void _DeleteIncomingEdges( _ThreadData* data, const NodeID node ) {
- std::vector< NodeID >& neighbours = data->neighbours;
+ inline void DeleteIncomingEdges(ContractorThreadData *data, const NodeID node)
+ {
+ std::vector<NodeID> &neighbours = data->neighbours;
neighbours.clear();
- //find all neighbours
- for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
- const NodeID u = _graph->GetTarget( e );
- if ( u != node )
- neighbours.push_back( u );
+ // find all neighbours
+ for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
+ {
+ const NodeID u = contractor_graph->GetTarget(e);
+ if (u != node)
+ {
+ neighbours.push_back(u);
+ }
}
- //eliminate duplicate entries ( forward + backward edges )
- std::sort( neighbours.begin(), neighbours.end() );
- neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
+ // eliminate duplicate entries ( forward + backward edges )
+ std::sort(neighbours.begin(), neighbours.end());
+ neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
- for ( int i = 0, e = ( int ) neighbours.size(); i < e; ++i ) {
- _graph->DeleteEdgesTo( neighbours[i], node );
+ for (int i = 0, e = (int)neighbours.size(); i < e; ++i)
+ {
+ contractor_graph->DeleteEdgesTo(neighbours[i], node);
}
}
- inline bool _UpdateNeighbours( std::vector< float > & priorities, std::vector< _PriorityData > & nodeData, _ThreadData* const data, const NodeID node) {
- std::vector< NodeID >& neighbours = data->neighbours;
+ inline bool UpdateNodeNeighbours(std::vector<float> &priorities,
+ std::vector<NodePriorityData> &node_data,
+ ContractorThreadData *const data,
+ const NodeID node)
+ {
+ std::vector<NodeID> &neighbours = data->neighbours;
neighbours.clear();
- //find all neighbours
- for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ) ; e < endEdges ; ++e ) {
- const NodeID u = _graph->GetTarget( e );
- if ( u == node )
+ // find all neighbours
+ for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
+ {
+ const NodeID u = contractor_graph->GetTarget(e);
+ if (u == node)
+ {
continue;
- neighbours.push_back( u );
- nodeData[u].depth = (std::max)(nodeData[node].depth + 1, nodeData[u].depth );
+ }
+ neighbours.push_back(u);
+ node_data[u].depth = (std::max)(node_data[node].depth + 1, node_data[u].depth);
}
- //eliminate duplicate entries ( forward + backward edges )
- std::sort( neighbours.begin(), neighbours.end() );
- neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
+ // eliminate duplicate entries ( forward + backward edges )
+ std::sort(neighbours.begin(), neighbours.end());
+ neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
- BOOST_FOREACH(const NodeID u, neighbours) {
- priorities[u] = _Evaluate( data, &( nodeData )[u], u );
+ // re-evaluate priorities of neighboring nodes
+ for (const NodeID u : neighbours)
+ {
+ priorities[u] = EvaluateNodePriority(data, &(node_data)[u], u);
}
return true;
}
- inline bool _IsIndependent( const std::vector< float >& priorities/*, const std::vector< _PriorityData >& nodeData*/, _ThreadData* const data, NodeID node ) const {
- const double priority = priorities[node];
+ inline bool IsNodeIndependent(
+ const std::vector<float> &priorities /*, const std::vector< NodePriorityData >& node_data*/,
+ ContractorThreadData *const data,
+ NodeID node) const
+ {
+ const float priority = priorities[node];
- std::vector< NodeID >& neighbours = data->neighbours;
+ std::vector<NodeID> &neighbours = data->neighbours;
neighbours.clear();
- for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( node ) ; e < _graph->EndEdges( node ) ; ++e ) {
- const NodeID target = _graph->GetTarget( e );
- if(node==target)
+ for (auto e : contractor_graph->GetAdjacentEdgeRange(node))
+ {
+ const NodeID target = contractor_graph->GetTarget(e);
+ if (node == target)
+ {
continue;
- const double targetPriority = priorities[target];
- assert( targetPriority >= 0 );
- //found a neighbour with lower priority?
- if ( priority > targetPriority )
+ }
+ const float target_priority = priorities[target];
+ BOOST_ASSERT(target_priority >= 0);
+ // found a neighbour with lower priority?
+ if (priority > target_priority)
+ {
return false;
- //tie breaking
- if ( fabs(priority - targetPriority) < FLT_EPSILON && bias(node, target) ) {
+ }
+ // tie breaking
+ if (std::abs(priority - target_priority) < std::numeric_limits<float>::epsilon() &&
+ bias(node, target))
+ {
return false;
}
- neighbours.push_back( target );
+ neighbours.push_back(target);
}
- std::sort( neighbours.begin(), neighbours.end() );
- neighbours.resize( std::unique( neighbours.begin(), neighbours.end() ) - neighbours.begin() );
+ std::sort(neighbours.begin(), neighbours.end());
+ neighbours.resize(std::unique(neighbours.begin(), neighbours.end()) - neighbours.begin());
- //examine all neighbours that are at most 2 hops away
- BOOST_FOREACH(const NodeID u, neighbours) {
- for ( _DynamicGraph::EdgeIterator e = _graph->BeginEdges( u ) ; e < _graph->EndEdges( u ) ; ++e ) {
- const NodeID target = _graph->GetTarget( e );
- if(node==target)
+ // examine all neighbours that are at most 2 hops away
+ for (const NodeID u : neighbours)
+ {
+ for (auto e : contractor_graph->GetAdjacentEdgeRange(u))
+ {
+ const NodeID target = contractor_graph->GetTarget(e);
+ if (node == target)
+ {
continue;
-
- const double targetPriority = priorities[target];
- assert( targetPriority >= 0 );
- //found a neighbour with lower priority?
- if ( priority > targetPriority)
+ }
+ const float target_priority = priorities[target];
+ assert(target_priority >= 0);
+ // found a neighbour with lower priority?
+ if (priority > target_priority)
+ {
return false;
- //tie breaking
- if ( fabs(priority - targetPriority) < FLT_EPSILON && bias(node, target) ) {
+ }
+ // tie breaking
+ if (std::abs(priority - target_priority) < std::numeric_limits<float>::epsilon() &&
+ bias(node, target))
+ {
return false;
}
}
@@ -759,25 +980,27 @@ private:
return true;
}
+ // This bias function takes up 22 assembly instructions in total on X86
+ inline bool bias(const NodeID a, const NodeID b) const
+ {
+ unsigned short hasha = fast_hash(a);
+ unsigned short hashb = fast_hash(b);
- /**
- * This bias function takes up 22 assembly instructions in total on X86
- */
- inline bool bias(const NodeID a, const NodeID b) const {
- unsigned short hasha = fastHash(a);
- unsigned short hashb = fastHash(b);
-
- //The compiler optimizes that to conditional register flags but without branching statements!
- if(hasha != hashb)
+ // The compiler optimizes that to conditional register flags but without branching
+ // statements!
+ if (hasha != hashb)
+ {
return hasha < hashb;
+ }
return a < b;
}
- boost::shared_ptr<_DynamicGraph> _graph;
- std::vector<_DynamicGraph::InputEdge> contractedEdges;
- unsigned temporaryStorageSlotID;
- std::vector<NodeID> oldNodeIDFromNewNodeIDMap;
- XORFastHash fastHash;
+ std::shared_ptr<ContractorGraph> contractor_graph;
+ std::vector<ContractorGraph::InputEdge> contracted_edge_list;
+ unsigned edge_storage_slot;
+ uint64_t temp_edge_counter;
+ std::vector<NodeID> orig_node_id_to_new_id_map;
+ XORFastHash fast_hash;
};
-#endif // CONTRACTOR_H_INCLUDED
+#endif // CONTRACTOR_H
diff --git a/Contractor/EdgeBasedGraphFactory.cpp b/Contractor/EdgeBasedGraphFactory.cpp
index 13f49ec..1e4e381 100644
--- a/Contractor/EdgeBasedGraphFactory.cpp
+++ b/Contractor/EdgeBasedGraphFactory.cpp
@@ -1,412 +1,779 @@
/*
- 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.
- */
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#include "EdgeBasedGraphFactory.h"
+#include "../Algorithms/BFSComponentExplorer.h"
+#include "../DataStructures/Percent.h"
+#include "../Util/ComputeAngle.h"
+#include "../Util/LuaUtil.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/TimingUtil.h"
+
+#include <boost/assert.hpp>
+
+#include <fstream>
+#include <limits>
+
+EdgeBasedGraphFactory::EdgeBasedGraphFactory(
+ const std::shared_ptr<NodeBasedDynamicGraph> &node_based_graph,
+ std::unique_ptr<RestrictionMap> restriction_map,
+ std::vector<NodeID> &barrier_node_list,
+ std::vector<NodeID> &traffic_light_node_list,
+ std::vector<NodeInfo> &m_node_info_list,
+ SpeedProfileProperties &speed_profile)
+ : speed_profile(speed_profile),
+ m_number_of_edge_based_nodes(std::numeric_limits<unsigned>::max()),
+ m_node_info_list(m_node_info_list), m_node_based_graph(node_based_graph),
+ m_restriction_map(std::move(restriction_map)), max_id(0)
+{
+
+ // insert into unordered sets for fast lookup
+ m_barrier_nodes.insert(barrier_node_list.begin(), barrier_node_list.end());
+ m_traffic_lights.insert(traffic_light_node_list.begin(), traffic_light_node_list.end());
+}
-template<>
-EdgeBasedGraphFactory::EdgeBasedGraphFactory(int nodes, std::vector<NodeBasedEdge> & inputEdges, std::vector<NodeID> & bn, std::vector<NodeID> & tl, std::vector<_Restriction> & irs, std::vector<NodeInfo> & nI, SpeedProfileProperties sp) : speedProfile(sp), inputNodeInfoList(nI), numberOfTurnRestrictions(irs.size()) {
- BOOST_FOREACH(const _Restriction & restriction, irs) {
- std::pair<NodeID, NodeID> restrictionSource = std::make_pair(restriction.fromNode, restriction.viaNode);
- unsigned index;
- RestrictionMap::iterator restrIter = _restrictionMap.find(restrictionSource);
- if(restrIter == _restrictionMap.end()) {
- index = _restrictionBucketVector.size();
- _restrictionBucketVector.resize(index+1);
- _restrictionMap[restrictionSource] = index;
- } else {
- index = restrIter->second;
- //Map already contains an is_only_*-restriction
- if(_restrictionBucketVector.at(index).begin()->second)
- continue;
- else if(restriction.flags.isOnly){
- //We are going to insert an is_only_*-restriction. There can be only one.
- _restrictionBucketVector.at(index).clear();
- }
+void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &output_edge_list)
+{
+ BOOST_ASSERT_MSG(0 == output_edge_list.size(), "Vector is not empty");
+ m_edge_based_edge_list.swap(output_edge_list);
+}
+
+void EdgeBasedGraphFactory::GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes)
+{
+#ifndef NDEBUG
+ for (const EdgeBasedNode &node : m_edge_based_node_list)
+ {
+ BOOST_ASSERT(m_node_info_list.at(node.u).lat != INT_MAX);
+ BOOST_ASSERT(m_node_info_list.at(node.u).lon != INT_MAX);
+ BOOST_ASSERT(m_node_info_list.at(node.v).lon != INT_MAX);
+ BOOST_ASSERT(m_node_info_list.at(node.v).lat != INT_MAX);
+ }
+#endif
+ nodes.swap(m_edge_based_node_list);
+}
+
+void
+EdgeBasedGraphFactory::InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool belongs_to_tiny_cc)
+{
+ // merge edges together into one EdgeBasedNode
+ BOOST_ASSERT(u != SPECIAL_NODEID);
+ BOOST_ASSERT(v != SPECIAL_NODEID);
+ BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+
+#ifndef NDEBUG
+ // find forward edge id and
+ const EdgeID e1b = m_node_based_graph->FindEdge(u, v);
+ BOOST_ASSERT(e1 == e1b);
+#endif
+
+ BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+ const EdgeData &forward_data = m_node_based_graph->GetEdgeData(e1);
+
+ // find reverse edge id and
+ const EdgeID e2 = m_node_based_graph->FindEdge(v, u);
+
+#ifndef NDEBUG
+ if (e2 == m_node_based_graph->EndEdges(v))
+ {
+ SimpleLogger().Write(logWARNING) << "Did not find edge (" << v << "," << u << ")";
+ }
+#endif
+ BOOST_ASSERT(e2 != SPECIAL_EDGEID);
+ BOOST_ASSERT(e2 < m_node_based_graph->EndEdges(v));
+ const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(e2);
+
+ if (forward_data.edgeBasedNodeID == SPECIAL_NODEID &&
+ reverse_data.edgeBasedNodeID == SPECIAL_NODEID)
+ {
+ return;
+ }
+
+ BOOST_ASSERT(m_geometry_compressor.HasEntryForID(e1) ==
+ m_geometry_compressor.HasEntryForID(e2));
+ if (m_geometry_compressor.HasEntryForID(e1))
+ {
+ BOOST_ASSERT(m_geometry_compressor.HasEntryForID(e2));
+
+ // reconstruct geometry and put in each individual edge with its offset
+ const std::vector<GeometryCompressor::CompressedNode> &forward_geometry =
+ m_geometry_compressor.GetBucketReference(e1);
+ const std::vector<GeometryCompressor::CompressedNode> &reverse_geometry =
+ m_geometry_compressor.GetBucketReference(e2);
+ BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
+ BOOST_ASSERT(0 != forward_geometry.size());
+
+ // reconstruct bidirectional edge with individual weights and put each into the NN index
+
+ std::vector<int> forward_dist_prefix_sum(forward_geometry.size(), 0);
+ std::vector<int> reverse_dist_prefix_sum(reverse_geometry.size(), 0);
+
+ // quick'n'dirty prefix sum as std::partial_sum needs addtional casts
+ // TODO: move to lambda function with C++11
+ int temp_sum = 0;
+
+ for (unsigned i = 0; i < forward_geometry.size(); ++i)
+ {
+ forward_dist_prefix_sum[i] = temp_sum;
+ temp_sum += forward_geometry[i].second;
+
+ BOOST_ASSERT(forward_data.distance >= temp_sum);
+ }
+
+ temp_sum = 0;
+ for (unsigned i = 0; i < reverse_geometry.size(); ++i)
+ {
+ temp_sum += reverse_geometry[reverse_geometry.size() - 1 - i].second;
+ reverse_dist_prefix_sum[i] = reverse_data.distance - temp_sum;
+ BOOST_ASSERT(reverse_data.distance >= temp_sum);
+ }
+
+ BOOST_ASSERT(forward_geometry.size() == reverse_geometry.size());
+
+ const unsigned geometry_size = forward_geometry.size();
+ BOOST_ASSERT(geometry_size > 1);
+ NodeID current_edge_source_coordinate_id = u;
+
+ if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
+ {
+ max_id = std::max(forward_data.edgeBasedNodeID, max_id);
+ }
+ if (SPECIAL_NODEID != reverse_data.edgeBasedNodeID)
+ {
+ max_id = std::max(reverse_data.edgeBasedNodeID, max_id);
}
- _restrictionBucketVector.at(index).push_back(std::make_pair(restriction.toNode, restriction.flags.isOnly));
+ // traverse arrays from start and end respectively
+ for (unsigned i = 0; i < geometry_size; ++i)
+ {
+ BOOST_ASSERT(current_edge_source_coordinate_id ==
+ reverse_geometry[geometry_size - 1 - i].first);
+ const NodeID current_edge_target_coordinate_id = forward_geometry[i].first;
+ BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
+
+ // build edges
+ m_edge_based_node_list.emplace_back(forward_data.edgeBasedNodeID,
+ reverse_data.edgeBasedNodeID,
+ current_edge_source_coordinate_id,
+ current_edge_target_coordinate_id,
+ forward_data.nameID,
+ forward_geometry[i].second,
+ reverse_geometry[i].second,
+ forward_dist_prefix_sum[i],
+ reverse_dist_prefix_sum[i],
+ m_geometry_compressor.GetPositionForID(e1),
+ i,
+ belongs_to_tiny_cc);
+ current_edge_source_coordinate_id = current_edge_target_coordinate_id;
+
+ BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
+
+ BOOST_ASSERT(u != m_edge_based_node_list.back().u ||
+ v != m_edge_based_node_list.back().v);
+
+ BOOST_ASSERT(u != m_edge_based_node_list.back().v ||
+ v != m_edge_based_node_list.back().u);
+ }
+
+ BOOST_ASSERT(current_edge_source_coordinate_id == v);
+ BOOST_ASSERT(m_edge_based_node_list.back().IsCompressed());
}
+ else
+ {
+ BOOST_ASSERT(!m_geometry_compressor.HasEntryForID(e2));
- _barrierNodes.insert(bn.begin(), bn.end());
- _trafficLights.insert(tl.begin(), tl.end());
-
- DeallocatingVector< _NodeBasedEdge > edges;
- _NodeBasedEdge edge;
- for ( std::vector< NodeBasedEdge >::const_iterator i = inputEdges.begin(); i != inputEdges.end(); ++i ) {
- if(!i->isForward()) {
- edge.source = i->target();
- edge.target = i->source();
- edge.data.backward = i->isForward();
- edge.data.forward = i->isBackward();
- } else {
- edge.source = i->source();
- edge.target = i->target();
- edge.data.forward = i->isForward();
- edge.data.backward = i->isBackward();
+ if (forward_data.edgeBasedNodeID != SPECIAL_NODEID)
+ {
+ BOOST_ASSERT(forward_data.forward);
}
- if(edge.source == edge.target) {
- continue;
+ if (reverse_data.edgeBasedNodeID != SPECIAL_NODEID)
+ {
+ BOOST_ASSERT(reverse_data.forward);
}
- edge.data.distance = (std::max)((int)i->weight(), 1 );
- assert( edge.data.distance > 0 );
- edge.data.shortcut = false;
- edge.data.roundabout = i->isRoundabout();
- edge.data.ignoreInGrid = i->ignoreInGrid();
- edge.data.nameID = i->name();
- edge.data.type = i->type();
- edge.data.isAccessRestricted = i->isAccessRestricted();
- edge.data.edgeBasedNodeID = edges.size();
- edge.data.contraFlow = i->isContraFlow();
- edges.push_back( edge );
- if( edge.data.backward ) {
- std::swap( edge.source, edge.target );
- edge.data.forward = i->isBackward();
- edge.data.backward = i->isForward();
- edge.data.edgeBasedNodeID = edges.size();
- edges.push_back( edge );
+ if (forward_data.edgeBasedNodeID == SPECIAL_NODEID)
+ {
+ BOOST_ASSERT(!forward_data.forward);
}
+ if (reverse_data.edgeBasedNodeID == SPECIAL_NODEID)
+ {
+ BOOST_ASSERT(!reverse_data.forward);
+ }
+
+ BOOST_ASSERT(forward_data.edgeBasedNodeID != SPECIAL_NODEID ||
+ reverse_data.edgeBasedNodeID != SPECIAL_NODEID);
+
+ m_edge_based_node_list.emplace_back(EdgeBasedNode(forward_data.edgeBasedNodeID,
+ reverse_data.edgeBasedNodeID,
+ u,
+ v,
+ forward_data.nameID,
+ forward_data.distance,
+ reverse_data.distance,
+ 0,
+ 0,
+ SPECIAL_EDGEID,
+ 0,
+ belongs_to_tiny_cc));
+ BOOST_ASSERT(!m_edge_based_node_list.back().IsCompressed());
}
- std::vector<NodeBasedEdge>().swap(inputEdges);
- std::sort( edges.begin(), edges.end() );
- _nodeBasedGraph = boost::make_shared<_NodeBasedDynamicGraph>( nodes, edges );
}
-void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector< EdgeBasedEdge >& outputEdgeList ) {
- BOOST_ASSERT_MSG(
- 0 == outputEdgeList.size(),
- "Vector is not empty"
- );
- edgeBasedEdges.swap(outputEdgeList);
+void EdgeBasedGraphFactory::FlushVectorToStream(
+ std::ofstream &edge_data_file, std::vector<OriginalEdgeData> &original_edge_data_vector) const
+{
+ if (original_edge_data_vector.empty()) {
+ return;
+ }
+ edge_data_file.write((char *)&(original_edge_data_vector[0]),
+ original_edge_data_vector.size() * sizeof(OriginalEdgeData));
+ original_edge_data_vector.clear();
}
-void EdgeBasedGraphFactory::GetEdgeBasedNodes( std::vector<EdgeBasedNode> & nodes) {
-#ifndef NDEBUG
- BOOST_FOREACH(EdgeBasedNode & node, edgeBasedNodes){
- assert(node.lat1 != INT_MAX); assert(node.lon1 != INT_MAX);
- assert(node.lat2 != INT_MAX); assert(node.lon2 != INT_MAX);
- }
-#endif
- nodes.swap(edgeBasedNodes);
+void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
+ const std::string &geometry_filename,
+ lua_State *lua_state)
+{
+
+ TIMER_START(geometry);
+ CompressGeometry();
+ TIMER_STOP(geometry);
+
+ TIMER_START(renumber);
+ RenumberEdges();
+ TIMER_STOP(renumber);
+
+ TIMER_START(generate_nodes);
+ GenerateEdgeExpandedNodes();
+ TIMER_STOP(generate_nodes);
+
+ TIMER_START(generate_edges);
+ GenerateEdgeExpandedEdges(original_edge_data_filename, lua_state);
+ TIMER_STOP(generate_edges);
+
+ m_geometry_compressor.SerializeInternalVector(geometry_filename);
+
+ SimpleLogger().Write() << "Timing statistics for edge-expanded graph:";
+ SimpleLogger().Write() << "Geometry compression: " << TIMER_SEC(geometry) << "s";
+ SimpleLogger().Write() << "Renumbering edges: " << TIMER_SEC(renumber) << "s";
+ SimpleLogger().Write() << "Generating nodes: " << TIMER_SEC(generate_nodes) << "s";
+ SimpleLogger().Write() << "Generating edges: " << TIMER_SEC(generate_edges) << "s";
}
-NodeID EdgeBasedGraphFactory::CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const {
- std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v);
- RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource);
- if (restrIter != _restrictionMap.end()) {
- unsigned index = restrIter->second;
- BOOST_FOREACH(const RestrictionSource & restrictionTarget, _restrictionBucketVector.at(index)) {
- if(restrictionTarget.second) {
- return restrictionTarget.first;
+void EdgeBasedGraphFactory::CompressGeometry()
+{
+ SimpleLogger().Write() << "Removing graph geometry while preserving topology";
+
+ const unsigned original_number_of_nodes = m_node_based_graph->GetNumberOfNodes();
+ const unsigned original_number_of_edges = m_node_based_graph->GetNumberOfEdges();
+
+ Percent p(original_number_of_nodes);
+ unsigned removed_node_count = 0;
+
+ for (NodeID v = 0; v < original_number_of_nodes; ++v)
+ {
+ p.printStatus(v);
+
+ // only contract degree 2 vertices
+ if (2 != m_node_based_graph->GetOutDegree(v))
+ {
+ continue;
+ }
+
+ // don't contract barrier node
+ if (m_barrier_nodes.end() != m_barrier_nodes.find(v))
+ {
+ continue;
+ }
+
+ // check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
+ if (m_restriction_map->IsViaNode(v))
+ {
+ continue;
+ }
+
+ const bool reverse_edge_order =
+ !(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(v)).forward);
+ const EdgeID forward_e2 = m_node_based_graph->BeginEdges(v) + reverse_edge_order;
+ BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
+ const EdgeID reverse_e2 = m_node_based_graph->BeginEdges(v) + 1 - reverse_edge_order;
+ BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
+
+ const EdgeData &fwd_edge_data2 = m_node_based_graph->GetEdgeData(forward_e2);
+ const EdgeData &rev_edge_data2 = m_node_based_graph->GetEdgeData(reverse_e2);
+
+ const NodeID w = m_node_based_graph->GetTarget(forward_e2);
+ BOOST_ASSERT(SPECIAL_NODEID != w);
+ BOOST_ASSERT(v != w);
+ const NodeID u = m_node_based_graph->GetTarget(reverse_e2);
+ BOOST_ASSERT(SPECIAL_NODEID != u);
+ BOOST_ASSERT(u != v);
+
+ const EdgeID forward_e1 = m_node_based_graph->FindEdge(u, v);
+ BOOST_ASSERT(m_node_based_graph->EndEdges(u) != forward_e1);
+ BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
+ BOOST_ASSERT(v == m_node_based_graph->GetTarget(forward_e1));
+ const EdgeID reverse_e1 = m_node_based_graph->FindEdge(w, v);
+ BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
+ BOOST_ASSERT(v == m_node_based_graph->GetTarget(reverse_e1));
+
+ const EdgeData &fwd_edge_data1 = m_node_based_graph->GetEdgeData(forward_e1);
+ const EdgeData &rev_edge_data1 = m_node_based_graph->GetEdgeData(reverse_e1);
+
+ if ((m_node_based_graph->FindEdge(u, w) != m_node_based_graph->EndEdges(u)) ||
+ (m_node_based_graph->FindEdge(w, u) != m_node_based_graph->EndEdges(w)))
+ {
+ continue;
+ }
+
+ if ( // TODO: rename to IsCompatibleTo
+ fwd_edge_data1.IsEqualTo(fwd_edge_data2) &&
+ rev_edge_data1.IsEqualTo(rev_edge_data2))
+ {
+ // Get distances before graph is modified
+ const int forward_weight1 = m_node_based_graph->GetEdgeData(forward_e1).distance;
+ const int forward_weight2 = m_node_based_graph->GetEdgeData(forward_e2).distance;
+
+ BOOST_ASSERT(0 != forward_weight1);
+ BOOST_ASSERT(0 != forward_weight2);
+
+ const int reverse_weight1 = m_node_based_graph->GetEdgeData(reverse_e1).distance;
+ const int reverse_weight2 = m_node_based_graph->GetEdgeData(reverse_e2).distance;
+
+ BOOST_ASSERT(0 != reverse_weight1);
+ BOOST_ASSERT(0 != forward_weight2);
+
+ const bool add_traffic_signal_penalty =
+ (m_traffic_lights.find(v) != m_traffic_lights.end());
+
+ // add weight of e2's to e1
+ m_node_based_graph->GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
+ m_node_based_graph->GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
+ if (add_traffic_signal_penalty)
+ {
+ m_node_based_graph->GetEdgeData(forward_e1).distance +=
+ speed_profile.trafficSignalPenalty;
+ m_node_based_graph->GetEdgeData(reverse_e1).distance +=
+ speed_profile.trafficSignalPenalty;
}
+
+ // extend e1's to targets of e2's
+ m_node_based_graph->SetTarget(forward_e1, w);
+ m_node_based_graph->SetTarget(reverse_e1, u);
+
+ // remove e2's (if bidir, otherwise only one)
+ m_node_based_graph->DeleteEdge(v, forward_e2);
+ m_node_based_graph->DeleteEdge(v, reverse_e2);
+
+ // update any involved turn restrictions
+ m_restriction_map->FixupStartingTurnRestriction(u, v, w);
+ m_restriction_map->FixupArrivingTurnRestriction(u, v, w);
+
+ m_restriction_map->FixupStartingTurnRestriction(w, v, u);
+ m_restriction_map->FixupArrivingTurnRestriction(w, v, u);
+
+ // store compressed geometry in container
+ m_geometry_compressor.CompressEdge(
+ forward_e1,
+ forward_e2,
+ v,
+ w,
+ forward_weight1 +
+ (add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 0),
+ forward_weight2);
+ m_geometry_compressor.CompressEdge(
+ reverse_e1,
+ reverse_e2,
+ v,
+ u,
+ reverse_weight1,
+ reverse_weight2 +
+ (add_traffic_signal_penalty ? speed_profile.trafficSignalPenalty : 0));
+ ++removed_node_count;
+
+ BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
+ m_node_based_graph->GetEdgeData(reverse_e1).nameID);
}
}
- return UINT_MAX;
+ SimpleLogger().Write() << "removed " << removed_node_count << " nodes";
+ m_geometry_compressor.PrintStatistics();
+
+ unsigned new_node_count = 0;
+ unsigned new_edge_count = 0;
+ for (unsigned i = 0; i < m_node_based_graph->GetNumberOfNodes(); ++i)
+ {
+ if (m_node_based_graph->GetOutDegree(i) > 0)
+ {
+ ++new_node_count;
+ new_edge_count += (m_node_based_graph->EndEdges(i) - m_node_based_graph->BeginEdges(i));
+ }
+ }
+ SimpleLogger().Write() << "new nodes: " << new_node_count << ", edges " << new_edge_count;
+ SimpleLogger().Write() << "Node compression ratio: " << new_node_count /
+ (double)original_number_of_nodes;
+ SimpleLogger().Write() << "Edge compression ratio: " << new_edge_count /
+ (double)original_number_of_edges;
}
-bool EdgeBasedGraphFactory::CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const {
- //only add an edge if turn is not a U-turn except it is the end of dead-end street.
- std::pair < NodeID, NodeID > restrictionSource = std::make_pair(u, v);
- RestrictionMap::const_iterator restrIter = _restrictionMap.find(restrictionSource);
- if (restrIter != _restrictionMap.end()) {
- unsigned index = restrIter->second;
- BOOST_FOREACH(RestrictionTarget restrictionTarget, _restrictionBucketVector.at(index)) {
- if(w == restrictionTarget.first)
- return true;
+/**
+ * Writes the id of the edge in the edge expanded graph (into the egde in the node based graph)
+ */
+void EdgeBasedGraphFactory::RenumberEdges()
+{
+ // renumber edge based node IDs
+ unsigned numbered_edges_count = 0;
+ for (NodeID current_node = 0; current_node < m_node_based_graph->GetNumberOfNodes();
+ ++current_node)
+ {
+ for (EdgeID current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
+ {
+ EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
+ if (!edge_data.forward)
+ {
+ continue;
+ }
+
+ BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
+ edge_data.edgeBasedNodeID = numbered_edges_count;
+ ++numbered_edges_count;
+
+ BOOST_ASSERT(SPECIAL_NODEID != edge_data.edgeBasedNodeID);
}
}
- return false;
+ m_number_of_edge_based_nodes = numbered_edges_count;
}
-void EdgeBasedGraphFactory::InsertEdgeBasedNode(
- _NodeBasedDynamicGraph::EdgeIterator e1,
- _NodeBasedDynamicGraph::NodeIterator u,
- _NodeBasedDynamicGraph::NodeIterator v,
- bool belongsToTinyComponent) {
- _NodeBasedDynamicGraph::EdgeData & data = _nodeBasedGraph->GetEdgeData(e1);
- EdgeBasedNode currentNode;
- currentNode.nameID = data.nameID;
- currentNode.lat1 = inputNodeInfoList[u].lat;
- currentNode.lon1 = inputNodeInfoList[u].lon;
- currentNode.lat2 = inputNodeInfoList[v].lat;
- currentNode.lon2 = inputNodeInfoList[v].lon;
- currentNode.belongsToTinyComponent = belongsToTinyComponent;
- currentNode.id = data.edgeBasedNodeID;
- currentNode.ignoreInGrid = data.ignoreInGrid;
- currentNode.weight = data.distance;
- edgeBasedNodes.push_back(currentNode);
-}
+/**
+ * Creates the nodes in the edge expanded graph from edges in the node-based graph.
+ */
+void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
+{
+ SimpleLogger().Write() << "Identifying components of the road network";
-void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename, lua_State *myLuaState) {
- Percent p(_nodeBasedGraph->GetNumberOfNodes());
- int numberOfSkippedTurns(0);
- int nodeBasedEdgeCounter(0);
- unsigned numberOfOriginalEdges(0);
- std::ofstream originalEdgeDataOutFile(originalEdgeDataFilename, std::ios::binary);
- originalEdgeDataOutFile.write((char*)&numberOfOriginalEdges, sizeof(unsigned));
-
-
- INFO("Identifying small components");
- //Run a BFS on the undirected graph and identify small components
- std::queue<std::pair<NodeID, NodeID> > bfsQueue;
- std::vector<unsigned> componentsIndex(_nodeBasedGraph->GetNumberOfNodes(), UINT_MAX);
- std::vector<NodeID> vectorOfComponentSizes;
- unsigned currentComponent = 0, sizeOfCurrentComponent = 0;
- //put unexplorered node with parent pointer into queue
- for(NodeID node = 0, endNodes = _nodeBasedGraph->GetNumberOfNodes(); node < endNodes; ++node) {
- if(UINT_MAX == componentsIndex[node]) {
- bfsQueue.push(std::make_pair(node, node));
- //mark node as read
- componentsIndex[node] = currentComponent;
- p.printIncrement();
- while(!bfsQueue.empty()) {
- //fetch element from BFS queue
- std::pair<NodeID, NodeID> currentQueueItem = bfsQueue.front();
- bfsQueue.pop();
- // INFO("sizeof queue: " << bfsQueue.size() << ", sizeOfCurrentComponents: " << sizeOfCurrentComponent << ", settled nodes: " << settledNodes++ << ", max: " << endNodes);
- const NodeID v = currentQueueItem.first; //current node
- const NodeID u = currentQueueItem.second; //parent
- //increment size counter of current component
- ++sizeOfCurrentComponent;
- const bool isBollardNode = (_barrierNodes.find(v) != _barrierNodes.end());
- if(!isBollardNode) {
- const NodeID onlyToNode = CheckForEmanatingIsOnlyTurn(u, v);
-
- //relaxieren edge outgoing edge like below where edge-expanded graph
- for(_NodeBasedDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) {
- _NodeBasedDynamicGraph::NodeIterator w = _nodeBasedGraph->GetTarget(e2);
-
- if(onlyToNode != UINT_MAX && w != onlyToNode) { //We are at an only_-restriction but not at the right turn.
- continue;
- }
- if( u != w ) { //only add an edge if turn is not a U-turn except it is the end of dead-end street.
- if (!CheckIfTurnIsRestricted(u, v, w) ) { //only add an edge if turn is not prohibited
- //insert next (node, parent) only if w has not yet been explored
- if(UINT_MAX == componentsIndex[w]) {
- //mark node as read
- componentsIndex[w] = currentComponent;
- bfsQueue.push(std::make_pair(w,v));
- p.printIncrement();
- }
- }
- }
- }
- }
+ // Run a BFS on the undirected graph and identify small components
+ BFSComponentExplorer<NodeBasedDynamicGraph> component_explorer(
+ *m_node_based_graph, *m_restriction_map, m_barrier_nodes);
+
+ component_explorer.run();
+
+ SimpleLogger().Write() << "identified: " << component_explorer.GetNumberOfComponents()
+ << " many components";
+ SimpleLogger().Write() << "generating edge-expanded nodes";
+
+ Percent p(m_node_based_graph->GetNumberOfNodes());
+
+ // loop over all edges and generate new set of nodes
+ for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
+ {
+ BOOST_ASSERT(u != SPECIAL_NODEID);
+ BOOST_ASSERT(u < m_node_based_graph->GetNumberOfNodes());
+ p.printIncrement();
+ for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
+ {
+ const EdgeData &edge_data = m_node_based_graph->GetEdgeData(e1);
+ if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
+ {
+ // continue;
}
- //push size into vector
- vectorOfComponentSizes.push_back(sizeOfCurrentComponent);
- //reset counters;
- sizeOfCurrentComponent = 0;
- ++currentComponent;
- }
- }
- INFO("identified: " << vectorOfComponentSizes.size() << " many components");
-
- p.reinit(_nodeBasedGraph->GetNumberOfNodes());
- //loop over all edges and generate new set of nodes.
- for(_NodeBasedDynamicGraph::NodeIterator u = 0; u < _nodeBasedGraph->GetNumberOfNodes(); ++u ) {
- for(_NodeBasedDynamicGraph::EdgeIterator e1 = _nodeBasedGraph->BeginEdges(u); e1 < _nodeBasedGraph->EndEdges(u); ++e1) {
- _NodeBasedDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1);
-
- if(_nodeBasedGraph->GetEdgeData(e1).type != SHRT_MAX) {
- assert(e1 != UINT_MAX);
- assert(u != UINT_MAX);
- assert(v != UINT_MAX);
- //edges that end on bollard nodes may actually be in two distinct components
- InsertEdgeBasedNode(e1, u, v, (std::min(vectorOfComponentSizes[componentsIndex[u]], vectorOfComponentSizes[componentsIndex[v]]) < 1000) );
+ BOOST_ASSERT(e1 != SPECIAL_EDGEID);
+ const NodeID v = m_node_based_graph->GetTarget(e1);
+
+ BOOST_ASSERT(SPECIAL_NODEID != v);
+ // pick only every other edge
+ if (u > v)
+ {
+ continue;
}
+
+ BOOST_ASSERT(u < v);
+ BOOST_ASSERT(edge_data.type != SHRT_MAX);
+
+ // Note: edges that end on barrier nodes or on a turn restriction
+ // may actually be in two distinct components. We choose the smallest
+ const unsigned size_of_component = std::min(component_explorer.GetComponentSize(u),
+ component_explorer.GetComponentSize(v));
+
+ const bool component_is_tiny = (size_of_component < 1000);
+ InsertEdgeBasedNode(u, v, e1, component_is_tiny);
}
}
- std::vector<NodeID>().swap(vectorOfComponentSizes);
- std::vector<NodeID>().swap(componentsIndex);
+ SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size()
+ << " nodes in edge-expanded graph";
+}
+
+/**
+ * Actually it also generates OriginalEdgeData and serializes them...
+ */
+void
+EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
+ lua_State *lua_state)
+{
+ SimpleLogger().Write() << "generating edge-expanded edges";
+
+ unsigned node_based_edge_counter = 0;
+ unsigned original_edges_counter = 0;
+
+ std::ofstream edge_data_file(original_edge_data_filename.c_str(), std::ios::binary);
+
+ // writes a dummy value that is updated later
+ edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
std::vector<OriginalEdgeData> original_edge_data_vector;
- original_edge_data_vector.reserve(10000);
-
- //Loop over all turns and generate new set of edges.
- //Three nested loop look super-linear, but we are dealing with a linear number of turns only.
- for(_NodeBasedDynamicGraph::NodeIterator u = 0; u < _nodeBasedGraph->GetNumberOfNodes(); ++u ) {
- for(_NodeBasedDynamicGraph::EdgeIterator e1 = _nodeBasedGraph->BeginEdges(u); e1 < _nodeBasedGraph->EndEdges(u); ++e1) {
- ++nodeBasedEdgeCounter;
- _NodeBasedDynamicGraph::NodeIterator v = _nodeBasedGraph->GetTarget(e1);
- bool isBollardNode = (_barrierNodes.find(v) != _barrierNodes.end());
- //EdgeWeight heightPenalty = ComputeHeightPenalty(u, v);
- NodeID onlyToNode = CheckForEmanatingIsOnlyTurn(u, v);
- for(_NodeBasedDynamicGraph::EdgeIterator e2 = _nodeBasedGraph->BeginEdges(v); e2 < _nodeBasedGraph->EndEdges(v); ++e2) {
- const _NodeBasedDynamicGraph::NodeIterator w = _nodeBasedGraph->GetTarget(e2);
-
- if(onlyToNode != UINT_MAX && w != onlyToNode) { //We are at an only_-restriction but not at the right turn.
- ++numberOfSkippedTurns;
+ original_edge_data_vector.reserve(1024 * 1024);
+
+ // Loop over all turns and generate new set of edges.
+ // Three nested loop look super-linear, but we are dealing with a (kind of)
+ // linear number of turns only.
+ unsigned restricted_turns_counter = 0;
+ unsigned skipped_uturns_counter = 0;
+ unsigned skipped_barrier_turns_counter = 0;
+ unsigned compressed = 0;
+
+ Percent p(m_node_based_graph->GetNumberOfNodes());
+
+ for (NodeID u = 0, end = m_node_based_graph->GetNumberOfNodes(); u < end; ++u)
+ {
+ for (EdgeID e1 : m_node_based_graph->GetAdjacentEdgeRange(u))
+ {
+ if (!m_node_based_graph->GetEdgeData(e1).forward)
+ {
+ continue;
+ }
+
+ ++node_based_edge_counter;
+ const NodeID v = m_node_based_graph->GetTarget(e1);
+ const NodeID to_node_of_only_restriction =
+ m_restriction_map->CheckForEmanatingIsOnlyTurn(u, v);
+ const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end());
+
+ for (EdgeID e2 : m_node_based_graph->GetAdjacentEdgeRange(v))
+ {
+ if (!m_node_based_graph->GetEdgeData(e2).forward)
+ {
continue;
}
+ const NodeID w = m_node_based_graph->GetTarget(e2);
- if(u == w && 1 != _nodeBasedGraph->GetOutDegree(v) ) {
+ if ((to_node_of_only_restriction != SPECIAL_NODEID) &&
+ (w != to_node_of_only_restriction))
+ {
+ // We are at an only_-restriction but not at the right turn.
+ ++restricted_turns_counter;
continue;
}
- if( !isBollardNode ) { //only add an edge if turn is not a U-turn except it is the end of dead-end street.
- if (!CheckIfTurnIsRestricted(u, v, w) || (onlyToNode != UINT_MAX && w == onlyToNode)) { //only add an edge if turn is not prohibited
- const _NodeBasedDynamicGraph::EdgeData edgeData1 = _nodeBasedGraph->GetEdgeData(e1);
- const _NodeBasedDynamicGraph::EdgeData edgeData2 = _nodeBasedGraph->GetEdgeData(e2);
- assert(edgeData1.edgeBasedNodeID < _nodeBasedGraph->GetNumberOfEdges());
- assert(edgeData2.edgeBasedNodeID < _nodeBasedGraph->GetNumberOfEdges());
-
- if(!edgeData1.forward || !edgeData2.forward) {
- continue;
- }
-
- unsigned distance = edgeData1.distance;
- if(_trafficLights.find(v) != _trafficLights.end()) {
- distance += speedProfile.trafficSignalPenalty;
- }
- unsigned penalty = 0;
- TurnInstruction turnInstruction = AnalyzeTurn(u, v, w, penalty, myLuaState);
- if(turnInstruction == TurnInstructions.UTurn)
- distance += speedProfile.uTurnPenalty;
-// if(!edgeData1.isAccessRestricted && edgeData2.isAccessRestricted) {
-// distance += TurnInstructions.AccessRestrictionPenalty;
-// turnInstruction |= TurnInstructions.AccessRestrictionFlag;
-// }
- distance += penalty;
-
-
- //distance += heightPenalty;
- //distance += ComputeTurnPenalty(u, v, w);
- assert(edgeData1.edgeBasedNodeID != edgeData2.edgeBasedNodeID);
- OriginalEdgeData oed(v,edgeData2.nameID, turnInstruction);
- original_edge_data_vector.push_back(oed);
- ++numberOfOriginalEdges;
-
- if(original_edge_data_vector.size() > 100000) {
- originalEdgeDataOutFile.write((char*)&(original_edge_data_vector[0]), original_edge_data_vector.size()*sizeof(OriginalEdgeData));
- original_edge_data_vector.clear();
- }
-
- EdgeBasedEdge newEdge(edgeData1.edgeBasedNodeID, edgeData2.edgeBasedNodeID, edgeBasedEdges.size(), distance, true, false );
- edgeBasedEdges.push_back(newEdge);
- } else {
- ++numberOfSkippedTurns;
+ if (is_barrier_node)
+ {
+ if (u != w)
+ {
+ ++skipped_barrier_turns_counter;
+ continue;
+ }
+ }
+ else
+ {
+ if ((u == w) && (m_node_based_graph->GetOutDegree(v) > 1))
+ {
+ ++skipped_uturns_counter;
+ continue;
}
}
+
+ // only add an edge if turn is not a U-turn except when it is
+ // at the end of a dead-end street
+ if (m_restriction_map->CheckIfTurnIsRestricted(u, v, w) &&
+ (to_node_of_only_restriction == SPECIAL_NODEID) &&
+ (w != to_node_of_only_restriction))
+ {
+ // We are at an only_-restriction but not at the right turn.
+ ++restricted_turns_counter;
+ continue;
+ }
+
+ // only add an edge if turn is not prohibited
+ const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(e1);
+ const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(e2);
+
+ BOOST_ASSERT(edge_data1.edgeBasedNodeID != edge_data2.edgeBasedNodeID);
+ BOOST_ASSERT(edge_data1.forward);
+ BOOST_ASSERT(edge_data2.forward);
+
+ // the following is the core of the loop.
+ unsigned distance = edge_data1.distance;
+ if (m_traffic_lights.find(v) != m_traffic_lights.end())
+ {
+ distance += speed_profile.trafficSignalPenalty;
+ }
+ const double angle = GetAngleBetweenThreeFixedPointCoordinates(
+ m_node_info_list[u], m_node_info_list[v], m_node_info_list[w]);
+ const int turn_penalty = GetTurnPenalty(angle, lua_state);
+ TurnInstruction turn_instruction = AnalyzeTurn(u, v, w, angle);
+ if (turn_instruction == TurnInstruction::UTurn)
+ {
+ distance += speed_profile.uTurnPenalty;
+ }
+ distance += turn_penalty;
+
+ const bool edge_is_compressed = m_geometry_compressor.HasEntryForID(e1);
+
+ if (edge_is_compressed)
+ {
+ ++compressed;
+ }
+
+ original_edge_data_vector.emplace_back(
+ (edge_is_compressed ? m_geometry_compressor.GetPositionForID(e1) : v),
+ edge_data1.nameID,
+ turn_instruction,
+ edge_is_compressed);
+
+ ++original_edges_counter;
+
+ if (original_edge_data_vector.size() > 1024 * 1024 * 10)
+ {
+ FlushVectorToStream(edge_data_file, original_edge_data_vector);
+ }
+
+ BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edgeBasedNodeID);
+ BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edgeBasedNodeID);
+
+ m_edge_based_edge_list.emplace_back(EdgeBasedEdge(edge_data1.edgeBasedNodeID,
+ edge_data2.edgeBasedNodeID,
+ m_edge_based_edge_list.size(),
+ distance,
+ true,
+ false));
}
}
p.printIncrement();
}
- originalEdgeDataOutFile.write((char*)&(original_edge_data_vector[0]), original_edge_data_vector.size()*sizeof(OriginalEdgeData));
- originalEdgeDataOutFile.seekp(std::ios::beg);
- originalEdgeDataOutFile.write((char*)&numberOfOriginalEdges, sizeof(unsigned));
- originalEdgeDataOutFile.close();
-
-// INFO("Sorting edge-based Nodes");
-// std::sort(edgeBasedNodes.begin(), edgeBasedNodes.end());
-// INFO("Removing duplicate nodes (if any)");
-// edgeBasedNodes.erase( std::unique(edgeBasedNodes.begin(), edgeBasedNodes.end()), edgeBasedNodes.end() );
-// INFO("Applying vector self-swap trick to free up memory");
-// INFO("size: " << edgeBasedNodes.size() << ", cap: " << edgeBasedNodes.capacity());
-// std::vector<EdgeBasedNode>(edgeBasedNodes).swap(edgeBasedNodes);
-// INFO("size: " << edgeBasedNodes.size() << ", cap: " << edgeBasedNodes.capacity());
- INFO("Node-based graph contains " << nodeBasedEdgeCounter << " edges");
- INFO("Edge-based graph contains " << edgeBasedEdges.size() << " edges");
-// INFO("Edge-based graph contains " << edgeBasedEdges.size() << " edges, blowup is " << 2*((double)edgeBasedEdges.size()/(double)nodeBasedEdgeCounter));
- INFO("Edge-based graph skipped " << numberOfSkippedTurns << " turns, defined by " << numberOfTurnRestrictions << " restrictions.");
- INFO("Generated " << edgeBasedNodes.size() << " edge based nodes");
+ FlushVectorToStream(edge_data_file, original_edge_data_vector);
+
+ edge_data_file.seekp(std::ios::beg);
+ edge_data_file.write((char *)&original_edges_counter, sizeof(unsigned));
+ edge_data_file.close();
+
+ SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() << " edge based nodes";
+ SimpleLogger().Write() << "Node-based graph contains " << node_based_edge_counter << " edges";
+ SimpleLogger().Write() << "Edge-expanded graph ...";
+ SimpleLogger().Write() << " contains " << m_edge_based_edge_list.size() << " edges";
+ SimpleLogger().Write() << " skips " << restricted_turns_counter << " turns, "
+ "defined by "
+ << m_restriction_map->size() << " restrictions";
+ SimpleLogger().Write() << " skips " << skipped_uturns_counter << " U turns";
+ SimpleLogger().Write() << " skips " << skipped_barrier_turns_counter << " turns over barriers";
}
-TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, unsigned& penalty, lua_State *myLuaState) const {
- const double angle = GetAngleBetweenTwoEdges(inputNodeInfoList[u], inputNodeInfoList[v], inputNodeInfoList[w]);
+int EdgeBasedGraphFactory::GetTurnPenalty(double angle, lua_State *lua_state) const
+{
- if( speedProfile.has_turn_penalty_function ) {
- try {
- //call lua profile to compute turn penalty
- penalty = luabind::call_function<int>( myLuaState, "turn_function", 180-angle );
- } catch (const luabind::error &er) {
- std::cerr << er.what() << std::endl;
- //TODO handle lua errors
+ if (speed_profile.has_turn_penalty_function)
+ {
+ try
+ {
+ // call lua profile to compute turn penalty
+ return luabind::call_function<int>(lua_state, "turn_function", 180. - angle);
}
- } else {
- penalty = 0;
+ catch (const luabind::error &er) { SimpleLogger().Write(logWARNING) << er.what(); }
}
+ return 0;
+}
- if(u == w) {
- return TurnInstructions.UTurn;
+TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn(const NodeID u,
+ const NodeID v,
+ const NodeID w,
+ double angle)
+ const
+{
+ if (u == w)
+ {
+ return TurnInstruction::UTurn;
}
- _NodeBasedDynamicGraph::EdgeIterator edge1 = _nodeBasedGraph->FindEdge(u, v);
- _NodeBasedDynamicGraph::EdgeIterator edge2 = _nodeBasedGraph->FindEdge(v, w);
+ const EdgeID edge1 = m_node_based_graph->FindEdge(u, v);
+ const EdgeID edge2 = m_node_based_graph->FindEdge(v, w);
- _NodeBasedDynamicGraph::EdgeData & data1 = _nodeBasedGraph->GetEdgeData(edge1);
- _NodeBasedDynamicGraph::EdgeData & data2 = _nodeBasedGraph->GetEdgeData(edge2);
+ const EdgeData &data1 = m_node_based_graph->GetEdgeData(edge1);
+ const EdgeData &data2 = m_node_based_graph->GetEdgeData(edge2);
- if(!data1.contraFlow && data2.contraFlow) {
- return TurnInstructions.EnterAgainstAllowedDirection;
+ if (!data1.contraFlow && data2.contraFlow)
+ {
+ return TurnInstruction::EnterAgainstAllowedDirection;
}
- if(data1.contraFlow && !data2.contraFlow) {
- return TurnInstructions.LeaveAgainstAllowedDirection;
+ if (data1.contraFlow && !data2.contraFlow)
+ {
+ return TurnInstruction::LeaveAgainstAllowedDirection;
}
- //roundabouts need to be handled explicitely
- if(data1.roundabout && data2.roundabout) {
- //Is a turn possible? If yes, we stay on the roundabout!
- if( 1 == (_nodeBasedGraph->EndEdges(v) - _nodeBasedGraph->BeginEdges(v)) ) {
- //No turn possible.
- return TurnInstructions.NoTurn;
+ // roundabouts need to be handled explicitely
+ if (data1.roundabout && data2.roundabout)
+ {
+ // Is a turn possible? If yes, we stay on the roundabout!
+ if (1 == m_node_based_graph->GetDirectedOutDegree(v))
+ {
+ // No turn possible.
+ return TurnInstruction::NoTurn;
}
- return TurnInstructions.StayOnRoundAbout;
+ return TurnInstruction::StayOnRoundAbout;
}
- //Does turn start or end on roundabout?
- if(data1.roundabout || data2.roundabout) {
- //We are entering the roundabout
- if( (!data1.roundabout) && data2.roundabout) {
- return TurnInstructions.EnterRoundAbout;
+ // Does turn start or end on roundabout?
+ if (data1.roundabout || data2.roundabout)
+ {
+ // We are entering the roundabout
+ if ((!data1.roundabout) && data2.roundabout)
+ {
+ return TurnInstruction::EnterRoundAbout;
}
- //We are leaving the roundabout
- if(data1.roundabout && (!data2.roundabout) ) {
- return TurnInstructions.LeaveRoundAbout;
+ // We are leaving the roundabout
+ if (data1.roundabout && (!data2.roundabout))
+ {
+ return TurnInstruction::LeaveRoundAbout;
}
}
- //If street names stay the same and if we are certain that it is not a roundabout, we skip it.
- if( (data1.nameID == data2.nameID) && (0 != data1.nameID)) {
- return TurnInstructions.NoTurn;
- }
- if( (data1.nameID == data2.nameID) && (0 == data1.nameID) && (_nodeBasedGraph->GetOutDegree(v) <= 2) ) {
- return TurnInstructions.NoTurn;
+ // If street names stay the same and if we are certain that it is not a
+ // a segment of a roundabout, we skip it.
+ if (data1.nameID == data2.nameID)
+ {
+ // TODO: Here we should also do a small graph exploration to check for
+ // more complex situations
+ if (0 != data1.nameID)
+ {
+ return TurnInstruction::NoTurn;
+ }
+ else if (m_node_based_graph->GetOutDegree(v) <= 2)
+ {
+ return TurnInstruction::NoTurn;
+ }
}
- return TurnInstructions.GetTurnDirectionOfInstruction(angle);
-}
-
-unsigned EdgeBasedGraphFactory::GetNumberOfNodes() const {
- return _nodeBasedGraph->GetNumberOfEdges();
+ return TurnInstructionsClass::GetTurnDirectionOfInstruction(angle);
}
-/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
-template<class CoordinateT>
-double EdgeBasedGraphFactory::GetAngleBetweenTwoEdges(const CoordinateT& A, const CoordinateT& C, const CoordinateT& B) const {
- const double v1x = (A.lon - C.lon)/100000.;
- const double v1y = lat2y(A.lat/100000.) - lat2y(C.lat/100000.);
- const double v2x = (B.lon - C.lon)/100000.;
- const double v2y = lat2y(B.lat/100000.) - lat2y(C.lat/100000.);
-
- double angle = (atan2(v2y,v2x) - atan2(v1y,v1x) )*180/M_PI;
- while(angle < 0)
- angle += 360;
- return angle;
+unsigned EdgeBasedGraphFactory::GetNumberOfEdgeBasedNodes() const
+{
+ return m_number_of_edge_based_nodes;
}
diff --git a/Contractor/EdgeBasedGraphFactory.h b/Contractor/EdgeBasedGraphFactory.h
index c51e4d2..cf489c5 100644
--- a/Contractor/EdgeBasedGraphFactory.h
+++ b/Contractor/EdgeBasedGraphFactory.h
@@ -1,162 +1,126 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-/*
- * This class constructs the edge base representation of a graph from a given node based edge list
- */
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+// This class constructs the edge-expanded routing graph
#ifndef EDGEBASEDGRAPHFACTORY_H_
#define EDGEBASEDGRAPHFACTORY_H_
#include "../typedefs.h"
#include "../DataStructures/DeallocatingVector.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../Extractor/ExtractorStructs.h"
-#include "../DataStructures/HashTable.h"
-#include "../DataStructures/ImportEdge.h"
-#include "../DataStructures/MercatorUtil.h"
-#include "../DataStructures/QueryEdge.h"
-#include "../DataStructures/Percent.h"
+#include "../DataStructures/EdgeBasedNode.h"
+#include "../DataStructures/OriginalEdgeData.h"
+#include "../DataStructures/QueryNode.h"
#include "../DataStructures/TurnInstructions.h"
-#include "../Util/BaseConfiguration.h"
-#include "../Util/LuaUtil.h"
-
-#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 "../DataStructures/NodeBasedGraph.h"
+#include "../DataStructures/RestrictionMap.h"
+#include "GeometryCompressor.h"
#include <algorithm>
+#include <iosfwd>
+#include <memory>
#include <queue>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
-class EdgeBasedGraphFactory : boost::noncopyable {
-public:
- struct EdgeBasedNode {
- bool operator<(const EdgeBasedNode & other) const {
- return other.id < id;
- }
+struct lua_State;
- bool operator==(const EdgeBasedNode & other) const {
- return id == other.id;
- }
+class EdgeBasedGraphFactory
+{
+ public:
+ EdgeBasedGraphFactory() = delete;
+ EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete;
- 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;
- }
+ struct SpeedProfileProperties;
+
+ explicit EdgeBasedGraphFactory(const std::shared_ptr<NodeBasedDynamicGraph> &node_based_graph,
+ std::unique_ptr<RestrictionMap> restricion_map,
+ std::vector<NodeID> &barrier_node_list,
+ std::vector<NodeID> &traffic_light_node_list,
+ std::vector<NodeInfo> &m_node_info_list,
+ SpeedProfileProperties &speed_profile);
+
+ void Run(const std::string &original_edge_data_filename,
+ const std::string &geometry_filename,
+ lua_State *lua_state);
+
+ void GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &edges);
+
+ void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
+
+ TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, double angle) const;
- inline bool isIgnored() const {
- return ignoreInGrid;
+ int GetTurnPenalty(double angle, lua_State *lua_state) const;
+
+ unsigned GetNumberOfEdgeBasedNodes() const;
+
+ struct SpeedProfileProperties
+ {
+ SpeedProfileProperties()
+ : trafficSignalPenalty(0), uTurnPenalty(0), has_turn_penalty_function(false)
+ {
}
- NodeID id;
- int lat1;
- int lat2;
- int lon1;
- int lon2:31;
- bool belongsToTinyComponent:1;
- NodeID nameID;
- unsigned weight:31;
- bool ignoreInGrid:1;
- };
-
- struct SpeedProfileProperties{
- SpeedProfileProperties() : trafficSignalPenalty(0), uTurnPenalty(0), has_turn_penalty_function(false) {}
+
int trafficSignalPenalty;
int uTurnPenalty;
bool has_turn_penalty_function;
- } speedProfile;
-
-private:
- struct _NodeBasedEdgeData {
- int distance;
- unsigned edgeBasedNodeID;
- unsigned nameID;
- short type;
- bool isAccessRestricted:1;
- bool shortcut:1;
- bool forward:1;
- bool backward:1;
- bool roundabout:1;
- bool ignoreInGrid:1;
- bool contraFlow:1;
- };
-
- struct _EdgeBasedEdgeData {
- int distance;
- unsigned via;
- unsigned nameID;
- bool forward;
- bool backward;
- TurnInstruction turnInstruction;
- };
-
- typedef DynamicGraph< _NodeBasedEdgeData > _NodeBasedDynamicGraph;
- typedef _NodeBasedDynamicGraph::InputEdge _NodeBasedEdge;
- std::vector<NodeInfo> inputNodeInfoList;
- unsigned numberOfTurnRestrictions;
-
- boost::shared_ptr<_NodeBasedDynamicGraph> _nodeBasedGraph;
- boost::unordered_set<NodeID> _barrierNodes;
- boost::unordered_set<NodeID> _trafficLights;
-
- typedef std::pair<NodeID, NodeID> RestrictionSource;
- typedef std::pair<NodeID, bool> RestrictionTarget;
- typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
- typedef boost::unordered_map<RestrictionSource, unsigned > RestrictionMap;
- std::vector<EmanatingRestrictionsVector> _restrictionBucketVector;
- RestrictionMap _restrictionMap;
-
- DeallocatingVector<EdgeBasedEdge> edgeBasedEdges;
- 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;
- void InsertEdgeBasedNode(
- _NodeBasedDynamicGraph::EdgeIterator e1,
- _NodeBasedDynamicGraph::NodeIterator u,
- _NodeBasedDynamicGraph::NodeIterator v,
- bool belongsToTinyComponent);
- template<class CoordinateT>
- double GetAngleBetweenTwoEdges(const CoordinateT& A, const CoordinateT& C, const CoordinateT& B) const;
-
-public:
- template< class InputEdgeT >
- explicit EdgeBasedGraphFactory(int nodes, std::vector<InputEdgeT> & inputEdges, std::vector<NodeID> & _bollardNodes, std::vector<NodeID> & trafficLights, std::vector<_Restriction> & inputRestrictions, std::vector<NodeInfo> & nI, SpeedProfileProperties speedProfile);
-
- void Run(const char * originalEdgeDataFilename, lua_State *myLuaState);
- void GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges );
- 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;
+ } speed_profile;
+
+ private:
+ typedef NodeBasedDynamicGraph::EdgeData EdgeData;
+
+ unsigned m_number_of_edge_based_nodes;
+
+ std::vector<NodeInfo> m_node_info_list;
+ std::vector<EdgeBasedNode> m_edge_based_node_list;
+ DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
+
+ std::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
+ std::unordered_set<NodeID> m_barrier_nodes;
+ std::unordered_set<NodeID> m_traffic_lights;
+
+ std::unique_ptr<RestrictionMap> m_restriction_map;
+
+ GeometryCompressor m_geometry_compressor;
+
+ void CompressGeometry();
+ void RenumberEdges();
+ void GenerateEdgeExpandedNodes();
+ void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
+ lua_State *lua_state);
+
+ void InsertEdgeBasedNode(NodeID u, NodeID v, EdgeID e1, bool belongsToTinyComponent);
+
+ void FlushVectorToStream(std::ofstream &edge_data_file,
+ std::vector<OriginalEdgeData> &original_edge_data_vector) const;
+
+ unsigned max_id;
};
#endif /* EDGEBASEDGRAPHFACTORY_H_ */
diff --git a/Contractor/GeometryCompressor.cpp b/Contractor/GeometryCompressor.cpp
new file mode 100644
index 0000000..7c51910
--- /dev/null
+++ b/Contractor/GeometryCompressor.cpp
@@ -0,0 +1,227 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "GeometryCompressor.h"
+#include "../Util/SimpleLogger.h"
+
+#include <boost/assert.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <limits>
+#include <string>
+
+int free_list_maximum = 0;
+int UniqueNumber() { return ++free_list_maximum; }
+
+GeometryCompressor::GeometryCompressor()
+{
+ m_free_list.reserve(100);
+ IncreaseFreeList();
+}
+
+void GeometryCompressor::IncreaseFreeList()
+{
+ m_compressed_geometries.resize(m_compressed_geometries.size() + 100);
+ for (unsigned i = 100; i > 0; --i)
+ {
+ m_free_list.emplace_back(free_list_maximum);
+ ++free_list_maximum;
+ }
+}
+
+bool GeometryCompressor::HasEntryForID(const EdgeID edge_id) const
+{
+ auto iter = m_edge_id_to_list_index_map.find(edge_id);
+ return iter != m_edge_id_to_list_index_map.end();
+}
+
+unsigned GeometryCompressor::GetPositionForID(const EdgeID edge_id) const
+{
+ auto map_iterator = m_edge_id_to_list_index_map.find(edge_id);
+ BOOST_ASSERT(map_iterator != m_edge_id_to_list_index_map.end());
+ BOOST_ASSERT(map_iterator->second < m_compressed_geometries.size());
+ return map_iterator->second;
+}
+
+void GeometryCompressor::SerializeInternalVector(const std::string &path) const
+{
+
+ boost::filesystem::fstream geometry_out_stream(path, std::ios::binary | std::ios::out);
+ const unsigned compressed_geometries = m_compressed_geometries.size() + 1;
+ BOOST_ASSERT(std::numeric_limits<unsigned>::max() != compressed_geometries);
+ geometry_out_stream.write((char *)&compressed_geometries, sizeof(unsigned));
+
+ // write indices array
+ unsigned prefix_sum_of_list_indices = 0;
+ for (const auto &elem : m_compressed_geometries)
+ {
+ geometry_out_stream.write((char *)&prefix_sum_of_list_indices, sizeof(unsigned));
+
+ const std::vector<CompressedNode> ¤t_vector = elem;
+ const unsigned unpacked_size = current_vector.size();
+ BOOST_ASSERT(std::numeric_limits<unsigned>::max() != unpacked_size);
+ prefix_sum_of_list_indices += unpacked_size;
+ }
+ // sentinel element
+ geometry_out_stream.write((char *)&prefix_sum_of_list_indices, sizeof(unsigned));
+
+ // number of geometry entries to follow, it is the (inclusive) prefix sum
+ geometry_out_stream.write((char *)&prefix_sum_of_list_indices, sizeof(unsigned));
+
+ unsigned control_sum = 0;
+ // write compressed geometries
+ for (auto &elem : m_compressed_geometries)
+ {
+ const std::vector<CompressedNode> ¤t_vector = elem;
+ const unsigned unpacked_size = current_vector.size();
+ control_sum += unpacked_size;
+ BOOST_ASSERT(std::numeric_limits<unsigned>::max() != unpacked_size);
+ for (const CompressedNode current_node : current_vector)
+ {
+ geometry_out_stream.write((char *)&(current_node.first), sizeof(NodeID));
+ }
+ }
+ BOOST_ASSERT(control_sum == prefix_sum_of_list_indices);
+ // all done, let's close the resource
+ geometry_out_stream.close();
+}
+
+void GeometryCompressor::CompressEdge(const EdgeID edge_id_1,
+ const EdgeID edge_id_2,
+ const NodeID via_node_id,
+ const NodeID target_node_id,
+ const EdgeWeight weight1,
+ const EdgeWeight weight2)
+{
+ // remove super-trivial geometries
+ BOOST_ASSERT(SPECIAL_EDGEID != edge_id_1);
+ BOOST_ASSERT(SPECIAL_EDGEID != edge_id_2);
+ BOOST_ASSERT(SPECIAL_NODEID != via_node_id);
+ BOOST_ASSERT(SPECIAL_NODEID != target_node_id);
+ BOOST_ASSERT(INVALID_EDGE_WEIGHT != weight1);
+ BOOST_ASSERT(INVALID_EDGE_WEIGHT != weight2);
+
+ // append list of removed edge_id plus via node to surviving edge id:
+ // <surv_1, .. , surv_n, via_node_id, rem_1, .. rem_n
+ //
+ // General scheme:
+ // 1. append via node id to list of edge_id_1
+ // 2. find list for edge_id_2, if yes add all elements and delete it
+
+ // Add via node id. List is created if it does not exist
+ if (!HasEntryForID(edge_id_1))
+ {
+ // create a new entry in the map
+ if (0 == m_free_list.size())
+ {
+ // make sure there is a place to put the entries
+ IncreaseFreeList();
+ }
+ BOOST_ASSERT(!m_free_list.empty());
+ m_edge_id_to_list_index_map[edge_id_1] = m_free_list.back();
+ m_free_list.pop_back();
+ }
+
+ // find bucket index
+ const auto iter = m_edge_id_to_list_index_map.find(edge_id_1);
+ BOOST_ASSERT(iter != m_edge_id_to_list_index_map.end());
+ const unsigned edge_bucket_id1 = iter->second;
+ BOOST_ASSERT(edge_bucket_id1 == GetPositionForID(edge_id_1));
+ BOOST_ASSERT(edge_bucket_id1 < m_compressed_geometries.size());
+
+ std::vector<CompressedNode> &edge_bucket_list1 = m_compressed_geometries[edge_bucket_id1];
+
+ if (edge_bucket_list1.empty())
+ {
+ edge_bucket_list1.emplace_back(via_node_id, weight1);
+ }
+
+ BOOST_ASSERT(0 < edge_bucket_list1.size());
+ BOOST_ASSERT(!edge_bucket_list1.empty());
+
+ if (HasEntryForID(edge_id_2))
+ {
+ // second edge is not atomic anymore
+ const unsigned list_to_remove_index = GetPositionForID(edge_id_2);
+ BOOST_ASSERT(list_to_remove_index < m_compressed_geometries.size());
+
+ std::vector<CompressedNode> &edge_bucket_list2 =
+ m_compressed_geometries[list_to_remove_index];
+
+ // found an existing list, append it to the list of edge_id_1
+ edge_bucket_list1.insert(
+ edge_bucket_list1.end(), edge_bucket_list2.begin(), edge_bucket_list2.end());
+
+ // remove the list of edge_id_2
+ m_edge_id_to_list_index_map.erase(edge_id_2);
+ BOOST_ASSERT(m_edge_id_to_list_index_map.end() ==
+ m_edge_id_to_list_index_map.find(edge_id_2));
+ edge_bucket_list2.clear();
+ BOOST_ASSERT(0 == edge_bucket_list2.size());
+ m_free_list.emplace_back(list_to_remove_index);
+ BOOST_ASSERT(list_to_remove_index == m_free_list.back());
+ }
+ else
+ {
+ // we are certain that the second edge is atomic.
+ edge_bucket_list1.emplace_back(target_node_id, weight2);
+ }
+}
+
+void GeometryCompressor::PrintStatistics() const
+{
+ const uint64_t compressed_edges = m_compressed_geometries.size();
+ BOOST_ASSERT(0 == compressed_edges % 2);
+ BOOST_ASSERT(m_compressed_geometries.size() + m_free_list.size() > 0);
+
+ uint64_t compressed_geometries = 0;
+ uint64_t longest_chain_length = 0;
+ for (const std::vector<CompressedNode> ¤t_vector : m_compressed_geometries)
+ {
+ compressed_geometries += current_vector.size();
+ longest_chain_length = std::max(longest_chain_length, (uint64_t)current_vector.size());
+ }
+
+ SimpleLogger().Write() << "Geometry successfully removed:"
+ "\n compressed edges: " << compressed_edges
+ << "\n compressed geometries: " << compressed_geometries
+ << "\n longest chain length: " << longest_chain_length
+ << "\n cmpr ratio: "
+ << ((float)compressed_edges /
+ std::max(compressed_geometries, (uint64_t)1))
+ << "\n avg chain length: "
+ << (float)compressed_geometries /
+ std::max((uint64_t)1, compressed_edges);
+}
+
+const std::vector<GeometryCompressor::CompressedNode> &
+GeometryCompressor::GetBucketReference(const EdgeID edge_id) const
+{
+ const unsigned index = m_edge_id_to_list_index_map.at(edge_id);
+ return m_compressed_geometries.at(index);
+}
diff --git a/Contractor/GeometryCompressor.h b/Contractor/GeometryCompressor.h
new file mode 100644
index 0000000..7c4fba4
--- /dev/null
+++ b/Contractor/GeometryCompressor.h
@@ -0,0 +1,65 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../typedefs.h"
+
+#include <unordered_map>
+
+#include <string>
+#include <vector>
+
+#ifndef GEOMETRY_COMPRESSOR_H
+#define GEOMETRY_COMPRESSOR_H
+
+class GeometryCompressor
+{
+ public:
+ typedef std::pair<NodeID, EdgeWeight> CompressedNode;
+
+ GeometryCompressor();
+ void CompressEdge(const EdgeID surviving_edge_id,
+ const EdgeID removed_edge_id,
+ const NodeID via_node_id,
+ const NodeID target_node,
+ const EdgeWeight weight1,
+ const EdgeWeight weight2);
+
+ bool HasEntryForID(const EdgeID edge_id) const;
+ void PrintStatistics() const;
+ void SerializeInternalVector(const std::string &path) const;
+ unsigned GetPositionForID(const EdgeID edge_id) const;
+ const std::vector<GeometryCompressor::CompressedNode> &
+ GetBucketReference(const EdgeID edge_id) const;
+
+ private:
+ void IncreaseFreeList();
+ std::vector<std::vector<CompressedNode>> m_compressed_geometries;
+ std::vector<unsigned> m_free_list;
+ std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
+};
+
+#endif // GEOMETRY_COMPRESSOR_H
diff --git a/Contractor/TemporaryStorage.cpp b/Contractor/TemporaryStorage.cpp
index 7c894b0..f9d4287 100644
--- a/Contractor/TemporaryStorage.cpp
+++ b/Contractor/TemporaryStorage.cpp
@@ -1,144 +1,172 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#include <boost/foreach.hpp>
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#include "TemporaryStorage.h"
-TemporaryStorage::TemporaryStorage() {
- try {
- tempDirectory = boost::filesystem::temp_directory_path();
- } catch(boost::filesystem::filesystem_error & e) {
- ERR("could not retrieve location of temporary path: " << e.what());
+StreamData::StreamData()
+ : write_mode(true),
+ temp_path(boost::filesystem::unique_path(temp_directory / TemporaryFilePattern)),
+ temp_file(new boost::filesystem::fstream(
+ temp_path, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary)),
+ readWriteMutex(std::make_shared<boost::mutex>())
+{
+ if (temp_file->fail())
+ {
+ throw OSRMException("temporary file could not be created");
}
}
-TemporaryStorage & TemporaryStorage::GetInstance(){
- static TemporaryStorage runningInstance;
- return runningInstance;
-}
+TemporaryStorage::TemporaryStorage() { temp_directory = boost::filesystem::temp_directory_path(); }
-TemporaryStorage::~TemporaryStorage() {
- removeAll();
+TemporaryStorage &TemporaryStorage::GetInstance()
+{
+ static TemporaryStorage static_instance;
+ return static_instance;
}
-void TemporaryStorage::removeAll() {
- boost::mutex::scoped_lock lock(mutex);
- try {
- for(unsigned slotID = 0; slotID < vectorOfStreamDatas.size(); ++slotID)
- deallocateSlot(slotID);
+TemporaryStorage::~TemporaryStorage() { RemoveAll(); }
- } catch(boost::filesystem::filesystem_error & e) {
- ERR("could not retrieve location of temporary path: " << e.what());
+void TemporaryStorage::RemoveAll()
+{
+ boost::mutex::scoped_lock lock(mutex);
+ for (unsigned slot_id = 0; slot_id < stream_data_list.size(); ++slot_id)
+ {
+ DeallocateSlot(slot_id);
}
- vectorOfStreamDatas.clear();
+ stream_data_list.clear();
}
-int TemporaryStorage::allocateSlot() {
+int TemporaryStorage::AllocateSlot()
+{
boost::mutex::scoped_lock lock(mutex);
- try {
- vectorOfStreamDatas.push_back(StreamData());
- //INFO("created new temporary file: " << vectorOfStreamDatas.back().pathToTemporaryFile);
- } catch(boost::filesystem::filesystem_error & e) {
- abort(e);
- }
- return vectorOfStreamDatas.size() - 1;
+ try { stream_data_list.push_back(StreamData()); }
+ catch (boost::filesystem::filesystem_error &e) { Abort(e); }
+ CheckIfTemporaryDeviceFull();
+ return stream_data_list.size() - 1;
}
-void TemporaryStorage::deallocateSlot(int slotID) {
- try {
- StreamData & data = vectorOfStreamDatas[slotID];
+void TemporaryStorage::DeallocateSlot(const int slot_id)
+{
+ try
+ {
+ StreamData &data = stream_data_list[slot_id];
boost::mutex::scoped_lock lock(*data.readWriteMutex);
- if(!boost::filesystem::exists(data.pathToTemporaryFile)) {
+ if (!boost::filesystem::exists(data.temp_path))
+ {
return;
}
- if(data.streamToTemporaryFile->is_open())
- data.streamToTemporaryFile->close();
+ if (data.temp_file->is_open())
+ {
+ data.temp_file->close();
+ }
- //INFO("deallocating slot " << slotID << " and its file: " << data.pathToTemporaryFile);
- boost::filesystem::remove(data.pathToTemporaryFile);
- } catch(boost::filesystem::filesystem_error & e) {
- abort(e);
+ boost::filesystem::remove(data.temp_path);
}
+ catch (boost::filesystem::filesystem_error &e) { Abort(e); }
}
-void TemporaryStorage::writeToSlot(int slotID, char * pointer, std::streamsize size) {
- try {
- StreamData & data = vectorOfStreamDatas[slotID];
+void TemporaryStorage::WriteToSlot(const int slot_id, char *pointer, const std::size_t size)
+{
+ try
+ {
+ StreamData &data = stream_data_list[slot_id];
+ BOOST_ASSERT(data.write_mode);
+
boost::mutex::scoped_lock lock(*data.readWriteMutex);
- if(!data.writeMode)
- ERR("Writing after first read is not allowed");
- data.streamToTemporaryFile->write(pointer, size);
- } catch(boost::filesystem::filesystem_error & e) {
- abort(e);
+ BOOST_ASSERT_MSG(data.write_mode, "Writing after first read is not allowed");
+ if (1073741824 < data.buffer.size())
+ {
+ data.temp_file->write(&data.buffer[0], data.buffer.size());
+ // data.temp_file->write(pointer, size);
+ data.buffer.clear();
+ CheckIfTemporaryDeviceFull();
+ }
+ data.buffer.insert(data.buffer.end(), pointer, pointer + size);
}
+ catch (boost::filesystem::filesystem_error &e) { Abort(e); }
}
-void TemporaryStorage::readFromSlot(int slotID, char * pointer, std::streamsize size) {
- try {
- StreamData & data = vectorOfStreamDatas[slotID];
+void TemporaryStorage::ReadFromSlot(const int slot_id, char *pointer, const std::size_t size)
+{
+ try
+ {
+ StreamData &data = stream_data_list[slot_id];
boost::mutex::scoped_lock lock(*data.readWriteMutex);
- if(data.writeMode) {
- data.writeMode = false;
- data.streamToTemporaryFile->seekg(0, data.streamToTemporaryFile->beg);
+ if (data.write_mode)
+ {
+ data.write_mode = false;
+ data.temp_file->write(&data.buffer[0], data.buffer.size());
+ data.buffer.clear();
+ data.temp_file->seekg(data.temp_file->beg);
+ BOOST_ASSERT(data.temp_file->beg == data.temp_file->tellg());
}
- data.streamToTemporaryFile->read(pointer, size);
- } catch(boost::filesystem::filesystem_error & e) {
- abort(e);
+ BOOST_ASSERT(!data.write_mode);
+ data.temp_file->read(pointer, size);
}
+ catch (boost::filesystem::filesystem_error &error) { Abort(error); }
}
-unsigned TemporaryStorage::getFreeBytesOnTemporaryDevice() {
- boost::filesystem::space_info tempSpaceInfo;
- try {
- tempSpaceInfo = boost::filesystem::space(tempDirectory);
- } catch(boost::filesystem::filesystem_error & e) {
- abort(e);
+uint64_t TemporaryStorage::GetFreeBytesOnTemporaryDevice()
+{
+ uint64_t value = -1;
+ try
+ {
+ boost::filesystem::path path = boost::filesystem::temp_directory_path();
+ boost::filesystem::space_info space_info = boost::filesystem::space(path);
+ value = space_info.free;
}
- return tempSpaceInfo.available;
+ catch (boost::filesystem::filesystem_error &error) { Abort(error); }
+ return value;
}
-boost::filesystem::fstream::pos_type TemporaryStorage::tell(int slotID) {
+void TemporaryStorage::CheckIfTemporaryDeviceFull()
+{
+ boost::filesystem::path path = boost::filesystem::temp_directory_path();
+ boost::filesystem::space_info space_info = boost::filesystem::space(path);
+ if ((1024 * 1024) > space_info.free)
+ {
+ throw OSRMException("temporary device is full");
+ }
+}
+
+boost::filesystem::fstream::pos_type TemporaryStorage::Tell(const int slot_id)
+{
boost::filesystem::fstream::pos_type position;
- try {
- StreamData & data = vectorOfStreamDatas[slotID];
+ try
+ {
+ StreamData &data = stream_data_list[slot_id];
boost::mutex::scoped_lock lock(*data.readWriteMutex);
- position = data.streamToTemporaryFile->tellp();
- } catch(boost::filesystem::filesystem_error & e) {
- abort(e);
- }
-// INFO("telling position: " << position);
+ position = data.temp_file->tellp();
+ }
+ catch (boost::filesystem::filesystem_error &e) { Abort(e); }
return position;
}
-void TemporaryStorage::abort(boost::filesystem::filesystem_error& ) {
- removeAll();
-// ERR("I/O Error occured: " << e.what());
-}
-
-void TemporaryStorage::seek(int slotID, boost::filesystem::fstream::pos_type position) {
- try {
- StreamData & data = vectorOfStreamDatas[slotID];
- boost::mutex::scoped_lock lock(*data.readWriteMutex);
- data.streamToTemporaryFile->seekg(position);
-// INFO("seeking to position: " << position);
- } catch(boost::filesystem::filesystem_error & e) {
- abort(e);
- }
+void TemporaryStorage::Abort(const boost::filesystem::filesystem_error &error)
+{
+ RemoveAll();
+ throw OSRMException(error.what());
}
diff --git a/Contractor/TemporaryStorage.h b/Contractor/TemporaryStorage.h
index e189981..ca8598b 100644
--- a/Contractor/TemporaryStorage.h
+++ b/Contractor/TemporaryStorage.h
@@ -1,113 +1,96 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef TEMPORARYSTORAGE_H_
#define TEMPORARYSTORAGE_H_
-#include <vector>
-#include <fstream>
+#include "../Util/BoostFileSystemFix.h"
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+#include "../typedefs.h"
+#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
-#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
-#include "../typedefs.h"
+#include <cstdint>
+
+#include <vector>
+#include <fstream>
+#include <memory>
-//This is one big workaround for latest boost renaming woes.
-
-#if BOOST_FILESYSTEM_VERSION < 3
-#warning Boost Installation with Filesystem3 missing, activating workaround
-#include <cstdio>
-namespace boost {
-namespace filesystem {
-inline path temp_directory_path() {
- char * buffer;
- buffer = tmpnam (NULL);
-
- return path(buffer);
-}
-
-inline path unique_path(const path&) {
- return temp_directory_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
- * On deallocation every slot gets deallocated
- *
- * Access is sequential, which means, that there is no random access
- * -> Data is written in first phase and reread in second.
- */
-
-static boost::filesystem::path tempDirectory;
+struct StreamData
+{
+ bool write_mode;
+ boost::filesystem::path temp_path;
+ std::shared_ptr<boost::filesystem::fstream> temp_file;
+ std::shared_ptr<boost::mutex> readWriteMutex;
+ std::vector<char> buffer;
+
+ StreamData();
+};
+
+// This class implements a singleton file storage for temporary data.
+// temporary slots can be accessed by other objects through an int
+// On deallocation every slot gets deallocated
+//
+// Access is sequential, which means, that there is no random access
+// -> Data is written in first phase and reread in second.
+
+static boost::filesystem::path temp_directory;
static std::string TemporaryFilePattern("OSRM-%%%%-%%%%-%%%%");
-class TemporaryStorage {
-public:
- static TemporaryStorage & GetInstance();
+class TemporaryStorage
+{
+ public:
+ static TemporaryStorage &GetInstance();
virtual ~TemporaryStorage();
- int allocateSlot();
- void deallocateSlot(int slotID);
- void writeToSlot(int slotID, char * pointer, std::streamsize size);
- void readFromSlot(int slotID, char * pointer, std::streamsize size);
- //returns the number of free bytes
- unsigned getFreeBytesOnTemporaryDevice();
- boost::filesystem::fstream::pos_type tell(int slotID);
- void seek(int slotID, boost::filesystem::fstream::pos_type);
- void removeAll();
-private:
+ int AllocateSlot();
+ void DeallocateSlot(const int slot_id);
+ void WriteToSlot(const int slot_id, char *pointer, const std::size_t size);
+ void ReadFromSlot(const int slot_id, char *pointer, const std::size_t size);
+ // returns the number of free bytes
+ uint64_t GetFreeBytesOnTemporaryDevice();
+ boost::filesystem::fstream::pos_type Tell(const int slot_id);
+ void RemoveAll();
+
+ private:
TemporaryStorage();
- TemporaryStorage(TemporaryStorage const &){};
- TemporaryStorage& operator=(TemporaryStorage const &) {
- return *this;
- }
- void abort(boost::filesystem::filesystem_error& e);
-
- struct StreamData {
- bool writeMode;
- boost::filesystem::path pathToTemporaryFile;
- boost::shared_ptr<boost::filesystem::fstream> streamToTemporaryFile;
- boost::shared_ptr<boost::mutex> readWriteMutex;
- StreamData() :
- writeMode(true),
- pathToTemporaryFile (boost::filesystem::unique_path(tempDirectory.append(TemporaryFilePattern.begin(), TemporaryFilePattern.end()))),
- streamToTemporaryFile(new boost::filesystem::fstream(pathToTemporaryFile, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary)),
- readWriteMutex(new boost::mutex)
- {
- if(streamToTemporaryFile->fail())
- ERR("Aborting, because temporary file at " << pathToTemporaryFile << " could not be created");
- }
- };
- //vector of file streams that is used to store temporary data
- std::vector<StreamData> vectorOfStreamDatas;
+ TemporaryStorage(TemporaryStorage const &) {};
+
+ TemporaryStorage &operator=(TemporaryStorage const &) { return *this; }
+
+ void Abort(const boost::filesystem::filesystem_error &e);
+ void CheckIfTemporaryDeviceFull();
+
+ // vector of file streams that is used to store temporary data
boost::mutex mutex;
+ std::vector<StreamData> stream_data_list;
};
#endif /* TEMPORARYSTORAGE_H_ */
diff --git a/DataStructures/BinaryHeap.h b/DataStructures/BinaryHeap.h
index f8b3470..00d3782 100644
--- a/DataStructures/BinaryHeap.h
+++ b/DataStructures/BinaryHeap.h
@@ -1,267 +1,289 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef BINARYHEAP_H_INCLUDED
-#define BINARYHEAP_H_INCLUDED
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//Not compatible with non contiguous node ids
+*/
+
+#ifndef BINARY_HEAP_H
+#define BINARY_HEAP_H
+
+#include <boost/assert.hpp>
-#include <cassert>
-#include <limits>
-#include <vector>
#include <algorithm>
+#include <limits>
#include <map>
-#include <boost/unordered_map.hpp>
-
-template< typename NodeID, typename Key >
-class ArrayStorage {
-public:
+#include <type_traits>
+#include <unordered_map>
+#include <vector>
- ArrayStorage( size_t size ) : positions( new Key[size] ) {
- memset(positions, 0, size*sizeof(Key));
+template <typename NodeID, typename Key> class ArrayStorage
+{
+ public:
+ explicit ArrayStorage(size_t size) : positions(new Key[size])
+ {
+ memset(positions, 0, size * sizeof(Key));
}
- ~ArrayStorage() {
- delete[] positions;
- }
+ ~ArrayStorage() { delete[] positions; }
- Key &operator[]( NodeID node ) {
- return positions[node];
- }
+ Key &operator[](NodeID node) { return positions[node]; }
void Clear() {}
-private:
- Key* positions;
+ private:
+ Key *positions;
};
-template< typename NodeID, typename Key >
-class MapStorage {
-public:
+template <typename NodeID, typename Key> class MapStorage
+{
+ public:
+ explicit MapStorage(size_t) {}
- MapStorage( size_t ) {}
+ Key &operator[](NodeID node) { return nodes[node]; }
- Key &operator[]( NodeID node ) {
- return nodes[node];
- }
-
- void Clear() {
- nodes.clear();
- }
-
-private:
- std::map< NodeID, Key > nodes;
+ void Clear() { nodes.clear(); }
+ private:
+ std::map<NodeID, Key> nodes;
};
-template< typename NodeID, typename Key >
-class UnorderedMapStorage {
-public:
-
- UnorderedMapStorage( size_t ) {
- //hash table gets 1000 Buckets
- nodes.rehash(1000);
- }
+template <typename NodeID, typename Key> class UnorderedMapStorage
+{
+ public:
+ explicit UnorderedMapStorage(size_t) { nodes.rehash(1000); }
- Key &operator[]( const NodeID node ) {
- return nodes[node];
- }
+ Key &operator[](const NodeID node) { return nodes[node]; }
- void Clear() {
- nodes.clear();
+ Key const &operator[](const NodeID node) const
+ {
+ auto iter = nodes.find(node);
+ return iter->second;
}
-private:
- boost::unordered_map< NodeID, Key > nodes;
-};
+ void Clear() { nodes.clear(); }
-template<typename NodeID = unsigned>
-struct _SimpleHeapData {
- NodeID parent;
- _SimpleHeapData( NodeID p ) : parent(p) { }
+ private:
+ std::unordered_map<NodeID, Key> nodes;
};
-template < typename NodeID, typename Key, typename Weight, typename Data, typename IndexStorage = ArrayStorage<NodeID, NodeID> >
-class BinaryHeap {
-private:
- BinaryHeap( const BinaryHeap& right );
- void operator=( const BinaryHeap& right );
-public:
+template <typename NodeID,
+ typename Key,
+ typename Weight,
+ typename Data,
+ typename IndexStorage = ArrayStorage<NodeID, NodeID>>
+class BinaryHeap
+{
+ private:
+ BinaryHeap(const BinaryHeap &right);
+ void operator=(const BinaryHeap &right);
+
+ public:
typedef Weight WeightType;
typedef Data DataType;
- BinaryHeap( size_t maxID )
- : nodeIndex( maxID ) {
- Clear();
- }
+ explicit BinaryHeap(size_t maxID) : node_index(maxID) { Clear(); }
- void Clear() {
- heap.resize( 1 );
- insertedNodes.clear();
- heap[0].weight = std::numeric_limits< Weight >::min();
- nodeIndex.Clear();
+ void Clear()
+ {
+ heap.resize(1);
+ inserted_nodes.clear();
+ heap[0].weight = std::numeric_limits<Weight>::min();
+ node_index.Clear();
}
- Key Size() const {
- return static_cast<Key>( heap.size() - 1 );
- }
+ std::size_t Size() const { return (heap.size() - 1); }
- void Insert( NodeID node, Weight weight, const Data &data ) {
+ bool Empty() const { return 0 == Size(); }
+
+ void Insert(NodeID node, Weight weight, const Data &data)
+ {
HeapElement element;
- element.index = static_cast<NodeID>(insertedNodes.size());
+ element.index = static_cast<NodeID>(inserted_nodes.size());
element.weight = weight;
const Key key = static_cast<Key>(heap.size());
- heap.push_back( element );
- insertedNodes.push_back( HeapNode( node, key, weight, data ) );
- nodeIndex[node] = element.index;
- Upheap( key );
+ heap.emplace_back(element);
+ inserted_nodes.emplace_back(node, key, weight, data);
+ node_index[node] = element.index;
+ Upheap(key);
CheckHeap();
}
- Data& GetData( NodeID node ) {
- const Key index = nodeIndex[node];
- return insertedNodes[index].data;
+ Data &GetData(NodeID node)
+ {
+ const Key index = node_index[node];
+ return inserted_nodes[index].data;
+ }
+
+ Data const &GetData(NodeID node) const
+ {
+ const Key index = node_index[node];
+ return inserted_nodes[index].data;
}
- Weight& GetKey( NodeID node ) {
- const Key index = nodeIndex[node];
- return insertedNodes[index].weight;
+ Weight &GetKey(NodeID node)
+ {
+ const Key index = node_index[node];
+ return inserted_nodes[index].weight;
}
- bool WasRemoved( NodeID node ) {
- assert( WasInserted( node ) );
- const Key index = nodeIndex[node];
- return insertedNodes[index].key == 0;
+ bool WasRemoved(const NodeID node)
+ {
+ BOOST_ASSERT(WasInserted(node));
+ const Key index = node_index[node];
+ return inserted_nodes[index].key == 0;
}
- bool WasInserted( NodeID node ) {
- const Key index = nodeIndex[node];
- if ( index >= static_cast<Key> (insertedNodes.size()) )
+ bool WasInserted(const NodeID node)
+ {
+ const Key index = node_index[node];
+ if (index >= static_cast<Key>(inserted_nodes.size()))
+ {
return false;
- return insertedNodes[index].node == node;
+ }
+ return inserted_nodes[index].node == node;
}
- NodeID Min() const {
- assert( heap.size() > 1 );
- return insertedNodes[heap[1].index].node;
+ NodeID Min() const
+ {
+ BOOST_ASSERT(heap.size() > 1);
+ return inserted_nodes[heap[1].index].node;
}
- NodeID DeleteMin() {
- assert( heap.size() > 1 );
+ NodeID DeleteMin()
+ {
+ BOOST_ASSERT(heap.size() > 1);
const Key removedIndex = heap[1].index;
- heap[1] = heap[heap.size()-1];
+ heap[1] = heap[heap.size() - 1];
heap.pop_back();
- if ( heap.size() > 1 )
- Downheap( 1 );
- insertedNodes[removedIndex].key = 0;
+ if (heap.size() > 1)
+ {
+ Downheap(1);
+ }
+ inserted_nodes[removedIndex].key = 0;
CheckHeap();
- return insertedNodes[removedIndex].node;
+ return inserted_nodes[removedIndex].node;
}
- void DeleteAll() {
- for ( typename std::vector< HeapElement >::iterator i = heap.begin() + 1, iend = heap.end(); i != iend; ++i )
- insertedNodes[i->index].key = 0;
- heap.resize( 1 );
- heap[0].weight = (std::numeric_limits< Weight >::min)();
+ void DeleteAll()
+ {
+ auto iend = heap.end();
+ for (typename std::vector<HeapElement>::iterator i = heap.begin() + 1; i != iend; ++i)
+ {
+ inserted_nodes[i->index].key = 0;
+ }
+ heap.resize(1);
+ heap[0].weight = (std::numeric_limits<Weight>::min)();
}
- void DecreaseKey( NodeID node, Weight weight ) {
- assert( UINT_MAX != node );
- const Key index = nodeIndex[node];
- Key key = insertedNodes[index].key;
- assert ( key >= 0 );
+ void DecreaseKey(NodeID node, Weight weight)
+ {
+ BOOST_ASSERT(std::numeric_limits<NodeID>::max() != node);
+ const Key &index = node_index[node];
+ Key &key = inserted_nodes[index].key;
+ BOOST_ASSERT(key >= 0);
- insertedNodes[index].weight = weight;
+ inserted_nodes[index].weight = weight;
heap[key].weight = weight;
- Upheap( key );
+ Upheap(key);
CheckHeap();
}
-private:
- class HeapNode {
- public:
- HeapNode() {
- }
- HeapNode( NodeID n, Key k, Weight w, Data d )
- : node( n ), key( k ), weight( w ), data( d ) {
- }
+ private:
+ class HeapNode
+ {
+ public:
+ HeapNode(NodeID n, Key k, Weight w, Data d) : node(n), key(k), weight(w), data(d) {}
NodeID node;
Key key;
Weight weight;
Data data;
};
- struct HeapElement {
+ struct HeapElement
+ {
Key index;
Weight weight;
};
- std::vector< HeapNode > insertedNodes;
- std::vector< HeapElement > heap;
- IndexStorage nodeIndex;
+ std::vector<HeapNode> inserted_nodes;
+ std::vector<HeapElement> heap;
+ IndexStorage node_index;
- void Downheap( Key key ) {
+ void Downheap(Key key)
+ {
const Key droppingIndex = heap[key].index;
const Weight weight = heap[key].weight;
Key nextKey = key << 1;
- while ( nextKey < static_cast<Key>( heap.size() ) ) {
+ while (nextKey < static_cast<Key>(heap.size()))
+ {
const Key nextKeyOther = nextKey + 1;
- if ( ( nextKeyOther < static_cast<Key> ( heap.size() ) )&& ( heap[nextKey].weight > heap[nextKeyOther].weight) )
+ if ((nextKeyOther < static_cast<Key>(heap.size())) &&
+ (heap[nextKey].weight > heap[nextKeyOther].weight))
+ {
nextKey = nextKeyOther;
-
- if ( weight <= heap[nextKey].weight )
+ }
+ if (weight <= heap[nextKey].weight)
+ {
break;
-
+ }
heap[key] = heap[nextKey];
- insertedNodes[heap[key].index].key = key;
+ inserted_nodes[heap[key].index].key = key;
key = nextKey;
nextKey <<= 1;
}
heap[key].index = droppingIndex;
heap[key].weight = weight;
- insertedNodes[droppingIndex].key = key;
+ inserted_nodes[droppingIndex].key = key;
}
- void Upheap( Key key ) {
+ void Upheap(Key key)
+ {
const Key risingIndex = heap[key].index;
const Weight weight = heap[key].weight;
Key nextKey = key >> 1;
- while ( heap[nextKey].weight > weight ) {
- assert( nextKey != 0 );
+ while (heap[nextKey].weight > weight)
+ {
+ BOOST_ASSERT(nextKey != 0);
heap[key] = heap[nextKey];
- insertedNodes[heap[key].index].key = key;
+ inserted_nodes[heap[key].index].key = key;
key = nextKey;
nextKey >>= 1;
}
heap[key].index = risingIndex;
heap[key].weight = weight;
- insertedNodes[risingIndex].key = key;
+ inserted_nodes[risingIndex].key = key;
}
- void CheckHeap() {
+ void CheckHeap()
+ {
#ifndef NDEBUG
- for ( Key i = 2; i < (Key) heap.size(); ++i ) {
- assert( heap[i].weight >= heap[i >> 1].weight );
+ for (Key i = 2; i < (Key)heap.size(); ++i)
+ {
+ BOOST_ASSERT(heap[i].weight >= heap[i >> 1].weight);
}
#endif
}
};
-#endif //#ifndef BINARYHEAP_H_INCLUDED
+#endif // BINARY_HEAP_H
diff --git a/DataStructures/ConcurrentQueue.h b/DataStructures/ConcurrentQueue.h
index 0466ab2..9d5b366 100644
--- a/DataStructures/ConcurrentQueue.h
+++ b/DataStructures/ConcurrentQueue.h
@@ -1,83 +1,85 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef CONCURRENTQUEUE_H_INCLUDED
-#define CONCURRENTQUEUE_H_INCLUDED
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <boost/bind.hpp>
-#include <boost/circular_buffer.hpp>
-#include <boost/thread/condition.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/thread.hpp>
-
-#include "../typedefs.h"
-
-template<typename Data>
-class ConcurrentQueue {
+*/
- typedef typename boost::circular_buffer<Data>::size_type size_t;
+#ifndef CONCURRENT_QUEUE_H
+#define CONCURRENT_QUEUE_H
-public:
- ConcurrentQueue(const size_t max_size) : internal_queue(max_size) { }
+#include "../typedefs.h"
- inline void push(Data const& data) {
- boost::mutex::scoped_lock lock(m_mutex);
- m_not_full.wait(lock, boost::bind(&ConcurrentQueue<Data>::is_not_full, this));
- internal_queue.push_back(data);
- lock.unlock();
+#include <boost/circular_buffer.hpp>
+#include <condition_variable>
+#include <mutex>
+
+template <typename Data> class ConcurrentQueue
+{
+ public:
+ explicit ConcurrentQueue(const size_t max_size) : m_internal_queue(max_size) {}
+
+ inline void push(const Data &data)
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_not_full.wait(lock,
+ [this]
+ { return m_internal_queue.size() < m_internal_queue.capacity(); });
+ m_internal_queue.push_back(data);
m_not_empty.notify_one();
}
- inline bool empty() const {
- return internal_queue.empty();
- }
+ inline bool empty() const { return m_internal_queue.empty(); }
- inline void wait_and_pop(Data& popped_value) {
- boost::mutex::scoped_lock lock(m_mutex);
- m_not_empty.wait(lock, boost::bind(&ConcurrentQueue<Data>::is_not_empty, this));
- popped_value=internal_queue.front();
- internal_queue.pop_front();
- lock.unlock();
+ inline void wait_and_pop(Data &popped_value)
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_not_empty.wait(lock,
+ [this]
+ { return !m_internal_queue.empty(); });
+ popped_value = m_internal_queue.front();
+ m_internal_queue.pop_front();
m_not_full.notify_one();
}
- inline bool try_pop(Data& popped_value) {
- boost::mutex::scoped_lock lock(m_mutex);
- if(internal_queue.empty()) {
+ inline bool try_pop(Data &popped_value)
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+ if (m_internal_queue.empty())
+ {
return false;
}
- popped_value=internal_queue.front();
- internal_queue.pop_front();
- lock.unlock();
+ popped_value = m_internal_queue.front();
+ m_internal_queue.pop_front();
m_not_full.notify_one();
return true;
}
-private:
- boost::circular_buffer<Data> internal_queue;
- boost::mutex m_mutex;
- boost::condition m_not_empty;
- boost::condition m_not_full;
-
- inline bool is_not_empty() const { return internal_queue.size() > 0; }
- inline bool is_not_full() const { return internal_queue.size() < internal_queue.capacity(); }
+ private:
+ boost::circular_buffer<Data> m_internal_queue;
+ std::mutex m_mutex;
+ std::condition_variable m_not_empty;
+ std::condition_variable m_not_full;
};
-#endif //#ifndef CONCURRENTQUEUE_H_INCLUDED
+#endif // CONCURRENT_QUEUE_H
diff --git a/DataStructures/Coordinate.cpp b/DataStructures/Coordinate.cpp
new file mode 100644
index 0000000..9c453e7
--- /dev/null
+++ b/DataStructures/Coordinate.cpp
@@ -0,0 +1,446 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <osrm/Coordinate.h>
+#include "../Util/MercatorUtil.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/StringUtil.h"
+
+#include <boost/assert.hpp>
+
+#ifndef NDEBUG
+#include <bitset>
+#endif
+#include <iostream>
+#include <limits>
+
+FixedPointCoordinate::FixedPointCoordinate()
+ : lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min())
+{
+}
+
+FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon)
+{
+#ifndef NDEBUG
+ if (0 != (std::abs(lat) >> 30))
+ {
+ std::bitset<32> y_coordinate_vector(lat);
+ SimpleLogger().Write(logDEBUG) << "broken lat: " << lat
+ << ", bits: " << y_coordinate_vector;
+ }
+ if (0 != (std::abs(lon) >> 30))
+ {
+ std::bitset<32> x_coordinate_vector(lon);
+ SimpleLogger().Write(logDEBUG) << "broken lon: " << lon
+ << ", bits: " << x_coordinate_vector;
+ }
+#endif
+}
+
+void FixedPointCoordinate::Reset()
+{
+ lat = std::numeric_limits<int>::min();
+ lon = std::numeric_limits<int>::min();
+}
+bool FixedPointCoordinate::isSet() const
+{
+ return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon);
+}
+bool FixedPointCoordinate::isValid() const
+{
+ if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
+ lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
+ {
+ return false;
+ }
+ return true;
+}
+bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const
+{
+ return lat == other.lat && lon == other.lon;
+}
+
+double FixedPointCoordinate::ApproximateDistance(const int lat1,
+ const int lon1,
+ const int lat2,
+ const int lon2)
+{
+ BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
+ double RAD = 0.017453292519943295769236907684886;
+ double lt1 = lat1 / COORDINATE_PRECISION;
+ double ln1 = lon1 / COORDINATE_PRECISION;
+ double lt2 = lat2 / COORDINATE_PRECISION;
+ double ln2 = lon2 / COORDINATE_PRECISION;
+ double dlat1 = lt1 * (RAD);
+
+ double dlong1 = ln1 * (RAD);
+ double dlat2 = lt2 * (RAD);
+ double dlong2 = ln2 * (RAD);
+
+ double dLong = dlong1 - dlong2;
+ double dLat = dlat1 - dlat2;
+
+ double aHarv = pow(sin(dLat / 2.0), 2.0) + cos(dlat1) * cos(dlat2) * pow(sin(dLong / 2.), 2);
+ double cHarv = 2. * atan2(sqrt(aHarv), sqrt(1.0 - aHarv));
+ // earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
+ // The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
+ const double earth = 6372797.560856;
+ return earth * cHarv;
+}
+
+double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &coordinate_1,
+ const FixedPointCoordinate &coordinate_2)
+{
+ return ApproximateDistance(
+ coordinate_1.lat, coordinate_1.lon, coordinate_2.lat, coordinate_2.lon);
+}
+
+float FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &coordinate_1,
+ const FixedPointCoordinate &coordinate_2)
+{
+ return ApproximateEuclideanDistance(
+ coordinate_1.lat, coordinate_1.lon, coordinate_2.lat, coordinate_2.lon);
+}
+
+float FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
+ const int lon1,
+ const int lat2,
+ const int lon2)
+{
+ BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
+ BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
+
+ const float RAD = 0.017453292519943295769236907684886f;
+ const float float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
+ const float float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
+ const float float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
+ const float float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
+
+ const float x_value = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.f);
+ const float y_value = float_lat2 - float_lat1;
+ const float earth_radius = 6372797.560856f;
+ return sqrt(x_value * x_value + y_value * y_value) * earth_radius;
+}
+
+float
+FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &source_coordinate,
+ const FixedPointCoordinate &target_coordinate,
+ const FixedPointCoordinate &point)
+{
+ // initialize values
+ const float x_value = lat2y(point.lat / COORDINATE_PRECISION);
+ const float y_value = point.lon / COORDINATE_PRECISION;
+ const float a = lat2y(source_coordinate.lat / COORDINATE_PRECISION);
+ const float b = source_coordinate.lon / COORDINATE_PRECISION;
+ const float c = lat2y(target_coordinate.lat / COORDINATE_PRECISION);
+ const float d = target_coordinate.lon / COORDINATE_PRECISION;
+ float p, q;
+ if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
+ {
+ const float slope = (d - b) / (c - a); // slope
+ // Projection of (x,y) on line joining (a,b) and (c,d)
+ p = ((x_value + (slope * y_value)) + (slope * slope * a - slope * b)) /
+ (1.f + slope * slope);
+ q = b + slope * (p - a);
+ }
+ else
+ {
+ p = c;
+ q = y_value;
+ }
+
+ float nY = (d * p - c * q) / (a * d - b * c);
+ // discretize the result to coordinate precision. it's a hack!
+ if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
+ {
+ nY = 0.f;
+ }
+
+ // compute ratio
+ float ratio = (p - nY * a) / c;
+ if (std::isnan(ratio))
+ {
+ ratio = (target_coordinate == point ? 1.f : 0.f);
+ }
+ else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
+ {
+ ratio = 0.f;
+ }
+ else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
+ {
+ ratio = 1.f;
+ }
+
+ //compute the nearest location
+ FixedPointCoordinate nearest_location;
+ BOOST_ASSERT(!std::isnan(ratio));
+ if (ratio <= 0.f)
+ { // point is "left" of edge
+ nearest_location = source_coordinate;
+ }
+ else if (ratio >= 1.f)
+ { // point is "right" of edge
+ nearest_location = target_coordinate;
+ }
+ else
+ { // point lies in between
+ nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
+ nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
+ }
+ BOOST_ASSERT(nearest_location.isValid());
+ return FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
+}
+
+float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
+ const FixedPointCoordinate &segment_target,
+ const FixedPointCoordinate &query_location,
+ FixedPointCoordinate &nearest_location,
+ float &ratio)
+{
+ BOOST_ASSERT(query_location.isValid());
+
+ // initialize values
+ const float x = lat2y(query_location.lat / COORDINATE_PRECISION);
+ const float y = query_location.lon / COORDINATE_PRECISION;
+ const float a = lat2y(segment_source.lat / COORDINATE_PRECISION);
+ const float b = segment_source.lon / COORDINATE_PRECISION;
+ const float c = lat2y(segment_target.lat / COORDINATE_PRECISION);
+ const float d = segment_target.lon / COORDINATE_PRECISION;
+ float p, q /*,mX*/, nY;
+ if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
+ {
+ const float 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.f + m * m);
+ q = b + m * (p - a);
+ }
+ else
+ {
+ p = c;
+ q = y;
+ }
+ nY = (d * p - c * q) / (a * d - b * c);
+
+ // discretize the result to coordinate precision. it's a hack!
+ if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
+ {
+ nY = 0.f;
+ }
+
+ // compute ratio
+ ratio = (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(ratio))
+ {
+ ratio = (segment_target == query_location ? 1.f : 0.f);
+ }
+ else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
+ {
+ ratio = 0.;
+ }
+ else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
+ {
+ ratio = 1.f;
+ }
+
+ // compute nearest location
+ BOOST_ASSERT(!std::isnan(ratio));
+ if (ratio <= 0.f)
+ {
+ nearest_location = segment_source;
+ }
+ else if (ratio >= 1.)
+ {
+ nearest_location = segment_target;
+ }
+ else
+ {
+ // point lies in between
+ nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
+ nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
+ }
+ BOOST_ASSERT(nearest_location.isValid());
+
+ const float approximate_distance =
+ FixedPointCoordinate::ApproximateEuclideanDistance(query_location, nearest_location);
+ BOOST_ASSERT(0. <= approximate_distance);
+ return approximate_distance;
+}
+
+void FixedPointCoordinate::convertInternalLatLonToString(const int value, std::string &output)
+{
+ char buffer[12];
+ buffer[11] = 0; // zero termination
+ output = printInt<11, 6>(buffer, value);
+}
+
+void FixedPointCoordinate::convertInternalCoordinateToString(const FixedPointCoordinate &coord,
+ std::string &output)
+{
+ std::string tmp;
+ tmp.reserve(23);
+ convertInternalLatLonToString(coord.lon, tmp);
+ output = tmp;
+ output += ",";
+ convertInternalLatLonToString(coord.lat, tmp);
+ output += tmp;
+}
+
+void
+FixedPointCoordinate::convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord,
+ std::string &output)
+{
+ std::string tmp;
+ tmp.reserve(23);
+ convertInternalLatLonToString(coord.lat, tmp);
+ output = tmp;
+ output += ",";
+ convertInternalLatLonToString(coord.lon, tmp);
+ output += tmp;
+}
+
+void FixedPointCoordinate::Output(std::ostream &out) const
+{
+ out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")";
+}
+
+float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &first_coordinate,
+ const FixedPointCoordinate &second_coordinate)
+{
+ const float lon_diff = second_coordinate.lon / COORDINATE_PRECISION - first_coordinate.lon / COORDINATE_PRECISION;
+ const float lon_delta = DegreeToRadian(lon_diff);
+ const float lat1 = DegreeToRadian(first_coordinate.lat / COORDINATE_PRECISION);
+ const float lat2 = DegreeToRadian(second_coordinate.lat / COORDINATE_PRECISION);
+ const float y = sin(lon_delta) * cos(lat2);
+ const float x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon_delta);
+ float result = RadianToDegree(std::atan2(y, x));
+ while (result < 0.f)
+ {
+ result += 360.f;
+ }
+
+ while (result >= 360.f)
+ {
+ result -= 360.f;
+ }
+ return result;
+}
+
+float FixedPointCoordinate::GetBearing(const FixedPointCoordinate &other) const
+{
+ const float lon_delta =
+ DegreeToRadian(lon / COORDINATE_PRECISION - other.lon / COORDINATE_PRECISION);
+ const float lat1 = DegreeToRadian(other.lat / COORDINATE_PRECISION);
+ const float lat2 = DegreeToRadian(lat / COORDINATE_PRECISION);
+ const float y_value = std::sin(lon_delta) * std::cos(lat2);
+ const float x_value =
+ std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
+ float result = RadianToDegree(std::atan2(y_value, x_value));
+
+ while (result < 0.f)
+ {
+ result += 360.f;
+ }
+
+ while (result >= 360.f)
+ {
+ result -= 360.f;
+ }
+ return result;
+}
+
+float FixedPointCoordinate::DegreeToRadian(const float degree) { return degree * (static_cast<float>(M_PI) / 180.f); }
+
+float FixedPointCoordinate::RadianToDegree(const float radian) { return radian * (180.f * static_cast<float>(M_1_PI)); }
+
+// This distance computation does integer arithmetic only and is a lot faster than
+// the other distance function which are numerically correct('ish).
+// It preserves some order among the elements that make it useful for certain purposes
+int FixedPointCoordinate::OrderedPerpendicularDistanceApproximation(
+ const FixedPointCoordinate &input_point,
+ const FixedPointCoordinate &segment_source,
+ const FixedPointCoordinate &segment_target)
+{
+ // initialize values
+ const float x = lat2y(input_point.lat / COORDINATE_PRECISION);
+ const float y = input_point.lon / COORDINATE_PRECISION;
+ const float a = lat2y(segment_source.lat / COORDINATE_PRECISION);
+ const float b = segment_source.lon / COORDINATE_PRECISION;
+ const float c = lat2y(segment_target.lat / COORDINATE_PRECISION);
+ const float d = segment_target.lon / COORDINATE_PRECISION;
+
+ float p, q;
+ if (a == c)
+ {
+ p = c;
+ q = y;
+ }
+ else
+ {
+ const float 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.f + m * m);
+ q = b + m * (p - a);
+ }
+
+ const float nY = (d * p - c * q) / (a * d - b * c);
+ float ratio = (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(ratio))
+ {
+ ratio = (segment_target == input_point) ? 1.f : 0.f;
+ }
+
+ // compute target quasi-location
+ int dx, dy;
+ if (ratio < 0.f)
+ {
+ dx = input_point.lon - segment_source.lon;
+ dy = input_point.lat - segment_source.lat;
+ }
+ else if (ratio > 1.f)
+ {
+ dx = input_point.lon - segment_target.lon;
+ dy = input_point.lat - segment_target.lat;
+ }
+ else
+ {
+ // point lies in between
+ dx = input_point.lon - static_cast<int>(q * COORDINATE_PRECISION);
+ dy = input_point.lat - static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
+ }
+
+ // return an approximation in the plane
+ return static_cast<int>(sqrt(dx * dx + dy * dy));
+}
diff --git a/DataStructures/Coordinate.h b/DataStructures/Coordinate.h
deleted file mode 100644
index bc63289..0000000
--- a/DataStructures/Coordinate.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- 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 COORDINATE_H_
-#define COORDINATE_H_
-
-#include <cassert>
-#include <cmath>
-#include <climits>
-
-#include <iostream>
-
-struct _Coordinate {
- int lat;
- int lon;
- _Coordinate () : lat(INT_MIN), lon(INT_MIN) {}
- _Coordinate (int t, int n) : lat(t) , lon(n) {}
- void Reset() {
- lat = INT_MIN;
- lon = INT_MIN;
- }
- bool isSet() const {
- return (INT_MIN != lat) && (INT_MIN != lon);
- }
- inline bool isValid() const {
- if(lat > 90*100000 || lat < -90*100000 || lon > 180*100000 || lon <-180*100000) {
- return false;
- }
- return true;
- }
- bool operator==(const _Coordinate & other) const {
- return lat == other.lat && lon == other.lon;
- }
-};
-
-inline std::ostream & operator<<(std::ostream & out, const _Coordinate & c){
- out << "(" << c.lat << "," << c.lon << ")";
- return out;
-}
-
-inline double ApproximateDistance( const int lat1, const int lon1, const int lat2, const int lon2 ) {
- assert(lat1 != INT_MIN);
- assert(lon1 != INT_MIN);
- assert(lat2 != INT_MIN);
- assert(lon2 != INT_MIN);
- double RAD = 0.017453292519943295769236907684886;
- double lt1 = lat1/100000.;
- double ln1 = lon1/100000.;
- double lt2 = lat2/100000.;
- double ln2 = lon2/100000.;
- double dlat1=lt1*(RAD);
-
- double dlong1=ln1*(RAD);
- double dlat2=lt2*(RAD);
- double dlong2=ln2*(RAD);
-
- double dLong=dlong1-dlong2;
- double dLat=dlat1-dlat2;
-
- double aHarv= pow(sin(dLat/2.0),2.0)+cos(dlat1)*cos(dlat2)*pow(sin(dLong/2.),2);
- double cHarv=2.*atan2(sqrt(aHarv),sqrt(1.0-aHarv));
- //earth's radius from wikipedia varies between 6,356.750 km — 6,378.135 km (˜3,949.901 — 3,963.189 miles)
- //The IUGG value for the equatorial radius of the Earth is 6378.137 km (3963.19 mile)
- const double earth=6372797.560856;//I am doing miles, just change this to radius in kilometers to get distances in km
- double distance=earth*cHarv;
- return distance;
-}
-
-inline double ApproximateDistance(const _Coordinate &c1, const _Coordinate &c2) {
- return ApproximateDistance( c1.lat, c1.lon, c2.lat, c2.lon );
-}
-
-inline double ApproximateDistanceByEuclid(const _Coordinate &c1, const _Coordinate &c2) {
- assert(c1.lat != INT_MIN);
- assert(c1.lon != INT_MIN);
- assert(c2.lat != INT_MIN);
- assert(c2.lon != INT_MIN);
- const double RAD = 0.017453292519943295769236907684886;
- const double lat1 = (c1.lat/100000.)*RAD;
- const double lon1 = (c1.lon/100000.)*RAD;
- const double lat2 = (c2.lat/100000.)*RAD;
- const double lon2 = (c2.lon/100000.)*RAD;
-
- const double x = (lon2-lon1) * cos((lat1+lat2)/2.);
- const double y = (lat2-lat1);
- const double earthRadius = 6372797.560856;
- const double d = sqrt(x*x + y*y) * earthRadius;
- return d;
-}
-
-#endif /* COORDINATE_H_ */
diff --git a/DataStructures/DeallocatingVector.h b/DataStructures/DeallocatingVector.h
index 89d8e2c..013cc1d 100644
--- a/DataStructures/DeallocatingVector.h
+++ b/DataStructures/DeallocatingVector.h
@@ -1,317 +1,400 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef DEALLOCATINGVECTOR_H_
#define DEALLOCATINGVECTOR_H_
-#include <cassert>
+#include <boost/assert.hpp>
+#include <cstring>
#include <vector>
-#if __cplusplus > 199711L
-#define DEALLOCATION_VECTOR_NULL_PTR nullptr
-#else
-#define DEALLOCATION_VECTOR_NULL_PTR NULL
-#endif
-
+template <typename ElementT,
+ std::size_t bucketSizeC = 8388608 / sizeof(ElementT),
+ bool DeallocateC = false>
+class DeallocatingVectorIterator : public std::iterator<std::random_access_iterator_tag, ElementT>
+{
+ protected:
+ class DeallocatingVectorIteratorState
+ {
+ private:
+ // make constructors explicit, so we do not mix random access and deallocation iterators.
+ DeallocatingVectorIteratorState();
-template<typename ElementT, std::size_t bucketSizeC = 8388608/sizeof(ElementT), bool DeallocateC = false>
-class DeallocatingVectorIterator : public std::iterator<std::random_access_iterator_tag, ElementT> {
-protected:
+ public:
+ explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r)
+ : index(r.index), bucket_list(r.bucket_list)
+ {
+ }
+ explicit DeallocatingVectorIteratorState(const std::size_t idx,
+ std::vector<ElementT *> &input_list)
+ : index(idx), bucket_list(input_list)
+ {
+ }
+ std::size_t index;
+ std::vector<ElementT *> &bucket_list;
- class DeallocatingVectorIteratorState {
- private:
- //make constructors explicit, so we do not mix random access and deallocation iterators.
- DeallocatingVectorIteratorState();
- public:
- explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r) : mData(r.mData), mIndex(r.mIndex), mBucketList(r.mBucketList) {}
- //explicit DeallocatingVectorIteratorState(const ElementT * ptr, const std::size_t idx, const std::vector<ElementT *> & input_list) : mData(ptr), mIndex(idx), mBucketList(input_list) {}
- explicit DeallocatingVectorIteratorState(const std::size_t idx, std::vector<ElementT *> & input_list) : mData(DEALLOCATION_VECTOR_NULL_PTR), mIndex(idx), mBucketList(input_list) {
- setPointerForIndex();
+ inline bool operator!=(const DeallocatingVectorIteratorState &other)
+ {
+ return index != other.index;
}
- ElementT * mData;
- std::size_t mIndex;
- std::vector<ElementT *> & mBucketList;
-
- inline void setPointerForIndex() {
- if(bucketSizeC*mBucketList.size() <= mIndex) {
- mData = DEALLOCATION_VECTOR_NULL_PTR;
- return;
- }
- std::size_t _bucket = mIndex/bucketSizeC;
- std::size_t _index = mIndex%bucketSizeC;
- mData = &(mBucketList[_bucket][_index]);
-
- if(DeallocateC) {
- //if we hopped over the border of the previous bucket, then delete that bucket.
- if(0 == _index && _bucket) {
- delete[] mBucketList[_bucket-1];
- mBucketList[_bucket-1] = DEALLOCATION_VECTOR_NULL_PTR;
- }
- }
+ inline bool operator==(const DeallocatingVectorIteratorState &other)
+ {
+ return index == other.index;
}
- inline bool operator!=(const DeallocatingVectorIteratorState &other) {
- return (mData != other.mData) || (mIndex != other.mIndex) || (mBucketList != other.mBucketList);
+
+ bool operator<(const DeallocatingVectorIteratorState &other) const
+ {
+ return index < other.index;
}
- inline bool operator==(const DeallocatingVectorIteratorState &other) {
- return (mData == other.mData) && (mIndex == other.mIndex) && (mBucketList == other.mBucketList);
+ bool operator>(const DeallocatingVectorIteratorState &other) const
+ {
+ return index > other.index;
}
- inline bool operator<(const DeallocatingVectorIteratorState &other) {
- return mIndex < other.mIndex;
+ bool operator>=(const DeallocatingVectorIteratorState &other) const
+ {
+ return index >= other.index;
}
- //This is a hack to make assignment operator possible with reference member
- inline DeallocatingVectorIteratorState& operator= (const DeallocatingVectorIteratorState &a) {
- if (this != &a) {
- this->DeallocatingVectorIteratorState::~DeallocatingVectorIteratorState(); // explicit non-virtual destructor
+ // This is a hack to make assignment operator possible with reference member
+ inline DeallocatingVectorIteratorState &operator=(const DeallocatingVectorIteratorState &a)
+ {
+ if (this != &a)
+ {
+ this->DeallocatingVectorIteratorState::
+ ~DeallocatingVectorIteratorState(); // explicit non-virtual destructor
new (this) DeallocatingVectorIteratorState(a); // placement new
}
return *this;
}
};
- DeallocatingVectorIteratorState mState;
+ DeallocatingVectorIteratorState current_state;
-public:
+ public:
typedef std::random_access_iterator_tag iterator_category;
- typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::value_type value_type;
- typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::difference_type difference_type;
+ typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::value_type
+ value_type;
+ typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::difference_type
+ difference_type;
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::reference reference;
typedef typename std::iterator<std::random_access_iterator_tag, ElementT>::pointer pointer;
DeallocatingVectorIterator() {}
- template<typename T2>
- DeallocatingVectorIterator(const DeallocatingVectorIterator<T2> & r) : mState(r.mState) {}
+ template <typename T2>
+ explicit DeallocatingVectorIterator(const DeallocatingVectorIterator<T2> &r)
+ : current_state(r.current_state)
+ {
+ }
- DeallocatingVectorIterator(std::size_t idx, std::vector<ElementT *> & input_list) : mState(idx, input_list) {}
- //DeallocatingVectorIterator(std::size_t idx, const std::vector<ElementT *> & input_list) : mState(idx, input_list) {}
- DeallocatingVectorIterator(const DeallocatingVectorIteratorState & r) : mState(r) {}
+ DeallocatingVectorIterator(std::size_t idx, std::vector<ElementT *> &input_list)
+ : current_state(idx, input_list)
+ {
+ }
+ explicit DeallocatingVectorIterator(const DeallocatingVectorIteratorState &r) : current_state(r) {}
- template<typename T2>
- DeallocatingVectorIterator& operator=(const DeallocatingVectorIterator<T2> &r) {
- if(DeallocateC) assert(false);
- mState = r.mState; return *this;
+ template <typename T2>
+ DeallocatingVectorIterator &operator=(const DeallocatingVectorIterator<T2> &r)
+ {
+ if (DeallocateC)
+ {
+ BOOST_ASSERT(false);
+ }
+ current_state = r.current_state;
+ return *this;
+ }
+
+ inline DeallocatingVectorIterator &operator++()
+ { // prefix
+ ++current_state.index;
+ return *this;
+ }
+
+ inline DeallocatingVectorIterator &operator--()
+ { // prefix
+ if (DeallocateC)
+ {
+ BOOST_ASSERT(false);
+ }
+ --current_state.index;
+ return *this;
}
- inline DeallocatingVectorIterator& operator++() { //prefix
-// if(DeallocateC) assert(false);
- ++mState.mIndex; mState.setPointerForIndex(); return *this;
+ inline DeallocatingVectorIterator operator++(int)
+ { // postfix
+ DeallocatingVectorIteratorState my_state(current_state);
+ current_state.index++;
+ return DeallocatingVectorIterator(my_state);
+ }
+ inline DeallocatingVectorIterator operator--(int)
+ { // postfix
+ if (DeallocateC)
+ {
+ BOOST_ASSERT(false);
+ }
+ DeallocatingVectorIteratorState my_state(current_state);
+ current_state.index--;
+ return DeallocatingVectorIterator(my_state);
}
- inline DeallocatingVectorIterator& operator--() { //prefix
- if(DeallocateC) assert(false);
- --mState.mIndex; mState.setPointerForIndex(); return *this;
+ inline DeallocatingVectorIterator operator+(const difference_type &n) const
+ {
+ DeallocatingVectorIteratorState my_state(current_state);
+ my_state.index += n;
+ return DeallocatingVectorIterator(my_state);
}
- inline DeallocatingVectorIterator operator++(int) { //postfix
- DeallocatingVectorIteratorState _myState(mState);
- mState.mIndex++; mState.setPointerForIndex();
- return DeallocatingVectorIterator(_myState);
+ inline DeallocatingVectorIterator &operator+=(const difference_type &n)
+ {
+ current_state.index += n;
+ return *this;
}
- inline DeallocatingVectorIterator operator --(int) { //postfix
- if(DeallocateC) assert(false);
- DeallocatingVectorIteratorState _myState(mState);
- mState.mIndex--; mState.setPointerForIndex();
- return DeallocatingVectorIterator(_myState);
+
+ inline DeallocatingVectorIterator operator-(const difference_type &n) const
+ {
+ if (DeallocateC)
+ {
+ BOOST_ASSERT(false);
+ }
+ DeallocatingVectorIteratorState my_state(current_state);
+ my_state.index -= n;
+ return DeallocatingVectorIterator(my_state);
}
- inline DeallocatingVectorIterator operator+(const difference_type& n) const {
- DeallocatingVectorIteratorState _myState(mState);
- _myState.mIndex+=n; _myState.setPointerForIndex();
- return DeallocatingVectorIterator(_myState);
+ inline DeallocatingVectorIterator &operator-=(const difference_type &n) const
+ {
+ if (DeallocateC)
+ {
+ BOOST_ASSERT(false);
+ }
+ current_state.index -= n;
+ return *this;
}
- inline DeallocatingVectorIterator& operator+=(const difference_type& n) const {
- mState.mIndex+=n; return *this;
+ inline reference operator*() const
+ {
+ std::size_t current_bucket = current_state.index / bucketSizeC;
+ std::size_t current_index = current_state.index % bucketSizeC;
+ return (current_state.bucket_list[current_bucket][current_index]);
}
- inline DeallocatingVectorIterator operator-(const difference_type& n) const {
- if(DeallocateC) assert(false);
- DeallocatingVectorIteratorState _myState(mState);
- _myState.mIndex-=n; _myState.setPointerForIndex();
- return DeallocatingVectorIterator(_myState);
+ inline pointer operator->() const
+ {
+ std::size_t current_bucket = current_state.index / bucketSizeC;
+ std::size_t current_index = current_state.index % bucketSizeC;
+ return &(current_state.bucket_list[current_bucket][current_index]);
}
- inline DeallocatingVectorIterator& operator-=(const difference_type &n) const {
- if(DeallocateC) assert(false);
- mState.mIndex-=n; return *this;
+ inline bool operator!=(const DeallocatingVectorIterator &other)
+ {
+ return current_state != other.current_state;
}
- inline reference operator*() const { return *mState.mData; }
- inline pointer operator->() const { return mState.mData; }
- inline reference operator[](const difference_type &n) const {
- if(DeallocateC) assert(false);
- DeallocatingVectorIteratorState _myState(mState);
- _myState.mIndex += n;
- _myState.setPointerForIndex;
- return _myState.mData;
+
+ inline bool operator==(const DeallocatingVectorIterator &other)
+ {
+ return current_state == other.current_state;
}
- inline bool operator!=(const DeallocatingVectorIterator & other) {
- return mState != other.mState;
+ inline bool operator<(const DeallocatingVectorIterator &other) const
+ {
+ return current_state < other.current_state;
}
- inline bool operator==(const DeallocatingVectorIterator & other) {
- return mState == other.mState;
+ inline bool operator>(const DeallocatingVectorIterator &other) const
+ {
+ return current_state > other.current_state;
}
- bool operator<(const DeallocatingVectorIterator & other) {
- return mState < other.mState;
+ inline bool operator>=(const DeallocatingVectorIterator &other) const
+ {
+ return current_state >= other.current_state;
}
- difference_type operator-(const DeallocatingVectorIterator & other) {
- if(DeallocateC) assert(false);
- return mState.mIndex-other.mState.mIndex;
+ difference_type operator-(const DeallocatingVectorIterator &other)
+ {
+ if (DeallocateC)
+ {
+ BOOST_ASSERT(false);
+ }
+ return current_state.index - other.current_state.index;
}
};
-template<typename ElementT, std::size_t bucketSizeC = 8388608/sizeof(ElementT) >
-class DeallocatingVector {
-private:
- std::size_t mCurrentSize;
- std::vector<ElementT *> mBucketList;
+template <typename ElementT, std::size_t bucketSizeC = 8388608 / sizeof(ElementT)>
+class DeallocatingVector
+{
+ private:
+ std::size_t current_size;
+ std::vector<ElementT *> bucket_list;
-public:
+ public:
typedef ElementT value_type;
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> iterator;
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, false> const_iterator;
- //this iterator deallocates all buckets that have been visited. Iterators to visited objects become invalid.
+ // this iterator deallocates all buckets that have been visited. Iterators to visited objects
+ // become invalid.
typedef DeallocatingVectorIterator<ElementT, bucketSizeC, true> deallocation_iterator;
- DeallocatingVector() : mCurrentSize(0) {
- //initial bucket
- mBucketList.push_back(new ElementT[bucketSizeC]);
+ DeallocatingVector() : current_size(0)
+ {
+ // initial bucket
+ bucket_list.emplace_back(new ElementT[bucketSizeC]);
}
- ~DeallocatingVector() {
- clear();
- }
+ ~DeallocatingVector() { clear(); }
- inline void swap(DeallocatingVector<ElementT, bucketSizeC> & other) {
- std::swap(mCurrentSize, other.mCurrentSize);
- mBucketList.swap(other.mBucketList);
+ inline void swap(DeallocatingVector<ElementT, bucketSizeC> &other)
+ {
+ std::swap(current_size, other.current_size);
+ bucket_list.swap(other.bucket_list);
}
- inline void clear() {
- //Delete[]'ing ptr's to all Buckets
- for(unsigned i = 0; i < mBucketList.size(); ++i) {
- if(DEALLOCATION_VECTOR_NULL_PTR != mBucketList[i]) {
- delete[] mBucketList[i];
- mBucketList[i] = DEALLOCATION_VECTOR_NULL_PTR;
+ inline void clear()
+ {
+ // Delete[]'ing ptr's to all Buckets
+ for (unsigned i = 0; i < bucket_list.size(); ++i)
+ {
+ if (nullptr != bucket_list[i])
+ {
+ delete[] bucket_list[i];
+ bucket_list[i] = nullptr;
}
}
- //Removing all ptrs from vector
- std::vector<ElementT *>().swap(mBucketList);
- mCurrentSize = 0;
+ // Removing all ptrs from vector
+ std::vector<ElementT *>().swap(bucket_list);
+ current_size = 0;
+ }
+
+ inline void push_back(const ElementT &element)
+ {
+ const std::size_t current_capacity = capacity();
+ if (current_size == current_capacity)
+ {
+ bucket_list.push_back(new ElementT[bucketSizeC]);
+ }
+
+ std::size_t current_index = size() % bucketSizeC;
+ bucket_list.back()[current_index] = element;
+ ++current_size;
}
- inline void push_back(const ElementT & element) {
- std::size_t _capacity = capacity();
- if(mCurrentSize == _capacity) {
- mBucketList.push_back(new ElementT[bucketSizeC]);
+ inline void emplace_back(const ElementT &&element)
+ {
+ const std::size_t current_capacity = capacity();
+ if (current_size == current_capacity)
+ {
+ bucket_list.push_back(new ElementT[bucketSizeC]);
}
- std::size_t _index = size()%bucketSizeC;
- mBucketList.back()[_index] = element;
- ++mCurrentSize;
+ const std::size_t current_index = size() % bucketSizeC;
+ bucket_list.back()[current_index] = element;
+ ++current_size;
}
- inline void reserve(const std::size_t) const {
- //don't do anything
+ inline void reserve(const std::size_t) const
+ {
+ // don't do anything
}
- inline void resize(const std::size_t new_size) {
- if(new_size > mCurrentSize) {
- while(capacity() < new_size) {
- mBucketList.push_back(new ElementT[bucketSizeC]);
+ inline void resize(const std::size_t new_size)
+ {
+ if (new_size > current_size)
+ {
+ while (capacity() < new_size)
+ {
+ bucket_list.push_back(new ElementT[bucketSizeC]);
}
- mCurrentSize = new_size;
+ current_size = new_size;
}
- if(new_size < mCurrentSize) {
- std::size_t number_of_necessary_buckets = 1+(new_size / bucketSizeC);
+ if (new_size < current_size)
+ {
+ const std::size_t number_of_necessary_buckets = 1 + (new_size / bucketSizeC);
- for(unsigned i = number_of_necessary_buckets; i < mBucketList.size(); ++i) {
- delete[] mBucketList[i];
+ for (std::size_t i = number_of_necessary_buckets; i < bucket_list.size(); ++i)
+ {
+ delete[] bucket_list[i];
}
- mBucketList.resize(number_of_necessary_buckets);
- mCurrentSize = new_size;
+ bucket_list.resize(number_of_necessary_buckets);
+ current_size = new_size;
}
}
- inline std::size_t size() const {
- return mCurrentSize;
- }
+ inline std::size_t size() const { return current_size; }
- inline std::size_t capacity() const {
- return mBucketList.size() * bucketSizeC;
- }
+ inline std::size_t capacity() const { return bucket_list.size() * bucketSizeC; }
- inline iterator begin() {
- return iterator(static_cast<std::size_t>(0), mBucketList);
- }
+ inline iterator begin() { return iterator(static_cast<std::size_t>(0), bucket_list); }
- inline iterator end() {
- return iterator(size(), mBucketList);
- }
+ inline iterator end() { return iterator(size(), bucket_list); }
- inline deallocation_iterator dbegin() {
- return deallocation_iterator(static_cast<std::size_t>(0), mBucketList);
+ inline deallocation_iterator dbegin()
+ {
+ return deallocation_iterator(static_cast<std::size_t>(0), bucket_list);
}
- inline deallocation_iterator dend() {
- return deallocation_iterator(size(), mBucketList);
- }
+ inline deallocation_iterator dend() { return deallocation_iterator(size(), bucket_list); }
- inline const_iterator begin() const {
- return const_iterator(static_cast<std::size_t>(0), mBucketList);
+ inline const_iterator begin() const
+ {
+ return const_iterator(static_cast<std::size_t>(0), bucket_list);
}
- inline const_iterator end() const {
- return const_iterator(size(), mBucketList);
- }
+ inline const_iterator end() const { return const_iterator(size(), bucket_list); }
- inline ElementT & operator[](const std::size_t index) {
+ inline ElementT &operator[](const std::size_t index)
+ {
std::size_t _bucket = index / bucketSizeC;
std::size_t _index = index % bucketSizeC;
- return (mBucketList[_bucket][_index]);
+ return (bucket_list[_bucket][_index]);
}
- const inline ElementT & operator[](const std::size_t index) const {
+ const inline ElementT &operator[](const std::size_t index) const
+ {
std::size_t _bucket = index / bucketSizeC;
std::size_t _index = index % bucketSizeC;
- return (mBucketList[_bucket][_index]);
+ return (bucket_list[_bucket][_index]);
}
- inline ElementT & back() {
- std::size_t _bucket = mCurrentSize / bucketSizeC;
- std::size_t _index = mCurrentSize % bucketSizeC;
- return (mBucketList[_bucket][_index]);
+ inline ElementT &back()
+ {
+ std::size_t _bucket = current_size / bucketSizeC;
+ std::size_t _index = current_size % bucketSizeC;
+ return (bucket_list[_bucket][_index]);
}
- const inline ElementT & back() const {
- std::size_t _bucket = mCurrentSize / bucketSizeC;
- std::size_t _index = mCurrentSize % bucketSizeC;
- return (mBucketList[_bucket][_index]);
+ const inline ElementT &back() const
+ {
+ std::size_t _bucket = current_size / bucketSizeC;
+ std::size_t _index = current_size % bucketSizeC;
+ return (bucket_list[_bucket][_index]);
}
};
diff --git a/DataStructures/DynamicGraph.h b/DataStructures/DynamicGraph.h
index 67db065..3dc48b6 100644
--- a/DataStructures/DynamicGraph.h
+++ b/DataStructures/DynamicGraph.h
@@ -1,233 +1,280 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef DYNAMICGRAPH_H_INCLUDED
-#define DYNAMICGRAPH_H_INCLUDED
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef DYNAMICGRAPH_H
+#define DYNAMICGRAPH_H
#include "../DataStructures/DeallocatingVector.h"
#include <boost/assert.hpp>
-#include <boost/integer.hpp>
+#include <boost/range/irange.hpp>
+
+#include <cstdint>
#include <algorithm>
#include <limits>
#include <vector>
-
-template< typename EdgeDataT>
-class DynamicGraph {
- public:
- typedef EdgeDataT EdgeData;
- typedef uint32_t NodeIterator;
- typedef uint32_t EdgeIterator;
-
- class InputEdge {
- public:
- NodeIterator source;
- NodeIterator target;
- EdgeDataT data;
- bool operator<( const InputEdge& right ) const {
- if ( source != right.source )
- return source < right.source;
- return target < right.target;
- }
- };
-
- //Constructs an empty graph with a given number of nodes.
- 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 );
+#include <atomic>
+
+template <typename EdgeDataT> class DynamicGraph
+{
+ public:
+ typedef decltype(boost::irange(0u,0u)) EdgeRange;
+ typedef EdgeDataT EdgeData;
+ typedef unsigned NodeIterator;
+ typedef unsigned EdgeIterator;
+
+ class InputEdge
+ {
+ public:
+ NodeIterator source;
+ NodeIterator target;
+ EdgeDataT data;
+ bool operator<(const InputEdge &right) const
+ {
+ if (source != right.source)
+ return source < right.source;
+ return target < right.target;
}
-
- template<class ContainerT>
- DynamicGraph( const int32_t nodes, const ContainerT &graph ) {
- m_numNodes = nodes;
- m_numEdges = ( EdgeIterator ) graph.size();
- m_nodes.reserve( m_numNodes +1);
- m_nodes.resize( m_numNodes +1);
- EdgeIterator edge = 0;
- EdgeIterator position = 0;
- for ( NodeIterator node = 0; node < m_numNodes; ++node ) {
- EdgeIterator lastEdge = edge;
- while ( edge < m_numEdges && graph[edge].source == node ) {
- ++edge;
- }
- m_nodes[node].firstEdge = position;
- m_nodes[node].edges = edge - lastEdge;
- position += m_nodes[node].edges;
- }
- m_nodes.back().firstEdge = position;
- m_edges.reserve( position * 1.1 );
- m_edges.resize( position );
- edge = 0;
- for ( NodeIterator node = 0; node < m_numNodes; ++node ) {
- 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;
- BOOST_ASSERT_MSG(
- graph[edge].data.distance > 0,
- "edge distance invalid"
- );
- ++edge;
- }
+ };
+
+ // Constructs an empty graph with a given number of nodes.
+ explicit 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 int32_t nodes, const ContainerT &graph)
+ {
+ m_numNodes = nodes;
+ m_numEdges = (EdgeIterator)graph.size();
+ m_nodes.reserve(m_numNodes + 1);
+ m_nodes.resize(m_numNodes + 1);
+ EdgeIterator edge = 0;
+ EdgeIterator position = 0;
+ for (NodeIterator node = 0; node < m_numNodes; ++node)
+ {
+ EdgeIterator lastEdge = edge;
+ while (edge < m_numEdges && graph[edge].source == node)
+ {
+ ++edge;
}
+ m_nodes[node].firstEdge = position;
+ m_nodes[node].edges = edge - lastEdge;
+ position += m_nodes[node].edges;
}
-
- ~DynamicGraph(){ }
-
- uint32_t GetNumberOfNodes() const {
- return m_numNodes;
- }
-
- uint32_t GetNumberOfEdges() const {
- return m_numEdges;
- }
-
- uint32_t GetOutDegree( const NodeIterator n ) const {
- return m_nodes[n].edges;
- }
-
- NodeIterator GetTarget( const EdgeIterator e ) const {
- return NodeIterator( m_edges[e].target );
+ m_nodes.back().firstEdge = position;
+ m_edges.reserve(static_cast<std::size_t>(position * 1.1));
+ m_edges.resize(position);
+ edge = 0;
+ for (NodeIterator node = 0; node < m_numNodes; ++node)
+ {
+ 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;
+ BOOST_ASSERT_MSG(graph[edge].data.distance > 0, "edge distance invalid");
+ ++edge;
+ }
}
+ }
- EdgeDataT &GetEdgeData( const EdgeIterator e ) {
- return m_edges[e].data;
- }
+ ~DynamicGraph() {}
- const EdgeDataT &GetEdgeData( const EdgeIterator e ) const {
- return m_edges[e].data;
- }
+ unsigned GetNumberOfNodes() const { return m_numNodes; }
- EdgeIterator BeginEdges( const NodeIterator n ) const {
- return EdgeIterator( m_nodes[n].firstEdge );
- }
+ unsigned GetNumberOfEdges() const { return m_numEdges; }
- EdgeIterator EndEdges( const NodeIterator n ) const {
- return EdgeIterator( m_nodes[n].firstEdge + m_nodes[n].edges );
- }
+ unsigned GetOutDegree(const NodeIterator n) const { return m_nodes[n].edges; }
- //adds an edge. Invalidates edge iterators for the source node
- EdgeIterator InsertEdge( const NodeIterator from, const NodeIterator to, const EdgeDataT &data ) {
- Node &node = m_nodes[from];
- EdgeIterator newFirstEdge = node.edges + node.firstEdge;
- if ( newFirstEdge >= m_edges.size() || !isDummy( newFirstEdge ) ) {
- if ( node.firstEdge != 0 && isDummy( node.firstEdge - 1 ) ) {
- node.firstEdge--;
- m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
- } else {
- EdgeIterator newFirstEdge = ( EdgeIterator ) m_edges.size();
- uint32_t newSize = node.edges * 1.1 + 2;
- EdgeIterator requiredCapacity = newSize + m_edges.size();
- EdgeIterator oldCapacity = m_edges.capacity();
- if ( requiredCapacity >= oldCapacity ) {
- m_edges.reserve( requiredCapacity * 1.1 );
- }
- m_edges.resize( m_edges.size() + newSize );
- for ( EdgeIterator i = 0; i < node.edges; ++i ) {
- m_edges[newFirstEdge + i ] = m_edges[node.firstEdge + i];
- makeDummy( node.firstEdge + i );
- }
- for ( EdgeIterator i = node.edges + 1; i < newSize; ++i )
- makeDummy( newFirstEdge + i );
- node.firstEdge = newFirstEdge;
- }
+ unsigned GetDirectedOutDegree(const NodeIterator n) const
+ {
+ unsigned degree = 0;
+ for(EdgeIterator edge = BeginEdges(n); edge < EndEdges(n); ++edge)
+ {
+ if (GetEdgeData(edge).forward)
+ {
+ ++degree;
}
- Edge &edge = m_edges[node.firstEdge + node.edges];
- edge.target = to;
- edge.data = data;
- ++m_numEdges;
- ++node.edges;
- return EdgeIterator( node.firstEdge + node.edges );
}
-
- //removes an edge. Invalidates edge iterators for the source node
- void DeleteEdge( const NodeIterator source, const EdgeIterator e ) {
- Node &node = m_nodes[source];
- --m_numEdges;
- --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)
- 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 {
- deleted++;
- m_edges[i] = m_edges[iend - deleted];
- makeDummy( iend - deleted );
- } while ( i < iend - deleted && m_edges[i].target == target );
+ return degree;
+ }
+
+ NodeIterator GetTarget(const EdgeIterator e) const { return NodeIterator(m_edges[e].target); }
+
+ void SetTarget(const EdgeIterator e, const NodeIterator n) { m_edges[e].target = n; }
+
+ EdgeDataT &GetEdgeData(const EdgeIterator e) { return m_edges[e].data; }
+
+ const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return m_edges[e].data; }
+
+ EdgeIterator BeginEdges(const NodeIterator n) const
+ {
+ return EdgeIterator(m_nodes[n].firstEdge);
+ }
+
+ EdgeIterator EndEdges(const NodeIterator n) const
+ {
+ return EdgeIterator(m_nodes[n].firstEdge + m_nodes[n].edges);
+ }
+
+ EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
+ {
+ return boost::irange(BeginEdges(node), EndEdges(node));
+ }
+
+ // adds an edge. Invalidates edge iterators for the source node
+ EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
+ {
+ Node &node = m_nodes[from];
+ EdgeIterator newFirstEdge = node.edges + node.firstEdge;
+ if (newFirstEdge >= m_edges.size() || !isDummy(newFirstEdge))
+ {
+ if (node.firstEdge != 0 && isDummy(node.firstEdge - 1))
+ {
+ node.firstEdge--;
+ m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
+ }
+ else
+ {
+ EdgeIterator newFirstEdge = (EdgeIterator)m_edges.size();
+ unsigned newSize = node.edges * 1.1 + 2;
+ EdgeIterator requiredCapacity = newSize + m_edges.size();
+ EdgeIterator oldCapacity = m_edges.capacity();
+ if (requiredCapacity >= oldCapacity)
+ {
+ m_edges.reserve(requiredCapacity * 1.1);
+ }
+ m_edges.resize(m_edges.size() + newSize);
+ for (EdgeIterator i = 0; i < node.edges; ++i)
+ {
+ m_edges[newFirstEdge + i] = m_edges[node.firstEdge + i];
+ makeDummy(node.firstEdge + i);
}
+ for (EdgeIterator i = node.edges + 1; i < newSize; ++i)
+ makeDummy(newFirstEdge + i);
+ node.firstEdge = newFirstEdge;
}
-
- #pragma omp atomic
- m_numEdges -= deleted;
- m_nodes[source].edges -= deleted;
-
- return deleted;
}
-
- //searches for a specific edge
- EdgeIterator FindEdge( const NodeIterator from, const NodeIterator to ) const {
- for ( EdgeIterator i = BeginEdges( from ), iend = EndEdges( from ); i != iend; ++i ) {
- if ( m_edges[i].target == to ) {
- return i;
- }
+ Edge &edge = m_edges[node.firstEdge + node.edges];
+ edge.target = to;
+ edge.data = data;
+ ++m_numEdges;
+ ++node.edges;
+ return EdgeIterator(node.firstEdge + node.edges);
+ }
+
+ // removes an edge. Invalidates edge iterators for the source node
+ void DeleteEdge(const NodeIterator source, const EdgeIterator e)
+ {
+ Node &node = m_nodes[source];
+ --m_numEdges;
+ --node.edges;
+ BOOST_ASSERT(std::numeric_limits<unsigned>::max() != node.edges);
+ const unsigned last = node.firstEdge + node.edges;
+ BOOST_ASSERT(std::numeric_limits<unsigned>::max() != last);
+ // swap with last edge
+ m_edges[e] = m_edges[last];
+ makeDummy(last);
+ }
+
+ // removes all edges (source,target)
+ 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
+ {
+ deleted++;
+ m_edges[i] = m_edges[iend - deleted];
+ makeDummy(iend - deleted);
+ } while (i < iend - deleted && m_edges[i].target == target);
}
- return EndEdges( from );
}
- protected:
+ m_numEdges -= deleted;
+ m_nodes[source].edges -= deleted;
- bool isDummy( const EdgeIterator edge ) const {
- return m_edges[edge].target == (std::numeric_limits< NodeIterator >::max)();
- }
+ return deleted;
+ }
- void makeDummy( const EdgeIterator edge ) {
- m_edges[edge].target = (std::numeric_limits< NodeIterator >::max)();
+ // searches for a specific edge
+ EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
+ {
+ for (EdgeIterator i = BeginEdges(from), iend = EndEdges(from); i != iend; ++i)
+ {
+ if (to == m_edges[i].target)
+ {
+ return i;
+ }
}
-
- struct Node {
- //index of the first edge
- EdgeIterator firstEdge;
- //amount of edges
- uint32_t edges;
- };
-
- struct Edge {
- NodeIterator target;
- EdgeDataT data;
- };
-
- NodeIterator m_numNodes;
- EdgeIterator m_numEdges;
-
- std::vector< Node > m_nodes;
- DeallocatingVector< Edge > m_edges;
+ return EndEdges(from);
+ }
+
+ protected:
+ bool isDummy(const EdgeIterator edge) const
+ {
+ return m_edges[edge].target == (std::numeric_limits<NodeIterator>::max)();
+ }
+
+ void makeDummy(const EdgeIterator edge)
+ {
+ m_edges[edge].target = (std::numeric_limits<NodeIterator>::max)();
+ }
+
+ struct Node
+ {
+ // index of the first edge
+ EdgeIterator firstEdge;
+ // amount of edges
+ unsigned edges;
+ };
+
+ struct Edge
+ {
+ NodeIterator target;
+ EdgeDataT data;
+ };
+
+ NodeIterator m_numNodes;
+ std::atomic_uint m_numEdges;
+
+ std::vector<Node> m_nodes;
+ DeallocatingVector<Edge> m_edges;
};
-#endif // DYNAMICGRAPH_H_INCLUDED
+#endif // DYNAMICGRAPH_H
diff --git a/DataStructures/EdgeBasedNode.h b/DataStructures/EdgeBasedNode.h
new file mode 100644
index 0000000..90f8b7c
--- /dev/null
+++ b/DataStructures/EdgeBasedNode.h
@@ -0,0 +1,90 @@
+#ifndef EDGE_BASED_NODE_H
+#define EDGE_BASED_NODE_H
+
+#include "../Util/SimpleLogger.h"
+#include "../typedefs.h"
+
+#include <osrm/Coordinate.h>
+
+#include <boost/assert.hpp>
+
+#include <limits>
+
+struct EdgeBasedNode
+{
+
+ EdgeBasedNode() :
+ forward_edge_based_node_id(SPECIAL_NODEID),
+ reverse_edge_based_node_id(SPECIAL_NODEID),
+ u(SPECIAL_NODEID),
+ v(SPECIAL_NODEID),
+ name_id(0),
+ forward_weight(INVALID_EDGE_WEIGHT >> 1),
+ reverse_weight(INVALID_EDGE_WEIGHT >> 1),
+ forward_offset(0),
+ reverse_offset(0),
+ packed_geometry_id(SPECIAL_EDGEID),
+ fwd_segment_position( std::numeric_limits<unsigned short>::max() ),
+ is_in_tiny_cc(false)
+ { }
+
+ explicit EdgeBasedNode(
+ NodeID forward_edge_based_node_id,
+ NodeID reverse_edge_based_node_id,
+ NodeID u,
+ NodeID v,
+ unsigned name_id,
+ int forward_weight,
+ int reverse_weight,
+ int forward_offset,
+ int reverse_offset,
+ unsigned packed_geometry_id,
+ unsigned short fwd_segment_position,
+ bool belongs_to_tiny_component
+ ) :
+ forward_edge_based_node_id(forward_edge_based_node_id),
+ reverse_edge_based_node_id(reverse_edge_based_node_id),
+ u(u),
+ v(v),
+ name_id(name_id),
+ forward_weight(forward_weight),
+ reverse_weight(reverse_weight),
+ forward_offset(forward_offset),
+ reverse_offset(reverse_offset),
+ packed_geometry_id(packed_geometry_id),
+ fwd_segment_position(fwd_segment_position),
+ is_in_tiny_cc(belongs_to_tiny_component)
+ {
+ BOOST_ASSERT((forward_edge_based_node_id != SPECIAL_NODEID) ||
+ (reverse_edge_based_node_id != SPECIAL_NODEID));
+ }
+
+ static inline FixedPointCoordinate Centroid(const FixedPointCoordinate & a, const FixedPointCoordinate & b)
+ {
+ FixedPointCoordinate centroid;
+ //The coordinates of the midpoint are given by:
+ centroid.lat = (a.lat + b.lat)/2;
+ centroid.lon = (a.lon + b.lon)/2;
+ return centroid;
+ }
+
+ bool IsCompressed() const
+ {
+ return packed_geometry_id != SPECIAL_EDGEID;
+ }
+
+ NodeID forward_edge_based_node_id; // needed for edge-expanded graph
+ NodeID reverse_edge_based_node_id; // needed for edge-expanded graph
+ NodeID u; // indices into the coordinates array
+ NodeID v; // indices into the coordinates array
+ unsigned name_id; // id of the edge name
+ int forward_weight; // weight of the edge
+ int reverse_weight; // weight in the other direction (may be different)
+ int forward_offset; // prefix sum of the weight up the edge TODO: short must suffice
+ int reverse_offset; // prefix sum of the weight from the edge TODO: short must suffice
+ unsigned packed_geometry_id; // if set, then the edge represents a packed geometry
+ unsigned short fwd_segment_position; // segment id in a compressed geometry
+ bool is_in_tiny_cc;
+};
+
+#endif //EDGE_BASED_NODE_H
diff --git a/DataStructures/GridEdge.h b/DataStructures/GridEdge.h
deleted file mode 100644
index 7b2dd78..0000000
--- a/DataStructures/GridEdge.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- 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 GRIDEDGE_H_
-#define GRIDEDGE_H_
-
-#include "Coordinate.h"
-
-struct _GridEdge {
- _GridEdge(NodeID n, NodeID na, int w, _Coordinate sc, _Coordinate tc, bool bttc) : edgeBasedNode(n), nameID(na), weight(w), startCoord(sc), targetCoord(tc), belongsToTinyComponent(bttc) {}
- _GridEdge() : edgeBasedNode(UINT_MAX), nameID(UINT_MAX), weight(INT_MAX), belongsToTinyComponent(false) {}
- NodeID edgeBasedNode;
- NodeID nameID;
- int weight;
- _Coordinate startCoord;
- _Coordinate targetCoord;
- bool belongsToTinyComponent;
-
- bool operator< ( const _GridEdge& right) const {
- return edgeBasedNode < right.edgeBasedNode;
- }
- bool operator== ( const _GridEdge& right) const {
- return edgeBasedNode == right.edgeBasedNode;
- }
-};
-
-struct GridEntry {
- GridEntry() : fileIndex(UINT_MAX), ramIndex(UINT_MAX){}
- GridEntry(_GridEdge e, unsigned f, unsigned r) : edge(e), fileIndex(f), ramIndex(r) {}
- _GridEdge edge;
- unsigned fileIndex;
- unsigned ramIndex;
- bool operator< ( const GridEntry& right ) const {
- return (edge.edgeBasedNode < right.edge.edgeBasedNode);
- }
- bool operator==( const GridEntry& right ) const {
- return right.edge.edgeBasedNode == edge.edgeBasedNode;
- }
-};
-
-struct CompareGridEdgeDataByFileIndex {
- bool operator () (const GridEntry & a, const GridEntry & b) const {
- return a.fileIndex < b.fileIndex;
- }
-};
-
-struct CompareGridEdgeDataByRamIndex {
- typedef GridEntry value_type;
-
- bool operator () (const GridEntry & a, const GridEntry & b) const {
- return a.ramIndex < b.ramIndex;
- }
- value_type max_value() {
- GridEntry e;
- e.ramIndex = (1024*1024) - 1;
- return e;
- }
- value_type min_value() {
- GridEntry e;
- e.ramIndex = 0;
- return e;
- }
-};
-
-#endif /* GRIDEDGE_H_ */
diff --git a/DataStructures/HashTable.h b/DataStructures/HashTable.h
index 57c2dde..199c6df 100644
--- a/DataStructures/HashTable.h
+++ b/DataStructures/HashTable.h
@@ -1,79 +1,78 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
- Created on: 18.11.2010
- Author: dennis
- */
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef HASHTABLE_H_
-#define HASHTABLE_H_
+*/
-#include <boost/unordered_map.hpp>
+#ifndef HASH_TABLE_H
+#define HASH_TABLE_H
-template<typename keyT, typename valueT>
-class HashTable {
- typedef boost::unordered_map<keyT, valueT> MyHashTable;
-public:
- typedef typename boost::unordered_map<keyT, valueT>::const_iterator MyIterator;
- typedef MyIterator iterator;
- HashTable() { }
- HashTable(const unsigned size) {
- table.resize(size);
- }
- inline void Add(const keyT& key, const valueT& value){
- table[key] = value;
- }
- inline void Set(const keyT& key, const valueT& value){
- table[key] = value;
- }
- inline valueT Find(const keyT& key) const {
- if(table.find(key) == table.end())
- return valueT();
- return table.find(key)->second;
- }
+#include <vector>
- inline bool Holds(const keyT& key) const {
- if(table.find(key) == table.end())
- return false;
- return true;
- }
- void EraseAll() {
- if(table.size() > 0)
- table.clear();
- }
+template <typename Key, typename Value>
+class HashTable
+{
+ private:
+ typedef std::pair<Key, Value> KeyValPair;
+ std::vector<KeyValPair> table;
+
+ public:
+ HashTable() {}
- inline valueT operator[] (keyT key) const {
- if(table.find(key) == table.end())
- return valueT();
- return table.find(key)->second;
+ inline void Add(Key const &key, Value const &value)
+ {
+ table.emplace_back(std::move(key), std::move(value));
}
- inline unsigned Size() const {
- return table.size();
+
+ inline void Clear()
+ {
+ table.clear();
}
- MyIterator begin() const {
- return table.begin();
+
+ inline const Value Find(Key const &key) const
+ {
+ for (const auto &key_val_pair : table)
+ {
+ if (key_val_pair.first == key)
+ {
+ return key_val_pair.second;
+ }
+ }
+ return Value();
}
- MyIterator end() const {
- return table.end();
+
+ inline const bool Holds(Key const &key) const
+ {
+ for (const auto &key_val_pair : table)
+ {
+ if (key_val_pair.first == key)
+ {
+ return true;
+ }
+ }
+ return false;
}
-private:
- MyHashTable table;
};
-#endif /* HASHTABLE_H_ */
+#endif /* HASH_TABLE_H */
diff --git a/DataStructures/HilbertValue.cpp b/DataStructures/HilbertValue.cpp
new file mode 100644
index 0000000..9cb88c7
--- /dev/null
+++ b/DataStructures/HilbertValue.cpp
@@ -0,0 +1,100 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "HilbertValue.h"
+
+#include <osrm/Coordinate.h>
+
+uint64_t HilbertCode::operator()(const FixedPointCoordinate ¤t_coordinate) const
+{
+ unsigned location[2];
+ location[0] = current_coordinate.lat + static_cast<int>(90 * COORDINATE_PRECISION);
+ location[1] = current_coordinate.lon + static_cast<int>(180 * COORDINATE_PRECISION);
+
+ TransposeCoordinate(location);
+ return BitInterleaving(location[0], location[1]);
+}
+
+uint64_t HilbertCode::BitInterleaving(const uint32_t latitude, const uint32_t longitude) const
+{
+ uint64_t result = 0;
+ for (int8_t index = 31; index >= 0; --index)
+ {
+ result |= (latitude >> index) & 1;
+ result <<= 1;
+ result |= (longitude >> index) & 1;
+ if (0 != index)
+ {
+ result <<= 1;
+ }
+ }
+ return result;
+}
+
+void HilbertCode::TransposeCoordinate(uint32_t *X) const
+{
+ 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)
+ {
+
+ const bool condition = (X[i] & Q);
+ if (condition)
+ {
+ 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)
+ {
+ const bool condition = (X[2 - 1] & Q);
+ if (condition)
+ {
+ t ^= Q - 1;
+ }
+ } // check if this for loop is wrong
+ for (i = 0; i < 2; ++i)
+ {
+ X[i] ^= t;
+ }
+}
diff --git a/DataStructures/HilbertValue.h b/DataStructures/HilbertValue.h
index 05e2bb1..9de2372 100644
--- a/DataStructures/HilbertValue.h
+++ b/DataStructures/HilbertValue.h
@@ -1,87 +1,49 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef HILBERTVALUE_H_
#define HILBERTVALUE_H_
-#include <boost/integer.hpp>
-#include <boost/noncopyable.hpp>
+#include <cstdint>
// 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);
+struct FixedPointCoordinate;
- 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;
- }
+class HilbertCode
+{
+ public:
+ uint64_t operator()(const FixedPointCoordinate ¤t_coordinate) const;
+ HilbertCode() {}
+ HilbertCode(const HilbertCode &) = delete;
- 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;
- }
- }
+ private:
+ inline uint64_t BitInterleaving(const uint32_t a, const uint32_t b) const;
+ inline void TransposeCoordinate(uint32_t *X) const;
};
#endif /* HILBERTVALUE_H_ */
diff --git a/DataStructures/ImportEdge.cpp b/DataStructures/ImportEdge.cpp
new file mode 100644
index 0000000..0d04b9f
--- /dev/null
+++ b/DataStructures/ImportEdge.cpp
@@ -0,0 +1,107 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "ImportEdge.h"
+
+#include <boost/assert.hpp>
+
+bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
+{
+ if (source == other.source)
+ {
+ if (target == other.target)
+ {
+ if (weight == other.weight)
+ {
+ return forward && backward && ((!other.forward) || (!other.backward));
+ }
+ return weight < other.weight;
+ }
+ return target < other.target;
+ }
+ return source < other.source;
+}
+
+NodeBasedEdge::NodeBasedEdge(NodeID source,
+ NodeID target,
+ NodeID name_id,
+ EdgeWeight weight,
+ bool forward,
+ bool backward,
+ short type,
+ bool roundabout,
+ bool in_tiny_cc,
+ bool access_restricted,
+ bool contra_flow,
+ bool is_split)
+ : source(source), target(target), name_id(name_id), weight(weight), type(type),
+ forward(forward), backward(backward), roundabout(roundabout), in_tiny_cc(in_tiny_cc),
+ access_restricted(access_restricted), contra_flow(contra_flow), is_split(is_split)
+{
+ BOOST_ASSERT_MSG(type > 0, "negative edge type");
+}
+
+bool EdgeBasedEdge::operator<(const EdgeBasedEdge &other) const
+{
+ if (source == other.source)
+ {
+ if (target == other.target)
+ {
+ if (weight == other.weight)
+ {
+ return forward && backward && ((!other.forward) || (!other.backward));
+ }
+ return weight < other.weight;
+ }
+ return target < other.target;
+ }
+ return source < other.source;
+}
+
+template <class EdgeT>
+EdgeBasedEdge::EdgeBasedEdge(const EdgeT &other)
+ : source(other.source), target(other.target), edge_id(other.data.via),
+ weight(other.data.distance), forward(other.data.forward), backward(other.data.backward)
+{
+}
+
+/** Default constructor. target and weight are set to 0.*/
+EdgeBasedEdge::EdgeBasedEdge()
+ : source(0), target(0), edge_id(0), weight(0), forward(false), backward(false)
+{
+}
+
+EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
+ const NodeID target,
+ const NodeID edge_id,
+ const EdgeWeight weight,
+ const bool forward,
+ const bool backward)
+ : source(source), target(target), edge_id(edge_id), weight(weight), forward(forward),
+ backward(backward)
+{
+}
diff --git a/DataStructures/ImportEdge.h b/DataStructures/ImportEdge.h
index 714560c..f79a484 100644
--- a/DataStructures/ImportEdge.h
+++ b/DataStructures/ImportEdge.h
@@ -1,142 +1,92 @@
/*
- 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 EDGE_H
-#define EDGE_H
-
-#include <cassert>
-
-class NodeBasedEdge {
-public:
-
- bool operator< (const NodeBasedEdge& e) const {
- if (source() == e.source()) {
- if (target() == e.target()) {
- if (weight() == e.weight()) {
- return (isForward() && isBackward() &&
- ((! e.isForward()) || (! e.isBackward())));
- }
- return (weight() < e.weight());
- }
- return (target() < e.target());
- }
- return (source() < e.source());
- }
-
- explicit NodeBasedEdge(NodeID s, NodeID t, NodeID n, EdgeWeight w, bool f, bool b, short ty, bool ra, bool ig, bool ar, bool cf) :
- _source(s), _target(t), _name(n), _weight(w), forward(f), backward(b), _type(ty), _roundabout(ra), _ignoreInGrid(ig), _accessRestricted(ar), _contraFlow(cf) { if(ty < 0) {ERR("Type: " << ty);}; }
-
- NodeID target() const {return _target; }
- NodeID source() const {return _source; }
- NodeID name() const { return _name; }
- EdgeWeight weight() const {return _weight; }
-
- short type() const { assert(_type >= 0); return _type; }
- bool isBackward() const { return backward; }
- bool isForward() const { return forward; }
- bool isLocatable() const { return _type != 14; }
- bool isRoundabout() const { return _roundabout; }
- bool ignoreInGrid() const { return _ignoreInGrid; }
- bool isAccessRestricted() const { return _accessRestricted; }
- bool isContraFlow() const { return _contraFlow; }
-
- NodeID _source;
- NodeID _target;
- NodeID _name;
- EdgeWeight _weight;
- bool forward;
- bool backward;
- short _type;
- bool _roundabout;
- bool _ignoreInGrid;
- bool _accessRestricted;
- bool _contraFlow;
-
-private:
- /** Default constructor. target and weight are set to 0.*/
- NodeBasedEdge() :
- _source(0), _target(0), _name(0), _weight(0), forward(0), backward(0), _type(0), _roundabout(false), _ignoreInGrid(false), _accessRestricted(false), _contraFlow(false) { assert(false); } //shall not be used.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef IMPORT_EDGE_H
+#define IMPORT_EDGE_H
+
+#include "../typedefs.h"
+
+struct NodeBasedEdge
+{
+ bool operator<(const NodeBasedEdge &e) const;
+
+ explicit NodeBasedEdge(NodeID source,
+ NodeID target,
+ NodeID name_id,
+ EdgeWeight weight,
+ bool forward,
+ bool backward,
+ short type,
+ bool roundabout,
+ bool in_tiny_cc,
+ bool access_restricted,
+ bool contra_flow,
+ bool is_split);
+
+ NodeID source;
+ NodeID target;
+ NodeID name_id;
+ EdgeWeight weight;
+ short type;
+ bool forward : 1;
+ bool backward : 1;
+ bool roundabout : 1;
+ bool in_tiny_cc : 1;
+ bool access_restricted : 1;
+ bool contra_flow : 1;
+ bool is_split : 1;
+
+ NodeBasedEdge() = delete;
};
-class EdgeBasedEdge {
-public:
-
- bool operator< (const EdgeBasedEdge& e) const {
- if (source() == e.source()) {
- if (target() == e.target()) {
- if (weight() == e.weight()) {
- return (isForward() && isBackward() &&
- ((! e.isForward()) || (! e.isBackward())));
- }
- return (weight() < e.weight());
- }
- return (target() < e.target());
- }
- return (source() < e.source());
- }
-
- template<class EdgeT>
- EdgeBasedEdge(const EdgeT & myEdge ) :
- m_source(myEdge.source),
- m_target(myEdge.target),
- m_edgeID(myEdge.data.via),
- m_weight(myEdge.data.distance),
- m_forward(myEdge.data.forward),
- m_backward(myEdge.data.backward)
- { }
-
- /** Default constructor. target and weight are set to 0.*/
- EdgeBasedEdge() :
- m_source(0),
- m_target(0),
- m_edgeID(0),
- m_weight(0),
- m_forward(false),
- m_backward(false)
- { }
-
- explicit EdgeBasedEdge(const NodeID s, const NodeID t, const NodeID v, const EdgeWeight w, const bool f, const bool b) :
- m_source(s),
- m_target(t),
- m_edgeID(v),
- m_weight(w),
- m_forward(f),
- m_backward(b)
- {}
-
- NodeID target() const {return m_target; }
- NodeID source() const {return m_source; }
- EdgeWeight weight() const {return m_weight; }
- NodeID id() const { return m_edgeID; }
- bool isBackward() const { return m_backward; }
- bool isForward() const { return m_forward; }
-private:
- NodeID m_source;
- NodeID m_target;
- NodeID m_edgeID;
- EdgeWeight m_weight:30;
- bool m_forward:1;
- bool m_backward:1;
+struct EdgeBasedEdge
+{
+
+ public:
+ bool operator<(const EdgeBasedEdge &e) const;
+
+ template <class EdgeT> explicit EdgeBasedEdge(const EdgeT &myEdge);
+
+ EdgeBasedEdge();
+
+ explicit EdgeBasedEdge(const NodeID source,
+ const NodeID target,
+ const NodeID edge_id,
+ const EdgeWeight weight,
+ const bool forward,
+ const bool backward);
+ NodeID source;
+ NodeID target;
+ NodeID edge_id;
+ EdgeWeight weight : 30;
+ bool forward : 1;
+ bool backward : 1;
};
typedef NodeBasedEdge ImportEdge;
-#endif // EDGE_H
+#endif /* IMPORT_EDGE_H */
diff --git a/DataStructures/ImportNode.cpp b/DataStructures/ImportNode.cpp
new file mode 100644
index 0000000..8975d40
--- /dev/null
+++ b/DataStructures/ImportNode.cpp
@@ -0,0 +1,64 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "ImportNode.h"
+
+#include <limits>
+
+ExternalMemoryNode::ExternalMemoryNode(
+ int lat, int lon, unsigned int node_id, bool bollard, bool traffic_light)
+ : NodeInfo(lat, lon, node_id), bollard(bollard), trafficLight(traffic_light)
+{
+}
+
+ExternalMemoryNode::ExternalMemoryNode() : bollard(false), trafficLight(false)
+{
+}
+
+ExternalMemoryNode ExternalMemoryNode::min_value()
+{
+ return ExternalMemoryNode(0, 0, 0, false, false);
+}
+
+ExternalMemoryNode ExternalMemoryNode::max_value()
+{
+ return ExternalMemoryNode(std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<unsigned>::max(),
+ false,
+ false);
+}
+
+void ImportNode::Clear()
+{
+ keyVals.Clear();
+ lat = 0;
+ lon = 0;
+ node_id = 0;
+ bollard = false;
+ trafficLight = false;
+}
diff --git a/DataStructures/ImportNode.h b/DataStructures/ImportNode.h
index b9c27be..b8a9451 100644
--- a/DataStructures/ImportNode.h
+++ b/DataStructures/ImportNode.h
@@ -1,54 +1,57 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef IMPORTNODE_H_
#define IMPORTNODE_H_
-#include "NodeCoords.h"
+#include "QueryNode.h"
#include "../DataStructures/HashTable.h"
+#include <string>
+
+struct ExternalMemoryNode : NodeInfo
+{
+ ExternalMemoryNode(int lat, int lon, unsigned int id, bool bollard, bool traffic_light);
-struct _Node : NodeInfo{
- _Node(int _lat, int _lon, unsigned int _id, bool _bollard, bool _trafficLight) : NodeInfo(_lat, _lon, _id), bollard(_bollard), trafficLight(_trafficLight) {}
- _Node() : bollard(false), trafficLight(false) {}
+ ExternalMemoryNode();
+
+ static ExternalMemoryNode min_value();
+
+ static ExternalMemoryNode max_value();
- static _Node min_value() {
- return _Node(0,0,0, false, false);
- }
- static _Node max_value() {
- return _Node((std::numeric_limits<int>::max)(), (std::numeric_limits<int>::max)(), (std::numeric_limits<unsigned int>::max)(), false, false);
- }
- NodeID key() const {
- return id;
- }
bool bollard;
bool trafficLight;
};
-struct ImportNode : public _Node {
+struct ImportNode : public ExternalMemoryNode
+{
HashTable<std::string, std::string> keyVals;
-
- inline void Clear() {
- keyVals.EraseAll();
- lat = 0; lon = 0; id = 0; bollard = false; trafficLight = false;
- }
+
+ inline void Clear();
};
#endif /* IMPORTNODE_H_ */
diff --git a/DataStructures/InputReaderFactory.h b/DataStructures/InputReaderFactory.h
index f58232f..3f6aa3c 100644
--- a/DataStructures/InputReaderFactory.h
+++ b/DataStructures/InputReaderFactory.h
@@ -1,94 +1,123 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef INPUTREADERFACTORY_H
-#define INPUTREADERFACTORY_H
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef INPUT_READER_FACTORY_H
+#define INPUT_READER_FACTORY_H
+
+#include <boost/assert.hpp>
#include <bzlib.h>
#include <libxml/xmlreader.h>
-struct BZ2Context {
- FILE* file;
- BZFILE* bz2;
+struct BZ2Context
+{
+ FILE *file;
+ BZFILE *bz2;
int error;
int nUnused;
char unused[BZ_MAX_UNUSED];
};
-int readFromBz2Stream( void* pointer, char* buffer, int len ) {
- void *unusedTmpVoid=NULL;
- char *unusedTmp=NULL;
- BZ2Context* context = (BZ2Context*) pointer;
+int readFromBz2Stream(void *pointer, char *buffer, int len)
+{
+ void *unusedTmpVoid = nullptr;
+ char *unusedTmp = nullptr;
+ BZ2Context *context = (BZ2Context *)pointer;
int read = 0;
- while(0 == read && !(BZ_STREAM_END == context->error && 0 == context->nUnused && feof(context->file))) {
+ while (0 == read &&
+ !(BZ_STREAM_END == context->error && 0 == context->nUnused && feof(context->file)))
+ {
read = BZ2_bzRead(&context->error, context->bz2, buffer, len);
- if(BZ_OK == context->error) {
+ if (BZ_OK == context->error)
+ {
return read;
- } else if(BZ_STREAM_END == context->error) {
+ }
+ else if (BZ_STREAM_END == context->error)
+ {
BZ2_bzReadGetUnused(&context->error, context->bz2, &unusedTmpVoid, &context->nUnused);
- if(BZ_OK != context->error) {std::cerr << "Could not BZ2_bzReadGetUnused" <<std::endl; exit(-1);};
- unusedTmp = (char*)unusedTmpVoid;
- for(int i=0;i<context->nUnused;i++) {
+ BOOST_ASSERT_MSG(BZ_OK == context->error, "Could not BZ2_bzReadGetUnused");
+ unusedTmp = (char *)unusedTmpVoid;
+ for (int i = 0; i < context->nUnused; i++)
+ {
context->unused[i] = unusedTmp[i];
}
BZ2_bzReadClose(&context->error, context->bz2);
- if(BZ_OK != context->error) {std::cerr << "Could not BZ2_bzReadClose" <<std::endl; exit(-1);};
+ BOOST_ASSERT_MSG(BZ_OK == context->error, "Could not BZ2_bzReadClose");
context->error = BZ_STREAM_END; // set to the stream end for next call to this function
- if(0 == context->nUnused && feof(context->file)) {
+ if (0 == context->nUnused && feof(context->file))
+ {
return read;
- } else {
- context->bz2 = BZ2_bzReadOpen(&context->error, context->file, 0, 0, context->unused, context->nUnused);
- if(NULL == context->bz2){std::cerr << "Could not open file" <<std::endl; exit(-1);};
}
- } else { std::cerr << "Could not read bz2 file" << std::endl; exit(-1); }
+ else
+ {
+ context->bz2 = BZ2_bzReadOpen(
+ &context->error, context->file, 0, 0, context->unused, context->nUnused);
+ BOOST_ASSERT_MSG(nullptr != context->bz2, "Could not open file");
+ }
+ }
+ else
+ {
+ BOOST_ASSERT_MSG(false, "Could not read bz2 file");
+ }
}
return read;
}
-int closeBz2Stream( void *pointer )
+int closeBz2Stream(void *pointer)
{
- BZ2Context* context = (BZ2Context*) pointer;
- fclose( context->file );
+ BZ2Context *context = (BZ2Context *)pointer;
+ fclose(context->file);
delete context;
return 0;
}
-xmlTextReaderPtr inputReaderFactory( const char* name )
+xmlTextReaderPtr inputReaderFactory(const char *name)
{
std::string inputName(name);
- if(inputName.find(".osm.bz2")!=std::string::npos)
+ if (inputName.find(".osm.bz2") != std::string::npos)
{
- BZ2Context* context = new BZ2Context();
+ BZ2Context *context = new BZ2Context();
context->error = false;
- context->file = fopen( name, "r" );
+ context->file = fopen(name, "r");
int error;
- context->bz2 = BZ2_bzReadOpen( &error, context->file, 0, 0, context->unused, context->nUnused );
- if ( context->bz2 == NULL || context->file == NULL ) {
+ context->bz2 =
+ BZ2_bzReadOpen(&error, context->file, 0, 0, context->unused, context->nUnused);
+ if (context->bz2 == nullptr || context->file == nullptr)
+ {
delete context;
- return NULL;
+ return nullptr;
}
- return xmlReaderForIO( readFromBz2Stream, closeBz2Stream, (void*) context, NULL, NULL, 0 );
- } else {
+ return xmlReaderForIO(readFromBz2Stream, closeBz2Stream, (void *)context, nullptr, nullptr, 0);
+ }
+ else
+ {
return xmlNewTextReaderFilename(name);
}
}
-#endif // INPUTREADERFACTORY_H
+#endif // INPUT_READER_FACTORY_H
diff --git a/DataStructures/JSONContainer.h b/DataStructures/JSONContainer.h
new file mode 100644
index 0000000..47dc34b
--- /dev/null
+++ b/DataStructures/JSONContainer.h
@@ -0,0 +1,237 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+// based on https://svn.apache.org/repos/asf/mesos/tags/release-0.9.0-incubating-RC0/src/common/json.hpp
+
+#ifndef JSON_CONTAINER_H
+#define JSON_CONTAINER_H
+
+#include "../Util/StringUtil.h"
+
+#include <boost/variant.hpp>
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <unordered_map>
+
+namespace JSON
+{
+
+struct String;
+struct Number;
+struct Object;
+struct Array;
+struct True;
+struct False;
+struct Null;
+
+typedef boost::variant<boost::recursive_wrapper<String>,
+ boost::recursive_wrapper<Number>,
+ boost::recursive_wrapper<Object>,
+ boost::recursive_wrapper<Array>,
+ boost::recursive_wrapper<True>,
+ boost::recursive_wrapper<False>,
+ boost::recursive_wrapper<Null> > Value;
+
+struct String
+{
+ String() {}
+ String(const char *value) : value(value) {}
+ String(const std::string &value) : value(value) {}
+ std::string value;
+};
+
+struct Number
+{
+ Number() {}
+ Number(double value) : value(value) {}
+ double value;
+};
+
+struct Object
+{
+ std::unordered_map<std::string, Value> values;
+};
+
+struct Array
+{
+ std::vector<Value> values;
+};
+
+struct True
+{
+};
+
+struct False
+{
+};
+
+struct Null
+{
+};
+
+struct Renderer : boost::static_visitor<>
+{
+ Renderer(std::ostream &_out) : out(_out) {}
+
+ void operator()(const String &string) const { out << "\"" << string.value << "\""; }
+
+ void operator()(const Number &number) const
+ {
+ out.precision(10);
+ out << number.value;
+ }
+
+ void operator()(const Object &object) const
+ {
+ out << "{";
+ auto iterator = object.values.begin();
+ while (iterator != object.values.end())
+ {
+ out << "\"" << (*iterator).first << "\":";
+ boost::apply_visitor(Renderer(out), (*iterator).second);
+ if (++iterator != object.values.end())
+ {
+ out << ",";
+ }
+ }
+ out << "}";
+ }
+
+ void operator()(const Array &array) const
+ {
+ out << "[";
+ std::vector<Value>::const_iterator iterator;
+ iterator = array.values.begin();
+ while (iterator != array.values.end())
+ {
+ boost::apply_visitor(Renderer(out), *iterator);
+ if (++iterator != array.values.end())
+ {
+ out << ",";
+ }
+ }
+ out << "]";
+ }
+
+ void operator()(const True &) const { out << "true"; }
+
+ void operator()(const False &) const { out << "false"; }
+
+ void operator()(const Null &) const { out << "null"; }
+
+ private:
+ std::ostream &out;
+};
+
+struct ArrayRenderer : boost::static_visitor<>
+{
+ ArrayRenderer(std::vector<char> &_out) : out(_out) {}
+
+ void operator()(const String &string) const {
+ out.push_back('\"');
+ out.insert(out.end(), string.value.begin(), string.value.end());
+ out.push_back('\"');
+ }
+
+ void operator()(const Number &number) const
+ {
+ const std::string number_string = FixedDoubleToString(number.value);
+ out.insert(out.end(), number_string.begin(), number_string.end());
+ }
+
+ void operator()(const Object &object) const
+ {
+ out.push_back('{');
+ auto iterator = object.values.begin();
+ while (iterator != object.values.end())
+ {
+ out.push_back('\"');
+ out.insert(out.end(), (*iterator).first.begin(), (*iterator).first.end());
+ out.push_back('\"');
+ out.push_back(':');
+
+ boost::apply_visitor(ArrayRenderer(out), (*iterator).second);
+ if (++iterator != object.values.end())
+ {
+ out.push_back(',');
+ }
+ }
+ out.push_back('}');
+ }
+
+ void operator()(const Array &array) const
+ {
+ out.push_back('[');
+ std::vector<Value>::const_iterator iterator;
+ iterator = array.values.begin();
+ while (iterator != array.values.end())
+ {
+ boost::apply_visitor(ArrayRenderer(out), *iterator);
+ if (++iterator != array.values.end())
+ {
+ out.push_back(',');
+ }
+ }
+ out.push_back(']');
+ }
+
+ void operator()(const True &) const {
+ const std::string temp("true");
+ out.insert(out.end(), temp.begin(), temp.end());
+ }
+
+ void operator()(const False &) const {
+ const std::string temp("false");
+ out.insert(out.end(), temp.begin(), temp.end());
+ }
+
+ void operator()(const Null &) const {
+ const std::string temp("null");
+ out.insert(out.end(), temp.begin(), temp.end());
+ }
+
+ private:
+ std::vector<char> &out;
+};
+
+inline void render(std::ostream &out, const Object &object)
+{
+ Value value = object;
+ boost::apply_visitor(Renderer(out), value);
+}
+
+inline void render(std::vector<char> &out, const Object &object)
+{
+ Value value = object;
+ boost::apply_visitor(ArrayRenderer(out), value);
+}
+
+} // namespace JSON
+
+#endif // JSON_CONTAINER_H
diff --git a/DataStructures/LRUCache.h b/DataStructures/LRUCache.h
index a2c0b13..75b9139 100644
--- a/DataStructures/LRUCache.h
+++ b/DataStructures/LRUCache.h
@@ -1,82 +1,97 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef LRUCACHE_H
#define LRUCACHE_H
#include <list>
-#include <boost/unordered_map.hpp>
+#include <unordered_map>
-template<typename KeyT, typename ValueT>
-class LRUCache {
-private:
- struct CacheEntry {
+template <typename KeyT, typename ValueT> class LRUCache
+{
+ private:
+ struct CacheEntry
+ {
CacheEntry(KeyT k, ValueT v) : key(k), value(v) {}
KeyT key;
ValueT value;
};
unsigned capacity;
std::list<CacheEntry> itemsInCache;
- boost::unordered_map<KeyT, typename std::list<CacheEntry>::iterator > positionMap;
-public:
- LRUCache(unsigned c) : capacity(c) {}
+ std::unordered_map<KeyT, typename std::list<CacheEntry>::iterator> positionMap;
- bool Holds(KeyT key) {
- if(positionMap.find(key) != positionMap.end()) {
+ public:
+ explicit LRUCache(unsigned c) : capacity(c) {}
+
+ bool Holds(KeyT key)
+ {
+ if (positionMap.find(key) != positionMap.end())
+ {
return true;
}
return false;
}
- void Insert(const KeyT key, ValueT &value) {
+ void Insert(const KeyT key, ValueT &value)
+ {
itemsInCache.push_front(CacheEntry(key, value));
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
- if(itemsInCache.size() > capacity) {
+ if (itemsInCache.size() > capacity)
+ {
positionMap.erase(itemsInCache.back().key);
itemsInCache.pop_back();
}
}
- void Insert(const KeyT key, ValueT value) {
+ void Insert(const KeyT key, ValueT value)
+ {
itemsInCache.push_front(CacheEntry(key, value));
positionMap.insert(std::make_pair(key, itemsInCache.begin()));
- if(itemsInCache.size() > capacity) {
+ if (itemsInCache.size() > capacity)
+ {
positionMap.erase(itemsInCache.back().key);
itemsInCache.pop_back();
}
}
- bool Fetch(const KeyT key, ValueT& result) {
- if(Holds(key)) {
+ bool Fetch(const KeyT key, ValueT &result)
+ {
+ if (Holds(key))
+ {
CacheEntry e = *(positionMap.find(key)->second);
result = e.value;
- //move to front
+ // move to front
itemsInCache.splice(positionMap.find(key)->second, itemsInCache, itemsInCache.begin());
positionMap.find(key)->second = itemsInCache.begin();
return true;
}
return false;
}
- unsigned Size() const {
- return itemsInCache.size();
- }
+ unsigned Size() const { return itemsInCache.size(); }
};
-#endif //LRUCACHE_H
+#endif // LRUCACHE_H
diff --git a/DataStructures/MercatorUtil.h b/DataStructures/MercatorUtil.h
deleted file mode 100644
index 15bea27..0000000
--- a/DataStructures/MercatorUtil.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- 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 MERCATORUTIL_H_
-#define MERCATORUTIL_H_
-
-#include <cmath>
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-inline double y2lat(double a) {
- return 180/M_PI * (2 * atan(exp(a*M_PI/180)) - M_PI/2);
-}
-
-inline double lat2y(double a) {
- return 180/M_PI * log(tan(M_PI/4+a*(M_PI/180)/2));
-}
-
-#endif /* MERCATORUTIL_H_ */
diff --git a/DataStructures/NNGrid.h b/DataStructures/NNGrid.h
deleted file mode 100644
index 22cb4e2..0000000
--- a/DataStructures/NNGrid.h
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- 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 NNGRID_H_
-#define NNGRID_H_
-
-#include <cassert>
-#include <cfloat>
-#include <cmath>
-#include <cstring>
-
-#include <algorithm>
-#include <fstream>
-#include <limits>
-#include <vector>
-
-#ifndef ROUTED
-#include <stxxl.h>
-#endif
-
-#ifdef _WIN32
-#include <math.h>
-#endif
-
-#include <boost/thread.hpp>
-#include <boost/foreach.hpp>
-#include <boost/unordered_map.hpp>
-
-#include "DeallocatingVector.h"
-#include "GridEdge.h"
-#include "Percent.h"
-#include "PhantomNodes.h"
-#include "MercatorUtil.h"
-#include "StaticGraph.h"
-#include "TimingUtil.h"
-#include "../Algorithms/Bresenham.h"
-
-namespace NNGrid{
-
-static boost::thread_specific_ptr<std::ifstream> localStream;
-
-template<bool WriteAccess = false>
-class NNGrid {
-public:
- NNGrid() /*: cellCache(500), fileCache(500)*/ {
- ramIndexTable.resize((1024*1024), std::numeric_limits<uint64_t>::max());
- }
-
- NNGrid(const char* rif, const char* _i) {
- if(WriteAccess) {
- ERR("Not available in Write mode");
- }
- iif = std::string(_i);
- ramIndexTable.resize((1024*1024), std::numeric_limits<uint64_t>::max());
- ramInFile.open(rif, std::ios::in | std::ios::binary);
- if(!ramInFile) { ERR(rif << " not found"); }
-
- }
-
- ~NNGrid() {
- if(ramInFile.is_open()) ramInFile.close();
-
-#ifndef ROUTED
- if (WriteAccess) {
- entries.clear();
- }
-#endif
- if(localStream.get() && localStream->is_open()) {
- localStream->close();
- }
- }
-
- void OpenIndexFiles() {
- assert(ramInFile.is_open());
- ramInFile.read(static_cast<char*>(static_cast<void*>(&ramIndexTable[0]) ), sizeof(uint64_t)*1024*1024);
- ramInFile.close();
- }
-
-#ifndef ROUTED
- template<typename EdgeT>
- inline void ConstructGrid(DeallocatingVector<EdgeT> & edgeList, const char * ramIndexOut, const char * fileIndexOut) {
- //TODO: Implement this using STXXL-Streams
- Percent p(edgeList.size());
- BOOST_FOREACH(EdgeT & edge, edgeList) {
- p.printIncrement();
- if(edge.ignoreInGrid)
- continue;
- int slat = 100000*lat2y(edge.lat1/100000.);
- int slon = edge.lon1;
- int tlat = 100000*lat2y(edge.lat2/100000.);
- int tlon = edge.lon2;
- AddEdge( _GridEdge( edge.id, edge.nameID, edge.weight, _Coordinate(slat, slon), _Coordinate(tlat, tlon), edge.belongsToTinyComponent ) );
- }
- if( 0 == entries.size() ) {
- ERR("No viable edges for nearest neighbor index. Aborting");
- }
- double timestamp = get_timestamp();
- //create index file on disk, old one is over written
- indexOutFile.open(fileIndexOut, std::ios::out | std::ios::binary | std::ios::trunc);
- //sort entries
- stxxl::sort(entries.begin(), entries.end(), CompareGridEdgeDataByRamIndex(), 1024*1024*1024);
- INFO("finished sorting after " << (get_timestamp() - timestamp) << "s");
- std::vector<GridEntry> entriesInFileWithRAMSameIndex;
- unsigned indexInRamTable = entries.begin()->ramIndex;
- uint64_t lastPositionInIndexFile = 0;
- std::cout << "writing data ..." << std::flush;
- p.reinit(entries.size());
- boost::unordered_map< unsigned, unsigned > cellMap(1024);
- BOOST_FOREACH(GridEntry & gridEntry, entries) {
- p.printIncrement();
- if(gridEntry.ramIndex != indexInRamTable) {
- cellMap.clear();
- BuildCellIndexToFileIndexMap(indexInRamTable, cellMap);
-
- unsigned numberOfBytesInCell = FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile, cellMap);
- ramIndexTable[indexInRamTable] = lastPositionInIndexFile;
- lastPositionInIndexFile += numberOfBytesInCell;
- entriesInFileWithRAMSameIndex.clear();
- indexInRamTable = gridEntry.ramIndex;
- }
- entriesInFileWithRAMSameIndex.push_back(gridEntry);
- }
- cellMap.clear();
- BuildCellIndexToFileIndexMap(indexInRamTable, cellMap);
- /*unsigned numberOfBytesInCell = */FillCell(entriesInFileWithRAMSameIndex, lastPositionInIndexFile, cellMap);
- ramIndexTable[indexInRamTable] = lastPositionInIndexFile;
- entriesInFileWithRAMSameIndex.clear();
- std::vector<GridEntry>().swap(entriesInFileWithRAMSameIndex);
- assert(entriesInFileWithRAMSameIndex.size() == 0);
- //close index file
- indexOutFile.close();
-
- //Serialize RAM Index
- std::ofstream ramFile(ramIndexOut, std::ios::out | std::ios::binary | std::ios::trunc);
- //write 4 MB of index Table in RAM
- ramFile.write((char *)&ramIndexTable[0], sizeof(uint64_t)*1024*1024 );
- //close ram index file
- ramFile.close();
- }
-#endif
- 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);
- }
-
- bool FindPhantomNodeForCoordinate( const _Coordinate & location, PhantomNode & resultNode, const unsigned zoomLevel) {
- bool ignoreTinyComponents = (zoomLevel <= 14);
-// INFO("Coordinate: " << location << ", zoomLevel: " << zoomLevel << ", ignoring tinyComponentents: " << (ignoreTinyComponents ? "yes" : "no"));
-// double time1 = get_timestamp();
- bool foundNode = false;
- const _Coordinate startCoord(100000*(lat2y(static_cast<double>(location.lat)/100000.)), location.lon);
- /** search for point on edge close to source */
- const unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
- std::vector<_GridEdge> candidates;
- const int lowerBoundForLoop = (fileIndex < 32768 ? 0 : -32768);
- for(int j = lowerBoundForLoop; (j < (32768+1)) && (fileIndex != UINT_MAX); j+=32768) {
- for(int i = -1; i < 2; ++i){
-// unsigned oldSize = candidates.size();
- GetContentsOfFileBucketEnumerated(fileIndex+i+j, candidates);
-// INFO("Getting fileIndex=" << fileIndex+i+j << " with " << candidates.size() - oldSize << " candidates");
- }
- }
-// INFO("looked up " << candidates.size());
- _GridEdge smallestEdge;
- _Coordinate tmp, edgeStartCoord, edgeEndCoord;
- double dist = std::numeric_limits<double>::max();
- double r, tmpDist;
-
- BOOST_FOREACH(const _GridEdge & candidate, candidates) {
- if(candidate.belongsToTinyComponent && ignoreTinyComponents)
- continue;
- r = 0.;
- tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r);
-// INFO("dist " << startCoord << "->[" << candidate.startCoord << "-" << candidate.targetCoord << "]=" << tmpDist );
-// INFO("Looking at edge " << candidate.edgeBasedNode << " at distance " << tmpDist);
- if(tmpDist < dist && !DoubleEpsilonCompare(dist, tmpDist)) {
-// INFO("a) " << candidate.edgeBasedNode << ", dist: " << tmpDist << ", tinyCC: " << (candidate.belongsToTinyComponent ? "yes" : "no"));
- dist = tmpDist;
- resultNode.edgeBasedNode = candidate.edgeBasedNode;
- resultNode.nodeBasedEdgeNameID = candidate.nameID;
- resultNode.weight1 = candidate.weight;
- resultNode.weight2 = INT_MAX;
- resultNode.location.lat = tmp.lat;
- resultNode.location.lon = tmp.lon;
- edgeStartCoord = candidate.startCoord;
- edgeEndCoord = candidate.targetCoord;
- foundNode = true;
- smallestEdge = candidate;
- //} else if(tmpDist < dist) {
- //INFO("a) ignored " << candidate.edgeBasedNode << " at distance " << std::fabs(dist - tmpDist));
- } else if(DoubleEpsilonCompare(dist, tmpDist) && 1 == std::abs(static_cast<int>(candidate.edgeBasedNode)-static_cast<int>(resultNode.edgeBasedNode) ) && CoordinatesAreEquivalent(edgeStartCoord, candidate.startCoord, edgeEndCoord, candidate.targetCoord)) {
- resultNode.edgeBasedNode = std::min(candidate.edgeBasedNode, resultNode.edgeBasedNode);
- resultNode.weight2 = candidate.weight;
- //INFO("b) " << candidate.edgeBasedNode << ", dist: " << tmpDist);
- }
- }
-
- // INFO("startcoord: " << smallestEdge.startCoord << ", tgtcoord" << smallestEdge.targetCoord << "result: " << newEndpoint);
- // INFO("length of old edge: " << ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord));
- // INFO("Length of new edge: " << ApproximateDistance(smallestEdge.startCoord, newEndpoint));
- // assert(!resultNode.isBidirected() || (resultNode.weight1 == resultNode.weight2));
- // if(resultNode.weight1 != resultNode.weight2) {
- // INFO("-> Weight1: " << resultNode.weight1 << ", weight2: " << resultNode.weight2);
- // INFO("-> node: " << resultNode.edgeBasedNode << ", bidir: " << (resultNode.isBidirected() ? "yes" : "no"));
- // }
-
-// INFO("startCoord: " << smallestEdge.startCoord << "; targetCoord: " << smallestEdge.targetCoord << "; newEndpoint: " << resultNode.location);
- const double ratio = (foundNode ? std::min(1., ApproximateDistance(smallestEdge.startCoord, resultNode.location)/ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord)) : 0);
- resultNode.location.lat = round(100000.*(y2lat(static_cast<double>(resultNode.location.lat)/100000.)));
-// INFO("Length of vector: " << ApproximateDistance(smallestEdge.startCoord, resultNode.location)/ApproximateDistance(smallestEdge.startCoord, smallestEdge.targetCoord));
- //Hack to fix rounding errors and wandering via nodes.
- if(std::abs(location.lon - resultNode.location.lon) == 1)
- resultNode.location.lon = location.lon;
- if(std::abs(location.lat - resultNode.location.lat) == 1)
- resultNode.location.lat = location.lat;
-
- resultNode.weight1 *= ratio;
- if(INT_MAX != resultNode.weight2) {
- resultNode.weight2 *= (1.-ratio);
- }
- resultNode.ratio = ratio;
-// INFO("start: " << edgeStartCoord << ", end: " << edgeEndCoord);
-// INFO("selected node: " << resultNode.edgeBasedNode << ", bidirected: " << (resultNode.isBidirected() ? "yes" : "no"));
-// INFO("New weight1: " << resultNode.weight1 << ", new weight2: " << resultNode.weight2 << ", ratio: " << ratio);
- // INFO("distance to input coordinate: " << ApproximateDistance(location, resultNode.location) << "\n--");
-// double time2 = get_timestamp();
-// INFO("NN-Lookup in " << 1000*(time2-time1) << "ms");
- return foundNode;
- }
-
- bool FindRoutingStarts(const _Coordinate& start, const _Coordinate& target, PhantomNodes & routingStarts, unsigned zoomLevel) {
- routingStarts.Reset();
- return (FindPhantomNodeForCoordinate( start, routingStarts.startPhantom, zoomLevel) &&
- FindPhantomNodeForCoordinate( target, routingStarts.targetPhantom, zoomLevel) );
- }
-
- bool FindNearestCoordinateOnEdgeInNodeBasedGraph(const _Coordinate& inputCoordinate, _Coordinate& outputCoordinate, unsigned zoomLevel = 18) {
- PhantomNode resultNode;
- bool foundNode = FindPhantomNodeForCoordinate(inputCoordinate, resultNode, zoomLevel);
- outputCoordinate = resultNode.location;
- return foundNode;
- }
-
- void FindNearestPointOnEdge(const _Coordinate& inputCoordinate, _Coordinate& outputCoordinate) {
- _Coordinate startCoord(100000*(lat2y(static_cast<double>(inputCoordinate.lat)/100000.)), inputCoordinate.lon);
- unsigned fileIndex = GetFileIndexForLatLon(startCoord.lat, startCoord.lon);
-
- std::vector<_GridEdge> candidates;
- boost::unordered_map< unsigned, unsigned > cellMap;
- for(int j = -32768; j < (32768+1); j+=32768) {
- for(int i = -1; i < 2; ++i) {
- GetContentsOfFileBucket(fileIndex+i+j, candidates, cellMap);
- }
- }
- _Coordinate tmp;
- double dist = (std::numeric_limits<double>::max)();
- BOOST_FOREACH(const _GridEdge & candidate, candidates) {
- double r = 0.;
- double tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r);
- if(tmpDist < dist) {
- dist = tmpDist;
- outputCoordinate.lat = round(100000*(y2lat(static_cast<double>(tmp.lat)/100000.)));
- outputCoordinate.lon = tmp.lon;
- }
- }
- }
-
-
-private:
- inline unsigned GetCellIndexFromRAMAndFileIndex(const unsigned ramIndex, const unsigned fileIndex) const {
- unsigned lineBase = ramIndex/1024;
- lineBase = lineBase*32*32768;
- unsigned columnBase = ramIndex%1024;
- columnBase=columnBase*32;
- for (int i = 0;i < 32;++i) {
- for (int j = 0;j < 32;++j) {
- const unsigned localFileIndex = lineBase + i * 32768 + columnBase + j;
- if(localFileIndex == fileIndex) {
- unsigned cellIndex = i * 32 + j;
- return cellIndex;
- }
- }
- }
- return UINT_MAX;
- }
-
- inline void BuildCellIndexToFileIndexMap(const unsigned ramIndex, boost::unordered_map<unsigned, unsigned >& cellMap){
- unsigned lineBase = ramIndex/1024;
- lineBase = lineBase*32*32768;
- unsigned columnBase = ramIndex%1024;
- columnBase=columnBase*32;
- std::vector<std::pair<unsigned, unsigned> >insertionVector(1024);
- for (int i = 0;i < 32;++i) {
- for (int j = 0;j < 32;++j) {
- unsigned fileIndex = lineBase + i * 32768 + columnBase + j;
- unsigned cellIndex = i * 32 + j;
- insertionVector[i * 32 + j] = std::make_pair(fileIndex, cellIndex);
- }
- }
- cellMap.insert(insertionVector.begin(), insertionVector.end());
- }
-
- inline bool DoubleEpsilonCompare(const double d1, const double d2) const {
- return (std::fabs(d1 - d2) < FLT_EPSILON);
- }
-
-#ifndef ROUTED
- inline unsigned FillCell(std::vector<GridEntry>& entriesWithSameRAMIndex, const uint64_t fileOffset, boost::unordered_map< unsigned, unsigned > & cellMap ) {
- std::vector<char> tmpBuffer(32*32*4096,0);
- uint64_t indexIntoTmpBuffer = 0;
- unsigned numberOfWrittenBytes = 0;
- assert(indexOutFile.is_open());
-
- std::vector<uint64_t> cellIndex(32*32,std::numeric_limits<uint64_t>::max());
-
- for(unsigned i = 0; i < entriesWithSameRAMIndex.size() -1; ++i) {
- assert(entriesWithSameRAMIndex[i].ramIndex== entriesWithSameRAMIndex[i+1].ramIndex);
- }
-
- //sort & unique
- std::sort(entriesWithSameRAMIndex.begin(), entriesWithSameRAMIndex.end(), CompareGridEdgeDataByFileIndex());
-// entriesWithSameRAMIndex.erase(std::unique(entriesWithSameRAMIndex.begin(), entriesWithSameRAMIndex.end()), entriesWithSameRAMIndex.end());
-
- //traverse each file bucket and write its contents to disk
- std::vector<GridEntry> entriesWithSameFileIndex;
- unsigned fileIndex = entriesWithSameRAMIndex.begin()->fileIndex;
-
- BOOST_FOREACH(GridEntry & gridEntry, entriesWithSameRAMIndex) {
- assert(cellMap.find(gridEntry.fileIndex) != cellMap.end() ); //asserting that file index belongs to cell index
- if(gridEntry.fileIndex != fileIndex) {
- // start in cellIndex vermerken
- int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex;
- int localCellIndex = cellMap.find(localFileIndex)->second;
- assert(cellMap.find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap.end());
-
- cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset;
- indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer);
- fileIndex = gridEntry.fileIndex;
- }
- entriesWithSameFileIndex.push_back(gridEntry);
- }
- assert(cellMap.find(entriesWithSameFileIndex.begin()->fileIndex) != cellMap.end());
- int localFileIndex = entriesWithSameFileIndex.begin()->fileIndex;
- int localCellIndex = cellMap.find(localFileIndex)->second;
-
- cellIndex[localCellIndex] = indexIntoTmpBuffer + fileOffset;
- indexIntoTmpBuffer += FlushEntriesWithSameFileIndexToBuffer(entriesWithSameFileIndex, tmpBuffer, indexIntoTmpBuffer);
-
- assert(entriesWithSameFileIndex.size() == 0);
- indexOutFile.write(static_cast<char*>(static_cast<void*>(&cellIndex[0])),32*32*sizeof(uint64_t));
- numberOfWrittenBytes += 32*32*sizeof(uint64_t);
-
- //write contents of tmpbuffer to disk
- indexOutFile.write(&tmpBuffer[0], indexIntoTmpBuffer*sizeof(char));
- numberOfWrittenBytes += indexIntoTmpBuffer*sizeof(char);
-
- return numberOfWrittenBytes;
- }
-
- inline unsigned FlushEntriesWithSameFileIndexToBuffer( std::vector<GridEntry> &vectorWithSameFileIndex, std::vector<char> & tmpBuffer, const uint64_t index) const {
- sort( vectorWithSameFileIndex.begin(), vectorWithSameFileIndex.end() );
- vectorWithSameFileIndex.erase(unique(vectorWithSameFileIndex.begin(), vectorWithSameFileIndex.end()), vectorWithSameFileIndex.end());
- const unsigned lengthOfBucket = vectorWithSameFileIndex.size();
- tmpBuffer.resize(tmpBuffer.size()+(sizeof(_GridEdge)*lengthOfBucket) + sizeof(unsigned) );
- unsigned counter = 0;
-
- for(unsigned i = 0; i < vectorWithSameFileIndex.size()-1; ++i) {
- assert( vectorWithSameFileIndex[i].fileIndex == vectorWithSameFileIndex[i+1].fileIndex );
- assert( vectorWithSameFileIndex[i].ramIndex == vectorWithSameFileIndex[i+1].ramIndex );
- }
-
- //write length of bucket
- memcpy((char*)&(tmpBuffer[index+counter]), (char*)&lengthOfBucket, sizeof(lengthOfBucket));
- counter += sizeof(lengthOfBucket);
-
- BOOST_FOREACH(const GridEntry & entry, vectorWithSameFileIndex) {
- char * data = (char*)&(entry.edge);
- memcpy(static_cast<char*>(static_cast<void*>(&(tmpBuffer[index+counter]) )), data, sizeof(entry.edge));
- counter += sizeof(entry.edge);
- }
- //Freeing data
- vectorWithSameFileIndex.clear();
- return counter;
- }
-#endif
-
- inline void GetContentsOfFileBucketEnumerated(const unsigned fileIndex, std::vector<_GridEdge>& result) const {
- unsigned ramIndex = GetRAMIndexFromFileIndex(fileIndex);
- uint64_t startIndexInFile = ramIndexTable[ramIndex];
- if(startIndexInFile == std::numeric_limits<uint64_t>::max()) {
- return;
- }
- unsigned enumeratedIndex = GetCellIndexFromRAMAndFileIndex(ramIndex, fileIndex);
-
- if(!localStream.get() || !localStream->is_open()) {
- localStream.reset(new std::ifstream(iif.c_str(), std::ios::in | std::ios::binary));
- }
- if(!localStream->good()) {
- localStream->clear(std::ios::goodbit);
- DEBUG("Resetting stale filestream");
- }
-
- //only read the single necessary cell index
- localStream->seekg(startIndexInFile+(enumeratedIndex*sizeof(uint64_t)));
- uint64_t fetchedIndex = 0;
- localStream->read(static_cast<char*>( static_cast<void*>(&fetchedIndex)), sizeof(uint64_t));
-
- if(fetchedIndex == std::numeric_limits<uint64_t>::max()) {
- return;
- }
- const uint64_t position = fetchedIndex + 32*32*sizeof(uint64_t) ;
-
- unsigned lengthOfBucket;
- unsigned currentSizeOfResult = result.size();
- localStream->seekg(position);
- localStream->read(static_cast<char*>( static_cast<void*>(&(lengthOfBucket))), sizeof(unsigned));
- result.resize(currentSizeOfResult+lengthOfBucket);
- localStream->read(static_cast<char*>( static_cast<void*>(&result[currentSizeOfResult])), lengthOfBucket*sizeof(_GridEdge));
- }
-
- inline void GetContentsOfFileBucket(const unsigned fileIndex, std::vector<_GridEdge>& result, boost::unordered_map< unsigned, unsigned> & cellMap) {
- unsigned ramIndex = GetRAMIndexFromFileIndex(fileIndex);
- uint64_t startIndexInFile = ramIndexTable[ramIndex];
- if(startIndexInFile == std::numeric_limits<uint64_t>::max()) {
- return;
- }
-
- uint64_t cellIndex[32*32];
-
- cellMap.clear();
- BuildCellIndexToFileIndexMap(ramIndex, cellMap);
- if(!localStream.get() || !localStream->is_open()) {
- localStream.reset(new std::ifstream(iif.c_str(), std::ios::in | std::ios::binary));
- }
- if(!localStream->good()) {
- localStream->clear(std::ios::goodbit);
- DEBUG("Resetting stale filestream");
- }
-
- localStream->seekg(startIndexInFile);
- localStream->read(static_cast<char*>(static_cast<void*>( cellIndex)), 32*32*sizeof(uint64_t));
- assert(cellMap.find(fileIndex) != cellMap.end());
- if(cellIndex[cellMap[fileIndex]] == std::numeric_limits<uint64_t>::max()) {
- return;
- }
- const uint64_t position = cellIndex[cellMap[fileIndex]] + 32*32*sizeof(uint64_t) ;
-
- unsigned lengthOfBucket;
- unsigned currentSizeOfResult = result.size();
- localStream->seekg(position);
- localStream->read(static_cast<char*>(static_cast<void*>(&(lengthOfBucket))), sizeof(unsigned));
- result.resize(currentSizeOfResult+lengthOfBucket);
- localStream->read(static_cast<char*>(static_cast<void*>(&result[currentSizeOfResult])), lengthOfBucket*sizeof(_GridEdge));
- }
-
-#ifndef ROUTED
- inline void AddEdge(const _GridEdge & edge) {
- std::vector<BresenhamPixel> indexList;
- GetListOfIndexesForEdgeAndGridSize(edge.startCoord, edge.targetCoord, indexList);
- for(unsigned i = 0; i < indexList.size(); ++i) {
- entries.push_back(GridEntry(edge, indexList[i].first, indexList[i].second));
- }
- }
-#endif
-
- inline double ComputeDistance(const _Coordinate& inputPoint, const _Coordinate& source, const _Coordinate& target, _Coordinate& nearest, double *r) {
-// INFO("comparing point " << inputPoint << " to edge [" << source << "-" << target << "]");
- 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;
-// INFO("x=" << x << ", y=" << y << ", a=" << a << ", b=" << b << ", c=" << c << ", d=" << d);
- 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 neednot calculate the values of m an n as we are just interested in the ratio
-// INFO("p=" << p << ", q=" << q << ", nY=" << nY << ", mX=" << mX);
- if(std::isnan(mX)) {
- *r = (target == inputPoint) ? 1. : 0.;
- } else {
- *r = mX;
- }
-// INFO("r=" << *r);
- if(*r<=0.){
- nearest.lat = source.lat;
- nearest.lon = source.lon;
-// INFO("a returning distance " << ((b - y)*(b - y) + (a - x)*(a - x)))
- return ((b - y)*(b - y) + (a - x)*(a - x));
- }
- else if(*r >= 1.){
- nearest.lat = target.lat;
- nearest.lon = target.lon;
-// INFO("b returning distance " << ((d - y)*(d - y) + (c - x)*(c - x)))
-
- return ((d - y)*(d - y) + (c - x)*(c - x));
- }
- // point lies in between
- nearest.lat = p;
- nearest.lon = q;
-// INFO("c returning distance " << (p-x)*(p-x) + (q-y)*(q-y))
-
- return (p-x)*(p-x) + (q-y)*(q-y);
- }
-
- inline void GetListOfIndexesForEdgeAndGridSize(const _Coordinate& start, const _Coordinate& target, std::vector<BresenhamPixel> &indexList) const {
- double lat1 = start.lat/100000.;
- double lon1 = start.lon/100000.;
-
- double x1 = ( lon1 + 180.0 ) / 360.0;
- double y1 = ( lat1 + 180.0 ) / 360.0;
-
- double lat2 = target.lat/100000.;
- double lon2 = target.lon/100000.;
-
- double x2 = ( lon2 + 180.0 ) / 360.0;
- double y2 = ( lat2 + 180.0 ) / 360.0;
-
- Bresenham(x1*32768, y1*32768, x2*32768, y2*32768, indexList);
- BOOST_FOREACH(BresenhamPixel & pixel, indexList) {
- int fileIndex = (pixel.second-1)*32768 + pixel.first;
- int ramIndex = GetRAMIndexFromFileIndex(fileIndex);
- pixel.first = fileIndex;
- pixel.second = ramIndex;
- }
- }
-
- inline unsigned GetFileIndexForLatLon(const int lt, const int ln) const {
- double lat = lt/100000.;
- double lon = ln/100000.;
-
- double x = ( lon + 180.0 ) / 360.0;
- double y = ( lat + 180.0 ) / 360.0;
-
- if( x>1.0 || x < 0.)
- return UINT_MAX;
- if( y>1.0 || y < 0.)
- return UINT_MAX;
-
- unsigned line = (32768 * (32768-1))*y;
- line = line - (line % 32768);
- assert(line % 32768 == 0);
- unsigned column = 32768.*x;
- unsigned fileIndex = line+column;
- return fileIndex;
- }
-
- inline unsigned GetRAMIndexFromFileIndex(const int fileIndex) const {
- unsigned fileLine = fileIndex / 32768;
- fileLine = fileLine / 32;
- fileLine = fileLine * 1024;
- unsigned fileColumn = (fileIndex % 32768);
- fileColumn = fileColumn / 32;
- unsigned ramIndex = fileLine + fileColumn;
- assert(ramIndex < 1024*1024);
- return ramIndex;
- }
-
- const static uint64_t END_OF_BUCKET_DELIMITER = boost::integer_traits<uint64_t>::const_max;
-
- std::ifstream ramInFile;
-#ifndef ROUTED
- std::ofstream indexOutFile;
- stxxl::vector<GridEntry> entries;
-#endif
- std::vector<uint64_t> ramIndexTable; //8 MB for first level index in RAM
- std::string iif;
- // LRUCache<int,std::vector<unsigned> > cellCache;
- // LRUCache<int,std::vector<_Edge> > fileCache;
-};
-}
-
-typedef NNGrid::NNGrid<false> ReadOnlyGrid;
-typedef NNGrid::NNGrid<true > WritableGrid;
-
-#endif /* NNGRID_H_ */
diff --git a/DataStructures/NodeBasedGraph.h b/DataStructures/NodeBasedGraph.h
new file mode 100644
index 0000000..98393fb
--- /dev/null
+++ b/DataStructures/NodeBasedGraph.h
@@ -0,0 +1,166 @@
+#ifndef __NODE_BASED_GRAPH_H__
+#define __NODE_BASED_GRAPH_H__
+
+#include "DynamicGraph.h"
+#include "ImportEdge.h"
+#include "../Util/SimpleLogger.h"
+
+#include <tbb/parallel_sort.h>
+
+#include <memory>
+
+struct NodeBasedEdgeData
+{
+ NodeBasedEdgeData()
+ : distance(INVALID_EDGE_WEIGHT), edgeBasedNodeID(SPECIAL_NODEID),
+ nameID(std::numeric_limits<unsigned>::max()), type(std::numeric_limits<short>::max()),
+ isAccessRestricted(false), shortcut(false), forward(false), backward(false),
+ roundabout(false), ignore_in_grid(false), contraFlow(false)
+ {
+ }
+
+ int distance;
+ unsigned edgeBasedNodeID;
+ unsigned nameID;
+ short type;
+ bool isAccessRestricted : 1;
+ bool shortcut : 1;
+ bool forward : 1;
+ bool backward : 1;
+ bool roundabout : 1;
+ bool ignore_in_grid : 1;
+ bool contraFlow : 1;
+
+ void SwapDirectionFlags()
+ {
+ bool temp_flag = forward;
+ forward = backward;
+ backward = temp_flag;
+ }
+
+ bool IsEqualTo(const NodeBasedEdgeData &other) const
+ {
+ return (forward == other.forward) && (backward == other.backward) &&
+ (nameID == other.nameID) && (ignore_in_grid == other.ignore_in_grid) &&
+ (contraFlow == other.contraFlow);
+ }
+};
+
+typedef DynamicGraph<NodeBasedEdgeData> NodeBasedDynamicGraph;
+
+// Factory method to create NodeBasedDynamicGraph from ImportEdges
+inline std::shared_ptr<NodeBasedDynamicGraph>
+NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
+{
+ static_assert(sizeof(NodeBasedEdgeData) == 16, "changing node based edge data size changes memory consumption");
+ // tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
+
+ DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
+ NodeBasedDynamicGraph::InputEdge edge;
+ for (const ImportEdge &import_edge : input_edge_list)
+ {
+ if (import_edge.forward)
+ {
+ edge.source = import_edge.source;
+ edge.target = import_edge.target;
+ edge.data.forward = import_edge.forward;
+ edge.data.backward = import_edge.backward;
+ }
+ else
+ {
+ edge.source = import_edge.target;
+ edge.target = import_edge.source;
+ edge.data.backward = import_edge.forward;
+ edge.data.forward = import_edge.backward;
+ }
+
+ if (edge.source == edge.target)
+ {
+ continue;
+ }
+
+ edge.data.distance = (std::max)((int)import_edge.weight, 1);
+ BOOST_ASSERT(edge.data.distance > 0);
+ edge.data.shortcut = false;
+ edge.data.roundabout = import_edge.roundabout;
+ edge.data.ignore_in_grid = import_edge.in_tiny_cc;
+ edge.data.nameID = import_edge.name_id;
+ edge.data.type = import_edge.type;
+ edge.data.isAccessRestricted = import_edge.access_restricted;
+ edge.data.contraFlow = import_edge.contra_flow;
+ edges_list.push_back(edge);
+
+ if (!import_edge.is_split)
+ {
+ using std::swap; // enable ADL
+ swap(edge.source, edge.target);
+ edge.data.SwapDirectionFlags();
+ edges_list.push_back(edge);
+ }
+ }
+
+ // remove duplicate edges
+ std::sort(edges_list.begin(), edges_list.end());
+ NodeID edge_count = 0;
+ for (NodeID i = 0; i < edges_list.size(); )
+ {
+ const NodeID source = edges_list[i].source;
+ const NodeID target = edges_list[i].target;
+ // remove eigenloops
+ if (source == target)
+ {
+ i++;
+ continue;
+ }
+ NodeBasedDynamicGraph::InputEdge forward_edge;
+ NodeBasedDynamicGraph::InputEdge reverse_edge;
+ forward_edge = reverse_edge = edges_list[i];
+ forward_edge.data.forward = reverse_edge.data.backward = true;
+ forward_edge.data.backward = reverse_edge.data.forward = false;
+ forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
+ forward_edge.data.distance = reverse_edge.data.distance =
+ std::numeric_limits<int>::max();
+ // remove parallel edges
+ while (i < edges_list.size() && edges_list[i].source == source && edges_list[i].target == target)
+ {
+ if (edges_list[i].data.forward)
+ {
+ forward_edge.data.distance =
+ std::min(edges_list[i].data.distance, forward_edge.data.distance);
+ }
+ if (edges_list[i].data.backward)
+ {
+ reverse_edge.data.distance =
+ std::min(edges_list[i].data.distance, reverse_edge.data.distance);
+ }
+ ++i;
+ }
+ // merge edges (s,t) and (t,s) into bidirectional edge
+ if (forward_edge.data.distance == reverse_edge.data.distance)
+ {
+ if ((int)forward_edge.data.distance != std::numeric_limits<int>::max())
+ {
+ forward_edge.data.backward = true;
+ edges_list[edge_count++] = forward_edge;
+ }
+ }
+ else
+ { // insert seperate edges
+ if (((int)forward_edge.data.distance) != std::numeric_limits<int>::max())
+ {
+ edges_list[edge_count++] = forward_edge;
+ }
+ if ((int)reverse_edge.data.distance != std::numeric_limits<int>::max())
+ {
+ edges_list[edge_count++] = reverse_edge;
+ }
+ }
+ }
+ edges_list.resize(edge_count);
+ SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of " << edges_list.size();
+
+ auto graph = std::make_shared<NodeBasedDynamicGraph>(number_of_nodes, edges_list);
+ return graph;
+}
+
+#endif // __NODE_BASED_GRAPH_H__
diff --git a/DataStructures/NodeCoords.h b/DataStructures/NodeCoords.h
deleted file mode 100644
index 4893a9d..0000000
--- a/DataStructures/NodeCoords.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- 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 _NODE_COORDS_H
-#define _NODE_COORDS_H
-
-#include <cassert>
-#include <cstddef>
-#include <climits>
-#include <limits>
-
-#include "../typedefs.h"
-
-template<typename NodeT>
-struct NodeCoords {
- typedef unsigned key_type; //type of NodeID
- typedef int value_type; //type of lat,lons
-
- NodeCoords(int _lat, int _lon, NodeT _id) : lat(_lat), lon(_lon), id(_id) {}
- NodeCoords() : lat(INT_MAX), lon(INT_MAX), id(UINT_MAX) {}
- int lat;
- int lon;
- NodeT id;
-
- static NodeCoords<NodeT> min_value() {
- return NodeCoords<NodeT>(-90*100000,-180*100000,std::numeric_limits<NodeT>::min());
- }
- static NodeCoords<NodeT> max_value() {
- return NodeCoords<NodeT>(90*100000, 180*100000, std::numeric_limits<NodeT>::max());
- }
-
- value_type operator[](std::size_t n) const {
- switch(n) {
- case 1:
- return lat;
- break;
- case 0:
- return lon;
- break;
- default:
- assert(false);
- return UINT_MAX;
- break;
- }
- assert(false);
- return UINT_MAX;
- }
-};
-
-typedef NodeCoords<NodeID> NodeInfo;
-
-#endif //_NODE_COORDS_H
diff --git a/DataStructures/NodeInformationHelpDesk.h b/DataStructures/NodeInformationHelpDesk.h
deleted file mode 100644
index f13c9ad..0000000
--- a/DataStructures/NodeInformationHelpDesk.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- 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 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>
-
-typedef EdgeBasedGraphFactory::EdgeBasedNode RTreeLeaf;
-
-class NodeInformationHelpDesk : boost::noncopyable{
-public:
- 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() {
- delete read_only_rtree;
- }
-
- void initNNGrid(
- std::ifstream& nodesInstream,
- std::ifstream& edgesInStream
- ) {
- DEBUG("Loading node data");
- NodeInfo b;
- while(!nodesInstream.eof()) {
- nodesInstream.read((char *)&b, sizeof(NodeInfo));
- coordinateVector.push_back(_Coordinate(b.lat, b.lon));
- }
- std::vector<_Coordinate>(coordinateVector).swap(coordinateVector);
- nodesInstream.close();
-
- DEBUG("Loading edge data");
- unsigned numberOfOrigEdges(0);
- edgesInStream.read((char*)&numberOfOrigEdges, sizeof(unsigned));
- origEdgeData_viaNode.resize(numberOfOrigEdges);
- origEdgeData_nameID.resize(numberOfOrigEdges);
- origEdgeData_turnInstruction.resize(numberOfOrigEdges);
-
- OriginalEdgeData deserialized_originalEdgeData;
- for(unsigned i = 0; i < numberOfOrigEdges; ++i) {
- edgesInStream.read((char*)&(deserialized_originalEdgeData), sizeof(OriginalEdgeData));
- origEdgeData_viaNode[i] = deserialized_originalEdgeData.viaNode;
- origEdgeData_nameID[i] = deserialized_originalEdgeData.nameID;
- origEdgeData_turnInstruction[i] = deserialized_originalEdgeData.turnInstruction;
- }
- edgesInStream.close();
- DEBUG("Loaded " << numberOfOrigEdges << " orig edges");
- DEBUG("Opening NN indices");
- }
-
- inline int getLatitudeOfNode(const unsigned id) const {
- const NodeID node = origEdgeData_viaNode.at(id);
- return coordinateVector.at(node).lat;
- }
-
- inline int getLongitudeOfNode(const unsigned id) const {
- const NodeID node = origEdgeData_viaNode.at(id);
- return coordinateVector.at(node).lon;
- }
-
- inline unsigned getNameIndexFromEdgeID(const unsigned id) const {
- return origEdgeData_nameID.at(id);
- }
-
- inline TurnInstruction getTurnInstructionFromEdgeID(const unsigned id) const {
- return origEdgeData_turnInstruction.at(id);
- }
-
- inline NodeID getNumberOfNodes() const {
- return number_of_nodes;
- }
-
- inline NodeID getNumberOfNodes2() const {
- return coordinateVector.size();
- }
-
- 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 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 {
- return checkSum;
- }
-
-private:
- std::vector<_Coordinate> coordinateVector;
- std::vector<NodeID> origEdgeData_viaNode;
- std::vector<unsigned> origEdgeData_nameID;
- std::vector<TurnInstruction> origEdgeData_turnInstruction;
-
- StaticRTree<EdgeBasedGraphFactory::EdgeBasedNode> * read_only_rtree;
- const unsigned number_of_nodes;
- const unsigned checkSum;
-};
-
-#endif /*NODEINFORMATIONHELPDESK_H_*/
diff --git a/DataStructures/OriginalEdgeData.h b/DataStructures/OriginalEdgeData.h
new file mode 100644
index 0000000..f75aeda
--- /dev/null
+++ b/DataStructures/OriginalEdgeData.h
@@ -0,0 +1,60 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef ORIGINAL_EDGE_DATA_H
+#define ORIGINAL_EDGE_DATA_H
+
+#include "TurnInstructions.h"
+#include "../typedefs.h"
+
+#include <limits>
+
+struct OriginalEdgeData
+{
+ explicit OriginalEdgeData(NodeID via_node,
+ unsigned name_id,
+ TurnInstruction turn_instruction,
+ bool compressed_geometry)
+ : via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
+ compressed_geometry(compressed_geometry)
+ {
+ }
+
+ OriginalEdgeData()
+ : via_node(std::numeric_limits<unsigned>::max()),
+ name_id(std::numeric_limits<unsigned>::max()),
+ turn_instruction(TurnInstruction::NoTurn), compressed_geometry(false)
+ {
+ }
+
+ NodeID via_node;
+ unsigned name_id;
+ TurnInstruction turn_instruction;
+ bool compressed_geometry;
+};
+
+#endif // ORIGINAL_EDGE_DATA_H
diff --git a/DataStructures/Percent.h b/DataStructures/Percent.h
index dafbe55..f201fc8 100644
--- a/DataStructures/Percent.h
+++ b/DataStructures/Percent.h
@@ -1,89 +1,96 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef PERCENT_H
#define PERCENT_H
#include <iostream>
-
+#include <atomic>
class Percent
{
-public:
- /**
- * Constructor.
- * @param maxValue the value that corresponds to 100%
- * @param step the progress is shown in steps of 'step' percent
- */
- Percent(unsigned maxValue, unsigned step = 5) {
- reinit(maxValue, step);
- }
+ public:
+ explicit Percent(unsigned max_value, unsigned step = 5) { reinit(max_value, step); }
- /** Reinitializes this object. */
- void reinit(unsigned maxValue, unsigned step = 5) {
- _maxValue = maxValue;
- _current_value = 0;
- _intervalPercent = _maxValue / 100;
- _nextThreshold = _intervalPercent;
- _lastPercent = 0;
- _step = step;
+ // Reinitializes
+ void reinit(unsigned max_value, unsigned step = 5)
+ {
+ m_max_value = max_value;
+ m_current_value = 0;
+ m_percent_interval = m_max_value / 100;
+ m_next_threshold = m_percent_interval;
+ m_last_percent = 0;
+ m_step = step;
}
- /** If there has been significant progress, display it. */
- void printStatus(unsigned currentValue) {
- if (currentValue >= _nextThreshold) {
- _nextThreshold += _intervalPercent;
- printPercent( currentValue / (double)_maxValue * 100 );
+ // If there has been significant progress, display it.
+ void printStatus(unsigned current_value)
+ {
+ if (current_value >= m_next_threshold)
+ {
+ m_next_threshold += m_percent_interval;
+ printPercent(current_value / (double)m_max_value * 100);
}
- if (currentValue + 1 == _maxValue)
+ if (current_value + 1 == m_max_value)
std::cout << " 100%" << std::endl;
}
void printIncrement()
{
-#pragma omp atomic
- ++_current_value;
- printStatus(_current_value);
+ ++m_current_value;
+ printStatus(m_current_value);
}
- void printAddition(const unsigned addition) {
-#pragma omp atomic
- _current_value += addition;
- printStatus(_current_value);
+ void printAddition(const unsigned addition)
+ {
+ m_current_value += addition;
+ printStatus(m_current_value);
}
-private:
- unsigned _current_value;
- unsigned _maxValue;
- unsigned _intervalPercent;
- unsigned _nextThreshold;
- unsigned _lastPercent;
- unsigned _step;
- /** Displays the new progress. */
- void printPercent(double percent) {
- while (percent >= _lastPercent+_step) {
- _lastPercent+=_step;
- if (_lastPercent % 10 == 0) {
- std::cout << " " << _lastPercent << "% ";
+ private:
+ std::atomic_uint m_current_value;
+ unsigned m_max_value;
+ unsigned m_percent_interval;
+ unsigned m_next_threshold;
+ unsigned m_last_percent;
+ unsigned m_step;
+
+ // Displays progress.
+ void printPercent(double percent)
+ {
+ while (percent >= m_last_percent + m_step)
+ {
+ m_last_percent += m_step;
+ if (m_last_percent % 10 == 0)
+ {
+ std::cout << " " << m_last_percent << "% ";
}
- else {
+ else
+ {
std::cout << ".";
}
std::cout.flush();
diff --git a/DataStructures/PhantomNodes.h b/DataStructures/PhantomNodes.h
index 2827d7a..2a2a924 100644
--- a/DataStructures/PhantomNodes.h
+++ b/DataStructures/PhantomNodes.h
@@ -1,94 +1,173 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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 PHANTOMNODES_H_
-#define PHANTOMNODES_H_
-
-#include "Coordinate.h"
-
-struct PhantomNode {
- PhantomNode() : edgeBasedNode(UINT_MAX), nodeBasedEdgeNameID(UINT_MAX), weight1(INT_MAX), weight2(INT_MAX), ratio(0.) {}
- NodeID edgeBasedNode;
- unsigned nodeBasedEdgeNameID;
- int weight1;
- int weight2;
- double ratio;
- _Coordinate location;
- void Reset() {
- edgeBasedNode = UINT_MAX;
- nodeBasedEdgeNameID = UINT_MAX;
- weight1 = INT_MAX;
- weight2 = INT_MAX;
- ratio = 0.;
- location.Reset();
- }
- bool isBidirected() const {
- return weight2 != INT_MAX;
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef PHANTOM_NODES_H
+#define PHANTOM_NODES_H
+
+#include <osrm/Coordinate.h>
+#include "../Util/SimpleLogger.h"
+#include "../typedefs.h"
+
+#include <vector>
+
+struct PhantomNode
+{
+ PhantomNode(NodeID forward_node_id, NodeID reverse_node_id, unsigned name_id,
+ int forward_weight, int reverse_weight, int forward_offset, int reverse_offset,
+ unsigned packed_geometry_id, FixedPointCoordinate &location,
+ unsigned short fwd_segment_position) :
+ forward_node_id(forward_node_id),
+ reverse_node_id(reverse_node_id),
+ name_id(name_id),
+ forward_weight(forward_weight),
+ reverse_weight(reverse_weight),
+ forward_offset(forward_offset),
+ reverse_offset(reverse_offset),
+ packed_geometry_id(packed_geometry_id),
+ location(location),
+ fwd_segment_position(fwd_segment_position)
+ { }
+
+ PhantomNode() :
+ forward_node_id(SPECIAL_NODEID),
+ reverse_node_id(SPECIAL_NODEID),
+ name_id(std::numeric_limits<unsigned>::max()),
+ forward_weight(INVALID_EDGE_WEIGHT),
+ reverse_weight(INVALID_EDGE_WEIGHT),
+ forward_offset(0),
+ reverse_offset(0),
+ packed_geometry_id(SPECIAL_EDGEID),
+ fwd_segment_position(0)
+ { }
+
+ NodeID forward_node_id;
+ NodeID reverse_node_id;
+ unsigned name_id;
+ int forward_weight;
+ int reverse_weight;
+ int forward_offset;
+ int reverse_offset;
+ unsigned packed_geometry_id;
+ FixedPointCoordinate location;
+ unsigned short fwd_segment_position;
+
+ int GetForwardWeightPlusOffset() const
+ {
+ if (SPECIAL_NODEID == forward_node_id)
+ {
+ return 0;
+ }
+ const int result = (forward_offset + forward_weight);
+ return result;
}
- bool isValid(const unsigned numberOfNodes) const {
- return location.isValid() && (edgeBasedNode < numberOfNodes) && (weight1 != INT_MAX) && (ratio >= 0.) && (ratio <= 1.) && (nodeBasedEdgeNameID != UINT_MAX);
+
+ int GetReverseWeightPlusOffset() const
+ {
+ if (SPECIAL_NODEID == reverse_node_id)
+ {
+ return 0;
+ }
+ const int result = (reverse_offset + reverse_weight);
+ return result;
}
- bool operator==(const PhantomNode & other) const {
- return location == other.location;
+ bool isBidirected() const
+ {
+ return (forward_node_id != SPECIAL_NODEID) &&
+ (reverse_node_id != SPECIAL_NODEID);
}
-};
-struct PhantomNodes {
- PhantomNode startPhantom;
- PhantomNode targetPhantom;
- void Reset() {
- startPhantom.Reset();
- targetPhantom.Reset();
+ bool IsCompressed() const
+ {
+ return (forward_offset != 0) || (reverse_offset != 0);
}
- bool PhantomsAreOnSameNodeBasedEdge() const {
- return (startPhantom.edgeBasedNode == targetPhantom.edgeBasedNode);
+ bool isValid(const unsigned numberOfNodes) const
+ {
+ return
+ location.isValid() &&
+ (
+ (forward_node_id < numberOfNodes) ||
+ (reverse_node_id < numberOfNodes)
+ ) &&
+ (
+ (forward_weight != INVALID_EDGE_WEIGHT) ||
+ (reverse_weight != INVALID_EDGE_WEIGHT)
+ ) &&
+ (name_id != std::numeric_limits<unsigned>::max()
+ );
}
- bool AtLeastOnePhantomNodeIsUINTMAX() const {
- return !(startPhantom.edgeBasedNode == UINT_MAX || targetPhantom.edgeBasedNode == UINT_MAX);
+ bool isValid() const
+ {
+ return location.isValid() &&
+ (name_id != std::numeric_limits<unsigned>::max());
}
- bool PhantomNodesHaveEqualLocation() const {
- return startPhantom == targetPhantom;
+ bool operator==(const PhantomNode & other) const
+ {
+ return location == other.location;
}
};
-inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn){
- out << "Node1: " << pn.startPhantom.edgeBasedNode << std::endl;
- out << "Node2: " << pn.targetPhantom.edgeBasedNode << std::endl;
- out << "startCoord: " << pn.startPhantom.location << std::endl;
- out << "targetCoord: " << pn.targetPhantom.location << std::endl;
+typedef std::vector<std::vector<PhantomNode>> PhantomNodeArray;
+
+struct PhantomNodeLists
+{
+ std::vector<PhantomNode> source_phantom_list;
+ std::vector<PhantomNode> target_phantom_list;
+};
+
+struct PhantomNodes
+{
+ PhantomNode source_phantom;
+ PhantomNode target_phantom;
+};
+
+inline std::ostream& operator<<(std::ostream &out, const PhantomNodes & pn)
+{
+ out << "source_coord: " << pn.source_phantom.location << "\n";
+ out << "target_coord: " << pn.target_phantom.location << std::endl;
return out;
}
-inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn){
- out << "node: " << pn.edgeBasedNode << ", name: " << pn.nodeBasedEdgeNameID << ", w1: " << pn.weight1 << ", w2: " << pn.weight2 << ", ratio: " << pn.ratio << ", loc: " << pn.location;
+inline std::ostream& operator<<(std::ostream &out, const PhantomNode & pn)
+{
+ out << "node1: " << pn.forward_node_id << ", " <<
+ "node2: " << pn.reverse_node_id << ", " <<
+ "name: " << pn.name_id << ", " <<
+ "fwd-w: " << pn.forward_weight << ", " <<
+ "rev-w: " << pn.reverse_weight << ", " <<
+ "fwd-o: " << pn.forward_offset << ", " <<
+ "rev-o: " << pn.reverse_offset << ", " <<
+ "geom: " << pn.packed_geometry_id << ", " <<
+ "pos: " << pn.fwd_segment_position << ", " <<
+ "loc: " << pn.location;
return out;
}
-struct NodesOfEdge {
- NodeID edgeBasedNode;
- double ratio;
- _Coordinate projectedPoint;
-};
-
-#endif /* PHANTOMNODES_H_ */
+#endif // PHANTOM_NODES_H
diff --git a/DataStructures/QueryEdge.h b/DataStructures/QueryEdge.h
index 3a2aecb..b84c180 100644
--- a/DataStructures/QueryEdge.h
+++ b/DataStructures/QueryEdge.h
@@ -1,75 +1,63 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
#ifndef QUERYEDGE_H_
#define QUERYEDGE_H_
-#include "TurnInstructions.h"
#include "../typedefs.h"
-#include <climits>
-
-struct OriginalEdgeData{
- explicit OriginalEdgeData(NodeID v, unsigned n, TurnInstruction t) : viaNode(v), nameID(n), turnInstruction(t) {}
- OriginalEdgeData() : viaNode(UINT_MAX), nameID(UINT_MAX), turnInstruction(UCHAR_MAX) {}
- NodeID viaNode;
- unsigned nameID;
- TurnInstruction turnInstruction;
-};
-
-struct QueryEdge {
+struct QueryEdge
+{
NodeID source;
NodeID target;
- struct EdgeData {
- NodeID id:31;
- bool shortcut:1;
- int distance:30;
- bool forward:1;
- bool backward:1;
+ struct EdgeData
+ {
+ NodeID id : 31;
+ bool shortcut : 1;
+ int distance : 30;
+ bool forward : 1;
+ bool backward : 1;
} data;
- bool operator<( const QueryEdge& right ) const {
- if ( source != right.source )
+
+ bool operator<(const QueryEdge &right) const
+ {
+ if (source != right.source)
+ {
return source < right.source;
+ }
return target < right.target;
}
- //sorts by source and other attributes
- static bool CompareBySource( const QueryEdge& left, const QueryEdge& right ) {
- if ( left.source != right.source )
- return left.source < right.source;
- int l = ( left.data.forward ? -1 : 0 ) + ( left.data.backward ? -1 : 0 );
- int r = ( right.data.forward ? -1 : 0 ) + ( right.data.backward ? -1 : 0 );
- if ( l != r )
- return l < r;
- if ( left.target != right.target )
- return left.target < right.target;
- return left.data.distance < right.data.distance;
- }
-
- bool operator== ( const QueryEdge& right ) const {
- return ( source == right.source && target == right.target && data.distance == right.data.distance &&
- data.shortcut == right.data.shortcut && data.forward == right.data.forward && data.backward == right.data.backward
- && data.id == right.data.id
- );
+ bool operator==(const QueryEdge &right) const
+ {
+ return (source == right.source && target == right.target &&
+ data.distance == right.data.distance && data.shortcut == right.data.shortcut &&
+ data.forward == right.data.forward && data.backward == right.data.backward &&
+ data.id == right.data.id);
}
};
diff --git a/DataStructures/QueryNode.h b/DataStructures/QueryNode.h
new file mode 100644
index 0000000..ee6b278
--- /dev/null
+++ b/DataStructures/QueryNode.h
@@ -0,0 +1,85 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef QUERY_NODE_H
+#define QUERY_NODE_H
+
+#include "../typedefs.h"
+
+#include <osrm/Coordinate.h>
+
+#include <boost/assert.hpp>
+
+#include <limits>
+
+struct NodeInfo
+{
+ typedef NodeID key_type; // type of NodeID
+ typedef int value_type; // type of lat,lons
+
+ explicit NodeInfo(int lat, int lon, NodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
+ NodeInfo()
+ : lat(std::numeric_limits<int>::max()), lon(std::numeric_limits<int>::max()),
+ node_id(std::numeric_limits<unsigned>::max())
+ {
+ }
+
+ int lat;
+ int lon;
+ NodeID node_id;
+
+ static NodeInfo min_value()
+ {
+ return NodeInfo(static_cast<int>(-90 * COORDINATE_PRECISION),
+ static_cast<int>(-180 * COORDINATE_PRECISION),
+ std::numeric_limits<NodeID>::min());
+ }
+
+ static NodeInfo max_value()
+ {
+ return NodeInfo(static_cast<int>(90 * COORDINATE_PRECISION),
+ static_cast<int>(180 * COORDINATE_PRECISION),
+ std::numeric_limits<NodeID>::max());
+ }
+
+ value_type operator[](const std::size_t n) const
+ {
+ switch (n)
+ {
+ case 1:
+ return lat;
+ case 0:
+ return lon;
+ default:
+ break;
+ }
+ BOOST_ASSERT_MSG(false, "should not happen");
+ return std::numeric_limits<unsigned>::max();
+ }
+};
+
+#endif // QUERY_NODE_H
diff --git a/DataStructures/RangeTable.h b/DataStructures/RangeTable.h
new file mode 100644
index 0000000..f9ec254
--- /dev/null
+++ b/DataStructures/RangeTable.h
@@ -0,0 +1,231 @@
+#ifndef __RANGE_TABLE_H__
+#define __RANGE_TABLE_H__
+
+#include "SharedMemoryFactory.h"
+#include "SharedMemoryVectorWrapper.h"
+
+#include <boost/range/irange.hpp>
+
+#include <fstream>
+#include <vector>
+#include <array>
+
+/*
+ * These pre-declarations are needed because parsing C++ is hard
+ * and otherwise the compiler gets confused.
+ */
+
+template<unsigned BLOCK_SIZE=16, bool USE_SHARED_MEMORY = false> class RangeTable;
+
+template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+std::ostream& operator<<(std::ostream &out, const RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table);
+
+template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+std::istream& operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table);
+
+/**
+ * Stores adjacent ranges in a compressed format.
+ *
+ * Maximum supported length of a range is 255.
+ *
+ * Note: BLOCK_SIZE is the number of differential encodoed values.
+ * But each block consists of an absolute value and BLOCK_SIZE differential values.
+ * So the effective block size is sizeof(unsigned) + BLOCK_SIZE.
+ */
+template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+class RangeTable
+{
+public:
+
+ typedef std::array<unsigned char, BLOCK_SIZE> BlockT;
+ typedef typename ShM<BlockT, USE_SHARED_MEMORY>::vector BlockContainerT;
+ typedef typename ShM<unsigned, USE_SHARED_MEMORY>::vector OffsetContainerT;
+ typedef decltype(boost::irange(0u,0u)) RangeT;
+
+ friend std::ostream& operator<< <>(std::ostream &out, const RangeTable &table);
+ friend std::istream& operator>> <>(std::istream &in, RangeTable &table);
+
+ RangeTable() : sum_lengths(0) {}
+
+ // for loading from shared memory
+ explicit RangeTable(OffsetContainerT& external_offsets, BlockContainerT& external_blocks, const unsigned sum_lengths)
+ : sum_lengths(sum_lengths)
+ {
+ block_offsets.swap(external_offsets);
+ diff_blocks.swap(external_blocks);
+ }
+
+ // construct table from length vector
+ explicit RangeTable(const std::vector<unsigned>& lengths)
+ {
+ const unsigned number_of_blocks = [&lengths]() {
+ unsigned num = (lengths.size() + 1) / (BLOCK_SIZE + 1);
+ if ((lengths.size() + 1) % (BLOCK_SIZE + 1) != 0)
+ {
+ num += 1;
+ }
+ return num;
+ }();
+
+ block_offsets.reserve(number_of_blocks);
+ diff_blocks.reserve(number_of_blocks);
+
+ unsigned last_length = 0;
+ unsigned lengths_prefix_sum = 0;
+ unsigned block_idx = 0;
+ unsigned block_counter = 0;
+ BlockT block;
+ unsigned block_sum = 0;
+ for (const unsigned l : lengths)
+ {
+ // first entry of a block: encode absolute offset
+ if (block_idx == 0)
+ {
+ block_offsets.push_back(lengths_prefix_sum);
+ block_sum = 0;
+ }
+ else
+ {
+ block[block_idx - 1] = last_length;
+ block_sum += last_length;
+ }
+
+ BOOST_ASSERT((block_idx == 0 && block_offsets[block_counter] == lengths_prefix_sum)
+ || lengths_prefix_sum == (block_offsets[block_counter]+block_sum));
+
+ // block is full
+ if (BLOCK_SIZE == block_idx)
+ {
+ diff_blocks.push_back(block);
+ block_counter++;
+ }
+
+ // we can only store strings with length 255
+ BOOST_ASSERT(l <= 255);
+
+ lengths_prefix_sum += l;
+ last_length = l;
+
+ block_idx = (block_idx + 1) % (BLOCK_SIZE + 1);
+ }
+
+ // Last block can't be finished because we didn't add the sentinel
+ BOOST_ASSERT (block_counter == (number_of_blocks - 1));
+
+ // one block missing: starts with guard value
+ if (0 == block_idx)
+ {
+ // the last value is used as sentinel
+ block_offsets.push_back(lengths_prefix_sum);
+ block_idx = (block_idx + 1) % BLOCK_SIZE;
+ }
+
+ while (0 != block_idx)
+ {
+ block[block_idx - 1] = last_length;
+ last_length = 0;
+ block_idx = (block_idx + 1) % (BLOCK_SIZE + 1);
+ }
+ diff_blocks.push_back(block);
+
+ BOOST_ASSERT(diff_blocks.size() == number_of_blocks && block_offsets.size() == number_of_blocks);
+
+ sum_lengths = lengths_prefix_sum;
+ }
+
+ inline RangeT GetRange(const unsigned id) const
+ {
+ BOOST_ASSERT(id < block_offsets.size() + diff_blocks.size() * BLOCK_SIZE);
+ // internal_idx 0 is implicitly stored in block_offsets[block_idx]
+ const unsigned internal_idx = id % (BLOCK_SIZE + 1);
+ const unsigned block_idx = id / (BLOCK_SIZE + 1);
+
+ BOOST_ASSERT(block_idx < diff_blocks.size());
+
+ unsigned begin_idx = 0;
+ unsigned end_idx = 0;
+ begin_idx = block_offsets[block_idx];
+ const BlockT& block = diff_blocks[block_idx];
+ if (internal_idx > 0)
+ {
+ begin_idx += PrefixSumAtIndex(internal_idx - 1, block);
+ }
+
+ // next index inside current block
+ if (internal_idx < BLOCK_SIZE)
+ {
+ // note internal_idx - 1 is the *current* index for uint8_blocks
+ end_idx = begin_idx + block[internal_idx];
+ }
+ else
+ {
+ BOOST_ASSERT(block_idx < block_offsets.size() - 1);
+ end_idx = block_offsets[block_idx + 1];
+ }
+
+ BOOST_ASSERT(begin_idx < sum_lengths && end_idx <= sum_lengths);
+ BOOST_ASSERT(begin_idx <= end_idx);
+
+ return boost::irange(begin_idx, end_idx);
+ }
+private:
+
+ inline unsigned PrefixSumAtIndex(int index, const BlockT& block) const;
+
+ // contains offset for each differential block
+ OffsetContainerT block_offsets;
+ // blocks of differential encoded offsets, should be aligned
+ BlockContainerT diff_blocks;
+ unsigned sum_lengths;
+};
+
+template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+unsigned RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY>::PrefixSumAtIndex(int index, const BlockT& block) const
+{
+ // this loop looks inefficent, but a modern compiler
+ // will emit nice SIMD here, at least for sensible block sizes. (I checked.)
+ unsigned sum = 0;
+ for (int i = 0; i <= index; ++i)
+ {
+ sum += block[i];
+ }
+
+ return sum;
+}
+
+template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+std::ostream& operator<<(std::ostream &out, const RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table)
+{
+ // write number of block
+ const unsigned number_of_blocks = table.diff_blocks.size();
+ out.write((char *) &number_of_blocks, sizeof(unsigned));
+ // write total length
+ out.write((char *) &table.sum_lengths, sizeof(unsigned));
+ // write block offsets
+ out.write((char *) table.block_offsets.data(), sizeof(unsigned) * table.block_offsets.size());
+ // write blocks
+ out.write((char *) table.diff_blocks.data(), BLOCK_SIZE * table.diff_blocks.size());
+
+ return out;
+}
+
+template<unsigned BLOCK_SIZE, bool USE_SHARED_MEMORY>
+std::istream& operator>>(std::istream &in, RangeTable<BLOCK_SIZE, USE_SHARED_MEMORY> &table)
+{
+ // read number of block
+ unsigned number_of_blocks;
+ in.read((char *) &number_of_blocks, sizeof(unsigned));
+ // read total length
+ in.read((char *) &table.sum_lengths, sizeof(unsigned));
+
+ table.block_offsets.resize(number_of_blocks);
+ table.diff_blocks.resize(number_of_blocks);
+
+ // read block offsets
+ in.read((char *) table.block_offsets.data(), sizeof(unsigned) * number_of_blocks);
+ // read blocks
+ in.read((char *) table.diff_blocks.data(), BLOCK_SIZE * number_of_blocks);
+ return in;
+}
+
+#endif
diff --git a/DataStructures/RawRouteData.h b/DataStructures/RawRouteData.h
new file mode 100644
index 0000000..e034b43
--- /dev/null
+++ b/DataStructures/RawRouteData.h
@@ -0,0 +1,80 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef RAW_ROUTE_DATA_H
+#define RAW_ROUTE_DATA_H
+
+#include "../DataStructures/PhantomNodes.h"
+#include "../DataStructures/TurnInstructions.h"
+#include "../typedefs.h"
+
+#include <osrm/Coordinate.h>
+
+#include <vector>
+
+struct PathData
+{
+ PathData()
+ : node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT),
+ segment_duration(INVALID_EDGE_WEIGHT),
+ turn_instruction(TurnInstruction::NoTurn)
+ {
+ }
+
+ PathData(NodeID node, unsigned name_id, TurnInstruction turn_instruction, EdgeWeight segment_duration)
+ : node(node), name_id(name_id), segment_duration(segment_duration), turn_instruction(turn_instruction)
+ {
+ }
+ NodeID node;
+ unsigned name_id;
+ EdgeWeight segment_duration;
+ TurnInstruction turn_instruction;
+};
+
+struct RawRouteData
+{
+ std::vector<std::vector<PathData>> unpacked_path_segments;
+ std::vector<PathData> unpacked_alternative;
+ std::vector<PhantomNodes> segment_end_coordinates;
+ std::vector<FixedPointCoordinate> raw_via_node_coordinates;
+ std::vector<bool> source_traversed_in_reverse;
+ std::vector<bool> target_traversed_in_reverse;
+ std::vector<bool> alt_source_traversed_in_reverse;
+ std::vector<bool> alt_target_traversed_in_reverse;
+ unsigned check_sum;
+ int shortest_path_length;
+ int alternative_path_length;
+
+ RawRouteData()
+ : check_sum(SPECIAL_NODEID),
+ shortest_path_length(INVALID_EDGE_WEIGHT),
+ alternative_path_length(INVALID_EDGE_WEIGHT)
+ {
+ }
+};
+
+#endif // RAW_ROUTE_DATA_H
diff --git a/DataStructures/Restriction.h b/DataStructures/Restriction.h
index 3627c6a..2b166f5 100644
--- a/DataStructures/Restriction.h
+++ b/DataStructures/Restriction.h
@@ -1,97 +1,126 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
-#ifndef RESTRICTION_H_
-#define RESTRICTION_H_
+#ifndef RESTRICTION_H
+#define RESTRICTION_H
-#include <climits>
+#include "../typedefs.h"
-struct _Restriction {
+#include <limits>
+
+struct TurnRestriction
+{
NodeID viaNode;
NodeID fromNode;
NodeID toNode;
- struct Bits { //mostly unused
- Bits() : isOnly(false), unused1(false), unused2(false), unused3(false), unused4(false), unused5(false), unused6(false), unused7(false) {}
- char isOnly:1;
- char unused1:1;
- char unused2:1;
- char unused3:1;
- char unused4:1;
- char unused5:1;
- char unused6:1;
- char unused7:1;
+ struct Bits
+ { // mostly unused
+ Bits()
+ : isOnly(false), unused1(false), unused2(false), unused3(false), unused4(false),
+ unused5(false), unused6(false), unused7(false)
+ {
+ }
+
+ bool isOnly : 1;
+ bool unused1 : 1;
+ bool unused2 : 1;
+ bool unused3 : 1;
+ bool unused4 : 1;
+ bool unused5 : 1;
+ bool unused6 : 1;
+ bool unused7 : 1;
} flags;
- _Restriction(NodeID vn) : viaNode(vn), fromNode(UINT_MAX), toNode(UINT_MAX) { }
- _Restriction(bool isOnly = false) : viaNode(UINT_MAX), fromNode(UINT_MAX), toNode(UINT_MAX) {
+ explicit TurnRestriction(NodeID viaNode)
+ : viaNode(viaNode), fromNode(std::numeric_limits<unsigned>::max()),
+ toNode(std::numeric_limits<unsigned>::max())
+ {
+ }
+
+ explicit TurnRestriction(const bool isOnly = false)
+ : viaNode(std::numeric_limits<unsigned>::max()),
+ fromNode(std::numeric_limits<unsigned>::max()),
+ toNode(std::numeric_limits<unsigned>::max())
+ {
flags.isOnly = isOnly;
}
};
-inline bool CmpRestrictionByFrom ( _Restriction a, _Restriction b) { return (a.fromNode < b.fromNode); }
-
-struct _RawRestrictionContainer {
- _Restriction restriction;
+struct InputRestrictionContainer
+{
EdgeID fromWay;
EdgeID toWay;
unsigned viaNode;
+ TurnRestriction restriction;
- _RawRestrictionContainer(EdgeID f, EdgeID t, NodeID vn, unsigned vw) : fromWay(f), toWay(t), viaNode(vw) { restriction.viaNode = vn;}
- _RawRestrictionContainer(bool isOnly = false) : fromWay(UINT_MAX), toWay(UINT_MAX), viaNode(UINT_MAX) { restriction.flags.isOnly = isOnly;}
-
- static _RawRestrictionContainer min_value() {
- return _RawRestrictionContainer(0, 0, 0, 0);
+ InputRestrictionContainer(EdgeID fromWay, EdgeID toWay, NodeID vn, unsigned vw)
+ : fromWay(fromWay), toWay(toWay), viaNode(vw)
+ {
+ restriction.viaNode = vn;
+ }
+ explicit InputRestrictionContainer(bool isOnly = false)
+ : fromWay(std::numeric_limits<unsigned>::max()),
+ toWay(std::numeric_limits<unsigned>::max()), viaNode(std::numeric_limits<unsigned>::max())
+ {
+ restriction.flags.isOnly = isOnly;
}
- static _RawRestrictionContainer max_value() {
- return _RawRestrictionContainer(UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX);
+
+ static InputRestrictionContainer min_value() { return InputRestrictionContainer(0, 0, 0, 0); }
+ static InputRestrictionContainer max_value()
+ {
+ return InputRestrictionContainer(std::numeric_limits<unsigned>::max(),
+ std::numeric_limits<unsigned>::max(),
+ std::numeric_limits<unsigned>::max(),
+ std::numeric_limits<unsigned>::max());
}
};
-struct CmpRestrictionContainerByFrom: public std::binary_function<_RawRestrictionContainer, _RawRestrictionContainer, bool> {
- typedef _RawRestrictionContainer value_type;
- bool operator () (const _RawRestrictionContainer & a, const _RawRestrictionContainer & b) const {
+struct CmpRestrictionContainerByFrom
+{
+ typedef InputRestrictionContainer value_type;
+ inline bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b)
+ const
+ {
return a.fromWay < b.fromWay;
}
- value_type max_value() {
- return _RawRestrictionContainer::max_value();
- }
- value_type min_value() {
- return _RawRestrictionContainer::min_value();
- }
+ inline value_type max_value() const { return InputRestrictionContainer::max_value(); }
+ inline value_type min_value() const { return InputRestrictionContainer::min_value(); }
};
-struct CmpRestrictionContainerByTo: public std::binary_function<_RawRestrictionContainer, _RawRestrictionContainer, bool> {
- typedef _RawRestrictionContainer value_type;
- bool operator () (const _RawRestrictionContainer & a, const _RawRestrictionContainer & b) const {
+struct CmpRestrictionContainerByTo
+{
+ typedef InputRestrictionContainer value_type;
+ inline bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b)
+ const
+ {
return a.toWay < b.toWay;
}
- value_type max_value() {
- return _RawRestrictionContainer::max_value();
- }
- value_type min_value() {
- return _RawRestrictionContainer::min_value();
- }
+ value_type max_value() const { return InputRestrictionContainer::max_value(); }
+ value_type min_value() const { return InputRestrictionContainer::min_value(); }
};
-
-
-#endif /* RESTRICTION_H_ */
+#endif // RESTRICTION_H
diff --git a/DataStructures/RestrictionMap.cpp b/DataStructures/RestrictionMap.cpp
new file mode 100644
index 0000000..1859b82
--- /dev/null
+++ b/DataStructures/RestrictionMap.cpp
@@ -0,0 +1,224 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "RestrictionMap.h"
+#include "NodeBasedGraph.h"
+
+#include "../Util/SimpleLogger.h"
+
+bool RestrictionMap::IsViaNode(const NodeID node) const
+{
+ return m_no_turn_via_node_set.find(node) != m_no_turn_via_node_set.end();
+}
+
+RestrictionMap::RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
+ const std::vector<TurnRestriction> &restriction_list)
+ : m_count(0), m_graph(graph)
+{
+ // decompose restriction consisting of a start, via and end node into a
+ // a pair of starting edge and a list of all end nodes
+ for (auto &restriction : restriction_list)
+ {
+ m_restriction_start_nodes.insert(restriction.fromNode);
+ m_no_turn_via_node_set.insert(restriction.viaNode);
+
+ RestrictionSource restriction_source = {restriction.fromNode, restriction.viaNode};
+
+ unsigned index;
+ auto restriction_iter = m_restriction_map.find(restriction_source);
+ if (restriction_iter == m_restriction_map.end())
+ {
+ index = m_restriction_bucket_list.size();
+ m_restriction_bucket_list.resize(index + 1);
+ m_restriction_map.emplace(restriction_source, index);
+ }
+ else
+ {
+ index = restriction_iter->second;
+ // Map already contains an is_only_*-restriction
+ if (m_restriction_bucket_list.at(index).begin()->is_only)
+ {
+ continue;
+ }
+ else if (restriction.flags.isOnly)
+ {
+ // We are going to insert an is_only_*-restriction. There can be only one.
+ m_count -= m_restriction_bucket_list.at(index).size();
+ m_restriction_bucket_list.at(index).clear();
+ }
+ }
+ ++m_count;
+ m_restriction_bucket_list.at(index)
+ .emplace_back(restriction.toNode, restriction.flags.isOnly);
+ }
+}
+
+// Replace end v with w in each turn restriction containing u as via node
+void RestrictionMap::FixupArrivingTurnRestriction(const NodeID node_u,
+ const NodeID node_v,
+ const NodeID node_w)
+{
+ BOOST_ASSERT(node_u != SPECIAL_NODEID);
+ BOOST_ASSERT(node_v != SPECIAL_NODEID);
+ BOOST_ASSERT(node_w != SPECIAL_NODEID);
+
+ if (!IsViaNode(node_u))
+ {
+ return;
+ }
+
+ // find all potential start edges. It is more efficent to get a (small) list
+ // of potential start edges than iterating over all buckets
+ std::vector<NodeID> predecessors;
+ for (const EdgeID current_edge_id : m_graph->GetAdjacentEdgeRange(node_u))
+ {
+ const EdgeData &edge_data = m_graph->GetEdgeData(current_edge_id);
+ const NodeID target = m_graph->GetTarget(current_edge_id);
+ if (edge_data.backward && (node_v != target))
+ {
+ predecessors.push_back(target);
+ }
+ }
+
+ for (const NodeID node_x : predecessors)
+ {
+ const auto restriction_iterator = m_restriction_map.find({node_x, node_u});
+ if (restriction_iterator == m_restriction_map.end())
+ {
+ continue;
+ }
+
+ const unsigned index = restriction_iterator->second;
+ auto &bucket = m_restriction_bucket_list.at(index);
+ for (RestrictionTarget &restriction_target : bucket)
+ {
+ if (node_v == restriction_target.target_node)
+ {
+ restriction_target.target_node = node_w;
+ }
+ }
+ }
+}
+
+// Replaces start edge (v, w) with (u, w). Only start node changes.
+void RestrictionMap::FixupStartingTurnRestriction(const NodeID node_u,
+ const NodeID node_v,
+ const NodeID node_w)
+{
+ BOOST_ASSERT(node_u != SPECIAL_NODEID);
+ BOOST_ASSERT(node_v != SPECIAL_NODEID);
+ BOOST_ASSERT(node_w != SPECIAL_NODEID);
+
+ if (!IsSourceNode(node_v))
+ {
+ return;
+ }
+
+ const auto restriction_iterator = m_restriction_map.find({node_v, node_w});
+ if (restriction_iterator != m_restriction_map.end())
+ {
+ const unsigned index = restriction_iterator->second;
+ // remove old restriction start (v,w)
+ m_restriction_map.erase(restriction_iterator);
+ m_restriction_start_nodes.emplace(node_u);
+ // insert new restriction start (u,w) (pointing to index)
+ RestrictionSource new_source = {node_u, node_w};
+ m_restriction_map.emplace(new_source, index);
+ }
+}
+
+// Check if edge (u, v) is the start of any turn restriction.
+// If so returns id of first target node.
+NodeID RestrictionMap::CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const
+{
+ BOOST_ASSERT(node_u != SPECIAL_NODEID);
+ BOOST_ASSERT(node_v != SPECIAL_NODEID);
+
+ if (!IsSourceNode(node_u))
+ {
+ return SPECIAL_NODEID;
+ }
+
+ auto restriction_iter = m_restriction_map.find({node_u, node_v});
+ if (restriction_iter != m_restriction_map.end())
+ {
+ const unsigned index = restriction_iter->second;
+ auto &bucket = m_restriction_bucket_list.at(index);
+ for (const RestrictionTarget &restriction_target : bucket)
+ {
+ if (restriction_target.is_only)
+ {
+ return restriction_target.target_node;
+ }
+ }
+ }
+ return SPECIAL_NODEID;
+}
+
+// Checks if turn <u,v,w> is actually a turn restriction.
+bool RestrictionMap::CheckIfTurnIsRestricted(const NodeID node_u,
+ const NodeID node_v,
+ const NodeID node_w) const
+{
+ // return false;
+
+ BOOST_ASSERT(node_u != SPECIAL_NODEID);
+ BOOST_ASSERT(node_v != SPECIAL_NODEID);
+ BOOST_ASSERT(node_w != SPECIAL_NODEID);
+
+ if (!IsSourceNode(node_u))
+ {
+ return false;
+ }
+
+ auto restriction_iter = m_restriction_map.find({node_u, node_v});
+ if (restriction_iter != m_restriction_map.end())
+ {
+ const unsigned index = restriction_iter->second;
+ const auto &bucket = m_restriction_bucket_list.at(index);
+ for (const RestrictionTarget &restriction_target : bucket)
+ {
+ if ((node_w == restriction_target.target_node) && // target found
+ (!restriction_target.is_only) // and not an only_-restr.
+ )
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// check of node is the start of any restriction
+bool RestrictionMap::IsSourceNode(const NodeID node) const
+{
+ if (m_restriction_start_nodes.find(node) == m_restriction_start_nodes.end())
+ {
+ return false;
+ }
+ return true;
+}
diff --git a/DataStructures/RestrictionMap.h b/DataStructures/RestrictionMap.h
new file mode 100644
index 0000000..8207b80
--- /dev/null
+++ b/DataStructures/RestrictionMap.h
@@ -0,0 +1,126 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef __RESTRICTION_MAP_H__
+#define __RESTRICTION_MAP_H__
+
+#include <memory>
+
+#include "DynamicGraph.h"
+#include "Restriction.h"
+#include "NodeBasedGraph.h"
+#include "../Util/StdHashExtensions.h"
+#include "../typedefs.h"
+
+#include <unordered_map>
+#include <unordered_set>
+
+struct RestrictionSource
+{
+ NodeID start_node;
+ NodeID via_node;
+
+ RestrictionSource(NodeID start, NodeID via) : start_node(start), via_node(via)
+ {
+ }
+
+ friend inline bool operator==(const RestrictionSource &lhs, const RestrictionSource &rhs)
+ {
+ return (lhs.start_node == rhs.start_node && lhs.via_node == rhs.via_node);
+ }
+};
+
+struct RestrictionTarget
+{
+ NodeID target_node;
+ bool is_only;
+
+ explicit RestrictionTarget(NodeID target, bool only) : target_node(target), is_only(only)
+ {
+ }
+
+ friend inline bool operator==(const RestrictionTarget &lhs, const RestrictionTarget &rhs)
+ {
+ return (lhs.target_node == rhs.target_node && lhs.is_only == rhs.is_only);
+ }
+};
+
+namespace std
+{
+template <> struct hash<RestrictionSource>
+{
+ size_t operator()(const RestrictionSource &r_source) const
+ {
+ return hash_val(r_source.start_node, r_source.via_node);
+ }
+};
+
+template <> struct hash<RestrictionTarget>
+{
+ size_t operator()(const RestrictionTarget &r_target) const
+ {
+ return hash_val(r_target.target_node, r_target.is_only);
+ }
+};
+}
+
+/**
+ \brief Efficent look up if an edge is the start + via node of a TurnRestriction
+ EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
+*/
+class RestrictionMap
+{
+ public:
+ RestrictionMap(const std::shared_ptr<NodeBasedDynamicGraph> &graph,
+ const std::vector<TurnRestriction> &input_restrictions_list);
+
+ void FixupArrivingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
+ void FixupStartingTurnRestriction(const NodeID u, const NodeID v, const NodeID w);
+ NodeID CheckForEmanatingIsOnlyTurn(const NodeID u, const NodeID v) const;
+ bool CheckIfTurnIsRestricted(const NodeID u, const NodeID v, const NodeID w) const;
+ bool IsViaNode(const NodeID node) const;
+ unsigned size()
+ {
+ return m_count;
+ }
+
+ private:
+ bool IsSourceNode(const NodeID node) const;
+ typedef std::vector<RestrictionTarget> EmanatingRestrictionsVector;
+ typedef NodeBasedDynamicGraph::EdgeData EdgeData;
+
+ unsigned m_count;
+ std::shared_ptr<NodeBasedDynamicGraph> m_graph;
+ //! index -> list of (target, isOnly)
+ std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
+ //! maps (start, via) -> bucket index
+ std::unordered_map<RestrictionSource, unsigned> m_restriction_map;
+ std::unordered_set<NodeID> m_restriction_start_nodes;
+ std::unordered_set<NodeID> m_no_turn_via_node_set;
+};
+
+#endif
diff --git a/DataStructures/RouteParameters.cpp b/DataStructures/RouteParameters.cpp
new file mode 100644
index 0000000..edc7311
--- /dev/null
+++ b/DataStructures/RouteParameters.cpp
@@ -0,0 +1,89 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <osrm/RouteParameters.h>
+
+#include <boost/fusion/container/vector.hpp>
+#include <boost/fusion/sequence/intrinsic.hpp>
+#include <boost/fusion/include/at_c.hpp>
+
+RouteParameters::RouteParameters()
+ : zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
+ compression(true), deprecatedAPI(false), check_sum(-1)
+{
+}
+
+void RouteParameters::setZoomLevel(const short level)
+{
+ if (18 >= level && 0 <= level)
+ {
+ zoom_level = level;
+ }
+}
+
+void RouteParameters::setAlternateRouteFlag(const bool flag) { alternate_route = flag; }
+
+void RouteParameters::setDeprecatedAPIFlag(const std::string &) { deprecatedAPI = true; }
+
+void RouteParameters::setChecksum(const unsigned sum) { check_sum = sum; }
+
+void RouteParameters::setInstructionFlag(const bool flag) { print_instructions = flag; }
+
+void RouteParameters::setService(const std::string &service_string) { service = service_string; }
+
+void RouteParameters::setOutputFormat(const std::string &format) { output_format = format; }
+
+void RouteParameters::setJSONpParameter(const std::string ¶meter)
+{
+ jsonp_parameter = parameter;
+}
+
+void RouteParameters::addHint(const std::string &hint)
+{
+ hints.resize(coordinates.size());
+ if (!hints.empty())
+ {
+ hints.back() = hint;
+ }
+}
+
+void RouteParameters::setLanguage(const std::string &language_string)
+{
+ language = language_string;
+}
+
+void RouteParameters::setGeometryFlag(const bool flag) { geometry = flag; }
+
+void RouteParameters::setCompressionFlag(const bool flag) { compression = flag; }
+
+void
+RouteParameters::addCoordinate(const boost::fusion::vector<double, double> &transmitted_coordinates)
+{
+ coordinates.emplace_back(
+ static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(transmitted_coordinates)),
+ static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(transmitted_coordinates)));
+}
diff --git a/DataStructures/SearchEngine.cpp b/DataStructures/SearchEngine.cpp
deleted file mode 100644
index 2a538a7..0000000
--- a/DataStructures/SearchEngine.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- 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;
-
diff --git a/DataStructures/SearchEngine.h b/DataStructures/SearchEngine.h
index 64d273b..58f5e77 100644
--- a/DataStructures/SearchEngine.h
+++ b/DataStructures/SearchEngine.h
@@ -1,68 +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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef SEARCHENGINE_H_
-#define SEARCHENGINE_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef SEARCHENGINE_H
+#define SEARCHENGINE_H
-#include "Coordinate.h"
-#include "NodeInformationHelpDesk.h"
-#include "PhantomNodes.h"
-#include "QueryEdge.h"
#include "SearchEngineData.h"
#include "../RoutingAlgorithms/AlternativePathRouting.h"
+#include "../RoutingAlgorithms/ManyToManyRouting.h"
#include "../RoutingAlgorithms/ShortestPathRouting.h"
-#include "../Util/StringUtil.h"
-#include "../typedefs.h"
-
-#include <climits>
-#include <string>
-#include <vector>
-
-class SearchEngine {
-private:
- SearchEngineData _queryData;
-
-public:
- ShortestPathRouting<SearchEngineData> shortestPath;
- AlternativeRouting<SearchEngineData> alternativePaths;
-
- SearchEngine(
- QueryGraph * g,
- NodeInformationHelpDesk * nh,
- std::vector<std::string> & n
- );
- ~SearchEngine();
+#include <type_traits>
- void GetCoordinatesForNodeID(NodeID id, _Coordinate& result) const;
+template <class DataFacadeT> class SearchEngine
+{
+ private:
+ DataFacadeT *facade;
+ SearchEngineData engine_working_data;
- void FindPhantomNodeForCoordinate(
- const _Coordinate & location,
- PhantomNode & result,
- unsigned zoomLevel
- ) const;
+ public:
+ ShortestPathRouting<DataFacadeT> shortest_path;
+ AlternativeRouting<DataFacadeT> alternative_path;
+ ManyToManyRouting<DataFacadeT> distance_table;
- NodeID GetNameIDForOriginDestinationNodeID(
- const NodeID s, const NodeID t) const;
+ explicit SearchEngine(DataFacadeT *facade)
+ : facade(facade), shortest_path(facade, engine_working_data),
+ alternative_path(facade, engine_working_data), distance_table(facade, engine_working_data)
+ {
+ static_assert(!std::is_pointer<DataFacadeT>::value, "don't instantiate with ptr type");
+ static_assert(std::is_object<DataFacadeT>::value, "don't instantiate with void, function, or reference");
+ }
- std::string GetEscapedNameForNameID(const unsigned nameID) const;
+ ~SearchEngine() {}
};
-#endif /* SEARCHENGINE_H_ */
+#endif // SEARCHENGINE_H
diff --git a/DataStructures/SearchEngineData.cpp b/DataStructures/SearchEngineData.cpp
index 77492f6..a5e4bfc 100644
--- a/DataStructures/SearchEngineData.cpp
+++ b/DataStructures/SearchEngineData.cpp
@@ -1,60 +1,93 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#include "SearchEngineData.h"
-void SearchEngineData::InitializeOrClearFirstThreadLocalStorage() {
- if(!forwardHeap.get()) {
- forwardHeap.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
- } else {
+#include "BinaryHeap.h"
+
+void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes)
+{
+ if (forwardHeap.get())
+ {
forwardHeap->Clear();
}
- if(!backwardHeap.get()) {
- backwardHeap.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
- } else {
+ else
+ {
+ forwardHeap.reset(new QueryHeap(number_of_nodes));
+ }
+
+ if (backwardHeap.get())
+ {
backwardHeap->Clear();
}
+ else
+ {
+ backwardHeap.reset(new QueryHeap(number_of_nodes));
+ }
}
-void SearchEngineData::InitializeOrClearSecondThreadLocalStorage() {
- if(!forwardHeap2.get()) {
- forwardHeap2.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
- } else {
+void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes)
+{
+ if (forwardHeap2.get())
+ {
forwardHeap2->Clear();
}
- if(!backwardHeap2.get()) {
- backwardHeap2.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
- } else {
+ else
+ {
+ forwardHeap2.reset(new QueryHeap(number_of_nodes));
+ }
+
+ if (backwardHeap2.get())
+ {
backwardHeap2->Clear();
}
+ else
+ {
+ backwardHeap2.reset(new QueryHeap(number_of_nodes));
+ }
}
-void SearchEngineData::InitializeOrClearThirdThreadLocalStorage() {
- if(!forwardHeap3.get()) {
- forwardHeap3.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
- } else {
+void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes)
+{
+ if (forwardHeap3.get())
+ {
forwardHeap3->Clear();
}
- if(!backwardHeap3.get()) {
- backwardHeap3.reset(new QueryHeap(nodeHelpDesk->getNumberOfNodes()));
- } else {
+ else
+ {
+ forwardHeap3.reset(new QueryHeap(number_of_nodes));
+ }
+
+ if (backwardHeap3.get())
+ {
backwardHeap3->Clear();
}
+ else
+ {
+ backwardHeap3.reset(new QueryHeap(number_of_nodes));
+ }
}
diff --git a/DataStructures/SearchEngineData.h b/DataStructures/SearchEngineData.h
index f9a2623..f0621e6 100644
--- a/DataStructures/SearchEngineData.h
+++ b/DataStructures/SearchEngineData.h
@@ -1,50 +1,49 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#include "BinaryHeap.h"
-#include "QueryEdge.h"
-#include "NodeInformationHelpDesk.h"
-#include "StaticGraph.h"
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "../typedefs.h"
+*/
-#include <boost/thread.hpp>
+#ifndef SEARCH_ENGINE_DATA_H
+#define SEARCH_ENGINE_DATA_H
-#include <string>
-#include <vector>
+#include <boost/thread/tss.hpp>
+
+#include "../typedefs.h"
+#include "BinaryHeap.h"
-struct _HeapData {
+struct HeapData
+{
NodeID parent;
- _HeapData( NodeID p ) : parent(p) { }
+ /* explicit */ 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;
+
+struct SearchEngineData
+{
+ typedef BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>> QueryHeap;
+ typedef boost::thread_specific_ptr<QueryHeap> SearchEngineHeapPtr;
+
static SearchEngineHeapPtr forwardHeap;
static SearchEngineHeapPtr backwardHeap;
static SearchEngineHeapPtr forwardHeap2;
@@ -52,9 +51,11 @@ struct SearchEngineData {
static SearchEngineHeapPtr forwardHeap3;
static SearchEngineHeapPtr backwardHeap3;
- void InitializeOrClearFirstThreadLocalStorage();
+ void InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes);
- void InitializeOrClearSecondThreadLocalStorage();
+ void InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes);
- void InitializeOrClearThirdThreadLocalStorage();
+ void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
};
+
+#endif // SEARCH_ENGINE_DATA_H
diff --git a/DataStructures/SegmentInformation.h b/DataStructures/SegmentInformation.h
index cbe4b81..f145804 100644
--- a/DataStructures/SegmentInformation.h
+++ b/DataStructures/SegmentInformation.h
@@ -1,42 +1,72 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef SEGMENTINFORMATION_H_
-#define SEGMENTINFORMATION_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <climits>
+*/
+
+#ifndef SEGMENT_INFORMATION_H
+#define SEGMENT_INFORMATION_H
#include "TurnInstructions.h"
-struct SegmentInformation {
- _Coordinate location;
- NodeID nameID;
- double length;
- unsigned duration;
- double bearing;
- TurnInstruction turnInstruction;
- bool necessary;
- SegmentInformation(const _Coordinate & loc, const NodeID nam, const double len, const unsigned dur, const TurnInstruction tInstr, const bool nec) :
- location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(nec) {}
- SegmentInformation(const _Coordinate & loc, const NodeID nam, const double len, const unsigned dur, const TurnInstruction tInstr) :
- location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(tInstr != 0) {}
+#include "../typedefs.h"
+
+#include <osrm/Coordinate.h>
+
+// Struct fits everything in one cache line
+struct SegmentInformation
+{
+ FixedPointCoordinate location;
+ NodeID name_id;
+ EdgeWeight duration;
+ float length;
+ short bearing; // more than enough [0..3600] fits into 12 bits
+ TurnInstruction turn_instruction;
+ bool necessary:1;
+ bool is_via_location:1;
+
+ explicit SegmentInformation(const FixedPointCoordinate &location,
+ const NodeID name_id,
+ const EdgeWeight duration,
+ const float length,
+ const TurnInstruction turn_instruction,
+ const bool necessary,
+ const bool is_via_location)
+ : location(location), name_id(name_id), duration(duration), length(length), bearing(0),
+ turn_instruction(turn_instruction), necessary(necessary), is_via_location(is_via_location)
+ {
+ }
+
+ explicit SegmentInformation(const FixedPointCoordinate &location,
+ const NodeID name_id,
+ const EdgeWeight duration,
+ const float length,
+ const TurnInstruction turn_instruction)
+ : location(location), name_id(name_id), duration(duration), length(length), bearing(0),
+ turn_instruction(turn_instruction), necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
+ {
+ }
};
-#endif /* SEGMENTINFORMATION_H_ */
+#endif /* SEGMENT_INFORMATION_H */
diff --git a/DataStructures/SharedMemoryFactory.h b/DataStructures/SharedMemoryFactory.h
new file mode 100644
index 0000000..a07e125
--- /dev/null
+++ b/DataStructures/SharedMemoryFactory.h
@@ -0,0 +1,370 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef SHARED_MEMORY_FACTORY_H
+#define SHARED_MEMORY_FACTORY_H
+
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/interprocess/mapped_region.hpp>
+#ifndef WIN32
+#include <boost/interprocess/xsi_shared_memory.hpp>
+#else
+#include <boost/interprocess/shared_memory_object.hpp>
+#endif
+
+#ifdef __linux__
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif
+
+// #include <cstring>
+#include <cstdint>
+
+#include <algorithm>
+#include <exception>
+
+struct OSRMLockFile
+{
+ boost::filesystem::path operator()()
+ {
+ boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path();
+ boost::filesystem::path lock_file = temp_dir / "osrm.lock";
+ return lock_file;
+ }
+};
+
+#ifndef WIN32
+class SharedMemory
+{
+
+ // Remove shared memory on destruction
+ class shm_remove
+ {
+ private:
+ int m_shmid;
+ bool m_initialized;
+
+ public:
+ void SetID(int shmid)
+ {
+ m_shmid = shmid;
+ m_initialized = true;
+ }
+
+ shm_remove() : m_shmid(INT_MIN), m_initialized(false) {}
+ shm_remove(const shm_remove &) = delete;
+ ~shm_remove()
+ {
+ if (m_initialized)
+ {
+ SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
+ if (!boost::interprocess::xsi_shared_memory::remove(m_shmid))
+ {
+ SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
+ }
+ }
+ }
+ };
+
+ public:
+ void *Ptr() const { return region.get_address(); }
+
+ SharedMemory() = delete;
+ SharedMemory(const SharedMemory &) = delete;
+
+ template <typename IdentifierT>
+ SharedMemory(const boost::filesystem::path &lock_file,
+ const IdentifierT id,
+ const uint64_t size = 0,
+ bool read_write = false,
+ bool remove_prev = true)
+ : key(lock_file.string().c_str(), id)
+ {
+ if (0 == size)
+ { // read_only
+ shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_only, key);
+
+ region = boost::interprocess::mapped_region(
+ shm,
+ (read_write ? boost::interprocess::read_write : boost::interprocess::read_only));
+ }
+ else
+ { // writeable pointer
+ // remove previously allocated mem
+ if (remove_prev)
+ {
+ Remove(key);
+ }
+ shm = boost::interprocess::xsi_shared_memory(
+ boost::interprocess::open_or_create, key, size);
+#ifdef __linux__
+ if (-1 == shmctl(shm.get_shmid(), SHM_LOCK, 0))
+ {
+ if (ENOMEM == errno)
+ {
+ SimpleLogger().Write(logWARNING) << "could not lock shared memory to RAM";
+ }
+ }
+#endif
+ region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
+
+ remover.SetID(shm.get_shmid());
+ SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size << " bytes";
+ }
+ }
+
+ template <typename IdentifierT> static bool RegionExists(const IdentifierT id)
+ {
+ bool result = true;
+ try
+ {
+ OSRMLockFile lock_file;
+ boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
+ result = RegionExists(key);
+ }
+ catch (...) { result = false; }
+ return result;
+ }
+
+ template <typename IdentifierT> static bool Remove(const IdentifierT id)
+ {
+ OSRMLockFile lock_file;
+ boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
+ return Remove(key);
+ }
+
+ private:
+ static bool RegionExists(const boost::interprocess::xsi_key &key)
+ {
+ bool result = true;
+ try { boost::interprocess::xsi_shared_memory shm(boost::interprocess::open_only, key); }
+ catch (...) { result = false; }
+ return result;
+ }
+
+ static bool Remove(const boost::interprocess::xsi_key &key)
+ {
+ bool ret = false;
+ try
+ {
+ SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
+ boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, key);
+ ret = boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
+ }
+ catch (const boost::interprocess::interprocess_exception &e)
+ {
+ if (e.get_error_code() != boost::interprocess::not_found_error)
+ {
+ throw;
+ }
+ }
+ return ret;
+ }
+
+ boost::interprocess::xsi_key key;
+ boost::interprocess::xsi_shared_memory shm;
+ boost::interprocess::mapped_region region;
+ shm_remove remover;
+};
+#else
+// Windows - specific code
+class SharedMemory : boost::noncopyable
+{
+ // Remove shared memory on destruction
+ class shm_remove : boost::noncopyable
+ {
+ private:
+ char *m_shmid;
+ bool m_initialized;
+
+ public:
+ void SetID(char *shmid)
+ {
+ m_shmid = shmid;
+ m_initialized = true;
+ }
+
+ shm_remove() : m_shmid("undefined"), m_initialized(false) {}
+
+ ~shm_remove()
+ {
+ if (m_initialized)
+ {
+ SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
+ if (!boost::interprocess::shared_memory_object::remove(m_shmid))
+ {
+ SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
+ }
+ }
+ }
+ };
+
+ public:
+ void *Ptr() const { return region.get_address(); }
+
+ SharedMemory(const boost::filesystem::path &lock_file,
+ const int id,
+ const uint64_t size = 0,
+ bool read_write = false,
+ bool remove_prev = true)
+ {
+ sprintf(key, "%s.%d", "osrm.lock", id);
+ if (0 == size)
+ { // read_only
+ shm = boost::interprocess::shared_memory_object(
+ boost::interprocess::open_only,
+ key,
+ read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
+ region = boost::interprocess::mapped_region(
+ shm, read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
+ }
+ else
+ { // writeable pointer
+ // remove previously allocated mem
+ if (remove_prev)
+ {
+ Remove(key);
+ }
+ shm = boost::interprocess::shared_memory_object(
+ boost::interprocess::open_or_create, key, boost::interprocess::read_write);
+ shm.truncate(size);
+ region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
+
+ remover.SetID(key);
+ SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size << " bytes";
+ }
+ }
+
+ static bool RegionExists(const int id)
+ {
+ bool result = true;
+ try
+ {
+ char k[500];
+ build_key(id, k);
+ result = RegionExists(k);
+ }
+ catch (...) { result = false; }
+ return result;
+ }
+
+ static bool Remove(const int id)
+ {
+ char k[500];
+ build_key(id, k);
+ return Remove(k);
+ }
+
+ private:
+ static void build_key(int id, char *key)
+ {
+ OSRMLockFile lock_file;
+ sprintf(key, "%s.%d", "osrm.lock", id);
+ }
+
+ static bool RegionExists(const char *key)
+ {
+ bool result = true;
+ try
+ {
+ boost::interprocess::shared_memory_object shm(
+ boost::interprocess::open_only, key, boost::interprocess::read_write);
+ }
+ catch (...) { result = false; }
+ return result;
+ }
+
+ static bool Remove(char *key)
+ {
+ bool ret = false;
+ try
+ {
+ SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
+ ret = boost::interprocess::shared_memory_object::remove(key);
+ }
+ catch (const boost::interprocess::interprocess_exception &e)
+ {
+ if (e.get_error_code() != boost::interprocess::not_found_error)
+ {
+ throw;
+ }
+ }
+ return ret;
+ }
+
+ char key[500];
+ boost::interprocess::shared_memory_object shm;
+ boost::interprocess::mapped_region region;
+ shm_remove remover;
+};
+#endif
+
+template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
+{
+ public:
+ template <typename IdentifierT>
+ static SharedMemory *Get(const IdentifierT &id,
+ const uint64_t size = 0,
+ bool read_write = false,
+ bool remove_prev = true)
+ {
+ try
+ {
+ LockFileT lock_file;
+ if (!boost::filesystem::exists(lock_file()))
+ {
+ if (0 == size)
+ {
+ throw OSRMException("lock file does not exist, exiting");
+ }
+ else
+ {
+ boost::filesystem::ofstream ofs(lock_file());
+ ofs.close();
+ }
+ }
+ return new SharedMemory(lock_file(), id, size, read_write, remove_prev);
+ }
+ catch (const boost::interprocess::interprocess_exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
+ << e.get_error_code();
+ throw OSRMException(e.what());
+ }
+ }
+
+ SharedMemoryFactory_tmpl() = delete;
+ SharedMemoryFactory_tmpl(const SharedMemoryFactory_tmpl &) = delete;
+};
+
+typedef SharedMemoryFactory_tmpl<> SharedMemoryFactory;
+
+#endif /* SHARED_MEMORY_POINTER_FACTORY_H */
diff --git a/DataStructures/SharedMemoryVectorWrapper.h b/DataStructures/SharedMemoryVectorWrapper.h
new file mode 100644
index 0000000..fe4baf3
--- /dev/null
+++ b/DataStructures/SharedMemoryVectorWrapper.h
@@ -0,0 +1,156 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef SHARED_MEMORY_VECTOR_WRAPPER_H
+#define SHARED_MEMORY_VECTOR_WRAPPER_H
+
+#include "../Util/SimpleLogger.h"
+
+#include <boost/assert.hpp>
+
+#include <algorithm>
+#include <iterator>
+#include <type_traits>
+#include <vector>
+
+template <typename DataT> class ShMemIterator : public std::iterator<std::input_iterator_tag, DataT>
+{
+ DataT *p;
+
+ public:
+ explicit ShMemIterator(DataT *x) : p(x) {}
+ ShMemIterator(const ShMemIterator &mit) : p(mit.p) {}
+ ShMemIterator &operator++()
+ {
+ ++p;
+ return *this;
+ }
+ ShMemIterator operator++(int)
+ {
+ ShMemIterator tmp(*this);
+ operator++();
+ return tmp;
+ }
+ ShMemIterator operator+(std::ptrdiff_t diff)
+ {
+ ShMemIterator tmp(p + diff);
+ return tmp;
+ }
+ bool operator==(const ShMemIterator &rhs) { return p == rhs.p; }
+ bool operator!=(const ShMemIterator &rhs) { return p != rhs.p; }
+ DataT &operator*() { return *p; }
+};
+
+template <typename DataT> class SharedMemoryWrapper
+{
+ private:
+ DataT *m_ptr;
+ std::size_t m_size;
+
+ public:
+ SharedMemoryWrapper() : m_ptr(nullptr), m_size(0) {}
+
+ SharedMemoryWrapper(DataT *ptr, std::size_t size) : m_ptr(ptr), m_size(size) {}
+
+ void swap(SharedMemoryWrapper<DataT> &other)
+ {
+ BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
+ std::swap(m_size, other.m_size);
+ std::swap(m_ptr, other.m_ptr);
+ }
+
+ DataT &at(const std::size_t index) { return m_ptr[index]; }
+
+ const DataT &at(const std::size_t index) const { return m_ptr[index]; }
+
+ ShMemIterator<DataT> begin() const { return ShMemIterator<DataT>(m_ptr); }
+
+ ShMemIterator<DataT> end() const { return ShMemIterator<DataT>(m_ptr + m_size); }
+
+ std::size_t size() const { return m_size; }
+
+ bool empty() const { return 0 == size(); }
+
+ DataT &operator[](const unsigned index)
+ {
+ BOOST_ASSERT_MSG(index < m_size, "invalid size");
+ return m_ptr[index];
+ }
+
+ const DataT &operator[](const unsigned index) const
+ {
+ BOOST_ASSERT_MSG(index < m_size, "invalid size");
+ return m_ptr[index];
+ }
+};
+
+template <> class SharedMemoryWrapper<bool>
+{
+ private:
+ unsigned *m_ptr;
+ std::size_t m_size;
+
+ public:
+ SharedMemoryWrapper() : m_ptr(nullptr), m_size(0) {}
+
+ SharedMemoryWrapper(unsigned *ptr, std::size_t size) : m_ptr(ptr), m_size(size) {}
+
+ void swap(SharedMemoryWrapper<bool> &other)
+ {
+ BOOST_ASSERT_MSG(m_size != 0 || other.size() != 0, "size invalid");
+ std::swap(m_size, other.m_size);
+ std::swap(m_ptr, other.m_ptr);
+ }
+
+ bool at(const std::size_t index) const
+ {
+ const std::size_t bucket = index / 32;
+ const unsigned offset = static_cast<unsigned>(index % 32);
+ return m_ptr[bucket] & (1 << offset);
+ }
+
+ std::size_t size() const { return m_size; }
+
+ bool empty() const { return 0 == size(); }
+
+ bool operator[](const unsigned index)
+ {
+ BOOST_ASSERT_MSG(index < m_size, "invalid size");
+ const unsigned bucket = index / 32;
+ const unsigned offset = index % 32;
+ return m_ptr[bucket] & (1 << offset);
+ }
+};
+
+template <typename DataT, bool UseSharedMemory> struct ShM
+{
+ typedef typename std::conditional<UseSharedMemory,
+ SharedMemoryWrapper<DataT>,
+ std::vector<DataT>>::type vector;
+};
+
+#endif // SHARED_MEMORY_VECTOR_WRAPPER_H
diff --git a/DataStructures/SimpleStack.h b/DataStructures/SimpleStack.h
deleted file mode 100644
index 0335bcc..0000000
--- a/DataStructures/SimpleStack.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- open source routing machine
- Copyright (C) Dennis Luxen, others 2010
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU AFFERO General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-or see http://www.gnu.org/licenses/agpl.txt.
- */
-
-#ifndef SIMPLESTACK_H_
-#define SIMPLESTACK_H_
-
-#include <cassert>
-#include <vector>
-
-template<typename StackItemT, class ContainerT = std::vector<StackItemT> >
-class SimpleStack {
-
-private:
- int last;
- ContainerT arr;
-
-public:
- SimpleStack() : last(-1) {
- }
-
- SimpleStack(std::size_t size_hint) : last(-1) {
- hint(size_hint);
- }
-
- inline void hint(std::size_t size_hint) {
- arr.reserve(size_hint);
- }
-
- inline void push(StackItemT t) {
- ++last;
- arr.push_back(t);
- }
-
- inline void pop() {
- arr.pop_back();
- --last;
- }
-
- inline StackItemT top() {
- assert (last >= 0);
- return arr[last];
- }
-
- inline int size() {
- return last+1;
- }
-
- inline bool empty() {
- return (-1 == last);
- }
-};
-
-
-#endif /* SIMPLESTACK_H_ */
diff --git a/DataStructures/StaticGraph.h b/DataStructures/StaticGraph.h
index eb41683..9210c87 100644
--- a/DataStructures/StaticGraph.h
+++ b/DataStructures/StaticGraph.h
@@ -1,113 +1,156 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef STATIC_GRAPH_H
+#define STATIC_GRAPH_H
+
+#include "../DataStructures/Percent.h"
+#include "../DataStructures/SharedMemoryVectorWrapper.h"
+#include "../Util/SimpleLogger.h"
+#include "../typedefs.h"
-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 <boost/assert.hpp>
+#include <boost/range/irange.hpp>
-#ifndef STATICGRAPH_H_INCLUDED
-#define STATICGRAPH_H_INCLUDED
+#include <tbb/parallel_sort.h>
-#include <vector>
#include <algorithm>
+#include <limits>
+#include <vector>
-#include "../typedefs.h"
-#include "ImportEdge.h"
-
-template< typename EdgeDataT>
-class StaticGraph {
-public:
+template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
+{
+ public:
+ typedef decltype(boost::irange(0u,0u)) EdgeRange;
typedef NodeID NodeIterator;
typedef NodeID EdgeIterator;
typedef EdgeDataT EdgeData;
- class InputEdge {
- public:
+ class InputEdge
+ {
+ public:
EdgeDataT data;
NodeIterator source;
NodeIterator target;
- bool operator<( const InputEdge& right ) const {
- if ( source != right.source )
+ bool operator<(const InputEdge &right) const
+ {
+ if (source != right.source)
+ {
return source < right.source;
+ }
return target < right.target;
}
};
- struct _StrNode {
- //index of the first edge
- EdgeIterator firstEdge;
+ struct NodeArrayEntry
+ {
+ // index of the first edge
+ EdgeIterator first_edge;
};
- struct _StrEdge {
+ struct EdgeArrayEntry
+ {
NodeID target;
EdgeDataT data;
};
- StaticGraph( const int nodes, std::vector< InputEdge > &graph ) {
- std::sort( graph.begin(), graph.end() );
- _numNodes = nodes;
- _numEdges = ( EdgeIterator ) graph.size();
- _nodes.resize( _numNodes + 1);
+ EdgeRange GetAdjacentEdgeRange(const NodeID node) const
+ {
+ return boost::irange(BeginEdges(node), EndEdges(node));
+ }
+
+ StaticGraph(const int nodes, std::vector<InputEdge> &graph)
+ {
+ tbb::parallel_sort(graph.begin(), graph.end());
+ number_of_nodes = nodes;
+ number_of_edges = (EdgeIterator)graph.size();
+ node_array.resize(number_of_nodes + 1);
EdgeIterator edge = 0;
EdgeIterator position = 0;
- for ( NodeIterator node = 0; node <= _numNodes; ++node ) {
- EdgeIterator lastEdge = edge;
- while ( edge < _numEdges && graph[edge].source == node )
+ for (NodeIterator node = 0; node <= number_of_nodes; ++node)
+ {
+ EdgeIterator last_edge = edge;
+ while (edge < number_of_edges && graph[edge].source == node)
+ {
++edge;
- _nodes[node].firstEdge = position; //=edge
- position += edge - lastEdge; //remove
+ }
+ node_array[node].first_edge = position; //=edge
+ position += edge - last_edge; // remove
}
- _edges.resize( position ); //(edge)
+ edge_array.resize(position); //(edge)
edge = 0;
- for ( NodeIterator node = 0; node < _numNodes; ++node ) {
- for ( EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) {
- _edges[i].target = graph[edge].target;
- _edges[i].data = graph[edge].data;
- assert(_edges[i].data.distance > 0);
+ for (NodeIterator node = 0; node < number_of_nodes; ++node)
+ {
+ EdgeIterator e = node_array[node + 1].first_edge;
+ for (EdgeIterator i = node_array[node].first_edge; i != e; ++i)
+ {
+ edge_array[i].target = graph[edge].target;
+ edge_array[i].data = graph[edge].data;
+ BOOST_ASSERT(edge_array[i].data.distance > 0);
edge++;
}
}
}
- StaticGraph( std::vector<_StrNode> & nodes, std::vector<_StrEdge> & edges) {
- _numNodes = nodes.size();
- _numEdges = edges.size();
+ StaticGraph(typename ShM<NodeArrayEntry, UseSharedMemory>::vector &nodes,
+ typename ShM<EdgeArrayEntry, UseSharedMemory>::vector &edges)
+ {
+ number_of_nodes = nodes.size() - 1;
+ number_of_edges = edges.size();
- _nodes.swap(nodes);
- _edges.swap(edges);
-
- //Add dummy node to end of _nodes array;
- _nodes.push_back(_nodes.back());
+ node_array.swap(nodes);
+ edge_array.swap(edges);
#ifndef NDEBUG
Percent p(GetNumberOfNodes());
- for(unsigned u = 0; u < GetNumberOfNodes(); ++u) {
- for(unsigned eid = BeginEdges(u); eid < EndEdges(u); ++eid) {
- unsigned v = GetTarget(eid);
- EdgeData & data = GetEdgeData(eid);
- if(data.shortcut) {
- unsigned eid2 = FindEdgeInEitherDirection(u, data.id);
- if(eid2 == UINT_MAX) {
- DEBUG("cannot find first segment of edge (" << u << "," << data.id << "," << v << ")");
- data.shortcut = false;
- }
- eid2 = FindEdgeInEitherDirection(data.id, v);
- if(eid2 == UINT_MAX) {
- DEBUG("cannot find second segment of edge (" << u << "," << data.id << "," << v << ")");
- data.shortcut = false;
- }
+ for (unsigned u = 0; u < GetNumberOfNodes(); ++u)
+ {
+ for (auto eid : GetAdjacentEdgeRange(u))
+ {
+ const EdgeData &data = GetEdgeData(eid);
+ if (!data.shortcut)
+ {
+ continue;
+ }
+ const unsigned v = GetTarget(eid);
+ const EdgeID first_edge_id = FindEdgeInEitherDirection(u, data.id);
+ if (SPECIAL_EDGEID == first_edge_id)
+ {
+ SimpleLogger().Write(logWARNING) << "cannot find first segment of edge ("
+ << u << "," << data.id << "," << v
+ << "), eid: " << eid;
+ BOOST_ASSERT(false);
+ }
+ const EdgeID second_edge_id = FindEdgeInEitherDirection(data.id, v);
+ if (SPECIAL_EDGEID == second_edge_id)
+ {
+ SimpleLogger().Write(logWARNING) << "cannot find second segment of edge ("
+ << u << "," << data.id << "," << v
+ << "), eid: " << eid;
+ BOOST_ASSERT(false);
}
}
p.printIncrement();
@@ -115,74 +158,76 @@ public:
#endif
}
- unsigned GetNumberOfNodes() const {
- return _numNodes;
- }
+ unsigned GetNumberOfNodes() const { return number_of_nodes -1; }
- unsigned GetNumberOfEdges() const {
- return _numEdges;
- }
+ unsigned GetNumberOfEdges() const { return number_of_edges; }
- unsigned GetOutDegree( const NodeIterator &n ) const {
- return BeginEdges(n)-EndEdges(n) - 1;
- }
+ unsigned GetOutDegree(const NodeIterator n) const { return BeginEdges(n) - EndEdges(n) - 1; }
- inline NodeIterator GetTarget( const EdgeIterator &e ) const {
- return NodeIterator( _edges[e].target );
+ inline NodeIterator GetTarget(const EdgeIterator e) const
+ {
+ return NodeIterator(edge_array[e].target);
}
- inline EdgeDataT &GetEdgeData( const EdgeIterator &e ) {
- return _edges[e].data;
- }
+ inline EdgeDataT &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; }
- const EdgeDataT &GetEdgeData( const EdgeIterator &e ) const {
- return _edges[e].data;
- }
+ const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return edge_array[e].data; }
- EdgeIterator BeginEdges( const NodeIterator &n ) const {
- return EdgeIterator( _nodes[n].firstEdge );
+ EdgeIterator BeginEdges(const NodeIterator n) const
+ {
+ return EdgeIterator(node_array.at(n).first_edge);
}
- EdgeIterator EndEdges( const NodeIterator &n ) const {
- return EdgeIterator( _nodes[n+1].firstEdge );
+ EdgeIterator EndEdges(const NodeIterator n) const
+ {
+ return EdgeIterator(node_array.at(n + 1).first_edge);
}
- //searches for a specific edge
- EdgeIterator FindEdge( const NodeIterator &from, const NodeIterator &to ) const {
- EdgeIterator smallestEdge = SPECIAL_EDGEID;
- EdgeWeight smallestWeight = UINT_MAX;
- for ( EdgeIterator edge = BeginEdges( from ); edge < EndEdges(from); edge++ ) {
+ // searches for a specific edge
+ EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
+ {
+ EdgeIterator smallest_edge = SPECIAL_EDGEID;
+ EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
+ for (auto edge : GetAdjacentEdgeRange(from))
+ {
const NodeID target = GetTarget(edge);
const EdgeWeight weight = GetEdgeData(edge).distance;
- if(target == to && weight < smallestWeight) {
- smallestEdge = edge; smallestWeight = weight;
+ if (target == to && weight < smallest_weight)
+ {
+ smallest_edge = edge;
+ smallest_weight = weight;
}
}
- return smallestEdge;
+ return smallest_edge;
}
- EdgeIterator FindEdgeInEitherDirection( const NodeIterator &from, const NodeIterator &to ) const {
- EdgeIterator tmp = FindEdge( from, to );
- return (UINT_MAX != tmp ? tmp : FindEdge( to, from ));
+ EdgeIterator FindEdgeInEitherDirection(const NodeIterator from, const NodeIterator to) const
+ {
+ EdgeIterator tmp = FindEdge(from, to);
+ return (SPECIAL_NODEID != tmp ? tmp : FindEdge(to, from));
}
- EdgeIterator FindEdgeIndicateIfReverse( const NodeIterator &from, const NodeIterator &to, bool & result ) const {
- EdgeIterator tmp = FindEdge( from, to );
- if(UINT_MAX == tmp) {
- tmp = FindEdge( to, from );
- if(UINT_MAX != tmp)
+ EdgeIterator
+ FindEdgeIndicateIfReverse(const NodeIterator from, const NodeIterator to, bool &result) const
+ {
+ EdgeIterator current_iterator = FindEdge(from, to);
+ if (SPECIAL_NODEID == current_iterator)
+ {
+ current_iterator = FindEdge(to, from);
+ if (SPECIAL_NODEID != current_iterator)
+ {
result = true;
+ }
}
- return tmp;
+ return current_iterator;
}
-private:
-
- NodeIterator _numNodes;
- EdgeIterator _numEdges;
+ private:
+ NodeIterator number_of_nodes;
+ EdgeIterator number_of_edges;
- std::vector< _StrNode > _nodes;
- std::vector< _StrEdge > _edges;
+ typename ShM<NodeArrayEntry, UseSharedMemory>::vector node_array;
+ typename ShM<EdgeArrayEntry, UseSharedMemory>::vector edge_array;
};
-#endif // STATICGRAPH_H_INCLUDED
+#endif // STATIC_GRAPH_H
diff --git a/DataStructures/StaticKDTree.h b/DataStructures/StaticKDTree.h
index 85ffb80..e36eee9 100644
--- a/DataStructures/StaticKDTree.h
+++ b/DataStructures/StaticKDTree.h
@@ -1,45 +1,55 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-KD Tree coded by Christian Vetter, Monav Project
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+// KD Tree coded by Christian Vetter, Monav Project
- */
#ifndef STATICKDTREE_H_INCLUDED
#define STATICKDTREE_H_INCLUDED
-#include <cassert>
+#include <boost/assert.hpp>
#include <vector>
#include <algorithm>
#include <stack>
#include <limits>
-namespace KDTree {
+namespace KDTree
+{
#define KDTREE_BASESIZE (8)
-template< unsigned k, typename T >
-class BoundingBox {
-public:
- BoundingBox() {
- for ( unsigned dim = 0; dim < k; ++dim ) {
- min[dim] = std::numeric_limits< T >::min();
- max[dim] = std::numeric_limits< T >::max();
+template <unsigned k, typename T> class BoundingBox
+{
+ public:
+ BoundingBox()
+ {
+ for (unsigned dim = 0; dim < k; ++dim)
+ {
+ min[dim] = std::numeric_limits<T>::min();
+ max[dim] = std::numeric_limits<T>::max();
}
}
@@ -47,102 +57,118 @@ public:
T max[k];
};
-struct NoData {};
+struct NoData
+{
+};
-template< unsigned k, typename T >
-class EuclidianMetric {
-public:
- double operator() ( const T left[k], const T right[k] ) {
+template <unsigned k, typename T> class EuclidianMetric
+{
+ public:
+ double operator()(const T left[k], const T right[k])
+ {
double result = 0;
- for ( unsigned i = 0; i < k; ++i ) {
+ for (unsigned i = 0; i < k; ++i)
+ {
double temp = (double)left[i] - (double)right[i];
result += temp * temp;
}
return result;
}
- double operator() ( const BoundingBox< k, T > &box, const T point[k] ) {
+ double operator()(const BoundingBox<k, T> &box, const T point[k])
+ {
T nearest[k];
- for ( unsigned dim = 0; dim < k; ++dim ) {
- if ( point[dim] < box.min[dim] )
+ for (unsigned dim = 0; dim < k; ++dim)
+ {
+ if (point[dim] < box.min[dim])
nearest[dim] = box.min[dim];
- else if ( point[dim] > box.max[dim] )
+ else if (point[dim] > box.max[dim])
nearest[dim] = box.max[dim];
else
nearest[dim] = point[dim];
}
- return operator() ( point, nearest );
+ return operator()(point, nearest);
}
};
-template < unsigned k, typename T, typename Data = NoData, typename Metric = EuclidianMetric< k, T > >
-class StaticKDTree {
-public:
-
- struct InputPoint {
+template <unsigned k, typename T, typename Data = NoData, typename Metric = EuclidianMetric<k, T>>
+class StaticKDTree
+{
+ public:
+ struct InputPoint
+ {
T coordinates[k];
Data data;
- bool operator==( const InputPoint& right )
- {
- for ( int i = 0; i < k; i++ ) {
- if ( coordinates[i] != right.coordinates[i] )
+ bool operator==(const InputPoint &right)
+ {
+ for (int i = 0; i < k; i++)
+ {
+ if (coordinates[i] != right.coordinates[i])
return false;
}
return true;
- }
+ }
};
- StaticKDTree( std::vector< InputPoint > * points ){
- assert( k > 0 );
- assert ( points->size() > 0 );
+ explicit StaticKDTree(std::vector<InputPoint> *points)
+ {
+ BOOST_ASSERT(k > 0);
+ BOOST_ASSERT(points->size() > 0);
size = points->size();
kdtree = new InputPoint[size];
- for ( Iterator i = 0; i != size; ++i ) {
+ for (Iterator i = 0; i != size; ++i)
+ {
kdtree[i] = points->at(i);
- for ( unsigned dim = 0; dim < k; ++dim ) {
- if ( kdtree[i].coordinates[dim] < boundingBox.min[dim] )
+ for (unsigned dim = 0; dim < k; ++dim)
+ {
+ if (kdtree[i].coordinates[dim] < boundingBox.min[dim])
boundingBox.min[dim] = kdtree[i].coordinates[dim];
- if ( kdtree[i].coordinates[dim] > boundingBox.max[dim] )
+ if (kdtree[i].coordinates[dim] > boundingBox.max[dim])
boundingBox.max[dim] = kdtree[i].coordinates[dim];
}
}
- std::stack< Tree > s;
- s.push ( Tree ( 0, size, 0 ) );
- while ( !s.empty() ) {
+ std::stack<Tree> s;
+ s.push(Tree(0, size, 0));
+ while (!s.empty())
+ {
Tree tree = s.top();
s.pop();
- if ( tree.right - tree.left < KDTREE_BASESIZE )
+ if (tree.right - tree.left < KDTREE_BASESIZE)
continue;
- Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
- std::nth_element( kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less( tree.dimension ) );
- s.push( Tree( tree.left, middle, ( tree.dimension + 1 ) % k ) );
- s.push( Tree( middle + 1, tree.right, ( tree.dimension + 1 ) % k ) );
+ Iterator middle = tree.left + (tree.right - tree.left) / 2;
+ std::nth_element(
+ kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less(tree.dimension));
+ s.push(Tree(tree.left, middle, (tree.dimension + 1) % k));
+ s.push(Tree(middle + 1, tree.right, (tree.dimension + 1) % k));
}
}
- ~StaticKDTree(){
- delete[] kdtree;
- }
+ ~StaticKDTree() { delete[] kdtree; }
- bool NearestNeighbor( InputPoint* result, const InputPoint& point ) {
+ bool NearestNeighbor(InputPoint *result, const InputPoint &point)
+ {
Metric distance;
bool found = false;
- double nearestDistance = std::numeric_limits< T >::max();
- std::stack< NNTree > s;
- s.push ( NNTree ( 0, size, 0, boundingBox ) );
- while ( !s.empty() ) {
+ double nearestDistance = std::numeric_limits<T>::max();
+ std::stack<NNTree> s;
+ s.push(NNTree(0, size, 0, boundingBox));
+ while (!s.empty())
+ {
NNTree tree = s.top();
s.pop();
- if ( distance( tree.box, point.coordinates ) >= nearestDistance )
+ if (distance(tree.box, point.coordinates) >= nearestDistance)
continue;
- if ( tree.right - tree.left < KDTREE_BASESIZE ) {
- for ( unsigned i = tree.left; i < tree.right; i++ ) {
- double newDistance = distance( kdtree[i].coordinates, point.coordinates );
- if ( newDistance < nearestDistance ) {
+ if (tree.right - tree.left < KDTREE_BASESIZE)
+ {
+ for (unsigned i = tree.left; i < tree.right; i++)
+ {
+ double newDistance = distance(kdtree[i].coordinates, point.coordinates);
+ if (newDistance < nearestDistance)
+ {
nearestDistance = newDistance;
*result = kdtree[i];
found = true;
@@ -151,73 +177,84 @@ public:
continue;
}
- Iterator middle = tree.left + ( tree.right - tree.left ) / 2;
+ Iterator middle = tree.left + (tree.right - tree.left) / 2;
- double newDistance = distance( kdtree[middle].coordinates, point.coordinates );
- if ( newDistance < nearestDistance ) {
+ double newDistance = distance(kdtree[middle].coordinates, point.coordinates);
+ if (newDistance < nearestDistance)
+ {
nearestDistance = newDistance;
*result = kdtree[middle];
found = true;
}
- Less comperator( tree.dimension );
- if ( !comperator( point, kdtree[middle] ) ) {
- NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box );
- NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box );
+ Less comperator(tree.dimension);
+ if (!comperator(point, kdtree[middle]))
+ {
+ NNTree first(middle + 1, tree.right, (tree.dimension + 1) % k, tree.box);
+ NNTree second(tree.left, middle, (tree.dimension + 1) % k, tree.box);
first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
- s.push( second );
- s.push( first );
+ s.push(second);
+ s.push(first);
}
- else {
- NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box );
- NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box );
+ else
+ {
+ NNTree first(middle + 1, tree.right, (tree.dimension + 1) % k, tree.box);
+ NNTree second(tree.left, middle, (tree.dimension + 1) % k, tree.box);
first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension];
- s.push( first );
- s.push( second );
+ s.push(first);
+ s.push(second);
}
}
return found;
}
-private:
+ private:
typedef unsigned Iterator;
- struct Tree {
+ struct Tree
+ {
Iterator left;
Iterator right;
unsigned dimension;
Tree() {}
- Tree( Iterator l, Iterator r, unsigned d ): left( l ), right( r ), dimension( d ) {}
+ Tree(Iterator l, Iterator r, unsigned d) : left(l), right(r), dimension(d) {}
};
- struct NNTree {
+ struct NNTree
+ {
Iterator left;
Iterator right;
unsigned dimension;
- BoundingBox< k, T > box;
+ BoundingBox<k, T> box;
NNTree() {}
- NNTree( Iterator l, Iterator r, unsigned d, const BoundingBox< k, T >& b ): left( l ), right( r ), dimension( d ), box ( b ) {}
+ NNTree(Iterator l, Iterator r, unsigned d, const BoundingBox<k, T> &b)
+ : left(l), right(r), dimension(d), box(b)
+ {
+ }
};
- class Less {
- public:
- Less( unsigned d ) {
+ class Less
+ {
+ public:
+ explicit Less(unsigned d)
+ {
dimension = d;
- assert( dimension < k );
+ BOOST_ASSERT(dimension < k);
}
- bool operator() ( const InputPoint& left, const InputPoint& right ) {
- assert( dimension < k );
+ bool operator()(const InputPoint &left, const InputPoint &right)
+ {
+ BOOST_ASSERT(dimension < k);
return left.coordinates[dimension] < right.coordinates[dimension];
}
- private:
+
+ private:
unsigned dimension;
};
- BoundingBox< k, T > boundingBox;
- InputPoint* kdtree;
+ BoundingBox<k, T> boundingBox;
+ InputPoint *kdtree;
Iterator size;
};
-
}
#endif // STATICKDTREE_H_INCLUDED
diff --git a/DataStructures/StaticRTree.h b/DataStructures/StaticRTree.h
index b85516f..ce306ad 100644
--- a/DataStructures/StaticRTree.h
+++ b/DataStructures/StaticRTree.h
@@ -1,909 +1,1036 @@
/*
- 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"
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef STATICRTREE_H
+#define STATICRTREE_H
+
#include "DeallocatingVector.h"
#include "HilbertValue.h"
+#include "PhantomNodes.h"
+#include "QueryNode.h"
+#include "SharedMemoryFactory.h"
+#include "SharedMemoryVectorWrapper.h"
+
+#include "../Util/MercatorUtil.h"
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/TimingUtil.h"
#include "../typedefs.h"
+#include <osrm/Coordinate.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/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
#include <boost/thread.hpp>
+#include <boost/variant.hpp>
-#include <cassert>
-#include <cfloat>
-#include <climits>
+#include <tbb/parallel_for.h>
+#include <tbb/parallel_sort.h>
#include <algorithm>
-#include <fstream>
+#include <array>
+#include <limits>
+#include <memory>
#include <queue>
+#include <string>
#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
+// tuning parameters
+const static uint32_t RTREE_BRANCHING_FACTOR = 64;
+const static uint32_t RTREE_LEAF_NODE_SIZE = 1024;
-static boost::thread_specific_ptr<std::ifstream> thread_local_rtree_stream;
+static boost::thread_specific_ptr<boost::filesystem::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) {}
+// Implements a static, i.e. packed, R-tree
+template <class EdgeDataT,
+ class CoordinateListT = std::vector<FixedPointCoordinate>,
+ bool UseSharedMemory = false>
+class StaticRTree
+{
+ public:
+ 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 InitializeMBRectangle(const std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> &objects,
+ const uint32_t element_count,
+ const std::vector<NodeInfo> &coordinate_list)
+ {
+ for (uint32_t i = 0; i < element_count; ++i)
+ {
+ min_lon = std::min(min_lon,
+ std::min(coordinate_list.at(objects[i].u).lon,
+ coordinate_list.at(objects[i].v).lon));
+ max_lon = std::max(max_lon,
+ std::max(coordinate_list.at(objects[i].u).lon,
+ coordinate_list.at(objects[i].v).lon));
+
+ min_lat = std::min(min_lat,
+ std::min(coordinate_list.at(objects[i].u).lat,
+ coordinate_list.at(objects[i].v).lat));
+ max_lat = std::max(max_lat,
+ std::max(coordinate_list.at(objects[i].u).lat,
+ coordinate_list.at(objects[i].v).lat));
}
+ BOOST_ASSERT(min_lat != std::numeric_limits<int>::min());
+ BOOST_ASSERT(min_lon != std::numeric_limits<int>::min());
+ BOOST_ASSERT(max_lat != std::numeric_limits<int>::min());
+ BOOST_ASSERT(max_lon != std::numeric_limits<int>::min());
}
- inline void AugmentMBRectangle(const RectangleInt2D & other) {
+ inline void MergeBoundingBoxes(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);
+ BOOST_ASSERT(min_lat != std::numeric_limits<int>::min());
+ BOOST_ASSERT(min_lon != std::numeric_limits<int>::min());
+ BOOST_ASSERT(max_lat != std::numeric_limits<int>::min());
+ BOOST_ASSERT(max_lon != std::numeric_limits<int>::min());
}
- 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;
+ inline FixedPointCoordinate Centroid() const
+ {
+ FixedPointCoordinate 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);
+ inline bool Intersects(const RectangleInt2D &other) const
+ {
+ FixedPointCoordinate upper_left(other.max_lat, other.min_lon);
+ FixedPointCoordinate upper_right(other.max_lat, other.max_lon);
+ FixedPointCoordinate lower_right(other.min_lat, other.max_lon);
+ FixedPointCoordinate lower_left(other.min_lat, other.min_lon);
- return (
- Contains(upper_left)
- || Contains(upper_right)
- || Contains(lower_right)
- || Contains(lower_left)
- );
+ 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;
+ inline float GetMinDist(const FixedPointCoordinate &location) const
+ {
+ const bool is_contained = Contains(location);
+ if (is_contained)
+ {
+ return 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
- )
- );
+ float min_dist = std::numeric_limits<float>::max();
+ min_dist = std::min(min_dist,
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ location.lat, location.lon, max_lat, min_lon));
+ min_dist = std::min(min_dist,
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ location.lat, location.lon, max_lat, max_lon));
+ min_dist = std::min(min_dist,
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ location.lat, location.lon, min_lat, max_lon));
+ min_dist = std::min(min_dist,
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ 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);
+ inline float GetMinMaxDist(const FixedPointCoordinate &location) const
+ {
+ float min_max_dist = std::numeric_limits<float>::max();
+ // Get minmax distance to each of the four sides
+ FixedPointCoordinate upper_left(max_lat, min_lon);
+ FixedPointCoordinate upper_right(max_lat, max_lon);
+ FixedPointCoordinate lower_right(min_lat, max_lon);
+ FixedPointCoordinate 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::max(
+ FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left),
+ FixedPointCoordinate::ApproximateEuclideanDistance(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::max(
+ FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right),
+ FixedPointCoordinate::ApproximateEuclideanDistance(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::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right),
+ FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left)));
min_max_dist = std::min(
- min_max_dist,
- std::max(
- ApproximateDistance(location, lower_left ),
- ApproximateDistance(location, upper_left )
- )
- );
+ min_max_dist,
+ std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left),
+ FixedPointCoordinate::ApproximateEuclideanDistance(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);
+ inline bool Contains(const FixedPointCoordinate &location) const
+ {
+ const bool lats_contained = (location.lat > min_lat) && (location.lat < max_lat);
+ const 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.;
+ inline friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect)
+ {
+ out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION
+ << " " << rect.max_lat / COORDINATE_PRECISION << ","
+ << rect.max_lon / COORDINATE_PRECISION;
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) {}
+ 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];
+ };
+
+ private:
+ struct WrappedInputElement
+ {
+ explicit WrappedInputElement(const uint64_t _hilbert_value, const uint32_t _array_index)
+ : m_hilbert_value(_hilbert_value), m_array_index(_array_index)
+ {
+ }
+
+ WrappedInputElement() : m_hilbert_value(0), m_array_index(UINT_MAX) {}
- uint32_t m_array_index;
uint64_t m_hilbert_value;
+ uint32_t m_array_index;
- inline bool operator<(const WrappedInputElement & other) const {
+ inline bool operator<(const WrappedInputElement &other) const
+ {
return m_hilbert_value < other.m_hilbert_value;
}
};
- struct LeafNode {
+ struct LeafNode
+ {
LeafNode() : object_count(0) {}
uint32_t object_count;
- DataT objects[RTREE_LEAF_NODE_SIZE];
+ std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> objects;
};
- 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 float dist, const uint32_t n_id)
+ : min_dist(dist), node_id(n_id)
+ {
+ }
+ QueryCandidate() : min_dist(std::numeric_limits<float>::max()), node_id(UINT_MAX) {}
+ float min_dist;
+ uint32_t node_id;
+ inline bool operator<(const QueryCandidate &other) const
+ {
+ // Attn: this is reversed order. std::pq is a max pq!
+ return other.min_dist < min_dist;
+ }
};
- 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;
+ typedef boost::variant<TreeNode, EdgeDataT> IncrementalQueryNodeType;
+ struct IncrementalQueryCandidate
+ {
+ explicit IncrementalQueryCandidate(const float dist, const IncrementalQueryNodeType &node)
+ : min_dist(dist), node(node)
+ {
+ }
+
+ IncrementalQueryCandidate() : min_dist(std::numeric_limits<float>::max()) {}
+
+ inline bool operator<(const IncrementalQueryCandidate &other) const
+ {
+ // Attn: this is reversed order. std::pq is a max pq!
+ return other.min_dist < min_dist;
}
+
+ inline bool RepresentsTreeNode() const
+ {
+ return boost::apply_visitor(decide_type_visitor(), node);
+ }
+
+ float min_dist;
+ IncrementalQueryNodeType node;
+
+ private:
+ class decide_type_visitor : public boost::static_visitor<bool>
+ {
+ public:
+ bool operator()(const TreeNode &) const { return true; }
+
+ template<typename AnotherType>
+ bool operator()(const AnotherType &) const { return false; }
+ };
};
- std::vector<TreeNode> m_search_tree;
+ typename ShM<TreeNode, UseSharedMemory>::vector m_search_tree;
uint64_t m_element_count;
+ const std::string m_leaf_node_filename;
+ std::shared_ptr<CoordinateListT> m_coordinate_list;
+
+ public:
+ StaticRTree() = delete;
+ StaticRTree(const StaticRTree &) = delete;
+
+ // Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
+ explicit StaticRTree(std::vector<EdgeDataT> &input_data_vector,
+ const std::string tree_node_filename,
+ const std::string leaf_node_filename,
+ const std::vector<NodeInfo> &coordinate_list)
+ : m_element_count(input_data_vector.size()), m_leaf_node_filename(leaf_node_filename)
+ {
+ SimpleLogger().Write() << "constructing r-tree of " << m_element_count
+ << " edge elements build on-top of " << coordinate_list.size()
+ << " coordinates";
+
+ TIMER_START(construction);
+ std::vector<WrappedInputElement> input_wrapper_vector(m_element_count);
+
+ HilbertCode get_hilbert_number;
+
+ // generate auxiliary vector of hilbert-values
+ tbb::parallel_for(
+ tbb::blocked_range<uint64_t>(0, m_element_count),
+ [&input_data_vector, &input_wrapper_vector, &get_hilbert_number, &coordinate_list](
+ const tbb::blocked_range<uint64_t> &range)
+ {
+ for (uint64_t element_counter = range.begin(); element_counter != range.end();
+ ++element_counter)
+ {
+ WrappedInputElement ¤t_wrapper = input_wrapper_vector[element_counter];
+ current_wrapper.m_array_index = element_counter;
+
+ EdgeDataT const ¤t_element = input_data_vector[element_counter];
+
+ // Get Hilbert-Value for centroid in mercartor projection
+ FixedPointCoordinate current_centroid = EdgeDataT::Centroid(
+ FixedPointCoordinate(coordinate_list.at(current_element.u).lat,
+ coordinate_list.at(current_element.u).lon),
+ FixedPointCoordinate(coordinate_list.at(current_element.v).lat,
+ coordinate_list.at(current_element.v).lon));
+ current_centroid.lat =
+ COORDINATE_PRECISION * lat2y(current_centroid.lat / COORDINATE_PRECISION);
+
+ current_wrapper.m_hilbert_value = get_hilbert_number(current_centroid);
+ }
+ });
+
+ // open leaf file
+ boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary);
+ leaf_node_file.write((char *)&m_element_count, sizeof(uint64_t));
- 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");
+ // sort the hilbert-value representatives
+ tbb::parallel_sort(input_wrapper_vector.begin(), input_wrapper_vector.end());
std::vector<TreeNode> tree_nodes_in_level;
- //pack M elements into leaf node and write to leaf file
+ // pack M elements into leaf node and write to leaf file
uint64_t processed_objects_count = 0;
- while(processed_objects_count < m_element_count) {
+ 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];
+ // SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " <<
+ // (sizeof(TreeNode)*tree_size) << " bytes";
+ 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))
+ {
+ 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);
+ // 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, coordinate_list);
current_node.child_is_on_disk = true;
current_node.children[0] = tree_nodes_in_level.size();
- tree_nodes_in_level.push_back(current_node);
+ tree_nodes_in_level.emplace_back(current_node);
- //write leaf_node to leaf node file
- leaf_node_file.write((char*)¤t_leaf, sizeof(current_leaf));
+ // write leaf_node to leaf node file
+ leaf_node_file.write((char *)¤t_leaf, sizeof(current_leaf));
processed_objects_count += current_leaf.object_count;
}
- // INFO("wrote " << processed_objects_count << " leaf objects");
-
- //close leaf file
+ // 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);
+ while (1 < tree_nodes_in_level.size())
+ {
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()) {
+ 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
+ // 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 ¤t_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
+ m_search_tree.emplace_back(current_child_node);
+ // merge MBRs
+ parent_node.minimum_bounding_rectangle.MergeBoundingBoxes(
+ 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_next_level.emplace_back(parent_node);
}
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]);
+ // last remaining entry is the root node, store it
+ m_search_tree.emplace_back(tree_nodes_in_level[0]);
- //reverse and renumber tree to have root at index 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;
+
+ uint32_t search_tree_size = m_search_tree.size();
+ tbb::parallel_for(tbb::blocked_range<uint32_t>(0, search_tree_size),
+ [this, &search_tree_size](const tbb::blocked_range<uint32_t> &range)
+ {
+ for (uint32_t i = range.begin(); i != range.end(); ++i)
+ {
+ TreeNode ¤t_tree_node = this->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 = search_tree_size - old_id - 1;
+ current_tree_node.children[j] = new_id;
+ }
}
- }
+ });
+
+ // open tree file
+ boost::filesystem::ofstream tree_node_file(tree_node_filename, std::ios::binary);
- //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.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. << ")");
-*/
+
+ TIMER_STOP(construction);
+ SimpleLogger().Write() << "finished r-tree construction in " << TIMER_SEC(construction)
+ << " seconds";
}
- //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);
+ // Read-only operation for queries
+ explicit StaticRTree(const boost::filesystem::path &node_file,
+ const boost::filesystem::path &leaf_file,
+ const std::shared_ptr<CoordinateListT> coordinate_list)
+ : m_leaf_node_filename(leaf_file.string())
+ {
+ // open tree node file and load into RAM.
+ m_coordinate_list = coordinate_list;
+
+ if (!boost::filesystem::exists(node_file))
+ {
+ throw OSRMException("ram index file does not exist");
+ }
+ if (0 == boost::filesystem::file_size(node_file))
+ {
+ throw OSRMException("ram index file is empty");
+ }
+ boost::filesystem::ifstream tree_node_file(node_file, 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");
+ tree_node_file.read((char *)&tree_size, sizeof(uint32_t));
+
m_search_tree.resize(tree_size);
- tree_node_file.read((char*)&m_search_tree[0], sizeof(TreeNode)*tree_size);
+ if (tree_size > 0)
+ {
+ 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
+ if (!boost::filesystem::exists(leaf_file))
+ {
+ throw OSRMException("mem index file does not exist");
+ }
+ if (0 == boost::filesystem::file_size(leaf_file))
+ {
+ throw OSRMException("mem index file is empty");
+ }
- //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));
+ boost::filesystem::ifstream leaf_node_file(leaf_file, 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");
+ // SimpleLogger().Write() << tree_size << " nodes in search tree";
+ // SimpleLogger().Write() << 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;
+ explicit StaticRTree(TreeNode *tree_node_ptr,
+ const uint32_t number_of_nodes,
+ const boost::filesystem::path &leaf_file,
+ std::shared_ptr<CoordinateListT> coordinate_list)
+ : m_search_tree(tree_node_ptr, number_of_nodes), m_leaf_node_filename(leaf_file.string()),
+ m_coordinate_list(coordinate_list)
+ {
+ // open leaf node file and store thread specific pointer
+ if (!boost::filesystem::exists(leaf_file))
+ {
+ throw OSRMException("mem index file does not exist");
+ }
+ if (0 == boost::filesystem::file_size(leaf_file))
+ {
+ throw OSRMException("mem index file is empty");
+ }
- 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;
+ boost::filesystem::ifstream leaf_node_file(leaf_file, std::ios::binary);
+ leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
+ leaf_node_file.close();
+
+ if (thread_local_rtree_stream.get())
+ {
+ thread_local_rtree_stream->close();
+ }
+
+ // SimpleLogger().Write() << tree_size << " nodes in search tree";
+ // SimpleLogger().Write() << m_element_count << " elements in leafs";
+ }
+ // Read-only operation for queries
+
+ bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
+ FixedPointCoordinate &result_coordinate,
+ const unsigned zoom_level)
+ {
+ bool ignore_tiny_components = (zoom_level <= 14);
- _Coordinate nearest, current_start_coordinate, current_end_coordinate;
+ float min_dist = std::numeric_limits<float>::max();
+ float min_max_dist = std::numeric_limits<float>::max();
- //initialize queue with root element
+ // 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) {
+ traversal_queue.emplace(0.f, 0);
+
+ while (!traversal_queue.empty())
+ {
+ const QueryCandidate current_query_node = traversal_queue.top();
+ traversal_queue.pop();
+
+ const bool prune_downward = (current_query_node.min_dist >= min_max_dist);
+ const bool prune_upward = (current_query_node.min_dist >= min_dist);
+ if (!prune_downward && !prune_upward)
+ { // downward pruning
+ TreeNode ¤t_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) {
+ for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
+ {
+ EdgeDataT const ¤t_edge = current_leaf_node.objects[i];
+ if (ignore_tiny_components && current_edge.is_in_tiny_cc)
+ {
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,
- ¤t_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;
+ float current_minimum_distance =
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ input_coordinate.lat,
+ input_coordinate.lon,
+ m_coordinate_list->at(current_edge.u).lat,
+ m_coordinate_list->at(current_edge.u).lon);
+ if (current_minimum_distance < min_dist)
+ {
+ // found a new minimum
+ min_dist = current_minimum_distance;
+ result_coordinate = m_coordinate_list->at(current_edge.u);
+ }
+
+ current_minimum_distance =
+ FixedPointCoordinate::ApproximateEuclideanDistance(
+ input_coordinate.lat,
+ input_coordinate.lon,
+ m_coordinate_list->at(current_edge.v).lat,
+ m_coordinate_list->at(current_edge.v).lon);
+
+ if (current_minimum_distance < min_dist)
+ {
+ // found a new minimum
+ min_dist = current_minimum_distance;
+ result_coordinate = m_coordinate_list->at(current_edge.v);
}
}
- } 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;
+ }
+ else
+ {
+ min_max_dist = ExploreTreeNode(current_tree_node,
+ input_coordinate,
+ min_dist,
+ min_max_dist,
+ traversal_queue);
+ }
+ }
+ }
+ return result_coordinate.isValid();
+ }
+
+ // implementation of the Hjaltason/Samet query [3], a BFS traversal of the tree
+ bool
+ IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ std::vector<PhantomNode> &result_phantom_node_vector,
+ const unsigned zoom_level,
+ const unsigned number_of_results,
+ const unsigned max_checked_segments = 4*RTREE_LEAF_NODE_SIZE)
+ {
+ // TIMER_START(samet);
+ // SimpleLogger().Write(logDEBUG) << "searching for " << number_of_results << " results";
+ std::vector<float> min_found_distances(number_of_results, std::numeric_limits<float>::max());
+
+ unsigned dequeues = 0;
+ unsigned inspected_mbrs = 0;
+ unsigned loaded_leafs = 0;
+ unsigned inspected_segments = 0;
+ unsigned pruned_elements = 0;
+ unsigned ignored_segments = 0;
+ unsigned ignored_mbrs = 0;
+
+ unsigned number_of_results_found_in_big_cc = 0;
+ unsigned number_of_results_found_in_tiny_cc = 0;
+
+ // initialize queue with root element
+ std::priority_queue<IncrementalQueryCandidate> traversal_queue;
+ traversal_queue.emplace(0.f, m_search_tree[0]);
+
+ while (!traversal_queue.empty())
+ {
+ const IncrementalQueryCandidate current_query_node = traversal_queue.top();
+ traversal_queue.pop();
+
+ ++dequeues;
+
+ const float current_min_dist = min_found_distances[number_of_results-1];
+
+ if (current_query_node.min_dist > current_min_dist)
+ {
+ ++pruned_elements;
+ continue;
+ }
+
+ if (current_query_node.RepresentsTreeNode())
+ {
+ const TreeNode & current_tree_node = boost::get<TreeNode>(current_query_node.node);
+ if (current_tree_node.child_is_on_disk)
+ {
+ ++loaded_leafs;
+ // SimpleLogger().Write(logDEBUG) << "loading leaf: " << current_tree_node.children[0] << " w/ mbr [" <<
+ // current_tree_node.minimum_bounding_rectangle.min_lat/COORDINATE_PRECISION << "," <<
+ // current_tree_node.minimum_bounding_rectangle.min_lon/COORDINATE_PRECISION << "," <<
+ // current_tree_node.minimum_bounding_rectangle.max_lat/COORDINATE_PRECISION << "-" <<
+ // current_tree_node.minimum_bounding_rectangle.max_lon/COORDINATE_PRECISION << "]";
+
+ LeafNode current_leaf_node;
+ LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node);
+ // Add all objects from leaf into queue
+ for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
+ {
+ const auto ¤t_edge = current_leaf_node.objects[i];
+ const float current_perpendicular_distance =
+ FixedPointCoordinate::ComputePerpendicularDistance(
+ m_coordinate_list->at(current_edge.u),
+ m_coordinate_list->at(current_edge.v),
+ input_coordinate);
+ // distance must be non-negative
+ BOOST_ASSERT(0. <= current_perpendicular_distance);
+
+ if (current_perpendicular_distance < current_min_dist)
+ {
+ traversal_queue.emplace(current_perpendicular_distance, current_edge);
}
- if (current_min_dist > min_max_dist) {
- continue;
+ else
+ {
+ ++ignored_segments;
}
- if (current_min_dist > min_dist) { //upward pruning
- continue;
+ }
+ // SimpleLogger().Write(logDEBUG) << "added " << current_leaf_node.object_count << " roads into queue of " << traversal_queue.size();
+ }
+ else
+ {
+ ++inspected_mbrs;
+ // explore inner node
+ // SimpleLogger().Write(logDEBUG) << "explore inner node w/ mbr [" <<
+ // current_tree_node.minimum_bounding_rectangle.min_lat/COORDINATE_PRECISION << "," <<
+ // current_tree_node.minimum_bounding_rectangle.min_lon/COORDINATE_PRECISION << "," <<
+ // current_tree_node.minimum_bounding_rectangle.max_lat/COORDINATE_PRECISION << "-" <<
+ // current_tree_node.minimum_bounding_rectangle.max_lon/COORDINATE_PRECISION << "," << "]";
+
+ // for each child mbr
+ for (uint32_t i = 0; i < current_tree_node.child_count; ++i)
+ {
+ const int32_t child_id = current_tree_node.children[i];
+ const TreeNode &child_tree_node = m_search_tree[child_id];
+ const RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
+ const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate);
+
+ // TODO - enough elements found, i.e. nearest distance > maximum distance?
+ // ie. some measure of 'confidence of accuracy'
+
+ // check if it needs to be explored by mindist
+ if (lower_bound_to_element < current_min_dist)
+ {
+ traversal_queue.emplace(lower_bound_to_element, child_tree_node);
+ }
+ else
+ {
+ ++ignored_mbrs;
}
- traversal_queue.push(QueryCandidate(child_id, current_min_dist));
}
+ // SimpleLogger().Write(logDEBUG) << "added " << current_tree_node.child_count << " mbrs into queue of " << traversal_queue.size();
}
}
- }
+ else
+ {
+ ++inspected_segments;
+ // inspecting an actual road segment
+ const EdgeDataT & current_segment = boost::get<EdgeDataT>(current_query_node.node);
+
+ // don't collect too many results from small components
+ if (number_of_results_found_in_big_cc == number_of_results && !current_segment.is_in_tiny_cc)
+ {
+ continue;
+ }
- 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;
+ // don't collect too many results from big components
+ if (number_of_results_found_in_tiny_cc == number_of_results && current_segment.is_in_tiny_cc)
+ {
+ continue;
+ }
- //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;
- }
+ // check if it is smaller than what we had before
+ float current_ratio = 0.;
+ FixedPointCoordinate foot_point_coordinate_on_segment;
+ const float current_perpendicular_distance =
+ FixedPointCoordinate::ComputePerpendicularDistance(
+ m_coordinate_list->at(current_segment.u),
+ m_coordinate_list->at(current_segment.v),
+ input_coordinate,
+ foot_point_coordinate_on_segment,
+ current_ratio);
+
+ BOOST_ASSERT(0. <= current_perpendicular_distance);
+
+ if ((current_perpendicular_distance < current_min_dist) &&
+ !EpsilonCompare(current_perpendicular_distance, current_min_dist))
+ {
+ // store phantom node in result vector
+ result_phantom_node_vector.emplace_back(
+ current_segment.forward_edge_based_node_id,
+ current_segment.reverse_edge_based_node_id,
+ current_segment.name_id,
+ current_segment.forward_weight,
+ current_segment.reverse_weight,
+ current_segment.forward_offset,
+ current_segment.reverse_offset,
+ current_segment.packed_geometry_id,
+ foot_point_coordinate_on_segment,
+ current_segment.fwd_segment_position);
+
+ // Hack to fix rounding errors and wandering via nodes.
+ FixUpRoundingIssue(input_coordinate, result_phantom_node_vector.back());
+
+ // set forward and reverse weights on the phantom node
+ SetForwardAndReverseWeightsOnPhantomNode(current_segment,
+ result_phantom_node_vector.back());
+
+ // do we have results only in a small scc
+ if (current_segment.is_in_tiny_cc)
+ {
+ ++number_of_results_found_in_tiny_cc;
+ }
+ else
+ {
+ // found an element in a large component
+ min_found_distances[number_of_results_found_in_big_cc] = current_perpendicular_distance;
+ ++number_of_results_found_in_big_cc;
+ // SimpleLogger().Write(logDEBUG) << std::setprecision(8) << foot_point_coordinate_on_segment << " at " << current_perpendicular_distance;
+ }
+ }
+ }
- 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;
+ // TODO add indicator to prune if maxdist > threshold
+ if (number_of_results == number_of_results_found_in_big_cc || inspected_segments >= max_checked_segments)
+ {
+ // SimpleLogger().Write(logDEBUG) << "flushing queue of " << traversal_queue.size() << " elements";
+ // work-around for traversal_queue.clear();
+ traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
+ }
+ }
+ // for (const PhantomNode& result_node : result_phantom_node_vector)
+ // {
+ // SimpleLogger().Write(logDEBUG) << std::setprecision(8) << "found location " << result_node.forward_node_id << " at " << result_node.location;
+ // }
+ // SimpleLogger().Write(logDEBUG) << "dequeues: " << dequeues;
+ // SimpleLogger().Write(logDEBUG) << "inspected_mbrs: " << inspected_mbrs;
+ // SimpleLogger().Write(logDEBUG) << "loaded_leafs: " << loaded_leafs;
+ // SimpleLogger().Write(logDEBUG) << "inspected_segments: " << inspected_segments;
+ // SimpleLogger().Write(logDEBUG) << "pruned_elements: " << pruned_elements;
+ // SimpleLogger().Write(logDEBUG) << "ignored_segments: " << ignored_segments;
+ // SimpleLogger().Write(logDEBUG) << "ignored_mbrs: " << ignored_mbrs;
+
+ // SimpleLogger().Write(logDEBUG) << "number_of_results_found_in_big_cc: " << number_of_results_found_in_big_cc;
+ // SimpleLogger().Write(logDEBUG) << "number_of_results_found_in_tiny_cc: " << number_of_results_found_in_tiny_cc;
+ // TIMER_STOP(samet);
+ // SimpleLogger().Write() << "query took " << TIMER_MSEC(samet) << "ms";
+
+ // if we found an element in either category, then we are good
+ return !result_phantom_node_vector.empty();
}
- */
- bool FindPhantomNodeForCoordinate(
- const _Coordinate & input_coordinate,
- PhantomNode & result_phantom_node,
- const unsigned zoom_level
- ) {
+ bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &result_phantom_node,
+ const unsigned zoom_level)
+ {
- bool ignore_tiny_components = (zoom_level <= 14);
- DataT nearest_edge;
+ std::vector<PhantomNode> result_phantom_node_vector;
+ IncrementalFindPhantomNodeForCoordinate(input_coordinate, result_phantom_node_vector, zoom_level, 2);
+ // if (!result_phantom_node_vector.empty())
+ // {
+ // result_phantom_node = result_phantom_node_vector.front();
+ // }
+ // return !result_phantom_node_vector.empty();
- 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;
+ const bool ignore_tiny_components = (zoom_level <= 14);
+ EdgeDataT nearest_edge;
- _Coordinate nearest, current_start_coordinate, current_end_coordinate;
+ float min_dist = std::numeric_limits<float>::max();
+ float min_max_dist = std::numeric_limits<float>::max();
- //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) {
+ traversal_queue.emplace(0.f, 0);
+
+ while (!traversal_queue.empty())
+ {
+ const QueryCandidate current_query_node = traversal_queue.top();
+ traversal_queue.pop();
+
+ const bool prune_downward = (current_query_node.min_dist > min_max_dist);
+ const bool prune_upward = (current_query_node.min_dist > min_dist);
+ if (!prune_downward && !prune_upward)
+ { // downward pruning
+ const TreeNode ¤t_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()) {
+ for (uint32_t i = 0; i < current_leaf_node.object_count; ++i)
+ {
+ const EdgeDataT ¤t_edge = current_leaf_node.objects[i];
+ if (ignore_tiny_components && current_edge.is_in_tiny_cc)
+ {
continue;
}
- double current_ratio = 0.;
- double current_perpendicular_distance = ComputePerpendicularDistance(
+ float current_ratio = 0.;
+ FixedPointCoordinate nearest;
+ const float current_perpendicular_distance =
+ FixedPointCoordinate::ComputePerpendicularDistance(
+ m_coordinate_list->at(current_edge.u),
+ m_coordinate_list->at(current_edge.v),
input_coordinate,
- _Coordinate(current_edge.lat1, current_edge.lon1),
- _Coordinate(current_edge.lat2, current_edge.lon2),
nearest,
- ¤t_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
+ current_ratio);
+
+ BOOST_ASSERT(0. <= current_perpendicular_distance);
+
+ if ((current_perpendicular_distance < min_dist) &&
+ !EpsilonCompare(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;
+ result_phantom_node = {current_edge.forward_edge_based_node_id,
+ current_edge.reverse_edge_based_node_id,
+ current_edge.name_id,
+ current_edge.forward_weight,
+ current_edge.reverse_weight,
+ current_edge.forward_offset,
+ current_edge.reverse_offset,
+ current_edge.packed_geometry_id,
+ nearest,
+ current_edge.fwd_segment_position};
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));
- }
+ }
+ else
+ {
+ min_max_dist = ExploreTreeNode(current_tree_node,
+ input_coordinate,
+ min_dist,
+ min_max_dist,
+ traversal_queue);
}
}
}
- 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);
+ if (result_phantom_node.location.isValid())
+ {
+ // Hack to fix rounding errors and wandering via nodes.
+ FixUpRoundingIssue(input_coordinate, result_phantom_node);
+
+ // set forward and reverse weights on the phantom node
+ SetForwardAndReverseWeightsOnPhantomNode(nearest_edge, result_phantom_node);
}
- result_phantom_node.ratio = ratio;
+ return result_phantom_node.location.isValid();
+ }
- //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;
+ private:
+
+ inline void SetForwardAndReverseWeightsOnPhantomNode(const EdgeDataT & nearest_edge,
+ PhantomNode &result_phantom_node) const
+ {
+ const float distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
+ m_coordinate_list->at(nearest_edge.u), result_phantom_node.location);
+ const float distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
+ m_coordinate_list->at(nearest_edge.u), m_coordinate_list->at(nearest_edge.v));
+ const float ratio = std::min(1.f, distance_1 / distance_2);
+
+ if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
+ {
+ result_phantom_node.forward_weight *= ratio;
}
- if(std::abs(input_coordinate.lat - result_phantom_node.location.lat) == 1) {
- result_phantom_node.location.lat = input_coordinate.lat;
+ if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
+ {
+ result_phantom_node.reverse_weight *= (1.f - ratio);
}
+ }
-// 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;
-
+ // fixup locations if too close to inputs
+ inline void FixUpRoundingIssue(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &result_phantom_node) const
+ {
+ if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon))
+ {
+ result_phantom_node.location.lon = input_coordinate.lon;
+ }
+ if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat))
+ {
+ result_phantom_node.location.lat = input_coordinate.lat;
+ }
}
-/*
- //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));
- }
- }
+ template <class QueueT>
+ inline float ExploreTreeNode(const TreeNode &parent,
+ const FixedPointCoordinate &input_coordinate,
+ const float min_dist,
+ const float min_max_dist,
+ QueueT &traversal_queue)
+ {
+ float new_min_max_dist = min_max_dist;
+ // traverse children, prune if global mindist is smaller than local one
+ for (uint32_t i = 0; i < parent.child_count; ++i)
+ {
+ const int32_t child_id = parent.children[i];
+ const TreeNode &child_tree_node = m_search_tree[child_id];
+ const RectangleT &child_rectangle = child_tree_node.minimum_bounding_rectangle;
+ const float lower_bound_to_element = child_rectangle.GetMinDist(input_coordinate);
+ const float upper_bound_to_element = child_rectangle.GetMinMaxDist(input_coordinate);
+ new_min_max_dist = std::min(new_min_max_dist, upper_bound_to_element);
+ if (lower_bound_to_element > new_min_max_dist)
+ {
+ continue;
+ }
+ if (lower_bound_to_element > min_dist)
+ {
+ continue;
}
+ traversal_queue.emplace(lower_bound_to_element, child_id);
}
- INFO("mindist: " << min_dist << ", io's: " << io_count << ", touched nodes: " << explored_tree_nodes_count);
- return found_return_value;
+ return new_min_max_dist;
}
- */
-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()) {
+
+ 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 boost::filesystem::ifstream(
+ m_leaf_node_filename, std::ios::in | std::ios::binary));
+ }
+ if (!thread_local_rtree_stream->good())
+ {
thread_local_rtree_stream->clear(std::ios::goodbit);
- DEBUG("Resetting stale filestream");
+ SimpleLogger().Write(logDEBUG) << "Resetting stale filestream";
}
- uint64_t seek_pos = sizeof(uint64_t) + leaf_id*sizeof(LeafNode);
+ const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
thread_local_rtree_stream->seekg(seek_pos);
+ BOOST_ASSERT_MSG(thread_local_rtree_stream->good(),
+ "Seeking to position in leaf file failed.");
thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode));
+ BOOST_ASSERT_MSG(thread_local_rtree_stream->good(), "Reading from leaf file failed.");
}
- 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 {
+ inline bool EdgesAreEquivalent(const FixedPointCoordinate &a,
+ const FixedPointCoordinate &b,
+ const FixedPointCoordinate &c,
+ const FixedPointCoordinate &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);
+ template <typename FloatT> inline bool EpsilonCompare(const FloatT d1, const FloatT d2) const
+ {
+ return (std::abs(d1 - d2) < std::numeric_limits<FloatT>::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_ */
+//[3] "Distance Browsing in Spatial Databases"; G. Hjaltason, H. Samet; 1999; ACM Trans. DB Sys
+// Vol.24 No.2, pp.265-318
+#endif // STATICRTREE_H
diff --git a/DataStructures/TimingUtil.h b/DataStructures/TimingUtil.h
deleted file mode 100644
index 6e980e2..0000000
--- a/DataStructures/TimingUtil.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- 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 TIMINGUTIL_H_
-#define TIMINGUTIL_H_
-
-#include <climits>
-#include <cstdlib>
-
-
-#ifdef _WIN32
- #include <sys/timeb.h>
- #include <sys/types.h>
- #include <winsock.h>
- void gettimeofday(struct timeval* t,void* timezone)
- { struct _timeb timebuffer;
- _ftime( &timebuffer );
- t->tv_sec=timebuffer.time;
- t->tv_usec=1000*timebuffer.millitm;
- }
-#else
- #include <sys/time.h>
-#endif
-
-/** Returns a timestamp (now) in seconds (incl. a fractional part). */
-static inline double get_timestamp() {
- struct timeval tp;
- gettimeofday(&tp, NULL);
- return double(tp.tv_sec) + tp.tv_usec / 1000000.;
-}
-
-
-#endif /* TIMINGUTIL_H_ */
diff --git a/DataStructures/TurnInstructions.h b/DataStructures/TurnInstructions.h
index 3284d9b..61de3b1 100644
--- a/DataStructures/TurnInstructions.h
+++ b/DataStructures/TurnInstructions.h
@@ -1,90 +1,90 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef TURNINSTRUCTIONS_H_
-#define TURNINSTRUCTIONS_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <boost/noncopyable.hpp>
+*/
-typedef unsigned char TurnInstruction;
+#ifndef TURN_INSTRUCTIONS_H
+#define TURN_INSTRUCTIONS_H
-//This is a hack until c++0x is available enough to use scoped enums
-struct TurnInstructionsClass : boost::noncopyable {
-
- const static TurnInstruction NoTurn = 0; //Give no instruction at all
- const static TurnInstruction GoStraight = 1; //Tell user to go straight!
- const static TurnInstruction TurnSlightRight = 2;
- const static TurnInstruction TurnRight = 3;
- const static TurnInstruction TurnSharpRight = 4;
- const static TurnInstruction UTurn = 5;
- const static TurnInstruction TurnSharpLeft = 6;
- const static TurnInstruction TurnLeft = 7;
- const static TurnInstruction TurnSlightLeft = 8;
- const static TurnInstruction ReachViaPoint = 9;
- const static TurnInstruction HeadOn = 10;
- const static TurnInstruction EnterRoundAbout = 11;
- const static TurnInstruction LeaveRoundAbout = 12;
- const static TurnInstruction StayOnRoundAbout = 13;
- const static TurnInstruction StartAtEndOfStreet = 14;
- const static TurnInstruction ReachedYourDestination = 15;
- const static TurnInstruction EnterAgainstAllowedDirection = 16;
- const static TurnInstruction LeaveAgainstAllowedDirection = 17;
-
- const static TurnInstruction AccessRestrictionFlag = 128;
- const static TurnInstruction InverseAccessRestrictionFlag = 0x7f; // ~128 does not work without a warning.
+enum class TurnInstruction : unsigned char
+{
+ NoTurn = 0, GoStraight, TurnSlightRight, TurnRight, TurnSharpRight, UTurn,
+ TurnSharpLeft, TurnLeft, TurnSlightLeft, ReachViaPoint, HeadOn, EnterRoundAbout,
+ LeaveRoundAbout, StayOnRoundAbout, StartAtEndOfStreet, ReachedYourDestination,
+ EnterAgainstAllowedDirection, LeaveAgainstAllowedDirection,
+ InverseAccessRestrictionFlag = 127,
+ AccessRestrictionFlag = 128,
+ AccessRestrictionPenalty = 129
+};
- const static int AccessRestrictionPenalty = 1 << 15; //unrelated to the bit set in the restriction flag
+struct TurnInstructionsClass
+{
+ TurnInstructionsClass() = delete;
+ TurnInstructionsClass(const TurnInstructionsClass&) = delete;
- static inline TurnInstruction GetTurnDirectionOfInstruction( const double angle ) {
- if(angle >= 23 && angle < 67) {
- return TurnSharpRight;
+ static inline TurnInstruction GetTurnDirectionOfInstruction(const double angle)
+ {
+ if (angle >= 23 && angle < 67)
+ {
+ return TurnInstruction::TurnSharpRight;
}
- if (angle >= 67 && angle < 113) {
- return TurnRight;
+ if (angle >= 67 && angle < 113)
+ {
+ return TurnInstruction::TurnRight;
}
- if (angle >= 113 && angle < 158) {
- return TurnSlightRight;
+ if (angle >= 113 && angle < 158)
+ {
+ return TurnInstruction::TurnSlightRight;
}
- if (angle >= 158 && angle < 202) {
- return GoStraight;
+ if (angle >= 158 && angle < 202)
+ {
+ return TurnInstruction::GoStraight;
}
- if (angle >= 202 && angle < 248) {
- return TurnSlightLeft;
+ if (angle >= 202 && angle < 248)
+ {
+ return TurnInstruction::TurnSlightLeft;
}
- if (angle >= 248 && angle < 292) {
- return TurnLeft;
+ if (angle >= 248 && angle < 292)
+ {
+ return TurnInstruction::TurnLeft;
}
- if (angle >= 292 && angle < 336) {
- return TurnSharpLeft;
+ if (angle >= 292 && angle < 336)
+ {
+ return TurnInstruction::TurnSharpLeft;
}
- return UTurn;
+ return TurnInstruction::UTurn;
}
- static inline bool TurnIsNecessary ( const short turnInstruction ) {
- if(NoTurn == turnInstruction || StayOnRoundAbout == turnInstruction)
+ static inline bool TurnIsNecessary(const TurnInstruction turn_instruction)
+ {
+ if (TurnInstruction::NoTurn == turn_instruction || TurnInstruction::StayOnRoundAbout == turn_instruction)
+ {
return false;
+ }
return true;
}
-
};
-static TurnInstructionsClass TurnInstructions;
-
-#endif /* TURNINSTRUCTIONS_H_ */
+#endif /* TURN_INSTRUCTIONS_H */
diff --git a/DataStructures/XORFastHash.h b/DataStructures/XORFastHash.h
index c3c1470..ee36830 100644
--- a/DataStructures/XORFastHash.h
+++ b/DataStructures/XORFastHash.h
@@ -1,31 +1,39 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef FASTXORHASH_H_
-#define FASTXORHASH_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef XOR_FAST_HASH_H
+#define XOR_FAST_HASH_H
#include <algorithm>
#include <vector>
/*
- This is an implementation of Tabulation hashing, which has suprising properties like universality.
+ This is an implementation of Tabulation hashing, which has suprising properties like
+ universality.
The space requirement is 2*2^16 = 256 kb of memory, which fits into L2 cache.
Evaluation boils down to 10 or less assembly instruction on any recent X86 CPU:
@@ -41,49 +49,61 @@ or see http://www.gnu.org/licenses/agpl.txt.
10: ret
*/
-class XORFastHash { //65k entries
+class XORFastHash
+{ // 65k entries
std::vector<unsigned short> table1;
std::vector<unsigned short> table2;
-public:
- XORFastHash() {
+
+ public:
+ XORFastHash()
+ {
table1.resize(2 << 16);
table2.resize(2 << 16);
- for(unsigned i = 0; i < (2 << 16); ++i) {
- table1[i] = i; table2[i] = i;
+ for (unsigned i = 0; i < (2 << 16); ++i)
+ {
+ table1[i] = i;
+ table2[i] = i;
}
std::random_shuffle(table1.begin(), table1.end());
std::random_shuffle(table2.begin(), table2.end());
}
- inline unsigned short operator()(const unsigned originalValue) const {
+ inline unsigned short operator()(const unsigned originalValue) const
+ {
unsigned short lsb = ((originalValue) & 0xffff);
unsigned short msb = (((originalValue) >> 16) & 0xffff);
return table1[lsb] ^ table2[msb];
}
};
-class XORMiniHash { //256 entries
+class XORMiniHash
+{ // 256 entries
std::vector<unsigned char> table1;
std::vector<unsigned char> table2;
std::vector<unsigned char> table3;
std::vector<unsigned char> table4;
-public:
- XORMiniHash() {
+ public:
+ XORMiniHash()
+ {
table1.resize(1 << 8);
table2.resize(1 << 8);
table3.resize(1 << 8);
table4.resize(1 << 8);
- for(unsigned i = 0; i < (1 << 8); ++i) {
- table1[i] = i; table2[i] = i;
- table3[i] = i; table4[i] = i;
+ for (unsigned i = 0; i < (1 << 8); ++i)
+ {
+ table1[i] = i;
+ table2[i] = i;
+ table3[i] = i;
+ table4[i] = i;
}
std::random_shuffle(table1.begin(), table1.end());
std::random_shuffle(table2.begin(), table2.end());
std::random_shuffle(table3.begin(), table3.end());
std::random_shuffle(table4.begin(), table4.end());
}
- unsigned char operator()(const unsigned originalValue) const {
+ unsigned char operator()(const unsigned originalValue) const
+ {
unsigned char byte1 = ((originalValue) & 0xff);
unsigned char byte2 = ((originalValue >> 8) & 0xff);
unsigned char byte3 = ((originalValue >> 16) & 0xff);
@@ -92,4 +112,4 @@ public:
}
};
-#endif /* FASTXORHASH_H_ */
+#endif // XOR_FAST_HASH_H
diff --git a/DataStructures/XORFastHashStorage.h b/DataStructures/XORFastHashStorage.h
index 91820e1..abdb9ac 100644
--- a/DataStructures/XORFastHashStorage.h
+++ b/DataStructures/XORFastHashStorage.h
@@ -1,80 +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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef XORFASTHASHSTORAGE_H_
-#define XORFASTHASHSTORAGE_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <climits>
-#include <vector>
-#include <bitset>
+*/
+
+#ifndef XOR_FAST_HASH_STORAGE_H
+#define XOR_FAST_HASH_STORAGE_H
#include "XORFastHash.h"
-template< typename NodeID, typename Key >
-class XORFastHashStorage {
-public:
- struct HashCell{
+#include <limits>
+#include <vector>
+
+template <typename NodeID, typename Key> class XORFastHashStorage
+{
+ public:
+ struct HashCell
+ {
Key key;
NodeID id;
unsigned time;
- HashCell() : key(UINT_MAX), id(UINT_MAX), time(UINT_MAX) {}
+ HashCell()
+ : key(std::numeric_limits<unsigned>::max()), id(std::numeric_limits<unsigned>::max()),
+ time(std::numeric_limits<unsigned>::max())
+ {
+ }
- HashCell(const HashCell & other) : key(other.key), id(other.id), time(other.time) { }
+ HashCell(const HashCell &other) : key(other.key), id(other.id), time(other.time) {}
- inline operator Key() const {
- return key;
- }
+ inline operator Key() const { return key; }
- inline void operator=(const Key & keyToInsert) {
- key = keyToInsert;
- }
+ inline void operator=(const Key &key_to_insert) { key = key_to_insert; }
};
- XORFastHashStorage( size_t ) : positions(2<<16), currentTimestamp(0) { }
+ explicit XORFastHashStorage(size_t) : positions(2 << 16), current_timestamp(0) {}
- inline HashCell& operator[]( const NodeID node ) {
- unsigned short position = fastHash(node);
- while((positions[position].time == currentTimestamp) && (positions[position].id != node)){
- ++position %= (2<<16);
+ inline HashCell &operator[](const NodeID node)
+ {
+ unsigned short position = fast_hasher(node);
+ while ((positions[position].time == current_timestamp) && (positions[position].id != node))
+ {
+ ++position %= (2 << 16);
}
positions[position].id = node;
- positions[position].time = currentTimestamp;
+ positions[position].time = current_timestamp;
return positions[position];
}
- inline void Clear() {
- ++currentTimestamp;
- if(UINT_MAX == currentTimestamp) {
+ inline void Clear()
+ {
+ ++current_timestamp;
+ if (std::numeric_limits<unsigned>::max() == current_timestamp)
+ {
positions.clear();
- positions.resize((2<<16));
+ positions.resize((2 << 16));
}
}
-private:
- XORFastHashStorage() : positions(2<<16), currentTimestamp(0) {}
+ private:
+ XORFastHashStorage() : positions(2 << 16), current_timestamp(0) {}
std::vector<HashCell> positions;
- XORFastHash fastHash;
- unsigned currentTimestamp;
+ XORFastHash fast_hasher;
+ unsigned current_timestamp;
};
-
-#endif /* XORFASTHASHSTORAGE_H_ */
-
+#endif // XOR_FAST_HASH_STORAGE_H
diff --git a/Descriptors/BaseDescriptor.h b/Descriptors/BaseDescriptor.h
index 2ead8bd..d06b9b6 100644
--- a/Descriptors/BaseDescriptor.h
+++ b/Descriptors/BaseDescriptor.h
@@ -1,55 +1,61 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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 BASE_DESCRIPTOR_H_
-#define BASE_DESCRIPTOR_H_
-
-#include <cassert>
-#include <cmath>
-#include <cstdio>
-#include <string>
-#include <vector>
-#include "../typedefs.h"
-#include "../DataStructures/HashTable.h"
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef BASE_DESCRIPTOR_H
+#define BASE_DESCRIPTOR_H
+
#include "../DataStructures/PhantomNodes.h"
-#include "../DataStructures/SearchEngine.h"
-#include "../Util/StringUtil.h"
+#include "../DataStructures/RawRouteData.h"
+#include "../typedefs.h"
-#include "../Plugins/RawRouteData.h"
+#include <osrm/Reply.h>
+
+#include <string>
+#include <vector>
-struct _DescriptorConfig {
- _DescriptorConfig() : instructions(true), geometry(true), encodeGeometry(true), z(18) {}
+struct DescriptorConfig
+{
+ DescriptorConfig() : instructions(true), geometry(true), encode_geometry(true), zoom_level(18)
+ {
+ }
bool instructions;
bool geometry;
- bool encodeGeometry;
- unsigned short z;
+ bool encode_geometry;
+ unsigned short zoom_level;
};
-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, SearchEngine &sEngine) = 0;
- virtual void SetConfig(const _DescriptorConfig & config) = 0;
+template <class DataFacadeT> class BaseDescriptor
+{
+ public:
+ BaseDescriptor() {}
+ // Maybe someone can explain the pure virtual destructor thing to me (dennis)
+ virtual ~BaseDescriptor() {}
+ virtual void Run(const RawRouteData &raw_route, http::Reply &reply) = 0;
+ virtual void SetConfig(const DescriptorConfig &config) = 0;
};
-#endif /* BASE_DESCRIPTOR_H_ */
+#endif // BASE_DESCRIPTOR_H
diff --git a/Descriptors/DescriptionFactory.cpp b/Descriptors/DescriptionFactory.cpp
index b1f2f85..5c9cbef 100644
--- a/Descriptors/DescriptionFactory.cpp
+++ b/Descriptors/DescriptionFactory.cpp
@@ -1,210 +1,93 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#include "DescriptionFactory.h"
-
-DescriptionFactory::DescriptionFactory() : entireLength(0) { }
-
-DescriptionFactory::~DescriptionFactory() { }
-
-inline double DescriptionFactory::DegreeToRadian(const double degree) const {
- return degree * (M_PI/180);
-}
-
-inline double DescriptionFactory::RadianToDegree(const double radian) const {
- return radian * (180/M_PI);
-}
-
-double DescriptionFactory::GetBearing(const _Coordinate& A, const _Coordinate& B) const {
- double deltaLong = DegreeToRadian(B.lon/100000. - A.lon/100000.);
-
- double lat1 = DegreeToRadian(A.lat/100000.);
- double lat2 = DegreeToRadian(B.lat/100000.);
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- double y = sin(deltaLong) * cos(lat2);
- double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(deltaLong);
- double result = RadianToDegree(atan2(y, x));
- while(result <= 0.)
- result += 360.;
- while(result >= 360.)
- result -= 360.;
+*/
- return result;
-}
+#include "DescriptionFactory.h"
-void DescriptionFactory::SetStartSegment(const PhantomNode & _startPhantom) {
- startPhantom = _startPhantom;
- AppendSegment(_startPhantom.location, _PathData(0, _startPhantom.nodeBasedEdgeNameID, 10, _startPhantom.weight1));
-}
+#include <osrm/Coordinate.h>
-void DescriptionFactory::SetEndSegment(const PhantomNode & _targetPhantom) {
- targetPhantom = _targetPhantom;
- pathDescription.push_back(SegmentInformation(_targetPhantom.location, _targetPhantom.nodeBasedEdgeNameID, 0, _targetPhantom.weight1, 0, true) );
-}
+#include "../typedefs.h"
+#include "../Algorithms/PolylineCompressor.h"
+#include "../DataStructures/PhantomNodes.h"
+#include "../DataStructures/RawRouteData.h"
+#include "../DataStructures/SegmentInformation.h"
+#include "../DataStructures/TurnInstructions.h"
-void DescriptionFactory::AppendSegment(const _Coordinate & coordinate, const _PathData & data ) {
- if(1 == pathDescription.size() && pathDescription.back().location == coordinate) {
- pathDescription.back().nameID = data.nameID;
- } else {
- pathDescription.push_back(SegmentInformation(coordinate, data.nameID, 0, data.durationOfSegment, data.turnInstruction) );
- }
-}
+DescriptionFactory::DescriptionFactory() : entireLength(0) { via_indices.push_back(0); }
-void DescriptionFactory::AppendEncodedPolylineString(std::string & output, bool isEncoded) {
- if(isEncoded)
- pc.printEncodedString(pathDescription, output);
- else
- pc.printUnencodedString(pathDescription, output);
-}
+std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }
-void DescriptionFactory::AppendEncodedPolylineString(std::string &output) {
- pc.printEncodedString(pathDescription, output);
+void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool traversed_in_reverse)
+{
+ start_phantom = source;
+ const EdgeWeight segment_duration =
+ (traversed_in_reverse ? source.reverse_weight : source.forward_weight);
+ AppendSegment(source.location,
+ PathData(0, source.name_id, TurnInstruction::HeadOn, segment_duration));
+ BOOST_ASSERT(path_description.back().duration == segment_duration);
}
-void DescriptionFactory::AppendUnencodedPolylineString(std::string &output) {
- pc.printUnencodedString(pathDescription, output);
+void DescriptionFactory::SetEndSegment(const PhantomNode &target, const bool traversed_in_reverse)
+{
+ target_phantom = target;
+ const EdgeWeight segment_duration =
+ (traversed_in_reverse ? target.reverse_weight : target.forward_weight);
+ path_description.emplace_back(
+ target.location, target.name_id, segment_duration, 0.f, TurnInstruction::NoTurn, true, true);
+ BOOST_ASSERT(path_description.back().duration == segment_duration);
}
-void DescriptionFactory::Run(const SearchEngine &sEngine, const unsigned zoomLevel) {
-
- if(0 == pathDescription.size())
+void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
+ const PathData &path_point)
+{
+ if ((1 == path_description.size()) && (path_description.back().location == coordinate))
+ {
+ path_description.back().name_id = path_point.name_id;
return;
-
-// unsigned entireLength = 0;
- /** starts at index 1 */
- pathDescription[0].length = 0;
- for(unsigned i = 1; i < pathDescription.size(); ++i) {
- pathDescription[i].length = ApproximateDistanceByEuclid(pathDescription[i-1].location, pathDescription[i].location);
}
- double lengthOfSegment = 0;
- unsigned durationOfSegment = 0;
- unsigned indexOfSegmentBegin = 0;
-
- std::string string0 = sEngine.GetEscapedNameForNameID(pathDescription[0].nameID);
- std::string string1;
-
-
- /*Simplify turn instructions
- Input :
- 10. Turn left on B 36 for 20 km
- 11. Continue on B 35; B 36 for 2 km
- 12. Continue on B 36 for 13 km
-
- becomes:
- 10. Turn left on B 36 for 35 km
- */
-//TODO: rework to check only end and start of string.
-// stl string is way to expensive
-
-// unsigned lastTurn = 0;
-// for(unsigned i = 1; i < pathDescription.size(); ++i) {
-// string1 = sEngine.GetEscapedNameForNameID(pathDescription[i].nameID);
-// if(TurnInstructionsClass::GoStraight == pathDescription[i].turnInstruction) {
-// if(std::string::npos != string0.find(string1+";")
-// || std::string::npos != string0.find(";"+string1)
-// || std::string::npos != string0.find(string1+" ;")
-// || std::string::npos != string0.find("; "+string1)
-// ){
-// INFO("->next correct: " << string0 << " contains " << string1);
-// for(; lastTurn != i; ++lastTurn)
-// pathDescription[lastTurn].nameID = pathDescription[i].nameID;
-// pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn;
-// } else if(std::string::npos != string1.find(string0+";")
-// || std::string::npos != string1.find(";"+string0)
-// || std::string::npos != string1.find(string0+" ;")
-// || std::string::npos != string1.find("; "+string0)
-// ){
-// INFO("->prev correct: " << string1 << " contains " << string0);
-// pathDescription[i].nameID = pathDescription[i-1].nameID;
-// pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn;
-// }
-// }
-// if (TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) {
-// lastTurn = i;
-// }
-// string0 = string1;
-// }
-
-
- for(unsigned i = 1; i < pathDescription.size(); ++i) {
- entireLength += pathDescription[i].length;
- lengthOfSegment += pathDescription[i].length;
- durationOfSegment += pathDescription[i].duration;
- pathDescription[indexOfSegmentBegin].length = lengthOfSegment;
- pathDescription[indexOfSegmentBegin].duration = durationOfSegment;
-
-
- if(TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) {
- //INFO("Turn after " << lengthOfSegment << "m into way with name id " << segment.nameID);
- assert(pathDescription[i].necessary);
- lengthOfSegment = 0;
- durationOfSegment = 0;
- indexOfSegmentBegin = i;
- }
- }
- // INFO("#segs: " << pathDescription.size());
-
- //Post-processing to remove empty or nearly empty path segments
- if(FLT_EPSILON > pathDescription.back().length) {
- // INFO("#segs: " << pathDescription.size() << ", last ratio: " << targetPhantom.ratio << ", length: " << pathDescription.back().length);
- if(pathDescription.size() > 2){
- pathDescription.pop_back();
- pathDescription.back().necessary = true;
- pathDescription.back().turnInstruction = TurnInstructions.NoTurn;
- targetPhantom.nodeBasedEdgeNameID = (pathDescription.end()-2)->nameID;
- // INFO("Deleting last turn instruction");
- }
- } else {
- pathDescription[indexOfSegmentBegin].duration *= (1.-targetPhantom.ratio);
- }
- if(FLT_EPSILON > pathDescription[0].length) {
- //TODO: this is never called actually?
- if(pathDescription.size() > 2) {
- pathDescription.erase(pathDescription.begin());
- pathDescription[0].turnInstruction = TurnInstructions.HeadOn;
- pathDescription[0].necessary = true;
- startPhantom.nodeBasedEdgeNameID = pathDescription[0].nameID;
- // INFO("Deleting first turn instruction, ratio: " << startPhantom.ratio << ", length: " << pathDescription[0].length);
- }
- } else {
- pathDescription[0].duration *= startPhantom.ratio;
- }
-
- //Generalize poly line
- dp.Run(pathDescription, zoomLevel);
+ path_description.emplace_back(coordinate,
+ path_point.name_id,
+ path_point.segment_duration,
+ 0,
+ path_point.turn_instruction);
+}
- //fix what needs to be fixed else
- for(unsigned i = 0; i < pathDescription.size()-1 && pathDescription.size() >= 2; ++i){
- if(pathDescription[i].necessary) {
- double angle = GetBearing(pathDescription[i].location, pathDescription[i+1].location);
- pathDescription[i].bearing = angle;
- }
+JSON::Value DescriptionFactory::AppendEncodedPolylineString(const bool return_encoded)
+{
+ if (return_encoded)
+ {
+ return polyline_compressor.printEncodedString(path_description);
}
-
-// BuildRouteSummary(entireLength, duration);
- return;
+ return polyline_compressor.printUnencodedString(path_description);
}
-void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time) {
- summary.startName = startPhantom.nodeBasedEdgeNameID;
- summary.destName = targetPhantom.nodeBasedEdgeNameID;
+void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
+{
+ summary.source_name_id = start_phantom.name_id;
+ summary.target_name_id = target_phantom.name_id;
summary.BuildDurationAndLengthStrings(distance, time);
}
diff --git a/Descriptors/DescriptionFactory.h b/Descriptors/DescriptionFactory.h
index 911aae7..d081bae 100644
--- a/Descriptors/DescriptionFactory.h
+++ b/Descriptors/DescriptionFactory.h
@@ -1,76 +1,215 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef DESCRIPTIONFACTORY_H_
#define DESCRIPTIONFACTORY_H_
-#include <vector>
-
-#include "../typedefs.h"
#include "../Algorithms/DouglasPeucker.h"
#include "../Algorithms/PolylineCompressor.h"
-#include "../DataStructures/Coordinate.h"
-#include "../DataStructures/SearchEngine.h"
+#include "../DataStructures/PhantomNodes.h"
#include "../DataStructures/SegmentInformation.h"
#include "../DataStructures/TurnInstructions.h"
+#include "../typedefs.h"
+#include <osrm/Coordinate.h>
+
+#include <limits>
+#include <vector>
+
+struct PathData;
/* This class is fed with all way segments in consecutive order
* and produces the description plus the encoded polyline */
-class DescriptionFactory {
- DouglasPeucker<SegmentInformation> dp;
- PolylineCompressor pc;
- PhantomNode startPhantom, targetPhantom;
+class DescriptionFactory
+{
+ DouglasPeucker polyline_generalizer;
+ PolylineCompressor polyline_compressor;
+ PhantomNode start_phantom, target_phantom;
double DegreeToRadian(const double degree) const;
double RadianToDegree(const double degree) const;
-public:
- struct _RouteSummary {
- std::string lengthString;
- std::string durationString;
- unsigned startName;
- unsigned destName;
- _RouteSummary() : lengthString("0"), durationString("0"), startName(0), destName(0) {}
- void BuildDurationAndLengthStrings(const double distance, const unsigned time) {
- //compute distance/duration for route summary
- intToString(round(distance), lengthString);
- int travelTime = time/10 + 1;
- intToString(travelTime, durationString);
+
+ std::vector<unsigned> via_indices;
+
+ public:
+ struct RouteSummary
+ {
+ unsigned distance;
+ EdgeWeight duration;
+ unsigned source_name_id;
+ unsigned target_name_id;
+ RouteSummary() : distance(0), duration(0), source_name_id(0), target_name_id(0) {}
+
+ void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
+ {
+ // compute distance/duration for route summary
+ distance = static_cast<unsigned>(round(raw_distance));
+ duration = static_cast<unsigned>(round(raw_duration / 10.));
}
} summary;
double entireLength;
- //I know, declaring this public is considered bad. I'm lazy
- std::vector <SegmentInformation> pathDescription;
+ // I know, declaring this public is considered bad. I'm lazy
+ std::vector<SegmentInformation> path_description;
DescriptionFactory();
- virtual ~DescriptionFactory();
- double GetBearing(const _Coordinate& C, const _Coordinate& B) const;
- void AppendEncodedPolylineString(std::string &output);
- void AppendUnencodedPolylineString(std::string &output);
- void AppendSegment(const _Coordinate & coordinate, const _PathData & data);
+ void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
void BuildRouteSummary(const double distance, const unsigned time);
- void SetStartSegment(const PhantomNode & startPhantom);
- void SetEndSegment(const PhantomNode & startPhantom);
- void AppendEncodedPolylineString(std::string & output, bool isEncoded);
- void Run(const SearchEngine &sEngine, const unsigned zoomLevel);
+ void SetStartSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
+ void SetEndSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
+ JSON::Value AppendEncodedPolylineString(const bool return_encoded);
+ std::vector<unsigned> const & GetViaIndices() const;
+
+ template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel)
+ {
+ if (path_description.empty())
+ {
+ return;
+ }
+
+ /** starts at index 1 */
+ path_description[0].length = 0;
+ for (unsigned i = 1; i < path_description.size(); ++i)
+ {
+ // move down names by one, q&d hack
+ path_description[i - 1].name_id = path_description[i].name_id;
+ path_description[i].length = FixedPointCoordinate::ApproximateEuclideanDistance(
+ path_description[i - 1].location, path_description[i].location);
+ }
+
+ /*Simplify turn instructions
+ Input :
+ 10. Turn left on B 36 for 20 km
+ 11. Continue on B 35; B 36 for 2 km
+ 12. Continue on B 36 for 13 km
+
+ becomes:
+ 10. Turn left on B 36 for 35 km
+ */
+ // TODO: rework to check only end and start of string.
+ // stl string is way to expensive
+
+ // unsigned lastTurn = 0;
+ // for(unsigned i = 1; i < path_description.size(); ++i) {
+ // string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
+ // if(TurnInstruction::GoStraight == path_description[i].turn_instruction) {
+ // if(std::string::npos != string0.find(string1+";")
+ // || std::string::npos != string0.find(";"+string1)
+ // || std::string::npos != string0.find(string1+" ;")
+ // || std::string::npos != string0.find("; "+string1)
+ // ){
+ // SimpleLogger().Write() << "->next correct: " << string0 << " contains " <<
+ // string1;
+ // for(; lastTurn != i; ++lastTurn)
+ // path_description[lastTurn].name_id = path_description[i].name_id;
+ // path_description[i].turn_instruction = TurnInstruction::NoTurn;
+ // } else if(std::string::npos != string1.find(string0+";")
+ // || std::string::npos != string1.find(";"+string0)
+ // || std::string::npos != string1.find(string0+" ;")
+ // || std::string::npos != string1.find("; "+string0)
+ // ){
+ // SimpleLogger().Write() << "->prev correct: " << string1 << " contains " <<
+ // string0;
+ // path_description[i].name_id = path_description[i-1].name_id;
+ // path_description[i].turn_instruction = TurnInstruction::NoTurn;
+ // }
+ // }
+ // if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
+ // lastTurn = i;
+ // }
+ // string0 = string1;
+ // }
+
+ float segment_length = 0.;
+ unsigned segment_duration = 0;
+ unsigned segment_start_index = 0;
+
+ for (unsigned i = 1; i < path_description.size(); ++i)
+ {
+ entireLength += path_description[i].length;
+ segment_length += path_description[i].length;
+ segment_duration += path_description[i].duration;
+ path_description[segment_start_index].length = segment_length;
+ path_description[segment_start_index].duration = segment_duration;
+
+ if (TurnInstruction::NoTurn != path_description[i].turn_instruction)
+ {
+ BOOST_ASSERT(path_description[i].necessary);
+ segment_length = 0;
+ segment_duration = 0;
+ segment_start_index = i;
+ }
+ }
+
+ // Post-processing to remove empty or nearly empty path segments
+ if (std::numeric_limits<double>::epsilon() > path_description.back().length)
+ {
+ if (path_description.size() > 2)
+ {
+ path_description.pop_back();
+ path_description.back().necessary = true;
+ path_description.back().turn_instruction = TurnInstruction::NoTurn;
+ target_phantom.name_id = (path_description.end() - 2)->name_id;
+ }
+ }
+ if (std::numeric_limits<double>::epsilon() > path_description.front().length)
+ {
+ if (path_description.size() > 2)
+ {
+ path_description.erase(path_description.begin());
+ path_description.front().turn_instruction = TurnInstruction::HeadOn;
+ path_description.front().necessary = true;
+ start_phantom.name_id = path_description.front().name_id;
+ }
+ }
+
+ // Generalize poly line
+ polyline_generalizer.Run(path_description, zoomLevel);
+
+ // fix what needs to be fixed else
+ unsigned necessary_pieces = 0; // a running index that counts the necessary pieces
+ for (unsigned i = 0; i < path_description.size() - 1 && path_description.size() >= 2; ++i)
+ {
+ if (path_description[i].necessary)
+ {
+ ++necessary_pieces;
+ if (path_description[i].is_via_location)
+ { //mark the end of a leg
+ via_indices.push_back(necessary_pieces);
+ }
+ const double angle = path_description[i+1].location.GetBearing(path_description[i].location);
+ path_description[i].bearing = static_cast<unsigned>(angle * 10);
+ }
+ }
+ via_indices.push_back(necessary_pieces+1);
+ BOOST_ASSERT(via_indices.size() >= 2);
+ // BOOST_ASSERT(0 != necessary_pieces || path_description.empty());
+ return;
+ }
};
#endif /* DESCRIPTIONFACTORY_H_ */
diff --git a/Descriptors/GPXDescriptor.h b/Descriptors/GPXDescriptor.h
index 1d3389a..50efd9a 100644
--- a/Descriptors/GPXDescriptor.h
+++ b/Descriptors/GPXDescriptor.h
@@ -1,65 +1,100 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef GPX_DESCRIPTOR_H_
-#define GPX_DESCRIPTOR_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef GPX_DESCRIPTOR_H
+#define GPX_DESCRIPTOR_H
-#include <boost/foreach.hpp>
#include "BaseDescriptor.h"
-class GPXDescriptor : public BaseDescriptor{
-private:
- _DescriptorConfig config;
- _Coordinate current;
-
- std::string tmp;
-public:
- void SetConfig(const _DescriptorConfig& c) { config = c; }
- 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\" "
- "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
- "\">";
- reply.content += "<metadata><copyright author=\"Project OSRM\"><license>Data (c) OpenStreetMap contributors (ODbL)</license></copyright></metadata>";
- reply.content += "<rte>";
- if(rawRoute.lengthOfShortestPath != INT_MAX && rawRoute.computedShortestPath.size()) {
- convertInternalLatLonToString(phantomNodes.startPhantom.location.lat, tmp);
- reply.content += "<rtept lat=\"" + tmp + "\" ";
- convertInternalLatLonToString(phantomNodes.startPhantom.location.lon, tmp);
- reply.content += "lon=\"" + tmp + "\"></rtept>";
-
- BOOST_FOREACH(const _PathData & pathData, rawRoute.computedShortestPath) {
- sEngine.GetCoordinatesForNodeID(pathData.node, current);
-
- convertInternalLatLonToString(current.lat, tmp);
- reply.content += "<rtept lat=\"" + tmp + "\" ";
- convertInternalLatLonToString(current.lon, tmp);
- reply.content += "lon=\"" + tmp + "\"></rtept>";
+template <class DataFacadeT> class GPXDescriptor : public BaseDescriptor<DataFacadeT>
+{
+ private:
+ DescriptorConfig config;
+ FixedPointCoordinate current;
+ DataFacadeT * facade;
+
+ void AddRoutePoint(const FixedPointCoordinate & coordinate, std::vector<char> & output)
+ {
+ const std::string route_point_head = "<rtept lat=\"";
+ const std::string route_point_middle = " lon=\"";
+ const std::string route_point_tail = "\"></rtept>";
+
+ std::string tmp;
+
+ FixedPointCoordinate::convertInternalLatLonToString(coordinate.lat, tmp);
+ output.insert(output.end(), route_point_head.begin(), route_point_head.end());
+ output.insert(output.end(), tmp.begin(), tmp.end());
+ output.push_back('\"');
+
+ FixedPointCoordinate::convertInternalLatLonToString(coordinate.lon, tmp);
+ output.insert(output.end(), route_point_middle.begin(), route_point_middle.end());
+ output.insert(output.end(), tmp.begin(), tmp.end());
+ output.insert(output.end(), route_point_tail.begin(), route_point_tail.end());
+ }
+
+ public:
+ GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
+
+ void SetConfig(const DescriptorConfig &c) { config = c; }
+
+ // TODO: reorder parameters
+ void Run(const RawRouteData &raw_route, http::Reply &reply)
+ {
+ std::string header("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<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\" "
+ "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
+ "\">"
+ "<metadata><copyright author=\"Project OSRM\"><license>Data (c)"
+ " OpenStreetMap contributors (ODbL)</license></copyright>"
+ "</metadata>"
+ "<rte>");
+ reply.content.insert(reply.content.end(), header.begin(), header.end());
+ const bool found_route = (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT) &&
+ (!raw_route.unpacked_path_segments.front().empty());
+ if (found_route)
+ {
+ AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location, reply.content);
+
+ for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
+ {
+ for (const PathData &path_data : path_data_vector)
+ {
+ const FixedPointCoordinate current_coordinate =
+ facade->GetCoordinateOfNode(path_data.node);
+ AddRoutePoint(current_coordinate, reply.content);
+ }
}
- convertInternalLatLonToString(phantomNodes.targetPhantom.location.lat, tmp);
- reply.content += "<rtept lat=\"" + tmp + "\" ";
- convertInternalLatLonToString(phantomNodes.targetPhantom.location.lon, tmp);
- reply.content += "lon=\"" + tmp + "\"></rtept>";
+ AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location, reply.content);
+
}
- reply.content += "</rte></gpx>";
+ std::string footer("</rte></gpx>");
+ reply.content.insert(reply.content.end(), footer.begin(), footer.end());
}
};
-#endif /* GPX_DESCRIPTOR_H_ */
+#endif // GPX_DESCRIPTOR_H
diff --git a/Descriptors/JSONDescriptor.h b/Descriptors/JSONDescriptor.h
index 1db2c68..938e4ef 100644
--- a/Descriptors/JSONDescriptor.h
+++ b/Descriptors/JSONDescriptor.h
@@ -1,392 +1,385 @@
-/*
- 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 JSON_DESCRIPTOR_H_
-#define JSON_DESCRIPTOR_H_
-
-#include <algorithm>
-
-#include <boost/lambda/lambda.hpp>
-#include <boost/bind.hpp>
-
-#include "BaseDescriptor.h"
-#include "DescriptionFactory.h"
-#include "../Algorithms/ObjectToBase64.h"
-#include "../DataStructures/SegmentInformation.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../Util/Azimuth.h"
-#include "../Util/StringUtil.h"
-
-class JSONDescriptor : public BaseDescriptor{
-private:
- _DescriptorConfig config;
- DescriptionFactory descriptionFactory;
- DescriptionFactory alternateDescriptionFactory;
- _Coordinate current;
- unsigned numberOfEnteredRestrictedAreas;
- struct {
- int startIndex;
- int nameID;
- int leaveAtExit;
- } roundAbout;
-
- struct Segment {
- Segment() : nameID(-1), length(-1), position(-1) {}
- Segment(int n, int l, int p) : nameID(n), length(l), position(p) {}
- int nameID;
- int length;
- int position;
- };
- std::vector<Segment> shortestSegments, alternativeSegments;
-
- struct RouteNames {
- std::string shortestPathName1;
- std::string shortestPathName2;
- std::string alternativePathName1;
- std::string alternativePathName2;
- };
-
-public:
- JSONDescriptor() : numberOfEnteredRestrictedAreas(0) {}
- void SetConfig(const _DescriptorConfig & c) { config = c; }
-
- void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngine &sEngine) {
-
- WriteHeaderToOutput(reply.content);
-
- if(rawRoute.lengthOfShortestPath != INT_MAX) {
- descriptionFactory.SetStartSegment(phantomNodes.startPhantom);
- reply.content += "0,"
- "\"status_message\": \"Found route between points\",";
-
- //Get all the coordinates for the computed route
- BOOST_FOREACH(const _PathData & pathData, rawRoute.computedShortestPath) {
- sEngine.GetCoordinatesForNodeID(pathData.node, current);
- descriptionFactory.AppendSegment(current, pathData );
- }
- descriptionFactory.SetEndSegment(phantomNodes.targetPhantom);
- } else {
- //We do not need to do much, if there is no route ;-)
- reply.content += "207,"
- "\"status_message\": \"Cannot find route between points\",";
- }
-
- descriptionFactory.Run(sEngine, config.z);
- reply.content += "\"route_geometry\": ";
- if(config.geometry) {
- descriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry);
- } else {
- reply.content += "[]";
- }
-
- reply.content += ","
- "\"route_instructions\": [";
- numberOfEnteredRestrictedAreas = 0;
- if(config.instructions) {
- BuildTextualDescription(descriptionFactory, reply, rawRoute.lengthOfShortestPath, sEngine, shortestSegments);
- } else {
- BOOST_FOREACH(const SegmentInformation & segment, descriptionFactory.pathDescription) {
- TurnInstruction currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
- numberOfEnteredRestrictedAreas += (currentInstruction != segment.turnInstruction);
- }
- }
- reply.content += "],";
- descriptionFactory.BuildRouteSummary(descriptionFactory.entireLength, rawRoute.lengthOfShortestPath - ( numberOfEnteredRestrictedAreas*TurnInstructions.AccessRestrictionPenalty));
-
- reply.content += "\"route_summary\":";
- reply.content += "{";
- reply.content += "\"total_distance\":";
- reply.content += descriptionFactory.summary.lengthString;
- reply.content += ","
- "\"total_time\":";
- reply.content += descriptionFactory.summary.durationString;
- reply.content += ","
- "\"start_point\":\"";
- reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.startName);
- reply.content += "\","
- "\"end_point\":\"";
- reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.destName);
- reply.content += "\"";
- reply.content += "}";
- reply.content +=",";
-
- //only one alternative route is computed at this time, so this is hardcoded
-
- if(rawRoute.lengthOfAlternativePath != INT_MAX) {
- alternateDescriptionFactory.SetStartSegment(phantomNodes.startPhantom);
- //Get all the coordinates for the computed route
- BOOST_FOREACH(const _PathData & pathData, rawRoute.computedAlternativePath) {
- sEngine.GetCoordinatesForNodeID(pathData.node, current);
- alternateDescriptionFactory.AppendSegment(current, pathData );
- }
- alternateDescriptionFactory.SetEndSegment(phantomNodes.targetPhantom);
- }
- alternateDescriptionFactory.Run(sEngine, config.z);
-
- //give an array of alternative routes
- reply.content += "\"alternative_geometries\": [";
- if(config.geometry && INT_MAX != rawRoute.lengthOfAlternativePath) {
- //Generate the linestrings for each alternative
- alternateDescriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry);
- }
- reply.content += "],";
- reply.content += "\"alternative_instructions\":[";
- numberOfEnteredRestrictedAreas = 0;
- if(INT_MAX != rawRoute.lengthOfAlternativePath) {
- reply.content += "[";
- //Generate instructions for each alternative
- if(config.instructions) {
- BuildTextualDescription(alternateDescriptionFactory, reply, rawRoute.lengthOfAlternativePath, sEngine, alternativeSegments);
- } else {
- BOOST_FOREACH(const SegmentInformation & segment, alternateDescriptionFactory.pathDescription) {
- TurnInstruction currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
- numberOfEnteredRestrictedAreas += (currentInstruction != segment.turnInstruction);
- }
- }
- reply.content += "]";
- }
- reply.content += "],";
- reply.content += "\"alternative_summaries\":[";
- if(INT_MAX != rawRoute.lengthOfAlternativePath) {
- //Generate route summary (length, duration) for each alternative
- alternateDescriptionFactory.BuildRouteSummary(alternateDescriptionFactory.entireLength, rawRoute.lengthOfAlternativePath - ( numberOfEnteredRestrictedAreas*TurnInstructions.AccessRestrictionPenalty));
- reply.content += "{";
- reply.content += "\"total_distance\":";
- reply.content += alternateDescriptionFactory.summary.lengthString;
- reply.content += ","
- "\"total_time\":";
- reply.content += alternateDescriptionFactory.summary.durationString;
- reply.content += ","
- "\"start_point\":\"";
- reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.startName);
- reply.content += "\","
- "\"end_point\":\"";
- reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.destName);
- reply.content += "\"";
- reply.content += "}";
- }
- reply.content += "],";
-
- //Get Names for both routes
- RouteNames routeNames;
- GetRouteNames(shortestSegments, alternativeSegments, sEngine, routeNames);
-
- reply.content += "\"route_name\":[\"";
- reply.content += routeNames.shortestPathName1;
- reply.content += "\",\"";
- reply.content += routeNames.shortestPathName2;
- reply.content += "\"],"
- "\"alternative_names\":[";
- reply.content += "[\"";
- reply.content += routeNames.alternativePathName1;
- reply.content += "\",\"";
- reply.content += routeNames.alternativePathName2;
- reply.content += "\"]";
- reply.content += "],";
- //list all viapoints so that the client may display it
- reply.content += "\"via_points\":[";
- std::string tmp;
- if(config.geometry && INT_MAX != rawRoute.lengthOfShortestPath) {
- for(unsigned i = 0; i < rawRoute.segmentEndCoordinates.size(); ++i) {
- reply.content += "[";
- if(rawRoute.segmentEndCoordinates[i].startPhantom.location.isSet())
- convertInternalReversedCoordinateToString(rawRoute.segmentEndCoordinates[i].startPhantom.location, tmp);
- else
- convertInternalReversedCoordinateToString(rawRoute.rawViaNodeCoordinates[i], tmp);
-
- reply.content += tmp;
- reply.content += "],";
- }
- reply.content += "[";
- if(rawRoute.segmentEndCoordinates.back().startPhantom.location.isSet())
- convertInternalReversedCoordinateToString(rawRoute.segmentEndCoordinates.back().targetPhantom.location, tmp);
- else
- convertInternalReversedCoordinateToString(rawRoute.rawViaNodeCoordinates.back(), tmp);
- reply.content += tmp;
- reply.content += "]";
- }
- reply.content += "],";
- reply.content += "\"hint_data\": {";
- reply.content += "\"checksum\":";
- intToString(rawRoute.checkSum, tmp);
- reply.content += tmp;
- reply.content += ", \"locations\": [";
-
- std::string hint;
- for(unsigned i = 0; i < rawRoute.segmentEndCoordinates.size(); ++i) {
- reply.content += "\"";
- EncodeObjectToBase64(rawRoute.segmentEndCoordinates[i].startPhantom, hint);
- reply.content += hint;
- reply.content += "\", ";
- }
- EncodeObjectToBase64(rawRoute.segmentEndCoordinates.back().targetPhantom, hint);
- reply.content += "\"";
- reply.content += hint;
- reply.content += "\"]";
- reply.content += "},";
- reply.content += "\"transactionId\": \"OSRM Routing Engine JSON Descriptor (v0.3)\"";
- reply.content += "}";
- }
-
- void GetRouteNames(std::vector<Segment> & shortestSegments, std::vector<Segment> & alternativeSegments, const SearchEngine &sEngine, RouteNames & routeNames) {
- /*** extract names for both alternatives ***/
-
- Segment shortestSegment1, shortestSegment2;
- Segment alternativeSegment1, alternativeSegment2;
-
- if(0 < shortestSegments.size()) {
- sort(shortestSegments.begin(), shortestSegments.end(), boost::bind(&Segment::length, _1) > boost::bind(&Segment::length, _2) );
- shortestSegment1 = shortestSegments[0];
- if(0 < alternativeSegments.size()) {
- sort(alternativeSegments.begin(), alternativeSegments.end(), boost::bind(&Segment::length, _1) > boost::bind(&Segment::length, _2) );
- alternativeSegment1 = alternativeSegments[0];
- }
- std::vector<Segment> shortestDifference(shortestSegments.size());
- std::vector<Segment> alternativeDifference(alternativeSegments.size());
- std::set_difference(shortestSegments.begin(), shortestSegments.end(), alternativeSegments.begin(), alternativeSegments.end(), shortestDifference.begin(), boost::bind(&Segment::nameID, _1) < boost::bind(&Segment::nameID, _2) );
- int size_of_difference = shortestDifference.size();
- if(0 < size_of_difference ) {
- int i = 0;
- while( i < size_of_difference && shortestDifference[i].nameID == shortestSegments[0].nameID) {
- ++i;
- }
- if(i < size_of_difference ) {
- shortestSegment2 = shortestDifference[i];
- }
- }
-
- std::set_difference(alternativeSegments.begin(), alternativeSegments.end(), shortestSegments.begin(), shortestSegments.end(), alternativeDifference.begin(), boost::bind(&Segment::nameID, _1) < boost::bind(&Segment::nameID, _2) );
- size_of_difference = alternativeDifference.size();
- if(0 < size_of_difference ) {
- int i = 0;
- while( i < size_of_difference && alternativeDifference[i].nameID == alternativeSegments[0].nameID) {
- ++i;
- }
- if(i < size_of_difference ) {
- alternativeSegment2 = alternativeDifference[i];
- }
- }
- if(shortestSegment1.position > shortestSegment2.position)
- std::swap(shortestSegment1, shortestSegment2);
-
- if(alternativeSegment1.position > alternativeSegment2.position)
- std::swap(alternativeSegment1, alternativeSegment2);
-
- routeNames.shortestPathName1 = sEngine.GetEscapedNameForNameID(shortestSegment1.nameID);
- routeNames.shortestPathName2 = sEngine.GetEscapedNameForNameID(shortestSegment2.nameID);
-
- routeNames.alternativePathName1 = sEngine.GetEscapedNameForNameID(alternativeSegment1.nameID);
- routeNames.alternativePathName2 = sEngine.GetEscapedNameForNameID(alternativeSegment2.nameID);
- }
- }
-
- inline void WriteHeaderToOutput(std::string & output) {
- output += "{"
- "\"version\": 0.3,"
- "\"status\":";
- }
-
- 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]
- //See also: http://developers.cloudmade.com/wiki/navengine/JSON_format
- unsigned prefixSumOfNecessarySegments = 0;
- roundAbout.leaveAtExit = 0;
- roundAbout.nameID = 0;
- std::string tmpDist, tmpLength, tmpDuration, tmpBearing, tmpInstruction;
- //Fetch data from Factory and generate a string from it.
- BOOST_FOREACH(const SegmentInformation & segment, descriptionFactory.pathDescription) {
- TurnInstruction currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
- numberOfEnteredRestrictedAreas += (currentInstruction != segment.turnInstruction);
- if(TurnInstructions.TurnIsNecessary( currentInstruction) ) {
- if(TurnInstructions.EnterRoundAbout == currentInstruction) {
- roundAbout.nameID = segment.nameID;
- roundAbout.startIndex = prefixSumOfNecessarySegments;
- } else {
- if(0 != prefixSumOfNecessarySegments){
- reply.content += ",";
- }
- reply.content += "[\"";
- if(TurnInstructions.LeaveRoundAbout == currentInstruction) {
- intToString(TurnInstructions.EnterRoundAbout, tmpInstruction);
- reply.content += tmpInstruction;
- reply.content += "-";
- intToString(roundAbout.leaveAtExit+1, tmpInstruction);
- reply.content += tmpInstruction;
- roundAbout.leaveAtExit = 0;
- } else {
- intToString(currentInstruction, tmpInstruction);
- reply.content += tmpInstruction;
- }
-
-
- reply.content += "\",\"";
- reply.content += sEngine.GetEscapedNameForNameID(segment.nameID);
- reply.content += "\",";
- intToString(segment.length, tmpDist);
- reply.content += tmpDist;
- reply.content += ",";
- intToString(prefixSumOfNecessarySegments, tmpLength);
- reply.content += tmpLength;
- reply.content += ",";
- intToString(segment.duration/10, tmpDuration);
- reply.content += tmpDuration;
- reply.content += ",\"";
- intToString(segment.length, tmpLength);
- reply.content += tmpLength;
- reply.content += "m\",\"";
- reply.content += Azimuth::Get(segment.bearing);
- reply.content += "\",";
- intToString(round(segment.bearing), tmpBearing);
- reply.content += tmpBearing;
- reply.content += "]";
-
- segmentVector.push_back( Segment(segment.nameID, segment.length, segmentVector.size() ));
- }
- } else if(TurnInstructions.StayOnRoundAbout == currentInstruction) {
- ++roundAbout.leaveAtExit;
- }
- if(segment.necessary)
- ++prefixSumOfNecessarySegments;
- }
- if(INT_MAX != lengthOfRoute) {
- reply.content += ",[\"";
- intToString(TurnInstructions.ReachedYourDestination, tmpInstruction);
- reply.content += tmpInstruction;
- reply.content += "\",\"";
- reply.content += "\",";
- reply.content += "0";
- reply.content += ",";
- intToString(prefixSumOfNecessarySegments-1, tmpLength);
- reply.content += tmpLength;
- reply.content += ",";
- reply.content += "0";
- reply.content += ",\"";
- reply.content += "\",\"";
- reply.content += Azimuth::Get(0.0);
- reply.content += "\",";
- reply.content += "0.0";
- reply.content += "]";
- }
- }
-
-};
-#endif /* JSON_DESCRIPTOR_H_ */
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef JSON_DESCRIPTOR_H_
+#define JSON_DESCRIPTOR_H_
+
+#include "BaseDescriptor.h"
+#include "DescriptionFactory.h"
+#include "../Algorithms/ObjectToBase64.h"
+#include "../Algorithms/ExtractRouteNames.h"
+#include "../DataStructures/JSONContainer.h"
+#include "../DataStructures/SegmentInformation.h"
+#include "../DataStructures/TurnInstructions.h"
+#include "../Util/Azimuth.h"
+#include "../Util/StringUtil.h"
+#include "../Util/TimingUtil.h"
+
+#include <algorithm>
+
+template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFacadeT>
+{
+ private:
+ DataFacadeT *facade;
+ DescriptorConfig config;
+ DescriptionFactory description_factory, alternate_description_factory;
+ FixedPointCoordinate current;
+ unsigned entered_restricted_area_count;
+ struct RoundAbout
+ {
+ RoundAbout() : start_index(INT_MAX), name_id(INVALID_NAMEID), leave_at_exit(INT_MAX) {}
+ int start_index;
+ unsigned name_id;
+ int leave_at_exit;
+ } round_about;
+
+ struct Segment
+ {
+ Segment() : name_id(INVALID_NAMEID), length(-1), position(0) {}
+ Segment(unsigned n, int l, unsigned p) : name_id(n), length(l), position(p) {}
+ unsigned name_id;
+ int length;
+ unsigned position;
+ };
+ std::vector<Segment> shortest_path_segments, alternative_path_segments;
+ ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
+
+ public:
+ JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0) {}
+
+ void SetConfig(const DescriptorConfig &c) { config = c; }
+
+ unsigned DescribeLeg(const std::vector<PathData> route_leg,
+ const PhantomNodes &leg_phantoms,
+ const bool target_traversed_in_reverse)
+ {
+ unsigned added_element_count = 0;
+ // Get all the coordinates for the computed route
+ FixedPointCoordinate current_coordinate;
+ for (const PathData &path_data : route_leg)
+ {
+ current_coordinate = facade->GetCoordinateOfNode(path_data.node);
+ description_factory.AppendSegment(current_coordinate, path_data);
+ ++added_element_count;
+ }
+ description_factory.SetEndSegment(leg_phantoms.target_phantom, target_traversed_in_reverse);
+ ++added_element_count;
+ BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
+ return added_element_count;
+ }
+
+ void Run(const RawRouteData &raw_route, http::Reply &reply)
+ {
+ JSON::Object json_result;
+ if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
+ {
+ // We do not need to do much, if there is no route ;-)
+ json_result.values["status"] = 207;
+ json_result.values["status_message"] = "Cannot find route between points";
+ JSON::render(reply.content, json_result);
+ return;
+ }
+
+ // check if first segment is non-zero
+ std::string road_name = facade->GetEscapedNameForNameID(
+ raw_route.segment_end_coordinates.front().source_phantom.name_id);
+
+ BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
+ raw_route.segment_end_coordinates.size());
+
+ description_factory.SetStartSegment(
+ raw_route.segment_end_coordinates.front().source_phantom,
+ raw_route.source_traversed_in_reverse.front());
+ json_result.values["status"] = 0;
+ json_result.values["status_message"] = "Found route between points";
+
+ // for each unpacked segment add the leg to the description
+ for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
+ {
+#ifndef NDEBUG
+ const int added_segments =
+#endif
+ DescribeLeg(raw_route.unpacked_path_segments[i],
+ raw_route.segment_end_coordinates[i],
+ raw_route.target_traversed_in_reverse[i]);
+ BOOST_ASSERT(0 < added_segments);
+ }
+ description_factory.Run(facade, config.zoom_level);
+
+ if (config.geometry)
+ {
+ JSON::Value route_geometry =
+ description_factory.AppendEncodedPolylineString(config.encode_geometry);
+ json_result.values["route_geometry"] = route_geometry;
+ }
+ if (config.instructions)
+ {
+ JSON::Array json_route_instructions;
+ BuildTextualDescription(description_factory,
+ json_route_instructions,
+ raw_route.shortest_path_length,
+ shortest_path_segments);
+ json_result.values["route_instructions"] = json_route_instructions;
+ }
+ description_factory.BuildRouteSummary(description_factory.entireLength,
+ raw_route.shortest_path_length);
+ JSON::Object json_route_summary;
+ json_route_summary.values["total_distance"] = description_factory.summary.distance;
+ json_route_summary.values["total_time"] = description_factory.summary.duration;
+ json_route_summary.values["start_point"] =
+ facade->GetEscapedNameForNameID(description_factory.summary.source_name_id);
+ json_route_summary.values["end_point"] =
+ facade->GetEscapedNameForNameID(description_factory.summary.target_name_id);
+ json_result.values["route_summary"] = json_route_summary;
+
+ BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
+
+ JSON::Array json_via_points_array;
+ JSON::Array json_first_coordinate;
+ json_first_coordinate.values.push_back(
+ raw_route.segment_end_coordinates.front().source_phantom.location.lat /
+ COORDINATE_PRECISION);
+ json_first_coordinate.values.push_back(
+ raw_route.segment_end_coordinates.front().source_phantom.location.lon /
+ COORDINATE_PRECISION);
+ json_via_points_array.values.push_back(json_first_coordinate);
+ for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
+ {
+ std::string tmp;
+ JSON::Array json_coordinate;
+ json_coordinate.values.push_back(nodes.target_phantom.location.lat /
+ COORDINATE_PRECISION);
+ json_coordinate.values.push_back(nodes.target_phantom.location.lon /
+ COORDINATE_PRECISION);
+ json_via_points_array.values.push_back(json_coordinate);
+ }
+ json_result.values["via_points"] = json_via_points_array;
+
+ JSON::Array json_via_indices_array;
+
+ std::vector<unsigned> const &shortest_leg_end_indices = description_factory.GetViaIndices();
+ json_via_indices_array.values.insert(json_via_indices_array.values.end(),
+ shortest_leg_end_indices.begin(),
+ shortest_leg_end_indices.end());
+ json_result.values["via_indices"] = json_via_indices_array;
+
+ // only one alternative route is computed at this time, so this is hardcoded
+ if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
+ {
+ json_result.values["found_alternative"] = JSON::True();
+ BOOST_ASSERT(!raw_route.alt_source_traversed_in_reverse.empty());
+ alternate_description_factory.SetStartSegment(
+ raw_route.segment_end_coordinates.front().source_phantom,
+ raw_route.alt_source_traversed_in_reverse.front());
+ // Get all the coordinates for the computed route
+ for (const PathData &path_data : raw_route.unpacked_alternative)
+ {
+ current = facade->GetCoordinateOfNode(path_data.node);
+ alternate_description_factory.AppendSegment(current, path_data);
+ }
+ alternate_description_factory.Run(facade, config.zoom_level);
+
+ if (config.geometry)
+ {
+ JSON::Value alternate_geometry_string =
+ alternate_description_factory.AppendEncodedPolylineString(
+ config.encode_geometry);
+ JSON::Array json_alternate_geometries_array;
+ json_alternate_geometries_array.values.push_back(alternate_geometry_string);
+ json_result.values["alternative_geometries"] = json_alternate_geometries_array;
+ }
+ // Generate instructions for each alternative (simulated here)
+ JSON::Array json_alt_instructions;
+ JSON::Array json_current_alt_instructions;
+ if (config.instructions)
+ {
+ BuildTextualDescription(alternate_description_factory,
+ json_current_alt_instructions,
+ raw_route.alternative_path_length,
+ alternative_path_segments);
+ json_alt_instructions.values.push_back(json_current_alt_instructions);
+ json_result.values["alternative_instructions"] = json_alt_instructions;
+ }
+ alternate_description_factory.BuildRouteSummary(
+ alternate_description_factory.entireLength, raw_route.alternative_path_length);
+
+ JSON::Object json_alternate_route_summary;
+ JSON::Array json_alternate_route_summary_array;
+ json_alternate_route_summary.values["total_distance"] =
+ alternate_description_factory.summary.distance;
+ json_alternate_route_summary.values["total_time"] =
+ alternate_description_factory.summary.duration;
+ json_alternate_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(
+ alternate_description_factory.summary.source_name_id);
+ json_alternate_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(
+ alternate_description_factory.summary.target_name_id);
+ json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
+ json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
+
+ std::vector<unsigned> const &alternate_leg_end_indices =
+ alternate_description_factory.GetViaIndices();
+ JSON::Array json_altenative_indices_array;
+ json_altenative_indices_array.values.insert(json_altenative_indices_array.values.end(),
+ alternate_leg_end_indices.begin(),
+ alternate_leg_end_indices.end());
+ json_result.values["alternative_indices"] = json_altenative_indices_array;
+ }
+ else
+ {
+ json_result.values["found_alternative"] = JSON::False();
+ }
+
+ // Get Names for both routes
+ RouteNames route_names =
+ GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
+ JSON::Array json_route_names;
+ json_route_names.values.push_back(route_names.shortest_path_name_1);
+ json_route_names.values.push_back(route_names.shortest_path_name_2);
+ json_result.values["route_name"] = json_route_names;
+
+ if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
+ {
+ JSON::Array json_alternate_names_array;
+ JSON::Array json_alternate_names;
+ json_alternate_names.values.push_back(route_names.alternative_path_name_1);
+ json_alternate_names.values.push_back(route_names.alternative_path_name_2);
+ json_alternate_names_array.values.push_back(json_alternate_names);
+ json_result.values["alternative_names"] = json_alternate_names_array;
+ }
+
+ JSON::Object json_hint_object;
+ json_hint_object.values["checksum"] = raw_route.check_sum;
+ JSON::Array json_location_hint_array;
+ std::string hint;
+ for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i)
+ {
+ EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
+ json_location_hint_array.values.push_back(hint);
+ }
+ EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
+ json_location_hint_array.values.push_back(hint);
+ json_hint_object.values["locations"] = json_location_hint_array;
+ json_result.values["hint_data"] = json_hint_object;
+
+ // render the content to the output array
+ TIMER_START(route_render);
+ JSON::render(reply.content, json_result);
+ TIMER_STOP(route_render);
+ SimpleLogger().Write(logDEBUG) << "rendering took: " << TIMER_MSEC(route_render);
+ }
+
+ // TODO: reorder parameters
+ inline void BuildTextualDescription(DescriptionFactory &description_factory,
+ JSON::Array &json_instruction_array,
+ const int route_length,
+ std::vector<Segment> &route_segments_list)
+ {
+ // Segment information has following format:
+ //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
+ unsigned necessary_segments_running_index = 1;
+ round_about.leave_at_exit = 0;
+ round_about.name_id = 0;
+ std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
+
+ // Fetch data from Factory and generate a string from it.
+ for (const SegmentInformation &segment : description_factory.path_description)
+ {
+ JSON::Array json_instruction_row;
+ TurnInstruction current_instruction = segment.turn_instruction;
+ entered_restricted_area_count += (current_instruction != segment.turn_instruction);
+ if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
+ {
+ if (TurnInstruction::EnterRoundAbout == current_instruction)
+ {
+ round_about.name_id = segment.name_id;
+ round_about.start_index = necessary_segments_running_index;
+ }
+ else
+ {
+ std::string current_turn_instruction;
+ if (TurnInstruction::LeaveRoundAbout == current_instruction)
+ {
+ temp_instruction =
+ IntToString(as_integer(TurnInstruction::EnterRoundAbout));
+ current_turn_instruction += temp_instruction;
+ current_turn_instruction += "-";
+ temp_instruction = IntToString(round_about.leave_at_exit + 1);
+ current_turn_instruction += temp_instruction;
+ round_about.leave_at_exit = 0;
+ }
+ else
+ {
+ temp_instruction = IntToString(as_integer(current_instruction));
+ current_turn_instruction += temp_instruction;
+ }
+ json_instruction_row.values.push_back(current_turn_instruction);
+
+ json_instruction_row.values.push_back(
+ facade->GetEscapedNameForNameID(segment.name_id));
+ json_instruction_row.values.push_back(std::round(segment.length));
+ json_instruction_row.values.push_back(necessary_segments_running_index);
+ json_instruction_row.values.push_back(round(segment.duration / 10));
+ json_instruction_row.values.push_back(
+ UintToString(static_cast<unsigned>(segment.length)) + "m");
+ const double bearing_value = (segment.bearing / 10.) ;
+ json_instruction_row.values.push_back(Azimuth::Get(bearing_value));
+ json_instruction_row.values.push_back(static_cast<unsigned>(round(bearing_value)));
+
+ route_segments_list.emplace_back(
+ segment.name_id, segment.length, route_segments_list.size());
+ json_instruction_array.values.push_back(json_instruction_row);
+ }
+ }
+ else if (TurnInstruction::StayOnRoundAbout == current_instruction)
+ {
+ ++round_about.leave_at_exit;
+ }
+ if (segment.necessary)
+ {
+ ++necessary_segments_running_index;
+ }
+ }
+
+ // TODO: check if this in an invariant
+ if (INVALID_EDGE_WEIGHT != route_length)
+ {
+ JSON::Array json_last_instruction_row;
+ temp_instruction = IntToString(as_integer(TurnInstruction::ReachedYourDestination));
+ json_last_instruction_row.values.push_back(temp_instruction);
+ json_last_instruction_row.values.push_back("");
+ json_last_instruction_row.values.push_back(0);
+ json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
+ json_last_instruction_row.values.push_back(0);
+ json_last_instruction_row.values.push_back("0m");
+ json_last_instruction_row.values.push_back(Azimuth::Get(0.0));
+ json_last_instruction_row.values.push_back(0.);
+ json_instruction_array.values.push_back(json_last_instruction_row);
+ }
+ }
+};
+
+#endif /* JSON_DESCRIPTOR_H_ */
diff --git a/Extractor/BaseParser.cpp b/Extractor/BaseParser.cpp
index 6981e95..4ab090f 100644
--- a/Extractor/BaseParser.cpp
+++ b/Extractor/BaseParser.cpp
@@ -1,114 +1,137 @@
/*
-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.
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
*/
#include "BaseParser.h"
+#include "ExtractionWay.h"
+#include "ScriptingEnvironment.h"
+
+#include "../DataStructures/ImportNode.h"
+#include "../Util/LuaUtil.h"
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/regex.hpp>
+#include <boost/ref.hpp>
+#include <boost/regex.hpp>
-BaseParser::BaseParser(ExtractorCallbacks* ec, ScriptingEnvironment& se) :
-extractor_callbacks(ec), scriptingEnvironment(se), luaState(NULL), use_turn_restrictions(true) {
- luaState = se.getLuaStateForThreadID(0);
+BaseParser::BaseParser(ExtractorCallbacks *extractor_callbacks,
+ ScriptingEnvironment &scripting_environment)
+ : extractor_callbacks(extractor_callbacks),
+ lua_state(scripting_environment.getLuaState()),
+ scripting_environment(scripting_environment), use_turn_restrictions(true)
+{
ReadUseRestrictionsSetting();
ReadRestrictionExceptions();
}
-void BaseParser::ReadUseRestrictionsSetting() {
- if( 0 != luaL_dostring( luaState, "return use_turn_restrictions\n") ) {
- ERR(lua_tostring( luaState,-1)<< " occured in scripting block");
+void BaseParser::ReadUseRestrictionsSetting()
+{
+ if (0 != luaL_dostring(lua_state, "return use_turn_restrictions\n"))
+ {
+ throw OSRMException("ERROR occured in scripting block");
}
- if( lua_isboolean( luaState, -1) ) {
- use_turn_restrictions = lua_toboolean(luaState, -1);
+ if (lua_isboolean(lua_state, -1))
+ {
+ use_turn_restrictions = lua_toboolean(lua_state, -1);
}
- if( use_turn_restrictions ) {
- INFO("Using turn restrictions" );
- } else {
- INFO("Ignoring turn restrictions" );
+ if (use_turn_restrictions)
+ {
+ SimpleLogger().Write() << "Using turn restrictions";
+ }
+ else
+ {
+ SimpleLogger().Write() << "Ignoring turn restrictions";
}
}
-void BaseParser::ReadRestrictionExceptions() {
- if(lua_function_exists(luaState, "get_exceptions" )) {
- //get list of turn restriction exceptions
- try {
- luabind::call_function<void>(
- luaState,
- "get_exceptions",
- boost::ref(restriction_exceptions)
- );
- INFO("Found " << restriction_exceptions.size() << " exceptions to turn restriction");
- BOOST_FOREACH(std::string & str, restriction_exceptions) {
- INFO(" " << str);
- }
- } catch (const luabind::error &er) {
- lua_State* Ler=er.state();
- report_errors(Ler, -1);
- ERR(er.what());
+void BaseParser::ReadRestrictionExceptions()
+{
+ if (lua_function_exists(lua_state, "get_exceptions"))
+ {
+ // get list of turn restriction exceptions
+ luabind::call_function<void>(
+ lua_state, "get_exceptions", boost::ref(restriction_exceptions));
+ const unsigned exception_count = restriction_exceptions.size();
+ SimpleLogger().Write() << "Found " << exception_count
+ << " exceptions to turn restrictions:";
+ for (const std::string &str : restriction_exceptions)
+ {
+ SimpleLogger().Write() << " " << str;
}
- } else {
- INFO("Found no exceptions to turn restrictions");
+ }
+ else
+ {
+ SimpleLogger().Write() << "Found no exceptions to turn restrictions";
}
}
-void BaseParser::report_errors(lua_State *L, const int status) const {
- if( 0!=status ) {
- std::cerr << "-- " << lua_tostring(L, -1) << std::endl;
- lua_pop(L, 1); // remove error message
+void BaseParser::report_errors(lua_State *lua_state, const int status) const
+{
+ if (0 != status)
+ {
+ std::cerr << "-- " << lua_tostring(lua_state, -1) << std::endl;
+ lua_pop(lua_state, 1); // remove error message
}
}
-void BaseParser::ParseNodeInLua(ImportNode& n, lua_State* localLuaState) {
- try {
- luabind::call_function<void>( localLuaState, "node_function", boost::ref(n) );
- } catch (const luabind::error &er) {
- lua_State* Ler=er.state();
- report_errors(Ler, -1);
- ERR(er.what());
- }
+void BaseParser::ParseNodeInLua(ImportNode &node, lua_State *local_lua_state)
+{
+ luabind::call_function<void>(local_lua_state, "node_function", boost::ref(node));
}
-void BaseParser::ParseWayInLua(ExtractionWay& w, lua_State* localLuaState) {
- if(2 > w.path.size()) {
- return;
- }
- try {
- luabind::call_function<void>( localLuaState, "way_function", boost::ref(w) );
- } catch (const luabind::error &er) {
- lua_State* Ler=er.state();
- report_errors(Ler, -1);
- ERR(er.what());
- }
+void BaseParser::ParseWayInLua(ExtractionWay &way, lua_State *local_lua_state)
+{
+ luabind::call_function<void>(local_lua_state, "way_function", boost::ref(way));
}
-bool BaseParser::ShouldIgnoreRestriction(const std::string& except_tag_string) const {
- //should this restriction be ignored? yes if there's an overlap between:
- //a) the list of modes in the except tag of the restriction (except_tag_string), ex: except=bus;bicycle
- //b) the lua profile defines a hierachy of modes, ex: [access, vehicle, bicycle]
-
- if( "" == except_tag_string ) {
+bool BaseParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
+{
+ // should this restriction be ignored? yes if there's an overlap between:
+ // a) the list of modes in the except tag of the restriction
+ // (except_tag_string), eg: except=bus;bicycle
+ // b) the lua profile defines a hierachy of modes,
+ // eg: [access, vehicle, bicycle]
+
+ if (except_tag_string.empty())
+ {
return false;
}
-
- //Be warned, this is quadratic work here, but we assume that
- //only a few exceptions are actually defined.
+
+ // Be warned, this is quadratic work here, but we assume that
+ // only a few exceptions are actually defined.
std::vector<std::string> exceptions;
boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*"));
- BOOST_FOREACH(std::string& str, exceptions) {
- if( restriction_exceptions.end() != std::find(restriction_exceptions.begin(), restriction_exceptions.end(), str) ) {
+ for (std::string ¤t_string : exceptions)
+ {
+ const auto string_iterator =
+ std::find(restriction_exceptions.begin(), restriction_exceptions.end(), current_string);
+ if (restriction_exceptions.end() != string_iterator)
+ {
return true;
}
}
diff --git a/Extractor/BaseParser.h b/Extractor/BaseParser.h
index 6a19efa..b18da34 100644
--- a/Extractor/BaseParser.h
+++ b/Extractor/BaseParser.h
@@ -1,59 +1,67 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef BASEPARSER_H_
#define BASEPARSER_H_
-extern "C" {
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
-}
-
-#include <boost/noncopyable.hpp>
+#include <string>
+#include <vector>
-#include "ExtractorCallbacks.h"
-#include "ScriptingEnvironment.h"
+struct lua_State;
+class ExtractorCallbacks;
+class ScriptingEnvironment;
+struct ExtractionWay;
+struct ImportNode;
-class BaseParser : boost::noncopyable {
-public:
- BaseParser(ExtractorCallbacks* ec, ScriptingEnvironment& se);
+class BaseParser
+{
+ public:
+ BaseParser() = delete;
+ BaseParser(const BaseParser &) = delete;
+ BaseParser(ExtractorCallbacks *extractor_callbacks,
+ ScriptingEnvironment &scripting_environment);
virtual ~BaseParser() {}
virtual bool ReadHeader() = 0;
virtual bool Parse() = 0;
- virtual void ParseNodeInLua(ImportNode& n, lua_State* luaStateForThread);
- virtual void ParseWayInLua(ExtractionWay& n, lua_State* luaStateForThread);
- virtual void report_errors(lua_State *L, const int status) const;
+ virtual void ParseNodeInLua(ImportNode &node, lua_State *lua_state);
+ virtual void ParseWayInLua(ExtractionWay &way, lua_State *lua_state);
+ virtual void report_errors(lua_State *lua_state, const int status) const;
-protected:
+ protected:
virtual void ReadUseRestrictionsSetting();
virtual void ReadRestrictionExceptions();
- virtual bool ShouldIgnoreRestriction(const std::string& except_tag_string) const;
-
- ExtractorCallbacks* extractor_callbacks;
- ScriptingEnvironment& scriptingEnvironment;
- lua_State* luaState;
+ virtual bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
+
+ ExtractorCallbacks *extractor_callbacks;
+ lua_State *lua_state;
+ ScriptingEnvironment &scripting_environment;
std::vector<std::string> restriction_exceptions;
bool use_turn_restrictions;
-
};
#endif /* BASEPARSER_H_ */
diff --git a/Extractor/ExtractionContainers.cpp b/Extractor/ExtractionContainers.cpp
index 2cb2baf..91981d6 100644
--- a/Extractor/ExtractionContainers.cpp
+++ b/Extractor/ExtractionContainers.cpp
@@ -1,306 +1,428 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#include "ExtractionContainers.h"
+#include "ExtractionWay.h"
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/TimingUtil.h"
+#include "../DataStructures/RangeTable.h"
+
+#include <boost/assert.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <stxxl/sort>
+
+#include <chrono>
+#include <limits>
+
+ExtractionContainers::ExtractionContainers()
+{
+ // Check if stxxl can be instantiated
+ stxxl::vector<unsigned> dummy_vector;
+ name_list.push_back("");
+}
+
+ExtractionContainers::~ExtractionContainers()
+{
+ used_node_id_list.clear();
+ all_nodes_list.clear();
+ all_edges_list.clear();
+ name_list.clear();
+ restrictions_list.clear();
+ way_start_end_id_list.clear();
+}
-void ExtractionContainers::PrepareData(const std::string & outputFileName, const std::string restrictionsFileName, const unsigned amountOfRAM) {
- try {
- unsigned usedNodeCounter = 0;
- unsigned usedEdgeCounter = 0;
- double time = get_timestamp();
- boost::uint64_t memory_to_use = static_cast<boost::uint64_t>(amountOfRAM) * 1024 * 1024 * 1024;
+void ExtractionContainers::PrepareData(const std::string &output_file_name,
+ const std::string &restrictions_file_name)
+{
+ try
+ {
+ unsigned number_of_used_nodes = 0;
+ unsigned number_of_used_edges = 0;
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
- stxxl::sort(usedNodeIDs.begin(), usedNodeIDs.end(), Cmp(), memory_to_use);
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
+ TIMER_START(sorting_used_nodes);
+ stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
+ TIMER_STOP(sorting_used_nodes);
+ std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
- time = get_timestamp();
std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush;
- stxxl::vector<NodeID>::iterator NewEnd = std::unique ( usedNodeIDs.begin(),usedNodeIDs.end() ) ;
- usedNodeIDs.resize ( NewEnd - usedNodeIDs.begin() );
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
- time = get_timestamp();
+ TIMER_START(erasing_dups);
+ auto new_end = std::unique(used_node_id_list.begin(), used_node_id_list.end());
+ used_node_id_list.resize(new_end - used_node_id_list.begin());
+ TIMER_STOP(erasing_dups);
+ std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
+
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
- stxxl::sort(allNodes.begin(), allNodes.end(), CmpNodeByID(), memory_to_use);
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
- time = get_timestamp();
+ TIMER_START(sorting_nodes);
+ stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), CmpNodeByID(), stxxl_memory);
+ TIMER_STOP(sorting_nodes);
+ std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
- std::cout << "[extractor] Sorting used ways ... " << std::flush;
- stxxl::sort(wayStartEndVector.begin(), wayStartEndVector.end(), CmpWayByID(), memory_to_use);
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
- std::cout << "[extractor] Sorting restrctns. by from... " << std::flush;
- stxxl::sort(restrictionsVector.begin(), restrictionsVector.end(), CmpRestrictionContainerByFrom(), memory_to_use);
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
+ std::cout << "[extractor] Sorting used ways ... " << std::flush;
+ TIMER_START(sort_ways);
+ stxxl::sort(
+ way_start_end_id_list.begin(), way_start_end_id_list.end(), CmpWayByID(), stxxl_memory);
+ TIMER_STOP(sort_ways);
+ std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
+
+ std::cout << "[extractor] Sorting restrictions. by from... " << std::flush;
+ TIMER_START(sort_restrictions);
+ stxxl::sort(restrictions_list.begin(),
+ restrictions_list.end(),
+ CmpRestrictionContainerByFrom(),
+ stxxl_memory);
+ TIMER_STOP(sort_restrictions);
+ std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
- STXXLRestrictionsVector::iterator restrictionsIT = restrictionsVector.begin();
- STXXLWayIDStartEndVector::iterator wayStartAndEndEdgeIT = wayStartEndVector.begin();
-
- while(wayStartAndEndEdgeIT != wayStartEndVector.end() && restrictionsIT != restrictionsVector.end()) {
- if(wayStartAndEndEdgeIT->wayID < restrictionsIT->fromWay){
- ++wayStartAndEndEdgeIT;
+ TIMER_START(fix_restriction_starts);
+ auto restrictions_iterator = restrictions_list.begin();
+ auto way_start_and_end_iterator = way_start_end_id_list.begin();
+
+ while (way_start_and_end_iterator != way_start_end_id_list.end() &&
+ restrictions_iterator != restrictions_list.end())
+ {
+ if (way_start_and_end_iterator->wayID < restrictions_iterator->fromWay)
+ {
+ ++way_start_and_end_iterator;
continue;
}
- if(wayStartAndEndEdgeIT->wayID > restrictionsIT->fromWay) {
- ++restrictionsIT;
+
+ if (way_start_and_end_iterator->wayID > restrictions_iterator->fromWay)
+ {
+ ++restrictions_iterator;
continue;
}
- assert(wayStartAndEndEdgeIT->wayID == restrictionsIT->fromWay);
- NodeID viaNode = restrictionsIT->restriction.viaNode;
-
- if(wayStartAndEndEdgeIT->firstStart == viaNode) {
- restrictionsIT->restriction.fromNode = wayStartAndEndEdgeIT->firstTarget;
- } else if(wayStartAndEndEdgeIT->firstTarget == viaNode) {
- restrictionsIT->restriction.fromNode = wayStartAndEndEdgeIT->firstStart;
- } else if(wayStartAndEndEdgeIT->lastStart == viaNode) {
- restrictionsIT->restriction.fromNode = wayStartAndEndEdgeIT->lastTarget;
- } else if(wayStartAndEndEdgeIT->lastTarget == viaNode) {
- restrictionsIT->restriction.fromNode = wayStartAndEndEdgeIT->lastStart;
+
+ BOOST_ASSERT(way_start_and_end_iterator->wayID == restrictions_iterator->fromWay);
+ const NodeID via_node_id = restrictions_iterator->restriction.viaNode;
+
+ if (way_start_and_end_iterator->firstStart == via_node_id)
+ {
+ restrictions_iterator->restriction.fromNode =
+ way_start_and_end_iterator->firstTarget;
+ }
+ else if (way_start_and_end_iterator->firstTarget == via_node_id)
+ {
+ restrictions_iterator->restriction.fromNode =
+ way_start_and_end_iterator->firstStart;
+ }
+ else if (way_start_and_end_iterator->lastStart == via_node_id)
+ {
+ restrictions_iterator->restriction.fromNode =
+ way_start_and_end_iterator->lastTarget;
}
- ++restrictionsIT;
+ else if (way_start_and_end_iterator->lastTarget == via_node_id)
+ {
+ restrictions_iterator->restriction.fromNode = way_start_and_end_iterator->lastStart;
+ }
+ ++restrictions_iterator;
}
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
- time = get_timestamp();
+ TIMER_STOP(fix_restriction_starts);
+ std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
- std::cout << "[extractor] Sorting restrctns. by to ... " << std::flush;
- stxxl::sort(restrictionsVector.begin(), restrictionsVector.end(), CmpRestrictionContainerByTo(), memory_to_use);
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
+ std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
+ TIMER_START(sort_restrictions_to);
+ stxxl::sort(restrictions_list.begin(),
+ restrictions_list.end(),
+ CmpRestrictionContainerByTo(),
+ stxxl_memory);
+ TIMER_STOP(sort_restrictions_to);
+ std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
- time = get_timestamp();
- unsigned usableRestrictionsCounter(0);
+ unsigned number_of_useable_restrictions = 0;
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
- restrictionsIT = restrictionsVector.begin();
- wayStartAndEndEdgeIT = wayStartEndVector.begin();
- while(wayStartAndEndEdgeIT != wayStartEndVector.end() && restrictionsIT != restrictionsVector.end()) {
- if(wayStartAndEndEdgeIT->wayID < restrictionsIT->toWay){
- ++wayStartAndEndEdgeIT;
+ TIMER_START(fix_restriction_ends);
+ restrictions_iterator = restrictions_list.begin();
+ way_start_and_end_iterator = way_start_end_id_list.begin();
+ while (way_start_and_end_iterator != way_start_end_id_list.end() &&
+ restrictions_iterator != restrictions_list.end())
+ {
+ if (way_start_and_end_iterator->wayID < restrictions_iterator->toWay)
+ {
+ ++way_start_and_end_iterator;
continue;
}
- if(wayStartAndEndEdgeIT->wayID > restrictionsIT->toWay) {
- ++restrictionsIT;
+ if (way_start_and_end_iterator->wayID > restrictions_iterator->toWay)
+ {
+ ++restrictions_iterator;
continue;
}
- NodeID viaNode = restrictionsIT->restriction.viaNode;
- if(wayStartAndEndEdgeIT->lastStart == viaNode) {
- restrictionsIT->restriction.toNode = wayStartAndEndEdgeIT->lastTarget;
- } else if(wayStartAndEndEdgeIT->lastTarget == viaNode) {
- restrictionsIT->restriction.toNode = wayStartAndEndEdgeIT->lastStart;
- } else if(wayStartAndEndEdgeIT->firstStart == viaNode) {
- restrictionsIT->restriction.toNode = wayStartAndEndEdgeIT->firstTarget;
- } else if(wayStartAndEndEdgeIT->firstTarget == viaNode) {
- restrictionsIT->restriction.toNode = wayStartAndEndEdgeIT->firstStart;
+ NodeID via_node_id = restrictions_iterator->restriction.viaNode;
+ if (way_start_and_end_iterator->lastStart == via_node_id)
+ {
+ restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastTarget;
+ }
+ else if (way_start_and_end_iterator->lastTarget == via_node_id)
+ {
+ restrictions_iterator->restriction.toNode = way_start_and_end_iterator->lastStart;
+ }
+ else if (way_start_and_end_iterator->firstStart == via_node_id)
+ {
+ restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstTarget;
+ }
+ else if (way_start_and_end_iterator->firstTarget == via_node_id)
+ {
+ restrictions_iterator->restriction.toNode = way_start_and_end_iterator->firstStart;
}
- if(UINT_MAX != restrictionsIT->restriction.fromNode && UINT_MAX != restrictionsIT->restriction.toNode) {
- ++usableRestrictionsCounter;
+ if (std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.fromNode &&
+ std::numeric_limits<unsigned>::max() != restrictions_iterator->restriction.toNode)
+ {
+ ++number_of_useable_restrictions;
}
- ++restrictionsIT;
+ ++restrictions_iterator;
}
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
- INFO("usable restrictions: " << usableRestrictionsCounter );
- //serialize restrictions
- std::ofstream restrictionsOutstream;
- restrictionsOutstream.open(restrictionsFileName.c_str(), std::ios::binary);
- restrictionsOutstream.write((char*)&usableRestrictionsCounter, sizeof(unsigned));
- for(restrictionsIT = restrictionsVector.begin(); restrictionsIT != restrictionsVector.end(); ++restrictionsIT) {
- if(UINT_MAX != restrictionsIT->restriction.fromNode && UINT_MAX != restrictionsIT->restriction.toNode) {
- restrictionsOutstream.write((char *)&(restrictionsIT->restriction), sizeof(_Restriction));
+ TIMER_STOP(fix_restriction_ends);
+ std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
+
+ SimpleLogger().Write() << "usable restrictions: " << number_of_useable_restrictions;
+ // serialize restrictions
+ std::ofstream restrictions_out_stream;
+ restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary);
+ restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
+ restrictions_out_stream.write((char *)&number_of_useable_restrictions, sizeof(unsigned));
+
+ for(const auto & restriction_container : restrictions_list)
+ {
+ if (std::numeric_limits<unsigned>::max() != restriction_container.restriction.fromNode &&
+ std::numeric_limits<unsigned>::max() != restriction_container.restriction.toNode)
+ {
+ restrictions_out_stream.write((char *)&(restriction_container.restriction),
+ sizeof(TurnRestriction));
}
}
- restrictionsOutstream.close();
+ restrictions_out_stream.close();
- std::ofstream fout;
- fout.open(outputFileName.c_str(), std::ios::binary);
- fout.write((char*)&usedNodeCounter, sizeof(unsigned));
- time = get_timestamp();
+ std::ofstream file_out_stream;
+ file_out_stream.open(output_file_name.c_str(), std::ios::binary);
+ file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
+ file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
-
- STXXLNodeVector::iterator nodesIT = allNodes.begin();
- STXXLNodeIDVector::iterator usedNodeIDsIT = usedNodeIDs.begin();
- while(usedNodeIDsIT != usedNodeIDs.end() && nodesIT != allNodes.end()) {
- if(*usedNodeIDsIT < nodesIT->id){
- ++usedNodeIDsIT;
+ TIMER_START(write_nodes);
+ // identify all used nodes by a merging step of two sorted lists
+ auto node_iterator = all_nodes_list.begin();
+ auto node_id_iterator = used_node_id_list.begin();
+ while (node_id_iterator != used_node_id_list.end() && node_iterator != all_nodes_list.end())
+ {
+ if (*node_id_iterator < node_iterator->node_id)
+ {
+ ++node_id_iterator;
continue;
}
- if(*usedNodeIDsIT > nodesIT->id) {
- ++nodesIT;
+ if (*node_id_iterator > node_iterator->node_id)
+ {
+ ++node_iterator;
continue;
}
- if(*usedNodeIDsIT == nodesIT->id) {
- fout.write((char*)&(*nodesIT), sizeof(_Node));
- ++usedNodeCounter;
- ++usedNodeIDsIT;
- ++nodesIT;
- }
+ BOOST_ASSERT(*node_id_iterator == node_iterator->node_id);
+
+ file_out_stream.write((char *)&(*node_iterator), sizeof(ExternalMemoryNode));
+
+ ++number_of_used_nodes;
+ ++node_id_iterator;
+ ++node_iterator;
}
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
+ TIMER_STOP(write_nodes);
+ std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
std::cout << "[extractor] setting number of nodes ... " << std::flush;
- std::ios::pos_type positionInFile = fout.tellp();
- fout.seekp(std::ios::beg);
- fout.write((char*)&usedNodeCounter, sizeof(unsigned));
- fout.seekp(positionInFile);
+ std::ios::pos_type previous_file_position = file_out_stream.tellp();
+ file_out_stream.seekp(std::ios::beg + sizeof(FingerPrint));
+ file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
+ file_out_stream.seekp(previous_file_position);
std::cout << "ok" << std::endl;
- time = get_timestamp();
// Sort edges by start.
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
- stxxl::sort(allEdges.begin(), allEdges.end(), CmpEdgeByStartID(), memory_to_use);
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
- time = get_timestamp();
+ TIMER_START(sort_edges_by_start);
+ stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
+ TIMER_STOP(sort_edges_by_start);
+ std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
+
std::cout << "[extractor] Setting start coords ... " << std::flush;
- fout.write((char*)&usedEdgeCounter, sizeof(unsigned));
+ TIMER_START(set_start_coords);
+ file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
// Traverse list of edges and nodes in parallel and set start coord
- nodesIT = allNodes.begin();
- STXXLEdgeVector::iterator edgeIT = allEdges.begin();
- while(edgeIT != allEdges.end() && nodesIT != allNodes.end()) {
- if(edgeIT->start < nodesIT->id){
- ++edgeIT;
+ node_iterator = all_nodes_list.begin();
+ auto edge_iterator = all_edges_list.begin();
+ while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
+ {
+ if (edge_iterator->start < node_iterator->node_id)
+ {
+ ++edge_iterator;
continue;
}
- if(edgeIT->start > nodesIT->id) {
- nodesIT++;
+ if (edge_iterator->start > node_iterator->node_id)
+ {
+ node_iterator++;
continue;
}
- if(edgeIT->start == nodesIT->id) {
- edgeIT->startCoord.lat = nodesIT->lat;
- edgeIT->startCoord.lon = nodesIT->lon;
- ++edgeIT;
- }
+
+ BOOST_ASSERT(edge_iterator->start == node_iterator->node_id);
+ edge_iterator->source_coordinate.lat = node_iterator->lat;
+ edge_iterator->source_coordinate.lon = node_iterator->lon;
+ ++edge_iterator;
}
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
- time = get_timestamp();
+ TIMER_STOP(set_start_coords);
+ std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
// Sort Edges by target
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
- stxxl::sort(allEdges.begin(), allEdges.end(), CmpEdgeByTargetID(), memory_to_use);
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
- time = get_timestamp();
+ TIMER_START(sort_edges_by_target);
+ stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByTargetID(), stxxl_memory);
+ TIMER_STOP(sort_edges_by_target);
+ std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
std::cout << "[extractor] Setting target coords ... " << std::flush;
+ TIMER_START(set_target_coords);
// Traverse list of edges and nodes in parallel and set target coord
- nodesIT = allNodes.begin();
- edgeIT = allEdges.begin();
-
- while(edgeIT != allEdges.end() && nodesIT != allNodes.end()) {
- if(edgeIT->target < nodesIT->id){
- ++edgeIT;
+ node_iterator = all_nodes_list.begin();
+ edge_iterator = all_edges_list.begin();
+
+ while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
+ {
+ if (edge_iterator->target < node_iterator->node_id)
+ {
+ ++edge_iterator;
continue;
}
- if(edgeIT->target > nodesIT->id) {
- ++nodesIT;
+ if (edge_iterator->target > node_iterator->node_id)
+ {
+ ++node_iterator;
continue;
}
- if(edgeIT->target == nodesIT->id) {
- if(edgeIT->startCoord.lat != INT_MIN && edgeIT->startCoord.lon != INT_MIN) {
- edgeIT->targetCoord.lat = nodesIT->lat;
- edgeIT->targetCoord.lon = nodesIT->lon;
-
- double distance = ApproximateDistance(edgeIT->startCoord.lat, edgeIT->startCoord.lon, nodesIT->lat, nodesIT->lon);
- assert(edgeIT->speed != -1);
- double weight = ( distance * 10. ) / (edgeIT->speed / 3.6);
- int intWeight = std::max(1, (int)std::floor((edgeIT->isDurationSet ? edgeIT->speed : weight)+.5) );
- int intDist = std::max(1, (int)distance);
- short zero = 0;
- short one = 1;
-
- fout.write((char*)&edgeIT->start, sizeof(unsigned));
- fout.write((char*)&edgeIT->target, sizeof(unsigned));
- fout.write((char*)&intDist, sizeof(int));
- switch(edgeIT->direction) {
- case ExtractionWay::notSure:
- fout.write((char*)&zero, sizeof(short));
- break;
- case ExtractionWay::oneway:
- fout.write((char*)&one, sizeof(short));
- break;
- case ExtractionWay::bidirectional:
- fout.write((char*)&zero, sizeof(short));
-
- break;
- case ExtractionWay::opposite:
- fout.write((char*)&one, sizeof(short));
- break;
- default:
- std::cerr << "[error] edge with no direction: " << edgeIT->direction << std::endl;
- assert(false);
- break;
- }
- fout.write((char*)&intWeight, sizeof(int));
- assert(edgeIT->type >= 0);
- fout.write((char*)&edgeIT->type, sizeof(short));
- fout.write((char*)&edgeIT->nameID, sizeof(unsigned));
- fout.write((char*)&edgeIT->isRoundabout, sizeof(bool));
- fout.write((char*)&edgeIT->ignoreInGrid, sizeof(bool));
- fout.write((char*)&edgeIT->isAccessRestricted, sizeof(bool));
- fout.write((char*)&edgeIT->isContraFlow, sizeof(bool));
- ++usedEdgeCounter;
+ BOOST_ASSERT(edge_iterator->target == node_iterator->node_id);
+ if (edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min() &&
+ edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
+ {
+ BOOST_ASSERT(edge_iterator->speed != -1);
+ BOOST_ASSERT(edge_iterator->type >= 0);
+ edge_iterator->target_coordinate.lat = node_iterator->lat;
+ edge_iterator->target_coordinate.lon = node_iterator->lon;
+
+ const double distance = FixedPointCoordinate::ApproximateEuclideanDistance(
+ edge_iterator->source_coordinate.lat,
+ edge_iterator->source_coordinate.lon,
+ node_iterator->lat,
+ node_iterator->lon);
+
+ const double weight = (distance * 10.) / (edge_iterator->speed / 3.6);
+ int integer_weight = std::max(
+ 1,
+ (int)std::floor(
+ (edge_iterator->is_duration_set ? edge_iterator->speed : weight) + .5));
+ int integer_distance = std::max(1, (int)distance);
+ short zero = 0;
+ short one = 1;
+
+ file_out_stream.write((char *)&edge_iterator->start, sizeof(unsigned));
+ file_out_stream.write((char *)&edge_iterator->target, sizeof(unsigned));
+ file_out_stream.write((char *)&integer_distance, sizeof(int));
+ switch (edge_iterator->direction)
+ {
+ case ExtractionWay::notSure:
+ file_out_stream.write((char *)&zero, sizeof(short));
+ break;
+ case ExtractionWay::oneway:
+ file_out_stream.write((char *)&one, sizeof(short));
+ break;
+ case ExtractionWay::bidirectional:
+ file_out_stream.write((char *)&zero, sizeof(short));
+ break;
+ case ExtractionWay::opposite:
+ file_out_stream.write((char *)&one, sizeof(short));
+ break;
+ default:
+ throw OSRMException("edge has broken direction");
}
- ++edgeIT;
+
+ file_out_stream.write((char *)&integer_weight, sizeof(int));
+ file_out_stream.write((char *)&edge_iterator->type, sizeof(short));
+ file_out_stream.write((char *)&edge_iterator->name_id, sizeof(unsigned));
+ file_out_stream.write((char *)&edge_iterator->is_roundabout, sizeof(bool));
+ file_out_stream.write((char *)&edge_iterator->is_in_tiny_cc, sizeof(bool));
+ file_out_stream.write((char *)&edge_iterator->is_access_restricted, sizeof(bool));
+ file_out_stream.write((char *)&edge_iterator->is_contra_flow, sizeof(bool));
+ file_out_stream.write((char *)&edge_iterator->is_split, sizeof(bool));
+ ++number_of_used_edges;
}
+ ++edge_iterator;
}
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
+ TIMER_STOP(set_target_coords);
+ std::cout << "ok, after " << TIMER_SEC(set_target_coords) << "s" << std::endl;
+
std::cout << "[extractor] setting number of edges ... " << std::flush;
- fout.seekp(positionInFile);
- fout.write((char*)&usedEdgeCounter, sizeof(unsigned));
- fout.close();
+ file_out_stream.seekp(previous_file_position);
+ file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
+ file_out_stream.close();
std::cout << "ok" << std::endl;
- time = get_timestamp();
+
std::cout << "[extractor] writing street name index ... " << std::flush;
- std::string nameOutFileName = (outputFileName + ".names");
- std::ofstream nameOutFile(nameOutFileName.c_str(), std::ios::binary);
- unsigned sizeOfNameIndex = nameVector.size();
- nameOutFile.write((char *)&(sizeOfNameIndex), sizeof(unsigned));
-
- BOOST_FOREACH(const std::string & str, nameVector) {
- unsigned lengthOfRawString = strlen(str.c_str());
- nameOutFile.write((char *)&(lengthOfRawString), sizeof(unsigned));
- nameOutFile.write(str.c_str(), lengthOfRawString);
+ TIMER_START(write_name_index);
+ std::string name_file_streamName = (output_file_name + ".names");
+ boost::filesystem::ofstream name_file_stream(name_file_streamName, std::ios::binary);
+
+ unsigned total_length = 0;
+ std::vector<unsigned> name_lengths;
+ for (const std::string &temp_string : name_list)
+ {
+ const unsigned string_length = std::min(static_cast<unsigned>(temp_string.length()), 255u);
+ name_lengths.push_back(string_length);
+ total_length += string_length;
}
- nameOutFile.close();
- std::cout << "ok, after " << get_timestamp() - time << "s" << std::endl;
-
- // time = get_timestamp();
- // cout << "[extractor] writing address list ... " << flush;
- //
- // adressFileName.append(".address");
- // ofstream addressOutFile(adressFileName.c_str());
- // for(STXXLAddressVector::iterator it = adressVector.begin(); it != adressVector.end(); it++) {
- // addressOutFile << it->node.id << "|" << it->node.lat << "|" << it->node.lon << "|" << it->city << "|" << it->street << "|" << it->housenumber << "|" << it->state << "|" << it->country << "\n";
- // }
- // addressOutFile.close();
- // cout << "ok, after " << get_timestamp() - time << "s" << endl;
+ RangeTable<> table(name_lengths);
+ name_file_stream << table;
- INFO("Processed " << usedNodeCounter << " nodes and " << usedEdgeCounter << " edges");
+ name_file_stream.write((char*) &total_length, sizeof(unsigned));
+ // write all chars consecutively
+ for (const std::string &temp_string : name_list)
+ {
+ const unsigned string_length = std::min(static_cast<unsigned>(temp_string.length()), 255u);
+ name_file_stream.write(temp_string.c_str(), string_length);
+ }
+ name_file_stream.close();
+ TIMER_STOP(write_name_index);
+ std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
- } catch ( const std::exception& e ) {
- std::cerr << "Caught Execption:" << e.what() << std::endl;
+ SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes and "
+ << number_of_used_edges << " edges";
}
+ catch (const std::exception &e) { std::cerr << "Caught Execption:" << e.what() << std::endl; }
}
-
diff --git a/Extractor/ExtractionContainers.h b/Extractor/ExtractionContainers.h
index f5dfa78..a272387 100644
--- a/Extractor/ExtractionContainers.h
+++ b/Extractor/ExtractionContainers.h
@@ -1,69 +1,69 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef EXTRACTIONCONTAINERS_H_
#define EXTRACTIONCONTAINERS_H_
+#include "InternalExtractorEdge.h"
#include "ExtractorStructs.h"
-#include "../DataStructures/TimingUtil.h"
+#include "../DataStructures/Restriction.h"
+#include "../Util/FingerPrint.h"
-#include <boost/foreach.hpp>
-#include <stxxl.h>
+#include <stxxl/vector>
-class ExtractionContainers {
-public:
+class ExtractionContainers
+{
+#ifndef _MSC_VER
+ constexpr static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? std::numeric_limits<int>::max() : std::numeric_limits<unsigned>::max());
+#else
+ const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
+#endif
+ public:
typedef stxxl::vector<NodeID> STXXLNodeIDVector;
- typedef stxxl::vector<_Node> STXXLNodeVector;
+ typedef stxxl::vector<ExternalMemoryNode> STXXLNodeVector;
typedef stxxl::vector<InternalExtractorEdge> STXXLEdgeVector;
typedef stxxl::vector<std::string> STXXLStringVector;
- typedef stxxl::vector<_RawRestrictionContainer> STXXLRestrictionsVector;
- typedef stxxl::vector<_WayIDStartAndEndEdge> STXXLWayIDStartEndVector;
-
- ExtractionContainers() {
- //Check if another instance of stxxl is already running or if there is a general problem
- try {
- stxxl::vector<unsigned> testForRunningInstance;
- } catch(std::exception & e) {
- ERR("Could not instantiate STXXL layer." << std::endl << e.what());
- }
+ typedef stxxl::vector<InputRestrictionContainer> STXXLRestrictionsVector;
+ typedef stxxl::vector<WayIDStartAndEndEdge> STXXLWayIDStartEndVector;
- nameVector.push_back("");
- }
- virtual ~ExtractionContainers() {
- usedNodeIDs.clear();
- allNodes.clear();
- allEdges.clear();
- nameVector.clear();
- restrictionsVector.clear();
- wayStartEndVector.clear();
- }
+ STXXLNodeIDVector used_node_id_list;
+ STXXLNodeVector all_nodes_list;
+ STXXLEdgeVector all_edges_list;
+ STXXLStringVector name_list;
+ STXXLRestrictionsVector restrictions_list;
+ STXXLWayIDStartEndVector way_start_end_id_list;
+ const FingerPrint fingerprint;
- void PrepareData( const std::string & outputFileName, const std::string restrictionsFileName, const unsigned amountOfRAM);
+ ExtractionContainers();
- STXXLNodeIDVector usedNodeIDs;
- STXXLNodeVector allNodes;
- STXXLEdgeVector allEdges;
- STXXLStringVector nameVector;
- STXXLRestrictionsVector restrictionsVector;
- STXXLWayIDStartEndVector wayStartEndVector;
+ virtual ~ExtractionContainers();
+ void PrepareData(const std::string &output_file_name,
+ const std::string &restrictions_file_name);
};
#endif /* EXTRACTIONCONTAINERS_H_ */
diff --git a/Extractor/ExtractionHelperFunctions.h b/Extractor/ExtractionHelperFunctions.h
index 6771939..a918744 100644
--- a/Extractor/ExtractionHelperFunctions.h
+++ b/Extractor/ExtractionHelperFunctions.h
@@ -1,83 +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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
-#ifndef EXTRACTIONHELPERFUNCTIONS_H_
-#define EXTRACTIONHELPERFUNCTIONS_H_
+#ifndef EXTRACTION_HELPER_FUNCTIONS_H
+#define EXTRACTION_HELPER_FUNCTIONS_H
+
+#include "../Util/StringUtil.h"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string_regex.hpp>
#include <boost/regex.hpp>
-#include <climits>
-
-#include "../Util/StringUtil.h"
+#include <limits>
namespace qi = boost::spirit::qi;
-//TODO: Move into LUA
+// TODO: Move into LUA
-inline bool durationIsValid(const std::string &s) {
- boost::regex e ("((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl);
+inline bool durationIsValid(const std::string &s)
+{
+ boost::regex e(
+ "((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
+ boost::regex_constants::icase | boost::regex_constants::perl);
- std::vector< std::string > result;
- boost::algorithm::split_regex( result, s, boost::regex( ":" ) ) ;
- bool matched = regex_match(s, e);
+ std::vector<std::string> result;
+ boost::algorithm::split_regex(result, s, boost::regex(":"));
+ const bool matched = regex_match(s, e);
return matched;
}
-inline unsigned parseDuration(const std::string &s) {
- unsigned hours = 0;
+inline unsigned parseDuration(const std::string &s)
+{
+ unsigned hours = 0;
unsigned minutes = 0;
unsigned seconds = 0;
- boost::regex e ("((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",boost::regex_constants::icase|boost::regex_constants::perl);
-
- std::vector< std::string > result;
- boost::algorithm::split_regex( result, s, boost::regex( ":" ) ) ;
- bool matched = regex_match(s, e);
- if(matched) {
- if(1 == result.size()) {
- minutes = stringToInt(result[0]);
- }
- if(2 == result.size()) {
- minutes = stringToInt(result[1]);
- hours = stringToInt(result[0]);
- }
- if(3 == result.size()) {
- seconds = stringToInt(result[2]);
- minutes = stringToInt(result[1]);
- hours = stringToInt(result[0]);
- }
- return 10*(3600*hours+60*minutes+seconds);
- }
- return UINT_MAX;
-}
-
-inline int parseMaxspeed(std::string input) { //call-by-value on purpose.
- boost::algorithm::to_lower(input);
- int n = stringToInt(input);
- if (input.find("mph") != std::string::npos || input.find("mp/h") != std::string::npos) {
- n = (n*1609)/1000;
+ boost::regex e(
+ "((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
+ boost::regex_constants::icase | boost::regex_constants::perl);
+
+ std::vector<std::string> result;
+ boost::algorithm::split_regex(result, s, boost::regex(":"));
+ const bool matched = regex_match(s, e);
+ if (matched)
+ {
+ if (1 == result.size())
+ {
+ minutes = StringToUint(result[0]);
+ }
+ if (2 == result.size())
+ {
+ minutes = StringToUint(result[1]);
+ hours = StringToUint(result[0]);
+ }
+ if (3 == result.size())
+ {
+ seconds = StringToUint(result[2]);
+ minutes = StringToUint(result[1]);
+ hours = StringToUint(result[0]);
+ }
+ return 10 * (3600 * hours + 60 * minutes + seconds);
}
- return n;
+ return std::numeric_limits<unsigned>::max();
}
-#endif /* EXTRACTIONHELPERFUNCTIONS_H_ */
+#endif // EXTRACTION_HELPER_FUNCTIONS_H_
diff --git a/Extractor/ExtractionWay.h b/Extractor/ExtractionWay.h
new file mode 100644
index 0000000..6c3c93d
--- /dev/null
+++ b/Extractor/ExtractionWay.h
@@ -0,0 +1,79 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef EXTRACTION_WAY_H
+#define EXTRACTION_WAY_H
+
+#include "../DataStructures/HashTable.h"
+#include "../typedefs.h"
+
+#include <string>
+#include <vector>
+
+struct ExtractionWay
+{
+ ExtractionWay() { Clear(); }
+
+ inline void Clear()
+ {
+ id = SPECIAL_NODEID;
+ nameID = INVALID_NAMEID;
+ path.clear();
+ keyVals.Clear();
+ direction = ExtractionWay::notSure;
+ speed = -1;
+ backward_speed = -1;
+ duration = -1;
+ type = -1;
+ access = true;
+ roundabout = false;
+ isAccessRestricted = false;
+ ignoreInGrid = false;
+ }
+
+ enum Directions
+ { notSure = 0,
+ oneway,
+ bidirectional,
+ opposite };
+ unsigned id;
+ unsigned nameID;
+ double speed;
+ double backward_speed;
+ double duration;
+ Directions direction;
+ std::string name;
+ short type;
+ bool access;
+ bool roundabout;
+ bool isAccessRestricted;
+ bool ignoreInGrid;
+ std::vector<NodeID> path;
+ HashTable<std::string, std::string> keyVals;
+};
+
+#endif // EXTRACTION_WAY_H
diff --git a/Extractor/ExtractorCallbacks.cpp b/Extractor/ExtractorCallbacks.cpp
index c8b5fc1..5e27817 100644
--- a/Extractor/ExtractorCallbacks.cpp
+++ b/Extractor/ExtractorCallbacks.cpp
@@ -1,142 +1,171 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-/*
- open source routing machine
- Copyright (C) Dennis Luxen, others 2010
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-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.
+#include "ExtractorCallbacks.h"
+#include "ExtractionContainers.h"
+#include "ExtractionWay.h"
-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 "../DataStructures/Restriction.h"
+#include "../DataStructures/ImportNode.h"
+#include "../Util/SimpleLogger.h"
+#include <osrm/Coordinate.h>
-#include "ExtractorCallbacks.h"
-#include "ExtractionHelperFunctions.h"
+#include <limits>
+#include <string>
+#include <vector>
-ExtractorCallbacks::ExtractorCallbacks() {externalMemory = NULL; stringMap = NULL; }
-ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap) {
- externalMemory = ext;
- stringMap = strMap;
+ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containers,
+ std::unordered_map<std::string, NodeID> &string_map)
+ : string_map(string_map), external_memory(extraction_containers)
+{
}
-ExtractorCallbacks::~ExtractorCallbacks() { }
-
/** warning: caller needs to take care of synchronization! */
-void ExtractorCallbacks::nodeFunction(const _Node &n) {
- if(n.lat <= 85*100000 && n.lat >= -85*100000) {
- externalMemory->allNodes.push_back(n);
+void ExtractorCallbacks::ProcessNode(const ExternalMemoryNode &n)
+{
+ if (n.lat <= 85 * COORDINATE_PRECISION && n.lat >= -85 * COORDINATE_PRECISION)
+ {
+ external_memory.all_nodes_list.push_back(n);
}
}
-bool ExtractorCallbacks::restrictionFunction(const _RawRestrictionContainer &r) {
- externalMemory->restrictionsVector.push_back(r);
+bool ExtractorCallbacks::ProcessRestriction(const InputRestrictionContainer &restriction)
+{
+ external_memory.restrictions_list.push_back(restriction);
return true;
}
/** warning: caller needs to take care of synchronization! */
-void ExtractorCallbacks::wayFunction(ExtractionWay &parsed_way) {
- if((0 < parsed_way.speed) || (0 < parsed_way.duration)) { //Only true if the way is specified by the speed profile
- if(UINT_MAX == parsed_way.id){
- DEBUG("found bogus way with id: " << parsed_way.id << " of size " << parsed_way.path.size());
- return;
- }
+void ExtractorCallbacks::ProcessWay(ExtractionWay &parsed_way)
+{
+ if ((0 >= parsed_way.speed) && (0 >= parsed_way.duration))
+ { // Only true if the way is specified by the speed profile
+ return;
+ }
- if(0 < parsed_way.duration) {
- //TODO: iterate all way segments and set duration corresponding to the length of each segment
- parsed_way.speed = parsed_way.duration/(parsed_way.path.size()-1);
- }
+ if (parsed_way.path.size() <= 1)
+ { // safe-guard against broken data
+ return;
+ }
- if(FLT_EPSILON >= fabs(-1. - parsed_way.speed)){
- DEBUG("found way with bogus speed, id: " << parsed_way.id);
- return;
- }
+ if (std::numeric_limits<unsigned>::max() == parsed_way.id)
+ {
+ SimpleLogger().Write(logDEBUG) << "found bogus way with id: " << parsed_way.id
+ << " of size " << parsed_way.path.size();
+ return;
+ }
- //Get the unique identifier for the street name
- const StringMap::const_iterator string_map_iterator = stringMap->find(parsed_way.name);
- if(stringMap->end() == string_map_iterator) {
- parsed_way.nameID = externalMemory->nameVector.size();
- externalMemory->nameVector.push_back(parsed_way.name);
- stringMap->insert(std::make_pair(parsed_way.name, parsed_way.nameID));
- } else {
- parsed_way.nameID = string_map_iterator->second;
- }
+ if (0 < parsed_way.duration)
+ {
+ // TODO: iterate all way segments and set duration corresponding to the length of each
+ // segment
+ parsed_way.speed = parsed_way.duration / (parsed_way.path.size() - 1);
+ }
- if(ExtractionWay::opposite == parsed_way.direction) {
- std::reverse( parsed_way.path.begin(), parsed_way.path.end() );
- parsed_way.direction = ExtractionWay::oneway;
- }
+ if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.speed))
+ {
+ SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id;
+ return;
+ }
- const bool split_bidirectional_edge = (parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed);
-
- for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) {
- externalMemory->allEdges.push_back(
- InternalExtractorEdge(parsed_way.path[n],
- parsed_way.path[n+1],
- parsed_way.type,
- (split_bidirectional_edge ? ExtractionWay::oneway : parsed_way.direction),
- parsed_way.speed,
- parsed_way.nameID,
- parsed_way.roundabout,
- parsed_way.ignoreInGrid,
- (0 < parsed_way.duration),
- parsed_way.isAccessRestricted
- )
- );
- externalMemory->usedNodeIDs.push_back(parsed_way.path[n]);
- }
- externalMemory->usedNodeIDs.push_back(parsed_way.path.back());
-
- //The following information is needed to identify start and end segments of restrictions
- externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back()));
-
- if(split_bidirectional_edge) { //Only true if the way should be split
- std::reverse( parsed_way.path.begin(), parsed_way.path.end() );
- for(std::vector< NodeID >::size_type n = 0; n < parsed_way.path.size()-1; ++n) {
- externalMemory->allEdges.push_back(
- InternalExtractorEdge(parsed_way.path[n],
- parsed_way.path[n+1],
- parsed_way.type,
- ExtractionWay::oneway,
- parsed_way.backward_speed,
- parsed_way.nameID,
- parsed_way.roundabout,
- parsed_way.ignoreInGrid,
- (0 < parsed_way.duration),
- parsed_way.isAccessRestricted,
- (ExtractionWay::oneway == parsed_way.direction)
- )
- );
- }
- externalMemory->wayStartEndVector.push_back(_WayIDStartAndEndEdge(parsed_way.id, parsed_way.path[0], parsed_way.path[1], parsed_way.path[parsed_way.path.size()-2], parsed_way.path.back()));
+ // Get the unique identifier for the street name
+ const auto &string_map_iterator = string_map.find(parsed_way.name);
+ if (string_map.end() == string_map_iterator)
+ {
+ parsed_way.nameID = external_memory.name_list.size();
+ external_memory.name_list.push_back(parsed_way.name);
+ string_map.insert(std::make_pair(parsed_way.name, parsed_way.nameID));
+ }
+ else
+ {
+ parsed_way.nameID = string_map_iterator->second;
+ }
+
+ if (ExtractionWay::opposite == parsed_way.direction)
+ {
+ std::reverse(parsed_way.path.begin(), parsed_way.path.end());
+ parsed_way.direction = ExtractionWay::oneway;
+ }
+
+ const bool split_edge =
+ (parsed_way.backward_speed > 0) && (parsed_way.speed != parsed_way.backward_speed);
+
+ for (unsigned n = 0; n < (parsed_way.path.size() - 1); ++n)
+ {
+ external_memory.all_edges_list.push_back(InternalExtractorEdge(
+ parsed_way.path[n],
+ parsed_way.path[n + 1],
+ parsed_way.type,
+ (split_edge ? ExtractionWay::oneway : parsed_way.direction),
+ parsed_way.speed,
+ parsed_way.nameID,
+ parsed_way.roundabout,
+ parsed_way.ignoreInGrid,
+ (0 < parsed_way.duration),
+ parsed_way.isAccessRestricted,
+ false,
+ split_edge));
+ external_memory.used_node_id_list.push_back(parsed_way.path[n]);
+ }
+ external_memory.used_node_id_list.push_back(parsed_way.path.back());
+
+ // The following information is needed to identify start and end segments of restrictions
+ external_memory.way_start_end_id_list.push_back(
+ WayIDStartAndEndEdge(parsed_way.id,
+ parsed_way.path[0],
+ parsed_way.path[1],
+ parsed_way.path[parsed_way.path.size() - 2],
+ parsed_way.path.back()));
+
+ if (split_edge)
+ { // Only true if the way should be split
+ std::reverse(parsed_way.path.begin(), parsed_way.path.end());
+ for (std::vector<NodeID>::size_type n = 0; n < parsed_way.path.size() - 1; ++n)
+ {
+ external_memory.all_edges_list.push_back(
+ InternalExtractorEdge(parsed_way.path[n],
+ parsed_way.path[n + 1],
+ parsed_way.type,
+ ExtractionWay::oneway,
+ parsed_way.backward_speed,
+ parsed_way.nameID,
+ parsed_way.roundabout,
+ parsed_way.ignoreInGrid,
+ (0 < parsed_way.duration),
+ parsed_way.isAccessRestricted,
+ (ExtractionWay::oneway == parsed_way.direction),
+ split_edge));
}
+ external_memory.way_start_end_id_list.push_back(
+ WayIDStartAndEndEdge(parsed_way.id,
+ parsed_way.path[0],
+ parsed_way.path[1],
+ parsed_way.path[parsed_way.path.size() - 2],
+ parsed_way.path.back()));
}
}
diff --git a/Extractor/ExtractorCallbacks.h b/Extractor/ExtractorCallbacks.h
index 4293d13..fcdb272 100644
--- a/Extractor/ExtractorCallbacks.h
+++ b/Extractor/ExtractorCallbacks.h
@@ -1,57 +1,63 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef EXTRACTORCALLBACKS_H_
-#define EXTRACTORCALLBACKS_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <string>
-#include <vector>
-
-#include <cfloat>
+*/
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/regex.hpp>
-#include <boost/regex.hpp>
+#ifndef EXTRACTOR_CALLBACKS_H
+#define EXTRACTOR_CALLBACKS_H
-#include "ExtractionContainers.h"
-#include "ExtractorStructs.h"
+#include "../typedefs.h"
-class ExtractorCallbacks{
-private:
- StringMap * stringMap;
- ExtractionContainers * externalMemory;
+#include <unordered_map>
+#include <string>
- ExtractorCallbacks();
-public:
- explicit ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap);
+struct ExternalMemoryNode;
+class ExtractionContainers;
+struct ExtractionWay;
+struct InputRestrictionContainer;
- ~ExtractorCallbacks();
+class ExtractorCallbacks
+{
+ private:
+ std::unordered_map<std::string, NodeID> &string_map;
+ ExtractionContainers &external_memory;
- /** warning: caller needs to take care of synchronization! */
- void nodeFunction(const _Node &n);
+ public:
+ ExtractorCallbacks() = delete;
+ ExtractorCallbacks(const ExtractorCallbacks &) = delete;
+ explicit ExtractorCallbacks(ExtractionContainers &extraction_containers,
+ std::unordered_map<std::string, NodeID> &string_map);
- bool restrictionFunction(const _RawRestrictionContainer &r);
+ // warning: caller needs to take care of synchronization!
+ void ProcessNode(const ExternalMemoryNode &node);
- /** warning: caller needs to take care of synchronization! */
- void wayFunction(ExtractionWay &w);
+ // warning: caller needs to take care of synchronization!
+ bool ProcessRestriction(const InputRestrictionContainer &restriction);
+ // warning: caller needs to take care of synchronization!
+ void ProcessWay(ExtractionWay &way);
};
-#endif /* EXTRACTORCALLBACKS_H_ */
+#endif /* EXTRACTOR_CALLBACKS_H */
diff --git a/Extractor/ExtractorStructs.h b/Extractor/ExtractorStructs.h
index fe21da9..51a74c3 100644
--- a/Extractor/ExtractorStructs.h
+++ b/Extractor/ExtractorStructs.h
@@ -1,222 +1,114 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef EXTRACTORSTRUCTS_H_
-#define EXTRACTORSTRUCTS_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <climits>
-#include <string>
+*/
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/regex.hpp>
-#include <boost/regex.hpp>
-#include <boost/unordered_map.hpp>
+#ifndef EXTRACTORSTRUCTS_H_
+#define EXTRACTORSTRUCTS_H_
-#include "../DataStructures/Coordinate.h"
#include "../DataStructures/HashTable.h"
#include "../DataStructures/ImportNode.h"
-#include "../DataStructures/NodeCoords.h"
-#include "../DataStructures/Restriction.h"
-#include "../DataStructures/TimingUtil.h"
#include "../typedefs.h"
-typedef boost::unordered_map<std::string, NodeID > StringMap;
-typedef boost::unordered_map<std::string, std::pair<int, short> > StringToIntPairMap;
-
-struct ExtractionWay {
- ExtractionWay() {
- Clear();
- }
-
- inline void Clear(){
- id = UINT_MAX;
- nameID = UINT_MAX;
- path.clear();
- keyVals.EraseAll();
- direction = ExtractionWay::notSure;
- speed = -1;
- backward_speed = -1;
- duration = -1;
- type = -1;
- access = true;
- roundabout = false;
- isAccessRestricted = false;
- ignoreInGrid = false;
- }
-
- enum Directions {
- notSure = 0, oneway, bidirectional, opposite
- };
- Directions direction;
- unsigned id;
- unsigned nameID;
- std::string name;
- double speed;
- double backward_speed;
- double duration;
- short type;
- bool access;
- bool roundabout;
- bool isAccessRestricted;
- bool ignoreInGrid;
- std::vector< NodeID > path;
- HashTable<std::string, std::string> keyVals;
-};
+#include <limits>
+#include <string>
-struct ExtractorRelation {
- ExtractorRelation() : type(unknown){}
- enum {
- unknown = 0, ferry, turnRestriction
- } type;
+struct ExtractorRelation
+{
+ ExtractorRelation() : type(unknown) {}
+ enum
+ { unknown = 0,
+ ferry,
+ turnRestriction } type;
HashTable<std::string, std::string> keyVals;
};
-struct InternalExtractorEdge {
- InternalExtractorEdge() : start(0), target(0), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) {};
- InternalExtractorEdge(NodeID s, NodeID t) : start(s), target(t), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) { }
- InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp): start(s), target(t), type(tp), direction(d), speed(sp), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) { }
- InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar), isContraFlow(false) {
- assert(0 <= type);
- }
- InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar, bool icf): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar), isContraFlow(icf) {
- assert(0 <= type);
- }
- NodeID start;
- NodeID target;
- short type;
- short direction;
- double speed;
- unsigned nameID;
- bool isRoundabout;
- bool ignoreInGrid;
- bool isDurationSet;
- bool isAccessRestricted;
- bool isContraFlow;
-
- _Coordinate startCoord;
- _Coordinate targetCoord;
-
- static InternalExtractorEdge min_value() {
- return InternalExtractorEdge(0,0);
- }
- static InternalExtractorEdge max_value() {
- return InternalExtractorEdge((std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)());
- }
-};
-
-
-
-struct _WayIDStartAndEndEdge {
+struct WayIDStartAndEndEdge
+{
unsigned wayID;
NodeID firstStart;
NodeID firstTarget;
NodeID lastStart;
NodeID lastTarget;
- _WayIDStartAndEndEdge() : wayID(UINT_MAX), firstStart(UINT_MAX), firstTarget(UINT_MAX), lastStart(UINT_MAX), lastTarget(UINT_MAX) {}
- _WayIDStartAndEndEdge(unsigned w, NodeID fs, NodeID ft, NodeID ls, NodeID lt) : wayID(w), firstStart(fs), firstTarget(ft), lastStart(ls), lastTarget(lt) {}
-
- static _WayIDStartAndEndEdge min_value() {
- return _WayIDStartAndEndEdge((std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)(), (std::numeric_limits<unsigned>::min)());
+ WayIDStartAndEndEdge()
+ : wayID(std::numeric_limits<unsigned>::max()), firstStart(std::numeric_limits<unsigned>::max()), firstTarget(std::numeric_limits<unsigned>::max()), lastStart(std::numeric_limits<unsigned>::max()),
+ lastTarget(std::numeric_limits<unsigned>::max())
+ {
}
- static _WayIDStartAndEndEdge max_value() {
- return _WayIDStartAndEndEdge((std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)(), (std::numeric_limits<unsigned>::max)());
- }
-};
-struct CmpWayByID : public std::binary_function<_WayIDStartAndEndEdge, _WayIDStartAndEndEdge, bool> {
- typedef _WayIDStartAndEndEdge value_type;
- bool operator () (const _WayIDStartAndEndEdge & a, const _WayIDStartAndEndEdge & b) const {
- return a.wayID < b.wayID;
- }
- value_type max_value() {
- return _WayIDStartAndEndEdge::max_value();
- }
- value_type min_value() {
- return _WayIDStartAndEndEdge::min_value();
+ explicit WayIDStartAndEndEdge(unsigned w, NodeID fs, NodeID ft, NodeID ls, NodeID lt)
+ : wayID(w), firstStart(fs), firstTarget(ft), lastStart(ls), lastTarget(lt)
+ {
}
-};
-struct Cmp : public std::binary_function<NodeID, NodeID, bool> {
- typedef NodeID value_type;
- bool operator () (const NodeID & a, const NodeID & b) const {
- return a < b;
- }
- value_type max_value() {
- return 0xffffffff;
+ static WayIDStartAndEndEdge min_value()
+ {
+ return WayIDStartAndEndEdge((std::numeric_limits<unsigned>::min)(),
+ (std::numeric_limits<unsigned>::min)(),
+ (std::numeric_limits<unsigned>::min)(),
+ (std::numeric_limits<unsigned>::min)(),
+ (std::numeric_limits<unsigned>::min)());
}
- value_type min_value() {
- return 0x0;
+ static WayIDStartAndEndEdge max_value()
+ {
+ return WayIDStartAndEndEdge((std::numeric_limits<unsigned>::max)(),
+ (std::numeric_limits<unsigned>::max)(),
+ (std::numeric_limits<unsigned>::max)(),
+ (std::numeric_limits<unsigned>::max)(),
+ (std::numeric_limits<unsigned>::max)());
}
};
-struct CmpNodeByID : public std::binary_function<_Node, _Node, bool> {
- typedef _Node value_type;
- bool operator () (const _Node & a, const _Node & b) const {
- return a.id < b.id;
- }
- value_type max_value() {
- return _Node::max_value();
- }
- value_type min_value() {
- return _Node::min_value();
+struct CmpWayByID
+{
+ typedef WayIDStartAndEndEdge value_type;
+ bool operator()(const WayIDStartAndEndEdge &a, const WayIDStartAndEndEdge &b) const
+ {
+ return a.wayID < b.wayID;
}
+ value_type max_value() { return WayIDStartAndEndEdge::max_value(); }
+ value_type min_value() { return WayIDStartAndEndEdge::min_value(); }
};
-struct CmpEdgeByStartID : public std::binary_function<InternalExtractorEdge, InternalExtractorEdge, bool> {
- typedef InternalExtractorEdge value_type;
- bool operator () (const InternalExtractorEdge & a, const InternalExtractorEdge & b) const {
- return a.start < b.start;
- }
- value_type max_value() {
- return InternalExtractorEdge::max_value();
- }
- value_type min_value() {
- return InternalExtractorEdge::min_value();
- }
+struct Cmp
+{
+ typedef NodeID value_type;
+ bool operator()(const NodeID left, const NodeID right) const { return left < right; }
+ value_type max_value() { return 0xffffffff; }
+ value_type min_value() { return 0x0; }
};
-struct CmpEdgeByTargetID : public std::binary_function<InternalExtractorEdge, InternalExtractorEdge, bool> {
- typedef InternalExtractorEdge value_type;
- bool operator () (const InternalExtractorEdge & a, const InternalExtractorEdge & b) const {
- return a.target < b.target;
- }
- value_type max_value() {
- return InternalExtractorEdge::max_value();
- }
- value_type min_value() {
- return InternalExtractorEdge::min_value();
+struct CmpNodeByID
+{
+ typedef ExternalMemoryNode value_type;
+ bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const
+ {
+ return left.node_id < right.node_id;
}
+ value_type max_value() { return ExternalMemoryNode::max_value(); }
+ value_type min_value() { return ExternalMemoryNode::min_value(); }
};
-inline std::string GetRandomString() {
- char s[128];
- static const char alphanum[] =
- "0123456789"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz";
-
- for (int i = 0; i < 127; ++i) {
- s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
- }
- s[127] = 0;
- return std::string(s);
-}
-
#endif /* EXTRACTORSTRUCTS_H_ */
diff --git a/Extractor/InternalExtractorEdge.h b/Extractor/InternalExtractorEdge.h
new file mode 100644
index 0000000..02903e8
--- /dev/null
+++ b/Extractor/InternalExtractorEdge.h
@@ -0,0 +1,120 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef INTERNAL_EXTRACTOR_EDGE_H
+#define INTERNAL_EXTRACTOR_EDGE_H
+
+#include "../typedefs.h"
+#include <osrm/Coordinate.h>
+
+#include <boost/assert.hpp>
+
+struct InternalExtractorEdge
+{
+ InternalExtractorEdge()
+ : start(0), target(0), type(0), direction(0), speed(0), name_id(0), is_roundabout(false),
+ is_in_tiny_cc(false), is_duration_set(false), is_access_restricted(false),
+ is_contra_flow(false), is_split(false)
+ {
+ }
+
+ explicit InternalExtractorEdge(NodeID start,
+ NodeID target,
+ short type,
+ short direction,
+ double speed,
+ unsigned name_id,
+ bool is_roundabout,
+ bool is_in_tiny_cc,
+ bool is_duration_set,
+ bool is_access_restricted,
+ bool is_contra_flow,
+ bool is_split)
+ : start(start), target(target), type(type), direction(direction), speed(speed),
+ name_id(name_id), is_roundabout(is_roundabout), is_in_tiny_cc(is_in_tiny_cc),
+ is_duration_set(is_duration_set), is_access_restricted(is_access_restricted),
+ is_contra_flow(is_contra_flow), is_split(is_split)
+ {
+ BOOST_ASSERT(0 <= type);
+ }
+
+ // necessary static util functions for stxxl's sorting
+ static InternalExtractorEdge min_value()
+ {
+ return InternalExtractorEdge(0, 0, 0, 0, 0, 0, false, false, false, false, false, false);
+ }
+ static InternalExtractorEdge max_value()
+ {
+ return InternalExtractorEdge(
+ SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, 0, false, false, false, false, false, false);
+ }
+
+ NodeID start;
+ NodeID target;
+ short type;
+ short direction;
+ double speed;
+ unsigned name_id;
+ bool is_roundabout;
+ bool is_in_tiny_cc;
+ bool is_duration_set;
+ bool is_access_restricted;
+ bool is_contra_flow;
+ bool is_split;
+
+ FixedPointCoordinate source_coordinate;
+ FixedPointCoordinate target_coordinate;
+};
+
+struct CmpEdgeByStartID
+{
+ typedef InternalExtractorEdge value_type;
+ bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
+ {
+ return a.start < b.start;
+ }
+
+ value_type max_value() { return InternalExtractorEdge::max_value(); }
+
+ value_type min_value() { return InternalExtractorEdge::min_value(); }
+};
+
+struct CmpEdgeByTargetID
+{
+ typedef InternalExtractorEdge value_type;
+
+ bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
+ {
+ return a.target < b.target;
+ }
+
+ value_type max_value() { return InternalExtractorEdge::max_value(); }
+
+ value_type min_value() { return InternalExtractorEdge::min_value(); }
+};
+
+#endif // INTERNAL_EXTRACTOR_EDGE_H
diff --git a/Extractor/PBFParser.cpp b/Extractor/PBFParser.cpp
index 51b099f..1abc480 100644
--- a/Extractor/PBFParser.cpp
+++ b/Extractor/PBFParser.cpp
@@ -1,482 +1,664 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#include "PBFParser.h"
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-PBFParser::PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se) : BaseParser( ec, se ) {
- GOOGLE_PROTOBUF_VERIFY_VERSION;
- //TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk?
- //NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free.
- threadDataQueue = boost::make_shared<ConcurrentQueue<_ThreadData*> >( 2500 ); /* Max 2500 items in queue, hardcoded. */
- input.open(fileName, std::ios::in | std::ios::binary);
+*/
- if (!input) {
- std::cerr << fileName << ": File not found." << std::endl;
- }
+#include "PBFParser.h"
-#ifndef NDEBUG
- blockCount = 0;
- groupCount = 0;
-#endif
+#include "ExtractionWay.h"
+#include "ExtractorCallbacks.h"
+#include "ScriptingEnvironment.h"
+
+#include "../DataStructures/HashTable.h"
+#include "../DataStructures/ImportNode.h"
+#include "../DataStructures/Restriction.h"
+#include "../Util/MachineInfo.h"
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+#include "../typedefs.h"
+
+#include <boost/assert.hpp>
+
+#include <tbb/parallel_for.h>
+#include <tbb/task_scheduler_init.h>
+
+#include <osrm/Coordinate.h>
+
+#include <zlib.h>
+
+#include <functional>
+#include <limits>
+#include <thread>
+
+PBFParser::PBFParser(const char *fileName,
+ ExtractorCallbacks *extractor_callbacks,
+ ScriptingEnvironment &scripting_environment,
+ unsigned num_threads)
+ : BaseParser(extractor_callbacks, scripting_environment)
+{
+ if (0 == num_threads)
+ {
+ num_parser_threads = tbb::task_scheduler_init::default_num_threads();
+ }
+ else
+ {
+ num_parser_threads = num_threads;
+ }
+
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+ // TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk?
+ // NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free.
+
+ // Max 2500 items in queue, hardcoded.
+ thread_data_queue = std::make_shared<ConcurrentQueue<ParserThreadData *>>(2500);
+ input.open(fileName, std::ios::in | std::ios::binary);
+
+ if (!input)
+ {
+ throw OSRMException("pbf file not found.");
+ }
+
+ block_count = 0;
+ group_count = 0;
}
-PBFParser::~PBFParser() {
- if(input.is_open()) {
- input.close();
- }
-
- // Clean up any leftover ThreadData objects in the queue
- _ThreadData* td;
- while (threadDataQueue->try_pop(td)) {
- delete td;
- }
- google::protobuf::ShutdownProtobufLibrary();
-
-#ifndef NDEBUG
- DEBUG("parsed " << blockCount << " blocks from pbf with " << groupCount << " groups");
-#endif
+PBFParser::~PBFParser()
+{
+ if (input.is_open())
+ {
+ input.close();
+ }
+
+ // Clean up any leftover ThreadData objects in the queue
+ ParserThreadData *thread_data;
+ while (thread_data_queue->try_pop(thread_data))
+ {
+ delete thread_data;
+ }
+ google::protobuf::ShutdownProtobufLibrary();
+
+ SimpleLogger().Write(logDEBUG) << "parsed " << block_count << " blocks from pbf with "
+ << group_count << " groups";
}
-inline bool PBFParser::ReadHeader() {
- _ThreadData initData;
- /** read Header */
- if(!readPBFBlobHeader(input, &initData)) {
- return false;
- }
-
- if(readBlob(input, &initData)) {
- if(!initData.PBFHeaderBlock.ParseFromArray(&(initData.charBuffer[0]), initData.charBuffer.size() ) ) {
- std::cerr << "[error] Header not parseable!" << std::endl;
- return false;
- }
-
- for(int i = 0, featureSize = initData.PBFHeaderBlock.required_features_size(); i < featureSize; ++i) {
- const std::string& feature = initData.PBFHeaderBlock.required_features( i );
- bool supported = false;
- if ( "OsmSchema-V0.6" == feature ) {
- supported = true;
- }
- else if ( "DenseNodes" == feature ) {
- supported = true;
- }
-
- if ( !supported ) {
- std::cerr << "[error] required feature not supported: " << feature.data() << std::endl;
- return false;
- }
- }
- } else {
- std::cerr << "[error] blob not loaded!" << std::endl;
- }
- return true;
+inline bool PBFParser::ReadHeader()
+{
+ ParserThreadData init_data;
+ /** read Header */
+ if (!readPBFBlobHeader(input, &init_data))
+ {
+ return false;
+ }
+
+ if (readBlob(input, &init_data))
+ {
+ if (!init_data.PBFHeaderBlock.ParseFromArray(&(init_data.charBuffer[0]),
+ static_cast<int>(init_data.charBuffer.size())))
+ {
+ std::cerr << "[error] Header not parseable!" << std::endl;
+ return false;
+ }
+
+ const auto feature_size = init_data.PBFHeaderBlock.required_features_size();
+ for (int i = 0; i < feature_size; ++i)
+ {
+ const std::string &feature = init_data.PBFHeaderBlock.required_features(i);
+ bool supported = false;
+ if ("OsmSchema-V0.6" == feature)
+ {
+ supported = true;
+ }
+ else if ("DenseNodes" == feature)
+ {
+ supported = true;
+ }
+
+ if (!supported)
+ {
+ std::cerr << "[error] required feature not supported: " << feature.data()
+ << std::endl;
+ return false;
+ }
+ }
+ }
+ else
+ {
+ std::cerr << "[error] blob not loaded!" << std::endl;
+ }
+ return true;
}
-inline void PBFParser::ReadData() {
- bool keepRunning = true;
- do {
- _ThreadData *threadData = new _ThreadData();
- keepRunning = readNextBlock(input, threadData);
-
- if (keepRunning) {
- threadDataQueue->push(threadData);
- } else {
- threadDataQueue->push(NULL); // No more data to read, parse stops when NULL encountered
- delete threadData;
- }
- } while(keepRunning);
+inline void PBFParser::ReadData()
+{
+ bool keep_running = true;
+ do
+ {
+ ParserThreadData *thread_data = new ParserThreadData();
+ keep_running = readNextBlock(input, thread_data);
+
+ if (keep_running)
+ {
+ thread_data_queue->push(thread_data);
+ }
+ else
+ {
+ // No more data to read, parse stops when nullptr encountered
+ thread_data_queue->push(nullptr);
+ delete thread_data;
+ }
+ } while (keep_running);
}
-inline void PBFParser::ParseData() {
- while (true) {
- _ThreadData *threadData;
- threadDataQueue->wait_and_pop(threadData);
- if( NULL==threadData ) {
- INFO("Parse Data Thread Finished");
- threadDataQueue->push(NULL); // Signal end of data for other threads
- break;
- }
-
- loadBlock(threadData);
-
- for(int i = 0, groupSize = threadData->PBFprimitiveBlock.primitivegroup_size(); i < groupSize; ++i) {
- threadData->currentGroupID = i;
- loadGroup(threadData);
-
- if(threadData->entityTypeIndicator == TypeNode) {
- parseNode(threadData);
- }
- if(threadData->entityTypeIndicator == TypeWay) {
- parseWay(threadData);
- }
- if(threadData->entityTypeIndicator == TypeRelation) {
- parseRelation(threadData);
- }
- if(threadData->entityTypeIndicator == TypeDenseNode) {
- parseDenseNode(threadData);
- }
- }
-
- delete threadData;
- threadData = NULL;
- }
+inline void PBFParser::ParseData()
+{
+ tbb::task_scheduler_init init(num_parser_threads);
+
+ while (true)
+ {
+ ParserThreadData *thread_data;
+ thread_data_queue->wait_and_pop(thread_data);
+ if (nullptr == thread_data)
+ {
+ thread_data_queue->push(nullptr); // Signal end of data for other threads
+ break;
+ }
+
+ loadBlock(thread_data);
+
+ int group_size = thread_data->PBFprimitiveBlock.primitivegroup_size();
+ for (int i = 0; i < group_size; ++i)
+ {
+ thread_data->currentGroupID = i;
+ loadGroup(thread_data);
+
+ if (thread_data->entityTypeIndicator == TypeNode)
+ {
+ parseNode(thread_data);
+ }
+ if (thread_data->entityTypeIndicator == TypeWay)
+ {
+ parseWay(thread_data);
+ }
+ if (thread_data->entityTypeIndicator == TypeRelation)
+ {
+ parseRelation(thread_data);
+ }
+ if (thread_data->entityTypeIndicator == TypeDenseNode)
+ {
+ parseDenseNode(thread_data);
+ }
+ }
+
+ delete thread_data;
+ thread_data = nullptr;
+ }
}
-inline bool PBFParser::Parse() {
- // Start the read and parse threads
- boost::thread readThread(boost::bind(&PBFParser::ReadData, this));
+inline bool PBFParser::Parse()
+{
+ // Start the read and parse threads
+ std::thread read_thread(std::bind(&PBFParser::ReadData, this));
- //Open several parse threads that are synchronized before call to
- boost::thread parseThread(boost::bind(&PBFParser::ParseData, this));
+ // Open several parse threads that are synchronized before call to
+ std::thread parse_thread(std::bind(&PBFParser::ParseData, this));
- // Wait for the threads to finish
- readThread.join();
- parseThread.join();
+ // Wait for the threads to finish
+ read_thread.join();
+ parse_thread.join();
- return true;
+ return true;
}
-inline void PBFParser::parseDenseNode(_ThreadData * threadData) {
- const OSMPBF::DenseNodes& dense = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).dense();
- int denseTagIndex = 0;
- int64_t m_lastDenseID = 0;
- int64_t m_lastDenseLatitude = 0;
- int64_t m_lastDenseLongitude = 0;
-
- const int number_of_nodes = dense.id_size();
- std::vector<ImportNode> extracted_nodes_vector(number_of_nodes);
- for(int i = 0; i < number_of_nodes; ++i) {
- m_lastDenseID += dense.id( i );
- m_lastDenseLatitude += dense.lat( i );
- m_lastDenseLongitude += dense.lon( i );
- 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 ) {
- ++denseTagIndex;
- break;
- }
- const int keyValue = dense.keys_vals ( denseTagIndex+1 );
- const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(tagValue).data();
- const std::string & value = threadData->PBFprimitiveBlock.stringtable().s(keyValue).data();
- extracted_nodes_vector[i].keyVals.Add(key, value);
- denseTagIndex += 2;
- }
- }
-
-#pragma omp parallel for schedule ( guided )
- for(int i = 0; i < number_of_nodes; ++i) {
- ImportNode &n = extracted_nodes_vector[i];
- ParseNodeInLua( n, scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()) );
- }
-
- BOOST_FOREACH(ImportNode &n, extracted_nodes_vector) {
- extractor_callbacks->nodeFunction(n);
- }
+inline void PBFParser::parseDenseNode(ParserThreadData *thread_data)
+{
+ const OSMPBF::DenseNodes &dense =
+ thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).dense();
+ int denseTagIndex = 0;
+ int64_t m_lastDenseID = 0;
+ int64_t m_lastDenseLatitude = 0;
+ int64_t m_lastDenseLongitude = 0;
+
+ const int number_of_nodes = dense.id_size();
+ std::vector<ImportNode> extracted_nodes_vector(number_of_nodes);
+ for (int i = 0; i < number_of_nodes; ++i)
+ {
+ m_lastDenseID += dense.id(i);
+ m_lastDenseLatitude += dense.lat(i);
+ m_lastDenseLongitude += dense.lon(i);
+ extracted_nodes_vector[i].node_id = static_cast<NodeID>(m_lastDenseID);
+ extracted_nodes_vector[i].lat = static_cast<int>(
+ COORDINATE_PRECISION *
+ ((double)m_lastDenseLatitude * thread_data->PBFprimitiveBlock.granularity() +
+ thread_data->PBFprimitiveBlock.lat_offset()) /
+ NANO);
+ extracted_nodes_vector[i].lon = static_cast<int>(
+ COORDINATE_PRECISION *
+ ((double)m_lastDenseLongitude * thread_data->PBFprimitiveBlock.granularity() +
+ thread_data->PBFprimitiveBlock.lon_offset()) /
+ NANO);
+ while (denseTagIndex < dense.keys_vals_size())
+ {
+ const int tagValue = dense.keys_vals(denseTagIndex);
+ if (0 == tagValue)
+ {
+ ++denseTagIndex;
+ break;
+ }
+ const int keyValue = dense.keys_vals(denseTagIndex + 1);
+ const std::string &key = thread_data->PBFprimitiveBlock.stringtable().s(tagValue);
+ const std::string &value = thread_data->PBFprimitiveBlock.stringtable().s(keyValue);
+ extracted_nodes_vector[i].keyVals.Add(std::move(key), std::move(value));
+ denseTagIndex += 2;
+ }
+ }
+
+ tbb::parallel_for(tbb::blocked_range<size_t>(0, extracted_nodes_vector.size()),
+ [this, &extracted_nodes_vector](const tbb::blocked_range<size_t> &range)
+ {
+ lua_State *lua_state = this->scripting_environment.getLuaState();
+ for (size_t i = range.begin(); i != range.end(); ++i)
+ {
+ ImportNode &import_node = extracted_nodes_vector[i];
+ ParseNodeInLua(import_node, lua_state);
+ }
+ });
+
+ for (const ImportNode &import_node : extracted_nodes_vector)
+ {
+ extractor_callbacks->ProcessNode(import_node);
+ }
}
-inline void PBFParser::parseNode(_ThreadData * ) {
- ERR("Parsing of simple nodes not supported. PBF should use dense nodes");
+inline void PBFParser::parseNode(ParserThreadData *)
+{
+ throw OSRMException("Parsing of simple nodes not supported. PBF should use dense nodes");
}
-inline void PBFParser::parseRelation(_ThreadData * threadData) {
- //TODO: leave early, if relation is not a restriction
- //TODO: reuse rawRestriction container
- if( !use_turn_restrictions ) {
- return;
- }
- const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
- for(int i = 0; i < group.relations_size(); ++i ) {
- std::string except_tag_string;
- const OSMPBF::Relation& inputRelation = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).relations(i);
- bool isRestriction = false;
- bool isOnlyRestriction = false;
- for(int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k) {
- const std::string & key = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k));
- const std::string & val = threadData->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k));
- if ("type" == key) {
- if( "restriction" == val) {
- isRestriction = true;
- } else {
- break;
- }
- }
- if ("restriction" == key) {
- if(val.find("only_") == 0) {
- isOnlyRestriction = true;
- }
- }
- if ("except" == key) {
- except_tag_string = val;
- }
- }
-
- if( isRestriction && ShouldIgnoreRestriction(except_tag_string) ) {
- continue;
- }
-
- if(isRestriction) {
- int64_t lastRef = 0;
- _RawRestrictionContainer currentRestrictionContainer(isOnlyRestriction);
- for(int rolesIndex = 0; rolesIndex < inputRelation.roles_sid_size(); ++rolesIndex) {
- std::string role(threadData->PBFprimitiveBlock.stringtable().s( inputRelation.roles_sid( rolesIndex ) ).data());
- lastRef += inputRelation.memids(rolesIndex);
-
- if(!("from" == role || "to" == role || "via" == role)) {
- continue;
- }
-
- switch(inputRelation.types(rolesIndex)) {
- case 0: //node
- if("from" == role || "to" == role) { //Only via should be a node
- continue;
- }
- assert("via" == role);
- if(UINT_MAX != currentRestrictionContainer.viaNode) {
- currentRestrictionContainer.viaNode = UINT_MAX;
- }
- assert(UINT_MAX == currentRestrictionContainer.viaNode);
- currentRestrictionContainer.restriction.viaNode = lastRef;
- break;
- case 1: //way
- assert("from" == role || "to" == role || "via" == role);
- if("from" == role) {
- currentRestrictionContainer.fromWay = lastRef;
- }
- if ("to" == role) {
- currentRestrictionContainer.toWay = lastRef;
- }
- if ("via" == role) {
- assert(currentRestrictionContainer.restriction.toNode == UINT_MAX);
- currentRestrictionContainer.viaNode = lastRef;
- }
- break;
- case 2: //relation, not used. relations relating to relations are evil.
- continue;
- assert(false);
- break;
-
- default: //should not happen
- //cout << "unknown";
- assert(false);
- break;
- }
- }
- if(!extractor_callbacks->restrictionFunction(currentRestrictionContainer)) {
- std::cerr << "[PBFParser] relation not parsed" << std::endl;
- }
- }
- }
+inline void PBFParser::parseRelation(ParserThreadData *thread_data)
+{
+ // TODO: leave early, if relation is not a restriction
+ // TODO: reuse rawRestriction container
+ if (!use_turn_restrictions)
+ {
+ return;
+ }
+ const OSMPBF::PrimitiveGroup &group =
+ thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID);
+
+ for (int i = 0, relation_size = group.relations_size(); i < relation_size; ++i)
+ {
+ std::string except_tag_string;
+ const OSMPBF::Relation &inputRelation =
+ thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).relations(i);
+ bool is_restriction = false;
+ bool is_only_restriction = false;
+ for (int k = 0, endOfKeys = inputRelation.keys_size(); k < endOfKeys; ++k)
+ {
+ const std::string &key =
+ thread_data->PBFprimitiveBlock.stringtable().s(inputRelation.keys(k));
+ const std::string &val =
+ thread_data->PBFprimitiveBlock.stringtable().s(inputRelation.vals(k));
+ if ("type" == key)
+ {
+ if ("restriction" == val)
+ {
+ is_restriction = true;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (("restriction" == key) && (val.find("only_") == 0))
+ {
+ is_only_restriction = true;
+ }
+ if ("except" == key)
+ {
+ except_tag_string = val;
+ }
+ }
+
+ if (is_restriction && ShouldIgnoreRestriction(except_tag_string))
+ {
+ continue;
+ }
+
+ if (is_restriction)
+ {
+ int64_t last_ref = 0;
+ InputRestrictionContainer current_restriction_container(is_only_restriction);
+ for (int rolesIndex = 0, last_role = inputRelation.roles_sid_size();
+ rolesIndex < last_role;
+ ++rolesIndex)
+ {
+ const std::string &role = thread_data->PBFprimitiveBlock.stringtable().s(
+ inputRelation.roles_sid(rolesIndex));
+ last_ref += inputRelation.memids(rolesIndex);
+
+ if (!("from" == role || "to" == role || "via" == role))
+ {
+ continue;
+ }
+
+ switch (inputRelation.types(rolesIndex))
+ {
+ case 0: // node
+ if ("from" == role || "to" == role)
+ { // Only via should be a node
+ continue;
+ }
+ BOOST_ASSERT("via" == role);
+ if (std::numeric_limits<unsigned>::max() !=
+ current_restriction_container.viaNode)
+ {
+ current_restriction_container.viaNode =
+ std::numeric_limits<unsigned>::max();
+ }
+ BOOST_ASSERT(std::numeric_limits<unsigned>::max() ==
+ current_restriction_container.viaNode);
+ current_restriction_container.restriction.viaNode =
+ static_cast<NodeID>(last_ref);
+ break;
+ case 1: // way
+ BOOST_ASSERT("from" == role || "to" == role || "via" == role);
+ if ("from" == role)
+ {
+ current_restriction_container.fromWay = static_cast<EdgeID>(last_ref);
+ }
+ if ("to" == role)
+ {
+ current_restriction_container.toWay = static_cast<EdgeID>(last_ref);
+ }
+ if ("via" == role)
+ {
+ BOOST_ASSERT(current_restriction_container.restriction.toNode ==
+ std::numeric_limits<unsigned>::max());
+ current_restriction_container.viaNode = static_cast<NodeID>(last_ref);
+ }
+ break;
+ case 2: // relation, not used. relations relating to relations are evil.
+ continue;
+ BOOST_ASSERT(false);
+ break;
+
+ default: // should not happen
+ BOOST_ASSERT(false);
+ break;
+ }
+ }
+ if (!extractor_callbacks->ProcessRestriction(current_restriction_container))
+ {
+ std::cerr << "[PBFParser] relation not parsed" << std::endl;
+ }
+ }
+ }
}
-inline void PBFParser::parseWay(_ThreadData * threadData) {
- const int number_of_ways = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways_size();
- std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
- for(int i = 0; i < number_of_ways; ++i) {
- const OSMPBF::Way& inputWay = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID ).ways( i );
- parsed_way_vector[i].id = inputWay.id();
- unsigned pathNode(0);
- const int number_of_referenced_nodes = inputWay.refs_size();
- 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 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);
- }
- }
-
-#pragma omp parallel for schedule ( guided )
- for(int i = 0; i < number_of_ways; ++i) {
- ExtractionWay & w = parsed_way_vector[i];
- ParseWayInLua( w, scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()) );
- }
-
- BOOST_FOREACH(ExtractionWay & w, parsed_way_vector) {
- extractor_callbacks->wayFunction(w);
- }
+inline void PBFParser::parseWay(ParserThreadData *thread_data)
+{
+ const int number_of_ways =
+ thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways_size();
+ std::vector<ExtractionWay> parsed_way_vector(number_of_ways);
+ for (int i = 0; i < number_of_ways; ++i)
+ {
+ const OSMPBF::Way &input_way =
+ thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID).ways(i);
+ parsed_way_vector[i].id = static_cast<EdgeID>(input_way.id());
+ unsigned node_id_in_path = 0;
+ const auto number_of_referenced_nodes = input_way.refs_size();
+ for (auto j = 0; j < number_of_referenced_nodes; ++j)
+ {
+ node_id_in_path += static_cast<NodeID>(input_way.refs(j));
+ parsed_way_vector[i].path.push_back(node_id_in_path);
+ }
+ BOOST_ASSERT(input_way.keys_size() == input_way.vals_size());
+ const auto number_of_keys = input_way.keys_size();
+ for (auto j = 0; j < number_of_keys; ++j)
+ {
+ const std::string &key =
+ thread_data->PBFprimitiveBlock.stringtable().s(input_way.keys(j));
+ const std::string &val =
+ thread_data->PBFprimitiveBlock.stringtable().s(input_way.vals(j));
+ parsed_way_vector[i].keyVals.Add(std::move(key), std::move(val));
+ }
+ }
+
+ // TODO: investigate if schedule guided will be handled by tbb automatically
+ tbb::parallel_for(tbb::blocked_range<size_t>(0, parsed_way_vector.size()),
+ [this, &parsed_way_vector](const tbb::blocked_range<size_t> &range)
+ {
+ lua_State *lua_state = this->scripting_environment.getLuaState();
+ for (size_t i = range.begin(); i != range.end(); i++)
+ {
+ ExtractionWay &extraction_way = parsed_way_vector[i];
+ if (2 <= extraction_way.path.size())
+ {
+ ParseWayInLua(extraction_way, lua_state);
+ }
+ }
+ });
+
+ for (ExtractionWay &extraction_way : parsed_way_vector)
+ {
+ if (2 <= extraction_way.path.size())
+ {
+ extractor_callbacks->ProcessWay(extraction_way);
+ }
+ }
}
-inline void PBFParser::loadGroup(_ThreadData * threadData) {
+inline void PBFParser::loadGroup(ParserThreadData *thread_data)
+{
#ifndef NDEBUG
- ++groupCount;
+ ++group_count;
#endif
- const OSMPBF::PrimitiveGroup& group = threadData->PBFprimitiveBlock.primitivegroup( threadData->currentGroupID );
- threadData->entityTypeIndicator = 0;
- if ( group.nodes_size() != 0 ) {
- threadData->entityTypeIndicator = TypeNode;
- }
- if ( group.ways_size() != 0 ) {
- threadData->entityTypeIndicator = TypeWay;
- }
- if ( group.relations_size() != 0 ) {
- threadData->entityTypeIndicator = TypeRelation;
- }
- if ( group.has_dense() ) {
- threadData->entityTypeIndicator = TypeDenseNode;
- assert( group.dense().id_size() != 0 );
- }
- assert( threadData->entityTypeIndicator != 0 );
+ const OSMPBF::PrimitiveGroup &group =
+ thread_data->PBFprimitiveBlock.primitivegroup(thread_data->currentGroupID);
+ thread_data->entityTypeIndicator = TypeDummy;
+ if (0 != group.nodes_size())
+ {
+ thread_data->entityTypeIndicator = TypeNode;
+ }
+ if (0 != group.ways_size())
+ {
+ thread_data->entityTypeIndicator = TypeWay;
+ }
+ if (0 != group.relations_size())
+ {
+ thread_data->entityTypeIndicator = TypeRelation;
+ }
+ if (group.has_dense())
+ {
+ thread_data->entityTypeIndicator = TypeDenseNode;
+ BOOST_ASSERT(0 != group.dense().id_size());
+ }
+ BOOST_ASSERT(thread_data->entityTypeIndicator != TypeDummy);
}
-inline void PBFParser::loadBlock(_ThreadData * threadData) {
-#ifndef NDEBUG
- ++blockCount;
-#endif
- threadData->currentGroupID = 0;
- threadData->currentEntityID = 0;
-}
-
-inline bool PBFParser::readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData) {
- int size(0);
- stream.read((char *)&size, sizeof(int));
- size = swapEndian(size);
- if(stream.eof()) {
- return false;
- }
- if ( size > MAX_BLOB_HEADER_SIZE || size < 0 ) {
- return false;
- }
- char *data = new char[size];
- stream.read(data, size*sizeof(data[0]));
-
- bool dataSuccessfullyParsed = (threadData->PBFBlobHeader).ParseFromArray( data, size);
- delete[] data;
- return dataSuccessfullyParsed;
+inline void PBFParser::loadBlock(ParserThreadData *thread_data)
+{
+ ++block_count;
+ thread_data->currentGroupID = 0;
+ thread_data->currentEntityID = 0;
}
-inline bool PBFParser::unpackZLIB(std::fstream &, _ThreadData * threadData) {
- unsigned rawSize = threadData->PBFBlob.raw_size();
- char* unpackedDataArray = new char[rawSize];
- z_stream compressedDataStream;
- compressedDataStream.next_in = ( unsigned char* ) threadData->PBFBlob.zlib_data().data();
- compressedDataStream.avail_in = threadData->PBFBlob.zlib_data().size();
- compressedDataStream.next_out = ( unsigned char* ) unpackedDataArray;
- compressedDataStream.avail_out = rawSize;
- compressedDataStream.zalloc = Z_NULL;
- compressedDataStream.zfree = Z_NULL;
- compressedDataStream.opaque = Z_NULL;
- int ret = inflateInit( &compressedDataStream );
- if ( ret != Z_OK ) {
- std::cerr << "[error] failed to init zlib stream" << std::endl;
- delete[] unpackedDataArray;
- return false;
- }
-
- ret = inflate( &compressedDataStream, Z_FINISH );
- if ( ret != Z_STREAM_END ) {
- std::cerr << "[error] failed to inflate zlib stream" << std::endl;
- std::cerr << "[error] Error type: " << ret << std::endl;
- delete[] unpackedDataArray;
- return false;
- }
-
- ret = inflateEnd( &compressedDataStream );
- if ( ret != Z_OK ) {
- std::cerr << "[error] failed to deinit zlib stream" << std::endl;
- delete[] unpackedDataArray;
- return false;
- }
-
- threadData->charBuffer.clear(); threadData->charBuffer.resize(rawSize);
- std::copy(unpackedDataArray, unpackedDataArray + rawSize, threadData->charBuffer.begin());
- delete[] unpackedDataArray;
- return true;
+inline bool PBFParser::readPBFBlobHeader(std::fstream &stream, ParserThreadData *thread_data)
+{
+ int size(0);
+ stream.read((char *)&size, sizeof(int));
+ size = SwapEndian(size);
+ if (stream.eof())
+ {
+ return false;
+ }
+ if (size > MAX_BLOB_HEADER_SIZE || size < 0)
+ {
+ return false;
+ }
+ char *data = new char[size];
+ stream.read(data, size * sizeof(data[0]));
+
+ bool dataSuccessfullyParsed = (thread_data->PBFBlobHeader).ParseFromArray(data, size);
+ delete[] data;
+ return dataSuccessfullyParsed;
}
-inline bool PBFParser::unpackLZMA(std::fstream &, _ThreadData * ) {
- return false;
+inline bool PBFParser::unpackZLIB(ParserThreadData *thread_data)
+{
+ auto raw_size = thread_data->PBFBlob.raw_size();
+ char *unpacked_data_array = new char[raw_size];
+ z_stream compressed_data_stream;
+ compressed_data_stream.next_in = (unsigned char *)thread_data->PBFBlob.zlib_data().data();
+ compressed_data_stream.avail_in = thread_data->PBFBlob.zlib_data().size();
+ compressed_data_stream.next_out = (unsigned char *)unpacked_data_array;
+ compressed_data_stream.avail_out = raw_size;
+ compressed_data_stream.zalloc = Z_NULL;
+ compressed_data_stream.zfree = Z_NULL;
+ compressed_data_stream.opaque = Z_NULL;
+ int return_code = inflateInit(&compressed_data_stream);
+ if (return_code != Z_OK)
+ {
+ std::cerr << "[error] failed to init zlib stream" << std::endl;
+ delete[] unpacked_data_array;
+ return false;
+ }
+
+ return_code = inflate(&compressed_data_stream, Z_FINISH);
+ if (return_code != Z_STREAM_END)
+ {
+ std::cerr << "[error] failed to inflate zlib stream" << std::endl;
+ std::cerr << "[error] Error type: " << return_code << std::endl;
+ delete[] unpacked_data_array;
+ return false;
+ }
+
+ return_code = inflateEnd(&compressed_data_stream);
+ if (return_code != Z_OK)
+ {
+ std::cerr << "[error] failed to deinit zlib stream" << std::endl;
+ delete[] unpacked_data_array;
+ return false;
+ }
+
+ thread_data->charBuffer.clear();
+ thread_data->charBuffer.resize(raw_size);
+ std::copy(unpacked_data_array, unpacked_data_array + raw_size, thread_data->charBuffer.begin());
+ delete[] unpacked_data_array;
+ return true;
}
-inline bool PBFParser::readBlob(std::fstream& stream, _ThreadData * threadData) {
- if(stream.eof()) {
- return false;
- }
-
- const int size = threadData->PBFBlobHeader.datasize();
- if ( size < 0 || size > MAX_BLOB_SIZE ) {
- std::cerr << "[error] invalid Blob size:" << size << std::endl;
- return false;
- }
-
- char* data = new char[size];
- stream.read(data, sizeof(data[0])*size);
-
- if ( !threadData->PBFBlob.ParseFromArray( data, size ) ) {
- std::cerr << "[error] failed to parse blob" << std::endl;
- delete[] data;
- return false;
- }
-
- if ( threadData->PBFBlob.has_raw() ) {
- const std::string& data = threadData->PBFBlob.raw();
- threadData->charBuffer.clear();
- threadData->charBuffer.resize( data.size() );
- std::copy(data.begin(), data.end(), threadData->charBuffer.begin());
- } else if ( threadData->PBFBlob.has_zlib_data() ) {
- if ( !unpackZLIB(stream, threadData) ) {
- std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
- delete[] data;
- return false;
- }
- } else if ( threadData->PBFBlob.has_lzma_data() ) {
- if ( !unpackLZMA(stream, threadData) ) {
- std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl;
- }
- delete[] data;
- return false;
- } else {
- std::cerr << "[error] Blob contains no data" << std::endl;
- delete[] data;
- return false;
- }
- delete[] data;
- return true;
+inline bool PBFParser::unpackLZMA(ParserThreadData *) { return false; }
+
+inline bool PBFParser::readBlob(std::fstream &stream, ParserThreadData *thread_data)
+{
+ if (stream.eof())
+ {
+ return false;
+ }
+
+ const int size = thread_data->PBFBlobHeader.datasize();
+ if (size < 0 || size > MAX_BLOB_SIZE)
+ {
+ std::cerr << "[error] invalid Blob size:" << size << std::endl;
+ return false;
+ }
+
+ char *data = new char[size];
+ stream.read(data, sizeof(data[0]) * size);
+
+ if (!thread_data->PBFBlob.ParseFromArray(data, size))
+ {
+ std::cerr << "[error] failed to parse blob" << std::endl;
+ delete[] data;
+ return false;
+ }
+
+ if (thread_data->PBFBlob.has_raw())
+ {
+ const std::string &data = thread_data->PBFBlob.raw();
+ thread_data->charBuffer.clear();
+ thread_data->charBuffer.resize(data.size());
+ std::copy(data.begin(), data.end(), thread_data->charBuffer.begin());
+ }
+ else if (thread_data->PBFBlob.has_zlib_data())
+ {
+ if (!unpackZLIB(thread_data))
+ {
+ std::cerr << "[error] zlib data encountered that could not be unpacked" << std::endl;
+ delete[] data;
+ return false;
+ }
+ }
+ else if (thread_data->PBFBlob.has_lzma_data())
+ {
+ if (!unpackLZMA(thread_data))
+ {
+ std::cerr << "[error] lzma data encountered that could not be unpacked" << std::endl;
+ }
+ delete[] data;
+ return false;
+ }
+ else
+ {
+ std::cerr << "[error] Blob contains no data" << std::endl;
+ delete[] data;
+ return false;
+ }
+ delete[] data;
+ return true;
}
-bool PBFParser::readNextBlock(std::fstream& stream, _ThreadData * threadData) {
- if(stream.eof()) {
- return false;
- }
-
- if ( !readPBFBlobHeader(stream, threadData) ){
- return false;
- }
-
- if ( threadData->PBFBlobHeader.type() != "OSMData" ) {
- return false;
- }
-
- if ( !readBlob(stream, threadData) ) {
- return false;
- }
-
- if ( !threadData->PBFprimitiveBlock.ParseFromArray( &(threadData->charBuffer[0]), threadData-> charBuffer.size() ) ) {
- ERR("failed to parse PrimitiveBlock");
- return false;
- }
- return true;
+bool PBFParser::readNextBlock(std::fstream &stream, ParserThreadData *thread_data)
+{
+ if (stream.eof())
+ {
+ return false;
+ }
+
+ if (!readPBFBlobHeader(stream, thread_data))
+ {
+ return false;
+ }
+
+ if (thread_data->PBFBlobHeader.type() != "OSMData")
+ {
+ return false;
+ }
+
+ if (!readBlob(stream, thread_data))
+ {
+ return false;
+ }
+
+ if (!thread_data->PBFprimitiveBlock.ParseFromArray(&(thread_data->charBuffer[0]),
+ thread_data->charBuffer.size()))
+ {
+ std::cerr << "failed to parse PrimitiveBlock" << std::endl;
+ return false;
+ }
+ return true;
}
diff --git a/Extractor/PBFParser.h b/Extractor/PBFParser.h
index f3748b6..c65a29d 100644
--- a/Extractor/PBFParser.h
+++ b/Extractor/PBFParser.h
@@ -1,57 +1,57 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#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>
+#include "../DataStructures/ConcurrentQueue.h"
#include <osmpbf/fileformat.pb.h>
#include <osmpbf/osmformat.pb.h>
-#include <zlib.h>
-
-
+#include <fstream>
+#include <memory>
-class PBFParser : public BaseParser {
+class PBFParser : public BaseParser
+{
- enum EntityType {
- TypeNode = 1,
- TypeWay = 2,
- TypeRelation = 4,
- TypeDenseNode = 8
- } ;
+ enum EntityType
+ { TypeDummy = 0,
+ TypeNode = 1,
+ TypeWay = 2,
+ TypeRelation = 4,
+ TypeDenseNode = 8 };
- struct _ThreadData {
+ struct ParserThreadData
+ {
int currentGroupID;
int currentEntityID;
- short entityTypeIndicator;
+ EntityType entityTypeIndicator;
OSMPBF::BlobHeader PBFBlobHeader;
OSMPBF::Blob PBFBlob;
@@ -62,41 +62,42 @@ class PBFParser : public BaseParser {
std::vector<char> charBuffer;
};
-public:
- PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se);
+ public:
+ PBFParser(const char *file_name,
+ ExtractorCallbacks *extractor_callbacks,
+ ScriptingEnvironment &scripting_environment,
+ unsigned num_parser_threads = 0);
virtual ~PBFParser();
inline bool ReadHeader();
- inline bool Parse();
+ inline bool Parse();
-private:
+ private:
inline void ReadData();
inline void ParseData();
- inline void parseDenseNode(_ThreadData * threadData);
- inline void parseNode(_ThreadData * );
- inline void parseRelation(_ThreadData * threadData);
- inline void parseWay(_ThreadData * threadData);
-
- inline void loadGroup(_ThreadData * threadData);
- inline void loadBlock(_ThreadData * threadData);
- inline bool readPBFBlobHeader(std::fstream& stream, _ThreadData * threadData);
- inline bool unpackZLIB(std::fstream &, _ThreadData * threadData);
- inline bool unpackLZMA(std::fstream &, _ThreadData * );
- inline bool readBlob(std::fstream& stream, _ThreadData * threadData) ;
- inline bool readNextBlock(std::fstream& stream, _ThreadData * threadData);
+ inline void parseDenseNode(ParserThreadData *thread_data);
+ inline void parseNode(ParserThreadData *thread_data);
+ inline void parseRelation(ParserThreadData *thread_data);
+ inline void parseWay(ParserThreadData *thread_data);
+
+ inline void loadGroup(ParserThreadData *thread_data);
+ inline void loadBlock(ParserThreadData *thread_data);
+ inline bool readPBFBlobHeader(std::fstream &stream, ParserThreadData *thread_data);
+ inline bool unpackZLIB(ParserThreadData *thread_data);
+ inline bool unpackLZMA(ParserThreadData *thread_data);
+ inline bool readBlob(std::fstream &stream, ParserThreadData *thread_data);
+ inline bool readNextBlock(std::fstream &stream, ParserThreadData *thread_data);
static const int NANO = 1000 * 1000 * 1000;
static const int MAX_BLOB_HEADER_SIZE = 64 * 1024;
static const int MAX_BLOB_SIZE = 32 * 1024 * 1024;
-#ifndef NDEBUG
- /* counting the number of read blocks and groups */
- unsigned groupCount;
- unsigned blockCount;
-#endif
+ unsigned group_count;
+ unsigned block_count;
- std::fstream input; // the input stream to parse
- boost::shared_ptr<ConcurrentQueue < _ThreadData* > > threadDataQueue;
+ std::fstream input; // the input stream to parse
+ std::shared_ptr<ConcurrentQueue<ParserThreadData *>> thread_data_queue;
+ unsigned num_parser_threads;
};
#endif /* PBFPARSER_H_ */
diff --git a/Extractor/ScriptingEnvironment.cpp b/Extractor/ScriptingEnvironment.cpp
index 6bab21c..01dee39 100644
--- a/Extractor/ScriptingEnvironment.cpp
+++ b/Extractor/ScriptingEnvironment.cpp
@@ -1,108 +1,121 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#include "ScriptingEnvironment.h"
+#include "ExtractionHelperFunctions.h"
+#include "ExtractionWay.h"
+#include "../DataStructures/ImportNode.h"
+#include "../Util/LuaUtil.h"
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+#include "../typedefs.h"
+
ScriptingEnvironment::ScriptingEnvironment() {}
-ScriptingEnvironment::ScriptingEnvironment(const char * fileName) {
- INFO("Using script " << fileName);
+ScriptingEnvironment::ScriptingEnvironment(const char *file_name)
+: file_name(file_name)
+{
+ SimpleLogger().Write() << "Using script " << file_name;
+}
+
+void ScriptingEnvironment::initLuaState(lua_State* lua_state)
+{
+ luabind::open(lua_state);
+ // open utility libraries string library;
+ luaL_openlibs(lua_state);
+
+ luaAddScriptFolderToLoadPath(lua_state, file_name.c_str());
+
+ // Add our function to the state's global scope
+ luabind::module(lua_state)[
+ luabind::def("print", LUA_print<std::string>),
+ luabind::def("durationIsValid", durationIsValid),
+ luabind::def("parseDuration", parseDuration)
+ ];
- // Create a new lua state
- for(int i = 0; i < omp_get_max_threads(); ++i)
- luaStateVector.push_back(luaL_newstate());
+ luabind::module(lua_state)[luabind::class_<HashTable<std::string, std::string>>("keyVals")
+ .def("Add", &HashTable<std::string, std::string>::Add)
+ .def("Find", &HashTable<std::string, std::string>::Find)
+ .def("Holds", &HashTable<std::string, std::string>::Holds)];
- // Connect LuaBind to this lua state for all threads
-#pragma omp parallel
+ luabind::module(lua_state)[luabind::class_<ImportNode>("Node")
+ .def(luabind::constructor<>())
+ .def_readwrite("lat", &ImportNode::lat)
+ .def_readwrite("lon", &ImportNode::lon)
+ .def_readonly("id", &ImportNode::node_id)
+ .def_readwrite("bollard", &ImportNode::bollard)
+ .def_readwrite("traffic_light", &ImportNode::trafficLight)
+ .def_readwrite("tags", &ImportNode::keyVals)];
+
+ luabind::module(lua_state)
+ [luabind::class_<ExtractionWay>("Way")
+ .def(luabind::constructor<>())
+ .def_readonly("id", &ExtractionWay::id)
+ .def_readwrite("name", &ExtractionWay::name)
+ .def_readwrite("speed", &ExtractionWay::speed)
+ .def_readwrite("backward_speed", &ExtractionWay::backward_speed)
+ .def_readwrite("duration", &ExtractionWay::duration)
+ .def_readwrite("type", &ExtractionWay::type)
+ .def_readwrite("access", &ExtractionWay::access)
+ .def_readwrite("roundabout", &ExtractionWay::roundabout)
+ .def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted)
+ .def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid)
+ .def_readwrite("tags", &ExtractionWay::keyVals)
+ .def_readwrite("direction", &ExtractionWay::direction)
+ .enum_("constants")[
+ luabind::value("notSure", 0),
+ luabind::value("oneway", 1),
+ luabind::value("bidirectional", 2),
+ luabind::value("opposite", 3)
+ ]];
+
+ // fails on c++11/OS X 10.9
+ luabind::module(lua_state)[luabind::class_<std::vector<std::string>>("vector").def(
+ "Add",
+ static_cast<void (std::vector<std::string>::*)(const std::string &)>(
+ &std::vector<std::string>::push_back))];
+
+ if (0 != luaL_dofile(lua_state, file_name.c_str()))
{
- lua_State * myLuaState = getLuaStateForThreadID(omp_get_thread_num());
- luabind::open(myLuaState);
- //open utility libraries string library;
- luaL_openlibs(myLuaState);
-
- luaAddScriptFolderToLoadPath( myLuaState, fileName );
-
- // Add our function to the state's global scope
- luabind::module(myLuaState) [
- luabind::def("print", LUA_print<std::string>),
- luabind::def("parseMaxspeed", parseMaxspeed),
- luabind::def("durationIsValid", durationIsValid),
- luabind::def("parseDuration", parseDuration)
- ];
-
- luabind::module(myLuaState) [
- luabind::class_<HashTable<std::string, std::string> >("keyVals")
- .def("Add", &HashTable<std::string, std::string>::Add)
- .def("Find", &HashTable<std::string, std::string>::Find)
- .def("Holds", &HashTable<std::string, std::string>::Holds)
- ];
-
- luabind::module(myLuaState) [
- luabind::class_<ImportNode>("Node")
- .def(luabind::constructor<>())
- .def_readwrite("lat", &ImportNode::lat)
- .def_readwrite("lon", &ImportNode::lon)
- .def_readwrite("id", &ImportNode::id)
- .def_readwrite("bollard", &ImportNode::bollard)
- .def_readwrite("traffic_light", &ImportNode::trafficLight)
- .def_readwrite("tags", &ImportNode::keyVals)
- ];
-
- luabind::module(myLuaState) [
- luabind::class_<ExtractionWay>("Way")
- .def(luabind::constructor<>())
- .def_readwrite("name", &ExtractionWay::name)
- .def_readwrite("speed", &ExtractionWay::speed)
- .def_readwrite("backward_speed", &ExtractionWay::backward_speed)
- .def_readwrite("duration", &ExtractionWay::duration)
- .def_readwrite("type", &ExtractionWay::type)
- .def_readwrite("access", &ExtractionWay::access)
- .def_readwrite("roundabout", &ExtractionWay::roundabout)
- .def_readwrite("is_access_restricted", &ExtractionWay::isAccessRestricted)
- .def_readwrite("ignore_in_grid", &ExtractionWay::ignoreInGrid)
- .def_readwrite("tags", &ExtractionWay::keyVals)
- .def_readwrite("direction", &ExtractionWay::direction)
- .enum_("constants")
- [
- luabind::value("notSure", 0),
- luabind::value("oneway", 1),
- luabind::value("bidirectional", 2),
- luabind::value("opposite", 3)
- ]
- ];
- luabind::module(myLuaState) [
- luabind::class_<std::vector<std::string> >("vector")
- .def("Add", &std::vector<std::string>::push_back)
- ];
-
- if(0 != luaL_dofile(myLuaState, fileName) ) {
- ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
- }
+ throw OSRMException("ERROR occured in scripting block");
}
}
-ScriptingEnvironment::~ScriptingEnvironment() {
- for(unsigned i = 0; i < luaStateVector.size(); ++i) {
- // luaStateVector[i];
+lua_State *ScriptingEnvironment::getLuaState()
+{
+ bool initialized = false;
+ auto& ref = script_contexts.local(initialized);
+ if (!initialized)
+ {
+ std::shared_ptr<lua_State> state(luaL_newstate(), lua_close);
+ ref = state;
+ initLuaState(ref.get());
}
-}
-lua_State * ScriptingEnvironment::getLuaStateForThreadID(const int id) {
- return luaStateVector[id];
+ return ref.get();
}
+
diff --git a/Extractor/ScriptingEnvironment.h b/Extractor/ScriptingEnvironment.h
index 015ff25..2b1fffe 100644
--- a/Extractor/ScriptingEnvironment.h
+++ b/Extractor/ScriptingEnvironment.h
@@ -1,50 +1,52 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, others 2010
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU AFFERO General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- any later version.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef SCRIPTINGENVIRONMENT_H_
#define SCRIPTINGENVIRONMENT_H_
-extern "C" {
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
-}
-#include <luabind/luabind.hpp>
+#include <string>
+#include <memory>
+#include <tbb/enumerable_thread_specific.h>
-#include "ExtractionHelperFunctions.h"
-#include "ExtractorStructs.h"
+struct lua_State;
-#include "../typedefs.h"
-#include "../DataStructures/ImportNode.h"
-#include "../Util/LuaUtil.h"
-#include "../Util/OpenMPWrapper.h"
-
-class ScriptingEnvironment {
-public:
+class ScriptingEnvironment
+{
+ public:
ScriptingEnvironment();
- ScriptingEnvironment(const char * fileName);
- virtual ~ScriptingEnvironment();
+ explicit ScriptingEnvironment(const char *file_name);
+
+ lua_State *getLuaState();
- lua_State * getLuaStateForThreadID(const int);
+ private:
+ void initLuaState(lua_State* lua_state);
- std::vector<lua_State *> luaStateVector;
+ std::string file_name;
+ tbb::enumerable_thread_specific<std::shared_ptr<lua_State>> script_contexts;
};
#endif /* SCRIPTINGENVIRONMENT_H_ */
diff --git a/Extractor/XMLParser.cpp b/Extractor/XMLParser.cpp
index fa810a7..3a5446e 100644
--- a/Extractor/XMLParser.cpp
+++ b/Extractor/XMLParser.cpp
@@ -1,276 +1,353 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
- 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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
- 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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#include <boost/ref.hpp>
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#include "XMLParser.h"
-#include "ExtractorStructs.h"
+#include "ExtractionWay.h"
+#include "ExtractorCallbacks.h"
+
#include "../DataStructures/HashTable.h"
+#include "../DataStructures/ImportNode.h"
#include "../DataStructures/InputReaderFactory.h"
+#include "../DataStructures/Restriction.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/StringUtil.h"
+#include "../typedefs.h"
+#include <osrm/Coordinate.h>
-XMLParser::XMLParser(const char * filename, ExtractorCallbacks* ec, ScriptingEnvironment& se) : BaseParser(ec, se) {
- WARN("Parsing plain .osm/.osm.bz2 is deprecated. Switch to .pbf");
- inputReader = inputReaderFactory(filename);
+XMLParser::XMLParser(const char *filename,
+ ExtractorCallbacks *extractor_callbacks,
+ ScriptingEnvironment &scripting_environment)
+ : BaseParser(extractor_callbacks, scripting_environment)
+{
+ inputReader = inputReaderFactory(filename);
}
-bool XMLParser::ReadHeader() {
- return (xmlTextReaderRead( inputReader ) == 1);
-}
-bool XMLParser::Parse() {
- while ( xmlTextReaderRead( inputReader ) == 1 ) {
- const int type = xmlTextReaderNodeType( inputReader );
-
- //1 is Element
- if ( type != 1 ) {
- continue;
- }
-
- xmlChar* currentName = xmlTextReaderName( inputReader );
- if ( currentName == NULL ) {
- continue;
- }
-
- if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) {
- ImportNode n = _ReadXMLNode();
- ParseNodeInLua( n, luaState );
- extractor_callbacks->nodeFunction(n);
-// if(!extractor_callbacks->nodeFunction(n))
-// std::cerr << "[XMLParser] dense node not parsed" << std::endl;
- }
-
- if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) {
- ExtractionWay way = _ReadXMLWay( );
- ParseWayInLua( way, luaState );
- extractor_callbacks->wayFunction(way);
-// if(!extractor_callbacks->wayFunction(way))
-// std::cerr << "[PBFParser] way not parsed" << std::endl;
- }
- if( use_turn_restrictions ) {
- if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) {
- _RawRestrictionContainer r = _ReadXMLRestriction();
- if(r.fromWay != UINT_MAX) {
- if(!extractor_callbacks->restrictionFunction(r)) {
- std::cerr << "[XMLParser] restriction not parsed" << std::endl;
- }
- }
- }
- }
- xmlFree( currentName );
- }
- return true;
+bool XMLParser::ReadHeader() { return xmlTextReaderRead(inputReader) == 1; }
+bool XMLParser::Parse()
+{
+ while (xmlTextReaderRead(inputReader) == 1)
+ {
+ const int type = xmlTextReaderNodeType(inputReader);
+
+ // 1 is Element
+ if (type != 1)
+ {
+ continue;
+ }
+
+ xmlChar *currentName = xmlTextReaderName(inputReader);
+ if (currentName == nullptr)
+ {
+ continue;
+ }
+
+ if (xmlStrEqual(currentName, (const xmlChar *)"node") == 1)
+ {
+ ImportNode current_node = ReadXMLNode();
+ ParseNodeInLua(current_node, lua_state);
+ extractor_callbacks->ProcessNode(current_node);
+ }
+
+ if (xmlStrEqual(currentName, (const xmlChar *)"way") == 1)
+ {
+ ExtractionWay way = ReadXMLWay();
+ ParseWayInLua(way, lua_state);
+ extractor_callbacks->ProcessWay(way);
+ }
+ if (use_turn_restrictions && xmlStrEqual(currentName, (const xmlChar *)"relation") == 1)
+ {
+ InputRestrictionContainer current_restriction = ReadXMLRestriction();
+ if ((UINT_MAX != current_restriction.fromWay) &&
+ !extractor_callbacks->ProcessRestriction(current_restriction))
+ {
+ std::cerr << "[XMLParser] restriction not parsed" << std::endl;
+ }
+ }
+ xmlFree(currentName);
+ }
+ return true;
}
-_RawRestrictionContainer XMLParser::_ReadXMLRestriction() {
- _RawRestrictionContainer restriction;
+InputRestrictionContainer XMLParser::ReadXMLRestriction()
+{
+
+ InputRestrictionContainer restriction;
+
+ if (xmlTextReaderIsEmptyElement(inputReader) == 1)
+ {
+ return restriction;
+ }
+
std::string except_tag_string;
+ const int depth = xmlTextReaderDepth(inputReader);
+ while (xmlTextReaderRead(inputReader) == 1)
+ {
+ const int child_type = xmlTextReaderNodeType(inputReader);
+ if (child_type != 1 && child_type != 15)
+ {
+ continue;
+ }
+ const int child_depth = xmlTextReaderDepth(inputReader);
+ xmlChar *child_name = xmlTextReaderName(inputReader);
+ if (child_name == nullptr)
+ {
+ continue;
+ }
+ if (depth == child_depth && child_type == 15 &&
+ xmlStrEqual(child_name, (const xmlChar *)"relation") == 1)
+ {
+ xmlFree(child_name);
+ break;
+ }
+ if (child_type != 1)
+ {
+ xmlFree(child_name);
+ continue;
+ }
+
+ if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
+ {
+ xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
+ xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
+ if (key != nullptr && value != nullptr)
+ {
+ if (xmlStrEqual(key, (const xmlChar *)"restriction") &&
+ StringStartsWith((const char *)value, "only_"))
+ {
+ restriction.restriction.flags.isOnly = true;
+ }
+ if (xmlStrEqual(key, (const xmlChar *)"except"))
+ {
+ except_tag_string = (const char *)value;
+ }
+ }
- if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) {
- const int depth = xmlTextReaderDepth( inputReader );while ( xmlTextReaderRead( inputReader ) == 1 ) {
- const int childType = xmlTextReaderNodeType( inputReader );
- if ( childType != 1 && childType != 15 ) {
- continue;
- }
- const int childDepth = xmlTextReaderDepth( inputReader );
- xmlChar* childName = xmlTextReaderName( inputReader );
- if ( childName == NULL ) {
- continue;
- }
- if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "relation" ) == 1 ) {
- xmlFree( childName );
- break;
- }
- if ( childType != 1 ) {
- xmlFree( childName );
- continue;
- }
-
- if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) {
- xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
- xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" );
- if ( k != NULL && value != NULL ) {
- if(xmlStrEqual(k, ( const xmlChar* ) "restriction" )){
- if(0 == std::string((const char *) value).find("only_")) {
- restriction.restriction.flags.isOnly = true;
- }
- }
- if ( xmlStrEqual(k, (const xmlChar *) "except") ) {
- except_tag_string = (const char*) value;
- }
- }
-
- if ( k != NULL ) {
- xmlFree( k );
- }
- if ( value != NULL ) {
- xmlFree( value );
- }
- } else if ( xmlStrEqual( childName, ( const xmlChar* ) "member" ) == 1 ) {
- xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" );
- if ( ref != NULL ) {
- xmlChar * role = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "role" );
- xmlChar * type = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "type" );
-
- if(xmlStrEqual(role, (const xmlChar *) "to") && xmlStrEqual(type, (const xmlChar *) "way")) {
- restriction.toWay = atoi((const char*) ref);
- }
- if(xmlStrEqual(role, (const xmlChar *) "from") && xmlStrEqual(type, (const xmlChar *) "way")) {
- restriction.fromWay = atoi((const char*) ref);
- }
- if(xmlStrEqual(role, (const xmlChar *) "via") && xmlStrEqual(type, (const xmlChar *) "node")) {
- restriction.restriction.viaNode = atoi((const char*) ref);
- }
-
- if(NULL != type) {
- xmlFree( type );
- }
- if(NULL != role) {
- xmlFree( role );
- }
- if(NULL != ref) {
- xmlFree( ref );
- }
- }
- }
- xmlFree( childName );
- }
- }
-
- if( ShouldIgnoreRestriction(except_tag_string) ) {
- restriction.fromWay = UINT_MAX; //workaround to ignore the restriction
- }
- return restriction;
+ if (key != nullptr)
+ {
+ xmlFree(key);
+ }
+ if (value != nullptr)
+ {
+ xmlFree(value);
+ }
+ }
+ else if (xmlStrEqual(child_name, (const xmlChar *)"member") == 1)
+ {
+ xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
+ if (ref != nullptr)
+ {
+ xmlChar *role = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"role");
+ xmlChar *type = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"type");
+
+ if (xmlStrEqual(role, (const xmlChar *)"to") &&
+ xmlStrEqual(type, (const xmlChar *)"way"))
+ {
+ restriction.toWay = StringToUint((const char *)ref);
+ }
+ if (xmlStrEqual(role, (const xmlChar *)"from") &&
+ xmlStrEqual(type, (const xmlChar *)"way"))
+ {
+ restriction.fromWay = StringToUint((const char *)ref);
+ }
+ if (xmlStrEqual(role, (const xmlChar *)"via") &&
+ xmlStrEqual(type, (const xmlChar *)"node"))
+ {
+ restriction.restriction.viaNode = StringToUint((const char *)ref);
+ }
+
+ if (nullptr != type)
+ {
+ xmlFree(type);
+ }
+ if (nullptr != role)
+ {
+ xmlFree(role);
+ }
+ if (nullptr != ref)
+ {
+ xmlFree(ref);
+ }
+ }
+ }
+ xmlFree(child_name);
+ }
+
+ if (ShouldIgnoreRestriction(except_tag_string))
+ {
+ restriction.fromWay = UINT_MAX; // workaround to ignore the restriction
+ }
+ return restriction;
}
-ExtractionWay XMLParser::_ReadXMLWay() {
- ExtractionWay way;
- if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) {
- const int depth = xmlTextReaderDepth( inputReader );
- while ( xmlTextReaderRead( inputReader ) == 1 ) {
- const int childType = xmlTextReaderNodeType( inputReader );
- if ( childType != 1 && childType != 15 ) {
- continue;
- }
- const int childDepth = xmlTextReaderDepth( inputReader );
- xmlChar* childName = xmlTextReaderName( inputReader );
- if ( childName == NULL ) {
- continue;
- }
-
- if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "way" ) == 1 ) {
- xmlChar* id = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" );
- way.id = atoi((char*)id);
- xmlFree(id);
- xmlFree( childName );
- break;
- }
- if ( childType != 1 ) {
- xmlFree( childName );
- continue;
- }
-
- if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) {
- xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
- xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" );
- // cout << "->k=" << k << ", v=" << value << endl;
- if ( k != NULL && value != NULL ) {
- way.keyVals.Add(std::string( (char *) k ), std::string( (char *) value));
- }
- if ( k != NULL ) {
- xmlFree( k );
- }
- if ( value != NULL ) {
- xmlFree( value );
- }
- } else if ( xmlStrEqual( childName, ( const xmlChar* ) "nd" ) == 1 ) {
- xmlChar* ref = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "ref" );
- if ( ref != NULL ) {
- way.path.push_back( atoi(( const char* ) ref ) );
- xmlFree( ref );
- }
- }
- xmlFree( childName );
- }
- }
- return way;
+ExtractionWay XMLParser::ReadXMLWay()
+{
+ ExtractionWay way;
+ if (xmlTextReaderIsEmptyElement(inputReader) == 1)
+ {
+ return way;
+ }
+ const int depth = xmlTextReaderDepth(inputReader);
+ while (xmlTextReaderRead(inputReader) == 1)
+ {
+ const int child_type = xmlTextReaderNodeType(inputReader);
+ if (child_type != 1 && child_type != 15)
+ {
+ continue;
+ }
+ const int child_depth = xmlTextReaderDepth(inputReader);
+ xmlChar *child_name = xmlTextReaderName(inputReader);
+ if (child_name == nullptr)
+ {
+ continue;
+ }
+
+ if (depth == child_depth && child_type == 15 &&
+ xmlStrEqual(child_name, (const xmlChar *)"way") == 1)
+ {
+ xmlChar *node_id = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
+ way.id = StringToUint((char *)node_id);
+ xmlFree(node_id);
+ xmlFree(child_name);
+ break;
+ }
+ if (child_type != 1)
+ {
+ xmlFree(child_name);
+ continue;
+ }
+
+ if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
+ {
+ xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
+ xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
+
+ if (key != nullptr && value != nullptr)
+ {
+ way.keyVals.Add(std::string((char *)key), std::string((char *)value));
+ }
+ if (key != nullptr)
+ {
+ xmlFree(key);
+ }
+ if (value != nullptr)
+ {
+ xmlFree(value);
+ }
+ }
+ else if (xmlStrEqual(child_name, (const xmlChar *)"nd") == 1)
+ {
+ xmlChar *ref = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"ref");
+ if (ref != nullptr)
+ {
+ way.path.push_back(StringToUint((const char *)ref));
+ xmlFree(ref);
+ }
+ }
+ xmlFree(child_name);
+ }
+ return way;
}
-ImportNode XMLParser::_ReadXMLNode() {
- ImportNode node;
-
- xmlChar* attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lat" );
- if ( attribute != NULL ) {
- node.lat = static_cast<NodeID>(100000.*atof(( const char* ) attribute ) );
- xmlFree( attribute );
- }
- attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "lon" );
- if ( attribute != NULL ) {
- node.lon = static_cast<NodeID>(100000.*atof(( const char* ) attribute ));
- xmlFree( attribute );
- }
- attribute = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "id" );
- if ( attribute != NULL ) {
- node.id = atoi(( const char* ) attribute );
- xmlFree( attribute );
- }
-
- if ( xmlTextReaderIsEmptyElement( inputReader ) != 1 ) {
- const int depth = xmlTextReaderDepth( inputReader );
- while ( xmlTextReaderRead( inputReader ) == 1 ) {
- const int childType = xmlTextReaderNodeType( inputReader );
- // 1 = Element, 15 = EndElement
- if ( childType != 1 && childType != 15 ) {
- continue;
- }
- const int childDepth = xmlTextReaderDepth( inputReader );
- xmlChar* childName = xmlTextReaderName( inputReader );
- if ( childName == NULL ) {
- continue;
- }
-
- if ( depth == childDepth && childType == 15 && xmlStrEqual( childName, ( const xmlChar* ) "node" ) == 1 ) {
- xmlFree( childName );
- break;
- }
- if ( childType != 1 ) {
- xmlFree( childName );
- continue;
- }
-
- if ( xmlStrEqual( childName, ( const xmlChar* ) "tag" ) == 1 ) {
- xmlChar* k = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "k" );
- xmlChar* value = xmlTextReaderGetAttribute( inputReader, ( const xmlChar* ) "v" );
- if ( k != NULL && value != NULL ) {
- node.keyVals.Add(std::string( reinterpret_cast<char*>(k) ), std::string( reinterpret_cast<char*>(value)));
- }
- if ( k != NULL ) {
- xmlFree( k );
- }
- if ( value != NULL ) {
- xmlFree( value );
- }
- }
-
- xmlFree( childName );
- }
- }
- return node;
+ImportNode XMLParser::ReadXMLNode()
+{
+ ImportNode node;
+
+ xmlChar *attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lat");
+ if (attribute != nullptr)
+ {
+ node.lat = static_cast<int>(COORDINATE_PRECISION * StringToDouble((const char *)attribute));
+ xmlFree(attribute);
+ }
+ attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"lon");
+ if (attribute != nullptr)
+ {
+ node.lon = static_cast<int>(COORDINATE_PRECISION * StringToDouble((const char *)attribute));
+ xmlFree(attribute);
+ }
+ attribute = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"id");
+ if (attribute != nullptr)
+ {
+ node.node_id = StringToUint((const char *)attribute);
+ xmlFree(attribute);
+ }
+
+ if (xmlTextReaderIsEmptyElement(inputReader) == 1)
+ {
+ return node;
+ }
+ const int depth = xmlTextReaderDepth(inputReader);
+ while (xmlTextReaderRead(inputReader) == 1)
+ {
+ const int child_type = xmlTextReaderNodeType(inputReader);
+ // 1 = Element, 15 = EndElement
+ if (child_type != 1 && child_type != 15)
+ {
+ continue;
+ }
+ const int child_depth = xmlTextReaderDepth(inputReader);
+ xmlChar *child_name = xmlTextReaderName(inputReader);
+ if (child_name == nullptr)
+ {
+ continue;
+ }
+
+ if (depth == child_depth && child_type == 15 &&
+ xmlStrEqual(child_name, (const xmlChar *)"node") == 1)
+ {
+ xmlFree(child_name);
+ break;
+ }
+ if (child_type != 1)
+ {
+ xmlFree(child_name);
+ continue;
+ }
+
+ if (xmlStrEqual(child_name, (const xmlChar *)"tag") == 1)
+ {
+ xmlChar *key = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"k");
+ xmlChar *value = xmlTextReaderGetAttribute(inputReader, (const xmlChar *)"v");
+ if (key != nullptr && value != nullptr)
+ {
+ node.keyVals.Add(std::string((char *)(key)), std::string((char *)(value)));
+ }
+ if (key != nullptr)
+ {
+ xmlFree(key);
+ }
+ if (value != nullptr)
+ {
+ xmlFree(value);
+ }
+ }
+
+ xmlFree(child_name);
+ }
+ return node;
}
diff --git a/Extractor/XMLParser.h b/Extractor/XMLParser.h
index a2af2fb..178747a 100644
--- a/Extractor/XMLParser.h
+++ b/Extractor/XMLParser.h
@@ -1,41 +1,53 @@
/*
- 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.
- */
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef XMLPARSER_H_
#define XMLPARSER_H_
+#include "BaseParser.h"
+#include "../DataStructures/Restriction.h"
+
#include <libxml/xmlreader.h>
-#include "../typedefs.h"
-#include "BaseParser.h"
+class ExtractorCallbacks;
-class XMLParser : public BaseParser {
-public:
- XMLParser(const char* filename, ExtractorCallbacks* ec, ScriptingEnvironment& se);
+class XMLParser : public BaseParser
+{
+ public:
+ XMLParser(const char *filename,
+ ExtractorCallbacks *extractor_callbacks,
+ ScriptingEnvironment &scripting_environment);
bool ReadHeader();
bool Parse();
-
-private:
- _RawRestrictionContainer _ReadXMLRestriction();
- ExtractionWay _ReadXMLWay();
- ImportNode _ReadXMLNode();
+
+ private:
+ InputRestrictionContainer ReadXMLRestriction();
+ ExtractionWay ReadXMLWay();
+ ImportNode ReadXMLNode();
xmlTextReaderPtr inputReader;
};
diff --git a/Gemfile.lock b/Gemfile.lock
index 32a3fda..ac056a0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,23 +1,23 @@
GEM
remote: http://rubygems.org/
specs:
- builder (3.0.0)
- cucumber (1.1.4)
+ builder (3.2.2)
+ cucumber (1.3.8)
builder (>= 2.1.2)
- diff-lcs (>= 1.1.2)
- gherkin (~> 2.7.1)
- json (>= 1.4.6)
- term-ansicolor (>= 1.0.6)
- diff-lcs (1.1.3)
- gherkin (2.7.6)
- json (>= 1.4.6)
- json (1.6.5)
+ diff-lcs (>= 1.1.3)
+ gherkin (~> 2.12.1)
+ multi_json (>= 1.7.5, < 2.0)
+ multi_test (>= 0.0.2)
+ diff-lcs (1.2.4)
+ gherkin (2.12.1)
+ multi_json (~> 1.3)
+ multi_json (1.8.0)
+ multi_test (0.0.2)
osmlib-base (0.1.4)
- rake (0.9.2.2)
- rspec-expectations (2.11.3)
- diff-lcs (~> 1.1.3)
- sys-proctable (0.9.1)
- term-ansicolor (1.0.7)
+ rake (10.1.0)
+ rspec-expectations (2.14.3)
+ diff-lcs (>= 1.1.3, < 2.0)
+ sys-proctable (0.9.3)
PLATFORMS
ruby
diff --git a/Include/osrm/Coordinate.h b/Include/osrm/Coordinate.h
new file mode 100644
index 0000000..dc05855
--- /dev/null
+++ b/Include/osrm/Coordinate.h
@@ -0,0 +1,105 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef FIXED_POINT_COORDINATE_H_
+#define FIXED_POINT_COORDINATE_H_
+
+#include <functional>
+#include <iosfwd> //for std::ostream
+#include <string>
+
+const float COORDINATE_PRECISION = 1000000.f;
+
+struct FixedPointCoordinate
+{
+ int lat;
+ int lon;
+
+ FixedPointCoordinate();
+ explicit FixedPointCoordinate(int lat, int lon);
+ void Reset();
+ bool isSet() const;
+ bool isValid() const;
+ bool operator==(const FixedPointCoordinate &other) const;
+
+ static double
+ ApproximateDistance(const int lat1, const int lon1, const int lat2, const int lon2);
+
+ static double ApproximateDistance(const FixedPointCoordinate &first_coordinate,
+ const FixedPointCoordinate &second_coordinate);
+
+ static float ApproximateEuclideanDistance(const FixedPointCoordinate &first_coordinate,
+ const FixedPointCoordinate &second_coordinate);
+
+ static float ApproximateEuclideanDistance(const int lat1,
+ const int lon1,
+ const int lat2,
+ const int lon2);
+
+ static float ApproximateSquaredEuclideanDistance(const FixedPointCoordinate &first_coordinate,
+ const FixedPointCoordinate &second_coordinate);
+
+ static void convertInternalLatLonToString(const int value, std::string &output);
+
+ static void convertInternalCoordinateToString(const FixedPointCoordinate &coordinate,
+ std::string &output);
+
+ static void convertInternalReversedCoordinateToString(const FixedPointCoordinate &coordinate,
+ std::string &output);
+
+ static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
+ const FixedPointCoordinate &segment_target,
+ const FixedPointCoordinate &query_location);
+
+ static float ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
+ const FixedPointCoordinate &segment_target,
+ const FixedPointCoordinate &query_location,
+ FixedPointCoordinate &nearest_location,
+ float &ratio);
+
+ static int OrderedPerpendicularDistanceApproximation(const FixedPointCoordinate& segment_source,
+ const FixedPointCoordinate& segment_target,
+ const FixedPointCoordinate& query_location);
+
+
+ static float GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B);
+
+ float GetBearing(const FixedPointCoordinate &other) const;
+
+ void Output(std::ostream &out) const;
+
+ static float DegreeToRadian(const float degree);
+ static float RadianToDegree(const float radian);
+};
+
+inline std::ostream &operator<<(std::ostream &out_stream, FixedPointCoordinate const &coordinate)
+{
+ coordinate.Output(out_stream);
+ return out_stream;
+}
+
+#endif /* FIXED_POINT_COORDINATE_H_ */
diff --git a/Include/osrm/Header.h b/Include/osrm/Header.h
new file mode 100644
index 0000000..de0b2ab
--- /dev/null
+++ b/Include/osrm/Header.h
@@ -0,0 +1,53 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef HTTP_HEADER_H
+#define HTTP_HEADER_H
+
+#include <string>
+#include <algorithm>
+
+namespace http
+{
+struct Header
+{
+ Header& operator=(const Header& other) = default;
+ Header(const std::string & name, const std::string & value) : name(name), value(value) {}
+ Header(const Header && other) : name(std::move(other.name)), value(std::move(other.value)) {}
+
+ void Clear()
+ {
+ name.clear();
+ value.clear();
+ }
+
+ std::string name;
+ std::string value;
+};
+}
+
+#endif // HTTP_HEADER_H
diff --git a/Include/osrm/Reply.h b/Include/osrm/Reply.h
new file mode 100644
index 0000000..a2ee1f4
--- /dev/null
+++ b/Include/osrm/Reply.h
@@ -0,0 +1,74 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef REPLY_H
+#define REPLY_H
+
+#include "Header.h"
+
+#include <boost/asio.hpp>
+
+#include <vector>
+
+namespace http
+{
+
+const char okHTML[] = "";
+const char badRequestHTML[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
+const char internalServerErrorHTML[] =
+ "{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
+const char seperators[] = {':', ' '};
+const char crlf[] = {'\r', '\n'};
+const std::string okString = "HTTP/1.0 200 OK\r\n";
+const std::string badRequestString = "HTTP/1.0 400 Bad Request\r\n";
+const std::string internalServerErrorString = "HTTP/1.0 500 Internal Server Error\r\n";
+
+class Reply
+{
+ public:
+ enum status_type
+ { ok = 200,
+ badRequest = 400,
+ internalServerError = 500 } status;
+
+ std::vector<Header> headers;
+ std::vector<boost::asio::const_buffer> ToBuffers();
+ std::vector<boost::asio::const_buffer> HeaderstoBuffers();
+ std::vector<char> content;
+ static Reply StockReply(status_type status);
+ void SetSize(const unsigned size);
+ void SetUncompressedSize();
+
+ Reply();
+
+ private:
+ std::string ToString(Reply::status_type status);
+ boost::asio::const_buffer ToBuffer(Reply::status_type status);
+};
+}
+
+#endif // REPLY_H
diff --git a/Include/osrm/RouteParameters.h b/Include/osrm/RouteParameters.h
new file mode 100644
index 0000000..89a1774
--- /dev/null
+++ b/Include/osrm/RouteParameters.h
@@ -0,0 +1,83 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef ROUTE_PARAMETERS_H
+#define ROUTE_PARAMETERS_H
+
+#include <osrm/Coordinate.h>
+
+#include <boost/fusion/container/vector/vector_fwd.hpp>
+
+#include <string>
+#include <vector>
+
+struct RouteParameters
+{
+ RouteParameters();
+
+ void setZoomLevel(const short level);
+
+ void setAlternateRouteFlag(const bool flag);
+
+ void setDeprecatedAPIFlag(const std::string &);
+
+ void setChecksum(const unsigned check_sum);
+
+ void setInstructionFlag(const bool flag);
+
+ void setService(const std::string &service);
+
+ void setOutputFormat(const std::string &format);
+
+ void setJSONpParameter(const std::string ¶meter);
+
+ void addHint(const std::string &hint);
+
+ void setLanguage(const std::string &language);
+
+ void setGeometryFlag(const bool flag);
+
+ void setCompressionFlag(const bool flag);
+
+ void addCoordinate(const boost::fusion::vector<double, double> &coordinates);
+
+ short zoom_level;
+ bool print_instructions;
+ bool alternate_route;
+ bool geometry;
+ bool compression;
+ bool deprecatedAPI;
+ unsigned check_sum;
+ std::string service;
+ std::string output_format;
+ std::string jsonp_parameter;
+ std::string language;
+ std::vector<std::string> hints;
+ std::vector<FixedPointCoordinate> coordinates;
+};
+
+#endif // ROUTE_PARAMETERS_H
diff --git a/Include/osrm/ServerPaths.h b/Include/osrm/ServerPaths.h
new file mode 100644
index 0000000..52b60c7
--- /dev/null
+++ b/Include/osrm/ServerPaths.h
@@ -0,0 +1,38 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef SERVER_PATH_H
+#define SERVER_PATH_H
+
+#include <boost/filesystem.hpp>
+
+#include <unordered_map>
+#include <string>
+
+typedef std::unordered_map<std::string, boost::filesystem::path> ServerPaths;
+
+#endif // SERVER_PATH_H
diff --git a/LICENCE.TXT b/LICENCE.TXT
index dba13ed..28fe97b 100644
--- a/LICENCE.TXT
+++ b/LICENCE.TXT
@@ -1,661 +1,22 @@
- GNU AFFERO GENERAL PUBLIC LICENSE
- Version 3, 19 November 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU Affero General Public License is a free, copyleft license for
-software and other kinds of works, specifically designed to ensure
-cooperation with the community in the case of network server software.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-our General Public Licenses are intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- Developers that use our General Public Licenses protect your rights
-with two steps: (1) assert copyright on the software, and (2) offer
-you this License which gives you legal permission to copy, distribute
-and/or modify the software.
-
- A secondary benefit of defending all users' freedom is that
-improvements made in alternate versions of the program, if they
-receive widespread use, become available for other developers to
-incorporate. Many developers of free software are heartened and
-encouraged by the resulting cooperation. However, in the case of
-software used on network servers, this result may fail to come about.
-The GNU General Public License permits making a modified version and
-letting the public access it on a server without ever releasing its
-source code to the public.
-
- The GNU Affero General Public License is designed specifically to
-ensure that, in such cases, the modified source code becomes available
-to the community. It requires the operator of a network server to
-provide the source code of the modified version running there to the
-users of that server. Therefore, public use of a modified version, on
-a publicly accessible server, gives the public access to the source
-code of the modified version.
-
- An older license, called the Affero General Public License and
-published by Affero, was designed to accomplish similar goals. This is
-a different license, not a version of the Affero GPL, but Affero has
-released a new version of the Affero GPL which permits relicensing under
-this license.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU Affero General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Remote Network Interaction; Use with the GNU General Public License.
-
- Notwithstanding any other provision of this License, if you modify the
-Program, your modified version must prominently offer all users
-interacting with it remotely through a computer network (if your version
-supports such interaction) an opportunity to receive the Corresponding
-Source of your version by providing access to the Corresponding Source
-from a network server at no charge, through some standard or customary
-means of facilitating copying of software. This Corresponding Source
-shall include the Corresponding Source for any work covered by version 3
-of the GNU General Public License that is incorporated pursuant to the
-following paragraph.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the work with which it is combined will remain governed by version
-3 of the GNU General Public License.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU Affero General Public License from time to time. Such new versions
-will be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU Affero General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU Affero General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU Affero General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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
- (at your option) 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 Affero 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, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If your software can interact with users remotely through a computer
-network, you should also make sure that it provides a way for users to
-get its source. For example, if your program is a web application, its
-interface could display a "Source" link that leads users to an archive
-of the code. There are many ways you could offer source, and different
-solutions will be better for different programs; see section 13 for the
-specific requirements.
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU AGPL, see
-<http://www.gnu.org/licenses/>.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Library/OSRM.h b/Library/OSRM.h
new file mode 100644
index 0000000..16b9977
--- /dev/null
+++ b/Library/OSRM.h
@@ -0,0 +1,52 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef OSRM_H
+#define OSRM_H
+
+#include <osrm/ServerPaths.h>
+
+class OSRM_impl;
+struct RouteParameters;
+
+namespace http
+{
+class Reply;
+}
+
+class OSRM
+{
+ private:
+ OSRM_impl *OSRM_pimpl_;
+
+ public:
+ explicit OSRM(const ServerPaths &paths, const bool use_shared_memory = false);
+ ~OSRM();
+ void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
+};
+
+#endif // OSRM_H
diff --git a/Library/OSRM_impl.cpp b/Library/OSRM_impl.cpp
new file mode 100644
index 0000000..5c20b5a
--- /dev/null
+++ b/Library/OSRM_impl.cpp
@@ -0,0 +1,167 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+namespace boost { namespace interprocess { class named_mutex; } }
+
+#include "OSRM_impl.h"
+#include "OSRM.h"
+
+#include <osrm/Reply.h>
+#include <osrm/RouteParameters.h>
+#include <osrm/ServerPaths.h>
+
+#include "../Plugins/BasePlugin.h"
+#include "../Plugins/DistanceTablePlugin.h"
+#include "../Plugins/HelloWorldPlugin.h"
+#include "../Plugins/LocatePlugin.h"
+#include "../Plugins/NearestPlugin.h"
+#include "../Plugins/TimestampPlugin.h"
+#include "../Plugins/ViaRoutePlugin.h"
+#include "../Server/DataStructures/BaseDataFacade.h"
+#include "../Server/DataStructures/InternalDataFacade.h"
+#include "../Server/DataStructures/SharedBarriers.h"
+#include "../Server/DataStructures/SharedDataFacade.h"
+#include "../Util/SimpleLogger.h"
+
+#include <boost/assert.hpp>
+#include <boost/interprocess/sync/named_condition.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+
+#include <algorithm>
+#include <fstream>
+#include <utility>
+#include <vector>
+
+OSRM_impl::OSRM_impl(const ServerPaths &server_paths, const bool use_shared_memory)
+ : use_shared_memory(use_shared_memory)
+{
+ if (use_shared_memory)
+ {
+ barrier = new SharedBarriers();
+ query_data_facade = new SharedDataFacade<QueryEdge::EdgeData>();
+ }
+ else
+ {
+ query_data_facade = new InternalDataFacade<QueryEdge::EdgeData>(server_paths);
+ }
+
+ // The following plugins handle all requests.
+ RegisterPlugin(new DistanceTablePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
+ RegisterPlugin(new HelloWorldPlugin());
+ RegisterPlugin(new LocatePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
+ RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
+ RegisterPlugin(new TimestampPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
+ RegisterPlugin(new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
+}
+
+OSRM_impl::~OSRM_impl()
+{
+ delete query_data_facade;
+ for (PluginMap::value_type &plugin_pointer : plugin_map)
+ {
+ delete plugin_pointer.second;
+ }
+ if (use_shared_memory)
+ {
+ delete barrier;
+ }
+}
+
+void OSRM_impl::RegisterPlugin(BasePlugin *plugin)
+{
+ SimpleLogger().Write() << "loaded plugin: " << plugin->GetDescriptor();
+ if (plugin_map.find(plugin->GetDescriptor()) != plugin_map.end())
+ {
+ delete plugin_map.find(plugin->GetDescriptor())->second;
+ }
+ plugin_map.emplace(plugin->GetDescriptor(), plugin);
+}
+
+void OSRM_impl::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
+{
+ const PluginMap::const_iterator &iter = plugin_map.find(route_parameters.service);
+
+ if (plugin_map.end() != iter)
+ {
+ reply.status = http::Reply::ok;
+ if (use_shared_memory)
+ {
+ // lock update pending
+ boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
+ barrier->pending_update_mutex);
+
+ // lock query
+ boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
+ barrier->query_mutex);
+
+ // unlock update pending
+ pending_lock.unlock();
+
+ // increment query count
+ ++(barrier->number_of_queries);
+
+ (static_cast<SharedDataFacade<QueryEdge::EdgeData> *>(query_data_facade))
+ ->CheckAndReloadFacade();
+ }
+
+ iter->second->HandleRequest(route_parameters, reply);
+ if (use_shared_memory)
+ {
+ // lock query
+ boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
+ barrier->query_mutex);
+
+ // decrement query count
+ --(barrier->number_of_queries);
+ BOOST_ASSERT_MSG(0 <= barrier->number_of_queries, "invalid number of queries");
+
+ // notify all processes that were waiting for this condition
+ if (0 == barrier->number_of_queries)
+ {
+ barrier->no_running_queries_condition.notify_all();
+ }
+ }
+ }
+ else
+ {
+ reply = http::Reply::StockReply(http::Reply::badRequest);
+ }
+}
+
+// proxy code for compilation firewall
+
+OSRM::OSRM(const ServerPaths &paths, const bool use_shared_memory)
+ : OSRM_pimpl_(new OSRM_impl(paths, use_shared_memory))
+{
+}
+
+OSRM::~OSRM() { delete OSRM_pimpl_; }
+
+void OSRM::RunQuery(RouteParameters &route_parameters, http::Reply &reply)
+{
+ OSRM_pimpl_->RunQuery(route_parameters, reply);
+}
diff --git a/Library/OSRM_impl.h b/Library/OSRM_impl.h
new file mode 100644
index 0000000..8ad98bb
--- /dev/null
+++ b/Library/OSRM_impl.h
@@ -0,0 +1,65 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef OSRM_IMPL_H
+#define OSRM_IMPL_H
+
+class BasePlugin;
+namespace http { class Reply; }
+struct RouteParameters;
+
+#include <osrm/ServerPaths.h>
+
+#include "../DataStructures/QueryEdge.h"
+
+#include <unordered_map>
+#include <string>
+
+struct SharedBarriers;
+template <class EdgeDataT> class BaseDataFacade;
+
+class OSRM_impl
+{
+ private:
+ typedef std::unordered_map<std::string, BasePlugin *> PluginMap;
+
+ public:
+ OSRM_impl(const ServerPaths &paths, const bool use_shared_memory);
+ OSRM_impl(const OSRM_impl &) = delete;
+ virtual ~OSRM_impl();
+ void RunQuery(RouteParameters &route_parameters, http::Reply &reply);
+
+ private:
+ void RegisterPlugin(BasePlugin *plugin);
+ PluginMap plugin_map;
+ bool use_shared_memory;
+ SharedBarriers *barrier;
+ // base class pointer to the objects
+ BaseDataFacade<QueryEdge::EdgeData> *query_data_facade;
+};
+
+#endif // OSRM_IMPL_H
diff --git a/Plugins/BasePlugin.h b/Plugins/BasePlugin.h
index 266d5d8..11c6940 100644
--- a/Plugins/BasePlugin.h
+++ b/Plugins/BasePlugin.h
@@ -1,41 +1,50 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef BASEPLUGIN_H_
#define BASEPLUGIN_H_
-#include <cassert>
+#include "../Util/StringUtil.h"
+
+#include <osrm/Coordinate.h>
+#include <osrm/Reply.h>
+#include <osrm/RouteParameters.h>
+
#include <string>
#include <vector>
-#include "RouteParameters.h"
-#include "../Server/BasicDatastructures.h"
-
-class BasePlugin {
-public:
- BasePlugin() { }
- //Maybe someone can explain the pure virtual destructor thing to me (dennis)
- virtual ~BasePlugin() { }
- virtual std::string GetDescriptor() const = 0;
- virtual std::string GetVersionString() const = 0 ;
- virtual void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) = 0;
+class BasePlugin
+{
+ public:
+ BasePlugin() {}
+ // Maybe someone can explain the pure virtual destructor thing to me (dennis)
+ virtual ~BasePlugin() {}
+ virtual const std::string GetDescriptor() const = 0;
+ virtual void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply) = 0;
};
#endif /* BASEPLUGIN_H_ */
diff --git a/Plugins/DistanceTablePlugin.h b/Plugins/DistanceTablePlugin.h
new file mode 100644
index 0000000..d3e307b
--- /dev/null
+++ b/Plugins/DistanceTablePlugin.h
@@ -0,0 +1,146 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef DISTANCE_TABLE_PLUGIN_H
+#define DISTANCE_TABLE_PLUGIN_H
+
+#include "BasePlugin.h"
+
+#include "../Algorithms/ObjectToBase64.h"
+#include "../DataStructures/JSONContainer.h"
+#include "../DataStructures/QueryEdge.h"
+#include "../DataStructures/SearchEngine.h"
+#include "../Descriptors/BaseDescriptor.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/StringUtil.h"
+#include "../Util/TimingUtil.h"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <unordered_map>
+#include <string>
+#include <vector>
+
+template <class DataFacadeT> class DistanceTablePlugin : public BasePlugin
+{
+ private:
+ std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
+
+ public:
+ explicit DistanceTablePlugin(DataFacadeT *facade) : descriptor_string("table"), facade(facade)
+ {
+ search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
+ }
+
+ virtual ~DistanceTablePlugin() {}
+
+ const std::string GetDescriptor() const { return descriptor_string; }
+
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+ {
+ // check number of parameters
+ if (2 > route_parameters.coordinates.size())
+ {
+ reply = http::Reply::StockReply(http::Reply::badRequest);
+ return;
+ }
+
+ RawRouteData raw_route;
+ raw_route.check_sum = facade->GetCheckSum();
+
+ if (std::any_of(begin(route_parameters.coordinates),
+ end(route_parameters.coordinates),
+ [&](FixedPointCoordinate coordinate)
+ { return !coordinate.isValid(); }))
+ {
+ reply = http::Reply::StockReply(http::Reply::badRequest);
+ return;
+ }
+
+ for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
+ {
+ raw_route.raw_via_node_coordinates.emplace_back(std::move(coordinate));
+ }
+
+ const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
+ unsigned max_locations =
+ std::min(100u, static_cast<unsigned>(raw_route.raw_via_node_coordinates.size()));
+ PhantomNodeArray phantom_node_vector(max_locations);
+ for (unsigned i = 0; i < max_locations; ++i)
+ {
+ if (checksum_OK && i < route_parameters.hints.size() &&
+ !route_parameters.hints[i].empty())
+ {
+ PhantomNode current_phantom_node;
+ DecodeObjectFromBase64(route_parameters.hints[i], current_phantom_node);
+ if (current_phantom_node.isValid(facade->GetNumberOfNodes()))
+ {
+ phantom_node_vector[i].emplace_back(std::move(current_phantom_node));
+ continue;
+ }
+ }
+ facade->IncrementalFindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
+ phantom_node_vector[i],
+ route_parameters.zoom_level,
+ 1);
+
+ BOOST_ASSERT(phantom_node_vector[i].front().isValid(facade->GetNumberOfNodes()));
+ }
+
+ // TIMER_START(distance_table);
+ std::shared_ptr<std::vector<EdgeWeight>> result_table =
+ search_engine_ptr->distance_table(phantom_node_vector);
+ // TIMER_STOP(distance_table);
+
+ if (!result_table)
+ {
+ reply = http::Reply::StockReply(http::Reply::badRequest);
+ return;
+ }
+ JSON::Object json_object;
+ JSON::Array json_array;
+ const unsigned number_of_locations = static_cast<unsigned>(phantom_node_vector.size());
+ for (unsigned row = 0; row < number_of_locations; ++row)
+ {
+ JSON::Array json_row;
+ auto row_begin_iterator = result_table->begin() + (row * number_of_locations);
+ auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_locations);
+ json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator);
+ json_array.values.push_back(json_row);
+ }
+ json_object.values["distance_table"] = json_array;
+ JSON::render(reply.content, json_object);
+ }
+
+ private:
+ std::string descriptor_string;
+ DataFacadeT *facade;
+};
+
+#endif // DISTANCE_TABLE_PLUGIN_H
diff --git a/Plugins/HelloWorldPlugin.h b/Plugins/HelloWorldPlugin.h
index ae0ff64..2d99a10 100644
--- a/Plugins/HelloWorldPlugin.h
+++ b/Plugins/HelloWorldPlugin.h
@@ -1,50 +1,103 @@
/*
- * LocatePlugin.h
- *
- * Created on: 01.01.2011
- * Author: dennis
- */
-#ifndef HELLOWORLDPLUGIN_H_
-#define HELLOWORLDPLUGIN_H_
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-#include <sstream>
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef HELLO_WORLD_PLUGIN_H
+#define HELLO_WORLD_PLUGIN_H
#include "BasePlugin.h"
-#include "RouteParameters.h"
-
-class HelloWorldPlugin : public BasePlugin {
-public:
- HelloWorldPlugin() {}
- virtual ~HelloWorldPlugin() { /*std::cout << GetDescriptor() << " destructor" << std::endl;*/ }
- std::string GetDescriptor() const { return std::string("hello"); }
- std::string GetVersionString() const { return std::string("0.1a"); }
-
- void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
- reply.status = http::Reply::ok;
- reply.content.append("<html><head><title>Hello World Demonstration Document</title></head><body><h1>Hello, World!</h1>");
- std::stringstream content;
- content << "<pre>";
- content << "zoom level: " << routeParameters.zoomLevel << "\n";
- content << "checksum: " << routeParameters.checkSum << "\n";
- content << "instructions: " << (routeParameters.printInstructions ? "yes" : "no") << "\n";
- content << "geometry: " << (routeParameters.geometry ? "yes" : "no") << "\n";
- content << "compression: " << (routeParameters.compression ? "yes" : "no") << "\n";
- content << "output format: " << routeParameters.outputFormat << "\n";
- content << "json parameter: " << routeParameters.jsonpParameter << "\n";
- content << "language: " << routeParameters.language << "<br>";
- content << "Number of locations: " << routeParameters.coordinates.size() << "\n";
- for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
- content << " [" << i << "] " << routeParameters.coordinates[i].lat/100000. << "," << routeParameters.coordinates[i].lon/100000. << "\n";
+#include "../DataStructures/JSONContainer.h"
+#include "../Util/StringUtil.h"
+
+#include <string>
+
+class HelloWorldPlugin : public BasePlugin
+{
+ private:
+ std::string temp_string;
+
+ public:
+ HelloWorldPlugin() : descriptor_string("hello") {}
+ virtual ~HelloWorldPlugin() {}
+ const std::string GetDescriptor() const { return descriptor_string; }
+
+ void HandleRequest(const RouteParameters &routeParameters, http::Reply &reply)
+ {
+ reply.status = http::Reply::ok;
+
+ JSON::Object json_result;
+ std::string temp_string;
+ json_result.values["title"] = "Hello World";
+
+ temp_string = IntToString(routeParameters.zoom_level);
+ json_result.values["zoom_level"] = temp_string;
+
+ temp_string = UintToString(routeParameters.check_sum);
+ json_result.values["check_sum"] = temp_string;
+ json_result.values["instructions"] = (routeParameters.print_instructions ? "yes" : "no");
+ json_result.values["geometry"] = (routeParameters.geometry ? "yes" : "no");
+ json_result.values["compression"] = (routeParameters.compression ? "yes" : "no");
+ json_result.values["output_format"] = (!routeParameters.output_format.empty() ? "yes" : "no");
+
+ json_result.values["jsonp_parameter"] = (!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
+ json_result.values["language"] = (!routeParameters.language.empty() ? "yes" : "no");
+
+ temp_string = UintToString(static_cast<unsigned>(routeParameters.coordinates.size()));
+ json_result.values["location_count"] = temp_string;
+
+ JSON::Array json_locations;
+ unsigned counter = 0;
+ for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
+ {
+ JSON::Object json_location;
+ JSON::Array json_coordinates;
+
+ json_coordinates.values.push_back(coordinate.lat / COORDINATE_PRECISION);
+ json_coordinates.values.push_back(coordinate.lon / COORDINATE_PRECISION);
+ json_location.values[UintToString(counter)] = json_coordinates;
+ json_locations.values.push_back(json_location);
+ ++counter;
}
- content << "Number of hints: " << routeParameters.hints.size() << "\n";
- for(unsigned i = 0; i < routeParameters.hints.size(); ++i) {
- content << " [" << i << "] " << routeParameters.hints[i] << "\n";
+ json_result.values["locations"] = json_locations;
+ json_result.values["hint_count"] = routeParameters.hints.size();
+
+ JSON::Array json_hints;
+ counter = 0;
+ for (const std::string ¤t_hint : routeParameters.hints)
+ {
+ json_hints.values.push_back(current_hint);
+ ++counter;
}
- content << "</pre>";
- reply.content.append(content.str());
- reply.content.append("</body></html>");
- }
+ json_result.values["hints"] = json_hints;
+
+ JSON::render(reply.content, json_result);
+ }
+
+ private:
+ std::string descriptor_string;
};
-#endif /* HELLOWORLDPLUGIN_H_ */
+#endif // HELLO_WORLD_PLUGIN_H
diff --git a/Plugins/LocatePlugin.h b/Plugins/LocatePlugin.h
index f1c7d60..518259d 100644
--- a/Plugins/LocatePlugin.h
+++ b/Plugins/LocatePlugin.h
@@ -1,113 +1,79 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef LOCATEPLUGIN_H_
-#define LOCATEPLUGIN_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef LOCATE_PLUGIN_H
+#define LOCATE_PLUGIN_H
#include "BasePlugin.h"
-#include "RouteParameters.h"
-#include "../DataStructures/NodeInformationHelpDesk.h"
-#include "../Server/DataStructures/QueryObjectsStorage.h"
+#include "../DataStructures/JSONContainer.h"
#include "../Util/StringUtil.h"
-#include <fstream>
+#include <string>
-/*
- * This Plugin locates the nearest node in the road network for a given coordinate.
- */
-class LocatePlugin : public BasePlugin {
-public:
- LocatePlugin(QueryObjectsStorage * objects) {
- nodeHelpDesk = objects->nodeHelpDesk;
- }
- std::string GetDescriptor() const { return std::string("locate"); }
- std::string GetVersionString() const { return std::string("0.3 (DL)"); }
- void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
- //check number of parameters
- if(!routeParameters.coordinates.size()) {
- reply = http::Reply::stockReply(http::Reply::badRequest);
- return;
- }
- if(false == checkCoord(routeParameters.coordinates[0])) {
- reply = http::Reply::stockReply(http::Reply::badRequest);
+// locates the nearest node in the road network for a given coordinate.
+template <class DataFacadeT> class LocatePlugin : public BasePlugin
+{
+ public:
+ explicit LocatePlugin(DataFacadeT *facade) : descriptor_string("locate"), facade(facade) {}
+ const std::string GetDescriptor() const { return descriptor_string; }
+
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+ {
+ // check number of parameters
+ if (route_parameters.coordinates.empty() ||
+ !route_parameters.coordinates.front().isValid())
+ {
+ reply = http::Reply::StockReply(http::Reply::badRequest);
return;
}
- //query to helpdesk
- _Coordinate result;
- std::string tmp;
- //json
-
-// JSONParameter = routeParameters.options.Find("jsonp");
- if("" != routeParameters.jsonpParameter) {
- reply.content += routeParameters.jsonpParameter;
- reply.content += "(";
+ JSON::Object json_result;
+ FixedPointCoordinate result;
+ if (!facade->LocateClosestEndPointForCoordinate(route_parameters.coordinates.front(),
+ result))
+ {
+ json_result.values["status"] = 207;
}
- reply.status = http::Reply::ok;
- reply.content += ("{");
- reply.content += ("\"version\":0.3,");
- if(!nodeHelpDesk->FindNearestNodeCoordForLatLon(routeParameters.coordinates[0], result)) {
- reply.content += ("\"status\":207,");
- reply.content += ("\"mapped_coordinate\":[]");
- } else {
- //Write coordinate to stream
+ else
+ {
reply.status = http::Reply::ok;
- reply.content += ("\"status\":0,");
- reply.content += ("\"mapped_coordinate\":");
- convertInternalLatLonToString(result.lat, tmp);
- reply.content += "[";
- reply.content += tmp;
- convertInternalLatLonToString(result.lon, tmp);
- reply.content += ",";
- reply.content += tmp;
- reply.content += "]";
- }
- reply.content += ",\"transactionId\": \"OSRM Routing Engine JSON Locate (v0.3)\"";
- reply.content += ("}");
- reply.headers.resize(3);
- if("" != routeParameters.jsonpParameter) {
- reply.content += ")";
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "text/javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"location.js\"";
- } else {
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "application/x-javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"location.json\"";
+ json_result.values["status"] = 0;
+ JSON::Array json_coordinate;
+ json_coordinate.values.push_back(result.lat/COORDINATE_PRECISION);
+ json_coordinate.values.push_back(result.lon/COORDINATE_PRECISION);
+ json_result.values["mapped_coordinate"] = json_coordinate;
}
- reply.headers[0].name = "Content-Length";
- intToString(reply.content.size(), tmp);
- reply.headers[0].value = tmp;
- return;
- }
-private:
- inline bool checkCoord(const _Coordinate & c) {
- if(c.lat > 90*100000 || c.lat < -90*100000 || c.lon > 180*100000 || c.lon <-180*100000) {
- return false;
- }
- return true;
+
+ JSON::render(reply.content, json_result);
}
- NodeInformationHelpDesk * nodeHelpDesk;
+ private:
+ std::string descriptor_string;
+ DataFacadeT *facade;
};
-#endif /* LOCATEPLUGIN_H_ */
+#endif /* LOCATE_PLUGIN_H */
diff --git a/Plugins/NearestPlugin.h b/Plugins/NearestPlugin.h
index c10230f..27bd016 100644
--- a/Plugins/NearestPlugin.h
+++ b/Plugins/NearestPlugin.h
@@ -1,124 +1,91 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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 NearestPlugin_H_
-#define NearestPlugin_H_
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-#include <fstream>
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-#include "BasePlugin.h"
-#include "RouteParameters.h"
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "../Server/DataStructures/QueryObjectsStorage.h"
+*/
-#include "../DataStructures/NodeInformationHelpDesk.h"
-#include "../Util/StringUtil.h"
+#ifndef NEAREST_PLUGIN_H
+#define NEAREST_PLUGIN_H
+
+#include "BasePlugin.h"
+#include "../DataStructures/JSONContainer.h"
+#include "../DataStructures/PhantomNodes.h"
+
+#include <string>
/*
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
*/
-class NearestPlugin : public BasePlugin {
-public:
- NearestPlugin(QueryObjectsStorage * objects) : names(objects->names) {
- nodeHelpDesk = objects->nodeHelpDesk;
- descriptorTable.Set("", 0); //default descriptor
- descriptorTable.Set("json", 1);
- }
- std::string GetDescriptor() const { return std::string("nearest"); }
- std::string GetVersionString() const { return std::string("0.3 (DL)"); }
- void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
- //check number of parameters
- if(!routeParameters.coordinates.size()) {
- reply = http::Reply::stockReply(http::Reply::badRequest);
- return;
- }
- if(false == checkCoord(routeParameters.coordinates[0])) {
- reply = http::Reply::stockReply(http::Reply::badRequest);
+template <class DataFacadeT> class NearestPlugin : public BasePlugin
+{
+ public:
+ explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") {}
+
+ const std::string GetDescriptor() const { return descriptor_string; }
+
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+ {
+ // check number of parameters
+ if (route_parameters.coordinates.empty() || !route_parameters.coordinates.front().isValid())
+ {
+ reply = http::Reply::StockReply(http::Reply::badRequest);
return;
}
- //query to helpdesk
- PhantomNode result;
- nodeHelpDesk->FindPhantomNodeForCoordinate(routeParameters.coordinates[0], result, routeParameters.zoomLevel);
+ std::vector<PhantomNode> phantom_node_vector;
+ facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates.front(),
+ phantom_node_vector,
+ route_parameters.zoom_level,
+ 1);
- std::string tmp;
- //json
-
- if("" != routeParameters.jsonpParameter) {
- reply.content += routeParameters.jsonpParameter;
- reply.content += "(";
+ JSON::Object json_result;
+ if (phantom_node_vector.empty() || !phantom_node_vector.front().isValid())
+ {
+ json_result.values["status"] = 207;
}
-
- reply.status = http::Reply::ok;
- reply.content += ("{");
- reply.content += ("\"version\":0.3,");
- reply.content += ("\"status\":");
- if(UINT_MAX != result.edgeBasedNode)
- reply.content += "0,";
else
- reply.content += "207,";
- reply.content += ("\"mapped_coordinate\":");
- reply.content += "[";
- if(UINT_MAX != result.edgeBasedNode) {
- convertInternalLatLonToString(result.location.lat, tmp);
- reply.content += tmp;
- convertInternalLatLonToString(result.location.lon, tmp);
- reply.content += ",";
- reply.content += tmp;
+ {
+ reply.status = http::Reply::ok;
+ json_result.values["status"] = 0;
+ JSON::Array json_coordinate;
+ json_coordinate.values.push_back(phantom_node_vector.front().location.lat /
+ COORDINATE_PRECISION);
+ json_coordinate.values.push_back(phantom_node_vector.front().location.lon /
+ COORDINATE_PRECISION);
+ json_result.values["mapped_coordinate"] = json_coordinate;
+ std::string temp_string;
+ facade->GetName(phantom_node_vector.front().name_id, temp_string);
+ json_result.values["name"] = temp_string;
}
- reply.content += "],";
- reply.content += "\"name\":\"";
- if(UINT_MAX != result.edgeBasedNode)
- reply.content += names[result.nodeBasedEdgeNameID];
- reply.content += "\"";
- reply.content += ",\"transactionId\":\"OSRM Routing Engine JSON Nearest (v0.3)\"";
- reply.content += ("}");
- reply.headers.resize(3);
- if("" != routeParameters.jsonpParameter) {
- reply.content += ")";
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "text/javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"location.js\"";
- } else {
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "application/x-javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"location.json\"";
- }
- reply.headers[0].name = "Content-Length";
- intToString(reply.content.size(), tmp);
- reply.headers[0].value = tmp;
- }
-private:
- inline bool checkCoord(const _Coordinate & c) {
- if(c.lat > 90*100000 || c.lat < -90*100000 || c.lon > 180*100000 || c.lon <-180*100000) {
- return false;
- }
- return true;
+
+ JSON::render(reply.content, json_result);
}
- NodeInformationHelpDesk * nodeHelpDesk;
- HashTable<std::string, unsigned> descriptorTable;
- std::vector<std::string> & names;
+ private:
+ DataFacadeT *facade;
+ std::string descriptor_string;
};
-#endif /* NearestPlugin_H_ */
+#endif /* NEAREST_PLUGIN_H */
diff --git a/Plugins/PluginMapFactory.h b/Plugins/PluginMapFactory.h
deleted file mode 100644
index 9027b18..0000000
--- a/Plugins/PluginMapFactory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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 PLUGINMAPFACTORY_H_
-#define PLUGINMAPFACTORY_H_
-
-//#include "../DataStructures/HashTable.h"
-//#include "../Plugins/BasePlugin.h"
-//
-//struct PluginMapFactory {
-// static HashTable<std::string, BasePlugin *> * CreatePluginMap() {
-// HashTable<std::string, BasePlugin *> * map = new HashTable<std::string, BasePlugin *>();
-//
-// }
-//};
-
-#endif /* PLUGINMAPFACTORY_H_ */
diff --git a/Plugins/RawRouteData.h b/Plugins/RawRouteData.h
deleted file mode 100644
index f0c1054..0000000
--- a/Plugins/RawRouteData.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- 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 RAWROUTEDATA_H_
-#define RAWROUTEDATA_H_
-
-#include "../typedefs.h"
-
-struct _PathData {
- _PathData(NodeID no, unsigned na, unsigned tu, unsigned dur) : node(no), nameID(na), durationOfSegment(dur), turnInstruction(tu) { }
- NodeID node;
- unsigned nameID;
- unsigned durationOfSegment;
- short turnInstruction;
-};
-
-struct RawRouteData {
- std::vector< _PathData > computedShortestPath;
- std::vector< _PathData > computedAlternativePath;
- std::vector< PhantomNodes > segmentEndCoordinates;
- std::vector< _Coordinate > rawViaNodeCoordinates;
- unsigned checkSum;
- int lengthOfShortestPath;
- int lengthOfAlternativePath;
- RawRouteData() : checkSum(UINT_MAX), lengthOfShortestPath(INT_MAX), lengthOfAlternativePath(INT_MAX) {}
-};
-
-#endif /* RAWROUTEDATA_H_ */
diff --git a/Plugins/RouteParameters.h b/Plugins/RouteParameters.h
deleted file mode 100644
index a718f96..0000000
--- a/Plugins/RouteParameters.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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 ROUTE_PARAMETERS_H
-#define ROUTE_PARAMETERS_H
-
-#include <string>
-#include <vector>
-
-#include <boost/fusion/sequence/intrinsic.hpp>
-
-#include "../DataStructures/Coordinate.h"
-
-struct RouteParameters {
- RouteParameters() : zoomLevel(18), printInstructions(false), alternateRoute(true), geometry(true), compression(true), deprecatedAPI(false), checkSum(-1) {}
- short zoomLevel;
- bool printInstructions;
- bool alternateRoute;
- bool geometry;
- bool compression;
- bool deprecatedAPI;
- unsigned checkSum;
- std::string service;
- std::string outputFormat;
- std::string jsonpParameter;
- std::string language;
- std::vector<std::string> hints;
- std::vector<_Coordinate> coordinates;
- typedef HashTable<std::string, std::string>::MyIterator OptionsIterator;
-
- void setZoomLevel(const short i) {
- if (18 > i && 0 < i)
- zoomLevel = i;
- }
-
- void setAlternateRouteFlag(const bool b) {
- alternateRoute = b;
- }
-
- void setDeprecatedAPIFlag(const std::string &) {
- deprecatedAPI = true;
- }
-
- void setChecksum(const unsigned c) {
- checkSum = c;
- }
-
- void setInstructionFlag(const bool b) {
- printInstructions = b;
- }
-
- void setService( const std::string & s) {
- service = s;
- }
-
- void setOutputFormat(const std::string & s) {
- outputFormat = s;
- }
-
- void setJSONpParameter(const std::string & s) {
- jsonpParameter = s;
- }
-
- void addHint(const std::string & s) {
- hints.resize(coordinates.size());
- hints.back() = s;
- }
-
- void setLanguage(const std::string & s) {
- language = s;
- }
-
- void setGeometryFlag(const bool b) {
- geometry = b;
- }
-
- void setCompressionFlag(const bool b) {
- compression = b;
- }
-
- void addCoordinate(boost::fusion::vector < double, double > arg_) {
- int lat = 100000.*boost::fusion::at_c < 0 > (arg_);
- int lon = 100000.*boost::fusion::at_c < 1 > (arg_);
- _Coordinate myCoordinate(lat, lon);
- coordinates.push_back(_Coordinate(lat, lon));
- }
-};
-
-
-#endif /*ROUTE_PARAMETERS_H*/
diff --git a/Plugins/TimestampPlugin.h b/Plugins/TimestampPlugin.h
index 33c606e..63f63b2 100644
--- a/Plugins/TimestampPlugin.h
+++ b/Plugins/TimestampPlugin.h
@@ -1,75 +1,59 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef TIMESTAMPPLUGIN_H_
-#define TIMESTAMPPLUGIN_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <cassert>
+*/
-#include "BasePlugin.h"
-#include "RouteParameters.h"
+#ifndef TIMESTAMP_PLUGIN_H
+#define TIMESTAMP_PLUGIN_H
-class TimestampPlugin : public BasePlugin {
-public:
- TimestampPlugin(QueryObjectsStorage * o) : objects(o) {
- }
- std::string GetDescriptor() const { return std::string("timestamp"); }
- std::string GetVersionString() const { return std::string("0.3 (DL)"); }
- void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
- std::string tmp;
+#include "../DataStructures/JSONContainer.h"
+#include "BasePlugin.h"
- //json
- if("" != routeParameters.jsonpParameter) {
- reply.content += routeParameters.jsonpParameter;
- reply.content += "(";
- }
+#include <string>
+template <class DataFacadeT> class TimestampPlugin : public BasePlugin
+{
+ public:
+ explicit TimestampPlugin(const DataFacadeT *facade)
+ : facade(facade), descriptor_string("timestamp")
+ {
+ }
+ const std::string GetDescriptor() const { return descriptor_string; }
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+ {
reply.status = http::Reply::ok;
- reply.content += ("{");
- reply.content += ("\"version\":0.3,");
- reply.content += ("\"status\":");
- reply.content += "0,";
- reply.content += ("\"timestamp\":\"");
- reply.content += objects->timestamp;
- reply.content += "\"";
- reply.content += ",\"transactionId\":\"OSRM Routing Engine JSON timestamp (v0.3)\"";
- reply.content += ("}");
- reply.headers.resize(3);
- if("" != routeParameters.jsonpParameter) {
- reply.content += ")";
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "text/javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"timestamp.js\"";
- } else {
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "application/x-javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"timestamp.json\"";
- }
- reply.headers[0].name = "Content-Length";
- intToString(reply.content.size(), tmp);
- reply.headers[0].value = tmp;
+ JSON::Object json_result;
+ json_result.values["status"] = 0;
+ const std::string timestamp = facade->GetTimestamp();
+ json_result.values["timestamp"] = timestamp;
+ JSON::render(reply.content, json_result);
}
-private:
- QueryObjectsStorage * objects;
+
+ private:
+ const DataFacadeT *facade;
+ std::string descriptor_string;
};
-#endif /* TIMESTAMPPLUGIN_H_ */
+#endif /* TIMESTAMP_PLUGIN_H */
diff --git a/Plugins/ViaRoutePlugin.h b/Plugins/ViaRoutePlugin.h
index 8249d99..b82d514 100644
--- a/Plugins/ViaRoutePlugin.h
+++ b/Plugins/ViaRoutePlugin.h
@@ -1,224 +1,173 @@
-/*
- 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 VIAROUTEPLUGIN_H_
-#define VIAROUTEPLUGIN_H_
-
-#include <cstdlib>
-#include <fstream>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "BasePlugin.h"
-#include "RouteParameters.h"
-
-#include "../Algorithms/ObjectToBase64.h"
-
-#include "../Descriptors/BaseDescriptor.h"
-#include "../Descriptors/GPXDescriptor.h"
-#include "../Descriptors/JSONDescriptor.h"
-
-#include "../DataStructures/HashTable.h"
-#include "../DataStructures/QueryEdge.h"
-#include "../DataStructures/StaticGraph.h"
-#include "../DataStructures/SearchEngine.h"
-
-#include "../Util/StringUtil.h"
-
-#include "../Server/DataStructures/QueryObjectsStorage.h"
-
-class ViaRoutePlugin : public BasePlugin {
-private:
- NodeInformationHelpDesk * nodeHelpDesk;
- std::vector<std::string> & names;
- StaticGraph<QueryEdge::EdgeData> * graph;
- HashTable<std::string, unsigned> descriptorTable;
- std::string pluginDescriptorString;
- SearchEngine * searchEnginePtr;
-public:
-
- ViaRoutePlugin(QueryObjectsStorage * objects, std::string psd = "viaroute") : names(objects->names), pluginDescriptorString(psd) {
- nodeHelpDesk = objects->nodeHelpDesk;
- graph = objects->graph;
-
- searchEnginePtr = new SearchEngine(graph, nodeHelpDesk, names);
-
- descriptorTable.Set("", 0); //default descriptor
- descriptorTable.Set("json", 0);
- descriptorTable.Set("gpx", 1);
- }
-
- virtual ~ViaRoutePlugin() {
- delete searchEnginePtr;
- }
-
- std::string GetDescriptor() const { return pluginDescriptorString; }
- std::string GetVersionString() const { return std::string("0.3 (DL)"); }
- void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) {
- //check number of parameters
- if( 2 > routeParameters.coordinates.size() ) {
- reply = http::Reply::stockReply(http::Reply::badRequest);
- return;
- }
-
- RawRouteData rawRoute;
- rawRoute.checkSum = nodeHelpDesk->GetCheckSum();
- bool checksumOK = (routeParameters.checkSum == rawRoute.checkSum);
- std::vector<std::string> textCoord;
- for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) {
- if(false == checkCoord(routeParameters.coordinates[i])) {
- reply = http::Reply::stockReply(http::Reply::badRequest);
- return;
- }
- rawRoute.rawViaNodeCoordinates.push_back(routeParameters.coordinates[i]);
- }
- std::vector<PhantomNode> phantomNodeVector(rawRoute.rawViaNodeCoordinates.size());
- for(unsigned i = 0; i < rawRoute.rawViaNodeCoordinates.size(); ++i) {
- if(checksumOK && i < routeParameters.hints.size() && "" != routeParameters.hints[i]) {
-// INFO("Decoding hint: " << routeParameters.hints[i] << " for location index " << i);
- DecodeObjectFromBase64(phantomNodeVector[i], routeParameters.hints[i]);
- if(phantomNodeVector[i].isValid(nodeHelpDesk->getNumberOfNodes())) {
-// INFO("Decoded hint " << i << " successfully");
- continue;
- }
- }
-// INFO("Brute force lookup of coordinate " << i);
- searchEnginePtr->FindPhantomNodeForCoordinate( rawRoute.rawViaNodeCoordinates[i], phantomNodeVector[i], routeParameters.zoomLevel);
- }
-
- for(unsigned i = 0; i < phantomNodeVector.size()-1; ++i) {
- PhantomNodes segmentPhantomNodes;
- segmentPhantomNodes.startPhantom = phantomNodeVector[i];
- segmentPhantomNodes.targetPhantom = phantomNodeVector[i+1];
- rawRoute.segmentEndCoordinates.push_back(segmentPhantomNodes);
- }
- if( ( routeParameters.alternateRoute ) && (1 == rawRoute.segmentEndCoordinates.size()) ) {
-// INFO("Checking for alternative paths");
- searchEnginePtr->alternativePaths(rawRoute.segmentEndCoordinates[0], rawRoute);
-
- } else {
- searchEnginePtr->shortestPath(rawRoute.segmentEndCoordinates, rawRoute);
- }
-
-
- if(INT_MAX == rawRoute.lengthOfShortestPath ) {
- DEBUG( "Error occurred, single path not found" );
- }
- reply.status = http::Reply::ok;
-
- //TODO: Move to member as smart pointer
- BaseDescriptor * desc;
- if("" != routeParameters.jsonpParameter) {
- reply.content += routeParameters.jsonpParameter;
- reply.content += "(";
- }
-
- _DescriptorConfig descriptorConfig;
- unsigned descriptorType = descriptorTable[routeParameters.outputFormat];
- descriptorConfig.z = routeParameters.zoomLevel;
- descriptorConfig.instructions = routeParameters.printInstructions;
- descriptorConfig.geometry = routeParameters.geometry;
- descriptorConfig.encodeGeometry = routeParameters.compression;
-
- switch(descriptorType){
- case 0:
- desc = new JSONDescriptor();
-
- break;
- case 1:
- desc = new GPXDescriptor();
-
- break;
- default:
- desc = new JSONDescriptor();
-
- break;
- }
-
- PhantomNodes phantomNodes;
- phantomNodes.startPhantom = rawRoute.segmentEndCoordinates[0].startPhantom;
-// INFO("Start location: " << phantomNodes.startPhantom.location)
- phantomNodes.targetPhantom = rawRoute.segmentEndCoordinates[rawRoute.segmentEndCoordinates.size()-1].targetPhantom;
-// INFO("TargetLocation: " << phantomNodes.targetPhantom.location);
-// INFO("Number of segments: " << rawRoute.segmentEndCoordinates.size());
- desc->SetConfig(descriptorConfig);
-
- desc->Run(reply, rawRoute, phantomNodes, *searchEnginePtr);
- if("" != routeParameters.jsonpParameter) {
- reply.content += ")\n";
- }
- reply.headers.resize(3);
- reply.headers[0].name = "Content-Length";
- std::string tmp;
- intToString(reply.content.size(), tmp);
- reply.headers[0].value = tmp;
- switch(descriptorType){
- case 0:
- if("" != routeParameters.jsonpParameter){
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "text/javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"route.js\"";
- } else {
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "application/x-javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"route.json\"";
- }
-
- break;
- case 1:
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "application/gpx+xml; charset=UTF-8";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"route.gpx\"";
-
- break;
- default:
- if("" != routeParameters.jsonpParameter){
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "text/javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"route.js\"";
- } else {
- reply.headers[1].name = "Content-Type";
- reply.headers[1].value = "application/x-javascript";
- reply.headers[2].name = "Content-Disposition";
- reply.headers[2].value = "attachment; filename=\"route.json\"";
- }
-
- break;
- }
-
- delete desc;
- return;
- }
-private:
- inline bool checkCoord(const _Coordinate & c) {
- if(c.lat > 90*100000 || c.lat < -90*100000 || c.lon > 180*100000 || c.lon <-180*100000) {
- return false;
- }
- return true;
- }
-};
-
-
-#endif /* VIAROUTEPLUGIN_H_ */
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef VIA_ROUTE_PLUGIN_H
+#define VIA_ROUTE_PLUGIN_H
+
+#include "BasePlugin.h"
+
+#include "../Algorithms/ObjectToBase64.h"
+
+#include "../DataStructures/QueryEdge.h"
+#include "../DataStructures/SearchEngine.h"
+#include "../Descriptors/BaseDescriptor.h"
+#include "../Descriptors/GPXDescriptor.h"
+#include "../Descriptors/JSONDescriptor.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/StringUtil.h"
+#include "../Util/TimingUtil.h"
+
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+#include <unordered_map>
+#include <string>
+#include <vector>
+
+template <class DataFacadeT> class ViaRoutePlugin : public BasePlugin
+{
+ private:
+ std::unordered_map<std::string, unsigned> descriptor_table;
+ std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
+
+ public:
+ explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
+ {
+ search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
+
+ descriptor_table.emplace("json", 0);
+ descriptor_table.emplace("gpx", 1);
+ // descriptor_table.emplace("geojson", 2);
+ }
+
+ virtual ~ViaRoutePlugin() {}
+
+ const std::string GetDescriptor() const { return descriptor_string; }
+
+ void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply)
+ {
+ // check number of parameters
+ if (2 > route_parameters.coordinates.size() ||
+ std::any_of(begin(route_parameters.coordinates),
+ end(route_parameters.coordinates),
+ [&](FixedPointCoordinate coordinate)
+ { return !coordinate.isValid(); }))
+ {
+ reply = http::Reply::StockReply(http::Reply::badRequest);
+ return;
+ }
+
+ RawRouteData raw_route;
+ raw_route.check_sum = facade->GetCheckSum();
+ for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
+ {
+ raw_route.raw_via_node_coordinates.emplace_back(coordinate);
+ }
+
+ std::vector<PhantomNode> phantom_node_vector(raw_route.raw_via_node_coordinates.size());
+ const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
+
+ for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i)
+ {
+ if (checksum_OK && i < route_parameters.hints.size() &&
+ !route_parameters.hints[i].empty())
+ {
+ DecodeObjectFromBase64(route_parameters.hints[i], phantom_node_vector[i]);
+ if (phantom_node_vector[i].isValid(facade->GetNumberOfNodes()))
+ {
+ continue;
+ }
+ }
+ facade->FindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
+ phantom_node_vector[i],
+ route_parameters.zoom_level);
+ }
+
+ PhantomNodes current_phantom_node_pair;
+ for (unsigned i = 0; i < phantom_node_vector.size() - 1; ++i)
+ {
+ current_phantom_node_pair.source_phantom = phantom_node_vector[i];
+ current_phantom_node_pair.target_phantom = phantom_node_vector[i + 1];
+ raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
+ }
+
+ const bool is_alternate_requested = route_parameters.alternate_route;
+ const bool is_only_one_segment = (1 == raw_route.segment_end_coordinates.size());
+ if (is_alternate_requested && is_only_one_segment)
+ {
+ search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
+ raw_route);
+ }
+ else
+ {
+ search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, raw_route);
+ }
+
+ if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
+ {
+ SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
+ }
+ reply.status = http::Reply::ok;
+
+ DescriptorConfig descriptor_config;
+
+ auto iter = descriptor_table.find(route_parameters.output_format);
+ unsigned descriptor_type = (iter != descriptor_table.end() ? iter->second : 0);
+
+ descriptor_config.zoom_level = route_parameters.zoom_level;
+ descriptor_config.instructions = route_parameters.print_instructions;
+ descriptor_config.geometry = route_parameters.geometry;
+ descriptor_config.encode_geometry = route_parameters.compression;
+
+ std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
+ switch (descriptor_type)
+ {
+ // case 0:
+ // descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
+ // break;
+ case 1:
+ descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(facade);
+ break;
+ // case 2:
+ // descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
+ // break;
+ default:
+ descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(facade);
+ break;
+ }
+
+ descriptor->SetConfig(descriptor_config);
+ descriptor->Run(raw_route, reply);
+ }
+
+ private:
+ std::string descriptor_string;
+ DataFacadeT *facade;
+};
+
+#endif // VIA_ROUTE_PLUGIN_H
diff --git a/README.TXT b/README.md
similarity index 52%
rename from README.TXT
rename to README.md
index a8ae177..1c77f72 100644
--- a/README.TXT
+++ b/README.md
@@ -1,3 +1,5 @@
+# Readme
+
For instructions on how to compile and run OSRM, please consult the Wiki at
https://github.com/DennisOSRM/Project-OSRM/wiki
@@ -6,8 +8,11 @@ or use our free and daily updated online service at
http://map.project-osrm.org
-When using the code in a scientific publication, please cite
+## References in publications
+
+When using the code in a (scientific) publication, please cite
+```
@inproceedings{luxen-vetter-2011,
author = {Luxen, Dennis and Vetter, Christian},
title = {Real-time routing with OpenStreetMap data},
@@ -23,5 +28,13 @@ When using the code in a scientific publication, please cite
acmid = {2094062},
publisher = {ACM},
address = {New York, NY, USA},
-}
+}
+```
+
+## Current build status
+| build config | branch | status |
+|:-------------|:--------|:------------|
+| Project OSRM | master | [![Build Status](https://travis-ci.org/DennisOSRM/Project-OSRM.png?branch=master)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
+| Project OSRM | develop | [![Build Status](https://travis-ci.org/DennisOSRM/Project-OSRM.png?branch=develop)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
+| LUAbind fork | master | [![Build Status](https://travis-ci.org/DennisOSRM/luabind.png?branch=master)](https://travis-ci.org/DennisOSRM/luabind) |
diff --git a/Rakefile b/Rakefile
index ccbb0cb..1c2ce9d 100644
--- a/Rakefile
+++ b/Rakefile
@@ -6,7 +6,7 @@ require 'sys/proctable'
BUILD_FOLDER = 'build'
DATA_FOLDER = 'sandbox'
-PROFILE = 'bicycle'
+PROFILE = 'examples/postgis'
OSRM_PORT = 5000
PROFILES_FOLDER = '../profiles'
@@ -59,47 +59,27 @@ def wait_for_shutdown name
raise "*** Could not terminate #{name}."
end
-def write_server_ini osm_file
- s=<<-EOF
- Threads = 1
- IP = 0.0.0.0
- Port = #{OSRM_PORT}
-
- hsgrData=#{osm_file}.osrm.hsgr
- nodesData=#{osm_file}.osrm.nodes
- edgesData=#{osm_file}.osrm.edges
- ramIndex=#{osm_file}.osrm.ramIndex
- fileIndex=#{osm_file}.osrm.fileIndex
- namesData=#{osm_file}.osrm.names
- timestamp=#{osm_file}.osrm.timestamp
- EOF
- File.open( 'server.ini', 'w') {|f| f.write( s ) }
-end
-
desc "Rebuild and run tests."
task :default => [:build]
desc "Build using CMake."
task :build do
- Dir.chdir BUILD_FOLDER do
- system "make"
+ if Dir.exists? BUILD_FOLDER
+ Dir.chdir BUILD_FOLDER do
+ system "make"
+ end
+ else
+ system "mkdir build; cd build; cmake ..; make"
end
end
desc "Setup config files."
task :setup do
- Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}"
- ['server.ini','extractor.ini','contractor.ini'].each do |file|
- unless File.exist? "#{DATA_FOLDER}/#{file}"
- puts "Copying #{file} template to #{DATA_FOLDER}/#{file}"
- FileUtils.cp file, "#{DATA_FOLDER}/#{file}"
- end
- end
end
desc "Download OSM data."
-task :download => :setup do
+task :download do
Dir.mkdir "#{DATA_FOLDER}" unless File.exist? "#{DATA_FOLDER}"
puts "Downloading..."
puts "curl http://download.geofabrik.de/europe/#{osm_data_country}-latest.osm.pbf -o #{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
@@ -118,26 +98,20 @@ task :crop do
end
desc "Reprocess OSM data."
-task :process => :setup do
- Dir.chdir DATA_FOLDER do
- 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 "../#{BUILD_FOLDER}/osrm-prepare #{osm_data_area_name}.osrm #{osm_data_area_name}.osrm.restrictions #{PROFILES_FOLDER}/#{PROFILE}.lua"
- puts
- end
+task :process => [:extract,:prepare] do
end
desc "Extract OSM data."
-task :extract => :setup do
+task :extract do
Dir.chdir DATA_FOLDER do
- raise "Error while extracting data." unless system "../#{BUILD_FOLDER}/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 --profile ../profiles/#{PROFILE}.lua"
end
end
desc "Prepare OSM data."
-task :prepare => :setup do
+task :prepare do
Dir.chdir DATA_FOLDER do
- 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"
+ raise "Error while preparing data." unless system "../#{BUILD_FOLDER}/osrm-prepare #{osm_data_area_name}.osrm --profile ../profiles/#{PROFILE}.lua"
end
end
@@ -154,19 +128,17 @@ task :test do
end
desc "Run the routing server in the terminal. Press Ctrl-C to stop."
-task :run => :setup do
+task :run do
Dir.chdir DATA_FOLDER do
- write_server_ini osm_data_area_name
- system "../#{BUILD_FOLDER}/osrm-routed"
+ system "../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT}"
end
end
desc "Launch the routing server in the background. Use rake:down to stop it."
-task :up => :setup do
+task :up do
Dir.chdir DATA_FOLDER do
abort("Already up.") if up?
- write_server_ini osm_data_area_name
- pipe = IO.popen("../#{BUILD_FOLDER}/osrm-routed 1>>osrm-routed.log 2>>osrm-routed.log")
+ pipe = IO.popen("../#{BUILD_FOLDER}/osrm-routed #{osm_data_area_name}.osrm --port #{OSRM_PORT} 1>>osrm-routed.log 2>>osrm-routed.log")
timeout = 5
(timeout*10).times do
begin
diff --git a/RoutingAlgorithms/AlternativePathRouting.h b/RoutingAlgorithms/AlternativePathRouting.h
index 4cd256b..3506f93 100644
--- a/RoutingAlgorithms/AlternativePathRouting.h
+++ b/RoutingAlgorithms/AlternativePathRouting.h
@@ -1,535 +1,858 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef ALTERNATIVEROUTES_H_
-#define ALTERNATIVEROUTES_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <boost/unordered_map.hpp>
-#include <vector>
-#include <cmath>
+*/
+
+#ifndef ALTERNATIVE_PATH_ROUTING_H
+#define ALTERNATIVE_PATH_ROUTING_H
#include "BasicRoutingInterface.h"
+#include "../DataStructures/SearchEngineData.h"
+
+#include <boost/assert.hpp>
+
+#include <unordered_map>
+#include <vector>
-const double VIAPATH_ALPHA = 0.15;
-const double VIAPATH_EPSILON = 0.10; //alternative at most 15% longer
-const double VIAPATH_GAMMA = 0.75; //alternative shares at most 75% with the shortest.
+const double VIAPATH_ALPHA = 0.10;
+const double VIAPATH_EPSILON = 0.15; // alternative at most 15% longer
+const double VIAPATH_GAMMA = 0.75; // alternative shares at most 75% with the shortest.
-template<class QueryDataT>
-class AlternativeRouting : private BasicRoutingInterface<QueryDataT> {
- typedef BasicRoutingInterface<QueryDataT> super;
- typedef typename QueryDataT::Graph SearchGraph;
- typedef typename QueryDataT::QueryHeap QueryHeap;
+template <class DataFacadeT> class AlternativeRouting : private BasicRoutingInterface<DataFacadeT>
+{
+ typedef BasicRoutingInterface<DataFacadeT> super;
+ typedef typename DataFacadeT::EdgeData EdgeData;
+ typedef SearchEngineData::QueryHeap QueryHeap;
typedef std::pair<NodeID, NodeID> SearchSpaceEdge;
- struct RankedCandidateNode {
- RankedCandidateNode(const NodeID n, const int l, const int s) : node(n), length(l), sharing(s) {}
+ struct RankedCandidateNode
+ {
+ RankedCandidateNode(const NodeID node, const int length, const int sharing)
+ : node(node), length(length), sharing(sharing)
+ {
+ }
+
NodeID node;
int length;
int sharing;
- bool operator<(const RankedCandidateNode& other) const {
- return (2*length + sharing) < (2*other.length + other.sharing);
+
+ bool operator<(const RankedCandidateNode &other) const
+ {
+ return (2 * length + sharing) < (2 * other.length + other.sharing);
}
};
+ DataFacadeT *facade;
+ SearchEngineData &engine_working_data;
- const SearchGraph * search_graph;
-
-public:
-
- AlternativeRouting(QueryDataT & qd) : super(qd), search_graph(qd.graph) { }
-
- ~AlternativeRouting() {}
+ public:
+ AlternativeRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
+ : super(facade), facade(facade), engine_working_data(engine_working_data)
+ {
+ }
- void operator()(const PhantomNodes & phantomNodePair, RawRouteData & rawRouteData) {
- if(!phantomNodePair.AtLeastOnePhantomNodeIsUINTMAX() || phantomNodePair.PhantomNodesHaveEqualLocation()) {
- rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX;
- return;
- }
+ virtual ~AlternativeRouting() {}
- std::vector<NodeID> alternativePath;
- std::vector<NodeID> viaNodeCandidates;
+ void operator()(const PhantomNodes &phantom_node_pair, RawRouteData &raw_route_data)
+ {
+ std::vector<NodeID> alternative_path;
+ std::vector<NodeID> via_node_candidate_list;
std::vector<SearchSpaceEdge> forward_search_space;
std::vector<SearchSpaceEdge> reverse_search_space;
- //Initialize Queues, semi-expensive because access to TSS invokes a system call
- super::_queryData.InitializeOrClearFirstThreadLocalStorage();
- super::_queryData.InitializeOrClearSecondThreadLocalStorage();
- super::_queryData.InitializeOrClearThirdThreadLocalStorage();
-
- QueryHeap & forward_heap1 = *(super::_queryData.forwardHeap);
- QueryHeap & reverse_heap1 = *(super::_queryData.backwardHeap);
- QueryHeap & forward_heap2 = *(super::_queryData.forwardHeap2);
- QueryHeap & reverse_heap2 = *(super::_queryData.backwardHeap2);
-
- int upper_bound_to_shortest_path_distance = INT_MAX;
- NodeID middle_node = UINT_MAX;
- forward_heap1.Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
- if(phantomNodePair.startPhantom.isBidirected() ) {
- forward_heap1.Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
- }
- reverse_heap1.Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode);
- if(phantomNodePair.targetPhantom.isBidirected() ) {
- reverse_heap1.Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1);
- }
-
- const int forward_offset = phantomNodePair.startPhantom.weight1 + (phantomNodePair.startPhantom.isBidirected() ? phantomNodePair.startPhantom.weight2 : 0);
- const int reverse_offset = phantomNodePair.targetPhantom.weight1 + (phantomNodePair.targetPhantom.isBidirected() ? phantomNodePair.targetPhantom.weight2 : 0);
-
- //exploration dijkstra from nodes s and t until deletemin/(1+epsilon) > _lengthOfShortestPath
- while(0 < (forward_heap1.Size() + reverse_heap1.Size())){
- if(0 < forward_heap1.Size()){
- AlternativeRoutingStep<true >(forward_heap1, reverse_heap1, &middle_node, &upper_bound_to_shortest_path_distance, viaNodeCandidates, forward_search_space, forward_offset);
+ // Init queues, semi-expensive because access to TSS invokes a sys-call
+ engine_working_data.InitializeOrClearFirstThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
+ engine_working_data.InitializeOrClearSecondThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
+ engine_working_data.InitializeOrClearThirdThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
+
+ QueryHeap &forward_heap1 = *(engine_working_data.forwardHeap);
+ QueryHeap &reverse_heap1 = *(engine_working_data.backwardHeap);
+ QueryHeap &forward_heap2 = *(engine_working_data.forwardHeap2);
+ QueryHeap &reverse_heap2 = *(engine_working_data.backwardHeap2);
+
+ int upper_bound_to_shortest_path_distance = INVALID_EDGE_WEIGHT;
+ NodeID middle_node = SPECIAL_NODEID;
+ if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
+ {
+ // SimpleLogger().Write(logDEBUG) << "fwd-a insert: " <<
+ // phantom_node_pair.source_phantom.forward_node_id << ", w: " <<
+ // -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
+ forward_heap1.Insert(phantom_node_pair.source_phantom.forward_node_id,
+ -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+ phantom_node_pair.source_phantom.forward_node_id);
+ }
+ if (phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
+ {
+ // SimpleLogger().Write(logDEBUG) << "fwd-b insert: " <<
+ // phantom_node_pair.source_phantom.reverse_node_id << ", w: " <<
+ // -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
+ forward_heap1.Insert(phantom_node_pair.source_phantom.reverse_node_id,
+ -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
+ phantom_node_pair.source_phantom.reverse_node_id);
+ }
+
+ if (phantom_node_pair.target_phantom.forward_node_id != SPECIAL_NODEID)
+ {
+ // SimpleLogger().Write(logDEBUG) << "rev-a insert: " <<
+ // phantom_node_pair.target_phantom.forward_node_id << ", w: " <<
+ // phantom_node_pair.target_phantom.GetForwardWeightPlusOffset();
+ reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_node_id,
+ phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
+ phantom_node_pair.target_phantom.forward_node_id);
+ }
+ if (phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID)
+ {
+ // SimpleLogger().Write(logDEBUG) << "rev-b insert: " <<
+ // phantom_node_pair.target_phantom.reverse_node_id << ", w: " <<
+ // phantom_node_pair.target_phantom.GetReverseWeightPlusOffset();
+ reverse_heap1.Insert(phantom_node_pair.target_phantom.reverse_node_id,
+ phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
+ phantom_node_pair.target_phantom.reverse_node_id);
+ }
+
+ // search from s and t till new_min/(1+epsilon) > length_of_shortest_path
+ while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
+ {
+ if (0 < forward_heap1.Size())
+ {
+ AlternativeRoutingStep<true>(forward_heap1,
+ reverse_heap1,
+ &middle_node,
+ &upper_bound_to_shortest_path_distance,
+ via_node_candidate_list,
+ forward_search_space);
}
- if(0 < reverse_heap1.Size()){
- AlternativeRoutingStep<false>(reverse_heap1, forward_heap1, &middle_node, &upper_bound_to_shortest_path_distance, viaNodeCandidates, reverse_search_space, reverse_offset);
+ if (0 < reverse_heap1.Size())
+ {
+ AlternativeRoutingStep<false>(reverse_heap1,
+ forward_heap1,
+ &middle_node,
+ &upper_bound_to_shortest_path_distance,
+ via_node_candidate_list,
+ reverse_search_space);
}
}
- sort_unique_resize(viaNodeCandidates);
+
+ if (INVALID_EDGE_WEIGHT == upper_bound_to_shortest_path_distance)
+ {
+ return;
+ }
+
+ sort_unique_resize(via_node_candidate_list);
std::vector<NodeID> packed_forward_path;
std::vector<NodeID> packed_reverse_path;
super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
- boost::unordered_map<NodeID, int> approximated_forward_sharing;
- boost::unordered_map<NodeID, int> approximated_reverse_sharing;
+
+ std::unordered_map<NodeID, int> approximated_forward_sharing;
+ std::unordered_map<NodeID, int> approximated_reverse_sharing;
unsigned index_into_forward_path = 0;
- //sweep over search space, compute forward sharing for each current edge (u,v)
- BOOST_FOREACH(const SearchSpaceEdge & current_edge, forward_search_space) {
- const NodeID u = current_edge.first;
- const NodeID v = current_edge.second;
- if(packed_forward_path.size() < index_into_forward_path && current_edge == forward_search_space[index_into_forward_path]) {
- //current_edge is on shortest path => sharing(u):=queue.GetKey(u);
- ++index_into_forward_path;
- approximated_forward_sharing[v] = forward_heap1.GetKey(u);
- } else {
- //sharing (s) = sharing (t)
- approximated_forward_sharing[v] = approximated_forward_sharing[u];
- }
+ // sweep over search space, compute forward sharing for each current edge (u,v)
+ for (const SearchSpaceEdge ¤t_edge : forward_search_space)
+ {
+ const NodeID u = current_edge.first;
+ const NodeID v = current_edge.second;
+ if ((packed_forward_path.size() < index_into_forward_path) &&
+ (current_edge == forward_search_space[index_into_forward_path]))
+ {
+ // current_edge is on shortest path => sharing(u):=queue.GetKey(u);
+ ++index_into_forward_path;
+ approximated_forward_sharing[v] = forward_heap1.GetKey(u);
+ }
+ else
+ {
+ // sharing (s) = sharing (t)
+ approximated_forward_sharing[v] = approximated_forward_sharing[u];
+ }
}
unsigned index_into_reverse_path = 0;
- //sweep over search space, compute backward sharing
- BOOST_FOREACH(const SearchSpaceEdge & current_edge, reverse_search_space) {
- const NodeID u = current_edge.first;
- const NodeID v = current_edge.second;
- if(packed_reverse_path.size() < index_into_reverse_path && current_edge == reverse_search_space[index_into_reverse_path]) {
- //current_edge is on shortest path => sharing(u):=queue.GetKey(u);
- ++index_into_reverse_path;
- approximated_reverse_sharing[v] = reverse_heap1.GetKey(u);
- } else {
- //sharing (s) = sharing (t)
- approximated_reverse_sharing[v] = approximated_reverse_sharing[u];
- }
- }
- std::vector<NodeID> nodes_that_passed_preselection;
- BOOST_FOREACH(const NodeID node, viaNodeCandidates) {
- int approximated_sharing = approximated_forward_sharing[node] + approximated_reverse_sharing[node];
- int approximated_length = forward_heap1.GetKey(node)+reverse_heap1.GetKey(node);
- bool lengthPassed = (approximated_length < upper_bound_to_shortest_path_distance*(1+VIAPATH_EPSILON));
- bool sharingPassed = (approximated_sharing <= upper_bound_to_shortest_path_distance*VIAPATH_GAMMA);
- bool stretchPassed = approximated_length - approximated_sharing < (1.+VIAPATH_EPSILON)*(upper_bound_to_shortest_path_distance-approximated_sharing);
-
- if(lengthPassed && sharingPassed && stretchPassed) {
- nodes_that_passed_preselection.push_back(node);
+ // sweep over search space, compute backward sharing
+ for (const SearchSpaceEdge ¤t_edge : reverse_search_space)
+ {
+ const NodeID u = current_edge.first;
+ const NodeID v = current_edge.second;
+ if ((packed_reverse_path.size() < index_into_reverse_path) &&
+ (current_edge == reverse_search_space[index_into_reverse_path]))
+ {
+ // current_edge is on shortest path => sharing(u):=queue.GetKey(u);
+ ++index_into_reverse_path;
+ approximated_reverse_sharing[v] = reverse_heap1.GetKey(u);
+ }
+ else
+ {
+ // sharing (s) = sharing (t)
+ const auto rev_iterator = approximated_reverse_sharing.find(u);
+ const int rev_sharing =
+ (rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0;
+ approximated_reverse_sharing[v] = rev_sharing;
}
}
- std::vector<NodeID> & packedShortestPath = packed_forward_path;
- std::reverse(packedShortestPath.begin(), packedShortestPath.end());
- packedShortestPath.push_back(middle_node);
- packedShortestPath.insert(packedShortestPath.end(),packed_reverse_path.begin(), packed_reverse_path.end());
- std::vector<RankedCandidateNode > rankedCandidates;
-
- //prioritizing via nodes for deep inspection
- BOOST_FOREACH(const NodeID node, nodes_that_passed_preselection) {
- int lengthOfViaPath = 0, sharingOfViaPath = 0;
- computeLengthAndSharingOfViaPath(node, &lengthOfViaPath, &sharingOfViaPath, forward_offset+reverse_offset, packedShortestPath);
- if(sharingOfViaPath <= upper_bound_to_shortest_path_distance*VIAPATH_GAMMA) {
- rankedCandidates.push_back(RankedCandidateNode(node, lengthOfViaPath, sharingOfViaPath));
+ // SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
+ // forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << "
+ // nodes";
+ // SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
+ // reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << "
+ // nodes";
+
+ std::vector<NodeID> preselected_node_list;
+ for (const NodeID node : via_node_candidate_list)
+ {
+ const auto fwd_iterator = approximated_forward_sharing.find(node);
+ const int fwd_sharing =
+ (fwd_iterator != approximated_forward_sharing.end()) ? fwd_iterator->second : 0;
+ const auto rev_iterator = approximated_reverse_sharing.find(node);
+ const int rev_sharing =
+ (rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0;
+
+ const int approximated_sharing = fwd_sharing + rev_sharing;
+ const int approximated_length = forward_heap1.GetKey(node) + reverse_heap1.GetKey(node);
+ const bool length_passes =
+ (approximated_length <
+ upper_bound_to_shortest_path_distance * (1 + VIAPATH_EPSILON));
+ const bool sharing_passes =
+ (approximated_sharing <= upper_bound_to_shortest_path_distance * VIAPATH_GAMMA);
+ const bool stretch_passes =
+ (approximated_length - approximated_sharing) <
+ ((1. + VIAPATH_ALPHA) *
+ (upper_bound_to_shortest_path_distance - approximated_sharing));
+
+ if (length_passes && sharing_passes && stretch_passes)
+ {
+ preselected_node_list.emplace_back(node);
}
}
- std::sort(rankedCandidates.begin(), rankedCandidates.end());
- NodeID selectedViaNode = UINT_MAX;
- int lengthOfViaPath = INT_MAX;
- NodeID s_v_middle = UINT_MAX, v_t_middle = UINT_MAX;
- BOOST_FOREACH(const RankedCandidateNode & candidate, rankedCandidates){
- if(viaNodeCandidatePasses_T_Test(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, candidate, forward_offset+reverse_offset, upper_bound_to_shortest_path_distance, &lengthOfViaPath, &s_v_middle, &v_t_middle)) {
+ // SimpleLogger().Write() << preselected_node_list.size() << " passed preselection";
+
+ std::vector<NodeID> &packed_shortest_path = packed_forward_path;
+ std::reverse(packed_shortest_path.begin(), packed_shortest_path.end());
+ packed_shortest_path.emplace_back(middle_node);
+ packed_shortest_path.insert(
+ packed_shortest_path.end(), packed_reverse_path.begin(), packed_reverse_path.end());
+ std::vector<RankedCandidateNode> ranked_candidates_list;
+
+ // prioritizing via nodes for deep inspection
+ for (const NodeID node : preselected_node_list)
+ {
+ int length_of_via_path = 0, sharing_of_via_path = 0;
+ ComputeLengthAndSharingOfViaPath(
+ node, &length_of_via_path, &sharing_of_via_path, packed_shortest_path);
+ const int maximum_allowed_sharing = static_cast<int>(
+ upper_bound_to_shortest_path_distance * VIAPATH_GAMMA);
+ if (sharing_of_via_path <= maximum_allowed_sharing &&
+ length_of_via_path <= upper_bound_to_shortest_path_distance * (1 + VIAPATH_EPSILON))
+ {
+ ranked_candidates_list.emplace_back(node, length_of_via_path, sharing_of_via_path);
+ }
+ }
+ std::sort(ranked_candidates_list.begin(), ranked_candidates_list.end());
+
+ NodeID selected_via_node = SPECIAL_NODEID;
+ int length_of_via_path = INVALID_EDGE_WEIGHT;
+ NodeID s_v_middle = SPECIAL_NODEID, v_t_middle = SPECIAL_NODEID;
+ for (const RankedCandidateNode &candidate : ranked_candidates_list)
+ {
+ if (ViaNodeCandidatePassesTTest(forward_heap1,
+ reverse_heap1,
+ forward_heap2,
+ reverse_heap2,
+ candidate,
+ upper_bound_to_shortest_path_distance,
+ &length_of_via_path,
+ &s_v_middle,
+ &v_t_middle))
+ {
// select first admissable
- selectedViaNode = candidate.node;
+ selected_via_node = candidate.node;
break;
}
}
- //Unpack shortest path and alternative, if they exist
- if(INT_MAX != upper_bound_to_shortest_path_distance) {
- super::UnpackPath(packedShortestPath, rawRouteData.computedShortestPath);
- rawRouteData.lengthOfShortestPath = upper_bound_to_shortest_path_distance;
+ // Unpack shortest path and alternative, if they exist
+ if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_distance)
+ {
+ BOOST_ASSERT(!packed_shortest_path.empty());
+ raw_route_data.unpacked_path_segments.resize(1);
+ raw_route_data.source_traversed_in_reverse.push_back(
+ (packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_node_id));
+ raw_route_data.target_traversed_in_reverse.push_back(
+ (packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_node_id));
+
+ super::UnpackPath(
+ // -- packed input
+ packed_shortest_path,
+ // -- start of route
+ phantom_node_pair,
+ // -- unpacked output
+ raw_route_data.unpacked_path_segments.front());
+ raw_route_data.shortest_path_length = upper_bound_to_shortest_path_distance;
+ }
+
+ if (SPECIAL_NODEID != selected_via_node)
+ {
+ std::vector<NodeID> packed_alternate_path;
+ // retrieve alternate path
+ RetrievePackedAlternatePath(forward_heap1,
+ reverse_heap1,
+ forward_heap2,
+ reverse_heap2,
+ s_v_middle,
+ v_t_middle,
+ packed_alternate_path);
+
+ raw_route_data.alt_source_traversed_in_reverse.push_back(
+ (packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_node_id));
+ raw_route_data.alt_target_traversed_in_reverse.push_back(
+ (packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id));
+
+ // unpack the alternate path
+ super::UnpackPath(
+ packed_alternate_path, phantom_node_pair, raw_route_data.unpacked_alternative);
+
+ raw_route_data.alternative_path_length = length_of_via_path;
} else {
- rawRouteData.lengthOfShortestPath = INT_MAX;
- }
-
- if(selectedViaNode != UINT_MAX) {
- retrievePackedViaPath(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, s_v_middle, v_t_middle, rawRouteData.computedAlternativePath);
- rawRouteData.lengthOfAlternativePath = lengthOfViaPath;
- } else {
- rawRouteData.lengthOfAlternativePath = INT_MAX;
+ BOOST_ASSERT(raw_route_data.alternative_path_length == INVALID_EDGE_WEIGHT);
}
}
-private:
- //unpack <s,..,v,..,t> by exploring search spaces from v
- inline void retrievePackedViaPath(QueryHeap & _forwardHeap1, QueryHeap & _backwardHeap1, QueryHeap & _forwardHeap2, QueryHeap & _backwardHeap2,
- const NodeID s_v_middle, const NodeID v_t_middle, std::vector<_PathData> & unpackedPath) {
- //unpack [s,v)
- std::vector<NodeID> packed_s_v_path, packed_v_t_path;
- super::RetrievePackedPathFromHeap(_forwardHeap1, _backwardHeap2, s_v_middle, packed_s_v_path);
- packed_s_v_path.resize(packed_s_v_path.size()-1);
- //unpack [v,t]
- super::RetrievePackedPathFromHeap(_forwardHeap2, _backwardHeap1, v_t_middle, packed_v_t_path);
- packed_s_v_path.insert(packed_s_v_path.end(),packed_v_t_path.begin(), packed_v_t_path.end() );
- super::UnpackPath(packed_s_v_path, unpackedPath);
+ private:
+ // unpack alternate <s,..,v,..,t> by exploring search spaces from v
+ inline void RetrievePackedAlternatePath(const QueryHeap &forward_heap1,
+ const QueryHeap &reverse_heap1,
+ const QueryHeap &forward_heap2,
+ const QueryHeap &reverse_heap2,
+ const NodeID s_v_middle,
+ const NodeID v_t_middle,
+ std::vector<NodeID> &packed_path) const
+ {
+ // fetch packed path [s,v)
+ std::vector<NodeID> packed_v_t_path;
+ super::RetrievePackedPathFromHeap(forward_heap1, reverse_heap2, s_v_middle, packed_path);
+ packed_path.pop_back(); // remove middle node. It's in both half-paths
+
+ // fetch patched path [v,t]
+ super::RetrievePackedPathFromHeap(
+ forward_heap2, reverse_heap1, v_t_middle, packed_v_t_path);
+
+ packed_path.insert(packed_path.end(), packed_v_t_path.begin(), packed_v_t_path.end());
}
- inline void computeLengthAndSharingOfViaPath(const NodeID via_node, int *real_length_of_via_path, int *sharing_of_via_path,
- const int offset, const std::vector<NodeID> & packed_shortest_path) {
- //compute and unpack <s,..,v> and <v,..,t> by exploring search spaces from v and intersecting against queues
- //only half-searches have to be done at this stage
- super::_queryData.InitializeOrClearSecondThreadLocalStorage();
-
- QueryHeap & existingForwardHeap = *super::_queryData.forwardHeap;
- QueryHeap & existingBackwardHeap = *super::_queryData.backwardHeap;
- QueryHeap & newForwardHeap = *super::_queryData.forwardHeap2;
- QueryHeap & newBackwardHeap = *super::_queryData.backwardHeap2;
-
- std::vector < NodeID > packed_s_v_path;
- std::vector < NodeID > packed_v_t_path;
-
- std::vector<NodeID> partiallyUnpackedShortestPath;
- std::vector<NodeID> partiallyUnpackedViaPath;
-
- NodeID s_v_middle = UINT_MAX;
- int upperBoundFor_s_v_Path = INT_MAX;//compute path <s,..,v> by reusing forward search from s
- newBackwardHeap.Insert(via_node, 0, via_node);
- while (0 < newBackwardHeap.Size()) {
- super::RoutingStep(newBackwardHeap, existingForwardHeap, &s_v_middle, &upperBoundFor_s_v_Path, 2 * offset, false);
- }
- //compute path <v,..,t> by reusing backward search from node t
- NodeID v_t_middle = UINT_MAX;
- int upperBoundFor_v_t_Path = INT_MAX;
- newForwardHeap.Insert(via_node, 0, via_node);
- while (0 < newForwardHeap.Size() ) {
- super::RoutingStep(newForwardHeap, existingBackwardHeap, &v_t_middle, &upperBoundFor_v_t_Path, 2 * offset, true);
- }
- *real_length_of_via_path = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path;
-
- if(UINT_MAX == s_v_middle || UINT_MAX == v_t_middle)
+ // TODO: reorder parameters
+ // compute and unpack <s,..,v> and <v,..,t> by exploring search spaces
+ // from v and intersecting against queues. only half-searches have to be
+ // done at this stage
+ inline void ComputeLengthAndSharingOfViaPath(const NodeID via_node,
+ int *real_length_of_via_path,
+ int *sharing_of_via_path,
+ const std::vector<NodeID> &packed_shortest_path)
+ {
+ engine_working_data.InitializeOrClearSecondThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
+
+ QueryHeap &existing_forward_heap = *engine_working_data.forwardHeap;
+ QueryHeap &existing_reverse_heap = *engine_working_data.backwardHeap;
+ QueryHeap &new_forward_heap = *engine_working_data.forwardHeap2;
+ QueryHeap &new_reverse_heap = *engine_working_data.backwardHeap2;
+
+ std::vector<NodeID> packed_s_v_path;
+ std::vector<NodeID> packed_v_t_path;
+
+ std::vector<NodeID> partially_unpacked_shortest_path;
+ std::vector<NodeID> partially_unpacked_via_path;
+
+ NodeID s_v_middle = SPECIAL_NODEID;
+ int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
+ new_reverse_heap.Insert(via_node, 0, via_node);
+ // compute path <s,..,v> by reusing forward search from s
+ while (!new_reverse_heap.Empty())
+ {
+ super::RoutingStep(new_reverse_heap,
+ existing_forward_heap,
+ &s_v_middle,
+ &upper_bound_s_v_path_length,
+ false);
+ }
+ // compute path <v,..,t> by reusing backward search from node t
+ NodeID v_t_middle = SPECIAL_NODEID;
+ int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT;
+ new_forward_heap.Insert(via_node, 0, via_node);
+ while (!new_forward_heap.Empty())
+ {
+ super::RoutingStep(new_forward_heap,
+ existing_reverse_heap,
+ &v_t_middle,
+ &upper_bound_of_v_t_path_length,
+ true);
+ }
+ *real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
+
+ if (SPECIAL_NODEID == s_v_middle || SPECIAL_NODEID == v_t_middle)
+ {
return;
+ }
- //retrieve packed paths
- super::RetrievePackedPathFromHeap(existingForwardHeap, newBackwardHeap, s_v_middle, packed_s_v_path);
- super::RetrievePackedPathFromHeap(newForwardHeap, existingBackwardHeap, v_t_middle, packed_v_t_path);
-
- //partial unpacking, compute sharing
- //First partially unpack s-->v until paths deviate, note length of common path.
- for (unsigned i = 0, lengthOfPackedPath = std::min( packed_s_v_path.size(), packed_shortest_path.size()) - 1; (i < lengthOfPackedPath); ++i) {
- if (packed_s_v_path[i] == packed_shortest_path[i] && packed_s_v_path[i + 1] == packed_shortest_path[i + 1]) {
- typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]);
- *sharing_of_via_path += search_graph->GetEdgeData(edgeID).distance;
- } else {
- if (packed_s_v_path[i] == packed_shortest_path[i]) {
- super::UnpackEdge(packed_s_v_path[i], packed_s_v_path[i+1], partiallyUnpackedViaPath);
- super::UnpackEdge(packed_shortest_path[i], packed_shortest_path[i+1], partiallyUnpackedShortestPath);
+ // retrieve packed paths
+ super::RetrievePackedPathFromHeap(
+ existing_forward_heap, new_reverse_heap, s_v_middle, packed_s_v_path);
+ super::RetrievePackedPathFromHeap(
+ new_forward_heap, existing_reverse_heap, v_t_middle, packed_v_t_path);
+
+ // partial unpacking, compute sharing
+ // First partially unpack s-->v until paths deviate, note length of common path.
+ const unsigned s_v_min_path_size =
+ std::min(packed_s_v_path.size(), packed_shortest_path.size()) - 1;
+ for (unsigned i = 0; i < s_v_min_path_size; ++i)
+ {
+ if (packed_s_v_path[i] == packed_shortest_path[i] &&
+ packed_s_v_path[i + 1] == packed_shortest_path[i + 1])
+ {
+ EdgeID edgeID =
+ facade->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]);
+ *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
+ }
+ else
+ {
+ if (packed_s_v_path[i] == packed_shortest_path[i])
+ {
+ super::UnpackEdge(
+ packed_s_v_path[i], packed_s_v_path[i + 1], partially_unpacked_via_path);
+ super::UnpackEdge(packed_shortest_path[i],
+ packed_shortest_path[i + 1],
+ partially_unpacked_shortest_path);
break;
}
}
}
- //traverse partially unpacked edge and note common prefix
- for (int i = 0, lengthOfPackedPath = std::min( partiallyUnpackedViaPath.size(), partiallyUnpackedShortestPath.size()) - 1; (i < lengthOfPackedPath) && (partiallyUnpackedViaPath[i] == partiallyUnpackedShortestPath[i] && partiallyUnpackedViaPath[i+1] == partiallyUnpackedShortestPath[i+1]); ++i) {
- typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection(partiallyUnpackedViaPath[i], partiallyUnpackedViaPath[i+1]);
- *sharing_of_via_path += search_graph->GetEdgeData(edgeID).distance;
- }
-
- //Second, partially unpack v-->t in reverse order until paths deviate and note lengths
- int viaPathIndex = packed_v_t_path.size() - 1;
- int shortestPathIndex = packed_shortest_path.size() - 1;
- for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex ) {
- if (packed_v_t_path[viaPathIndex - 1] == packed_shortest_path[shortestPathIndex - 1] && packed_v_t_path[viaPathIndex] == packed_shortest_path[shortestPathIndex]) {
- typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection( packed_v_t_path[viaPathIndex - 1], packed_v_t_path[viaPathIndex]);
- *sharing_of_via_path += search_graph->GetEdgeData(edgeID).distance;
- } else {
- if (packed_v_t_path[viaPathIndex] == packed_shortest_path[shortestPathIndex]) {
- super::UnpackEdge(packed_v_t_path[viaPathIndex-1], packed_v_t_path[viaPathIndex], partiallyUnpackedViaPath);
- super::UnpackEdge(packed_shortest_path[shortestPathIndex-1] , packed_shortest_path[shortestPathIndex], partiallyUnpackedShortestPath);
+ // traverse partially unpacked edge and note common prefix
+ for (int i = 0,
+ packed_path_length = std::min(partially_unpacked_via_path.size(),
+ partially_unpacked_shortest_path.size()) -
+ 1;
+ (i < packed_path_length) &&
+ (partially_unpacked_via_path[i] == partially_unpacked_shortest_path[i] &&
+ partially_unpacked_via_path[i + 1] == partially_unpacked_shortest_path[i + 1]);
+ ++i)
+ {
+ EdgeID edgeID = facade->FindEdgeInEitherDirection(partially_unpacked_via_path[i],
+ partially_unpacked_via_path[i + 1]);
+ *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
+ }
+
+ // Second, partially unpack v-->t in reverse order until paths deviate and note lengths
+ int via_path_index = packed_v_t_path.size() - 1;
+ int shortest_path_index = packed_shortest_path.size() - 1;
+ for (; via_path_index > 0 && shortest_path_index > 0;
+ --via_path_index, --shortest_path_index)
+ {
+ if (packed_v_t_path[via_path_index - 1] ==
+ packed_shortest_path[shortest_path_index - 1] &&
+ packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index])
+ {
+ EdgeID edgeID = facade->FindEdgeInEitherDirection(
+ packed_v_t_path[via_path_index - 1], packed_v_t_path[via_path_index]);
+ *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
+ }
+ else
+ {
+ if (packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index])
+ {
+ super::UnpackEdge(packed_v_t_path[via_path_index - 1],
+ packed_v_t_path[via_path_index],
+ partially_unpacked_via_path);
+ super::UnpackEdge(packed_shortest_path[shortest_path_index - 1],
+ packed_shortest_path[shortest_path_index],
+ partially_unpacked_shortest_path);
break;
}
}
}
- viaPathIndex = partiallyUnpackedViaPath.size() - 1;
- shortestPathIndex = partiallyUnpackedShortestPath.size() - 1;
- for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex) {
- if (partiallyUnpackedViaPath[viaPathIndex - 1] == partiallyUnpackedShortestPath[shortestPathIndex - 1] && partiallyUnpackedViaPath[viaPathIndex] == partiallyUnpackedShortestPath[shortestPathIndex]) {
- typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection( partiallyUnpackedViaPath[viaPathIndex - 1], partiallyUnpackedViaPath[viaPathIndex]);
- *sharing_of_via_path += search_graph->GetEdgeData(edgeID).distance;
- } else {
+ via_path_index = partially_unpacked_via_path.size() - 1;
+ shortest_path_index = partially_unpacked_shortest_path.size() - 1;
+ for (; via_path_index > 0 && shortest_path_index > 0;
+ --via_path_index, --shortest_path_index)
+ {
+ if (partially_unpacked_via_path[via_path_index - 1] ==
+ partially_unpacked_shortest_path[shortest_path_index - 1] &&
+ partially_unpacked_via_path[via_path_index] ==
+ partially_unpacked_shortest_path[shortest_path_index])
+ {
+ EdgeID edgeID = facade->FindEdgeInEitherDirection(
+ partially_unpacked_via_path[via_path_index - 1],
+ partially_unpacked_via_path[via_path_index]);
+ *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
+ }
+ else
+ {
break;
}
}
- //finished partial unpacking spree! Amount of sharing is stored to appropriate pointer variable
- }
-
- inline int approximateAmountOfSharing(const NodeID middleNodeIDOfAlternativePath, QueryHeap & _forwardHeap, QueryHeap & _backwardHeap, const std::vector<NodeID> & packedShortestPath) {
- std::vector<NodeID> packedAlternativePath;
- super::RetrievePackedPathFromHeap(_forwardHeap, _backwardHeap, middleNodeIDOfAlternativePath, packedAlternativePath);
-
- if(packedShortestPath.size() < 2 || packedAlternativePath.size() < 2)
- return 0;
-
- int sharing = 0;
- int aindex = 0;
- //compute forward sharing
- while( (packedAlternativePath[aindex] == packedShortestPath[aindex]) && (packedAlternativePath[aindex+1] == packedShortestPath[aindex+1]) ) {
- // INFO("retrieving edge (" << packedAlternativePath[aindex] << "," << packedAlternativePath[aindex+1] << ")");
- typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex+1]);
- sharing += search_graph->GetEdgeData(edgeID).distance;
- ++aindex;
- }
-
- aindex = packedAlternativePath.size()-1;
- int bindex = packedShortestPath.size()-1;
- //compute backward sharing
- while( aindex > 0 && bindex > 0 && (packedAlternativePath[aindex] == packedShortestPath[bindex]) && (packedAlternativePath[aindex-1] == packedShortestPath[bindex-1]) ) {
- typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex-1]);
- sharing += search_graph->GetEdgeData(edgeID).distance;
- --aindex; --bindex;
- }
- return sharing;
+ // finished partial unpacking spree! Amount of sharing is stored to appropriate pointer
+ // variable
}
- template<bool forwardDirection>
- inline void AlternativeRoutingStep(
- QueryHeap & _forward_heap,
- QueryHeap & _reverse_heap,
- NodeID *middle_node,
- int *upper_bound_to_shortest_path_distance,
- std::vector<NodeID>& searchSpaceIntersection,
- std::vector<SearchSpaceEdge> & search_space,
- const int edgeBasedOffset
- ) const {
- const NodeID node = _forward_heap.DeleteMin();
- const int distance = _forward_heap.GetKey(node);
- int scaledDistance = (distance-edgeBasedOffset)/(1.+VIAPATH_EPSILON);
- if(scaledDistance > *upper_bound_to_shortest_path_distance){
- _forward_heap.DeleteAll();
+ // inline int approximateAmountOfSharing(
+ // const NodeID alternate_path_middle_node_id,
+ // QueryHeap & forward_heap,
+ // QueryHeap & reverse_heap,
+ // const std::vector<NodeID> & packed_shortest_path
+ // ) const {
+ // std::vector<NodeID> packed_alternate_path;
+ // super::RetrievePackedPathFromHeap(
+ // forward_heap,
+ // reverse_heap,
+ // alternate_path_middle_node_id,
+ // packed_alternate_path
+ // );
+
+ // if(packed_shortest_path.size() < 2 || packed_alternate_path.size() < 2) {
+ // return 0;
+ // }
+
+ // int sharing = 0;
+ // int aindex = 0;
+ // //compute forward sharing
+ // while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) &&
+ // (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) {
+ // // SimpleLogger().Write() << "retrieving edge (" <<
+ // packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
+ // EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
+ // packed_alternate_path[aindex+1]);
+ // sharing += facade->GetEdgeData(edgeID).distance;
+ // ++aindex;
+ // }
+
+ // aindex = packed_alternate_path.size()-1;
+ // int bindex = packed_shortest_path.size()-1;
+ // //compute backward sharing
+ // while( aindex > 0 && bindex > 0 && (packed_alternate_path[aindex] ==
+ // packed_shortest_path[bindex]) && (packed_alternate_path[aindex-1] ==
+ // packed_shortest_path[bindex-1]) ) {
+ // EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
+ // packed_alternate_path[aindex-1]);
+ // sharing += facade->GetEdgeData(edgeID).distance;
+ // --aindex; --bindex;
+ // }
+ // return sharing;
+ // }
+
+ // todo: reorder parameters
+ template <bool is_forward_directed>
+ inline void AlternativeRoutingStep(QueryHeap &forward_heap,
+ QueryHeap &reverse_heap,
+ NodeID *middle_node,
+ int *upper_bound_to_shortest_path_distance,
+ std::vector<NodeID> &search_space_intersection,
+ std::vector<SearchSpaceEdge> &search_space) const
+ {
+ const NodeID node = forward_heap.DeleteMin();
+ const int distance = forward_heap.GetKey(node);
+ const int scaled_distance = static_cast<int>(distance / (1. + VIAPATH_EPSILON));
+ if ((INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_distance) &&
+ (scaled_distance > *upper_bound_to_shortest_path_distance))
+ {
+ forward_heap.DeleteAll();
return;
}
- search_space.push_back(std::make_pair(_forward_heap.GetData( node ).parent, node));
+ search_space.emplace_back(forward_heap.GetData(node).parent, node);
- if(_reverse_heap.WasInserted(node) ){
- searchSpaceIntersection.push_back(node);
+ if (reverse_heap.WasInserted(node))
+ {
+ search_space_intersection.emplace_back(node);
- const int newDistance = _reverse_heap.GetKey(node) + distance;
- if(newDistance < *upper_bound_to_shortest_path_distance ){
- if(newDistance>=0 ) {
+ const int new_distance = reverse_heap.GetKey(node) + distance;
+ if (new_distance < *upper_bound_to_shortest_path_distance)
+ {
+ if (new_distance >= 0)
+ {
*middle_node = node;
- *upper_bound_to_shortest_path_distance = newDistance;
+ *upper_bound_to_shortest_path_distance = new_distance;
}
}
}
- for ( typename SearchGraph::EdgeIterator edge = search_graph->BeginEdges( node ); edge < search_graph->EndEdges(node); edge++ ) {
- const typename SearchGraph::EdgeData & data = search_graph->GetEdgeData(edge);
- bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward );
- if(forwardDirectionFlag) {
+ for (auto edge : facade->GetAdjacentEdgeRange(node))
+ {
+ const EdgeData &data = facade->GetEdgeData(edge);
+ const bool edge_is_forward_directed =
+ (is_forward_directed ? data.forward : data.backward);
+ if (edge_is_forward_directed)
+ {
- const NodeID to = search_graph->GetTarget(edge);
- const int edgeWeight = data.distance;
+ const NodeID to = facade->GetTarget(edge);
+ const int edge_weight = data.distance;
- assert( edgeWeight > 0 );
- const int toDistance = distance + edgeWeight;
-
- //New Node discovered -> Add to Heap + Node Info Storage
- if ( !_forward_heap.WasInserted( to ) ) {
- _forward_heap.Insert( to, toDistance, node );
+ BOOST_ASSERT(edge_weight > 0);
+ const int to_distance = distance + edge_weight;
+ // New Node discovered -> Add to Heap + Node Info Storage
+ if (!forward_heap.WasInserted(to))
+ {
+ forward_heap.Insert(to, to_distance, node);
}
- //Found a shorter Path -> Update distance
- else if ( toDistance < _forward_heap.GetKey( to ) ) {
- _forward_heap.GetData( to ).parent = node;
- _forward_heap.DecreaseKey( to, toDistance );
- //new parent
+ // Found a shorter Path -> Update distance
+ else if (to_distance < forward_heap.GetKey(to))
+ {
+ // new parent
+ forward_heap.GetData(to).parent = node;
+ // decreased distance
+ forward_heap.DecreaseKey(to, to_distance);
}
}
}
}
- //conduct T-Test
- inline bool viaNodeCandidatePasses_T_Test( QueryHeap& existingForwardHeap, QueryHeap& existingBackwardHeap, QueryHeap& newForwardHeap, QueryHeap& newBackwardHeap, const RankedCandidateNode& candidate, const int offset, const int lengthOfShortestPath, int * lengthOfViaPath, NodeID * s_v_middle, NodeID * v_t_middle) {
- newForwardHeap.Clear();
- newBackwardHeap.Clear();
- std::vector < NodeID > packed_s_v_path;
- std::vector < NodeID > packed_v_t_path;
+ // conduct T-Test
+ inline bool ViaNodeCandidatePassesTTest(QueryHeap &existing_forward_heap,
+ QueryHeap &existing_reverse_heap,
+ QueryHeap &new_forward_heap,
+ QueryHeap &new_reverse_heap,
+ const RankedCandidateNode &candidate,
+ const int length_of_shortest_path,
+ int *length_of_via_path,
+ NodeID *s_v_middle,
+ NodeID *v_t_middle) const
+ {
+ new_forward_heap.Clear();
+ new_reverse_heap.Clear();
+ std::vector<NodeID> packed_s_v_path;
+ std::vector<NodeID> packed_v_t_path;
+
+ *s_v_middle = SPECIAL_NODEID;
+ int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
+ // compute path <s,..,v> by reusing forward search from s
+ new_reverse_heap.Insert(candidate.node, 0, candidate.node);
+ while (new_reverse_heap.Size() > 0)
+ {
+ super::RoutingStep(new_reverse_heap,
+ existing_forward_heap,
+ s_v_middle,
+ &upper_bound_s_v_path_length,
+ false);
+ }
+
+ if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
+ {
+ return false;
+ }
- *s_v_middle = UINT_MAX;
- int upperBoundFor_s_v_Path = INT_MAX;
- //compute path <s,..,v> by reusing forward search from s
- newBackwardHeap.Insert(candidate.node, 0, candidate.node);
- while (newBackwardHeap.Size() > 0) {
- super::RoutingStep(newBackwardHeap, existingForwardHeap, s_v_middle, &upperBoundFor_s_v_Path, 2*offset, false);
+ // compute path <v,..,t> by reusing backward search from t
+ *v_t_middle = SPECIAL_NODEID;
+ int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT;
+ new_forward_heap.Insert(candidate.node, 0, candidate.node);
+ while (new_forward_heap.Size() > 0)
+ {
+ super::RoutingStep(new_forward_heap,
+ existing_reverse_heap,
+ v_t_middle,
+ &upper_bound_of_v_t_path_length,
+ true);
}
- if(INT_MAX == upperBoundFor_s_v_Path)
+ if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
+ {
return false;
-
- //compute path <v,..,t> by reusing backward search from t
- *v_t_middle = UINT_MAX;
- int upperBoundFor_v_t_Path = INT_MAX;
- newForwardHeap.Insert(candidate.node, 0, candidate.node);
- while (newForwardHeap.Size() > 0) {
- super::RoutingStep(newForwardHeap, existingBackwardHeap, v_t_middle, &upperBoundFor_v_t_Path, 2*offset, true);
}
- if(INT_MAX == upperBoundFor_v_t_Path)
- return false;
+ *length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
- *lengthOfViaPath = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path;
+ // retrieve packed paths
+ super::RetrievePackedPathFromHeap(
+ existing_forward_heap, new_reverse_heap, *s_v_middle, packed_s_v_path);
- //retrieve packed paths
- super::RetrievePackedPathFromHeap(existingForwardHeap, newBackwardHeap, *s_v_middle, packed_s_v_path);
- super::RetrievePackedPathFromHeap(newForwardHeap, existingBackwardHeap, *v_t_middle, packed_v_t_path);
+ super::RetrievePackedPathFromHeap(
+ new_forward_heap, existing_reverse_heap, *v_t_middle, packed_v_t_path);
NodeID s_P = *s_v_middle, t_P = *v_t_middle;
- if(UINT_MAX == s_P) {
+ if (SPECIAL_NODEID == s_P)
+ {
return false;
}
- if(UINT_MAX == t_P) {
+ if (SPECIAL_NODEID == t_P)
+ {
return false;
}
- const int T_threshold = VIAPATH_EPSILON * lengthOfShortestPath;
- int unpackedUntilDistance = 0;
-
- std::stack<SearchSpaceEdge> unpackStack;
- //Traverse path s-->v
- for (unsigned i = packed_s_v_path.size() - 1; (i > 0) && unpackStack.empty(); --i) {
- typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection( packed_s_v_path[i - 1], packed_s_v_path[i]);
- int lengthOfCurrentEdge = search_graph->GetEdgeData(edgeID).distance;
- if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) {
- unpackStack.push(std::make_pair(packed_s_v_path[i - 1], packed_s_v_path[i]));
- } else {
- unpackedUntilDistance += lengthOfCurrentEdge;
+ const int T_threshold = static_cast<int>(VIAPATH_EPSILON * length_of_shortest_path);
+ int unpacked_until_distance = 0;
+
+ std::stack<SearchSpaceEdge> unpack_stack;
+ // Traverse path s-->v
+ for (std::size_t i = packed_s_v_path.size() - 1; (i > 0) && unpack_stack.empty(); --i)
+ {
+ const EdgeID current_edge_id =
+ facade->FindEdgeInEitherDirection(packed_s_v_path[i - 1], packed_s_v_path[i]);
+ const int length_of_current_edge = facade->GetEdgeData(current_edge_id).distance;
+ if ((length_of_current_edge + unpacked_until_distance) >= T_threshold)
+ {
+ unpack_stack.emplace(packed_s_v_path[i - 1], packed_s_v_path[i]);
+ }
+ else
+ {
+ unpacked_until_distance += length_of_current_edge;
s_P = packed_s_v_path[i - 1];
}
}
- while (!unpackStack.empty()) {
- const SearchSpaceEdge viaPathEdge = unpackStack.top();
- unpackStack.pop();
- typename SearchGraph::EdgeIterator edgeIDInViaPath = search_graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second);
- if(UINT_MAX == edgeIDInViaPath)
+ while (!unpack_stack.empty())
+ {
+ const SearchSpaceEdge via_path_edge = unpack_stack.top();
+ unpack_stack.pop();
+ EdgeID edge_in_via_path_id =
+ facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second);
+
+ if (SPECIAL_EDGEID == edge_in_via_path_id)
+ {
return false;
- typename SearchGraph::EdgeData currentEdgeData = search_graph->GetEdgeData(edgeIDInViaPath);
- bool IsViaEdgeShortCut = currentEdgeData.shortcut;
- if (IsViaEdgeShortCut) {
- const NodeID middleOfViaPath = currentEdgeData.id;
- typename SearchGraph::EdgeIterator edgeIDOfSecondSegment = search_graph->FindEdgeInEitherDirection(middleOfViaPath, viaPathEdge.second);
- int lengthOfSecondSegment = search_graph->GetEdgeData(edgeIDOfSecondSegment).distance;
- //attention: !unpacking in reverse!
- //Check if second segment is the one to go over treshold? if yes add second segment to stack, else push first segment to stack and add distance of second one.
- if (unpackedUntilDistance + lengthOfSecondSegment >= T_threshold) {
- unpackStack.push(std::make_pair(middleOfViaPath, viaPathEdge.second));
- } else {
- unpackedUntilDistance += lengthOfSecondSegment;
- unpackStack.push(std::make_pair(viaPathEdge.first, middleOfViaPath));
+ }
+
+ const EdgeData ¤t_edge_data = facade->GetEdgeData(edge_in_via_path_id);
+ const bool current_edge_is_shortcut = current_edge_data.shortcut;
+ if (current_edge_is_shortcut)
+ {
+ const NodeID via_path_middle_node_id = current_edge_data.id;
+ const EdgeID second_segment_edge_id = facade->FindEdgeInEitherDirection(
+ via_path_middle_node_id, via_path_edge.second);
+ const int second_segment_length =
+ facade->GetEdgeData(second_segment_edge_id).distance;
+ // attention: !unpacking in reverse!
+ // Check if second segment is the one to go over treshold? if yes add second segment
+ // to stack, else push first segment to stack and add distance of second one.
+ if (unpacked_until_distance + second_segment_length >= T_threshold)
+ {
+ unpack_stack.emplace(via_path_middle_node_id, via_path_edge.second);
}
- } else {
+ else
+ {
+ unpacked_until_distance += second_segment_length;
+ unpack_stack.emplace(via_path_edge.first, via_path_middle_node_id);
+ }
+ }
+ else
+ {
// edge is not a shortcut, set the start node for T-Test to end of edge.
- unpackedUntilDistance += currentEdgeData.distance;
- s_P = viaPathEdge.first;
+ unpacked_until_distance += current_edge_data.distance;
+ s_P = via_path_edge.first;
}
}
- int lengthOfPathT_Test_Path = unpackedUntilDistance;
- unpackedUntilDistance = 0;
- //Traverse path s-->v
- for (unsigned i = 0, lengthOfPackedPath = packed_v_t_path.size() - 1; (i < lengthOfPackedPath) && unpackStack.empty(); ++i) {
- typename SearchGraph::EdgeIterator edgeID = search_graph->FindEdgeInEitherDirection( packed_v_t_path[i], packed_v_t_path[i + 1]);
- int lengthOfCurrentEdge = search_graph->GetEdgeData(edgeID).distance;
- if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) {
- unpackStack.push( std::make_pair(packed_v_t_path[i], packed_v_t_path[i + 1]));
- } else {
- unpackedUntilDistance += lengthOfCurrentEdge;
+ int t_test_path_length = unpacked_until_distance;
+ unpacked_until_distance = 0;
+ // Traverse path s-->v
+ BOOST_ASSERT(!packed_v_t_path.empty());
+ for (unsigned i = 0, packed_path_length = static_cast<unsigned>(packed_v_t_path.size() - 1);
+ (i < packed_path_length) && unpack_stack.empty();
+ ++i)
+ {
+ const EdgeID edgeID =
+ facade->FindEdgeInEitherDirection(packed_v_t_path[i], packed_v_t_path[i + 1]);
+ int length_of_current_edge = facade->GetEdgeData(edgeID).distance;
+ if (length_of_current_edge + unpacked_until_distance >= T_threshold)
+ {
+ unpack_stack.emplace(packed_v_t_path[i], packed_v_t_path[i + 1]);
+ }
+ else
+ {
+ unpacked_until_distance += length_of_current_edge;
t_P = packed_v_t_path[i + 1];
}
}
- while (!unpackStack.empty()) {
- const SearchSpaceEdge viaPathEdge = unpackStack.top();
- unpackStack.pop();
- typename SearchGraph::EdgeIterator edgeIDInViaPath = search_graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second);
- if(UINT_MAX == edgeIDInViaPath)
+ while (!unpack_stack.empty())
+ {
+ const SearchSpaceEdge via_path_edge = unpack_stack.top();
+ unpack_stack.pop();
+ EdgeID edge_in_via_path_id =
+ facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second);
+ if (SPECIAL_EDGEID == edge_in_via_path_id)
+ {
return false;
- typename SearchGraph::EdgeData currentEdgeData = search_graph->GetEdgeData(edgeIDInViaPath);
- const bool IsViaEdgeShortCut = currentEdgeData.shortcut;
- if (IsViaEdgeShortCut) {
- const NodeID middleOfViaPath = currentEdgeData.id;
- typename SearchGraph::EdgeIterator edgeIDOfFirstSegment = search_graph->FindEdgeInEitherDirection(viaPathEdge.first, middleOfViaPath);
- int lengthOfFirstSegment = search_graph->GetEdgeData( edgeIDOfFirstSegment).distance;
- //Check if first segment is the one to go over treshold? if yes first segment to stack, else push second segment to stack and add distance of first one.
- if (unpackedUntilDistance + lengthOfFirstSegment >= T_threshold) {
- unpackStack.push( std::make_pair(viaPathEdge.first, middleOfViaPath));
- } else {
- unpackedUntilDistance += lengthOfFirstSegment;
- unpackStack.push( std::make_pair(middleOfViaPath, viaPathEdge.second));
+ }
+
+ const EdgeData ¤t_edge_data = facade->GetEdgeData(edge_in_via_path_id);
+ const bool IsViaEdgeShortCut = current_edge_data.shortcut;
+ if (IsViaEdgeShortCut)
+ {
+ const NodeID middleOfViaPath = current_edge_data.id;
+ EdgeID edgeIDOfFirstSegment =
+ facade->FindEdgeInEitherDirection(via_path_edge.first, middleOfViaPath);
+ int lengthOfFirstSegment = facade->GetEdgeData(edgeIDOfFirstSegment).distance;
+ // Check if first segment is the one to go over treshold? if yes first segment to
+ // stack, else push second segment to stack and add distance of first one.
+ if (unpacked_until_distance + lengthOfFirstSegment >= T_threshold)
+ {
+ unpack_stack.emplace(via_path_edge.first, middleOfViaPath);
+ }
+ else
+ {
+ unpacked_until_distance += lengthOfFirstSegment;
+ unpack_stack.emplace(middleOfViaPath, via_path_edge.second);
}
- } else {
+ }
+ else
+ {
// edge is not a shortcut, set the start node for T-Test to end of edge.
- unpackedUntilDistance += currentEdgeData.distance;
- t_P = viaPathEdge.second;
+ unpacked_until_distance += current_edge_data.distance;
+ t_P = via_path_edge.second;
}
}
- lengthOfPathT_Test_Path += unpackedUntilDistance;
- //Run actual T-Test query and compare if distances equal.
- super::_queryData.InitializeOrClearThirdThreadLocalStorage();
+ t_test_path_length += unpacked_until_distance;
+ // Run actual T-Test query and compare if distances equal.
+ engine_working_data.InitializeOrClearThirdThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
+
+ QueryHeap &forward_heap3 = *engine_working_data.forwardHeap3;
+ QueryHeap &reverse_heap3 = *engine_working_data.backwardHeap3;
+ int upper_bound = INVALID_EDGE_WEIGHT;
+ NodeID middle = SPECIAL_NODEID;
- QueryHeap& forward_heap3 = *super::_queryData.forwardHeap3;
- QueryHeap& backward_heap3 = *super::_queryData.backwardHeap3;
- int _upperBound = INT_MAX;
- NodeID middle = UINT_MAX;
forward_heap3.Insert(s_P, 0, s_P);
- backward_heap3.Insert(t_P, 0, t_P);
- //exploration from s and t until deletemin/(1+epsilon) > _lengthOfShortestPath
- while (forward_heap3.Size() + backward_heap3.Size() > 0) {
- if (forward_heap3.Size() > 0) {
- super::RoutingStep(forward_heap3, backward_heap3, &middle, &_upperBound, offset, true);
+ reverse_heap3.Insert(t_P, 0, t_P);
+ // exploration from s and t until deletemin/(1+epsilon) > _lengt_oO_sShortest_path
+ while ((forward_heap3.Size() + reverse_heap3.Size()) > 0)
+ {
+ if (!forward_heap3.Empty())
+ {
+ super::RoutingStep(forward_heap3, reverse_heap3, &middle, &upper_bound, true);
}
- if (backward_heap3.Size() > 0) {
- super::RoutingStep(backward_heap3, forward_heap3, &middle, &_upperBound, offset, false);
+ if (!reverse_heap3.Empty())
+ {
+ super::RoutingStep(reverse_heap3, forward_heap3, &middle, &upper_bound, false);
}
}
- return (_upperBound <= lengthOfPathT_Test_Path);
+ return (upper_bound <= t_test_path_length);
}
};
-#endif /* ALTERNATIVEROUTES_H_ */
+#endif /* ALTERNATIVE_PATH_ROUTING_H */
diff --git a/RoutingAlgorithms/BasicRoutingInterface.h b/RoutingAlgorithms/BasicRoutingInterface.h
index caef97a..464c088 100644
--- a/RoutingAlgorithms/BasicRoutingInterface.h
+++ b/RoutingAlgorithms/BasicRoutingInterface.h
@@ -1,225 +1,411 @@
/*
- 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 BASICROUTINGINTERFACE_H_
-#define BASICROUTINGINTERFACE_H_
-
-#include "../Plugins/RawRouteData.h"
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef BASIC_ROUTING_INTERFACE_H
+#define BASIC_ROUTING_INTERFACE_H
+
+#include "../DataStructures/RawRouteData.h"
+#include "../DataStructures/SearchEngineData.h"
+#include "../DataStructures/TurnInstructions.h"
#include "../Util/ContainerUtils.h"
+#include "../Util/SimpleLogger.h"
-#include <boost/noncopyable.hpp>
-
-#include <cassert>
-#include <climits>
+#include <boost/assert.hpp>
#include <stack>
-template<class QueryDataT>
-class BasicRoutingInterface : boost::noncopyable{
-protected:
- QueryDataT & _queryData;
-public:
- BasicRoutingInterface(QueryDataT & qd) : _queryData(qd) { }
- virtual ~BasicRoutingInterface(){ };
-
- 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 ){
- if(newDistance>=0 ) {
- *middle = node;
- *_upperbound = newDistance;
- } else {
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap2;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap2;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::forwardHeap3;
+SearchEngineData::SearchEngineHeapPtr SearchEngineData::backwardHeap3;
+
+template <class DataFacadeT> class BasicRoutingInterface
+{
+ private:
+ typedef typename DataFacadeT::EdgeData EdgeData;
+
+ protected:
+ DataFacadeT *facade;
+
+ public:
+ BasicRoutingInterface() = delete;
+ BasicRoutingInterface(const BasicRoutingInterface &) = delete;
+ explicit BasicRoutingInterface(DataFacadeT *facade) : facade(facade) {}
+ virtual ~BasicRoutingInterface() {};
+
+ inline void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
+ SearchEngineData::QueryHeap &reverse_heap,
+ NodeID *middle_node_id,
+ int *upper_bound,
+ const bool forward_direction) const
+ {
+ const NodeID node = forward_heap.DeleteMin();
+ const int distance = forward_heap.GetKey(node);
+ if (reverse_heap.WasInserted(node))
+ {
+ const int new_distance = reverse_heap.GetKey(node) + distance;
+ if (new_distance < *upper_bound)
+ {
+ if (new_distance >= 0)
+ {
+ *middle_node_id = node;
+ *upper_bound = new_distance;
}
}
}
- if(distance-edgeBasedOffset > *_upperbound){
- _forwardHeap.DeleteAll();
+ if (distance > *upper_bound)
+ {
+ forward_heap.DeleteAll();
return;
}
- //Stalling
- for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); ++edge ) {
- const typename QueryDataT::Graph::EdgeData & data = _queryData.graph->GetEdgeData(edge);
- bool backwardDirectionFlag = (!forwardDirection) ? data.forward : data.backward;
- if(backwardDirectionFlag) {
- const NodeID to = _queryData.graph->GetTarget(edge);
- const int edgeWeight = data.distance;
-
- assert( edgeWeight > 0 );
-
- if(_forwardHeap.WasInserted( to )) {
- if(_forwardHeap.GetKey( to ) + edgeWeight < distance) {
+ // Stalling
+ for (auto edge : facade->GetAdjacentEdgeRange(node))
+ {
+ const EdgeData &data = facade->GetEdgeData(edge);
+ const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
+ if (reverse_flag)
+ {
+ const NodeID to = facade->GetTarget(edge);
+ const int edge_weight = data.distance;
+
+ BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
+
+ if (forward_heap.WasInserted(to))
+ {
+ if (forward_heap.GetKey(to) + edge_weight < distance)
+ {
return;
}
}
}
}
- for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); ++edge ) {
- const typename QueryDataT::Graph::EdgeData & data = _queryData.graph->GetEdgeData(edge);
- bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward );
- if(forwardDirectionFlag) {
+ for (auto edge : facade->GetAdjacentEdgeRange(node))
+ {
+ const EdgeData &data = facade->GetEdgeData(edge);
+ bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
+ if (forward_directionFlag)
+ {
- const NodeID to = _queryData.graph->GetTarget(edge);
- const int edgeWeight = data.distance;
+ const NodeID to = facade->GetTarget(edge);
+ const int edge_weight = data.distance;
- assert( edgeWeight > 0 );
- const int toDistance = distance + edgeWeight;
+ BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
+ const int to_distance = distance + edge_weight;
- //New Node discovered -> Add to Heap + Node Info Storage
- if ( !_forwardHeap.WasInserted( to ) ) {
- _forwardHeap.Insert( to, toDistance, node );
+ // New Node discovered -> Add to Heap + Node Info Storage
+ if (!forward_heap.WasInserted(to))
+ {
+ forward_heap.Insert(to, to_distance, node);
}
- //Found a shorter Path -> Update distance
- else if ( toDistance < _forwardHeap.GetKey( to ) ) {
- _forwardHeap.GetData( to ).parent = node;
- _forwardHeap.DecreaseKey( to, toDistance );
- //new parent
+ // Found a shorter Path -> Update distance
+ else if (to_distance < forward_heap.GetKey(to))
+ {
+ // new parent
+ forward_heap.GetData(to).parent = node;
+ forward_heap.DecreaseKey(to, to_distance);
}
}
}
}
- inline void UnpackPath(const std::vector<NodeID> & packedPath, std::vector<_PathData> & unpackedPath) const {
- const unsigned sizeOfPackedPath = packedPath.size();
- std::stack<std::pair<NodeID, NodeID> > recursionStack;
-
- //We have to push the path in reverse order onto the stack because it's LIFO.
- for(unsigned i = sizeOfPackedPath-1; i > 0; --i){
- recursionStack.push(std::make_pair(packedPath[i-1], packedPath[i]));
+ inline void UnpackPath(const std::vector<NodeID> &packed_path,
+ const PhantomNodes &phantom_node_pair,
+ std::vector<PathData> &unpacked_path) const
+ {
+ const bool start_traversed_in_reverse =
+ (packed_path.front() != phantom_node_pair.source_phantom.forward_node_id);
+ const bool target_traversed_in_reverse =
+ (packed_path.back() != phantom_node_pair.target_phantom.forward_node_id);
+
+ const unsigned packed_path_size = static_cast<unsigned>(packed_path.size());
+ std::stack<std::pair<NodeID, NodeID>> recursion_stack;
+
+ // We have to push the path in reverse order onto the stack because it's LIFO.
+ for (unsigned i = packed_path_size - 1; i > 0; --i)
+ {
+ recursion_stack.emplace(packed_path[i - 1], packed_path[i]);
}
std::pair<NodeID, NodeID> edge;
- while(!recursionStack.empty()) {
- edge = recursionStack.top();
- recursionStack.pop();
-
- typename QueryDataT::Graph::EdgeIterator smallestEdge = SPECIAL_EDGEID;
- int smallestWeight = INT_MAX;
- for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.first);eit < _queryData.graph->EndEdges(edge.first);++eit){
- const int weight = _queryData.graph->GetEdgeData(eit).distance;
- if(_queryData.graph->GetTarget(eit) == edge.second && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).forward){
- smallestEdge = eit;
- smallestWeight = weight;
+ while (!recursion_stack.empty())
+ {
+ /*
+ Graphical representation of variables:
+
+ edge.first edge.second
+ *------------------>*
+ edge_id
+ */
+ edge = recursion_stack.top();
+ recursion_stack.pop();
+
+ // facade->FindEdge does not suffice here in case of shortcuts.
+ // The above explanation unclear? Think!
+ EdgeID smaller_edge_id = SPECIAL_EDGEID;
+ int edge_weight = INT_MAX;
+ for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+ {
+ const int weight = facade->GetEdgeData(edge_id).distance;
+ if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
+ facade->GetEdgeData(edge_id).forward)
+ {
+ smaller_edge_id = edge_id;
+ edge_weight = weight;
}
}
- if(smallestEdge == SPECIAL_EDGEID){
- for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.second);eit < _queryData.graph->EndEdges(edge.second);++eit){
- const int weight = _queryData.graph->GetEdgeData(eit).distance;
- if(_queryData.graph->GetTarget(eit) == edge.first && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).backward){
- smallestEdge = eit;
- smallestWeight = weight;
+ /*
+ Graphical representation of variables:
+
+ edge.first edge.second
+ *<------------------*
+ edge_id
+ */
+ if (SPECIAL_EDGEID == smaller_edge_id)
+ {
+ for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+ {
+ const int weight = facade->GetEdgeData(edge_id).distance;
+ if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
+ facade->GetEdgeData(edge_id).backward)
+ {
+ smaller_edge_id = edge_id;
+ edge_weight = weight;
+ }
+ }
+ }
+ BOOST_ASSERT_MSG(edge_weight != INVALID_EDGE_WEIGHT, "edge id invalid");
+
+ const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
+ if (ed.shortcut)
+ { // unpack
+ const NodeID middle_node_id = ed.id;
+ // again, we need to this in reversed order
+ recursion_stack.emplace(middle_node_id, edge.second);
+ recursion_stack.emplace(edge.first, middle_node_id);
+ }
+ else
+ {
+ BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
+ unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
+ const TurnInstruction turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
+
+ if (!facade->EdgeIsCompressed(ed.id))
+ {
+ BOOST_ASSERT(!facade->EdgeIsCompressed(ed.id));
+ unpacked_path.emplace_back(facade->GetGeometryIndexForEdgeID(ed.id),
+ name_index,
+ turn_instruction,
+ ed.distance);
+ }
+ else
+ {
+ std::vector<unsigned> id_vector;
+ facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
+ id_vector);
+
+ const int start_index =
+ (unpacked_path.empty()
+ ? ((start_traversed_in_reverse)
+ ? id_vector.size() -
+ phantom_node_pair.source_phantom.fwd_segment_position - 1
+ : phantom_node_pair.source_phantom.fwd_segment_position)
+ : 0);
+ const int end_index = id_vector.size();
+
+ BOOST_ASSERT(start_index >= 0);
+ BOOST_ASSERT(start_index <= end_index);
+ for (int i = start_index; i < end_index; ++i)
+ {
+ unpacked_path.emplace_back(id_vector[i], name_index, TurnInstruction::NoTurn, 0);
}
+ unpacked_path.back().turn_instruction = turn_instruction;
+ unpacked_path.back().segment_duration = ed.distance;
}
}
- assert(smallestWeight != INT_MAX);
+ }
+ if (SPECIAL_EDGEID != phantom_node_pair.target_phantom.packed_geometry_id)
+ {
+ std::vector<unsigned> id_vector;
+ facade->GetUncompressedGeometry(phantom_node_pair.target_phantom.packed_geometry_id,
+ id_vector);
+ if (target_traversed_in_reverse)
+ {
+ std::reverse(id_vector.begin(), id_vector.end());
+ }
+ const bool is_local_path = (phantom_node_pair.source_phantom.packed_geometry_id ==
+ phantom_node_pair.target_phantom.packed_geometry_id) &&
+ unpacked_path.empty();
+
+ int start_index = 0;
+ int end_index = phantom_node_pair.target_phantom.fwd_segment_position;
+ if (target_traversed_in_reverse)
+ {
+ end_index =
+ id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
+ }
+ if (is_local_path)
+ {
+ start_index = phantom_node_pair.source_phantom.fwd_segment_position;
+ end_index = phantom_node_pair.target_phantom.fwd_segment_position;
+ if (target_traversed_in_reverse)
+ {
+ start_index =
+ id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position;
+ end_index =
+ id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
+ }
+ }
+
+ BOOST_ASSERT(start_index >= 0);
+ for (int i = start_index; i != end_index; (start_index < end_index ? ++i : --i))
+ {
+ BOOST_ASSERT(i >= -1);
+ unpacked_path.emplace_back(PathData{id_vector[i],
+ phantom_node_pair.target_phantom.name_id,
+ TurnInstruction::NoTurn,
+ 0});
+ }
+ }
- const typename QueryDataT::Graph::EdgeData& ed = _queryData.graph->GetEdgeData(smallestEdge);
- if(ed.shortcut) {//unpack
- const NodeID middle = ed.id;
- //again, we need to this in reversed order
- recursionStack.push(std::make_pair(middle, edge.second));
- recursionStack.push(std::make_pair(edge.first, middle));
- } else {
- assert(!ed.shortcut);
- unpackedPath.push_back(_PathData(ed.id, _queryData.nodeHelpDesk->getNameIndexFromEdgeID(ed.id), _queryData.nodeHelpDesk->getTurnInstructionFromEdgeID(ed.id), ed.distance) );
+ // there is no equivalent to a node-based node in an edge-expanded graph.
+ // two equivalent routes may start (or end) at different node-based edges
+ // as they are added with the offset how much "distance" on the edge
+ // has already been traversed. Depending on offset one needs to remove
+ // the last node.
+ if (unpacked_path.size() > 1)
+ {
+ const unsigned last_index = unpacked_path.size() - 1;
+ const unsigned second_to_last_index = last_index - 1;
+
+ // looks like a trivially true check but tests for underflow
+ BOOST_ASSERT(last_index > second_to_last_index);
+
+ if (unpacked_path[last_index].node == unpacked_path[second_to_last_index].node)
+ {
+ unpacked_path.pop_back();
}
+ BOOST_ASSERT(!unpacked_path.empty());
}
}
- inline void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> & unpackedPath) const {
- std::stack<std::pair<NodeID, NodeID> > recursionStack;
- recursionStack.push(std::make_pair(s,t));
+ inline void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> &unpacked_path) const
+ {
+ std::stack<std::pair<NodeID, NodeID>> recursion_stack;
+ recursion_stack.emplace(s, t);
std::pair<NodeID, NodeID> edge;
- while(!recursionStack.empty()) {
- edge = recursionStack.top();
- recursionStack.pop();
-
- typename QueryDataT::Graph::EdgeIterator smallestEdge = SPECIAL_EDGEID;
- int smallestWeight = INT_MAX;
- for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.first);eit < _queryData.graph->EndEdges(edge.first);++eit){
- const int weight = _queryData.graph->GetEdgeData(eit).distance;
- if(_queryData.graph->GetTarget(eit) == edge.second && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).forward){
- smallestEdge = eit;
- smallestWeight = weight;
+ while (!recursion_stack.empty())
+ {
+ edge = recursion_stack.top();
+ recursion_stack.pop();
+
+ EdgeID smaller_edge_id = SPECIAL_EDGEID;
+ int edge_weight = INT_MAX;
+ for (auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
+ {
+ const int weight = facade->GetEdgeData(edge_id).distance;
+ if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
+ facade->GetEdgeData(edge_id).forward)
+ {
+ smaller_edge_id = edge_id;
+ edge_weight = weight;
}
}
- if(smallestEdge == SPECIAL_EDGEID){
- for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.second);eit < _queryData.graph->EndEdges(edge.second);++eit){
- const int weight = _queryData.graph->GetEdgeData(eit).distance;
- if(_queryData.graph->GetTarget(eit) == edge.first && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).backward){
- smallestEdge = eit;
- smallestWeight = weight;
+ if (SPECIAL_EDGEID == smaller_edge_id)
+ {
+ for (auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
+ {
+ const int weight = facade->GetEdgeData(edge_id).distance;
+ if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
+ facade->GetEdgeData(edge_id).backward)
+ {
+ smaller_edge_id = edge_id;
+ edge_weight = weight;
}
}
}
- assert(smallestWeight != INT_MAX);
-
- const typename QueryDataT::Graph::EdgeData& ed = _queryData.graph->GetEdgeData(smallestEdge);
- if(ed.shortcut) {//unpack
- const NodeID middle = ed.id;
- //again, we need to this in reversed order
- recursionStack.push(std::make_pair(middle, edge.second));
- recursionStack.push(std::make_pair(edge.first, middle));
- } else {
- assert(!ed.shortcut);
- unpackedPath.push_back(edge.first );
+ BOOST_ASSERT_MSG(edge_weight != INT_MAX, "edge weight invalid");
+
+ const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
+ if (ed.shortcut)
+ { // unpack
+ const NodeID middle_node_id = ed.id;
+ // again, we need to this in reversed order
+ recursion_stack.emplace(middle_node_id, edge.second);
+ recursion_stack.emplace(edge.first, middle_node_id);
+ }
+ else
+ {
+ BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
+ unpacked_path.emplace_back(edge.first);
}
}
- unpackedPath.push_back(t);
+ unpacked_path.emplace_back(t);
}
- inline void RetrievePackedPathFromHeap(typename QueryDataT::QueryHeap & _fHeap, typename QueryDataT::QueryHeap & _bHeap, const NodeID middle, std::vector<NodeID>& packedPath) const {
- NodeID pathNode = middle;
- while(pathNode != _fHeap.GetData(pathNode).parent) {
- pathNode = _fHeap.GetData(pathNode).parent;
- packedPath.push_back(pathNode);
+ inline void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
+ const SearchEngineData::QueryHeap &reverse_heap,
+ const NodeID middle_node_id,
+ std::vector<NodeID> &packed_path) const
+ {
+ NodeID current_node_id = middle_node_id;
+ while (current_node_id != forward_heap.GetData(current_node_id).parent)
+ {
+ current_node_id = forward_heap.GetData(current_node_id).parent;
+ packed_path.emplace_back(current_node_id);
+ }
+ std::reverse(packed_path.begin(), packed_path.end());
+ packed_path.emplace_back(middle_node_id);
+ current_node_id = middle_node_id;
+ while (current_node_id != reverse_heap.GetData(current_node_id).parent)
+ {
+ current_node_id = reverse_heap.GetData(current_node_id).parent;
+ packed_path.emplace_back(current_node_id);
}
-
- std::reverse(packedPath.begin(), packedPath.end());
- packedPath.push_back(middle);
- pathNode = middle;
- while (pathNode != _bHeap.GetData(pathNode).parent){
- pathNode = _bHeap.GetData(pathNode).parent;
- packedPath.push_back(pathNode);
- }
}
- inline void RetrievePackedPathFromSingleHeap(typename QueryDataT::QueryHeap & search_heap, const NodeID middle, std::vector<NodeID>& packed_path) const {
- NodeID pathNode = middle;
- while(pathNode != search_heap.GetData(pathNode).parent) {
- pathNode = search_heap.GetData(pathNode).parent;
- packed_path.push_back(pathNode);
+ inline void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
+ const NodeID middle_node_id,
+ std::vector<NodeID> &packed_path) const
+ {
+ NodeID current_node_id = middle_node_id;
+ while (current_node_id != search_heap.GetData(current_node_id).parent)
+ {
+ current_node_id = search_heap.GetData(current_node_id).parent;
+ packed_path.emplace_back(current_node_id);
}
}
};
-
-#endif /* BASICROUTINGINTERFACE_H_ */
+#endif // BASIC_ROUTING_INTERFACE_H
diff --git a/RoutingAlgorithms/ManyToManyRouting.h b/RoutingAlgorithms/ManyToManyRouting.h
new file mode 100644
index 0000000..7819c67
--- /dev/null
+++ b/RoutingAlgorithms/ManyToManyRouting.h
@@ -0,0 +1,264 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef MANY_TO_MANY_ROUTING_H
+#define MANY_TO_MANY_ROUTING_H
+
+#include "BasicRoutingInterface.h"
+#include "../DataStructures/SearchEngineData.h"
+#include "../typedefs.h"
+
+#include <boost/assert.hpp>
+
+#include <limits>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+template <class DataFacadeT> class ManyToManyRouting : public BasicRoutingInterface<DataFacadeT>
+{
+ typedef BasicRoutingInterface<DataFacadeT> super;
+ typedef SearchEngineData::QueryHeap QueryHeap;
+ SearchEngineData &engine_working_data;
+
+ struct NodeBucket
+ {
+ unsigned target_id; // essentially a row in the distance matrix
+ EdgeWeight distance;
+ NodeBucket(const unsigned target_id, const EdgeWeight distance)
+ : target_id(target_id), distance(distance)
+ {
+ }
+ };
+ typedef std::unordered_map<NodeID, std::vector<NodeBucket>> SearchSpaceWithBuckets;
+
+ public:
+ ManyToManyRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
+ : super(facade), engine_working_data(engine_working_data)
+ {
+ }
+
+ ~ManyToManyRouting() {}
+
+ std::shared_ptr<std::vector<EdgeWeight>> operator()(const PhantomNodeArray &phantom_nodes_array)
+ const
+ {
+ const unsigned number_of_locations = static_cast<unsigned>(phantom_nodes_array.size());
+ std::shared_ptr<std::vector<EdgeWeight>> result_table =
+ std::make_shared<std::vector<EdgeWeight>>(number_of_locations * number_of_locations,
+ std::numeric_limits<EdgeWeight>::max());
+
+ engine_working_data.InitializeOrClearFirstThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
+
+ QueryHeap &query_heap = *(engine_working_data.forwardHeap);
+
+ SearchSpaceWithBuckets search_space_with_buckets;
+
+ unsigned target_id = 0;
+ for (const std::vector<PhantomNode> &phantom_node_vector : phantom_nodes_array)
+ {
+ query_heap.Clear();
+ // insert target(s) at distance 0
+
+ for (const PhantomNode &phantom_node : phantom_node_vector)
+ {
+ if (SPECIAL_NODEID != phantom_node.forward_node_id)
+ {
+ query_heap.Insert(phantom_node.forward_node_id,
+ phantom_node.GetForwardWeightPlusOffset(),
+ phantom_node.forward_node_id);
+ }
+ if (SPECIAL_NODEID != phantom_node.reverse_node_id)
+ {
+ query_heap.Insert(phantom_node.reverse_node_id,
+ phantom_node.GetReverseWeightPlusOffset(),
+ phantom_node.reverse_node_id);
+ }
+ }
+
+ // explore search space
+ while (!query_heap.Empty())
+ {
+ BackwardRoutingStep(target_id, query_heap, search_space_with_buckets);
+ }
+ ++target_id;
+ }
+
+ // for each source do forward search
+ unsigned source_id = 0;
+ for (const std::vector<PhantomNode> &phantom_node_vector : phantom_nodes_array)
+ {
+ query_heap.Clear();
+ for (const PhantomNode &phantom_node : phantom_node_vector)
+ {
+ // insert sources at distance 0
+ if (SPECIAL_NODEID != phantom_node.forward_node_id)
+ {
+ query_heap.Insert(phantom_node.forward_node_id,
+ -phantom_node.GetForwardWeightPlusOffset(),
+ phantom_node.forward_node_id);
+ }
+ if (SPECIAL_NODEID != phantom_node.reverse_node_id)
+ {
+ query_heap.Insert(phantom_node.reverse_node_id,
+ -phantom_node.GetReverseWeightPlusOffset(),
+ phantom_node.reverse_node_id);
+ }
+ }
+
+ // explore search space
+ while (!query_heap.Empty())
+ {
+ ForwardRoutingStep(source_id,
+ number_of_locations,
+ query_heap,
+ search_space_with_buckets,
+ result_table);
+ }
+
+ ++source_id;
+ }
+ BOOST_ASSERT(source_id == target_id);
+ return result_table;
+ }
+
+ void ForwardRoutingStep(const unsigned source_id,
+ const unsigned number_of_locations,
+ QueryHeap &query_heap,
+ const SearchSpaceWithBuckets &search_space_with_buckets,
+ std::shared_ptr<std::vector<EdgeWeight>> result_table) const
+ {
+ const NodeID node = query_heap.DeleteMin();
+ const int source_distance = query_heap.GetKey(node);
+
+ // check if each encountered node has an entry
+ const auto bucket_iterator = search_space_with_buckets.find(node);
+ // iterate bucket if there exists one
+ if (bucket_iterator != search_space_with_buckets.end())
+ {
+ const std::vector<NodeBucket> &bucket_list = bucket_iterator->second;
+ for (const NodeBucket ¤t_bucket : bucket_list)
+ {
+ // get target id from bucket entry
+ const unsigned target_id = current_bucket.target_id;
+ const int target_distance = current_bucket.distance;
+ const EdgeWeight current_distance =
+ (*result_table)[source_id * number_of_locations + target_id];
+ // check if new distance is better
+ const EdgeWeight new_distance = source_distance + target_distance;
+ if (new_distance >= 0 && new_distance < current_distance)
+ {
+ (*result_table)[source_id * number_of_locations + target_id] =
+ (source_distance + target_distance);
+ }
+ }
+ }
+ if (StallAtNode<true>(node, source_distance, query_heap))
+ {
+ return;
+ }
+ RelaxOutgoingEdges<true>(node, source_distance, query_heap);
+ }
+
+ void BackwardRoutingStep(const unsigned target_id,
+ QueryHeap &query_heap,
+ SearchSpaceWithBuckets &search_space_with_buckets) const
+ {
+ const NodeID node = query_heap.DeleteMin();
+ const int target_distance = query_heap.GetKey(node);
+
+ // store settled nodes in search space bucket
+ search_space_with_buckets[node].emplace_back(target_id, target_distance);
+
+ if (StallAtNode<false>(node, target_distance, query_heap))
+ {
+ return;
+ }
+
+ RelaxOutgoingEdges<false>(node, target_distance, query_heap);
+ }
+
+ template <bool forward_direction>
+ inline void
+ RelaxOutgoingEdges(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap) const
+ {
+ for (auto edge : super::facade->GetAdjacentEdgeRange(node))
+ {
+ const auto &data = super::facade->GetEdgeData(edge);
+ const bool direction_flag = (forward_direction ? data.forward : data.backward);
+ if (direction_flag)
+ {
+ const NodeID to = super::facade->GetTarget(edge);
+ const int edge_weight = data.distance;
+
+ BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
+ const int to_distance = distance + edge_weight;
+
+ // New Node discovered -> Add to Heap + Node Info Storage
+ if (!query_heap.WasInserted(to))
+ {
+ query_heap.Insert(to, to_distance, node);
+ }
+ // Found a shorter Path -> Update distance
+ else if (to_distance < query_heap.GetKey(to))
+ {
+ // new parent
+ query_heap.GetData(to).parent = node;
+ query_heap.DecreaseKey(to, to_distance);
+ }
+ }
+ }
+ }
+
+ // Stalling
+ template <bool forward_direction>
+ inline bool StallAtNode(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap)
+ const
+ {
+ for (auto edge : super::facade->GetAdjacentEdgeRange(node))
+ {
+ const auto &data = super::facade->GetEdgeData(edge);
+ const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
+ if (reverse_flag)
+ {
+ const NodeID to = super::facade->GetTarget(edge);
+ const int edge_weight = data.distance;
+ BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
+ if (query_heap.WasInserted(to))
+ {
+ if (query_heap.GetKey(to) + edge_weight < distance)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+};
+#endif
diff --git a/RoutingAlgorithms/ShortestPathRouting.h b/RoutingAlgorithms/ShortestPathRouting.h
index 472e7dd..cc5afe5 100644
--- a/RoutingAlgorithms/ShortestPathRouting.h
+++ b/RoutingAlgorithms/ShortestPathRouting.h
@@ -1,201 +1,318 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
-#ifndef SHORTESTPATHROUTING_H_
-#define SHORTESTPATHROUTING_H_
+#ifndef SHORTEST_PATH_ROUTING_H
+#define SHORTEST_PATH_ROUTING_H
+
+#include <boost/assert.hpp>
#include "BasicRoutingInterface.h"
+#include "../DataStructures/SearchEngineData.h"
+#include "../typedefs.h"
+
+template <class DataFacadeT> class ShortestPathRouting : public BasicRoutingInterface<DataFacadeT>
+{
+ typedef BasicRoutingInterface<DataFacadeT> super;
+ typedef SearchEngineData::QueryHeap QueryHeap;
+ SearchEngineData &engine_working_data;
-template<class QueryDataT>
-class ShortestPathRouting : public BasicRoutingInterface<QueryDataT>{
- typedef BasicRoutingInterface<QueryDataT> super;
- typedef typename QueryDataT::QueryHeap QueryHeap;
-public:
- ShortestPathRouting( QueryDataT & qd) : super(qd) {}
+ public:
+ ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
+ : super(facade), engine_working_data(engine_working_data)
+ {
+ }
~ShortestPathRouting() {}
- void operator()(std::vector<PhantomNodes> & phantomNodesVector, RawRouteData & rawRouteData) const {
- BOOST_FOREACH(const PhantomNodes & phantomNodePair, phantomNodesVector) {
- if(!phantomNodePair.AtLeastOnePhantomNodeIsUINTMAX()) {
- rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX;
- return;
- }
- }
+ void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
+ RawRouteData &raw_route_data) const
+ {
int distance1 = 0;
int distance2 = 0;
-
- bool searchFrom1stStartNode = true;
- bool searchFrom2ndStartNode = true;
+ bool search_from_1st_node = true;
+ bool search_from_2nd_node = true;
NodeID middle1 = UINT_MAX;
NodeID middle2 = UINT_MAX;
- std::vector<NodeID> packedPath1;
- std::vector<NodeID> packedPath2;
+ std::vector<std::vector<NodeID>> packed_legs1(phantom_nodes_vector.size());
+ std::vector<std::vector<NodeID>> packed_legs2(phantom_nodes_vector.size());
- super::_queryData.InitializeOrClearFirstThreadLocalStorage();
- super::_queryData.InitializeOrClearSecondThreadLocalStorage();
- super::_queryData.InitializeOrClearThirdThreadLocalStorage();
+ engine_working_data.InitializeOrClearFirstThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
+ engine_working_data.InitializeOrClearSecondThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
+ engine_working_data.InitializeOrClearThirdThreadLocalStorage(
+ super::facade->GetNumberOfNodes());
- QueryHeap & forward_heap1 = *(super::_queryData.forwardHeap);
- QueryHeap & reverse_heap1 = *(super::_queryData.backwardHeap);
- QueryHeap & forward_heap2 = *(super::_queryData.forwardHeap2);
- QueryHeap & reverse_heap2 = *(super::_queryData.backwardHeap2);
+ QueryHeap &forward_heap1 = *(engine_working_data.forwardHeap);
+ QueryHeap &reverse_heap1 = *(engine_working_data.backwardHeap);
+ QueryHeap &forward_heap2 = *(engine_working_data.forwardHeap2);
+ QueryHeap &reverse_heap2 = *(engine_working_data.backwardHeap2);
- //Get distance to next pair of target nodes.
- BOOST_FOREACH(const PhantomNodes & phantomNodePair, phantomNodesVector) {
- forward_heap1.Clear(); forward_heap2.Clear();
- reverse_heap1.Clear(); reverse_heap2.Clear();
- int _localUpperbound1 = INT_MAX;
- int _localUpperbound2 = INT_MAX;
+ int current_leg = 0;
+ // Get distance to next pair of target nodes.
+ for (const PhantomNodes &phantom_node_pair : phantom_nodes_vector)
+ {
+ forward_heap1.Clear();
+ forward_heap2.Clear();
+ reverse_heap1.Clear();
+ reverse_heap2.Clear();
+ int local_upper_bound1 = INT_MAX;
+ int local_upper_bound2 = INT_MAX;
middle1 = UINT_MAX;
middle2 = UINT_MAX;
- //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);
-
- //run two-Target Dijkstra routing step.
- while(0 < (forward_heap1.Size() + reverse_heap1.Size() )){
- if(0 < forward_heap1.Size()){
- super::RoutingStep(forward_heap1, reverse_heap1, &middle1, &_localUpperbound1, forward_offset, true);
+ // insert new starting nodes into forward heap, adjusted by previous distances.
+ if (search_from_1st_node &&
+ phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
+ {
+ forward_heap1.Insert(
+ phantom_node_pair.source_phantom.forward_node_id,
+ distance1 - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+ phantom_node_pair.source_phantom.forward_node_id);
+ forward_heap2.Insert(
+ phantom_node_pair.source_phantom.forward_node_id,
+ distance1 - phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
+ phantom_node_pair.source_phantom.forward_node_id);
+ }
+ if (search_from_2nd_node &&
+ phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
+ {
+ forward_heap1.Insert(
+ phantom_node_pair.source_phantom.reverse_node_id,
+ distance2 - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
+ phantom_node_pair.source_phantom.reverse_node_id);
+ forward_heap2.Insert(
+ phantom_node_pair.source_phantom.reverse_node_id,
+ distance2 - phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
+ phantom_node_pair.source_phantom.reverse_node_id);
+ }
+
+ // insert new backward nodes into backward heap, unadjusted.
+ if (phantom_node_pair.target_phantom.forward_node_id != SPECIAL_NODEID)
+ {
+ reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_node_id,
+ phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
+ phantom_node_pair.target_phantom.forward_node_id);
+ }
+
+ if (phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID)
+ {
+ reverse_heap2.Insert(phantom_node_pair.target_phantom.reverse_node_id,
+ phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
+ phantom_node_pair.target_phantom.reverse_node_id);
+ }
+
+ // run two-Target Dijkstra routing step.
+ while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
+ {
+ if (0 < forward_heap1.Size())
+ {
+ super::RoutingStep(
+ forward_heap1, reverse_heap1, &middle1, &local_upper_bound1, true);
}
- if(0 < reverse_heap1.Size() ){
- super::RoutingStep(reverse_heap1, forward_heap1, &middle1, &_localUpperbound1, reverse_offset, false);
+ if (0 < reverse_heap1.Size())
+ {
+ super::RoutingStep(
+ reverse_heap1, forward_heap1, &middle1, &local_upper_bound1, false);
}
}
- if(0 < reverse_heap2.Size()) {
- while(0 < (forward_heap2.Size() + reverse_heap2.Size() )){
- if(0 < forward_heap2.Size()){
- super::RoutingStep(forward_heap2, reverse_heap2, &middle2, &_localUpperbound2, forward_offset, true);
+
+ if (!reverse_heap2.Empty())
+ {
+ while (0 < (forward_heap2.Size() + reverse_heap2.Size()))
+ {
+ if (0 < forward_heap2.Size())
+ {
+ super::RoutingStep(
+ forward_heap2, reverse_heap2, &middle2, &local_upper_bound2, true);
}
- if(0 < reverse_heap2.Size()){
- super::RoutingStep(reverse_heap2, forward_heap2, &middle2, &_localUpperbound2, reverse_offset, false);
+ if (0 < reverse_heap2.Size())
+ {
+ super::RoutingStep(
+ reverse_heap2, forward_heap2, &middle2, &local_upper_bound2, false);
}
}
}
- //No path found for both target nodes?
- if((INT_MAX == _localUpperbound1) && (INT_MAX == _localUpperbound2)) {
- rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX;
+ // No path found for both target nodes?
+ if ((INVALID_EDGE_WEIGHT == local_upper_bound1) &&
+ (INVALID_EDGE_WEIGHT == local_upper_bound2))
+ {
+ raw_route_data.shortest_path_length = INVALID_EDGE_WEIGHT;
+ raw_route_data.alternative_path_length = INVALID_EDGE_WEIGHT;
return;
}
- if(UINT_MAX == middle1) {
- searchFrom1stStartNode = false;
+
+ search_from_1st_node = true;
+ search_from_2nd_node = true;
+ if (SPECIAL_NODEID == middle1)
+ {
+ search_from_1st_node = false;
}
- if(UINT_MAX == middle2) {
- searchFrom2ndStartNode = false;
+ if (SPECIAL_NODEID == middle2)
+ {
+ search_from_2nd_node = false;
}
- //Was at most one of the two paths not found?
- assert(!(INT_MAX == distance1 && INT_MAX == distance2));
+ // Was at most one of the two paths not found?
+ BOOST_ASSERT_MSG((INT_MAX != distance1 || INT_MAX != distance2), "no path found");
+
+ // Unpack paths if they exist
+ std::vector<NodeID> temporary_packed_leg1;
+ std::vector<NodeID> temporary_packed_leg2;
- //Unpack paths if they exist
- std::vector<NodeID> temporaryPackedPath1;
- std::vector<NodeID> temporaryPackedPath2;
- if(INT_MAX != _localUpperbound1) {
- super::RetrievePackedPathFromHeap(forward_heap1, reverse_heap1, middle1, temporaryPackedPath1);
+ BOOST_ASSERT((unsigned)current_leg < packed_legs1.size());
+ BOOST_ASSERT((unsigned)current_leg < packed_legs2.size());
+
+ if (INVALID_EDGE_WEIGHT != local_upper_bound1)
+ {
+ super::RetrievePackedPathFromHeap(
+ forward_heap1, reverse_heap1, middle1, temporary_packed_leg1);
}
- if(INT_MAX != _localUpperbound2) {
- super::RetrievePackedPathFromHeap(forward_heap2, reverse_heap2, middle2, temporaryPackedPath2);
+ if (INVALID_EDGE_WEIGHT != local_upper_bound2)
+ {
+ super::RetrievePackedPathFromHeap(
+ forward_heap2, reverse_heap2, middle2, temporary_packed_leg2);
}
- //if one of the paths was not found, replace it with the other one.
- if(0 == temporaryPackedPath1.size()) {
- temporaryPackedPath1.insert(temporaryPackedPath1.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end());
- _localUpperbound1 = _localUpperbound2;
+ // if one of the paths was not found, replace it with the other one.
+ if (temporary_packed_leg1.empty())
+ {
+ temporary_packed_leg1.insert(temporary_packed_leg1.end(),
+ temporary_packed_leg2.begin(),
+ temporary_packed_leg2.end());
+ local_upper_bound1 = local_upper_bound2;
}
- if(0 == temporaryPackedPath2.size()) {
- temporaryPackedPath2.insert(temporaryPackedPath2.end(), temporaryPackedPath1.begin(), temporaryPackedPath1.end());
- _localUpperbound2 = _localUpperbound1;
+ if (temporary_packed_leg2.empty())
+ {
+ temporary_packed_leg2.insert(temporary_packed_leg2.end(),
+ temporary_packed_leg1.begin(),
+ temporary_packed_leg1.end());
+ local_upper_bound2 = local_upper_bound1;
}
- assert(0 < temporaryPackedPath1.size() && 0 < temporaryPackedPath2.size());
+ BOOST_ASSERT_MSG(!temporary_packed_leg1.empty() || !temporary_packed_leg2.empty(),
+ "tempory packed paths empty");
+
+ BOOST_ASSERT((0 == current_leg) || !packed_legs1[current_leg - 1].empty());
+ BOOST_ASSERT((0 == current_leg) || !packed_legs2[current_leg - 1].empty());
- //Plug paths together, s.t. end of packed path is begin of temporary packed path
- if(0 < packedPath1.size() && 0 < packedPath2.size() ) {
- if( *(temporaryPackedPath1.begin()) == *(temporaryPackedPath2.begin())) {
- //both new route segments start with the same node, thus one of the packedPath must go.
- assert( (packedPath1.size() == packedPath2.size() ) || (*(packedPath1.end()-1) != *(packedPath2.end()-1)) );
- if( *(packedPath1.end()-1) == *(temporaryPackedPath1.begin())) {
- packedPath2.clear();
- packedPath2.insert(packedPath2.end(), packedPath1.begin(), packedPath1.end());
- distance2 = distance1;
- } else {
- packedPath1.clear();
- packedPath1.insert(packedPath1.end(), packedPath2.begin(), packedPath2.end());
- distance1 = distance2;
+ if (0 < current_leg)
+ {
+ const NodeID end_id_of_segment1 = packed_legs1[current_leg - 1].back();
+ const NodeID end_id_of_segment2 = packed_legs2[current_leg - 1].back();
+ BOOST_ASSERT(!temporary_packed_leg1.empty());
+ const NodeID start_id_of_leg1 = temporary_packed_leg1.front();
+ const NodeID start_id_of_leg2 = temporary_packed_leg2.front();
+ if ((end_id_of_segment1 != start_id_of_leg1) &&
+ (end_id_of_segment2 != start_id_of_leg2))
+ {
+ std::swap(temporary_packed_leg1, temporary_packed_leg2);
+ std::swap(local_upper_bound1, local_upper_bound2);
+ }
+ }
+
+ // remove the shorter path if both legs end at the same segment
+ if (0 < current_leg)
+ {
+ const NodeID start_id_of_leg1 = temporary_packed_leg1.front();
+ const NodeID start_id_of_leg2 = temporary_packed_leg2.front();
+ if (start_id_of_leg1 == start_id_of_leg2)
+ {
+ const NodeID last_id_of_packed_legs1 = packed_legs1[current_leg - 1].back();
+ const NodeID last_id_of_packed_legs2 = packed_legs2[current_leg - 1].back();
+ if (start_id_of_leg1 != last_id_of_packed_legs1)
+ {
+ packed_legs1 = packed_legs2;
+ BOOST_ASSERT(start_id_of_leg1 == temporary_packed_leg1.front());
}
- } else {
- //packed paths 1 and 2 may need to switch.
- if(*(packedPath1.end()-1) != *(temporaryPackedPath1.begin())) {
- packedPath1.swap(packedPath2);
- std::swap(distance1, distance2);
+ else if (start_id_of_leg2 != last_id_of_packed_legs2)
+ {
+ packed_legs2 = packed_legs1;
+ BOOST_ASSERT(start_id_of_leg2 == temporary_packed_leg2.front());
}
}
}
- packedPath1.insert(packedPath1.end(), temporaryPackedPath1.begin(), temporaryPackedPath1.end());
- packedPath2.insert(packedPath2.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end());
+ BOOST_ASSERT(packed_legs1.size() == packed_legs2.size());
- if( (packedPath1.back() == packedPath2.back()) && phantomNodePair.targetPhantom.isBidirected() ) {
+ packed_legs1[current_leg].insert(packed_legs1[current_leg].end(),
+ temporary_packed_leg1.begin(),
+ temporary_packed_leg1.end());
+ BOOST_ASSERT(packed_legs1[current_leg].size() == temporary_packed_leg1.size());
+ packed_legs2[current_leg].insert(packed_legs2[current_leg].end(),
+ temporary_packed_leg2.begin(),
+ temporary_packed_leg2.end());
+ BOOST_ASSERT(packed_legs2[current_leg].size() == temporary_packed_leg2.size());
- NodeID lastNodeID = packedPath2.back();
- searchFrom1stStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode+1);
- searchFrom2ndStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode);
+ if ((packed_legs1[current_leg].back() == packed_legs2[current_leg].back()) &&
+ phantom_node_pair.target_phantom.isBidirected())
+ {
+ const NodeID last_node_id = packed_legs2[current_leg].back();
+ search_from_1st_node &=
+ !(last_node_id == phantom_node_pair.target_phantom.reverse_node_id);
+ search_from_2nd_node &=
+ !(last_node_id == phantom_node_pair.target_phantom.forward_node_id);
+ BOOST_ASSERT(search_from_1st_node != search_from_2nd_node);
}
- distance1 += _localUpperbound1;
- distance2 += _localUpperbound2;
+ distance1 = local_upper_bound1;
+ distance2 = local_upper_bound2;
+ ++current_leg;
+ }
+
+ if (distance1 > distance2)
+ {
+ std::swap(packed_legs1, packed_legs2);
}
+ raw_route_data.unpacked_path_segments.resize(packed_legs1.size());
+
+ for (unsigned i = 0; i < packed_legs1.size(); ++i)
+ {
+ BOOST_ASSERT(!phantom_nodes_vector.empty());
+ BOOST_ASSERT(packed_legs1.size() == raw_route_data.unpacked_path_segments.size());
+
+ PhantomNodes unpack_phantom_node_pair = phantom_nodes_vector[i];
+ super::UnpackPath(
+ // -- packed input
+ packed_legs1[i],
+ // -- start and end of (sub-)route
+ unpack_phantom_node_pair,
+ // -- unpacked output
+ raw_route_data.unpacked_path_segments[i]);
- if(distance1 > distance2){
- std::swap(packedPath1, packedPath2);
+ raw_route_data.source_traversed_in_reverse.push_back(
+ (packed_legs1[i].front() != phantom_nodes_vector[i].source_phantom.forward_node_id));
+ raw_route_data.target_traversed_in_reverse.push_back(
+ (packed_legs1[i].back() != phantom_nodes_vector[i].target_phantom.forward_node_id));
}
- remove_consecutive_duplicates_from_vector(packedPath1);
- super::UnpackPath(packedPath1, rawRouteData.computedShortestPath);
- rawRouteData.lengthOfShortestPath = std::min(distance1, distance2);
- return;
+ raw_route_data.shortest_path_length = std::min(distance1, distance2);
}
};
-#endif /* SHORTESTPATHROUTING_H_ */
+#endif /* SHORTEST_PATH_ROUTING_H */
diff --git a/Server/APIGrammar.h b/Server/APIGrammar.h
index 3b87941..4c339d0 100644
--- a/Server/APIGrammar.h
+++ b/Server/APIGrammar.h
@@ -1,24 +1,29 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
#ifndef APIGRAMMAR_H_
#define APIGRAMMAR_H_
@@ -30,15 +35,17 @@ or see http://www.gnu.org/licenses/agpl.txt.
namespace qi = boost::spirit::qi;
template <typename Iterator, class HandlerT>
-struct APIGrammar : qi::grammar<Iterator> {
- APIGrammar(HandlerT * h) : APIGrammar::base_type(api_call), handler(h) {
+struct APIGrammar : qi::grammar<Iterator>
+{
+ explicit APIGrammar(HandlerT * h) : APIGrammar::base_type(api_call), handler(h)
+ {
api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >> *(query);
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | cmp | language | instruction | geometry | alt_route | old_API) ) ;
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
- jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithDot[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
- checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
+ jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
+ checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >> qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
@@ -48,16 +55,17 @@ struct APIGrammar : qi::grammar<Iterator> {
alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >> qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >> string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
- string = +(qi::char_("a-zA-Z"));
- stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
+ string = +(qi::char_("a-zA-Z"));
+ stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
+ stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') | (qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z") ));
}
+
qi::rule<Iterator> api_call, query;
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location, hint,
- stringwithDot, language, instruction, geometry,
+ stringwithDot, stringwithPercent, language, instruction, geometry,
cmp, alt_route, old_API;
HandlerT * handler;
};
-
#endif /* APIGRAMMAR_H_ */
diff --git a/Server/BasicDatastructures.h b/Server/BasicDatastructures.h
deleted file mode 100644
index 366abae..0000000
--- a/Server/BasicDatastructures.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- 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 BASIC_DATASTRUCTURES_H
-#define BASIC_DATASTRUCTURES_H
-#include <string>
-#include <sstream>
-#include <boost/foreach.hpp>
-
-#include "../Util/StringUtil.h"
-
-namespace http {
-
-const std::string okString = "HTTP/1.0 200 OK\r\n";
-const std::string badRequestString = "HTTP/1.0 400 Bad Request\r\n";
-const std::string internalServerErrorString = "HTTP/1.0 500 Internal Server Error\r\n";
-
-const char okHTML[] = "";
-const char badRequestHTML[] = "<html><head><title>Bad Request</title></head><body><h1>400 Bad Request</h1></body></html>";
-const char internalServerErrorHTML[] = "<html><head><title>Internal Server Error</title></head><body><h1>500 Internal Server Error</h1></body></html>";
-const char seperators[] = { ':', ' ' };
-const char crlf[] = { '\r', '\n' };
-
-struct Header {
- std::string name;
- std::string value;
- void Clear() {
- name.clear();
- value.clear();
- }
-};
-
-enum CompressionType {
- noCompression,
- gzipRFC1952,
- deflateRFC1951
-} Compression;
-
-struct Request {
- std::string uri;
- std::string referrer;
- std::string agent;
- boost::asio::ip::address endpoint;
-};
-
-struct Reply {
- Reply() : status(ok) { content.reserve(2 << 20); }
- enum status_type {
- ok = 200,
- badRequest = 400,
- internalServerError = 500
- } status;
-
- std::vector<Header> headers;
- std::vector<boost::asio::const_buffer> toBuffers();
- std::vector<boost::asio::const_buffer> HeaderstoBuffers();
- std::string content;
- static Reply stockReply(status_type status);
- void setSize(const unsigned size) {
- BOOST_FOREACH ( Header& h, headers) {
- if("Content-Length" == h.name) {
- std::string sizeString;
- intToString(size,h.value );
- }
- }
- }
-};
-
-boost::asio::const_buffer ToBuffer(Reply::status_type status) {
- switch (status) {
- case Reply::ok:
- return boost::asio::buffer(okString);
- case Reply::internalServerError:
- return boost::asio::buffer(internalServerErrorString);
- default:
- return boost::asio::buffer(badRequestString);
- }
-}
-
-std::string ToString(Reply::status_type status) {
- switch (status) {
- case Reply::ok:
- return okHTML;
- case Reply::badRequest:
- return badRequestHTML;
- default:
- return internalServerErrorHTML;
- }
-}
-
-std::vector<boost::asio::const_buffer> Reply::toBuffers(){
- std::vector<boost::asio::const_buffer> buffers;
- buffers.push_back(ToBuffer(status));
- for (std::size_t i = 0; i < headers.size(); ++i) {
- Header& h = headers[i];
- buffers.push_back(boost::asio::buffer(h.name));
- buffers.push_back(boost::asio::buffer(seperators));
- buffers.push_back(boost::asio::buffer(h.value));
- buffers.push_back(boost::asio::buffer(crlf));
- }
- buffers.push_back(boost::asio::buffer(crlf));
- buffers.push_back(boost::asio::buffer(content));
- return buffers;
-}
-
-std::vector<boost::asio::const_buffer> Reply::HeaderstoBuffers(){
- std::vector<boost::asio::const_buffer> buffers;
- buffers.push_back(ToBuffer(status));
- for (std::size_t i = 0; i < headers.size(); ++i) {
- Header& h = headers[i];
-// std::cout << h.name << ": " << h.value << std::endl;
- buffers.push_back(boost::asio::buffer(h.name));
- buffers.push_back(boost::asio::buffer(seperators));
- buffers.push_back(boost::asio::buffer(h.value));
- buffers.push_back(boost::asio::buffer(crlf));
- }
- buffers.push_back(boost::asio::buffer(crlf));
- return buffers;
-}
-
-Reply Reply::stockReply(Reply::status_type status) {
- Reply rep;
- rep.status = status;
- rep.content = ToString(status);
- rep.headers.resize(3);
- rep.headers[0].name = "Access-Control-Allow-Origin";
- rep.headers[0].value = "*";
- rep.headers[1].name = "Content-Length";
-
- 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;
-}
-} // namespace http
-
-#endif //BASIC_DATASTRUCTURES_H
diff --git a/Server/Connection.cpp b/Server/Connection.cpp
new file mode 100644
index 0000000..674fe62
--- /dev/null
+++ b/Server/Connection.cpp
@@ -0,0 +1,174 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "Connection.h"
+#include "RequestHandler.h"
+#include "RequestParser.h"
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
+#include <boost/iostreams/filter/gzip.hpp>
+
+#include <string>
+#include <vector>
+
+namespace http
+{
+
+Connection::Connection(boost::asio::io_service &io_service, RequestHandler &handler)
+ : strand(io_service), TCP_socket(io_service), request_handler(handler)
+{
+}
+
+boost::asio::ip::tcp::socket &Connection::socket() { return TCP_socket; }
+
+/// Start the first asynchronous operation for the connection.
+void Connection::start()
+{
+ TCP_socket.async_read_some(
+ boost::asio::buffer(incoming_data_buffer),
+ strand.wrap(boost::bind(&Connection::handle_read,
+ this->shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+}
+
+void Connection::handle_read(const boost::system::error_code &error, std::size_t bytes_transferred)
+{
+ if (error)
+ {
+ return;
+ }
+
+ // no error detected, let's parse the request
+ CompressionType compression_type(noCompression);
+ boost::tribool result;
+ boost::tie(result, boost::tuples::ignore) =
+ request_parser.Parse(request,
+ incoming_data_buffer.data(),
+ incoming_data_buffer.data() + bytes_transferred,
+ &compression_type);
+
+ // the request has been parsed
+ if (result)
+ {
+ request.endpoint = TCP_socket.remote_endpoint().address();
+ request_handler.handle_request(request, reply);
+
+ // Header compression_header;
+ std::vector<char> compressed_output;
+ std::vector<boost::asio::const_buffer> output_buffer;
+
+ // compress the result w/ gzip/deflate if requested
+ switch (compression_type)
+ {
+ case deflateRFC1951:
+ // use deflate for compression
+ reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "deflate"});
+ CompressBufferCollection(reply.content, compression_type, compressed_output);
+ reply.SetSize(static_cast<unsigned>(compressed_output.size()));
+ output_buffer = reply.HeaderstoBuffers();
+ output_buffer.push_back(boost::asio::buffer(compressed_output));
+ break;
+ case gzipRFC1952:
+ // use gzip for compression
+ reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "gzip"});
+ CompressBufferCollection(reply.content, compression_type, compressed_output);
+ reply.SetSize(static_cast<unsigned>(compressed_output.size()));
+ output_buffer = reply.HeaderstoBuffers();
+ output_buffer.push_back(boost::asio::buffer(compressed_output));
+ break;
+ case noCompression:
+ // don't use any compression
+ reply.SetUncompressedSize();
+ output_buffer = reply.ToBuffers();
+ break;
+ }
+ // write result to stream
+ boost::asio::async_write(TCP_socket,
+ output_buffer,
+ strand.wrap(boost::bind(&Connection::handle_write,
+ this->shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+ else if (!result)
+ { // request is not parseable
+ reply = Reply::StockReply(Reply::badRequest);
+
+ boost::asio::async_write(TCP_socket,
+ reply.ToBuffers(),
+ strand.wrap(boost::bind(&Connection::handle_write,
+ this->shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+ else
+ {
+ // we don't have a result yet, so continue reading
+ TCP_socket.async_read_some(
+ boost::asio::buffer(incoming_data_buffer),
+ strand.wrap(boost::bind(&Connection::handle_read,
+ this->shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ }
+}
+
+/// Handle completion of a write operation.
+void Connection::handle_write(const boost::system::error_code &error)
+{
+ if (!error)
+ {
+ // Initiate graceful connection closure.
+ boost::system::error_code ignore_error;
+ TCP_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_error);
+ }
+}
+
+void Connection::CompressBufferCollection(std::vector<char> uncompressed_data,
+ CompressionType compression_type,
+ std::vector<char> &compressed_data)
+{
+ boost::iostreams::gzip_params compression_parameters;
+
+ // there's a trade-off between speed and size. speed wins
+ compression_parameters.level = boost::iostreams::zlib::best_speed;
+ // check which compression flavor is used
+ if (deflateRFC1951 == compression_type)
+ {
+ compression_parameters.noheader = true;
+ }
+
+ BOOST_ASSERT(compressed_data.empty());
+ // plug data into boost's compression stream
+ boost::iostreams::filtering_ostream gzip_stream;
+ gzip_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
+ gzip_stream.push(boost::iostreams::back_inserter(compressed_data));
+ gzip_stream.write(&uncompressed_data[0], uncompressed_data.size());
+ boost::iostreams::close(gzip_stream);
+}
+}
diff --git a/Server/Connection.h b/Server/Connection.h
index 5dd4b79..bc03c15 100644
--- a/Server/Connection.h
+++ b/Server/Connection.h
@@ -1,179 +1,104 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef CONNECTION_H
#define CONNECTION_H
-#include <vector>
+#include "RequestParser.h"
+#include "Http/CompressionType.h"
+#include "Http/Request.h"
+
+#include <osrm/Reply.h>
-#include <boost/asio.hpp>
#include <boost/array.hpp>
-#include <boost/bind.hpp>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
+#include <boost/asio.hpp>
+#include <boost/config.hpp>
+#include <boost/version.hpp>
+
+ #include <memory>
+ #include <string>
+ #include <vector>
+
+//workaround for incomplete std::shared_ptr compatibility in old boost versions
+#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
+
+namespace boost {
+template<class T>
+const T* get_pointer(std::shared_ptr<T> const& p)
+{
+ return p.get();
+}
+
+template<class T>
+T* get_pointer(std::shared_ptr<T>& p)
+{
+ return p.get();
+}
+} // namespace boost
+
+#endif
+
-#include "BasicDatastructures.h"
-#include "RequestHandler.h"
-#include "RequestParser.h"
-#include "zlib.h"
+class RequestHandler;
-namespace http {
+namespace http
+{
/// Represents a single connection from a client.
-class Connection : public boost::enable_shared_from_this<Connection>, private boost::noncopyable {
-public:
- explicit Connection(boost::asio::io_service& io_service, RequestHandler& handler) : strand(io_service), TCPsocket(io_service), requestHandler(handler) {}
-
- boost::asio::ip::tcp::socket& socket() {
- return TCPsocket;
- }
-
- /// Start the first asynchronous operation for the connection.
- void start() {
- TCPsocket.async_read_some(boost::asio::buffer(incomingDataBuffer), strand.wrap( boost::bind(&Connection::handleRead, this->shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
- }
-
-private:
- void handleRead(const boost::system::error_code& e, std::size_t bytes_transferred) {
- if (!e) {
- CompressionType compressionType(noCompression);
- boost::tribool result;
- boost::tie(result, boost::tuples::ignore) = requestParser.Parse( request, incomingDataBuffer.data(), incomingDataBuffer.data() + bytes_transferred, &compressionType);
-
- if (result) {
- // std::cout << "----" << std::endl;
- // if(compressionType == gzipRFC1952)
- // std::cout << "[debug] using gzip" << std::endl;
- // if(compressionType == deflateRFC1951)
- // std::cout << "[debug] using deflate" << std::endl;
- // if(compressionType == noCompression)
- // std::cout << "[debug] no compression" << std::endl;
- request.endpoint = TCPsocket.remote_endpoint().address();
- requestHandler.handle_request(request, reply);
-
- Header compressionHeader;
- std::vector<unsigned char> compressed;
- std::vector<boost::asio::const_buffer> outputBuffer;
- switch(compressionType) {
- case deflateRFC1951:
- compressionHeader.name = "Content-Encoding";
- compressionHeader.value = "deflate";
- reply.headers.insert(reply.headers.begin(), compressionHeader); //push_back(compressionHeader);
- compressCharArray(reply.content.c_str(), reply.content.length(), compressed, compressionType);
- reply.setSize(compressed.size());
- outputBuffer = reply.HeaderstoBuffers();
- outputBuffer.push_back(boost::asio::buffer(compressed));
- boost::asio::async_write(TCPsocket, outputBuffer, strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));
- break;
- case gzipRFC1952:
- compressionHeader.name = "Content-Encoding";
- compressionHeader.value = "gzip";
- reply.headers.insert(reply.headers.begin(), compressionHeader);
- compressCharArray(reply.content.c_str(), reply.content.length(), compressed, compressionType);
- reply.setSize(compressed.size());
- outputBuffer = reply.HeaderstoBuffers();
- outputBuffer.push_back(boost::asio::buffer(compressed));
- boost::asio::async_write(TCPsocket, outputBuffer, strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));break;
- case noCompression:
- boost::asio::async_write(TCPsocket, reply.toBuffers(), strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));
- break;
- }
-
- } else if (!result) {
- reply = Reply::stockReply(Reply::badRequest);
- boost::asio::async_write(TCPsocket, reply.toBuffers(), strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));
- } else {
- TCPsocket.async_read_some(boost::asio::buffer(incomingDataBuffer), strand.wrap( boost::bind(&Connection::handleRead, this->shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
- }
- }
- }
-
- /// Handle completion of a write operation.
- void handleWrite(const boost::system::error_code& e) {
- if (!e) {
- // Initiate graceful connection closure.
- boost::system::error_code ignoredEC;
- TCPsocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignoredEC);
- }
- // No new asynchronous operations are started. This means that all shared_ptr
- // references to the connection object will disappear and the object will be
- // destroyed automatically after this handler returns. The connection class's
- // destructor closes the socket.
- }
-
- void compressCharArray(const void *in_data, size_t in_data_size, std::vector<unsigned char> &buffer, CompressionType type) {
- const size_t BUFSIZE = 128 * 1024;
- unsigned char temp_buffer[BUFSIZE];
-
- z_stream strm;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.total_out = 0;
- strm.next_in = (unsigned char *)(in_data);
- strm.avail_in = in_data_size;
- strm.next_out = temp_buffer;
- strm.avail_out = BUFSIZE;
- strm.data_type = Z_ASCII;
-
- switch(type){
- case deflateRFC1951:
- deflateInit(&strm, Z_BEST_SPEED);
- break;
- case gzipRFC1952:
- /*
- * Big thanks to deusty who explains how to have gzip compression turned on by the right call to deflateInit2():
- * http://deusty.blogspot.com/2007/07/gzip-compressiondecompression.html
- */
- deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 9, Z_DEFAULT_STRATEGY);
- break;
- default:
- assert(false);
- break;
- }
-
- int deflate_res = Z_OK;
- do {
- if (strm.avail_out == 0) {
- buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE);
- strm.next_out = temp_buffer;
- strm.avail_out = BUFSIZE;
- }
- deflate_res = deflate(&strm, Z_FINISH);
-
- } while (deflate_res == Z_OK);
-
- assert(deflate_res == Z_STREAM_END);
- buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE - strm.avail_out);
- deflateEnd(&strm);
- }
-
- boost::asio::io_service::strand strand;
- boost::asio::ip::tcp::socket TCPsocket;
- RequestHandler& requestHandler;
- boost::array<char, 8192> incomingDataBuffer;
- Request request;
- RequestParser requestParser;
- Reply reply;
+class Connection : public std::enable_shared_from_this<Connection>
+{
+ public:
+ explicit Connection(boost::asio::io_service &io_service, RequestHandler &handler);
+ Connection(const Connection &) = delete;
+ Connection() = delete;
+
+ boost::asio::ip::tcp::socket &socket();
+
+ /// Start the first asynchronous operation for the connection.
+ void start();
+
+ private:
+ void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
+
+ /// Handle completion of a write operation.
+ void handle_write(const boost::system::error_code &e);
+
+ void CompressBufferCollection(std::vector<char> uncompressed_data,
+ CompressionType compression_type,
+ std::vector<char> &compressed_data);
+
+ boost::asio::io_service::strand strand;
+ boost::asio::ip::tcp::socket TCP_socket;
+ RequestHandler &request_handler;
+ boost::array<char, 8192> incoming_data_buffer;
+ Request request;
+ RequestParser request_parser;
+ Reply reply;
};
} // namespace http
diff --git a/Server/DataStructures/BaseDataFacade.h b/Server/DataStructures/BaseDataFacade.h
new file mode 100644
index 0000000..7897ca4
--- /dev/null
+++ b/Server/DataStructures/BaseDataFacade.h
@@ -0,0 +1,125 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef BASE_DATA_FACADE_H
+#define BASE_DATA_FACADE_H
+
+// Exposes all data access interfaces to the algorithms via base class ptr
+
+#include "../../DataStructures/EdgeBasedNode.h"
+#include "../../DataStructures/ImportNode.h"
+#include "../../DataStructures/PhantomNodes.h"
+#include "../../DataStructures/TurnInstructions.h"
+#include "../../Util/OSRMException.h"
+#include "../../Util/StringUtil.h"
+#include "../../typedefs.h"
+
+#include <boost/range/irange.hpp>
+
+#include <osrm/Coordinate.h>
+
+#include <string>
+
+typedef decltype(boost::irange(0u,0u)) EdgeRange;
+
+template <class EdgeDataT> class BaseDataFacade
+{
+ public:
+ typedef EdgeBasedNode RTreeLeaf;
+ typedef EdgeDataT EdgeData;
+ BaseDataFacade() {}
+ virtual ~BaseDataFacade() {}
+
+ // search graph access
+ virtual unsigned GetNumberOfNodes() const = 0;
+
+ virtual unsigned GetNumberOfEdges() const = 0;
+
+ virtual unsigned GetOutDegree(const NodeID n) const = 0;
+
+ virtual NodeID GetTarget(const EdgeID e) const = 0;
+
+ virtual EdgeDataT &GetEdgeData(const EdgeID e) = 0;
+
+ // virtual const EdgeDataT &GetEdgeData( const EdgeID e ) const = 0;
+
+ virtual EdgeID BeginEdges(const NodeID n) const = 0;
+
+ virtual EdgeID EndEdges(const NodeID n) const = 0;
+
+ virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
+
+ // searches for a specific edge
+ virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
+
+ virtual EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const = 0;
+
+ virtual EdgeID
+ FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
+
+ // node and edge information access
+ virtual FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const = 0;
+
+ virtual bool EdgeIsCompressed(const unsigned id) const = 0;
+
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const = 0;
+
+ virtual void GetUncompressedGeometry(const unsigned id,
+ std::vector<unsigned> &result_nodes) const = 0;
+
+ virtual TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
+
+ virtual bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
+ FixedPointCoordinate &result,
+ const unsigned zoom_level = 18) const = 0;
+
+ virtual bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &resulting_phantom_node,
+ const unsigned zoom_level) const = 0;
+
+ virtual bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ std::vector<PhantomNode> &resulting_phantom_node_vector,
+ const unsigned zoom_level,
+ const unsigned number_of_results) const = 0;
+
+ virtual unsigned GetCheckSum() const = 0;
+
+ virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
+
+ virtual void GetName(const unsigned name_id, std::string &result) const = 0;
+
+ std::string GetEscapedNameForNameID(const unsigned name_id) const
+ {
+ std::string temporary_string;
+ GetName(name_id, temporary_string);
+ return EscapeJSONString(temporary_string);
+ }
+
+ virtual std::string GetTimestamp() const = 0;
+};
+
+#endif // BASE_DATA_FACADE_H
diff --git a/Server/DataStructures/InternalDataFacade.h b/Server/DataStructures/InternalDataFacade.h
new file mode 100644
index 0000000..c2055bb
--- /dev/null
+++ b/Server/DataStructures/InternalDataFacade.h
@@ -0,0 +1,430 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef INTERNAL_DATA_FACADE
+#define INTERNAL_DATA_FACADE
+
+// implements all data storage when shared memory is _NOT_ used
+
+#include "BaseDataFacade.h"
+
+#include "../../DataStructures/OriginalEdgeData.h"
+#include "../../DataStructures/QueryNode.h"
+#include "../../DataStructures/QueryEdge.h"
+#include "../../DataStructures/SharedMemoryVectorWrapper.h"
+#include "../../DataStructures/StaticGraph.h"
+#include "../../DataStructures/StaticRTree.h"
+#include "../../DataStructures/RangeTable.h"
+#include "../../Util/BoostFileSystemFix.h"
+#include "../../Util/GraphLoader.h"
+#include "../../Util/ProgramOptions.h"
+#include "../../Util/SimpleLogger.h"
+
+#include <osrm/Coordinate.h>
+
+template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<EdgeDataT>
+{
+
+ private:
+ typedef BaseDataFacade<EdgeDataT> super;
+ typedef StaticGraph<typename super::EdgeData> QueryGraph;
+ typedef typename QueryGraph::InputEdge InputEdge;
+ typedef typename super::RTreeLeaf RTreeLeaf;
+
+ InternalDataFacade() {}
+
+ unsigned m_check_sum;
+ unsigned m_number_of_nodes;
+ QueryGraph *m_query_graph;
+ std::string m_timestamp;
+
+ std::shared_ptr<ShM<FixedPointCoordinate, false>::vector> m_coordinate_list;
+ ShM<NodeID, false>::vector m_via_node_list;
+ ShM<unsigned, false>::vector m_name_ID_list;
+ ShM<TurnInstruction, false>::vector m_turn_instruction_list;
+ ShM<char, false>::vector m_names_char_list;
+ ShM<bool, false>::vector m_egde_is_compressed;
+ ShM<unsigned, false>::vector m_geometry_indices;
+ ShM<unsigned, false>::vector m_geometry_list;
+
+ std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>>
+ m_static_rtree;
+ RangeTable<16, false> m_name_table;
+
+ void LoadTimestamp(const boost::filesystem::path ×tamp_path)
+ {
+ if (boost::filesystem::exists(timestamp_path))
+ {
+ SimpleLogger().Write() << "Loading Timestamp";
+ boost::filesystem::ifstream timestamp_stream(timestamp_path);
+ if (!timestamp_stream)
+ {
+ SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
+ }
+ getline(timestamp_stream, m_timestamp);
+ timestamp_stream.close();
+ }
+ if (m_timestamp.empty())
+ {
+ m_timestamp = "n/a";
+ }
+ if (25 < m_timestamp.length())
+ {
+ m_timestamp.resize(25);
+ }
+ }
+
+ void LoadGraph(const boost::filesystem::path &hsgr_path)
+ {
+ typename ShM<typename QueryGraph::NodeArrayEntry, false>::vector node_list;
+ typename ShM<typename QueryGraph::EdgeArrayEntry, false>::vector edge_list;
+
+ SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
+
+ m_number_of_nodes = readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
+
+ BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
+ // BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
+ SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size()
+ << " edges";
+ m_query_graph = new QueryGraph(node_list, edge_list);
+
+ BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
+ BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
+ SimpleLogger().Write() << "Data checksum is " << m_check_sum;
+ }
+
+ void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file,
+ const boost::filesystem::path &edges_file)
+ {
+ boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
+
+ NodeInfo current_node;
+ unsigned number_of_coordinates = 0;
+ nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
+ m_coordinate_list =
+ std::make_shared<std::vector<FixedPointCoordinate>>(number_of_coordinates);
+ for (unsigned i = 0; i < number_of_coordinates; ++i)
+ {
+ nodes_input_stream.read((char *)¤t_node, sizeof(NodeInfo));
+ m_coordinate_list->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
+ BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lat) >> 30) == 0);
+ BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lon) >> 30) == 0);
+ }
+ nodes_input_stream.close();
+
+ boost::filesystem::ifstream edges_input_stream(edges_file, std::ios::binary);
+ unsigned number_of_edges = 0;
+ edges_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
+ m_via_node_list.resize(number_of_edges);
+ m_name_ID_list.resize(number_of_edges);
+ m_turn_instruction_list.resize(number_of_edges);
+ m_egde_is_compressed.resize(number_of_edges);
+
+ unsigned compressed = 0;
+
+ OriginalEdgeData current_edge_data;
+ for (unsigned i = 0; i < number_of_edges; ++i)
+ {
+ edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
+ m_via_node_list[i] = current_edge_data.via_node;
+ m_name_ID_list[i] = current_edge_data.name_id;
+ m_turn_instruction_list[i] = current_edge_data.turn_instruction;
+ m_egde_is_compressed[i] = current_edge_data.compressed_geometry;
+ if (m_egde_is_compressed[i])
+ {
+ ++compressed;
+ }
+ }
+
+ edges_input_stream.close();
+ }
+
+ void LoadGeometries(const boost::filesystem::path &geometry_file)
+ {
+ std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
+ unsigned number_of_indices = 0;
+ unsigned number_of_compressed_geometries = 0;
+
+ geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
+
+ m_geometry_indices.resize(number_of_indices);
+ if (number_of_indices > 0)
+ {
+ geometry_stream.read((char *)&(m_geometry_indices[0]),
+ number_of_indices * sizeof(unsigned));
+ }
+
+ geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
+
+ BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
+ m_geometry_list.resize(number_of_compressed_geometries);
+
+ if (number_of_compressed_geometries > 0)
+ {
+ geometry_stream.read((char *)&(m_geometry_list[0]),
+ number_of_compressed_geometries * sizeof(unsigned));
+ }
+ geometry_stream.close();
+ }
+
+ void LoadRTree(const boost::filesystem::path &ram_index_path,
+ const boost::filesystem::path &file_index_path)
+ {
+ BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
+
+ m_static_rtree = std::make_shared<StaticRTree<RTreeLeaf>>(
+ ram_index_path, file_index_path, m_coordinate_list);
+ }
+
+ void LoadStreetNames(const boost::filesystem::path &names_file)
+ {
+ boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
+
+ name_stream >> m_name_table;
+
+ unsigned number_of_chars = 0;
+ name_stream.read((char *)&number_of_chars, sizeof(unsigned));
+ BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
+ m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
+ name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
+ if (0 == m_names_char_list.size())
+ {
+ SimpleLogger().Write(logWARNING) << "list of street names is empty";
+ }
+ name_stream.close();
+ }
+
+ public:
+ ~InternalDataFacade()
+ {
+ delete m_query_graph;
+ m_static_rtree.reset();
+ }
+
+ explicit InternalDataFacade(const ServerPaths &server_paths)
+ {
+ // generate paths of data files
+ if (server_paths.find("hsgrdata") == server_paths.end())
+ {
+ throw OSRMException("no hsgr file given in ini file");
+ }
+ if (server_paths.find("ramindex") == server_paths.end())
+ {
+ throw OSRMException("no ram index file given in ini file");
+ }
+ if (server_paths.find("fileindex") == server_paths.end())
+ {
+ throw OSRMException("no leaf index file given in ini file");
+ }
+ if (server_paths.find("geometries") == server_paths.end())
+ {
+ throw OSRMException("no geometries file given in ini file");
+ }
+ if (server_paths.find("nodesdata") == server_paths.end())
+ {
+ throw OSRMException("no nodes file given in ini file");
+ }
+ if (server_paths.find("edgesdata") == server_paths.end())
+ {
+ throw OSRMException("no edges file given in ini file");
+ }
+ if (server_paths.find("namesdata") == server_paths.end())
+ {
+ throw OSRMException("no names file given in ini file");
+ }
+
+ ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ const boost::filesystem::path &hsgr_path = paths_iterator->second;
+ paths_iterator = server_paths.find("timestamp");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ const boost::filesystem::path ×tamp_path = paths_iterator->second;
+ paths_iterator = server_paths.find("ramindex");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ const boost::filesystem::path &ram_index_path = paths_iterator->second;
+ paths_iterator = server_paths.find("fileindex");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ const boost::filesystem::path &file_index_path = paths_iterator->second;
+ paths_iterator = server_paths.find("nodesdata");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ const boost::filesystem::path &nodes_data_path = paths_iterator->second;
+ paths_iterator = server_paths.find("edgesdata");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ const boost::filesystem::path &edges_data_path = paths_iterator->second;
+ paths_iterator = server_paths.find("namesdata");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ const boost::filesystem::path &names_data_path = paths_iterator->second;
+ paths_iterator = server_paths.find("geometries");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ const boost::filesystem::path &geometries_path = paths_iterator->second;
+
+ // load data
+ SimpleLogger().Write() << "loading graph data";
+ AssertPathExists(hsgr_path);
+ LoadGraph(hsgr_path);
+ SimpleLogger().Write() << "loading egde information";
+ AssertPathExists(nodes_data_path);
+ AssertPathExists(edges_data_path);
+ LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
+ SimpleLogger().Write() << "loading geometries";
+ AssertPathExists(geometries_path);
+ LoadGeometries(geometries_path);
+ SimpleLogger().Write() << "loading r-tree";
+ AssertPathExists(ram_index_path);
+ AssertPathExists(file_index_path);
+ LoadRTree(ram_index_path, file_index_path);
+ SimpleLogger().Write() << "loading timestamp";
+ LoadTimestamp(timestamp_path);
+ SimpleLogger().Write() << "loading street names";
+ AssertPathExists(names_data_path);
+ LoadStreetNames(names_data_path);
+ }
+
+ // search graph access
+ unsigned GetNumberOfNodes() const { return m_query_graph->GetNumberOfNodes(); }
+
+ unsigned GetNumberOfEdges() const { return m_query_graph->GetNumberOfEdges(); }
+
+ unsigned GetOutDegree(const NodeID n) const { return m_query_graph->GetOutDegree(n); }
+
+ NodeID GetTarget(const EdgeID e) const { return m_query_graph->GetTarget(e); }
+
+ EdgeDataT &GetEdgeData(const EdgeID e) { return m_query_graph->GetEdgeData(e); }
+
+ const EdgeDataT &GetEdgeData(const EdgeID e) const { return m_query_graph->GetEdgeData(e); }
+
+ EdgeID BeginEdges(const NodeID n) const { return m_query_graph->BeginEdges(n); }
+
+ EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
+
+ EdgeRange GetAdjacentEdgeRange(const NodeID node) const
+ {
+ return m_query_graph->GetAdjacentEdgeRange(node);
+ };
+
+ // searches for a specific edge
+ EdgeID FindEdge(const NodeID from, const NodeID to) const
+ {
+ return m_query_graph->FindEdge(from, to);
+ }
+
+ EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const
+ {
+ return m_query_graph->FindEdgeInEitherDirection(from, to);
+ }
+
+ EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const
+ {
+ return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
+ }
+
+ // node and edge information access
+ FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const
+ {
+ return m_coordinate_list->at(id);
+ };
+
+ bool EdgeIsCompressed(const unsigned id) const { return m_egde_is_compressed.at(id); }
+
+ TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const
+ {
+ return m_turn_instruction_list.at(id);
+ }
+
+ bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
+ FixedPointCoordinate &result,
+ const unsigned zoom_level = 18) const
+ {
+ return m_static_rtree->LocateClosestEndPointForCoordinate(
+ input_coordinate, result, zoom_level);
+ }
+
+ bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &resulting_phantom_node,
+ const unsigned zoom_level) const
+ {
+ return m_static_rtree->FindPhantomNodeForCoordinate(
+ input_coordinate, resulting_phantom_node, zoom_level);
+ }
+
+ bool
+ IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ std::vector<PhantomNode> &resulting_phantom_node_vector,
+ const unsigned zoom_level,
+ const unsigned number_of_results) const
+ {
+ return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
+ input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
+ }
+
+ unsigned GetCheckSum() const { return m_check_sum; }
+
+ unsigned GetNameIndexFromEdgeID(const unsigned id) const
+ {
+ return m_name_ID_list.at(id);
+ };
+
+ void GetName(const unsigned name_id, std::string &result) const
+ {
+ if (UINT_MAX == name_id)
+ {
+ result = "";
+ return;
+ }
+ auto range = m_name_table.GetRange(name_id);
+
+ result.clear();
+ if (range.begin() != range.end())
+ {
+ result.resize(range.back() - range.front() + 1);
+ std::copy(m_names_char_list.begin() + range.front(),
+ m_names_char_list.begin() + range.back() + 1,
+ result.begin());
+ }
+ }
+
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const
+ {
+ return m_via_node_list.at(id);
+ }
+
+ virtual void GetUncompressedGeometry(const unsigned id, std::vector<unsigned> &result_nodes)
+ const
+ {
+ const unsigned begin = m_geometry_indices.at(id);
+ const unsigned end = m_geometry_indices.at(id + 1);
+
+ result_nodes.clear();
+ result_nodes.insert(
+ result_nodes.begin(), m_geometry_list.begin() + begin, m_geometry_list.begin() + end);
+ }
+
+ std::string GetTimestamp() const { return m_timestamp; }
+};
+
+#endif // INTERNAL_DATA_FACADE
diff --git a/Server/DataStructures/QueryObjectsStorage.cpp b/Server/DataStructures/QueryObjectsStorage.cpp
deleted file mode 100644
index df15f53..0000000
--- a/Server/DataStructures/QueryObjectsStorage.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- 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 "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
-) {
- 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
- );
-
- INFO("Data checksum is " << checkSum);
- graph = new QueryGraph(nodeList, edgeList);
- assert(0 == nodeList.size());
- assert(0 == edgeList.size());
-
- if(timestampPath.length()) {
- INFO("Loading Timestamp");
- std::ifstream timestampInStream(timestampPath.c_str());
- if(!timestampInStream) { WARN(timestampPath << " not found"); }
-
- getline(timestampInStream, timestamp);
- timestampInStream.close();
- }
- if(!timestamp.length())
- timestamp = "n/a";
- if(25 < timestamp.length())
- timestamp.resize(25);
-
- INFO("Loading auxiliary information");
- //Init nearest neighbor data structure
- std::ifstream nodesInStream(nodesPath.c_str(), std::ios::binary);
- if(!nodesInStream) { ERR(nodesPath << " not found"); }
- std::ifstream edgesInStream(edgesPath.c_str(), std::ios::binary);
- if(!edgesInStream) { ERR(edgesPath << " not found"); }
- nodeHelpDesk = new NodeInformationHelpDesk(ramIndexPath.c_str(), fileIndexPath.c_str(), n, checkSum);
- nodeHelpDesk->initNNGrid(nodesInStream, edgesInStream);
-
- //deserialize street name list
- INFO("Loading names index");
- std::ifstream namesInStream(namesPath.c_str(), std::ios::binary);
- if(!namesInStream) { ERR(namesPath << " not found"); }
- unsigned size(0);
- namesInStream.read((char *)&size, sizeof(unsigned));
- // names = new std::vector<std::string>();
-
- char buf[1024];
- for(unsigned i = 0; i < size; ++i) {
- unsigned sizeOfString = 0;
- namesInStream.read((char *)&sizeOfString, sizeof(unsigned));
- buf[sizeOfString] = '\0'; // instead of memset
- namesInStream.read(buf, sizeOfString);
- names.push_back(buf);
- }
- std::vector<std::string>(names).swap(names);
- hsgrInStream.close();
- namesInStream.close();
- INFO("All query data structures loaded");
-}
-
-QueryObjectsStorage::~QueryObjectsStorage() {
- // delete names;
- delete graph;
- delete nodeHelpDesk;
-}
diff --git a/Server/DataStructures/QueryObjectsStorage.h b/Server/DataStructures/QueryObjectsStorage.h
deleted file mode 100644
index be8bba0..0000000
--- a/Server/DataStructures/QueryObjectsStorage.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- 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 QUERYOBJECTSSTORAGE_H_
-#define QUERYOBJECTSSTORAGE_H_
-
-#include<vector>
-#include<string>
-
-#include "../../DataStructures/NodeInformationHelpDesk.h"
-#include "../../DataStructures/QueryEdge.h"
-#include "../../DataStructures/StaticGraph.h"
-
-struct QueryObjectsStorage {
- typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
- typedef QueryGraph::InputEdge InputEdge;
-
- NodeInformationHelpDesk * nodeHelpDesk;
- std::vector<std::string> names;
- QueryGraph * graph;
- std::string timestamp;
- unsigned checkSum;
-
- QueryObjectsStorage(std::string hsgrPath, std::string ramIndexPath, std::string fileIndexPath, std::string nodesPath, std::string edgesPath, std::string namesPath, std::string timestampPath);
-
- ~QueryObjectsStorage();
-};
-
-#endif /* QUERYOBJECTSSTORAGE_H_ */
diff --git a/Server/DataStructures/SharedBarriers.h b/Server/DataStructures/SharedBarriers.h
new file mode 100644
index 0000000..36ba08b
--- /dev/null
+++ b/Server/DataStructures/SharedBarriers.h
@@ -0,0 +1,60 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef SHARED_BARRIER_H
+#define SHARED_BARRIER_H
+
+#include <boost/interprocess/sync/named_mutex.hpp>
+#include <boost/interprocess/sync/named_condition.hpp>
+
+struct SharedBarriers
+{
+
+ SharedBarriers()
+ : pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
+ update_mutex(boost::interprocess::open_or_create, "update"),
+ query_mutex(boost::interprocess::open_or_create, "query"),
+ no_running_queries_condition(boost::interprocess::open_or_create, "no_running_queries"),
+ update_ongoing(false), number_of_queries(0)
+ {
+ }
+
+ // Mutex to protect access to the boolean variable
+ boost::interprocess::named_mutex pending_update_mutex;
+ boost::interprocess::named_mutex update_mutex;
+ boost::interprocess::named_mutex query_mutex;
+
+ // Condition that no update is running
+ boost::interprocess::named_condition no_running_queries_condition;
+
+ // Is there an ongoing update?
+ bool update_ongoing;
+ // Is there any query?
+ int number_of_queries;
+};
+
+#endif // SHARED_BARRIER_H
diff --git a/Server/DataStructures/SharedDataFacade.h b/Server/DataStructures/SharedDataFacade.h
new file mode 100644
index 0000000..a2cb990
--- /dev/null
+++ b/Server/DataStructures/SharedDataFacade.h
@@ -0,0 +1,398 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef SHARED_DATA_FACADE_H
+#define SHARED_DATA_FACADE_H
+
+// implements all data storage when shared memory _IS_ used
+
+#include "BaseDataFacade.h"
+#include "SharedDataType.h"
+
+#include "../../DataStructures/RangeTable.h"
+#include "../../DataStructures/StaticGraph.h"
+#include "../../DataStructures/StaticRTree.h"
+#include "../../Util/BoostFileSystemFix.h"
+#include "../../Util/ProgramOptions.h"
+#include "../../Util/SimpleLogger.h"
+
+#include <algorithm>
+#include <memory>
+
+template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDataT>
+{
+
+ private:
+ typedef EdgeDataT EdgeData;
+ typedef BaseDataFacade<EdgeData> super;
+ typedef StaticGraph<EdgeData, true> QueryGraph;
+ typedef typename StaticGraph<EdgeData, true>::NodeArrayEntry GraphNode;
+ typedef typename StaticGraph<EdgeData, true>::EdgeArrayEntry GraphEdge;
+ typedef typename RangeTable<16, true>::BlockT NameIndexBlock;
+ typedef typename QueryGraph::InputEdge InputEdge;
+ typedef typename super::RTreeLeaf RTreeLeaf;
+ typedef typename StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode
+ RTreeNode;
+
+ SharedDataLayout *data_layout;
+ char *shared_memory;
+ SharedDataTimestamp *data_timestamp_ptr;
+
+ SharedDataType CURRENT_LAYOUT;
+ SharedDataType CURRENT_DATA;
+ unsigned CURRENT_TIMESTAMP;
+
+ unsigned m_check_sum;
+ unsigned m_number_of_nodes;
+ std::shared_ptr<QueryGraph> m_query_graph;
+ std::shared_ptr<SharedMemory> m_layout_memory;
+ std::shared_ptr<SharedMemory> m_large_memory;
+ std::string m_timestamp;
+
+ std::shared_ptr<ShM<FixedPointCoordinate, true>::vector> m_coordinate_list;
+ ShM<NodeID, true>::vector m_via_node_list;
+ ShM<unsigned, true>::vector m_name_ID_list;
+ ShM<TurnInstruction, true>::vector m_turn_instruction_list;
+ ShM<char, true>::vector m_names_char_list;
+ ShM<unsigned, true>::vector m_name_begin_indices;
+ ShM<bool, true>::vector m_egde_is_compressed;
+ ShM<unsigned, true>::vector m_geometry_indices;
+ ShM<unsigned, true>::vector m_geometry_list;
+
+ std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>
+ m_static_rtree;
+
+ std::shared_ptr<RangeTable<16, true>> m_name_table;
+
+ void LoadChecksum()
+ {
+ m_check_sum =
+ *data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::HSGR_CHECKSUM);
+ SimpleLogger().Write() << "set checksum: " << m_check_sum;
+ }
+
+ void LoadTimestamp()
+ {
+ char *timestamp_ptr =
+ data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::TIMESTAMP);
+ m_timestamp.resize(data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP));
+ std::copy(timestamp_ptr,
+ timestamp_ptr + data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP),
+ m_timestamp.begin());
+ }
+
+ void LoadRTree(const boost::filesystem::path &file_index_path)
+ {
+ BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
+
+ RTreeNode *tree_ptr =
+ data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
+ m_static_rtree =
+ std::make_shared<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>(
+ tree_ptr,
+ data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
+ file_index_path,
+ m_coordinate_list);
+ }
+
+ void LoadGraph()
+ {
+ m_number_of_nodes = data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST];
+ GraphNode *graph_nodes_ptr =
+ data_layout->GetBlockPtr<GraphNode>(shared_memory, SharedDataLayout::GRAPH_NODE_LIST);
+
+ GraphEdge *graph_edges_ptr =
+ data_layout->GetBlockPtr<GraphEdge>(shared_memory, SharedDataLayout::GRAPH_EDGE_LIST);
+
+ typename ShM<GraphNode, true>::vector node_list(
+ graph_nodes_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST]);
+ typename ShM<GraphEdge, true>::vector edge_list(
+ graph_edges_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_EDGE_LIST]);
+ m_query_graph.reset(new QueryGraph(node_list, edge_list));
+ }
+
+ void LoadNodeAndEdgeInformation()
+ {
+
+ FixedPointCoordinate *coordinate_list_ptr = data_layout->GetBlockPtr<FixedPointCoordinate>(
+ shared_memory, SharedDataLayout::COORDINATE_LIST);
+ m_coordinate_list = std::make_shared<ShM<FixedPointCoordinate, true>::vector>(
+ coordinate_list_ptr, data_layout->num_entries[SharedDataLayout::COORDINATE_LIST]);
+
+ TurnInstruction *turn_instruction_list_ptr = data_layout->GetBlockPtr<TurnInstruction>(
+ shared_memory, SharedDataLayout::TURN_INSTRUCTION);
+ typename ShM<TurnInstruction, true>::vector turn_instruction_list(
+ turn_instruction_list_ptr,
+ data_layout->num_entries[SharedDataLayout::TURN_INSTRUCTION]);
+ m_turn_instruction_list.swap(turn_instruction_list);
+
+ unsigned *name_id_list_ptr =
+ data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_ID_LIST);
+ typename ShM<unsigned, true>::vector name_id_list(
+ name_id_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_ID_LIST]);
+ m_name_ID_list.swap(name_id_list);
+ }
+
+ void LoadViaNodeList()
+ {
+ NodeID *via_node_list_ptr =
+ data_layout->GetBlockPtr<NodeID>(shared_memory, SharedDataLayout::VIA_NODE_LIST);
+ typename ShM<NodeID, true>::vector via_node_list(
+ via_node_list_ptr, data_layout->num_entries[SharedDataLayout::VIA_NODE_LIST]);
+ m_via_node_list.swap(via_node_list);
+ }
+
+ void LoadNames()
+ {
+ unsigned *offsets_ptr =
+ data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_OFFSETS);
+ NameIndexBlock *blocks_ptr =
+ data_layout->GetBlockPtr<NameIndexBlock>(shared_memory, SharedDataLayout::NAME_BLOCKS);
+ typename ShM<unsigned, true>::vector name_offsets(
+ offsets_ptr, data_layout->num_entries[SharedDataLayout::NAME_OFFSETS]);
+ typename ShM<NameIndexBlock, true>::vector name_blocks(
+ blocks_ptr, data_layout->num_entries[SharedDataLayout::NAME_BLOCKS]);
+
+ char *names_list_ptr =
+ data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::NAME_CHAR_LIST);
+ typename ShM<char, true>::vector names_char_list(
+ names_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_CHAR_LIST]);
+ m_name_table = std::make_shared<RangeTable<16, true>>(
+ name_offsets, name_blocks, names_char_list.size());
+
+ m_names_char_list.swap(names_char_list);
+ }
+
+ void LoadGeometries()
+ {
+ unsigned *geometries_compressed_ptr = data_layout->GetBlockPtr<unsigned>(
+ shared_memory, SharedDataLayout::GEOMETRIES_INDICATORS);
+ typename ShM<bool, true>::vector egde_is_compressed(
+ geometries_compressed_ptr,
+ data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDICATORS]);
+ m_egde_is_compressed.swap(egde_is_compressed);
+
+ unsigned *geometries_index_ptr =
+ data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_INDEX);
+ typename ShM<unsigned, true>::vector geometry_begin_indices(
+ geometries_index_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDEX]);
+ m_geometry_indices.swap(geometry_begin_indices);
+
+ unsigned *geometries_list_ptr =
+ data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_LIST);
+ typename ShM<unsigned, true>::vector geometry_list(
+ geometries_list_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_LIST]);
+ m_geometry_list.swap(geometry_list);
+ }
+
+ public:
+ SharedDataFacade()
+ {
+ data_timestamp_ptr = (SharedDataTimestamp *)SharedMemoryFactory::Get(
+ CURRENT_REGIONS, sizeof(SharedDataTimestamp), false, false)->Ptr();
+
+ CURRENT_LAYOUT = LAYOUT_NONE;
+ CURRENT_DATA = DATA_NONE;
+ CURRENT_TIMESTAMP = 0;
+
+ // load data
+ CheckAndReloadFacade();
+ }
+
+ void CheckAndReloadFacade()
+ {
+ if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
+ CURRENT_DATA != data_timestamp_ptr->data ||
+ CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
+ {
+ // release the previous shared memory segments
+ SharedMemory::Remove(CURRENT_LAYOUT);
+ SharedMemory::Remove(CURRENT_DATA);
+
+ CURRENT_LAYOUT = data_timestamp_ptr->layout;
+ CURRENT_DATA = data_timestamp_ptr->data;
+ CURRENT_TIMESTAMP = data_timestamp_ptr->timestamp;
+
+ m_layout_memory.reset(SharedMemoryFactory::Get(CURRENT_LAYOUT));
+
+ data_layout = (SharedDataLayout *)(m_layout_memory->Ptr());
+
+ m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
+ shared_memory = (char *)(m_large_memory->Ptr());
+
+ std::ofstream out("debug.bin");
+ out.write(shared_memory, data_layout->GetSizeOfLayout());
+ out.close();
+
+ const char *file_index_ptr =
+ data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
+ boost::filesystem::path file_index_path(file_index_ptr);
+ if (!boost::filesystem::exists(file_index_path))
+ {
+ SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
+ throw OSRMException("Could not load leaf index file."
+ "Is any data loaded into shared memory?");
+ }
+
+ LoadGraph();
+ LoadChecksum();
+ LoadNodeAndEdgeInformation();
+ LoadGeometries();
+ LoadRTree(file_index_path);
+ LoadTimestamp();
+ LoadViaNodeList();
+ LoadNames();
+
+ data_layout->PrintInformation();
+ }
+ }
+
+ // search graph access
+ unsigned GetNumberOfNodes() const { return m_query_graph->GetNumberOfNodes(); }
+
+ unsigned GetNumberOfEdges() const { return m_query_graph->GetNumberOfEdges(); }
+
+ unsigned GetOutDegree(const NodeID n) const { return m_query_graph->GetOutDegree(n); }
+
+ NodeID GetTarget(const EdgeID e) const { return m_query_graph->GetTarget(e); }
+
+ EdgeDataT &GetEdgeData(const EdgeID e) { return m_query_graph->GetEdgeData(e); }
+
+ // const EdgeDataT &GetEdgeData( const EdgeID e ) const {
+ // return m_query_graph->GetEdgeData(e);
+ // }
+
+ EdgeID BeginEdges(const NodeID n) const { return m_query_graph->BeginEdges(n); }
+
+ EdgeID EndEdges(const NodeID n) const { return m_query_graph->EndEdges(n); }
+
+ EdgeRange GetAdjacentEdgeRange(const NodeID node) const
+ {
+ return m_query_graph->GetAdjacentEdgeRange(node);
+ };
+
+ // searches for a specific edge
+ EdgeID FindEdge(const NodeID from, const NodeID to) const
+ {
+ return m_query_graph->FindEdge(from, to);
+ }
+
+ EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const
+ {
+ return m_query_graph->FindEdgeInEitherDirection(from, to);
+ }
+
+ EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const
+ {
+ return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
+ }
+
+ // node and edge information access
+ FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const
+ {
+ return m_coordinate_list->at(id);
+ };
+
+ virtual bool EdgeIsCompressed(const unsigned id) const { return m_egde_is_compressed.at(id); }
+
+ virtual void GetUncompressedGeometry(const unsigned id, std::vector<unsigned> &result_nodes)
+ const
+ {
+ const unsigned begin = m_geometry_indices.at(id);
+ const unsigned end = m_geometry_indices.at(id + 1);
+
+ result_nodes.clear();
+ result_nodes.insert(
+ result_nodes.begin(), m_geometry_list.begin() + begin, m_geometry_list.begin() + end);
+ }
+
+ virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const
+ {
+ return m_via_node_list.at(id);
+ }
+
+ TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const
+ {
+ return m_turn_instruction_list.at(id);
+ }
+
+ bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
+ FixedPointCoordinate &result,
+ const unsigned zoom_level = 18) const
+ {
+ return m_static_rtree->LocateClosestEndPointForCoordinate(
+ input_coordinate, result, zoom_level);
+ }
+
+ bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ PhantomNode &resulting_phantom_node,
+ const unsigned zoom_level) const
+ {
+ return m_static_rtree->FindPhantomNodeForCoordinate(
+ input_coordinate, resulting_phantom_node, zoom_level);
+ }
+
+ bool
+ IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
+ std::vector<PhantomNode> &resulting_phantom_node_vector,
+ const unsigned zoom_level,
+ const unsigned number_of_results) const
+ {
+ return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
+ input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
+ }
+
+ unsigned GetCheckSum() const { return m_check_sum; }
+
+ unsigned GetNameIndexFromEdgeID(const unsigned id) const
+ {
+ return m_name_ID_list.at(id);
+ };
+
+ void GetName(const unsigned name_id, std::string &result) const
+ {
+ if (UINT_MAX == name_id)
+ {
+ result = "";
+ return;
+ }
+ auto range = m_name_table->GetRange(name_id);
+
+ result.clear();
+ if (range.begin() != range.end())
+ {
+ result.resize(range.back() - range.front() + 1);
+ std::copy(m_names_char_list.begin() + range.front(),
+ m_names_char_list.begin() + range.back() + 1,
+ result.begin());
+ }
+ }
+
+ std::string GetTimestamp() const { return m_timestamp; }
+};
+
+#endif // SHARED_DATA_FACADE_H
diff --git a/Server/DataStructures/SharedDataType.h b/Server/DataStructures/SharedDataType.h
new file mode 100644
index 0000000..98bdfd5
--- /dev/null
+++ b/Server/DataStructures/SharedDataType.h
@@ -0,0 +1,190 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef SHARED_DATA_TYPE_H_
+#define SHARED_DATA_TYPE_H_
+
+#include "../../Util/OSRMException.h"
+#include "../../Util/SimpleLogger.h"
+
+#include <cstdint>
+
+#include <array>
+
+// Added at the start and end of each block as sanity check
+constexpr char CANARY[] = "OSRM";
+
+struct SharedDataLayout
+{
+ enum BlockID {
+ NAME_OFFSETS = 0,
+ NAME_BLOCKS,
+ NAME_CHAR_LIST,
+ NAME_ID_LIST,
+ VIA_NODE_LIST,
+ GRAPH_NODE_LIST,
+ GRAPH_EDGE_LIST,
+ COORDINATE_LIST,
+ TURN_INSTRUCTION,
+ R_SEARCH_TREE,
+ GEOMETRIES_INDEX,
+ GEOMETRIES_LIST,
+ GEOMETRIES_INDICATORS,
+ HSGR_CHECKSUM,
+ TIMESTAMP,
+ FILE_INDEX_PATH,
+ NUM_BLOCKS
+ };
+
+ std::array<uint64_t, NUM_BLOCKS> num_entries;
+ std::array<uint64_t, NUM_BLOCKS> entry_size;
+
+ SharedDataLayout()
+ : num_entries()
+ , entry_size()
+ {
+ }
+
+ void PrintInformation() const
+ {
+ SimpleLogger().Write(logDEBUG) << "-";
+ SimpleLogger().Write(logDEBUG) << "name_offsets_size: " << num_entries[NAME_OFFSETS];
+ SimpleLogger().Write(logDEBUG) << "name_blocks_size: " << num_entries[NAME_BLOCKS];
+ SimpleLogger().Write(logDEBUG) << "name_char_list_size: " << num_entries[NAME_CHAR_LIST];
+ SimpleLogger().Write(logDEBUG) << "name_id_list_size: " << num_entries[NAME_ID_LIST];
+ SimpleLogger().Write(logDEBUG) << "via_node_list_size: " << num_entries[VIA_NODE_LIST];
+ SimpleLogger().Write(logDEBUG) << "graph_node_list_size: " << num_entries[GRAPH_NODE_LIST];
+ SimpleLogger().Write(logDEBUG) << "graph_edge_list_size: " << num_entries[GRAPH_EDGE_LIST];
+ SimpleLogger().Write(logDEBUG) << "timestamp_length: " << num_entries[TIMESTAMP];
+ SimpleLogger().Write(logDEBUG) << "coordinate_list_size: " << num_entries[COORDINATE_LIST];
+ SimpleLogger().Write(logDEBUG) << "turn_instruction_list_size: " << num_entries[TURN_INSTRUCTION];
+ SimpleLogger().Write(logDEBUG) << "r_search_tree_size: " << num_entries[R_SEARCH_TREE];
+ SimpleLogger().Write(logDEBUG) << "geometries_indicators: " << num_entries[GEOMETRIES_INDICATORS]
+ << "/" << ((num_entries[GEOMETRIES_INDICATORS] / 8) + 1);
+ SimpleLogger().Write(logDEBUG) << "geometries_index_list_size: " << num_entries[GEOMETRIES_INDEX];
+ SimpleLogger().Write(logDEBUG) << "geometries_list_size: " << num_entries[GEOMETRIES_LIST];
+ SimpleLogger().Write(logDEBUG) << "sizeof(checksum): " << entry_size[HSGR_CHECKSUM];
+
+ SimpleLogger().Write(logDEBUG) << "NAME_OFFSETS " << ": " << GetBlockSize(NAME_OFFSETS );
+ SimpleLogger().Write(logDEBUG) << "NAME_BLOCKS " << ": " << GetBlockSize(NAME_BLOCKS );
+ SimpleLogger().Write(logDEBUG) << "NAME_CHAR_LIST " << ": " << GetBlockSize(NAME_CHAR_LIST );
+ SimpleLogger().Write(logDEBUG) << "NAME_ID_LIST " << ": " << GetBlockSize(NAME_ID_LIST );
+ SimpleLogger().Write(logDEBUG) << "VIA_NODE_LIST " << ": " << GetBlockSize(VIA_NODE_LIST );
+ SimpleLogger().Write(logDEBUG) << "GRAPH_NODE_LIST " << ": " << GetBlockSize(GRAPH_NODE_LIST );
+ SimpleLogger().Write(logDEBUG) << "GRAPH_EDGE_LIST " << ": " << GetBlockSize(GRAPH_EDGE_LIST );
+ SimpleLogger().Write(logDEBUG) << "COORDINATE_LIST " << ": " << GetBlockSize(COORDINATE_LIST );
+ SimpleLogger().Write(logDEBUG) << "TURN_INSTRUCTION " << ": " << GetBlockSize(TURN_INSTRUCTION );
+ SimpleLogger().Write(logDEBUG) << "R_SEARCH_TREE " << ": " << GetBlockSize(R_SEARCH_TREE );
+ SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDEX " << ": " << GetBlockSize(GEOMETRIES_INDEX );
+ SimpleLogger().Write(logDEBUG) << "GEOMETRIES_LIST " << ": " << GetBlockSize(GEOMETRIES_LIST );
+ SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDICATORS" << ": " << GetBlockSize(GEOMETRIES_INDICATORS);
+ SimpleLogger().Write(logDEBUG) << "HSGR_CHECKSUM " << ": " << GetBlockSize(HSGR_CHECKSUM );
+ SimpleLogger().Write(logDEBUG) << "TIMESTAMP " << ": " << GetBlockSize(TIMESTAMP );
+ SimpleLogger().Write(logDEBUG) << "FILE_INDEX_PATH " << ": " << GetBlockSize(FILE_INDEX_PATH );
+ }
+
+ template<typename T>
+ inline void SetBlockSize(BlockID bid, uint64_t entries)
+ {
+ num_entries[bid] = entries;
+ entry_size[bid] = sizeof(T);
+ }
+
+ inline uint64_t GetBlockSize(BlockID bid) const
+ {
+ // special encoding
+ if (bid == GEOMETRIES_INDICATORS)
+ {
+ return (num_entries[GEOMETRIES_INDICATORS]/32 + 1) * entry_size[GEOMETRIES_INDICATORS];
+ }
+
+ return num_entries[bid] * entry_size[bid];
+ }
+
+ inline uint64_t GetSizeOfLayout() const
+ {
+ return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS*2*sizeof(CANARY);
+ }
+
+ inline uint64_t GetBlockOffset(BlockID bid) const
+ {
+ uint64_t result = sizeof(CANARY);
+ for (auto i = 0; i < bid; i++)
+ {
+ result += GetBlockSize((BlockID) i) + 2*sizeof(CANARY);
+ }
+ return result;
+ }
+
+ template<typename T, bool WRITE_CANARY=false>
+ inline T* GetBlockPtr(char* shared_memory, BlockID bid)
+ {
+ T* ptr = (T*)(shared_memory + GetBlockOffset(bid));
+ if (WRITE_CANARY)
+ {
+ char* start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
+ char* end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
+ std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
+ std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
+ }
+ else
+ {
+ char* start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
+ char* end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
+ bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
+ bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
+ if (!start_canary_alive)
+ {
+ throw OSRMException("Start canary of block corrupted.");
+ }
+ if (!end_canary_alive)
+ {
+ throw OSRMException("End canary of block corrupted.");
+ }
+ }
+
+ return ptr;
+ }
+};
+
+enum SharedDataType
+{ CURRENT_REGIONS,
+ LAYOUT_1,
+ DATA_1,
+ LAYOUT_2,
+ DATA_2,
+ LAYOUT_NONE,
+ DATA_NONE };
+
+struct SharedDataTimestamp
+{
+ SharedDataType layout;
+ SharedDataType data;
+ unsigned timestamp;
+};
+
+#endif /* SHARED_DATA_TYPE_H_ */
diff --git a/Server/Http/CompressionType.h b/Server/Http/CompressionType.h
new file mode 100644
index 0000000..74d0b62
--- /dev/null
+++ b/Server/Http/CompressionType.h
@@ -0,0 +1,41 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef COMPRESSION_TYPE_H
+#define COMPRESSION_TYPE_H
+
+namespace http
+{
+
+enum CompressionType
+{ noCompression,
+ gzipRFC1952,
+ deflateRFC1951 };
+
+} // namespace http
+
+#endif // COMPRESSION_TYPE_H
diff --git a/Server/Http/Reply.cpp b/Server/Http/Reply.cpp
new file mode 100644
index 0000000..b3247ec
--- /dev/null
+++ b/Server/Http/Reply.cpp
@@ -0,0 +1,123 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include <osrm/Reply.h>
+
+#include "../../Util/StringUtil.h"
+
+namespace http
+{
+
+void Reply::SetSize(const unsigned size)
+{
+ for (Header &h : headers)
+ {
+ if ("Content-Length" == h.name)
+ {
+ h.value = UintToString(size);
+ }
+ }
+}
+
+// Sets the size of the uncompressed output.
+void Reply::SetUncompressedSize() { SetSize(static_cast<unsigned>(content.size())); }
+
+std::vector<boost::asio::const_buffer> Reply::ToBuffers()
+{
+ std::vector<boost::asio::const_buffer> buffers;
+ buffers.push_back(ToBuffer(status));
+ for (const Header &h : headers)
+ {
+ buffers.push_back(boost::asio::buffer(h.name));
+ buffers.push_back(boost::asio::buffer(seperators));
+ buffers.push_back(boost::asio::buffer(h.value));
+ buffers.push_back(boost::asio::buffer(crlf));
+ }
+ buffers.push_back(boost::asio::buffer(crlf));
+ buffers.push_back(boost::asio::buffer(content));
+ return buffers;
+}
+
+std::vector<boost::asio::const_buffer> Reply::HeaderstoBuffers()
+{
+ std::vector<boost::asio::const_buffer> buffers;
+ buffers.push_back(ToBuffer(status));
+ for (std::size_t i = 0; i < headers.size(); ++i)
+ {
+ Header ¤t_header = headers[i];
+ buffers.push_back(boost::asio::buffer(current_header.name));
+ buffers.push_back(boost::asio::buffer(seperators));
+ buffers.push_back(boost::asio::buffer(current_header.value));
+ buffers.push_back(boost::asio::buffer(crlf));
+ }
+ buffers.push_back(boost::asio::buffer(crlf));
+ return buffers;
+}
+
+Reply Reply::StockReply(Reply::status_type status)
+{
+ Reply reply;
+ reply.status = status;
+ reply.content.clear();
+
+ const std::string status_string = reply.ToString(status);
+ reply.content.insert(reply.content.end(), status_string.begin(), status_string.end());
+ reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
+ reply.headers.emplace_back("Content-Length",
+ UintToString(static_cast<unsigned>(reply.content.size())));
+ reply.headers.emplace_back("Content-Type", "text/html");
+ return reply;
+}
+
+std::string Reply::ToString(Reply::status_type status)
+{
+ if (Reply::ok == status)
+ {
+ return okHTML;
+ }
+ if (Reply::badRequest == status)
+ {
+ return badRequestHTML;
+ }
+ return internalServerErrorHTML;
+}
+
+boost::asio::const_buffer Reply::ToBuffer(Reply::status_type status)
+{
+ if (Reply::ok == status)
+ {
+ return boost::asio::buffer(okString);
+ }
+ if (Reply::internalServerError == status)
+ {
+ return boost::asio::buffer(internalServerErrorString);
+ }
+ return boost::asio::buffer(badRequestString);
+}
+
+Reply::Reply() : status(ok) {}
+}
diff --git a/Server/Http/Request.h b/Server/Http/Request.h
new file mode 100644
index 0000000..4746a5e
--- /dev/null
+++ b/Server/Http/Request.h
@@ -0,0 +1,48 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef REQUEST_H
+#define REQUEST_H
+
+#include <boost/asio.hpp>
+
+#include <string>
+
+namespace http
+{
+
+struct Request
+{
+ std::string uri;
+ std::string referrer;
+ std::string agent;
+ boost::asio::ip::address endpoint;
+};
+
+} // namespace http
+
+#endif // REQUEST_H
diff --git a/Server/RequestHandler.cpp b/Server/RequestHandler.cpp
new file mode 100644
index 0000000..36a2808
--- /dev/null
+++ b/Server/RequestHandler.cpp
@@ -0,0 +1,142 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "APIGrammar.h"
+#include "RequestHandler.h"
+#include "Http/Request.h"
+
+#include "../DataStructures/JSONContainer.h"
+#include "../Library/OSRM.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/StringUtil.h"
+#include "../typedefs.h"
+
+#include <osrm/Reply.h>
+#include <osrm/RouteParameters.h>
+
+#include <ctime>
+
+#include <algorithm>
+#include <iostream>
+
+RequestHandler::RequestHandler() : routing_machine(nullptr) {}
+
+void RequestHandler::handle_request(const http::Request &req, http::Reply &reply)
+{
+ // parse command
+ try
+ {
+ std::string request;
+ URIDecode(req.uri, request);
+
+ // deactivated as GCC apparently does not implement that, not even in 4.9
+ // std::time_t t = std::time(nullptr);
+ // SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
+ // " " << req.endpoint.to_string() << " " <<
+ // req.referrer << ( 0 == req.referrer.length() ? "- " :" ") <<
+ // req.agent << ( 0 == req.agent.length() ? "- " :" ") << request;
+
+ time_t ltime;
+ struct tm *Tm;
+
+ ltime = time(nullptr);
+ Tm = localtime(<ime);
+
+ // log timestamp
+ SimpleLogger().Write() << (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() ? "- " : " ") << request;
+
+ RouteParameters route_parameters;
+ APIGrammarParser api_parser(&route_parameters);
+
+ auto iter = request.begin();
+ const bool result = boost::spirit::qi::parse(iter, request.end(), api_parser);
+
+ // check if the was an error with the request
+ if (!result || (iter != request.end()))
+ {
+ reply = http::Reply::StockReply(http::Reply::badRequest);
+ reply.content.clear();
+ const unsigned position = static_cast<unsigned>(std::distance(request.begin(), iter));
+ JSON::Object json_result;
+ json_result.values["status"] = 400;
+ std::string message = "Query string malformed close to position ";
+ message += UintToString(position);
+ json_result.values["status_message"] = message;
+ JSON::render(reply.content, json_result);
+ return;
+ }
+
+ // parsing done, lets call the right plugin to handle the request
+ BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
+
+ if (!route_parameters.jsonp_parameter.empty())
+ { // prepend response with jsonp parameter
+ const std::string json_p = (route_parameters.jsonp_parameter + "(");
+ reply.content.insert(reply.content.end(), json_p.begin(), json_p.end());
+ }
+ routing_machine->RunQuery(route_parameters, reply);
+ if (!route_parameters.jsonp_parameter.empty())
+ { // append brace to jsonp response
+ reply.content.push_back(')');
+ }
+
+ // set headers
+ reply.headers.emplace_back("Content-Length",
+ UintToString(static_cast<unsigned>(reply.content.size())));
+ if ("gpx" == route_parameters.output_format)
+ { // gpx file
+ reply.headers.emplace_back("Content-Type", "application/gpx+xml; charset=UTF-8");
+ reply.headers.emplace_back("Content-Disposition", "attachment; filename=\"route.gpx\"");
+ }
+ else if (route_parameters.jsonp_parameter.empty())
+ { // json file
+ reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
+ reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.json\"");
+ }
+ else
+ { // jsonp
+ reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
+ reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.js\"");
+ }
+ }
+ catch (const std::exception &e)
+ {
+ reply = http::Reply::StockReply(http::Reply::internalServerError);
+ SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
+ << ", uri: " << req.uri;
+ return;
+ }
+}
+
+void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
diff --git a/Server/RequestHandler.h b/Server/RequestHandler.h
index 9dd0e28..462c34f 100644
--- a/Server/RequestHandler.h
+++ b/Server/RequestHandler.h
@@ -1,117 +1,59 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef REQUEST_HANDLER_H
#define REQUEST_HANDLER_H
-#include <algorithm>
-#include <cctype> // std::tolower
#include <string>
-#include <iostream>
-#include <boost/noncopyable.hpp>
-
-#include "APIGrammar.h"
-#include "BasicDatastructures.h"
-#include "../DataStructures/HashTable.h"
-#include "../Plugins/BasePlugin.h"
-#include "../Plugins/RouteParameters.h"
-#include "../Util/StringUtil.h"
-#include "../typedefs.h"
-
-namespace http {
-
-class RequestHandler : private boost::noncopyable {
-public:
- explicit RequestHandler() : _pluginCount(0) { }
-
- ~RequestHandler() {
-
- for(unsigned i = 0; i < _pluginVector.size(); i++) {
- BasePlugin * tempPointer = _pluginVector[i];
- delete tempPointer;
- }
- }
-
- 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
- time_t ltime;
- struct tm *Tm;
+template <typename Iterator, class HandlerT> struct APIGrammar;
+struct RouteParameters;
+class OSRM;
- ltime=time(NULL);
- Tm=localtime(<ime);
+namespace http
+{
+class Reply;
+struct Request;
+}
- 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 );
- }
+class RequestHandler
+{
- RouteParameters routeParameters;
- APIGrammar<std::string::iterator, RouteParameters> apiParser(&routeParameters);
+ public:
+ typedef APIGrammar<std::string::iterator, RouteParameters> APIGrammarParser;
- std::string::iterator it = request.begin();
- bool result = boost::spirit::qi::parse(it, request.end(), apiParser); // returns true if successful
- if (!result || (it != request.end()) ) {
- rep = http::Reply::stockReply(http::Reply::badRequest);
- int position = std::distance(request.begin(), it);
- std::string tmp_position_string;
- intToString(position, tmp_position_string);
- rep.content += "Input seems to be malformed close to position ";
- rep.content += "<br><pre>";
- rep.content += request;
- rep.content += tmp_position_string;
- rep.content += "<br>";
- for(unsigned i = 0, end = std::distance(request.begin(), it); i < end; ++i)
- rep.content += " ";
- rep.content += "^<br></pre>";
- } else {
- //Finished parsing, lets call the right plugin to handle the request
- if(pluginMap.Holds(routeParameters.service)) {
- rep.status = Reply::ok;
- _pluginVector[pluginMap.Find(routeParameters.service)]->HandleRequest(routeParameters, rep );
- } else {
- rep = Reply::stockReply(Reply::badRequest);
- }
- return;
- }
- } catch(std::exception& e) {
- rep = Reply::stockReply(Reply::internalServerError);
- std::cerr << "[server error] code: " << e.what() << ", uri: " << req.uri << std::endl;
- return;
- }
- };
+ RequestHandler();
+ RequestHandler(const RequestHandler &) = delete;
- void RegisterPlugin(BasePlugin * plugin) {
- std::cout << "[handler] registering plugin " << plugin->GetDescriptor() << std::endl;
- pluginMap.Add(plugin->GetDescriptor(), _pluginCount);
- _pluginVector.push_back(plugin);
- ++_pluginCount;
- }
+ void handle_request(const http::Request &req, http::Reply &rep);
+ void RegisterRoutingMachine(OSRM *osrm);
-private:
- HashTable<std::string, unsigned> pluginMap;
- std::vector<BasePlugin *> _pluginVector;
- unsigned _pluginCount;
+ private:
+ OSRM *routing_machine;
};
-} // namespace http
#endif // REQUEST_HANDLER_H
diff --git a/Server/RequestParser.cpp b/Server/RequestParser.cpp
new file mode 100644
index 0000000..cad05b9
--- /dev/null
+++ b/Server/RequestParser.cpp
@@ -0,0 +1,306 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "Http/Request.h"
+#include "RequestParser.h"
+
+namespace http
+{
+
+RequestParser::RequestParser() : state_(method_start), header({"", ""}) {}
+
+void RequestParser::Reset() { state_ = method_start; }
+
+boost::tuple<boost::tribool, char *>
+RequestParser::Parse(Request &req, char *begin, char *end, http::CompressionType *compression_type)
+{
+ while (begin != end)
+ {
+ boost::tribool result = consume(req, *begin++, compression_type);
+ if (result || !result)
+ {
+ return boost::make_tuple(result, begin);
+ }
+ }
+ boost::tribool result = boost::indeterminate;
+ return boost::make_tuple(result, begin);
+}
+
+boost::tribool
+RequestParser::consume(Request &req, char input, http::CompressionType *compression_type)
+{
+ switch (state_)
+ {
+ case method_start:
+ if (!isChar(input) || isCTL(input) || isTSpecial(input))
+ {
+ return false;
+ }
+ state_ = method;
+ return boost::indeterminate;
+ case method:
+ if (input == ' ')
+ {
+ state_ = uri;
+ return boost::indeterminate;
+ }
+ if (!isChar(input) || isCTL(input) || isTSpecial(input))
+ {
+ return false;
+ }
+ return boost::indeterminate;
+ case uri_start:
+ if (isCTL(input))
+ {
+ return false;
+ }
+ state_ = uri;
+ req.uri.push_back(input);
+ return boost::indeterminate;
+ case uri:
+ if (input == ' ')
+ {
+ state_ = http_version_h;
+ return boost::indeterminate;
+ }
+ if (isCTL(input))
+ {
+ return false;
+ }
+ req.uri.push_back(input);
+ return boost::indeterminate;
+ case http_version_h:
+ if (input == 'H')
+ {
+ state_ = http_version_t_1;
+ return boost::indeterminate;
+ }
+ return false;
+ case http_version_t_1:
+ if (input == 'T')
+ {
+ state_ = http_version_t_2;
+ return boost::indeterminate;
+ }
+ return false;
+ case http_version_t_2:
+ if (input == 'T')
+ {
+ state_ = http_version_p;
+ return boost::indeterminate;
+ }
+ return false;
+ case http_version_p:
+ if (input == 'P')
+ {
+ state_ = http_version_slash;
+ return boost::indeterminate;
+ }
+ return false;
+ case http_version_slash:
+ if (input == '/')
+ {
+ state_ = http_version_major_start;
+ return boost::indeterminate;
+ }
+ return false;
+ case http_version_major_start:
+ if (isDigit(input))
+ {
+ state_ = http_version_major;
+ return boost::indeterminate;
+ }
+ return false;
+ case http_version_major:
+ if (input == '.')
+ {
+ state_ = http_version_minor_start;
+ return boost::indeterminate;
+ }
+ if (isDigit(input))
+ {
+ return boost::indeterminate;
+ }
+ return false;
+ case http_version_minor_start:
+ if (isDigit(input))
+ {
+ state_ = http_version_minor;
+ return boost::indeterminate;
+ }
+ return false;
+ case http_version_minor:
+ if (input == '\r')
+ {
+ state_ = expecting_newline_1;
+ return boost::indeterminate;
+ }
+ if (isDigit(input))
+ {
+ return boost::indeterminate;
+ }
+ return false;
+ case expecting_newline_1:
+ if (input == '\n')
+ {
+ state_ = header_line_start;
+ return boost::indeterminate;
+ }
+ return false;
+ case header_line_start:
+ if (header.name == "Accept-Encoding")
+ {
+ /* giving gzip precedence over deflate */
+ if (header.value.find("deflate") != std::string::npos)
+ {
+ *compression_type = deflateRFC1951;
+ }
+ if (header.value.find("gzip") != std::string::npos)
+ {
+ *compression_type = gzipRFC1952;
+ }
+ }
+
+ if ("Referer" == header.name)
+ {
+ req.referrer = header.value;
+ }
+
+ if ("User-Agent" == header.name)
+ {
+ req.agent = header.value;
+ }
+
+ if (input == '\r')
+ {
+ state_ = expecting_newline_3;
+ return boost::indeterminate;
+ }
+ if (!isChar(input) || isCTL(input) || isTSpecial(input))
+ {
+ return false;
+ }
+ state_ = header_name;
+ header.Clear();
+ header.name.push_back(input);
+ return boost::indeterminate;
+ case header_lws:
+ if (input == '\r')
+ {
+ state_ = expecting_newline_2;
+ return boost::indeterminate;
+ }
+ if (input == ' ' || input == '\t')
+ {
+ return boost::indeterminate;
+ }
+ if (isCTL(input))
+ {
+ return false;
+ }
+ state_ = header_value;
+ return boost::indeterminate;
+ case header_name:
+ if (input == ':')
+ {
+ state_ = space_before_header_value;
+ return boost::indeterminate;
+ }
+ if (!isChar(input) || isCTL(input) || isTSpecial(input))
+ {
+ return false;
+ }
+ header.name.push_back(input);
+ return boost::indeterminate;
+ case space_before_header_value:
+ if (input == ' ')
+ {
+ state_ = header_value;
+ return boost::indeterminate;
+ }
+ return false;
+ case header_value:
+ if (input == '\r')
+ {
+ state_ = expecting_newline_2;
+ return boost::indeterminate;
+ }
+ if (isCTL(input))
+ {
+ return false;
+ }
+ header.value.push_back(input);
+ return boost::indeterminate;
+ case expecting_newline_2:
+ if (input == '\n')
+ {
+ state_ = header_line_start;
+ return boost::indeterminate;
+ }
+ return false;
+ default: // expecting_newline_3:
+ return (input == '\n');
+ // default:
+ // return false;
+ }
+}
+
+inline bool RequestParser::isChar(int c) { return c >= 0 && c <= 127; }
+
+inline bool RequestParser::isCTL(int c) { return (c >= 0 && c <= 31) || (c == 127); }
+
+inline bool RequestParser::isTSpecial(int c)
+{
+ switch (c)
+ {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '"':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+ case '{':
+ case '}':
+ case ' ':
+ case '\t':
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline bool RequestParser::isDigit(int c) { return c >= '0' && c <= '9'; }
+}
diff --git a/Server/RequestParser.h b/Server/RequestParser.h
index 7e33f9e..4b74d83 100644
--- a/Server/RequestParser.h
+++ b/Server/RequestParser.h
@@ -1,287 +1,86 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef REQUEST_PARSER_H
#define REQUEST_PARSER_H
+#include "Http/CompressionType.h"
+#include <osrm/Header.h>
+
#include <boost/logic/tribool.hpp>
#include <boost/tuple/tuple.hpp>
-#include "BasicDatastructures.h"
-
-namespace http {
-
-class RequestParser {
-public:
- RequestParser() : state_(method_start) { }
- void Reset() { state_ = method_start; }
-
- boost::tuple<boost::tribool, char*> Parse(Request& req, char* begin, char* end, CompressionType * compressionType) {
- while (begin != end) {
- boost::tribool result = consume(req, *begin++, compressionType);
- if (result || !result){
- return boost::make_tuple(result, begin);
- }
- }
- boost::tribool result = boost::indeterminate;
- return boost::make_tuple(result, begin);
- }
-
-private:
- boost::tribool consume(Request& req, char input, CompressionType * compressionType) {
- switch (state_) {
- case method_start:
- if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
- return false;
- } else {
- state_ = method;
- return boost::indeterminate;
- }
- case method:
- if (input == ' ') {
- state_ = uri;
- return boost::indeterminate;
- } else if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
- return false;
- } else {
- return boost::indeterminate;
- }
- case uri_start:
- if (isCTL(input)) {
- return false;
- } else {
- state_ = uri;
- req.uri.push_back(input);
- return boost::indeterminate;
- }
- case uri:
- if (input == ' ') {
- state_ = http_version_h;
- return boost::indeterminate;
- } else if (isCTL(input)) {
- return false;
- } else {
- req.uri.push_back(input);
- return boost::indeterminate;
- }
- case http_version_h:
- if (input == 'H') {
- state_ = http_version_t_1;
- return boost::indeterminate;
- } else {
- return false;
- }
- case http_version_t_1:
- if (input == 'T') {
- state_ = http_version_t_2;
- return boost::indeterminate;
- } else {
- return false;
- }
- case http_version_t_2:
- if (input == 'T') {
- state_ = http_version_p;
- return boost::indeterminate;
- } else {
- return false;
- }
- case http_version_p:
- if (input == 'P') {
- state_ = http_version_slash;
- return boost::indeterminate;
- } else {
- return false;
- }
- case http_version_slash:
- if (input == '/') {
- state_ = http_version_major_start;
- return boost::indeterminate;
- } else {
- return false;
- }
- case http_version_major_start:
- if (isDigit(input)) {
- state_ = http_version_major;
- return boost::indeterminate;
- } else {
- return false;
- }
- case http_version_major:
- if (input == '.') {
- state_ = http_version_minor_start;
- return boost::indeterminate;
- } else if (isDigit(input)) {
- return boost::indeterminate;
- } else {
- return false;
- }
- case http_version_minor_start:
- if (isDigit(input)) {
- state_ = http_version_minor;
- return boost::indeterminate;
- } else {
- return false;
- }
- case http_version_minor:
- if (input == '\r') {
- state_ = expecting_newline_1;
- return boost::indeterminate;
- } else if (isDigit(input)) {
- return boost::indeterminate;
- }
- else {
- return false;
- }
- case expecting_newline_1:
- if (input == '\n') {
- state_ = header_line_start;
- return boost::indeterminate;
- } else {
- return false;
- }
- case header_line_start:
- if(header.name == "Accept-Encoding") {
- /* giving gzip precedence over deflate */
- if(header.value.find("deflate") != std::string::npos)
- *compressionType = deflateRFC1951;
- if(header.value.find("gzip") != std::string::npos)
- *compressionType = gzipRFC1952;
- }
-
- if("Referer" == header.name)
- req.referrer = header.value;
-
- if("User-Agent" == header.name)
- req.agent = header.value;
-
- if (input == '\r') {
- state_ = expecting_newline_3;
- return boost::indeterminate;
- } else if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
- return false;
- } else {
- state_ = header_name;
- header.Clear();
- header.name.push_back(input);
- return boost::indeterminate;
- }
- case header_lws:
- if (input == '\r') {
- state_ = expecting_newline_2;
- return boost::indeterminate;
- } else if (input == ' ' || input == '\t') {
- return boost::indeterminate;
- }
- else if (isCTL(input)) {
- return false;
- } else {
- state_ = header_value;
- return boost::indeterminate;
- }
- case header_name:
- if (input == ':') {
- state_ = space_before_header_value;
- return boost::indeterminate;
- } else if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
- return false;
- } else {
- header.name.push_back(input);
- return boost::indeterminate;
- }
- case space_before_header_value:
- if (input == ' ') {
- state_ = header_value;
- return boost::indeterminate;
- } else {
- return false;
- }
- case header_value:
- if (input == '\r') {
- state_ = expecting_newline_2;
- return boost::indeterminate;
- } else if (isCTL(input)) {
- return false;
- } else {
- header.value.push_back(input);
- return boost::indeterminate;
- }
- case expecting_newline_2:
- if (input == '\n') {
- state_ = header_line_start;
- return boost::indeterminate;
- } else {
- return false;
- }
- case expecting_newline_3:
- return (input == '\n');
- default:
- return false;
- }
- }
-
- inline bool isChar(int c) {
- return c >= 0 && c <= 127;
- }
-
- inline bool isCTL(int c) {
- return (c >= 0 && c <= 31) || (c == 127);
- }
-
- inline bool isTSpecial(int c) {
- switch (c) {
- case '(': case ')': case '<': case '>': case '@':
- case ',': case ';': case ':': case '\\': case '"':
- case '/': case '[': case ']': case '?': case '=':
- case '{': case '}': case ' ': case '\t':
- return true;
- default:
- return false;
- }
- }
-
- inline bool isDigit(int c) {
- return c >= '0' && c <= '9';
- }
- enum state {
- method_start,
- method,
- uri_start,
- uri,
- http_version_h,
- http_version_t_1,
- http_version_t_2,
- http_version_p,
- http_version_slash,
- http_version_major_start,
- http_version_major,
- http_version_minor_start,
- http_version_minor,
- expecting_newline_1,
- header_line_start,
- header_lws,
- header_name,
- space_before_header_value,
- header_value,
- expecting_newline_2,
- expecting_newline_3
- } state_;
+namespace http
+{
+
+struct Request;
+
+class RequestParser
+{
+ public:
+ RequestParser();
+ void Reset();
+
+ boost::tuple<boost::tribool, char *>
+ Parse(Request &req, char *begin, char *end, CompressionType *compressionType);
+
+ private:
+ boost::tribool consume(Request &req, char input, CompressionType *compressionType);
+
+ inline bool isChar(int c);
+
+ inline bool isCTL(int c);
+
+ inline bool isTSpecial(int c);
+
+ inline bool isDigit(int c);
+
+ enum state
+ { method_start,
+ method,
+ uri_start,
+ uri,
+ http_version_h,
+ http_version_t_1,
+ http_version_t_2,
+ http_version_p,
+ http_version_slash,
+ http_version_major_start,
+ http_version_major,
+ http_version_minor_start,
+ http_version_minor,
+ expecting_newline_1,
+ header_line_start,
+ header_lws,
+ header_name,
+ space_before_header_value,
+ header_value,
+ expecting_newline_2,
+ expecting_newline_3 } state_;
Header header;
};
diff --git a/Server/Server.h b/Server/Server.h
index db525f5..be18c3b 100644
--- a/Server/Server.h
+++ b/Server/Server.h
@@ -1,88 +1,108 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef SERVER_H
#define SERVER_H
-#include <vector>
-#include <boost/asio.hpp>
-#include <boost/bind.hpp>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/thread.hpp>
+#include "../Util/StringUtil.h"
#include "Connection.h"
#include "RequestHandler.h"
-namespace http {
-
-class Server: private boost::noncopyable {
-public:
- explicit Server(const std::string& address, const std::string& port, unsigned thread_pool_size) : threadPoolSize(thread_pool_size), acceptor(ioService), newConnection(new Connection(ioService, requestHandler)), requestHandler(){
- boost::asio::ip::tcp::resolver resolver(ioService);
- boost::asio::ip::tcp::resolver::query query(address, port);
- boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
-
- acceptor.open(endpoint.protocol());
- acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
- acceptor.bind(endpoint);
- acceptor.listen();
- acceptor.async_accept(newConnection->socket(), boost::bind(&Server::handleAccept, this, boost::asio::placeholders::error));
- }
-
- void Run() {
- std::vector<boost::shared_ptr<boost::thread> > threads;
- for (unsigned i = 0; i < threadPoolSize; ++i) {
- boost::shared_ptr<boost::thread> thread(new boost::thread(boost::bind(&boost::asio::io_service::run, &ioService)));
- threads.push_back(thread);
- }
- for (unsigned i = 0; i < threads.size(); ++i)
- threads[i]->join();
- }
-
- void Stop() {
- ioService.stop();
- }
-
- RequestHandler & GetRequestHandlerPtr() {
- return requestHandler;
- }
-
-private:
- typedef boost::shared_ptr<Connection > ConnectionPtr;
-
- void handleAccept(const boost::system::error_code& e) {
- if (!e) {
- newConnection->start();
- newConnection.reset(new Connection(ioService, requestHandler));
- acceptor.async_accept(newConnection->socket(), boost::bind(&Server::handleAccept, this, boost::asio::placeholders::error));
- }
- }
-
- unsigned threadPoolSize;
- boost::asio::io_service ioService;
- boost::asio::ip::tcp::acceptor acceptor;
- ConnectionPtr newConnection;
- RequestHandler requestHandler;
-};
+#include <boost/asio.hpp>
+#include <boost/bind.hpp>
-} // namespace http
+#include <functional>
+#include <memory>
+#include <thread>
+#include <vector>
+
+class Server
+{
+ public:
+ explicit Server(const std::string &address, const int port, const unsigned thread_pool_size)
+ : thread_pool_size(thread_pool_size), acceptor(io_service),
+ new_connection(new http::Connection(io_service, request_handler)), request_handler()
+ {
+ const std::string port_string = IntToString(port);
+
+ boost::asio::ip::tcp::resolver resolver(io_service);
+ boost::asio::ip::tcp::resolver::query query(address, port_string);
+ boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
+
+ acceptor.open(endpoint.protocol());
+ acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ acceptor.bind(endpoint);
+ acceptor.listen();
+ acceptor.async_accept(
+ new_connection->socket(),
+ boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
+ }
+
+ Server() = delete;
+ Server(const Server &) = delete;
+
+ void Run()
+ {
+ std::vector<std::shared_ptr<std::thread>> threads;
+ for (unsigned i = 0; i < thread_pool_size; ++i)
+ {
+ std::shared_ptr<std::thread> thread = std::make_shared<std::thread>(
+ boost::bind(&boost::asio::io_service::run, &io_service));
+ threads.push_back(thread);
+ }
+ for (unsigned i = 0; i < threads.size(); ++i)
+ {
+ threads[i]->join();
+ }
+ }
+
+ void Stop() { io_service.stop(); }
+
+ RequestHandler &GetRequestHandlerPtr() { return request_handler; }
+
+ private:
+ void HandleAccept(const boost::system::error_code &e)
+ {
+ if (!e)
+ {
+ new_connection->start();
+ new_connection.reset(new http::Connection(io_service, request_handler));
+ acceptor.async_accept(
+ new_connection->socket(),
+ boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
+ }
+ }
+
+ unsigned thread_pool_size;
+ boost::asio::io_service io_service;
+ boost::asio::ip::tcp::acceptor acceptor;
+ std::shared_ptr<http::Connection> new_connection;
+ RequestHandler request_handler;
+};
#endif // SERVER_H
diff --git a/Server/ServerConfiguration.h b/Server/ServerConfiguration.h
deleted file mode 100644
index 0393a7f..0000000
--- a/Server/ServerConfiguration.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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 SERVERCONFIGURATION_H_
-#define SERVERCONFIGURATION_H_
-
-#include "../Util/BaseConfiguration.h"
-
-typedef BaseConfiguration ServerConfiguration;
-
-#endif /* SERVERCONFIGURATION_H_ */
diff --git a/Server/ServerFactory.h b/Server/ServerFactory.h
index 966dc92..5e037cf 100644
--- a/Server/ServerFactory.h
+++ b/Server/ServerFactory.h
@@ -1,84 +1,49 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
- Created on: 26.11.2010
- Author: dennis
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+*/
-#ifndef SERVERFACTORY_H_
-#define SERVERFACTORY_H_
-
-#include <zlib.h>
+#ifndef SERVER_FACTORY_H
+#define SERVER_FACTORY_H
#include "Server.h"
-#include "ServerConfiguration.h"
-
-#include "../Util/InputFileUtil.h"
-#include "../Util/OpenMPWrapper.h"
-#include "../Util/StringUtil.h"
-
-#include "../typedefs.h"
-
-typedef http::Server Server;
-
-struct ServerFactory {
- static Server * CreateServer(ServerConfiguration& serverConfig) {
-
- if(!testDataFile(serverConfig.GetParameter("nodesData"))) {
- ERR("nodes file not found");
- }
+#include "../Util/SimpleLogger.h"
- if(!testDataFile(serverConfig.GetParameter("hsgrData"))) {
- ERR("hsgr file not found");
- }
-
- if(!testDataFile(serverConfig.GetParameter("namesData"))) {
- ERR("names file not found");
- }
-
- if(!testDataFile(serverConfig.GetParameter("ramIndex"))) {
- ERR("ram index file not found");
- }
-
- if(!testDataFile(serverConfig.GetParameter("fileIndex"))) {
- ERR("file index file not found");
- }
-
- int threads = omp_get_num_procs();
- if(serverConfig.GetParameter("IP") == "")
- serverConfig.SetParameter("IP", "0.0.0.0");
- if(serverConfig.GetParameter("Port") == "")
- serverConfig.SetParameter("Port", "5000");
-
- if(stringToInt(serverConfig.GetParameter("Threads")) != 0 && stringToInt(serverConfig.GetParameter("Threads")) <= threads)
- threads = stringToInt( serverConfig.GetParameter("Threads") );
-
- std::cout << "[server] http 1.1 compression handled by zlib version " << zlibVersion() << std::endl;
- Server * server = new Server(serverConfig.GetParameter("IP"), serverConfig.GetParameter("Port"), threads);
- return server;
- }
+#include <zlib.h>
- static Server * CreateServer(const char * iniFile) {
- ServerConfiguration serverConfig(iniFile);
- return CreateServer(serverConfig);
- }
+struct ServerFactory
+{
+ ServerFactory() = delete;
+ ServerFactory(const ServerFactory &) = delete;
+ static Server *CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
+ {
+ SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
+ const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
+ const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
+ return new Server(ip_address, ip_port, real_num_threads);
+ }
};
-#endif /* SERVERFACTORY_H_ */
+#endif // SERVER_FACTORY_H
diff --git a/Tools/componentAnalysis.cpp b/Tools/componentAnalysis.cpp
deleted file mode 100644
index 64790aa..0000000
--- a/Tools/componentAnalysis.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
- */
-
-#define VERBOSE(x) x
-#define VERBOSE2(x)
-
-#ifdef NDEBUG
-#undef VERBOSE
-#undef VERBOSE2
-#endif
-
-#include <boost/foreach.hpp>
-
-#include <fstream>
-#include <istream>
-#include <iostream>
-#include <cstring>
-#include <string>
-#include <vector>
-
-#include "../typedefs.h"
-#include "../Algorithms/StronglyConnectedComponents.h"
-#include "../DataStructures/BinaryHeap.h"
-#include "../DataStructures/DeallocatingVector.h"
-#include "../DataStructures/DynamicGraph.h"
-#include "../DataStructures/QueryEdge.h"
-#include "../DataStructures/TurnInstructions.h"
-#include "../Util/BaseConfiguration.h"
-#include "../Util/InputFileUtil.h"
-#include "../Util/GraphLoader.h"
-
-using namespace std;
-
-typedef QueryEdge::EdgeData EdgeData;
-typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
-typedef BaseConfiguration ContractorConfiguration;
-
-std::vector<NodeInfo> internalToExternalNodeMapping;
-std::vector<_Restriction> inputRestrictions;
-std::vector<NodeID> bollardNodes;
-std::vector<NodeID> trafficLightNodes;
-
-int main (int argc, char *argv[]) {
- if(argc < 3) {
- ERR("usage: " << std::endl << argv[0] << " <osrm-data> <osrm-restrictions>");
- }
- std::string SRTM_ROOT;
-
- INFO("Using restrictions from file: " << argv[2]);
- std::ifstream restrictionsInstream(argv[2], ios::binary);
- if(!restrictionsInstream.good()) {
- ERR("Could not access <osrm-restrictions> files");
- }
- _Restriction restriction;
- unsigned usableRestrictionsCounter(0);
- restrictionsInstream.read((char*)&usableRestrictionsCounter, sizeof(unsigned));
- inputRestrictions.resize(usableRestrictionsCounter);
- restrictionsInstream.read((char *)&(inputRestrictions[0]), usableRestrictionsCounter*sizeof(_Restriction));
- restrictionsInstream.close();
-
- std::ifstream in;
- in.open (argv[1], std::ifstream::in | std::ifstream::binary);
- if (!in.is_open()) {
- ERR("Cannot open " << argv[1]);
- }
-
- std::vector<ImportEdge> edgeList;
- NodeID nodeBasedNodeNumber = readBinaryOSRMGraphFromStream(in, edgeList, bollardNodes, trafficLightNodes, &internalToExternalNodeMapping, inputRestrictions);
- in.close();
- INFO(inputRestrictions.size() << " restrictions, " << bollardNodes.size() << " bollard nodes, " << trafficLightNodes.size() << " traffic lights");
-
- /***
- * Building an edge-expanded graph from node-based input an turn restrictions
- */
-
- INFO("Starting SCC graph traversal");
- TarjanSCC * tarjan = new TarjanSCC (nodeBasedNodeNumber, edgeList, bollardNodes, trafficLightNodes, inputRestrictions, internalToExternalNodeMapping);
- std::vector<ImportEdge>().swap(edgeList);
- tarjan->Run();
- std::vector<_Restriction>().swap(inputRestrictions);
- std::vector<NodeID>().swap(bollardNodes);
- std::vector<NodeID>().swap(trafficLightNodes);
- INFO("finished component analysis");
- return 0;
-}
diff --git a/Tools/components.cpp b/Tools/components.cpp
new file mode 100644
index 0000000..945d94f
--- /dev/null
+++ b/Tools/components.cpp
@@ -0,0 +1,136 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../typedefs.h"
+#include "../Algorithms/StronglyConnectedComponents.h"
+#include "../DataStructures/DynamicGraph.h"
+#include "../DataStructures/QueryEdge.h"
+#include "../DataStructures/TurnInstructions.h"
+#include "../Util/GraphLoader.h"
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/FingerPrint.h"
+
+#include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
+
+typedef QueryEdge::EdgeData EdgeData;
+typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
+
+std::vector<NodeInfo> internal_to_external_node_map;
+std::vector<TurnRestriction> restrictions_vector;
+std::vector<NodeID> bollard_node_IDs_vector;
+std::vector<NodeID> traffic_light_node_IDs_vector;
+
+int main(int argc, char *argv[])
+{
+ LogPolicy::GetInstance().Unmute();
+ if (argc < 3)
+ {
+ SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0] << " <osrm> <osrm.restrictions>";
+ return -1;
+ }
+
+ try
+ {
+ SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
+ std::ifstream restriction_ifstream(argv[2], std::ios::binary);
+ const FingerPrint fingerprint_orig;
+ FingerPrint fingerprint_loaded;
+ restriction_ifstream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+
+ if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+ {
+ SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
+ "Reprocess to get rid of this warning.";
+ }
+
+ if (!restriction_ifstream.good())
+ {
+ throw OSRMException("Could not access <osrm-restrictions> files");
+ }
+ uint32_t usable_restriction_count = 0;
+ restriction_ifstream.read((char *)&usable_restriction_count, sizeof(uint32_t));
+ restrictions_vector.resize(usable_restriction_count);
+
+ if (usable_restriction_count>0)
+ {
+ restriction_ifstream.read((char *)&(restrictions_vector[0]),
+ usable_restriction_count * sizeof(TurnRestriction));
+ }
+ restriction_ifstream.close();
+
+ std::ifstream input_stream;
+ input_stream.open(argv[1], std::ifstream::in | std::ifstream::binary);
+
+ if (!input_stream.is_open())
+ {
+ throw OSRMException("Cannot open osrm file");
+ }
+
+ std::vector<ImportEdge> edge_list;
+ const NodeID number_of_nodes = readBinaryOSRMGraphFromStream(input_stream,
+ edge_list,
+ bollard_node_IDs_vector,
+ traffic_light_node_IDs_vector,
+ &internal_to_external_node_map,
+ restrictions_vector);
+ input_stream.close();
+
+ BOOST_ASSERT_MSG(restrictions_vector.size() == usable_restriction_count,
+ "size of restrictions_vector changed");
+
+ SimpleLogger().Write() << restrictions_vector.size() << " restrictions, "
+ << bollard_node_IDs_vector.size() << " bollard nodes, "
+ << traffic_light_node_IDs_vector.size() << " traffic lights";
+
+ /***
+ * Building an edge-expanded graph from node-based input an turn
+ * restrictions
+ */
+
+ SimpleLogger().Write() << "Starting SCC graph traversal";
+ std::shared_ptr<TarjanSCC> tarjan =
+ std::make_shared<TarjanSCC>(number_of_nodes,
+ edge_list,
+ bollard_node_IDs_vector,
+ traffic_light_node_IDs_vector,
+ restrictions_vector,
+ internal_to_external_node_map);
+ std::vector<ImportEdge>().swap(edge_list);
+
+ tarjan->Run();
+ SimpleLogger().Write() << "finished component analysis";
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ }
+ return 0;
+}
diff --git a/Tools/io-benchmark.cpp b/Tools/io-benchmark.cpp
new file mode 100644
index 0000000..6304aae
--- /dev/null
+++ b/Tools/io-benchmark.cpp
@@ -0,0 +1,348 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../Util/GitDescription.h"
+#include "../Util/OSRMException.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/TimingUtil.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <fcntl.h>
+#ifdef __linux__
+#include <malloc.h>
+#endif
+
+#include <algorithm>
+#include <chrono>
+#include <iomanip>
+#include <numeric>
+#include <vector>
+
+const unsigned number_of_elements = 268435456;
+
+struct Statistics
+{
+ double min, max, med, mean, dev;
+};
+
+void RunStatistics(std::vector<double> &timings_vector, Statistics &stats)
+{
+ std::sort(timings_vector.begin(), timings_vector.end());
+ stats.min = timings_vector.front();
+ stats.max = timings_vector.back();
+ stats.med = timings_vector[timings_vector.size() / 2];
+ double primary_sum = std::accumulate(timings_vector.begin(), timings_vector.end(), 0.0);
+ stats.mean = primary_sum / timings_vector.size();
+
+ double primary_sq_sum = std::inner_product(
+ timings_vector.begin(), timings_vector.end(), timings_vector.begin(), 0.0);
+ stats.dev = std::sqrt(primary_sq_sum / timings_vector.size() - (stats.mean * stats.mean));
+}
+
+int main(int argc, char *argv[])
+{
+ LogPolicy::GetInstance().Unmute();
+
+ SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
+ << "compiled at " << __DATE__ << ", " __TIME__;
+
+#ifdef __FreeBSD__
+ SimpleLogger().Write() << "Not supported on FreeBSD";
+ return 0;
+#endif
+#ifdef WIN32
+ SimpleLogger().Write() << "Not supported on Windows";
+ return 0;
+#else
+
+
+ if (1 == argc)
+ {
+ SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " /path/on/device";
+ return -1;
+ }
+
+ boost::filesystem::path test_path = boost::filesystem::path(argv[1]);
+ test_path /= "osrm.tst";
+ SimpleLogger().Write(logDEBUG) << "temporary file: " << test_path.string();
+
+ try
+ {
+ // create files for testing
+ if (2 == argc)
+ {
+ // create file to test
+ if (boost::filesystem::exists(test_path))
+ {
+ throw OSRMException("Data file already exists");
+ }
+
+ int *random_array = new int[number_of_elements];
+ std::generate(random_array, random_array + number_of_elements, std::rand);
+#ifdef __APPLE__
+ FILE *fd = fopen(test_path.string().c_str(), "w");
+ fcntl(fileno(fd), F_NOCACHE, 1);
+ fcntl(fileno(fd), F_RDAHEAD, 0);
+ TIMER_START(write_1gb);
+ write(fileno(fd), (char *)random_array, number_of_elements * sizeof(unsigned));
+ TIMER_STOP(write_1gb);
+ fclose(fd);
+#endif
+#ifdef __linux__
+ int f =
+ open(test_path.string().c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, S_IRWXU);
+ if (-1 == f)
+ {
+ throw OSRMException("Could not open random data file");
+ }
+ TIMER_START(write_1gb);
+ int ret = write(f, random_array, number_of_elements * sizeof(unsigned));
+ if (0 > ret)
+ {
+ throw OSRMException("could not write random data file");
+ }
+ TIMER_STOP(write_1gb);
+ close(f);
+#endif
+ delete[] random_array;
+ SimpleLogger().Write(logDEBUG) << "writing raw 1GB took " << TIMER_SEC(write_1gb)
+ << "s";
+ SimpleLogger().Write() << "raw write performance: " << std::setprecision(5)
+ << std::fixed << 1024 * 1024 / TIMER_SEC(write_1gb)
+ << "MB/sec";
+
+ SimpleLogger().Write(logDEBUG)
+ << "finished creation of random data. Flush disk cache now!";
+ }
+ else
+ {
+ // Run Non-Cached I/O benchmarks
+ if (!boost::filesystem::exists(test_path))
+ {
+ throw OSRMException("data file does not exist");
+ }
+
+ // volatiles do not get optimized
+ Statistics stats;
+
+#ifdef __APPLE__
+ volatile unsigned single_block[1024];
+ char *raw_array = new char[number_of_elements * sizeof(unsigned)];
+ FILE *fd = fopen(test_path.string().c_str(), "r");
+ fcntl(fileno(fd), F_NOCACHE, 1);
+ fcntl(fileno(fd), F_RDAHEAD, 0);
+#endif
+#ifdef __linux__
+ char *single_block = (char *)memalign(512, 1024 * sizeof(unsigned));
+
+ int f = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+ if (-1 == f)
+ {
+ SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
+ return -1;
+ }
+ char *raw_array = (char *)memalign(512, number_of_elements * sizeof(unsigned));
+#endif
+ TIMER_START(read_1gb);
+#ifdef __APPLE__
+ read(fileno(fd), raw_array, number_of_elements * sizeof(unsigned));
+ close(fileno(fd));
+ fd = fopen(test_path.string().c_str(), "r");
+#endif
+#ifdef __linux__
+ int ret = read(f, raw_array, number_of_elements * sizeof(unsigned));
+ SimpleLogger().Write(logDEBUG) << "read " << ret
+ << " bytes, error: " << strerror(errno);
+ close(f);
+ f = open(test_path.string().c_str(), O_RDONLY | O_DIRECT | O_SYNC);
+ SimpleLogger().Write(logDEBUG) << "opened, error: " << strerror(errno);
+#endif
+ TIMER_STOP(read_1gb);
+
+ SimpleLogger().Write(logDEBUG) << "reading raw 1GB took " << TIMER_SEC(read_1gb)
+ << "s";
+ SimpleLogger().Write() << "raw read performance: " << std::setprecision(5) << std::fixed
+ << 1024 * 1024 / TIMER_SEC(read_1gb) << "MB/sec";
+
+ std::vector<double> timing_results_raw_random;
+ SimpleLogger().Write(logDEBUG) << "running 1000 random I/Os of 4KB";
+
+#ifdef __APPLE__
+ fseek(fd, 0, SEEK_SET);
+#endif
+#ifdef __linux__
+ lseek(f, 0, SEEK_SET);
+#endif
+ // make 1000 random access, time each I/O seperately
+ unsigned number_of_blocks = (number_of_elements * sizeof(unsigned) - 1) / 4096;
+ for (unsigned i = 0; i < 1000; ++i)
+ {
+ unsigned block_to_read = std::rand() % number_of_blocks;
+ off_t current_offset = block_to_read * 4096;
+ TIMER_START(random_access);
+#ifdef __APPLE__
+ int ret1 = fseek(fd, current_offset, SEEK_SET);
+ int ret2 = read(fileno(fd), (char *)&single_block[0], 4096);
+#endif
+
+#ifdef __FreeBSD__
+ int ret1 = 0;
+ int ret2 = 0;
+#endif
+
+#ifdef __linux__
+ int ret1 = lseek(f, current_offset, SEEK_SET);
+ int ret2 = read(f, (char *)single_block, 4096);
+#endif
+ TIMER_STOP(random_access);
+ if (((off_t) - 1) == ret1)
+ {
+ SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+ SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
+ throw OSRMException("seek error");
+ }
+ if (-1 == ret2)
+ {
+ SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+ SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
+ throw OSRMException("read error");
+ }
+ timing_results_raw_random.push_back(TIMER_SEC(random_access));
+ }
+
+ // Do statistics
+ SimpleLogger().Write(logDEBUG) << "running raw random I/O statistics";
+ std::ofstream random_csv("random.csv", std::ios::trunc);
+ for (unsigned i = 0; i < timing_results_raw_random.size(); ++i)
+ {
+ random_csv << i << ", " << timing_results_raw_random[i] << std::endl;
+ }
+ random_csv.close();
+ RunStatistics(timing_results_raw_random, stats);
+
+ SimpleLogger().Write() << "raw random I/O: " << std::setprecision(5) << std::fixed
+ << "min: " << stats.min << "ms, "
+ << "mean: " << stats.mean << "ms, "
+ << "med: " << stats.med << "ms, "
+ << "max: " << stats.max << "ms, "
+ << "dev: " << stats.dev << "ms";
+
+ std::vector<double> timing_results_raw_seq;
+#ifdef __APPLE__
+ fseek(fd, 0, SEEK_SET);
+#endif
+#ifdef __linux__
+ lseek(f, 0, SEEK_SET);
+#endif
+
+ // read every 100th block
+ for (unsigned i = 0; i < 1000; ++i)
+ {
+ off_t current_offset = i * 4096;
+ TIMER_START(read_every_100);
+#ifdef __APPLE__
+ int ret1 = fseek(fd, current_offset, SEEK_SET);
+ int ret2 = read(fileno(fd), (char *)&single_block, 4096);
+#endif
+
+#ifdef __FreeBSD__
+ int ret1 = 0;
+ int ret2 = 0;
+#endif
+
+#ifdef __linux__
+ int ret1 = lseek(f, current_offset, SEEK_SET);
+
+ int ret2 = read(f, (char *)single_block, 4096);
+#endif
+ TIMER_STOP(read_every_100);
+ if (((off_t) - 1) == ret1)
+ {
+ SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+ SimpleLogger().Write(logWARNING) << "seek error " << strerror(errno);
+ throw OSRMException("seek error");
+ }
+ if (-1 == ret2)
+ {
+ SimpleLogger().Write(logWARNING) << "offset: " << current_offset;
+ SimpleLogger().Write(logWARNING) << "read error " << strerror(errno);
+ throw OSRMException("read error");
+ }
+ timing_results_raw_seq.push_back(TIMER_SEC(read_every_100));
+ }
+#ifdef __APPLE__
+ fclose(fd);
+ // free(single_element);
+ free(raw_array);
+// free(single_block);
+#endif
+#ifdef __linux__
+ close(f);
+#endif
+ // Do statistics
+ SimpleLogger().Write(logDEBUG) << "running sequential I/O statistics";
+ // print simple statistics: min, max, median, variance
+ std::ofstream seq_csv("sequential.csv", std::ios::trunc);
+ for (unsigned i = 0; i < timing_results_raw_seq.size(); ++i)
+ {
+ seq_csv << i << ", " << timing_results_raw_seq[i] << std::endl;
+ }
+ seq_csv.close();
+ RunStatistics(timing_results_raw_seq, stats);
+ SimpleLogger().Write() << "raw sequential I/O: " << std::setprecision(5) << std::fixed
+ << "min: " << stats.min << "ms, "
+ << "mean: " << stats.mean << "ms, "
+ << "med: " << stats.med << "ms, "
+ << "max: " << stats.max << "ms, "
+ << "dev: " << stats.dev << "ms";
+
+ if (boost::filesystem::exists(test_path))
+ {
+ boost::filesystem::remove(test_path);
+ SimpleLogger().Write(logDEBUG) << "removing temporary files";
+ }
+ }
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
+ SimpleLogger().Write(logWARNING) << "cleaning up, and exiting";
+ if (boost::filesystem::exists(test_path))
+ {
+ boost::filesystem::remove(test_path);
+ SimpleLogger().Write(logWARNING) << "removing temporary files";
+ }
+ return -1;
+ }
+ return 0;
+#endif
+}
diff --git a/Tools/simpleclient.cpp b/Tools/simpleclient.cpp
new file mode 100644
index 0000000..68d4b1d
--- /dev/null
+++ b/Tools/simpleclient.cpp
@@ -0,0 +1,131 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../Library/OSRM.h"
+#include "../Util/GitDescription.h"
+#include "../Util/ProgramOptions.h"
+#include "../Util/SimpleLogger.h"
+
+#include <osrm/Reply.h>
+#include <osrm/RouteParameters.h>
+#include <osrm/ServerPaths.h>
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+
+#include <iostream>
+#include <stack>
+#include <string>
+#include <sstream>
+
+// Dude, real recursions on the OS stack? You must be brave...
+void print_tree(boost::property_tree::ptree const &property_tree, const unsigned recursion_depth)
+{
+ auto end = property_tree.end();
+ for (auto tree_iterator = property_tree.begin(); tree_iterator != end; ++tree_iterator)
+ {
+ for (unsigned current_recursion = 0; current_recursion < recursion_depth;
+ ++current_recursion)
+ {
+ std::cout << " " << std::flush;
+ }
+ std::cout << tree_iterator->first << ": " << tree_iterator->second.get_value<std::string>()
+ << std::endl;
+ print_tree(tree_iterator->second, recursion_depth + 1);
+ }
+}
+
+int main(int argc, const char *argv[])
+{
+ LogPolicy::GetInstance().Unmute();
+ try
+ {
+ std::string ip_address;
+ int ip_port, requested_thread_num;
+ bool use_shared_memory = false, trial = false;
+ ServerPaths server_paths;
+ if (!GenerateServerProgramOptions(argc,
+ argv,
+ server_paths,
+ ip_address,
+ ip_port,
+ requested_thread_num,
+ use_shared_memory,
+ trial))
+ {
+ return 0;
+ }
+
+ SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
+ << "compiled at " << __DATE__ << ", " __TIME__;
+
+ OSRM routing_machine(server_paths, use_shared_memory);
+
+ RouteParameters route_parameters;
+ route_parameters.zoom_level = 18; // no generalization
+ route_parameters.print_instructions = true; // turn by turn instructions
+ route_parameters.alternate_route = true; // get an alternate route, too
+ route_parameters.geometry = true; // retrieve geometry of route
+ route_parameters.compression = true; // polyline encoding
+ route_parameters.check_sum = UINT_MAX; // see wiki
+ route_parameters.service = "viaroute"; // that's routing
+ route_parameters.output_format = "json";
+ route_parameters.jsonp_parameter = ""; // set for jsonp wrapping
+ route_parameters.language = ""; // unused atm
+ // route_parameters.hints.push_back(); // see wiki, saves I/O if done properly
+
+ // start_coordinate
+ route_parameters.coordinates.emplace_back(52.519930 * COORDINATE_PRECISION,
+ 13.438640 * COORDINATE_PRECISION);
+ // target_coordinate
+ route_parameters.coordinates.emplace_back(52.513191 * COORDINATE_PRECISION,
+ 13.415852 * COORDINATE_PRECISION);
+ http::Reply osrm_reply;
+ routing_machine.RunQuery(route_parameters, osrm_reply);
+
+ // attention: super-inefficient hack below:
+
+ std::stringstream my_stream;
+ for (const auto &element : osrm_reply.content)
+ {
+ std::cout << element;
+ my_stream << element;
+ }
+ std::cout << std::endl;
+
+ boost::property_tree::ptree property_tree;
+ boost::property_tree::read_json(my_stream, property_tree);
+
+ print_tree(property_tree, 0);
+ }
+ catch (std::exception ¤t_exception)
+ {
+ SimpleLogger().Write(logWARNING) << "caught exception: " << current_exception.what();
+ return -1;
+ }
+ return 0;
+}
diff --git a/Tools/unlock_all_mutexes.cpp b/Tools/unlock_all_mutexes.cpp
new file mode 100644
index 0000000..4d4156f
--- /dev/null
+++ b/Tools/unlock_all_mutexes.cpp
@@ -0,0 +1,52 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "../Util/GitDescription.h"
+#include "../Util/SimpleLogger.h"
+#include "../Server/DataStructures/SharedBarriers.h"
+
+#include <iostream>
+
+int main()
+{
+ LogPolicy::GetInstance().Unmute();
+ try
+ {
+ SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
+ << "compiled at " << __DATE__ << ", " __TIME__;
+ SimpleLogger().Write() << "Releasing all locks";
+ SharedBarriers barrier;
+ barrier.pending_update_mutex.unlock();
+ barrier.query_mutex.unlock();
+ barrier.update_mutex.unlock();
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "[excpetion] " << e.what();
+ }
+ return 0;
+}
diff --git a/Util/Azimuth.h b/Util/Azimuth.h
index 166f55f..c4bf815 100644
--- a/Util/Azimuth.h
+++ b/Util/Azimuth.h
@@ -1,52 +1,73 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
-#ifndef AZIMUTH_H_
-#define AZIMUTH_H_
+#ifndef AZIMUTH_H
+#define AZIMUTH_H
#include <string>
-struct Azimuth {
- static std::string Get(const double heading) {
- if(heading <= 202.5) {
- if(heading >= 0 && heading <= 22.5)
+struct Azimuth
+{
+ static std::string Get(const double heading)
+ {
+ if (heading <= 202.5)
+ {
+ if (heading >= 0 && heading <= 22.5)
+ {
return "N";
- if(heading > 22.5 && heading <= 67.5)
+ }
+ if (heading > 22.5 && heading <= 67.5)
+ {
return "NE";
- if(heading > 67.5 && heading <= 112.5)
+ }
+ if (heading > 67.5 && heading <= 112.5)
+ {
return "E";
- if(heading > 112.5 && heading <= 157.5)
+ }
+ if (heading > 112.5 && heading <= 157.5)
+ {
return "SE";
+ }
return "S";
}
- if(heading > 202.5 && heading <= 247.5)
+ if (heading > 202.5 && heading <= 247.5)
+ {
return "SW";
- if(heading > 247.5 && heading <= 292.5)
+ }
+ if (heading > 247.5 && heading <= 292.5)
+ {
return "W";
- if(heading > 292.5 && heading <= 337.5)
+ }
+ if (heading > 292.5 && heading <= 337.5)
+ {
return "NW";
+ }
return "N";
}
};
-
-#endif /* AZIMUTH_H_ */
+#endif // AZIMUTH_H
diff --git a/Util/BaseConfiguration.h b/Util/BaseConfiguration.h
deleted file mode 100644
index 69bc61f..0000000
--- a/Util/BaseConfiguration.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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 BASECONFIGURATION_H_
-#define BASECONFIGURATION_H_
-
-#include <iostream>
-#include <string>
-#include <exception>
-#include <fstream>
-
-#include "../DataStructures/HashTable.h"
-
-class BaseConfiguration {
-public:
- BaseConfiguration(const char * configFile) {
- std::ifstream config( configFile );
- if(!config) {
- std::cerr << "[config] .ini not found" << std::endl;
- return;
- }
-
- std::string line;
- try {
- if (config.is_open()) {
- while ( config.good() ) {
- getline (config,line);
- std::vector<std::string> tokens;
- Tokenize(line, tokens);
- if(2 == tokens.size() )
- parameters.Add(tokens[0], tokens[1]);
- }
- config.close();
- }
- } catch(std::exception& e) {
- ERR("[config] " << configFile << " not found -> Exception: " <<e.what());
- if(config.is_open())
- config.close();
- }
- }
-
- std::string GetParameter(const char * key){
- return GetParameter(std::string(key));
- }
-
- std::string GetParameter(std::string key) {
- return parameters.Find(key);
- }
-
- void SetParameter(const char* key, const char* value) {
- SetParameter(std::string(key), std::string(value));
- }
-
- void SetParameter(std::string key, std::string value) {
- parameters.Set(key, value);
- }
-
-private:
- void Tokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters = "=") {
- std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
- std::string::size_type pos = str.find_first_of(delimiters, lastPos);
-
- while (std::string::npos != pos || std::string::npos != lastPos) {
- std::string temp = str.substr(lastPos, pos - lastPos);
- TrimStringRight(temp);
- TrimStringLeft(temp);
- tokens.push_back( temp );
- lastPos = str.find_first_not_of(delimiters, pos);
- pos = str.find_first_of(delimiters, lastPos);
- }
- }
- void TrimStringRight(std::string& str) {
- std::string::size_type pos = str.find_last_not_of(" ");
- if (pos != std::string::npos)
- str.erase(pos+1);
- else
- str.erase( str.begin() , str.end() );
- }
- void TrimStringLeft(std::string& str) {
- std::string::size_type pos = str.find_first_not_of(" ");
- if (pos != std::string::npos)
- str.erase(0, pos);
- else
- str.erase( str.begin() , str.end() );
- }
-
- HashTable<std::string, std::string> parameters;
-};
-
-#endif /* BASECONFIGURATION_H_ */
diff --git a/Util/BoostFileSystemFix.h b/Util/BoostFileSystemFix.h
new file mode 100644
index 0000000..1e1e98e
--- /dev/null
+++ b/Util/BoostFileSystemFix.h
@@ -0,0 +1,147 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef BOOST_FILE_SYSTEM_FIX_H
+#define BOOST_FILE_SYSTEM_FIX_H
+
+#include "OSRMException.h"
+#include "SimpleLogger.h"
+
+#include <boost/any.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+// This is one big workaround for latest boost renaming woes.
+
+#if BOOST_FILESYSTEM_VERSION < 3
+#warning Boost Installation with Filesystem3 missing, activating workaround
+#include <cstdio>
+#endif
+
+namespace boost
+{
+namespace filesystem
+{
+
+// Validator for boost::filesystem::path, that verifies that the file
+// exists. The validate() function must be defined in the same namespace
+// as the target type, (boost::filesystem::path in this case), otherwise
+// it is not called
+// inline void validate(
+// boost::any & v,
+// const std::vector<std::string> & values,
+// boost::filesystem::path *,
+// int
+// ) {
+// boost::program_options::validators::check_first_occurrence(v);
+// const std::string & input_string =
+// boost::program_options::validators::get_single_string(values);
+// // SimpleLogger().Write() << "validator called for " << input_string;
+// // SimpleLogger().Write() << "validator called for " << input_string;
+// if(boost::filesystem::is_regular_file(input_string)) {
+// v = boost::any(boost::filesystem::path(input_string));
+// } else {
+// throw OSRMException(input_string + " not found");
+// }
+// }
+
+// adapted from:
+// http://stackoverflow.com/questions/1746136/how-do-i-normalize-a-pathname-using-boostfilesystem
+inline boost::filesystem::path
+portable_canonical(const boost::filesystem::path &relative_path,
+ const boost::filesystem::path ¤t_path = boost::filesystem::current_path())
+{
+ const boost::filesystem::path absolute_path =
+ boost::filesystem::absolute(relative_path, current_path);
+
+ boost::filesystem::path canonical_path;
+ for (auto path_iterator = absolute_path.begin(); path_iterator != absolute_path.end();
+ ++path_iterator)
+ {
+ if (".." == path_iterator->string())
+ {
+ // /a/b/.. is not necessarily /a if b is a symbolic link
+ if (boost::filesystem::is_symlink(canonical_path))
+ {
+ canonical_path /= *path_iterator;
+ }
+ else if (".." == canonical_path.filename())
+ {
+ // /a/b/../.. is not /a/b/.. under most circumstances
+ // We can end up with ..s in our result because of symbolic links
+ canonical_path /= *path_iterator;
+ }
+ else
+ {
+ // Otherwise it should be safe to resolve the parent
+ canonical_path = canonical_path.parent_path();
+ }
+ }
+ else if ("." == path_iterator->string())
+ {
+ // Ignore
+ }
+ else
+ {
+ // Just cat other path entries
+ canonical_path /= *path_iterator;
+ }
+ }
+ BOOST_ASSERT(canonical_path.is_absolute());
+ BOOST_ASSERT(boost::filesystem::exists(canonical_path));
+ return canonical_path;
+}
+
+#if BOOST_FILESYSTEM_VERSION < 3
+
+inline path temp_directory_path()
+{
+ char *buffer;
+ buffer = tmpnam(NULL);
+
+ return path(buffer);
+}
+
+inline path unique_path(const path &) { return temp_directory_path(); }
+
+#endif
+}
+}
+
+#ifndef BOOST_FILESYSTEM_VERSION
+#define BOOST_FILESYSTEM_VERSION 3
+#endif
+
+inline void AssertPathExists(const boost::filesystem::path &path)
+{
+ if (!boost::filesystem::is_regular_file(path))
+ {
+ throw OSRMException(path.string() + " not found.");
+ }
+}
+
+#endif /* BOOST_FILE_SYSTEM_FIX_H */
diff --git a/Util/ComputeAngle.h b/Util/ComputeAngle.h
new file mode 100644
index 0000000..02f678a
--- /dev/null
+++ b/Util/ComputeAngle.h
@@ -0,0 +1,57 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef COMPUTE_ANGLE_H
+#define COMPUTE_ANGLE_H
+
+#include "TrigonometryTables.h"
+#include "../Util/MercatorUtil.h"
+#include <osrm/Coordinate.h>
+
+#include <boost/assert.hpp>
+#include <cmath>
+
+/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
+template <class CoordinateT>
+inline static double GetAngleBetweenThreeFixedPointCoordinates(const CoordinateT &A,
+ const CoordinateT &C,
+ const CoordinateT &B)
+{
+ const double v1x = (A.lon - C.lon) / COORDINATE_PRECISION;
+ const double v1y = lat2y(A.lat / COORDINATE_PRECISION) - lat2y(C.lat / COORDINATE_PRECISION);
+ const double v2x = (B.lon - C.lon) / COORDINATE_PRECISION;
+ const double v2y = lat2y(B.lat / COORDINATE_PRECISION) - lat2y(C.lat / COORDINATE_PRECISION);
+
+ double angle = (atan2_lookup(v2y, v2x) - atan2_lookup(v1y, v1x)) * 180 / M_PI;
+ while (angle < 0)
+ {
+ angle += 360;
+ }
+ return angle;
+}
+
+#endif // COMPUTE_ANGLE_H
diff --git a/Util/ContainerUtils.h b/Util/ContainerUtils.h
index 215e988..2517545 100644
--- a/Util/ContainerUtils.h
+++ b/Util/ContainerUtils.h
@@ -1,9 +1,29 @@
/*
- * ContainerUtils.h
- *
- * Created on: 02.02.2013
- * Author: dennis
- */
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef CONTAINERUTILS_H_
#define CONTAINERUTILS_H_
@@ -11,24 +31,41 @@
#include <algorithm>
#include <vector>
-template<typename T>
-inline void sort_unique_resize(std::vector<T> & vector) {
- std::sort(vector.begin(), vector.end());
- unsigned number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
- vector.resize(number_of_unique_elements);
+template <typename T> inline void sort_unique_resize(std::vector<T> &vector)
+{
+ std::sort(vector.begin(), vector.end());
+ const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
+ vector.resize(number_of_unique_elements);
}
-template<typename T>
-inline void sort_unique_resize_shrink_vector(std::vector<T> & vector) {
- sort_unique_resize(vector);
- std::vector<T>().swap(vector);
+template <typename T> inline void sort_unique_resize_shrink_vector(std::vector<T> &vector)
+{
+ sort_unique_resize(vector);
+ std::vector<T>().swap(vector);
}
-template<typename T>
-inline void remove_consecutive_duplicates_from_vector(std::vector<T> & vector) {
- unsigned number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
+template <typename T> inline void remove_consecutive_duplicates_from_vector(std::vector<T> &vector)
+{
+ const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) - vector.begin();
vector.resize(number_of_unique_elements);
}
+template <typename FwdIter, typename Func>
+Func for_each_pair(FwdIter iter_begin, FwdIter iter_end, Func func)
+{
+ if (iter_begin == iter_end)
+ {
+ return func;
+ }
+
+ FwdIter iter_next = iter_begin;
+ ++iter_next;
+
+ for (; iter_next != iter_end; ++iter_begin, ++iter_next)
+ {
+ func(*iter_begin, *iter_next);
+ }
+ return func;
+}
#endif /* CONTAINERUTILS_H_ */
diff --git a/Util/DataStoreOptions.h b/Util/DataStoreOptions.h
new file mode 100644
index 0000000..7a76bfb
--- /dev/null
+++ b/Util/DataStoreOptions.h
@@ -0,0 +1,284 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef DATA_STORE_OPTIONS_H
+#define DATA_STORE_OPTIONS_H
+
+#include "BoostFileSystemFix.h"
+#include "GitDescription.h"
+#include "IniFileUtil.h"
+#include "OSRMException.h"
+#include "SimpleLogger.h"
+
+#include <osrm/ServerPaths.h>
+
+#include <boost/any.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+#include <string>
+
+// generate boost::program_options object for the routing part
+inline bool GenerateDataStoreOptions(const int argc, const char *argv[], ServerPaths &paths, bool & springclean)
+{
+ // declare a group of options that will be allowed only on command line
+ boost::program_options::options_description generic_options("Options");
+ generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")
+ ("springclean,s", "Remove all regions in shared memory")("config,c",
+ boost::program_options::value<boost::filesystem::path>(&paths["config"])
+ ->default_value("server.ini"),
+ "Path to a configuration file");
+
+ // declare a group of options that will be allowed both on command line
+ // as well as in a config file
+ boost::program_options::options_description config_options("Configuration");
+ config_options.add_options()(
+ "hsgrdata",
+ boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
+ ".hsgr file")("nodesdata",
+ boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
+ ".nodes file")(
+ "edgesdata",
+ boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
+ ".edges file")("geometry",
+ boost::program_options::value<boost::filesystem::path>(&paths["geometry"]),
+ ".geometry file")(
+ "ramindex",
+ boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
+ ".ramIndex file")(
+ "fileindex",
+ boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
+ ".fileIndex file")(
+ "namesdata",
+ boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
+ ".names file")("timestamp",
+ boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
+ ".timestamp file");
+
+ // hidden options, will be allowed both on command line and in config
+ // file, but will not be shown to the user
+ boost::program_options::options_description hidden_options("Hidden options");
+ hidden_options.add_options()(
+ "base,b",
+ boost::program_options::value<boost::filesystem::path>(&paths["base"]),
+ "base path to .osrm file");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("base", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description config_file_options;
+ config_file_options.add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ boost::filesystem::basename(argv[0]) + " [<options>] <configuration>");
+ visible_options.add(generic_options).add(config_options);
+
+ // parse command line options
+ boost::program_options::variables_map option_variables;
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(cmdline_options)
+ .positional(positional_options)
+ .run(),
+ option_variables);
+
+ if (option_variables.count("version"))
+ {
+ SimpleLogger().Write() << g_GIT_DESCRIPTION;
+ return false;
+ }
+
+ if (option_variables.count("help"))
+ {
+ SimpleLogger().Write() << visible_options;
+ return false;
+ }
+
+ if (option_variables.count("springclean"))
+ {
+ springclean = true;
+ return true;
+ }
+ boost::program_options::notify(option_variables);
+
+ const bool parameter_present = (paths.find("hsgrdata") != paths.end() &&
+ !paths.find("hsgrdata")->second.string().empty()) ||
+ (paths.find("nodesdata") != paths.end() &&
+ !paths.find("nodesdata")->second.string().empty()) ||
+ (paths.find("edgesdata") != paths.end() &&
+ !paths.find("edgesdata")->second.string().empty()) ||
+ (paths.find("geometry") != paths.end() &&
+ !paths.find("geometry")->second.string().empty()) ||
+ (paths.find("ramindex") != paths.end() &&
+ !paths.find("ramindex")->second.string().empty()) ||
+ (paths.find("fileindex") != paths.end() &&
+ !paths.find("fileindex")->second.string().empty()) ||
+ (paths.find("timestamp") != paths.end() &&
+ !paths.find("timestamp")->second.string().empty());
+
+ if (parameter_present)
+ {
+ if ((paths.find("config") != paths.end() &&
+ boost::filesystem::is_regular_file(paths.find("config")->second)) ||
+ option_variables.count("base"))
+ {
+ SimpleLogger().Write(logWARNING) << "conflicting parameters";
+ SimpleLogger().Write() << visible_options;
+ return false;
+ }
+ }
+
+ // parse config file
+ ServerPaths::iterator path_iterator = paths.find("config");
+ if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
+ !option_variables.count("base"))
+ {
+ SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
+ std::string ini_file_contents = ReadIniFileAndLowerContents(path_iterator->second);
+ std::stringstream config_stream(ini_file_contents);
+ boost::program_options::store(parse_config_file(config_stream, config_file_options),
+ option_variables);
+ boost::program_options::notify(option_variables);
+ }
+ else if (option_variables.count("base"))
+ {
+ path_iterator = paths.find("base");
+ BOOST_ASSERT(paths.end() != path_iterator);
+ std::string base_string = path_iterator->second.string();
+
+ path_iterator = paths.find("hsgrdata");
+ if (path_iterator != paths.end())
+ {
+ path_iterator->second = base_string + ".hsgr";
+ }
+
+ path_iterator = paths.find("nodesdata");
+ if (path_iterator != paths.end())
+ {
+ path_iterator->second = base_string + ".nodes";
+ }
+
+ path_iterator = paths.find("edgesdata");
+ if (path_iterator != paths.end())
+ {
+ path_iterator->second = base_string + ".edges";
+ }
+
+ path_iterator = paths.find("geometry");
+ if (path_iterator != paths.end())
+ {
+ path_iterator->second = base_string + ".geometry";
+ }
+
+ path_iterator = paths.find("ramindex");
+ if (path_iterator != paths.end())
+ {
+ path_iterator->second = base_string + ".ramIndex";
+ }
+
+ path_iterator = paths.find("fileindex");
+ if (path_iterator != paths.end())
+ {
+ path_iterator->second = base_string + ".fileIndex";
+ }
+
+ path_iterator = paths.find("namesdata");
+ if (path_iterator != paths.end())
+ {
+ path_iterator->second = base_string + ".names";
+ }
+
+ path_iterator = paths.find("timestamp");
+ if (path_iterator != paths.end())
+ {
+ path_iterator->second = base_string + ".timestamp";
+ }
+ }
+
+ path_iterator = paths.find("hsgrdata");
+ if (path_iterator == paths.end() || path_iterator->second.string().empty())
+ {
+ throw OSRMException(".hsgr file must be specified");
+ }
+ AssertPathExists(path_iterator->second);
+
+ path_iterator = paths.find("nodesdata");
+ if (path_iterator == paths.end() || path_iterator->second.string().empty())
+ {
+ throw OSRMException(".nodes file must be specified");
+ }
+ AssertPathExists(path_iterator->second);
+
+ path_iterator = paths.find("edgesdata");
+ if (path_iterator == paths.end() || path_iterator->second.string().empty())
+ {
+ throw OSRMException(".edges file must be specified");
+ }
+ AssertPathExists(path_iterator->second);
+
+ path_iterator = paths.find("geometry");
+ if (path_iterator == paths.end() || path_iterator->second.string().empty())
+ {
+ throw OSRMException(".geometry file must be specified");
+ }
+ AssertPathExists(path_iterator->second);
+
+ path_iterator = paths.find("ramindex");
+ if (path_iterator == paths.end() || path_iterator->second.string().empty())
+ {
+ throw OSRMException(".ramindex file must be specified");
+ }
+ AssertPathExists(path_iterator->second);
+
+ path_iterator = paths.find("fileindex");
+ if (path_iterator == paths.end() || path_iterator->second.string().empty())
+ {
+ throw OSRMException(".fileindex file must be specified");
+ }
+ AssertPathExists(path_iterator->second);
+
+ path_iterator = paths.find("namesdata");
+ if (path_iterator == paths.end() || path_iterator->second.string().empty())
+ {
+ throw OSRMException(".names file must be specified");
+ }
+ AssertPathExists(path_iterator->second);
+
+ path_iterator = paths.find("timestamp");
+ if (path_iterator == paths.end() || path_iterator->second.string().empty())
+ {
+ throw OSRMException(".timestamp file must be specified");
+ }
+
+ return true;
+}
+
+#endif /* DATA_STORE_OPTIONS_H */
diff --git a/Util/FingerPrint.cpp.in b/Util/FingerPrint.cpp.in
new file mode 100644
index 0000000..d1ce4f0
--- /dev/null
+++ b/Util/FingerPrint.cpp.in
@@ -0,0 +1,106 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "FingerPrint.h"
+
+#include "OSRMException.h"
+
+#include <boost/uuid/name_generator.hpp>
+
+#include <cstring>
+
+#include <algorithm>
+#include <string>
+
+#cmakedefine01 HAS64BITS
+#cmakedefine MD5PREPARE "${MD5PREPARE}"
+#cmakedefine MD5RTREE "${MD5RTREE}"
+#cmakedefine MD5GRAPH "${MD5GRAPH}"
+#cmakedefine MD5OBJECTS "${MD5OBJECTS}"
+
+FingerPrint::FingerPrint() : magic_number(1297240911)
+{
+ md5_prepare[32] = md5_tree[32] = md5_graph[32] = md5_objects[32] = '\0';
+
+ boost::uuids::name_generator gen(named_uuid);
+ std::string temp_string(__DATE__);
+ temp_string += __TIME__;
+
+ std::memcpy(md5_prepare, MD5PREPARE, strlen(MD5PREPARE));
+ temp_string += md5_prepare;
+ std::memcpy(md5_tree, MD5RTREE, 32);
+ temp_string += md5_tree;
+ std::memcpy(md5_graph, MD5GRAPH, 32);
+ temp_string += md5_graph;
+ std::memcpy(md5_objects, MD5OBJECTS, 32);
+ temp_string += md5_objects;
+
+ named_uuid = gen(temp_string);
+ has_64_bits = HAS64BITS;
+}
+
+FingerPrint::~FingerPrint() {}
+
+const boost::uuids::uuid &FingerPrint::GetFingerPrint() const { return named_uuid; }
+
+bool FingerPrint::IsMagicNumberOK() const { return 1297240911 == magic_number; }
+
+bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
+{
+ if (!other.IsMagicNumberOK())
+ {
+ throw OSRMException("hsgr input file misses magic number. Check or reprocess the file");
+ }
+ return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
+}
+
+bool FingerPrint::TestPrepare(const FingerPrint &other) const
+{
+ if (!other.IsMagicNumberOK())
+ {
+ throw OSRMException("osrm input file misses magic number. Check or reprocess the file");
+ }
+ return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
+}
+
+bool FingerPrint::TestRTree(const FingerPrint &other) const
+{
+ if (!other.IsMagicNumberOK())
+ {
+ throw OSRMException("r-tree input file misses magic number. Check or reprocess the file");
+ }
+ return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
+}
+
+bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
+{
+ if (!other.IsMagicNumberOK())
+ {
+ throw OSRMException("missing magic number. Check or reprocess the file");
+ }
+ return std::equal(md5_objects, md5_objects + 32, other.md5_objects);
+}
diff --git a/Util/FingerPrint.h b/Util/FingerPrint.h
new file mode 100644
index 0000000..c61fe36
--- /dev/null
+++ b/Util/FingerPrint.h
@@ -0,0 +1,60 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef FINGERPRINT_H
+#define FINGERPRINT_H
+
+#include <boost/uuid/uuid.hpp>
+
+// implements a singleton, i.e. there is one and only one conviguration object
+class FingerPrint
+{
+ public:
+ FingerPrint();
+ FingerPrint(const FingerPrint&) = delete;
+ ~FingerPrint();
+ const boost::uuids::uuid &GetFingerPrint() const;
+ bool IsMagicNumberOK() const;
+ bool TestGraphUtil(const FingerPrint &other) const;
+ bool TestPrepare(const FingerPrint &other) const;
+ bool TestRTree(const FingerPrint &other) const;
+ bool TestNodeInfo(const FingerPrint &other) const;
+ bool TestQueryObjects(const FingerPrint &other) const;
+
+ private:
+ const unsigned magic_number;
+ char md5_prepare[33];
+ char md5_tree[33];
+ char md5_graph[33];
+ char md5_objects[33];
+
+ // initialize to {6ba7b810-9dad-11d1-80b4-00c04fd430c8}
+ boost::uuids::uuid named_uuid;
+ bool has_64_bits;
+};
+
+#endif /* FingerPrint_H */
diff --git a/Util/GitDescription.cpp.in b/Util/GitDescription.cpp.in
new file mode 100644
index 0000000..6f4ba7e
--- /dev/null
+++ b/Util/GitDescription.cpp.in
@@ -0,0 +1,29 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#define GIT_DESCRIPTION "${GIT_DESCRIPTION}"
+char g_GIT_DESCRIPTION[] = GIT_DESCRIPTION;
diff --git a/Util/GitDescription.h b/Util/GitDescription.h
new file mode 100644
index 0000000..d3a00f4
--- /dev/null
+++ b/Util/GitDescription.h
@@ -0,0 +1,33 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef GIT_DESCRIPTION_H
+#define GIT_DESCRIPTION_H
+
+extern char g_GIT_DESCRIPTION[];
+
+#endif //GIT_DESCRIPTION_H
diff --git a/Util/GraphLoader.h b/Util/GraphLoader.h
index 5dc50f8..612332b 100644
--- a/Util/GraphLoader.h
+++ b/Util/GraphLoader.h
@@ -1,377 +1,320 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef GRAPHLOADER_H
#define GRAPHLOADER_H
+#include "OSRMException.h"
#include "../DataStructures/ImportNode.h"
#include "../DataStructures/ImportEdge.h"
-#include "../DataStructures/NodeCoords.h"
+#include "../DataStructures/QueryNode.h"
#include "../DataStructures/Restriction.h"
+#include "../Util/SimpleLogger.h"
+#include "../Util/FingerPrint.h"
#include "../typedefs.h"
#include <boost/assert.hpp>
-#include <boost/unordered_map.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <tbb/parallel_sort.h>
-#include <cassert>
#include <cmath>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iomanip>
+#include <unordered_map>
#include <vector>
-typedef boost::unordered_map<NodeID, NodeID> ExternalNodeMap;
-
-template<class EdgeT>
-struct _ExcessRemover {
- inline bool operator()( const EdgeT & edge ) const {
- return edge.source() == UINT_MAX;
+template <typename EdgeT>
+NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
+ std::vector<EdgeT> &edge_list,
+ std::vector<NodeID> &barrier_node_list,
+ std::vector<NodeID> &traffic_light_node_list,
+ std::vector<NodeInfo> *int_to_ext_node_id_map,
+ std::vector<TurnRestriction> &restriction_list)
+{
+ const FingerPrint fingerprint_orig;
+ FingerPrint fingerprint_loaded;
+ input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+
+ if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+ {
+ SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
+ "Reprocess to get rid of this warning.";
}
-};
-template<typename EdgeT>
-NodeID readBinaryOSRMGraphFromStream(std::istream &in, std::vector<EdgeT>& edgeList, std::vector<NodeID> &bollardNodes, std::vector<NodeID> &trafficLightNodes, std::vector<NodeInfo> * int2ExtNodeMap, std::vector<_Restriction> & inputRestrictions) {
NodeID n, source, target;
EdgeID m;
- short dir;// direction (0 = open, 1 = forward, 2+ = open)
- ExternalNodeMap ext2IntNodeMap;
- in.read((char*)&n, sizeof(NodeID));
- DEBUG("Importing n = " << n << " nodes ");
- _Node node;
- for (NodeID i=0; i<n; ++i) {
- in.read((char*)&node, sizeof(_Node));
- int2ExtNodeMap->push_back(NodeInfo(node.lat, node.lon, node.id));
- ext2IntNodeMap.insert(std::make_pair(node.id, i));
- if(node.bollard)
- bollardNodes.push_back(i);
- if(node.trafficLight)
- trafficLightNodes.push_back(i);
+ short dir; // direction (0 = open, 1 = forward, 2+ = open)
+ std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
+ input_stream.read((char *)&n, sizeof(NodeID));
+ SimpleLogger().Write() << "Importing n = " << n << " nodes ";
+ ExternalMemoryNode current_node;
+ for (NodeID i = 0; i < n; ++i)
+ {
+ input_stream.read((char *)¤t_node, sizeof(ExternalMemoryNode));
+ int_to_ext_node_id_map->emplace_back(current_node.lat, current_node.lon, current_node.node_id);
+ ext_to_int_id_map.emplace(current_node.node_id, i);
+ if (current_node.bollard)
+ {
+ barrier_node_list.emplace_back(i);
+ }
+ if (current_node.trafficLight)
+ {
+ traffic_light_node_list.emplace_back(i);
+ }
}
- //tighten vector sizes
- std::vector<NodeID>(bollardNodes).swap(bollardNodes);
- std::vector<NodeID>(trafficLightNodes).swap(trafficLightNodes);
-
- in.read((char*)&m, sizeof(unsigned));
- DEBUG(" and " << m << " edges ");
- for(unsigned i = 0; i < inputRestrictions.size(); ++i) {
- ExternalNodeMap::iterator intNodeID = ext2IntNodeMap.find(inputRestrictions[i].fromNode);
- if( intNodeID == ext2IntNodeMap.end()) {
- DEBUG("Unmapped from Node of restriction");
+ // tighten vector sizes
+ barrier_node_list.shrink_to_fit();
+ traffic_light_node_list.shrink_to_fit();
+ input_stream.read((char *)&m, sizeof(unsigned));
+ SimpleLogger().Write() << " and " << m << " edges ";
+ for (TurnRestriction ¤t_restriction : restriction_list)
+ {
+ auto internal_id_iter = ext_to_int_id_map.find(current_restriction.fromNode);
+ if (internal_id_iter == ext_to_int_id_map.end())
+ {
+ SimpleLogger().Write(logDEBUG) << "Unmapped from Node of restriction";
continue;
-
}
- inputRestrictions[i].fromNode = intNodeID->second;
+ current_restriction.fromNode = internal_id_iter->second;
- intNodeID = ext2IntNodeMap.find(inputRestrictions[i].viaNode);
- if( intNodeID == ext2IntNodeMap.end()) {
- DEBUG("Unmapped via node of restriction");
+ internal_id_iter = ext_to_int_id_map.find(current_restriction.viaNode);
+ if (internal_id_iter == ext_to_int_id_map.end())
+ {
+ SimpleLogger().Write(logDEBUG) << "Unmapped via node of restriction";
continue;
}
- inputRestrictions[i].viaNode = intNodeID->second;
+ current_restriction.viaNode = internal_id_iter->second;
- intNodeID = ext2IntNodeMap.find(inputRestrictions[i].toNode);
- if( intNodeID == ext2IntNodeMap.end()) {
- DEBUG("Unmapped to node of restriction");
+ internal_id_iter = ext_to_int_id_map.find(current_restriction.toNode);
+ if (internal_id_iter == ext_to_int_id_map.end())
+ {
+ SimpleLogger().Write(logDEBUG) << "Unmapped to node of restriction";
continue;
}
- inputRestrictions[i].toNode = intNodeID->second;
+ current_restriction.toNode = internal_id_iter->second;
}
- edgeList.reserve(m);
+ edge_list.reserve(m);
EdgeWeight weight;
short type;
NodeID nameID;
int length;
- bool isRoundabout, ignoreInGrid, isAccessRestricted, isContraFlow;
-
- for (EdgeID i=0; i<m; ++i) {
- in.read((char*)&source, sizeof(unsigned));
- in.read((char*)&target, sizeof(unsigned));
- in.read((char*)&length, sizeof(int));
- in.read((char*)&dir, sizeof(short));
- in.read((char*)&weight, sizeof(int));
- in.read((char*)&type, sizeof(short));
- in.read((char*)&nameID, sizeof(unsigned));
- in.read((char*)&isRoundabout, sizeof(bool));
- in.read((char*)&ignoreInGrid, sizeof(bool));
- in.read((char*)&isAccessRestricted, sizeof(bool));
- in.read((char*)&isContraFlow, sizeof(bool));
-
- BOOST_ASSERT_MSG(length > 0, "loaded null length edge" );
+ bool is_roundabout, ignore_in_grid, is_access_restricted, is_contra_flow, is_split;
+
+ for (EdgeID i = 0; i < m; ++i)
+ {
+ input_stream.read((char *)&source, sizeof(unsigned));
+ input_stream.read((char *)&target, sizeof(unsigned));
+ input_stream.read((char *)&length, sizeof(int));
+ input_stream.read((char *)&dir, sizeof(short));
+ input_stream.read((char *)&weight, sizeof(int));
+ input_stream.read((char *)&type, sizeof(short));
+ input_stream.read((char *)&nameID, sizeof(unsigned));
+ input_stream.read((char *)&is_roundabout, sizeof(bool));
+ input_stream.read((char *)&ignore_in_grid, sizeof(bool));
+ input_stream.read((char *)&is_access_restricted, sizeof(bool));
+ input_stream.read((char *)&is_contra_flow, sizeof(bool));
+ input_stream.read((char *)&is_split, sizeof(bool));
+
+ 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");
+ BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
bool forward = true;
bool backward = true;
- if (1 == dir) { backward = false; }
- if (2 == dir) { forward = false; }
+ if (1 == dir)
+ {
+ backward = false;
+ }
+ if (2 == dir)
+ {
+ forward = false;
+ }
- assert(type >= 0);
+ BOOST_ASSERT(type >= 0);
- // translate the external NodeIDs to internal IDs
- ExternalNodeMap::iterator intNodeID = ext2IntNodeMap.find(source);
- if( ext2IntNodeMap.find(source) == ext2IntNodeMap.end()) {
+ // translate the external NodeIDs to internal IDs
+ auto internal_id_iter = ext_to_int_id_map.find(source);
+ if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
+ {
#ifndef NDEBUG
- WARN(" unresolved source NodeID: " << source );
+ SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
#endif
continue;
}
- source = intNodeID->second;
- intNodeID = ext2IntNodeMap.find(target);
- if(ext2IntNodeMap.find(target) == ext2IntNodeMap.end()) {
+ source = internal_id_iter->second;
+ internal_id_iter = ext_to_int_id_map.find(target);
+ if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
+ {
#ifndef NDEBUG
- WARN("unresolved target NodeID : " << target );
+ SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
#endif
continue;
}
- target = intNodeID->second;
- BOOST_ASSERT_MSG(source != UINT_MAX && target != UINT_MAX,
- "nonexisting source or target"
- );
+ target = internal_id_iter->second;
+ BOOST_ASSERT_MSG(source != UINT_MAX && target != UINT_MAX, "nonexisting source or target");
- if(source > target) {
+ if (source > target)
+ {
std::swap(source, target);
std::swap(forward, backward);
}
- EdgeT inputEdge(source, target, nameID, weight, forward, backward, type, isRoundabout, ignoreInGrid, isAccessRestricted, isContraFlow );
- edgeList.push_back(inputEdge);
+ edge_list.emplace_back(source,
+ target,
+ nameID,
+ weight,
+ forward,
+ backward,
+ type,
+ is_roundabout,
+ ignore_in_grid,
+ is_access_restricted,
+ is_contra_flow,
+ is_split);
}
- std::sort(edgeList.begin(), edgeList.end());
- for(unsigned i = 1; i < edgeList.size(); ++i) {
- if( (edgeList[i-1].target() == edgeList[i].target()) && (edgeList[i-1].source() == edgeList[i].source()) ) {
- bool edgeFlagsAreEquivalent = (edgeList[i-1].isForward() == edgeList[i].isForward()) && (edgeList[i-1].isBackward() == edgeList[i].isBackward());
- bool edgeFlagsAreSuperSet1 = (edgeList[i-1].isForward() && edgeList[i-1].isBackward()) && (edgeList[i].isBackward() != edgeList[i].isBackward() );
- bool edgeFlagsAreSuperSet2 = (edgeList[i].isForward() && edgeList[i].isBackward()) && (edgeList[i-1].isBackward() != edgeList[i-1].isBackward() );
-
- if( edgeFlagsAreEquivalent ) {
- edgeList[i]._weight = std::min(edgeList[i-1].weight(), edgeList[i].weight());
- edgeList[i-1]._source = UINT_MAX;
- } else if (edgeFlagsAreSuperSet1) {
- if(edgeList[i-1].weight() <= edgeList[i].weight()) {
- //edge i-1 is smaller and goes in both directions. Throw away the other edge
- edgeList[i]._source = UINT_MAX;
- } else {
- //edge i-1 is open in both directions, but edge i is smaller in one direction. Close edge i-1 in this direction
- edgeList[i-1].forward = !edgeList[i].isForward();
- edgeList[i-1].backward = !edgeList[i].isBackward();
+
+ tbb::parallel_sort(edge_list.begin(), edge_list.end());
+ for (unsigned i = 1; i < edge_list.size(); ++i)
+ {
+ if ((edge_list[i - 1].target == edge_list[i].target) &&
+ (edge_list[i - 1].source == edge_list[i].source))
+ {
+ const bool edge_flags_equivalent =
+ (edge_list[i - 1].forward == edge_list[i].forward) &&
+ (edge_list[i - 1].backward == edge_list[i].backward);
+ const bool edge_flags_are_superset1 =
+ (edge_list[i - 1].forward && edge_list[i - 1].backward) &&
+ (edge_list[i].backward != edge_list[i].backward);
+ const bool edge_flags_are_superset_2 =
+ (edge_list[i].forward && edge_list[i].backward) &&
+ (edge_list[i - 1].backward != edge_list[i - 1].backward);
+
+ if (edge_flags_equivalent)
+ {
+ edge_list[i].weight = std::min(edge_list[i - 1].weight, edge_list[i].weight);
+ edge_list[i - 1].source = UINT_MAX;
+ }
+ else if (edge_flags_are_superset1)
+ {
+ if (edge_list[i - 1].weight <= edge_list[i].weight)
+ {
+ // edge i-1 is smaller and goes in both directions. Throw away the other edge
+ edge_list[i].source = UINT_MAX;
+ }
+ else
+ {
+ // edge i-1 is open in both directions, but edge i is smaller in one direction.
+ // Close edge i-1 in this direction
+ edge_list[i - 1].forward = !edge_list[i].forward;
+ edge_list[i - 1].backward = !edge_list[i].backward;
+ }
+ }
+ else if (edge_flags_are_superset_2)
+ {
+ if (edge_list[i - 1].weight <= edge_list[i].weight)
+ {
+ // edge i-1 is smaller for one direction. edge i is open in both. close edge i
+ // in the other direction
+ edge_list[i].forward = !edge_list[i - 1].forward;
+ edge_list[i].backward = !edge_list[i - 1].backward;
+ }
+ else
+ {
+ // edge i is smaller and goes in both direction. Throw away edge i-1
+ edge_list[i - 1].source = UINT_MAX;
}
- } else if (edgeFlagsAreSuperSet2) {
- if(edgeList[i-1].weight() <= edgeList[i].weight()) {
- //edge i-1 is smaller for one direction. edge i is open in both. close edge i in the other direction
- edgeList[i].forward = !edgeList[i-1].isForward();
- edgeList[i].backward = !edgeList[i-1].isBackward();
- } else {
- //edge i is smaller and goes in both direction. Throw away edge i-1
- edgeList[i-1]._source = UINT_MAX;
- }
}
}
}
- typename std::vector<EdgeT>::iterator newEnd = std::remove_if(edgeList.begin(), edgeList.end(), _ExcessRemover<EdgeT>());
- ext2IntNodeMap.clear();
- std::vector<EdgeT>(edgeList.begin(), newEnd).swap(edgeList); //remove excess candidates.
- INFO("Graph loaded ok and has " << edgeList.size() << " edges");
+ const auto new_end_iter = std::remove_if(edge_list.begin(),
+ edge_list.end(),
+ [](const EdgeT &edge)
+ { return edge.source == SPECIAL_NODEID; });
+ ext_to_int_id_map.clear();
+ edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
+ edge_list.shrink_to_fit();
+ SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
return n;
}
-template<typename EdgeT>
-NodeID readDTMPGraphFromStream(std::istream &in, std::vector<EdgeT>& edgeList, std::vector<NodeInfo> * int2ExtNodeMap) {
- NodeID n, source, target, id;
- EdgeID m;
- int dir, xcoord, ycoord;// direction (0 = open, 1 = forward, 2+ = open)
- ExternalNodeMap ext2IntNodeMap;
- in >> n;
- DEBUG("Importing n = " << n << " nodes ");
- for (NodeID i=0; i<n;++i) {
- in >> id >> ycoord >> xcoord;
- int2ExtNodeMap->push_back(NodeInfo(xcoord, ycoord, id));
- ext2IntNodeMap.insert(std::make_pair(id, i));
- }
- in >> m;
- DEBUG(" and " << m << " edges");
-
- edgeList.reserve(m);
- for (EdgeID i=0; i<m; ++i) {
- EdgeWeight weight;
- unsigned speedType(0);
- short type(0);
- // NodeID nameID;
- int length;
- in >> source >> target >> length >> dir >> speedType;
-
- if(dir == 3)
- dir = 0;
-
- switch(speedType) {
- case 1:
- weight = 130;
- break;
- case 2:
- weight = 120;
- break;
- case 3:
- weight = 110;
- break;
- case 4:
- weight = 100;
- break;
- case 5:
- weight = 90;
- break;
- case 6:
- weight = 80;
- break;
- case 7:
- weight = 70;
- break;
- case 8:
- weight = 60;
- break;
- case 9:
- weight = 50;
- break;
- case 10:
- weight = 40;
- break;
- case 11:
- weight = 30;
- break;
- case 12:
- weight = 20;
- break;
- case 13:
- weight = length;
- break;
- case 15:
- weight = 10;
- break;
- default:
- weight = 0;
- break;
- }
- weight = length*weight/3.6;
- if(speedType == 13)
- weight = length;
- assert(length > 0);
- assert(weight > 0);
- if(dir <0 || dir > 2)
- WARN("direction bogus: " << dir);
- assert(0<=dir && dir<=2);
-
- bool forward = true;
- bool backward = true;
- if (dir == 1) backward = false;
- if (dir == 2) forward = false;
-
- if(length == 0) { ERR("loaded null length edge"); }
-
- // translate the external NodeIDs to internal IDs
- ExternalNodeMap::iterator intNodeID = ext2IntNodeMap.find(source);
- if( ext2IntNodeMap.find(source) == ext2IntNodeMap.end()) {
- ERR("after " << edgeList.size() << " edges" << "\n->" << source << "," << target << "," << length << "," << dir << "," << weight << "\n->unresolved source NodeID: " << source);
- }
- source = intNodeID->second;
- intNodeID = ext2IntNodeMap.find(target);
- if(ext2IntNodeMap.find(target) == ext2IntNodeMap.end()) { ERR("unresolved target NodeID : " << target); }
- target = intNodeID->second;
+template <typename NodeT, typename EdgeT>
+unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
+ std::vector<NodeT> &node_list,
+ std::vector<EdgeT> &edge_list,
+ unsigned *check_sum)
+{
+ if (!boost::filesystem::exists(hsgr_file))
+ {
+ throw OSRMException("hsgr file does not exist");
+ }
+ if (0 == boost::filesystem::file_size(hsgr_file))
+ {
+ throw OSRMException("hsgr file is empty");
+ }
- if(source == UINT_MAX || target == UINT_MAX) { ERR("nonexisting source or target" ); }
+ boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
- EdgeT inputEdge(source, target, 0, weight, forward, backward, type );
- edgeList.push_back(inputEdge);
+ FingerPrint fingerprint_loaded, fingerprint_orig;
+ hsgr_input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+ if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+ {
+ SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
+ "Reprocess to get rid of this warning.";
}
- ext2IntNodeMap.clear();
- std::vector<EdgeT>(edgeList.begin(), edgeList.end()).swap(edgeList); //remove excess candidates.
- std::cout << "ok" << std::endl;
- return n;
-}
-
-template<typename EdgeT>
-NodeID readDDSGGraphFromStream(std::istream &in, std::vector<EdgeT>& edgeList, std::vector<NodeID> & int2ExtNodeMap) {
- ExternalNodeMap nodeMap;
- NodeID n, source, target;
- unsigned numberOfNodes = 0;
- char d;
- EdgeID m;
- int dir;// direction (0 = open, 1 = forward, 2+ = open)
- in >> d;
- in >> n;
- in >> m;
-#ifndef DEBUG
- std::cout << "expecting " << n << " nodes and " << m << " edges ..." << flush;
-#endif
- edgeList.reserve(m);
- for (EdgeID i=0; i<m; i++) {
- EdgeWeight weight;
- in >> source >> target >> weight >> dir;
- assert(weight > 0);
- if(dir <0 || dir > 3)
- ERR( "[error] direction bogus: " << dir );
- assert(0<=dir && dir<=3);
+ unsigned number_of_nodes = 0;
+ unsigned number_of_edges = 0;
+ hsgr_input_stream.read((char *)check_sum, sizeof(unsigned));
+ hsgr_input_stream.read((char *)&number_of_nodes, sizeof(unsigned));
+ BOOST_ASSERT_MSG(0 != number_of_nodes, "number of nodes is zero");
+ hsgr_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
- bool forward = true;
- bool backward = true;
- if (dir == 1) backward = false;
- if (dir == 2) forward = false;
- if (dir == 3) {backward = true; forward = true;}
+ SimpleLogger().Write() << "number_of_nodes: " << number_of_nodes
+ << ", number_of_edges: " << number_of_edges;
- if(weight == 0) { ERR("loaded null length edge"); }
+ // BOOST_ASSERT_MSG( 0 != number_of_edges, "number of edges is zero");
+ node_list.resize(number_of_nodes + 1);
+ hsgr_input_stream.read((char *)&(node_list[0]), number_of_nodes * sizeof(NodeT));
- if( nodeMap.find(source) == nodeMap.end()) {
- nodeMap.insert(std::make_pair(source, numberOfNodes ));
- int2ExtNodeMap.push_back(source);
- numberOfNodes++;
- }
- if( nodeMap.find(target) == nodeMap.end()) {
- nodeMap.insert(std::make_pair(target, numberOfNodes));
- int2ExtNodeMap.push_back(target);
- numberOfNodes++;
- }
- EdgeT inputEdge(source, target, 0, weight, forward, backward, 1 );
- edgeList.push_back(inputEdge);
+ edge_list.resize(number_of_edges);
+ if (number_of_edges > 0)
+ {
+ hsgr_input_stream.read((char *)&(edge_list[0]), number_of_edges * sizeof(EdgeT));
}
- std::vector<EdgeT>(edgeList.begin(), edgeList.end()).swap(edgeList); //remove excess candidates.
-
- nodeMap.clear();
- return numberOfNodes;
-}
-
-template<typename NodeT, typename EdgeT>
-unsigned readHSGRFromStream(std::istream &in, std::vector<NodeT>& nodeList, std::vector<EdgeT> & edgeList, unsigned * checkSum) {
- unsigned numberOfNodes = 0;
- in.read((char*) checkSum, sizeof(unsigned));
- in.read((char*) & numberOfNodes, sizeof(unsigned));
- nodeList.resize(numberOfNodes + 1);
- in.read((char*) &(nodeList[0]), numberOfNodes*sizeof(NodeT));
-
- unsigned numberOfEdges = 0;
- in.read((char*) &numberOfEdges, sizeof(unsigned));
- edgeList.resize(numberOfEdges);
- in.read((char*) &(edgeList[0]), numberOfEdges*sizeof(EdgeT));
+ hsgr_input_stream.close();
- return numberOfNodes;
+ return number_of_nodes;
}
#endif // GRAPHLOADER_H
diff --git a/Util/IniFileUtil.h b/Util/IniFileUtil.h
new file mode 100644
index 0000000..ea1d7a1
--- /dev/null
+++ b/Util/IniFileUtil.h
@@ -0,0 +1,49 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef INI_FILE_UTIL_H
+#define INI_FILE_UTIL_H
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/regex.hpp>
+
+#include <regex>
+#include <string>
+
+// support old capitalized option names by down-casing them with a regex replace
+inline std::string ReadIniFileAndLowerContents(const boost::filesystem::path &path)
+{
+ boost::filesystem::fstream config_stream(path);
+ std::string ini_file_content((std::istreambuf_iterator<char>(config_stream)),
+ std::istreambuf_iterator<char>());
+ boost::regex regex( "^([^=]*)" ); //match from start of line to '='
+ std::string format( "\\L$1\\E" ); //replace with downcased substring
+ return boost::regex_replace( ini_file_content, regex, format );
+}
+
+#endif // INI_FILE_UTIL_H
diff --git a/Util/InputFileUtil.h b/Util/InputFileUtil.h
deleted file mode 100644
index 685d92f..0000000
--- a/Util/InputFileUtil.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- 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 INPUTFILEUTIL_H_
-#define INPUTFILEUTIL_H_
-
-#include <boost/filesystem.hpp>
-
-#include "../typedefs.h"
-
-// Check if file exists and if it can be opened for reading with ifstream an object
-inline bool testDataFile(const std::string & filename){
- boost::filesystem::path fileToTest(filename);
- if(!boost::filesystem::exists(fileToTest)) {
- WARN("Failed to open file " << filename << " for reading.");
- return false;
- }
- return true;
-}
-
-inline bool testDataFiles(int argc, char *argv[]){
- for(int i = 0; i < argc; ++i) {
- if(!testDataFile(argv[i]))
- return false;
- }
- return true;
-}
-
-#endif /* INPUTFILEUTIL_H_ */
diff --git a/Util/LinuxStackTrace.h b/Util/LinuxStackTrace.h
deleted file mode 100644
index a3a23a7..0000000
--- a/Util/LinuxStackTrace.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- 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 LINUXSTACKTRACE_H_
-#define LINUXSTACKTRACE_H_
-
-#include <string>
-
-
-#ifdef __linux__
-#include <cxxabi.h>
-#include <execinfo.h>
-#include <csignal>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-
-#include <sstream>
-
-std::string binaryName;
-
-std::string getFileAndLine (char * offset_end) {
- std::string a(offset_end);
- std::string result;
- a = a.substr(2,a.length()-3);
- static char buf[256];
- std::string command("/usr/bin/addr2line -C -e " + binaryName + " -f -i " + a);
- // prepare command to be executed
- // our program need to be passed after the -e parameter
- FILE* f = popen (command.c_str(), "r");
-
- if (f == NULL) {
- perror (buf);
- return "";
- }
- // get function name
- if ( NULL != fgets (buf, 256, f) ) {
-
- // get file and line
- if ( NULL != fgets (buf, 256, f) ) {
-
- if (buf[0] != '?') {
- result = ( buf);
- } else {
- result = "unkown";
- }
- } else { result = ""; }
- } else { result = ""; }
- pclose(f);
- return result;
-}
-
-
-void crashHandler(int sig_num, siginfo_t * info, void * ) {
- const size_t maxDepth = 100;
- //size_t stackDepth;
-
- void *stackAddrs[maxDepth];
- backtrace(stackAddrs, maxDepth);
-
- std::cerr << "signal " << sig_num << " (" << strsignal(sig_num) << "), address is " << info->si_addr << " from " << stackAddrs[0] << std::endl;
-
- void * array[50];
- int size = backtrace(array, 50);
-
- array[1] = stackAddrs[0];
-
- char ** messages = backtrace_symbols(array, size);
-
- // skip first stack frame (points here)
- for (int i = 1; i < size-1 && messages != NULL; ++i) {
- char *mangledname = 0, *offset_begin = 0, *offset_end = 0;
-
- // find parantheses and +address offset surrounding mangled name
- for (char *p = messages[i+1]; *p; ++p) {
- if (*p == '(') {
- mangledname = p;
- } else if (*p == '+') {
- offset_begin = p;
- } else if (*p == ')') {
- offset_end = p;
- break;
- }
- }
-
- // if the line could be processed, attempt to demangle the symbol
- if (mangledname && offset_begin && offset_end && mangledname < offset_begin) {
- *mangledname++ = '\0';
- *offset_begin++ = '\0';
- *offset_end++ = '\0';
-
- int status;
- char * real_name = abi::__cxa_demangle(mangledname, 0, 0, &status);
-
- // if demangling is successful, output the demangled function name
- if (status == 0) {
- std::cerr << "[bt]: (" << i << ") " << messages[i+1] << " : " << real_name << " " << getFileAndLine(offset_end);
- }
- // otherwise, output the mangled function name
- else {
- std::cerr << "[bt]: (" << i << ") " << messages[i+1] << " : "
- << mangledname << "+" << offset_begin << offset_end
- << std::endl;
- }
- free(real_name);
- }
- // otherwise, print the whole line
- else {
- std::cerr << "[bt]: (" << i << ") " << messages[i+1] << std::endl;
- }
- }
- std::cerr << std::endl;
-
- free(messages);
-
- exit(EXIT_FAILURE);
-}
-
-void installCrashHandler(std::string b) {
- binaryName = b;
-#ifndef NDEBUG
- struct sigaction sigact;
- sigemptyset(&sigact.sa_mask);
- sigact.sa_sigaction = crashHandler;
- sigact.sa_flags = SA_RESTART | SA_SIGINFO;
-
- if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) != 0) {
- std::cerr << "error setting signal handler for " << SIGSEGV << " " << strsignal(SIGSEGV) << std::endl;
-
- exit(EXIT_FAILURE);
- }
-#endif
-}
-#else
-inline void installCrashHandler(std::string ) {}
-#endif
-#endif /* LINUXSTACKTRACE_H_ */
diff --git a/Util/LuaUtil.h b/Util/LuaUtil.h
index 3793d8b..5c502c9 100644
--- a/Util/LuaUtil.h
+++ b/Util/LuaUtil.h
@@ -1,57 +1,66 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef LUAUTIL_H_
-#define LUAUTIL_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef LUA_UTIL_H
+#define LUA_UTIL_H
extern "C" {
- #include <lua.h>
- #include <lauxlib.h>
- #include <lualib.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
}
#include <boost/filesystem/convenience.hpp>
#include <luabind/luabind.hpp>
+
#include <iostream>
#include <string>
-template<typename T>
-void LUA_print(T number) {
- std::cout << "[LUA] " << number << std::endl;
-}
+template <typename T> void LUA_print(T output) { std::cout << "[LUA] " << output << std::endl; }
// Check if the lua function <name> is defined
-inline bool lua_function_exists(lua_State* lua_state, const char* name) {
- luabind::object g = luabind::globals(lua_state);
- luabind::object func = g[name];
- return func && (luabind::type(func) == LUA_TFUNCTION);
+inline bool lua_function_exists(lua_State *lua_state, const char *name)
+{
+ luabind::object globals_table = luabind::globals(lua_state);
+ luabind::object lua_function = globals_table[name];
+ return lua_function && (luabind::type(lua_function) == LUA_TFUNCTION);
}
-// Add the folder contain the script to the lua load path, so script can easily require() other lua scripts inside that folder, or subfolders.
+// Add the folder contain the script to the lua load path, so script can easily require() other lua
+// scripts inside that folder, or subfolders.
// See http://lua-users.org/wiki/PackagePath for details on the package.path syntax.
-inline void luaAddScriptFolderToLoadPath(lua_State* myLuaState, const char* fileName) {
- const boost::filesystem::path profilePath( fileName );
- std::string folder = profilePath.parent_path().string();
- //TODO: This code is most probably not Windows safe since it uses UNIX'ish path delimiters
- const std::string luaCode = "package.path = \"" + folder + "/?.lua;profiles/?.lua;\" .. package.path";
- luaL_dostring( myLuaState, luaCode.c_str() );
+inline void luaAddScriptFolderToLoadPath(lua_State *lua_state, const char *file_name)
+{
+ const boost::filesystem::path profile_path(file_name);
+ std::string folder = profile_path.parent_path().string();
+ // TODO: This code is most probably not Windows safe since it uses UNIX'ish path delimiters
+ const std::string lua_code =
+ "package.path = \"" + folder + "/?.lua;profiles/?.lua;\" .. package.path";
+ luaL_dostring(lua_state, lua_code.c_str());
}
-#endif /* LUAUTIL_H_ */
+#endif // LUA_UTIL_H
diff --git a/Util/MachineInfo.h b/Util/MachineInfo.h
index 7c0f31c..c5cb052 100644
--- a/Util/MachineInfo.h
+++ b/Util/MachineInfo.h
@@ -1,86 +1,57 @@
/*
- 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.
- */
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#ifndef MACHINE_INFO_H
#define MACHINE_INFO_H
-#if defined(__APPLE__) || defined(__FreeBSD__)
-extern "C" {
-#include <sys/types.h>
-#include <sys/sysctl.h>
-}
-#elif defined _WIN32
-#include <windows.h>
-#endif
+enum Endianness
+{ LittleEndian = 1,
+ BigEndian = 2 };
-enum Endianness {
- LittleEndian = 1,
- BigEndian = 2
-};
-
-//Function is optimized to a single 'mov eax,1' on GCC, clang and icc using -O3
-inline Endianness getMachineEndianness() {
+// Function is optimized to a single 'mov eax,1' on GCC, clang and icc using -O3
+inline Endianness GetMachineEndianness()
+{
int i(1);
- char *p = (char *) &i;
+ char *p = (char *)&i;
if (1 == p[0])
+ {
return LittleEndian;
+ }
return BigEndian;
}
// Reverses Network Byte Order into something usable, compiles down to a bswap-mov combination
-inline unsigned swapEndian(unsigned x) {
- if(getMachineEndianness() == LittleEndian)
- return ( (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24) );
+inline unsigned SwapEndian(unsigned x)
+{
+ if (GetMachineEndianness() == LittleEndian)
+ {
+ return ((x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24));
+ }
return x;
}
-// Returns the physical memory size in kilobytes
-inline unsigned GetPhysicalmemory(void){
-#if defined(SUN5) || defined(__linux__)
- return (sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE));
-
-#elif defined(__APPLE__)
- int mib[2] = {CTL_HW, HW_MEMSIZE};
- long long memsize;
- size_t len = sizeof(memsize);
- sysctl(mib, 2, &memsize, &len, NULL, 0);
- return memsize/1024;
-
-#elif defined(__FreeBSD__)
- int mib[2] = {CTL_HW, HW_PHYSMEM};
- long long memsize;
- size_t len = sizeof(memsize);
- sysctl(mib, 2, &memsize, &len, NULL, 0);
- return memsize/1024;
-
-#elif defined(_WIN32)
- MEMORYSTATUSEX status;
- status.dwLength = sizeof(status);
- GlobalMemoryStatusEx(&status);
- return status.ullTotalPhys/1024;
-#else
- std::cout << "[Warning] Compiling on unknown architecture." << std::endl
- << "Please file a ticket at http://project-osrm.org" << std::endl;
- return 2048*1024; /* 128 Mb default memory */
-
-#endif
-}
#endif // MACHINE_INFO_H
-
diff --git a/Util/MercatorUtil.h b/Util/MercatorUtil.h
new file mode 100644
index 0000000..31d1139
--- /dev/null
+++ b/Util/MercatorUtil.h
@@ -0,0 +1,43 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef MERCATOR_UTIL_H
+#define MERCATOR_UTIL_H
+
+#include <cmath>
+
+inline float y2lat(const float a)
+{
+ return 180.f * static_cast<float>(M_1_PI) * (2.f * std::atan(std::exp(a * static_cast<float>(M_PI) / 180.f)) - static_cast<float>(M_PI_2));
+}
+
+inline float lat2y(const float a)
+{
+ return 180.f * static_cast<float>(M_1_PI) * std::log(std::tan(static_cast<float>(M_PI_4) + a * (static_cast<float>(M_PI) / 180.f) / 2.f));
+}
+
+#endif // MERCATOR_UTIL_H
diff --git a/Util/OSRMException.h b/Util/OSRMException.h
new file mode 100644
index 0000000..f4f4290
--- /dev/null
+++ b/Util/OSRMException.h
@@ -0,0 +1,46 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef OSRM_EXCEPTION_H
+#define OSRM_EXCEPTION_H
+
+#include <exception>
+#include <string>
+
+class OSRMException : public std::exception
+{
+ public:
+ explicit OSRMException(const char *message) : message(message) {}
+ explicit OSRMException(const std::string &message) : message(message) {}
+ virtual ~OSRMException() throw() {}
+
+ private:
+ virtual const char *what() const throw() { return message.c_str(); }
+ const std::string message;
+};
+
+#endif /* OSRM_EXCEPTION_H */
diff --git a/Util/OpenMPWrapper.h b/Util/OpenMPWrapper.h
deleted file mode 100644
index 232dcbd..0000000
--- a/Util/OpenMPWrapper.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- 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 _OPENMPREPLACEMENTY_H
-#define _OPENMPREPLACEMENTY_H
-
-#ifdef _OPENMP
-#include <omp.h>
-#else
-inline const int omp_get_num_procs() { return 1; }
-inline const int omp_get_max_threads() { return 1; }
-inline const int omp_get_thread_num() { return 0; }
-inline const void omp_set_num_threads(int i) {}
-#endif
-
-#endif
diff --git a/Util/ProgramOptions.h b/Util/ProgramOptions.h
new file mode 100644
index 0000000..c6e5448
--- /dev/null
+++ b/Util/ProgramOptions.h
@@ -0,0 +1,270 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef PROGAM_OPTIONS_H
+#define PROGAM_OPTIONS_H
+
+#include "GitDescription.h"
+#include "IniFileUtil.h"
+#include "OSRMException.h"
+#include "SimpleLogger.h"
+
+#include <osrm/ServerPaths.h>
+
+#include <boost/any.hpp>
+#include <boost/program_options.hpp>
+
+#include <fstream>
+#include <string>
+
+const static unsigned INIT_OK_START_ENGINE = 0;
+const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1;
+const static unsigned INIT_FAILED = -1;
+
+// generate boost::program_options object for the routing part
+inline unsigned GenerateServerProgramOptions(const int argc,
+ const char *argv[],
+ ServerPaths &paths,
+ std::string &ip_address,
+ int &ip_port,
+ int &requested_num_threads,
+ bool &use_shared_memory,
+ bool &trial)
+{
+
+ // declare a group of options that will be allowed only on command line
+ boost::program_options::options_description generic_options("Options");
+ generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
+ "config,c",
+ boost::program_options::value<boost::filesystem::path>(&paths["config"])
+ ->default_value("server.ini"),
+ "Path to a configuration file")(
+ "trial",
+ boost::program_options::value<bool>(&trial)->implicit_value(true),
+ "Quit after initialization");
+
+ // declare a group of options that will be allowed both on command line
+ // as well as in a config file
+ boost::program_options::options_description config_options("Configuration");
+ config_options.add_options()(
+ "hsgrdata",
+ boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
+ ".hsgr file")("nodesdata",
+ boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
+ ".nodes file")(
+ "edgesdata",
+ boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
+ ".edges file")("geometry",
+ boost::program_options::value<boost::filesystem::path>(&paths["geometries"]),
+ ".geometry file")(
+ "ramindex",
+ boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
+ ".ramIndex file")(
+ "fileindex",
+ boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
+ "File index file")(
+ "namesdata",
+ boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
+ ".names file")("timestamp",
+ boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
+ ".timestamp file")(
+ "ip,i",
+ boost::program_options::value<std::string>(&ip_address)->default_value("0.0.0.0"),
+ "IP address")(
+ "port,p", boost::program_options::value<int>(&ip_port)->default_value(5000), "TCP/IP port")(
+ "threads,t",
+ boost::program_options::value<int>(&requested_num_threads)->default_value(8),
+ "Number of threads to use")(
+ "sharedmemory,s",
+ boost::program_options::value<bool>(&use_shared_memory)->implicit_value(true),
+ "Load data from shared memory");
+
+ // hidden options, will be allowed both on command line and in config
+ // file, but will not be shown to the user
+ boost::program_options::options_description hidden_options("Hidden options");
+ hidden_options.add_options()(
+ "base,b",
+ boost::program_options::value<boost::filesystem::path>(&paths["base"]),
+ "base path to .osrm file");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("base", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description config_file_options;
+ config_file_options.add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ boost::filesystem::basename(argv[0]) + " <base.osrm> [<options>]");
+ visible_options.add(generic_options).add(config_options);
+
+ // parse command line options
+ boost::program_options::variables_map option_variables;
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(cmdline_options)
+ .positional(positional_options)
+ .run(),
+ option_variables);
+
+ if (option_variables.count("version"))
+ {
+ SimpleLogger().Write() << g_GIT_DESCRIPTION;
+ return INIT_OK_DO_NOT_START_ENGINE;
+ }
+
+ if (option_variables.count("help"))
+ {
+ SimpleLogger().Write() << visible_options;
+ return INIT_OK_DO_NOT_START_ENGINE;
+ }
+
+ boost::program_options::notify(option_variables);
+
+ // parse config file
+ ServerPaths::iterator path_iterator = paths.find("config");
+ if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
+ !option_variables.count("base"))
+ {
+ SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
+ std::string ini_file_contents = ReadIniFileAndLowerContents(path_iterator->second);
+ std::stringstream config_stream(ini_file_contents);
+ boost::program_options::store(parse_config_file(config_stream, config_file_options),
+ option_variables);
+ boost::program_options::notify(option_variables);
+ return INIT_OK_START_ENGINE;
+ }
+
+ if (1 > requested_num_threads)
+ {
+ throw OSRMException("Number of threads must be a positive number");
+ }
+
+ if (!use_shared_memory && option_variables.count("base"))
+ {
+ path_iterator = paths.find("base");
+ BOOST_ASSERT(paths.end() != path_iterator);
+ std::string base_string = path_iterator->second.string();
+
+ path_iterator = paths.find("hsgrdata");
+ if (path_iterator != paths.end() &&
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ path_iterator->second = base_string + ".hsgr";
+ }
+ else
+ {
+ throw OSRMException(base_string + ".hsgr not found");
+ }
+
+ path_iterator = paths.find("nodesdata");
+ if (path_iterator != paths.end() &&
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ path_iterator->second = base_string + ".nodes";
+ }
+ else
+ {
+ throw OSRMException(base_string + ".nodes not found");
+ }
+
+ path_iterator = paths.find("edgesdata");
+ if (path_iterator != paths.end() &&
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ path_iterator->second = base_string + ".edges";
+ }
+ else
+ {
+ throw OSRMException(base_string + ".edges not found");
+ }
+
+ path_iterator = paths.find("geometries");
+ if (path_iterator != paths.end() &&
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ path_iterator->second = base_string + ".geometry";
+ }
+ else
+ {
+ throw OSRMException(base_string + ".geometry not found");
+ }
+
+ path_iterator = paths.find("ramindex");
+ if (path_iterator != paths.end() &&
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ path_iterator->second = base_string + ".ramIndex";
+ }
+ else
+ {
+ throw OSRMException(base_string + ".ramIndex not found");
+ }
+
+ path_iterator = paths.find("fileindex");
+ if (path_iterator != paths.end() &&
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ path_iterator->second = base_string + ".fileIndex";
+ }
+ else
+ {
+ throw OSRMException(base_string + ".fileIndex not found");
+ }
+
+ path_iterator = paths.find("namesdata");
+ if (path_iterator != paths.end() &&
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ path_iterator->second = base_string + ".names";
+ }
+ else
+ {
+ throw OSRMException(base_string + ".namesIndex not found");
+ }
+
+ path_iterator = paths.find("timestamp");
+ if (path_iterator != paths.end() &&
+ !boost::filesystem::is_regular_file(path_iterator->second))
+ {
+ path_iterator->second = base_string + ".timestamp";
+ }
+
+ return INIT_OK_START_ENGINE;
+ }
+ if (use_shared_memory && !option_variables.count("base"))
+ {
+ return INIT_OK_START_ENGINE;
+ }
+ SimpleLogger().Write() << visible_options;
+ return INIT_OK_DO_NOT_START_ENGINE;
+}
+
+#endif /* PROGRAM_OPTIONS_H */
diff --git a/Util/SimpleLogger.h b/Util/SimpleLogger.h
new file mode 100644
index 0000000..a234c96
--- /dev/null
+++ b/Util/SimpleLogger.h
@@ -0,0 +1,158 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef SIMPLE_LOGGER_H
+#define SIMPLE_LOGGER_H
+
+#include <boost/assert.hpp>
+
+#include <cstdio>
+
+#ifdef _MSC_VER
+#include <io.h>
+#define isatty _isatty
+#define fileno _fileno
+#else
+#include <unistd.h>
+#endif
+
+#include <ostream>
+#include <iostream>
+#include <mutex>
+#include <sstream>
+
+enum LogLevel
+{ logINFO,
+ logWARNING,
+ logDEBUG };
+
+const char COL_RESET[] = "\x1b[0m";
+const char RED[] = "\x1b[31m";
+const char GREEN[] = "\x1b[32m";
+const char YELLOW[] = "\x1b[33m";
+const char BLUE[] = "\x1b[34m";
+const char MAGENTA[] = "\x1b[35m";
+const char CYAN[] = "\x1b[36m";
+
+class LogPolicy
+{
+ public:
+ void Unmute() { m_is_mute = false; }
+
+ void Mute() { m_is_mute = true; }
+
+ bool IsMute() const { return m_is_mute; }
+
+ static LogPolicy &GetInstance()
+ {
+ static LogPolicy runningInstance;
+ return runningInstance;
+ }
+
+ LogPolicy(const LogPolicy &) = delete;
+
+ private:
+ LogPolicy() : m_is_mute(true) {}
+ bool m_is_mute;
+};
+
+class SimpleLogger
+{
+ public:
+ SimpleLogger() : level(logINFO) {}
+
+ std::mutex& get_mutex()
+ {
+ static std::mutex m;
+ return m;
+ }
+
+
+ std::ostringstream &Write(LogLevel l = logINFO)
+ {
+ std::lock_guard<std::mutex> lock(get_mutex());
+ try
+ {
+ level = l;
+ os << "[";
+ switch (level)
+ {
+ case logINFO:
+ os << "info";
+ break;
+ case logWARNING:
+ os << "warn";
+ break;
+ case logDEBUG:
+#ifndef NDEBUG
+ os << "debug";
+#endif
+ break;
+ default:
+ BOOST_ASSERT_MSG(false, "should not happen");
+ break;
+ }
+ os << "] ";
+ }
+ catch (...) {}
+ return os;
+ }
+
+ virtual ~SimpleLogger()
+ {
+ std::lock_guard<std::mutex> lock(get_mutex());
+ if (!LogPolicy::GetInstance().IsMute())
+ {
+ const bool is_terminal = ( 0 != isatty(fileno(stdout)) ? true : false);
+ switch (level)
+ {
+ case logINFO:
+ std::cout << os.str() << (is_terminal ? COL_RESET : "") << std::endl;
+ break;
+ case logWARNING:
+ std::cerr << (is_terminal ? RED : "") << os.str() << (is_terminal ? COL_RESET : "")
+ << std::endl;
+ break;
+ case logDEBUG:
+#ifndef NDEBUG
+ std::cout << (is_terminal ? YELLOW : "") << os.str()
+ << (is_terminal ? COL_RESET : "") << std::endl;
+#endif
+ break;
+ default:
+ BOOST_ASSERT_MSG(false, "should not happen");
+ break;
+ }
+ }
+ }
+
+ private:
+ LogLevel level;
+ std::ostringstream os;
+};
+
+#endif /* SIMPLE_LOGGER_H */
diff --git a/Util/StdHashExtensions.h b/Util/StdHashExtensions.h
new file mode 100644
index 0000000..50cd337
--- /dev/null
+++ b/Util/StdHashExtensions.h
@@ -0,0 +1,73 @@
+/*
+
+Copyright (c) 2014, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef STD_HASH_EXTENSIONS_H
+#define STD_HASH_EXTENSIONS_H
+
+#include <functional>
+
+// this is largely inspired by boost's hash combine as can be found in
+// "The C++ Standard Library" 2nd Edition. Nicolai M. Josuttis. 2012.
+template<typename T>
+inline void hash_combine(std::size_t &seed, const T& val)
+{
+ seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+}
+
+template<typename T>
+inline void hash_val(std::size_t &seed, const T& val)
+{
+ hash_combine(seed, val);
+}
+
+template<typename T, typename ... Types>
+inline void hash_val(std::size_t &seed, const T& val, const Types& ... args)
+{
+ hash_combine(seed, val);
+ hash_val(seed, args ...);
+}
+
+template<typename ... Types>
+inline std::size_t hash_val( const Types&... args)
+{
+ std::size_t seed = 0;
+ hash_val(seed, args...);
+ return seed;
+}
+
+namespace std
+{
+template <typename T1, typename T2> struct hash<std::pair<T1, T2>>
+{
+ size_t operator()(const std::pair<T1, T2> &pair) const
+ {
+ return hash_val(pair.first, pair.second);
+ }
+};
+}
+
+#endif // STD_HASH_EXTENSIONS_H
diff --git a/Util/StringUtil.h b/Util/StringUtil.h
index b09ac16..68a9ac9 100644
--- a/Util/StringUtil.h
+++ b/Util/StringUtil.h
@@ -1,163 +1,318 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef STRINGUTIL_H_
-#define STRINGUTIL_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <string>
-#include <boost/algorithm/string.hpp>
+*/
+
+#ifndef STRINGUTIL_H
+#define STRINGUTIL_H
+#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/qi.hpp>
#include <cstdio>
-
-#include "../DataStructures/Coordinate.h"
-#include "../typedefs.h"
+#include <cctype>
+#include <string>
+#include <type_traits>
+#include <vector>
// precision: position after decimal point
// length: maximum number of digits including comma and decimals
-template< int length, int precision >
-static inline char* printInt( char* buffer, int value ) {
- bool minus = false;
- if ( value < 0 ) {
- minus = true;
+// work with negative values to prevent overflowing when taking -value
+template <int length, int precision> static inline char *printInt(char *buffer, int value)
+{
+ bool minus = true;
+ if (value > 0)
+ {
+ minus = false;
value = -value;
}
buffer += length - 1;
- for ( int i = 0; i < precision; i++ ) {
- *buffer = '0' + ( value % 10 );
+ for (int i = 0; i < precision; i++)
+ {
+ *buffer = '0' - (value % 10);
value /= 10;
buffer--;
}
*buffer = '.';
buffer--;
- for ( int i = precision + 1; i < length; i++ ) {
- *buffer = '0' + ( value % 10 );
+ for (int i = precision + 1; i < length; i++)
+ {
+ *buffer = '0' - (value % 10);
value /= 10;
- if ( value == 0 ) break;
+ if (value == 0)
+ break;
buffer--;
}
- if ( minus ) {
+ if (minus)
+ {
buffer--;
*buffer = '-';
}
return buffer;
}
-static inline void intToString(const int value, std::string & output) {
- // The largest 32-bit integer is 4294967295, that is 10 chars
- // On the safe side, add 1 for sign, and 1 for trailing zero
- output.clear();
+// convert scoped enums to integers
+template <typename Enumeration>
+auto as_integer(Enumeration const value)
+ -> typename std::underlying_type<Enumeration>::type
+{
+ return static_cast<typename std::underlying_type<Enumeration>::type>(value);
+}
+
+static inline std::string IntToString(const int value)
+{
+ std::string output;
std::back_insert_iterator<std::string> sink(output);
boost::spirit::karma::generate(sink, boost::spirit::karma::int_, value);
+ return output;
}
-static inline int stringToInt(const std::string& input) {
- std::string::const_iterator realBeginOfNumber = input.begin();
- //Delete any trailing white-spaces
- while(realBeginOfNumber != input.end() && std::isspace(*realBeginOfNumber))
- ++realBeginOfNumber;
- int value = 0; // 2
- boost::spirit::qi::parse(realBeginOfNumber, input.end(), boost::spirit::int_, value); // 3
- return value;
+static inline std::string UintToString(const unsigned value)
+{
+ std::string output;
+ std::back_insert_iterator<std::string> sink(output);
+ boost::spirit::karma::generate(sink, boost::spirit::karma::uint_, value);
+ return output;
}
-static inline void doubleToString(const double value, std::string & output){
+static inline void int64ToString(const int64_t value, std::string &output)
+{
output.clear();
std::back_insert_iterator<std::string> sink(output);
- boost::spirit::karma::generate(sink, boost::spirit::karma::double_, value);
+ boost::spirit::karma::generate(sink, boost::spirit::karma::long_long, value);
}
-static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string & output){
- // The largest 32-bit integer is 4294967295, that is 10 chars
- // On the safe side, add 1 for sign, and 1 for trailing zero
- char buffer[12] ;
- sprintf(buffer, "%g", value) ;
- output = buffer ;
+static inline int StringToInt(const std::string &input)
+{
+ auto first_digit = input.begin();
+ // Delete any trailing white-spaces
+ while (first_digit != input.end() && std::isspace(*first_digit))
+ {
+ ++first_digit;
+ }
+ int value = 0;
+ boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::int_, value);
+ return value;
}
-static inline void convertInternalLatLonToString(const int value, std::string & output) {
- char buffer[100];
- buffer[10] = 0; // Nullterminierung
- char* string = printInt< 10, 5 >( buffer, value );
- output = string;
+static inline unsigned StringToUint(const std::string &input)
+{
+ auto first_digit = input.begin();
+ // Delete any trailing white-spaces
+ while (first_digit != input.end() && std::isspace(*first_digit))
+ {
+ ++first_digit;
+ }
+ unsigned value = 0;
+ boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::uint_, value);
+ return value;
}
-static inline void convertInternalCoordinateToString(const _Coordinate & coord, std::string & output) {
- std::string tmp;
- convertInternalLatLonToString(coord.lon, tmp);
- output = tmp;
- output += ",";
- convertInternalLatLonToString(coord.lat, tmp);
- output += tmp;
- output += " ";
+static inline uint64_t StringToInt64(const std::string &input)
+{
+ auto first_digit = input.begin();
+ // Delete any trailing white-spaces
+ while (first_digit != input.end() && std::isspace(*first_digit))
+ {
+ ++first_digit;
+ }
+ uint64_t value = 0;
+ boost::spirit::qi::parse(first_digit, input.end(), boost::spirit::long_long, value);
+ return value;
}
-static inline void convertInternalReversedCoordinateToString(const _Coordinate & coord, std::string & output) {
- std::string tmp;
- convertInternalLatLonToString(coord.lat, tmp);
- output = tmp;
- output += ",";
- convertInternalLatLonToString(coord.lon, tmp);
- output += tmp;
- output += " ";
+
+// source: http://tinodidriksen.com/2011/05/28/cpp-convert-string-to-double-speed/
+static inline double StringToDouble(const char *p)
+{
+ double r = 0.0;
+ bool neg = false;
+ if (*p == '-')
+ {
+ neg = true;
+ ++p;
+ }
+ while (*p >= '0' && *p <= '9')
+ {
+ r = (r * 10.0) + (*p - '0');
+ ++p;
+ }
+ if (*p == '.')
+ {
+ double f = 0.0;
+ int n = 0;
+ ++p;
+ while (*p >= '0' && *p <= '9')
+ {
+ f = (f * 10.0) + (*p - '0');
+ ++p;
+ ++n;
+ }
+ r += f / std::pow(10.0, n);
+ }
+ if (neg)
+ {
+ r = -r;
+ }
+ return r;
}
-inline void replaceAll(std::string &s, const std::string &sub, const std::string &other) {
- boost::replace_all(s, sub, other);
+template <typename T>
+struct scientific_policy : boost::spirit::karma::real_policies<T>
+{
+ // we want the numbers always to be in fixed format
+ static int floatfield(T n) { return boost::spirit::karma::real_policies<T>::fmtflags::fixed; }
+ static unsigned int precision(T) { return 6; }
+};
+typedef
+boost::spirit::karma::real_generator<double, scientific_policy<double> >
+science_type;
+
+static inline std::string FixedDoubleToString(const double value)
+{
+ std::string output;
+ std::back_insert_iterator<std::string> sink(output);
+ boost::spirit::karma::generate(sink, science_type(), value);
+ if (output.size() >= 2 && output[output.size()-2] == '.' && output[output.size()-1] == '0')
+ {
+ output.resize(output.size()-2);
+ }
+ return output;
}
-inline void stringSplit(const std::string &s, const char delim, std::vector<std::string>& result) {
- boost::split(result, s, boost::is_any_of(std::string(&delim)));
+static inline std::string DoubleToString(const double value)
+{
+ std::string output;
+ std::back_insert_iterator<std::string> sink(output);
+ boost::spirit::karma::generate(sink, value);
+ return output;
}
-static std::string originals[] = {"&", "\"", "<", ">", "'", "[", "]", "\\"};
-static std::string entities[] = {"&", """, "<", ">", "'", "&91;", "&93;", " \" };
+static inline void doubleToStringWithTwoDigitsBehindComma(const double value, std::string &output)
+{
+ // The largest 32-bit integer is 4294967295, that is 10 chars
+ // On the safe side, add 1 for sign, and 1 for trailing zero
+ char buffer[12];
+ sprintf(buffer, "%g", value);
+ output = buffer;
+}
+
+inline void replaceAll(std::string &s, const std::string &sub, const std::string &other)
+{
+ boost::replace_all(s, sub, other);
+}
-inline std::string HTMLEntitize( const std::string & input) {
- std::string result(input);
- for(unsigned i = 0; i < sizeof(originals)/sizeof(std::string); ++i) {
- replaceAll(result, originals[i], entities[i]);
+inline std::string EscapeJSONString(const std::string &input)
+{
+ std::string output;
+ output.reserve(input.size());
+ for (auto iter = input.begin(); iter != input.end(); ++iter)
+ {
+ switch (iter[0])
+ {
+ case '\\':
+ output += "\\\\";
+ break;
+ case '"':
+ output += "\\\"";
+ break;
+ case '/':
+ output += "\\/";
+ break;
+ case '\b':
+ output += "\\b";
+ break;
+ case '\f':
+ output += "\\f";
+ break;
+ case '\n':
+ output += "\\n";
+ break;
+ case '\r':
+ output += "\\r";
+ break;
+ case '\t':
+ output += "\\t";
+ break;
+ default:
+ output += *iter;
+ break;
+ }
}
- return result;
+ return output;
}
-inline std::string HTMLDeEntitize( std::string & result) {
- for(unsigned i = 0; i < sizeof(originals)/sizeof(std::string); ++i) {
- replaceAll(result, entities[i], originals[i]);
+static std::string originals[] = {"&", "\"", "<", ">", "'", "[", "]", "\\"};
+static std::string entities[] = {"&", """, "<", ">",
+ "'", "&91;", "&93;", " \"};
+
+inline std::size_t URIDecode(const std::string &input, std::string &output)
+{
+ auto src_iter = input.begin();
+ output.resize(input.size() + 1);
+ std::size_t decoded_length = 0;
+ for (decoded_length = 0; src_iter != input.end(); ++decoded_length)
+ {
+ if (src_iter[0] == '%' && src_iter[1] && src_iter[2] && isxdigit(src_iter[1]) &&
+ isxdigit(src_iter[2]))
+ {
+ std::string::value_type a = src_iter[1];
+ std::string::value_type b = src_iter[2];
+ a -= src_iter[1] < 58 ? 48 : src_iter[1] < 71 ? 55 : 87;
+ b -= src_iter[2] < 58 ? 48 : src_iter[2] < 71 ? 55 : 87;
+ output[decoded_length] = 16 * a + b;
+ src_iter += 3;
+ continue;
+ }
+ output[decoded_length] = *src_iter++;
}
- return result;
+ output.resize(decoded_length);
+ return decoded_length;
}
-inline bool StringStartsWith(const std::string & input, const std::string & prefix) {
+inline std::size_t URIDecodeInPlace(std::string &URI) { return URIDecode(URI, URI); }
+
+inline bool StringStartsWith(const std::string &input, const std::string &prefix)
+{
return boost::starts_with(input, prefix);
}
-// Function returns a 'random' filename in temporary directors.
-// May not be platform independent.
-inline void GetTemporaryFileName(std::string & filename) {
- char buffer[L_tmpnam];
- char * retPointer = tmpnam (buffer);
- if(0 == retPointer)
- ERR("Could not create temporary file name");
- filename = buffer;
+inline std::string GetRandomString()
+{
+ std::string s;
+ s.resize(128);
+ static const char alphanum[] = "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+ for (int i = 0; i < 127; ++i)
+ {
+ s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
+ }
+ s[127] = 0;
+ return s;
}
-#endif /* STRINGUTIL_H_ */
+#endif // STRINGUTIL_H
diff --git a/Util/TimingUtil.h b/Util/TimingUtil.h
new file mode 100644
index 0000000..c1505ce
--- /dev/null
+++ b/Util/TimingUtil.h
@@ -0,0 +1,39 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TIMINGUTIL_H
+#define TIMINGUTIL_H
+
+#include <chrono>
+
+#define TIMER_START(_X) auto _X##_start = std::chrono::steady_clock::now(), _X##_stop = _X##_start
+#define TIMER_STOP(_X) _X##_stop = std::chrono::steady_clock::now()
+#define TIMER_MSEC(_X) std::chrono::duration_cast<std::chrono::milliseconds>(_X##_stop - _X##_start).count()
+#define TIMER_SEC(_X) (0.001*std::chrono::duration_cast<std::chrono::milliseconds>(_X##_stop - _X##_start).count())
+#define TIMER_MIN(_X) std::chrono::duration_cast<std::chrono::minutes>(_X##_stop - _X##_start).count()
+
+#endif // TIMINGUTIL_H
diff --git a/Util/TrigonometryTables.h b/Util/TrigonometryTables.h
new file mode 100644
index 0000000..d145404
--- /dev/null
+++ b/Util/TrigonometryTables.h
@@ -0,0 +1,790 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef TRIGONOMETRY_TABLES_H
+#define TRIGONOMETRY_TABLES_H
+
+#include "../typedefs.h"
+#include <cmath>
+
+#include <limits>
+
+constexpr unsigned short atan_table[4096] = {
+0x0000, 0x0014, 0x0028, 0x003d, 0x0051, 0x0065,
+0x007a, 0x008e, 0x00a3, 0x00b7, 0x00cb, 0x00e0,
+0x00f4, 0x0108, 0x011d, 0x0131, 0x0146, 0x015a,
+0x016e, 0x0183, 0x0197, 0x01ab, 0x01c0, 0x01d4,
+0x01e9, 0x01fd, 0x0211, 0x0226, 0x023a, 0x024e,
+0x0263, 0x0277, 0x028c, 0x02a0, 0x02b4, 0x02c9,
+0x02dd, 0x02f1, 0x0306, 0x031a, 0x032f, 0x0343,
+0x0357, 0x036c, 0x0380, 0x0394, 0x03a9, 0x03bd,
+0x03d2, 0x03e6, 0x03fa, 0x040f, 0x0423, 0x0437,
+0x044c, 0x0460, 0x0475, 0x0489, 0x049d, 0x04b2,
+0x04c6, 0x04da, 0x04ef, 0x0503, 0x0517, 0x052c,
+0x0540, 0x0555, 0x0569, 0x057d, 0x0592, 0x05a6,
+0x05ba, 0x05cf, 0x05e3, 0x05f8, 0x060c, 0x0620,
+0x0635, 0x0649, 0x065d, 0x0672, 0x0686, 0x069b,
+0x06af, 0x06c3, 0x06d8, 0x06ec, 0x0700, 0x0715,
+0x0729, 0x073d, 0x0752, 0x0766, 0x077b, 0x078f,
+0x07a3, 0x07b8, 0x07cc, 0x07e0, 0x07f5, 0x0809,
+0x081d, 0x0832, 0x0846, 0x085b, 0x086f, 0x0883,
+0x0898, 0x08ac, 0x08c0, 0x08d5, 0x08e9, 0x08fd,
+0x0912, 0x0926, 0x093b, 0x094f, 0x0963, 0x0978,
+0x098c, 0x09a0, 0x09b5, 0x09c9, 0x09dd, 0x09f2,
+0x0a06, 0x0a1a, 0x0a2f, 0x0a43, 0x0a58, 0x0a6c,
+0x0a80, 0x0a95, 0x0aa9, 0x0abd, 0x0ad2, 0x0ae6,
+0x0afa, 0x0b0f, 0x0b23, 0x0b37, 0x0b4c, 0x0b60,
+0x0b75, 0x0b89, 0x0b9d, 0x0bb2, 0x0bc6, 0x0bda,
+0x0bef, 0x0c03, 0x0c17, 0x0c2c, 0x0c40, 0x0c54,
+0x0c69, 0x0c7d, 0x0c91, 0x0ca6, 0x0cba, 0x0cce,
+0x0ce3, 0x0cf7, 0x0d0b, 0x0d20, 0x0d34, 0x0d48,
+0x0d5d, 0x0d71, 0x0d86, 0x0d9a, 0x0dae, 0x0dc3,
+0x0dd7, 0x0deb, 0x0e00, 0x0e14, 0x0e28, 0x0e3d,
+0x0e51, 0x0e65, 0x0e7a, 0x0e8e, 0x0ea2, 0x0eb7,
+0x0ecb, 0x0edf, 0x0ef4, 0x0f08, 0x0f1c, 0x0f31,
+0x0f45, 0x0f59, 0x0f6e, 0x0f82, 0x0f96, 0x0fab,
+0x0fbf, 0x0fd3, 0x0fe8, 0x0ffc, 0x1010, 0x1025,
+0x1039, 0x104d, 0x1062, 0x1076, 0x108a, 0x109e,
+0x10b3, 0x10c7, 0x10db, 0x10f0, 0x1104, 0x1118,
+0x112d, 0x1141, 0x1155, 0x116a, 0x117e, 0x1192,
+0x11a7, 0x11bb, 0x11cf, 0x11e4, 0x11f8, 0x120c,
+0x1221, 0x1235, 0x1249, 0x125d, 0x1272, 0x1286,
+0x129a, 0x12af, 0x12c3, 0x12d7, 0x12ec, 0x1300,
+0x1314, 0x1329, 0x133d, 0x1351, 0x1365, 0x137a,
+0x138e, 0x13a2, 0x13b7, 0x13cb, 0x13df, 0x13f4,
+0x1408, 0x141c, 0x1431, 0x1445, 0x1459, 0x146d,
+0x1482, 0x1496, 0x14aa, 0x14bf, 0x14d3, 0x14e7,
+0x14fb, 0x1510, 0x1524, 0x1538, 0x154d, 0x1561,
+0x1575, 0x1589, 0x159e, 0x15b2, 0x15c6, 0x15db,
+0x15ef, 0x1603, 0x1617, 0x162c, 0x1640, 0x1654,
+0x1669, 0x167d, 0x1691, 0x16a5, 0x16ba, 0x16ce,
+0x16e2, 0x16f7, 0x170b, 0x171f, 0x1733, 0x1748,
+0x175c, 0x1770, 0x1784, 0x1799, 0x17ad, 0x17c1,
+0x17d6, 0x17ea, 0x17fe, 0x1812, 0x1827, 0x183b,
+0x184f, 0x1863, 0x1878, 0x188c, 0x18a0, 0x18b4,
+0x18c9, 0x18dd, 0x18f1, 0x1905, 0x191a, 0x192e,
+0x1942, 0x1957, 0x196b, 0x197f, 0x1993, 0x19a8,
+0x19bc, 0x19d0, 0x19e4, 0x19f9, 0x1a0d, 0x1a21,
+0x1a35, 0x1a49, 0x1a5e, 0x1a72, 0x1a86, 0x1a9a,
+0x1aaf, 0x1ac3, 0x1ad7, 0x1aeb, 0x1b00, 0x1b14,
+0x1b28, 0x1b3c, 0x1b51, 0x1b65, 0x1b79, 0x1b8d,
+0x1ba2, 0x1bb6, 0x1bca, 0x1bde, 0x1bf2, 0x1c07,
+0x1c1b, 0x1c2f, 0x1c43, 0x1c58, 0x1c6c, 0x1c80,
+0x1c94, 0x1ca8, 0x1cbd, 0x1cd1, 0x1ce5, 0x1cf9,
+0x1d0e, 0x1d22, 0x1d36, 0x1d4a, 0x1d5e, 0x1d73,
+0x1d87, 0x1d9b, 0x1daf, 0x1dc3, 0x1dd8, 0x1dec,
+0x1e00, 0x1e14, 0x1e28, 0x1e3d, 0x1e51, 0x1e65,
+0x1e79, 0x1e8d, 0x1ea2, 0x1eb6, 0x1eca, 0x1ede,
+0x1ef2, 0x1f07, 0x1f1b, 0x1f2f, 0x1f43, 0x1f57,
+0x1f6c, 0x1f80, 0x1f94, 0x1fa8, 0x1fbc, 0x1fd1,
+0x1fe5, 0x1ff9, 0x200d, 0x2021, 0x2035, 0x204a,
+0x205e, 0x2072, 0x2086, 0x209a, 0x20ae, 0x20c3,
+0x20d7, 0x20eb, 0x20ff, 0x2113, 0x2127, 0x213c,
+0x2150, 0x2164, 0x2178, 0x218c, 0x21a0, 0x21b5,
+0x21c9, 0x21dd, 0x21f1, 0x2205, 0x2219, 0x222e,
+0x2242, 0x2256, 0x226a, 0x227e, 0x2292, 0x22a6,
+0x22bb, 0x22cf, 0x22e3, 0x22f7, 0x230b, 0x231f,
+0x2333, 0x2348, 0x235c, 0x2370, 0x2384, 0x2398,
+0x23ac, 0x23c0, 0x23d5, 0x23e9, 0x23fd, 0x2411,
+0x2425, 0x2439, 0x244d, 0x2461, 0x2476, 0x248a,
+0x249e, 0x24b2, 0x24c6, 0x24da, 0x24ee, 0x2502,
+0x2517, 0x252b, 0x253f, 0x2553, 0x2567, 0x257b,
+0x258f, 0x25a3, 0x25b7, 0x25cb, 0x25e0, 0x25f4,
+0x2608, 0x261c, 0x2630, 0x2644, 0x2658, 0x266c,
+0x2680, 0x2694, 0x26a9, 0x26bd, 0x26d1, 0x26e5,
+0x26f9, 0x270d, 0x2721, 0x2735, 0x2749, 0x275d,
+0x2771, 0x2785, 0x279a, 0x27ae, 0x27c2, 0x27d6,
+0x27ea, 0x27fe, 0x2812, 0x2826, 0x283a, 0x284e,
+0x2862, 0x2876, 0x288a, 0x289e, 0x28b3, 0x28c7,
+0x28db, 0x28ef, 0x2903, 0x2917, 0x292b, 0x293f,
+0x2953, 0x2967, 0x297b, 0x298f, 0x29a3, 0x29b7,
+0x29cb, 0x29df, 0x29f3, 0x2a07, 0x2a1b, 0x2a2f,
+0x2a43, 0x2a58, 0x2a6c, 0x2a80, 0x2a94, 0x2aa8,
+0x2abc, 0x2ad0, 0x2ae4, 0x2af8, 0x2b0c, 0x2b20,
+0x2b34, 0x2b48, 0x2b5c, 0x2b70, 0x2b84, 0x2b98,
+0x2bac, 0x2bc0, 0x2bd4, 0x2be8, 0x2bfc, 0x2c10,
+0x2c24, 0x2c38, 0x2c4c, 0x2c60, 0x2c74, 0x2c88,
+0x2c9c, 0x2cb0, 0x2cc4, 0x2cd8, 0x2cec, 0x2d00,
+0x2d14, 0x2d28, 0x2d3c, 0x2d50, 0x2d64, 0x2d78,
+0x2d8c, 0x2da0, 0x2db4, 0x2dc8, 0x2ddc, 0x2df0,
+0x2e04, 0x2e18, 0x2e2c, 0x2e40, 0x2e54, 0x2e68,
+0x2e7c, 0x2e90, 0x2ea3, 0x2eb7, 0x2ecb, 0x2edf,
+0x2ef3, 0x2f07, 0x2f1b, 0x2f2f, 0x2f43, 0x2f57,
+0x2f6b, 0x2f7f, 0x2f93, 0x2fa7, 0x2fbb, 0x2fcf,
+0x2fe3, 0x2ff7, 0x300b, 0x301e, 0x3032, 0x3046,
+0x305a, 0x306e, 0x3082, 0x3096, 0x30aa, 0x30be,
+0x30d2, 0x30e6, 0x30fa, 0x310e, 0x3122, 0x3135,
+0x3149, 0x315d, 0x3171, 0x3185, 0x3199, 0x31ad,
+0x31c1, 0x31d5, 0x31e9, 0x31fd, 0x3210, 0x3224,
+0x3238, 0x324c, 0x3260, 0x3274, 0x3288, 0x329c,
+0x32b0, 0x32c3, 0x32d7, 0x32eb, 0x32ff, 0x3313,
+0x3327, 0x333b, 0x334f, 0x3363, 0x3376, 0x338a,
+0x339e, 0x33b2, 0x33c6, 0x33da, 0x33ee, 0x3401,
+0x3415, 0x3429, 0x343d, 0x3451, 0x3465, 0x3479,
+0x348c, 0x34a0, 0x34b4, 0x34c8, 0x34dc, 0x34f0,
+0x3504, 0x3517, 0x352b, 0x353f, 0x3553, 0x3567,
+0x357b, 0x358e, 0x35a2, 0x35b6, 0x35ca, 0x35de,
+0x35f2, 0x3605, 0x3619, 0x362d, 0x3641, 0x3655,
+0x3668, 0x367c, 0x3690, 0x36a4, 0x36b8, 0x36cb,
+0x36df, 0x36f3, 0x3707, 0x371b, 0x372f, 0x3742,
+0x3756, 0x376a, 0x377e, 0x3791, 0x37a5, 0x37b9,
+0x37cd, 0x37e1, 0x37f4, 0x3808, 0x381c, 0x3830,
+0x3844, 0x3857, 0x386b, 0x387f, 0x3893, 0x38a6,
+0x38ba, 0x38ce, 0x38e2, 0x38f5, 0x3909, 0x391d,
+0x3931, 0x3944, 0x3958, 0x396c, 0x3980, 0x3993,
+0x39a7, 0x39bb, 0x39cf, 0x39e2, 0x39f6, 0x3a0a,
+0x3a1e, 0x3a31, 0x3a45, 0x3a59, 0x3a6d, 0x3a80,
+0x3a94, 0x3aa8, 0x3abb, 0x3acf, 0x3ae3, 0x3af7,
+0x3b0a, 0x3b1e, 0x3b32, 0x3b45, 0x3b59, 0x3b6d,
+0x3b81, 0x3b94, 0x3ba8, 0x3bbc, 0x3bcf, 0x3be3,
+0x3bf7, 0x3c0b, 0x3c1e, 0x3c32, 0x3c46, 0x3c59,
+0x3c6d, 0x3c81, 0x3c94, 0x3ca8, 0x3cbc, 0x3ccf,
+0x3ce3, 0x3cf7, 0x3d0a, 0x3d1e, 0x3d32, 0x3d45,
+0x3d59, 0x3d6d, 0x3d80, 0x3d94, 0x3da8, 0x3dbb,
+0x3dcf, 0x3de3, 0x3df6, 0x3e0a, 0x3e1e, 0x3e31,
+0x3e45, 0x3e59, 0x3e6c, 0x3e80, 0x3e93, 0x3ea7,
+0x3ebb, 0x3ece, 0x3ee2, 0x3ef6, 0x3f09, 0x3f1d,
+0x3f30, 0x3f44, 0x3f58, 0x3f6b, 0x3f7f, 0x3f93,
+0x3fa6, 0x3fba, 0x3fcd, 0x3fe1, 0x3ff5, 0x4008,
+0x401c, 0x402f, 0x4043, 0x4057, 0x406a, 0x407e,
+0x4091, 0x40a5, 0x40b8, 0x40cc, 0x40e0, 0x40f3,
+0x4107, 0x411a, 0x412e, 0x4142, 0x4155, 0x4169,
+0x417c, 0x4190, 0x41a3, 0x41b7, 0x41ca, 0x41de,
+0x41f2, 0x4205, 0x4219, 0x422c, 0x4240, 0x4253,
+0x4267, 0x427a, 0x428e, 0x42a1, 0x42b5, 0x42c9,
+0x42dc, 0x42f0, 0x4303, 0x4317, 0x432a, 0x433e,
+0x4351, 0x4365, 0x4378, 0x438c, 0x439f, 0x43b3,
+0x43c6, 0x43da, 0x43ed, 0x4401, 0x4414, 0x4428,
+0x443b, 0x444f, 0x4462, 0x4476, 0x4489, 0x449d,
+0x44b0, 0x44c4, 0x44d7, 0x44eb, 0x44fe, 0x4512,
+0x4525, 0x4539, 0x454c, 0x4560, 0x4573, 0x4586,
+0x459a, 0x45ad, 0x45c1, 0x45d4, 0x45e8, 0x45fb,
+0x460f, 0x4622, 0x4636, 0x4649, 0x465c, 0x4670,
+0x4683, 0x4697, 0x46aa, 0x46be, 0x46d1, 0x46e5,
+0x46f8, 0x470b, 0x471f, 0x4732, 0x4746, 0x4759,
+0x476c, 0x4780, 0x4793, 0x47a7, 0x47ba, 0x47cd,
+0x47e1, 0x47f4, 0x4808, 0x481b, 0x482e, 0x4842,
+0x4855, 0x4869, 0x487c, 0x488f, 0x48a3, 0x48b6,
+0x48ca, 0x48dd, 0x48f0, 0x4904, 0x4917, 0x492a,
+0x493e, 0x4951, 0x4965, 0x4978, 0x498b, 0x499f,
+0x49b2, 0x49c5, 0x49d9, 0x49ec, 0x49ff, 0x4a13,
+0x4a26, 0x4a39, 0x4a4d, 0x4a60, 0x4a73, 0x4a87,
+0x4a9a, 0x4aad, 0x4ac1, 0x4ad4, 0x4ae7, 0x4afb,
+0x4b0e, 0x4b21, 0x4b35, 0x4b48, 0x4b5b, 0x4b6f,
+0x4b82, 0x4b95, 0x4ba8, 0x4bbc, 0x4bcf, 0x4be2,
+0x4bf6, 0x4c09, 0x4c1c, 0x4c2f, 0x4c43, 0x4c56,
+0x4c69, 0x4c7d, 0x4c90, 0x4ca3, 0x4cb6, 0x4cca,
+0x4cdd, 0x4cf0, 0x4d03, 0x4d17, 0x4d2a, 0x4d3d,
+0x4d50, 0x4d64, 0x4d77, 0x4d8a, 0x4d9d, 0x4db1,
+0x4dc4, 0x4dd7, 0x4dea, 0x4dfe, 0x4e11, 0x4e24,
+0x4e37, 0x4e4b, 0x4e5e, 0x4e71, 0x4e84, 0x4e97,
+0x4eab, 0x4ebe, 0x4ed1, 0x4ee4, 0x4ef7, 0x4f0b,
+0x4f1e, 0x4f31, 0x4f44, 0x4f57, 0x4f6b, 0x4f7e,
+0x4f91, 0x4fa4, 0x4fb7, 0x4fcb, 0x4fde, 0x4ff1,
+0x5004, 0x5017, 0x502a, 0x503e, 0x5051, 0x5064,
+0x5077, 0x508a, 0x509d, 0x50b1, 0x50c4, 0x50d7,
+0x50ea, 0x50fd, 0x5110, 0x5123, 0x5137, 0x514a,
+0x515d, 0x5170, 0x5183, 0x5196, 0x51a9, 0x51bc,
+0x51d0, 0x51e3, 0x51f6, 0x5209, 0x521c, 0x522f,
+0x5242, 0x5255, 0x5268, 0x527c, 0x528f, 0x52a2,
+0x52b5, 0x52c8, 0x52db, 0x52ee, 0x5301, 0x5314,
+0x5327, 0x533a, 0x534e, 0x5361, 0x5374, 0x5387,
+0x539a, 0x53ad, 0x53c0, 0x53d3, 0x53e6, 0x53f9,
+0x540c, 0x541f, 0x5432, 0x5445, 0x5458, 0x546b,
+0x547e, 0x5491, 0x54a5, 0x54b8, 0x54cb, 0x54de,
+0x54f1, 0x5504, 0x5517, 0x552a, 0x553d, 0x5550,
+0x5563, 0x5576, 0x5589, 0x559c, 0x55af, 0x55c2,
+0x55d5, 0x55e8, 0x55fb, 0x560e, 0x5621, 0x5634,
+0x5647, 0x565a, 0x566d, 0x5680, 0x5693, 0x56a6,
+0x56b9, 0x56cb, 0x56de, 0x56f1, 0x5704, 0x5717,
+0x572a, 0x573d, 0x5750, 0x5763, 0x5776, 0x5789,
+0x579c, 0x57af, 0x57c2, 0x57d5, 0x57e8, 0x57fb,
+0x580e, 0x5820, 0x5833, 0x5846, 0x5859, 0x586c,
+0x587f, 0x5892, 0x58a5, 0x58b8, 0x58cb, 0x58de,
+0x58f0, 0x5903, 0x5916, 0x5929, 0x593c, 0x594f,
+0x5962, 0x5975, 0x5988, 0x599a, 0x59ad, 0x59c0,
+0x59d3, 0x59e6, 0x59f9, 0x5a0c, 0x5a1f, 0x5a31,
+0x5a44, 0x5a57, 0x5a6a, 0x5a7d, 0x5a90, 0x5aa2,
+0x5ab5, 0x5ac8, 0x5adb, 0x5aee, 0x5b01, 0x5b13,
+0x5b26, 0x5b39, 0x5b4c, 0x5b5f, 0x5b72, 0x5b84,
+0x5b97, 0x5baa, 0x5bbd, 0x5bd0, 0x5be2, 0x5bf5,
+0x5c08, 0x5c1b, 0x5c2e, 0x5c40, 0x5c53, 0x5c66,
+0x5c79, 0x5c8c, 0x5c9e, 0x5cb1, 0x5cc4, 0x5cd7,
+0x5ce9, 0x5cfc, 0x5d0f, 0x5d22, 0x5d34, 0x5d47,
+0x5d5a, 0x5d6d, 0x5d7f, 0x5d92, 0x5da5, 0x5db8,
+0x5dca, 0x5ddd, 0x5df0, 0x5e03, 0x5e15, 0x5e28,
+0x5e3b, 0x5e4d, 0x5e60, 0x5e73, 0x5e86, 0x5e98,
+0x5eab, 0x5ebe, 0x5ed0, 0x5ee3, 0x5ef6, 0x5f09,
+0x5f1b, 0x5f2e, 0x5f41, 0x5f53, 0x5f66, 0x5f79,
+0x5f8b, 0x5f9e, 0x5fb1, 0x5fc3, 0x5fd6, 0x5fe9,
+0x5ffb, 0x600e, 0x6021, 0x6033, 0x6046, 0x6059,
+0x606b, 0x607e, 0x6091, 0x60a3, 0x60b6, 0x60c8,
+0x60db, 0x60ee, 0x6100, 0x6113, 0x6126, 0x6138,
+0x614b, 0x615d, 0x6170, 0x6183, 0x6195, 0x61a8,
+0x61ba, 0x61cd, 0x61e0, 0x61f2, 0x6205, 0x6217,
+0x622a, 0x623d, 0x624f, 0x6262, 0x6274, 0x6287,
+0x6299, 0x62ac, 0x62bf, 0x62d1, 0x62e4, 0x62f6,
+0x6309, 0x631b, 0x632e, 0x6340, 0x6353, 0x6366,
+0x6378, 0x638b, 0x639d, 0x63b0, 0x63c2, 0x63d5,
+0x63e7, 0x63fa, 0x640c, 0x641f, 0x6431, 0x6444,
+0x6456, 0x6469, 0x647b, 0x648e, 0x64a0, 0x64b3,
+0x64c5, 0x64d8, 0x64ea, 0x64fd, 0x650f, 0x6522,
+0x6534, 0x6547, 0x6559, 0x656c, 0x657e, 0x6591,
+0x65a3, 0x65b5, 0x65c8, 0x65da, 0x65ed, 0x65ff,
+0x6612, 0x6624, 0x6637, 0x6649, 0x665b, 0x666e,
+0x6680, 0x6693, 0x66a5, 0x66b8, 0x66ca, 0x66dc,
+0x66ef, 0x6701, 0x6714, 0x6726, 0x6738, 0x674b,
+0x675d, 0x6770, 0x6782, 0x6794, 0x67a7, 0x67b9,
+0x67cc, 0x67de, 0x67f0, 0x6803, 0x6815, 0x6827,
+0x683a, 0x684c, 0x685e, 0x6871, 0x6883, 0x6896,
+0x68a8, 0x68ba, 0x68cd, 0x68df, 0x68f1, 0x6904,
+0x6916, 0x6928, 0x693b, 0x694d, 0x695f, 0x6972,
+0x6984, 0x6996, 0x69a8, 0x69bb, 0x69cd, 0x69df,
+0x69f2, 0x6a04, 0x6a16, 0x6a29, 0x6a3b, 0x6a4d,
+0x6a5f, 0x6a72, 0x6a84, 0x6a96, 0x6aa9, 0x6abb,
+0x6acd, 0x6adf, 0x6af2, 0x6b04, 0x6b16, 0x6b28,
+0x6b3b, 0x6b4d, 0x6b5f, 0x6b71, 0x6b84, 0x6b96,
+0x6ba8, 0x6bba, 0x6bcd, 0x6bdf, 0x6bf1, 0x6c03,
+0x6c15, 0x6c28, 0x6c3a, 0x6c4c, 0x6c5e, 0x6c70,
+0x6c83, 0x6c95, 0x6ca7, 0x6cb9, 0x6ccb, 0x6cde,
+0x6cf0, 0x6d02, 0x6d14, 0x6d26, 0x6d39, 0x6d4b,
+0x6d5d, 0x6d6f, 0x6d81, 0x6d93, 0x6da6, 0x6db8,
+0x6dca, 0x6ddc, 0x6dee, 0x6e00, 0x6e12, 0x6e25,
+0x6e37, 0x6e49, 0x6e5b, 0x6e6d, 0x6e7f, 0x6e91,
+0x6ea3, 0x6eb6, 0x6ec8, 0x6eda, 0x6eec, 0x6efe,
+0x6f10, 0x6f22, 0x6f34, 0x6f46, 0x6f58, 0x6f6b,
+0x6f7d, 0x6f8f, 0x6fa1, 0x6fb3, 0x6fc5, 0x6fd7,
+0x6fe9, 0x6ffb, 0x700d, 0x701f, 0x7031, 0x7043,
+0x7055, 0x7068, 0x707a, 0x708c, 0x709e, 0x70b0,
+0x70c2, 0x70d4, 0x70e6, 0x70f8, 0x710a, 0x711c,
+0x712e, 0x7140, 0x7152, 0x7164, 0x7176, 0x7188,
+0x719a, 0x71ac, 0x71be, 0x71d0, 0x71e2, 0x71f4,
+0x7206, 0x7218, 0x722a, 0x723c, 0x724e, 0x7260,
+0x7272, 0x7284, 0x7296, 0x72a8, 0x72ba, 0x72cc,
+0x72dd, 0x72ef, 0x7301, 0x7313, 0x7325, 0x7337,
+0x7349, 0x735b, 0x736d, 0x737f, 0x7391, 0x73a3,
+0x73b5, 0x73c7, 0x73d8, 0x73ea, 0x73fc, 0x740e,
+0x7420, 0x7432, 0x7444, 0x7456, 0x7468, 0x747a,
+0x748b, 0x749d, 0x74af, 0x74c1, 0x74d3, 0x74e5,
+0x74f7, 0x7509, 0x751a, 0x752c, 0x753e, 0x7550,
+0x7562, 0x7574, 0x7585, 0x7597, 0x75a9, 0x75bb,
+0x75cd, 0x75df, 0x75f0, 0x7602, 0x7614, 0x7626,
+0x7638, 0x764a, 0x765b, 0x766d, 0x767f, 0x7691,
+0x76a3, 0x76b4, 0x76c6, 0x76d8, 0x76ea, 0x76fb,
+0x770d, 0x771f, 0x7731, 0x7743, 0x7754, 0x7766,
+0x7778, 0x778a, 0x779b, 0x77ad, 0x77bf, 0x77d1,
+0x77e2, 0x77f4, 0x7806, 0x7818, 0x7829, 0x783b,
+0x784d, 0x785e, 0x7870, 0x7882, 0x7894, 0x78a5,
+0x78b7, 0x78c9, 0x78da, 0x78ec, 0x78fe, 0x7910,
+0x7921, 0x7933, 0x7945, 0x7956, 0x7968, 0x797a,
+0x798b, 0x799d, 0x79af, 0x79c0, 0x79d2, 0x79e4,
+0x79f5, 0x7a07, 0x7a19, 0x7a2a, 0x7a3c, 0x7a4e,
+0x7a5f, 0x7a71, 0x7a82, 0x7a94, 0x7aa6, 0x7ab7,
+0x7ac9, 0x7adb, 0x7aec, 0x7afe, 0x7b0f, 0x7b21,
+0x7b33, 0x7b44, 0x7b56, 0x7b67, 0x7b79, 0x7b8b,
+0x7b9c, 0x7bae, 0x7bbf, 0x7bd1, 0x7be2, 0x7bf4,
+0x7c06, 0x7c17, 0x7c29, 0x7c3a, 0x7c4c, 0x7c5d,
+0x7c6f, 0x7c81, 0x7c92, 0x7ca4, 0x7cb5, 0x7cc7,
+0x7cd8, 0x7cea, 0x7cfb, 0x7d0d, 0x7d1e, 0x7d30,
+0x7d41, 0x7d53, 0x7d64, 0x7d76, 0x7d87, 0x7d99,
+0x7daa, 0x7dbc, 0x7dcd, 0x7ddf, 0x7df0, 0x7e02,
+0x7e13, 0x7e25, 0x7e36, 0x7e48, 0x7e59, 0x7e6b,
+0x7e7c, 0x7e8e, 0x7e9f, 0x7eb0, 0x7ec2, 0x7ed3,
+0x7ee5, 0x7ef6, 0x7f08, 0x7f19, 0x7f2b, 0x7f3c,
+0x7f4d, 0x7f5f, 0x7f70, 0x7f82, 0x7f93, 0x7fa4,
+0x7fb6, 0x7fc7, 0x7fd9, 0x7fea, 0x7ffb, 0x800d,
+0x801e, 0x8030, 0x8041, 0x8052, 0x8064, 0x8075,
+0x8086, 0x8098, 0x80a9, 0x80bb, 0x80cc, 0x80dd,
+0x80ef, 0x8100, 0x8111, 0x8123, 0x8134, 0x8145,
+0x8157, 0x8168, 0x8179, 0x818b, 0x819c, 0x81ad,
+0x81bf, 0x81d0, 0x81e1, 0x81f3, 0x8204, 0x8215,
+0x8226, 0x8238, 0x8249, 0x825a, 0x826c, 0x827d,
+0x828e, 0x829f, 0x82b1, 0x82c2, 0x82d3, 0x82e5,
+0x82f6, 0x8307, 0x8318, 0x832a, 0x833b, 0x834c,
+0x835d, 0x836f, 0x8380, 0x8391, 0x83a2, 0x83b3,
+0x83c5, 0x83d6, 0x83e7, 0x83f8, 0x840a, 0x841b,
+0x842c, 0x843d, 0x844e, 0x8460, 0x8471, 0x8482,
+0x8493, 0x84a4, 0x84b6, 0x84c7, 0x84d8, 0x84e9,
+0x84fa, 0x850b, 0x851d, 0x852e, 0x853f, 0x8550,
+0x8561, 0x8572, 0x8584, 0x8595, 0x85a6, 0x85b7,
+0x85c8, 0x85d9, 0x85ea, 0x85fb, 0x860d, 0x861e,
+0x862f, 0x8640, 0x8651, 0x8662, 0x8673, 0x8684,
+0x8695, 0x86a7, 0x86b8, 0x86c9, 0x86da, 0x86eb,
+0x86fc, 0x870d, 0x871e, 0x872f, 0x8740, 0x8751,
+0x8762, 0x8773, 0x8784, 0x8796, 0x87a7, 0x87b8,
+0x87c9, 0x87da, 0x87eb, 0x87fc, 0x880d, 0x881e,
+0x882f, 0x8840, 0x8851, 0x8862, 0x8873, 0x8884,
+0x8895, 0x88a6, 0x88b7, 0x88c8, 0x88d9, 0x88ea,
+0x88fb, 0x890c, 0x891d, 0x892e, 0x893f, 0x8950,
+0x8961, 0x8972, 0x8983, 0x8994, 0x89a5, 0x89b6,
+0x89c6, 0x89d7, 0x89e8, 0x89f9, 0x8a0a, 0x8a1b,
+0x8a2c, 0x8a3d, 0x8a4e, 0x8a5f, 0x8a70, 0x8a81,
+0x8a92, 0x8aa3, 0x8ab3, 0x8ac4, 0x8ad5, 0x8ae6,
+0x8af7, 0x8b08, 0x8b19, 0x8b2a, 0x8b3b, 0x8b4b,
+0x8b5c, 0x8b6d, 0x8b7e, 0x8b8f, 0x8ba0, 0x8bb1,
+0x8bc1, 0x8bd2, 0x8be3, 0x8bf4, 0x8c05, 0x8c16,
+0x8c27, 0x8c37, 0x8c48, 0x8c59, 0x8c6a, 0x8c7b,
+0x8c8c, 0x8c9c, 0x8cad, 0x8cbe, 0x8ccf, 0x8ce0,
+0x8cf0, 0x8d01, 0x8d12, 0x8d23, 0x8d34, 0x8d44,
+0x8d55, 0x8d66, 0x8d77, 0x8d87, 0x8d98, 0x8da9,
+0x8dba, 0x8dca, 0x8ddb, 0x8dec, 0x8dfd, 0x8e0d,
+0x8e1e, 0x8e2f, 0x8e40, 0x8e50, 0x8e61, 0x8e72,
+0x8e83, 0x8e93, 0x8ea4, 0x8eb5, 0x8ec5, 0x8ed6,
+0x8ee7, 0x8ef8, 0x8f08, 0x8f19, 0x8f2a, 0x8f3a,
+0x8f4b, 0x8f5c, 0x8f6c, 0x8f7d, 0x8f8e, 0x8f9e,
+0x8faf, 0x8fc0, 0x8fd0, 0x8fe1, 0x8ff2, 0x9002,
+0x9013, 0x9024, 0x9034, 0x9045, 0x9056, 0x9066,
+0x9077, 0x9088, 0x9098, 0x90a9, 0x90b9, 0x90ca,
+0x90db, 0x90eb, 0x90fc, 0x910c, 0x911d, 0x912e,
+0x913e, 0x914f, 0x915f, 0x9170, 0x9181, 0x9191,
+0x91a2, 0x91b2, 0x91c3, 0x91d3, 0x91e4, 0x91f5,
+0x9205, 0x9216, 0x9226, 0x9237, 0x9247, 0x9258,
+0x9268, 0x9279, 0x9289, 0x929a, 0x92aa, 0x92bb,
+0x92cc, 0x92dc, 0x92ed, 0x92fd, 0x930e, 0x931e,
+0x932f, 0x933f, 0x9350, 0x9360, 0x9370, 0x9381,
+0x9391, 0x93a2, 0x93b2, 0x93c3, 0x93d3, 0x93e4,
+0x93f4, 0x9405, 0x9415, 0x9426, 0x9436, 0x9447,
+0x9457, 0x9467, 0x9478, 0x9488, 0x9499, 0x94a9,
+0x94ba, 0x94ca, 0x94da, 0x94eb, 0x94fb, 0x950c,
+0x951c, 0x952c, 0x953d, 0x954d, 0x955e, 0x956e,
+0x957e, 0x958f, 0x959f, 0x95af, 0x95c0, 0x95d0,
+0x95e1, 0x95f1, 0x9601, 0x9612, 0x9622, 0x9632,
+0x9643, 0x9653, 0x9663, 0x9674, 0x9684, 0x9694,
+0x96a5, 0x96b5, 0x96c5, 0x96d6, 0x96e6, 0x96f6,
+0x9707, 0x9717, 0x9727, 0x9738, 0x9748, 0x9758,
+0x9768, 0x9779, 0x9789, 0x9799, 0x97aa, 0x97ba,
+0x97ca, 0x97da, 0x97eb, 0x97fb, 0x980b, 0x981b,
+0x982c, 0x983c, 0x984c, 0x985c, 0x986d, 0x987d,
+0x988d, 0x989d, 0x98ad, 0x98be, 0x98ce, 0x98de,
+0x98ee, 0x98ff, 0x990f, 0x991f, 0x992f, 0x993f,
+0x9950, 0x9960, 0x9970, 0x9980, 0x9990, 0x99a0,
+0x99b1, 0x99c1, 0x99d1, 0x99e1, 0x99f1, 0x9a01,
+0x9a12, 0x9a22, 0x9a32, 0x9a42, 0x9a52, 0x9a62,
+0x9a72, 0x9a83, 0x9a93, 0x9aa3, 0x9ab3, 0x9ac3,
+0x9ad3, 0x9ae3, 0x9af3, 0x9b04, 0x9b14, 0x9b24,
+0x9b34, 0x9b44, 0x9b54, 0x9b64, 0x9b74, 0x9b84,
+0x9b94, 0x9ba4, 0x9bb5, 0x9bc5, 0x9bd5, 0x9be5,
+0x9bf5, 0x9c05, 0x9c15, 0x9c25, 0x9c35, 0x9c45,
+0x9c55, 0x9c65, 0x9c75, 0x9c85, 0x9c95, 0x9ca5,
+0x9cb5, 0x9cc5, 0x9cd5, 0x9ce5, 0x9cf5, 0x9d05,
+0x9d15, 0x9d25, 0x9d35, 0x9d45, 0x9d55, 0x9d65,
+0x9d75, 0x9d85, 0x9d95, 0x9da5, 0x9db5, 0x9dc5,
+0x9dd5, 0x9de5, 0x9df5, 0x9e05, 0x9e15, 0x9e25,
+0x9e35, 0x9e45, 0x9e55, 0x9e65, 0x9e74, 0x9e84,
+0x9e94, 0x9ea4, 0x9eb4, 0x9ec4, 0x9ed4, 0x9ee4,
+0x9ef4, 0x9f04, 0x9f14, 0x9f23, 0x9f33, 0x9f43,
+0x9f53, 0x9f63, 0x9f73, 0x9f83, 0x9f93, 0x9fa3,
+0x9fb2, 0x9fc2, 0x9fd2, 0x9fe2, 0x9ff2, 0xa002,
+0xa012, 0xa021, 0xa031, 0xa041, 0xa051, 0xa061,
+0xa071, 0xa080, 0xa090, 0xa0a0, 0xa0b0, 0xa0c0,
+0xa0cf, 0xa0df, 0xa0ef, 0xa0ff, 0xa10f, 0xa11e,
+0xa12e, 0xa13e, 0xa14e, 0xa15e, 0xa16d, 0xa17d,
+0xa18d, 0xa19d, 0xa1ac, 0xa1bc, 0xa1cc, 0xa1dc,
+0xa1eb, 0xa1fb, 0xa20b, 0xa21b, 0xa22a, 0xa23a,
+0xa24a, 0xa25a, 0xa269, 0xa279, 0xa289, 0xa298,
+0xa2a8, 0xa2b8, 0xa2c8, 0xa2d7, 0xa2e7, 0xa2f7,
+0xa306, 0xa316, 0xa326, 0xa335, 0xa345, 0xa355,
+0xa364, 0xa374, 0xa384, 0xa393, 0xa3a3, 0xa3b3,
+0xa3c2, 0xa3d2, 0xa3e2, 0xa3f1, 0xa401, 0xa411,
+0xa420, 0xa430, 0xa440, 0xa44f, 0xa45f, 0xa46e,
+0xa47e, 0xa48e, 0xa49d, 0xa4ad, 0xa4bc, 0xa4cc,
+0xa4dc, 0xa4eb, 0xa4fb, 0xa50a, 0xa51a, 0xa52a,
+0xa539, 0xa549, 0xa558, 0xa568, 0xa577, 0xa587,
+0xa597, 0xa5a6, 0xa5b6, 0xa5c5, 0xa5d5, 0xa5e4,
+0xa5f4, 0xa603, 0xa613, 0xa622, 0xa632, 0xa641,
+0xa651, 0xa660, 0xa670, 0xa67f, 0xa68f, 0xa69e,
+0xa6ae, 0xa6bd, 0xa6cd, 0xa6dc, 0xa6ec, 0xa6fb,
+0xa70b, 0xa71a, 0xa72a, 0xa739, 0xa749, 0xa758,
+0xa768, 0xa777, 0xa787, 0xa796, 0xa7a5, 0xa7b5,
+0xa7c4, 0xa7d4, 0xa7e3, 0xa7f3, 0xa802, 0xa812,
+0xa821, 0xa830, 0xa840, 0xa84f, 0xa85f, 0xa86e,
+0xa87d, 0xa88d, 0xa89c, 0xa8ac, 0xa8bb, 0xa8ca,
+0xa8da, 0xa8e9, 0xa8f8, 0xa908, 0xa917, 0xa927,
+0xa936, 0xa945, 0xa955, 0xa964, 0xa973, 0xa983,
+0xa992, 0xa9a1, 0xa9b1, 0xa9c0, 0xa9cf, 0xa9df,
+0xa9ee, 0xa9fd, 0xaa0d, 0xaa1c, 0xaa2b, 0xaa3b,
+0xaa4a, 0xaa59, 0xaa69, 0xaa78, 0xaa87, 0xaa96,
+0xaaa6, 0xaab5, 0xaac4, 0xaad4, 0xaae3, 0xaaf2,
+0xab01, 0xab11, 0xab20, 0xab2f, 0xab3e, 0xab4e,
+0xab5d, 0xab6c, 0xab7b, 0xab8b, 0xab9a, 0xaba9,
+0xabb8, 0xabc7, 0xabd7, 0xabe6, 0xabf5, 0xac04,
+0xac14, 0xac23, 0xac32, 0xac41, 0xac50, 0xac60,
+0xac6f, 0xac7e, 0xac8d, 0xac9c, 0xacab, 0xacbb,
+0xacca, 0xacd9, 0xace8, 0xacf7, 0xad06, 0xad16,
+0xad25, 0xad34, 0xad43, 0xad52, 0xad61, 0xad70,
+0xad80, 0xad8f, 0xad9e, 0xadad, 0xadbc, 0xadcb,
+0xadda, 0xade9, 0xadf8, 0xae08, 0xae17, 0xae26,
+0xae35, 0xae44, 0xae53, 0xae62, 0xae71, 0xae80,
+0xae8f, 0xae9e, 0xaead, 0xaebd, 0xaecc, 0xaedb,
+0xaeea, 0xaef9, 0xaf08, 0xaf17, 0xaf26, 0xaf35,
+0xaf44, 0xaf53, 0xaf62, 0xaf71, 0xaf80, 0xaf8f,
+0xaf9e, 0xafad, 0xafbc, 0xafcb, 0xafda, 0xafe9,
+0xaff8, 0xb007, 0xb016, 0xb025, 0xb034, 0xb043,
+0xb052, 0xb061, 0xb070, 0xb07f, 0xb08e, 0xb09d,
+0xb0ac, 0xb0bb, 0xb0ca, 0xb0d9, 0xb0e8, 0xb0f6,
+0xb105, 0xb114, 0xb123, 0xb132, 0xb141, 0xb150,
+0xb15f, 0xb16e, 0xb17d, 0xb18c, 0xb19b, 0xb1aa,
+0xb1b8, 0xb1c7, 0xb1d6, 0xb1e5, 0xb1f4, 0xb203,
+0xb212, 0xb221, 0xb22f, 0xb23e, 0xb24d, 0xb25c,
+0xb26b, 0xb27a, 0xb289, 0xb297, 0xb2a6, 0xb2b5,
+0xb2c4, 0xb2d3, 0xb2e2, 0xb2f1, 0xb2ff, 0xb30e,
+0xb31d, 0xb32c, 0xb33b, 0xb349, 0xb358, 0xb367,
+0xb376, 0xb385, 0xb393, 0xb3a2, 0xb3b1, 0xb3c0,
+0xb3cf, 0xb3dd, 0xb3ec, 0xb3fb, 0xb40a, 0xb418,
+0xb427, 0xb436, 0xb445, 0xb453, 0xb462, 0xb471,
+0xb480, 0xb48e, 0xb49d, 0xb4ac, 0xb4bb, 0xb4c9,
+0xb4d8, 0xb4e7, 0xb4f6, 0xb504, 0xb513, 0xb522,
+0xb530, 0xb53f, 0xb54e, 0xb55c, 0xb56b, 0xb57a,
+0xb588, 0xb597, 0xb5a6, 0xb5b5, 0xb5c3, 0xb5d2,
+0xb5e1, 0xb5ef, 0xb5fe, 0xb60d, 0xb61b, 0xb62a,
+0xb638, 0xb647, 0xb656, 0xb664, 0xb673, 0xb682,
+0xb690, 0xb69f, 0xb6ae, 0xb6bc, 0xb6cb, 0xb6d9,
+0xb6e8, 0xb6f7, 0xb705, 0xb714, 0xb722, 0xb731,
+0xb740, 0xb74e, 0xb75d, 0xb76b, 0xb77a, 0xb788,
+0xb797, 0xb7a6, 0xb7b4, 0xb7c3, 0xb7d1, 0xb7e0,
+0xb7ee, 0xb7fd, 0xb80b, 0xb81a, 0xb829, 0xb837,
+0xb846, 0xb854, 0xb863, 0xb871, 0xb880, 0xb88e,
+0xb89d, 0xb8ab, 0xb8ba, 0xb8c8, 0xb8d7, 0xb8e5,
+0xb8f4, 0xb902, 0xb911, 0xb91f, 0xb92e, 0xb93c,
+0xb94b, 0xb959, 0xb968, 0xb976, 0xb984, 0xb993,
+0xb9a1, 0xb9b0, 0xb9be, 0xb9cd, 0xb9db, 0xb9ea,
+0xb9f8, 0xba06, 0xba15, 0xba23, 0xba32, 0xba40,
+0xba4f, 0xba5d, 0xba6b, 0xba7a, 0xba88, 0xba97,
+0xbaa5, 0xbab3, 0xbac2, 0xbad0, 0xbade, 0xbaed,
+0xbafb, 0xbb0a, 0xbb18, 0xbb26, 0xbb35, 0xbb43,
+0xbb51, 0xbb60, 0xbb6e, 0xbb7c, 0xbb8b, 0xbb99,
+0xbba8, 0xbbb6, 0xbbc4, 0xbbd3, 0xbbe1, 0xbbef,
+0xbbfd, 0xbc0c, 0xbc1a, 0xbc28, 0xbc37, 0xbc45,
+0xbc53, 0xbc62, 0xbc70, 0xbc7e, 0xbc8c, 0xbc9b,
+0xbca9, 0xbcb7, 0xbcc6, 0xbcd4, 0xbce2, 0xbcf0,
+0xbcff, 0xbd0d, 0xbd1b, 0xbd29, 0xbd38, 0xbd46,
+0xbd54, 0xbd62, 0xbd71, 0xbd7f, 0xbd8d, 0xbd9b,
+0xbdaa, 0xbdb8, 0xbdc6, 0xbdd4, 0xbde2, 0xbdf1,
+0xbdff, 0xbe0d, 0xbe1b, 0xbe29, 0xbe38, 0xbe46,
+0xbe54, 0xbe62, 0xbe70, 0xbe7f, 0xbe8d, 0xbe9b,
+0xbea9, 0xbeb7, 0xbec5, 0xbed4, 0xbee2, 0xbef0,
+0xbefe, 0xbf0c, 0xbf1a, 0xbf28, 0xbf37, 0xbf45,
+0xbf53, 0xbf61, 0xbf6f, 0xbf7d, 0xbf8b, 0xbf99,
+0xbfa7, 0xbfb6, 0xbfc4, 0xbfd2, 0xbfe0, 0xbfee,
+0xbffc, 0xc00a, 0xc018, 0xc026, 0xc034, 0xc042,
+0xc051, 0xc05f, 0xc06d, 0xc07b, 0xc089, 0xc097,
+0xc0a5, 0xc0b3, 0xc0c1, 0xc0cf, 0xc0dd, 0xc0eb,
+0xc0f9, 0xc107, 0xc115, 0xc123, 0xc131, 0xc13f,
+0xc14d, 0xc15b, 0xc169, 0xc177, 0xc185, 0xc193,
+0xc1a1, 0xc1af, 0xc1bd, 0xc1cb, 0xc1d9, 0xc1e7,
+0xc1f5, 0xc203, 0xc211, 0xc21f, 0xc22d, 0xc23b,
+0xc249, 0xc257, 0xc265, 0xc273, 0xc281, 0xc28f,
+0xc29d, 0xc2ab, 0xc2b8, 0xc2c6, 0xc2d4, 0xc2e2,
+0xc2f0, 0xc2fe, 0xc30c, 0xc31a, 0xc328, 0xc336,
+0xc344, 0xc352, 0xc35f, 0xc36d, 0xc37b, 0xc389,
+0xc397, 0xc3a5, 0xc3b3, 0xc3c1, 0xc3ce, 0xc3dc,
+0xc3ea, 0xc3f8, 0xc406, 0xc414, 0xc422, 0xc42f,
+0xc43d, 0xc44b, 0xc459, 0xc467, 0xc475, 0xc482,
+0xc490, 0xc49e, 0xc4ac, 0xc4ba, 0xc4c7, 0xc4d5,
+0xc4e3, 0xc4f1, 0xc4ff, 0xc50d, 0xc51a, 0xc528,
+0xc536, 0xc544, 0xc551, 0xc55f, 0xc56d, 0xc57b,
+0xc589, 0xc596, 0xc5a4, 0xc5b2, 0xc5c0, 0xc5cd,
+0xc5db, 0xc5e9, 0xc5f7, 0xc604, 0xc612, 0xc620,
+0xc62d, 0xc63b, 0xc649, 0xc657, 0xc664, 0xc672,
+0xc680, 0xc68d, 0xc69b, 0xc6a9, 0xc6b7, 0xc6c4,
+0xc6d2, 0xc6e0, 0xc6ed, 0xc6fb, 0xc709, 0xc716,
+0xc724, 0xc732, 0xc73f, 0xc74d, 0xc75b, 0xc768,
+0xc776, 0xc784, 0xc791, 0xc79f, 0xc7ad, 0xc7ba,
+0xc7c8, 0xc7d6, 0xc7e3, 0xc7f1, 0xc7fe, 0xc80c,
+0xc81a, 0xc827, 0xc835, 0xc842, 0xc850, 0xc85e,
+0xc86b, 0xc879, 0xc886, 0xc894, 0xc8a2, 0xc8af,
+0xc8bd, 0xc8ca, 0xc8d8, 0xc8e5, 0xc8f3, 0xc901,
+0xc90e, 0xc91c, 0xc929, 0xc937, 0xc944, 0xc952,
+0xc95f, 0xc96d, 0xc97b, 0xc988, 0xc996, 0xc9a3,
+0xc9b1, 0xc9be, 0xc9cc, 0xc9d9, 0xc9e7, 0xc9f4,
+0xca02, 0xca0f, 0xca1d, 0xca2a, 0xca38, 0xca45,
+0xca53, 0xca60, 0xca6e, 0xca7b, 0xca89, 0xca96,
+0xcaa4, 0xcab1, 0xcabe, 0xcacc, 0xcad9, 0xcae7,
+0xcaf4, 0xcb02, 0xcb0f, 0xcb1d, 0xcb2a, 0xcb37,
+0xcb45, 0xcb52, 0xcb60, 0xcb6d, 0xcb7b, 0xcb88,
+0xcb95, 0xcba3, 0xcbb0, 0xcbbe, 0xcbcb, 0xcbd8,
+0xcbe6, 0xcbf3, 0xcc01, 0xcc0e, 0xcc1b, 0xcc29,
+0xcc36, 0xcc43, 0xcc51, 0xcc5e, 0xcc6c, 0xcc79,
+0xcc86, 0xcc94, 0xcca1, 0xccae, 0xccbc, 0xccc9,
+0xccd6, 0xcce4, 0xccf1, 0xccfe, 0xcd0c, 0xcd19,
+0xcd26, 0xcd34, 0xcd41, 0xcd4e, 0xcd5b, 0xcd69,
+0xcd76, 0xcd83, 0xcd91, 0xcd9e, 0xcdab, 0xcdb9,
+0xcdc6, 0xcdd3, 0xcde0, 0xcdee, 0xcdfb, 0xce08,
+0xce15, 0xce23, 0xce30, 0xce3d, 0xce4a, 0xce58,
+0xce65, 0xce72, 0xce7f, 0xce8d, 0xce9a, 0xcea7,
+0xceb4, 0xcec2, 0xcecf, 0xcedc, 0xcee9, 0xcef6,
+0xcf04, 0xcf11, 0xcf1e, 0xcf2b, 0xcf38, 0xcf46,
+0xcf53, 0xcf60, 0xcf6d, 0xcf7a, 0xcf87, 0xcf95,
+0xcfa2, 0xcfaf, 0xcfbc, 0xcfc9, 0xcfd6, 0xcfe4,
+0xcff1, 0xcffe, 0xd00b, 0xd018, 0xd025, 0xd032,
+0xd040, 0xd04d, 0xd05a, 0xd067, 0xd074, 0xd081,
+0xd08e, 0xd09b, 0xd0a9, 0xd0b6, 0xd0c3, 0xd0d0,
+0xd0dd, 0xd0ea, 0xd0f7, 0xd104, 0xd111, 0xd11e,
+0xd12b, 0xd139, 0xd146, 0xd153, 0xd160, 0xd16d,
+0xd17a, 0xd187, 0xd194, 0xd1a1, 0xd1ae, 0xd1bb,
+0xd1c8, 0xd1d5, 0xd1e2, 0xd1ef, 0xd1fc, 0xd209,
+0xd216, 0xd223, 0xd230, 0xd23d, 0xd24a, 0xd257,
+0xd264, 0xd271, 0xd27e, 0xd28b, 0xd298, 0xd2a5,
+0xd2b2, 0xd2bf, 0xd2cc, 0xd2d9, 0xd2e6, 0xd2f3,
+0xd300, 0xd30d, 0xd31a, 0xd327, 0xd334, 0xd341,
+0xd34e, 0xd35b, 0xd368, 0xd375, 0xd382, 0xd38f,
+0xd39c, 0xd3a8, 0xd3b5, 0xd3c2, 0xd3cf, 0xd3dc,
+0xd3e9, 0xd3f6, 0xd403, 0xd410, 0xd41d, 0xd42a,
+0xd436, 0xd443, 0xd450, 0xd45d, 0xd46a, 0xd477,
+0xd484, 0xd491, 0xd49e, 0xd4aa, 0xd4b7, 0xd4c4,
+0xd4d1, 0xd4de, 0xd4eb, 0xd4f8, 0xd504, 0xd511,
+0xd51e, 0xd52b, 0xd538, 0xd545, 0xd551, 0xd55e,
+0xd56b, 0xd578, 0xd585, 0xd591, 0xd59e, 0xd5ab,
+0xd5b8, 0xd5c5, 0xd5d1, 0xd5de, 0xd5eb, 0xd5f8,
+0xd605, 0xd611, 0xd61e, 0xd62b, 0xd638, 0xd645,
+0xd651, 0xd65e, 0xd66b, 0xd678, 0xd684, 0xd691,
+0xd69e, 0xd6ab, 0xd6b7, 0xd6c4, 0xd6d1, 0xd6de,
+0xd6ea, 0xd6f7, 0xd704, 0xd710, 0xd71d, 0xd72a,
+0xd737, 0xd743, 0xd750, 0xd75d, 0xd769, 0xd776,
+0xd783, 0xd78f, 0xd79c, 0xd7a9, 0xd7b6, 0xd7c2,
+0xd7cf, 0xd7dc, 0xd7e8, 0xd7f5, 0xd802, 0xd80e,
+0xd81b, 0xd828, 0xd834, 0xd841, 0xd84e, 0xd85a,
+0xd867, 0xd873, 0xd880, 0xd88d, 0xd899, 0xd8a6,
+0xd8b3, 0xd8bf, 0xd8cc, 0xd8d8, 0xd8e5, 0xd8f2,
+0xd8fe, 0xd90b, 0xd917, 0xd924, 0xd931, 0xd93d,
+0xd94a, 0xd956, 0xd963, 0xd970, 0xd97c, 0xd989,
+0xd995, 0xd9a2, 0xd9ae, 0xd9bb, 0xd9c8, 0xd9d4,
+0xd9e1, 0xd9ed, 0xd9fa, 0xda06, 0xda13, 0xda1f,
+0xda2c, 0xda38, 0xda45, 0xda51, 0xda5e, 0xda6a,
+0xda77, 0xda84, 0xda90, 0xda9d, 0xdaa9, 0xdab6,
+0xdac2, 0xdacf, 0xdadb, 0xdae7, 0xdaf4, 0xdb00,
+0xdb0d, 0xdb19, 0xdb26, 0xdb32, 0xdb3f, 0xdb4b,
+0xdb58, 0xdb64, 0xdb71, 0xdb7d, 0xdb8a, 0xdb96,
+0xdba2, 0xdbaf, 0xdbbb, 0xdbc8, 0xdbd4, 0xdbe1,
+0xdbed, 0xdbf9, 0xdc06, 0xdc12, 0xdc1f, 0xdc2b,
+0xdc38, 0xdc44, 0xdc50, 0xdc5d, 0xdc69, 0xdc76,
+0xdc82, 0xdc8e, 0xdc9b, 0xdca7, 0xdcb3, 0xdcc0,
+0xdccc, 0xdcd9, 0xdce5, 0xdcf1, 0xdcfe, 0xdd0a,
+0xdd16, 0xdd23, 0xdd2f, 0xdd3b, 0xdd48, 0xdd54,
+0xdd60, 0xdd6d, 0xdd79, 0xdd85, 0xdd92, 0xdd9e,
+0xddaa, 0xddb7, 0xddc3, 0xddcf, 0xdddc, 0xdde8,
+0xddf4, 0xde01, 0xde0d, 0xde19, 0xde25, 0xde32,
+0xde3e, 0xde4a, 0xde57, 0xde63, 0xde6f, 0xde7b,
+0xde88, 0xde94, 0xdea0, 0xdeac, 0xdeb9, 0xdec5,
+0xded1, 0xdedd, 0xdeea, 0xdef6, 0xdf02, 0xdf0e,
+0xdf1b, 0xdf27, 0xdf33, 0xdf3f, 0xdf4c, 0xdf58,
+0xdf64, 0xdf70, 0xdf7c, 0xdf89, 0xdf95, 0xdfa1,
+0xdfad, 0xdfb9, 0xdfc6, 0xdfd2, 0xdfde, 0xdfea,
+0xdff6, 0xe003, 0xe00f, 0xe01b, 0xe027, 0xe033,
+0xe03f, 0xe04c, 0xe058, 0xe064, 0xe070, 0xe07c,
+0xe088, 0xe094, 0xe0a1, 0xe0ad, 0xe0b9, 0xe0c5,
+0xe0d1, 0xe0dd, 0xe0e9, 0xe0f5, 0xe102, 0xe10e,
+0xe11a, 0xe126, 0xe132, 0xe13e, 0xe14a, 0xe156,
+0xe162, 0xe16e, 0xe17b, 0xe187, 0xe193, 0xe19f,
+0xe1ab, 0xe1b7, 0xe1c3, 0xe1cf, 0xe1db, 0xe1e7,
+0xe1f3, 0xe1ff, 0xe20b, 0xe217, 0xe223, 0xe22f,
+0xe23c, 0xe248, 0xe254, 0xe260, 0xe26c, 0xe278,
+0xe284, 0xe290, 0xe29c, 0xe2a8, 0xe2b4, 0xe2c0,
+0xe2cc, 0xe2d8, 0xe2e4, 0xe2f0, 0xe2fc, 0xe308,
+0xe314, 0xe320, 0xe32c, 0xe338, 0xe344, 0xe350,
+0xe35c, 0xe368, 0xe374, 0xe380, 0xe38b, 0xe397,
+0xe3a3, 0xe3af, 0xe3bb, 0xe3c7, 0xe3d3, 0xe3df,
+0xe3eb, 0xe3f7, 0xe403, 0xe40f, 0xe41b, 0xe427,
+0xe433, 0xe43f, 0xe44a, 0xe456, 0xe462, 0xe46e,
+0xe47a, 0xe486, 0xe492, 0xe49e, 0xe4aa, 0xe4b6,
+0xe4c1, 0xe4cd, 0xe4d9, 0xe4e5, 0xe4f1, 0xe4fd,
+0xe509, 0xe515, 0xe520, 0xe52c, 0xe538, 0xe544,
+0xe550, 0xe55c, 0xe567, 0xe573, 0xe57f, 0xe58b,
+0xe597, 0xe5a3, 0xe5af, 0xe5ba, 0xe5c6, 0xe5d2,
+0xe5de, 0xe5ea, 0xe5f5, 0xe601, 0xe60d, 0xe619,
+0xe625, 0xe630, 0xe63c, 0xe648, 0xe654, 0xe660,
+0xe66b, 0xe677, 0xe683, 0xe68f, 0xe69a, 0xe6a6,
+0xe6b2, 0xe6be, 0xe6ca, 0xe6d5, 0xe6e1, 0xe6ed,
+0xe6f9, 0xe704, 0xe710, 0xe71c, 0xe727, 0xe733,
+0xe73f, 0xe74b, 0xe756, 0xe762, 0xe76e, 0xe77a,
+0xe785, 0xe791, 0xe79d, 0xe7a8, 0xe7b4, 0xe7c0,
+0xe7cb, 0xe7d7, 0xe7e3, 0xe7ef, 0xe7fa, 0xe806,
+0xe812, 0xe81d, 0xe829, 0xe835, 0xe840, 0xe84c,
+0xe858, 0xe863, 0xe86f, 0xe87b, 0xe886, 0xe892,
+0xe89e, 0xe8a9, 0xe8b5, 0xe8c0, 0xe8cc, 0xe8d8,
+0xe8e3, 0xe8ef, 0xe8fb, 0xe906, 0xe912, 0xe91d,
+0xe929, 0xe935, 0xe940, 0xe94c, 0xe958, 0xe963,
+0xe96f, 0xe97a, 0xe986, 0xe991, 0xe99d, 0xe9a9,
+0xe9b4, 0xe9c0, 0xe9cb, 0xe9d7, 0xe9e3, 0xe9ee,
+0xe9fa, 0xea05, 0xea11, 0xea1c, 0xea28, 0xea33,
+0xea3f, 0xea4a, 0xea56, 0xea62, 0xea6d, 0xea79,
+0xea84, 0xea90, 0xea9b, 0xeaa7, 0xeab2, 0xeabe,
+0xeac9, 0xead5, 0xeae0, 0xeaec, 0xeaf7, 0xeb03,
+0xeb0e, 0xeb1a, 0xeb25, 0xeb31, 0xeb3c, 0xeb48,
+0xeb53, 0xeb5f, 0xeb6a, 0xeb76, 0xeb81, 0xeb8d,
+0xeb98, 0xeba3, 0xebaf, 0xebba, 0xebc6, 0xebd1,
+0xebdd, 0xebe8, 0xebf4, 0xebff, 0xec0a, 0xec16,
+0xec21, 0xec2d, 0xec38, 0xec44, 0xec4f, 0xec5a,
+0xec66, 0xec71, 0xec7d, 0xec88, 0xec93, 0xec9f,
+0xecaa, 0xecb6, 0xecc1, 0xeccc, 0xecd8, 0xece3,
+0xecef, 0xecfa, 0xed05, 0xed11, 0xed1c, 0xed27,
+0xed33, 0xed3e, 0xed4a, 0xed55, 0xed60, 0xed6c,
+0xed77, 0xed82, 0xed8e, 0xed99, 0xeda4, 0xedb0,
+0xedbb, 0xedc6, 0xedd2, 0xeddd, 0xede8, 0xedf4,
+0xedff, 0xee0a, 0xee15, 0xee21, 0xee2c, 0xee37,
+0xee43, 0xee4e, 0xee59, 0xee65, 0xee70, 0xee7b,
+0xee86, 0xee92, 0xee9d, 0xeea8, 0xeeb3, 0xeebf,
+0xeeca, 0xeed5, 0xeee1, 0xeeec, 0xeef7, 0xef02,
+0xef0e, 0xef19, 0xef24, 0xef2f, 0xef3a, 0xef46,
+0xef51, 0xef5c, 0xef67, 0xef73, 0xef7e, 0xef89,
+0xef94, 0xef9f, 0xefab, 0xefb6, 0xefc1, 0xefcc,
+0xefd7, 0xefe3, 0xefee, 0xeff9, 0xf004, 0xf00f,
+0xf01b, 0xf026, 0xf031, 0xf03c, 0xf047, 0xf052,
+0xf05e, 0xf069, 0xf074, 0xf07f, 0xf08a, 0xf095,
+0xf0a1, 0xf0ac, 0xf0b7, 0xf0c2, 0xf0cd, 0xf0d8,
+0xf0e3, 0xf0ef, 0xf0fa, 0xf105, 0xf110, 0xf11b,
+0xf126, 0xf131, 0xf13c, 0xf147, 0xf153, 0xf15e,
+0xf169, 0xf174, 0xf17f, 0xf18a, 0xf195, 0xf1a0,
+0xf1ab, 0xf1b6, 0xf1c2, 0xf1cd, 0xf1d8, 0xf1e3,
+0xf1ee, 0xf1f9, 0xf204, 0xf20f, 0xf21a, 0xf225,
+0xf230, 0xf23b, 0xf246, 0xf251, 0xf25c, 0xf267,
+0xf272, 0xf27d, 0xf288, 0xf293, 0xf29f, 0xf2aa,
+0xf2b5, 0xf2c0, 0xf2cb, 0xf2d6, 0xf2e1, 0xf2ec,
+0xf2f7, 0xf302, 0xf30d, 0xf318, 0xf323, 0xf32e,
+0xf339, 0xf344, 0xf34f, 0xf35a, 0xf364, 0xf36f,
+0xf37a, 0xf385, 0xf390, 0xf39b, 0xf3a6, 0xf3b1,
+0xf3bc, 0xf3c7, 0xf3d2, 0xf3dd, 0xf3e8, 0xf3f3,
+0xf3fe, 0xf409, 0xf414, 0xf41f, 0xf42a, 0xf435,
+0xf43f, 0xf44a, 0xf455, 0xf460, 0xf46b, 0xf476,
+0xf481, 0xf48c, 0xf497, 0xf4a2, 0xf4ad, 0xf4b7,
+0xf4c2, 0xf4cd, 0xf4d8, 0xf4e3, 0xf4ee, 0xf4f9,
+0xf504, 0xf50f, 0xf519, 0xf524, 0xf52f, 0xf53a,
+0xf545, 0xf550, 0xf55b, 0xf565, 0xf570, 0xf57b,
+0xf586, 0xf591, 0xf59c, 0xf5a6, 0xf5b1, 0xf5bc,
+0xf5c7, 0xf5d2, 0xf5dd, 0xf5e7, 0xf5f2, 0xf5fd,
+0xf608, 0xf613, 0xf61d, 0xf628, 0xf633, 0xf63e,
+0xf649, 0xf653, 0xf65e, 0xf669, 0xf674, 0xf67f,
+0xf689, 0xf694, 0xf69f, 0xf6aa, 0xf6b4, 0xf6bf,
+0xf6ca, 0xf6d5, 0xf6e0, 0xf6ea, 0xf6f5, 0xf700,
+0xf70b, 0xf715, 0xf720, 0xf72b, 0xf736, 0xf740,
+0xf74b, 0xf756, 0xf760, 0xf76b, 0xf776, 0xf781,
+0xf78b, 0xf796, 0xf7a1, 0xf7ab, 0xf7b6, 0xf7c1,
+0xf7cc, 0xf7d6, 0xf7e1, 0xf7ec, 0xf7f6, 0xf801,
+0xf80c, 0xf816, 0xf821, 0xf82c, 0xf836, 0xf841,
+0xf84c, 0xf856, 0xf861, 0xf86c, 0xf876, 0xf881,
+0xf88c, 0xf896, 0xf8a1, 0xf8ac, 0xf8b6, 0xf8c1,
+0xf8cc, 0xf8d6, 0xf8e1, 0xf8ec, 0xf8f6, 0xf901,
+0xf90b, 0xf916, 0xf921, 0xf92b, 0xf936, 0xf941,
+0xf94b, 0xf956, 0xf960, 0xf96b, 0xf976, 0xf980,
+0xf98b, 0xf995, 0xf9a0, 0xf9aa, 0xf9b5, 0xf9c0,
+0xf9ca, 0xf9d5, 0xf9df, 0xf9ea, 0xf9f4, 0xf9ff,
+0xfa0a, 0xfa14, 0xfa1f, 0xfa29, 0xfa34, 0xfa3e,
+0xfa49, 0xfa53, 0xfa5e, 0xfa69, 0xfa73, 0xfa7e,
+0xfa88, 0xfa93, 0xfa9d, 0xfaa8, 0xfab2, 0xfabd,
+0xfac7, 0xfad2, 0xfadc, 0xfae7, 0xfaf1, 0xfafc,
+0xfb06, 0xfb11, 0xfb1b, 0xfb26, 0xfb30, 0xfb3b,
+0xfb45, 0xfb50, 0xfb5a, 0xfb65, 0xfb6f, 0xfb7a,
+0xfb84, 0xfb8f, 0xfb99, 0xfba4, 0xfbae, 0xfbb8,
+0xfbc3, 0xfbcd, 0xfbd8, 0xfbe2, 0xfbed, 0xfbf7,
+0xfc02, 0xfc0c, 0xfc16, 0xfc21, 0xfc2b, 0xfc36,
+0xfc40, 0xfc4b, 0xfc55, 0xfc5f, 0xfc6a, 0xfc74,
+0xfc7f, 0xfc89, 0xfc93, 0xfc9e, 0xfca8, 0xfcb3,
+0xfcbd, 0xfcc7, 0xfcd2, 0xfcdc, 0xfce7, 0xfcf1,
+0xfcfb, 0xfd06, 0xfd10, 0xfd1a, 0xfd25, 0xfd2f,
+0xfd3a, 0xfd44, 0xfd4e, 0xfd59, 0xfd63, 0xfd6d,
+0xfd78, 0xfd82, 0xfd8c, 0xfd97, 0xfda1, 0xfdab,
+0xfdb6, 0xfdc0, 0xfdca, 0xfdd5, 0xfddf, 0xfde9,
+0xfdf4, 0xfdfe, 0xfe08, 0xfe13, 0xfe1d, 0xfe27,
+0xfe32, 0xfe3c, 0xfe46, 0xfe50, 0xfe5b, 0xfe65,
+0xfe6f, 0xfe7a, 0xfe84, 0xfe8e, 0xfe98, 0xfea3,
+0xfead, 0xfeb7, 0xfec1, 0xfecc, 0xfed6, 0xfee0,
+0xfeeb, 0xfef5, 0xfeff, 0xff09, 0xff14, 0xff1e,
+0xff28, 0xff32, 0xff3c, 0xff47, 0xff51, 0xff5b,
+0xff65, 0xff70, 0xff7a, 0xff84, 0xff8e, 0xff98,
+0xffa3, 0xffad, 0xffb7, 0xffc1, 0xffcc, 0xffd6,
+0xffe0, 0xffea, 0xfff4, 0xffff
+};
+
+// max value is pi/4
+constexpr double SCALING_FACTOR = 4. / M_PI * 0xFFFF;
+
+inline double atan2_lookup(double y, double x)
+{
+ if (std::abs(x) < std::numeric_limits<double>::epsilon())
+ {
+ if (y >= 0.)
+ {
+ return M_PI / 2.;
+ }
+ else
+ {
+ return -M_PI / 2.;
+ }
+ }
+
+ unsigned octant = 0;
+
+ if (x < 0.)
+ {
+ octant = 1;
+ x = -x;
+ }
+ if (y < 0.)
+ {
+ octant |= 2;
+ y = -y;
+ }
+
+ double t = y / x;
+ if (t > 1.0)
+ {
+ octant |= 4;
+ t = 1.0 / t;
+ }
+
+ double angle = atan_table[(unsigned)(t * 4095)] / SCALING_FACTOR;
+
+ switch (octant)
+ {
+ case 0:
+ break;
+ case 1:
+ angle = M_PI - angle;
+ break;
+ case 2:
+ angle = -angle;
+ break;
+ case 3:
+ angle = -M_PI + angle;
+ break;
+ case 4:
+ angle = M_PI / 2.0 - angle;
+ break;
+ case 5:
+ angle = M_PI / 2.0 + angle;
+ break;
+ case 6:
+ angle = -M_PI / 2.0 + angle;
+ break;
+ case 7:
+ angle = -M_PI / 2.0 - angle;
+ break;
+ }
+ return angle;
+}
+
+#endif // TRIGONOMETRY_TABLES_H
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..7d6f835
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,67 @@
+environment:
+ matrix:
+ - configuration: Debug
+ - configuration: Release
+
+# branches to build
+branches:
+ # whitelist
+ only:
+ - develop
+
+# Operating system (build VM template)
+os: Windows Server 2012 R2
+
+# scripts that are called at very beginning, before repo cloning
+init:
+ - git config --global core.autocrlf input
+
+# clone directory
+clone_folder: c:\projects\osrm
+
+platform: x64
+
+install:
+ # by default, all script lines are interpreted as batch
+ - cd c:\projects\osrm
+ - curl -O http://build.project-osrm.org/libs_osrm_%Configuration%.7z
+ - 7z x libs_osrm_%Configuration%.7z | find ":"
+
+build_script:
+ - cd c:/projects/osrm
+ - mkdir build
+ - cd build
+ - echo Running cmake...
+ - call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
+ - SET P=c:/projects/osrm
+ - set TBB_INSTALL_DIR=%P%/tbb
+ - set TBB_ARCH_PLATFORM=intel64/vc12
+ - cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%Configuration% -DBZIP2_INCLUDE_DIR=%P%/libs/include -DBZIP2_LIBRARIES=%P%/libs/lib/libbz2.lib -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_USE_STATIC_LIBS=ON
+ - nmake
+ - if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip *.exe *.pdb %P%/libs/bin/*.dll -tzip)
+
+test: off
+
+artifacts:
+ - path: osrm_Debug.zip
+ name: osrm_Debug.zip
+ - path: osrm_Release.zip
+ name: osrm_Release.zip
+
+deploy:
+ provider: FTP
+ server:
+ secure: ef7oiQTTXFGt8NdNiOHm/uRFVrUttzyFbIlnaeHhQvw=
+ username:
+ secure: Bw+Se2GTJxA6+GtRkEc//tQSBHOuFIuJHBjFwR9cD+8=
+ password:
+ secure: eqwESZqxMXC/j5mOCpaXuw==
+ folder: /
+ enable_ssl: true
+ active_mode: false
+
+# notifications:
+# - provider: HipChat
+# auth_token:
+# secure: boLE7BjcahdIUxv9jkN7U3F8iOASF+MkhtctlVoWJoo=
+# room: Directions
diff --git a/cmake/CheckCXXCompilerFlag.cmake b/cmake/CheckCXXCompilerFlag.cmake
new file mode 100644
index 0000000..e396f75
--- /dev/null
+++ b/cmake/CheckCXXCompilerFlag.cmake
@@ -0,0 +1,29 @@
+# - Check whether the CXX compiler supports a given flag.
+# CHECK_CXX_COMPILER_FLAG(<flag> <var>)
+# <flag> - the compiler flag
+# <var> - variable to store the result
+# This internally calls the check_cxx_source_compiles macro. See help
+# for CheckCXXSourceCompiles for a listing of variables that can
+# modify the build.
+
+# Copyright (c) 2006, Alexander Neundorf, <neundorf at kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+INCLUDE(CheckCXXSourceCompiles)
+
+MACRO (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
+ SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
+ SET(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
+ CHECK_CXX_SOURCE_COMPILES("int main() { return 0;}" ${_RESULT}
+ # Some compilers do not fail with a bad flag
+ FAIL_REGEX "unrecognized .*option" # GNU
+ FAIL_REGEX "ignoring unknown option" # MSVC
+ FAIL_REGEX "[Uu]nknown option" # HP
+ FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro
+ FAIL_REGEX "command option .* is not recognized" # XL
+ )
+ SET (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
+ENDMACRO (CHECK_CXX_COMPILER_FLAG)
diff --git a/cmake/FindLua52.cmake b/cmake/FindLua52.cmake
new file mode 100644
index 0000000..d17fbf6
--- /dev/null
+++ b/cmake/FindLua52.cmake
@@ -0,0 +1,82 @@
+# Locate Lua library
+# This module defines
+# LUA52_FOUND, if false, do not try to link to Lua
+# LUA_LIBRARIES
+# LUA_INCLUDE_DIR, where to find lua.h
+# LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
+#
+# Note that the expected include convention is
+# #include "lua.h"
+# and not
+# #include <lua/lua.h>
+# This is because, the lua location is not standardized and may exist
+# in locations other than lua/
+
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+# Copyright 2013 for Project-OSRM, Lua5.1 => Lua5.2
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+find_path(LUA_INCLUDE_DIR lua.h
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES include/lua52 include/lua5.2 include/lua-5.2 include/lua include
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+)
+
+find_library(LUA_LIBRARY
+ NAMES lua52 lua5.2 lua-5.2 lua
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES lib
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+)
+
+if(LUA_LIBRARY)
+ # include the math library for Unix
+ if(UNIX AND NOT APPLE AND NOT BEOS)
+ find_library(LUA_MATH_LIBRARY m)
+ set( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
+ # For Windows and Mac, don't need to explicitly include the math library
+ else()
+ set( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries")
+ endif()
+endif()
+
+if(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h")
+ file(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"")
+
+ string(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}")
+ unset(lua_version_str)
+endif()
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua52
+ REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
+ VERSION_VAR LUA_VERSION_STRING)
+
+mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY)
+
diff --git a/cmake/FindLuaJIT.cmake b/cmake/FindLuaJIT.cmake
new file mode 100644
index 0000000..5d5e6ac
--- /dev/null
+++ b/cmake/FindLuaJIT.cmake
@@ -0,0 +1,93 @@
+# Locate Lua library
+# This module defines
+# LUAJIT_FOUND, if false, do not try to link to Lua
+# LUAJIT_LIBRARIES
+# LUAJIT_INCLUDE_DIR, where to find lua.h
+#
+# Note that the expected include convention is
+# #include "lua.h"
+# and not
+# #include <lua/lua.h>
+# This is because, the lua location is not standardized and may exist
+# in locations other than lua/
+
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+# License text for the above reference.)
+#
+# ################
+# 2010 - modified for cronkite to find luajit instead of lua, as it was before.
+#
+
+if ( NOT LuaJIT_FIND_VERSION )
+ MESSAGE(FATAL_ERROR "You need to specify a version of libluajit to use")
+ENDIF()
+
+IF( NOT LUAJIT_FIND_QUIETLY )
+ MESSAGE(STATUS "Looking for LuaJIT ${LuaJIT_FIND_VERSION}")
+ENDIF()
+
+FIND_PATH(LUAJIT_INCLUDE_DIR lua.h
+ HINTS
+ $ENV{LUAJIT_DIR}
+ PATH_SUFFIXES include/luajit-2.0 include/luajit2.0 include/luajit include
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+)
+
+FIND_LIBRARY(LUAJIT_LIBRARY
+ NAMES luajit-${LuaJIT_FIND_VERSION_MAJOR}${LuaJIT_FIND_VERSION_MINOR} luajit-${LuaJIT_FIND_VERSION}
+ HINTS
+ $ENV{LUAJIT_DIR}
+ PATH_SUFFIXES lib64 lib
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+)
+
+IF(LUAJIT_LIBRARY)
+ # include the math library for Unix
+ IF(UNIX AND NOT APPLE)
+ FIND_LIBRARY(LUAJIT_MATH_LIBRARY m)
+ SET( LUAJIT_LIBRARIES "${LUAJIT_LIBRARY};${LUAJIT_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
+ # For Windows and Mac, don't need to explicitly include the math library
+ ELSE(UNIX AND NOT APPLE)
+ SET( LUAJIT_LIBRARIES "${LUAJIT_LIBRARY}" CACHE STRING "Lua Libraries")
+ ENDIF(UNIX AND NOT APPLE)
+ENDIF(LUAJIT_LIBRARY)
+
+INCLUDE(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LUAJIT_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LUAJIT DEFAULT_MSG LUAJIT_LIBRARIES LUAJIT_INCLUDE_DIR)
+
+IF( NOT LUAJIT_FIND_QUIETLY )
+ IF( LUAJIT_FOUND AND LUAJIT_LIBRARIES)
+ MESSAGE(STATUS "Found LuaJIT: ${LUAJIT_LIBRARY}" )
+ MARK_AS_ADVANCED(LUAJIT_INCLUDE_DIR LUAJIT_LIBRARIES LUAJIT_LIBRARY LUAJIT_MATH_LIBRARY)
+ ELSE()
+ SET ( LUAJIT_FOUND FALSE )
+ ENDIF()
+ENDIF()
diff --git a/cmake/FindLuabind.cmake b/cmake/FindLuabind.cmake
index 39b3250..4b99b3c 100644
--- a/cmake/FindLuabind.cmake
+++ b/cmake/FindLuabind.cmake
@@ -27,7 +27,7 @@ FIND_PATH(LUABIND_INCLUDE_DIR luabind.hpp
)
FIND_LIBRARY(LUABIND_LIBRARY
- NAMES luabind
+ NAMES luabind luabind09
HINTS
$ENV{LUABIND_DIR}
PATH_SUFFIXES lib64 lib
@@ -72,4 +72,4 @@ IF( NOT LUABIND_FIND_QUIETLY )
ENDIF()
ENDIF()
-MARK_AS_ADVANCED(LUABIND_INCLUDE_DIR LUABIND_LIBRARIES LUABIND_LIBRARY LUABIND_LIBRARY_DBG)
+MARK_AS_ADVANCED(LUABIND_INCLUDE_DIR LUABIND_LIBRARIES LUABIND_LIBRARY LUABIND_LIBRARY_DBG)
diff --git a/cmake/FindSTXXL.cmake b/cmake/FindSTXXL.cmake
index 52d508c..76a2722 100644
--- a/cmake/FindSTXXL.cmake
+++ b/cmake/FindSTXXL.cmake
@@ -48,4 +48,4 @@ IF( NOT STXXL_FIND_QUIETLY )
ENDIF()
ENDIF()
-MARK_AS_ADVANCED(STXXL_INCLUDE_DIR STXXL_LIBRARY)
+MARK_AS_ADVANCED(STXXL_INCLUDE_DIR STXXL_LIBRARY)
diff --git a/cmake/FindTBB.cmake b/cmake/FindTBB.cmake
new file mode 100644
index 0000000..f9e3e0f
--- /dev/null
+++ b/cmake/FindTBB.cmake
@@ -0,0 +1,283 @@
+# Locate Intel Threading Building Blocks include paths and libraries
+# FindTBB.cmake can be found at https://code.google.com/p/findtbb/
+# Written by Hannes Hofmann <hannes.hofmann _at_ informatik.uni-erlangen.de>
+# Improvements by Gino van den Bergen <gino _at_ dtecta.com>,
+# Florian Uhlig <F.Uhlig _at_ gsi.de>,
+# Jiri Marsik <jiri.marsik89 _at_ gmail.com>
+
+# The MIT License
+#
+# Copyright (c) 2011 Hannes Hofmann
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler.
+# e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21"
+# TBB_ARCH_PLATFORM is set by the build script tbbvars[.bat|.sh|.csh], which can be found
+# in the TBB installation directory (TBB_INSTALL_DIR).
+#
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+#
+# For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER.
+# TBB_ARCHITECTURE [ ia32 | em64t | itanium ]
+# which architecture to use
+# TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9
+# which compiler to use (detected automatically on Windows)
+
+# This module respects
+# TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR}
+
+# This module defines
+# TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc.
+# TBB_LIBRARY_DIRS, where to find libtbb, libtbbmalloc
+# TBB_DEBUG_LIBRARY_DIRS, where to find libtbb_debug, libtbbmalloc_debug
+# TBB_INSTALL_DIR, the base TBB install directory
+# TBB_LIBRARIES, the libraries to link against to use TBB.
+# TBB_DEBUG_LIBRARIES, the libraries to link against to use TBB with debug symbols.
+# TBB_FOUND, If false, don't try to use TBB.
+# TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h
+
+
+if (WIN32)
+ # has em64t/vc8 em64t/vc9
+ # has ia32/vc7.1 ia32/vc8 ia32/vc9
+ set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB")
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ if (MSVC71)
+ set (_TBB_COMPILER "vc7.1")
+ endif(MSVC71)
+ if (MSVC80)
+ set(_TBB_COMPILER "vc8")
+ endif(MSVC80)
+ if (MSVC90)
+ set(_TBB_COMPILER "vc9")
+ endif(MSVC90)
+ if(MSVC10)
+ set(_TBB_COMPILER "vc10")
+ endif(MSVC10)
+ # Todo: add other Windows compilers such as ICL.
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+endif (WIN32)
+
+if (UNIX)
+ if (APPLE)
+ # MAC
+ set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions")
+ # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ # default flavor on apple: ia32/cc4.0.1_os10.4.9
+ # Jiri: There is no reason to presume there is only one flavor and
+ # that user's setting of variables should be ignored.
+ if(NOT TBB_COMPILER)
+ set(_TBB_COMPILER "cc4.0.1_os10.4.9")
+ elseif (NOT TBB_COMPILER)
+ set(_TBB_COMPILER ${TBB_COMPILER})
+ endif(NOT TBB_COMPILER)
+ if(NOT TBB_ARCHITECTURE)
+ set(_TBB_ARCHITECTURE "ia32")
+ elseif(NOT TBB_ARCHITECTURE)
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+ endif(NOT TBB_ARCHITECTURE)
+ else (APPLE)
+ # LINUX
+ set(_TBB_DEFAULT_INSTALL_DIR "/opt/intel/tbb" "/usr/local/include" "/usr/include")
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21
+ # has ia32/*
+ # has itanium/*
+ set(_TBB_COMPILER ${TBB_COMPILER})
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+ endif (APPLE)
+endif (UNIX)
+
+if (CMAKE_SYSTEM MATCHES "SunOS.*")
+# SUN
+# not yet supported
+# has em64t/cc3.4.3_kernel5.10
+# has ia32/*
+endif (CMAKE_SYSTEM MATCHES "SunOS.*")
+
+
+#-- Clear the public variables
+set (TBB_FOUND "NO")
+
+
+#-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR}
+# first: use CMake variable TBB_INSTALL_DIR
+if (TBB_INSTALL_DIR)
+ set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR})
+endif (TBB_INSTALL_DIR)
+# second: use environment variable
+if (NOT _TBB_INSTALL_DIR)
+ if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR})
+ endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+ # Intel recommends setting TBB21_INSTALL_DIR
+ if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR})
+ endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+ if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR})
+ endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+ if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR})
+ endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+endif (NOT _TBB_INSTALL_DIR)
+# third: try to find path automatically
+if (NOT _TBB_INSTALL_DIR)
+ if (_TBB_DEFAULT_INSTALL_DIR)
+ set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR})
+ endif (_TBB_DEFAULT_INSTALL_DIR)
+endif (NOT _TBB_INSTALL_DIR)
+# sanity check
+if (NOT _TBB_INSTALL_DIR)
+ message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}")
+else (NOT _TBB_INSTALL_DIR)
+# finally: set the cached CMake variable TBB_INSTALL_DIR
+if (NOT TBB_INSTALL_DIR)
+ set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory")
+ mark_as_advanced(TBB_INSTALL_DIR)
+endif (NOT TBB_INSTALL_DIR)
+
+
+#-- A macro to rewrite the paths of the library. This is necessary, because
+# find_library() always found the em64t/vc9 version of the TBB libs
+macro(TBB_CORRECT_LIB_DIR var_name)
+# if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+ string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+# endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+ string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+ string(REPLACE vc7.1 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc8 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc9 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc10 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+endmacro(TBB_CORRECT_LIB_DIR var_content)
+
+
+#-- Look for include directory and set ${TBB_INCLUDE_DIR}
+set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include)
+# Jiri: tbbvars now sets the CPATH environment variable to the directory
+# containing the headers.
+find_path(TBB_INCLUDE_DIR
+ tbb/task_scheduler_init.h
+ PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH
+)
+mark_as_advanced(TBB_INCLUDE_DIR)
+
+
+#-- Look for libraries
+# GvdB: $ENV{TBB_ARCH_PLATFORM} is set by the build script tbbvars[.bat|.sh|.csh]
+if (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "")
+ set (_TBB_LIBRARY_DIR
+ ${_TBB_INSTALL_DIR}/lib/$ENV{TBB_ARCH_PLATFORM}
+ ${_TBB_INSTALL_DIR}/$ENV{TBB_ARCH_PLATFORM}/lib
+ )
+endif (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "")
+# Jiri: This block isn't mutually exclusive with the previous one
+# (hence no else), instead I test if the user really specified
+# the variables in question.
+if ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL ""))
+ # HH: deprecated
+ message(STATUS "[Warning] FindTBB.cmake: The use of TBB_ARCHITECTURE and TBB_COMPILER is deprecated and may not be supported in future versions. Please set \$ENV{TBB_ARCH_PLATFORM} (using tbbvars.[bat|csh|sh]).")
+ # Jiri: It doesn't hurt to look in more places, so I store the hints from
+ # ENV{TBB_ARCH_PLATFORM} and the TBB_ARCHITECTURE and TBB_COMPILER
+ # variables and search them both.
+ set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}/lib" ${_TBB_LIBRARY_DIR})
+endif ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL ""))
+
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib)
+
+# Jiri: No reason not to check the default paths. From recent versions,
+# tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH
+# variables, which now point to the directories of the lib files.
+# It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS
+# argument instead of the implicit PATHS as it isn't hard-coded
+# but computed by system introspection. Searching the LIBRARY_PATH
+# and LD_LIBRARY_PATH environment variables is now even more important
+# that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates
+# the use of TBB built from sources.
+find_library(TBB_LIBRARY ${_TBB_LIB_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY ${_TBB_LIB_MALLOC_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+#Extract path from TBB_LIBRARY name
+get_filename_component(TBB_LIBRARY_DIR ${TBB_LIBRARY} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY)
+mark_as_advanced(TBB_LIBRARY TBB_MALLOC_LIBRARY)
+
+#-- Look for debug libraries
+# Jiri: Changed the same way as for the release libraries.
+find_library(TBB_LIBRARY_DEBUG ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+# Jiri: Self-built TBB stores the debug libraries in a separate directory.
+# Extract path from TBB_LIBRARY_DEBUG name
+get_filename_component(TBB_LIBRARY_DEBUG_DIR ${TBB_LIBRARY_DEBUG} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY_DEBUG)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY_DEBUG)
+mark_as_advanced(TBB_LIBRARY_DEBUG TBB_MALLOC_LIBRARY_DEBUG)
+
+
+if (TBB_INCLUDE_DIR)
+ if (TBB_LIBRARY)
+ set (TBB_FOUND "YES")
+ set (TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY} ${TBB_LIBRARIES})
+ set (TBB_DEBUG_LIBRARIES ${TBB_LIBRARY_DEBUG} ${TBB_MALLOC_LIBRARY_DEBUG} ${TBB_DEBUG_LIBRARIES})
+ set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE)
+ set (TBB_LIBRARY_DIRS ${TBB_LIBRARY_DIR} CACHE PATH "TBB library directory" FORCE)
+ # Jiri: Self-built TBB stores the debug libraries in a separate directory.
+ set (TBB_DEBUG_LIBRARY_DIRS ${TBB_LIBRARY_DEBUG_DIR} CACHE PATH "TBB debug library directory" FORCE)
+ mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARY_DIRS TBB_DEBUG_LIBRARY_DIRS TBB_LIBRARIES TBB_DEBUG_LIBRARIES)
+ message(STATUS "Found Intel TBB")
+ endif (TBB_LIBRARY)
+endif (TBB_INCLUDE_DIR)
+
+if (NOT TBB_FOUND)
+ message("ERROR: Intel TBB NOT found!")
+ message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}")
+ # do only throw fatal, if this pkg is REQUIRED
+ if (TBB_FIND_REQUIRED)
+ message(FATAL_ERROR "Could NOT find TBB library.")
+ endif (TBB_FIND_REQUIRED)
+endif (NOT TBB_FOUND)
+
+endif (NOT _TBB_INSTALL_DIR)
+
+if (TBB_FOUND)
+ set(TBB_INTERFACE_VERSION 0)
+ FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS)
+ STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}")
+ set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}")
+endif (TBB_FOUND)
diff --git a/cmake/FingerPrint-Config.cmake b/cmake/FingerPrint-Config.cmake
new file mode 100644
index 0000000..7b45d5c
--- /dev/null
+++ b/cmake/FingerPrint-Config.cmake
@@ -0,0 +1,10 @@
+set(OLDFILE ${SOURCE_DIR}/Util/FingerPrint.cpp)
+if (EXISTS ${OLDFILE})
+ file(REMOVE_RECURSE ${OLDFILE})
+endif()
+file(MD5 ${SOURCE_DIR}/prepare.cpp MD5PREPARE)
+file(MD5 ${SOURCE_DIR}/DataStructures/StaticRTree.h MD5RTREE)
+file(MD5 ${SOURCE_DIR}/Util/GraphLoader.h MD5GRAPH)
+file(MD5 ${SOURCE_DIR}/Server/DataStructures/InternalDataFacade.h MD5OBJECTS)
+
+CONFIGURE_FILE( ${SOURCE_DIR}/Util/FingerPrint.cpp.in ${SOURCE_DIR}/Util/FingerPrint.cpp )
diff --git a/cmake/GetGitRevisionDescription.cmake.in b/cmake/GetGitRevisionDescription.cmake.in
new file mode 100644
index 0000000..888ce13
--- /dev/null
+++ b/cmake/GetGitRevisionDescription.cmake.in
@@ -0,0 +1,38 @@
+#
+# Internal file for GetGitRevisionDescription.cmake
+#
+# Requires CMake 2.6 or newer (uses the 'function' command)
+#
+# Original Author:
+# 2009-2010 Ryan Pavlik <rpavlik at iastate.edu> <abiryan at 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)
+
+set(HEAD_HASH)
+
+file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
+
+string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
+if(HEAD_CONTENTS MATCHES "ref")
+ # named branch
+ string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
+ if(EXISTS "@GIT_DIR@/${HEAD_REF}")
+ configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
+ elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
+ configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
+ set(HEAD_HASH "${HEAD_REF}")
+ endif()
+else()
+ # detached HEAD
+ configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
+endif()
+
+if(NOT HEAD_HASH)
+ file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
+ string(STRIP "${HEAD_HASH}" HEAD_HASH)
+endif()
diff --git a/cmake/cmake_options_script.py b/cmake/cmake_options_script.py
new file mode 100644
index 0000000..52e943e
--- /dev/null
+++ b/cmake/cmake_options_script.py
@@ -0,0 +1,45 @@
+# Based on @berenm's pull request https://github.com/quarnster/SublimeClang/pull/135
+# Create the database with cmake with for example: cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
+# or you could have set(CMAKE_EXPORT_COMPILE_COMMANDS ON) in your CMakeLists.txt
+# Usage within SublimeClang:
+# "sublimeclang_options_script": "python ${home}/code/cmake_options_script.py ${project_path:build}/compile_commands.json",
+
+
+import re
+import os
+import os.path
+import pickle
+import sys
+import json
+
+compilation_database_pattern = re.compile('(?<=\s)-[DIOUWfgs][^=\s]+(?:=\\"[^"]+\\"|=[^"]\S+)?')
+
+def load_db(filename):
+ compilation_database = {}
+ with open(filename) as compilation_database_file:
+ compilation_database_entries = json.load(compilation_database_file)
+
+ total = len(compilation_database_entries)
+ entry = 0
+ for compilation_entry in compilation_database_entries:
+ entry = entry + 1
+ compilation_database[compilation_entry["file"]] = [ p.strip() for p in compilation_database_pattern.findall(compilation_entry["command"]) ]
+ return compilation_database
+
+scriptpath = os.path.dirname(os.path.abspath(sys.argv[1]))
+cache_file = "%s/cached_options.txt" % (scriptpath)
+
+db = None
+if os.access(cache_file, os.R_OK) == 0:
+ db = load_db(sys.argv[1])
+ f = open(cache_file, "wb")
+ pickle.dump(db, f)
+ f.close()
+else:
+ f = open(cache_file)
+ db = pickle.load(f)
+ f.close()
+
+if db and sys.argv[2] in db:
+ for option in db[sys.argv[2]]:
+ print option
diff --git a/cmake/pkgconfig.in b/cmake/pkgconfig.in
new file mode 100644
index 0000000..e81feba
--- /dev/null
+++ b/cmake/pkgconfig.in
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+includedir=${prefix}/include/osrm
+libdir=${prefix}/lib
+
+Name: libOSRM
+Description: Project OSRM library
+Version: @GIT_DESCRIPTION@
+Requires:
+Libs: -L${libdir} -lOSRM
+Libs.private: @BOOST_LIBRARY_LISTING@
+Cflags: -I${includedir}
diff --git a/config/cucumber.yml b/config/cucumber.yml
index 5a9fa4e..2cdea36 100644
--- a/config/cucumber.yml
+++ b/config/cucumber.yml
@@ -1,5 +1,9 @@
# config/cucumber.yml
##YAML Template
---
-default: --require features
-verify: --require features --tags ~@todo --tag ~@stress -f progress
\ No newline at end of file
+default: --require features --tags ~@todo --tags ~@bug --tag ~@stress
+verify: --require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress
+jenkins: --require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress
+bugs: --require features --tags @bug
+todo: --require features --tags @todo
+all: --require features
diff --git a/contractor.ini b/contractor.ini
deleted file mode 100644
index 4da33c7..0000000
--- a/contractor.ini
+++ /dev/null
@@ -1 +0,0 @@
-Threads = 4
diff --git a/createHierarchy.cpp b/createHierarchy.cpp
deleted file mode 100644
index 5e6343d..0000000
--- a/createHierarchy.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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 "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>
-#include <cstring>
-#include <string>
-#include <vector>
-
-typedef QueryEdge::EdgeData EdgeData;
-typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
-typedef StaticGraph<EdgeData>::InputEdge StaticEdge;
-typedef BaseConfiguration ContractorConfiguration;
-
-std::vector<NodeInfo> internalToExternalNodeMapping;
-std::vector<_Restriction> inputRestrictions;
-std::vector<NodeID> bollardNodes;
-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>]");
- }
-
- double startupTime = get_timestamp();
- unsigned numberOfThreads = omp_get_num_procs();
- if(testDataFile("contractor.ini")) {
- ContractorConfiguration contractorConfig("contractor.ini");
- unsigned rawNumber = stringToInt(contractorConfig.GetParameter("Threads"));
- if(rawNumber != 0 && rawNumber <= numberOfThreads)
- numberOfThreads = rawNumber;
- }
- omp_set_num_threads(numberOfThreads);
-
- INFO("Using restrictions from file: " << argv[2]);
- std::ifstream restrictionsInstream(argv[2], std::ios::binary);
- if(!restrictionsInstream.good()) {
- ERR("Could not access <osrm-restrictions> files");
- }
- _Restriction restriction;
- unsigned usableRestrictionsCounter(0);
- restrictionsInstream.read((char*)&usableRestrictionsCounter, sizeof(unsigned));
- inputRestrictions.resize(usableRestrictionsCounter);
- restrictionsInstream.read((char *)&(inputRestrictions[0]), usableRestrictionsCounter*sizeof(_Restriction));
- restrictionsInstream.close();
-
- std::ifstream in;
- in.open (argv[1], std::ifstream::in | std::ifstream::binary);
- if (!in.is_open()) {
- ERR("Cannot open " << argv[1]);
- }
-
- std::string nodeOut(argv[1]); nodeOut += ".nodes";
- std::string edgeOut(argv[1]); edgeOut += ".edges";
- std::string graphOut(argv[1]); graphOut += ".hsgr";
- std::string 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") )) {
- ERR("Need profile.lua to apply traffic signal penalty");
- }
-
- // Create a new lua state
- lua_State *myLuaState = luaL_newstate();
-
- // Connect LuaBind to this lua state
- luabind::open(myLuaState);
-
- //open utility libraries string library;
- luaL_openlibs(myLuaState);
-
- //adjust lua load path
- luaAddScriptFolderToLoadPath( myLuaState, (argc > 3 ? argv[3] : "profile.lua") );
-
- // Now call our function in a lua script
- INFO("Parsing speedprofile from " << (argc > 3 ? argv[3] : "profile.lua") );
- if(0 != luaL_dofile(myLuaState, (argc > 3 ? argv[3] : "profile.lua") )) {
- ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
- }
-
- EdgeBasedGraphFactory::SpeedProfileProperties speedProfile;
-
- if(0 != luaL_dostring( myLuaState, "return traffic_signal_penalty\n")) {
- ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
- }
- speedProfile.trafficSignalPenalty = 10*lua_tointeger(myLuaState, -1);
-
- if(0 != luaL_dostring( myLuaState, "return u_turn_penalty\n")) {
- ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
- }
- speedProfile.uTurnPenalty = 10*lua_tointeger(myLuaState, -1);
-
- speedProfile.has_turn_penalty_function = lua_function_exists( myLuaState, "turn_function" );
-
- std::vector<ImportEdge> edgeList;
- NodeID nodeBasedNodeNumber = readBinaryOSRMGraphFromStream(in, edgeList, bollardNodes, trafficLightNodes, &internalToExternalNodeMapping, inputRestrictions);
- in.close();
- INFO(inputRestrictions.size() << " restrictions, " << bollardNodes.size() << " bollard nodes, " << trafficLightNodes.size() << " traffic lights");
- if(0 == edgeList.size())
- ERR("The input data is broken. It is impossible to do any turns in this graph");
-
-
- /***
- * Building an edge-expanded graph from node-based input an turn restrictions
- */
-
- INFO("Generating edge-expanded graph representation");
- EdgeBasedGraphFactory * edgeBasedGraphFactory = new EdgeBasedGraphFactory (nodeBasedNodeNumber, edgeList, bollardNodes, trafficLightNodes, inputRestrictions, internalToExternalNodeMapping, speedProfile);
- std::vector<ImportEdge>().swap(edgeList);
- edgeBasedGraphFactory->Run(edgeOut.c_str(), myLuaState);
- std::vector<_Restriction>().swap(inputRestrictions);
- std::vector<NodeID>().swap(bollardNodes);
- std::vector<NodeID>().swap(trafficLightNodes);
- NodeID edgeBasedNodeNumber = edgeBasedGraphFactory->GetNumberOfNodes();
- DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
- edgeBasedGraphFactory->GetEdgeBasedEdges(edgeBasedEdgeList);
- std::vector<EdgeBasedGraphFactory::EdgeBasedNode> nodeBasedEdgeList;
- edgeBasedGraphFactory->GetEdgeBasedNodes(nodeBasedEdgeList);
- delete edgeBasedGraphFactory;
-
- /***
- * Writing info on original (node-based) nodes
- */
-
- INFO("writing node map ...");
- std::ofstream mapOutFile(nodeOut.c_str(), std::ios::binary);
- mapOutFile.write((char *)&(internalToExternalNodeMapping[0]), internalToExternalNodeMapping.size()*sizeof(NodeInfo));
- mapOutFile.close();
- std::vector<NodeInfo>().swap(internalToExternalNodeMapping);
-
- double expansionHasFinishedTime = get_timestamp() - startupTime;
-
- /***
- * Building grid-like nearest-neighbor data structure
- */
-
- INFO("building r-tree ...");
- StaticRTree<EdgeBasedGraphFactory::EdgeBasedNode> * rtree =
- new StaticRTree<EdgeBasedGraphFactory::EdgeBasedNode>(
- nodeBasedEdgeList,
- rtree_nodes_path.c_str(),
- rtree_leafs_path.c_str()
- );
- delete rtree;
- IteratorbasedCRC32<std::vector<EdgeBasedGraphFactory::EdgeBasedNode> > crc32;
- unsigned crc32OfNodeBasedEdgeList = crc32(nodeBasedEdgeList.begin(), nodeBasedEdgeList.end() );
- nodeBasedEdgeList.clear();
- INFO("CRC32 based checksum is " << crc32OfNodeBasedEdgeList);
-
- /***
- * Contracting the edge-expanded graph
- */
-
- INFO("initializing contractor");
- Contractor* contractor = new Contractor( edgeBasedNodeNumber, edgeBasedEdgeList );
- double contractionStartedTimestamp(get_timestamp());
- contractor->Run();
- INFO("Contraction took " << get_timestamp() - contractionStartedTimestamp << " sec");
-
- DeallocatingVector< QueryEdge > contractedEdgeList;
- contractor->GetEdges( contractedEdgeList );
- delete contractor;
-
- /***
- * Sorting contracted edges in a way that the static query graph can read some in in-place.
- */
-
- INFO("Building Node Array");
- std::sort(contractedEdgeList.begin(), contractedEdgeList.end());
- unsigned numberOfNodes = 0;
- unsigned numberOfEdges = contractedEdgeList.size();
- INFO("Serializing compacted graph of " << numberOfEdges << " edges");
- std::ofstream edgeOutFile(graphOut.c_str(), std::ios::binary);
-
- BOOST_FOREACH(const QueryEdge & edge, contractedEdgeList) {
- if(edge.source > numberOfNodes) {
- numberOfNodes = edge.source;
- }
- if(edge.target > numberOfNodes) {
- numberOfNodes = edge.target;
- }
- }
- numberOfNodes+=1;
-
- std::vector< StaticGraph<EdgeData>::_StrNode > _nodes;
- _nodes.resize( numberOfNodes + 1 );
-
- StaticGraph<EdgeData>::EdgeIterator edge = 0;
- StaticGraph<EdgeData>::EdgeIterator position = 0;
- for ( StaticGraph<EdgeData>::NodeIterator node = 0; node <= numberOfNodes; ++node ) {
- StaticGraph<EdgeData>::EdgeIterator lastEdge = edge;
- while ( edge < numberOfEdges && contractedEdgeList[edge].source == node )
- ++edge;
- _nodes[node].firstEdge = position; //=edge
- position += edge - lastEdge; //remove
- }
- ++numberOfNodes;
- //Serialize numberOfNodes, nodes
- edgeOutFile.write((char*) &crc32OfNodeBasedEdgeList, sizeof(unsigned));
- edgeOutFile.write((char*) &numberOfNodes, sizeof(unsigned));
- edgeOutFile.write((char*) &_nodes[0], sizeof(StaticGraph<EdgeData>::_StrNode)*(numberOfNodes));
- //Serialize number of Edges
- edgeOutFile.write((char*) &position, sizeof(unsigned));
- --numberOfNodes;
- edge = 0;
- int usedEdgeCounter = 0;
- StaticGraph<EdgeData>::_StrEdge currentEdge;
- for ( StaticGraph<EdgeData>::NodeIterator node = 0; node < numberOfNodes; ++node ) {
- for ( StaticGraph<EdgeData>::EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) {
- assert(node != contractedEdgeList[edge].target);
- currentEdge.target = contractedEdgeList[edge].target;
- currentEdge.data = contractedEdgeList[edge].data;
- if(currentEdge.data.distance <= 0) {
- INFO("Edge: " << i << ",source: " << contractedEdgeList[edge].source << ", target: " << contractedEdgeList[edge].target << ", dist: " << currentEdge.data.distance);
- ERR("Failed at edges of node " << node << " of " << numberOfNodes);
- }
- //Serialize edges
- edgeOutFile.write((char*) ¤tEdge, sizeof(StaticGraph<EdgeData>::_StrEdge));
- ++edge;
- ++usedEdgeCounter;
- }
- }
- double endTime = (get_timestamp() - startupTime);
- INFO("Expansion : " << (nodeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< (edgeBasedNodeNumber/expansionHasFinishedTime) << " edges/sec");
- INFO("Contraction: " << (edgeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< usedEdgeCounter/endTime << " edges/sec");
-
- edgeOutFile.close();
- //cleanedEdgeList.clear();
- _nodes.clear();
- INFO("finished preprocessing");
- } catch (std::exception &e) {
- ERR("Exception occured: " << e.what());
- }
- return 0;
-}
diff --git a/datastore.cpp b/datastore.cpp
new file mode 100644
index 0000000..10d5bf5
--- /dev/null
+++ b/datastore.cpp
@@ -0,0 +1,575 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include "DataStructures/OriginalEdgeData.h"
+#include "DataStructures/RangeTable.h"
+#include "DataStructures/QueryEdge.h"
+#include "DataStructures/SharedMemoryFactory.h"
+#include "DataStructures/SharedMemoryVectorWrapper.h"
+#include "DataStructures/StaticGraph.h"
+#include "DataStructures/StaticRTree.h"
+#include "DataStructures/TurnInstructions.h"
+#include "Server/DataStructures/BaseDataFacade.h"
+#include "Server/DataStructures/SharedDataType.h"
+#include "Server/DataStructures/SharedBarriers.h"
+#include "Util/BoostFileSystemFix.h"
+#include "Util/DataStoreOptions.h"
+#include "Util/SimpleLogger.h"
+#include "Util/FingerPrint.h"
+#include "typedefs.h"
+
+#include <osrm/Coordinate.h>
+
+typedef BaseDataFacade<QueryEdge::EdgeData>::RTreeLeaf RTreeLeaf;
+typedef StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>::TreeNode RTreeNode;
+typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;
+
+#ifdef __linux__
+#include <sys/mman.h>
+#endif
+
+#include <boost/filesystem/fstream.hpp>
+#include <boost/iostreams/seek.hpp>
+
+#include <cstdint>
+
+#include <fstream>
+#include <string>
+
+int main(const int argc, const char *argv[])
+{
+ LogPolicy::GetInstance().Unmute();
+ SharedBarriers barrier;
+
+#ifdef __linux__
+ const bool lock_flags = MCL_CURRENT | MCL_FUTURE;
+ if (-1 == mlockall(lock_flags))
+ {
+ SimpleLogger().Write(logWARNING) << "Process " << argv[0] << " could not request RAM lock";
+ }
+#endif
+
+ try
+ {
+ try
+ {
+ boost::interprocess::scoped_lock<boost::interprocess::named_mutex> pending_lock(
+ barrier.pending_update_mutex);
+ }
+ catch (...)
+ {
+ // hard unlock in case of any exception.
+ barrier.pending_update_mutex.unlock();
+ }
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
+ }
+
+ try
+ {
+ SimpleLogger().Write(logDEBUG) << "Checking input parameters";
+
+ ServerPaths server_paths;
+ bool springclean = false;
+ if (!GenerateDataStoreOptions(argc, argv, server_paths, springclean))
+ {
+ return 0;
+ }
+ if (springclean)
+ {
+ SimpleLogger().Write() << "spring-cleaning all shared memory regions";
+ // find all existing shmem regions and remove them.
+ if (SharedMemory::RegionExists(DATA_1) && !SharedMemory::Remove(DATA_1))
+ {
+ SimpleLogger().Write(logWARNING) << "could not delete DATA_1";
+ }
+ if (SharedMemory::RegionExists(LAYOUT_1) && !SharedMemory::Remove(LAYOUT_1))
+ {
+ SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_1";
+ }
+ if (SharedMemory::RegionExists(DATA_2) && !SharedMemory::Remove(DATA_2))
+ {
+ SimpleLogger().Write(logWARNING) << "could not delete DATA_2";
+ }
+ if (SharedMemory::RegionExists(LAYOUT_2) && !SharedMemory::Remove(LAYOUT_2))
+ {
+ SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_2";
+ }
+ if (SharedMemory::RegionExists(CURRENT_REGIONS) &&
+ !SharedMemory::Remove(CURRENT_REGIONS))
+ {
+ SimpleLogger().Write(logWARNING) << "could not delete CURRENT_REGIONS";
+ }
+ return 0;
+ }
+
+ if (server_paths.find("hsgrdata") == server_paths.end())
+ {
+ throw OSRMException("no hsgr file found");
+ }
+ if (server_paths.find("ramindex") == server_paths.end())
+ {
+ throw OSRMException("no ram index file found");
+ }
+ if (server_paths.find("fileindex") == server_paths.end())
+ {
+ throw OSRMException("no leaf index file found");
+ }
+ if (server_paths.find("nodesdata") == server_paths.end())
+ {
+ throw OSRMException("no nodes file found");
+ }
+ if (server_paths.find("edgesdata") == server_paths.end())
+ {
+ throw OSRMException("no edges file found");
+ }
+ if (server_paths.find("namesdata") == server_paths.end())
+ {
+ throw OSRMException("no names file found");
+ }
+ if (server_paths.find("geometry") == server_paths.end())
+ {
+ throw OSRMException("no geometry file found");
+ }
+
+ ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ BOOST_ASSERT(!paths_iterator->second.empty());
+ const boost::filesystem::path &hsgr_path = paths_iterator->second;
+ paths_iterator = server_paths.find("timestamp");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ BOOST_ASSERT(!paths_iterator->second.empty());
+ const boost::filesystem::path ×tamp_path = paths_iterator->second;
+ paths_iterator = server_paths.find("ramindex");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ BOOST_ASSERT(!paths_iterator->second.empty());
+ const boost::filesystem::path &ram_index_path = paths_iterator->second;
+ paths_iterator = server_paths.find("fileindex");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ BOOST_ASSERT(!paths_iterator->second.empty());
+ const boost::filesystem::path index_file_path_absolute =
+ boost::filesystem::portable_canonical(paths_iterator->second);
+ const std::string &file_index_path = index_file_path_absolute.string();
+ paths_iterator = server_paths.find("nodesdata");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ BOOST_ASSERT(!paths_iterator->second.empty());
+ const boost::filesystem::path &nodes_data_path = paths_iterator->second;
+ paths_iterator = server_paths.find("edgesdata");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ BOOST_ASSERT(!paths_iterator->second.empty());
+ const boost::filesystem::path &edges_data_path = paths_iterator->second;
+ paths_iterator = server_paths.find("namesdata");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ BOOST_ASSERT(!paths_iterator->second.empty());
+ const boost::filesystem::path &names_data_path = paths_iterator->second;
+ paths_iterator = server_paths.find("geometry");
+ BOOST_ASSERT(server_paths.end() != paths_iterator);
+ BOOST_ASSERT(!paths_iterator->second.empty());
+ const boost::filesystem::path &geometries_data_path = paths_iterator->second;
+
+ // get the shared memory segment to use
+ bool use_first_segment = SharedMemory::RegionExists(LAYOUT_2);
+ const SharedDataType LAYOUT = [&]
+ {
+ if (use_first_segment)
+ {
+ return LAYOUT_1;
+ }
+ return LAYOUT_2;
+ }();
+ const SharedDataType DATA = [&]
+ {
+ if (use_first_segment)
+ {
+ return DATA_1;
+ }
+ return DATA_2;
+ }();
+
+ // Allocate a memory layout in shared memory, deallocate previous
+ SharedMemory *layout_memory = SharedMemoryFactory::Get(LAYOUT, sizeof(SharedDataLayout));
+ SharedDataLayout *shared_layout_ptr = static_cast<SharedDataLayout *>(layout_memory->Ptr());
+ shared_layout_ptr = new (layout_memory->Ptr()) SharedDataLayout();
+
+ shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::FILE_INDEX_PATH,
+ file_index_path.length() + 1);
+
+ // collect number of elements to store in shared memory object
+ SimpleLogger().Write() << "load names from: " << names_data_path;
+ // number of entries in name index
+ boost::filesystem::ifstream name_stream(names_data_path, std::ios::binary);
+ unsigned name_blocks = 0;
+ name_stream.read((char *)&name_blocks, sizeof(unsigned));
+ shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::NAME_OFFSETS, name_blocks);
+ shared_layout_ptr->SetBlockSize<typename RangeTable<16, true>::BlockT>(
+ SharedDataLayout::NAME_BLOCKS, name_blocks);
+ SimpleLogger().Write() << "name offsets size: " << name_blocks;
+ BOOST_ASSERT_MSG(0 != name_blocks, "name file broken");
+
+ unsigned number_of_chars = 0;
+ name_stream.read((char *)&number_of_chars, sizeof(unsigned));
+ shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::NAME_CHAR_LIST, number_of_chars);
+
+ // Loading information for original edges
+ boost::filesystem::ifstream edges_input_stream(edges_data_path, std::ios::binary);
+ unsigned number_of_original_edges = 0;
+ edges_input_stream.read((char *)&number_of_original_edges, sizeof(unsigned));
+
+ // note: settings this all to the same size is correct, we extract them from the same struct
+ shared_layout_ptr->SetBlockSize<NodeID>(SharedDataLayout::VIA_NODE_LIST,
+ number_of_original_edges);
+ shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::NAME_ID_LIST,
+ number_of_original_edges);
+ shared_layout_ptr->SetBlockSize<TurnInstruction>(SharedDataLayout::TURN_INSTRUCTION,
+ number_of_original_edges);
+ // note: there are 32 geometry indicators in one unsigned block
+ shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_INDICATORS,
+ number_of_original_edges);
+
+ boost::filesystem::ifstream hsgr_input_stream(hsgr_path, std::ios::binary);
+
+ FingerPrint fingerprint_loaded, fingerprint_orig;
+ hsgr_input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+ if (fingerprint_loaded.TestGraphUtil(fingerprint_orig))
+ {
+ SimpleLogger().Write(logDEBUG) << "Fingerprint checked out ok";
+ }
+ else
+ {
+ SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build. "
+ "Reprocess to get rid of this warning.";
+ }
+
+ // load checksum
+ unsigned checksum = 0;
+ hsgr_input_stream.read((char *)&checksum, sizeof(unsigned));
+ shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::HSGR_CHECKSUM, 1);
+ // load graph node size
+ unsigned number_of_graph_nodes = 0;
+ hsgr_input_stream.read((char *)&number_of_graph_nodes, sizeof(unsigned));
+
+ BOOST_ASSERT_MSG((0 != number_of_graph_nodes), "number of nodes is zero");
+ shared_layout_ptr->SetBlockSize<QueryGraph::NodeArrayEntry>(
+ SharedDataLayout::GRAPH_NODE_LIST, number_of_graph_nodes);
+
+ // load graph edge size
+ unsigned number_of_graph_edges = 0;
+ hsgr_input_stream.read((char *)&number_of_graph_edges, sizeof(unsigned));
+ BOOST_ASSERT_MSG(0 != number_of_graph_edges, "number of graph edges is zero");
+ shared_layout_ptr->SetBlockSize<QueryGraph::EdgeArrayEntry>(
+ SharedDataLayout::GRAPH_EDGE_LIST, number_of_graph_edges);
+
+ // load rsearch tree size
+ boost::filesystem::ifstream tree_node_file(ram_index_path, std::ios::binary);
+
+ uint32_t tree_size = 0;
+ tree_node_file.read((char *)&tree_size, sizeof(uint32_t));
+ shared_layout_ptr->SetBlockSize<RTreeNode>(SharedDataLayout::R_SEARCH_TREE, tree_size);
+
+ // load timestamp size
+ std::string m_timestamp;
+ if (boost::filesystem::exists(timestamp_path))
+ {
+ boost::filesystem::ifstream timestamp_stream(timestamp_path);
+ if (!timestamp_stream)
+ {
+ SimpleLogger().Write(logWARNING) << timestamp_path
+ << " not found. setting to default";
+ }
+ else
+ {
+ getline(timestamp_stream, m_timestamp);
+ timestamp_stream.close();
+ }
+ }
+ if (m_timestamp.empty())
+ {
+ m_timestamp = "n/a";
+ }
+ if (25 < m_timestamp.length())
+ {
+ m_timestamp.resize(25);
+ }
+ shared_layout_ptr->SetBlockSize<char>(SharedDataLayout::TIMESTAMP, m_timestamp.length());
+
+ // load coordinate size
+ boost::filesystem::ifstream nodes_input_stream(nodes_data_path, std::ios::binary);
+ unsigned coordinate_list_size = 0;
+ nodes_input_stream.read((char *)&coordinate_list_size, sizeof(unsigned));
+ shared_layout_ptr->SetBlockSize<FixedPointCoordinate>(SharedDataLayout::COORDINATE_LIST,
+ coordinate_list_size);
+
+ // load geometries sizes
+ std::ifstream geometry_input_stream(geometries_data_path.string().c_str(),
+ std::ios::binary);
+ unsigned number_of_geometries_indices = 0;
+ unsigned number_of_compressed_geometries = 0;
+
+ geometry_input_stream.read((char *)&number_of_geometries_indices, sizeof(unsigned));
+ shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_INDEX,
+ number_of_geometries_indices);
+ boost::iostreams::seek(
+ geometry_input_stream, number_of_geometries_indices * sizeof(unsigned), BOOST_IOS::cur);
+ geometry_input_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
+ shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::GEOMETRIES_LIST,
+ number_of_compressed_geometries);
+
+ // allocate shared memory block
+ SimpleLogger().Write() << "allocating shared memory of "
+ << shared_layout_ptr->GetSizeOfLayout() << " bytes";
+ SharedMemory *shared_memory =
+ SharedMemoryFactory::Get(DATA, shared_layout_ptr->GetSizeOfLayout());
+ char *shared_memory_ptr = static_cast<char *>(shared_memory->Ptr());
+
+ // read actual data into shared memory object //
+
+ // hsgr checksum
+ unsigned *checksum_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
+ shared_memory_ptr, SharedDataLayout::HSGR_CHECKSUM);
+ *checksum_ptr = checksum;
+
+ // ram index file name
+ char *file_index_path_ptr = shared_layout_ptr->GetBlockPtr<char, true>(
+ shared_memory_ptr, SharedDataLayout::FILE_INDEX_PATH);
+ // make sure we have 0 ending
+ std::fill(file_index_path_ptr,
+ file_index_path_ptr +
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::FILE_INDEX_PATH),
+ 0);
+ std::copy(file_index_path.begin(), file_index_path.end(), file_index_path_ptr);
+
+ // Loading street names
+ unsigned *name_offsets_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
+ shared_memory_ptr, SharedDataLayout::NAME_OFFSETS);
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::NAME_OFFSETS) > 0)
+ {
+ name_stream.read((char *)name_offsets_ptr,
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::NAME_OFFSETS));
+ }
+
+ unsigned *name_blocks_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
+ shared_memory_ptr, SharedDataLayout::NAME_BLOCKS);
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::NAME_BLOCKS) > 0)
+ {
+ name_stream.read((char *)name_blocks_ptr,
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::NAME_BLOCKS));
+ }
+
+ char *name_char_ptr = shared_layout_ptr->GetBlockPtr<char, true>(
+ shared_memory_ptr, SharedDataLayout::NAME_CHAR_LIST);
+ unsigned temp_length;
+ name_stream.read((char *)&temp_length, sizeof(unsigned));
+
+ BOOST_ASSERT_MSG(temp_length ==
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::NAME_CHAR_LIST),
+ "Name file corrupted!");
+
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::NAME_CHAR_LIST) > 0)
+ {
+ name_stream.read(name_char_ptr,
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::NAME_CHAR_LIST));
+ }
+
+ name_stream.close();
+
+ // load original edge information
+ NodeID *via_node_ptr = shared_layout_ptr->GetBlockPtr<NodeID, true>(
+ shared_memory_ptr, SharedDataLayout::VIA_NODE_LIST);
+
+ unsigned *name_id_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
+ shared_memory_ptr, SharedDataLayout::NAME_ID_LIST);
+
+ TurnInstruction *turn_instructions_ptr =
+ shared_layout_ptr->GetBlockPtr<TurnInstruction, true>(
+ shared_memory_ptr, SharedDataLayout::TURN_INSTRUCTION);
+
+ unsigned *geometries_indicator_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
+ shared_memory_ptr, SharedDataLayout::GEOMETRIES_INDICATORS);
+
+ OriginalEdgeData current_edge_data;
+ for (unsigned i = 0; i < number_of_original_edges; ++i)
+ {
+ edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
+ via_node_ptr[i] = current_edge_data.via_node;
+ name_id_ptr[i] = current_edge_data.name_id;
+ turn_instructions_ptr[i] = current_edge_data.turn_instruction;
+
+ const unsigned bucket = i / 32;
+ const unsigned offset = i % 32;
+ const unsigned value = [&]
+ {
+ unsigned return_value = 0;
+ if (0 != offset)
+ {
+ return_value = geometries_indicator_ptr[bucket];
+ }
+ return return_value;
+ }();
+ if (current_edge_data.compressed_geometry)
+ {
+ geometries_indicator_ptr[bucket] = (value | (1 << offset));
+ }
+ }
+ edges_input_stream.close();
+
+ // load compressed geometry
+ unsigned temporary_value;
+ unsigned *geometries_index_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
+ shared_memory_ptr, SharedDataLayout::GEOMETRIES_INDEX);
+ geometry_input_stream.seekg(0, geometry_input_stream.beg);
+ geometry_input_stream.read((char *)&temporary_value, sizeof(unsigned));
+ BOOST_ASSERT(temporary_value ==
+ shared_layout_ptr->num_entries[SharedDataLayout::GEOMETRIES_INDEX]);
+
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::GEOMETRIES_INDEX) > 0)
+ {
+ geometry_input_stream.read(
+ (char *)geometries_index_ptr,
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::GEOMETRIES_INDEX));
+ }
+ unsigned *geometries_list_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
+ shared_memory_ptr, SharedDataLayout::GEOMETRIES_LIST);
+
+ geometry_input_stream.read((char *)&temporary_value, sizeof(unsigned));
+ BOOST_ASSERT(temporary_value ==
+ shared_layout_ptr->num_entries[SharedDataLayout::GEOMETRIES_LIST]);
+
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::GEOMETRIES_LIST) > 0)
+ {
+ geometry_input_stream.read(
+ (char *)geometries_list_ptr,
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::GEOMETRIES_LIST));
+ }
+
+ // Loading list of coordinates
+ FixedPointCoordinate *coordinates_ptr =
+ shared_layout_ptr->GetBlockPtr<FixedPointCoordinate, true>(
+ shared_memory_ptr, SharedDataLayout::COORDINATE_LIST);
+
+ NodeInfo current_node;
+ for (unsigned i = 0; i < coordinate_list_size; ++i)
+ {
+ nodes_input_stream.read((char *)¤t_node, sizeof(NodeInfo));
+ coordinates_ptr[i] = FixedPointCoordinate(current_node.lat, current_node.lon);
+ }
+ nodes_input_stream.close();
+
+ // store timestamp
+ char *timestamp_ptr = shared_layout_ptr->GetBlockPtr<char, true>(
+ shared_memory_ptr, SharedDataLayout::TIMESTAMP);
+ std::copy(m_timestamp.c_str(), m_timestamp.c_str() + m_timestamp.length(), timestamp_ptr);
+
+ // store search tree portion of rtree
+ char *rtree_ptr = shared_layout_ptr->GetBlockPtr<char, true>(
+ shared_memory_ptr, SharedDataLayout::R_SEARCH_TREE);
+
+ if (tree_size > 0)
+ {
+ tree_node_file.read(rtree_ptr, sizeof(RTreeNode) * tree_size);
+ }
+ tree_node_file.close();
+
+ // load the nodes of the search graph
+ QueryGraph::NodeArrayEntry *graph_node_list_ptr =
+ shared_layout_ptr->GetBlockPtr<QueryGraph::NodeArrayEntry, true>(
+ shared_memory_ptr, SharedDataLayout::GRAPH_NODE_LIST);
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::GRAPH_NODE_LIST) > 0)
+ {
+ hsgr_input_stream.read(
+ (char *)graph_node_list_ptr,
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::GRAPH_NODE_LIST));
+ }
+
+ // load the edges of the search graph
+ QueryGraph::EdgeArrayEntry *graph_edge_list_ptr =
+ shared_layout_ptr->GetBlockPtr<QueryGraph::EdgeArrayEntry, true>(
+ shared_memory_ptr, SharedDataLayout::GRAPH_EDGE_LIST);
+ if (shared_layout_ptr->GetBlockSize(SharedDataLayout::GRAPH_EDGE_LIST) > 0)
+ {
+ hsgr_input_stream.read(
+ (char *)graph_edge_list_ptr,
+ shared_layout_ptr->GetBlockSize(SharedDataLayout::GRAPH_EDGE_LIST));
+ }
+ hsgr_input_stream.close();
+
+ // acquire lock
+ SharedMemory *data_type_memory =
+ SharedMemoryFactory::Get(CURRENT_REGIONS, sizeof(SharedDataTimestamp), true, false);
+ SharedDataTimestamp *data_timestamp_ptr =
+ static_cast<SharedDataTimestamp *>(data_type_memory->Ptr());
+
+ boost::interprocess::scoped_lock<boost::interprocess::named_mutex> query_lock(
+ barrier.query_mutex);
+
+ // notify all processes that were waiting for this condition
+ if (0 < barrier.number_of_queries)
+ {
+ barrier.no_running_queries_condition.wait(query_lock);
+ }
+
+ data_timestamp_ptr->layout = LAYOUT;
+ data_timestamp_ptr->data = DATA;
+ data_timestamp_ptr->timestamp += 1;
+ if (use_first_segment)
+ {
+ BOOST_ASSERT(DATA == DATA_1);
+ BOOST_ASSERT(LAYOUT == LAYOUT_1);
+ if (!SharedMemory::Remove(DATA_2))
+ {
+ SimpleLogger().Write(logWARNING) << "could not delete DATA_2";
+ }
+ if (!SharedMemory::Remove(LAYOUT_2))
+ {
+ SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_2";
+ }
+ }
+ else
+ {
+ BOOST_ASSERT(DATA == DATA_2);
+ BOOST_ASSERT(LAYOUT == LAYOUT_2);
+ if (!SharedMemory::Remove(DATA_1))
+ {
+ SimpleLogger().Write(logWARNING) << "could not delete DATA_1";
+ }
+ if (!SharedMemory::Remove(LAYOUT_1))
+ {
+ SimpleLogger().Write(logWARNING) << "could not delete LAYOUT_1";
+ }
+ }
+ SimpleLogger().Write() << "all data loaded";
+
+ shared_layout_ptr->PrintInformation();
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
+ }
+
+ return 0;
+}
diff --git a/extractor.cpp b/extractor.cpp
index 3beeef5..b170b74 100644
--- a/extractor.cpp
+++ b/extractor.cpp
@@ -1,123 +1,286 @@
/*
- 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
#include "Extractor/ExtractorCallbacks.h"
#include "Extractor/ExtractionContainers.h"
#include "Extractor/ScriptingEnvironment.h"
#include "Extractor/PBFParser.h"
#include "Extractor/XMLParser.h"
-#include "Util/BaseConfiguration.h"
-#include "Util/InputFileUtil.h"
+#include "Util/FingerPrint.h"
+#include "Util/GitDescription.h"
#include "Util/MachineInfo.h"
-#include "Util/OpenMPWrapper.h"
+#include "Util/OSRMException.h"
+#include "Util/ProgramOptions.h"
+#include "Util/SimpleLogger.h"
#include "Util/StringUtil.h"
+#include "Util/TimingUtil.h"
#include "typedefs.h"
#include <cstdlib>
+
+#include <thread>
+#include <chrono>
#include <iostream>
#include <fstream>
-
#include <string>
+#include <unordered_map>
-typedef BaseConfiguration ExtractorConfiguration;
+#include <tbb/task_scheduler_init.h>
-ExtractorCallbacks * extractCallBacks;
+ExtractorCallbacks *extractor_callbacks;
+FingerPrint fingerprint;
-int main (int argc, char *argv[]) {
- double earliestTime = get_timestamp();
+int main(int argc, char *argv[])
+{
+ try
+ {
+ LogPolicy::GetInstance().Unmute();
- if(argc < 2) {
- ERR("usage: \n" << argv[0] << " <file.osm/.osm.bz2/.osm.pbf> [<profile.lua>]");
- }
+ TIMER_START(extracting);
- /*** Setup Scripting Environment ***/
- ScriptingEnvironment scriptingEnvironment((argc > 2 ? argv[2] : "profile.lua"));
+ boost::filesystem::path config_file_path, input_path, profile_path;
+ unsigned requested_num_threads;
- unsigned numberOfThreads = omp_get_num_procs();
- if(testDataFile("extractor.ini")) {
- ExtractorConfiguration extractorConfig("extractor.ini");
- unsigned rawNumber = stringToInt(extractorConfig.GetParameter("Threads"));
- if( rawNumber != 0 && rawNumber <= numberOfThreads)
- numberOfThreads = rawNumber;
- }
- omp_set_num_threads(numberOfThreads);
-
- INFO("extracting data from input file " << argv[1]);
- bool isPBF(false);
- std::string outputFileName(argv[1]);
- std::string restrictionsFileName(argv[1]);
- std::string::size_type pos = outputFileName.find(".osm.bz2");
- if(pos==std::string::npos) {
- pos = outputFileName.find(".osm.pbf");
- if(pos!=std::string::npos) {
- isPBF = true;
+ // declare a group of options that will be allowed only on command line
+ boost::program_options::options_description generic_options("Options");
+ generic_options.add_options()("version,v", "Show version")("help,h",
+ "Show this help message")(
+ "config,c",
+ boost::program_options::value<boost::filesystem::path>(&config_file_path)
+ ->default_value("extractor.ini"),
+ "Path to a configuration file.");
+
+ // declare a group of options that will be allowed both on command line and in config file
+ boost::program_options::options_description config_options("Configuration");
+ config_options.add_options()("profile,p",
+ boost::program_options::value<boost::filesystem::path>(
+ &profile_path)->default_value("profile.lua"),
+ "Path to LUA routing profile")(
+ "threads,t",
+ boost::program_options::value<unsigned int>(&requested_num_threads)->default_value(tbb::task_scheduler_init::default_num_threads()),
+ "Number of threads to use");
+
+ // hidden options, will be allowed both on command line and in config file, but will not be
+ // shown to the user
+ boost::program_options::options_description hidden_options("Hidden options");
+ hidden_options.add_options()(
+ "input,i",
+ boost::program_options::value<boost::filesystem::path>(&input_path),
+ "Input file in .osm, .osm.bz2 or .osm.pbf format");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("input", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description config_file_options;
+ config_file_options.add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ boost::filesystem::basename(argv[0]) + " <input.osm/.osm.bz2/.osm.pbf> [options]");
+ visible_options.add(generic_options).add(config_options);
+
+ // parse command line options
+ boost::program_options::variables_map option_variables;
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(cmdline_options)
+ .positional(positional_options)
+ .run(),
+ option_variables);
+
+ if (option_variables.count("version"))
+ {
+ SimpleLogger().Write() << g_GIT_DESCRIPTION;
+ return 0;
}
- }
- if(pos!=std::string::npos) {
- outputFileName.replace(pos, 8, ".osrm");
- restrictionsFileName.replace(pos, 8, ".osrm.restrictions");
- } else {
- pos=outputFileName.find(".osm");
- if(pos!=std::string::npos) {
- outputFileName.replace(pos, 5, ".osrm");
- restrictionsFileName.replace(pos, 5, ".osrm.restrictions");
- } else {
- outputFileName.append(".osrm");
- restrictionsFileName.append(".osrm.restrictions");
+
+ if (option_variables.count("help"))
+ {
+ SimpleLogger().Write() << visible_options;
+ return 0;
}
- }
- unsigned amountOfRAM = 1;
- unsigned installedRAM = GetPhysicalmemory();
- if(installedRAM < 2048264) {
- WARN("Machine has less than 2GB RAM.");
- }
+ boost::program_options::notify(option_variables);
- StringMap stringMap;
- ExtractionContainers externalMemory;
+ // parse config file
+ if (boost::filesystem::is_regular_file(config_file_path))
+ {
+ SimpleLogger().Write() << "Reading options from: " << config_file_path.string();
+ std::string ini_file_contents = ReadIniFileAndLowerContents(config_file_path);
+ std::stringstream config_stream(ini_file_contents);
+ boost::program_options::store(parse_config_file(config_stream, config_file_options),
+ option_variables);
+ boost::program_options::notify(option_variables);
+ }
- stringMap[""] = 0;
- extractCallBacks = new ExtractorCallbacks(&externalMemory, &stringMap);
- BaseParser* parser;
- if(isPBF) {
- parser = new PBFParser(argv[1], extractCallBacks, scriptingEnvironment);
- } else {
- parser = new XMLParser(argv[1], extractCallBacks, scriptingEnvironment);
- }
+ if (!option_variables.count("input"))
+ {
+ SimpleLogger().Write() << visible_options;
+ return 0;
+ }
- if(!parser->ReadHeader()) {
- ERR("Parser not initialized!");
- }
- INFO("Parsing in progress..");
- double time = get_timestamp();
- parser->Parse();
- INFO("Parsing finished after " << get_timestamp() - time << " seconds");
+ if (1 > requested_num_threads)
+ {
+ SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+ return 1;
+ }
- externalMemory.PrepareData(outputFileName, restrictionsFileName, amountOfRAM);
+ if (!boost::filesystem::is_regular_file(input_path))
+ {
+ SimpleLogger().Write(logWARNING) << "Input file " << input_path.string()
+ << " not found!";
+ return 1;
+ }
- stringMap.clear();
- delete parser;
- delete extractCallBacks;
- INFO("finished after " << get_timestamp() - earliestTime << "s");
+ if (!boost::filesystem::is_regular_file(profile_path))
+ {
+ SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string()
+ << " not found!";
+ return 1;
+ }
- std::cout << "\nRun:\n"
- "./osrm-prepare " << outputFileName << " " << restrictionsFileName << std::endl;
+ const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
+
+ SimpleLogger().Write() << "Input file: " << input_path.filename().string();
+ SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
+ SimpleLogger().Write() << "Threads: " << requested_num_threads;
+ if (recommended_num_threads != requested_num_threads)
+ {
+ SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
+ << recommended_num_threads
+ << "! This setting may have performance side-effects.";
+ }
+
+ tbb::task_scheduler_init init(requested_num_threads);
+
+ /*** Setup Scripting Environment ***/
+ ScriptingEnvironment scripting_environment(profile_path.string().c_str());
+
+ bool file_has_pbf_format(false);
+ std::string output_file_name = input_path.string();
+ std::string restriction_fileName = input_path.string();
+ std::string::size_type pos = output_file_name.find(".osm.bz2");
+ if (pos == std::string::npos)
+ {
+ pos = output_file_name.find(".osm.pbf");
+ if (pos != std::string::npos)
+ {
+ file_has_pbf_format = true;
+ } else {
+ pos = output_file_name.find(".osm.xml");
+ }
+ }
+ if (pos == std::string::npos)
+ {
+ pos = output_file_name.find(".pbf");
+ if (pos != std::string::npos)
+ {
+ file_has_pbf_format = true;
+ }
+ }
+ if (pos == std::string::npos)
+ {
+ pos = output_file_name.find(".osm");
+ if (pos == std::string::npos)
+ {
+ output_file_name.append(".osrm");
+ restriction_fileName.append(".osrm.restrictions");
+ }
+ else
+ {
+ output_file_name.replace(pos, 5, ".osrm");
+ restriction_fileName.replace(pos, 5, ".osrm.restrictions");
+ }
+ }
+ else
+ {
+ output_file_name.replace(pos, 8, ".osrm");
+ restriction_fileName.replace(pos, 8, ".osrm.restrictions");
+ }
+
+ std::unordered_map<std::string, NodeID> string_map;
+ ExtractionContainers extraction_containers;
+
+ string_map[""] = 0;
+ extractor_callbacks = new ExtractorCallbacks(extraction_containers, string_map);
+ BaseParser *parser;
+ if (file_has_pbf_format)
+ {
+ parser = new PBFParser(input_path.string().c_str(),
+ extractor_callbacks,
+ scripting_environment,
+ requested_num_threads);
+ }
+ else
+ {
+ parser = new XMLParser(input_path.string().c_str(), extractor_callbacks, scripting_environment);
+ }
+
+ if (!parser->ReadHeader())
+ {
+ throw OSRMException("Parser not initialized!");
+ }
+ SimpleLogger().Write() << "Parsing in progress..";
+ TIMER_START(parsing);
+
+ parser->Parse();
+ delete parser;
+ delete extractor_callbacks;
+
+ TIMER_STOP(parsing);
+ SimpleLogger().Write() << "Parsing finished after " << TIMER_SEC(parsing)
+ << " seconds";
+
+ if (extraction_containers.all_edges_list.empty())
+ {
+ SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+ return 1;
+ }
+
+ extraction_containers.PrepareData(output_file_name, restriction_fileName);
+
+ TIMER_STOP(extracting);
+ SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting)
+ << "s";
+ SimpleLogger().Write() << "To prepare the data for routing, run: "
+ << "./osrm-prepare " << output_file_name << std::endl;
+ }
+ catch (boost::program_options::too_many_positional_options_error &)
+ {
+ SimpleLogger().Write(logWARNING) << "Only one input file can be specified";
+ return 1;
+ }
+ catch (std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << e.what();
+ return 1;
+ }
return 0;
}
diff --git a/extractor.ini b/extractor.ini
deleted file mode 100644
index 8dd11de..0000000
--- a/extractor.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-Memory = 2
-Threads = 10
diff --git a/features/bicycle/access.feature b/features/bicycle/access.feature
index cb1fc0d..2087327 100644
--- a/features/bicycle/access.feature
+++ b/features/bicycle/access.feature
@@ -1,173 +1,173 @@
@routing @bicycle @access
Feature: Bike - Access tags on ways
-Reference: http://wiki.openstreetmap.org/wiki/Key:access
+# Reference: http://wiki.openstreetmap.org/wiki/Key:access
- Background:
- Given the profile "bicycle"
-
- Scenario: Bike - Access tag hierachy on ways
- Then routability should be
- | highway | access | vehicle | bicycle | bothw |
- | | | | | x |
- | | yes | | | x |
- | | no | | | |
- | | | yes | | x |
- | | | no | | |
- | | no | yes | | x |
- | | yes | no | | |
- | | | | yes | x |
- | | | | no | |
- | | no | | yes | x |
- | | yes | | no | |
- | | | no | yes | x |
- | | | yes | no | |
- | runway | | | | |
- | runway | yes | | | x |
- | runway | no | | | |
- | runway | | yes | | x |
- | runway | | no | | |
- | runway | no | yes | | x |
- | runway | yes | no | | |
- | runway | | | yes | x |
- | runway | | | no | |
- | runway | no | | yes | x |
- | runway | yes | | no | |
- | runway | | no | yes | x |
- | runway | | yes | no | |
+ Background:
+ Given the profile "bicycle"
+
+ Scenario: Bike - Access tag hierachy on ways
+ Then routability should be
+ | highway | access | vehicle | bicycle | bothw |
+ | | | | | x |
+ | | yes | | | x |
+ | | no | | | |
+ | | | yes | | x |
+ | | | no | | |
+ | | no | yes | | x |
+ | | yes | no | | |
+ | | | | yes | x |
+ | | | | no | |
+ | | no | | yes | x |
+ | | yes | | no | |
+ | | | no | yes | x |
+ | | | yes | no | |
+ | runway | | | | |
+ | runway | yes | | | x |
+ | runway | no | | | |
+ | runway | | yes | | x |
+ | runway | | no | | |
+ | runway | no | yes | | x |
+ | runway | yes | no | | |
+ | runway | | | yes | x |
+ | runway | | | no | |
+ | runway | no | | yes | x |
+ | runway | yes | | no | |
+ | runway | | no | yes | x |
+ | runway | | yes | no | |
@todo
- Scenario: Bike - Access tag in forward direction
- Then routability should be
- | highway | access:forward | vehicle:forward | bicycle:forward | forw | backw |
- | | | | | x | |
- | | yes | | | x | |
- | | no | | | | |
- | | | yes | | x | |
- | | | no | | | |
- | | no | yes | | x | |
- | | yes | no | | | |
- | | | | yes | x | |
- | | | | no | | |
- | | no | | yes | x | |
- | | yes | | no | | |
- | | | no | yes | x | |
- | | | yes | no | | |
- | runway | | | | x | |
- | runway | yes | | | x | |
- | runway | no | | | | |
- | runway | | yes | | x | |
- | runway | | no | | | |
- | runway | no | yes | | x | |
- | runway | yes | no | | | |
- | runway | | | yes | x | |
- | runway | | | no | | |
- | runway | no | | yes | x | |
- | runway | yes | | no | | |
- | runway | | no | yes | x | |
- | runway | | yes | no | | |
+ Scenario: Bike - Access tag in forward direction
+ Then routability should be
+ | highway | access:forward | vehicle:forward | bicycle:forward | forw | backw |
+ | | | | | x | |
+ | | yes | | | x | |
+ | | no | | | | |
+ | | | yes | | x | |
+ | | | no | | | |
+ | | no | yes | | x | |
+ | | yes | no | | | |
+ | | | | yes | x | |
+ | | | | no | | |
+ | | no | | yes | x | |
+ | | yes | | no | | |
+ | | | no | yes | x | |
+ | | | yes | no | | |
+ | runway | | | | x | |
+ | runway | yes | | | x | |
+ | runway | no | | | | |
+ | runway | | yes | | x | |
+ | runway | | no | | | |
+ | runway | no | yes | | x | |
+ | runway | yes | no | | | |
+ | runway | | | yes | x | |
+ | runway | | | no | | |
+ | runway | no | | yes | x | |
+ | runway | yes | | no | | |
+ | runway | | no | yes | x | |
+ | runway | | yes | no | | |
@todo
- Scenario: Bike - Access tag in backward direction
- Then routability should be
- | highway | access:forward | vehicle:forward | bicycle:forward | forw | backw |
- | | | | | | x |
- | | yes | | | | x |
- | | no | | | | |
- | | | yes | | | x |
- | | | no | | | |
- | | no | yes | | | x |
- | | yes | no | | | |
- | | | | yes | | x |
- | | | | no | | |
- | | no | | yes | | x |
- | | yes | | no | | |
- | | | no | yes | | x |
- | | | yes | no | | |
- | runway | | | | | x |
- | runway | yes | | | | x |
- | runway | no | | | | |
- | runway | | yes | | | x |
- | runway | | no | | | |
- | runway | no | yes | | | x |
- | runway | yes | no | | | |
- | runway | | | yes | | x |
- | runway | | | no | | |
- | runway | no | | yes | | x |
- | runway | yes | | no | | |
- | runway | | no | yes | | x |
- | runway | | yes | no | | |
+ Scenario: Bike - Access tag in backward direction
+ Then routability should be
+ | highway | access:forward | vehicle:forward | bicycle:forward | forw | backw |
+ | | | | | | x |
+ | | yes | | | | x |
+ | | no | | | | |
+ | | | yes | | | x |
+ | | | no | | | |
+ | | no | yes | | | x |
+ | | yes | no | | | |
+ | | | | yes | | x |
+ | | | | no | | |
+ | | no | | yes | | x |
+ | | yes | | no | | |
+ | | | no | yes | | x |
+ | | | yes | no | | |
+ | runway | | | | | x |
+ | runway | yes | | | | x |
+ | runway | no | | | | |
+ | runway | | yes | | | x |
+ | runway | | no | | | |
+ | runway | no | yes | | | x |
+ | runway | yes | no | | | |
+ | runway | | | yes | | x |
+ | runway | | | no | | |
+ | runway | no | | yes | | x |
+ | runway | yes | | no | | |
+ | runway | | no | yes | | x |
+ | runway | | yes | no | | |
- Scenario: Bike - Overwriting implied acccess on ways
- Then routability should be
- | highway | access | vehicle | bicycle | bothw |
- | cycleway | | | | x |
- | runway | | | | |
- | cycleway | no | | | |
- | cycleway | | no | | |
- | cycleway | | | no | |
- | runway | yes | | | x |
- | runway | | yes | | x |
- | runway | | | yes | x |
+ Scenario: Bike - Overwriting implied acccess on ways
+ Then routability should be
+ | highway | access | vehicle | bicycle | bothw |
+ | cycleway | | | | x |
+ | runway | | | | |
+ | cycleway | no | | | |
+ | cycleway | | no | | |
+ | cycleway | | | no | |
+ | runway | yes | | | x |
+ | runway | | yes | | x |
+ | runway | | | yes | x |
- Scenario: Bike - Access tags on ways
- Then routability should be
- | access | vehicle | bicycle | bothw |
- | | | | x |
- | yes | | | x |
- | permissive | | | x |
- | designated | | | x |
- | some_tag | | | x |
- | no | | | |
- | private | | | |
- | agricultural | | | |
- | forestery | | | |
- | | yes | | x |
- | | permissive | | x |
- | | designated | | x |
- | | some_tag | | x |
- | | no | | |
- | | private | | |
- | | agricultural | | |
- | | forestery | | |
- | | | yes | x |
- | | | permissive | x |
- | | | designated | x |
- | | | some_tag | x |
- | | | no | |
- | | | private | |
- | | | agricultural | |
- | | | forestery | |
+ Scenario: Bike - Access tags on ways
+ Then routability should be
+ | access | vehicle | bicycle | bothw |
+ | | | | x |
+ | yes | | | x |
+ | permissive | | | x |
+ | designated | | | x |
+ | some_tag | | | x |
+ | no | | | |
+ | private | | | |
+ | agricultural | | | |
+ | forestery | | | |
+ | | yes | | x |
+ | | permissive | | x |
+ | | designated | | x |
+ | | some_tag | | x |
+ | | no | | |
+ | | private | | |
+ | | agricultural | | |
+ | | forestery | | |
+ | | | yes | x |
+ | | | permissive | x |
+ | | | designated | x |
+ | | | some_tag | x |
+ | | | no | |
+ | | | private | |
+ | | | agricultural | |
+ | | | forestery | |
- Scenario: Bike - Access tags on both node and way
- Then routability should be
- | access | node/access | bothw |
- | yes | yes | x |
- | yes | no | |
- | yes | some_tag | x |
- | no | yes | |
- | no | no | |
- | no | some_tag | |
- | some_tag | yes | x |
- | some_tag | no | |
- | some_tag | some_tag | x |
+ Scenario: Bike - Access tags on both node and way
+ Then routability should be
+ | access | node/access | bothw |
+ | yes | yes | x |
+ | yes | no | |
+ | yes | some_tag | x |
+ | no | yes | |
+ | no | no | |
+ | no | some_tag | |
+ | some_tag | yes | x |
+ | some_tag | no | |
+ | some_tag | some_tag | x |
- Scenario: Bike - Access combinations
- Then routability should be
- | highway | access | vehicle | bicycle | bothw |
- | runway | private | | yes | x |
- | footway | | no | permissive | x |
- | motorway | | | yes | x |
- | track | forestry | | permissive | x |
- | cycleway | yes | designated | no | |
- | primary | | yes | private | |
- | residential | permissive | | no | |
+ Scenario: Bike - Access combinations
+ Then routability should be
+ | highway | access | vehicle | bicycle | forw | backw |
+ | runway | private | | yes | x | x |
+ | footway | | no | permissive | x | x |
+ | motorway | | | yes | x | |
+ | track | forestry | | permissive | x | x |
+ | cycleway | yes | designated | no | | |
+ | primary | | yes | private | | |
+ | residential | permissive | | no | | |
- Scenario: Bike - Ignore access tags for other modes
- Then routability should be
- | highway | boat | motor_vehicle | moped | bothw |
- | river | yes | | | |
- | cycleway | no | | | x |
- | runway | | yes | | |
- | cycleway | | no | | x |
- | runway | | | yes | |
- | cycleway | | | no | x |
+ Scenario: Bike - Ignore access tags for other modes
+ Then routability should be
+ | highway | boat | motor_vehicle | moped | bothw |
+ | river | yes | | | |
+ | cycleway | no | | | x |
+ | runway | | yes | | |
+ | cycleway | | no | | x |
+ | runway | | | yes | |
+ | cycleway | | | no | x |
diff --git a/features/bicycle/access_node.feature b/features/bicycle/access_node.feature
index eba808d..5a6f2b5 100644
--- a/features/bicycle/access_node.feature
+++ b/features/bicycle/access_node.feature
@@ -1,64 +1,64 @@
@routing @bicycle @access
Feature: Bike - Access tags on nodes
-Reference: http://wiki.openstreetmap.org/wiki/Key:access
+# Reference: http://wiki.openstreetmap.org/wiki/Key:access
- Background:
- Given the profile "bicycle"
+ Background:
+ Given the profile "bicycle"
- Scenario: Bike - Access tag hierachy on nodes
- Then routability should be
- | node/access | node/vehicle | node/bicycle | bothw |
- | | | | x |
- | yes | | | x |
- | no | | | |
- | | yes | | x |
- | | no | | |
- | no | yes | | x |
- | yes | no | | |
- | | | yes | x |
- | | | no | |
- | no | | yes | x |
- | yes | | no | |
- | | no | yes | x |
- | | yes | no | |
+ Scenario: Bike - Access tag hierachy on nodes
+ Then routability should be
+ | node/access | node/vehicle | node/bicycle | bothw |
+ | | | | x |
+ | yes | | | x |
+ | no | | | |
+ | | yes | | x |
+ | | no | | |
+ | no | yes | | x |
+ | yes | no | | |
+ | | | yes | x |
+ | | | no | |
+ | no | | yes | x |
+ | yes | | no | |
+ | | no | yes | x |
+ | | yes | no | |
- Scenario: Bike - Overwriting implied acccess on nodes
- Then routability should be
- | highway | node/access | node/vehicle | node/bicycle | bothw |
- | cycleway | | | | x |
- | runway | | | | |
- | cycleway | no | | | |
- | cycleway | | no | | |
- | cycleway | | | no | |
- | runway | yes | | | |
- | runway | | yes | | |
- | runway | | | yes | |
+ Scenario: Bike - Overwriting implied acccess on nodes doesn't overwrite way
+ Then routability should be
+ | highway | node/access | node/vehicle | node/bicycle | bothw |
+ | cycleway | | | | x |
+ | runway | | | | |
+ | cycleway | no | | | |
+ | cycleway | | no | | |
+ | cycleway | | | no | |
+ | runway | yes | | | |
+ | runway | | yes | | |
+ | runway | | | yes | |
- Scenario: Bike - Access tags on nodes
- Then routability should be
- | node/access | node/vehicle | node/bicycle | bothw |
- | | | | x |
- | yes | | | x |
- | permissive | | | x |
- | designated | | | x |
- | some_tag | | | x |
- | no | | | |
- | private | | | |
- | agricultural | | | |
- | forestery | | | |
- | | yes | | x |
- | | permissive | | x |
- | | designated | | x |
- | | some_tag | | x |
- | | no | | |
- | | private | | |
- | | agricultural | | |
- | | forestery | | |
- | | | yes | x |
- | | | permissive | x |
- | | | designated | x |
- | | | some_tag | x |
- | | | no | |
- | | | private | |
- | | | agricultural | |
- | | | forestery | |
\ No newline at end of file
+ Scenario: Bike - Access tags on nodes
+ Then routability should be
+ | node/access | node/vehicle | node/bicycle | bothw |
+ | | | | x |
+ | yes | | | x |
+ | permissive | | | x |
+ | designated | | | x |
+ | some_tag | | | x |
+ | no | | | |
+ | private | | | |
+ | agricultural | | | |
+ | forestery | | | |
+ | | yes | | x |
+ | | permissive | | x |
+ | | designated | | x |
+ | | some_tag | | x |
+ | | no | | |
+ | | private | | |
+ | | agricultural | | |
+ | | forestery | | |
+ | | | yes | x |
+ | | | permissive | x |
+ | | | designated | x |
+ | | | some_tag | x |
+ | | | no | |
+ | | | private | |
+ | | | agricultural | |
+ | | | forestery | |
diff --git a/features/bicycle/area.feature b/features/bicycle/area.feature
index 541f026..062e86f 100644
--- a/features/bicycle/area.feature
+++ b/features/bicycle/area.feature
@@ -1,103 +1,103 @@
@routing @bicycle @area
Feature: Bike - Squares and other areas
- Background:
- Given the profile "bicycle"
-
- @square
- Scenario: Bike - Route along edge of a squares
- Given the node map
- | x | |
- | a | b |
- | d | c |
+ Background:
+ Given the profile "bicycle"
- And the ways
- | nodes | area | highway |
- | xa | | primary |
- | abcda | yes | residential |
-
- When I route I should get
- | from | to | route |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
-
- @building
- Scenario: Bike - Don't route on buildings
- Given the node map
- | x | |
- | a | b |
- | d | c |
+ @square
+ Scenario: Bike - Route along edge of a squares
+ Given the node map
+ | x | |
+ | a | b |
+ | d | c |
- And the ways
- | nodes | highway | area | building | access |
- | xa | primary | | | |
- | abcda | (nil) | yes | yes | yes |
+ And the ways
+ | nodes | area | highway |
+ | xa | | primary |
+ | abcda | yes | residential |
- When I route I should get
- | from | to | route |
- | 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
- Given the node map
- | e | | | f |
- | x | a | b | y |
- | | d | c | |
+ When I route I should get
+ | from | to | route |
+ | a | b | abcda |
+ | a | d | abcda |
+ | b | c | abcda |
+ | c | b | abcda |
+ | c | d | abcda |
+ | d | c | abcda |
+ | d | a | abcda |
+ | a | d | abcda |
- And the ways
- | nodes | highway | amenity |
- | xa | primary | |
- | by | primary | |
- | xefy | primary | |
- | abcda | (nil) | parking |
+ @building
+ Scenario: Bike - Don't route on buildings
+ Given the node map
+ | x | |
+ | a | b |
+ | d | c |
- When I route I should get
- | from | to | route |
- | x | y | xa,abcda,by |
- | y | x | by,abcda,xa |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
-
- @train @platform
- Scenario: Bike - railway platforms
- Given the node map
- | x | a | b | y |
- | | d | c | |
+ And the ways
+ | nodes | highway | area | building | access |
+ | xa | primary | | | |
+ | abcda | (nil) | yes | yes | yes |
- And the ways
- | nodes | highway | railway |
- | xa | primary | |
- | by | primary | |
- | abcda | (nil) | platform |
+ When I route I should get
+ | from | to | route |
+ | a | b | xa |
+ | a | d | xa |
+ | b | c | xa |
+ | c | b | xa |
+ | c | d | xa |
+ | d | c | xa |
+ | d | a | xa |
+ | a | d | xa |
- When I route I should get
- | from | to | route |
- | x | y | xa,abcda,by |
- | y | x | by,abcda,xa |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
\ No newline at end of file
+ @parking
+ Scenario: Bike - parking areas
+ Given the node map
+ | e | | | f |
+ | x | a | b | y |
+ | | d | c | |
+
+ And the ways
+ | nodes | highway | amenity |
+ | xa | primary | |
+ | by | primary | |
+ | xefy | primary | |
+ | abcda | (nil) | parking |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,abcda,by |
+ | y | x | by,abcda,xa |
+ | a | b | abcda |
+ | a | d | abcda |
+ | b | c | abcda |
+ | c | b | abcda |
+ | c | d | abcda |
+ | d | c | abcda |
+ | d | a | abcda |
+ | a | d | abcda |
+
+ @train @platform
+ Scenario: Bike - railway platforms
+ Given the node map
+ | x | a | b | y |
+ | | d | c | |
+
+ And the ways
+ | nodes | highway | railway |
+ | xa | primary | |
+ | by | primary | |
+ | abcda | (nil) | platform |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,abcda,by |
+ | y | x | by,abcda,xa |
+ | a | b | abcda |
+ | a | d | abcda |
+ | b | c | abcda |
+ | c | b | abcda |
+ | c | d | abcda |
+ | d | c | abcda |
+ | d | a | abcda |
+ | a | d | abcda |
diff --git a/features/bicycle/barrier.feature b/features/bicycle/barrier.feature
index ed387c1..d39a570 100644
--- a/features/bicycle/barrier.feature
+++ b/features/bicycle/barrier.feature
@@ -1,39 +1,39 @@
@routing @bicycle @barrier
Feature: Barriers
- Background:
- Given the profile "bicycle"
+ Background:
+ Given the profile "bicycle"
- Scenario: Bike - Barriers
- Then routability should be
- | node/barrier | bothw |
- | | x |
- | bollard | x |
- | gate | x |
- | cycle_barrier | x |
- | cattle_grid | x |
- | border_control | x |
- | toll_booth | x |
- | sally_port | x |
- | entrance | x |
- | wall | |
- | fence | |
- | some_tag | |
+ Scenario: Bike - Barriers
+ Then routability should be
+ | node/barrier | bothw |
+ | | x |
+ | bollard | x |
+ | gate | x |
+ | cycle_barrier | x |
+ | cattle_grid | x |
+ | border_control | x |
+ | toll_booth | x |
+ | sally_port | x |
+ | entrance | x |
+ | wall | |
+ | fence | |
+ | some_tag | |
- Scenario: Bike - Access tag trumphs barriers
- Then routability should be
- | node/barrier | node/access | bothw |
- | bollard | | x |
- | bollard | yes | x |
- | bollard | permissive | x |
- | bollard | designated | x |
- | bollard | no | |
- | bollard | private | |
- | bollard | agricultural | |
- | wall | | |
- | wall | yes | x |
- | wall | permissive | x |
- | wall | designated | x |
- | wall | no | |
- | wall | private | |
- | wall | agricultural | |
+ Scenario: Bike - Access tag trumphs barriers
+ Then routability should be
+ | node/barrier | node/access | bothw |
+ | bollard | | x |
+ | bollard | yes | x |
+ | bollard | permissive | x |
+ | bollard | designated | x |
+ | bollard | no | |
+ | bollard | private | |
+ | bollard | agricultural | |
+ | wall | | |
+ | wall | yes | x |
+ | wall | permissive | x |
+ | wall | designated | x |
+ | wall | no | |
+ | wall | private | |
+ | wall | agricultural | |
diff --git a/features/bicycle/cycleway.feature b/features/bicycle/cycleway.feature
index f260294..643fdce 100644
--- a/features/bicycle/cycleway.feature
+++ b/features/bicycle/cycleway.feature
@@ -1,81 +1,81 @@
@routing @bicycle @cycleway
Feature: Bike - Cycle tracks/lanes
-Reference: http://wiki.openstreetmap.org/wiki/Key:cycleway
+# Reference: http://wiki.openstreetmap.org/wiki/Key:cycleway
- Background:
- Given the profile "bicycle"
-
- Scenario: Bike - Cycle tracks/lanes should enable biking
- Then routability should be
- | highway | cycleway | bothw |
- | motorway | | |
- | motorway | track | x |
- | motorway | lane | x |
- | motorway | shared | x |
- | motorway | share_busway | x |
- | motorway | sharrow | x |
- | some_tag | track | x |
- | some_tag | lane | x |
- | some_tag | shared | x |
- | some_tag | share_busway | x |
- | some_tag | sharrow | x |
- | residential | track | x |
- | residential | lane | x |
- | residential | shared | x |
- | residential | share_busway | x |
- | residential | sharrow | x |
+ Background:
+ Given the profile "bicycle"
- Scenario: Bike - Left/right side cycleways on implied bidirectionals
- Then routability should be
- | highway | cycleway | cycleway:left | cycleway:right | forw | backw |
- | primary | | | | x | x |
- | primary | track | | | x | x |
- | primary | opposite | | | x | x |
- | primary | | track | | x | x |
- | primary | | opposite | | x | x |
- | primary | | | track | x | x |
- | primary | | | opposite | x | x |
- | primary | | track | track | x | x |
- | primary | | opposite | opposite | x | x |
- | primary | | track | opposite | x | x |
- | primary | | opposite | track | x | x |
+ Scenario: Bike - Cycle tracks/lanes should enable biking
+ Then routability should be
+ | highway | cycleway | forw | backw |
+ | motorway | | | |
+ | motorway | track | x | |
+ | motorway | lane | x | |
+ | motorway | shared | x | |
+ | motorway | share_busway | x | |
+ | motorway | sharrow | x | |
+ | some_tag | track | x | x |
+ | some_tag | lane | x | x |
+ | some_tag | shared | x | x |
+ | some_tag | share_busway | x | x |
+ | some_tag | sharrow | x | x |
+ | residential | track | x | x |
+ | residential | lane | x | x |
+ | residential | shared | x | x |
+ | residential | share_busway | x | x |
+ | residential | sharrow | x | x |
- Scenario: Bike - Left/right side cycleways on implied oneways
- Then routability should be
- | highway | cycleway | cycleway:left | cycleway:right | forw | backw |
- | primary | | | | x | x |
- | motorway | | | | | |
- | motorway | track | | | x | |
- | motorway | opposite | | | | x |
- | motorway | | track | | | x |
- | motorway | | opposite | | | x |
- | motorway | | | track | x | |
- | motorway | | | opposite | x | |
- | motorway | | track | track | x | x |
- | motorway | | opposite | opposite | x | x |
- | motorway | | track | opposite | x | x |
- | motorway | | opposite | track | x | x |
+ Scenario: Bike - Left/right side cycleways on implied bidirectionals
+ Then routability should be
+ | highway | cycleway | cycleway:left | cycleway:right | forw | backw |
+ | primary | | | | x | x |
+ | primary | track | | | x | x |
+ | primary | opposite | | | x | x |
+ | primary | | track | | x | x |
+ | primary | | opposite | | x | x |
+ | primary | | | track | x | x |
+ | primary | | | opposite | x | x |
+ | primary | | track | track | x | x |
+ | primary | | opposite | opposite | x | x |
+ | primary | | track | opposite | x | x |
+ | primary | | opposite | track | x | x |
- Scenario: Bike - Invalid cycleway tags
- Then routability should be
- | highway | cycleway | bothw |
- | primary | | x |
- | primary | yes | x |
- | primary | no | x |
- | primary | some_track | x |
- | motorway | | |
- | motorway | yes | |
- | motorway | no | |
- | motorway | some_track | |
-
- Scenario: Bike - Access tags should overwrite cycleway access
- Then routability should be
- | highway | cycleway | access | bothw |
- | motorway | track | no | |
- | residential | track | no | |
- | footway | track | no | |
- | cycleway | track | no | |
- | motorway | lane | yes | x |
- | residential | lane | yes | x |
- | footway | lane | yes | x |
- | cycleway | lane | yes | x |
+ Scenario: Bike - Left/right side cycleways on implied oneways
+ Then routability should be
+ | highway | cycleway | cycleway:left | cycleway:right | forw | backw |
+ | primary | | | | x | x |
+ | motorway | | | | | |
+ | motorway | track | | | x | |
+ | motorway | opposite | | | | x |
+ | motorway | | track | | | x |
+ | motorway | | opposite | | | x |
+ | motorway | | | track | x | |
+ | motorway | | | opposite | x | |
+ | motorway | | track | track | x | x |
+ | motorway | | opposite | opposite | x | x |
+ | motorway | | track | opposite | x | x |
+ | motorway | | opposite | track | x | x |
+
+ Scenario: Bike - Invalid cycleway tags
+ Then routability should be
+ | highway | cycleway | bothw |
+ | primary | | x |
+ | primary | yes | x |
+ | primary | no | x |
+ | primary | some_track | x |
+ | motorway | | |
+ | motorway | yes | |
+ | motorway | no | |
+ | motorway | some_track | |
+
+ Scenario: Bike - Access tags should overwrite cycleway access
+ Then routability should be
+ | highway | cycleway | access | forw | backw |
+ | motorway | track | no | | |
+ | residential | track | no | | |
+ | footway | track | no | | |
+ | cycleway | track | no | | |
+ | motorway | lane | yes | x | |
+ | residential | lane | yes | x | x |
+ | footway | lane | yes | x | x |
+ | cycleway | lane | yes | x | x |
diff --git a/features/bicycle/destination.feature b/features/bicycle/destination.feature
index b3f8b5b..9c71198 100644
--- a/features/bicycle/destination.feature
+++ b/features/bicycle/destination.feature
@@ -1,77 +1,77 @@
@routing @bicycle @destination @todo
Feature: Bike - Destination only, no passing through
- Background:
- Given the profile "bicycle"
-
- Scenario: Bike - Destination only street
- Given the node map
- | a | | | | e |
- | | b | c | d | |
- | | | | | |
- | x | | | | y |
+ Background:
+ Given the profile "bicycle"
- And the ways
- | nodes | access |
- | ab | |
- | bcd | destination |
- | de | |
- | axye | |
+ Scenario: Bike - Destination only street
+ Given the node map
+ | a | | | | e |
+ | | b | c | d | |
+ | | | | | |
+ | x | | | | y |
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ab,bcd |
- | a | d | ab,bcd |
- | a | e | axye |
- | e | d | de |
- | e | c | de,bcd |
- | e | b | de,bcd |
- | e | a | axye |
-
- Scenario: Bike - Destination only street
- Given the node map
- | a | | | | e |
- | | b | c | d | |
- | | | | | |
- | x | | | | y |
+ And the ways
+ | nodes | access |
+ | ab | |
+ | bcd | destination |
+ | de | |
+ | axye | |
- And the ways
- | nodes | access |
- | ab | |
- | bc | destination |
- | cd | destination |
- | de | |
- | axye | |
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | a | c | ab,bcd |
+ | a | d | ab,bcd |
+ | a | e | axye |
+ | e | d | de |
+ | e | c | de,bcd |
+ | e | b | de,bcd |
+ | e | a | axye |
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ab,bc |
- | a | d | ab,bc,cd |
- | a | e | axye |
- | e | d | de |
- | e | c | de,dc |
- | e | b | de,dc,bc |
- | e | a | axye |
+ Scenario: Bike - Destination only street
+ Given the node map
+ | a | | | | e |
+ | | b | c | d | |
+ | | | | | |
+ | x | | | | y |
- Scenario: Bike - Routing inside a destination only area
- Given the node map
- | a | | c | | e |
- | | b | | d | |
- | x | | | | y |
+ And the ways
+ | nodes | access |
+ | ab | |
+ | bc | destination |
+ | cd | destination |
+ | de | |
+ | axye | |
- And the ways
- | nodes | access |
- | ab | destination |
- | bc | destination |
- | cd | destination |
- | de | destination |
- | axye | |
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | a | c | ab,bc |
+ | a | d | ab,bc,cd |
+ | a | e | axye |
+ | e | d | de |
+ | e | c | de,dc |
+ | e | b | de,dc,bc |
+ | e | a | axye |
- When I route I should get
- | from | to | route |
- | a | e | ab,bc,cd,de |
- | e | a | de,cd,bc,ab |
- | b | d | bc,cd |
- | d | b | cd,bc |
\ No newline at end of file
+ Scenario: Bike - Routing inside a destination only area
+ Given the node map
+ | a | | c | | e |
+ | | b | | d | |
+ | x | | | | y |
+
+ And the ways
+ | nodes | access |
+ | ab | destination |
+ | bc | destination |
+ | cd | destination |
+ | de | destination |
+ | axye | |
+
+ When I route I should get
+ | from | to | route |
+ | a | e | ab,bc,cd,de |
+ | e | a | de,cd,bc,ab |
+ | b | d | bc,cd |
+ | d | b | cd,bc |
diff --git a/features/bicycle/ferry.feature b/features/bicycle/ferry.feature
index 5d67df7..85c925f 100644
--- a/features/bicycle/ferry.feature
+++ b/features/bicycle/ferry.feature
@@ -1,63 +1,63 @@
@routing @bicycle @ferry
Feature: Bike - Handle ferry routes
- Background:
- Given the profile "bicycle"
-
- Scenario: Bike - Ferry route
- Given the node map
- | a | b | c | | |
- | | | d | | |
- | | | e | f | g |
-
- And the ways
- | nodes | highway | route | bicycle |
- | abc | primary | | |
- | cde | | ferry | yes |
- | efg | primary | | |
-
- When I route I should get
- | from | to | route |
- | a | g | abc,cde,efg |
- | b | f | abc,cde,efg |
- | e | c | cde |
- | e | b | cde,abc |
- | e | a | cde,abc |
- | c | e | cde |
- | c | f | cde,efg |
- | c | g | cde,efg |
-
- Scenario: Bike - Ferry duration, single node
- Given the node map
- | a | b | c | d |
- | | | e | f |
- | | | g | h |
- | | | i | j |
-
- And the ways
- | nodes | highway | route | bicycle | duration |
- | ab | primary | | | |
- | cd | primary | | | |
- | ef | primary | | | |
- | gh | primary | | | |
- | ij | primary | | | |
- | bc | | ferry | yes | 0:01 |
- | be | | ferry | yes | 0:10 |
- | bg | | ferry | yes | 1:00 |
- | bi | | ferry | yes | 10:00 |
-
- Scenario: Bike - Ferry duration, multiple nodes
- Given the node map
- | x | | | | | y |
- | | a | b | c | d | |
-
- And the ways
- | nodes | highway | route | bicycle | duration |
- | xa | primary | | | |
- | yd | primary | | | |
- | abcd | | ferry | yes | 1:00 |
-
- When I route I should get
- | from | to | route | time |
- | a | d | abcd | 3600s +-10 |
- | d | a | abcd | 3600s +-10 |
+ Background:
+ Given the profile "bicycle"
+
+ Scenario: Bike - Ferry route
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+
+ And the ways
+ | nodes | highway | route | bicycle |
+ | abc | primary | | |
+ | cde | | ferry | yes |
+ | efg | primary | | |
+
+ When I route I should get
+ | from | to | route |
+ | a | g | abc,cde,efg |
+ | b | f | abc,cde,efg |
+ | e | c | cde |
+ | e | b | cde,abc |
+ | e | a | cde,abc |
+ | c | e | cde |
+ | c | f | cde,efg |
+ | c | g | cde,efg |
+
+ Scenario: Bike - Ferry duration, single node
+ Given the node map
+ | a | b | c | d |
+ | | | e | f |
+ | | | g | h |
+ | | | i | j |
+
+ And the ways
+ | nodes | highway | route | bicycle | duration |
+ | ab | primary | | | |
+ | cd | primary | | | |
+ | ef | primary | | | |
+ | gh | primary | | | |
+ | ij | primary | | | |
+ | bc | | ferry | yes | 0:01 |
+ | be | | ferry | yes | 0:10 |
+ | bg | | ferry | yes | 1:00 |
+ | bi | | ferry | yes | 10:00 |
+
+ Scenario: Bike - Ferry duration, multiple nodes
+ Given the node map
+ | x | | | | | y |
+ | | a | b | c | d | |
+
+ And the ways
+ | nodes | highway | route | bicycle | duration |
+ | xa | primary | | | |
+ | yd | primary | | | |
+ | abcd | | ferry | yes | 1:00 |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | d | abcd | 3600s +-10 |
+ | d | a | abcd | 3600s +-10 |
diff --git a/features/bicycle/maxspeed.feature b/features/bicycle/maxspeed.feature
index 9924f55..ba5bfba 100644
--- a/features/bicycle/maxspeed.feature
+++ b/features/bicycle/maxspeed.feature
@@ -1,70 +1,88 @@
@routing @maxspeed @bicycle
Feature: Bike - Max speed restrictions
- Background: Use specific speeds
- Given the profile "bicycle"
+ Background: Use specific speeds
+ Given the profile "bicycle"
+ And a grid size of 1000 meters
- Scenario: Bicycle - Respect maxspeeds when lower that way type speed
- Then routability should be
- | highway | maxspeed | bothw |
- | residential | | 49s ~10% |
- | residential | 10 | 72s ~10% |
+ Scenario: Bicycle - Respect maxspeeds when lower that way type speed
+ Then routability should be
+ | highway | maxspeed | bothw |
+ | residential | | 15 km/h |
+ | residential | 10 | 10 km/h |
+
+ Scenario: Bicycle - Ignore maxspeed when higher than way speed
+ Then routability should be
+ | highway | maxspeed | bothw |
+ | residential | | 15 km/h |
+ | residential | 80 | 15 km/h |
- Scenario: Bicycle - Ignore maxspeed when higher than way speed
- Then routability should be
- | highway | maxspeed | bothw |
- | residential | | 49s ~10% |
- | residential | 80 | 49s ~10% |
-
@todo
- Scenario: Bicycle - Maxspeed formats
- Then routability should be
- | highway | maxspeed | bothw |
- | residential | | 49s ~10% |
- | residential | 5 | 144s ~10% |
- | residential | 5mph | 90s ~10% |
- | residential | 5 mph | 90s ~10% |
- | residential | 5MPH | 90s ~10% |
- | residential | 5 MPH | 90s ~10% |
- | trunk | 5unknown | 49s ~10% |
- | trunk | 5 unknown | 49s ~10% |
+ Scenario: Bicycle - Maxspeed formats
+ Then routability should be
+ | highway | maxspeed | bothw |
+ | residential | | 49s ~10% |
+ | residential | 5 | 144s ~10% |
+ | residential | 5mph | 90s ~10% |
+ | residential | 5 mph | 90s ~10% |
+ | residential | 5MPH | 90s ~10% |
+ | residential | 5 MPH | 90s ~10% |
+ | trunk | 5unknown | 49s ~10% |
+ | trunk | 5 unknown | 49s ~10% |
@todo
- Scenario: Bicycle - Maxspeed special tags
- Then routability should be
- | highway | maxspeed | bothw |
- | residential | | 49s ~10% |
- | residential | none | 49s ~10% |
- | residential | signals | 49s ~10% |
+ Scenario: Bicycle - Maxspeed special tags
+ Then routability should be
+ | highway | maxspeed | bothw |
+ | residential | | 49s ~10% |
+ | residential | none | 49s ~10% |
+ | residential | signals | 49s ~10% |
- Scenario: Bike - Do not use maxspeed when higher that way type speed
- Given the node map
- | a | b | c |
+ Scenario: Bike - Do not use maxspeed when higher that way type speed
+ Given the node map
+ | a | b | c |
- And the ways
- | nodes | highway | maxspeed |
- | ab | residential | |
- | bc | residential | 80 |
+ And the ways
+ | nodes | highway | maxspeed |
+ | ab | residential | |
+ | bc | residential | 80 |
- When I route I should get
- | from | to | route | time |
- | a | b | ab | 24s ~5% |
- | b | c | bc | 24s ~5% |
+ When I route I should get
+ | from | to | route | speed |
+ | a | b | ab | 15 km/h |
+ | b | c | bc | 15 km/h |
- Scenario: Bike - Forward/backward maxspeed
+ Scenario: Bike - Forward/backward maxspeed
Given the shortcuts
- | key | value |
- | bike | 49s ~10% |
- | run | 73s ~10% |
- | walk | 145s ~10% |
- | snail | 720s ~10% |
+ | key | value |
+ | bike | 49s ~10% |
+ | run | 73s ~10% |
+ | walk | 145s ~10% |
+ | snail | 720s ~10% |
+
+ Then routability should be
+ | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw |
+ | | | | 15 km/h | 15 km/h |
+ | 10 | | | 10 km/h | 10 km/h |
+ | | 10 | | 10 km/h | 15 km/h |
+ | | | 10 | 15 km/h | 10 km/h |
+ | 2 | 10 | | 10 km/h | 2 km/h |
+ | 2 | | 10 | 2 km/h | 10 km/h |
+ | 2 | 5 | 10 | 5 km/h | 10 km/h |
- Then routability should be
- | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw |
- | | | | bike | bike |
- | 10 | | | run | run |
- | | 10 | | run | bike |
- | | | 10 | bike | run |
- | 1 | 10 | | run | snail |
- | 1 | | 10 | snail | run |
- | 1 | 5 | 10 | walk | run |
+ Scenario: Bike - Maxspeed should not allow routing on unroutable ways
+ Then routability should be
+ | highway | railway | access | maxspeed | maxspeed:forward | maxspeed:backward | bothw |
+ | primary | | | | | | x |
+ | secondary | | no | | | | |
+ | secondary | | no | 100 | | | |
+ | secondary | | no | | 100 | | |
+ | secondary | | no | | | 100 | |
+ | (nil) | train | | | | | |
+ | (nil) | train | | 100 | | | |
+ | (nil) | train | | | 100 | | |
+ | (nil) | train | | | | 100 | |
+ | runway | | | | | | |
+ | runway | | | 100 | | | |
+ | runway | | | | 100 | | |
+ | runway | | | | | 100 | |
diff --git a/features/bicycle/mode.feature b/features/bicycle/mode.feature
index c24af46..eac0430 100644
--- a/features/bicycle/mode.feature
+++ b/features/bicycle/mode.feature
@@ -1,89 +1,89 @@
@routing @bicycle @mode
Feature: Bike - Mode flag
- Background:
- Given the profile "bicycle"
-
+ Background:
+ Given the profile "bicycle"
+
@todo
Scenario: Bike - Mode when using a ferry
- Given the node map
- | a | b | |
- | | c | d |
+ Given the node map
+ | a | b | |
+ | | c | d |
- And the ways
- | nodes | highway | route | duration |
- | ab | primary | | |
- | bc | | ferry | 0:01 |
- | cd | primary | | |
+ 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 |
+ 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 |
+ @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 | |
+ 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 |
+ 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 |
+ @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 |
+ 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 |
+ 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 |
+ @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 | |
+ 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 |
+ 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 |
diff --git a/features/bicycle/names.feature b/features/bicycle/names.feature
index d8a1ecf..b0e2ec0 100644
--- a/features/bicycle/names.feature
+++ b/features/bicycle/names.feature
@@ -1,49 +1,33 @@
@routing @bicycle @names
Feature: Bike - Street names in instructions
- Background:
- Given the profile "bicycle"
-
- Scenario: Bike - A named street
- Given the node map
- | a | b |
- | | c |
-
- And the ways
- | nodes | name |
- | ab | My Way |
- | bc | Your Way |
-
- When I route I should get
- | 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 |
+ Background:
+ Given the profile "bicycle"
- And the ways
- | nodes | highway | name |
- | ab | cycleway | |
- | bcd | track | |
+ Scenario: Bike - A named street
+ Given the node map
+ | a | b |
+ | | c |
- When I route I should get
- | from | to | route |
- | a | d | {highway:cycleway},{highway:track} |
+ And the ways
+ | nodes | name |
+ | ab | My Way |
+ | bc | Your Way |
- @area @names @todo
- Scenario: Bike - name on streets overlapping an area
- Given the node map
- | x | a | b | y |
- | | d | c | |
+ When I route I should get
+ | from | to | route |
+ | a | c | My Way,Your Way |
- And the ways
- | nodes | highway | area |
- | xaby | residential | |
- | abcda | residential | yes |
+ @unnamed
+ Scenario: Bike - Use way type to describe unnamed ways
+ Given the node map
+ | a | b | c | d |
- When I route I should get
- | from | to | route |
- | x | y | xaby |
- | y | x | xaby |
+ And the ways
+ | nodes | highway | name |
+ | ab | cycleway | |
+ | bcd | track | |
+
+ When I route I should get
+ | from | to | route |
+ | a | d | {highway:cycleway},{highway:track} |
diff --git a/features/bicycle/oneway.feature b/features/bicycle/oneway.feature
index ee0d713..4dd9e1f 100644
--- a/features/bicycle/oneway.feature
+++ b/features/bicycle/oneway.feature
@@ -1,128 +1,128 @@
@routing @bicycle @oneway
Feature: Bike - Oneway streets
-Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing
-Usually we can push bikes against oneways, but we use foot=no to prevent this in these tests
-
- Background:
- Given the profile "bicycle"
-
- Scenario: Bike - Simple oneway
- Then routability should be
- | highway | foot | oneway | forw | backw |
- | primary | no | yes | x | |
-
- Scenario: Simple reverse oneway
- Then routability should be
- | highway | foot | oneway | forw | backw |
- | primary | no | -1 | | x |
-
- Scenario: Bike - Around the Block
- Given the node map
- | a | b |
- | d | c |
-
- And the ways
- | nodes | oneway | foot |
- | ab | yes | no |
- | bc | | no |
- | cd | | no |
- | da | | no |
-
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | a | bc,cd,da |
-
- Scenario: Bike - Handle various oneway tag values
- Then routability should be
- | foot | oneway | forw | backw |
- | no | | x | x |
- | no | nonsense | x | x |
- | no | no | x | x |
- | no | false | x | x |
- | no | 0 | x | x |
- | no | yes | x | |
- | no | true | x | |
- | no | 1 | x | |
- | no | -1 | | x |
-
- Scenario: Bike - Implied oneways
- Then routability should be
- | highway | foot | bicycle | junction | forw | backw |
- | | no | | | x | x |
- | | no | | roundabout | x | |
- | motorway | no | yes | | x | |
- | motorway_link | no | yes | | x | |
- | motorway | no | yes | roundabout | x | |
- | motorway_link | no | yes | roundabout | x | |
-
- Scenario: Bike - Overriding implied oneways
- Then routability should be
- | highway | foot | junction | oneway | forw | backw |
- | primary | no | roundabout | no | x | x |
- | primary | no | roundabout | yes | x | |
- | motorway_link | no | | -1 | | |
- | trunk_link | no | | -1 | | |
- | primary | no | roundabout | -1 | | x |
-
- Scenario: Bike - Oneway:bicycle should override normal oneways tags
- Then routability should be
- | foot | oneway:bicycle | oneway | junction | forw | backw |
- | no | yes | | | x | |
- | no | yes | yes | | x | |
- | no | yes | no | | x | |
- | no | yes | -1 | | x | |
- | no | yes | | roundabout | x | |
- | no | no | | | x | x |
- | no | no | yes | | x | x |
- | no | no | no | | x | x |
- | no | no | -1 | | x | x |
- | no | no | | roundabout | x | x |
- | no | -1 | | | | x |
- | no | -1 | yes | | | x |
- | no | -1 | no | | | x |
- | no | -1 | -1 | | | x |
- | no | -1 | | roundabout | | x |
-
- Scenario: Bike - Contra flow
- Then routability should be
- | foot | oneway | cycleway | forw | backw |
- | no | yes | opposite | x | x |
- | no | yes | opposite_track | x | x |
- | no | yes | opposite_lane | x | x |
- | no | -1 | opposite | x | x |
- | no | -1 | opposite_track | x | x |
- | no | -1 | opposite_lane | x | x |
- | no | no | opposite | x | x |
- | no | no | opposite_track | x | x |
- | no | no | opposite_lane | x | x |
-
- Scenario: Bike - Should not be affected by car tags
- Then routability should be
- | foot | junction | oneway | oneway:car | forw | backw |
- | no | | yes | yes | x | |
- | no | | yes | no | x | |
- | no | | yes | -1 | x | |
- | no | | no | yes | x | x |
- | no | | no | no | x | x |
- | no | | no | -1 | x | x |
- | no | | -1 | yes | | x |
- | no | | -1 | no | | x |
- | no | | -1 | -1 | | x |
- | no | roundabout | | yes | x | |
- | no | roundabout | | no | x | |
- | no | roundabout | | -1 | x | |
-
- 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 |
\ No newline at end of file
+# Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing
+# Usually we can push bikes against oneways, but we use foot=no to prevent this in these tests
+
+ Background:
+ Given the profile "bicycle"
+
+ Scenario: Bike - Simple oneway
+ Then routability should be
+ | highway | foot | oneway | forw | backw |
+ | primary | no | yes | x | |
+
+ Scenario: Simple reverse oneway
+ Then routability should be
+ | highway | foot | oneway | forw | backw |
+ | primary | no | -1 | | x |
+
+ Scenario: Bike - Around the Block
+ Given the node map
+ | a | b |
+ | d | c |
+
+ And the ways
+ | nodes | oneway | foot |
+ | ab | yes | no |
+ | bc | | no |
+ | cd | | no |
+ | da | | no |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | b | a | bc,cd,da |
+
+ Scenario: Bike - Handle various oneway tag values
+ Then routability should be
+ | foot | oneway | forw | backw |
+ | no | | x | x |
+ | no | nonsense | x | x |
+ | no | no | x | x |
+ | no | false | x | x |
+ | no | 0 | x | x |
+ | no | yes | x | |
+ | no | true | x | |
+ | no | 1 | x | |
+ | no | -1 | | x |
+
+ Scenario: Bike - Implied oneways
+ Then routability should be
+ | highway | foot | bicycle | junction | forw | backw |
+ | | no | | | x | x |
+ | | no | | roundabout | x | |
+ | motorway | no | yes | | x | |
+ | motorway_link | no | yes | | x | |
+ | motorway | no | yes | roundabout | x | |
+ | motorway_link | no | yes | roundabout | x | |
+
+ Scenario: Bike - Overriding implied oneways
+ Then routability should be
+ | highway | foot | junction | oneway | forw | backw |
+ | primary | no | roundabout | no | x | x |
+ | primary | no | roundabout | yes | x | |
+ | motorway_link | no | | -1 | | |
+ | trunk_link | no | | -1 | | |
+ | primary | no | roundabout | -1 | | x |
+
+ Scenario: Bike - Oneway:bicycle should override normal oneways tags
+ Then routability should be
+ | foot | oneway:bicycle | oneway | junction | forw | backw |
+ | no | yes | | | x | |
+ | no | yes | yes | | x | |
+ | no | yes | no | | x | |
+ | no | yes | -1 | | x | |
+ | no | yes | | roundabout | x | |
+ | no | no | | | x | x |
+ | no | no | yes | | x | x |
+ | no | no | no | | x | x |
+ | no | no | -1 | | x | x |
+ | no | no | | roundabout | x | x |
+ | no | -1 | | | | x |
+ | no | -1 | yes | | | x |
+ | no | -1 | no | | | x |
+ | no | -1 | -1 | | | x |
+ | no | -1 | | roundabout | | x |
+
+ Scenario: Bike - Contra flow
+ Then routability should be
+ | foot | oneway | cycleway | forw | backw |
+ | no | yes | opposite | x | x |
+ | no | yes | opposite_track | x | x |
+ | no | yes | opposite_lane | x | x |
+ | no | -1 | opposite | x | x |
+ | no | -1 | opposite_track | x | x |
+ | no | -1 | opposite_lane | x | x |
+ | no | no | opposite | x | x |
+ | no | no | opposite_track | x | x |
+ | no | no | opposite_lane | x | x |
+
+ Scenario: Bike - Should not be affected by car tags
+ Then routability should be
+ | foot | junction | oneway | oneway:car | forw | backw |
+ | no | | yes | yes | x | |
+ | no | | yes | no | x | |
+ | no | | yes | -1 | x | |
+ | no | | no | yes | x | x |
+ | no | | no | no | x | x |
+ | no | | no | -1 | x | x |
+ | no | | -1 | yes | | x |
+ | no | | -1 | no | | x |
+ | no | | -1 | -1 | | x |
+ | no | roundabout | | yes | x | |
+ | no | roundabout | | no | x | |
+ | no | roundabout | | -1 | x | |
+
+ 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 |
diff --git a/features/bicycle/pushing.feature b/features/bicycle/pushing.feature
index 13590d0..2b23829 100644
--- a/features/bicycle/pushing.feature
+++ b/features/bicycle/pushing.feature
@@ -1,124 +1,124 @@
@routing @bicycle @pushing
Feature: Bike - Accessability of different way types
- Background:
- Given the profile "bicycle"
+ Background:
+ Given the profile "bicycle"
Given the shortcuts
- | key | value |
- | bike | 49s ~20% |
- | foot | 121s ~20% |
+ | key | value |
+ | bike | 49s ~20% |
+ | foot | 121s ~20% |
- Scenario: Bike - Pushing bikes on pedestrian-only ways
- Then routability should be
- | highway | oneway | forw | backw |
- | (nil) | | | |
- | cycleway | | bike | bike |
- | primary | | bike | bike |
- | pedestrian | | foot | foot |
- | footway | | foot | foot |
- | primary | yes | bike | foot |
+ Scenario: Bike - Pushing bikes on pedestrian-only ways
+ Then routability should be
+ | highway | oneway | forw | backw |
+ | (nil) | | | |
+ | cycleway | | bike | bike |
+ | primary | | bike | bike |
+ | pedestrian | | foot | foot |
+ | footway | | foot | foot |
+ | primary | yes | bike | foot |
- Scenario: Bike - Pushing bikes against normal oneways
- Then routability should be
- | highway | oneway | forw | backw |
- | (nil) | | | |
- | primary | yes | bike | foot |
- | pedestrian | yes | foot | foot |
+ Scenario: Bike - Pushing bikes against normal oneways
+ Then routability should be
+ | highway | oneway | forw | backw |
+ | (nil) | | | |
+ | primary | yes | bike | foot |
+ | pedestrian | yes | foot | foot |
- Scenario: Bike - Pushing bikes against reverse oneways
- Then routability should be
- | highway | oneway | forw | backw |
- | (nil) | | | |
- | primary | -1 | foot | bike |
- | pedestrian | -1 | foot | foot |
+ Scenario: Bike - Pushing bikes against reverse oneways
+ Then routability should be
+ | highway | oneway | forw | backw |
+ | (nil) | | | |
+ | primary | -1 | foot | bike |
+ | pedestrian | -1 | foot | foot |
- @square
- Scenario: Bike - Push bikes on pedestrian areas
- Given the node map
- | x | |
- | a | b |
- | d | c |
+ @square
+ Scenario: Bike - Push bikes on pedestrian areas
+ Given the node map
+ | x | |
+ | a | b |
+ | d | c |
- And the ways
- | nodes | area | highway |
- | xa | | primary |
- | abcda | yes | pedestrian |
+ And the ways
+ | nodes | area | highway |
+ | xa | | primary |
+ | abcda | yes | pedestrian |
- When I route I should get
- | from | to | route |
- | a | b | abcda |
- | a | d | abcda |
- | b | c | abcda |
- | c | b | abcda |
- | c | d | abcda |
- | d | c | abcda |
- | d | a | abcda |
- | a | d | abcda |
+ When I route I should get
+ | from | to | route |
+ | a | b | abcda |
+ | a | d | abcda |
+ | b | c | abcda |
+ | c | b | abcda |
+ | c | d | abcda |
+ | d | c | abcda |
+ | d | a | abcda |
+ | a | d | abcda |
- Scenario: Bike - Pushing bikes on ways with foot=yes
- Then routability should be
- | highway | foot | bothw |
- | motorway | | |
- | motorway | yes | foot |
- | runway | | |
- | runway | yes | foot |
+ Scenario: Bike - Pushing bikes on ways with foot=yes
+ Then routability should be
+ | highway | foot | forw | backw |
+ | motorway | | | |
+ | motorway | yes | foot | |
+ | runway | | | |
+ | runway | yes | foot | foot |
@todo
- Scenario: Bike - Pushing bikes on ways with foot=yes in one direction
- Then routability should be
- | highway | foot:forward | foot:backward | forw | backw |
- | motorway | | | | |
- | motorway | yes | | foot | |
- | motorway | | yes | | foot |
+ Scenario: Bike - Pushing bikes on ways with foot=yes in one direction
+ Then routability should be
+ | highway | foot:forward | foot:backward | forw | backw |
+ | motorway | | | | |
+ | motorway | yes | | foot | |
+ | motorway | | yes | | foot |
@construction
- Scenario: Bike - Don't allow routing on ways still under construction
- Then routability should be
- | highway | foot | bicycle | bothw |
- | primary | | | x |
- | construction | | | |
- | construction | yes | | |
- | construction | | yes | |
+ Scenario: Bike - Don't allow routing on ways still under construction
+ Then routability should be
+ | highway | foot | bicycle | bothw |
+ | primary | | | x |
+ | construction | | | |
+ | construction | yes | | |
+ | construction | | yes | |
@roundabout
- Scenario: Bike - Don't push bikes against oneway flow on roundabouts
- Then routability should be
- | junction | forw | backw |
- | roundabout | x | |
+ Scenario: Bike - Don't push bikes against oneway flow on roundabouts
+ 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 |
+ 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 | |
+ 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 |
+ 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
+ @todo
Scenario: Bike - Instructions when pushing bike on footway/pedestrian, etc.
- Given the node map
- | a | b | |
- | | c | d |
+ Given the node map
+ | a | b | |
+ | | c | d |
- And the ways
- | nodes | highway |
- | ab | primary |
- | bc | footway |
- | cd | primary |
+ 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 |
\ No newline at end of file
+ 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 |
diff --git a/features/bicycle/ref.feature b/features/bicycle/ref.feature
index da15859..3afde77 100644
--- a/features/bicycle/ref.feature
+++ b/features/bicycle/ref.feature
@@ -1,41 +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 |
+ 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 |
diff --git a/features/bicycle/restrictions.feature b/features/bicycle/restrictions.feature
index 2d5fa40..6218d81 100644
--- a/features/bicycle/restrictions.feature
+++ b/features/bicycle/restrictions.feature
@@ -1,289 +1,289 @@
@routing @bicycle @restrictions
Feature: Bike - Turn restrictions
- Ignore turn restrictions on bicycle, since you always become a temporary pedestrian.
- Note that if u-turns are allowed, turn restrictions can lead to suprising, but correct, routes.
-
- Background:
- Given the profile "bicycle"
-
- @no_turning
- Scenario: Bike - No left turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | nj | -1 | no |
- | wj | -1 | no |
- | ej | -1 | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | wj | j | no_left_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @no_turning
- Scenario: Bike - No right turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | nj | -1 | no |
- | wj | -1 | no |
- | ej | -1 | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | ej | j | no_right_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @no_turning
- Scenario: Bike - No u-turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | nj | -1 | no |
- | wj | -1 | no |
- | ej | -1 | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | wj | j | no_u_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @no_turning
- Scenario: Bike - Handle any no_* relation
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | nj | -1 | no |
- | wj | -1 | no |
- | ej | -1 | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | wj | j | no_weird_zigzags |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @only_turning
- Scenario: Bike - Only left turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | nj | -1 | no |
- | wj | -1 | no |
- | ej | -1 | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | wj | j | only_left_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @only_turning
- Scenario: Bike - Only right turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | nj | -1 | no |
- | wj | -1 | no |
- | ej | -1 | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | ej | j | only_right_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @only_turning
- Scenario: Bike - Only straight on
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | nj | -1 | no |
- | wj | -1 | no |
- | ej | -1 | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | nj | j | only_straight_on |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @no_turning
- Scenario: Bike - Handle any only_* restriction
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | nj | -1 | no |
- | wj | -1 | no |
- | ej | -1 | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | nj | j | only_weird_zigzags |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @except
- Scenario: Bike - Except tag and on no_ restrictions
- Given the node map
- | b | x | c |
- | a | j | d |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | no | no |
- | xj | -1 | no |
- | aj | -1 | no |
- | bj | no | no |
- | cj | -1 | no |
- | dj | -1 | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction | except |
- | restriction | sj | aj | j | no_left_turn | bicycle |
- | restriction | sj | bj | j | no_left_turn | |
- | restriction | sj | cj | j | no_right_turn | |
- | restriction | sj | dj | j | no_right_turn | bicycle |
-
- When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | sj,bj |
- | s | c | sj,cj |
- | s | d | sj,dj |
-
- @except
- Scenario: Bike - Except tag and on only_ restrictions
- Given the node map
- | a | | b |
- | | j | |
- | | s | |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | aj | no | no |
- | bj | no | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction | except |
- | restriction | sj | aj | j | only_straight_on | bicycle |
-
- When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | sj,bj |
-
- @except
- Scenario: Bike - Multiple except tag values
- Given the node map
- | s | j | a |
- | | | b |
- | | | c |
- | | | d |
- | | | e |
- | | | f |
-
- And the ways
- | nodes | oneway | foot |
- | sj | yes | no |
- | ja | yes | no |
- | jb | yes | no |
- | jc | yes | no |
- | jd | yes | no |
- | je | yes | no |
- | jf | yes | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction | except |
- | restriction | sj | ja | j | no_straight_on | |
- | restriction | sj | jb | j | no_straight_on | bicycle |
- | restriction | sj | jc | j | no_straight_on | bus; bicycle |
- | restriction | sj | jd | j | no_straight_on | bicycle; motocar |
- | restriction | sj | je | j | no_straight_on | bus, bicycle |
- | restriction | sj | jf | j | no_straight_on | bicycle, bus |
-
- When I route I should get
- | from | to | route |
- | s | a | sj,ja |
- | s | b | sj,jb |
- | s | c | sj,jc |
- | s | d | sj,jd |
- | s | e | sj,je |
- | s | f | sj,jf |
+# Ignore turn restrictions on bicycle, since you always become a temporary pedestrian.
+# Note that if u-turns are allowed, turn restrictions can lead to suprising, but correct, routes.
+
+ Background:
+ Given the profile "bicycle"
+
+ @no_turning
+ Scenario: Bike - No left turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | nj | -1 | no |
+ | wj | -1 | no |
+ | ej | -1 | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_left_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Bike - No right turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | nj | -1 | no |
+ | wj | -1 | no |
+ | ej | -1 | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | ej | j | no_right_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Bike - No u-turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | nj | -1 | no |
+ | wj | -1 | no |
+ | ej | -1 | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_u_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Bike - Handle any no_* relation
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | nj | -1 | no |
+ | wj | -1 | no |
+ | ej | -1 | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_weird_zigzags |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @only_turning
+ Scenario: Bike - Only left turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | nj | -1 | no |
+ | wj | -1 | no |
+ | ej | -1 | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | only_left_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @only_turning
+ Scenario: Bike - Only right turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | nj | -1 | no |
+ | wj | -1 | no |
+ | ej | -1 | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | ej | j | only_right_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @only_turning
+ Scenario: Bike - Only straight on
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | nj | -1 | no |
+ | wj | -1 | no |
+ | ej | -1 | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | nj | j | only_straight_on |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Bike - Handle any only_* restriction
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | nj | -1 | no |
+ | wj | -1 | no |
+ | ej | -1 | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | nj | j | only_weird_zigzags |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @except
+ Scenario: Bike - Except tag and on no_ restrictions
+ Given the node map
+ | b | x | c |
+ | a | j | d |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | no | no |
+ | xj | -1 | no |
+ | aj | -1 | no |
+ | bj | no | no |
+ | cj | -1 | no |
+ | dj | -1 | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction | except |
+ | restriction | sj | aj | j | no_left_turn | bicycle |
+ | restriction | sj | bj | j | no_left_turn | |
+ | restriction | sj | cj | j | no_right_turn | |
+ | restriction | sj | dj | j | no_right_turn | bicycle |
+
+ When I route I should get
+ | from | to | route |
+ | s | a | sj,aj |
+ | s | b | sj,bj |
+ | s | c | sj,cj |
+ | s | d | sj,dj |
+
+ @except
+ Scenario: Bike - Except tag and on only_ restrictions
+ Given the node map
+ | a | | b |
+ | | j | |
+ | | s | |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | aj | no | no |
+ | bj | no | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction | except |
+ | restriction | sj | aj | j | only_straight_on | bicycle |
+
+ When I route I should get
+ | from | to | route |
+ | s | a | sj,aj |
+ | s | b | sj,bj |
+
+ @except
+ Scenario: Bike - Multiple except tag values
+ Given the node map
+ | s | j | a |
+ | | | b |
+ | | | c |
+ | | | d |
+ | | | e |
+ | | | f |
+
+ And the ways
+ | nodes | oneway | foot |
+ | sj | yes | no |
+ | ja | yes | no |
+ | jb | yes | no |
+ | jc | yes | no |
+ | jd | yes | no |
+ | je | yes | no |
+ | jf | yes | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction | except |
+ | restriction | sj | ja | j | no_straight_on | |
+ | restriction | sj | jb | j | no_straight_on | bicycle |
+ | restriction | sj | jc | j | no_straight_on | bus; bicycle |
+ | restriction | sj | jd | j | no_straight_on | bicycle; motocar |
+ | restriction | sj | je | j | no_straight_on | bus, bicycle |
+ | restriction | sj | jf | j | no_straight_on | bicycle, bus |
+
+ When I route I should get
+ | from | to | route |
+ | s | a | sj,ja |
+ | s | b | sj,jb |
+ | s | c | sj,jc |
+ | s | d | sj,jd |
+ | s | e | sj,je |
+ | s | f | sj,jf |
diff --git a/features/bicycle/roundabout.feature b/features/bicycle/roundabout.feature
new file mode 100644
index 0000000..6123280
--- /dev/null
+++ b/features/bicycle/roundabout.feature
@@ -0,0 +1,30 @@
+ at routing @bicycle @roundabout @instruction
+Feature: Roundabout Instructions
+
+ Background:
+ Given the profile "bicycle"
+
+ Scenario: Bicycle - Roundabout instructions
+ Given the node map
+ | | | v | | |
+ | | | d | | |
+ | s | a | | c | u |
+ | | | b | | |
+ | | | t | | |
+
+ And the ways
+ | nodes | junction |
+ | sa | |
+ | tb | |
+ | uc | |
+ | vd | |
+ | abcda | roundabout |
+
+ When I route I should get
+ | from | to | route | turns |
+ | s | t | sa,tb | head,enter_roundabout-1,destination |
+ | s | u | sa,uc | head,enter_roundabout-2,destination |
+ | s | v | sa,vd | head,enter_roundabout-3,destination |
+ | u | v | uc,vd | head,enter_roundabout-1,destination |
+ | u | s | uc,sa | head,enter_roundabout-2,destination |
+ | u | t | uc,tb | head,enter_roundabout-3,destination |
diff --git a/features/bicycle/stop_area.feature b/features/bicycle/stop_area.feature
index 7113808..5f6c3bc 100644
--- a/features/bicycle/stop_area.feature
+++ b/features/bicycle/stop_area.feature
@@ -1,37 +1,37 @@
@routing @bicycle @stop_area @todo
Feature: Bike - Stop areas for public transport
-Platforms and railway/bus lines are connected using a relation rather that a way, as specified in:
-http://wiki.openstreetmap.org/wiki/Tag:public_transport%3Dstop_area
+# Platforms and railway/bus lines are connected using a relation rather that a way, as specified in:
+# http://wiki.openstreetmap.org/wiki/Tag:public_transport%3Dstop_area
- Background:
- Given the profile "bicycle"
-
- Scenario: Bike - Platforms tagged using public_transport
- Then routability should be
- | highway | public_transport | bicycle | bothw |
- | primary | | | x |
- | (nil) | platform | | x |
+ Background:
+ Given the profile "bicycle"
- Scenario: Bike - railway platforms
- Given the node map
- | a | b | c | d |
- | | s | t | |
+ Scenario: Bike - Platforms tagged using public_transport
+ Then routability should be
+ | highway | public_transport | bicycle | bothw |
+ | primary | | | x |
+ | (nil) | platform | | x |
+
+ Scenario: Bike - railway platforms
+ Given the node map
+ | a | b | c | d |
+ | | s | t | |
And the nodes
- | node | public_transport |
- | c | stop_position |
-
- And the ways
- | nodes | highway | railway | bicycle | public_transport |
- | abcd | (nil) | train | yes | |
- | st | (nil) | (nil) | | platform |
+ | node | public_transport |
+ | c | stop_position |
+
+ And the ways
+ | nodes | highway | railway | bicycle | public_transport |
+ | abcd | (nil) | train | yes | |
+ | st | (nil) | (nil) | | platform |
- And the relations
- | type | public_transport | node:stop | way:platform |
- | public_transport | stop_area | c | st |
+ And the relations
+ | type | public_transport | node:stop | way:platform |
+ | public_transport | stop_area | c | st |
- When I route I should get
- | from | to | route |
- | a | d | abcd |
- | s | t | st |
- | s | d | /st,.+,abcd/ |
+ When I route I should get
+ | from | to | route |
+ | a | d | abcd |
+ | s | t | st |
+ | s | d | /st,.+,abcd/ |
diff --git a/features/bicycle/surface.feature b/features/bicycle/surface.feature
new file mode 100644
index 0000000..216307b
--- /dev/null
+++ b/features/bicycle/surface.feature
@@ -0,0 +1,40 @@
+ at routing @surface @bicycle
+Feature: Bike - Surfaces
+
+ Background:
+ Given the profile "bicycle"
+
+ Scenario: Bicycle - Slow surfaces
+ Then routability should be
+ | highway | surface | bothw |
+ | cycleway | | 48s |
+ | cycleway | asphalt | 48s |
+ | cycleway | cobblestone:flattened | 72s |
+ | cycleway | paving_stones | 72s |
+ | cycleway | compacted | 72s |
+ | cycleway | cobblestone | 120s |
+ | cycleway | unpaved | 120s |
+ | cycleway | fine_gravel | 120s |
+ | cycleway | gravel | 120s |
+ | cycleway | pebbelstone | 120s |
+ | cycleway | dirt | 120s |
+ | cycleway | earth | 120s |
+ | cycleway | grass | 120s |
+ | cycleway | mud | 240s |
+ | cycleway | sand | 240s |
+
+ Scenario: Bicycle - Good surfaces on small paths
+ Then routability should be
+ | highway | surface | bothw |
+ | cycleway | | 48s |
+ | path | | 60s |
+ | track | | 60s |
+ | track | asphalt | 48s |
+ | path | asphalt | 48s |
+
+ Scenario: Bicycle - Surfaces should not make unknown ways routable
+ Then routability should be
+ | highway | surface | bothw |
+ | cycleway | | 48s |
+ | nosense | | |
+ | nosense | asphalt | |
diff --git a/features/bicycle/train.feature b/features/bicycle/train.feature
index a4af362..aafa203 100644
--- a/features/bicycle/train.feature
+++ b/features/bicycle/train.feature
@@ -1,39 +1,39 @@
@routing @bicycle @train
Feature: Bike - Handle ferry routes
-Bringing bikes on trains and subways
+# Bringing bikes on trains and subways
- Background:
- Given the profile "bicycle"
-
- Scenario: Bike - Bringing bikes on trains
- Then routability should be
- | highway | railway | bicycle | bothw |
- | primary | | | x |
- | (nil) | train | | |
- | (nil) | train | no | |
- | (nil) | train | yes | x |
- | (nil) | railway | | |
- | (nil) | railway | no | |
- | (nil) | railway | yes | x |
- | (nil) | subway | | |
- | (nil) | subway | no | |
- | (nil) | subway | yes | x |
- | (nil) | tram | | |
- | (nil) | tram | no | |
- | (nil) | tram | yes | x |
- | (nil) | light_rail | | |
- | (nil) | light_rail | no | |
- | (nil) | light_rail | yes | x |
- | (nil) | monorail | | |
- | (nil) | monorail | no | |
- | (nil) | monorail | yes | x |
- | (nil) | some_tag | | |
- | (nil) | some_tag | no | |
- | (nil) | some_tag | yes | x |
+ Background:
+ Given the profile "bicycle"
- @construction
- Scenario: Bike - Don't route on railways under construction
- Then routability should be
- | highway | railway | bicycle | bothw |
- | primary | | | x |
- | (nil) | construction | yes | |
+ Scenario: Bike - Bringing bikes on trains
+ Then routability should be
+ | highway | railway | bicycle | bothw |
+ | primary | | | x |
+ | (nil) | train | | |
+ | (nil) | train | no | |
+ | (nil) | train | yes | x |
+ | (nil) | railway | | |
+ | (nil) | railway | no | |
+ | (nil) | railway | yes | x |
+ | (nil) | subway | | |
+ | (nil) | subway | no | |
+ | (nil) | subway | yes | x |
+ | (nil) | tram | | |
+ | (nil) | tram | no | |
+ | (nil) | tram | yes | x |
+ | (nil) | light_rail | | |
+ | (nil) | light_rail | no | |
+ | (nil) | light_rail | yes | x |
+ | (nil) | monorail | | |
+ | (nil) | monorail | no | |
+ | (nil) | monorail | yes | x |
+ | (nil) | some_tag | | |
+ | (nil) | some_tag | no | |
+ | (nil) | some_tag | yes | x |
+
+ @construction
+ Scenario: Bike - Don't route on railways under construction
+ Then routability should be
+ | highway | railway | bicycle | bothw |
+ | primary | | | x |
+ | (nil) | construction | yes | |
diff --git a/features/bicycle/turn_penalty.feature b/features/bicycle/turn_penalty.feature
index 157cbf2..d8c46b8 100644
--- a/features/bicycle/turn_penalty.feature
+++ b/features/bicycle/turn_penalty.feature
@@ -2,32 +2,32 @@
Feature: Turn Penalties
Background:
- Given the profile "turnbot"
+ Given the profile "turnbot"
Scenario: Bike - turns should incur a delay that depend on the angle
Given the node map
- | c | d | e |
- | b | j | f |
- | a | s | g |
+ | c | d | e |
+ | b | j | f |
+ | a | s | g |
And the ways
- | nodes |
- | sj |
- | ja |
- | jb |
- | jc |
- | jd |
- | je |
- | jf |
- | jg |
+ | nodes |
+ | sj |
+ | ja |
+ | jb |
+ | jc |
+ | jd |
+ | je |
+ | jf |
+ | jg |
When I route I should get
- | from | to | route | time | distance |
- | s | a | sj,ja | 39s +-1 | 242m +-1 |
- | s | b | sj,jb | 30s +-1 | 200m +-1 |
- | s | c | sj,jc | 29s +-1 | 242m +-1 |
- | s | d | sj,jd | 20s +-1 | 200m +-1 |
- | s | e | sj,je | 29s +-1 | 242m +-1 |
- | s | f | sj,jf | 30s +-1 | 200m +-1 |
- | s | g | sj,jg | 39s +-1 | 242m +-1 |
\ No newline at end of file
+ | from | to | route | time | distance |
+ | s | a | sj,ja | 39s +-1 | 242m +-1 |
+ | s | b | sj,jb | 30s +-1 | 200m +-1 |
+ | s | c | sj,jc | 29s +-1 | 242m +-1 |
+ | s | d | sj,jd | 20s +-1 | 200m +-1 |
+ | s | e | sj,je | 29s +-1 | 242m +-1 |
+ | s | f | sj,jf | 30s +-1 | 200m +-1 |
+ | s | g | sj,jg | 39s +-1 | 242m +-1 |
\ No newline at end of file
diff --git a/features/bicycle/way.feature b/features/bicycle/way.feature
index f5ad5bb..b9beb5f 100644
--- a/features/bicycle/way.feature
+++ b/features/bicycle/way.feature
@@ -1,41 +1,42 @@
@routing @bicycle @way
Feature: Bike - Accessability of different way types
- Background:
- Given the profile "bicycle"
+ Background:
+ Given the profile "bicycle"
- Scenario: Bike - Routability of way types
- Bikes are allowed on footways etc because you can pull your bike at a lower speed.
- Pier is not allowed, since it's tagged using man_made=pier.
- Then routability should be
- | highway | bothw |
- | (nil) | |
- | motorway | |
- | motorway_link | |
- | trunk | |
- | trunk_link | |
- | primary | x |
- | primary_link | x |
- | secondary | x |
- | secondary_link | x |
- | tertiary | x |
- | tertiary_link | x |
- | residential | x |
- | service | x |
- | unclassified | x |
- | living_street | x |
- | road | x |
- | track | x |
- | path | x |
- | footway | x |
- | pedestrian | x |
- | steps | x |
- | cycleway | x |
- | bridleway | |
- | pier | |
+ Scenario: Bike - Routability of way types
+ # Bikes are allowed on footways etc because you can pull your bike at a lower speed.
+ # Pier is not allowed, since it's tagged using man_made=pier.
- Scenario: Bike - Routability of man_made structures
- Then routability should be
- | highway | man_made | bothw |
- | (nil) | (nil) | |
- | (nil) | pier | x |
+ Then routability should be
+ | highway | bothw |
+ | (nil) | |
+ | motorway | |
+ | motorway_link | |
+ | trunk | |
+ | trunk_link | |
+ | primary | x |
+ | primary_link | x |
+ | secondary | x |
+ | secondary_link | x |
+ | tertiary | x |
+ | tertiary_link | x |
+ | residential | x |
+ | service | x |
+ | unclassified | x |
+ | living_street | x |
+ | road | x |
+ | track | x |
+ | path | x |
+ | footway | x |
+ | pedestrian | x |
+ | steps | x |
+ | cycleway | x |
+ | bridleway | |
+ | pier | |
+
+ Scenario: Bike - Routability of man_made structures
+ Then routability should be
+ | highway | man_made | bothw |
+ | (nil) | (nil) | |
+ | (nil) | pier | x |
diff --git a/features/car/access.feature b/features/car/access.feature
index 97e61c5..37dfed4 100644
--- a/features/car/access.feature
+++ b/features/car/access.feature
@@ -1,144 +1,144 @@
@routing @car @access
Feature: Car - Restricted access
-Reference: http://wiki.openstreetmap.org/wiki/Key:access
+# Reference: http://wiki.openstreetmap.org/wiki/Key:access
- Background:
- Given the profile "car"
-
- Scenario: Car - Access tag hierachy on ways
- Then routability should be
- | access | vehicle | motor_vehicle | motorcar | bothw |
- | | | | | x |
- | yes | | | | x |
- | no | | | | |
- | | yes | | | x |
- | | no | | | |
- | no | yes | | | x |
- | yes | no | | | |
- | | | yes | | x |
- | | | no | | |
- | no | | yes | | x |
- | yes | | no | | |
- | | no | yes | | x |
- | | yes | no | | |
- | | | | yes | x |
- | | | | no | |
- | no | | | yes | x |
- | yes | | | no | |
- | | no | | yes | x |
- | | yes | | no | |
- | | | no | yes | x |
- | | | yes | no | |
+ Background:
+ Given the profile "car"
- Scenario: Car - Access tag hierachy on nodes
- Then routability should be
- | node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
- | | | | | x |
- | yes | | | | x |
- | no | | | | |
- | | yes | | | x |
- | | no | | | |
- | no | yes | | | x |
- | yes | no | | | |
- | | | yes | | x |
- | | | no | | |
- | no | | yes | | x |
- | yes | | no | | |
- | | no | yes | | x |
- | | yes | no | | |
- | | | | yes | x |
- | | | | no | |
- | no | | | yes | x |
- | yes | | | no | |
- | | no | | yes | x |
- | | yes | | no | |
- | | | no | yes | x |
- | | | yes | no | |
+ Scenario: Car - Access tag hierachy on ways
+ Then routability should be
+ | access | vehicle | motor_vehicle | motorcar | bothw |
+ | | | | | x |
+ | yes | | | | x |
+ | no | | | | |
+ | | yes | | | x |
+ | | no | | | |
+ | no | yes | | | x |
+ | yes | no | | | |
+ | | | yes | | x |
+ | | | no | | |
+ | no | | yes | | x |
+ | yes | | no | | |
+ | | no | yes | | x |
+ | | yes | no | | |
+ | | | | yes | x |
+ | | | | no | |
+ | no | | | yes | x |
+ | yes | | | no | |
+ | | no | | yes | x |
+ | | yes | | no | |
+ | | | no | yes | x |
+ | | | yes | no | |
- Scenario: Car - Overwriting implied acccess on ways
- Then routability should be
- | highway | access | vehicle | motor_vehicle | motorcar | bothw |
- | primary | | | | | x |
- | runway | | | | | |
- | primary | no | | | | |
- | primary | | no | | | |
- | primary | | | no | | |
- | primary | | | | no | |
- | runway | yes | | | | x |
- | runway | | yes | | | x |
- | runway | | | yes | | x |
- | runway | | | | yes | x |
+ Scenario: Car - Access tag hierachy on nodes
+ Then routability should be
+ | node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
+ | | | | | x |
+ | yes | | | | x |
+ | no | | | | |
+ | | yes | | | x |
+ | | no | | | |
+ | no | yes | | | x |
+ | yes | no | | | |
+ | | | yes | | x |
+ | | | no | | |
+ | no | | yes | | x |
+ | yes | | no | | |
+ | | no | yes | | x |
+ | | yes | no | | |
+ | | | | yes | x |
+ | | | | no | |
+ | no | | | yes | x |
+ | yes | | | no | |
+ | | no | | yes | x |
+ | | yes | | no | |
+ | | | no | yes | x |
+ | | | yes | no | |
- Scenario: Car - Overwriting implied acccess on nodes
- Then routability should be
- | highway | node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
- | primary | | | | | x |
- | runway | | | | | |
- | primary | no | | | | |
- | primary | | no | | | |
- | primary | | | no | | |
- | primary | | | | no | |
- | runway | yes | | | | |
- | runway | | yes | | | |
- | runway | | | yes | | |
- | runway | | | | yes | |
-
- Scenario: Car - Access tags on ways
- Then routability should be
- | access | bothw |
- | yes | x |
- | permissive | x |
- | designated | x |
- | no | |
- | private | |
- | agricultural | |
- | forestry | |
- | some_tag | x |
+ Scenario: Car - Overwriting implied acccess on ways
+ Then routability should be
+ | highway | access | vehicle | motor_vehicle | motorcar | bothw |
+ | primary | | | | | x |
+ | runway | | | | | |
+ | primary | no | | | | |
+ | primary | | no | | | |
+ | primary | | | no | | |
+ | primary | | | | no | |
+ | runway | yes | | | | x |
+ | runway | | yes | | | x |
+ | runway | | | yes | | x |
+ | runway | | | | yes | x |
+ Scenario: Car - Overwriting implied acccess on nodes
+ Then routability should be
+ | highway | node/access | node/vehicle | node/motor_vehicle | node/motorcar | bothw |
+ | primary | | | | | x |
+ | runway | | | | | |
+ | primary | no | | | | |
+ | primary | | no | | | |
+ | primary | | | no | | |
+ | primary | | | | no | |
+ | runway | yes | | | | |
+ | runway | | yes | | | |
+ | runway | | | yes | | |
+ | runway | | | | yes | |
- Scenario: Car - Access tags on nodes
- Then routability should be
- | node/access | bothw |
- | yes | x |
- | permissive | x |
- | designated | x |
- | no | |
- | private | |
- | agricultural | |
- | forestry | |
- | some_tag | x |
+ Scenario: Car - Access tags on ways
+ Then routability should be
+ | access | bothw |
+ | yes | x |
+ | permissive | x |
+ | designated | x |
+ | no | |
+ | private | |
+ | agricultural | |
+ | forestry | |
+ | some_tag | x |
- Scenario: Car - Access tags on both node and way
- Then routability should be
- | access | node/access | bothw |
- | yes | yes | x |
- | yes | no | |
- | yes | some_tag | x |
- | no | yes | |
- | no | no | |
- | no | some_tag | |
- | some_tag | yes | x |
- | some_tag | no | |
- | some_tag | some_tag | x |
- Scenario: Car - Access combinations
- Then routability should be
- | highway | accesss | vehicle | motor_vehicle | motorcar | bothw |
- | runway | private | | | permissive | x |
- | primary | forestry | | yes | | x |
- | cycleway | | | designated | | x |
- | residential | | yes | no | | |
- | motorway | yes | permissive | | private | |
- | trunk | agricultural | designated | permissive | no | |
+ Scenario: Car - Access tags on nodes
+ Then routability should be
+ | node/access | bothw |
+ | yes | x |
+ | permissive | x |
+ | designated | x |
+ | no | |
+ | private | |
+ | agricultural | |
+ | forestry | |
+ | some_tag | x |
- Scenario: Car - Ignore access tags for other modes
- Then routability should be
- | highway | foot | bicycle | psv | motorhome | bothw |
- | runway | yes | | | | |
- | primary | no | | | | x |
- | runway | | yes | | | |
- | primary | | no | | | x |
- | runway | | | yes | | |
- | primary | | | no | | x |
- | runway | | | | yes | |
- | primary | | | | no | x |
+ Scenario: Car - Access tags on both node and way
+ Then routability should be
+ | access | node/access | bothw |
+ | yes | yes | x |
+ | yes | no | |
+ | yes | some_tag | x |
+ | no | yes | |
+ | no | no | |
+ | no | some_tag | |
+ | some_tag | yes | x |
+ | some_tag | no | |
+ | some_tag | some_tag | x |
+
+ Scenario: Car - Access combinations
+ Then routability should be
+ | highway | accesss | vehicle | motor_vehicle | motorcar | bothw |
+ | runway | private | | | permissive | x |
+ | primary | forestry | | yes | | x |
+ | cycleway | | | designated | | x |
+ | residential | | yes | no | | |
+ | motorway | yes | permissive | | private | |
+ | trunk | agricultural | designated | permissive | no | |
+
+ Scenario: Car - Ignore access tags for other modes
+ Then routability should be
+ | highway | foot | bicycle | psv | motorhome | bothw |
+ | runway | yes | | | | |
+ | primary | no | | | | x |
+ | runway | | yes | | | |
+ | primary | | no | | | x |
+ | runway | | | yes | | |
+ | primary | | | no | | x |
+ | runway | | | | yes | |
+ | primary | | | | no | x |
diff --git a/features/car/barrier.feature b/features/car/barrier.feature
index 9d37d35..e637049 100644
--- a/features/car/barrier.feature
+++ b/features/car/barrier.feature
@@ -1,38 +1,38 @@
@routing @car @barrier
Feature: Car - Barriers
- Background:
- Given the profile "car"
+ Background:
+ Given the profile "car"
- Scenario: Car - Barriers
- Then routability should be
- | node/barrier | bothw |
- | | x |
- | bollard | |
- | gate | x |
- | cattle_grid | x |
- | border_control | x |
- | toll_booth | x |
- | sally_port | x |
- | entrance | |
- | wall | |
- | fence | |
- | some_tag | |
+ Scenario: Car - Barriers
+ Then routability should be
+ | node/barrier | bothw |
+ | | x |
+ | bollard | |
+ | gate | x |
+ | cattle_grid | x |
+ | border_control | x |
+ | toll_booth | x |
+ | sally_port | x |
+ | entrance | x |
+ | wall | |
+ | fence | |
+ | some_tag | |
- Scenario: Car - Access tag trumphs barriers
- Then routability should be
- | node/barrier | node/access | bothw |
- | gate | | x |
- | gate | yes | x |
- | gate | permissive | x |
- | gate | designated | x |
- | gate | no | |
- | gate | private | |
- | gate | agricultural | |
- | wall | | |
- | wall | yes | x |
- | wall | permissive | x |
- | wall | designated | x |
- | wall | no | |
- | wall | private | |
- | wall | agricultural | |
+ Scenario: Car - Access tag trumphs barriers
+ Then routability should be
+ | node/barrier | node/access | bothw |
+ | gate | | x |
+ | gate | yes | x |
+ | gate | permissive | x |
+ | gate | designated | x |
+ | gate | no | |
+ | gate | private | |
+ | gate | agricultural | |
+ | wall | | |
+ | wall | yes | x |
+ | wall | permissive | x |
+ | wall | designated | x |
+ | wall | no | |
+ | wall | private | |
+ | wall | agricultural | |
diff --git a/features/car/destination.feature b/features/car/destination.feature
index 43059e1..506aa21 100644
--- a/features/car/destination.feature
+++ b/features/car/destination.feature
@@ -1,77 +1,77 @@
@routing @car @destination @todo
Feature: Car - Destination only, no passing through
- Background:
- Given the profile "car"
-
- Scenario: Car - Destination only street
- Given the node map
- | a | | | | e |
- | | b | c | d | |
- | | | | | |
- | x | | | | y |
+ Background:
+ Given the profile "car"
- And the ways
- | nodes | access |
- | ab | |
- | bcd | destination |
- | de | |
- | axye | |
+ Scenario: Car - Destination only street
+ Given the node map
+ | a | | | | e |
+ | | b | c | d | |
+ | | | | | |
+ | x | | | | y |
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ab,bcd |
- | a | d | ab,bcd |
- | a | e | axye |
- | e | d | de |
- | e | c | de,bcd |
- | e | b | de,bcd |
- | e | a | axye |
-
- Scenario: Car - Destination only street
- Given the node map
- | a | | | | e |
- | | b | c | d | |
- | | | | | |
- | x | | | | y |
+ And the ways
+ | nodes | access |
+ | ab | |
+ | bcd | destination |
+ | de | |
+ | axye | |
- And the ways
- | nodes | access |
- | ab | |
- | bc | destination |
- | cd | destination |
- | de | |
- | axye | |
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | a | c | ab,bcd |
+ | a | d | ab,bcd |
+ | a | e | axye |
+ | e | d | de |
+ | e | c | de,bcd |
+ | e | b | de,bcd |
+ | e | a | axye |
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ab,bc |
- | a | d | ab,bc,cd |
- | a | e | axye |
- | e | d | de |
- | e | c | de,dc |
- | e | b | de,dc,bc |
- | e | a | axye |
+ Scenario: Car - Destination only street
+ Given the node map
+ | a | | | | e |
+ | | b | c | d | |
+ | | | | | |
+ | x | | | | y |
- Scenario: Car - Routing inside a destination only area
- Given the node map
- | a | | c | | e |
- | | b | | d | |
- | x | | | | y |
+ And the ways
+ | nodes | access |
+ | ab | |
+ | bc | destination |
+ | cd | destination |
+ | de | |
+ | axye | |
- And the ways
- | nodes | access |
- | ab | destination |
- | bc | destination |
- | cd | destination |
- | de | destination |
- | axye | |
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | a | c | ab,bc |
+ | a | d | ab,bc,cd |
+ | a | e | axye |
+ | e | d | de |
+ | e | c | de,dc |
+ | e | b | de,dc,bc |
+ | e | a | axye |
- When I route I should get
- | from | to | route |
- | a | e | ab,bc,cd,de |
- | e | a | de,cd,bc,ab |
- | b | d | bc,cd |
- | d | b | cd,bc |
\ No newline at end of file
+ Scenario: Car - Routing inside a destination only area
+ Given the node map
+ | a | | c | | e |
+ | | b | | d | |
+ | x | | | | y |
+
+ And the ways
+ | nodes | access |
+ | ab | destination |
+ | bc | destination |
+ | cd | destination |
+ | de | destination |
+ | axye | |
+
+ When I route I should get
+ | from | to | route |
+ | a | e | ab,bc,cd,de |
+ | e | a | de,cd,bc,ab |
+ | b | d | bc,cd |
+ | d | b | cd,bc |
diff --git a/features/car/ferry.feature b/features/car/ferry.feature
index 3182c75..3e90cf0 100644
--- a/features/car/ferry.feature
+++ b/features/car/ferry.feature
@@ -1,30 +1,28 @@
@routing @car @ferry
Feature: Car - Handle ferry routes
- Background:
- Given the profile "car"
-
- Scenario: Car - Use a ferry route
- Given the node map
- | a | b | c | | |
- | | | d | | |
- | | | e | f | g |
-
- And the ways
- | nodes | highway | route | bicycle |
- | abc | primary | | |
- | cde | | ferry | yes |
- | efg | primary | | |
-
- When I route I should get
- | from | to | route |
- | a | g | abc,cde,efg |
- | b | f | abc,cde,efg |
- | e | c | cde |
- | e | b | cde,abc |
- | e | a | cde,abc |
- | c | e | cde |
- | c | f | cde,efg |
- | c | g | cde,efg |
+ Background:
+ Given the profile "car"
+ Scenario: Car - Use a ferry route
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+ And the ways
+ | nodes | highway | route | bicycle |
+ | abc | primary | | |
+ | cde | | ferry | yes |
+ | efg | primary | | |
+
+ When I route I should get
+ | from | to | route |
+ | a | g | abc,cde,efg |
+ | b | f | abc,cde,efg |
+ | e | c | cde |
+ | e | b | cde,abc |
+ | e | a | cde,abc |
+ | c | e | cde |
+ | c | f | cde,efg |
+ | c | g | cde,efg |
diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature
index 3e09a0a..9e77cde 100644
--- a/features/car/maxspeed.feature
+++ b/features/car/maxspeed.feature
@@ -1,54 +1,65 @@
@routing @maxspeed @car
Feature: Car - Max speed restrictions
+OSRM will use 4/5 of the projected free-flow speed.
- Background: Use specific speeds
- Given the profile "car"
- Given a grid size of 1000 meters
-
- Scenario: Car - Respect maxspeeds when lower that way type speed
- Given the node map
- | a | b | c |
-
- And the ways
- | nodes | highway | maxspeed |
- | ab | trunk | |
- | bc | trunk | 10 |
-
- When I route I should get
- | from | to | route | time |
- | a | b | ab | 42s ~10% |
- | b | c | bc | 360s ~10% |
-
- Scenario: Car - Do not ignore maxspeed when higher than way speed
- Given the node map
- | a | b | c |
-
- And the ways
- | nodes | highway | maxspeed |
- | ab | residential | |
- | bc | residential | 85 |
-
- When I route I should get
- | from | to | route | time |
- | a | b | ab | 144s ~10% |
- | b | c | bc | 42s ~10% |
-
- Scenario: Car - Forward/backward maxspeed
- Given the shortcuts
- | key | value |
- | car | 12s ~10% |
- | run | 73s ~10% |
- | walk | 146s ~10% |
- | snail | 720s ~10% |
-
- And a grid size of 100 meters
-
- Then routability should be
- | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw |
- | | | | car | car |
- | 10 | | | run | run |
- | | 10 | | run | car |
- | | | 10 | car | run |
- | 1 | 10 | | run | snail |
- | 1 | | 10 | snail | run |
- | 1 | 5 | 10 | walk | run |
+ Background: Use specific speeds
+ Given the profile "car"
+ Given a grid size of 1000 meters
+
+ Scenario: Car - Respect maxspeeds when lower that way type speed
+ Given the node map
+ | a | b | c |
+
+ And the ways
+ | nodes | highway | maxspeed |
+ | ab | trunk | |
+ | bc | trunk | 60 |
+
+ When I route I should get
+ | from | to | route | speed |
+ | a | b | ab | 67 km/h |
+ | b | c | bc | 48 km/h +- 1 |
+
+ Scenario: Car - Do not ignore maxspeed when higher than way speed
+ Given the node map
+ | a | b | c |
+
+ And the ways
+ | nodes | highway | maxspeed |
+ | ab | residential | |
+ | bc | residential | 90 |
+
+ When I route I should get
+ | from | to | route | speed |
+ | a | b | ab | 20 km/h |
+ | b | c | bc | 72 km/h +- 1 |
+
+ Scenario: Car - Forward/backward maxspeed
+ Given a grid size of 100 meters
+
+ Then routability should be
+ | highway | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw |
+ | primary | | | | 51 km/h | 51 km/h |
+ | primary | 60 | | | 48 km/h | 48 km/h |
+ | primary | | 60 | | 48 km/h | 65 km/h |
+ | primary | | | 60 | 51 km/h | 48 km/h |
+ | primary | 15 | 60 | | 48 km/h | 15 km/h +- 1 |
+ | primary | 15 | | 60 | 12 km/h +- 1| 48 km/h |
+ | primary | 15 | 30 | 60 | 24 km/h | 48 km/h |
+
+ Scenario: Car - Maxspeed should not allow routing on unroutable ways
+ Then routability should be
+ | highway | railway | access | maxspeed | maxspeed:forward | maxspeed:backward | bothw |
+ | primary | | | | | | x |
+ | secondary | | no | | | | |
+ | secondary | | no | 100 | | | |
+ | secondary | | no | | 100 | | |
+ | secondary | | no | | | 100 | |
+ | (nil) | train | | | | | |
+ | (nil) | train | | 100 | | | |
+ | (nil) | train | | | 100 | | |
+ | (nil) | train | | | | 100 | |
+ | runway | | | | | | |
+ | runway | | | 100 | | | |
+ | runway | | | | 100 | | |
+ | runway | | | | | 100 | |
diff --git a/features/car/names.feature b/features/car/names.feature
index d7d98b7..ac4bfc8 100644
--- a/features/car/names.feature
+++ b/features/car/names.feature
@@ -1,33 +1,33 @@
@routing @car @names
Feature: Car - Street names in instructions
- Background:
- Given the profile "car"
-
- Scenario: Car - A named street
- Given the node map
- | a | b |
- | | c |
-
- And the ways
- | nodes | name |
- | ab | My Way |
- | bc | Your Way |
-
- When I route I should get
- | from | to | route |
- | a | c | My Way,Your Way |
-
- @todo
- Scenario: Car - Use way type to describe unnamed ways
- Given the node map
- | a | b | c | d |
+ Background:
+ Given the profile "car"
- And the ways
- | nodes | highway | name |
- | ab | tertiary | |
- | bcd | residential | |
+ Scenario: Car - A named street
+ Given the node map
+ | a | b |
+ | | c |
- When I route I should get
- | from | to | route |
- | a | c | tertiary,residential |
+ And the ways
+ | nodes | name |
+ | ab | My Way |
+ | bc | Your Way |
+
+ When I route I should get
+ | from | to | route |
+ | a | c | My Way,Your Way |
+
+ @todo
+ Scenario: Car - Use way type to describe unnamed ways
+ Given the node map
+ | a | b | c | d |
+
+ And the ways
+ | nodes | highway | name |
+ | ab | tertiary | |
+ | bcd | residential | |
+
+ When I route I should get
+ | from | to | route |
+ | a | c | tertiary,residential |
diff --git a/features/car/oneway.feature b/features/car/oneway.feature
index b181085..b47c3c6 100644
--- a/features/car/oneway.feature
+++ b/features/car/oneway.feature
@@ -1,73 +1,79 @@
@routing @car @oneway
Feature: Car - Oneway streets
-Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing
+# Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing
- Background:
- Given the profile "car"
-
- Scenario: Car - Simple oneway
- Then routability should be
- | highway | oneway | forw | backw |
- | primary | yes | x | |
+ Background:
+ Given the profile "car"
- Scenario: Car - Simple reverse oneway
- Then routability should be
- | highway | oneway | forw | backw |
- | primary | -1 | | x |
+ Scenario: Car - Simple oneway
+ Then routability should be
+ | highway | oneway | forw | backw |
+ | primary | yes | x | |
- Scenario: Car - Implied onewatys
- Then routability should be
- | highway | junction | forw | backw |
- | motorway | | x | |
- | motorway_link | | x | |
- | primary | | x | x |
- | motorway | roundabout | x | |
- | motorway_link | roundabout | x | |
- | primary | roundabout | x | |
+ Scenario: Car - Simple reverse oneway
+ Then routability should be
+ | highway | oneway | forw | backw |
+ | primary | -1 | | x |
- Scenario: Car - Around the Block
- Given the node map
- | a | b |
- | d | c |
-
- And the ways
- | nodes | oneway |
- | ab | yes |
- | bc | |
- | cd | |
- | da | |
-
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | a | bc,cd,da |
-
- Scenario: Car - Cars should not be affected by bicycle tags
- Then routability should be
- | highway | junction | oneway | oneway:bicycle | forw | backw |
- | primary | | yes | yes | x | |
- | primary | | yes | no | x | |
- | primary | | yes | -1 | x | |
- | primary | | no | yes | x | x |
- | primary | | no | no | x | x |
- | primary | | no | -1 | x | x |
- | primary | | -1 | yes | | x |
- | primary | | -1 | no | | x |
- | primary | | -1 | -1 | | x |
- | primary | roundabout | | yes | x | |
- | primary | roundabout | | no | x | |
- | primary | roundabout | | -1 | x | |
+ Scenario: Car - Implied oneways
+ Then routability should be
+ | highway | junction | forw | backw |
+ | motorway | | x | |
+ | motorway_link | | x | |
+ | primary | | x | x |
+ | motorway | roundabout | x | |
+ | motorway_link | roundabout | x | |
+ | primary | roundabout | x | |
- Scenario: Car - Two consecutive oneways
- Given the node map
- | a | b | c |
+ Scenario: Car - Overrule implied oneway
+ Then routability should be
+ | highway | oneway | forw | backw |
+ | motorway | no | x | x |
+ | motorway_link | no | x | x |
- And the ways
- | nodes | oneway |
- | ab | yes |
- | bc | yes |
+ Scenario: Car - Around the Block
+ Given the node map
+ | a | b |
+ | d | c |
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+ | bc | |
+ | cd | |
+ | da | |
- When I route I should get
- | from | to | route |
- | a | c | ab,bc |
\ No newline at end of file
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | b | a | bc,cd,da |
+
+ Scenario: Car - Cars should not be affected by bicycle tags
+ Then routability should be
+ | highway | junction | oneway | oneway:bicycle | forw | backw |
+ | primary | | yes | yes | x | |
+ | primary | | yes | no | x | |
+ | primary | | yes | -1 | x | |
+ | primary | | no | yes | x | x |
+ | primary | | no | no | x | x |
+ | primary | | no | -1 | x | x |
+ | primary | | -1 | yes | | x |
+ | primary | | -1 | no | | x |
+ | primary | | -1 | -1 | | x |
+ | 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 |
diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature
index 91ba298..b4ccdbe 100644
--- a/features/car/restrictions.feature
+++ b/features/car/restrictions.feature
@@ -1,251 +1,314 @@
@routing @car @restrictions
Feature: Car - Turn restrictions
- Handle turn restrictions as defined by http://wiki.openstreetmap.org/wiki/Relation:restriction
- Note that if u-turns are allowed, turn restrictions can lead to suprising, but correct, routes.
-
- Background: Use car routing
- Given the profile "car"
-
- @no_turning
- Scenario: Car - No left turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | nj | -1 |
- | wj | -1 |
- | ej | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | wj | j | no_left_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @no_turning
- Scenario: Car - No right turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | nj | -1 |
- | wj | -1 |
- | ej | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | ej | j | no_right_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | sj,nj |
- | s | e | |
-
- @no_turning
- Scenario: Car - No u-turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | nj | -1 |
- | wj | -1 |
- | ej | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | wj | j | no_u_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @no_turning
- Scenario: Car - Handle any no_* relation
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | nj | -1 |
- | wj | -1 |
- | ej | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | wj | j | no_weird_zigzags |
-
- When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | sj,ej |
-
- @only_turning
- Scenario: Car - Only left turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | nj | -1 |
- | wj | -1 |
- | ej | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | wj | j | only_left_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | sj,wj |
- | s | n | |
- | s | e | |
-
- @only_turning
- Scenario: Car - Only right turn
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | nj | -1 |
- | wj | -1 |
- | ej | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | ej | j | only_right_turn |
-
- When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | |
- | s | e | sj,ej |
-
- @only_turning
- Scenario: Car - Only straight on
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | nj | -1 |
- | wj | -1 |
- | ej | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | nj | j | only_straight_on |
-
- When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | |
-
- @no_turning
- Scenario: Car - Handle any only_* restriction
- Given the node map
- | | n | |
- | w | j | e |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | nj | -1 |
- | wj | -1 |
- | ej | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction |
- | restriction | sj | nj | j | only_weird_zigzags |
-
- When I route I should get
- | from | to | route |
- | s | w | |
- | s | n | sj,nj |
- | s | e | |
-
- @except
- Scenario: Car - Except tag and on no_ restrictions
- Given the node map
- | b | x | c |
- | a | j | d |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | no |
- | xj | -1 |
- | aj | -1 |
- | bj | no |
- | cj | no |
- | dj | -1 |
-
- And the relations
- | type | way:from | way:to | node:via | restriction | except |
- | restriction | sj | aj | j | no_left_turn | motorcar |
- | restriction | sj | bj | j | no_left_turn | |
- | restriction | sj | cj | j | no_right_turn | |
- | restriction | sj | dj | j | no_right_turn | motorcar |
-
- When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | |
- | s | c | |
- | s | d | sj,dj |
-
- @except
- Scenario: Car - Except tag and on only_ restrictions
- Given the node map
- | a | | b |
- | | j | |
- | | s | |
-
- And the ways
- | nodes | oneway |
- | sj | yes |
- | aj | no |
- | bj | no |
-
- And the relations
- | type | way:from | way:to | node:via | restriction | except |
- | restriction | sj | aj | j | only_straight_on | motorcar |
-
- When I route I should get
- | from | to | route |
- | s | a | sj,aj |
- | s | b | sj,bj |
+# Handle turn restrictions as defined by http://wiki.openstreetmap.org/wiki/Relation:restriction
+# Note that if u-turns are allowed, turn restrictions can lead to suprising, but correct, routes.
+
+ Background: Use car routing
+ Given the profile "car"
+
+ @no_turning
+ Scenario: Car - No left turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_left_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Car - No straight on
+ Given the node map
+ | a | b | j | d | e |
+ | v | | | | z |
+ | | w | x | y | |
+
+ And the ways
+ | nodes | oneway |
+ | ab | no |
+ | bj | no |
+ | jd | no |
+ | de | no |
+ | av | yes |
+ | vw | yes |
+ | wx | yes |
+ | xy | yes |
+ | yz | yes |
+ | ze | yes |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | bj | jd | j | no_straight_on |
+
+ When I route I should get
+ | from | to | route |
+ | a | e | av,vw,wx,xy,yz,ze |
+
+ @no_turning
+ Scenario: Car - No right turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | ej | j | no_right_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | |
+
+ @no_turning
+ Scenario: Car - No u-turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_u_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Car - Handle any no_* relation
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_weird_zigzags |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @only_turning
+ Scenario: Car - Only left turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | only_left_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | |
+ | s | e | |
+
+ @only_turning
+ Scenario: Car - Only right turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | ej | j | only_right_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | |
+ | s | n | |
+ | s | e | sj,ej |
+
+ @only_turning
+ Scenario: Car - Only straight on
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | nj | j | only_straight_on |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj |
+ | s | e | |
+
+ @no_turning
+ Scenario: Car - Handle any only_* restriction
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | nj | j | only_weird_zigzags |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj |
+ | s | e | |
+
+ @except
+ Scenario: Car - Except tag and on no_ restrictions
+ Given the node map
+ | b | x | c |
+ | a | j | d |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | no |
+ | xj | -1 |
+ | aj | -1 |
+ | bj | no |
+ | cj | no |
+ | dj | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction | except |
+ | restriction | sj | aj | j | no_left_turn | motorcar |
+ | restriction | sj | bj | j | no_left_turn | |
+ | restriction | sj | cj | j | no_right_turn | |
+ | restriction | sj | dj | j | no_right_turn | motorcar |
+
+ When I route I should get
+ | from | to | route |
+ | s | a | sj,aj |
+ | s | b | |
+ | s | c | |
+ | s | d | sj,dj |
+
+ @except
+ Scenario: Car - Except tag and on only_ restrictions
+ Given the node map
+ | a | | b |
+ | | j | |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | aj | no |
+ | bj | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction | except |
+ | restriction | sj | aj | j | only_straight_on | motorcar |
+
+ When I route I should get
+ | from | to | route |
+ | s | a | sj,aj |
+ | s | b | sj,bj |
+
+ @except
+ Scenario: Car - Several only_ restrictions at the same segment
+ Given the node map
+ | | | | | y | | | | |
+ | i | j | f | b | x | a | e | g | h |
+ | | | | | | | | | |
+ | | | | c | | d | | | |
+
+ And the ways
+ | nodes | oneway |
+ | fb | no |
+ | bx | -1 |
+ | xa | no |
+ | ae | no |
+ | cb | no |
+ | dc | -1 |
+ | da | no |
+ | fj | no |
+ | jf | no |
+ | ge | no |
+ | hg | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | ae | xa | a | only_straight_on |
+ | restriction | xb | fb | b | only_straight_on |
+ | restriction | cb | bx | b | only_right_turn |
+ | restriction | da | ae | a | only_right_turn |
+
+ When I route I should get
+ | from | to | route |
+ | e | f | ae,xa,bx,fb |
+ | c | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb |
+ | d | f | da,ae,ge,hg,hg,ge,ae,xa,bx,fb |
diff --git a/features/car/roundabout.feature b/features/car/roundabout.feature
new file mode 100644
index 0000000..2965479
--- /dev/null
+++ b/features/car/roundabout.feature
@@ -0,0 +1,30 @@
+ at routing @car @roundabout @instruction
+Feature: Roundabout Instructions
+
+ Background:
+ Given the profile "car"
+
+ Scenario: Car - Roundabout instructions
+ Given the node map
+ | | | v | | |
+ | | | d | | |
+ | s | a | | c | u |
+ | | | b | | |
+ | | | t | | |
+
+ And the ways
+ | nodes | junction |
+ | sa | |
+ | tb | |
+ | uc | |
+ | vd | |
+ | abcda | roundabout |
+
+ When I route I should get
+ | from | to | route | turns |
+ | s | t | sa,tb | head,enter_roundabout-1,destination |
+ | s | u | sa,uc | head,enter_roundabout-2,destination |
+ | s | v | sa,vd | head,enter_roundabout-3,destination |
+ | u | v | uc,vd | head,enter_roundabout-1,destination |
+ | u | s | uc,sa | head,enter_roundabout-2,destination |
+ | u | t | uc,tb | head,enter_roundabout-3,destination |
diff --git a/features/car/shuttle_train.feature b/features/car/shuttle_train.feature
index e58ffa2..97f32e5 100644
--- a/features/car/shuttle_train.feature
+++ b/features/car/shuttle_train.feature
@@ -1,33 +1,31 @@
@routing @car @shuttle_train
Feature: Car - Handle ferryshuttle train routes
- Background:
- Given the profile "car"
+ Background:
+ Given the profile "car"
- Scenario: Car - Use a ferry route
- Given the node map
- | a | b | c | | | |
- | | | d | | | |
- | | | e | f | g | h |
-
- And the ways
- | nodes | highway | route | bicycle |
- | abc | primary | | |
- | cde | | shuttle_train | yes |
- | ef | primary | | |
- | fg | | ferry_man | |
- | gh | primary | | no |
-
- When I route I should get
- | from | to | route |
- | a | f | abc,cde,ef |
- | b | f | abc,cde,ef |
- | e | c | cde |
- | e | b | cde,abc |
- | e | a | cde,abc |
- | c | e | cde |
- | c | f | cde,ef |
- | f | g | |
- | g | h | gh |
+ Scenario: Car - Use a ferry route
+ Given the node map
+ | a | b | c | | | |
+ | | | d | | | |
+ | | | e | f | g | h |
+ And the ways
+ | nodes | highway | route | bicycle |
+ | abc | primary | | |
+ | cde | | shuttle_train | yes |
+ | ef | primary | | |
+ | fg | | ferry_man | |
+ | gh | primary | | no |
+ When I route I should get
+ | from | to | route |
+ | a | f | abc,cde,ef |
+ | b | f | abc,cde,ef |
+ | e | c | cde |
+ | e | b | cde,abc |
+ | e | a | cde,abc |
+ | c | e | cde |
+ | c | f | cde,ef |
+ | f | g | |
+ | g | h | gh |
diff --git a/features/car/speed.feature b/features/car/speed.feature
new file mode 100644
index 0000000..4f54a33
--- /dev/null
+++ b/features/car/speed.feature
@@ -0,0 +1,24 @@
+ at routing @car @speed
+Feature: Car - speeds
+
+ Background:
+ Given the profile "car"
+ And a grid size of 1000 meters
+
+ Scenario: Car - speed of various way types
+ Then routability should be
+ | highway | oneway | bothw |
+ | motorway | no | 72 km/h |
+ | motorway_link | no | 60 km/h |
+ | trunk | no | 67 km/h +- 1 |
+ | trunk_link | no | 55 km/h +- 1 |
+ | primary | no | 52 km/h +- 1 |
+ | primary_link | no | 48 km/h |
+ | secondary | no | 43 km/h +- 1 |
+ | secondary_link | no | 40 km/h |
+ | tertiary | no | 32 km/h |
+ | tertiary_link | no | 24 km/h |
+ | unclassified | no | 20 km/h |
+ | residential | no | 20 km/h |
+ | living_street | no | 8 km/h |
+ | service | no | 12 km/h |
diff --git a/features/car/way.feature b/features/car/way.feature
index 8ca62a5..d6d324c 100644
--- a/features/car/way.feature
+++ b/features/car/way.feature
@@ -1,33 +1,33 @@
@routing @car @way
Feature: Car - Accessability of different way types
- Background:
- Given the profile "car"
+ Background:
+ Given the profile "car"
- Scenario: Car - Basic access
- Then routability should be
- | highway | forw |
- | (nil) | |
- | motorway | x |
- | motorway_link | x |
- | trunk | x |
- | trunk_link | x |
- | primary | x |
- | primary_link | x |
- | secondary | x |
- | secondary_link | x |
- | tertiary | x |
- | tertiary_link | x |
- | residential | x |
- | service | x |
- | unclassified | x |
- | living_street | x |
- | road | |
- | track | |
- | path | |
- | footway | |
- | pedestrian | |
- | steps | |
- | pier | |
- | cycleway | |
- | bridleway | |
\ No newline at end of file
+ Scenario: Car - Basic access
+ Then routability should be
+ | highway | forw |
+ | (nil) | |
+ | motorway | x |
+ | motorway_link | x |
+ | trunk | x |
+ | trunk_link | x |
+ | primary | x |
+ | primary_link | x |
+ | secondary | x |
+ | secondary_link | x |
+ | tertiary | x |
+ | tertiary_link | x |
+ | residential | x |
+ | service | x |
+ | unclassified | x |
+ | living_street | x |
+ | road | |
+ | track | |
+ | path | |
+ | footway | |
+ | pedestrian | |
+ | steps | |
+ | pier | |
+ | cycleway | |
+ | bridleway | |
diff --git a/features/foot/access.feature b/features/foot/access.feature
new file mode 100644
index 0000000..4d81d0e
--- /dev/null
+++ b/features/foot/access.feature
@@ -0,0 +1,95 @@
+ at routing @foot @access
+Feature: Foot - Access tags on ways
+# Reference: http://wiki.openstreetmap.org/wiki/Key:access
+
+ Background:
+ Given the profile "foot"
+
+ Scenario: Foot - Access tag hierachy on ways
+ Then routability should be
+ | highway | access | foot | bothw |
+ | footway | | | x |
+ | footway | | yes | x |
+ | footway | | no | |
+ | footway | yes | | x |
+ | footway | yes | yes | x |
+ | footway | yes | no | |
+ | footway | no | | |
+ | footway | no | yes | x |
+ | footway | no | no | |
+ | motorway | | | |
+ | motorway | | yes | x |
+ | motorway | | no | |
+ | motorway | yes | | x |
+ | motorway | yes | yes | x |
+ | motorway | yes | no | |
+ | motorway | no | | |
+ | motorway | no | yes | x |
+ | motorway | no | no | |
+
+
+ Scenario: Foot - Overwriting implied acccess on ways
+ Then routability should be
+ | highway | access | foot | bothw |
+ | footway | | | x |
+ | motorway | | | |
+ | footway | no | | |
+ | footway | | | x |
+ | footway | | no | |
+ | motorway | yes | | x |
+ | motorway | | | |
+ | motorway | | yes | x |
+
+ Scenario: Foot - Access tags on ways
+ Then routability should be
+ | access | foot | bothw |
+ | | | x |
+ | yes | | x |
+ | permissive | | x |
+ | designated | | x |
+ | some_tag | | x |
+ | no | | |
+ | private | | |
+ | agricultural | | |
+ | forestery | | |
+ | | yes | x |
+ | | permissive | x |
+ | | designated | x |
+ | | some_tag | x |
+ | | no | |
+ | | private | |
+ | | agricultural | |
+ | | forestery | |
+
+ Scenario: Foot - Access tags on both node and way
+ Then routability should be
+ | access | node/access | bothw |
+ | yes | yes | x |
+ | yes | no | |
+ | yes | some_tag | x |
+ | no | yes | |
+ | no | no | |
+ | no | some_tag | |
+ | some_tag | yes | x |
+ | some_tag | no | |
+ | some_tag | some_tag | x |
+
+ Scenario: Foot - Access combinations
+ Then routability should be
+ | highway | access | foot | bothw |
+ | motorway | private | yes | x |
+ | footway | | permissive | x |
+ | track | forestry | permissive | x |
+ | footway | yes | no | |
+ | primary | | private | |
+ | residential | permissive | no | |
+
+ Scenario: Foot - Ignore access tags for other modes
+ Then routability should be
+ | highway | boat | motor_vehicle | moped | bothw |
+ | river | yes | | | |
+ | footway | no | | | x |
+ | motorway | | yes | | |
+ | footway | | no | | x |
+ | motorway | | | yes | |
+ | footway | | | no | x |
diff --git a/features/foot/access_node.feature b/features/foot/access_node.feature
new file mode 100644
index 0000000..5a4a131
--- /dev/null
+++ b/features/foot/access_node.feature
@@ -0,0 +1,50 @@
+ at routing @foot @access
+Feature: Foot - Access tags on nodes
+# Reference: http://wiki.openstreetmap.org/wiki/Key:access
+
+ Background:
+ Given the profile "foot"
+
+ Scenario: Foot - Access tag hierachy on nodes
+ Then routability should be
+ | node/access | node/foot | bothw |
+ | | | x |
+ | | yes | x |
+ | | no | |
+ | yes | | x |
+ | yes | yes | x |
+ | yes | no | |
+ | no | | |
+ | no | yes | x |
+ | no | no | |
+
+ Scenario: Foot - Overwriting implied acccess on nodes doesn't overwrite way
+ Then routability should be
+ | highway | node/access | node/foot | bothw |
+ | footway | | | x |
+ | footway | no | | |
+ | footway | | no | |
+ | motorway | | | |
+ | motorway | yes | | |
+ | motorway | | yes | |
+
+ Scenario: Foot - Access tags on nodes
+ Then routability should be
+ | node/access | node/foot | bothw |
+ | | | x |
+ | yes | | x |
+ | permissive | | x |
+ | designated | | x |
+ | some_tag | | x |
+ | no | | |
+ | private | | |
+ | agricultural | | |
+ | forestery | | |
+ | no | yes | x |
+ | no | permissive | x |
+ | no | designated | x |
+ | no | some_tag | x |
+ | yes | no | |
+ | yes | private | |
+ | yes | agricultural | |
+ | yes | forestery | |
diff --git a/features/foot/area.feature b/features/foot/area.feature
new file mode 100644
index 0000000..6edd585
--- /dev/null
+++ b/features/foot/area.feature
@@ -0,0 +1,103 @@
+ at routing @foot @area
+Feature: Foot - Squares and other areas
+
+ Background:
+ Given the profile "foot"
+
+ @square
+ Scenario: Foot - Route along edge of a squares
+ Given the node map
+ | x | |
+ | a | b |
+ | d | c |
+
+ And the ways
+ | nodes | area | highway |
+ | xa | | primary |
+ | abcda | yes | residential |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | abcda |
+ | a | d | abcda |
+ | b | c | abcda |
+ | c | b | abcda |
+ | c | d | abcda |
+ | d | c | abcda |
+ | d | a | abcda |
+ | a | d | abcda |
+
+ @building
+ Scenario: Foot - Don't route on buildings
+ Given the node map
+ | x | |
+ | a | b |
+ | d | c |
+
+ And the ways
+ | nodes | highway | area | building | access |
+ | xa | primary | | | |
+ | abcda | (nil) | yes | yes | yes |
+
+ When I route I should get
+ | from | to | route |
+ | 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: Foot - parking areas
+ Given the node map
+ | e | | | f |
+ | x | a | b | y |
+ | | d | c | |
+
+ And the ways
+ | nodes | highway | amenity |
+ | xa | primary | |
+ | by | primary | |
+ | xefy | primary | |
+ | abcda | (nil) | parking |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,abcda,by |
+ | y | x | by,abcda,xa |
+ | a | b | abcda |
+ | a | d | abcda |
+ | b | c | abcda |
+ | c | b | abcda |
+ | c | d | abcda |
+ | d | c | abcda |
+ | d | a | abcda |
+ | a | d | abcda |
+
+ @train @platform
+ Scenario: Foot - railway platforms
+ Given the node map
+ | x | a | b | y |
+ | | d | c | |
+
+ And the ways
+ | nodes | highway | railway |
+ | xa | primary | |
+ | by | primary | |
+ | abcda | (nil) | platform |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,abcda,by |
+ | y | x | by,abcda,xa |
+ | a | b | abcda |
+ | a | d | abcda |
+ | b | c | abcda |
+ | c | b | abcda |
+ | c | d | abcda |
+ | d | c | abcda |
+ | d | a | abcda |
+ | a | d | abcda |
diff --git a/features/foot/barrier.feature b/features/foot/barrier.feature
new file mode 100644
index 0000000..18fa4de
--- /dev/null
+++ b/features/foot/barrier.feature
@@ -0,0 +1,39 @@
+ at routing @foot @barrier
+Feature: Barriers
+
+ Background:
+ Given the profile "foot"
+
+ Scenario: Foot - Barriers
+ Then routability should be
+ | node/barrier | bothw |
+ | | x |
+ | bollard | x |
+ | gate | x |
+ | cycle_barrier | x |
+ | cattle_grid | x |
+ | border_control | x |
+ | toll_booth | x |
+ | sally_port | x |
+ | entrance | x |
+ | wall | |
+ | fence | |
+ | some_tag | |
+
+ Scenario: Foot - Access tag trumphs barriers
+ Then routability should be
+ | node/barrier | node/access | bothw |
+ | bollard | | x |
+ | bollard | yes | x |
+ | bollard | permissive | x |
+ | bollard | designated | x |
+ | bollard | no | |
+ | bollard | private | |
+ | bollard | agricultural | |
+ | wall | | |
+ | wall | yes | x |
+ | wall | permissive | x |
+ | wall | designated | x |
+ | gate | no | |
+ | gate | private | |
+ | gate | agricultural | |
diff --git a/features/foot/ferry.feature b/features/foot/ferry.feature
new file mode 100644
index 0000000..4308756
--- /dev/null
+++ b/features/foot/ferry.feature
@@ -0,0 +1,63 @@
+ at routing @foot @ferry
+Feature: Foot - Handle ferry routes
+
+ Background:
+ Given the profile "foot"
+
+ Scenario: Foot - Ferry route
+ Given the node map
+ | a | b | c | | |
+ | | | d | | |
+ | | | e | f | g |
+
+ And the ways
+ | nodes | highway | route | foot |
+ | abc | primary | | |
+ | cde | | ferry | yes |
+ | efg | primary | | |
+
+ When I route I should get
+ | from | to | route |
+ | a | g | abc,cde,efg |
+ | b | f | abc,cde,efg |
+ | e | c | cde |
+ | e | b | cde,abc |
+ | e | a | cde,abc |
+ | c | e | cde |
+ | c | f | cde,efg |
+ | c | g | cde,efg |
+
+ Scenario: Foot - Ferry duration, single node
+ Given the node map
+ | a | b | c | d |
+ | | | e | f |
+ | | | g | h |
+ | | | i | j |
+
+ And the ways
+ | nodes | highway | route | foot | duration |
+ | ab | primary | | | |
+ | cd | primary | | | |
+ | ef | primary | | | |
+ | gh | primary | | | |
+ | ij | primary | | | |
+ | bc | | ferry | yes | 0:01 |
+ | be | | ferry | yes | 0:10 |
+ | bg | | ferry | yes | 1:00 |
+ | bi | | ferry | yes | 10:00 |
+
+ Scenario: Foot - Ferry duration, multiple nodes
+ Given the node map
+ | x | | | | | y |
+ | | a | b | c | d | |
+
+ And the ways
+ | nodes | highway | route | foot | duration |
+ | xa | primary | | | |
+ | yd | primary | | | |
+ | abcd | | ferry | yes | 1:00 |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | d | abcd | 3600s +-10 |
+ | d | a | abcd | 3600s +-10 |
diff --git a/features/foot/maxspeed.feature b/features/foot/maxspeed.feature
index 8a3571a..d4e3583 100644
--- a/features/foot/maxspeed.feature
+++ b/features/foot/maxspeed.feature
@@ -1,20 +1,19 @@
- at routing @maxspeed @foot
+ at routing @foot @maxspeed
Feature: Foot - Ignore max speed restrictions
Background: Use specific speeds
- Given the profile "foot"
+ Given the profile "foot"
- at todo
-Scenario: Foot - Ignore maxspeed
- Then routability should be
- | highway | maxspeed | bothw |
- | residential | | 145s ~10% |
- | residential | 1 | 145s ~10% |
- | residential | 100 | 145s ~10% |
- | residential | 1 | 145s ~10% |
- | residential | 1mph | 145s ~10% |
- | residential | 1 mph | 145s ~10% |
- | residential | 1unknown | 145s ~10% |
- | residential | 1 unknown | 145s ~10% |
- | residential | none | 145s ~10% |
- | residential | signals | 145s ~10% |
+ Scenario: Foot - Ignore maxspeed
+ Then routability should be
+ | highway | maxspeed | bothw |
+ | residential | | 145s ~10% |
+ | residential | 1 | 145s ~10% |
+ | residential | 100 | 145s ~10% |
+ | residential | 1 | 145s ~10% |
+ | residential | 1mph | 145s ~10% |
+ | residential | 1 mph | 145s ~10% |
+ | residential | 1unknown | 145s ~10% |
+ | residential | 1 unknown | 145s ~10% |
+ | residential | none | 145s ~10% |
+ | residential | signals | 145s ~10% |
diff --git a/features/foot/names.feature b/features/foot/names.feature
new file mode 100644
index 0000000..d5fdcc7
--- /dev/null
+++ b/features/foot/names.feature
@@ -0,0 +1,33 @@
+ at routing @foot @names
+Feature: Foot - Street names in instructions
+
+ Background:
+ Given the profile "foot"
+
+ Scenario: Foot - A named street
+ Given the node map
+ | a | b |
+ | | c |
+
+ And the ways
+ | nodes | name |
+ | ab | My Way |
+ | bc | Your Way |
+
+ When I route I should get
+ | from | to | route |
+ | a | c | My Way,Your Way |
+
+ @unnamed
+ Scenario: Foot - Use way type to describe unnamed ways
+ Given the node map
+ | a | b | c | d |
+
+ And the ways
+ | nodes | highway | name |
+ | ab | footway | |
+ | bcd | track | |
+
+ When I route I should get
+ | from | to | route |
+ | a | d | {highway:footway},{highway:track} |
diff --git a/features/foot/oneway.feature b/features/foot/oneway.feature
index e1c96e3..77562e5 100644
--- a/features/foot/oneway.feature
+++ b/features/foot/oneway.feature
@@ -1,60 +1,60 @@
@routing @foot @oneway
Feature: Foot - Oneway streets
-Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing
+# Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing
- Background:
- Given the profile "foot"
-
- Scenario: Foot - Walking should not be affected by oneways
- Then routability should be
- | oneway | bothw |
- | | x |
- | nonsense | x |
- | no | x |
- | false | x |
- | 0 | x |
- | yes | x |
- | true | x |
- | 1 | x |
- | -1 | x |
+ Background:
+ Given the profile "foot"
- Scenario: Foot - Walking and roundabouts
- Then routability should be
- | junction | bothw |
- | roundarout | x |
+ Scenario: Foot - Walking should not be affected by oneways
+ Then routability should be
+ | oneway | bothw |
+ | | x |
+ | nonsense | x |
+ | no | x |
+ | false | x |
+ | 0 | x |
+ | yes | x |
+ | true | x |
+ | 1 | x |
+ | -1 | x |
- Scenario: Foot - Oneway:foot tag should not cause walking on big roads
- Then routability should be
- | highway | oneway:foot | bothw |
- | footway | | x |
- | motorway | yes | |
- | motorway_link | yes | |
- | trunk | yes | |
- | trunk_link | yes | |
- | motorway | no | |
- | motorway_link | no | |
- | trunk | no | |
- | trunk_link | no | |
- | motorway | -1 | |
- | motorway_link | -1 | |
- | trunk | -1 | |
- | trunk_link | -1 | |
-
- Scenario: Foot - Walking should respect oneway:foot
- Then routability should be
- | oneway:foot | oneway | junction | forw | backw |
- | yes | | | x | |
- | yes | yes | | x | |
- | yes | no | | x | |
- | yes | -1 | | x | |
- | yes | | roundabout | x | |
- | no | | | x | x |
- | no | yes | | x | x |
- | no | no | | x | x |
- | no | -1 | | x | x |
- | no | | roundabout | x | x |
- | -1 | | | | x |
- | -1 | yes | | | x |
- | -1 | no | | | x |
- | -1 | -1 | | | x |
- | -1 | | roundabout | | x |
\ No newline at end of file
+ Scenario: Foot - Walking and roundabouts
+ Then routability should be
+ | junction | bothw |
+ | roundarout | x |
+
+ Scenario: Foot - Oneway:foot tag should not cause walking on big roads
+ Then routability should be
+ | highway | oneway:foot | bothw |
+ | footway | | x |
+ | motorway | yes | |
+ | motorway_link | yes | |
+ | trunk | yes | |
+ | trunk_link | yes | |
+ | motorway | no | |
+ | motorway_link | no | |
+ | trunk | no | |
+ | trunk_link | no | |
+ | motorway | -1 | |
+ | motorway_link | -1 | |
+ | trunk | -1 | |
+ | trunk_link | -1 | |
+
+ Scenario: Foot - Walking should respect oneway:foot
+ Then routability should be
+ | oneway:foot | oneway | junction | forw | backw |
+ | yes | | | x | |
+ | yes | yes | | x | |
+ | yes | no | | x | |
+ | yes | -1 | | x | |
+ | yes | | roundabout | x | |
+ | no | | | x | x |
+ | no | yes | | x | x |
+ | no | no | | x | x |
+ | no | -1 | | x | x |
+ | no | | roundabout | x | x |
+ | -1 | | | | x |
+ | -1 | yes | | | x |
+ | -1 | no | | | x |
+ | -1 | -1 | | | x |
+ | -1 | | roundabout | | x |
diff --git a/features/foot/ref.feature b/features/foot/ref.feature
new file mode 100644
index 0000000..bc0c77e
--- /dev/null
+++ b/features/foot/ref.feature
@@ -0,0 +1,41 @@
+ at routing @foot @ref @name
+Feature: Foot - Way ref
+
+ Background:
+ Given the profile "foot"
+
+ Scenario: Foot - 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: Foot - 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: Foot - 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 |
diff --git a/features/foot/restrictions.feature b/features/foot/restrictions.feature
new file mode 100644
index 0000000..8d6a029
--- /dev/null
+++ b/features/foot/restrictions.feature
@@ -0,0 +1,288 @@
+ at routing @foot @restrictions
+Feature: Foot - Turn restrictions
+# Ignore turn restrictions on foot.
+
+ Background:
+ Given the profile "foot"
+
+ @no_turning
+ Scenario: Foot - No left turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_left_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Foot - No right turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | ej | j | no_right_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Foot - No u-turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_u_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Foot - Handle any no_* relation
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_weird_zigzags |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @only_turning
+ Scenario: Foot - Only left turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | only_left_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @only_turning
+ Scenario: Foot - Only right turn
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | ej | j | only_right_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @only_turning
+ Scenario: Foot - Only straight on
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | nj | j | only_straight_on |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @no_turning
+ Scenario: Foot - Handle any only_* restriction
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | nj | j | only_weird_zigzags |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | sj,wj |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+ @except
+ Scenario: Foot - Except tag and on no_ restrictions
+ Given the node map
+ | b | x | c |
+ | a | j | d |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | no |
+ | xj | -1 |
+ | aj | -1 |
+ | bj | no |
+ | cj | -1 |
+ | dj | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction | except |
+ | restriction | sj | aj | j | no_left_turn | foot |
+ | restriction | sj | bj | j | no_left_turn | |
+ | restriction | sj | cj | j | no_right_turn | |
+ | restriction | sj | dj | j | no_right_turn | foot |
+
+ When I route I should get
+ | from | to | route |
+ | s | a | sj,aj |
+ | s | b | sj,bj |
+ | s | c | sj,cj |
+ | s | d | sj,dj |
+
+ @except
+ Scenario: Foot - Except tag and on only_ restrictions
+ Given the node map
+ | a | | b |
+ | | j | |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | aj | no |
+ | bj | no |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction | except |
+ | restriction | sj | aj | j | only_straight_on | foot |
+
+ When I route I should get
+ | from | to | route |
+ | s | a | sj,aj |
+ | s | b | sj,bj |
+
+ @except
+ Scenario: Foot - Multiple except tag values
+ Given the node map
+ | s | j | a |
+ | | | b |
+ | | | c |
+ | | | d |
+ | | | e |
+ | | | f |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | ja | yes |
+ | jb | yes |
+ | jc | yes |
+ | jd | yes |
+ | je | yes |
+ | jf | yes |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction | except |
+ | restriction | sj | ja | j | no_straight_on | |
+ | restriction | sj | jb | j | no_straight_on | foot |
+ | restriction | sj | jc | j | no_straight_on | bus; foot |
+ | restriction | sj | jd | j | no_straight_on | foot; motocar |
+ | restriction | sj | je | j | no_straight_on | bus, foot |
+ | restriction | sj | jf | j | no_straight_on | foot, bus |
+
+ When I route I should get
+ | from | to | route |
+ | s | a | sj,ja |
+ | s | b | sj,jb |
+ | s | c | sj,jc |
+ | s | d | sj,jd |
+ | s | e | sj,je |
+ | s | f | sj,jf |
diff --git a/features/foot/roundabout.feature b/features/foot/roundabout.feature
new file mode 100644
index 0000000..5aa9860
--- /dev/null
+++ b/features/foot/roundabout.feature
@@ -0,0 +1,34 @@
+ at routing @foot @roundabout @instruction
+Feature: Roundabout Instructions
+
+ Background:
+ Given the profile "foot"
+
+ @todo
+ Scenario: Foot - Roundabout instructions
+ # You can walk in both directions on a roundabout, bu the normal roundabout instructions don't
+ # make sense when you're going the opposite way around the roundabout.
+
+ Given the node map
+ | | | v | | |
+ | | | d | | |
+ | s | a | | c | u |
+ | | | b | | |
+ | | | t | | |
+
+ And the ways
+ | nodes | junction |
+ | sa | |
+ | tb | |
+ | uc | |
+ | vd | |
+ | abcda | roundabout |
+
+ When I route I should get
+ | from | to | route | turns |
+ | s | t | sa,tb | head,enter_roundabout-1,destination |
+ | s | u | sa,uc | head,enter_roundabout-2,destination |
+ | s | v | sa,vd | head,enter_roundabout-3,destination |
+ | u | v | uc,vd | head,enter_roundabout-1,destination |
+ | u | s | uc,sa | head,enter_roundabout-2,destination |
+ | u | t | uc,tb | head,enter_roundabout-3,destination |
diff --git a/features/foot/surface.feature b/features/foot/surface.feature
new file mode 100644
index 0000000..556c3d8
--- /dev/null
+++ b/features/foot/surface.feature
@@ -0,0 +1,15 @@
+ at routing @foot @surface
+Feature: Foot - Surfaces
+
+ Background:
+ Given the profile "foot"
+
+ Scenario: Foot - Slow surfaces
+ Then routability should be
+ | highway | surface | bothw |
+ | footway | | 145s ~10% |
+ | footway | fine_gravel | 193s ~10% |
+ | footway | gravel | 193s ~10% |
+ | footway | pebbelstone | 193s ~10% |
+ | footway | mud | 289s ~10% |
+ | footway | sand | 289s ~10% |
diff --git a/features/foot/way.feature b/features/foot/way.feature
index e18d9f8..653c773 100644
--- a/features/foot/way.feature
+++ b/features/foot/way.feature
@@ -1,32 +1,32 @@
@routing @foot @way
Feature: Foot - Accessability of different way types
- Background:
- Given the profile "foot"
+ Background:
+ Given the profile "foot"
- Scenario: Foot - Basic access
- Then routability should be
- | highway | forw |
- | motorway | |
- | motorway_link | |
- | trunk | |
- | trunk_link | |
- | primary | x |
- | primary_link | x |
- | secondary | x |
- | secondary_link | x |
- | tertiary | x |
- | tertiary_link | x |
- | residential | x |
- | service | x |
- | unclassified | x |
- | living_street | x |
- | road | x |
- | track | x |
- | path | x |
- | footway | x |
- | pedestrian | x |
- | steps | x |
- | pier | x |
- | cycleway | |
- | bridleway | |
\ No newline at end of file
+ Scenario: Foot - Basic access
+ Then routability should be
+ | highway | forw |
+ | motorway | |
+ | motorway_link | |
+ | trunk | |
+ | trunk_link | |
+ | primary | x |
+ | primary_link | x |
+ | secondary | x |
+ | secondary_link | x |
+ | tertiary | x |
+ | tertiary_link | x |
+ | residential | x |
+ | service | x |
+ | unclassified | x |
+ | living_street | x |
+ | road | x |
+ | track | x |
+ | path | x |
+ | footway | x |
+ | pedestrian | x |
+ | steps | x |
+ | pier | x |
+ | cycleway | |
+ | bridleway | |
diff --git a/features/investigate/weird.feature b/features/investigate/weird.feature
deleted file mode 100644
index f84a075..0000000
--- a/features/investigate/weird.feature
+++ /dev/null
@@ -1,42 +0,0 @@
- at routing @weird
-Feature: Weird routings discovered
-
- Background:
- Given the profile "testbot"
-
- Scenario: Routing on a oneway roundabout
- Given the node map
- | | d | c | |
- | e | | | b |
- | f | | | a |
- | | g | h | |
-
- And the ways
- | nodes | oneway |
- | ab | yes |
- | bc | yes |
- | cd | yes |
- | de | yes |
- | ef | yes |
- | fg | yes |
- | gh | yes |
- | ha | yes |
-
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | c | bc |
- | c | d | cd |
- | d | e | de |
- | e | f | ef |
- | f | g | fg |
- | g | h | gh |
- | h | a | ha |
- | b | a | bc,cd,de,ef,fg,gh,ha |
- | c | b | cd,de,ef,fg,gh,ha,ab |
- | d | c | de,ef,fg,gh,ha,ab,bc |
- | e | d | ef,fg,gh,ha,ab,bc,cd |
- | f | e | fg,gh,ha,ab,bc,cd,de |
- | g | f | gh,ha,ab,bc,cd,de,ef |
- | h | g | ha,ab,bc,cd,de,ef,fg |
- | a | h | ab,bc,cd,de,ef,fg,gh |
\ No newline at end of file
diff --git a/features/locate/locate.feature b/features/locate/locate.feature
new file mode 100644
index 0000000..838bcd5
--- /dev/null
+++ b/features/locate/locate.feature
@@ -0,0 +1,197 @@
+ at locate
+Feature: Locate - return nearest node
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Locate - two ways crossing
+ Given the node map
+ | | | 0 | c | 1 | | |
+ | | | | | | | |
+ | 7 | | | n | | | 2 |
+ | a | | k | x | m | | b |
+ | 6 | | | l | | | 3 |
+ | | | | | | | |
+ | | | 5 | d | 4 | | |
+
+ And the ways
+ | nodes |
+ | axb |
+ | cxd |
+
+ When I request locate I should get
+ | in | out |
+ | 0 | c |
+ | 1 | c |
+ | 2 | b |
+ | 3 | b |
+ | 4 | d |
+ | 5 | d |
+ | 6 | a |
+ | 7 | a |
+ | a | a |
+ | b | b |
+ | c | c |
+ | d | d |
+ | k | x |
+ | l | x |
+ | m | x |
+ | n | x |
+
+ Scenario: Locate - inside a triangle
+ Given the node map
+ | | | | | | c | | | | | |
+ | | | | | | 7 | | | | | |
+ | | | | y | | | | z | | | |
+ | | | 5 | | 0 | | 1 | | 8 | | |
+ | 6 | | | 2 | | 3 | | 4 | | | 9 |
+ | a | | | x | | u | | w | | | b |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | ca |
+
+ When I request locate I should get
+ | in | out |
+ | 0 | c |
+ | 1 | c |
+ | 2 | a |
+ | 3 | c |
+ | 4 | b |
+ | 5 | a |
+ | 6 | a |
+ | 7 | c |
+ | 8 | b |
+ | 9 | b |
+ | x | a |
+ | y | c |
+ | z | c |
+ | w | b |
+
+ Scenario: Nearest - easy-west way
+ Given the node map
+ | 3 | 4 | | 5 | 6 |
+ | 2 | a | x | b | 7 |
+ | 1 | 0 | | 9 | 8 |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I request locate I should get
+ | in | out |
+ | 0 | a |
+ | 1 | a |
+ | 2 | a |
+ | 3 | a |
+ | 4 | a |
+ | 5 | b |
+ | 6 | b |
+ | 7 | b |
+ | 8 | b |
+ | 9 | b |
+
+ Scenario: Nearest - north-south way
+ Given the node map
+ | 1 | 2 | 3 |
+ | 0 | a | 4 |
+ | | x | |
+ | 9 | b | 5 |
+ | 8 | 7 | 6 |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I request locate I should get
+ | in | out |
+ | 0 | a |
+ | 1 | a |
+ | 2 | a |
+ | 3 | a |
+ | 4 | a |
+ | 5 | b |
+ | 6 | b |
+ | 7 | b |
+ | 8 | b |
+ | 9 | b |
+
+ Scenario: Nearest - diagonal 1
+ Given the node map
+ | 2 | | 3 | | | |
+ | | a | | 4 | | |
+ | 1 | | x | | 5 | |
+ | | 0 | | y | | 6 |
+ | | | 9 | | b | |
+ | | | | 8 | | 7 |
+
+ And the ways
+ | nodes |
+ | axyb |
+
+ When I request locate I should get
+ | in | out |
+ | 0 | x |
+ | 1 | a |
+ | 2 | a |
+ | 3 | a |
+ | 4 | x |
+ | 5 | y |
+ | 6 | b |
+ | 7 | b |
+ | 8 | b |
+ | 9 | y |
+ | a | a |
+ | b | b |
+ | x | x |
+ | y | y |
+
+ Scenario: Nearest - diagonal 2
+ Given the node map
+ | | | | 6 | | 7 |
+ | | | 5 | | b | |
+ | | 4 | | y | | 8 |
+ | 3 | | x | | 9 | |
+ | | a | | 0 | | |
+ | 2 | | 1 | | | |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I request nearest I should get
+ | in | out |
+ | 0 | x |
+ | 1 | a |
+ | 2 | a |
+ | 3 | a |
+ | 4 | x |
+ | 5 | y |
+ | 6 | b |
+ | 7 | b |
+ | 8 | b |
+ | 9 | y |
+ | a | a |
+ | b | b |
+ | x | x |
+ | y | y |
+
+ Scenario: Locate - High lat/lon
+ Given the node locations
+ | node | lat | lon |
+ | a | -85 | -180 |
+ | b | 0 | 0 |
+ | c | 85 | 180 |
+ | x | -84 | -180 |
+ | y | 84 | 180 |
+
+ And the ways
+ | nodes |
+ | abc |
+
+ When I request locate I should get
+ | in | out |
+ | x | a |
+ | y | c |
diff --git a/features/nearest/pick.feature b/features/nearest/pick.feature
index f3bd76d..08e6652 100644
--- a/features/nearest/pick.feature
+++ b/features/nearest/pick.feature
@@ -1,56 +1,78 @@
@nearest
Feature: Locating Nearest node on a Way - pick closest way
- Background:
- Given the profile "testbot"
-
- Scenario: Nearest - two ways crossing
- Given the node map
- | | 0 | c | 1 | |
- | 7 | | n | | 2 |
- | a | k | x | m | b |
- | 6 | | l | | 3 |
- | | 5 | d | 4 | |
-
- And the ways
- | nodes |
- | axb |
- | cxd |
-
- When I request nearest I should get
- | in | out |
- | 0 | c |
- | 1 | c |
- | 2 | b |
- | 3 | b |
- | 4 | d |
- | 5 | d |
- | 6 | a |
- | 7 | a |
- | k | k |
- | l | l |
- | m | m |
- | n | n |
-
- Scenario: Nearest - inside a triangle
- Given the node map
- | | | | | | c | | | | | |
- | | | | | | | | | | | |
- | | | | y | | | | z | | | |
- | | | | | 0 | | 1 | | | | |
- | | | | 2 | | 3 | | 4 | | | |
- | a | | | x | | u | | w | | | b |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | ca |
-
- When I request nearest I should get
- | in | out |
- | 0 | y |
- | 1 | z |
- | 2 | x |
- | 3 | u |
- | 4 | w |
\ No newline at end of file
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Nearest - two ways crossing
+ Given the node map
+ | | 0 | c | 1 | |
+ | 7 | | n | | 2 |
+ | a | k | x | m | b |
+ | 6 | | l | | 3 |
+ | | 5 | d | 4 | |
+
+ And the ways
+ | nodes |
+ | axb |
+ | cxd |
+
+ When I request nearest I should get
+ | in | out |
+ | 0 | c |
+ | 1 | c |
+ | 2 | b |
+ | 3 | b |
+ | 4 | d |
+ | 5 | d |
+ | 6 | a |
+ | 7 | a |
+ | k | k |
+ | l | l |
+ | m | m |
+ | n | n |
+
+ Scenario: Nearest - inside a triangle
+ Given the node map
+ | | | | | | c | | | | | |
+ | | | | | | | | | | | |
+ | | | | y | | | | z | | | |
+ | | | | | 0 | | 1 | | | | |
+ | | | | 2 | | 3 | | 4 | | | |
+ | a | | | x | | u | | w | | | b |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | ca |
+
+ When I request nearest I should get
+ | in | out |
+ | 0 | y |
+ | 1 | z |
+ | 2 | x |
+ | 3 | u |
+ | 4 | w |
+
+ Scenario: Nearest - High lat/lon
+ Given the node locations
+ | node | lat | lon |
+ | a | -85 | -180 |
+ | b | -85 | -160 |
+ | c | -85 | -140 |
+ | x | 75 | -180 |
+ | y | 75 | -180 |
+ | v | 1 | 1 |
+ | w | -1 | -1 |
+
+ And the ways
+ | nodes |
+ | abc |
+
+ When I request nearest I should get
+ | in | out |
+ | x | a |
+ | y | a |
+ | v | c |
+ | w | c |
diff --git a/features/nearest/projection.feature b/features/nearest/projection.feature
index f33a19f..33a8278 100644
--- a/features/nearest/projection.feature
+++ b/features/nearest/projection.feature
@@ -1,105 +1,105 @@
@nearest
Feature: Locating Nearest node on a Way - basic projection onto way
- Background:
- Given the profile "testbot"
-
- Scenario: Nearest - easy-west way
- Given the node map
- | 0 | 1 | 2 | 3 | 4 |
- | | a | x | b | |
- | 5 | 6 | 7 | 8 | 9 |
+ Background:
+ Given the profile "testbot"
- And the ways
- | nodes |
- | ab |
+ Scenario: Nearest - easy-west way
+ Given the node map
+ | 0 | 1 | 2 | 3 | 4 |
+ | | a | x | b | |
+ | 5 | 6 | 7 | 8 | 9 |
- When I request nearest I should get
- | in | out |
- | 0 | a |
- | 1 | a |
- | 2 | x |
- | 3 | b |
- | 4 | b |
- | 5 | a |
- | 6 | a |
- | 7 | x |
- | 8 | b |
- | 9 | b |
+ And the ways
+ | nodes |
+ | ab |
- Scenario: Nearest - north-south way
- Given the node map
- | 0 | | 5 |
- | 1 | a | 6 |
- | 2 | x | 7 |
- | 3 | b | 8 |
- | 4 | | 9 |
-
- And the ways
- | nodes |
- | ab |
+ When I request nearest I should get
+ | in | out |
+ | 0 | a |
+ | 1 | a |
+ | 2 | x |
+ | 3 | b |
+ | 4 | b |
+ | 5 | a |
+ | 6 | a |
+ | 7 | x |
+ | 8 | b |
+ | 9 | b |
- When I request nearest I should get
- | in | out |
- | 0 | a |
- | 1 | a |
- | 2 | x |
- | 3 | b |
- | 4 | b |
- | 5 | a |
- | 6 | a |
- | 7 | x |
- | 8 | b |
- | 9 | b |
+ Scenario: Nearest - north-south way
+ Given the node map
+ | 0 | | 5 |
+ | 1 | a | 6 |
+ | 2 | x | 7 |
+ | 3 | b | 8 |
+ | 4 | | 9 |
- Scenario: Nearest - diagonal 1
- Given the node map
- | 8 | | 4 | | | |
- | | a | | 5 | | |
- | 0 | | x | | 6 | |
- | | 1 | | y | | 7 |
- | | | 2 | | b | |
- | | | | 3 | | 9 |
+ And the ways
+ | nodes |
+ | ab |
- And the ways
- | nodes |
- | ab |
+ When I request nearest I should get
+ | in | out |
+ | 0 | a |
+ | 1 | a |
+ | 2 | x |
+ | 3 | b |
+ | 4 | b |
+ | 5 | a |
+ | 6 | a |
+ | 7 | x |
+ | 8 | b |
+ | 9 | b |
- When I request nearest I should get
- | in | out |
- | 0 | a |
- | 1 | x |
- | 2 | y |
- | 3 | b |
- | 4 | a |
- | 5 | x |
- | 6 | y |
- | 7 | b |
- | 8 | a |
- | 9 | b |
+ Scenario: Nearest - diagonal 1
+ Given the node map
+ | 8 | | 4 | | | |
+ | | a | | 5 | | |
+ | 0 | | x | | 6 | |
+ | | 1 | | y | | 7 |
+ | | | 2 | | b | |
+ | | | | 3 | | 9 |
- Scenario: Nearest - diagonal 2
- Given the node map
- | | | | 3 | | 9 |
- | | | 2 | | b | |
- | | 1 | | y | | 7 |
- | 0 | | x | | 6 | |
- | | a | | 5 | | |
- | 8 | | 4 | | | |
+ And the ways
+ | nodes |
+ | ab |
- And the ways
- | nodes |
- | ab |
+ When I request nearest I should get
+ | in | out |
+ | 0 | a |
+ | 1 | x |
+ | 2 | y |
+ | 3 | b |
+ | 4 | a |
+ | 5 | x |
+ | 6 | y |
+ | 7 | b |
+ | 8 | a |
+ | 9 | b |
- When I request nearest I should get
- | in | out |
- | 0 | a |
- | 1 | x |
- | 2 | y |
- | 3 | b |
- | 4 | a |
- | 5 | x |
- | 6 | y |
- | 7 | b |
- | 8 | a |
- | 9 | b |
+ Scenario: Nearest - diagonal 2
+ Given the node map
+ | | | | 3 | | 9 |
+ | | | 2 | | b | |
+ | | 1 | | y | | 7 |
+ | 0 | | x | | 6 | |
+ | | a | | 5 | | |
+ | 8 | | 4 | | | |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I request nearest I should get
+ | in | out |
+ | 0 | a |
+ | 1 | x |
+ | 2 | y |
+ | 3 | b |
+ | 4 | a |
+ | 5 | x |
+ | 6 | y |
+ | 7 | b |
+ | 8 | a |
+ | 9 | b |
diff --git a/features/options/extract/files.feature b/features/options/extract/files.feature
new file mode 100644
index 0000000..3061263
--- /dev/null
+++ b/features/options/extract/files.feature
@@ -0,0 +1,30 @@
+ at extract @options @files
+Feature: osrm-extract command line options: files
+# expansions:
+# {base} => path to current input file
+# {profile} => path to current profile script
+
+ Background:
+ Given the profile "testbot"
+ And the node map
+ | a | b |
+ And the ways
+ | nodes |
+ | ab |
+ And the data has been saved to disk
+
+ Scenario: osrm-extract - Passing base file
+ When I run "osrm-extract {base}.osm --profile {profile}"
+ Then stderr should be empty
+ And it should exit with code 0
+
+ Scenario: osrm-extract - Order of options should not matter
+ When I run "osrm-extract --profile {profile} {base}.osm"
+ Then stderr should be empty
+ And it should exit with code 0
+
+ Scenario: osrm-extract - Missing input file
+ When I run "osrm-extract over-the-rainbow.osrm --profile {profile}"
+ And stderr should contain "over-the-rainbow.osrm"
+ And stderr should contain "not found"
+ And it should exit with code 1
diff --git a/features/options/extract/help.feature b/features/options/extract/help.feature
new file mode 100644
index 0000000..3215e6a
--- /dev/null
+++ b/features/options/extract/help.feature
@@ -0,0 +1,47 @@
+ at extract @options @help
+Feature: osrm-extract command line options: help
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: osrm-extract - Help should be shown when no options are passed
+ When I run "osrm-extract"
+ Then stderr should be empty
+ And stdout should contain "osrm-extract <input.osm/.osm.bz2/.osm.pbf> [options]:"
+ And stdout should contain "Options:"
+ And stdout should contain "--version"
+ And stdout should contain "--help"
+ And stdout should contain "--config"
+ And stdout should contain "Configuration:"
+ And stdout should contain "--profile"
+ And stdout should contain "--threads"
+ And stdout should contain 12 lines
+ And it should exit with code 0
+
+ Scenario: osrm-extract - Help, short
+ When I run "osrm-extract -h"
+ Then stderr should be empty
+ And stdout should contain "osrm-extract <input.osm/.osm.bz2/.osm.pbf> [options]:"
+ And stdout should contain "Options:"
+ And stdout should contain "--version"
+ And stdout should contain "--help"
+ And stdout should contain "--config"
+ And stdout should contain "Configuration:"
+ And stdout should contain "--profile"
+ And stdout should contain "--threads"
+ And stdout should contain 12 lines
+ And it should exit with code 0
+
+ Scenario: osrm-extract - Help, long
+ When I run "osrm-extract --help"
+ Then stderr should be empty
+ And stdout should contain "osrm-extract <input.osm/.osm.bz2/.osm.pbf> [options]:"
+ And stdout should contain "Options:"
+ And stdout should contain "--version"
+ And stdout should contain "--help"
+ And stdout should contain "--config"
+ And stdout should contain "Configuration:"
+ And stdout should contain "--profile"
+ And stdout should contain "--threads"
+ And stdout should contain 12 lines
+ And it should exit with code 0
diff --git a/features/options/extract/invalid.feature b/features/options/extract/invalid.feature
new file mode 100644
index 0000000..169e53c
--- /dev/null
+++ b/features/options/extract/invalid.feature
@@ -0,0 +1,12 @@
+ at extract @options @invalid
+Feature: osrm-extract command line options: invalid options
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: osrm-extract - Non-existing option
+ When I run "osrm-extract --fly-me-to-the-moon"
+ Then stdout should be empty
+ And stderr should contain "option"
+ And stderr should contain "fly-me-to-the-moon"
+ And it should exit with code 1
diff --git a/features/options/extract/version.feature b/features/options/extract/version.feature
new file mode 100644
index 0000000..0dd5f65
--- /dev/null
+++ b/features/options/extract/version.feature
@@ -0,0 +1,22 @@
+ at extract @options @version
+Feature: osrm-extract command line options: version
+# the regex will match these two formats:
+# v0.3.7.0 # this is the normal format when you build from a git clone
+# -128-NOTFOUND # if you build from a shallow clone (used on Travis)
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: osrm-extract - Version, short
+ When I run "osrm-extract --v"
+ Then stderr should be empty
+ And stdout should contain 1 line
+ And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
+ And it should exit with code 0
+
+ Scenario: osrm-extract - Version, long
+ When I run "osrm-extract --version"
+ Then stderr should be empty
+ And stdout should contain 1 line
+ And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
+ And it should exit with code 0
diff --git a/features/options/prepare/files.feature b/features/options/prepare/files.feature
new file mode 100644
index 0000000..de356a8
--- /dev/null
+++ b/features/options/prepare/files.feature
@@ -0,0 +1,30 @@
+ at prepare @options @files
+Feature: osrm-prepare command line options: files
+# expansions:
+# {base} => path to current input file
+# {profile} => path to current profile script
+
+ Background:
+ Given the profile "testbot"
+ And the node map
+ | a | b |
+ And the ways
+ | nodes |
+ | ab |
+ And the data has been extracted
+
+ Scenario: osrm-prepare - Passing base file
+ When I run "osrm-prepare {base}.osrm --profile {profile}"
+ Then stderr should be empty
+ And it should exit with code 0
+
+ Scenario: osrm-prepare - Order of options should not matter
+ When I run "osrm-prepare --profile {profile} {base}.osrm"
+ Then stderr should be empty
+ And it should exit with code 0
+
+ Scenario: osrm-prepare - Missing input file
+ When I run "osrm-prepare over-the-rainbow.osrm --profile {profile}"
+ And stderr should contain "over-the-rainbow.osrm"
+ And stderr should contain "not found"
+ And it should exit with code 1
diff --git a/features/options/prepare/help.feature b/features/options/prepare/help.feature
new file mode 100644
index 0000000..49497ae
--- /dev/null
+++ b/features/options/prepare/help.feature
@@ -0,0 +1,50 @@
+ at prepare @options @help
+Feature: osrm-prepare command line options: help
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: osrm-prepare - Help should be shown when no options are passed
+ When I run "osrm-prepare"
+ Then stderr should be empty
+ And stdout should contain "osrm-prepare <input.osrm> [options]:"
+ And stdout should contain "Options:"
+ And stdout should contain "--version"
+ And stdout should contain "--help"
+ And stdout should contain "--config"
+ And stdout should contain "Configuration:"
+ And stdout should contain "--restrictions"
+ And stdout should contain "--profile"
+ And stdout should contain "--threads"
+ And stdout should contain 15 lines
+ And it should exit with code 0
+
+ Scenario: osrm-prepare - Help, short
+ When I run "osrm-prepare -h"
+ Then stderr should be empty
+ And stdout should contain "osrm-prepare <input.osrm> [options]:"
+ And stdout should contain "Options:"
+ And stdout should contain "--version"
+ And stdout should contain "--help"
+ And stdout should contain "--config"
+ And stdout should contain "Configuration:"
+ And stdout should contain "--restrictions"
+ And stdout should contain "--profile"
+ And stdout should contain "--threads"
+ And stdout should contain 15 lines
+ And it should exit with code 0
+
+ Scenario: osrm-prepare - Help, long
+ When I run "osrm-prepare --help"
+ Then stderr should be empty
+ And stdout should contain "osrm-prepare <input.osrm> [options]:"
+ And stdout should contain "Options:"
+ And stdout should contain "--version"
+ And stdout should contain "--help"
+ And stdout should contain "--config"
+ And stdout should contain "Configuration:"
+ And stdout should contain "--restrictions"
+ And stdout should contain "--profile"
+ And stdout should contain "--threads"
+ And stdout should contain 15 lines
+ And it should exit with code 0
diff --git a/features/options/prepare/invalid.feature b/features/options/prepare/invalid.feature
new file mode 100644
index 0000000..7450390
--- /dev/null
+++ b/features/options/prepare/invalid.feature
@@ -0,0 +1,12 @@
+ at prepare @options @invalid
+Feature: osrm-prepare command line options: invalid options
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: osrm-prepare - Non-existing option
+ When I run "osrm-prepare --fly-me-to-the-moon"
+ Then stdout should be empty
+ And stderr should contain "option"
+ And stderr should contain "fly-me-to-the-moon"
+ And it should exit with code 1
diff --git a/features/options/prepare/version.feature b/features/options/prepare/version.feature
new file mode 100644
index 0000000..7a821c6
--- /dev/null
+++ b/features/options/prepare/version.feature
@@ -0,0 +1,22 @@
+ at prepare @options @version
+Feature: osrm-prepare command line options: version
+# the regex will match these two formats:
+# v0.3.7.0 # this is the normal format when you build from a git clone
+# -128-NOTFOUND # if you build from a shallow clone (used on Travis)
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: osrm-prepare - Version, short
+ When I run "osrm-prepare --v"
+ Then stderr should be empty
+ And stdout should contain 1 line
+ And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
+ And it should exit with code 0
+
+ Scenario: osrm-prepare - Version, long
+ When I run "osrm-prepare --version"
+ Then stderr should be empty
+ And stdout should contain 1 line
+ And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
+ And it should exit with code 0
diff --git a/features/options/routed/files.feature b/features/options/routed/files.feature
new file mode 100644
index 0000000..716b2a4
--- /dev/null
+++ b/features/options/routed/files.feature
@@ -0,0 +1,27 @@
+ at routed @options @files
+Feature: osrm-routed command line options: files
+# Normally when launching osrm-routed, it will keep running as a server until it's shut down.
+# For testing program options, the --trial option is used, which causes osrm-routed to quit
+# immediately after initialization. This makes testing easier and faster.
+#
+# The {base} part of the options to osrm-routed will be expanded to the actual base path of
+# the preprocessed file.
+
+ Background:
+ Given the profile "testbot"
+ And the node map
+ | a | b |
+ And the ways
+ | nodes |
+ | ab |
+ And the data has been prepared
+
+ Scenario: osrm-routed - Passing base file
+ When I run "osrm-routed {base}.osrm --trial"
+ Then stdout should contain /^\[info\] starting up engines/
+ And stdout should contain /\d{1,2}\.\d{1,2}\.\d{1,2}/
+ And stdout should contain /compiled at/
+ And stdout should contain /^\[info\] loaded plugin: viaroute/
+ And stdout should contain /^\[info\] trial run/
+ And stdout should contain /^\[info\] shutdown completed/
+ And it should exit with code 0
\ No newline at end of file
diff --git a/features/options/routed/help.feature b/features/options/routed/help.feature
new file mode 100644
index 0000000..9603c40
--- /dev/null
+++ b/features/options/routed/help.feature
@@ -0,0 +1,77 @@
+ at routed @options @help
+Feature: osrm-routed command line options: help
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: osrm-routed - Help should be shown when no options are passed
+ When I run "osrm-routed"
+ Then stderr should be empty
+ And stdout should contain "osrm-routed <base.osrm> [<options>]:"
+ And stdout should contain "Options:"
+ And stdout should contain "--version"
+ And stdout should contain "--help"
+ And stdout should contain "--config"
+ And stdout should contain "--trial"
+ And stdout should contain "Configuration:"
+ And stdout should contain "--hsgrdata arg"
+ And stdout should contain "--nodesdata arg"
+ And stdout should contain "--edgesdata arg"
+ And stdout should contain "--ramindex arg"
+ And stdout should contain "--fileindex arg"
+ And stdout should contain "--namesdata arg"
+ And stdout should contain "--timestamp arg"
+ And stdout should contain "--ip"
+ And stdout should contain "--port"
+ And stdout should contain "--threads"
+ And stdout should contain "--sharedmemory"
+ And stdout should contain 22 lines
+ And it should exit with code 0
+
+ Scenario: osrm-routed - Help, short
+ When I run "osrm-routed -h"
+ Then stderr should be empty
+ And stdout should contain "osrm-routed <base.osrm> [<options>]:"
+ And stdout should contain "Options:"
+ And stdout should contain "--version"
+ And stdout should contain "--help"
+ And stdout should contain "--config"
+ And stdout should contain "--trial"
+ And stdout should contain "Configuration:"
+ And stdout should contain "--hsgrdata arg"
+ And stdout should contain "--nodesdata arg"
+ And stdout should contain "--edgesdata arg"
+ And stdout should contain "--ramindex arg"
+ And stdout should contain "--fileindex arg"
+ And stdout should contain "--namesdata arg"
+ And stdout should contain "--timestamp arg"
+ And stdout should contain "--ip"
+ And stdout should contain "--port"
+ And stdout should contain "--threads"
+ And stdout should contain "--sharedmemory"
+ And stdout should contain 22 lines
+ And it should exit with code 0
+
+ Scenario: osrm-routed - Help, long
+ When I run "osrm-routed --help"
+ Then stderr should be empty
+ And stdout should contain "osrm-routed <base.osrm> [<options>]:"
+ And stdout should contain "Options:"
+ And stdout should contain "--version"
+ And stdout should contain "--help"
+ And stdout should contain "--config"
+ And stdout should contain "--trial"
+ And stdout should contain "Configuration:"
+ And stdout should contain "--hsgrdata arg"
+ And stdout should contain "--nodesdata arg"
+ And stdout should contain "--edgesdata arg"
+ And stdout should contain "--ramindex arg"
+ And stdout should contain "--fileindex arg"
+ And stdout should contain "--namesdata arg"
+ And stdout should contain "--timestamp arg"
+ And stdout should contain "--ip"
+ And stdout should contain "--port"
+ And stdout should contain "--threads"
+ And stdout should contain "--sharedmemory"
+ And stdout should contain 22 lines
+ And it should exit with code 0
diff --git a/features/options/routed/invalid.feature b/features/options/routed/invalid.feature
new file mode 100644
index 0000000..a6d62d7
--- /dev/null
+++ b/features/options/routed/invalid.feature
@@ -0,0 +1,19 @@
+ at routed @options @invalid
+Feature: osrm-routed command line options: invalid options
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: osrm-routed - Non-existing option
+ When I run "osrm-routed --fly-me-to-the-moon"
+ Then stdout should be empty
+ And stderr should contain "exception"
+ And stderr should contain "fly-me-to-the-moon"
+ And it should exit with code 1
+
+ Scenario: osrm-routed - Missing file
+ When I run "osrm-routed over-the-rainbow.osrm"
+ Then stdout should contain "over-the-rainbow.osrm"
+ And stderr should contain "exception"
+ And stderr should contain "not found"
+ And it should exit with code 1
diff --git a/features/options/routed/version.feature b/features/options/routed/version.feature
new file mode 100644
index 0000000..b544e36
--- /dev/null
+++ b/features/options/routed/version.feature
@@ -0,0 +1,22 @@
+ at routed @options @version
+Feature: osrm-routed command line options: version
+# the regex will match these two formats:
+# v0.3.7.0 # this is the normal format when you build from a git clone
+# -128-NOTFOUND # if you build from a shallow clone (used on Travis)
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: osrm-routed - Version, short
+ When I run "osrm-routed --v"
+ Then stderr should be empty
+ And stdout should contain 1 line
+ And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
+ And it should exit with code 0
+
+ Scenario: osrm-routed - Version, long
+ When I run "osrm-routed --version"
+ Then stderr should be empty
+ And stdout should contain 1 line
+ And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/
+ And it should exit with code 0
diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb
index 1e021b6..e0985a4 100644
--- a/features/step_definitions/data.rb
+++ b/features/step_definitions/data.rb
@@ -2,10 +2,18 @@ Given /^the profile "([^"]*)"$/ do |profile|
set_profile profile
end
+Given(/^the import format "(.*?)"$/) do |format|
+ set_input_format format
+end
+
Given /^a grid size of (\d+) meters$/ do |meters|
set_grid_size meters
end
+Given /^the origin ([-+]?[0-9]*\.?[0-9]+),([-+]?[0-9]*\.?[0-9]+)$/ do |lat,lon|
+ set_origin [lon.to_f,lat.to_f]
+end
+
Given /^the shortcuts$/ do |table|
table.hashes.each do |row|
shortcuts_hash[ row['key'] ] = row['value']
@@ -19,11 +27,11 @@ Given /^the node map$/ do |table|
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]
- add_osm_node name, *table_coord_to_lonlat(ci,ri)
+ raise "*** duplicate node '#{name}'" if name_node_hash[name]
+ 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)
+ raise "*** duplicate node '#{name}'" if location_hash[name]
+ add_location name, *table_coord_to_lonlat(ci,ri)
end
end
end
@@ -35,9 +43,9 @@ Given /^the node locations$/ do |table|
name = row['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
+ add_osm_node name, row['lon'].to_f, row['lat'].to_f
else
- add_location name, row['lon'].to_f, row['lat'].to_f
+ add_location name, row['lon'].to_f, row['lat'].to_f
end
end
end
@@ -52,10 +60,11 @@ Given /^the nodes$/ do |table|
end
Given /^the ways$/ do |table|
+ raise "*** Map data already defined - did you pass an input file in this scenaria?" if @osm_str
table.hashes.each do |row|
way = OSM::Way.new make_osm_id, OSM_USER, OSM_TIMESTAMP
way.uid = OSM_UID
-
+
nodes = row.delete 'nodes'
raise "*** duplicate way '#{nodes}'" if name_way_hash[nodes]
nodes.each_char do |c|
@@ -64,14 +73,14 @@ Given /^the ways$/ do |table|
raise "*** unknown node '#{c}'" unless node
way << node
end
-
+
defaults = { 'highway' => 'primary' }
tags = defaults.merge(row)
if row['highway'] == '(nil)'
tags.delete 'highway'
end
-
+
if row['name'] == nil
tags['name'] = nodes
elsif (row['name'] == '""') || (row['name'] == "''")
@@ -81,7 +90,7 @@ Given /^the ways$/ do |table|
else
tags['name'] = row['name']
end
-
+
way << tags
osm_db << way
name_way_hash[nodes] = way
@@ -89,6 +98,7 @@ Given /^the ways$/ do |table|
end
Given /^the relations$/ do |table|
+ raise "*** Map data already defined - did you pass an input file in this scenaria?" if @osm_str
table.hashes.each do |row|
relation = OSM::Relation.new make_osm_id, OSM_USER, OSM_TIMESTAMP
row.each_pair do |key,value|
@@ -119,3 +129,32 @@ end
Given /^the defaults$/ do
end
+Given /^the input file ([^"]*)$/ do |file|
+ raise "*** Input file must in .osm format" unless File.extname(file)=='.osm'
+ @osm_str = File.read file
+end
+
+Given /^the data has been saved to disk$/ do
+ begin
+ write_input_data
+ rescue OSRMError => e
+ @process_error = e
+ end
+end
+
+Given /^the data has been extracted$/ do
+ begin
+ write_input_data
+ extract_data unless extracted?
+ rescue OSRMError => e
+ @process_error = e
+ end
+end
+
+Given /^the data has been prepared$/ do
+ begin
+ reprocess
+ rescue OSRMError => e
+ @process_error = e
+ end
+end
diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/locate.rb
similarity index 72%
copy from features/step_definitions/nearest.rb
copy to features/step_definitions/locate.rb
index 3b65792..9d3d74f 100644
--- a/features/step_definitions/nearest.rb
+++ b/features/step_definitions/locate.rb
@@ -1,7 +1,7 @@
-When /^I request nearest I should get$/ do |table|
+When /^I request locate I should get$/ do |table|
reprocess
actual = []
- OSRMLauncher.new do
+ OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
table.hashes.each_with_index do |row,ri|
in_node = find_node_by_name row['in']
raise "*** unknown in-node '#{row['in']}" unless in_node
@@ -9,16 +9,16 @@ When /^I request nearest I should get$/ do |table|
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}")
+ response = request_locate("#{in_node.lat},#{in_node.lon}")
if response.code == "200" && response.body.empty? == false
json = JSON.parse response.body
if json['status'] == 0
coord = json['mapped_coordinate']
end
end
-
+
got = {'in' => row['in'], 'out' => coord }
-
+
ok = true
row.keys.each do |key|
if key=='out'
@@ -30,22 +30,22 @@ When /^I request nearest I should get$/ do |table|
end
end
end
-
+
unless ok
- failed = { :attempt => 'nearest', :query => @query, :response => response }
+ failed = { :attempt => 'locate', :query => @query, :response => response }
log_fail row,got,[failed]
end
-
+
actual << got
end
end
table.routing_diff! actual
end
-When /^I request nearest (\d+) times I should get$/ do |n,table|
+When /^I request locate (\d+) times I should get$/ do |n,table|
ok = true
n.to_i.times do
- ok = false unless step "I request nearest I should get", table
+ ok = false unless step "I request locate I should get", table
end
ok
-end
\ No newline at end of file
+end
diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb
index 3b65792..ae5a79c 100644
--- a/features/step_definitions/nearest.rb
+++ b/features/step_definitions/nearest.rb
@@ -1,7 +1,7 @@
When /^I request nearest I should get$/ do |table|
reprocess
actual = []
- OSRMLauncher.new do
+ OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
table.hashes.each_with_index do |row,ri|
in_node = find_node_by_name row['in']
raise "*** unknown in-node '#{row['in']}" unless in_node
@@ -16,9 +16,9 @@ When /^I request nearest I should get$/ do |table|
coord = json['mapped_coordinate']
end
end
-
+
got = {'in' => row['in'], 'out' => coord }
-
+
ok = true
row.keys.each do |key|
if key=='out'
@@ -30,12 +30,12 @@ When /^I request nearest I should get$/ do |table|
end
end
end
-
+
unless ok
failed = { :attempt => 'nearest', :query => @query, :response => response }
log_fail row,got,[failed]
end
-
+
actual << got
end
end
@@ -48,4 +48,4 @@ When /^I request nearest (\d+) times I should get$/ do |n,table|
ok = false unless step "I request nearest I should get", table
end
ok
-end
\ No newline at end of file
+end
diff --git a/features/step_definitions/options.rb b/features/step_definitions/options.rb
new file mode 100644
index 0000000..ac3bc99
--- /dev/null
+++ b/features/step_definitions/options.rb
@@ -0,0 +1,49 @@
+When(/^I run "osrm\-routed\s?(.*?)"$/) do |options|
+ begin
+ Timeout.timeout(1) { run_bin 'osrm-routed', options }
+ rescue Timeout::Error
+ raise "*** osrm-routed didn't quit. Maybe the --trial option wasn't used?"
+ end
+end
+
+When(/^I run "osrm\-extract\s?(.*?)"$/) do |options|
+ run_bin 'osrm-extract', options
+end
+
+When(/^I run "osrm\-prepare\s?(.*?)"$/) do |options|
+ run_bin 'osrm-prepare', options
+end
+
+Then /^it should exit with code (\d+)$/ do |code|
+ @exit_code.should == code.to_i
+end
+
+Then /^stdout should contain "(.*?)"$/ do |str|
+ @stdout.should include(str)
+end
+
+Then /^stderr should contain "(.*?)"$/ do |str|
+ @stderr.should include(str)
+end
+
+Then(/^stdout should contain \/(.*)\/$/) do |regex_str|
+ regex = Regexp.new regex_str
+ @stdout.should =~ regex
+end
+
+Then(/^stderr should contain \/(.*)\/$/) do |regex_str|
+ regex = Regexp.new regex_str
+ @stderr.should =~ regex
+end
+
+Then /^stdout should be empty$/ do
+ @stdout.should == ""
+end
+
+Then /^stderr should be empty$/ do
+ @stderr.should == ""
+end
+
+Then /^stdout should contain (\d+) lines?$/ do |lines|
+ @stdout.lines.count.should == lines.to_i
+end
diff --git a/features/step_definitions/requests.rb b/features/step_definitions/requests.rb
index d965b1a..519a739 100644
--- a/features/step_definitions/requests.rb
+++ b/features/step_definitions/requests.rb
@@ -1,6 +1,6 @@
When /^I request \/(.*)$/ do |path|
reprocess
- OSRMLauncher.new do
+ OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
@response = request_path path
end
end
@@ -16,9 +16,17 @@ Then /^response should be valid JSON$/ do
end
Then /^response should be well-formed$/ do
- @json['version'].class.should == Float
@json['status'].class.should == Fixnum
- @json['transactionId'].class.should == String
+end
+
+Then /^status code should be (\d+)$/ do |code|
+ @json = JSON.parse @response.body
+ @json['status'].should == code.to_i
+end
+
+Then /^status message should be "(.*?)"$/ do |message|
+ @json = JSON.parse @response.body
+ @json['status_message'].should == message
end
Then /^response should be a well-formed route$/ do
@@ -28,18 +36,11 @@ Then /^response should be a well-formed route$/ do
@json['route_geometry'].class.should == String
@json['route_instructions'].class.should == Array
@json['via_points'].class.should == Array
-end
-
-When /^I preprocess data$/ do
- begin
- reprocess
- rescue OSRMError => e
- @process_error = e
- end
+ @json['via_indices'].class.should == Array
end
Then /^"([^"]*)" should return code (\d+)$/ do |binary, code|
@process_error.is_a?(OSRMError).should == true
@process_error.process.should == binary
@process_error.code.to_i.should == code.to_i
-end
+end
\ No newline at end of file
diff --git a/features/step_definitions/routability.rb b/features/step_definitions/routability.rb
index 078428a..161171f 100644
--- a/features/step_definitions/routability.rb
+++ b/features/step_definitions/routability.rb
@@ -1,3 +1,42 @@
+def test_routability_row i
+ result = {}
+ ['forw','backw'].each do |direction|
+ a = Location.new @origin[0]+(1+WAY_SPACING*i)*@zoom, @origin[1]
+ b = Location.new @origin[0]+(3+WAY_SPACING*i)*@zoom, @origin[1]
+ r = {}
+ r[:response] = request_route direction=='forw' ? [a,b] : [b,a]
+ r[:query] = @query
+ r[:json] = JSON.parse(r[:response].body)
+
+ r[:status] = route_status r[:response]
+ if r[:status].empty? == false
+ r[:route] = way_list r[:json]['route_instructions']
+
+ if r[:route]=="w#{i}"
+ r[:time] = r[:json]['route_summary']['total_time']
+ r[:distance] = r[:json]['route_summary']['total_distance']
+ r[:speed] = r[:time]>0 ? (3.6*r[:distance]/r[:time]).to_i : nil
+ else
+ # if we hit the wrong way segment, we assume it's
+ # because the one we tested was not unroutable
+ r[:status] = nil
+ end
+ end
+ result[direction] = r
+ end
+
+ # check if forw and backw returned the same values
+ result['bothw'] = {}
+ [:status,:time,:distance,:speed].each do |key|
+ if result['forw'][key] == result['backw'][key]
+ result['bothw'][key] = result['forw'][key]
+ else
+ result['bothw'][key] = 'diff'
+ end
+ end
+ result
+end
+
Then /^routability should be$/ do |table|
build_ways_from_table table
reprocess
@@ -5,46 +44,34 @@ Then /^routability should be$/ do |table|
if table.headers&["forw","backw","bothw"] == []
raise "*** routability tabel must contain either 'forw', 'backw' or 'bothw' column"
end
- OSRMLauncher.new do
+ OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
table.hashes.each_with_index do |row,i|
- got = row.dup
+ output_row = row.dup
attempts = []
- ['forw','backw','bothw'].each do |direction|
- if table.headers.include? direction
- if direction == 'forw' || direction == 'bothw'
- 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'
- 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
- json = JSON.parse(response.body)
- 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"
- end
- end
- if FuzzyMatch.match got[direction], want
- got[direction] = row[direction]
- else
- attempts << { :attempt => direction, :query => @query, :response => response }
- end
+ result = test_routability_row i
+ directions = ['forw','backw','bothw']
+ (directions & table.headers).each do |direction|
+ want = shortcuts_hash[row[direction]] || row[direction] #expand shortcuts
+ case want
+ when '', 'x'
+ output_row[direction] = result[direction][:status].to_s
+ when /^\d+s/
+ output_row[direction] = "#{result[direction][:time]}s"
+ when /^\d+ km\/h/
+ output_row[direction] = "#{result[direction][:speed]} km/h"
+ else
+ raise "*** Unknown expectation format: #{want}"
end
+
+ if FuzzyMatch.match output_row[direction], want
+ output_row[direction] = row[direction]
+ end
+ end
+
+ if output_row != row
+ log_fail row,output_row,result
end
- log_fail row,got,attempts if got != row
- actual << got
+ actual << output_row
end
end
table.routing_diff! actual
diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb
index 13c8b6a..92b69ea 100644
--- a/features/step_definitions/routing.rb
+++ b/features/step_definitions/routing.rb
@@ -1,31 +1,38 @@
When /^I route I should get$/ do |table|
reprocess
actual = []
- OSRMLauncher.new do
+ OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
table.hashes.each_with_index do |row,ri|
- 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
+ if row['request']
+ got = {'request' => row['request'] }
+ response = request_url row['request']
+ else
+ params = {}
+ 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'] }
+ response = request_route waypoints, params
+ 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'] }
+ response = request_route waypoints, params
+ else
+ raise "*** no waypoints"
end
- got = {'waypoints' => row['waypoints'] }
- else
- raise "*** no waypoints"
end
-
- params = {}
+
row.each_pair do |k,v|
if k =~ /param:(.*)/
if v=='(nil)'
@@ -36,54 +43,87 @@ When /^I route I should get$/ do |table|
got[k]=v
end
end
-
- response = request_route(waypoints, params)
- if response.code == "200" && response.body.empty? == false
+
+ if response.body.empty? == false
json = JSON.parse response.body
+ end
+
+ if response.body.empty? == false
if json['status'] == 0
instructions = way_list json['route_instructions']
bearings = bearing_list json['route_instructions']
compasses = compass_list json['route_instructions']
turns = turn_list json['route_instructions']
modes = mode_list json['route_instructions']
+ times = time_list json['route_instructions']
+ distances = distance_list json['route_instructions']
end
end
-
- if table.headers.include? 'start'
- got['start'] = instructions ? json['route_summary']['start_point'] : nil
+
+ if table.headers.include? 'status'
+ got['status'] = json['status'].to_s
end
- if table.headers.include? 'end'
- got['end'] = instructions ? json['route_summary']['end_point'] : nil
+ if table.headers.include? 'message'
+ got['message'] = json['status_message']
end
- if table.headers.include? 'route'
- got['route'] = (instructions || '').strip
- if table.headers.include?('distance')
- if row['distance']!=''
- raise "*** Distance must be specied in meters. (ex: 250m)" unless row['distance'] =~ /\d+m/
- end
- got['distance'] = instructions ? "#{json['route_summary']['total_distance'].to_s}m" : ''
- end
- if table.headers.include?('time')
- raise "*** Time must be specied in seconds. (ex: 60s)" unless row['time'] =~ /\d+s/
- got['time'] = instructions ? "#{json['route_summary']['total_time'].to_s}s" : ''
- end
- if table.headers.include? 'bearing'
- got['bearing'] = bearings
- end
- if table.headers.include? 'compass'
- got['compass'] = compasses
+ if table.headers.include? '#' # comment column
+ got['#'] = row['#'] # copy value so it always match
+ end
+
+ if response.code == "200"
+ if table.headers.include? 'start'
+ got['start'] = instructions ? json['route_summary']['start_point'] : nil
end
- if table.headers.include? 'turns'
- got['turns'] = turns
+ if table.headers.include? 'end'
+ got['end'] = instructions ? json['route_summary']['end_point'] : nil
end
- if table.headers.include? 'modes'
- got['modes'] = modes
+ if table.headers.include? 'geometry'
+ got['geometry'] = json['route_geometry']
end
- if table.headers.include? '#' # comment column
- got['#'] = row['#'] # copy value so it always match
+ if table.headers.include? 'route'
+ got['route'] = (instructions || '').strip
+ if table.headers.include?('distance')
+ if row['distance']!=''
+ raise "*** Distance must be specied in meters. (ex: 250m)" unless row['distance'] =~ /\d+m/
+ end
+ got['distance'] = instructions ? "#{json['route_summary']['total_distance'].to_s}m" : ''
+ end
+ if table.headers.include?('time')
+ raise "*** Time must be specied in seconds. (ex: 60s)" unless row['time'] =~ /\d+s/
+ got['time'] = instructions ? "#{json['route_summary']['total_time'].to_s}s" : ''
+ end
+ if table.headers.include?('speed')
+ if row['speed'] != '' && instructions
+ raise "*** Speed must be specied in km/h. (ex: 50 km/h)" unless row['speed'] =~ /\d+ km\/h/
+ time = json['route_summary']['total_time']
+ distance = json['route_summary']['total_distance']
+ speed = time>0 ? (3.6*distance/time).to_i : nil
+ got['speed'] = "#{speed} km/h"
+ else
+ got['speed'] = ''
+ end
+ end
+ if table.headers.include? 'bearing'
+ got['bearing'] = bearings
+ end
+ if table.headers.include? 'compass'
+ got['compass'] = compasses
+ end
+ if table.headers.include? 'turns'
+ got['turns'] = turns
+ end
+ if table.headers.include? 'modes'
+ got['modes'] = modes
+ end
+ if table.headers.include? 'times'
+ got['times'] = times
+ end
+ if table.headers.include? 'distances'
+ got['distances'] = distances
+ end
end
end
-
+
ok = true
row.keys.each do |key|
if FuzzyMatch.match got[key], row[key]
@@ -92,12 +132,11 @@ When /^I route I should get$/ do |table|
ok = false
end
end
-
+
unless ok
- failed = { :attempt => 'route', :query => @query, :response => response }
- log_fail row,got,[failed]
+ log_fail row,got, { 'route' => {:query => @query, :response => response} }
end
-
+
actual << got
end
end
diff --git a/features/stress/launch.feature b/features/stress/launch.feature
index 2463782..10c13c8 100644
--- a/features/stress/launch.feature
+++ b/features/stress/launch.feature
@@ -1,58 +1,58 @@
@stress
Feature: Stress testing
-
- Background:
- Given the profile "testbot"
-
- Scenario: Stress - 10km star, request 1 route
- #osrm-routed hangs very often
- Given a grid size of 10000 meters
- Given the node map
- | h | a | b |
- | g | x | c |
- | f | e | d |
- And the ways
- | nodes | highway |
- | xa | primary |
- | xb | primary |
- | xc | primary |
- | xd | primary |
- | xe | primary |
- | xf | primary |
- | xg | primary |
- | xh | primary |
+ Background:
+ Given the profile "testbot"
- When I route 100 times I should get
- | from | to | route |
- | x | h | xh |
+ Scenario: Stress - 10km star, request 1 route
+ #osrm-routed hangs very often
+ Given a grid size of 10000 meters
+ Given the node map
+ | h | a | b |
+ | g | x | c |
+ | f | e | d |
- Scenario: Stress - 10km star, request 8 routes
- #osrm-routed hangs sometimes
- Given a grid size of 10000 meters
- Given the node map
- | h | a | b |
- | g | x | c |
- | f | e | d |
+ And the ways
+ | nodes | highway |
+ | xa | primary |
+ | xb | primary |
+ | xc | primary |
+ | xd | primary |
+ | xe | primary |
+ | xf | primary |
+ | xg | primary |
+ | xh | primary |
- And the ways
- | nodes | highway |
- | xa | primary |
- | xb | primary |
- | xc | primary |
- | xd | primary |
- | xe | primary |
- | xf | primary |
- | xg | primary |
- | xh | primary |
+ When I route 100 times I should get
+ | from | to | route |
+ | x | h | xh |
- When I route 100 times I should get
- | from | to | route |
- | x | a | xa |
- | x | b | xb |
- | x | c | xc |
- | x | d | xd |
- | x | e | xe |
- | x | f | xf |
- | x | g | xg |
- | x | h | xh |
+ Scenario: Stress - 10km star, request 8 routes
+ #osrm-routed hangs sometimes
+ Given a grid size of 10000 meters
+ Given the node map
+ | h | a | b |
+ | g | x | c |
+ | f | e | d |
+
+ And the ways
+ | nodes | highway |
+ | xa | primary |
+ | xb | primary |
+ | xc | primary |
+ | xd | primary |
+ | xe | primary |
+ | xf | primary |
+ | xg | primary |
+ | xh | primary |
+
+ When I route 100 times I should get
+ | from | to | route |
+ | x | a | xa |
+ | x | b | xb |
+ | x | c | xc |
+ | x | d | xd |
+ | x | e | xe |
+ | x | f | xf |
+ | x | g | xg |
+ | x | h | xh |
diff --git a/features/support/config.rb b/features/support/config.rb
index 63350d5..e61c9fc 100644
--- a/features/support/config.rb
+++ b/features/support/config.rb
@@ -10,21 +10,3 @@ end
def set_profile profile
@profile = profile
end
-
-def write_server_ini
- s=<<-EOF
-Threads = 1
-IP = 0.0.0.0
-Port = #{OSRM_PORT}
-
-hsgrData=#{@osm_file}.osrm.hsgr
-nodesData=#{@osm_file}.osrm.nodes
-edgesData=#{@osm_file}.osrm.edges
-ramIndex=#{@osm_file}.osrm.ramIndex
-fileIndex=#{@osm_file}.osrm.fileIndex
-namesData=#{@osm_file}.osrm.names
-timestamp=#{@osm_file}.osrm.timestamp
-EOF
- File.open( 'server.ini', 'w') {|f| f.write( s ) }
-end
-
diff --git a/features/support/cucumber.rb b/features/support/cucumber.rb
index 78465be..a43082a 100644
--- a/features/support/cucumber.rb
+++ b/features/support/cucumber.rb
@@ -23,7 +23,7 @@ class Cucumber::Ast::Table
require_diff_lcs
cell_matrix.extend(Diff::LCS)
changes = cell_matrix.diff(other_table_cell_matrix).flatten
-
+
inserted = 0
missing = 0
@@ -43,7 +43,7 @@ class Cucumber::Ast::Table
#change index so we interleave instead
insert_row_pos = change.position + inserted + 1
#insert_row_pos = change.position + missing #original
-
+
inserted_row = change.element
inserted_row.each{|cell| cell.status = :comment}
cell_matrix.insert(insert_row_pos, inserted_row)
@@ -66,7 +66,7 @@ class Cucumber::Ast::Table
end
clear_cache!
- should_raise =
+ should_raise =
missing_row_pos && options[:missing_row] ||
insert_row_pos && options[:surplus_row] ||
missing_col && options[:missing_col] ||
diff --git a/features/support/data.rb b/features/support/data.rb
index dbb0398..7c1ba88 100644
--- a/features/support/data.rb
+++ b/features/support/data.rb
@@ -2,29 +2,22 @@ require 'OSM/objects' #osmlib gem
require 'OSM/Database'
require 'builder'
-OSM_USER = 'osrm'
-OSM_GENERATOR = 'osrm-test'
-OSM_UID = 1
-TEST_FOLDER = 'test'
-DATA_FOLDER = 'cache'
-PREPROCESS_LOG_FILE = 'preprocessing.log'
-LOG_FILE = 'fail.log'
-OSM_TIMESTAMP = '2000-00-00T00:00:00Z'
-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
+ attr_accessor :lon,:lat
+
+ def initialize lon,lat
+ @lat = lat
+ @lon = lon
+ end
+end
+
+def set_input_format format
+ raise '*** Input format must be eiter "osm" or "pbf"' unless ['pbf','osm'].include? format.to_s
+ @input_format = format.to_s
+end
+
+def input_format
+ @input_format || DEFAULT_INPUT_FORMAT
end
def sanitized_scenario_title
@@ -38,22 +31,26 @@ def set_grid_size meters
@zoom = meters.to_f*0.8990679362704610899694577444566908445396483347536032203503E-5
end
+def set_origin origin
+ @origin = origin
+end
+
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 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, 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...
- node1 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+(0+WAY_SPACING*ri)*@zoom, ORIGIN[1]
- node2 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+(1+WAY_SPACING*ri)*@zoom, ORIGIN[1]
- node3 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+(2+WAY_SPACING*ri)*@zoom, ORIGIN[1]
- node4 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+(3+WAY_SPACING*ri)*@zoom, ORIGIN[1]
- node5 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+(4+WAY_SPACING*ri)*@zoom, ORIGIN[1]
+ node1 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(0+WAY_SPACING*ri)*@zoom, @origin[1]
+ node2 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(1+WAY_SPACING*ri)*@zoom, @origin[1]
+ node3 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(2+WAY_SPACING*ri)*@zoom, @origin[1]
+ node4 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(3+WAY_SPACING*ri)*@zoom, @origin[1]
+ node5 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, @origin[0]+(4+WAY_SPACING*ri)*@zoom, @origin[1]
node1.uid = OSM_UID
node2.uid = OSM_UID
node3.uid = OSM_UID
@@ -70,7 +67,7 @@ def build_ways_from_table table
osm_db << node3
osm_db << node4
osm_db << node5
-
+
#...with a way between them
way = OSM::Way.new make_osm_id, OSM_USER, OSM_TIMESTAMP
way.uid = OSM_UID
@@ -79,22 +76,22 @@ def build_ways_from_table table
way << node3
way << node4
way << node5
-
+
tags = row.dup
-
+
# remove tags that describe expected test result
tags.reject! do |k,v|
- k =~ /^forw\b/ ||
+ k =~ /^forw\b/ ||
k =~ /^backw\b/ ||
k =~ /^bothw\b/
end
-
+
##remove empty tags
tags.reject! { |k,v| v=='' }
-
+
# sort tag keys in the form of 'node/....'
way_tags = { 'highway' => 'primary' }
-
+
node_tags = {}
tags.each_pair do |k,v|
if k =~ /node\/(.*)/
@@ -111,39 +108,39 @@ def build_ways_from_table table
end
end
end
-
+
way_tags['name'] = "w#{ri}"
way << way_tags
node3 << node_tags
-
+
osm_db << way
end
end
def table_coord_to_lonlat ci,ri
- [ORIGIN[0]+ci*@zoom, ORIGIN[1]-ri*@zoom]
+ [@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
+ 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)
+ location_hash[name] = Location.new(lon,lat)
end
def find_node_by_name 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
+ 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
@@ -207,7 +204,7 @@ def osm_str
@osm_str
end
-def write_osm
+def write_osm
#write .oms file if needed
Dir.mkdir DATA_FOLDER unless File.exist? DATA_FOLDER
@osm_file = "#{DATA_FOLDER}/#{sanitized_scenario_title}_#{fingerprint}"
@@ -220,7 +217,7 @@ def convert_osm_to_pbf
unless File.exist?("#{@osm_file}.osm.pbf")
log_preprocess_info
log "== Converting #{@osm_file}.osm to protobuffer format...", :preprocess
- unless system "osmosis --read-xml #{@osm_file}.osm --write-pbf #{@osm_file}.osm.pbf omitmetadata=true 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE}"
+ unless system "osmosis --read-xml #{@osm_file}.osm --write-pbf #{@osm_file}.osm.pbf omitmetadata=true >>#{PREPROCESS_LOG_FILE} 2>&1"
raise OsmosisError.new $?, "osmosis exited with code #{$?.exitstatus}"
end
log '', :preprocess
@@ -241,31 +238,44 @@ def write_timestamp
File.open( "#{@osm_file}.osrm.timestamp", 'w') {|f| f.write(OSM_TIMESTAMP) }
end
-def reprocess
- use_pbf = true
+def pbf?
+ input_format=='pbf'
+end
+def write_input_data
Dir.chdir TEST_FOLDER do
write_osm
write_timestamp
- convert_osm_to_pbf if use_pbf
- unless extracted?
- log_preprocess_info
- log "== Extracting #{@osm_file}.osm...", :preprocess
- 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
- log '', :preprocess
+ convert_osm_to_pbf if pbf?
+ end
+end
+
+def extract_data
+ Dir.chdir TEST_FOLDER do
+ log_preprocess_info
+ log "== Extracting #{@osm_file}.osm...", :preprocess
+ unless system "#{BIN_PATH}/osrm-extract #{@osm_file}.osm#{'.pbf' if pbf?} --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
+ log "*** Exited with code #{$?.exitstatus}.", :preprocess
+ raise ExtractError.new $?.exitstatus, "osrm-extract exited with code #{$?.exitstatus}."
end
- unless prepared?
- log_preprocess_info
- log "== Preparing #{@osm_file}.osm...", :preprocess
- 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
- log '', :preprocess
+ log '', :preprocess
+ end
+end
+
+def prepare_data
+ Dir.chdir TEST_FOLDER do
+ log_preprocess_info
+ log "== Preparing #{@osm_file}.osm...", :preprocess
+ unless system "#{BIN_PATH}/osrm-prepare #{@osm_file}.osrm --profile #{PROFILES_PATH}/#{@profile}.lua >>#{PREPROCESS_LOG_FILE} 2>&1"
+ log "*** Exited with code #{$?.exitstatus}.", :preprocess
+ raise PrepareError.new $?.exitstatus, "osrm-prepare exited with code #{$?.exitstatus}."
end
- log_preprocess_done
- write_server_ini
+ log '', :preprocess
end
end
+
+def reprocess
+ write_input_data
+ extract_data unless extracted?
+ prepare_data unless prepared?
+ log_preprocess_done
+end
diff --git a/features/support/env.rb b/features/support/env.rb
index 13a0b0c..a6a9ca0 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -1,10 +1,26 @@
require 'rspec/expectations'
DEFAULT_PORT = 5000
+DEFAULT_TIMEOUT = 2
+
+ROOT_FOLDER = Dir.pwd
+OSM_USER = 'osrm'
+OSM_GENERATOR = 'osrm-test'
+OSM_UID = 1
+TEST_FOLDER = File.join ROOT_FOLDER, 'test'
+DATA_FOLDER = 'cache'
+OSM_TIMESTAMP = '2000-00-00T00:00:00Z'
+DEFAULT_SPEEDPROFILE = 'bicycle'
+WAY_SPACING = 100
+DEFAULT_GRID_SIZE = 100 #meters
+PROFILES_PATH = File.join ROOT_FOLDER, 'profiles'
+BIN_PATH = File.join ROOT_FOLDER, 'build'
+DEFAULT_INPUT_FORMAT = 'osm'
+DEFAULT_ORIGIN = [1,1]
puts "Ruby version #{RUBY_VERSION}"
-unless RUBY_VERSION =~ /^1.9/
+unless RUBY_VERSION.to_f >= 1.9
raise "*** Please upgrade to Ruby 1.9.x to run the OSRM cucumber tests"
end
@@ -16,3 +32,26 @@ else
puts "Using default port #{OSRM_PORT}"
end
+if ENV["OSRM_TIMEOUT"]
+ OSRM_TIMEOUT = ENV["OSRM_TIMEOUT"].to_i
+ puts "Timeout set to #{OSRM_TIMEOUT}"
+else
+ OSRM_TIMEOUT = DEFAULT_TIMEOUT
+ puts "Using default timeout #{OSRM_TIMEOUT}"
+end
+
+unless File.exists? TEST_FOLDER
+ raise "*** Test folder #{TEST_FOLDER} doesn't exist."
+end
+
+if ENV['OS']=~/Windows.*/ then
+ EXE='.exe'
+ QQ='"'
+else
+ EXE=''
+ QQ=''
+end
+
+AfterConfiguration do |config|
+ clear_log_files
+end
\ No newline at end of file
diff --git a/features/support/exceptions.rb b/features/support/exceptions.rb
index 22a6868..2901bfe 100644
--- a/features/support/exceptions.rb
+++ b/features/support/exceptions.rb
@@ -10,16 +10,23 @@ class OSRMError < StandardError
@log = log
@extract = log_tail @log, @lines
end
-
+
def to_s
"*** #{@msg}\nLast #{@lines} lines from #{@log}:\n#{@extract}\n"
end
-
+
private
-
+
def log_tail path, n
- File.open(path) do |f|
- return f.tail(n).map { |line| " > #{line}" }.join "\n"
+ Dir.chdir TEST_FOLDER do
+ expanded = File.expand_path path
+ if File.exists? expanded
+ File.open(expanded) do |f|
+ return f.tail(n).map { |line| " #{line}" }.join "\n"
+ end
+ else
+ return "File '#{expanded} does not exist!"
+ end
end
end
end
diff --git a/features/support/file.rb b/features/support/file.rb
index cd8fd14..dfaae0a 100644
--- a/features/support/file.rb
+++ b/features/support/file.rb
@@ -1,22 +1,34 @@
class File
-
- #read last n lines of a file. useful for getting last part of a big log file.
+
+ # read last n lines of a file (trailing newlines are ignored)
def tail(n)
+ return [] if size==0
buffer = 1024
- idx = (size - buffer).abs
- chunks = []
- lines = 0
+ str = nil
- begin
- seek(idx)
- chunk = read(buffer)
- lines += chunk.count("\n")
- chunks.unshift chunk
- idx -= buffer
- end while lines < ( n + 1 ) && pos != 0
+ if size>buffer
+ chunks = []
+ lines = 0
+ idx = size
+ begin
+ idx -= buffer # rewind
+ if idx<0
+ buffer += idx # adjust last read to avoid negative index
+ idx = 0
+ end
+ seek(idx)
+ chunk = read(buffer)
+ chunk.gsub!(/\n+\Z/,"") if chunks.empty? # strip newlines from end of file (first chunk)
+ lines += chunk.count("\n") # update total lines found
+ chunks.unshift chunk # prepend
+ end while lines<(n) && idx>0 # stop when enough lines found or no more to read
+ str = chunks.join('')
+ else
+ str = read(buffer)
+ end
- tail_of_file = chunks.join('')
- ary = tail_of_file.split(/\n/)
- lines_to_return = ary[ ary.size - n, ary.size - 1 ]
+ # return last n lines of str
+ lines = str.split("\n")
+ lines.size>=n ? lines[-n,n] : lines
end
end
\ No newline at end of file
diff --git a/features/support/fuzzy.rb b/features/support/fuzzy.rb
index 611d1ef..066d9c5 100644
--- a/features/support/fuzzy.rb
+++ b/features/support/fuzzy.rb
@@ -1,14 +1,17 @@
-
class FuzzyMatch
def self.match got, want
if got == want
return true
elsif want.match /(.*)\s+~(.+)%$/ #percentage range: 100 ~5%
- margin = 1 - $2.to_f*0.01
- from = $1.to_f*margin
- to = $1.to_f/margin
- return got.to_f >= from && got.to_f <= to
+ target = $1.to_f
+ percentage = $2.to_f
+ if target==0
+ return true
+ else
+ ratio = (1-(got.to_f / target)).abs;
+ return 100*ratio < percentage;
+ end
elsif want.match /(.*)\s+\+\-(.+)$/ #absolute range: 100 +-5
margin = $2.to_f
from = $1.to_f-margin
@@ -18,13 +21,12 @@ class FuzzyMatch
return got =~ /#{$1}/
else
return false
- end
+ end
end
-
+
def self.match_location got, want
match( got[0], "#{want.lat} ~0.0025%" ) &&
match( got[1], "#{want.lon} ~0.0025%" )
end
-
-end
+end
diff --git a/features/support/hash.rb b/features/support/hash.rb
index e37a6f2..197cd42 100644
--- a/features/support/hash.rb
+++ b/features/support/hash.rb
@@ -1,10 +1,13 @@
require 'digest/sha1'
+bin_extract_hash = nil
+profile_hashes = nil
+
def hash_of_files paths
paths = [paths] unless paths.is_a? Array
hash = Digest::SHA1.new
for path in paths do
- open(path,'r') do |io|
+ open(path,'rb') do |io|
while !io.eof
buf = io.readpartial 1024
hash.update buf
@@ -16,8 +19,8 @@ end
def profile_hash
- @@profile_hashes ||= {}
- @@profile_hashes[@profile] ||= hash_of_files "#{PROFILES_PATH}/#{@profile}.lua"
+ profile_hashes ||= {}
+ profile_hashes[@profile] ||= hash_of_files "#{PROFILES_PATH}/#{@profile}.lua"
end
def osm_hash
@@ -29,19 +32,18 @@ def lua_lib_hash
end
def bin_extract_hash
- @@bin_extract_hash ||= hash_of_files "#{BIN_PATH}/osrm-extract"
+ bin_extract_hash ||= hash_of_files "#{BIN_PATH}/osrm-extract#{EXE}"
end
def bin_prepare_hash
- @@bin_prepare_hash ||= hash_of_files "#{BIN_PATH}/osrm-prepare"
+ bin_prepare_hash ||= hash_of_files "#{BIN_PATH}/osrm-prepare#{EXE}"
end
def bin_routed_hash
- @@bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed"
+ bin_routed_hash ||= hash_of_files "#{BIN_PATH}/osrm-routed#{EXE}"
end
#combine state of data, profile and binaries into a hash that identifies the exact test scenario
def fingerprint
@fingerprint ||= Digest::SHA1.hexdigest "#{bin_extract_hash}-#{bin_prepare_hash}-#{bin_routed_hash}-#{profile_hash}-#{lua_lib_hash}-#{osm_hash}"
end
-
diff --git a/features/support/hooks.rb b/features/support/hooks.rb
index 41f9b3d..4c58a17 100644
--- a/features/support/hooks.rb
+++ b/features/support/hooks.rb
@@ -2,16 +2,33 @@
STRESS_TIMEOUT = 300
Before do |scenario|
- @scenario_title = scenario.title
+ # feature name
+ case scenario
+ when Cucumber::Ast::Scenario
+ @feature_name = scenario.feature.name
+ when Cucumber::Ast::OutlineTable::ExampleRow
+ @feature_name = scenario.scenario_outline.feature.name
+ end
+
+ # scenario name
+ case scenario
+ when Cucumber::Ast::Scenario
+ @scenario_title = scenario.name
+ when Cucumber::Ast::OutlineTable::ExampleRow
+ @scenario_title = scenario.scenario_outline.name
+ end
+
+
@scenario_time = Time.now.strftime("%Y-%m-%dT%H:%m:%SZ")
reset_data
@has_logged_preprocess_info = false
@has_logged_scenario_info = false
set_grid_size DEFAULT_GRID_SIZE
+ set_origin DEFAULT_ORIGIN
end
Around('@stress') do |scenario, block|
- Timeout.timeout(STRESS_TIMEOUT) do
+ Timeout.timeout(STRESS_TIMEOUT) do
block.call
end
end
diff --git a/features/support/launch.rb b/features/support/launch.rb
index e4252d8..e55867a 100644
--- a/features/support/launch.rb
+++ b/features/support/launch.rb
@@ -1,12 +1,17 @@
require 'socket'
require 'open3'
-LAUNCH_TIMEOUT = 2
-SHUTDOWN_TIMEOUT = 2
+if ENV['OS']==/Windows.*/ then
+ TERMSIGNAL='TERM'
+else
+ TERMSIGNAL=9
+end
+
OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
-class OSRMLauncher
- def initialize &block
+class OSRMBackgroundLauncher
+ def initialize input_file, &block
+ @input_file = input_file
Dir.chdir TEST_FOLDER do
begin
launch
@@ -18,42 +23,49 @@ class OSRMLauncher
end
private
-
+
def launch
- Timeout.timeout(LAUNCH_TIMEOUT) do
+ Timeout.timeout(OSRM_TIMEOUT) do
osrm_up
wait_for_connection
end
rescue Timeout::Error
raise RoutedError.new "Launching osrm-routed timed out."
end
-
+
def shutdown
- Timeout.timeout(SHUTDOWN_TIMEOUT) do
+ Timeout.timeout(OSRM_TIMEOUT) do
osrm_down
end
rescue Timeout::Error
kill
raise RoutedError.new "Shutting down osrm-routed timed out."
end
-
-
+
+
def osrm_up?
if @pid
- `ps -o state -p #{@pid}`.split[1].to_s =~ /^[DRST]/
- else
- false
+ begin
+ if Process.waitpid(@pid, Process::WNOHANG) then
+ false
+ else
+ true
+ end
+ rescue Errno::ESRCH, Errno::ECHILD
+ false
+ end
end
end
def osrm_up
return if osrm_up?
- @pid = Process.spawn(["#{BIN_PATH}/osrm-routed",''],:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
+ @pid = Process.spawn("#{BIN_PATH}/osrm-routed #{@input_file} --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
+ Process.detach(@pid) # avoid zombie processes
end
def osrm_down
if @pid
- Process.kill 'TERM', @pid
+ Process.kill TERMSIGNAL, @pid
wait_for_shutdown
end
end
@@ -67,7 +79,7 @@ class OSRMLauncher
def wait_for_connection
while true
begin
- socket = TCPSocket.new('localhost', OSRM_PORT)
+ socket = TCPSocket.new('127.0.0.1', OSRM_PORT)
return
rescue Errno::ECONNREFUSED
sleep 0.1
diff --git a/features/support/nearest.rb b/features/support/locate.rb
similarity index 66%
copy from features/support/nearest.rb
copy to features/support/locate.rb
index e371307..9007247 100644
--- a/features/support/nearest.rb
+++ b/features/support/locate.rb
@@ -1,9 +1,9 @@
require 'net/http'
-def request_nearest_url path
+def request_locate_url path
@query = path
uri = URI.parse "#{HOST}/#{path}"
- Timeout.timeout(REQUEST_TIMEOUT) do
+ Timeout.timeout(OSRM_TIMEOUT) do
Net::HTTP.get_response uri
end
rescue Errno::ECONNREFUSED => e
@@ -12,6 +12,6 @@ rescue Timeout::Error
raise "*** osrm-routed did not respond."
end
-def request_nearest a
- request_nearest_url "nearest?loc=#{a}"
+def request_locate a
+ request_locate_url "locate?loc=#{a}"
end
diff --git a/features/support/log.rb b/features/support/log.rb
index 7aed850..e5d34cc 100644
--- a/features/support/log.rb
+++ b/features/support/log.rb
@@ -1,3 +1,19 @@
+# logging
+
+PREPROCESS_LOG_FILE = 'preprocessing.log'
+LOG_FILE = 'fail.log'
+
+
+def clear_log_files
+ Dir.chdir TEST_FOLDER do
+ # emptying existing files, rather than deleting and writing new ones makes it
+ # easier to use tail -f from the command line
+ `echo '' > #{OSRM_ROUTED_LOG_FILE}`
+ `echo '' > #{PREPROCESS_LOG_FILE}`
+ `echo '' > #{LOG_FILE}`
+ end
+end
+
def log s='', type=nil
if type == :preprocess
file = PREPROCESS_LOG_FILE
@@ -24,17 +40,20 @@ def log_scenario_fail_info
@has_logged_scenario_info = true
end
-def log_fail expected,actual,failed
+def log_fail expected,got,attempts
log_scenario_fail_info
log "== "
log "Expected: #{expected}"
- log "Got: #{actual}"
+ log "Got: #{got}"
log
- failed.each do |fail|
- log "Attempt: #{fail[:attempt]}"
- log "Query: #{fail[:query]}"
- log "Response: #{fail[:response].body}"
- log
+ ['route','forw','backw'].each do |direction|
+ if attempts[direction]
+ attempts[direction]
+ log "Direction: #{direction}"
+ log "Query: #{attempts[direction][:query]}"
+ log "Response: #{attempts[direction][:response].body}"
+ log
+ end
end
end
@@ -63,5 +82,3 @@ end
def log_preprocess_done
end
-
-
diff --git a/features/support/nearest.rb b/features/support/nearest.rb
index e371307..77fc351 100644
--- a/features/support/nearest.rb
+++ b/features/support/nearest.rb
@@ -3,7 +3,7 @@ require 'net/http'
def request_nearest_url path
@query = path
uri = URI.parse "#{HOST}/#{path}"
- Timeout.timeout(REQUEST_TIMEOUT) do
+ Timeout.timeout(OSRM_TIMEOUT) do
Net::HTTP.get_response uri
end
rescue Errno::ECONNREFUSED => e
diff --git a/features/support/osm_parser.rb b/features/support/osm_parser.rb
index ea4e9bd..1da7c73 100644
--- a/features/support/osm_parser.rb
+++ b/features/support/osm_parser.rb
@@ -1,23 +1,25 @@
require 'OSM/StreamParser'
+locations = nil
+
class OSMTestParserCallbacks < OSM::Callbacks
- @@locations = nil
-
+ locations = nil
+
def self.locations
- if @@locations
- @@locations
+ if locations
+ locations
else
- #parse the test file, so we can later reference nodes and ways by name in tests
- @@locations = {}
+ #parse the test file, so we can later reference nodes and ways by name in tests
+ locations = {}
file = 'test/data/test.osm'
callbacks = OSMTestParserCallbacks.new
parser = OSM::StreamParser.new(:filename => file, :callbacks => callbacks)
parser.parse
- puts @@locations
+ puts locations
end
end
def node(node)
- @@locations[node.name] = [node.lat,node.lon]
+ locations[node.name] = [node.lat,node.lon]
end
end
\ No newline at end of file
diff --git a/features/support/route.rb b/features/support/route.rb
index 9cfbbfa..745edc0 100644
--- a/features/support/route.rb
+++ b/features/support/route.rb
@@ -1,7 +1,6 @@
require 'net/http'
-HOST = "http://localhost:#{OSRM_PORT}"
-REQUEST_TIMEOUT = 1
+HOST = "http://127.0.0.1:#{OSRM_PORT}"
DESTINATION_REACHED = 15 #OSRM instruction code
class Hash
@@ -17,7 +16,20 @@ def request_path path, waypoints=[], options={}
params = (locs + options.to_param).join('&')
params = nil if params==""
uri = URI.parse ["#{HOST}/#{path}", params].compact.join('?')
- Timeout.timeout(REQUEST_TIMEOUT) do
+ @query = uri.to_s
+ Timeout.timeout(OSRM_TIMEOUT) do
+ Net::HTTP.get_response uri
+ end
+rescue Errno::ECONNREFUSED => e
+ raise "*** osrm-routed is not running."
+rescue Timeout::Error
+ raise "*** osrm-routed did not respond."
+end
+
+def request_url path
+ uri = URI.parse"#{HOST}/#{path}"
+ @query = uri.to_s
+ Timeout.timeout(OSRM_TIMEOUT) do
Net::HTTP.get_response uri
end
rescue Errno::ECONNREFUSED => e
@@ -31,26 +43,6 @@ def request_route waypoints, params={}
request_path "viaroute", waypoints, defaults.merge(params)
end
-def parse_response response
- if response.code == "200" && response.body.empty? == false
- json = JSON.parse response.body
- if json['status'] == 0
- route = way_list json['route_instructions']
- if route.empty?
- "Empty route: #{json['route_instructions']}"
- else
- "Route: #{route}"
- end
- elsif json['status'] == 207
- "No route"
- else
- "Status: #{json['status']}"
- end
- else
- "HTTP: #{response.code}"
- end
-end
-
def got_route? response
if response.code == "200" && !response.body.empty?
json = JSON.parse response.body
@@ -80,56 +72,67 @@ def route_status response
end
end
+def extract_instruction_list instructions, index, postfix=nil
+ if instructions
+ instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }.
+ map { |r| r[index] }.
+ map { |r| (r=="" || r==nil) ? '""' : "#{r}#{postfix}" }.
+ join(',')
+ end
+end
+
def way_list instructions
- instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }.
- map { |r| r[1] }.
- map { |r| r=="" ? '""' : r }.
- join(',')
+ extract_instruction_list instructions, 1
end
def compass_list instructions
- instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }.
- map { |r| r[6] }.
- map { |r| r=="" ? '""' : r }.
- join(',')
+ extract_instruction_list instructions, 6
end
def bearing_list instructions
- instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }.
- map { |r| r[7] }.
- map { |r| r=="" ? '""' : r }.
- join(',')
+ extract_instruction_list instructions, 7
end
def turn_list instructions
- types = {
- 0 => :none,
- 1 => :straight,
- 2 => :slight_right,
- 3 => :right,
- 4 => :sharp_right,
- 5 => :u_turn,
- 6 => :sharp_left,
- 7 => :left,
- 8 => :slight_left,
- 9 => :via,
- 10 => :head,
- 11 => :enter_roundabout,
- 12 => :leave_roundabout,
- 13 => :stay_roundabout,
- 14 => :start_end_of_street,
- 15 => :destination,
- 16 => :enter_contraflow,
- 17 => :leave_contraflow
- }
- instructions.
- map { |r| types[r[0].to_i].to_s }.
- join(',')
+ if instructions
+ types = {
+ 0 => :none,
+ 1 => :straight,
+ 2 => :slight_right,
+ 3 => :right,
+ 4 => :sharp_right,
+ 5 => :u_turn,
+ 6 => :sharp_left,
+ 7 => :left,
+ 8 => :slight_left,
+ 9 => :via,
+ 10 => :head,
+ 11 => :enter_roundabout,
+ 12 => :leave_roundabout,
+ 13 => :stay_roundabout,
+ 14 => :start_end_of_street,
+ 15 => :destination,
+ 16 => :enter_contraflow,
+ 17 => :leave_contraflow
+ }
+ # replace instructions codes with strings
+ # "11-3" (enter roundabout and leave a 3rd exit) gets converted to "enter_roundabout-3"
+ instructions.map do |r|
+ r[0].to_s.gsub(/^\d*/) do |match|
+ types[match.to_i].to_s
+ end
+ end.join(',')
+ end
end
def mode_list instructions
- instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }.
- map { |r| r[8] }.
- map { |r| (r=="" || r==nil) ? '""' : r }.
- join(',')
-end
\ No newline at end of file
+ extract_instruction_list instructions, 8
+end
+
+def time_list instructions
+ extract_instruction_list instructions, 4, "s"
+end
+
+def distance_list instructions
+ extract_instruction_list instructions, 2, "m"
+end
diff --git a/features/support/run.rb b/features/support/run.rb
new file mode 100644
index 0000000..794050a
--- /dev/null
+++ b/features/support/run.rb
@@ -0,0 +1,18 @@
+def run_bin bin, options
+ Dir.chdir TEST_FOLDER do
+ opt = options.dup
+
+ if opt.include? '{base}'
+ raise "*** {base} is missing" unless @osm_file
+ opt.gsub! "{base}", "#{@osm_file}"
+ end
+
+ if opt.include? '{profile}'
+ opt.gsub! "{profile}", "#{PROFILES_PATH}/#{@profile}.lua"
+ end
+
+ @stdout = `#{QQ}#{BIN_PATH}/#{bin}#{EXE}#{QQ} #{opt} 2>error.log`
+ @stderr = File.read 'error.log'
+ @exit_code = $?.exitstatus
+ end
+end
\ No newline at end of file
diff --git a/features/testbot/bad.feature b/features/testbot/bad.feature
index 8fb3703..f0f3cfa 100644
--- a/features/testbot/bad.feature
+++ b/features/testbot/bad.feature
@@ -1,86 +1,86 @@
@routing @bad
Feature: Handle bad data in a graceful manner
-
- Background:
- Given the profile "testbot"
- Scenario: Empty dataset
- Given the node map
- | |
+ Background:
+ Given the profile "testbot"
- Given the ways
- | nodes |
-
- When I preprocess data
- Then "osrm-extract" should return code 255
+ Scenario: Empty dataset
+ Given the node map
+ | |
- Scenario: Only dead-end oneways
- Given the node map
- | a | b | c | d | e |
+ Given the ways
+ | nodes |
- Given the ways
- | nodes | oneway |
- | abcde | yes |
+ When the data has been prepared
+ Then "osrm-extract" should return code 1
+
+ Scenario: Only dead-end oneways
+ Given the node map
+ | a | b | c | d | e |
+
+ Given the ways
+ | nodes | oneway |
+ | abcde | yes |
+
+ When I route I should get
+ | from | to | route |
+ | b | d | abcde |
- When I route I should get
- | from | to | route |
- | b | d | abcde |
-
@todo
- Scenario: Start/end point at the same location
- Given the node map
- | a | b |
- | 1 | 2 |
+ Scenario: Start/end point at the same location
+ Given the node map
+ | a | b |
+ | 1 | 2 |
- Given the ways
- | nodes |
- | ab |
+ Given the ways
+ | nodes |
+ | ab |
- When I route I should get
- | from | to | route |
- | a | a | |
- | b | b | |
- | 1 | 1 | |
- | 2 | 2 | |
+ When I route I should get
+ | from | to | route |
+ | a | a | |
+ | b | b | |
+ | 1 | 1 | |
+ | 2 | 2 | |
- @poles
- Scenario: Routing close to the north/south pole
- Mercator is undefined close to the poles.
- All nodes and request with latitude to close to either of the poles should therefore be ignored.
+ @poles
+ Scenario: Routing close to the north/south pole
+ # Mercator is undefined close to the poles.
+ # All nodes and request with latitude to close to either of the poles should therefore be ignored.
- Given the node locations
- | node | lat | lon |
- | a | 89 | 0 |
- | b | 87 | 0 |
- | c | 82 | 0 |
- | d | 80 | 0 |
- | e | 78 | 0 |
- | k | -78 | 0 |
- | l | -80 | 0 |
- | m | -82 | 0 |
-# | n | -87 | 0 |
-# | o | -89 | 0 |
+ Given the node locations
+ | node | lat | lon |
+ | a | 89 | 0 |
+ | b | 87 | 0 |
+ | c | 82 | 0 |
+ | d | 80 | 0 |
+ | e | 78 | 0 |
+ | k | -78 | 0 |
+ | l | -80 | 0 |
+ | m | -82 | 0 |
+ # | n | -87 | 0 |
+ # | o | -89 | 0 |
- And the ways
- | nodes |
-# | ab |
- | bc |
- | cd |
- | de |
- | kl |
- | lm |
-# | mn |
-# | no |
+ And the ways
+ | nodes |
+ # | ab |
+ | bc |
+ | cd |
+ | de |
+ | kl |
+ | lm |
+ # | mn |
+ # | no |
- When I route I should get
- | from | to | route |
-# | 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 |
+ When I route I should get
+ | from | to | route |
+ # | 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 |
diff --git a/features/testbot/basic.feature b/features/testbot/basic.feature
index aabdcaa..4164319 100644
--- a/features/testbot/basic.feature
+++ b/features/testbot/basic.feature
@@ -1,272 +1,253 @@
@routing @basic
Feature: Basic Routing
-
- Background:
- Given the profile "testbot"
-
- @smallest
- Scenario: A single way with two nodes
- Given the node map
- | a | b |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | a | ab |
-
- Scenario: Routing in between two nodes of way
- Given the node map
- | a | b | 1 | 2 | c | d |
-
- And the ways
- | nodes |
- | abcd |
-
- When I route I should get
- | from | to | route |
- | 1 | 2 | abcd |
- | 2 | 1 | abcd |
-
- Scenario: Routing between the middle nodes of way
- Given the node map
- | a | b | c | d | e | f |
-
- And the ways
- | nodes |
- | abcdef |
-
- When I route I should get
- | from | to | route |
- | b | c | abcdef |
- | b | d | abcdef |
- | b | e | abcdef |
- | c | b | abcdef |
- | c | d | abcdef |
- | c | e | abcdef |
- | d | b | abcdef |
- | d | c | abcdef |
- | d | e | abcdef |
- | e | b | abcdef |
- | e | c | abcdef |
- | e | d | abcdef |
-
- Scenario: Two ways connected in a straight line
- Given the node map
- | a | b | c |
-
- And the ways
- | nodes |
- | ab |
- | bc |
+
+ Background:
+ Given the profile "testbot"
+
+ @smallest
+ Scenario: A single way with two nodes
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | b | a | ab |
+
+ Scenario: Routing in between two nodes of way
+ Given the node map
+ | a | b | 1 | 2 | c | d |
+
+ And the ways
+ | nodes |
+ | abcd |
+
+ When I route I should get
+ | from | to | route |
+ | 1 | 2 | abcd |
+ | 2 | 1 | abcd |
+
+ Scenario: Routing between the middle nodes of way
+ Given the node map
+ | a | b | c | d | e | f |
+
+ And the ways
+ | nodes |
+ | abcdef |
+
+ When I route I should get
+ | from | to | route |
+ | b | c | abcdef |
+ | b | d | abcdef |
+ | b | e | abcdef |
+ | c | b | abcdef |
+ | c | d | abcdef |
+ | c | e | abcdef |
+ | d | b | abcdef |
+ | d | c | abcdef |
+ | d | e | abcdef |
+ | e | b | abcdef |
+ | e | c | abcdef |
+ | e | d | abcdef |
+
+ Scenario: Two ways connected in a straight line
+ Given the node map
+ | a | b | c |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+
+ When I route I should get
+ | from | to | route |
+ | a | c | ab,bc |
+ | c | a | bc,ab |
+ | a | b | ab |
+ | b | a | ab |
+ | b | c | bc |
+ | c | b | bc |
+
+ Scenario: 2 unconnected parallel ways
+ Given the node map
+ | a | b | c |
+ | d | e | f |
+
+ And the ways
+ | nodes |
+ | abc |
+ | def |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | abc |
+ | b | a | abc |
+ | b | c | abc |
+ | c | b | abc |
+ | d | e | def |
+ | e | d | def |
+ | e | f | def |
+ | f | e | def |
+ | a | d | |
+ | d | a | |
+ | b | d | |
+ | d | b | |
+ | c | d | |
+ | d | c | |
+ | a | e | |
+ | e | a | |
+ | b | e | |
+ | e | b | |
+ | c | e | |
+ | e | c | |
+ | a | f | |
+ | f | a | |
+ | b | f | |
+ | f | b | |
+ | c | f | |
+ | f | c | |
+
+ Scenario: 3 ways connected in a triangle
+ Given the node map
+ | a | | b |
+ | | | |
+ | | c | |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | ca |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | a | c | ca |
+ | b | c | bc |
+ | b | a | ab |
+ | c | a | ca |
+ | c | b | bc |
+
+ Scenario: 3 connected triangles
+ Given a grid size of 100 meters
+ Given the node map
+ | x | a | | b | s |
+ | y | | | | t |
+ | | | c | | |
+ | | v | | w | |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | ca |
+ | ax |
+ | xy |
+ | ya |
+ | bs |
+ | st |
+ | tb |
+ | cv |
+ | vw |
+ | wc |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | a | c | ca |
+ | b | c | bc |
+ | b | a | ab |
+ | c | a | ca |
+ | c | b | bc |
+
+ Scenario: To ways connected at a 45 degree angle
+ Given the node map
+ | a | | |
+ | b | | |
+ | c | d | e |
+
+ And the ways
+ | nodes |
+ | abc |
+ | cde |
+
+ When I route I should get
+ | from | to | route |
+ | b | d | abc,cde |
+ | a | e | abc,cde |
+ | a | c | abc |
+ | c | a | abc |
+ | c | e | cde |
+ | e | c | cde |
+
+ Scenario: Grid city center
+ Given the node map
+ | a | b | c | d |
+ | e | f | g | h |
+ | i | j | k | l |
+ | m | n | o | p |
+
+ And the ways
+ | nodes |
+ | abcd |
+ | efgh |
+ | ijkl |
+ | mnop |
+ | aeim |
+ | bfjn |
+ | cgko |
+ | dhlp |
+
+ When I route I should get
+ | from | to | route |
+ | f | g | efgh |
+ | g | f | efgh |
+ | f | j | bfjn |
+ | j | f | bfjn |
+
+ Scenario: Grid city periphery
+ Given the node map
+ | a | b | c | d |
+ | e | f | g | h |
+ | i | j | k | l |
+ | m | n | o | p |
+
+ And the ways
+ | nodes |
+ | abcd |
+ | efgh |
+ | ijkl |
+ | mnop |
+ | aeim |
+ | bfjn |
+ | cgko |
+ | dhlp |
+
+ When I route I should get
+ | from | to | route |
+ | a | d | abcd |
+ | d | a | abcd |
+ | a | m | aeim |
+ | m | a | aeim |
- When I route I should get
- | from | to | route |
- | a | c | ab,bc |
- | c | a | bc,ab |
- | a | b | ab |
- | b | a | ab |
- | b | c | bc |
- | c | b | bc |
-
- Scenario: 2 unconnected parallel ways
- Given the node map
- | a | b | c |
- | d | e | f |
-
- And the ways
- | nodes |
- | abc |
- | def |
-
- When I route I should get
- | from | to | route |
- | a | b | abc |
- | b | a | abc |
- | b | c | abc |
- | c | b | abc |
- | d | e | def |
- | e | d | def |
- | e | f | def |
- | f | e | def |
- | a | d | |
- | d | a | |
- | b | d | |
- | d | b | |
- | c | d | |
- | d | c | |
- | a | e | |
- | e | a | |
- | b | e | |
- | e | b | |
- | c | e | |
- | e | c | |
- | a | f | |
- | f | a | |
- | b | f | |
- | f | b | |
- | c | f | |
- | f | c | |
-
- Scenario: 3 ways connected in a triangle
- Given the node map
- | a | | b |
- | | | |
- | | c | |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | ca |
-
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ca |
- | b | c | bc |
- | b | a | ab |
- | c | a | ca |
- | c | b | bc |
-
- Scenario: 3 connected triangles
- Given a grid size of 100 meters
- Given the node map
- | x | a | | b | s |
- | y | | | | t |
- | | | c | | |
- | | v | | w | |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | ca |
- | ax |
- | xy |
- | ya |
- | bs |
- | st |
- | tb |
- | cv |
- | vw |
- | wc |
-
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | a | c | ca |
- | b | c | bc |
- | b | a | ab |
- | c | a | ca |
- | c | b | bc |
-
- Scenario: To ways connected at a 45 degree angle
- Given the node map
- | a | | |
- | b | | |
- | c | d | e |
-
- And the ways
- | nodes |
- | abc |
- | cde |
-
- When I route I should get
- | from | to | route |
- | b | d | abc,cde |
- | a | e | abc,cde |
- | a | c | abc |
- | c | a | abc |
- | c | e | cde |
- | e | c | cde |
-
- Scenario: Grid city center
- Given the node map
- | a | b | c | d |
- | e | f | g | h |
- | i | j | k | l |
- | m | n | o | p |
-
- And the ways
- | nodes |
- | abcd |
- | efgh |
- | ijkl |
- | mnop |
- | aeim |
- | bfjn |
- | cgko |
- | dhlp |
-
- When I route I should get
- | from | to | route |
- | f | g | efgh |
- | g | f | efgh |
- | f | j | bfjn |
- | j | f | bfjn |
-
- Scenario: Grid city periphery
- Given the node map
- | a | b | c | d |
- | e | f | g | h |
- | i | j | k | l |
- | m | n | o | p |
-
- And the ways
- | nodes |
- | abcd |
- | efgh |
- | ijkl |
- | mnop |
- | aeim |
- | bfjn |
- | cgko |
- | dhlp |
-
- When I route I should get
- | from | to | route |
- | a | d | abcd |
- | d | a | abcd |
- | a | m | aeim |
- | m | a | aeim |
-
- Scenario: Routing on a oneway roundabout
- Given the node map
- | | d | c | |
- | e | | | b |
- | f | | | a |
- | | g | h | |
-
- And the ways
- | nodes | oneway |
- | ab | yes |
- | bc | yes |
- | cd | yes |
- | de | yes |
- | ef | yes |
- | fg | yes |
- | gh | yes |
- | ha | yes |
-
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | c | bc |
- | c | d | cd |
- | d | e | de |
- | e | f | ef |
- | f | g | fg |
- | g | h | gh |
- | h | a | ha |
- | b | a | bc,cd,de,ef,fg,gh,ha |
- | c | b | cd,de,ef,fg,gh,ha,ab |
- | d | c | de,ef,fg,gh,ha,ab,bc |
- | e | d | ef,fg,gh,ha,ab,bc,cd |
- | f | e | fg,gh,ha,ab,bc,cd,de |
- | g | f | gh,ha,ab,bc,cd,de,ef |
- | h | g | ha,ab,bc,cd,de,ef,fg |
- | a | h | ab,bc,cd,de,ef,fg,gh |
+ Scenario: Testbot - Triangle challenge
+ 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 |
diff --git a/features/testbot/bearing.feature b/features/testbot/bearing.feature
index 48ac5bd..c306af9 100644
--- a/features/testbot/bearing.feature
+++ b/features/testbot/bearing.feature
@@ -1,141 +1,211 @@
@routing @bearing
Feature: Compass bearing
-
- Background:
- Given the profile "testbot"
-
- Scenario: Bearing when going northwest
- Given the node map
- | b | |
- | | a |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route | compass | bearing |
- | a | b | ab | NW | 315 |
-
- Scenario: Bearing when going west
- Given the node map
- | b | a |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route | compass | bearing |
- | a | b | ab | W | 270 |
-
- Scenario: Bearing af 45 degree intervals
- Given the node map
- | b | a | h |
- | c | x | g |
- | d | e | f |
-
- And the ways
- | nodes |
- | xa |
- | xb |
- | xc |
- | xd |
- | xe |
- | xf |
- | xg |
- | xh |
-
- When I route I should get
- | from | to | route | compass | bearing |
- | x | a | xa | N | 0 |
- | x | b | xb | NW | 315 |
- | x | c | xc | W | 270 |
- | x | d | xd | SW | 225 |
- | x | e | xe | S | 180 |
- | x | f | xf | SE | 135 |
- | x | g | xg | E | 90 |
- | x | h | xh | NE | 45 |
-
- Scenario: Bearing in a roundabout
- Given the node map
- | | d | c | |
- | e | | | b |
- | f | | | a |
- | | g | h | |
-
- And the ways
- | nodes | oneway |
- | ab | yes |
- | bc | yes |
- | cd | yes |
- | de | yes |
- | ef | yes |
- | fg | yes |
- | gh | yes |
- | ha | yes |
-
- When I route I should get
- | from | to | route | compass | bearing |
- | c | b | cd,de,ef,fg,gh,ha,ab | W,SW,S,SE,E,NE,N | 270,225,180,135,90,45,0 |
- | g | f | gh,ha,ab,bc,cd,de,ef | E,NE,N,NW,W,SW,S | 90,45,0,315,270,225,180 |
-
- Scenario: Bearing should stay constant when zig-zagging
- Given the node map
- | b | d | f | h |
- | a | c | e | g |
-
- And the ways
- | nodes |
- | ab |
- | bc |
- | cd |
- | de |
- | ef |
- | fg |
- | gh |
-
- When I route I should get
- | from | to | route | compass | bearing |
- | a | h | ab,bc,cd,de,ef,fg,gh | N,SE,N,SE,N,SE,N | 0,135,0,135,0,135,0 |
-
- Scenario: Bearings on an east-west way.
- Given the node map
- | a | b | c | d | e | f |
-
- And the ways
- | nodes |
- | abcdef |
-
- When I route I should get
- | from | to | route | compass | bearing |
- | a | b | abcdef | E | 90 |
- | a | c | abcdef | E | 90 |
- | a | d | abcdef | E | 90 |
- | a | e | abcdef | E | 90 |
- | a | f | abcdef | E | 90 |
- | b | a | abcdef | W | 270 |
- | b | c | abcdef | E | 90 |
- | b | d | abcdef | E | 90 |
- | b | e | abcdef | E | 90 |
- | b | f | abcdef | E | 90 |
- | c | a | abcdef | W | 270 |
- | c | b | abcdef | W | 270 |
- | c | d | abcdef | E | 90 |
- | c | e | abcdef | E | 90 |
- | c | f | abcdef | E | 90 |
- | d | a | abcdef | W | 270 |
- | d | b | abcdef | W | 270 |
- | d | c | abcdef | W | 270 |
- | d | e | abcdef | E | 90 |
- | d | f | abcdef | E | 90 |
- | e | a | abcdef | W | 270 |
- | e | b | abcdef | W | 270 |
- | e | c | abcdef | W | 270 |
- | e | d | abcdef | W | 270 |
- | e | f | abcdef | E | 90 |
- | f | a | abcdef | W | 270 |
- | f | b | abcdef | W | 270 |
- | f | c | abcdef | W | 270 |
- | f | d | abcdef | W | 270 |
- | f | e | abcdef | W | 270 |
\ No newline at end of file
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Bearing when going northwest
+ Given the node map
+ | b | |
+ | | a |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | compass | bearing |
+ | a | b | ab | NW | 315 |
+
+ Scenario: Bearing when going west
+ Given the node map
+ | b | a |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | compass | bearing |
+ | a | b | ab | W | 270 |
+
+ Scenario: Bearing af 45 degree intervals
+ Given the node map
+ | b | a | h |
+ | c | x | g |
+ | d | e | f |
+
+ And the ways
+ | nodes |
+ | xa |
+ | xb |
+ | xc |
+ | xd |
+ | xe |
+ | xf |
+ | xg |
+ | xh |
+
+ When I route I should get
+ | from | to | route | compass | bearing |
+ | x | a | xa | N | 0 |
+ | x | b | xb | NW | 315 |
+ | x | c | xc | W | 270 |
+ | x | d | xd | SW | 225 |
+ | x | e | xe | S | 180 |
+ | x | f | xf | SE | 135 |
+ | x | g | xg | E | 90 |
+ | x | h | xh | NE | 45 |
+
+ Scenario: Bearing in a roundabout
+ Given the node map
+ | | d | c | |
+ | e | | | b |
+ | f | | | a |
+ | | g | h | |
+
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+ | bc | yes |
+ | cd | yes |
+ | de | yes |
+ | ef | yes |
+ | fg | yes |
+ | gh | yes |
+ | ha | yes |
+
+ When I route I should get
+ | from | to | route | compass | bearing |
+ | c | b | cd,de,ef,fg,gh,ha,ab | W,SW,S,SE,E,NE,N | 270,225,180,135,90,45,0 |
+ | g | f | gh,ha,ab,bc,cd,de,ef | E,NE,N,NW,W,SW,S | 90,45,0,315,270,225,180 |
+
+ Scenario: Bearing should stay constant when zig-zagging
+ Given the node map
+ | b | d | f | h |
+ | a | c | e | g |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | cd |
+ | de |
+ | ef |
+ | fg |
+ | gh |
+
+ When I route I should get
+ | from | to | route | compass | bearing |
+ | a | h | ab,bc,cd,de,ef,fg,gh | N,SE,N,SE,N,SE,N | 0,135,0,135,0,135,0 |
+
+ Scenario: Bearings on an east-west way.
+ Given the node map
+ | a | b | c | d | e | f |
+
+ And the ways
+ | nodes |
+ | abcdef |
+
+ When I route I should get
+ | from | to | route | compass | bearing |
+ | a | b | abcdef | E | 90 |
+ | a | c | abcdef | E | 90 |
+ | a | d | abcdef | E | 90 |
+ | a | e | abcdef | E | 90 |
+ | a | f | abcdef | E | 90 |
+ | b | a | abcdef | W | 270 |
+ | b | c | abcdef | E | 90 |
+ | b | d | abcdef | E | 90 |
+ | b | e | abcdef | E | 90 |
+ | b | f | abcdef | E | 90 |
+ | c | a | abcdef | W | 270 |
+ | c | b | abcdef | W | 270 |
+ | c | d | abcdef | E | 90 |
+ | c | e | abcdef | E | 90 |
+ | c | f | abcdef | E | 90 |
+ | d | a | abcdef | W | 270 |
+ | d | b | abcdef | W | 270 |
+ | d | c | abcdef | W | 270 |
+ | d | e | abcdef | E | 90 |
+ | d | f | abcdef | E | 90 |
+ | e | a | abcdef | W | 270 |
+ | e | b | abcdef | W | 270 |
+ | e | c | abcdef | W | 270 |
+ | e | d | abcdef | W | 270 |
+ | e | f | abcdef | E | 90 |
+ | f | a | abcdef | W | 270 |
+ | f | b | abcdef | W | 270 |
+ | f | c | abcdef | W | 270 |
+ | f | d | abcdef | W | 270 |
+ | f | e | abcdef | W | 270 |
+
+ Scenario: Bearings at high latitudes
+ # The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html,
+ # to form square with sides of 1 km.
+
+ Given the node locations
+ | node | lat | lon |
+ | a | 80 | 0 |
+ | b | 80.006389 | 0 |
+ | c | 80.006389 | 0.036667 |
+ | d | 80 | 0.036667 |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | cd |
+ | da |
+ | ac |
+ | bd |
+
+ When I route I should get
+ | from | to | route | compass | bearing |
+ | a | b | ab | N | 0 |
+ | b | c | bc | E | 90 |
+ | c | d | cd | S | 180 |
+ | d | a | da | W | 270 |
+ | b | a | ab | S | 180 |
+ | c | b | bc | W | 270 |
+ | d | c | cd | N | 0 |
+ | a | d | da | E | 90 |
+ | a | c | ac | NE | 45 |
+ | c | a | ac | SW | 225 |
+ | b | d | bd | SE | 135 |
+ | d | b | bd | NW | 315 |
+
+ Scenario: Bearings at high negative latitudes
+ # The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html,
+ # to form square with sides of 1 km.
+
+ Given the node locations
+ | node | lat | lon |
+ | a | -80 | 0 |
+ | b | -80.006389 | 0 |
+ | c | -80.006389 | 0.036667 |
+ | d | -80 | 0.036667 |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | cd |
+ | da |
+ | ac |
+ | bd |
+
+ When I route I should get
+ | from | to | route | compass | bearing |
+ | a | b | ab | S | 180 |
+ | b | c | bc | E | 90 |
+ | c | d | cd | N | 0 |
+ | d | a | da | W | 270 |
+ | b | a | ab | N | 0 |
+ | c | b | bc | W | 270 |
+ | d | c | cd | S | 180 |
+ | a | d | da | E | 90 |
+ | a | c | ac | SE | 135 |
+ | c | a | ac | NW | 315 |
+ | b | d | bd | NE | 45 |
+ | d | b | bd | SW | 225 |
diff --git a/features/testbot/bearing_param.feature b/features/testbot/bearing_param.feature
index 24d329d..e9db873 100644
--- a/features/testbot/bearing_param.feature
+++ b/features/testbot/bearing_param.feature
@@ -1,93 +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 |
+Feature: Bearing parameter
- 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
+ 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 |
+ 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 |
- 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 |
- 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 |
+ 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 |
+ 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 |
diff --git a/features/testbot/bug.feature b/features/testbot/bug.feature
deleted file mode 100644
index 6eb1349..0000000
--- a/features/testbot/bug.feature
+++ /dev/null
@@ -1,23 +0,0 @@
- at 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 |
diff --git a/features/testbot/bugs.feature b/features/testbot/bugs.feature
new file mode 100644
index 0000000..26be28a
--- /dev/null
+++ b/features/testbot/bugs.feature
@@ -0,0 +1,5 @@
+ at routing @testbot @bug
+Feature: Known bugs
+
+ Background:
+ Given the profile "testbot"
diff --git a/features/testbot/distance.feature b/features/testbot/distance.feature
index 1fb436b..f9f166b 100644
--- a/features/testbot/distance.feature
+++ b/features/testbot/distance.feature
@@ -1,228 +1,228 @@
@routing @distance
Feature: Distance calculation
-
- Background:
- Given the profile "testbot"
-
- Scenario: 100m distance
- Given a grid size of 100 meters
- Given the node map
- | a | b |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | ab | 100m +- 2 |
-
- Scenario: Distance should equal sum of segments, leftwinded
- Given the node map
- | e | |
- | d | c |
- | a | b |
-
- And the ways
- | nodes |
- | abcde |
-
- When I route I should get
- | from | to | route | distance |
- | a | d | abcde | 300m +-2 |
-
- Scenario: Distance should equal sum of segments, rightwinded
- Given the node map
- | | e |
- | c | d |
- | b | a |
-
- And the ways
- | nodes |
- | abcde |
-
- When I route I should get
- | from | to | route | distance |
- | a | d | abcde | 300m +-2 |
-
- Scenario: 10m distances
- Given a grid size of 10 meters
- Given the node map
- | a | b |
- | | c |
-
- And the ways
- | nodes |
- | abc |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | abc | 10m +-2 |
- | b | a | abc | 10m +-2 |
- | b | c | abc | 10m +-2 |
- | c | b | abc | 10m +-2 |
- | a | c | abc | 20m +-4 |
- | c | a | abc | 20m +-4 |
-
- Scenario: 100m distances
- Given a grid size of 100 meters
- Given the node map
- | a | b |
- | | c |
-
- And the ways
- | nodes |
- | abc |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | abc | 100m +-2 |
- | b | a | abc | 100m +-2 |
- | b | c | abc | 100m +-2 |
- | c | b | abc | 100m +-2 |
- | a | c | abc | 200m +-4 |
- | c | a | abc | 200m +-4 |
-
- Scenario: 1km distance
- Given a grid size of 1000 meters
- Given the node map
- | a | b |
- | | c |
-
- And the ways
- | nodes |
- | abc |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | abc | 1000m +-2 |
- | b | a | abc | 1000m +-2 |
- | b | c | abc | 1000m +-2 |
- | c | b | abc | 1000m +-2 |
- | a | c | abc | 2000m +-4 |
- | c | a | abc | 2000m +-4 |
-
- Scenario: Distance of a winding south-north path
- Given a grid size of 10 meters
- Given the node map
- | a | b |
- | d | c |
- | e | f |
- | h | g |
-
- And the ways
- | nodes |
- | abcdefgh |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | abcdefgh | 10m +-2 |
- | a | c | abcdefgh | 20m +-4 |
- | a | d | abcdefgh | 30m +-6 |
- | a | e | abcdefgh | 40m +-8 |
- | a | f | abcdefgh | 50m +-10 |
- | a | g | abcdefgh | 60m +-12 |
- | a | h | abcdefgh | 70m +-14 |
-
- Scenario: Distance of a winding east-west path
- Given a grid size of 10 meters
- Given the node map
- | a | d | e | h |
- | b | c | f | g |
-
- And the ways
- | nodes |
- | abcdefgh |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | abcdefgh | 10m +-2 |
- | a | c | abcdefgh | 20m +-4 |
- | a | d | abcdefgh | 30m +-6 |
- | a | e | abcdefgh | 40m +-8 |
- | a | f | abcdefgh | 50m +-10 |
- | a | g | abcdefgh | 60m +-12 |
- | a | h | abcdefgh | 70m +-14 |
-
- Scenario: Geometric distances
- Given a grid size of 1000 meters
- Given the node map
- | v | w | y | a | b | c | d |
- | u | | | | | | e |
- | t | | | | | | f |
- | s | | | x | | | g |
- | r | | | | | | h |
- | q | | | | | | i |
- | p | o | n | m | l | k | j |
-
- And the ways
- | nodes |
- | xa |
- | xb |
- | xc |
- | xd |
- | xe |
- | xf |
- | xg |
- | xh |
- | xi |
- | xj |
- | xk |
- | xl |
- | xm |
- | xn |
- | xo |
- | xp |
- | xq |
- | xr |
- | xs |
- | xt |
- | xu |
- | xv |
- | xw |
- | xy |
-
- When I route I should get
- | from | to | route | distance |
- | x | a | xa | 3000m +-2 |
- | x | b | xb | 3162m +-2 |
- | x | c | xc | 3606m +-2 |
- | x | d | xd | 4243m +-2 |
- | x | e | xe | 3606m +-2 |
- | x | f | xf | 3162m +-2 |
- | x | g | xg | 3000m +-2 |
- | x | h | xh | 3162m +-2 |
- | x | i | xi | 3606m +-2 |
- | x | j | xj | 4243m +-2 |
- | x | k | xk | 3606m +-2 |
- | x | l | xl | 3162m +-2 |
- | x | m | xm | 3000m +-2 |
- | x | n | xn | 3162m +-2 |
- | x | o | xo | 3606m +-2 |
- | x | p | xp | 4243m +-2 |
- | x | q | xq | 3606m +-2 |
- | x | r | xr | 3162m +-2 |
- | x | s | xs | 3000m +-2 |
- | x | t | xt | 3162m +-2 |
- | x | u | xu | 3606m +-2 |
- | x | v | xv | 4243m +-2 |
- | x | w | xw | 3606m +-2 |
- | x | y | xy | 3162m +-2 |
-
- @maze
- Scenario: Distance of a maze of short segments
- Given a grid size of 7 meters
- Given the node map
- | a | b | s | t |
- | d | c | r | q |
- | e | f | o | p |
- | h | g | n | m |
- | i | j | k | l |
-
- And the ways
- | nodes |
- | abcdefghijklmnopqrst |
-
- When I route I should get
- | from | to | route | distance |
- | a | t | abcdefghijklmnopqrst | 133m +-2 |
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: 100m distance
+ Given a grid size of 100 meters
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | ab | 100m +- 2 |
+
+ Scenario: Distance should equal sum of segments, leftwinded
+ Given the node map
+ | e | |
+ | d | c |
+ | a | b |
+
+ And the ways
+ | nodes |
+ | abcde |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | d | abcde | 300m +-2 |
+
+ Scenario: Distance should equal sum of segments, rightwinded
+ Given the node map
+ | | e |
+ | c | d |
+ | b | a |
+
+ And the ways
+ | nodes |
+ | abcde |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | d | abcde | 300m +-2 |
+
+ Scenario: 10m distances
+ Given a grid size of 10 meters
+ Given the node map
+ | a | b |
+ | | c |
+
+ And the ways
+ | nodes |
+ | abc |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | abc | 10m +-2 |
+ | b | a | abc | 10m +-2 |
+ | b | c | abc | 10m +-2 |
+ | c | b | abc | 10m +-2 |
+ | a | c | abc | 20m +-4 |
+ | c | a | abc | 20m +-4 |
+
+ Scenario: 100m distances
+ Given a grid size of 100 meters
+ Given the node map
+ | a | b |
+ | | c |
+
+ And the ways
+ | nodes |
+ | abc |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | abc | 100m +-2 |
+ | b | a | abc | 100m +-2 |
+ | b | c | abc | 100m +-2 |
+ | c | b | abc | 100m +-2 |
+ | a | c | abc | 200m +-4 |
+ | c | a | abc | 200m +-4 |
+
+ Scenario: 1km distance
+ Given a grid size of 1000 meters
+ Given the node map
+ | a | b |
+ | | c |
+
+ And the ways
+ | nodes |
+ | abc |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | abc | 1000m +-2 |
+ | b | a | abc | 1000m +-2 |
+ | b | c | abc | 1000m +-2 |
+ | c | b | abc | 1000m +-2 |
+ | a | c | abc | 2000m +-4 |
+ | c | a | abc | 2000m +-4 |
+
+ Scenario: Distance of a winding south-north path
+ Given a grid size of 10 meters
+ Given the node map
+ | a | b |
+ | d | c |
+ | e | f |
+ | h | g |
+
+ And the ways
+ | nodes |
+ | abcdefgh |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | abcdefgh | 10m +-2 |
+ | a | c | abcdefgh | 20m +-4 |
+ | a | d | abcdefgh | 30m +-6 |
+ | a | e | abcdefgh | 40m +-8 |
+ | a | f | abcdefgh | 50m +-10 |
+ | a | g | abcdefgh | 60m +-12 |
+ | a | h | abcdefgh | 70m +-14 |
+
+ Scenario: Distance of a winding east-west path
+ Given a grid size of 10 meters
+ Given the node map
+ | a | d | e | h |
+ | b | c | f | g |
+
+ And the ways
+ | nodes |
+ | abcdefgh |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | abcdefgh | 10m +-2 |
+ | a | c | abcdefgh | 20m +-4 |
+ | a | d | abcdefgh | 30m +-6 |
+ | a | e | abcdefgh | 40m +-8 |
+ | a | f | abcdefgh | 50m +-10 |
+ | a | g | abcdefgh | 60m +-12 |
+ | a | h | abcdefgh | 70m +-14 |
+
+ Scenario: Geometric distances
+ Given a grid size of 1000 meters
+ Given the node map
+ | v | w | y | a | b | c | d |
+ | u | | | | | | e |
+ | t | | | | | | f |
+ | s | | | x | | | g |
+ | r | | | | | | h |
+ | q | | | | | | i |
+ | p | o | n | m | l | k | j |
+
+ And the ways
+ | nodes |
+ | xa |
+ | xb |
+ | xc |
+ | xd |
+ | xe |
+ | xf |
+ | xg |
+ | xh |
+ | xi |
+ | xj |
+ | xk |
+ | xl |
+ | xm |
+ | xn |
+ | xo |
+ | xp |
+ | xq |
+ | xr |
+ | xs |
+ | xt |
+ | xu |
+ | xv |
+ | xw |
+ | xy |
+
+ When I route I should get
+ | from | to | route | distance |
+ | x | a | xa | 3000m +-2 |
+ | x | b | xb | 3162m +-2 |
+ | x | c | xc | 3606m +-2 |
+ | x | d | xd | 4243m +-2 |
+ | x | e | xe | 3606m +-2 |
+ | x | f | xf | 3162m +-2 |
+ | x | g | xg | 3000m +-2 |
+ | x | h | xh | 3162m +-2 |
+ | x | i | xi | 3606m +-2 |
+ | x | j | xj | 4243m +-2 |
+ | x | k | xk | 3606m +-2 |
+ | x | l | xl | 3162m +-2 |
+ | x | m | xm | 3000m +-2 |
+ | x | n | xn | 3162m +-2 |
+ | x | o | xo | 3606m +-2 |
+ | x | p | xp | 4243m +-2 |
+ | x | q | xq | 3606m +-2 |
+ | x | r | xr | 3162m +-2 |
+ | x | s | xs | 3000m +-2 |
+ | x | t | xt | 3162m +-2 |
+ | x | u | xu | 3606m +-2 |
+ | x | v | xv | 4243m +-2 |
+ | x | w | xw | 3606m +-2 |
+ | x | y | xy | 3162m +-2 |
+
+ @maze
+ Scenario: Distance of a maze of short segments
+ Given a grid size of 7 meters
+ Given the node map
+ | a | b | s | t |
+ | d | c | r | q |
+ | e | f | o | p |
+ | h | g | n | m |
+ | i | j | k | l |
+
+ And the ways
+ | nodes |
+ | abcdefghijklmnopqrst |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | t | abcdefghijklmnopqrst | 133m +-2 |
diff --git a/features/testbot/duration.feature b/features/testbot/duration.feature
index ab6571c..d5c6e46 100644
--- a/features/testbot/duration.feature
+++ b/features/testbot/duration.feature
@@ -1,42 +1,42 @@
@routing @testbot @routes @duration
Feature: Durations
- Background:
- Given the profile "testbot"
-
+ Background:
+ Given the profile "testbot"
+
Scenario: Duration of ways
- Given the node map
- | a | b | | | | f |
- | | | | e | | |
- | | c | | | d | |
-
- And the ways
- | nodes | highway | duration |
- | ab | primary | 0:01 |
- | bc | primary | 0:10 |
- | cd | primary | 1:00 |
- | de | primary | 10:00 |
- | ef | primary | 01:02:03 |
+ Given the node map
+ | a | b | | | | f |
+ | | | | e | | |
+ | | c | | | d | |
+
+ And the ways
+ | nodes | highway | duration |
+ | ab | primary | 0:01 |
+ | bc | primary | 0:10 |
+ | cd | primary | 1:00 |
+ | de | primary | 10:00 |
+ | ef | primary | 01:02:03 |
+
+ When I route I should get
+ | from | to | route | distance | time |
+ | a | b | ab | 100m +-1 | 60s +-1 |
+ | b | c | bc | 200m +-1 | 600s +-1 |
+ | c | d | cd | 300m +-1 | 3600s +-1 |
+ | d | e | de | 141m +-2 | 36000s +-1 |
+ | e | f | ef | 224m +-2 | 3723s +-1 |
- When I route I should get
- | from | to | route | distance | time |
- | a | b | ab | 100m +-1 | 60s +-1 |
- | b | c | bc | 200m +-1 | 600s +-1 |
- | c | d | cd | 300m +-1 | 3600s +-1 |
- | d | e | de | 144m +-2 | 36000s +-1 |
- | e | f | ef | 224m +-2 | 3723s +-1 |
-
@todo
Scenario: Partial duration of ways
- Given the node map
- | a | b | | c |
+ Given the node map
+ | a | b | | c |
- And the ways
- | nodes | highway | duration |
- | abc | primary | 0:01 |
+ And the ways
+ | nodes | highway | duration |
+ | abc | primary | 0:01 |
- When I route I should get
- | from | to | route | distance | time |
- | a | c | abc | 300m +-1 | 60s +-1 |
- | a | b | ab | 100m +-1 | 20s +-1 |
- | b | c | bc | 200m +-1 | 40s +-1 |
+ When I route I should get
+ | from | to | route | distance | time |
+ | a | c | abc | 300m +-1 | 60s +-1 |
+ | a | b | ab | 100m +-1 | 20s +-1 |
+ | b | c | bc | 200m +-1 | 40s +-1 |
diff --git a/features/testbot/example.feature b/features/testbot/example.feature
index 699d35c..c2aa1e9 100644
--- a/features/testbot/example.feature
+++ b/features/testbot/example.feature
@@ -1,38 +1,37 @@
@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"
-
+ Background:
+ Given the profile "testbot"
+
Scenario: Testbot - Processing Flow
- Given the node map
- | | | | d |
- | a | b | c | |
- | | | | e |
+ Given the node map
+ | | | | d |
+ | a | b | c | |
+ | | | | e |
- And the ways
- | nodes | highway | oneway |
- | abc | primary | |
- | cd | primary | yes |
- | ce | river | |
- | de | primary | |
+ 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 |
+ 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 |
diff --git a/features/testbot/fastest.feature b/features/testbot/fastest.feature
index 572280c..9a5cf24 100644
--- a/features/testbot/fastest.feature
+++ b/features/testbot/fastest.feature
@@ -1,38 +1,38 @@
@routing @fastest
Feature: Choosing fastest route
-
- Background:
- Given the profile "testbot"
-
- Scenario: Pick the geometrically shortest route, way types being equal
- Given the node map
- | | | s | | |
- | | | t | | |
- | x | a | | b | y |
- And the ways
- | nodes | highway |
- | xa | primary |
- | by | primary |
- | atb | primary |
- | asb | primary |
+ Background:
+ Given the profile "testbot"
- When I route I should get
- | from | to | route |
- | x | y | xa,atb,by |
- | y | x | by,atb,xa |
+ Scenario: Pick the geometrically shortest route, way types being equal
+ Given the node map
+ | | | s | | |
+ | | | t | | |
+ | x | a | | b | y |
- Scenario: Pick the fastest route, even when it's longer
- Given the node map
- | | p | |
- | a | s | b |
+ And the ways
+ | nodes | highway |
+ | xa | primary |
+ | by | primary |
+ | atb | primary |
+ | asb | primary |
- And the ways
- | nodes | highway |
- | apb | primary |
- | asb | secondary |
+ When I route I should get
+ | from | to | route |
+ | x | y | xa,atb,by |
+ | y | x | by,atb,xa |
- When I route I should get
- | from | to | route |
- | a | b | apb |
- | b | a | apb |
+ Scenario: Pick the fastest route, even when it's longer
+ Given the node map
+ | | p | |
+ | a | s | b |
+
+ And the ways
+ | nodes | highway |
+ | apb | primary |
+ | asb | secondary |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | apb |
+ | b | a | apb |
diff --git a/features/testbot/ferry.feature b/features/testbot/ferry.feature
index 7bd4353..5516061 100644
--- a/features/testbot/ferry.feature
+++ b/features/testbot/ferry.feature
@@ -1,175 +1,175 @@
@routing @testbot @ferry
Feature: Testbot - Handle ferry routes
- Background:
- Given the profile "testbot"
-
- Scenario: Testbot - Ferry duration, single node
- Given the node map
- | a | b | c | d |
- | e | f | g | h |
- | i | j | k | l |
- | m | n | o | p |
- | q | r | s | t |
-
- And the ways
- | nodes | highway | route | duration |
- | ab | primary | | |
- | cd | primary | | |
- | ef | primary | | |
- | gh | primary | | |
- | ij | primary | | |
- | kl | primary | | |
- | mn | primary | | |
- | op | primary | | |
- | qr | primary | | |
- | st | primary | | |
- | bc | | ferry | 0:01 |
- | fg | | ferry | 0:10 |
- | jk | | ferry | 1:00 |
- | no | | ferry | 24:00 |
- | rs | | ferry | 96:00 |
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Testbot - Ferry duration, single node
+ Given the node map
+ | a | b | c | d |
+ | e | f | g | h |
+ | i | j | k | l |
+ | m | n | o | p |
+ | q | r | s | t |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | ab | primary | | |
+ | cd | primary | | |
+ | ef | primary | | |
+ | gh | primary | | |
+ | ij | primary | | |
+ | kl | primary | | |
+ | mn | primary | | |
+ | op | primary | | |
+ | qr | primary | | |
+ | st | primary | | |
+ | bc | | ferry | 0:01 |
+ | fg | | ferry | 0:10 |
+ | jk | | ferry | 1:00 |
+ | no | | ferry | 24:00 |
+ | rs | | ferry | 96:00 |
When I route I should get
- | from | to | route | time |
- | b | c | bc | 60s +-1 |
- | f | g | fg | 600s +-1 |
- | j | k | jk | 3600s +-1 |
- | n | o | no | 86400s +-1 |
- | r | s | rs | 345600s +-1 |
-
+ | from | to | route | time |
+ | b | c | bc | 60s +-1 |
+ | f | g | fg | 600s +-1 |
+ | j | k | jk | 3600s +-1 |
+ | n | o | no | 86400s +-1 |
+ | r | s | rs | 345600s +-1 |
+
@todo
- Scenario: Testbot - Week long ferry routes
- Given the node map
- | a | b | c | d |
- | e | f | g | h |
- | i | j | k | l |
-
- And the ways
- | nodes | highway | route | duration |
- | ab | primary | | |
- | cd | primary | | |
- | ef | primary | | |
- | gh | primary | | |
- | ij | primary | | |
- | kl | primary | | |
- | bc | | ferry | 24:00 |
- | fg | | ferry | 168:00 |
- | jk | | ferry | 720:00 |
-
- When I route I should get
- | from | to | route | time |
- | b | c | bc | 86400s +-1 |
- | f | g | fg | 604800s +-1 |
- | j | k | jk | 259200s +-1 |
-
- Scenario: Testbot - Ferry duration, multiple nodes
- Given the node map
- | x | | | | | y |
- | | a | b | c | d | |
-
- And the ways
- | nodes | highway | route | duration |
- | xa | primary | | |
- | yd | primary | | |
- | ad | | ferry | 1:00 |
-
- When I route I should get
- | from | to | route | time |
- | a | d | ad | 3600s +-1 |
- | d | a | ad | 3600s +-1 |
-
+ Scenario: Testbot - Week long ferry routes
+ Given the node map
+ | a | b | c | d |
+ | e | f | g | h |
+ | i | j | k | l |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | ab | primary | | |
+ | cd | primary | | |
+ | ef | primary | | |
+ | gh | primary | | |
+ | ij | primary | | |
+ | kl | primary | | |
+ | bc | | ferry | 24:00 |
+ | fg | | ferry | 168:00 |
+ | jk | | ferry | 720:00 |
+
+ When I route I should get
+ | from | to | route | time |
+ | b | c | bc | 86400s +-1 |
+ | f | g | fg | 604800s +-1 |
+ | j | k | jk | 259200s +-1 |
+
+ Scenario: Testbot - Ferry duration, multiple nodes
+ Given the node map
+ | x | | | | | y |
+ | | a | b | c | d | |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | xa | primary | | |
+ | yd | primary | | |
+ | ad | | ferry | 1:00 |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | d | ad | 3600s +-1 |
+ | d | a | ad | 3600s +-1 |
+
@todo
- Scenario: Testbot - Ferry duration, individual parts, fast
+ Scenario: Testbot - Ferry duration, individual parts, fast
Given a grid size of 10000 meters
- Given the node map
- | x | y | | z | | | v |
- | a | b | | c | | | d |
-
- And the ways
- | nodes | highway | route | duration |
- | xa | primary | | |
- | yb | primary | | |
- | zc | primary | | |
- | vd | primary | | |
- | abcd | | ferry | 0:06 |
-
- When I route I should get
- | from | to | route | time |
- | a | d | abcd | 360s +-1 |
- | a | b | abcd | 60s +-1 |
- | b | c | abcd | 120s +-1 |
- | c | d | abcd | 180s +-1 |
-
+ Given the node map
+ | x | y | | z | | | v |
+ | a | b | | c | | | d |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | xa | primary | | |
+ | yb | primary | | |
+ | zc | primary | | |
+ | vd | primary | | |
+ | abcd | | ferry | 0:06 |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | d | abcd | 360s +-1 |
+ | a | b | abcd | 60s +-1 |
+ | b | c | abcd | 120s +-1 |
+ | c | d | abcd | 180s +-1 |
+
@todo
- Scenario: Testbot - Ferry duration, individual parts, slow
- Given the node map
- | x | y | | z | | | v |
- | a | b | | c | | | d |
-
- And the ways
- | nodes | highway | route | duration |
- | xa | primary | | |
- | yb | primary | | |
- | zc | primary | | |
- | vd | primary | | |
- | abcd | | ferry | 1:00 |
-
- When I route I should get
- | from | to | route | time |
- | a | d | abcd | 3600s ~1% |
- | a | b | abcd | 600s ~1% |
- | b | c | abcd | 1200s ~1% |
- | c | d | abcd | 1800s ~1% |
-
- Scenario: Testbot - Ferry duration, connected routes
- Given the node map
- | x | | | | d | | | | y |
- | | a | b | c | | e | f | g | t |
-
- And the ways
- | nodes | highway | route | duration |
- | xa | primary | | |
- | yg | primary | | |
- | abcd | | ferry | 0:30 |
- | defg | | ferry | 0:30 |
-
- When I route I should get
- | from | to | route | time |
- | a | g | abcd,defg | 3600s +-1 |
- | g | a | defg,abcd | 3600s +-1 |
-
- Scenario: Testbot - Prefer road when faster than ferry
- Given the node map
- | x | a | b | c | |
- | | | | | d |
- | y | g | f | e | |
-
- And the ways
- | nodes | highway | route | duration |
- | xa | primary | | |
- | yg | primary | | |
- | xy | primary | | |
- | abcd | | ferry | 0:01 |
- | defg | | ferry | 0:01 |
-
- When I route I should get
- | from | to | route | time |
- | a | g | xa,xy,yg | 60s +-25% |
- | g | a | yg,xy,xa | 60s +-25% |
-
- Scenario: Testbot - Long winding ferry route
- Given the node map
- | x | | b | | d | | f | | y |
- | | a | | c | | e | | g | |
-
- And the ways
- | nodes | highway | route | duration |
- | xa | primary | | |
- | yg | primary | | |
- | abcdefg | | ferry | 6:30 |
-
- When I route I should get
- | from | to | route | time |
- | a | g | abcdefg | 23400s +-1 |
- | g | a | abcdefg | 23400s +-1 |
+ Scenario: Testbot - Ferry duration, individual parts, slow
+ Given the node map
+ | x | y | | z | | | v |
+ | a | b | | c | | | d |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | xa | primary | | |
+ | yb | primary | | |
+ | zc | primary | | |
+ | vd | primary | | |
+ | abcd | | ferry | 1:00 |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | d | abcd | 3600s ~1% |
+ | a | b | abcd | 600s ~1% |
+ | b | c | abcd | 1200s ~1% |
+ | c | d | abcd | 1800s ~1% |
+
+ Scenario: Testbot - Ferry duration, connected routes
+ Given the node map
+ | x | | | | d | | | | y |
+ | | a | b | c | | e | f | g | t |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | xa | primary | | |
+ | yg | primary | | |
+ | abcd | | ferry | 0:30 |
+ | defg | | ferry | 0:30 |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | g | abcd,defg | 3600s +-1 |
+ | g | a | defg,abcd | 3600s +-1 |
+
+ Scenario: Testbot - Prefer road when faster than ferry
+ Given the node map
+ | x | a | b | c | |
+ | | | | | d |
+ | y | g | f | e | |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | xa | primary | | |
+ | yg | primary | | |
+ | xy | primary | | |
+ | abcd | | ferry | 0:01 |
+ | defg | | ferry | 0:01 |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | g | xa,xy,yg | 60s +-25% |
+ | g | a | yg,xy,xa | 60s +-25% |
+
+ Scenario: Testbot - Long winding ferry route
+ Given the node map
+ | x | | b | | d | | f | | y |
+ | | a | | c | | e | | g | |
+
+ And the ways
+ | nodes | highway | route | duration |
+ | xa | primary | | |
+ | yg | primary | | |
+ | abcdefg | | ferry | 6:30 |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | g | abcdefg | 23400s +-2 |
+ | g | a | abcdefg | 23400s +-2 |
diff --git a/features/testbot/fixed.feature b/features/testbot/fixed.feature
new file mode 100644
index 0000000..0edf25c
--- /dev/null
+++ b/features/testbot/fixed.feature
@@ -0,0 +1,26 @@
+ at routing @testbot @fixed
+Feature: Fixed bugs, kept to check for regressions
+
+ Background:
+ Given the profile "testbot"
+
+ @726
+ Scenario: Weird looping, manual input
+ Given the node locations
+ | node | lat | lon |
+ | a | 55.660778 | 12.573909 |
+ | b | 55.660672 | 12.573693 |
+ | c | 55.660128 | 12.572546 |
+ | d | 55.660015 | 12.572476 |
+ | e | 55.660119 | 12.572325 |
+ | x | 55.660818 | 12.574051 |
+ | y | 55.660073 | 12.574067 |
+
+ And the ways
+ | nodes |
+ | abc |
+ | cdec |
+
+ When I route I should get
+ | from | to | route | turns |
+ | x | y | abc | head,destination |
diff --git a/features/testbot/geometry.feature b/features/testbot/geometry.feature
new file mode 100644
index 0000000..553af93
--- /dev/null
+++ b/features/testbot/geometry.feature
@@ -0,0 +1,30 @@
+ at routing
+Feature: Retrieve geometry
+
+ Background: Use some profile
+ Given the profile "testbot"
+
+
+ @geometry
+ Scenario: Route retrieving geometry
+ Given the node locations
+ | node | lat | lon |
+ | a | 1.0 | 1.5 |
+ | b | 2.0 | 2.5 |
+ | c | 3.0 | 3.5 |
+ | d | 4.0 | 4.5 |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | cd |
+
+ When I route I should get
+ | from | to | route | geometry |
+ | a | c | ab,bc | _c`\|@_upzA_c`\|@_c`\|@_c`\|@_c`\|@ |
+ | b | d | bc,cd | _gayB_yqwC_c`\|@_c`\|@_c`\|@_c`\|@ |
+
+# Mind the \ before the pipes
+# polycodec.rb decode2 '_c`|@_upzA_c`|@_c`|@_c`|@_c`|@' [[1.0, 1.5], [2.0, 2.5], [3.0, 3.5]]
+# polycodec.rb decode2 '_gayB_yqwC_c`|@_c`|@_c`|@_c`|@' [[2.0, 2.5], [3.0, 3.5], [4.0, 4.5]]
diff --git a/features/testbot/graph.feature b/features/testbot/graph.feature
index 97a5171..a870106 100644
--- a/features/testbot/graph.feature
+++ b/features/testbot/graph.feature
@@ -1,22 +1,21 @@
@routing @graph
Feature: Basic Routing
-Test the input data descibed on https://github.com/DennisOSRM/Project-OSRM/wiki/Graph-representation
+#Test the input data descibed on https://github.com/DennisOSRM/Project-OSRM/wiki/Graph-representation
- Background:
- Given the profile "testbot"
-
- @smallest
- Scenario: Graph transformation
- Given the node map
- | | | d |
- | a | b | c |
- | | | e |
-
- And the ways
- | nodes |
- | abc |
- | dce |
-
- When I route I should get
- | from | to | route |
- | a | e | abc,dce |
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Graph transformation
+ Given the node map
+ | | | d |
+ | a | b | c |
+ | | | e |
+
+ And the ways
+ | nodes |
+ | abc |
+ | dce |
+
+ When I route I should get
+ | from | to | route |
+ | a | e | abc,dce |
diff --git a/features/testbot/impedance.feature b/features/testbot/impedance.feature
index 0e53623..cab9ec3 100644
--- a/features/testbot/impedance.feature
+++ b/features/testbot/impedance.feature
@@ -1,96 +1,95 @@
@routing @testbot @impedance @todo
Feature: Setting impedance and speed separately
-These tests assume that the speed is not factored into the impedance by OSRM internally.
-Instead the speed can optionally be factored into the weiht in the lua profile.
+# These tests assume that the speed is not factored into the impedance by OSRM internally.
+# Instead the speed can optionally be factored into the weiht in the lua profile.
+# Note: With the default grid size of 100m, the diagonals has a length if 141.42m
-Note: With the default grid size of 100m, the diagonals has a length if 141.42m
+ Background:
+ Given the profile "testbot"
- Background:
- Given the profile "testbot"
-
- Scenario: Use impedance to pick route, even when longer/slower
- Given the node map
- | | s | | t | | u | | v | |
- | a | | b | | c | | d | | e |
+ Scenario: Use impedance to pick route, even when longer/slower
+ Given the node map
+ | | s | | t | | u | | v | |
+ | a | | b | | c | | d | | e |
- And the ways
- | nodes | impedance |
- | ab | 1.3 |
- | asb | 1 |
- | bc | 1.5 |
- | btc | 1 |
- | cd | 0.015 |
- | cud | 0.010 |
- | de | 150000 |
- | dve | 100000 |
+ And the ways
+ | nodes | impedance |
+ | ab | 1.3 |
+ | asb | 1 |
+ | bc | 1.5 |
+ | btc | 1 |
+ | cd | 0.015 |
+ | cud | 0.010 |
+ | de | 150000 |
+ | dve | 100000 |
- When I route I should get
- | from | to | route | distance |
- | a | b | ab | 200m +-1 |
- | b | a | ab | 200m +-1 |
- | b | c | btc | 282m +-1 |
- | c | b | btc | 282m +-1 |
- | c | d | cud | 282m +-1 |
- | d | c | cud | 282m +-1 |
- | d | e | dve | 282m +-1 |
- | e | d | dve | 282m +-1 |
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | ab | 200m +-1 |
+ | b | a | ab | 200m +-1 |
+ | b | c | btc | 282m +-1 |
+ | c | b | btc | 282m +-1 |
+ | c | d | cud | 282m +-1 |
+ | d | c | cud | 282m +-1 |
+ | d | e | dve | 282m +-1 |
+ | e | d | dve | 282m +-1 |
- Scenario: Weight should default to 1
- Given the node map
- | | s | | t | |
- | a | | b | | c |
+ Scenario: Weight should default to 1
+ Given the node map
+ | | s | | t | |
+ | a | | b | | c |
- And the ways
- | nodes | impedance |
- | ab | 1.40 |
- | asb | |
- | bc | 1.42 |
- | btc | |
+ And the ways
+ | nodes | impedance |
+ | ab | 1.40 |
+ | asb | |
+ | bc | 1.42 |
+ | btc | |
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | a | ab |
- | b | c | btc |
- | c | b | btc |
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | b | a | ab |
+ | b | c | btc |
+ | c | b | btc |
- Scenario: Use both impedance and speed (multiplied) when picking route
- OSRM should not factor speed into impedance internally. However, the profile can choose to do so,
- and this test expect the testbot profile to do it.
- Given the node map
- | | s | | t | |
- | a | | b | | c |
+ Scenario: Use both impedance and speed (multiplied) when picking route
+ # OSRM should not factor speed into impedance internally. However, the profile can choose to do so,
+ # and this test expect the testbot profile to do it.
+ Given the node map
+ | | s | | t | |
+ | a | | b | | c |
- And the ways
- | nodes | impedance | highway |
- | ab | 2.80 | primary |
- | asb | 1 | secondary |
- | bc | 2.84 | primary |
- | btc | 1 | secondary |
+ And the ways
+ | nodes | impedance | highway |
+ | ab | 2.80 | primary |
+ | asb | 1 | secondary |
+ | bc | 2.84 | primary |
+ | btc | 1 | secondary |
- When I route I should get
- | from | to | route |
- | a | b | ab |
- | b | a | ab |
- | b | c | btc |
- | c | b | btc |
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | b | a | ab |
+ | b | c | btc |
+ | c | b | btc |
- Scenario: Weight should influence neither speed nor travel time.
- Given the node map
- | a | b | c |
- | t | | |
+ Scenario: Weight should influence neither speed nor travel time.
+ Given the node map
+ | a | b | c |
+ | t | | |
- And the ways
- | nodes |
- | ab |
- | bc |
- | at |
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | at |
- When I route I should get
- | from | to | route | distance | time |
- | a | b | ab | 100m +-1 | 10s +-1 |
- | b | a | ab | 100m +-1 | 10s +-1 |
- | b | c | bc | 100m +-1 | 10s +-1 |
- | c | b | bc | 100m +-1 | 10s +-1 |
- | a | c | ab,bc | 200m +-1 | 20s +-1 |
- | c | a | bc,ab | 200m +-1 | 20s +-1 |
+ When I route I should get
+ | from | to | route | distance | time |
+ | a | b | ab | 100m +-1 | 10s +-1 |
+ | b | a | ab | 100m +-1 | 10s +-1 |
+ | b | c | bc | 100m +-1 | 10s +-1 |
+ | c | b | bc | 100m +-1 | 10s +-1 |
+ | a | c | ab,bc | 200m +-1 | 20s +-1 |
+ | c | a | bc,ab | 200m +-1 | 20s +-1 |
diff --git a/features/testbot/loop.feature b/features/testbot/loop.feature
new file mode 100644
index 0000000..eb5b45e
--- /dev/null
+++ b/features/testbot/loop.feature
@@ -0,0 +1,78 @@
+ at routing @726
+Feature: Avoid weird loops caused by rounding errors
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Avoid weird loops 1
+ Given the node locations
+ | node | lat | lon |
+ | a | 55.6602463 | 12.5717242 |
+ | b | 55.6600270 | 12.5723008 |
+ | c | 55.6601840 | 12.5725037 |
+ | d | 55.6604146 | 12.5719299 |
+ | e | 55.6599410 | 12.5727592 |
+ | f | 55.6606727 | 12.5736932 |
+ | g | 55.6603422 | 12.5732619 |
+ | h | 55.6607785 | 12.5739097 |
+ | i | 55.6600566 | 12.5725070 |
+ | x | 55.6608180 | 12.5740510 |
+ | y | 55.6600730 | 12.5740670 |
+
+ And the ways
+ | nodes |
+ | ab |
+ | hfgd |
+ | icd |
+ | ad |
+ | ie |
+
+ When I route I should get
+ | from | to | route | turns |
+ | x | y | hfgd | head,destination |
+
+ Scenario: Avoid weird loops 2
+ Given the node locations
+ | node | lat | lon |
+ | a | 55.660778 | 12.573909 |
+ | b | 55.660672 | 12.573693 |
+ | c | 55.660128 | 12.572546 |
+ | d | 55.660015 | 12.572476 |
+ | e | 55.660119 | 12.572325 |
+ | x | 55.660818 | 12.574051 |
+ | y | 55.660073 | 12.574067 |
+
+ And the ways
+ | nodes |
+ | abc |
+ | cdec |
+
+ When I route I should get
+ | from | to | route | turns |
+ | x | y | abc | head,destination |
+
+ @412
+ Scenario: Avoid weird loops 3
+ And the node map
+ | a | | |
+ | b | e | |
+ | | | 1 |
+ | | | |
+ | | | 2 |
+ | | | |
+ | | c | f |
+ | | d | |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | cd | primary |
+ | be | secondary |
+ | ef | secondary |
+ | cf | secondary |
+
+ When I route I should get
+ | waypoints | route | turns |
+ | a,2,d | ab,be,ef,cf,cd | head,left,right,right,left,destination |
+ | a,1,d | ab,be,ef,cf,cd | head,left,right,right,left,destination |
diff --git a/features/testbot/maxspeed.feature b/features/testbot/maxspeed.feature
index c6b210e..5b27f9d 100644
--- a/features/testbot/maxspeed.feature
+++ b/features/testbot/maxspeed.feature
@@ -1,52 +1,29 @@
@routing @maxspeed @testbot
Feature: Car - Max speed restrictions
- Background: Use specific speeds
- Given the profile "testbot"
-
- Scenario: Testbot - Respect maxspeeds when lower that way type speed
- Given the node map
- | a | b | c | d |
+ Background: Use specific speeds
+ Given the profile "testbot"
- And the ways
- | nodes | maxspeed |
- | ab | |
- | bc | 24 |
- | cd | 18 |
+ Scenario: Testbot - Respect maxspeeds when lower that way type speed
+ Then routability should be
+ | maxspeed | bothw |
+ | | 36 km/h |
+ | 18 | 18 km/h |
- When I route I should get
- | from | to | route | time |
- | a | b | ab | 10s +-1 |
- | b | a | ab | 10s +-1 |
- | b | c | bc | 15s +-1 |
- | c | b | bc | 15s +-1 |
- | c | d | cd | 20s +-1 |
- | d | c | cd | 20s +-1 |
-
- Scenario: Testbot - Ignore maxspeed when higher than way speed
- Given the node map
- | a | b | c |
-
- And the ways
- | nodes | maxspeed |
- | ab | |
- | bc | 200 |
-
- When I route I should get
- | from | to | route | time |
- | a | b | ab | 10s +-1 |
- | b | a | ab | 10s +-1 |
- | b | c | bc | 10s +-1 |
- | c | b | bc | 10s +-1 |
+ Scenario: Testbot - Ignore maxspeed when higher than way speed
+ Then routability should be
+ | maxspeed | bothw |
+ | | 36 km/h |
+ | 100 km/h | 36 km/h |
@opposite
Scenario: Testbot - Forward/backward maxspeed
- Then routability should be
- | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw |
- | | | | 20s +-1 | 20s +-1 |
- | 18 | | | 40s +-1 | 40s +-1 |
- | | 18 | | 40s +-1 | 20s +-1 |
- | | | 18 | 20s +-1 | 40s +-1 |
- | 9 | 18 | | 40s +-1 | 80s +-1 |
- | 9 | | 18 | 80s +-1 | 40s +-1 |
- | 9 | 24 | 18 | 30s +-1 | 40s +-1 |
\ No newline at end of file
+ Then routability should be
+ | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw |
+ | | | | 36 km/h | 36 km/h |
+ | 18 | | | 18 km/h | 18 km/h |
+ | | 18 | | 18 km/h | 36 km/h |
+ | | | 18 | 36 km/h | 18 km/h |
+ | 9 | 18 | | 18 km/h | 9 km/h |
+ | 9 | | 18 | 9 km/h | 18 km/h |
+ | 9 | 24 | 18 | 24 km/h | 18 km/h |
\ No newline at end of file
diff --git a/features/testbot/mode.feature b/features/testbot/mode.feature
index 3192c48..bcc087e 100644
--- a/features/testbot/mode.feature
+++ b/features/testbot/mode.feature
@@ -1,26 +1,26 @@
@routing @testbot @mode
Feature: Testbot - Mode flag
- Background:
- Given the profile "testbot"
-
+ Background:
+ Given the profile "testbot"
+
@todo
- Scenario: Bike - Mode
- Given the node map
- | a | b | |
- | | c | d |
+ 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 | | |
+ 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 |
+ 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 |
diff --git a/features/testbot/oneway.feature b/features/testbot/oneway.feature
new file mode 100644
index 0000000..c21d8b1
--- /dev/null
+++ b/features/testbot/oneway.feature
@@ -0,0 +1,44 @@
+ at routing @testbot @oneway
+Feature: Testbot - oneways
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Routing on a oneway roundabout
+ Given the node map
+ | x | | | v | | |
+ | | | d | c | | |
+ | | e | | | b | |
+ | | f | | | a | |
+ | | | g | h | | |
+
+ And the ways
+ | nodes | oneway |
+ | ab | yes |
+ | bc | yes |
+ | cd | yes |
+ | de | yes |
+ | ef | yes |
+ | fg | yes |
+ | gh | yes |
+ | ha | yes |
+ | vx | yes |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | ab |
+ | b | c | bc |
+ | c | d | cd |
+ | d | e | de |
+ | e | f | ef |
+ | f | g | fg |
+ | g | h | gh |
+ | h | a | ha |
+ | b | a | bc,cd,de,ef,fg,gh,ha |
+ | c | b | cd,de,ef,fg,gh,ha,ab |
+ | d | c | de,ef,fg,gh,ha,ab,bc |
+ | e | d | ef,fg,gh,ha,ab,bc,cd |
+ | f | e | fg,gh,ha,ab,bc,cd,de |
+ | g | f | gh,ha,ab,bc,cd,de,ef |
+ | h | g | ha,ab,bc,cd,de,ef,fg |
+ | a | h | ab,bc,cd,de,ef,fg,gh |
diff --git a/features/testbot/opposite.feature b/features/testbot/opposite.feature
index c242c97..c19755c 100644
--- a/features/testbot/opposite.feature
+++ b/features/testbot/opposite.feature
@@ -1,18 +1,18 @@
@routing @testbot @opposite
Feature: Separate settings for forward/backward direction
-
- Background:
- Given the profile "testbot"
-
- Scenario: Testbot - Going against the flow
- Given the node map
- | a | b | c | d |
-
- And the ways
- | nodes | highway |
- | abcd | river |
-
- When I route I should get
- | from | to | route | distance | time |
- | a | d | abcd | 300 +- 1m | 30s |
- | d | a | abcd | 300 +- 1m | 68s |
\ No newline at end of file
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Testbot - Going against the flow
+ Given the node map
+ | a | b | c | d |
+
+ And the ways
+ | nodes | highway |
+ | abcd | river |
+
+ When I route I should get
+ | from | to | route | distance | speed |
+ | a | d | abcd | 300 +- 1m | 36 km/h |
+ | d | a | abcd | 300 +- 1m | 16 km/h +- 1 |
diff --git a/features/testbot/origin.feature b/features/testbot/origin.feature
index 3fe6d97..c43e04e 100644
--- a/features/testbot/origin.feature
+++ b/features/testbot/origin.feature
@@ -1,75 +1,75 @@
@routing @origin
Feature: Routing close to the [0,0] origin
-
- Background:
- Given the profile "testbot"
-
- Scenario: East-west oneways close to the origin
- Given the node locations
- | node | lat | lon |
- | a | 0 | 0 |
- | b | 0.0008990679362704611 | 0 |
- | c | 0.0017981358725409223 | 0 |
- | d | 0.0026972038088113833 | 0 |
- And the ways
- | nodes | oneway |
- | abcd | yes |
+ Background:
+ Given the profile "testbot"
- When I route I should get
- | from | to | route | distance |
- | b | c | abcd | 100m +-1 |
- | c | b | | |
+ Scenario: East-west oneways close to the origin
+ Given the node locations
+ | node | lat | lon |
+ | a | 0 | 0 |
+ | b | 0.0008990679362704611 | 0 |
+ | c | 0.0017981358725409223 | 0 |
+ | d | 0.0026972038088113833 | 0 |
- Scenario: North-south oneways close to the origin
- Given the node locations
- | node | lat | lon |
- | a | 0 | 0 |
- | b | 0 | 0.0008990679362704611 |
- | c | 0 | 0.0017981358725409223 |
- | d | 0 | 0.0026972038088113833 |
+ And the ways
+ | nodes | oneway |
+ | abcd | yes |
- And the ways
- | nodes | oneway |
- | abcd | yes |
+ When I route I should get
+ | from | to | route | distance |
+ | b | c | abcd | 100m +-1 |
+ | c | b | | |
- When I route I should get
- | from | to | route | distance |
- | b | c | abcd | 100m +-1 |
- | c | b | | |
-
- Scenario: East-west oneways crossing the origin
- Given the node locations
- | node | lat | lon |
- | a | -0.0017981358725409223 | 0 |
- | b | -0.0008990679362704611 | 0 |
- | c | 0 | 0 |
- | d | 0.0008990679362704611 | 0 |
- | e | 0.0017981358725409223 | 0 |
+ Scenario: North-south oneways close to the origin
+ Given the node locations
+ | node | lat | lon |
+ | a | 0 | 0 |
+ | b | 0 | 0.0008990679362704611 |
+ | c | 0 | 0.0017981358725409223 |
+ | d | 0 | 0.0026972038088113833 |
- And the ways
- | nodes | oneway |
- | abcde | yes |
+ And the ways
+ | nodes | oneway |
+ | abcd | yes |
- When I route I should get
- | from | to | route | distance |
- | b | d | abcde | 200m +-2 |
- | d | b | | |
-
- Scenario: North-south oneways crossing the origin
- Given the node locations
- | node | lat | lon |
- | a | 0 | -0.0017981358725409223 |
- | b | 0 | -0.0008990679362704611 |
- | c | 0 | 0 |
- | d | 0 | 0.0008990679362704611 |
- | e | 0 | 0.0017981358725409223 |
+ When I route I should get
+ | from | to | route | distance |
+ | b | c | abcd | 100m +-1 |
+ | c | b | | |
- And the ways
- | nodes | oneway |
- | abcde | yes |
+ Scenario: East-west oneways crossing the origin
+ Given the node locations
+ | node | lat | lon |
+ | a | -0.0017981358725409223 | 0 |
+ | b | -0.0008990679362704611 | 0 |
+ | c | 0 | 0 |
+ | d | 0.0008990679362704611 | 0 |
+ | e | 0.0017981358725409223 | 0 |
- When I route I should get
- | from | to | route | distance |
- | b | d | abcde | 200m +-2 |
- | d | b | | |
+ And the ways
+ | nodes | oneway |
+ | abcde | yes |
+
+ When I route I should get
+ | from | to | route | distance |
+ | b | d | abcde | 200m +-2 |
+ | d | b | | |
+
+ Scenario: North-south oneways crossing the origin
+ Given the node locations
+ | node | lat | lon |
+ | a | 0 | -0.0017981358725409223 |
+ | b | 0 | -0.0008990679362704611 |
+ | c | 0 | 0 |
+ | d | 0 | 0.0008990679362704611 |
+ | e | 0 | 0.0017981358725409223 |
+
+ And the ways
+ | nodes | oneway |
+ | abcde | yes |
+
+ When I route I should get
+ | from | to | route | distance |
+ | b | d | abcde | 200m +-2 |
+ | d | b | | |
diff --git a/features/testbot/overlap.feature b/features/testbot/overlap.feature
new file mode 100644
index 0000000..509867f
--- /dev/null
+++ b/features/testbot/overlap.feature
@@ -0,0 +1,39 @@
+ at routing @testbot @overlap
+Feature: Testbot - overlapping ways
+
+ Background:
+ Given the profile "testbot"
+
+ @bug @610
+ Scenario: Testbot - multiple way between same nodes
+ Note that cb is connecting the same two nodes as bc
+ Given the node map
+ | a | b | c | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | cd | primary |
+ | cb | secondary |
+
+ When I route I should get
+ | from | to | route |
+ | a | d | ab,bc,cd |
+ | d | a | cd,bc,ab |
+
+ @bug @610
+ Scenario: Testbot - area on top of way
+ Given the node map
+ | x | a | b | y |
+ | | d | c | |
+
+ And the ways
+ | nodes | highway | area |
+ | xaby | primary | |
+ | abcda | secondary | yes |
+
+ When I route I should get
+ | from | to | route |
+ | x | y | xaby |
+ | y | x | xaby |
diff --git a/features/testbot/penalty.feature b/features/testbot/penalty.feature
index 97d5e6a..85f43c7 100644
--- a/features/testbot/penalty.feature
+++ b/features/testbot/penalty.feature
@@ -1,168 +1,168 @@
@routing @penalty @signal
Feature: Penalties
-Testbot uses a signal penalty of 7s.
-
- Background:
- Given the profile "testbot"
-
- Scenario: Traffic signals should incur a delay, without changing distance
- Given the node map
- | a | b | c |
- | d | e | f |
-
- And the nodes
- | node | highway |
- | e | traffic_signals |
-
- And the ways
- | nodes |
- | abc |
- | def |
-
- When I route I should get
- | from | to | route | time | distance |
- | a | c | abc | 20s +-1 | 200m +-1 |
- | d | f | def | 27s +-1 | 200m +-1 |
-
- Scenario: Signal penalty should not depend on way type
- Given the node map
- | a | b | c |
- | d | e | f |
- | g | h | i |
-
- And the nodes
- | node | highway |
- | b | traffic_signals |
- | e | traffic_signals |
- | h | traffic_signals |
-
- And the ways
- | nodes | highway |
- | abc | primary |
- | def | secondary |
- | ghi | tertiary |
-
- When I route I should get
- | from | to | route | time |
- | a | c | abc | 27s +-1 |
- | d | f | def | 47s +-1 |
- | g | i | ghi | 67s +-1 |
-
- Scenario: Passing multiple traffic signals should incur a accumulated delay
- Given the node map
- | a | b | c | d | e |
-
- And the nodes
- | node | highway |
- | b | traffic_signals |
- | c | traffic_signals |
- | d | traffic_signals |
-
- And the ways
- | nodes |
- | abcde |
-
- When I route I should get
- | 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 |
- | d | e | f |
- | g | h | i |
-
- And the nodes
- | node | highway |
- | b | traffic_signals |
- | e | traffic_signals |
- | h | traffic_signals |
-
- And the ways
- | nodes | highway |
- | abc | primary |
- | def | secondary |
- | ghi | tertiary |
-
- 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
- Given the node map
- | a | b | c | d | e |
-
- And the nodes
- | node | highway |
- | b | traffic_signals |
- | c | traffic_signals |
- | d | traffic_signals |
-
- And the ways
- | nodes |
- | abcde |
-
- When I route I should get
- | 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 |
-
- And the nodes
- | node | highway |
- | b | traffic_signals |
-
- And the ways
- | nodes |
- | abc |
-
- When I route I should get
- | from | to | route | time |
- | a | b | abc | 10s +-1 |
- | b | a | abc | 10s +-1 |
-
- Scenario: Routing between signals on the same way should not incur a delay
- Given the node map
- | a | b | c | d |
-
- And the nodes
- | node | highway |
- | a | traffic_signals |
- | d | traffic_signals |
-
- And the ways
- | nodes | highway |
- | abcd | primary |
-
- When I route I should get
- | from | to | route | time |
- | b | c | abcd | 10s +-1 |
- | c | b | abcd | 10s +-1 |
-
- Scenario: Prefer faster route without traffic signals
- Given a grid size of 50 meters
- And the node map
- | a | | b | | c |
- | | | d | | |
-
- And the nodes
- | node | highway |
- | b | traffic_signals |
-
- And the ways
- | nodes | highway |
- | abc | primary |
- | adc | primary |
-
- When I route I should get
- | from | to | route |
- | a | c | adc |
\ No newline at end of file
+# Testbot uses a signal penalty of 7s.
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Traffic signals should incur a delay, without changing distance
+ Given the node map
+ | a | b | c |
+ | d | e | f |
+
+ And the nodes
+ | node | highway |
+ | e | traffic_signals |
+
+ And the ways
+ | nodes |
+ | abc |
+ | def |
+
+ When I route I should get
+ | from | to | route | time | distance |
+ | a | c | abc | 20s +-1 | 200m +-1 |
+ | d | f | def | 27s +-1 | 200m +-1 |
+
+ Scenario: Signal penalty should not depend on way type
+ Given the node map
+ | a | b | c |
+ | d | e | f |
+ | g | h | i |
+
+ And the nodes
+ | node | highway |
+ | b | traffic_signals |
+ | e | traffic_signals |
+ | h | traffic_signals |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | def | secondary |
+ | ghi | tertiary |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | c | abc | 27s +-1 |
+ | d | f | def | 47s +-1 |
+ | g | i | ghi | 67s +-1 |
+
+ Scenario: Passing multiple traffic signals should incur a accumulated delay
+ Given the node map
+ | a | b | c | d | e |
+
+ And the nodes
+ | node | highway |
+ | b | traffic_signals |
+ | c | traffic_signals |
+ | d | traffic_signals |
+
+ And the ways
+ | nodes |
+ | abcde |
+
+ When I route I should get
+ | 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 |
+ | d | e | f |
+ | g | h | i |
+
+ And the nodes
+ | node | highway |
+ | b | traffic_signals |
+ | e | traffic_signals |
+ | h | traffic_signals |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | def | secondary |
+ | ghi | tertiary |
+
+ 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
+ Given the node map
+ | a | b | c | d | e |
+
+ And the nodes
+ | node | highway |
+ | b | traffic_signals |
+ | c | traffic_signals |
+ | d | traffic_signals |
+
+ And the ways
+ | nodes |
+ | abcde |
+
+ When I route I should get
+ | 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 |
+
+ And the nodes
+ | node | highway |
+ | b | traffic_signals |
+
+ And the ways
+ | nodes |
+ | abc |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | b | abc | 10s +-1 |
+ | b | a | abc | 10s +-1 |
+
+ Scenario: Routing between signals on the same way should not incur a delay
+ Given the node map
+ | a | b | c | d |
+
+ And the nodes
+ | node | highway |
+ | a | traffic_signals |
+ | d | traffic_signals |
+
+ And the ways
+ | nodes | highway |
+ | abcd | primary |
+
+ When I route I should get
+ | from | to | route | time |
+ | b | c | abcd | 10s +-1 |
+ | c | b | abcd | 10s +-1 |
+
+ Scenario: Prefer faster route without traffic signals
+ Given a grid size of 50 meters
+ And the node map
+ | a | | b | | c |
+ | | | d | | |
+
+ And the nodes
+ | node | highway |
+ | b | traffic_signals |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | adc | primary |
+
+ When I route I should get
+ | from | to | route |
+ | a | c | adc |
diff --git a/features/testbot/planetary.feature b/features/testbot/planetary.feature
index 242ba8b..f2ba21e 100644
--- a/features/testbot/planetary.feature
+++ b/features/testbot/planetary.feature
@@ -1,86 +1,86 @@
@routing @planetary
Feature: Distance calculation
-
- Scenario: Approximated Longitudinal distances at equator
- Given the node locations
- | node | lat | lon |
- | a | 0 | 80 |
- | b | 0 | 0 |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
-
- Scenario: Approximated Longitudinal distances at latitude 45
- Given the node locations
- | node | lat | lon |
- | c | 45 | 80 |
- | d | 45 | 0 |
-
- And the ways
- | nodes |
- | cd |
-
- When I route I should get
- | from | to | route | distance |
- | c | d | cd | 6028844m ~4.5% |
-
- Scenario: Approximated Longitudinal distances at latitude 80
- Given the node locations
- | node | lat | lon |
- | c | 80 | 80 |
- | d | 80 | 0 |
-
- And the ways
- | nodes |
- | cd |
-
- When I route I should get
- | from | to | route | distance |
- | c | d | cd | 1431469m ~9.5% |
-
- Scenario: Approximated Latitudinal distances at longitude 0
- Given the node locations
- | node | lat | lon |
- | a | 80 | 0 |
- | b | 0 | 0 |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
-
- Scenario: Approximated Latitudinal distances at longitude 45
- Given the node locations
- | node | lat | lon |
- | a | 80 | 45 |
- | b | 0 | 45 |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
-
- Scenario: Approximated Latitudinal distances at longitude 80
- Given the node locations
- | node | lat | lon |
- | a | 80 | 80 |
- | b | 0 | 80 |
-
- And the ways
- | nodes |
- | ab |
-
- When I route I should get
- | from | to | route | distance |
- | a | b | ab | 8905559m ~0.1% |
+
+ Scenario: Approximated Longitudinal distances at equator
+ Given the node locations
+ | node | lat | lon |
+ | a | 0 | 80 |
+ | b | 0 | 0 |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | ab | 8905559m ~0.1% |
+
+ Scenario: Approximated Longitudinal distances at latitude 45
+ Given the node locations
+ | node | lat | lon |
+ | c | 45 | 80 |
+ | d | 45 | 0 |
+
+ And the ways
+ | nodes |
+ | cd |
+
+ When I route I should get
+ | from | to | route | distance |
+ | c | d | cd | 6028844m ~4.5% |
+
+ Scenario: Approximated Longitudinal distances at latitude 80
+ Given the node locations
+ | node | lat | lon |
+ | c | 80 | 80 |
+ | d | 80 | 0 |
+
+ And the ways
+ | nodes |
+ | cd |
+
+ When I route I should get
+ | from | to | route | distance |
+ | c | d | cd | 1431469m ~9.5% |
+
+ Scenario: Approximated Latitudinal distances at longitude 0
+ Given the node locations
+ | node | lat | lon |
+ | a | 80 | 0 |
+ | b | 0 | 0 |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | ab | 8905559m ~0.1% |
+
+ Scenario: Approximated Latitudinal distances at longitude 45
+ Given the node locations
+ | node | lat | lon |
+ | a | 80 | 45 |
+ | b | 0 | 45 |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | ab | 8905559m ~0.1% |
+
+ Scenario: Approximated Latitudinal distances at longitude 80
+ Given the node locations
+ | node | lat | lon |
+ | a | 80 | 80 |
+ | b | 0 | 80 |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | ab | 8905559m ~0.1% |
diff --git a/features/testbot/projection.feature b/features/testbot/projection.feature
new file mode 100644
index 0000000..ed2f2fc
--- /dev/null
+++ b/features/testbot/projection.feature
@@ -0,0 +1,38 @@
+ at routing @projection
+Feature: Projection to nearest point on road
+# Waypoints are projected perpendiculary onto the closest road
+
+ Background:
+ # The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html
+ # The nodes are placed as follows, with ab, bc and bd all being 1 km in length each:
+ # | | | c |
+ # | | b | | (this is sketch only, real data is in the table below)
+ # | a | | d |
+
+ Given the profile "testbot"
+ Given the node locations
+ | node | lat | lon |
+ | a | 80.00000 | 0.00000 |
+ | b | 80.00639 | 0.03667 |
+ | c | 80.01278 | 0.07333 |
+ | d | 80.00000 | 0.07333 |
+
+ And the ways
+ | nodes |
+ | abc |
+
+ Scenario: Projection onto way at high latitudes, 1km distance
+ When I route I should get
+ | from | to | route | compass | bearing | distance |
+ | b | a | abc | SW | 225 | 1000m +-7 |
+ | b | c | abc | NE | 45 | 1000m +-7 |
+ | a | d | abc | NE | 45 | 1000m +-7 |
+ | d | a | abc | SW | 225 | 1000m +-7 |
+ | c | d | abc | SW | 225 | 1000m +-8 |
+ | d | c | abc | NE | 45 +-5 | 1000m +-8 |
+
+ Scenario: Projection onto way at high latitudes, no distance
+ When I route I should get
+ | from | to | route | distance |
+ | d | b | abc | 0m +-5 |
+ | b | d | abc | 0m +-5 |
diff --git a/features/testbot/protobuffer.feature b/features/testbot/protobuffer.feature
new file mode 100644
index 0000000..a77ff34
--- /dev/null
+++ b/features/testbot/protobuffer.feature
@@ -0,0 +1,156 @@
+ at routing @pbf
+Feature: Importing protobuffer (.pbf) format
+# Test normally read .osm, which is faster than .pbf files,
+# since we don't need to use osmosis to first convert to .pbf
+# The scenarios in this file test the ability to import .pbf files,
+# including nodes, way, restictions, and a various special situations.
+
+ Background:
+ Given the profile "testbot"
+ And the import format "pbf"
+
+ Scenario: Testbot - Protobuffer import, nodes and ways
+ 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 |
+
+
+ Scenario: Testbot - Protobuffer import, turn restiction relations
+ Given the node map
+ | | n | |
+ | w | j | e |
+ | | s | |
+
+ And the ways
+ | nodes | oneway |
+ | sj | yes |
+ | nj | -1 |
+ | wj | -1 |
+ | ej | -1 |
+
+ And the relations
+ | type | way:from | way:to | node:via | restriction |
+ | restriction | sj | wj | j | no_left_turn |
+
+ When I route I should get
+ | from | to | route |
+ | s | w | |
+ | s | n | sj,nj |
+ | s | e | sj,ej |
+
+
+ Scenario: Testbot - Protobuffer import, distances at longitude 45
+ Given the node locations
+ | node | lat | lon |
+ | a | 80 | 45 |
+ | b | 0 | 45 |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | ab | 8905559m ~0.1% |
+
+ Scenario: Testbot - Protobuffer import, distances at longitude 80
+ Given the node locations
+ | node | lat | lon |
+ | a | 80 | 80 |
+ | b | 0 | 80 |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | distance |
+ | a | b | ab | 8905559m ~0.1% |
+
+ Scenario: Testbot - Protobuffer import, empty dataset
+ Given the node map
+ | |
+
+ Given the ways
+ | nodes |
+
+ When the data has been prepared
+ Then "osrm-extract" should return code 1
+
+
+ Scenario: Testbot - Protobuffer import, streetnames with UTF characters
+ Given the node map
+ | a | b | c | d |
+
+ And the ways
+ | nodes | name |
+ | ab | Scandinavian København |
+ | bc | Japanese 東京 |
+ | cd | Cyrillic Москва |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | Scandinavian København |
+ | b | c | Japanese 東京 |
+ | c | d | Cyrillic Москва |
+
+ Scenario: Testbot - Protobuffer import, bearing af 45 degree intervals
+ Given the node map
+ | b | a | h |
+ | c | x | g |
+ | d | e | f |
+
+ And the ways
+ | nodes |
+ | xa |
+ | xb |
+ | xc |
+ | xd |
+ | xe |
+ | xf |
+ | xg |
+ | xh |
+
+ When I route I should get
+ | from | to | route | compass | bearing |
+ | x | a | xa | N | 0 |
+ | x | b | xb | NW | 315 |
+ | x | c | xc | W | 270 |
+ | x | d | xd | SW | 225 |
+ | x | e | xe | S | 180 |
+ | x | f | xf | SE | 135 |
+ | x | g | xg | E | 90 |
+ | x | h | xh | NE | 45 |
+
+
+ Scenario: Testbot - Protobuffer import, rraffic signals should incur a delay
+ Given the node map
+ | a | b | c |
+ | d | e | f |
+
+ And the nodes
+ | node | highway |
+ | e | traffic_signals |
+
+ And the ways
+ | nodes |
+ | abc |
+ | def |
+
+ When I route I should get
+ | from | to | route | time | distance |
+ | a | c | abc | 20s +-1 | 200m +-1 |
+ | d | f | def | 27s +-1 | 200m +-1 |
diff --git a/features/testbot/roundabout.feature b/features/testbot/roundabout.feature
new file mode 100644
index 0000000..570b14b
--- /dev/null
+++ b/features/testbot/roundabout.feature
@@ -0,0 +1,76 @@
+ at routing @testbot @roundabout @instruction
+Feature: Roundabout Instructions
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Testbot - Roundabout
+ Given the node map
+ | | | v | | |
+ | | | d | | |
+ | s | a | | c | u |
+ | | | b | | |
+ | | | t | | |
+
+ And the ways
+ | nodes | junction |
+ | sa | |
+ | tb | |
+ | uc | |
+ | vd | |
+ | abcda | roundabout |
+
+ When I route I should get
+ | from | to | route | turns |
+ | s | t | sa,tb | head,enter_roundabout-1,destination |
+ | s | u | sa,uc | head,enter_roundabout-2,destination |
+ | s | v | sa,vd | head,enter_roundabout-3,destination |
+ | t | u | tb,uc | head,enter_roundabout-1,destination |
+ | t | v | tb,vd | head,enter_roundabout-2,destination |
+ | t | s | tb,sa | head,enter_roundabout-3,destination |
+ | u | v | uc,vd | head,enter_roundabout-1,destination |
+ | u | s | uc,sa | head,enter_roundabout-2,destination |
+ | u | t | uc,tb | head,enter_roundabout-3,destination |
+ | v | s | vd,sa | head,enter_roundabout-1,destination |
+ | v | t | vd,tb | head,enter_roundabout-2,destination |
+ | v | u | vd,uc | head,enter_roundabout-3,destination |
+
+ Scenario: Testbot - Roundabout with oneway links
+ Given the node map
+ | | | p | o | | |
+ | | | h | g | | |
+ | i | a | | | f | n |
+ | j | b | | | e | m |
+ | | | c | d | | |
+ | | | k | l | | |
+
+ And the ways
+ | nodes | junction | oneway |
+ | ai | | yes |
+ | jb | | yes |
+ | ck | | yes |
+ | ld | | yes |
+ | em | | yes |
+ | nf | | yes |
+ | go | | yes |
+ | ph | | yes |
+ | abcdefgha | roundabout | |
+
+ When I route I should get
+ | from | to | route | turns |
+ | j | k | jb,ck | head,enter_roundabout-1,destination |
+ | j | m | jb,em | head,enter_roundabout-2,destination |
+ | j | o | jb,go | head,enter_roundabout-3,destination |
+ | j | i | jb,ai | head,enter_roundabout-4,destination |
+ | l | m | ld,em | head,enter_roundabout-1,destination |
+ | l | o | ld,go | head,enter_roundabout-2,destination |
+ | l | i | ld,ai | head,enter_roundabout-3,destination |
+ | l | k | ld,ck | head,enter_roundabout-4,destination |
+ | n | o | nf,go | head,enter_roundabout-1,destination |
+ | n | i | nf,ai | head,enter_roundabout-2,destination |
+ | n | k | nf,ck | head,enter_roundabout-3,destination |
+ | n | m | nf,em | head,enter_roundabout-4,destination |
+ | p | i | ph,ai | head,enter_roundabout-1,destination |
+ | p | k | ph,ck | head,enter_roundabout-2,destination |
+ | p | m | ph,em | head,enter_roundabout-3,destination |
+ | p | o | ph,go | head,enter_roundabout-4,destination |
diff --git a/features/testbot/routes.feature b/features/testbot/routes.feature
index 763b347..bc1d75e 100644
--- a/features/testbot/routes.feature
+++ b/features/testbot/routes.feature
@@ -1,35 +1,35 @@
@routing @testbot @routes @todo
Feature: OSM Route Relation
- Background:
- Given the profile "testbot"
-
- Scenario: Prioritize ways that are part of route relations
- This scenario assumes that the testbot uses an impedance of 0.5 for ways that are part of 'testbot' routes.
-
- Given the node map
- | s | | | t | | | |
- | a | | | b | | | c |
- | | | | | | | |
- | | | | u | | | v |
+ Background:
+ Given the profile "testbot"
- And the ways
- | nodes |
- | ab |
- | bc |
- | as |
- | stb |
- | bu |
- | uvc |
+ Scenario: Prioritize ways that are part of route relations
+ # This scenario assumes that the testbot uses an impedance of 0.5 for ways that are part of 'testbot' routes.
- And the relations
- | type | route | way:route |
- | route | testbot | as,stb |
- | route | testbot | bu,uvc |
+ Given the node map
+ | s | | | t | | | |
+ | a | | | b | | | c |
+ | | | | | | | |
+ | | | | u | | | v |
- When I route I should get
- | from | to | route | distance | time |
- | b | c | bc | 300m +-1 | 30s +-1 |
- | c | b | bc | 300m +-1 | 30s +-1 |
- | a | b | as,stb | 500m +-1 | 50s +-1 |
- | b | a | stb,as | 500m +-1 | 50s +-1 |
\ No newline at end of file
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | as |
+ | stb |
+ | bu |
+ | uvc |
+
+ And the relations
+ | type | route | way:route |
+ | route | testbot | as,stb |
+ | route | testbot | bu,uvc |
+
+ When I route I should get
+ | from | to | route | distance | time |
+ | b | c | bc | 300m +-1 | 30s +-1 |
+ | c | b | bc | 300m +-1 | 30s +-1 |
+ | a | b | as,stb | 500m +-1 | 50s +-1 |
+ | b | a | stb,as | 500m +-1 | 50s +-1 |
diff --git a/features/testbot/snap.feature b/features/testbot/snap.feature
index bb3156d..c8a04bf 100644
--- a/features/testbot/snap.feature
+++ b/features/testbot/snap.feature
@@ -1,154 +1,154 @@
@routing @snap
-Feature: Snap start/end point to the nearest way
-
- Background:
- Given the profile "testbot"
-
- Scenario: Snap to nearest protruding oneway
- Given the node map
- | | 1 | | 2 | |
- | 8 | | n | | 3 |
- | | w | c | e | |
- | 7 | | s | | 4 |
- | | 6 | | 5 | |
-
- And the ways
- | nodes |
- | nc |
- | ec |
- | sc |
- | wc |
-
- When I route I should get
- | from | to | route |
- | 1 | c | nc |
- | 2 | c | nc |
- | 3 | c | ec |
- | 4 | c | ec |
- | 5 | c | sc |
- | 6 | c | sc |
- | 7 | c | wc |
- | 8 | c | wc |
-
- Scenario: Snap to nearest edge of a square
- Given the node map
- | 4 | 5 | 6 | 7 |
- | 3 | a | | u |
- | 2 | | | |
- | 1 | d | | b |
-
- And the ways
- | nodes |
- | aub |
- | adb |
-
- When I route I should get
- | from | to | route |
- | 1 | b | adb |
- | 2 | b | adb |
- | 6 | b | aub |
- | 7 | b | aub |
-
- Scenario: Snap to edge right under start/end point
- Given the node map
- | d | e | f | g |
- | c | | | h |
- | b | | | i |
- | a | l | k | j |
-
- And the ways
- | nodes |
- | abcd |
- | defg |
- | ghij |
- | jkla |
-
- When I route I should get
- | from | to | route |
- | a | b | abcd |
- | a | c | abcd |
- | a | d | abcd |
- | a | e | abcd,defg |
- | a | f | abcd,defg |
- | a | h | jkla,ghij |
- | a | i | jkla,ghij |
- | a | j | jkla |
- | a | k | jkla |
- | a | l | jkla |
-
- Scenario: Snap to correct way at large scales
- Given a grid size of 1000 meters
- Given the node map
- | | | | a |
- | x | | | b |
- | | | | c |
-
- And the ways
- | nodes |
- | xa |
- | xb |
- | xc |
-
- When I route I should get
- | from | to | route |
- | x | a | xa |
- | x | b | xb |
- | x | c | xc |
- | a | x | xa |
- | b | x | xb |
- | c | x | xc |
-
- Scenario: Find edges within 1km, and the same from 10km
- Given a grid size of 1000 meters
- Given the node map
- | p | | | | | | | | | | | i | | | | | | | | | | | j |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | 8 | | 1 | | 2 | | | | | | | | | |
- | | | | | | | | | | | h | a | b | | | | | | | | | | |
- | o | | | | | | | | | 7 | g | x | c | 3 | | | | | | | | | k |
- | | | | | | | | | | | f | e | d | | | | | | | | | | |
- | | | | | | | | | | 6 | | 5 | | 4 | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | | | | | | | | |
- | n | | | | | | | | | | | m | | | | | | | | | | | l |
-
- Given the ways
- | nodes |
- | xa |
- | xb |
- | xc |
- | xd |
- | xe |
- | xf |
- | xg |
- | xh |
-
- When I route I should get
- | from | to | route |
- | x | 1 | xa |
- | x | 2 | xb |
- | x | 3 | xc |
- | x | 4 | xd |
- | x | 5 | xe |
- | x | 6 | xf |
- | x | 7 | xg |
- | x | 8 | xh |
- | x | i | xa |
- | x | j | xb |
- | x | k | xc |
- | x | l | xd |
- | x | m | xe |
- | x | n | xf |
- | x | o | xg |
- | x | p | xh |
\ No newline at end of file
+Feature: Snap start/end point to the nearest way
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Snap to nearest protruding oneway
+ Given the node map
+ | | 1 | | 2 | |
+ | 8 | | n | | 3 |
+ | | w | c | e | |
+ | 7 | | s | | 4 |
+ | | 6 | | 5 | |
+
+ And the ways
+ | nodes |
+ | nc |
+ | ec |
+ | sc |
+ | wc |
+
+ When I route I should get
+ | from | to | route |
+ | 1 | c | nc |
+ | 2 | c | nc |
+ | 3 | c | ec |
+ | 4 | c | ec |
+ | 5 | c | sc |
+ | 6 | c | sc |
+ | 7 | c | wc |
+ | 8 | c | wc |
+
+ Scenario: Snap to nearest edge of a square
+ Given the node map
+ | 4 | 5 | 6 | 7 |
+ | 3 | a | | u |
+ | 2 | | | |
+ | 1 | d | | b |
+
+ And the ways
+ | nodes |
+ | aub |
+ | adb |
+
+ When I route I should get
+ | from | to | route |
+ | 1 | b | adb |
+ | 2 | b | adb |
+ | 6 | b | aub |
+ | 7 | b | aub |
+
+ Scenario: Snap to edge right under start/end point
+ Given the node map
+ | d | e | f | g |
+ | c | | | h |
+ | b | | | i |
+ | a | l | k | j |
+
+ And the ways
+ | nodes |
+ | abcd |
+ | defg |
+ | ghij |
+ | jkla |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | abcd |
+ | a | c | abcd |
+ | a | d | abcd |
+ | a | e | abcd,defg |
+ | a | f | abcd,defg |
+ | a | h | jkla,ghij |
+ | a | i | jkla,ghij |
+ | a | j | jkla |
+ | a | k | jkla |
+ | a | l | jkla |
+
+ Scenario: Snap to correct way at large scales
+ Given a grid size of 1000 meters
+ Given the node map
+ | | | | a |
+ | x | | | b |
+ | | | | c |
+
+ And the ways
+ | nodes |
+ | xa |
+ | xb |
+ | xc |
+
+ When I route I should get
+ | from | to | route |
+ | x | a | xa |
+ | x | b | xb |
+ | x | c | xc |
+ | a | x | xa |
+ | b | x | xb |
+ | c | x | xc |
+
+ Scenario: Find edges within 1km, and the same from 10km
+ Given a grid size of 1000 meters
+ Given the node map
+ | p | | | | | | | | | | | i | | | | | | | | | | | j |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | 8 | | 1 | | 2 | | | | | | | | | |
+ | | | | | | | | | | | h | a | b | | | | | | | | | | |
+ | o | | | | | | | | | 7 | g | x | c | 3 | | | | | | | | | k |
+ | | | | | | | | | | | f | e | d | | | | | | | | | | |
+ | | | | | | | | | | 6 | | 5 | | 4 | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | | | | | | | | | |
+ | n | | | | | | | | | | | m | | | | | | | | | | | l |
+
+ Given the ways
+ | nodes |
+ | xa |
+ | xb |
+ | xc |
+ | xd |
+ | xe |
+ | xf |
+ | xg |
+ | xh |
+
+ When I route I should get
+ | from | to | route |
+ | x | 1 | xa |
+ | x | 2 | xb |
+ | x | 3 | xc |
+ | x | 4 | xd |
+ | x | 5 | xe |
+ | x | 6 | xf |
+ | x | 7 | xg |
+ | x | 8 | xh |
+ | x | i | xa |
+ | x | j | xb |
+ | x | k | xc |
+ | x | l | xd |
+ | x | m | xe |
+ | x | n | xf |
+ | x | o | xg |
+ | x | p | xh |
diff --git a/features/testbot/speed.feature b/features/testbot/speed.feature
new file mode 100644
index 0000000..2eb3724
--- /dev/null
+++ b/features/testbot/speed.feature
@@ -0,0 +1,31 @@
+ at routing @speed @testbot
+Feature: Testbot - speeds
+
+ Background: Use specific speeds
+ Given the profile "testbot"
+
+ Scenario: Testbot - Speed on roads
+ Then routability should be
+ | highway | bothw |
+ | primary | 36 km/h |
+ | unknown | 24 km/h |
+ | secondary | 18 km/h |
+ | tertiary | 12 km/h |
+
+ Scenario: Testbot - Speed on rivers, table
+ Then routability should be
+ | highway | forw | backw |
+ | river | 36 km/h | 16 km/h |
+
+ Scenario: Testbot - Speed on rivers, map
+ Given the node map
+ | a | b |
+
+ And the ways
+ | nodes | highway |
+ | ab | river |
+
+ When I route I should get
+ | from | to | route | speed | time | distance |
+ | a | b | ab | 36 km/h | 10s | 100m |
+ | b | a | ab | 16 km/h +- 1 | 23s | 100m |
diff --git a/features/testbot/status.feature b/features/testbot/status.feature
new file mode 100644
index 0000000..4fa15eb
--- /dev/null
+++ b/features/testbot/status.feature
@@ -0,0 +1,67 @@
+ at routing @status
+Feature: Status messages
+
+ Background:
+ Given the profile "testbot"
+
+ Scenario: Route found
+ Given the node map
+ | a | b |
+
+ Given the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | from | to | route | status | message |
+ | a | b | ab | 0 | Found route between points |
+ | b | a | ab | 0 | Found route between points |
+
+ Scenario: No route found
+ Given the node map
+ | a | b |
+ | | |
+ | c | d |
+
+ Given the ways
+ | nodes |
+ | ab |
+ | cd |
+
+ When I route I should get
+ | from | to | route | status | message |
+ | a | b | ab | 0 | Found route between points |
+ | c | d | cd | 0 | Found route between points |
+ | a | c | | 207 | Cannot find route between points |
+ | b | d | | 207 | Cannot find route between points |
+
+ Scenario: Malformed requests
+ Given the node locations
+ | node | lat | lon |
+ | a | 1.00 | 1.00 |
+ | b | 1.01 | 1.00 |
+
+ And the ways
+ | nodes |
+ | ab |
+
+ When I route I should get
+ | request | status | message |
+ | viaroute?loc=1,1&loc=1.01,1 | 0 | Found route between points |
+ | nonsense | 400 | Bad Request |
+ | nonsense?loc=1,1&loc=1.01,1 | 400 | Bad Request |
+ | | 400 | Query string malformed close to position 0 |
+ | / | 400 | Query string malformed close to position 0 |
+ | ? | 400 | Query string malformed close to position 0 |
+ | viaroute/loc= | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=1 | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=1,1 | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=1,1,1 | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=x | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=x,y | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=1,1&loc= | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=1,1&loc=1 | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=1,1&loc=1,1 | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=1,1&loc=1,1,1 | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=1,1&loc=x | 400 | Query string malformed close to position 9 |
+ | viaroute/loc=1,1&loc=x,y | 400 | Query string malformed close to position 9 |
diff --git a/features/testbot/time.feature b/features/testbot/time.feature
index b10544f..e0ccc37 100644
--- a/features/testbot/time.feature
+++ b/features/testbot/time.feature
@@ -1,215 +1,237 @@
@routing @time
Feature: Estimation of travel time
-Testbot speeds:
-Primary road: 36km/h = 36000m/3600s = 100m/10s
-Secondary road: 18km/h = 18000m/3600s = 100m/20s
-Tertiary road: 12km/h = 12000m/3600s = 100m/30s
-
- Background: Use specific speeds
- Given the profile "testbot"
-
- Scenario: Basic travel time, 10m scale
- Given a grid size of 10 meters
- Given the node map
- | h | a | b |
- | g | x | c |
- | f | e | d |
-
- And the ways
- | nodes | highway |
- | xa | primary |
- | xb | primary |
- | xc | primary |
- | xd | primary |
- | xe | primary |
- | xf | primary |
- | xg | primary |
- | xh | primary |
-
- When I route I should get
- | from | to | route | time |
- | x | a | xa | 1s +-1 |
- | x | b | xb | 1s +-1 |
- | x | c | xc | 1s +-1 |
- | x | d | xd | 1s +-1 |
- | x | e | xe | 1s +-1 |
- | x | f | xf | 1s +-1 |
- | x | g | xg | 1s +-1 |
- | x | h | xh | 1s +-1 |
-
- Scenario: Basic travel time, 100m scale
- Given a grid size of 100 meters
- Given the node map
- | h | a | b |
- | g | x | c |
- | f | e | d |
-
- And the ways
- | nodes | highway |
- | xa | primary |
- | xb | primary |
- | xc | primary |
- | xd | primary |
- | xe | primary |
- | xf | primary |
- | xg | primary |
- | xh | primary |
-
- When I route I should get
- | from | to | route | time |
- | x | a | xa | 10s +-1 |
- | x | b | xb | 14s +-1 |
- | x | c | xc | 10s +-1 |
- | x | d | xd | 14s +-1 |
- | x | e | xe | 10s +-1 |
- | x | f | xf | 14s +-1 |
- | x | g | xg | 10s +-1 |
- | x | h | xh | 14s +-1 |
-
- Scenario: Basic travel time, 1km scale
- Given a grid size of 1000 meters
- Given the node map
- | h | a | b |
- | g | x | c |
- | f | e | d |
-
- And the ways
- | nodes | highway |
- | xa | primary |
- | xb | primary |
- | xc | primary |
- | xd | primary |
- | xe | primary |
- | xf | primary |
- | xg | primary |
- | xh | primary |
-
- When I route I should get
- | from | to | route | time |
- | x | a | xa | 100s +-1 |
- | x | b | xb | 141s +-1 |
- | x | c | xc | 100s +-1 |
- | x | d | xd | 141s +-1 |
- | x | e | xe | 100s +-1 |
- | x | f | xf | 141s +-1 |
- | x | g | xg | 100s +-1 |
- | x | h | xh | 141s +-1 |
-
- Scenario: Basic travel time, 10km scale
- Given a grid size of 10000 meters
- Given the node map
- | h | a | b |
- | g | x | c |
- | f | e | d |
-
- And the ways
- | nodes | highway |
- | xa | primary |
- | xb | primary |
- | xc | primary |
- | xd | primary |
- | xe | primary |
- | xf | primary |
- | xg | primary |
- | xh | primary |
-
- When I route I should get
- | from | to | route | time |
- | x | a | xa | 1000s +-1 |
- | x | b | xb | 1414s +-1 |
- | x | c | xc | 1000s +-1 |
- | x | d | xd | 1414s +-1 |
- | x | e | xe | 1000s +-1 |
- | x | f | xf | 1414s +-1 |
- | x | g | xg | 1000s +-1 |
- | x | h | xh | 1414s +-1 |
-
- Scenario: Time of travel depending on way type
- Given the node map
- | a | b |
- | c | d |
- | e | f |
-
- And the ways
- | nodes | highway |
- | ab | primary |
- | cd | secondary |
- | ef | tertiary |
- | ace | something |
-
- When I route I should get
- | from | to | route | time |
- | a | b | ab | 10s +-1 |
- | c | d | cd | 20s +-1 |
- | e | f | ef | 30s +-1 |
-
- Scenario: Time of travel on a series of ways
- Given the node map
- | a | b | |
- | | c | d |
-
- And the ways
- | nodes | highway |
- | ab | primary |
- | bc | primary |
- | cd | primary |
-
- When I route I should get
- | from | to | route | time |
- | a | b | ab | 10s +-1 |
- | a | c | ab,bc | 20s +-1 |
- | a | d | ab,bc,cd | 30s +-1 |
-
- Scenario: Time of travel on a winding way
- Given the node map
- | a | | i | h |
- | b | c | | g |
- | | d | e | f |
-
- And the ways
- | nodes | highway |
- | abcdefghi | primary |
-
- When I route I should get
- | from | to | route | time |
- | a | b | abcdefghi | 10s +-1 |
- | a | e | abcdefghi | 40s +-1 |
- | a | i | abcdefghi | 80s +-1 |
-
- Scenario: Time of travel on combination of road types
- Given the node map
- | a | b | c |
- | | | d |
- | | | e |
-
- And the ways
- | nodes | highway |
- | abc | primary |
- | cde | tertiary |
-
- When I route I should get
- | from | to | route | time |
- | b | c | abc | 10s +-1 |
- | c | e | cde | 60s +-1 |
- | b | d | abc,cde | 40s +-1 |
- | a | e | abc,cde | 80s +-1 |
-
- Scenario: Time of travel on part of a way
- Given the node map
- | a | 1 |
- | | 2 |
- | | 3 |
- | b | 4 |
-
- And the ways
- | nodes | highway |
- | ab | primary |
-
- When I route I should get
- | from | to | route | time |
- | 1 | 2 | ab | 10s +-1 |
- | 1 | 3 | ab | 20s +-1 |
- | 1 | 4 | ab | 30s +-1 |
- | 4 | 3 | ab | 10s +-1 |
- | 4 | 2 | ab | 20s +-1 |
- | 4 | 1 | ab | 30s +-1 |
+# Testbot speeds:
+# Primary road: 36km/h = 36000m/3600s = 100m/10s
+# Secondary road: 18km/h = 18000m/3600s = 100m/20s
+# Tertiary road: 12km/h = 12000m/3600s = 100m/30s
+
+ Background: Use specific speeds
+ Given the profile "testbot"
+
+ Scenario: Basic travel time, 10m scale
+ Given a grid size of 10 meters
+ Given the node map
+ | h | a | b |
+ | g | x | c |
+ | f | e | d |
+
+ And the ways
+ | nodes | highway |
+ | xa | primary |
+ | xb | primary |
+ | xc | primary |
+ | xd | primary |
+ | xe | primary |
+ | xf | primary |
+ | xg | primary |
+ | xh | primary |
+
+ When I route I should get
+ | from | to | route | time |
+ | x | a | xa | 1s +-1 |
+ | x | b | xb | 1s +-1 |
+ | x | c | xc | 1s +-1 |
+ | x | d | xd | 1s +-1 |
+ | x | e | xe | 1s +-1 |
+ | x | f | xf | 1s +-1 |
+ | x | g | xg | 1s +-1 |
+ | x | h | xh | 1s +-1 |
+
+ Scenario: Basic travel time, 100m scale
+ Given a grid size of 100 meters
+ Given the node map
+ | h | a | b |
+ | g | x | c |
+ | f | e | d |
+
+ And the ways
+ | nodes | highway |
+ | xa | primary |
+ | xb | primary |
+ | xc | primary |
+ | xd | primary |
+ | xe | primary |
+ | xf | primary |
+ | xg | primary |
+ | xh | primary |
+
+ When I route I should get
+ | from | to | route | time |
+ | x | a | xa | 10s +-1 |
+ | x | b | xb | 14s +-1 |
+ | x | c | xc | 10s +-1 |
+ | x | d | xd | 14s +-1 |
+ | x | e | xe | 10s +-1 |
+ | x | f | xf | 14s +-1 |
+ | x | g | xg | 10s +-1 |
+ | x | h | xh | 14s +-1 |
+
+ Scenario: Basic travel time, 1km scale
+ Given a grid size of 1000 meters
+ Given the node map
+ | h | a | b |
+ | g | x | c |
+ | f | e | d |
+
+ And the ways
+ | nodes | highway |
+ | xa | primary |
+ | xb | primary |
+ | xc | primary |
+ | xd | primary |
+ | xe | primary |
+ | xf | primary |
+ | xg | primary |
+ | xh | primary |
+
+ When I route I should get
+ | from | to | route | time |
+ | x | a | xa | 100s +-1 |
+ | x | b | xb | 141s +-1 |
+ | x | c | xc | 100s +-1 |
+ | x | d | xd | 141s +-1 |
+ | x | e | xe | 100s +-1 |
+ | x | f | xf | 141s +-1 |
+ | x | g | xg | 100s +-1 |
+ | x | h | xh | 141s +-1 |
+
+ Scenario: Basic travel time, 10km scale
+ Given a grid size of 10000 meters
+ Given the node map
+ | h | a | b |
+ | g | x | c |
+ | f | e | d |
+
+ And the ways
+ | nodes | highway |
+ | xa | primary |
+ | xb | primary |
+ | xc | primary |
+ | xd | primary |
+ | xe | primary |
+ | xf | primary |
+ | xg | primary |
+ | xh | primary |
+
+ When I route I should get
+ | from | to | route | time |
+ | x | a | xa | 1000s +-1 |
+ | x | b | xb | 1414s +-1 |
+ | x | c | xc | 1000s +-1 |
+ | x | d | xd | 1414s +-1 |
+ | x | e | xe | 1000s +-1 |
+ | x | f | xf | 1414s +-1 |
+ | x | g | xg | 1000s +-1 |
+ | x | h | xh | 1414s +-1 |
+
+ Scenario: Time of travel depending on way type
+ Given the node map
+ | a | b |
+ | c | d |
+ | e | f |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | cd | secondary |
+ | ef | tertiary |
+ | ace | something |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | b | ab | 10s +-1 |
+ | c | d | cd | 20s +-1 |
+ | e | f | ef | 30s +-1 |
+
+ Scenario: Time of travel on a series of ways
+ Given the node map
+ | a | b | |
+ | | c | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | cd | primary |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | b | ab | 10s +-1 |
+ | a | c | ab,bc | 20s +-1 |
+ | a | d | ab,bc,cd | 30s +-1 |
+
+ Scenario: Time of travel on a winding way
+ Given the node map
+ | a | | i | h |
+ | b | c | | g |
+ | | d | e | f |
+
+ And the ways
+ | nodes | highway |
+ | abcdefghi | primary |
+
+ When I route I should get
+ | from | to | route | time |
+ | a | b | abcdefghi | 10s +-1 |
+ | a | e | abcdefghi | 40s +-1 |
+ | a | i | abcdefghi | 80s +-1 |
+
+ Scenario: Time of travel on combination of road types
+ Given the node map
+ | a | b | c |
+ | | | d |
+ | | | e |
+
+ And the ways
+ | nodes | highway |
+ | abc | primary |
+ | cde | tertiary |
+
+ When I route I should get
+ | from | to | route | time |
+ | b | c | abc | 10s +-1 |
+ | c | e | cde | 60s +-1 |
+ | b | d | abc,cde | 40s +-1 |
+ | a | e | abc,cde | 80s +-1 |
+
+ Scenario: Time of travel on part of a way
+ Given the node map
+ | a | 1 |
+ | | 2 |
+ | | 3 |
+ | b | 4 |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+
+ When I route I should get
+ | from | to | route | time |
+ | 1 | 2 | ab | 10s +-1 |
+ | 1 | 3 | ab | 20s +-1 |
+ | 1 | 4 | ab | 30s +-1 |
+ | 4 | 3 | ab | 10s +-1 |
+ | 4 | 2 | ab | 20s +-1 |
+ | 4 | 1 | ab | 30s +-1 |
+
+ Scenario: Total travel time should match sum of times of individual ways
+ Given a grid size of 1000 meters
+ And the node map
+ | a | b | | | |
+ | | | | | |
+ | | c | | | d |
+
+ And the ways
+ | nodes | highway |
+ | ab | primary |
+ | bc | primary |
+ | cd | primary |
+
+ When I route I should get
+ | from | to | route | distances | distance | times | time |
+ | a | b | ab | 1000m +-1 | 1000m +-1 | 100s +-1 | 100s +-1 |
+ | b | c | bc | 2000m +-1 | 2000m +-1 | 200s +-1 | 200s +-1 |
+ | c | d | cd | 3000m +-1 | 3000m +-1 | 300s +-1 | 300s +-1 |
+ | a | c | ab,bc | 1000m,2000m +-1 | 3000m +-1 | 100s,200s +-1 | 300s +-1 |
+ | b | d | bc,cd | 2000m,3000m +-1 | 5000m +-1 | 200s,300s +-1 | 500s +-1 |
+ | a | d | ab,bc,cd | 1000m,2000m,3000m +-1 | 6000m +-1 | 100s,200s,300s +-1 | 600s +-1 |
diff --git a/features/testbot/turns.feature b/features/testbot/turns.feature
index 5a14c9e..87bf21f 100644
--- a/features/testbot/turns.feature
+++ b/features/testbot/turns.feature
@@ -1,123 +1,123 @@
@routing @turns
Feature: Turn directions/codes
-
- Background:
- Given the profile "testbot"
-
- Scenario: Turn directions
- Given the node map
- | o | p | a | b | c |
- | n | | | | d |
- | m | | x | | e |
- | l | | | | f |
- | k | j | i | h | g |
- And the ways
- | nodes |
- | xa |
- | xb |
- | xc |
- | xd |
- | xe |
- | xf |
- | xg |
- | xh |
- | xi |
- | xj |
- | xk |
- | xl |
- | xm |
- | xn |
- | xo |
- | xp |
+ Background:
+ Given the profile "testbot"
- When I route I should get
- | from | to | route | turns |
- | i | k | xi,xk | head,sharp_left,destination |
- | i | m | xi,xm | head,left,destination |
- | i | o | xi,xo | head,slight_left,destination |
- | i | a | xi,xa | head,straight,destination |
- | i | c | xi,xc | head,slight_right,destination |
- | i | e | xi,xe | head,right,destination |
- | i | g | xi,xg | head,sharp_right,destination |
+ Scenario: Turn directions
+ Given the node map
+ | o | p | a | b | c |
+ | n | | | | d |
+ | m | | x | | e |
+ | l | | | | f |
+ | k | j | i | h | g |
- | k | m | xk,xm | head,sharp_left,destination |
- | k | o | xk,xo | head,left,destination |
- | k | a | xk,xa | head,slight_left,destination |
- | k | c | xk,xc | head,straight,destination |
- | k | e | xk,xe | head,slight_right,destination |
- | k | g | xk,xg | head,right,destination |
- | k | i | xk,xi | head,sharp_right,destination |
+ And the ways
+ | nodes |
+ | xa |
+ | xb |
+ | xc |
+ | xd |
+ | xe |
+ | xf |
+ | xg |
+ | xh |
+ | xi |
+ | xj |
+ | xk |
+ | xl |
+ | xm |
+ | xn |
+ | xo |
+ | xp |
- | m | o | xm,xo | head,sharp_left,destination |
- | m | a | xm,xa | head,left,destination |
- | m | c | xm,xc | head,slight_left,destination |
- | m | e | xm,xe | head,straight,destination |
- | m | g | xm,xg | head,slight_right,destination |
- | m | i | xm,xi | head,right,destination |
- | m | k | xm,xk | head,sharp_right,destination |
+ When I route I should get
+ | from | to | route | turns |
+ | i | k | xi,xk | head,sharp_left,destination |
+ | i | m | xi,xm | head,left,destination |
+ | i | o | xi,xo | head,slight_left,destination |
+ | i | a | xi,xa | head,straight,destination |
+ | i | c | xi,xc | head,slight_right,destination |
+ | i | e | xi,xe | head,right,destination |
+ | i | g | xi,xg | head,sharp_right,destination |
- | o | a | xo,xa | head,sharp_left,destination |
- | o | c | xo,xc | head,left,destination |
- | o | e | xo,xe | head,slight_left,destination |
- | o | g | xo,xg | head,straight,destination |
- | o | i | xo,xi | head,slight_right,destination |
- | o | k | xo,xk | head,right,destination |
- | o | m | xo,xm | head,sharp_right,destination |
+ | k | m | xk,xm | head,sharp_left,destination |
+ | k | o | xk,xo | head,left,destination |
+ | k | a | xk,xa | head,slight_left,destination |
+ | k | c | xk,xc | head,straight,destination |
+ | k | e | xk,xe | head,slight_right,destination |
+ | k | g | xk,xg | head,right,destination |
+ | k | i | xk,xi | head,sharp_right,destination |
- | a | c | xa,xc | head,sharp_left,destination |
- | a | e | xa,xe | head,left,destination |
- | a | g | xa,xg | head,slight_left,destination |
- | a | i | xa,xi | head,straight,destination |
- | a | k | xa,xk | head,slight_right,destination |
- | a | m | xa,xm | head,right,destination |
- | a | o | xa,xo | head,sharp_right,destination |
+ | m | o | xm,xo | head,sharp_left,destination |
+ | m | a | xm,xa | head,left,destination |
+ | m | c | xm,xc | head,slight_left,destination |
+ | m | e | xm,xe | head,straight,destination |
+ | m | g | xm,xg | head,slight_right,destination |
+ | m | i | xm,xi | head,right,destination |
+ | m | k | xm,xk | head,sharp_right,destination |
- | c | e | xc,xe | head,sharp_left,destination |
- | c | g | xc,xg | head,left,destination |
- | c | i | xc,xi | head,slight_left,destination |
- | c | k | xc,xk | head,straight,destination |
- | c | m | xc,xm | head,slight_right,destination |
- | c | o | xc,xo | head,right,destination |
- | c | a | xc,xa | head,sharp_right,destination |
+ | o | a | xo,xa | head,sharp_left,destination |
+ | o | c | xo,xc | head,left,destination |
+ | o | e | xo,xe | head,slight_left,destination |
+ | o | g | xo,xg | head,straight,destination |
+ | o | i | xo,xi | head,slight_right,destination |
+ | o | k | xo,xk | head,right,destination |
+ | o | m | xo,xm | head,sharp_right,destination |
- | e | g | xe,xg | head,sharp_left,destination |
- | e | i | xe,xi | head,left,destination |
- | e | k | xe,xk | head,slight_left,destination |
- | e | m | xe,xm | head,straight,destination |
- | e | o | xe,xo | head,slight_right,destination |
- | e | a | xe,xa | head,right,destination |
- | e | c | xe,xc | head,sharp_right,destination |
+ | a | c | xa,xc | head,sharp_left,destination |
+ | a | e | xa,xe | head,left,destination |
+ | a | g | xa,xg | head,slight_left,destination |
+ | a | i | xa,xi | head,straight,destination |
+ | a | k | xa,xk | head,slight_right,destination |
+ | a | m | xa,xm | head,right,destination |
+ | a | o | xa,xo | head,sharp_right,destination |
- | g | i | xg,xi | head,sharp_left,destination |
- | g | k | xg,xk | head,left,destination |
- | g | m | xg,xm | head,slight_left,destination |
- | g | o | xg,xo | head,straight,destination |
- | g | a | xg,xa | head,slight_right,destination |
- | g | c | xg,xc | head,right,destination |
- | g | e | xg,xe | head,sharp_right,destination |
-
- Scenario: Turn instructions at high latitude
- https://github.com/DennisOSRM/Project-OSRM/issues/532
- Given the node locations
- | node | lat | lon |
- | a | 55.68740 | 12.52430 |
- | b | 55.68745 | 12.52409 |
- | c | 55.68711 | 12.52383 |
- | x | -55.68740 | 12.52430 |
- | y | -55.68745 | 12.52409 |
- | z | -55.68711 | 12.52383 |
+ | c | e | xc,xe | head,sharp_left,destination |
+ | c | g | xc,xg | head,left,destination |
+ | c | i | xc,xi | head,slight_left,destination |
+ | c | k | xc,xk | head,straight,destination |
+ | c | m | xc,xm | head,slight_right,destination |
+ | c | o | xc,xo | head,right,destination |
+ | c | a | xc,xa | head,sharp_right,destination |
- And the ways
- | nodes |
- | ab |
- | bc |
- | xy |
- | yz |
+ | e | g | xe,xg | head,sharp_left,destination |
+ | e | i | xe,xi | head,left,destination |
+ | e | k | xe,xk | head,slight_left,destination |
+ | e | m | xe,xm | head,straight,destination |
+ | e | o | xe,xo | head,slight_right,destination |
+ | e | a | xe,xa | head,right,destination |
+ | e | c | xe,xc | head,sharp_right,destination |
- When I route I should get
- | from | to | route | turns |
- | a | c | ab,bc | head,left,destination |
- | c | a | bc,ab | head,right,destination |
- | x | z | xy,yz | head,right,destination |
- | z | x | yz,xy | head,left,destination |
+ | g | i | xg,xi | head,sharp_left,destination |
+ | g | k | xg,xk | head,left,destination |
+ | g | m | xg,xm | head,slight_left,destination |
+ | g | o | xg,xo | head,straight,destination |
+ | g | a | xg,xa | head,slight_right,destination |
+ | g | c | xg,xc | head,right,destination |
+ | g | e | xg,xe | head,sharp_right,destination |
+
+ Scenario: Turn instructions at high latitude
+ # https://github.com/DennisOSRM/Project-OSRM/issues/532
+ Given the node locations
+ | node | lat | lon |
+ | a | 55.68740 | 12.52430 |
+ | b | 55.68745 | 12.52409 |
+ | c | 55.68711 | 12.52383 |
+ | x | -55.68740 | 12.52430 |
+ | y | -55.68745 | 12.52409 |
+ | z | -55.68711 | 12.52383 |
+
+ And the ways
+ | nodes |
+ | ab |
+ | bc |
+ | xy |
+ | yz |
+
+ When I route I should get
+ | from | to | route | turns |
+ | a | c | ab,bc | head,left,destination |
+ | c | a | bc,ab | head,right,destination |
+ | x | z | xy,yz | head,right,destination |
+ | z | x | yz,xy | head,left,destination |
diff --git a/features/testbot/utf.feature b/features/testbot/utf.feature
index 784bd4c..e9d324c 100644
--- a/features/testbot/utf.feature
+++ b/features/testbot/utf.feature
@@ -1,21 +1,21 @@
@routing @utf
Feature: Handling of UTF characters
-
- Background:
- Given the profile "testbot"
-
- Scenario: Streetnames with UTF characters
- Given the node map
- | a | b | c | d |
- And the ways
- | nodes | name |
- | ab | Scandinavian København |
- | bc | Japanese 東京 |
- | cd | Cyrillic Москва |
+ Background:
+ Given the profile "testbot"
- When I route I should get
- | from | to | route |
- | a | b | Scandinavian København |
- | b | c | Japanese 東京 |
- | c | d | Cyrillic Москва |
+ Scenario: Streetnames with UTF characters
+ Given the node map
+ | a | b | c | d |
+
+ And the ways
+ | nodes | name |
+ | ab | Scandinavian København |
+ | bc | Japanese 東京 |
+ | cd | Cyrillic Москва |
+
+ When I route I should get
+ | from | to | route |
+ | a | b | Scandinavian København |
+ | b | c | Japanese 東京 |
+ | c | d | Cyrillic Москва |
diff --git a/features/testbot/via.feature b/features/testbot/via.feature
index 5ba8bac..79fe540 100644
--- a/features/testbot/via.feature
+++ b/features/testbot/via.feature
@@ -4,49 +4,99 @@ Feature: Via points
Background:
Given the profile "testbot"
- Scenario: Simple via point
- Given the node map
- | a | b | c |
+ Scenario: Simple via point
+ Given the node map
+ | a | b | c |
- And the ways
- | nodes |
- | abc |
+ And the ways
+ | nodes |
+ | abc |
- When I route I should get
- | waypoints | route |
- | a,b,c | abc |
- | c,b,a | 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 | |
+ | 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 | ab,bcd,de,efg |
+ | a,c,f,h | ab,bcd,de,efg,gh |
+
+ Scenario: Via points on ring of oneways
+ # xa it to avoid only having a single ring, which cna trigger edge cases
+ Given the node map
+ | x | | | | | | |
+ | a | 1 | b | 2 | c | 3 | d |
+ | f | | | | | | e |
+
+ And the ways
+ | nodes | oneway |
+ | xa | |
+ | ab | yes |
+ | bc | yes |
+ | cd | yes |
+ | de | yes |
+ | ef | yes |
+ | fa | yes |
+
+ When I route I should get
+ | waypoints | route | distance | turns |
+ | 1,3 | ab,bc,cd | 400m +-1 | head,straight,straight,destination |
+ | 3,1 | cd,de,ef,fa,ab | 1000m +-1 | head,right,right,right,right,destination |
+ | 1,2,3 | ab,bc,cd | 400m +-1 | head,straight,straight,destination |
+ | 1,3,2 | ab,bc,cd,de,ef,fa,ab,bc | 1600m +-1 | head,straight,straight,right,right,right,right,straight,destination |
+ | 3,2,1 | cd,de,ef,fa,ab,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,straight,right,right,right,right,destination |
+
+ @bug
+ Scenario: Via points on ring on the same oneway
+ # xa it to avoid only having a single ring, which cna trigger edge cases
+ Given the node map
+ | x | | | | |
+ | a | 1 | 2 | 3 | b |
+ | d | | | | c |
And the ways
- | nodes |
- | abc |
- | bd |
+ | nodes | oneway |
+ | xa | |
+ | ab | yes |
+ | bc | yes |
+ | cd | yes |
+ | da | yes |
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 |
+ | waypoints | route | distance | turns |
+ | 1,3 | ab | 200m +-1 | head,destination |
+ | 3,1 | ab,bc,cd,da,ab | 800m +-1 | head,right,right,right,right,destination |
+ | 1,2,3 | ab | 200m +-1 | head,destination |
+ | 1,3,2 | ab,bc,cd,da,ab | 1100m +-1 | head,right,right,right,right,destination |
+ | 3,2,1 | ab,bc,cd,da,ab,bc,cd,da,ab | 1600m +-1 | head,right,right,right,right,right,right,right,right,destination |
diff --git a/features/timestamp/timestamp.feature b/features/timestamp/timestamp.feature
index 7886bad..70ef91c 100644
--- a/features/timestamp/timestamp.feature
+++ b/features/timestamp/timestamp.feature
@@ -1,12 +1,11 @@
@timestamp
Feature: Timestamp
-
- Scenario: Request timestamp
- Given the node map
- | a | b |
- And the ways
- | nodes |
- | ab |
- When I request /timestamp
- Then I should get a valid timestamp
-
+
+ Scenario: Request timestamp
+ Given the node map
+ | a | b |
+ And the ways
+ | nodes |
+ | ab |
+ When I request /timestamp
+ Then I should get a valid timestamp
diff --git a/prepare.cpp b/prepare.cpp
new file mode 100644
index 0000000..bb0dab4
--- /dev/null
+++ b/prepare.cpp
@@ -0,0 +1,523 @@
+/*
+
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#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 "DataStructures/RestrictionMap.h"
+#include "Util/GitDescription.h"
+#include "Util/GraphLoader.h"
+#include "Util/LuaUtil.h"
+#include "Util/OSRMException.h"
+
+#include "Util/SimpleLogger.h"
+#include "Util/StringUtil.h"
+#include "Util/TimingUtil.h"
+#include "typedefs.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include <luabind/luabind.hpp>
+
+#include <thread>
+#include <chrono>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <tbb/task_scheduler_init.h>
+#include <tbb/parallel_sort.h>
+
+typedef QueryEdge::EdgeData EdgeData;
+typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
+typedef StaticGraph<EdgeData>::InputEdge StaticEdge;
+
+std::vector<NodeInfo> internal_to_external_node_map;
+std::vector<TurnRestriction> restriction_list;
+std::vector<NodeID> barrier_node_list;
+std::vector<NodeID> traffic_light_list;
+std::vector<ImportEdge> edge_list;
+
+int main(int argc, char *argv[])
+{
+ try
+ {
+ LogPolicy::GetInstance().Unmute();
+ TIMER_START(preparing);
+ TIMER_START(expansion);
+
+ boost::filesystem::path config_file_path, input_path, restrictions_path, profile_path;
+ unsigned int requested_num_threads;
+
+ // declare a group of options that will be allowed only on command line
+ boost::program_options::options_description generic_options("Options");
+ generic_options.add_options()("version,v", "Show version")("help,h",
+ "Show this help message")(
+ "config,c",
+ boost::program_options::value<boost::filesystem::path>(&config_file_path)
+ ->default_value("contractor.ini"),
+ "Path to a configuration file.");
+
+ // declare a group of options that will be allowed both on command line and in config file
+ boost::program_options::options_description config_options("Configuration");
+ config_options.add_options()(
+ "restrictions,r",
+ boost::program_options::value<boost::filesystem::path>(&restrictions_path),
+ "Restrictions file in .osrm.restrictions format")(
+ "profile,p",
+ boost::program_options::value<boost::filesystem::path>(&profile_path)
+ ->default_value("profile.lua"),
+ "Path to LUA routing profile")(
+ "threads,t",
+ boost::program_options::value<unsigned int>(&requested_num_threads)->default_value(tbb::task_scheduler_init::default_num_threads()),
+ "Number of threads to use");
+
+ // hidden options, will be allowed both on command line and in config file, but will not be
+ // shown to the user
+ boost::program_options::options_description hidden_options("Hidden options");
+ hidden_options.add_options()(
+ "input,i",
+ boost::program_options::value<boost::filesystem::path>(&input_path),
+ "Input file in .osm, .osm.bz2 or .osm.pbf format");
+
+ // positional option
+ boost::program_options::positional_options_description positional_options;
+ positional_options.add("input", 1);
+
+ // combine above options for parsing
+ boost::program_options::options_description cmdline_options;
+ cmdline_options.add(generic_options).add(config_options).add(hidden_options);
+
+ boost::program_options::options_description config_file_options;
+ config_file_options.add(config_options).add(hidden_options);
+
+ boost::program_options::options_description visible_options(
+ "Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
+ visible_options.add(generic_options).add(config_options);
+
+ // parse command line options
+ boost::program_options::variables_map option_variables;
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(cmdline_options)
+ .positional(positional_options)
+ .run(),
+ option_variables);
+
+ if (option_variables.count("version"))
+ {
+ SimpleLogger().Write() << g_GIT_DESCRIPTION;
+ return 0;
+ }
+
+ if (option_variables.count("help"))
+ {
+ SimpleLogger().Write() << "\n" << visible_options;
+ return 0;
+ }
+
+ boost::program_options::notify(option_variables);
+
+ if (!option_variables.count("restrictions"))
+ {
+ restrictions_path = std::string(input_path.string() + ".restrictions");
+ }
+
+ if (!option_variables.count("input"))
+ {
+ SimpleLogger().Write() << "\n" << visible_options;
+ return 0;
+ }
+
+ if (!boost::filesystem::is_regular_file(input_path))
+ {
+ SimpleLogger().Write(logWARNING) << "Input file " << input_path.string()
+ << " not found!";
+ return 1;
+ }
+
+ if (!boost::filesystem::is_regular_file(profile_path))
+ {
+ SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string()
+ << " not found!";
+ return 1;
+ }
+
+ if (1 > requested_num_threads)
+ {
+ SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
+ return 1;
+ }
+
+ const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
+
+ SimpleLogger().Write() << "Input file: " << input_path.filename().string();
+ SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string();
+ SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
+ SimpleLogger().Write() << "Threads: " << requested_num_threads;
+ if (recommended_num_threads != requested_num_threads)
+ {
+ SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
+ << recommended_num_threads
+ << "! This setting may have performance side-effects.";
+ }
+
+ tbb::task_scheduler_init init(requested_num_threads);
+
+ LogPolicy::GetInstance().Unmute();
+ boost::filesystem::ifstream restriction_stream(restrictions_path, std::ios::binary);
+ TurnRestriction restriction;
+ FingerPrint fingerprint_loaded, fingerprint_orig;
+ unsigned number_of_usable_restrictions = 0;
+ restriction_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
+ if (!fingerprint_loaded.TestPrepare(fingerprint_orig))
+ {
+ SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
+ "Reprocess to get rid of this warning.";
+ }
+
+ restriction_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
+ restriction_list.resize(number_of_usable_restrictions);
+ if (number_of_usable_restrictions > 0)
+ {
+ restriction_stream.read((char *)&(restriction_list[0]),
+ number_of_usable_restrictions * sizeof(TurnRestriction));
+ }
+ restriction_stream.close();
+
+ boost::filesystem::ifstream in;
+ in.open(input_path, std::ios::in | std::ios::binary);
+
+ const std::string node_filename = input_path.string() + ".nodes";
+ const std::string edge_out = input_path.string() + ".edges";
+ const std::string geometry_filename = input_path.string() + ".geometry";
+ const std::string graphOut = input_path.string() + ".hsgr";
+ const std::string rtree_nodes_path = input_path.string() + ".ramIndex";
+ const std::string rtree_leafs_path = input_path.string() + ".fileIndex";
+
+ /*** Setup Scripting Environment ***/
+
+ // Create a new lua state
+ lua_State *lua_state = luaL_newstate();
+
+ // Connect LuaBind to this lua state
+ luabind::open(lua_state);
+
+ // open utility libraries string library;
+ luaL_openlibs(lua_state);
+
+ // adjust lua load path
+ luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str());
+
+ // Now call our function in a lua script
+ if (0 != luaL_dofile(lua_state, profile_path.string().c_str()))
+ {
+ std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
+ return 1;
+ }
+
+ EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
+
+ if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
+ {
+ std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
+ return 1;
+ }
+ speed_profile.trafficSignalPenalty = 10 * lua_tointeger(lua_state, -1);
+ SimpleLogger().Write(logDEBUG)
+ << "traffic_signal_penalty: " << speed_profile.trafficSignalPenalty;
+
+ if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
+ {
+ std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
+ return 1;
+ }
+ speed_profile.uTurnPenalty = 10 * lua_tointeger(lua_state, -1);
+
+ speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
+
+ #ifdef WIN32
+ #pragma message ("Memory consumption on Windows can be higher due to memory alignment")
+ #else
+ static_assert(sizeof(ImportEdge) == 20,
+ "changing ImportEdge type has influence on memory consumption!");
+ #endif
+ std::vector<ImportEdge> edge_list;
+ NodeID number_of_node_based_nodes =
+ readBinaryOSRMGraphFromStream(in,
+ edge_list,
+ barrier_node_list,
+ traffic_light_list,
+ &internal_to_external_node_map,
+ restriction_list);
+ in.close();
+
+ if (edge_list.empty())
+ {
+ SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
+ return 1;
+ }
+
+ SimpleLogger().Write() << restriction_list.size() << " restrictions, "
+ << barrier_node_list.size() << " bollard nodes, "
+ << traffic_light_list.size() << " traffic lights";
+
+ /***
+ * Building an edge-expanded graph from node-based input and turn restrictions
+ */
+
+ SimpleLogger().Write() << "Generating edge-expanded graph representation";
+ std::shared_ptr<NodeBasedDynamicGraph> node_based_graph =
+ NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
+ std::unique_ptr<RestrictionMap> restriction_map =
+ std::unique_ptr<RestrictionMap>(new RestrictionMap(node_based_graph, restriction_list));
+ EdgeBasedGraphFactory *edge_based_graph_factor =
+ new EdgeBasedGraphFactory(node_based_graph,
+ std::move(restriction_map),
+ barrier_node_list,
+ traffic_light_list,
+ internal_to_external_node_map,
+ speed_profile);
+ edge_list.clear();
+ edge_list.shrink_to_fit();
+
+ edge_based_graph_factor->Run(edge_out, geometry_filename, lua_state);
+
+ restriction_list.clear();
+ restriction_list.shrink_to_fit();
+ barrier_node_list.clear();
+ barrier_node_list.shrink_to_fit();
+ traffic_light_list.clear();
+ traffic_light_list.shrink_to_fit();
+
+ unsigned number_of_edge_based_nodes = edge_based_graph_factor->GetNumberOfEdgeBasedNodes();
+ BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
+ DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
+ #ifndef WIN32
+ static_assert(sizeof(EdgeBasedEdge) == 16,
+ "changing ImportEdge type has influence on memory consumption!");
+ #endif
+
+ edge_based_graph_factor->GetEdgeBasedEdges(edgeBasedEdgeList);
+ std::vector<EdgeBasedNode> node_based_edge_list;
+ edge_based_graph_factor->GetEdgeBasedNodes(node_based_edge_list);
+ delete edge_based_graph_factor;
+
+ // TODO actually use scoping: Split this up in subfunctions
+ node_based_graph.reset();
+
+ TIMER_STOP(expansion);
+
+ // Building grid-like nearest-neighbor data structure
+ SimpleLogger().Write() << "building r-tree ...";
+ StaticRTree<EdgeBasedNode> *rtree =
+ new StaticRTree<EdgeBasedNode>(node_based_edge_list,
+ rtree_nodes_path.c_str(),
+ rtree_leafs_path.c_str(),
+ internal_to_external_node_map);
+ delete rtree;
+ IteratorbasedCRC32<std::vector<EdgeBasedNode>> crc32;
+ unsigned node_based_edge_list_CRC32 =
+ crc32(node_based_edge_list.begin(), node_based_edge_list.end());
+ node_based_edge_list.clear();
+ node_based_edge_list.shrink_to_fit();
+ SimpleLogger().Write() << "CRC32: " << node_based_edge_list_CRC32;
+
+ /***
+ * Writing info on original (node-based) nodes
+ */
+
+ SimpleLogger().Write() << "writing node map ...";
+ boost::filesystem::ofstream node_stream(node_filename, std::ios::binary);
+ const unsigned size_of_mapping = internal_to_external_node_map.size();
+ node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
+ if (size_of_mapping > 0)
+ {
+ node_stream.write((char *)&(internal_to_external_node_map[0]),
+ size_of_mapping * sizeof(NodeInfo));
+ }
+ node_stream.close();
+ internal_to_external_node_map.clear();
+ internal_to_external_node_map.shrink_to_fit();
+
+ /***
+ * Contracting the edge-expanded graph
+ */
+
+ SimpleLogger().Write() << "initializing contractor";
+ Contractor *contractor = new Contractor(number_of_edge_based_nodes, edgeBasedEdgeList);
+
+ TIMER_START(contraction);
+ contractor->Run();
+ TIMER_STOP(contraction);
+
+ SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
+
+ DeallocatingVector<QueryEdge> contracted_edge_list;
+ contractor->GetEdges(contracted_edge_list);
+ delete contractor;
+
+ /***
+ * Sorting contracted edges in a way that the static query graph can read some in in-place.
+ */
+
+ std::sort(contracted_edge_list.begin(), contracted_edge_list.end());
+ unsigned max_used_node_id = 0;
+ unsigned contracted_edge_count = contracted_edge_list.size();
+ SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
+ << " edges";
+
+ boost::filesystem::ofstream hsgr_output_stream(graphOut, std::ios::binary);
+ hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint));
+ for (const QueryEdge &edge : contracted_edge_list)
+ {
+ BOOST_ASSERT(UINT_MAX != edge.source);
+ BOOST_ASSERT(UINT_MAX != edge.target);
+
+ max_used_node_id = std::max(max_used_node_id, edge.source);
+ max_used_node_id = std::max(max_used_node_id, edge.target);
+ }
+ SimpleLogger().Write(logDEBUG) << "input graph has " << number_of_edge_based_nodes
+ << " nodes";
+ SimpleLogger().Write(logDEBUG) << "contracted graph has " << max_used_node_id << " nodes";
+ max_used_node_id += 1;
+
+ std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array;
+ node_array.resize(number_of_edge_based_nodes + 1);
+
+ SimpleLogger().Write() << "Building node array";
+ StaticGraph<EdgeData>::EdgeIterator edge = 0;
+ StaticGraph<EdgeData>::EdgeIterator position = 0;
+ StaticGraph<EdgeData>::EdgeIterator last_edge = edge;
+
+ for (StaticGraph<EdgeData>::NodeIterator node = 0; node < max_used_node_id; ++node)
+ {
+ last_edge = edge;
+ while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
+ {
+ ++edge;
+ }
+ node_array[node].first_edge = position; //=edge
+ position += edge - last_edge; // remove
+ }
+
+ for (unsigned sentinel_counter = max_used_node_id; sentinel_counter != node_array.size();
+ ++sentinel_counter)
+ {
+ // sentinel element, guarded against underflow
+ node_array[sentinel_counter].first_edge = contracted_edge_count;
+ }
+
+ unsigned node_array_size = node_array.size();
+ // serialize crc32, aka checksum
+ hsgr_output_stream.write((char *)&node_based_edge_list_CRC32, sizeof(unsigned));
+ // serialize number of nodes
+ hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
+ // serialize number of edges
+ hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
+ // serialize all nodes
+ if (node_array_size > 0)
+ {
+ hsgr_output_stream.write((char *)&node_array[0],
+ sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
+ }
+ // serialize all edges
+
+ SimpleLogger().Write() << "Building edge array";
+ edge = 0;
+ int number_of_used_edges = 0;
+
+ StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
+ for (unsigned edge = 0; edge < contracted_edge_list.size(); ++edge)
+ {
+ // no eigen loops
+ BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target);
+ current_edge.target = contracted_edge_list[edge].target;
+ current_edge.data = contracted_edge_list[edge].data;
+
+ // every target needs to be valid
+ BOOST_ASSERT(current_edge.target < max_used_node_id);
+#ifndef NDEBUG
+ if (current_edge.data.distance <= 0)
+ {
+ SimpleLogger().Write(logWARNING)
+ << "Edge: " << edge << ",source: " << contracted_edge_list[edge].source
+ << ", target: " << contracted_edge_list[edge].target
+ << ", dist: " << current_edge.data.distance;
+
+ SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
+ << contracted_edge_list[edge].source << "/"
+ << node_array.size() - 1;
+ return 1;
+ }
+#endif
+ hsgr_output_stream.write((char *)¤t_edge,
+ sizeof(StaticGraph<EdgeData>::EdgeArrayEntry));
+ ++number_of_used_edges;
+ }
+ hsgr_output_stream.close();
+
+ TIMER_STOP(preparing);
+
+ SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
+ SimpleLogger().Write() << "Expansion : "
+ << (number_of_node_based_nodes / TIMER_SEC(expansion))
+ << " nodes/sec and "
+ << (number_of_edge_based_nodes / TIMER_SEC(expansion))
+ << " edges/sec";
+
+ SimpleLogger().Write() << "Contraction: "
+ << (number_of_edge_based_nodes / TIMER_SEC(contraction))
+ << " nodes/sec and "
+ << number_of_used_edges / TIMER_SEC(contraction)
+ << " edges/sec";
+
+ node_array.clear();
+ SimpleLogger().Write() << "finished preprocessing";
+ }
+ catch (boost::program_options::too_many_positional_options_error &)
+ {
+ SimpleLogger().Write(logWARNING) << "Only one file can be specified";
+ return 1;
+ }
+ catch (boost::program_options::error &e)
+ {
+ SimpleLogger().Write(logWARNING) << e.what();
+ return 1;
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "Exception occured: " << e.what() << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/profile.lua b/profile.lua
new file mode 120000
index 0000000..bad7e6b
--- /dev/null
+++ b/profile.lua
@@ -0,0 +1 @@
+profiles/car.lua
\ No newline at end of file
diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua
index 98d03c8..3efa3d0 100644
--- a/profiles/bicycle.lua
+++ b/profiles/bicycle.lua
@@ -1,8 +1,8 @@
require("lib/access")
-- Begin of globals
-barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true}
-access_tag_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true }
+barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true }
+access_tag_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestery"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
access_tags_hierachy = { "bicycle", "vehicle", "access" }
@@ -14,103 +14,120 @@ default_speed = 15
walking_speed = 6
-bicycle_speeds = {
- ["cycleway"] = default_speed,
- ["primary"] = default_speed,
- ["primary_link"] = default_speed,
- ["secondary"] = default_speed,
- ["secondary_link"] = default_speed,
- ["tertiary"] = default_speed,
- ["tertiary_link"] = default_speed,
- ["residential"] = default_speed,
- ["unclassified"] = default_speed,
- ["living_street"] = default_speed,
- ["road"] = default_speed,
- ["service"] = default_speed,
- ["track"] = 12,
- ["path"] = 12
- --["footway"] = 12,
- --["pedestrian"] = 12,
+bicycle_speeds = {
+ ["cycleway"] = default_speed,
+ ["primary"] = default_speed,
+ ["primary_link"] = default_speed,
+ ["secondary"] = default_speed,
+ ["secondary_link"] = default_speed,
+ ["tertiary"] = default_speed,
+ ["tertiary_link"] = default_speed,
+ ["residential"] = default_speed,
+ ["unclassified"] = default_speed,
+ ["living_street"] = default_speed,
+ ["road"] = default_speed,
+ ["service"] = default_speed,
+ ["track"] = 12,
+ ["path"] = 12
+ --["footway"] = 12,
+ --["pedestrian"] = 12,
}
-pedestrian_speeds = {
- ["footway"] = walking_speed,
- ["pedestrian"] = walking_speed,
- ["steps"] = 2
+pedestrian_speeds = {
+ ["footway"] = walking_speed,
+ ["pedestrian"] = walking_speed,
+ ["steps"] = 2
}
-railway_speeds = {
- ["train"] = 10,
- ["railway"] = 10,
- ["subway"] = 10,
- ["light_rail"] = 10,
- ["monorail"] = 10,
- ["tram"] = 10
+railway_speeds = {
+ ["train"] = 10,
+ ["railway"] = 10,
+ ["subway"] = 10,
+ ["light_rail"] = 10,
+ ["monorail"] = 10,
+ ["tram"] = 10
}
-platform_speeds = {
- ["platform"] = walking_speed
+platform_speeds = {
+ ["platform"] = walking_speed
}
-amenity_speeds = {
- ["parking"] = 10,
- ["parking_entrance"] = 10
+amenity_speeds = {
+ ["parking"] = 10,
+ ["parking_entrance"] = 10
}
-man_made_speeds = {
- ["pier"] = walking_speed
+man_made_speeds = {
+ ["pier"] = walking_speed
}
-route_speeds = {
- ["ferry"] = 5
+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
+surface_speeds = {
+ ["asphalt"] = default_speed,
+ ["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
-use_restrictions = true
-ignore_areas = true -- future feature
-traffic_signal_penalty = 5
-u_turn_penalty = 20
+take_minimum_of_speeds = true
+obey_oneway = true
+obey_bollards = false
+use_restrictions = true
+ignore_areas = true -- future feature
+traffic_signal_penalty = 5
+u_turn_penalty = 20
use_turn_restrictions = false
-turn_penalty = 60
-turn_bias = 1.4
+turn_penalty = 60
+turn_bias = 1.4
-- End of globals
+
+local function parse_maxspeed(source)
+ if not source then
+ return 0
+ end
+ local n = tonumber(source:match("%d*"))
+ if not n then
+ n = 0
+ end
+ if string.match(source, "mph") or string.match(source, "mp/h") then
+ n = (n*1609)/1000;
+ end
+ return n
+end
+
+
function get_exceptions(vector)
- for i,v in ipairs(restriction_exception_tags) do
- vector:Add(v)
- end
+ for i,v in ipairs(restriction_exception_tags) do
+ vector:Add(v)
+ end
end
function node_function (node)
- local barrier = node.tags:Find ("barrier")
- local access = Access.find_access_tag(node, access_tags_hierachy)
- local traffic_signal = node.tags:Find("highway")
-
- -- flag node if it carries a traffic light
+ 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
@@ -125,229 +142,235 @@ function node_function (node)
node.bollard = true
end
end
-
- return 1
+
+ -- return 1
end
function way_function (way)
- -- initial routability check, filters out buildings, boundaries, etc
- local highway = way.tags:Find("highway")
- local route = way.tags:Find("route")
- local man_made = way.tags:Find("man_made")
- local railway = way.tags:Find("railway")
- local amenity = way.tags:Find("amenity")
- local public_transport = way.tags:Find("public_transport")
- if (not highway or highway == '') and
- (not route or route == '') and
- (not railway or railway=='') and
- (not amenity or amenity=='') and
- (not man_made or man_made=='') and
- (not public_transport or public_transport=='')
- then
- return 0
+ -- initial routability check, filters out buildings, boundaries, etc
+ local highway = way.tags:Find("highway")
+ local route = way.tags:Find("route")
+ local man_made = way.tags:Find("man_made")
+ local railway = way.tags:Find("railway")
+ local amenity = way.tags:Find("amenity")
+ local public_transport = way.tags:Find("public_transport")
+ if (not highway or highway == '') and
+ (not route or route == '') and
+ (not railway or railway=='') and
+ (not amenity or amenity=='') and
+ (not man_made or man_made=='') and
+ (not public_transport or public_transport=='')
+ then
+ return 0
+ end
+
+ -- don't route on ways or railways that are still under construction
+ if highway=='construction' or railway=='construction' then
+ return 0
+ end
+
+ -- access
+ local access = Access.find_access_tag(way, access_tags_hierachy)
+ if access_tag_blacklist[access] then
+ return 0
+ end
+
+ -- other tags
+ local name = way.tags:Find("name")
+ local ref = way.tags:Find("ref")
+ local junction = way.tags:Find("junction")
+ local maxspeed = parse_maxspeed(way.tags:Find ( "maxspeed") )
+ local maxspeed_forward = parse_maxspeed(way.tags:Find( "maxspeed:forward"))
+ local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward"))
+ local barrier = way.tags:Find("barrier")
+ local oneway = way.tags:Find("oneway")
+ local onewayClass = way.tags:Find("oneway:bicycle")
+ local cycleway = way.tags:Find("cycleway")
+ local cycleway_left = way.tags:Find("cycleway:left")
+ local cycleway_right = way.tags:Find("cycleway:right")
+ local duration = way.tags:Find("duration")
+ 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 and "" ~= name then
+ way.name = name .. ' / ' .. ref
+ elseif "" ~= ref then
+ way.name = ref
+ elseif "" ~= name then
+ way.name = name
+ else
+ -- if no name exists, use way type
+ -- this encoding scheme is excepted to be a temporary solution
+ way.name = "{highway:"..highway.."}"
+ end
+
+ -- roundabout handling
+ if "roundabout" == junction then
+ way.roundabout = true;
+ end
+
+ -- speed
+ if route_speeds[route] then
+ -- ferries (doesn't cover routes tagged using relations)
+ way.direction = Way.bidirectional
+ way.ignore_in_grid = true
+ if durationIsValid(duration) then
+ way.duration = math.max( 1, parseDuration(duration) )
+ else
+ way.speed = route_speeds[route]
end
-
- -- don't route on ways or railways that are still under construction
- if highway=='construction' or railway=='construction' then
- return 0
+ elseif railway and platform_speeds[railway] then
+ -- railway platforms (old tagging scheme)
+ way.speed = platform_speeds[railway]
+ elseif platform_speeds[public_transport] then
+ -- public_transport platforms (new tagging platform)
+ way.speed = platform_speeds[public_transport]
+ elseif railway and railway_speeds[railway] then
+ -- railways
+ if access and access_tag_whitelist[access] then
+ way.speed = railway_speeds[railway]
+ way.direction = Way.bidirectional
end
-
- -- access
- local access = Access.find_access_tag(way, access_tags_hierachy)
- if access_tag_blacklist[access] then
- return 0
+ elseif amenity and amenity_speeds[amenity] then
+ -- parking areas
+ way.speed = amenity_speeds[amenity]
+ elseif bicycle_speeds[highway] then
+ -- regular ways
+ way.speed = bicycle_speeds[highway]
+ elseif access and access_tag_whitelist[access] then
+ -- unknown way, but valid access tag
+ way.speed = default_speed
+ else
+ -- biking not allowed, maybe we can push our bike?
+ -- essentially requires pedestrian profiling, for example foot=no mean we can't push a bike
+ -- TODO: if we can push, the way should be marked as pedestrion mode, but there's no way to do it yet from lua..
+ if foot ~= 'no' then
+ if pedestrian_speeds[highway] then
+ -- pedestrian-only ways and areas
+ way.speed = pedestrian_speeds[highway]
+ elseif man_made and man_made_speeds[man_made] then
+ -- man made structures
+ way.speed = man_made_speeds[man_made]
+ elseif foot == 'yes' then
+ way.speed = walking_speed
+ end
end
+ end
+ -- direction
+ way.direction = Way.bidirectional
+ local impliedOneway = false
+ if junction == "roundabout" or highway == "motorway_link" or highway == "motorway" then
+ way.direction = Way.oneway
+ impliedOneway = true
+ end
- -- other tags
- local name = way.tags:Find("name")
- local ref = way.tags:Find("ref")
- local junction = way.tags:Find("junction")
- local maxspeed = parseMaxspeed(way.tags:Find ( "maxspeed") )
- local maxspeed_forward = parseMaxspeed(way.tags:Find( "maxspeed:forward"))
- local maxspeed_backward = parseMaxspeed(way.tags:Find( "maxspeed:backward"))
- local barrier = way.tags:Find("barrier")
- local oneway = way.tags:Find("oneway")
- local onewayClass = way.tags:Find("oneway:bicycle")
- local cycleway = way.tags:Find("cycleway")
- local cycleway_left = way.tags:Find("cycleway:left")
- local cycleway_right = way.tags:Find("cycleway:right")
- local duration = way.tags:Find("duration")
- 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 and "" ~= name then
- way.name = name .. ' / ' .. ref
- elseif "" ~= ref then
- way.name = ref
- elseif "" ~= name then
- way.name = name
- else
- way.name = "{highway:"..highway.."}" -- if no name exists, use way type
- -- this encoding scheme is excepted to be a temporary solution
- end
-
- -- speed
- if route_speeds[route] then
- -- ferries (doesn't cover routes tagged using relations)
- way.direction = Way.bidirectional
- way.ignore_in_grid = true
- if durationIsValid(duration) then
- way.duration = math.max( 1, parseDuration(duration) )
- else
- way.speed = route_speeds[route]
- end
- elseif railway and platform_speeds[railway] then
- -- railway platforms (old tagging scheme)
- way.speed = platform_speeds[railway]
- elseif platform_speeds[public_transport] then
- -- public_transport platforms (new tagging platform)
- way.speed = platform_speeds[public_transport]
- elseif railway and railway_speeds[railway] then
- -- railways
- if access and access_tag_whitelist[access] then
- way.speed = railway_speeds[railway]
- way.direction = Way.bidirectional
- end
- elseif amenity and amenity_speeds[amenity] then
- -- parking areas
- way.speed = amenity_speeds[amenity]
- elseif bicycle_speeds[highway] then
- -- regular ways
- way.speed = bicycle_speeds[highway]
- elseif access and access_tag_whitelist[access] then
- -- unknown way, but valid access tag
- way.speed = default_speed
- else
- -- biking not allowed, maybe we can push our bike?
- -- essentially requires pedestrian profiling, for example foot=no mean we can't push a bike
- -- TODO: if we can push, the way should be marked as pedestrion mode, but there's no way to do it yet from lua..
- if foot ~= 'no' then
- if pedestrian_speeds[highway] then
- -- pedestrian-only ways and areas
- way.speed = pedestrian_speeds[highway]
- elseif man_made and man_made_speeds[man_made] then
- -- man made structures
- way.speed = man_made_speeds[man_made]
- elseif foot == 'yes' then
- way.speed = walking_speed
- end
- end
+ if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
+ way.direction = Way.oneway
+ elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
+ way.direction = Way.bidirectional
+ elseif onewayClass == "-1" then
+ way.direction = Way.opposite
+ elseif oneway == "no" or oneway == "0" or oneway == "false" then
+ way.direction = Way.bidirectional
+ elseif cycleway and string.find(cycleway, "opposite") == 1 then
+ if impliedOneway then
+ way.direction = Way.opposite
+ else
+ way.direction = Way.bidirectional
end
-
- -- direction
- way.direction = Way.bidirectional
- local impliedOneway = false
- if junction == "roundabout" or highway == "motorway_link" or highway == "motorway" then
- way.direction = Way.oneway
- impliedOneway = true
- end
-
- if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
- way.direction = Way.oneway
- elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
- way.direction = Way.bidirectional
- elseif onewayClass == "-1" then
- way.direction = Way.opposite
- elseif oneway == "no" or oneway == "0" or oneway == "false" then
- way.direction = Way.bidirectional
- elseif cycleway and string.find(cycleway, "opposite") == 1 then
- if impliedOneway then
- way.direction = Way.opposite
- else
- way.direction = Way.bidirectional
- end
- elseif cycleway_left and cycleway_tags[cycleway_left] and cycleway_right and cycleway_tags[cycleway_right] then
- way.direction = Way.bidirectional
- elseif cycleway_left and cycleway_tags[cycleway_left] then
- if impliedOneway then
- way.direction = Way.opposite
- else
- way.direction = Way.bidirectional
- end
- elseif cycleway_right and cycleway_tags[cycleway_right] then
- if impliedOneway then
- way.direction = Way.oneway
- else
- way.direction = Way.bidirectional
- end
- elseif oneway == "-1" then
- way.direction = Way.opposite
- elseif oneway == "yes" or oneway == "1" or oneway == "true" then
- way.direction = Way.oneway
- end
-
- -- pushing bikes
- if bicycle_speeds[highway] or pedestrian_speeds[highway] then
- if foot ~= 'no' then
- if junction ~= "roundabout" then
- if way.direction == Way.oneway then
- way.backward_speed = walking_speed
- elseif way.direction == Way.opposite then
- way.backward_speed = walking_speed
- way.speed = way.speed
- end
- end
- end
- if way.backward_speed == way.speed then
- -- TODO: no way yet to mark a way as pedestrian mode if forward/backward speeds are equal
- way.direction = Way.bidirectional
- end
+ elseif cycleway_left and cycleway_tags[cycleway_left] and cycleway_right and cycleway_tags[cycleway_right] then
+ way.direction = Way.bidirectional
+ elseif cycleway_left and cycleway_tags[cycleway_left] then
+ if impliedOneway then
+ way.direction = Way.opposite
+ else
+ way.direction = Way.bidirectional
end
+ elseif cycleway_right and cycleway_tags[cycleway_right] then
+ if impliedOneway then
+ way.direction = Way.oneway
+ else
+ way.direction = Way.bidirectional
+ end
+ elseif oneway == "-1" then
+ way.direction = Way.opposite
+ elseif oneway == "yes" or oneway == "1" or oneway == "true" then
+ way.direction = Way.oneway
+ end
-
- -- cycleways
- if cycleway and cycleway_tags[cycleway] then
- way.speed = bicycle_speeds["cycleway"]
- elseif cycleway_left and cycleway_tags[cycleway_left] then
- way.speed = bicycle_speeds["cycleway"]
- elseif cycleway_right and cycleway_tags[cycleway_right] then
- 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)
+ -- pushing bikes
+ if bicycle_speeds[highway] or pedestrian_speeds[highway] then
+ if foot ~= 'no' then
+ if junction ~= "roundabout" then
+ if way.direction == Way.oneway then
+ way.backward_speed = walking_speed
+ elseif way.direction == Way.opposite then
+ way.backward_speed = walking_speed
+ way.speed = way.speed
end
+ end
+ end
+ if way.backward_speed == way.speed then
+ -- TODO: no way yet to mark a way as pedestrian mode if forward/backward speeds are equal
+ way.direction = Way.bidirectional
end
+ end
- -- maxspeed
- -- TODO: maxspeed of backward direction
- if take_minimum_of_speeds then
- if maxspeed and maxspeed>0 then
- way.speed = math.min(way.speed, maxspeed)
- end
- end
+ -- cycleways
+ if cycleway and cycleway_tags[cycleway] then
+ way.speed = bicycle_speeds["cycleway"]
+ elseif cycleway_left and cycleway_tags[cycleway_left] then
+ way.speed = bicycle_speeds["cycleway"]
+ elseif cycleway_right and cycleway_tags[cycleway_right] then
+ way.speed = bicycle_speeds["cycleway"]
+ 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
+ -- surfaces
+ if surface then
+ surface_speed = surface_speeds[surface]
+ if surface_speed then
+ if way.speed > 0 then
+ way.speed = surface_speed
+ end
+ if way.backward_speed > 0 then
+ way.backward_speed = surface_speed
+ end
end
- if maxspeed_backward ~= nil and maxspeed_backward > 0 then
- way.backward_speed = maxspeed_backward
+ end
+
+ -- maxspeed
+ -- TODO: maxspeed of backward direction
+ if take_minimum_of_speeds then
+ if maxspeed and maxspeed>0 then
+ way.speed = math.min(way.speed, maxspeed)
end
+ end
+ -- Override speed settings if explicit forward/backward maxspeeds are given
+ if way.speed > 0 and maxspeed_forward ~= nil and maxspeed_forward > 0 then
+ if Way.bidirectional == way.direction then
+ way.backward_speed = way.speed
+ end
+ way.speed = maxspeed_forward
+ end
+ if maxspeed_backward ~= nil and maxspeed_backward > 0 then
+ way.backward_speed = maxspeed_backward
+ end
-
- way.type = 1
- return 1
+ way.type = 1
+ return 1
end
function turn_function (angle)
- -- compute turn penalty as angle^2, with a left/right bias
- k = turn_penalty/(90.0*90.0)
- if angle>=0 then
- return angle*angle*k/turn_bias
- else
- return angle*angle*k*turn_bias
- end
+ -- compute turn penalty as angle^2, with a left/right bias
+ k = turn_penalty/(90.0*90.0)
+ if angle>=0 then
+ return angle*angle*k/turn_bias
+ else
+ return angle*angle*k*turn_bias
+ end
end
diff --git a/profiles/car.lua b/profiles/car.lua
index ff7c379..9c65852 100644
--- a/profiles/car.lua
+++ b/profiles/car.lua
@@ -1,9 +1,9 @@
-- Begin of globals
-require("lib/access")
+--require("lib/access") --function temporarily inlined
-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 }
+barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["entrance"] = 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, ["emergency"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
access_tags = { "motorcar", "motor_vehicle", "vehicle" }
access_tags_hierachy = { "motorcar", "motor_vehicle", "vehicle", "access" }
@@ -29,145 +29,193 @@ speed_profile = {
-- ["track"] = 5,
["ferry"] = 5,
["shuttle_train"] = 10,
- ["default"] = 50
+ ["default"] = 10
}
-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
+traffic_signal_penalty = 2
-- End of globals
+local take_minimum_of_speeds = false
+local obey_oneway = true
+local obey_bollards = true
+local use_turn_restrictions = true
+local ignore_areas = true -- future feature
+local u_turn_penalty = 20
+
+local abs = math.abs
+local min = math.min
+local max = math.max
+
+local speed_reduction = 0.8
+
+local function find_access_tag(source,access_tags_hierachy)
+ for i,v in ipairs(access_tags_hierachy) do
+ local has_tag = source.tags:Holds(v)
+ if has_tag then
+ return source.tags:Find(v)
+ end
+ end
+ return nil
+end
function get_exceptions(vector)
- for i,v in ipairs(restriction_exception_tags) do
- vector:Add(v)
- end
+ 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)
+ if not source then
+ return 0
+ end
+ local n = tonumber(source:match("%d*"))
+ if not n then
+ n = 0
+ end
+ if string.match(source, "mph") or string.match(source, "mp/h") then
+ n = (n*1609)/1000;
+ end
+ return n
end
+-- function turn_function (angle)
+-- -- print ("called at angle " .. angle )
+-- local index = math.abs(math.floor(angle/10+0.5))+1 -- +1 'coz LUA starts as idx 1
+-- local penalty = turn_cost_table[index]
+-- -- print ("index: " .. index .. ", bias: " .. penalty )
+-- return penalty
+-- 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")
+ local access = find_access_tag(node, access_tags_hierachy)
--flag node if it carries a traffic light
+ if node.tags:Holds("highway") then
+ if node.tags:Find("highway") == "traffic_signals" then
+ node.traffic_light = true;
+ end
+ end
- 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
+ -- parse access and barrier tags
+ if access and access ~= "" then
+ if access_tag_blacklist[access] then
+ node.bollard = true
+ end
+ elseif node.tags:Holds("barrier") then
+ local barrier = node.tags:Find("barrier")
+ if barrier_whitelist[barrier] then
+ return
+ else
+ node.bollard = true
+ end
+ end
end
-
function way_function (way)
-- we dont route over areas
- local area = way.tags:Find("area")
- if ignore_areas and ("yes" == area) then
- return 0
+ local is_area = way.tags:Holds("area")
+ if ignore_areas and is_area then
+ local area = way.tags:Find("area")
+ if "yes" == area then
+ return
+ end
end
-- check if oneway tag is unsupported
local oneway = way.tags:Find("oneway")
if "reversible" == oneway then
- return 0
+ return
+ end
+
+ local is_impassable = way.tags:Holds("impassable")
+ if is_impassable then
+ local impassable = way.tags:Find("impassable")
+ if "yes" == impassable then
+ return
+ end
+ end
+
+ local is_status = way.tags:Holds("status")
+ if is_status then
+ local status = way.tags:Find("status")
+ if "impassable" == status then
+ return
+ end
end
-- Check if we are allowed to access the way
- local access = Access.find_access_tag(way, access_tags_hierachy)
+ local access = find_access_tag(way, access_tags_hierachy)
if access_tag_blacklist[access] then
- return 0
+ return
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 = parse_maxspeed(way.tags:Find( "maxspeed:forward"))
- local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward"))
- local barrier = way.tags:Find("barrier")
- local cycleway = way.tags:Find("cycleway")
- local duration = way.tags:Find("duration")
- local service = way.tags:Find("service")
-
-
- -- 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
+ local route_speed = speed_profile[route]
+ if(route_speed and route_speed > 0) then
+ highway = route;
+ local duration = way.tags:Find("duration")
if durationIsValid(duration) then
- way.duration = math.max( parseDuration(duration), 1 );
+ way.duration = 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
+ way.speed = route_speed
+ end
+
+ -- leave early of this way is not accessible
+ if "" == highway then
+ return
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
+ if way.speed == -1 then
+ local highway_speed = speed_profile[highway]
+ local max_speed = parse_maxspeed( way.tags:Find("maxspeed") )
+ -- Set the avg speed on the way if it is accessible by road class
+ if highway_speed then
+ if max_speed > highway_speed then
+ way.speed = max_speed
+ -- max_speed = math.huge
+ else
+ way.speed = highway_speed
+ end
else
- if 0 == maxspeed then
- maxspeed = math.huge
+ -- Set the avg speed on ways that are marked accessible
+ if access_tag_whitelist[access] then
+ way.speed = speed_profile["default"]
end
- way.speed = math.min(speed_profile[highway], maxspeed)
end
+ if 0 == max_speed then
+ max_speed = math.huge
+ end
+ way.speed = min(way.speed, max_speed)
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)
+ if -1 == way.speed then
+ return
+ end
+
+ -- parse the remaining tags
+ local name = way.tags:Find("name")
+ local ref = way.tags:Find("ref")
+ local junction = way.tags:Find("junction")
+ -- local barrier = way.tags:Find("barrier")
+ -- local cycleway = way.tags:Find("cycleway")
+ local service = way.tags:Find("service")
+
+ -- 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
-- Set access restriction flag if access is allowed under certain restrictions only
@@ -177,43 +225,54 @@ function way_function (way)
-- 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
+ way.is_access_restricted = true
end
-- Set direction according to tags on way
way.direction = Way.bidirectional
- 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
+ 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" and oneway ~="no") or
+ (highway == "motorway" and oneway ~= "no") then
+ way.direction = Way.oneway
end
end
-- Override speed settings if explicit forward/backward maxspeeds are given
- if maxspeed_forward ~= nil and maxspeed_forward > 0 then
+ local maxspeed_forward = parse_maxspeed(way.tags:Find( "maxspeed:forward"))
+ local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward"))
+ if 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
+ if 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
+ if ignore_in_grid[highway] then
+ way.ignore_in_grid = true
+ end
+ way.type = 1
- way.type = 1
- return 1
+ -- scale speeds to get better avg driving times
+ way.speed = way.speed * speed_reduction
+ if maxspeed_backward > 0 then
+ way.backward_speed = way.backward_speed*speed_reduction
+ end
+ return
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
+ for v in vector.nodes do
+ node_function(v)
+ end
end
diff --git a/profiles/examples/postgis.lua b/profiles/examples/postgis.lua
new file mode 100644
index 0000000..b101a27
--- /dev/null
+++ b/profiles/examples/postgis.lua
@@ -0,0 +1,82 @@
+
+-- This example shows how to query external data stored in PostGIS when processing ways.
+
+-- This profile assumes that OSM data has been imported to PostGIS using imposm to a db
+-- with the name 'imposm', the default user and no password. It assumes areas with
+-- landusage=* was imported to the table osm_landusages, containting the columns type and area.
+-- Seee http://imposm.org/ for more info on imposm.
+-- Other tools for importing OSM data to PostGIS include osm2pgsql and osmosis.
+
+-- It uses the PostGIS function ST_DWithin() to find areas tagged with landuse=industrial
+-- that are within 100 meters of the way.
+-- It then slows down the routing depending on the number and size of the industrial area.
+
+-- The end result is that routes will tend to avoid industrial area. Passing through
+-- industrial areas is still possible, it's just slower, and thus avoided if a reasonable
+-- alternative is found.
+
+-- We use the osm id as the key when querying PostGIS. Be sure to add an index to the colunn
+-- containing the osm id (osm_id in this case), otherwise you will suffer form very
+-- bad performance. You should also have spatial indexes on the relevant gemoetry columns.
+
+-- More info about using SQL form LUA can be found at http://www.keplerproject.org/luasql/
+
+-- Happy routing!
+
+
+-- Open PostGIS connection
+lua_sql = require "luasql.postgres" -- we will connect to a postgresql database
+sql_env = assert( lua_sql.postgres() )
+sql_con = assert( sql_env:connect("imposm") ) -- you can add db user/password here if needed
+print("PostGIS connection opened")
+
+-- these settings are read directly by osrm
+take_minimum_of_speeds = true
+obey_oneway = true
+obey_bollards = true
+use_restrictions = true
+ignore_areas = true -- future feature
+traffic_signal_penalty = 7 -- seconds
+u_turn_penalty = 20
+
+-- nodes processing, called from OSRM
+function node_function(node)
+ return 1
+end
+
+-- ways processing, called from OSRM
+function way_function (way)
+ -- only route on ways with highway=*
+ local highway = way.tags:Find("highway")
+ if (not highway or highway=='') then
+ return 0
+ end
+
+ -- Query PostGIS for industrial areas close to the way, then group by way and sum the areas.
+ -- We take the square root of the area to get a estimate of the length of the side of the area,
+ -- and thus a rough guess of how far we might be travelling along the area.
+
+ local sql_query = " " ..
+ "SELECT SUM(SQRT(area.area)) AS val " ..
+ "FROM osm_ways way " ..
+ "LEFT JOIN osm_landusages area ON ST_DWithin(way.geometry, area.geometry, 100) " ..
+ "WHERE area.type IN ('industrial') AND way.osm_id=" .. way.id .. " " ..
+ "GROUP BY way.id"
+
+ local cursor = assert( sql_con:execute(sql_query) ) -- execute querty
+ local row = cursor:fetch( {}, "a" ) -- fetch first (and only) row
+ way.speed = 20.0 -- default speed
+ if row then
+ local val = tonumber(row.val) -- read 'val' from row
+ if val > 10 then
+ way.speed = way.speed / math.log10( val ) -- reduce speed by amount of industry close by
+ end
+ end
+ cursor:close() -- done with this query
+
+ -- set other required info for this way
+ way.name = way.tags:Find("name")
+ way.direction = Way.bidirectional
+ way.type = 1
+ return 1
+end
diff --git a/profiles/foot.lua b/profiles/foot.lua
index 6a15fb2..ae0dd60 100644
--- a/profiles/foot.lua
+++ b/profiles/foot.lua
@@ -1,193 +1,205 @@
-- Foot profile
--- Begin of globals
+require("lib/access")
-bollards_whitelist = { [""] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true}
+barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true}
access_tag_whitelist = { ["yes"] = true, ["foot"] = true, ["permissive"] = true, ["designated"] = true }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestery"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
-access_tags = { "foot" }
+access_tags_hierachy = { "foot", "access" }
service_tag_restricted = { ["parking_aisle"] = true }
ignore_in_grid = { ["ferry"] = true }
restriction_exception_tags = { "foot" }
-speed_profile = {
- ["primary"] = 5,
- ["primary_link"] = 5,
- ["secondary"] = 5,
- ["secondary_link"] = 5,
- ["tertiary"] = 5,
- ["tertiary_link"] = 5,
- ["unclassified"] = 5,
- ["residential"] = 5,
- ["road"] = 5,
- ["living_street"] = 5,
- ["service"] = 5,
- ["track"] = 5,
- ["path"] = 5,
- ["steps"] = 5,
- ["ferry"] = 5,
- ["pedestrian"] = 5,
- ["footway"] = 5,
- ["pier"] = 5,
- ["default"] = 5
+walking_speed = 5
+
+speeds = {
+ ["primary"] = walking_speed,
+ ["primary_link"] = walking_speed,
+ ["secondary"] = walking_speed,
+ ["secondary_link"] = walking_speed,
+ ["tertiary"] = walking_speed,
+ ["tertiary_link"] = walking_speed,
+ ["unclassified"] = walking_speed,
+ ["residential"] = walking_speed,
+ ["road"] = walking_speed,
+ ["living_street"] = walking_speed,
+ ["service"] = walking_speed,
+ ["track"] = walking_speed,
+ ["path"] = walking_speed,
+ ["steps"] = walking_speed,
+ ["pedestrian"] = walking_speed,
+ ["footway"] = walking_speed,
+ ["pier"] = walking_speed,
+ ["default"] = walking_speed
+}
+
+route_speeds = {
+ ["ferry"] = 5
}
+platform_speeds = {
+ ["platform"] = walking_speed
+}
+
+amenity_speeds = {
+ ["parking"] = walking_speed,
+ ["parking_entrance"] = walking_speed
+}
+
+man_made_speeds = {
+ ["pier"] = walking_speed
+}
+
+surface_speeds = {
+ ["fine_gravel"] = walking_speed*0.75,
+ ["gravel"] = walking_speed*0.75,
+ ["pebbelstone"] = walking_speed*0.75,
+ ["mud"] = walking_speed*0.5,
+ ["sand"] = walking_speed*0.5
+}
-take_minimum_of_speeds = true
-obey_oneway = true
-obey_bollards = false
-use_restrictions = false
-ignore_areas = true -- future feature
traffic_signal_penalty = 2
u_turn_penalty = 2
use_turn_restrictions = false
--- End of globals
function get_exceptions(vector)
- for i,v in ipairs(restriction_exception_tags) do
+ for i,v in ipairs(restriction_exception_tags) do
vector:Add(v)
end
end
function node_function (node)
- local barrier = node.tags:Find ("barrier")
- local access = node.tags:Find ("access")
- 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
-
- if obey_bollards then
- --flag node as unpassable if it black listed as unpassable
- if access_tag_blacklist[barrier] then
- node.bollard = true;
- end
-
- --reverse the previous flag if there is an access tag specifying entrance
- if node.bollard and not bollards_whitelist[barrier] and not access_tag_whitelist[barrier] then
- node.bollard = false;
- end
- end
- return 1
+ 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
+ else
+ node.bollard = false
+ end
+ elseif barrier and barrier ~= "" then
+ if barrier_whitelist[barrier] then
+ node.bollard = false
+ else
+ node.bollard = true
+ end
+ end
+
+ return 1
end
function way_function (way)
+ -- initial routability check, filters out buildings, boundaries, etc
+ local highway = way.tags:Find("highway")
+ local route = way.tags:Find("route")
+ local man_made = way.tags:Find("man_made")
+ local railway = way.tags:Find("railway")
+ local amenity = way.tags:Find("amenity")
+ local public_transport = way.tags:Find("public_transport")
+ if (not highway or highway == '') and
+ (not route or route == '') and
+ (not railway or railway=='') and
+ (not amenity or amenity=='') and
+ (not man_made or man_made=='') and
+ (not public_transport or public_transport=='')
+ then
+ return 0
+ end
- -- 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 = parseMaxspeed(way.tags:Find ( "maxspeed") )
- local man_made = way.tags:Find("man_made")
- local barrier = way.tags:Find("barrier")
- local oneway = way.tags:Find("oneway")
- local onewayClass = way.tags:Find("oneway:foot")
- local duration = way.tags:Find("duration")
- local service = way.tags:Find("service")
- local area = way.tags:Find("area")
- local access = way.tags:Find("access")
-
- -- Second parse the way according to these properties
+ -- don't route on ways that are still under construction
+ if highway=='construction' then
+ return 0
+ end
- if ignore_areas and ("yes" == area) then
+ -- access
+ local access = Access.find_access_tag(way, access_tags_hierachy)
+ if access_tag_blacklist[access] then
return 0
- end
-
- -- Check if we are allowed to access the way
- if access_tag_blacklist[access] ~=nil and access_tag_blacklist[access] then
- return 0;
end
-
- -- Check if our vehicle types are forbidden
- for i,v in ipairs(access_tags) do
- local mode_value = way.tags:Find(v)
- if nil ~= mode_value and "no" == mode_value then
- return 0;
- end
- end
-
-
- -- Set the name that will be used for instructions
- if "" ~= ref then
- way.name = ref
+
+ local name = way.tags:Find("name")
+ local ref = way.tags:Find("ref")
+ local junction = way.tags:Find("junction")
+ local onewayClass = way.tags:Find("oneway:foot")
+ local duration = way.tags:Find("duration")
+ 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 and "" ~= name then
+ way.name = name .. ' / ' .. ref
+ elseif "" ~= ref then
+ way.name = ref
elseif "" ~= name then
- way.name = name
+ way.name = name
+ else
+ way.name = "{highway:"..highway.."}" -- if no name exists, use way type
+ -- this encoding scheme is excepted to be a temporary solution
end
-
+
+ -- roundabouts
if "roundabout" == junction then
way.roundabout = true;
end
- -- Handling ferries and piers
-
- if (speed_profile[route] ~= nil and speed_profile[route] > 0) or
- (speed_profile[man_made] ~= nil and speed_profile[man_made] > 0)
- then
- if durationIsValid(duration) then
- way.speed = parseDuration(duration) / math.max(1, numberOfNodesInWay-1);
- way.is_duration_set = true;
- end
- way.direction = Way.bidirectional;
- if speed_profile[route] ~= nil then
- highway = route;
- elseif speed_profile[man_made] ~= nil then
- highway = man_made;
- end
- if not way.is_duration_set 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
- way.speed = speed_profile[highway]
- end
-
- -- Set the avg speed on ways that are marked accessible
- if access_tag_whitelist[access] and way.speed == -1 then
- if (0 < maxspeed and not take_minimum_of_speeds) or maxspeed == 0 then
- maxspeed = math.huge
- end
- way.speed = math.min(speed_profile["default"], maxspeed)
+ -- speed
+ if route_speeds[route] then
+ -- ferries (doesn't cover routes tagged using relations)
+ way.direction = Way.bidirectional
+ way.ignore_in_grid = true
+ if durationIsValid(duration) then
+ way.duration = math.max( 1, parseDuration(duration) )
+ else
+ way.speed = route_speeds[route]
+ end
+ elseif railway and platform_speeds[railway] then
+ -- railway platforms (old tagging scheme)
+ way.speed = platform_speeds[railway]
+ elseif platform_speeds[public_transport] then
+ -- public_transport platforms (new tagging platform)
+ way.speed = platform_speeds[public_transport]
+ elseif amenity and amenity_speeds[amenity] then
+ -- parking areas
+ way.speed = amenity_speeds[amenity]
+ elseif speeds[highway] then
+ -- regular ways
+ way.speed = speeds[highway]
+ elseif access and access_tag_whitelist[access] then
+ -- unknown way, but valid access tag
+ way.speed = walking_speed
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
+ -- oneway
+ if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
+ way.direction = Way.oneway
+ elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
+ way.direction = Way.bidirectional
+ elseif onewayClass == "-1" then
+ way.direction = Way.opposite
+ else
+ way.direction = Way.bidirectional
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 onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then
- way.direction = Way.oneway
- elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then
- way.direction = Way.bidirectional
- elseif onewayClass == "-1" then
- way.direction = Way.opposite
- else
- way.direction = Way.bidirectional
- end
- else
- way.direction = Way.bidirectional
+ -- 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
-
- -- 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
+ return 1
end
diff --git a/profiles/testbot.lua b/profiles/testbot.lua
index f934fea..66d6599 100644
--- a/profiles/testbot.lua
+++ b/profiles/testbot.lua
@@ -2,106 +2,111 @@
-- Moves at fixed, well-known speeds, practical for testing speed and travel times:
--- Primary road: 36km/h = 36000m/3600s = 100m/10s
--- Secondary road: 18km/h = 18000m/3600s = 100m/20s
--- Tertiary road: 12km/h = 12000m/3600s = 100m/30s
-
-speed_profile = {
- ["primary"] = 36,
- ["secondary"] = 18,
- ["tertiary"] = 12,
- ["default"] = 24
+-- Primary road: 36km/h = 36000m/3600s = 100m/10s
+-- Secondary road: 18km/h = 18000m/3600s = 100m/20s
+-- Tertiary road: 12km/h = 12000m/3600s = 100m/30s
+
+speed_profile = {
+ ["primary"] = 36,
+ ["secondary"] = 18,
+ ["tertiary"] = 12,
+ ["default"] = 24
}
-- these settings are read directly by osrm
-take_minimum_of_speeds = true
-obey_oneway = true
-obey_bollards = true
-use_restrictions = true
-ignore_areas = true -- future feature
-traffic_signal_penalty = 7 -- seconds
-u_turn_penalty = 20
+take_minimum_of_speeds = true
+obey_oneway = true
+obey_barriers = true
+use_turn_restrictions = true
+ignore_areas = true -- future feature
+traffic_signal_penalty = 7 -- seconds
+u_turn_penalty = 20
function limit_speed(speed, limits)
- -- don't use ipairs(), since it stops at the first nil value
- for i=1, #limits do
- limit = limits[i]
- if limit ~= nil and limit > 0 then
- if limit < speed then
- return limit -- stop at first speedlimit that's smaller than speed
- end
- end
+ -- don't use ipairs(), since it stops at the first nil value
+ for i=1, #limits do
+ limit = limits[i]
+ if limit ~= nil and limit > 0 then
+ if limit < speed then
+ return limit -- stop at first speedlimit that's smaller than speed
+ end
end
- return speed
+ end
+ return speed
end
function node_function (node)
- local traffic_signal = node.tags:Find("highway")
+ local traffic_signal = node.tags:Find("highway")
- if traffic_signal == "traffic_signals" then
- node.traffic_light = true;
- -- TODO: a way to set the penalty value
- end
- return 1
+ if traffic_signal == "traffic_signals" then
+ node.traffic_light = true;
+ -- TODO: a way to set the penalty value
+ end
+ return 1
end
function way_function (way)
- local highway = way.tags:Find("highway")
- local name = way.tags:Find("name")
- local oneway = way.tags:Find("oneway")
- local route = way.tags:Find("route")
- local duration = way.tags:Find("duration")
- local maxspeed = tonumber(way.tags:Find ( "maxspeed"))
- local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward"))
- local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward"))
-
- way.name = name
-
- if route ~= nil and durationIsValid(duration) then
- way.duration = math.max( 1, parseDuration(duration) )
- else
- local speed_forw = speed_profile[highway] or speed_profile['default']
- local speed_back = speed_forw
-
- if highway == "river" then
- local temp_speed = speed_forw;
- speed_forw = temp_speed*1.5
- speed_back = temp_speed/1.5
- end
-
- if maxspeed_forward ~= nil and maxspeed_forward > 0 then
- speed_forw = maxspeed_forward
- else
- if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then
- speed_forw = maxspeed
- end
- end
-
- if maxspeed_backward ~= nil and maxspeed_backward > 0 then
- speed_back = maxspeed_backward
- else
- if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then
- speed_back = maxspeed
- end
- end
-
- way.speed = speed_forw
- if speed_back ~= way_forw then
- way.backward_speed = speed_back
- end
- end
-
- if oneway == "no" or oneway == "0" or oneway == "false" then
- way.direction = Way.bidirectional
- elseif oneway == "-1" then
- way.direction = Way.opposite
- elseif oneway == "yes" or oneway == "1" or oneway == "true" then
- way.direction = Way.oneway
- else
- way.direction = Way.bidirectional
- end
-
- way.type = 1
- return 1
+ local highway = way.tags:Find("highway")
+ local name = way.tags:Find("name")
+ local oneway = way.tags:Find("oneway")
+ local route = way.tags:Find("route")
+ local duration = way.tags:Find("duration")
+ local maxspeed = tonumber(way.tags:Find ( "maxspeed"))
+ local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward"))
+ local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward"))
+ local junction = way.tags:Find("junction")
+
+ way.name = name
+
+ if route ~= nil and durationIsValid(duration) then
+ way.duration = math.max( 1, parseDuration(duration) )
+ else
+ local speed_forw = speed_profile[highway] or speed_profile['default']
+ local speed_back = speed_forw
+
+ if highway == "river" then
+ local temp_speed = speed_forw;
+ speed_forw = temp_speed*1.5
+ speed_back = temp_speed/1.5
+ end
+
+ if maxspeed_forward ~= nil and maxspeed_forward > 0 then
+ speed_forw = maxspeed_forward
+ else
+ if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then
+ speed_forw = maxspeed
+ end
+ end
+
+ if maxspeed_backward ~= nil and maxspeed_backward > 0 then
+ speed_back = maxspeed_backward
+ else
+ if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then
+ speed_back = maxspeed
+ end
+ end
+
+ way.speed = speed_forw
+ if speed_back ~= way_forw then
+ way.backward_speed = speed_back
+ end
+ end
+
+ if oneway == "no" or oneway == "0" or oneway == "false" then
+ way.direction = Way.bidirectional
+ elseif oneway == "-1" then
+ way.direction = Way.opposite
+ elseif oneway == "yes" or oneway == "1" or oneway == "true" or junction == "roundabout" then
+ way.direction = Way.oneway
+ else
+ way.direction = Way.bidirectional
+ end
+
+ if junction == 'roundabout' then
+ way.roundabout = true
+ end
+
+ way.type = 1
+ return 1
end
diff --git a/routed.cpp b/routed.cpp
index e097bd7..adf2e2d 100644
--- a/routed.cpp
+++ b/routed.cpp
@@ -1,90 +1,127 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
- */
-#ifdef __linux__
-#include <sys/mman.h>
-#endif
-#include <iostream>
-#include <signal.h>
-#include <boost/bind.hpp>
-#include <boost/date_time.hpp>
-#include <boost/thread.hpp>
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-#include "Server/DataStructures/QueryObjectsStorage.h"
-#include "Server/ServerConfiguration.h"
-#include "Server/ServerFactory.h"
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-#include "Plugins/HelloWorldPlugin.h"
-#include "Plugins/LocatePlugin.h"
-#include "Plugins/NearestPlugin.h"
-#include "Plugins/TimestampPlugin.h"
-#include "Plugins/ViaRoutePlugin.h"
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#include "Util/InputFileUtil.h"
-#include "Util/OpenMPWrapper.h"
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef _WIN32
-#include "Util/LinuxStackTrace.h"
+*/
+
+#include "Library/OSRM.h"
+#include "Server/ServerFactory.h"
+#include "Util/GitDescription.h"
+#include "Util/ProgramOptions.h"
+#include "Util/SimpleLogger.h"
+#include "Util/FingerPrint.h"
+
+#ifdef __linux__
+#include <sys/mman.h>
#endif
-typedef http::RequestHandler RequestHandler;
+#include <cstdlib>
+
+#include <signal.h>
+
+#include <chrono>
+#include <functional>
+#include <future>
+#include <iostream>
+#include <thread>
#ifdef _WIN32
boost::function0<void> console_ctrl_function;
BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
{
- switch (ctrl_type)
- {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- case CTRL_CLOSE_EVENT:
- case CTRL_SHUTDOWN_EVENT:
- console_ctrl_function();
- return TRUE;
- default:
- return FALSE;
- }
+ switch (ctrl_type)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ case CTRL_CLOSE_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ console_ctrl_function();
+ return TRUE;
+ default:
+ return FALSE;
+ }
}
#endif
-int main (int argc, char * argv[]) {
-#ifdef __linux__
- if(!mlockall(MCL_CURRENT | MCL_FUTURE))
- WARN("Process " << argv[0] << "could not be locked to RAM");
-#endif
-#ifndef _WIN32
+int main(int argc, const char *argv[])
+{
+ try
+ {
+ LogPolicy::GetInstance().Unmute();
+
+ bool use_shared_memory = false, trial_run = false;
+ std::string ip_address;
+ int ip_port, requested_thread_num;
+
+ ServerPaths server_paths;
+
+ const unsigned init_result = GenerateServerProgramOptions(argc,
+ argv,
+ server_paths,
+ ip_address,
+ ip_port,
+ requested_thread_num,
+ use_shared_memory,
+ trial_run);
+ if (init_result == INIT_OK_DO_NOT_START_ENGINE)
+ {
+ return 0;
+ }
+ if (init_result == INIT_FAILED)
+ {
+ return 1;
+ }
- installCrashHandler(argv[0]);
+#ifdef __linux__
+ const int lock_flags = MCL_CURRENT | MCL_FUTURE;
+ if (-1 == mlockall(lock_flags))
+ {
+ SimpleLogger().Write(logWARNING) << argv[0] << " could not be locked to RAM";
+ }
#endif
+ SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", "
+ << "compiled at " << __DATE__ << ", " __TIME__;
- // Bug - testing not necessary. testDataFiles also tries to open the first
- // argv, which is the name of exec file
- //if(testDataFiles(argc, argv)==false) {
- //std::cerr << "[error] at least one data file name seems to be bogus!" << std::endl;
- //exit(-1);
- //}
-
- try {
- std::cout << std::endl << "[server] starting up engines, saved at " << __TIMESTAMP__ << std::endl;
-
+ if (use_shared_memory)
+ {
+ SimpleLogger().Write(logDEBUG) << "Loading from shared memory";
+ }
+ else
+ {
+ SimpleLogger().Write() << "HSGR file:\t" << server_paths["hsgrdata"];
+ SimpleLogger().Write(logDEBUG) << "Nodes file:\t" << server_paths["nodesdata"];
+ SimpleLogger().Write(logDEBUG) << "Edges file:\t" << server_paths["edgesdata"];
+ SimpleLogger().Write(logDEBUG) << "Geometry file:\t" << server_paths["geometries"];
+ SimpleLogger().Write(logDEBUG) << "RAM file:\t" << server_paths["ramindex"];
+ SimpleLogger().Write(logDEBUG) << "Index file:\t" << server_paths["fileindex"];
+ SimpleLogger().Write(logDEBUG) << "Names file:\t" << server_paths["namesdata"];
+ SimpleLogger().Write(logDEBUG) << "Timestamp file:\t" << server_paths["timestamp"];
+ SimpleLogger().Write(logDEBUG) << "Threads:\t" << requested_thread_num;
+ SimpleLogger().Write(logDEBUG) << "IP address:\t" << ip_address;
+ SimpleLogger().Write(logDEBUG) << "IP port:\t" << ip_port;
+ }
#ifndef _WIN32
int sig = 0;
sigset_t new_mask;
@@ -93,63 +130,64 @@ int main (int argc, char * argv[]) {
pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
#endif
- ServerConfiguration serverConfig((argc > 1 ? argv[1] : "server.ini"));
- Server * s = ServerFactory::CreateServer(serverConfig);
- RequestHandler & h = s->GetRequestHandlerPtr();
+ OSRM osrm_lib(server_paths, use_shared_memory);
+ Server *routing_server =
+ ServerFactory::CreateServer(ip_address, ip_port, requested_thread_num);
- QueryObjectsStorage * objects = new QueryObjectsStorage(serverConfig.GetParameter("hsgrData"),
- serverConfig.GetParameter("ramIndex"),
- serverConfig.GetParameter("fileIndex"),
- serverConfig.GetParameter("nodesData"),
- serverConfig.GetParameter("edgesData"),
- serverConfig.GetParameter("namesData"),
- serverConfig.GetParameter("timestamp")
- );
+ routing_server->GetRequestHandlerPtr().RegisterRoutingMachine(&osrm_lib);
- h.RegisterPlugin(new HelloWorldPlugin());
-
- h.RegisterPlugin(new LocatePlugin(objects));
-
- h.RegisterPlugin(new NearestPlugin(objects));
-
- h.RegisterPlugin(new TimestampPlugin(objects));
-
- h.RegisterPlugin(new ViaRoutePlugin(objects));
-
- boost::thread t(boost::bind(&Server::Run, s));
+ if (trial_run)
+ {
+ SimpleLogger().Write() << "trial run, quitting after successful initialization";
+ }
+ else
+ {
+ std::packaged_task<int()> server_task([&]()->int{ routing_server->Run(); return 0; });
+ auto future = server_task.get_future();
+ std::thread server_thread(std::move(server_task));
#ifndef _WIN32
- sigset_t wait_mask;
- pthread_sigmask(SIG_SETMASK, &old_mask, 0);
- sigemptyset(&wait_mask);
- sigaddset(&wait_mask, SIGINT);
- sigaddset(&wait_mask, SIGQUIT);
- sigaddset(&wait_mask, SIGTERM);
- pthread_sigmask(SIG_BLOCK, &wait_mask, 0);
- std::cout << "[server] running and waiting for requests" << std::endl;
- sigwait(&wait_mask, &sig);
+ sigset_t wait_mask;
+ pthread_sigmask(SIG_SETMASK, &old_mask, 0);
+ sigemptyset(&wait_mask);
+ sigaddset(&wait_mask, SIGINT);
+ sigaddset(&wait_mask, SIGQUIT);
+ sigaddset(&wait_mask, SIGTERM);
+ pthread_sigmask(SIG_BLOCK, &wait_mask, 0);
+ SimpleLogger().Write() << "running and waiting for requests";
+ sigwait(&wait_mask, &sig);
#else
- // Set console control handler to allow server to be stopped.
- console_ctrl_function = boost::bind(&Server::Stop, s);
- SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
- std::cout << "[server] running and waiting for requests" << std::endl;
- s->Run();
+ // Set console control handler to allow server to be stopped.
+ console_ctrl_function = std::bind(&Server::Stop, routing_server);
+ SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
+ SimpleLogger().Write() << "running and waiting for requests";
+ routing_server->Run();
#endif
-
- std::cout << "[server] initiating shutdown" << std::endl;
- s->Stop();
- std::cout << "[server] stopping threads" << std::endl;
-
- if(!t.timed_join(boost::posix_time::seconds(2))) {
-// INFO("Threads did not finish within 2 seconds. Hard abort!");
+ SimpleLogger().Write() << "initiating shutdown";
+ routing_server->Stop();
+ SimpleLogger().Write() << "stopping threads";
+
+ auto status = future.wait_for(std::chrono::seconds(2));
+
+ if (status != std::future_status::ready)
+ {
+ SimpleLogger().Write(logWARNING) << "Didn't exit within 2 seconds. Hard abort!";
+ server_task.reset(); // just kill it
+ }
+ else
+ {
+ server_thread.join();
+ }
}
- std::cout << "[server] freeing objects" << std::endl;
- delete s;
- delete objects;
- std::cout << "[server] shutdown completed" << std::endl;
- } catch (std::exception& e) {
- std::cerr << "[fatal error] exception: " << e.what() << std::endl;
+ SimpleLogger().Write() << "freeing objects";
+ delete routing_server;
+ SimpleLogger().Write() << "shutdown completed";
+ }
+ catch (const std::exception &e)
+ {
+ SimpleLogger().Write(logWARNING) << "exception: " << e.what();
+ return 1;
}
#ifdef __linux__
munlockall();
diff --git a/server.ini b/server.ini
deleted file mode 100644
index 3fe844a..0000000
--- a/server.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-Threads = 8
-IP = 0.0.0.0
-Port = 5000
-
-hsgrData=/opt/osm/berlin.osrm.hsgr
-nodesData=/opt/osm/berlin.osrm.nodes
-edgesData=/opt/osm/berlin.osrm.edges
-ramIndex=/opt/osm/berlin.osrm.ramIndex
-fileIndex=/opt/osm/berlin.osrm.fileIndex
-namesData=/opt/osm/berlin.osrm.names
-timestamp=/opt/osm/berlin.osrm.timestamp
diff --git a/test/contractor.ini b/test/contractor.ini
deleted file mode 100644
index 4da33c7..0000000
--- a/test/contractor.ini
+++ /dev/null
@@ -1 +0,0 @@
-Threads = 4
diff --git a/test/extractor.ini b/test/extractor.ini
deleted file mode 100644
index eca8b17..0000000
--- a/test/extractor.ini
+++ /dev/null
@@ -1 +0,0 @@
-Memory = 1
diff --git a/typedefs.h b/typedefs.h
index a962598..ff1d2a1 100644
--- a/typedefs.h
+++ b/typedefs.h
@@ -1,68 +1,50 @@
/*
- open source routing machine
- Copyright (C) Dennis Luxen, 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.
+Copyright (c) 2013, Project OSRM, Dennis Luxen, others
+All rights reserved.
-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.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
-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.
- */
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
-#ifndef TYPEDEFS_H_
-#define TYPEDEFS_H_
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <cmath>
-#include <climits>
-#include <cstdlib>
+*/
-// To fix long and long long woes
-#include <boost/integer.hpp>
-#include <boost/integer_traits.hpp>
+#ifndef TYPEDEFS_H
+#define TYPEDEFS_H
-#ifdef __APPLE__
-#include <signal.h>
-#endif
-
-#include <iostream>
-
-#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)
-#else
-#define DEBUG(x) do {std::cout << "[d " << __FILE__ << ":" << __LINE__ << "] " << x << std::endl;} while(0);
-#endif
+#include <limits>
+// Necessary workaround for Windows as VS doesn't implement C99
+#ifdef _MSC_VER
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
-
-// Necessary workaround for Windows as VS doesn't implement C99
-#ifdef _MSC_VER
-template<typename digitT>
-digitT round(digitT x) {
- return std::floor(x + 0.5);
-}
+#define constexpr const static
#endif
-
typedef unsigned int NodeID;
typedef unsigned int EdgeID;
-typedef unsigned int EdgeWeight;
+typedef int EdgeWeight;
-static const NodeID SPECIAL_NODEID = boost::integer_traits<uint32_t>::const_max;
-static const EdgeID SPECIAL_EDGEID = boost::integer_traits<uint32_t>::const_max;
+constexpr NodeID SPECIAL_NODEID = std::numeric_limits<unsigned>::max();
+constexpr EdgeID SPECIAL_EDGEID = std::numeric_limits<unsigned>::max();
+constexpr unsigned INVALID_NAMEID = std::numeric_limits<unsigned>::max();
+constexpr EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<int>::max();
-#endif /* TYPEDEFS_H_ */
+#endif /* TYPEDEFS_H */
diff --git a/win/createHierarchy.vcproj b/win/createHierarchy.vcproj
deleted file mode 100644
index 428c56c..0000000
--- a/win/createHierarchy.vcproj
+++ /dev/null
@@ -1,459 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="createHierarchy"
- ProjectGUID="{38C3EEAC-032B-4BEA-BECB-C694A47AA7E2}"
- RootNamespace="createHierarchy"
- Keyword="Win32Proj"
- TargetFrameworkVersion="196613"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="$(SolutionDir)bin-debug"
- IntermediateDirectory="$(SolutionDir)bin-debug"
- ConfigurationType="1"
- InheritedPropertySheets=".\osrm.vsprops"
- CharacterSet="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_RTLDLL -DBOOST_LIB_DIAGNOSTIC -DSTXXL_BOOST_TIMESTAMP -DSTXXL_BOOST_CONFIG -DSTXXL_BOOST_FILESYSTEM -DSTXXL_BOOST_THREADS -DSTXXL_BOOST_RANDOM /EHsc /EHs /wd4820 /wd4217 /wd4668 /wd4619 /wd4625 /wd4626 /wd4355 /wd4996 -D_SCL_SECURE_NO_DEPRECATE /F 16777216 /nologo "
- Optimization="0"
- AdditionalIncludeDirectories=""$(BoostPath)";"$(StxxlPath)\include";"$(LibXml2Path)\include";"$(IconvPath)\include";"$(SparsehashPath)\src\";"$(SparsehashPath)\src\windows";"$(Bzip2Path)\include";"$(ZlibPath)\include";..\;"$(ProtobufPath)\include";"$(SolutionDir)""
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- OpenMP="true"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- DebugInformationFormat="4"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/STACK:16777216 /NOLOGO /OPT:REF"
- AdditionalDependencies="libbz2.lib libxml2.lib zlibd.lib libprotobuf-debug.lib libstxxl-debug.lib"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""$(BoostPath)\lib";"$(StxxlPath)\lib";"$(LibXml2Path)\lib";"$(IconvPath)\lib";"$(Bzip2Path)\lib";"$(ZlibPath)\lib";"$(ProtobufPath)\lib""
- GenerateDebugInformation="true"
- SubSystem="1"
- RandomizedBaseAddress="1"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="xcopy "$(SolutionDir)..\contractor.ini" "$(OutDir)\" /f /y"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="$(SolutionDir)bin"
- IntermediateDirectory="$(SolutionDir)bin"
- ConfigurationType="1"
- InheritedPropertySheets=".\osrm.vsprops"
- CharacterSet="1"
- WholeProgramOptimization="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_RTLDLL -DBOOST_LIB_DIAGNOSTIC -DSTXXL_BOOST_TIMESTAMP -DSTXXL_BOOST_CONFIG -DSTXXL_BOOST_FILESYSTEM -DSTXXL_BOOST_THREADS -DSTXXL_BOOST_RANDOM /EHsc /EHs /wd4820 /wd4217 /wd4668 /wd4619 /wd4625 /wd4626 /wd4355 /wd4996 -D_SCL_SECURE_NO_DEPRECATE /F 16777216 /nologo "
- Optimization="2"
- EnableIntrinsicFunctions="true"
- AdditionalIncludeDirectories=""$(BoostPath)";"$(StxxlPath)\include";"$(LibXml2Path)\include";"$(IconvPath)\include";"$(SparsehashPath)\src\";"$(SparsehashPath)\src\windows";"$(Bzip2Path)\include";"$(ZlibPath)\include";..\;"$(ProtobufPath)\include""
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
- RuntimeLibrary="2"
- EnableFunctionLevelLinking="true"
- OpenMP="true"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- DebugInformationFormat="0"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/STACK:16777216 /NOLOGO /OPT:REF"
- AdditionalDependencies="libbz2.lib libxml2.lib zlib.lib libprotobuf.lib libstxxl.lib"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""$(BoostPath)\lib";"$(StxxlPath)\lib";"$(LibXml2Path)\lib";"$(IconvPath)\lib";"$(Bzip2Path)\lib";"$(ZlibPath)\lib";"$(ProtobufPath)\lib""
- GenerateDebugInformation="false"
- SubSystem="1"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- RandomizedBaseAddress="1"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="xcopy "$(SolutionDir)..\contractor.ini" "$(OutDir)\" /f /y"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
- >
- <File
- RelativePath="..\createHierarchy.cpp"
- >
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
- >
- <File
- RelativePath="getopt.h"
- >
- </File>
- <File
- RelativePath="..\typedefs.h"
- >
- </File>
- <File
- RelativePath="unistd.h"
- >
- </File>
- <Filter
- Name="Contractor"
- >
- <File
- RelativePath="..\Contractor\ContractionCleanup.h"
- >
- </File>
- <File
- RelativePath="..\Contractor\Contractor.h"
- >
- </File>
- </Filter>
- <Filter
- Name="DataStructures"
- >
- <File
- RelativePath="..\DataStructures\BaseParser.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\BinaryHeap.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\DynamicGraph.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ExtractorCallBacks.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ExtractorStructs.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\GridEdge.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\HashTable.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ImportEdge.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\InputReaderFactory.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\LevelInformation.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\LRUCache.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\NNGrid.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\NodeCoords.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\NodeInformationHelpDesk.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\PBFParser.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\Percent.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\PhantomNodes.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\PolylineCompressor.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\SearchEngine.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\StaticGraph.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\StaticKDTree.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\Util.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\XMLParser.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Plugins"
- >
- <File
- RelativePath="..\Plugins\BaseDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\BasePlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\GPXDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\HelloWorldPlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\JSONDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\KMLDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\LocatePlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\NearestPlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\ObjectForPluginStruct.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\PluginMapFactory.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\RawRouteData.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\RouteParameters.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\RoutePlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\ViaRoutePlugin.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Server"
- >
- <File
- RelativePath="..\Server\BasicDatastructures.h"
- >
- </File>
- <File
- RelativePath="..\Server\Connection.h"
- >
- </File>
- <File
- RelativePath="..\Server\RequestHandler.h"
- >
- </File>
- <File
- RelativePath="..\Server\RequestParser.h"
- >
- </File>
- <File
- RelativePath="..\Server\Server.h"
- >
- </File>
- <File
- RelativePath="..\Server\ServerConfiguration.h"
- >
- </File>
- <File
- RelativePath="..\Server\ServerFactory.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Util"
- >
- <File
- RelativePath="..\Util\BaseConfiguration.h"
- >
- </File>
- <File
- RelativePath="..\Util\GraphLoader.h"
- >
- </File>
- <File
- RelativePath="..\Util\InputFileUtil.h"
- >
- </File>
- <File
- RelativePath="..\Util\LinuxStackTrace.h"
- >
- </File>
- <File
- RelativePath="..\Util\MachineInfo.h"
- >
- </File>
- <File
- RelativePath="..\Util\StringUtil.h"
- >
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
- >
- </Filter>
- <File
- RelativePath="..\DataStructures\pbf-proto\fileformat.proto"
- >
- </File>
- <File
- RelativePath="..\DataStructures\pbf-proto\osmformat.proto"
- >
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/win/extractor.vcproj b/win/extractor.vcproj
deleted file mode 100644
index 2821f87..0000000
--- a/win/extractor.vcproj
+++ /dev/null
@@ -1,532 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="extractor"
- ProjectGUID="{F630F025-637A-43DF-9258-2860AE9E6740}"
- RootNamespace="extractor"
- Keyword="Win32Proj"
- TargetFrameworkVersion="196613"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="$(SolutionDir)bin-debug"
- IntermediateDirectory="$(SolutionDir)bin-debug"
- ConfigurationType="1"
- InheritedPropertySheets=".\osrm.vsprops"
- CharacterSet="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- CommandLine=""
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_RTLDLL -DBOOST_LIB_DIAGNOSTIC -DSTXXL_BOOST_TIMESTAMP -DSTXXL_BOOST_CONFIG -DSTXXL_BOOST_FILESYSTEM -DSTXXL_BOOST_THREADS -DSTXXL_BOOST_RANDOM /EHsc /EHs /wd4820 /wd4217 /wd4668 /wd4619 /wd4625 /wd4626 /wd4355 /wd4996 -D_SCL_SECURE_NO_DEPRECATE /F 16777216 /nologo "
- Optimization="0"
- AdditionalIncludeDirectories=""$(BoostPath)";"$(StxxlPath)\include";"$(LibXml2Path)\include";"$(IconvPath)\include";"$(SparsehashPath)\src\";"$(SparsehashPath)\src\windows";"$(Bzip2Path)\include";"$(ZlibPath)\include";..\;"$(ProtobufPath)\include";"$(SolutionDir)""
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- OpenMP="true"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- DebugInformationFormat="4"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/STACK:16777216 /NOLOGO /OPT:REF"
- AdditionalDependencies="libbz2.lib libxml2.lib zlibd.lib libprotobuf-debug.lib libstxxl-debug.lib"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""$(BoostPath)\lib";"$(StxxlPath)\lib";"$(LibXml2Path)\lib";"$(IconvPath)\lib";"$(Bzip2Path)\lib";"$(ZlibPath)\lib";"$(ProtobufPath)\lib""
- GenerateDebugInformation="true"
- SubSystem="1"
- RandomizedBaseAddress="1"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="xcopy "$(SolutionDir)..\.stxxl" "$(OutDir)\" /f /y
xcopy "$(SolutionDir)..\extractor.ini" "$(OutDir)\" /f /y
xcopy "$(SolutionDir)..\speedprofile.ini" "$(OutDir)\" /f /y
xcopy "$(Bzip2Path)\bin\libbz2.dll" "$(OutDir)\" /f /y
"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="$(SolutionDir)bin"
- IntermediateDirectory="$(SolutionDir)bin"
- ConfigurationType="1"
- InheritedPropertySheets=".\osrm.vsprops"
- CharacterSet="1"
- WholeProgramOptimization="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_RTLDLL -DBOOST_LIB_DIAGNOSTIC -DSTXXL_BOOST_TIMESTAMP -DSTXXL_BOOST_CONFIG -DSTXXL_BOOST_FILESYSTEM -DSTXXL_BOOST_THREADS -DSTXXL_BOOST_RANDOM /EHsc /EHs /wd4820 /wd4217 /wd4668 /wd4619 /wd4625 /wd4626 /wd4355 /wd4996 -D_SCL_SECURE_NO_DEPRECATE /F 16777216 /nologo "
- Optimization="2"
- EnableIntrinsicFunctions="true"
- AdditionalIncludeDirectories=""$(BoostPath)";"$(StxxlPath)\include";"$(LibXml2Path)\include";"$(IconvPath)\include";"$(SparsehashPath)\src\";"$(SparsehashPath)\src\windows";"$(Bzip2Path)\include";"$(ZlibPath)\include";..\;"$(ProtobufPath)\include""
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
- RuntimeLibrary="2"
- EnableFunctionLevelLinking="true"
- OpenMP="true"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- DebugInformationFormat="0"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/STACK:16777216 /NOLOGO /OPT:REF"
- AdditionalDependencies="libbz2.lib libxml2.lib zlib.lib libprotobuf.lib libstxxl.lib"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""$(BoostPath)\lib";"$(StxxlPath)\lib";"$(LibXml2Path)\lib";"$(IconvPath)\lib";"$(Bzip2Path)\lib";"$(ZlibPath)\lib";"$(ProtobufPath)\lib""
- GenerateDebugInformation="false"
- SubSystem="1"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- RandomizedBaseAddress="1"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="xcopy "$(SolutionDir)..\.stxxl" "$(OutDir)\" /f /y
xcopy "$(SolutionDir)..\extractor.ini" "$(OutDir)\" /f /y
xcopy "$(SolutionDir)..\speedprofile.ini" "$(OutDir)\" /f /y
xcopy "$(Bzip2Path)\bin\libbz2.dll" "$(OutDir)\" /f /y
"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
- >
- <File
- RelativePath="..\extractor.cpp"
- >
- </File>
- <Filter
- Name="DataStructures"
- >
- <Filter
- Name="pbf-proto"
- >
- <File
- RelativePath="..\DataStructures\pbf-proto\fileformat.pb.cc"
- >
- </File>
- <File
- RelativePath="..\DataStructures\pbf-proto\osmformat.pb.cc"
- >
- </File>
- </Filter>
- </Filter>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
- >
- <File
- RelativePath="getopt.h"
- >
- </File>
- <File
- RelativePath="..\typedefs.h"
- >
- </File>
- <File
- RelativePath="unistd.h"
- >
- </File>
- <Filter
- Name="Contractor"
- >
- <File
- RelativePath="..\Contractor\ContractionCleanup.h"
- >
- </File>
- <File
- RelativePath="..\Contractor\Contractor.h"
- >
- </File>
- </Filter>
- <Filter
- Name="DataStructures"
- >
- <File
- RelativePath="..\DataStructures\BaseParser.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\BinaryHeap.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ConcurrentQueue.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\DynamicGraph.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ExtractorCallBacks.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ExtractorStructs.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\GridEdge.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\HashTable.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ImportEdge.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\InputReaderFactory.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\LevelInformation.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\LRUCache.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\NNGrid.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\NodeCoords.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\NodeInformationHelpDesk.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\PBFParser.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\Percent.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\PhantomNodes.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\PolylineCompressor.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\SearchEngine.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\StaticGraph.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\StaticKDTree.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\Util.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\XMLParser.h"
- >
- </File>
- <Filter
- Name="pbf-proto"
- >
- <File
- RelativePath="..\DataStructures\pbf-proto\fileformat.pb.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\pbf-proto\osmformat.pb.h"
- >
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="Plugins"
- >
- <File
- RelativePath="..\Plugins\BaseDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\BasePlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\GPXDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\HelloWorldPlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\JSONDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\KMLDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\LocatePlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\NearestPlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\ObjectForPluginStruct.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\PluginMapFactory.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\RawRouteData.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\RouteParameters.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\RoutePlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\ViaRoutePlugin.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Server"
- >
- <File
- RelativePath="..\Server\BasicDatastructures.h"
- >
- </File>
- <File
- RelativePath="..\Server\Connection.h"
- >
- </File>
- <File
- RelativePath="..\Server\RequestHandler.h"
- >
- </File>
- <File
- RelativePath="..\Server\RequestParser.h"
- >
- </File>
- <File
- RelativePath="..\Server\Server.h"
- >
- </File>
- <File
- RelativePath="..\Server\ServerConfiguration.h"
- >
- </File>
- <File
- RelativePath="..\Server\ServerFactory.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Util"
- >
- <File
- RelativePath="..\Util\BaseConfiguration.h"
- >
- </File>
- <File
- RelativePath="..\Util\GraphLoader.h"
- >
- </File>
- <File
- RelativePath="..\Util\InputFileUtil.h"
- >
- </File>
- <File
- RelativePath="..\Util\LinuxStackTrace.h"
- >
- </File>
- <File
- RelativePath="..\Util\MachineInfo.h"
- >
- </File>
- <File
- RelativePath="..\Util\StringUtil.h"
- >
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
- >
- </Filter>
- <File
- RelativePath="..\DataStructures\pbf-proto\fileformat.proto"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- Description="Generating fileformat.pb.{h,cc}..."
- CommandLine=""$(ProtobufPath)/bin/protoc" -I"$(SolutionDir).." --cpp_out=.. "$(SolutionDir)../DataStructures/pbf-proto/fileformat.proto"
"
- Outputs=""$(SolutionDir)../DataStructures/pbf-proto/fileformat.pb.h";"$(SolutionDir)../DataStructures/pbf-proto/fileformat.pb.cc""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- Description="Generating fileformat.pb.{h,cc}..."
- CommandLine=""$(ProtobufPath)/bin/protoc" -I"$(SolutionDir).." --cpp_out=.. "$(SolutionDir)../DataStructures/pbf-proto/fileformat.proto"
"
- Outputs=""$(SolutionDir)../DataStructures/pbf-proto/fileformat.pb.h";"$(SolutionDir)../DataStructures/pbf-proto/fileformat.pb.cc""
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\DataStructures\pbf-proto\osmformat.proto"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- Description="Generating osmformat.pb.{h,cc}..."
- CommandLine=""$(ProtobufPath)/bin/protoc" -I"$(SolutionDir).." --cpp_out=.. "$(SolutionDir)../DataStructures/pbf-proto/osmformat.proto"
"
- Outputs=""$(SolutionDir)../DataStructures/pbf-proto/osmformat.pb.h";"$(SolutionDir)../DataStructures/pbf-proto/osmformat.pb.cc""
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCustomBuildTool"
- Description="Generating osmformat.pb.{h,cc}..."
- CommandLine=""$(ProtobufPath)/bin/protoc" -I"$(SolutionDir).." --cpp_out=.. "$(SolutionDir)../DataStructures/pbf-proto/osmformat.proto"
"
- Outputs=""$(SolutionDir)../DataStructures/pbf-proto/osmformat.pb.h";"$(SolutionDir)../DataStructures/pbf-proto/osmformat.pb.cc""
- />
- </FileConfiguration>
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/win/getopt.c b/win/getopt.c
deleted file mode 100644
index d19c36f..0000000
--- a/win/getopt.c
+++ /dev/null
@@ -1,1260 +0,0 @@
-#ifdef _WIN32
-/* Getopt for GNU.
- NOTE: getopt is now part of the C library, so if you don't know what
- "Keep this file name-space clean" means, talk to drepper at gnu.org
- before changing it!
- Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001
- Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
-
-/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
- Ditto for AIX 3.2 and <stdlib.h>. */
-#ifndef _NO_PROTO
-# define _NO_PROTO
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#if !defined __STDC__ || !__STDC__
-/* This is a separate conditional since some stdc systems
- reject `defined (const)'. */
-# ifndef const
-# define const
-# endif
-#endif
-
-#include <stdio.h>
-
-/* Comment out all this code if we are using the GNU C Library, and are not
- actually compiling the library itself. This code is part of the GNU C
- Library, but also included in many other GNU distributions. Compiling
- and linking in this code is a waste when using the GNU C library
- (especially if it is a shared library). Rather than having every GNU
- program understand `configure --with-gnu-libc' and omit the object files,
- it is simpler to just do this in the source for each such file. */
-
-#define GETOPT_INTERFACE_VERSION 2
-#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
-# include <gnu-versions.h>
-# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
-# define ELIDE_CODE
-# endif
-#endif
-
-#ifndef ELIDE_CODE
-
-
-/* This needs to come after some library #include
- to get __GNU_LIBRARY__ defined. */
-#ifdef __GNU_LIBRARY__
-/* Don't include stdlib.h for non-GNU C libraries because some of them
- contain conflicting prototypes for getopt. */
-# include <stdlib.h>
-# include <unistd.h>
-#endif /* GNU C library. */
-
-#ifdef VMS
-# include <unixlib.h>
-# if HAVE_STRING_H - 0
-# include <string.h>
-# endif
-#endif
-
-#ifndef _
-/* This is for other GNU distributions with internationalized messages. */
-# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
-# include <libintl.h>
-# ifndef _
-# define _(msgid) gettext (msgid)
-# endif
-# else
-# define _(msgid) (msgid)
-# endif
-# if defined _LIBC && defined USE_IN_LIBIO
-# include <wchar.h>
-# endif
-#endif
-
-/* This version of `getopt' appears to the caller like standard Unix `getopt'
- but it behaves differently for the user, since it allows the user
- to intersperse the options with the other arguments.
-
- As `getopt' works, it permutes the elements of ARGV so that,
- when it is done, all the options precede everything else. Thus
- all application programs are extended to handle flexible argument order.
-
- Setting the environment variable POSIXLY_CORRECT disables permutation.
- Then the behavior is completely standard.
-
- GNU application programs can use a third alternative mode in which
- they can distinguish the relative order of options and other arguments. */
-
-#include "getopt.h"
-
-/* For communication from `getopt' to the caller.
- When `getopt' finds an option that takes an argument,
- the argument value is returned here.
- Also, when `ordering' is RETURN_IN_ORDER,
- each non-option ARGV-element is returned here. */
-
-char *optarg;
-
-/* Index in ARGV of the next element to be scanned.
- This is used for communication to and from the caller
- and for communication between successive calls to `getopt'.
-
- On entry to `getopt', zero means this is the first call; initialize.
-
- When `getopt' returns -1, this is the index of the first of the
- non-option elements that the caller should itself scan.
-
- Otherwise, `optind' communicates from one call to the next
- how much of ARGV has been scanned so far. */
-
-/* 1003.2 says this must be 1 before any call. */
-int optind = 1;
-
-/* Formerly, initialization of getopt depended on optind==0, which
- causes problems with re-calling getopt as programs generally don't
- know that. */
-
-int __getopt_initialized;
-
-/* The next char to be scanned in the option-element
- in which the last option character we returned was found.
- This allows us to pick up the scan where we left off.
-
- If this is zero, or a null string, it means resume the scan
- by advancing to the next ARGV-element. */
-
-static char *nextchar;
-
-/* Callers store zero here to inhibit the error message
- for unrecognized options. */
-
-int opterr = 1;
-
-/* Set to an option character which was unrecognized.
- This must be initialized on some systems to avoid linking in the
- system's own getopt implementation. */
-
-int optopt = '?';
-
-/* Describe how to deal with options that follow non-option ARGV-elements.
-
- If the caller did not specify anything,
- the default is REQUIRE_ORDER if the environment variable
- POSIXLY_CORRECT is defined, PERMUTE otherwise.
-
- REQUIRE_ORDER means don't recognize them as options;
- stop option processing when the first non-option is seen.
- This is what Unix does.
- This mode of operation is selected by either setting the environment
- variable POSIXLY_CORRECT, or using `+' as the first character
- of the list of option characters.
-
- PERMUTE is the default. We permute the contents of ARGV as we scan,
- so that eventually all the non-options are at the end. This allows options
- to be given in any order, even with programs that were not written to
- expect this.
-
- RETURN_IN_ORDER is an option available to programs that were written
- to expect options and other ARGV-elements in any order and that care about
- the ordering of the two. We describe each non-option ARGV-element
- as if it were the argument of an option with character code 1.
- Using `-' as the first character of the list of option characters
- selects this mode of operation.
-
- The special argument `--' forces an end of option-scanning regardless
- of the value of `ordering'. In the case of RETURN_IN_ORDER, only
- `--' can cause `getopt' to return -1 with `optind' != ARGC. */
-
-static enum
-{
- REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
-} ordering;
-
-/* Value of POSIXLY_CORRECT environment variable. */
-static char *posixly_correct;
-
-#ifdef __GNU_LIBRARY__
-/* We want to avoid inclusion of string.h with non-GNU libraries
- because there are many ways it can cause trouble.
- On some systems, it contains special magic macros that don't work
- in GCC. */
-# include <string.h>
-# define my_index strchr
-#else
-
-# if HAVE_STRING_H || WIN32 /* Pete Wilson mod 7/28/02 */
-# include <string.h>
-# else
-# include <strings.h>
-# endif
-
-/* Avoid depending on library functions or files
- whose names are inconsistent. */
-
-#ifndef getenv
-extern char *getenv ();
-#endif
-
-static char *
-my_index (str, chr)
- const char *str;
- int chr;
-{
- while (*str)
- {
- if (*str == chr)
- return (char *) str;
- str++;
- }
- return 0;
-}
-
-/* If using GCC, we can safely declare strlen this way.
- If not using GCC, it is ok not to declare it. */
-#ifdef __GNUC__
-/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
- That was relevant to code that was here before. */
-# if (!defined __STDC__ || !__STDC__) && !defined strlen
-/* gcc with -traditional declares the built-in strlen to return int,
- and has done so at least since version 2.4.5. -- rms. */
-extern int strlen (const char *);
-# endif /* not __STDC__ */
-#endif /* __GNUC__ */
-
-#endif /* not __GNU_LIBRARY__ */
-
-/* Handle permutation of arguments. */
-
-/* Describe the part of ARGV that contains non-options that have
- been skipped. `first_nonopt' is the index in ARGV of the first of them;
- `last_nonopt' is the index after the last of them. */
-
-static int first_nonopt;
-static int last_nonopt;
-
-#ifdef _LIBC
-/* Stored original parameters.
- XXX This is no good solution. We should rather copy the args so
- that we can compare them later. But we must not use malloc(3). */
-extern int __libc_argc;
-extern char **__libc_argv;
-
-/* Bash 2.0 gives us an environment variable containing flags
- indicating ARGV elements that should not be considered arguments. */
-
-# ifdef USE_NONOPTION_FLAGS
-/* Defined in getopt_init.c */
-extern char *__getopt_nonoption_flags;
-
-static int nonoption_flags_max_len;
-static int nonoption_flags_len;
-# endif
-
-# ifdef USE_NONOPTION_FLAGS
-# define SWAP_FLAGS(ch1, ch2) \
- if (nonoption_flags_len > 0) \
- { \
- char __tmp = __getopt_nonoption_flags[ch1]; \
- __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
- __getopt_nonoption_flags[ch2] = __tmp; \
- }
-# else
-# define SWAP_FLAGS(ch1, ch2)
-# endif
-#else /* !_LIBC */
-# define SWAP_FLAGS(ch1, ch2)
-#endif /* _LIBC */
-
-/* Exchange two adjacent subsequences of ARGV.
- One subsequence is elements [first_nonopt,last_nonopt)
- which contains all the non-options that have been skipped so far.
- The other is elements [last_nonopt,optind), which contains all
- the options processed since those non-options were skipped.
-
- `first_nonopt' and `last_nonopt' are relocated so that they describe
- the new indices of the non-options in ARGV after they are moved. */
-
-#if defined __STDC__ && __STDC__
-static void exchange (char **);
-#endif
-
-static void
-exchange (argv)
- char **argv;
-{
- int bottom = first_nonopt;
- int middle = last_nonopt;
- int top = optind;
- char *tem;
-
- /* Exchange the shorter segment with the far end of the longer segment.
- That puts the shorter segment into the right place.
- It leaves the longer segment in the right place overall,
- but it consists of two parts that need to be swapped next. */
-
-#if defined _LIBC && defined USE_NONOPTION_FLAGS
- /* First make sure the handling of the `__getopt_nonoption_flags'
- string can work normally. Our top argument must be in the range
- of the string. */
- if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
- {
- /* We must extend the array. The user plays games with us and
- presents new arguments. */
- char *new_str = malloc (top + 1);
- if (new_str == NULL)
- nonoption_flags_len = nonoption_flags_max_len = 0;
- else
- {
- memset (__mempcpy (new_str, __getopt_nonoption_flags,
- nonoption_flags_max_len),
- '\0', top + 1 - nonoption_flags_max_len);
- nonoption_flags_max_len = top + 1;
- __getopt_nonoption_flags = new_str;
- }
- }
-#endif
-
- while (top > middle && middle > bottom)
- {
- if (top - middle > middle - bottom)
- {
- /* Bottom segment is the short one. */
- int len = middle - bottom;
- register int i;
-
- /* Swap it with the top part of the top segment. */
- for (i = 0; i < len; i++)
- {
- tem = argv[bottom + i];
- argv[bottom + i] = argv[top - (middle - bottom) + i];
- argv[top - (middle - bottom) + i] = tem;
- SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
- }
- /* Exclude the moved bottom segment from further swapping. */
- top -= len;
- }
- else
- {
- /* Top segment is the short one. */
- int len = top - middle;
- register int i;
-
- /* Swap it with the bottom part of the bottom segment. */
- for (i = 0; i < len; i++)
- {
- tem = argv[bottom + i];
- argv[bottom + i] = argv[middle + i];
- argv[middle + i] = tem;
- SWAP_FLAGS (bottom + i, middle + i);
- }
- /* Exclude the moved top segment from further swapping. */
- bottom += len;
- }
- }
-
- /* Update records for the slots the non-options now occupy. */
-
- first_nonopt += (optind - last_nonopt);
- last_nonopt = optind;
-}
-
-/* Initialize the internal data when the first call is made. */
-
-#if defined __STDC__ && __STDC__
-static const char *_getopt_initialize (int, char *const *, const char *);
-#endif
-static const char *
-_getopt_initialize (argc, argv, optstring)
- int argc;
- char *const *argv;
- const char *optstring;
-{
- /* Start processing options with ARGV-element 1 (since ARGV-element 0
- is the program name); the sequence of previously skipped
- non-option ARGV-elements is empty. */
-
- first_nonopt = last_nonopt = optind;
-
- nextchar = NULL;
-
- posixly_correct = getenv ("POSIXLY_CORRECT");
-
- /* Determine how to handle the ordering of options and nonoptions. */
-
- if (optstring[0] == '-')
- {
- ordering = RETURN_IN_ORDER;
- ++optstring;
- }
- else if (optstring[0] == '+')
- {
- ordering = REQUIRE_ORDER;
- ++optstring;
- }
- else if (posixly_correct != NULL)
- ordering = REQUIRE_ORDER;
- else
- ordering = PERMUTE;
-
-#if defined _LIBC && defined USE_NONOPTION_FLAGS
- if (posixly_correct == NULL
- && argc == __libc_argc && argv == __libc_argv)
- {
- if (nonoption_flags_max_len == 0)
- {
- if (__getopt_nonoption_flags == NULL
- || __getopt_nonoption_flags[0] == '\0')
- nonoption_flags_max_len = -1;
- else
- {
- const char *orig_str = __getopt_nonoption_flags;
- int len = nonoption_flags_max_len = strlen (orig_str);
- if (nonoption_flags_max_len < argc)
- nonoption_flags_max_len = argc;
- __getopt_nonoption_flags =
- (char *) malloc (nonoption_flags_max_len);
- if (__getopt_nonoption_flags == NULL)
- nonoption_flags_max_len = -1;
- else
- memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
- '\0', nonoption_flags_max_len - len);
- }
- }
- nonoption_flags_len = nonoption_flags_max_len;
- }
- else
- nonoption_flags_len = 0;
-#endif
-
- return optstring;
-}
-
-/* Scan elements of ARGV (whose length is ARGC) for option characters
- given in OPTSTRING.
-
- If an element of ARGV starts with '-', and is not exactly "-" or "--",
- then it is an option element. The characters of this element
- (aside from the initial '-') are option characters. If `getopt'
- is called repeatedly, it returns successively each of the option characters
- from each of the option elements.
-
- If `getopt' finds another option character, it returns that character,
- updating `optind' and `nextchar' so that the next call to `getopt' can
- resume the scan with the following option character or ARGV-element.
-
- If there are no more option characters, `getopt' returns -1.
- Then `optind' is the index in ARGV of the first ARGV-element
- that is not an option. (The ARGV-elements have been permuted
- so that those that are not options now come last.)
-
- OPTSTRING is a string containing the legitimate option characters.
- If an option character is seen that is not listed in OPTSTRING,
- return '?' after printing an error message. If you set `opterr' to
- zero, the error message is suppressed but we still return '?'.
-
- If a char in OPTSTRING is followed by a colon, that means it wants an arg,
- so the following text in the same ARGV-element, or the text of the following
- ARGV-element, is returned in `optarg'. Two colons mean an option that
- wants an optional arg; if there is text in the current ARGV-element,
- it is returned in `optarg', otherwise `optarg' is set to zero.
-
- If OPTSTRING starts with `-' or `+', it requests different methods of
- handling the non-option ARGV-elements.
- See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
-
- Long-named options begin with `--' instead of `-'.
- Their names may be abbreviated as long as the abbreviation is unique
- or is an exact match for some defined option. If they have an
- argument, it follows the option name in the same ARGV-element, separated
- from the option name by a `=', or else the in next ARGV-element.
- When `getopt' finds a long-named option, it returns 0 if that option's
- `flag' field is nonzero, the value of the option's `val' field
- if the `flag' field is zero.
-
- The elements of ARGV aren't really const, because we permute them.
- But we pretend they're const in the prototype to be compatible
- with other systems.
-
- LONGOPTS is a vector of `struct option' terminated by an
- element containing a name which is zero.
-
- LONGIND returns the index in LONGOPT of the long-named option found.
- It is only valid when a long-named option has been found by the most
- recent call.
-
- If LONG_ONLY is nonzero, '-' as well as '--' can introduce
- long-named options. */
-
-int
-_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
- int argc;
- char *const *argv;
- const char *optstring;
- const struct option *longopts;
- int *longind;
- int long_only;
-{
- int print_errors = opterr;
- if (optstring[0] == ':')
- print_errors = 0;
-
- if (argc < 1)
- return -1;
-
- optarg = NULL;
-
- if (optind == 0 || !__getopt_initialized)
- {
- if (optind == 0)
- optind = 1; /* Don't scan ARGV[0], the program name. */
- optstring = _getopt_initialize (argc, argv, optstring);
- __getopt_initialized = 1;
- }
-
- /* Test whether ARGV[optind] points to a non-option argument.
- Either it does not have option syntax, or there is an environment flag
- from the shell indicating it is not an option. The later information
- is only used when the used in the GNU libc. */
-#if defined _LIBC && defined USE_NONOPTION_FLAGS
-# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
- || (optind < nonoption_flags_len \
- && __getopt_nonoption_flags[optind] == '1'))
-#else
-# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
-#endif
-
- if (nextchar == NULL || *nextchar == '\0')
- {
- /* Advance to the next ARGV-element. */
-
- /* Give FIRST_NONOPT and LAST_NONOPT rational values if OPTIND has been
- moved back by the user (who may also have changed the arguments). */
- if (last_nonopt > optind)
- last_nonopt = optind;
- if (first_nonopt > optind)
- first_nonopt = optind;
-
- if (ordering == PERMUTE)
- {
- /* If we have just processed some options following some non-options,
- exchange them so that the options come first. */
-
- if (first_nonopt != last_nonopt && last_nonopt != optind)
- exchange ((char **) argv);
- else if (last_nonopt != optind)
- first_nonopt = optind;
-
- /* Skip any additional non-options
- and extend the range of non-options previously skipped. */
-
- while (optind < argc && NONOPTION_P)
- optind++;
- last_nonopt = optind;
- }
-
- /* The special ARGV-element `--' means premature end of options.
- Skip it like a null option,
- then exchange with previous non-options as if it were an option,
- then skip everything else like a non-option. */
-
- if (optind != argc && !strcmp (argv[optind], "--"))
- {
- optind++;
-
- if (first_nonopt != last_nonopt && last_nonopt != optind)
- exchange ((char **) argv);
- else if (first_nonopt == last_nonopt)
- first_nonopt = optind;
- last_nonopt = argc;
-
- optind = argc;
- }
-
- /* If we have done all the ARGV-elements, stop the scan
- and back over any non-options that we skipped and permuted. */
-
- if (optind == argc)
- {
- /* Set the next-arg-index to point at the non-options
- that we previously skipped, so the caller will digest them. */
- if (first_nonopt != last_nonopt)
- optind = first_nonopt;
- return -1;
- }
-
- /* If we have come to a non-option and did not permute it,
- either stop the scan or describe it to the caller and pass it by. */
-
- if (NONOPTION_P)
- {
- if (ordering == REQUIRE_ORDER)
- return -1;
- optarg = argv[optind++];
- return 1;
- }
-
- /* We have found another option-ARGV-element.
- Skip the initial punctuation. */
-
- nextchar = (argv[optind] + 1
- + (longopts != NULL && argv[optind][1] == '-'));
- }
-
- /* Decode the current option-ARGV-element. */
-
- /* Check whether the ARGV-element is a long option.
-
- If long_only and the ARGV-element has the form "-f", where f is
- a valid short option, don't consider it an abbreviated form of
- a long option that starts with f. Otherwise there would be no
- way to give the -f short option.
-
- On the other hand, if there's a long option "fubar" and
- the ARGV-element is "-fu", do consider that an abbreviation of
- the long option, just like "--fu", and not "-f" with arg "u".
-
- This distinction seems to be the most useful approach. */
-
- if (longopts != NULL
- && (argv[optind][1] == '-'
- || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
- {
- char *nameend;
- const struct option *p;
- const struct option *pfound = NULL;
- int exact = 0;
- int ambig = 0;
- int indfound = -1;
- int option_index;
-
- for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
- /* Do nothing. */ ;
-
- /* Test all long options for either exact match
- or abbreviated matches. */
- for (p = longopts, option_index = 0; p->name; p++, option_index++)
- if (!strncmp (p->name, nextchar, nameend - nextchar))
- {
- if ((unsigned int) (nameend - nextchar)
- == (unsigned int) strlen (p->name))
- {
- /* Exact match found. */
- pfound = p;
- indfound = option_index;
- exact = 1;
- break;
- }
- else if (pfound == NULL)
- {
- /* First nonexact match found. */
- pfound = p;
- indfound = option_index;
- }
- else if (long_only
- || pfound->has_arg != p->has_arg
- || pfound->flag != p->flag
- || pfound->val != p->val)
- /* Second or later nonexact match found. */
- ambig = 1;
- }
-
- if (ambig && !exact)
- {
- if (print_errors)
- {
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-
- __asprintf (&buf, _("%s: option `%s' is ambiguous\n"),
- argv[0], argv[optind]);
-
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#else
- fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
- argv[0], argv[optind]);
-#endif
- }
- nextchar += strlen (nextchar);
- optind++;
- optopt = 0;
- return '?';
- }
-
- if (pfound != NULL)
- {
- option_index = indfound;
- optind++;
- if (*nameend)
- {
- /* Don't test has_arg with >, because some C compilers don't
- allow it to be used on enums. */
- if (pfound->has_arg)
- optarg = nameend + 1;
- else
- {
- if (print_errors)
- {
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-#endif
-
- if (argv[optind - 1][1] == '-')
- {
- /* --option */
-#if defined _LIBC && defined USE_IN_LIBIO
- __asprintf (&buf, _("\
-%s: option `--%s' doesn't allow an argument\n"),
- argv[0], pfound->name);
-#else
- fprintf (stderr, _("\
-%s: option `--%s' doesn't allow an argument\n"),
- argv[0], pfound->name);
-#endif
- }
- else
- {
- /* +option or -option */
-#if defined _LIBC && defined USE_IN_LIBIO
- __asprintf (&buf, _("\
-%s: option `%c%s' doesn't allow an argument\n"),
- argv[0], argv[optind - 1][0],
- pfound->name);
-#else
- fprintf (stderr, _("\
-%s: option `%c%s' doesn't allow an argument\n"),
- argv[0], argv[optind - 1][0], pfound->name);
-#endif
- }
-
-#if defined _LIBC && defined USE_IN_LIBIO
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#endif
- }
-
- nextchar += strlen (nextchar);
-
- optopt = pfound->val;
- return '?';
- }
- }
- else if (pfound->has_arg == 1)
- {
- if (optind < argc)
- optarg = argv[optind++];
- else
- {
- if (print_errors)
- {
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-
- __asprintf (&buf,
- _("%s: option `%s' requires an argument\n"),
- argv[0], argv[optind - 1]);
-
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#else
- fprintf (stderr,
- _("%s: option `%s' requires an argument\n"),
- argv[0], argv[optind - 1]);
-#endif
- }
- nextchar += strlen (nextchar);
- optopt = pfound->val;
- return optstring[0] == ':' ? ':' : '?';
- }
- }
- nextchar += strlen (nextchar);
- if (longind != NULL)
- *longind = option_index;
- if (pfound->flag)
- {
- *(pfound->flag) = pfound->val;
- return 0;
- }
- return pfound->val;
- }
-
- /* Can't find it as a long option. If this is not getopt_long_only,
- or the option starts with '--' or is not a valid short
- option, then it's an error.
- Otherwise interpret it as a short option. */
- if (!long_only || argv[optind][1] == '-'
- || my_index (optstring, *nextchar) == NULL)
- {
- if (print_errors)
- {
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-#endif
-
- if (argv[optind][1] == '-')
- {
- /* --option */
-#if defined _LIBC && defined USE_IN_LIBIO
- __asprintf (&buf, _("%s: unrecognized option `--%s'\n"),
- argv[0], nextchar);
-#else
- fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
- argv[0], nextchar);
-#endif
- }
- else
- {
- /* +option or -option */
-#if defined _LIBC && defined USE_IN_LIBIO
- __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"),
- argv[0], argv[optind][0], nextchar);
-#else
- fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
- argv[0], argv[optind][0], nextchar);
-#endif
- }
-
-#if defined _LIBC && defined USE_IN_LIBIO
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#endif
- }
- nextchar = (char *) "";
- optind++;
- optopt = 0;
- return '?';
- }
- }
-
- /* Look at and handle the next short option-character. */
-
- {
- char c = *nextchar++;
- char *temp = my_index (optstring, c);
-
- /* Increment `optind' when we start to process its last character. */
- if (*nextchar == '\0')
- ++optind;
-
- if (temp == NULL || c == ':')
- {
- if (print_errors)
- {
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-#endif
-
- if (posixly_correct)
- {
- /* 1003.2 specifies the format of this message. */
-#if defined _LIBC && defined USE_IN_LIBIO
- __asprintf (&buf, _("%s: illegal option -- %c\n"),
- argv[0], c);
-#else
- fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c);
-#endif
- }
- else
- {
-#if defined _LIBC && defined USE_IN_LIBIO
- __asprintf (&buf, _("%s: invalid option -- %c\n"),
- argv[0], c);
-#else
- fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c);
-#endif
- }
-
-#if defined _LIBC && defined USE_IN_LIBIO
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#endif
- }
- optopt = c;
- return '?';
- }
- /* Convenience. Treat POSIX -W foo same as long option --foo */
- if (temp[0] == 'W' && temp[1] == ';')
- {
- char *nameend;
- const struct option *p;
- const struct option *pfound = NULL;
- int exact = 0;
- int ambig = 0;
- int indfound = 0;
- int option_index;
-
- /* This is an option that requires an argument. */
- if (*nextchar != '\0')
- {
- optarg = nextchar;
- /* If we end this ARGV-element by taking the rest as an arg,
- we must advance to the next element now. */
- optind++;
- }
- else if (optind == argc)
- {
- if (print_errors)
- {
- /* 1003.2 specifies the format of this message. */
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-
- __asprintf (&buf, _("%s: option requires an argument -- %c\n"),
- argv[0], c);
-
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#else
- fprintf (stderr, _("%s: option requires an argument -- %c\n"),
- argv[0], c);
-#endif
- }
- optopt = c;
- if (optstring[0] == ':')
- c = ':';
- else
- c = '?';
- return c;
- }
- else
- /* We already incremented `optind' once;
- increment it again when taking next ARGV-elt as argument. */
- optarg = argv[optind++];
-
- /* optarg is now the argument, see if it's in the
- table of longopts. */
-
- for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
- /* Do nothing. */ ;
-
- /* Test all long options for either exact match
- or abbreviated matches. */
- for (p = longopts, option_index = 0; p->name; p++, option_index++)
- if (!strncmp (p->name, nextchar, nameend - nextchar))
- {
- if ((unsigned int) (nameend - nextchar) == strlen (p->name))
- {
- /* Exact match found. */
- pfound = p;
- indfound = option_index;
- exact = 1;
- break;
- }
- else if (pfound == NULL)
- {
- /* First nonexact match found. */
- pfound = p;
- indfound = option_index;
- }
- else
- /* Second or later nonexact match found. */
- ambig = 1;
- }
- if (ambig && !exact)
- {
- if (print_errors)
- {
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-
- __asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"),
- argv[0], argv[optind]);
-
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#else
- fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
- argv[0], argv[optind]);
-#endif
- }
- nextchar += strlen (nextchar);
- optind++;
- return '?';
- }
- if (pfound != NULL)
- {
- option_index = indfound;
- if (*nameend)
- {
- /* Don't test has_arg with >, because some C compilers don't
- allow it to be used on enums. */
- if (pfound->has_arg)
- optarg = nameend + 1;
- else
- {
- if (print_errors)
- {
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-
- __asprintf (&buf, _("\
-%s: option `-W %s' doesn't allow an argument\n"),
- argv[0], pfound->name);
-
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#else
- fprintf (stderr, _("\
-%s: option `-W %s' doesn't allow an argument\n"),
- argv[0], pfound->name);
-#endif
- }
-
- nextchar += strlen (nextchar);
- return '?';
- }
- }
- else if (pfound->has_arg == 1)
- {
- if (optind < argc)
- optarg = argv[optind++];
- else
- {
- if (print_errors)
- {
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-
- __asprintf (&buf, _("\
-%s: option `%s' requires an argument\n"),
- argv[0], argv[optind - 1]);
-
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#else
- fprintf (stderr,
- _("%s: option `%s' requires an argument\n"),
- argv[0], argv[optind - 1]);
-#endif
- }
- nextchar += strlen (nextchar);
- return optstring[0] == ':' ? ':' : '?';
- }
- }
- nextchar += strlen (nextchar);
- if (longind != NULL)
- *longind = option_index;
- if (pfound->flag)
- {
- *(pfound->flag) = pfound->val;
- return 0;
- }
- return pfound->val;
- }
- nextchar = NULL;
- return 'W'; /* Let the application handle it. */
- }
- if (temp[1] == ':')
- {
- if (temp[2] == ':')
- {
- /* This is an option that accepts an argument optionally. */
- if (*nextchar != '\0')
- {
- optarg = nextchar;
- optind++;
- }
- else
- optarg = NULL;
- nextchar = NULL;
- }
- else
- {
- /* This is an option that requires an argument. */
- if (*nextchar != '\0')
- {
- optarg = nextchar;
- /* If we end this ARGV-element by taking the rest as an arg,
- we must advance to the next element now. */
- optind++;
- }
- else if (optind == argc)
- {
- if (print_errors)
- {
- /* 1003.2 specifies the format of this message. */
-#if defined _LIBC && defined USE_IN_LIBIO
- char *buf;
-
- __asprintf (&buf,
- _("%s: option requires an argument -- %c\n"),
- argv[0], c);
-
- if (_IO_fwide (stderr, 0) > 0)
- __fwprintf (stderr, L"%s", buf);
- else
- fputs (buf, stderr);
-
- free (buf);
-#else
- fprintf (stderr,
- _("%s: option requires an argument -- %c\n"),
- argv[0], c);
-#endif
- }
- optopt = c;
- if (optstring[0] == ':')
- c = ':';
- else
- c = '?';
- }
- else
- /* We already incremented `optind' once;
- increment it again when taking next ARGV-elt as argument. */
- optarg = argv[optind++];
- nextchar = NULL;
- }
- }
- return c;
- }
-}
-
-int
-getopt (argc, argv, optstring)
- int argc;
- char *const *argv;
- const char *optstring;
-{
- return _getopt_internal (argc, argv, optstring,
- (const struct option *) 0,
- (int *) 0,
- 0);
-}
-
-#endif /* Not ELIDE_CODE. */
-
-
-/* Compile with -DTEST to make an executable for use in testing
- the above definition of `getopt'. */
-
-/* #define TEST */ /* Pete Wilson mod 7/28/02 */
-#ifdef TEST
-
-#ifndef exit /* Pete Wilson mod 7/28/02 */
- int exit(int); /* Pete Wilson mod 7/28/02 */
-#endif /* Pete Wilson mod 7/28/02 */
-
-int
-main (argc, argv)
- int argc;
- char **argv;
-{
- int c;
- int digit_optind = 0;
-
- while (1)
- {
- int this_option_optind = optind ? optind : 1;
-
- c = getopt (argc, argv, "abc:d:0123456789");
- if (c == -1)
- break;
-
- switch (c)
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (digit_optind != 0 && digit_optind != this_option_optind)
- printf ("digits occur in two different argv-elements.\n");
- digit_optind = this_option_optind;
- printf ("option %c\n", c);
- break;
-
- case 'a':
- printf ("option a\n");
- break;
-
- case 'b':
- printf ("option b\n");
- break;
-
- case 'c':
- printf ("option c with value `%s'\n", optarg);
- break;
-
- case '?':
- break;
-
- default:
- printf ("?? getopt returned character code 0%o ??\n", c);
- }
- }
-
- if (optind < argc)
- {
- printf ("non-option ARGV-elements: ");
- while (optind < argc)
- printf ("%s ", argv[optind++]);
- printf ("\n");
- }
-
- exit (0);
-}
-
-#endif /* TEST */
-#endif
diff --git a/win/getopt.h b/win/getopt.h
deleted file mode 100644
index 455d531..0000000
--- a/win/getopt.h
+++ /dev/null
@@ -1,189 +0,0 @@
-#ifdef _WIN32
-/* getopt.h */
-/* Declarations for getopt.
- Copyright (C) 1989-1994, 1996-1999, 2001 Free Software
- Foundation, Inc. This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute
- it and/or modify it under the terms of the GNU Lesser
- General Public License as published by the Free Software
- Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- The GNU C Library 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 Lesser General Public
- License for more details.
-
- You should have received a copy of the GNU Lesser General
- Public License along with the GNU C Library; if not, write
- to the Free Software Foundation, Inc., 59 Temple Place,
- Suite 330, Boston, MA 02111-1307 USA. */
-
-
-
-
-#ifndef _GETOPT_H
-
-#ifndef __need_getopt
-# define _GETOPT_H 1
-#endif
-
-/* If __GNU_LIBRARY__ is not already defined, either we are being used
- standalone, or this is the first header included in the source file.
- If we are being used with glibc, we need to include <features.h>, but
- that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
- not defined, include <ctype.h>, which will pull in <features.h> for us
- if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
- doesn't flood the namespace with stuff the way some other headers do.) */
-#if !defined __GNU_LIBRARY__
-# include <ctype.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* For communication from `getopt' to the caller.
- When `getopt' finds an option that takes an argument,
- the argument value is returned here.
- Also, when `ordering' is RETURN_IN_ORDER,
- each non-option ARGV-element is returned here. */
-
-extern char *optarg;
-
-/* Index in ARGV of the next element to be scanned.
- This is used for communication to and from the caller
- and for communication between successive calls to `getopt'.
-
- On entry to `getopt', zero means this is the first call; initialize.
-
- When `getopt' returns -1, this is the index of the first of the
- non-option elements that the caller should itself scan.
-
- Otherwise, `optind' communicates from one call to the next
- how much of ARGV has been scanned so far. */
-
-extern int optind;
-
-/* Callers store zero here to inhibit the error message `getopt' prints
- for unrecognized options. */
-
-extern int opterr;
-
-/* Set to an option character which was unrecognized. */
-
-extern int optopt;
-
-#ifndef __need_getopt
-/* Describe the long-named options requested by the application.
- The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
- of `struct option' terminated by an element containing a name which is
- zero.
-
- The field `has_arg' is:
- no_argument (or 0) if the option does not take an argument,
- required_argument (or 1) if the option requires an argument,
- optional_argument (or 2) if the option takes an optional argument.
-
- If the field `flag' is not NULL, it points to a variable that is set
- to the value given in the field `val' when the option is found, but
- left unchanged if the option is not found.
-
- To have a long-named option do something other than set an `int' to
- a compiled-in constant, such as set a value from `optarg', set the
- option's `flag' field to zero and its `val' field to a nonzero
- value (the equivalent single-letter option character, if there is
- one). For long options that have a zero `flag' field, `getopt'
- returns the contents of the `val' field. */
-
-struct option
-{
-# if (defined __STDC__ && __STDC__) || defined __cplusplus
- const char *name;
-# else
- char *name;
-# endif
- /* has_arg can't be an enum because some compilers complain about
- type mismatches in all the code that assumes it is an int. */
- int has_arg;
- int *flag;
- int val;
-};
-
-/* Names for the values of the `has_arg' field of `struct option'. */
-
-# define no_argument 0
-# define required_argument 1
-# define optional_argument 2
-#endif /* need getopt */
-
-
-/* Get definitions and prototypes for functions to process the
- arguments in ARGV (ARGC of them, minus the program name) for
- options given in OPTS.
-
- Return the option character from OPTS just read. Return -1 when
- there are no more options. For unrecognized options, or options
- missing arguments, `optopt' is set to the option letter, and '?' is
- returned.
-
- The OPTS string is a list of characters which are recognized option
- letters, optionally followed by colons, specifying that that letter
- takes an argument, to be placed in `optarg'.
-
- If a letter in OPTS is followed by two colons, its argument is
- optional. This behavior is specific to the GNU `getopt'.
-
- The argument `--' causes premature termination of argument
- scanning, explicitly telling `getopt' that there are no more
- options.
-
- If OPTS begins with `--', then non-option arguments are treated as
- arguments to the option '\0'. This behavior is specific to the GNU
- `getopt'. */
-
-#if (defined __STDC__ && __STDC__) || defined __cplusplus
-# ifdef __GNU_LIBRARY__
-/* Many other libraries have conflicting prototypes for getopt, with
- differences in the consts, in stdlib.h. To avoid compilation
- errors, only prototype getopt for the GNU C library. */
-extern int getopt (int ___argc, char *const *___argv, const char *__shortopts);
-# else /* not __GNU_LIBRARY__ */
-extern int getopt ();
-# endif /* __GNU_LIBRARY__ */
-
-# ifndef __need_getopt
-extern int getopt_long (int ___argc, char *const *___argv,
- const char *__shortopts,
- const struct option *__longopts, int *__longind);
-extern int getopt_long_only (int ___argc, char *const *___argv,
- const char *__shortopts,
- const struct option *__longopts, int *__longind);
-
-/* Internal only. Users should not call this directly. */
-extern int _getopt_internal (int ___argc, char *const *___argv,
- const char *__shortopts,
- const struct option *__longopts, int *__longind,
- int __long_only);
-# endif
-#else /* not __STDC__ */
-extern int getopt ();
-# ifndef __need_getopt
-extern int getopt_long ();
-extern int getopt_long_only ();
-
-extern int _getopt_internal ();
-# endif
-#endif /* __STDC__ */
-
-#ifdef __cplusplus
-}
-#endif
-
-/* Make sure we later can get all the definitions and declarations. */
-#undef __need_getopt
-
-#endif /* getopt.h */
-#endif
diff --git a/win/osrm.sln b/win/osrm.sln
deleted file mode 100644
index 62634fc..0000000
--- a/win/osrm.sln
+++ /dev/null
@@ -1,29 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "extractor", "extractor.vcproj", "{F630F025-637A-43DF-9258-2860AE9E6740}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "createHierarchy", "createHierarchy.vcproj", "{38C3EEAC-032B-4BEA-BECB-C694A47AA7E2}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "routed", "routed.vcproj", "{675D419D-E442-4A21-9030-B54B4C09439A}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Release|Win32 = Release|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {F630F025-637A-43DF-9258-2860AE9E6740}.Debug|Win32.ActiveCfg = Debug|Win32
- {F630F025-637A-43DF-9258-2860AE9E6740}.Debug|Win32.Build.0 = Debug|Win32
- {F630F025-637A-43DF-9258-2860AE9E6740}.Release|Win32.ActiveCfg = Release|Win32
- {F630F025-637A-43DF-9258-2860AE9E6740}.Release|Win32.Build.0 = Release|Win32
- {38C3EEAC-032B-4BEA-BECB-C694A47AA7E2}.Debug|Win32.ActiveCfg = Debug|Win32
- {38C3EEAC-032B-4BEA-BECB-C694A47AA7E2}.Release|Win32.ActiveCfg = Release|Win32
- {38C3EEAC-032B-4BEA-BECB-C694A47AA7E2}.Release|Win32.Build.0 = Release|Win32
- {675D419D-E442-4A21-9030-B54B4C09439A}.Debug|Win32.ActiveCfg = Debug|Win32
- {675D419D-E442-4A21-9030-B54B4C09439A}.Release|Win32.ActiveCfg = Release|Win32
- {675D419D-E442-4A21-9030-B54B4C09439A}.Release|Win32.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/win/osrm.vsprops b/win/osrm.vsprops
deleted file mode 100644
index 08d15be..0000000
--- a/win/osrm.vsprops
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioPropertySheet
- ProjectType="Visual C++"
- Version="8.00"
- Name="osrm"
- >
- <UserMacro
- Name="BoostPath"
- Value="$(SolutionDir)lib\boost_1_47\"
- />
- <UserMacro
- Name="Bzip2Path"
- Value="$(SolutionDir)lib\bzip2-1.0.6\"
- />
- <UserMacro
- Name="IconvPath"
- Value="$(SolutionDir)lib\iconv-1.9.2.win32\"
- />
- <UserMacro
- Name="LibXml2Path"
- Value="$(SolutionDir)lib\libxml2-2.7.8.win32\"
- />
- <UserMacro
- Name="ProtobufPath"
- Value="$(SolutionDir)lib\protobuf-2.4.1\"
- />
- <UserMacro
- Name="SparsehashPath"
- Value="$(SolutionDir)lib\sparsehash-1.11\"
- />
- <UserMacro
- Name="StxxlPath"
- Value="$(SolutionDir)lib\stxxl-1.3.1\"
- />
- <UserMacro
- Name="ZlibPath"
- Value="$(SolutionDir)lib\zlib-1.2.5\"
- />
-</VisualStudioPropertySheet>
diff --git a/win/routed.vcproj b/win/routed.vcproj
deleted file mode 100644
index 8f4c183..0000000
--- a/win/routed.vcproj
+++ /dev/null
@@ -1,459 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9.00"
- Name="routed"
- ProjectGUID="{675D419D-E442-4A21-9030-B54B4C09439A}"
- RootNamespace="routed"
- Keyword="Win32Proj"
- TargetFrameworkVersion="196613"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="$(SolutionDir)bin-debug"
- IntermediateDirectory="$(SolutionDir)bin-debug"
- ConfigurationType="1"
- InheritedPropertySheets=".\osrm.vsprops"
- CharacterSet="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_RTLDLL -DBOOST_LIB_DIAGNOSTIC -DSTXXL_BOOST_TIMESTAMP -DSTXXL_BOOST_CONFIG -DSTXXL_BOOST_FILESYSTEM -DSTXXL_BOOST_THREADS -DSTXXL_BOOST_RANDOM /EHsc /EHs /wd4820 /wd4217 /wd4668 /wd4619 /wd4625 /wd4626 /wd4355 /wd4996 -D_SCL_SECURE_NO_DEPRECATE /F 16777216 /nologo "
- Optimization="0"
- AdditionalIncludeDirectories=""$(BoostPath)";"$(StxxlPath)\include";"$(LibXml2Path)\include";"$(IconvPath)\include";"$(SparsehashPath)\src\";"$(SparsehashPath)\src\windows";"$(Bzip2Path)\include";"$(ZlibPath)\include";..\;"$(ProtobufPath)\include";"$(SolutionDir)""
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- OpenMP="true"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- DebugInformationFormat="4"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/STACK:16777216 /NOLOGO /OPT:REF"
- AdditionalDependencies="libbz2.lib libxml2.lib zlibd.lib libprotobuf-debug.lib libstxxl-debug.lib"
- LinkIncremental="2"
- AdditionalLibraryDirectories=""$(BoostPath)\lib";"$(StxxlPath)\lib";"$(LibXml2Path)\lib";"$(IconvPath)\lib";"$(Bzip2Path)\lib";"$(ZlibPath)\lib";"$(ProtobufPath)\lib""
- GenerateDebugInformation="true"
- SubSystem="1"
- RandomizedBaseAddress="1"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="xcopy "$(SolutionDir)..\server.ini" "$(OutDir)\" /f /y"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="$(SolutionDir)bin"
- IntermediateDirectory="$(SolutionDir)bin"
- ConfigurationType="1"
- InheritedPropertySheets=".\osrm.vsprops"
- CharacterSet="1"
- WholeProgramOptimization="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- AdditionalOptions="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_RTLDLL -DBOOST_LIB_DIAGNOSTIC -DSTXXL_BOOST_TIMESTAMP -DSTXXL_BOOST_CONFIG -DSTXXL_BOOST_FILESYSTEM -DSTXXL_BOOST_THREADS -DSTXXL_BOOST_RANDOM /EHsc /EHs /wd4820 /wd4217 /wd4668 /wd4619 /wd4625 /wd4626 /wd4355 /wd4996 -D_SCL_SECURE_NO_DEPRECATE /F 16777216 /nologo "
- Optimization="2"
- EnableIntrinsicFunctions="true"
- AdditionalIncludeDirectories=""$(BoostPath)";"$(StxxlPath)\include";"$(LibXml2Path)\include";"$(IconvPath)\include";"$(SparsehashPath)\src\";"$(SparsehashPath)\src\windows";"$(Bzip2Path)\include";"$(ZlibPath)\include";..\;"$(ProtobufPath)\include""
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
- RuntimeLibrary="2"
- EnableFunctionLevelLinking="true"
- OpenMP="true"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- DebugInformationFormat="0"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/STACK:16777216 /NOLOGO /OPT:REF"
- AdditionalDependencies="libbz2.lib libxml2.lib zlib.lib libprotobuf.lib libstxxl.lib"
- LinkIncremental="1"
- AdditionalLibraryDirectories=""$(BoostPath)\lib";"$(StxxlPath)\lib";"$(LibXml2Path)\lib";"$(IconvPath)\lib";"$(Bzip2Path)\lib";"$(ZlibPath)\lib";"$(ProtobufPath)\lib""
- GenerateDebugInformation="false"
- SubSystem="1"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- RandomizedBaseAddress="1"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="xcopy "$(SolutionDir)..\server.ini" "$(OutDir)\" /f /y"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
- >
- <File
- RelativePath="..\routed.cpp"
- >
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
- >
- <File
- RelativePath="getopt.h"
- >
- </File>
- <File
- RelativePath="..\typedefs.h"
- >
- </File>
- <File
- RelativePath="unistd.h"
- >
- </File>
- <Filter
- Name="Contractor"
- >
- <File
- RelativePath="..\Contractor\ContractionCleanup.h"
- >
- </File>
- <File
- RelativePath="..\Contractor\Contractor.h"
- >
- </File>
- </Filter>
- <Filter
- Name="DataStructures"
- >
- <File
- RelativePath="..\DataStructures\BaseParser.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\BinaryHeap.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\DynamicGraph.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ExtractorCallBacks.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ExtractorStructs.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\GridEdge.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\HashTable.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\ImportEdge.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\InputReaderFactory.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\LevelInformation.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\LRUCache.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\NNGrid.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\NodeCoords.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\NodeInformationHelpDesk.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\PBFParser.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\Percent.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\PhantomNodes.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\PolylineCompressor.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\SearchEngine.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\StaticGraph.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\StaticKDTree.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\Util.h"
- >
- </File>
- <File
- RelativePath="..\DataStructures\XMLParser.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Plugins"
- >
- <File
- RelativePath="..\Plugins\BaseDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\BasePlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\GPXDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\HelloWorldPlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\JSONDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\KMLDescriptor.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\LocatePlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\NearestPlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\ObjectForPluginStruct.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\PluginMapFactory.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\RawRouteData.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\RouteParameters.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\RoutePlugin.h"
- >
- </File>
- <File
- RelativePath="..\Plugins\ViaRoutePlugin.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Server"
- >
- <File
- RelativePath="..\Server\BasicDatastructures.h"
- >
- </File>
- <File
- RelativePath="..\Server\Connection.h"
- >
- </File>
- <File
- RelativePath="..\Server\RequestHandler.h"
- >
- </File>
- <File
- RelativePath="..\Server\RequestParser.h"
- >
- </File>
- <File
- RelativePath="..\Server\Server.h"
- >
- </File>
- <File
- RelativePath="..\Server\ServerConfiguration.h"
- >
- </File>
- <File
- RelativePath="..\Server\ServerFactory.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Util"
- >
- <File
- RelativePath="..\Util\BaseConfiguration.h"
- >
- </File>
- <File
- RelativePath="..\Util\GraphLoader.h"
- >
- </File>
- <File
- RelativePath="..\Util\InputFileUtil.h"
- >
- </File>
- <File
- RelativePath="..\Util\LinuxStackTrace.h"
- >
- </File>
- <File
- RelativePath="..\Util\MachineInfo.h"
- >
- </File>
- <File
- RelativePath="..\Util\StringUtil.h"
- >
- </File>
- </Filter>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
- >
- </Filter>
- <File
- RelativePath="..\DataStructures\pbf-proto\fileformat.proto"
- >
- </File>
- <File
- RelativePath="..\DataStructures\pbf-proto\osmformat.proto"
- >
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/win/unistd.h b/win/unistd.h
deleted file mode 100644
index 442c158..0000000
--- a/win/unistd.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifdef _WIN32
-#ifndef _UNISTD_H
-#define _UNISTD_H 1
-
-/* This file intended to serve as a drop-in replacement for
- * unistd.h on Windows
- * Please add functionality as neeeded
- */
-
-#include <stdlib.h>
-#include <io.h>
-#include <getopt.h> /* getopt from: http://www.pwilson.net/sample.html. */
-
-#define srandom srand
-#define random rand
-
-const int W_OK = 2;
-const int R_OK = 4;
-
-#define access _access
-#define ftruncate _chsize
-
-#define ssize_t int
-
-#define STDIN_FILENO 0
-#define STDOUT_FILENO 1
-#define STDERR_FILENO 2
-
-#endif /* unistd.h */
-#endif
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/osrm.git
More information about the Pkg-grass-devel
mailing list