renamed: Algorithms/* -> algorithms/*
This commit is contained in:
		
							parent
							
								
									c28c441e77
								
							
						
					
					
						commit
						d8eea0ce0e
					
				
							
								
								
									
										174
									
								
								algorithms/bfs_components.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								algorithms/bfs_components.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,174 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | 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 BFS_COMPONENTS_HPP_ | ||||||
|  | #define BFS_COMPONENTS_HPP_ | ||||||
|  | 
 | ||||||
|  | #include "../typedefs.h" | ||||||
|  | #include "../DataStructures/restriction_map.hpp" | ||||||
|  | 
 | ||||||
|  | #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 &dynamic_graph, | ||||||
|  |                          const RestrictionMap &restrictions, | ||||||
|  |                          const std::unordered_set<NodeID> &barrier_nodes) | ||||||
|  |         : m_graph(dynamic_graph), 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. | ||||||
|  |      */ | ||||||
|  |     unsigned int GetComponentSize(const NodeID node) const | ||||||
|  |     { | ||||||
|  |         BOOST_ASSERT(node < m_component_index_list.size()); | ||||||
|  | 
 | ||||||
|  |         return m_component_index_size[m_component_index_list[node]]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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. | ||||||
|  |      */ | ||||||
|  |     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 // BFS_COMPONENTS_HPP_
 | ||||||
							
								
								
									
										146
									
								
								algorithms/crc32_processor.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								algorithms/crc32_processor.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,146 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | 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 ITERATOR_BASED_CRC32_H | ||||||
|  | #define ITERATOR_BASED_CRC32_H | ||||||
|  | 
 | ||||||
|  | #if defined(__x86_64__) && !defined(__MINGW64__) | ||||||
|  | #include <cpuid.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include <boost/crc.hpp> // for boost::crc_32_type
 | ||||||
|  | 
 | ||||||
|  | #include <iterator> | ||||||
|  | 
 | ||||||
|  | class IteratorbasedCRC32 | ||||||
|  | { | ||||||
|  |   public: | ||||||
|  |     bool using_hardware() const { return use_hardware_implementation; } | ||||||
|  | 
 | ||||||
|  |     IteratorbasedCRC32() : crc(0) { use_hardware_implementation = detect_hardware_support(); } | ||||||
|  | 
 | ||||||
|  |     template <class Iterator> unsigned operator()(Iterator iter, const Iterator end) | ||||||
|  |     { | ||||||
|  |         unsigned crc = 0; | ||||||
|  |         while (iter != end) | ||||||
|  |         { | ||||||
|  |             using value_type = typename std::iterator_traits<Iterator>::value_type; | ||||||
|  |             char *data = (char *)(&(*iter)); | ||||||
|  | 
 | ||||||
|  |             if (use_hardware_implementation) | ||||||
|  |             { | ||||||
|  |                 crc = compute_in_hardware(data, sizeof(value_type)); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 crc = compute_in_software(data, sizeof(value_type)); | ||||||
|  |             } | ||||||
|  |             ++iter; | ||||||
|  |         } | ||||||
|  |         return crc; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   private: | ||||||
|  |     bool detect_hardware_support() const | ||||||
|  |     { | ||||||
|  |         static const int sse42_bit = 0x00100000; | ||||||
|  |         const unsigned ecx = cpuid(); | ||||||
|  |         const bool sse42_found = (ecx & sse42_bit) != 0; | ||||||
|  |         return sse42_found; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     unsigned compute_in_software(char *str, unsigned len) | ||||||
|  |     { | ||||||
|  |         crc_processor.process_bytes(str, len); | ||||||
|  |         return crc_processor.checksum(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // adapted from http://byteworm.com/2010/10/13/crc32/
 | ||||||
|  |     unsigned compute_in_hardware(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; | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |         return crc; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | #if defined(__MINGW64__) || defined(_MSC_VER) | ||||||
|  |     inline void | ||||||
|  |     __get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) const | ||||||
|  |     { | ||||||
|  |         *ecx = 0; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> crc_processor; | ||||||
|  |     unsigned crc; | ||||||
|  |     bool use_hardware_implementation; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct RangebasedCRC32 | ||||||
|  | { | ||||||
|  |     template<typename Iteratable> | ||||||
|  |     unsigned operator()(const Iteratable &iterable) | ||||||
|  |     { | ||||||
|  |         return crc32(std::begin(iterable), std::end(iterable)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool using_hardware() const { return crc32.using_hardware(); } | ||||||
|  | 
 | ||||||
|  |   private: | ||||||
|  |     IteratorbasedCRC32 crc32; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif /* ITERATOR_BASED_CRC32_H */ | ||||||
							
								
								
									
										166
									
								
								algorithms/douglas_peucker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								algorithms/douglas_peucker.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | 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 "douglas_peucker.hpp" | ||||||
|  | 
 | ||||||
|  | #include "../DataStructures/segment_information.hpp" | ||||||
|  | #include "../Util/integer_range.hpp" | ||||||
|  | 
 | ||||||
|  | #include <osrm/Coordinate.h> | ||||||
|  | 
 | ||||||
|  | #include <boost/assert.hpp> | ||||||
|  | 
 | ||||||
|  | #include <cmath> | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | 
 | ||||||
|  | namespace | ||||||
|  | { | ||||||
|  | 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; | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DouglasPeucker::Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level) | ||||||
|  | { | ||||||
|  |     Run(std::begin(input_geometry), std::end(input_geometry), zoom_level); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DouglasPeucker::Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level) | ||||||
|  | { | ||||||
|  |     unsigned size = std::distance(begin, end); | ||||||
|  |     if (size < 2) | ||||||
|  |     { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     begin->necessary = true; | ||||||
|  |     std::prev(end)->necessary = true; | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         BOOST_ASSERT_MSG(zoom_level < DOUGLAS_PEUCKER_THRESHOLDS.size(), "unsupported zoom level"); | ||||||
|  |         RandomAccessIt left_border = begin; | ||||||
|  |         RandomAccessIt right_border = std::next(begin); | ||||||
|  |         // Sweep over array and identify those ranges that need to be checked
 | ||||||
|  |         do | ||||||
|  |         { | ||||||
|  |             // traverse list until new border element found
 | ||||||
|  |             if (right_border->necessary) | ||||||
|  |             { | ||||||
|  |                 // sanity checks
 | ||||||
|  |                 BOOST_ASSERT(left_border->necessary); | ||||||
|  |                 BOOST_ASSERT(right_border->necessary); | ||||||
|  |                 recursion_stack.emplace(left_border, right_border); | ||||||
|  |                 left_border = right_border; | ||||||
|  |             } | ||||||
|  |             ++right_border; | ||||||
|  |         } while (right_border != end); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // 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(pair.first->necessary, "left border must be necessary"); | ||||||
|  |         BOOST_ASSERT_MSG(pair.second->necessary, "right border must be necessary"); | ||||||
|  |         BOOST_ASSERT_MSG(std::distance(pair.second, end) > 0, "right border outside of geometry"); | ||||||
|  |         BOOST_ASSERT_MSG(std::distance(pair.first, pair.second) >= 0, | ||||||
|  |                          "left border on the wrong side"); | ||||||
|  | 
 | ||||||
|  |         int max_int_distance = 0; | ||||||
|  |         auto farthest_entry_it = pair.second; | ||||||
|  |         const CoordinatePairCalculator dist_calc(pair.first->location, pair.second->location); | ||||||
|  | 
 | ||||||
|  |         // sweep over range to find the maximum
 | ||||||
|  |         for (auto it = std::next(pair.first); it != pair.second; ++it) | ||||||
|  |         { | ||||||
|  |             const int distance = dist_calc(it->location); | ||||||
|  |             // found new feasible maximum?
 | ||||||
|  |             if (distance > max_int_distance && distance > DOUGLAS_PEUCKER_THRESHOLDS[zoom_level]) | ||||||
|  |             { | ||||||
|  |                 farthest_entry_it = it; | ||||||
|  |                 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
 | ||||||
|  |             farthest_entry_it->necessary = true; | ||||||
|  |             if (1 < std::distance(pair.first, farthest_entry_it)) | ||||||
|  |             { | ||||||
|  |                 recursion_stack.emplace(pair.first, farthest_entry_it); | ||||||
|  |             } | ||||||
|  |             if (1 < std::distance(farthest_entry_it, pair.second)) | ||||||
|  |             { | ||||||
|  |                 recursion_stack.emplace(farthest_entry_it, pair.second); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										80
									
								
								algorithms/douglas_peucker.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								algorithms/douglas_peucker.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -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 DOUGLAS_PEUCKER_HPP_ | ||||||
|  | #define DOUGLAS_PEUCKER_HPP_ | ||||||
|  | 
 | ||||||
|  | #include <stack> | ||||||
|  | #include <vector> | ||||||
|  | #include <array> | ||||||
|  | 
 | ||||||
|  | /* 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. | ||||||
|  |  * Note: points may also be pre-selected*/ | ||||||
|  | 
 | ||||||
|  | struct SegmentInformation; | ||||||
|  | 
 | ||||||
|  | static const std::array<int, 19> 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
 | ||||||
|  | }}; | ||||||
|  | 
 | ||||||
|  | class DouglasPeucker | ||||||
|  | { | ||||||
|  |   public: | ||||||
|  |     using RandomAccessIt = std::vector<SegmentInformation>::iterator; | ||||||
|  | 
 | ||||||
|  |     using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>; | ||||||
|  |     // Stack to simulate the recursion
 | ||||||
|  |     std::stack<GeometryRange> recursion_stack; | ||||||
|  | 
 | ||||||
|  |   public: | ||||||
|  |     void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level); | ||||||
|  |     void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif /* DOUGLAS_PEUCKER_HPP_ */ | ||||||
							
								
								
									
										94
									
								
								algorithms/object_encoder.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								algorithms/object_encoder.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | 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 OBJECT_ENCODER_HPP | ||||||
|  | #define OBJECT_ENCODER_HPP | ||||||
|  | 
 | ||||||
|  | #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 <algorithm> | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | struct ObjectEncoder | ||||||
|  | { | ||||||
|  |     using base64_t = boost::archive::iterators::base64_from_binary< | ||||||
|  |         boost::archive::iterators::transform_width<const char *, 6, 8>>; | ||||||
|  | 
 | ||||||
|  |     using binary_t = boost::archive::iterators::transform_width< | ||||||
|  |         boost::archive::iterators::binary_from_base64<std::string::const_iterator>, | ||||||
|  |         8, | ||||||
|  |         6>; | ||||||
|  | 
 | ||||||
|  |     template <class ObjectT> | ||||||
|  |     static void EncodeToBase64(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 ObjectT> | ||||||
|  |     static void DecodeFromBase64(const std::string &input, ObjectT &object) | ||||||
|  |     { | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             std::string encoded(input); | ||||||
|  |             // replace "-" with "+" and "_" with "/"
 | ||||||
|  |             replaceAll(encoded, "-", "+"); | ||||||
|  |             replaceAll(encoded, "_", "/"); | ||||||
|  | 
 | ||||||
|  |             std::copy(binary_t(encoded.begin()), | ||||||
|  |                       binary_t(encoded.begin() + encoded.length() - 1), | ||||||
|  |                       (char *)&object); | ||||||
|  |         } | ||||||
|  |         catch (...) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif /* OBJECT_ENCODER_HPP */ | ||||||
							
								
								
									
										98
									
								
								algorithms/polyline_compressor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								algorithms/polyline_compressor.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | 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 "polyline_compressor.hpp" | ||||||
|  | #include "../DataStructures/segment_information.hpp" | ||||||
|  | 
 | ||||||
|  | #include <osrm/Coordinate.h> | ||||||
|  | 
 | ||||||
|  | std::string PolylineCompressor::encode_vector(std::vector<int> &numbers) const | ||||||
|  | { | ||||||
|  |     std::string output; | ||||||
|  |     const auto end = numbers.size(); | ||||||
|  |     for (std::size_t i = 0; i < end; ++i) | ||||||
|  |     { | ||||||
|  |         numbers[i] <<= 1; | ||||||
|  |         if (numbers[i] < 0) | ||||||
|  |         { | ||||||
|  |             numbers[i] = ~(numbers[i]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     for (const int number : numbers) | ||||||
|  |     { | ||||||
|  |         output += encode_number(number); | ||||||
|  |     } | ||||||
|  |     return output; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string PolylineCompressor::encode_number(int number_to_encode) const | ||||||
|  | { | ||||||
|  |     std::string output; | ||||||
|  |     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); | ||||||
|  |     } | ||||||
|  |     return output; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string | ||||||
|  | PolylineCompressor::get_encoded_string(const std::vector<SegmentInformation> &polyline) const | ||||||
|  | { | ||||||
|  |     if (polyline.empty()) | ||||||
|  |     { | ||||||
|  |         return {}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::vector<int> delta_numbers; | ||||||
|  |     delta_numbers.reserve((polyline.size() - 1) * 2); | ||||||
|  |     FixedPointCoordinate previous_coordinate = {0, 0}; | ||||||
|  |     for (const auto &segment : polyline) | ||||||
|  |     { | ||||||
|  |         if (segment.necessary) | ||||||
|  |         { | ||||||
|  |             const int lat_diff = segment.location.lat - previous_coordinate.lat; | ||||||
|  |             const int lon_diff = segment.location.lon - previous_coordinate.lon; | ||||||
|  |             delta_numbers.emplace_back(lat_diff); | ||||||
|  |             delta_numbers.emplace_back(lon_diff); | ||||||
|  |             previous_coordinate = segment.location; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return encode_vector(delta_numbers); | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								algorithms/polyline_compressor.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								algorithms/polyline_compressor.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | 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 POLYLINECOMPRESSOR_H_ | ||||||
|  | #define POLYLINECOMPRESSOR_H_ | ||||||
|  | 
 | ||||||
|  | struct SegmentInformation; | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | class PolylineCompressor | ||||||
|  | { | ||||||
|  |   private: | ||||||
|  |     std::string encode_vector(std::vector<int> &numbers) const; | ||||||
|  | 
 | ||||||
|  |     std::string encode_number(const int number_to_encode) const; | ||||||
|  | 
 | ||||||
|  |   public: | ||||||
|  |     std::string get_encoded_string(const std::vector<SegmentInformation> &polyline) const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif /* POLYLINECOMPRESSOR_H_ */ | ||||||
							
								
								
									
										56
									
								
								algorithms/polyline_formatter.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								algorithms/polyline_formatter.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | 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 "polyline_formatter.hpp" | ||||||
|  | 
 | ||||||
|  | #include "polyline_compressor.hpp" | ||||||
|  | #include "../DataStructures/segment_information.hpp" | ||||||
|  | 
 | ||||||
|  | #include <osrm/Coordinate.h> | ||||||
|  | 
 | ||||||
|  | JSON::String | ||||||
|  | PolylineFormatter::printEncodedString(const std::vector<SegmentInformation> &polyline) const | ||||||
|  | { | ||||||
|  |     return JSON::String(PolylineCompressor().get_encoded_string(polyline)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | JSON::Array | ||||||
|  | PolylineFormatter::printUnencodedString(const std::vector<SegmentInformation> &polyline) const | ||||||
|  | { | ||||||
|  |     JSON::Array json_geometry_array; | ||||||
|  |     for (const auto &segment : polyline) | ||||||
|  |     { | ||||||
|  |         if (segment.necessary) | ||||||
|  |         { | ||||||
|  |             JSON::Array json_coordinate; | ||||||
|  |             json_coordinate.values.push_back(segment.location.lat / COORDINATE_PRECISION); | ||||||
|  |             json_coordinate.values.push_back(segment.location.lon / COORDINATE_PRECISION); | ||||||
|  |             json_geometry_array.values.push_back(json_coordinate); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return json_geometry_array; | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								algorithms/polyline_formatter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								algorithms/polyline_formatter.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | 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 POLYLINE_FORMATTER_H_ | ||||||
|  | #define POLYLINE_FORMATTER_H_ | ||||||
|  | 
 | ||||||
|  | struct SegmentInformation; | ||||||
|  | 
 | ||||||
|  | #include "../DataStructures/JSONContainer.h" | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | struct PolylineFormatter | ||||||
|  | { | ||||||
|  |     JSON::String printEncodedString(const std::vector<SegmentInformation> &polyline) const; | ||||||
|  | 
 | ||||||
|  |     JSON::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif /* POLYLINE_FORMATTER_H_ */ | ||||||
							
								
								
									
										169
									
								
								algorithms/route_name_extraction.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								algorithms/route_name_extraction.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -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 && segment.name_id != 0) | ||||||
|  |             { | ||||||
|  |                 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_segment_1.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_segment_1.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
 | ||||||
							
								
								
									
										459
									
								
								algorithms/tiny_components.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										459
									
								
								algorithms/tiny_components.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,459 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | 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 STRONGLYCONNECTEDCOMPONENTS_H_ | ||||||
|  | #define STRONGLYCONNECTEDCOMPONENTS_H_ | ||||||
|  | 
 | ||||||
|  | #include "../typedefs.h" | ||||||
|  | #include "../DataStructures/DeallocatingVector.h" | ||||||
|  | #include "../DataStructures/DynamicGraph.h" | ||||||
|  | #include "../DataStructures/ImportEdge.h" | ||||||
|  | #include "../DataStructures/QueryNode.h" | ||||||
|  | #include "../DataStructures/Percent.h" | ||||||
|  | #include "../DataStructures/Restriction.h" | ||||||
|  | #include "../DataStructures/TurnInstructions.h" | ||||||
|  | 
 | ||||||
|  | #include "../Util/integer_range.hpp" | ||||||
|  | #include "../Util/OSRMException.h" | ||||||
|  | #include "../Util/simple_logger.hpp" | ||||||
|  | #include "../Util/StdHashExtensions.h" | ||||||
|  | #include "../Util/TimingUtil.h" | ||||||
|  | 
 | ||||||
|  | #include <osrm/Coordinate.h> | ||||||
|  | 
 | ||||||
|  | #include <boost/assert.hpp> | ||||||
|  | #include <boost/filesystem.hpp> | ||||||
|  | 
 | ||||||
|  | #include <tbb/parallel_sort.h> | ||||||
|  | 
 | ||||||
|  | #if defined(__APPLE__) || defined (_WIN32) | ||||||
|  | #include <gdal.h> | ||||||
|  | #include <ogrsf_frmts.h> | ||||||
|  | #else | ||||||
|  | #include <gdal/gdal.h> | ||||||
|  | #include <gdal/ogrsf_frmts.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include <cstdint> | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | #include <stack> | ||||||
|  | #include <unordered_map> | ||||||
|  | #include <unordered_set> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | class TarjanSCC | ||||||
|  | { | ||||||
|  |   private: | ||||||
|  |     struct TarjanNode | ||||||
|  |     { | ||||||
|  |         TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {} | ||||||
|  |         unsigned index; | ||||||
|  |         unsigned low_link; | ||||||
|  |         bool on_stack; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     struct TarjanEdgeData | ||||||
|  |     { | ||||||
|  |         TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {} | ||||||
|  |         TarjanEdgeData(int distance, unsigned name_id) : distance(distance), name_id(name_id) {} | ||||||
|  |         int distance; | ||||||
|  |         unsigned name_id; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     struct TarjanStackFrame | ||||||
|  |     { | ||||||
|  |         explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {} | ||||||
|  |         NodeID v; | ||||||
|  |         NodeID parent; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     using TarjanDynamicGraph = DynamicGraph<TarjanEdgeData>; | ||||||
|  |     using TarjanEdge = TarjanDynamicGraph::InputEdge; | ||||||
|  |     using RestrictionSource = std::pair<NodeID, NodeID>; | ||||||
|  |     using RestrictionTarget = std::pair<NodeID, bool>; | ||||||
|  |     using EmanatingRestrictionsVector = std::vector<RestrictionTarget>; | ||||||
|  |     using RestrictionMap = std::unordered_map<RestrictionSource, unsigned>; | ||||||
|  | 
 | ||||||
|  |     std::vector<QueryNode> m_coordinate_list; | ||||||
|  |     std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list; | ||||||
|  |     std::shared_ptr<TarjanDynamicGraph> m_node_based_graph; | ||||||
|  |     std::unordered_set<NodeID> barrier_node_list; | ||||||
|  |     std::unordered_set<NodeID> 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<QueryNode> &nI) | ||||||
|  |         : m_coordinate_list(nI), m_restriction_counter(irs.size()) | ||||||
|  |     { | ||||||
|  |         TIMER_START(SCC_LOAD); | ||||||
|  |         for (const TurnRestriction &restriction : irs) | ||||||
|  |         { | ||||||
|  |             std::pair<NodeID, NodeID> restriction_source = {restriction.from.node, | ||||||
|  |                                                             restriction.via.node}; | ||||||
|  |             unsigned index = 0; | ||||||
|  |             const auto restriction_iterator = m_restriction_map.find(restriction_source); | ||||||
|  |             if (restriction_iterator == 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_iterator->second; | ||||||
|  |                 // Map already contains an is_only_*-restriction
 | ||||||
|  |                 if (m_restriction_bucket_list.at(index).begin()->second) | ||||||
|  |                 { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |                 else if (restriction.flags.is_only) | ||||||
|  |                 { | ||||||
|  |                     // We are going to insert an is_only_*-restriction. There can be only one.
 | ||||||
|  |                     m_restriction_bucket_list.at(index).clear(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             m_restriction_bucket_list.at(index) | ||||||
|  |                 .emplace_back(restriction.to.node, restriction.flags.is_only); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         barrier_node_list.insert(bn.begin(), bn.end()); | ||||||
|  |         traffic_light_list.insert(tl.begin(), tl.end()); | ||||||
|  | 
 | ||||||
|  |         DeallocatingVector<TarjanEdge> edge_list; | ||||||
|  |         for (const NodeBasedEdge &input_edge : input_edges) | ||||||
|  |         { | ||||||
|  |             if (input_edge.source == input_edge.target) | ||||||
|  |             { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (input_edge.forward) | ||||||
|  |             { | ||||||
|  |                 edge_list.emplace_back(input_edge.source, | ||||||
|  |                                        input_edge.target, | ||||||
|  |                                        (std::max)((int)input_edge.weight, 1), | ||||||
|  |                                        input_edge.name_id); | ||||||
|  |             } | ||||||
|  |             if (input_edge.backward) | ||||||
|  |             { | ||||||
|  |                 edge_list.emplace_back(input_edge.target, | ||||||
|  |                                        input_edge.source, | ||||||
|  |                                        (std::max)((int)input_edge.weight, 1), | ||||||
|  |                                        input_edge.name_id); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         input_edges.clear(); | ||||||
|  |         input_edges.shrink_to_fit(); | ||||||
|  |         BOOST_ASSERT_MSG(0 == input_edges.size() && 0 == input_edges.capacity(), | ||||||
|  |                          "input edge vector not properly deallocated"); | ||||||
|  | 
 | ||||||
|  |         tbb::parallel_sort(edge_list.begin(), edge_list.end()); | ||||||
|  |         m_node_based_graph = std::make_shared<TarjanDynamicGraph>(number_of_nodes, edge_list); | ||||||
|  |         TIMER_STOP(SCC_LOAD); | ||||||
|  |         SimpleLogger().Write() << "Loading data into SCC took " << TIMER_MSEC(SCC_LOAD)/1000. << "s"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ~TarjanSCC() { m_node_based_graph.reset(); } | ||||||
|  | 
 | ||||||
|  |     void Run() | ||||||
|  |     { | ||||||
|  |         TIMER_START(SCC_RUN_SETUP); | ||||||
|  |         // remove files from previous run if exist
 | ||||||
|  |         DeleteFileIfExists("component.dbf"); | ||||||
|  |         DeleteFileIfExists("component.shx"); | ||||||
|  |         DeleteFileIfExists("component.shp"); | ||||||
|  | 
 | ||||||
|  |         Percent p(m_node_based_graph->GetNumberOfNodes()); | ||||||
|  | 
 | ||||||
|  |         OGRRegisterAll(); | ||||||
|  | 
 | ||||||
|  |         const char *pszDriverName = "ESRI Shapefile"; | ||||||
|  |         OGRSFDriver *poDriver = | ||||||
|  |             OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName); | ||||||
|  |         if (nullptr == poDriver) | ||||||
|  |         { | ||||||
|  |             throw OSRMException("ESRI Shapefile driver not available"); | ||||||
|  |         } | ||||||
|  |         OGRDataSource *poDS = poDriver->CreateDataSource("component.shp", nullptr); | ||||||
|  | 
 | ||||||
|  |         if (nullptr == poDS) | ||||||
|  |         { | ||||||
|  |             throw OSRMException("Creation of output file failed"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         OGRSpatialReference *poSRS = new OGRSpatialReference(); | ||||||
|  |         poSRS->importFromEPSG(4326); | ||||||
|  | 
 | ||||||
|  |         OGRLayer *poLayer = poDS->CreateLayer("component", poSRS, wkbLineString, nullptr); | ||||||
|  | 
 | ||||||
|  |         if (nullptr == poLayer) | ||||||
|  |         { | ||||||
|  |             throw OSRMException("Layer creation failed."); | ||||||
|  |         } | ||||||
|  |         TIMER_STOP(SCC_RUN_SETUP); | ||||||
|  |         SimpleLogger().Write() << "shapefile setup took " << TIMER_MSEC(SCC_RUN_SETUP)/1000. << "s"; | ||||||
|  | 
 | ||||||
|  |         TIMER_START(SCC_RUN); | ||||||
|  |         // The following is a hack to distinguish between stuff that happens
 | ||||||
|  |         // before the recursive call and stuff that happens after
 | ||||||
|  |         std::stack<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(), | ||||||
|  |                                                SPECIAL_NODEID); | ||||||
|  |         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; | ||||||
|  |         const NodeID last_node = m_node_based_graph->GetNumberOfNodes(); | ||||||
|  |         std::vector<bool> processing_node_before_recursion(m_node_based_graph->GetNumberOfNodes(), true); | ||||||
|  |         for(const NodeID node : osrm::irange(0u, last_node)) | ||||||
|  |         { | ||||||
|  |             if (SPECIAL_NODEID == components_index[node]) | ||||||
|  |             { | ||||||
|  |                 recursion_stack.emplace(TarjanStackFrame(node, node)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             while (!recursion_stack.empty()) | ||||||
|  |             { | ||||||
|  |                 TarjanStackFrame currentFrame = recursion_stack.top(); | ||||||
|  |                 const NodeID v = currentFrame.v; | ||||||
|  |                 recursion_stack.pop(); | ||||||
|  |                 const bool before_recursion = processing_node_before_recursion[v]; | ||||||
|  | 
 | ||||||
|  |                 if (before_recursion && tarjan_node_list[v].index != UINT_MAX) | ||||||
|  |                 { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (before_recursion) | ||||||
|  |                 { | ||||||
|  |                     // Mark frame to handle tail of recursion
 | ||||||
|  |                     recursion_stack.emplace(currentFrame); | ||||||
|  |                     processing_node_before_recursion[v] = false; | ||||||
|  | 
 | ||||||
|  |                     // 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; | ||||||
|  | 
 | ||||||
|  |                     // Traverse outgoing edges
 | ||||||
|  |                     for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(v)) | ||||||
|  |                     { | ||||||
|  |                         const TarjanDynamicGraph::NodeIterator vprime = | ||||||
|  |                             m_node_based_graph->GetTarget(current_edge); | ||||||
|  |                         if (SPECIAL_NODEID == tarjan_node_list[vprime].index) | ||||||
|  |                         { | ||||||
|  |                             recursion_stack.emplace(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 | ||||||
|  |                 { | ||||||
|  |                     processing_node_before_recursion[v] = true; | ||||||
|  |                     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 | ||||||
|  |                         { | ||||||
|  |                             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; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         TIMER_STOP(SCC_RUN); | ||||||
|  |         SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN)/1000. << "s"; | ||||||
|  |         SimpleLogger().Write() << "identified: " << component_size_vector.size() | ||||||
|  |                                << " many components, marking small components"; | ||||||
|  | 
 | ||||||
|  |         TIMER_START(SCC_OUTPUT); | ||||||
|  | 
 | ||||||
|  |         const unsigned size_one_counter = std::count_if(component_size_vector.begin(), | ||||||
|  |                                                         component_size_vector.end(), | ||||||
|  |                                                         [](unsigned value) | ||||||
|  |                                                         { | ||||||
|  |             return 1 == value; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1"; | ||||||
|  | 
 | ||||||
|  |         uint64_t total_network_distance = 0; | ||||||
|  |         p.reinit(m_node_based_graph->GetNumberOfNodes()); | ||||||
|  |         // const NodeID last_u_node = m_node_based_graph->GetNumberOfNodes();
 | ||||||
|  |         for (const NodeID source : osrm::irange(0u, last_node)) | ||||||
|  |         { | ||||||
|  |             p.printIncrement(); | ||||||
|  |             for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(source)) | ||||||
|  |             { | ||||||
|  |                 const TarjanDynamicGraph::NodeIterator target = | ||||||
|  |                     m_node_based_graph->GetTarget(current_edge); | ||||||
|  | 
 | ||||||
|  |                 if (source < target || | ||||||
|  |                     m_node_based_graph->EndEdges(target) == | ||||||
|  |                         m_node_based_graph->FindEdge(target, source)) | ||||||
|  |                 { | ||||||
|  |                     total_network_distance += | ||||||
|  |                         100 * FixedPointCoordinate::ApproximateEuclideanDistance( | ||||||
|  |                                   m_coordinate_list[source].lat, | ||||||
|  |                                   m_coordinate_list[source].lon, | ||||||
|  |                                   m_coordinate_list[target].lat, | ||||||
|  |                                   m_coordinate_list[target].lon); | ||||||
|  | 
 | ||||||
|  |                     BOOST_ASSERT(current_edge != SPECIAL_EDGEID); | ||||||
|  |                     BOOST_ASSERT(source != SPECIAL_NODEID); | ||||||
|  |                     BOOST_ASSERT(target != SPECIAL_NODEID); | ||||||
|  | 
 | ||||||
|  |                     const unsigned size_of_containing_component = | ||||||
|  |                         std::min(component_size_vector[components_index[source]], | ||||||
|  |                                  component_size_vector[components_index[target]]); | ||||||
|  | 
 | ||||||
|  |                     // edges that end on bollard nodes may actually be in two distinct components
 | ||||||
|  |                     if (size_of_containing_component < 10) | ||||||
|  |                     { | ||||||
|  |                         OGRLineString lineString; | ||||||
|  |                         lineString.addPoint(m_coordinate_list[source].lon / COORDINATE_PRECISION, | ||||||
|  |                                             m_coordinate_list[source].lat / COORDINATE_PRECISION); | ||||||
|  |                         lineString.addPoint(m_coordinate_list[target].lon / COORDINATE_PRECISION, | ||||||
|  |                                             m_coordinate_list[target].lat / COORDINATE_PRECISION); | ||||||
|  | 
 | ||||||
|  |                         OGRFeature *poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn()); | ||||||
|  | 
 | ||||||
|  |                         poFeature->SetGeometry(&lineString); | ||||||
|  |                         if (OGRERR_NONE != poLayer->CreateFeature(poFeature)) | ||||||
|  |                         { | ||||||
|  |                             throw OSRMException("Failed to create feature in shapefile."); | ||||||
|  |                         } | ||||||
|  |                         OGRFeature::DestroyFeature(poFeature); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         OGRDataSource::DestroyDataSource(poDS); | ||||||
|  |         component_size_vector.clear(); | ||||||
|  |         component_size_vector.shrink_to_fit(); | ||||||
|  |         BOOST_ASSERT_MSG(0 == component_size_vector.size() && 0 == component_size_vector.capacity(), | ||||||
|  |                          "component_size_vector not properly deallocated"); | ||||||
|  | 
 | ||||||
|  |         components_index.clear(); | ||||||
|  |         components_index.shrink_to_fit(); | ||||||
|  |         BOOST_ASSERT_MSG(0 == components_index.size() && 0 == components_index.capacity(), | ||||||
|  |                          "components_index not properly deallocated"); | ||||||
|  |         TIMER_STOP(SCC_OUTPUT); | ||||||
|  |         SimpleLogger().Write() << "generating output took: " << TIMER_MSEC(SCC_OUTPUT)/1000. << "s"; | ||||||
|  | 
 | ||||||
|  |         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> restriction_source = {u, v}; | ||||||
|  |         const auto 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 SPECIAL_NODEID; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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}; | ||||||
|  |         const auto restriction_iterator = m_restriction_map.find(restriction_source); | ||||||
|  |         if (restriction_iterator != m_restriction_map.end()) | ||||||
|  |         { | ||||||
|  |             const unsigned index = restriction_iterator->second; | ||||||
|  |             for (const RestrictionTarget &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_ */ | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user