502 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			502 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 | 
						|
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 "../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/SimpleLogger.h"
 | 
						|
 | 
						|
#include <Coordinate.h>
 | 
						|
 | 
						|
#include <boost/assert.hpp>
 | 
						|
#include <boost/filesystem.hpp>
 | 
						|
#include <boost/foreach.hpp>
 | 
						|
#include <boost/integer.hpp>
 | 
						|
#include <boost/make_shared.hpp>
 | 
						|
#include <boost/unordered_map.hpp>
 | 
						|
#include <boost/unordered_set.hpp>
 | 
						|
 | 
						|
#ifdef __APPLE__
 | 
						|
    #include <gdal.h>
 | 
						|
    #include <ogrsf_frmts.h>
 | 
						|
#else
 | 
						|
    #include <gdal/gdal.h>
 | 
						|
    #include <gdal/ogrsf_frmts.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <stack>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
class TarjanSCC {
 | 
						|
private:
 | 
						|
 | 
						|
    struct TarjanNode {
 | 
						|
        TarjanNode() : index(UINT_MAX), lowlink(UINT_MAX), onStack(false) {}
 | 
						|
        unsigned index;
 | 
						|
        unsigned lowlink;
 | 
						|
        bool onStack;
 | 
						|
    };
 | 
						|
 | 
						|
    struct TarjanEdgeData {
 | 
						|
        int distance;
 | 
						|
        unsigned nameID:31;
 | 
						|
        bool shortcut:1;
 | 
						|
        short type;
 | 
						|
        bool isAccessRestricted:1;
 | 
						|
        bool forward:1;
 | 
						|
        bool backward:1;
 | 
						|
        bool roundabout:1;
 | 
						|
        bool ignoreInGrid:1;
 | 
						|
        bool reversedEdge:1;
 | 
						|
    };
 | 
						|
 | 
						|
    struct TarjanStackFrame {
 | 
						|
        explicit TarjanStackFrame(
 | 
						|
            NodeID v,
 | 
						|
            NodeID parent
 | 
						|
        ) : v(v), parent(parent) { }
 | 
						|
        NodeID v;
 | 
						|
        NodeID parent;
 | 
						|
    };
 | 
						|
 | 
						|
    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 boost::unordered_map<RestrictionSource, unsigned > RestrictionMap;
 | 
						|
 | 
						|
    std::vector<NodeInfo>                       m_coordinate_list;
 | 
						|
    std::vector<EmanatingRestrictionsVector>    m_restriction_bucket_list;
 | 
						|
    boost::shared_ptr<TarjanDynamicGraph>       m_node_based_graph;
 | 
						|
    boost::unordered_set<NodeID>                m_barrier_node_list;
 | 
						|
    boost::unordered_set<NodeID>                m_traffic_light_list;
 | 
						|
    unsigned                                    m_restriction_counter;
 | 
						|
    RestrictionMap                              m_restriction_map;
 | 
						|
 | 
						|
    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;
 | 
						|
    };
 | 
						|
 | 
						|
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())
 | 
						|
    {
 | 
						|
        BOOST_FOREACH(const TurnRestriction & restriction, irs) {
 | 
						|
            std::pair<NodeID, NodeID> restrictionSource = std::make_pair(
 | 
						|
                restriction.fromNode, restriction.viaNode
 | 
						|
            );
 | 
						|
            unsigned index;
 | 
						|
            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[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.
 | 
						|
                    m_restriction_bucket_list.at(index).clear();
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            m_restriction_bucket_list.at(index).push_back(
 | 
						|
                std::make_pair(restriction.toNode, restriction.flags.isOnly)
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        m_barrier_node_list.insert(bn.begin(), bn.end());
 | 
						|
        m_traffic_light_list.insert(tl.begin(), tl.end());
 | 
						|
 | 
						|
        DeallocatingVector< TarjanEdge > edge_list;
 | 
						|
        BOOST_FOREACH(const NodeBasedEdge & input_edge, input_edges) {
 | 
						|
            TarjanEdge edge;
 | 
						|
            if(!input_edge.isForward()) {
 | 
						|
                edge.source = input_edge.target();
 | 
						|
                edge.target = input_edge.source();
 | 
						|
                edge.data.backward = input_edge.isForward();
 | 
						|
                edge.data.forward = input_edge.isBackward();
 | 
						|
            } else {
 | 
						|
                edge.source = input_edge.source();
 | 
						|
                edge.target = input_edge.target();
 | 
						|
                edge.data.forward = input_edge.isForward();
 | 
						|
                edge.data.backward = input_edge.isBackward();
 | 
						|
            }
 | 
						|
            if(edge.source == edge.target) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            edge.data.distance = (std::max)((int)input_edge.weight(), 1 );
 | 
						|
            BOOST_ASSERT( edge.data.distance > 0 );
 | 
						|
            edge.data.shortcut = false;
 | 
						|
            edge.data.roundabout = input_edge.isRoundabout();
 | 
						|
            edge.data.ignoreInGrid = input_edge.ignoreInGrid();
 | 
						|
            edge.data.nameID = input_edge.name();
 | 
						|
            edge.data.type = input_edge.type();
 | 
						|
            edge.data.isAccessRestricted = input_edge.isAccessRestricted();
 | 
						|
            edge.data.reversedEdge = false;
 | 
						|
            edge_list.push_back( edge );
 | 
						|
            if( edge.data.backward ) {
 | 
						|
                std::swap( edge.source, edge.target );
 | 
						|
                edge.data.forward = input_edge.isBackward();
 | 
						|
                edge.data.backward = input_edge.isForward();
 | 
						|
                edge.data.reversedEdge = true;
 | 
						|
                edge_list.push_back( edge );
 | 
						|
            }
 | 
						|
        }
 | 
						|
        std::vector<NodeBasedEdge>().swap(input_edges);
 | 
						|
        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 = boost::make_shared<TarjanDynamicGraph>(
 | 
						|
            number_of_nodes,
 | 
						|
            edge_list
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    ~TarjanSCC() {
 | 
						|
        m_node_based_graph.reset();
 | 
						|
    }
 | 
						|
 | 
						|
    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();
 | 
						|
 | 
						|
        const char *pszDriverName = "ESRI Shapefile";
 | 
						|
        OGRSFDriver * poDriver = OGRSFDriverRegistrar::GetRegistrar()->
 | 
						|
            GetDriverByName( pszDriverName );
 | 
						|
        if( NULL == poDriver ) {
 | 
						|
            throw OSRMException("ESRI Shapefile driver not available");
 | 
						|
        }
 | 
						|
        OGRDataSource * poDS = poDriver->CreateDataSource(
 | 
						|
            "component.shp",
 | 
						|
            NULL
 | 
						|
        );
 | 
						|
 | 
						|
        if( NULL == poDS ) {
 | 
						|
            throw OSRMException("Creation of output file failed");
 | 
						|
        }
 | 
						|
 | 
						|
        OGRLayer * poLayer = poDS->CreateLayer(
 | 
						|
            "component",
 | 
						|
            NULL,
 | 
						|
            wkbLineString,
 | 
						|
            NULL
 | 
						|
        );
 | 
						|
 | 
						|
        if( NULL == 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> > 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, last_node = m_node_based_graph->GetNumberOfNodes();
 | 
						|
            node < last_node;
 | 
						|
            ++node
 | 
						|
        ) {
 | 
						|
            if(UINT_MAX == components_index[node]) {
 | 
						|
                recursion_stack.push(
 | 
						|
                    std::make_pair(true, TarjanStackFrame(node,node))
 | 
						|
                );
 | 
						|
            }
 | 
						|
 | 
						|
            while(!recursion_stack.empty()) {
 | 
						|
                bool before_recursion = recursion_stack.top().first;
 | 
						|
                TarjanStackFrame currentFrame = recursion_stack.top().second;
 | 
						|
                NodeID v = currentFrame.v;
 | 
						|
                recursion_stack.pop();
 | 
						|
 | 
						|
                if(before_recursion) {
 | 
						|
                    //Mark frame to handle tail of recursion
 | 
						|
                    recursion_stack.push(std::make_pair(false, currentFrame));
 | 
						|
 | 
						|
                    //Mark essential information for SCC
 | 
						|
                    tarjan_node_list[v].index = index;
 | 
						|
                    tarjan_node_list[v].lowlink = index;
 | 
						|
                    tarjan_stack.push(v);
 | 
						|
                    tarjan_node_list[v].onStack = true;
 | 
						|
                    ++index;
 | 
						|
 | 
						|
                    //Traverse outgoing edges
 | 
						|
                    for(
 | 
						|
                        TarjanDynamicGraph::EdgeIterator e2 = m_node_based_graph->BeginEdges(v);
 | 
						|
                        e2 < m_node_based_graph->EndEdges(v);
 | 
						|
                        ++e2
 | 
						|
                    ) {
 | 
						|
                        const TarjanDynamicGraph::NodeIterator vprime =
 | 
						|
                            m_node_based_graph->GetTarget(e2);
 | 
						|
                        if(UINT_MAX == tarjan_node_list[vprime].index) {
 | 
						|
                            recursion_stack.push(
 | 
						|
                                std::make_pair(
 | 
						|
                                    true,
 | 
						|
                                    TarjanStackFrame(vprime, v)
 | 
						|
                                )
 | 
						|
                            );
 | 
						|
                        } else {
 | 
						|
                            if(
 | 
						|
                                tarjan_node_list[vprime].onStack &&
 | 
						|
                                tarjan_node_list[vprime].index < tarjan_node_list[v].lowlink
 | 
						|
                            ) {
 | 
						|
                                tarjan_node_list[v].lowlink = tarjan_node_list[vprime].index;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    tarjan_node_list[currentFrame.parent].lowlink =
 | 
						|
                        std::min(
 | 
						|
                            tarjan_node_list[currentFrame.parent].lowlink,
 | 
						|
                            tarjan_node_list[v].lowlink
 | 
						|
                        );
 | 
						|
                    //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].lowlink == tarjan_node_list[v].index) {
 | 
						|
                        NodeID vprime;
 | 
						|
                        do {
 | 
						|
                            vprime = tarjan_stack.top(); tarjan_stack.pop();
 | 
						|
                            tarjan_node_list[vprime].onStack = false;
 | 
						|
                            components_index[vprime] = component_index;
 | 
						|
                            ++size_of_current_component;
 | 
						|
                        } while( v != vprime);
 | 
						|
 | 
						|
                        component_size_vector.push_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;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        SimpleLogger().Write() <<
 | 
						|
            "identified: " << component_size_vector.size() <<
 | 
						|
            " many components, marking small components";
 | 
						|
 | 
						|
        unsigned size_one_counter = 0;
 | 
						|
        for(unsigned i = 0, end = component_size_vector.size(); i < end; ++i){
 | 
						|
            if(1 == component_size_vector[i]) {
 | 
						|
                ++size_one_counter;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        SimpleLogger().Write() <<
 | 
						|
            "identified " << size_one_counter << " SCCs of size 1";
 | 
						|
 | 
						|
        uint64_t total_network_distance = 0;
 | 
						|
        p.reinit(m_node_based_graph->GetNumberOfNodes());
 | 
						|
        for(
 | 
						|
            TarjanDynamicGraph::NodeIterator u = 0, last_u_node = m_node_based_graph->GetNumberOfNodes();
 | 
						|
            u < last_u_node;
 | 
						|
            ++u
 | 
						|
         ) {
 | 
						|
            p.printIncrement();
 | 
						|
            for(
 | 
						|
                TarjanDynamicGraph::EdgeIterator e1 = m_node_based_graph->BeginEdges(u), last_edge = m_node_based_graph->EndEdges(u);
 | 
						|
                e1 < last_edge;
 | 
						|
                ++e1
 | 
						|
            ) {
 | 
						|
                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(
 | 
						|
                            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 = 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 );
 | 
						|
        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 > restriction_source = std::make_pair(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;
 | 
						|
            BOOST_FOREACH(
 | 
						|
                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 > restriction_source = std::make_pair(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;
 | 
						|
            BOOST_FOREACH(
 | 
						|
                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_ */
 |