SUMO - Simulation of Urban MObility

NBNodeCont.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00007 // Container for nodes during the netbuilding process
00008 /****************************************************************************/
00009 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00010 // Copyright (C) 2001-2011 DLR (http://www.dlr.de/) and contributors
00011 /****************************************************************************/
00012 //
00013 //   This program is free software; you can redistribute it and/or modify
00014 //   it under the terms of the GNU General Public License as published by
00015 //   the Free Software Foundation; either version 2 of the License, or
00016 //   (at your option) any later version.
00017 //
00018 /****************************************************************************/
00019 
00020 
00021 // ===========================================================================
00022 // included modules
00023 // ===========================================================================
00024 #ifdef _MSC_VER
00025 #include <windows_config.h>
00026 #else
00027 #include <config.h>
00028 #endif
00029 
00030 #include <string>
00031 #include <map>
00032 #include <algorithm>
00033 #include <cmath>
00034 #include <utils/options/OptionsCont.h>
00035 #include <utils/geom/Boundary.h>
00036 #include <utils/geom/GeomHelper.h>
00037 #include <utils/common/MsgHandler.h>
00038 #include <utils/common/UtilExceptions.h>
00039 #include <utils/common/StringTokenizer.h>
00040 #include <utils/common/StdDefs.h>
00041 #include <utils/common/ToString.h>
00042 #include <utils/xml/SUMOXMLDefinitions.h>
00043 #include <utils/geom/GeoConvHelper.h>
00044 #include <utils/iodevices/OutputDevice.h>
00045 #include "NBDistrict.h"
00046 #include "NBEdgeCont.h"
00047 #include "NBTrafficLightLogicCont.h"
00048 #include "NBJoinedEdgesMap.h"
00049 #include "NBOwnTLDef.h"
00050 #include "NBNodeCont.h"
00051 
00052 #ifdef CHECK_MEMORY_LEAKS
00053 #include <foreign/nvwa/debug_new.h>
00054 #endif // CHECK_MEMORY_LEAKS
00055 
00056 
00057 // ===========================================================================
00058 // method definitions
00059 // ===========================================================================
00060 NBNodeCont::NBNodeCont() throw()
00061     : myInternalID(1) {}
00062 
00063 
00064 NBNodeCont::~NBNodeCont() throw() {
00065     clear();
00066 }
00067 
00068 
00069 // ----------- Insertion/removal/retrieval of nodes
00070 bool
00071 NBNodeCont::insert(const std::string& id, const Position& position,
00072                    NBDistrict* district) throw() {
00073     NodeCont::iterator i = myNodes.find(id);
00074     if (i!=myNodes.end()) {
00075         return false;
00076     }
00077     NBNode* node = new NBNode(id, position, district);
00078     myNodes[id] = node;
00079     return true;
00080 }
00081 
00082 
00083 bool
00084 NBNodeCont::insert(const std::string& id, const Position& position) throw() {
00085     NodeCont::iterator i = myNodes.find(id);
00086     if (i!=myNodes.end()) {
00087         return false;
00088     }
00089     NBNode* node = new NBNode(id, position);
00090     myNodes[id] = node;
00091     return true;
00092 }
00093 
00094 
00095 Position
00096 NBNodeCont::insert(const std::string& id) throw() {
00097     std::pair<SUMOReal, SUMOReal> ret(-1.0, -1.0);
00098     NodeCont::iterator i = myNodes.find(id);
00099     if (i!=myNodes.end()) {
00100         return (*i).second->getPosition();
00101     } else {
00102         NBNode* node = new NBNode(id, Position(-1.0, -1.0));
00103         myNodes[id] = node;
00104     }
00105     return Position(-1, -1);
00106 }
00107 
00108 
00109 bool
00110 NBNodeCont::insert(NBNode* node) throw() {
00111     std::string id = node->getID();
00112     NodeCont::iterator i = myNodes.find(id);
00113     if (i!=myNodes.end()) {
00114         return false;
00115     }
00116     myNodes[id] = node;
00117     return true;
00118 }
00119 
00120 
00121 NBNode*
00122 NBNodeCont::retrieve(const std::string& id) const throw() {
00123     NodeCont::const_iterator i = myNodes.find(id);
00124     if (i==myNodes.end()) {
00125         return 0;
00126     }
00127     return (*i).second;
00128 }
00129 
00130 
00131 NBNode*
00132 NBNodeCont::retrieve(const Position& position, SUMOReal offset) const throw() {
00133     for (NodeCont::const_iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00134         NBNode* node = (*i).second;
00135         if (fabs(node->getPosition().x()-position.x())<offset
00136                 &&
00137                 fabs(node->getPosition().y()-position.y())<offset) {
00138             return node;
00139         }
00140     }
00141     return 0;
00142 }
00143 
00144 
00145 bool
00146 NBNodeCont::erase(NBNode* node) throw() {
00147     if (extract(node)) {
00148         delete node;
00149         return true;
00150     } else {
00151         return false;
00152     }
00153 }
00154 
00155 
00156 bool
00157 NBNodeCont::extract(NBNode* node, bool remember) throw() {
00158     NodeCont::iterator i = myNodes.find(node->getID());
00159     if (i==myNodes.end()) {
00160         return false;
00161     }
00162     myNodes.erase(i);
00163     node->removeTrafficLights();
00164     if (remember) {
00165         myExtractedNodes.insert(node);
00166     }
00167     return true;
00168 }
00169 
00170 
00171 // ----------- Adapting the input
00172 void
00173 NBNodeCont::removeDummyEdges(NBDistrictCont& dc, NBEdgeCont& ec,
00174                              NBTrafficLightLogicCont& tc) {
00175     unsigned int no = 0;
00176     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00177         no += (*i).second->removeDummyEdges(dc, ec, tc);
00178     }
00179     if (no!=0) {
00180         WRITE_WARNING(toString(no) + " dummy edge(s) removed.");
00181     }
00182 }
00183 
00184 
00185 void
00186 NBNodeCont::joinDoubleNodeConnections(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) {
00187     // magic values
00188     SUMOReal distanceThreshold = 7; // don't merge edges further apart
00189     SUMOReal lengthThreshold = 0.05; // don't merge edges with higher relative length-difference
00190 
00191     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00192         // count the edges to other nodes outgoing from the current node
00193         std::map<NBNode*, EdgeVector> connectionCount;
00194         const EdgeVector& outgoing = (*i).second->getOutgoingEdges();
00195         for (EdgeVector::const_iterator j=outgoing.begin(); j!=outgoing.end(); j++) {
00196             NBEdge* e = (*j);
00197             NBNode* connected = e->getToNode();
00198             if (connectionCount.find(connected)==connectionCount.end()) {
00199                 connectionCount[connected] = EdgeVector();
00200             }
00201             connectionCount[connected].push_back(e);
00202         }
00203         // check whether more than a single edge connect another node and join them
00204         std::map<NBNode*, EdgeVector>::iterator k;
00205         for (k=connectionCount.begin(); k!=connectionCount.end(); k++) {
00206             // possibly we do not have anything to join...
00207             if ((*k).second.size()<2) {
00208                 continue;
00209             }
00210             // for the edges that seem to be a single street,
00211             //  check whether the geometry is similar
00212             const EdgeVector& ev = (*k).second;
00213             const NBEdge* const first = ev.front();
00214             EdgeVector::const_iterator jci; // join candidate iterator
00215             for (jci=ev.begin()+1; jci!=ev.end(); ++jci) {
00216                 const SUMOReal relativeLengthDifference = fabs(first->getLoadedLength() - (*jci)->getLoadedLength()) / first->getLoadedLength();
00217                 if ((!first->isNearEnough2BeJoined2(*jci, distanceThreshold)) ||
00218                         (relativeLengthDifference > lengthThreshold) ||
00219                         (first->getSpeed() != (*jci)->getSpeed())
00220                         // @todo check vclass
00221                    ) {
00222                     break;
00223                 }
00224             }
00225             // @bug If there are 3 edges of which 2 can be joined, no joining will
00226             //   take place with the current implementation
00227             if (jci == ev.end()) {
00228                 ec.joinSameNodeConnectingEdges(dc, tlc, ev);
00229             }
00230         }
00231     }
00232 }
00233 
00234 
00235 void
00236 NBNodeCont::removeIsolatedRoads(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tc) {
00237     UNUSED_PARAMETER(tc);
00238     // Warn of isolated edges, i.e. a single edge with no connection to another edge
00239     int edgeCounter = 0;
00240     const std::vector<std::string> &edgeNames = ec.getAllNames();
00241     for (std::vector<std::string>::const_iterator it = edgeNames.begin(); it != edgeNames.end(); ++it) {
00242         // Test whether this node starts at a dead end, i.e. it has only one adjacent node
00243         // to which an edge exists and from which an edge may come.
00244         NBEdge* e = ec.retrieve(*it);
00245         if (e == 0) {
00246             continue;
00247         }
00248         NBNode* from = e->getFromNode();
00249         const EdgeVector& outgoingEdges = from->getOutgoingEdges();
00250         if (outgoingEdges.size() != 1) {
00251             // At this node, several edges or no edge start; so, this node is no dead end.
00252             continue;
00253         }
00254         const EdgeVector& incomingEdges = from->getIncomingEdges();
00255         if (incomingEdges.size() > 1) {
00256             // At this node, several edges end; so, this node is no dead end.
00257             continue;
00258         } else if (incomingEdges.size() == 1) {
00259             NBNode* fromNodeOfIncomingEdge = incomingEdges[0]->getFromNode();
00260             NBNode* toNodeOfOutgoingEdge = outgoingEdges[0]->getToNode();
00261             if (fromNodeOfIncomingEdge != toNodeOfOutgoingEdge) {
00262                 // At this node, an edge ends which is not the inverse direction of
00263                 // the starting node.
00264                 continue;
00265             }
00266         }
00267         // Now we know that the edge e starts a dead end.
00268         // Next we test if the dead end is isolated, i.e. does not lead to a junction
00269         bool hasJunction = false;
00270         EdgeVector road;
00271         NBEdge* eOld = 0;
00272         NBNode* to;
00273         std::set<NBNode*> adjacentNodes;
00274         do {
00275             road.push_back(e);
00276             eOld = e;
00277             from = e->getFromNode();
00278             to = e->getToNode();
00279             const EdgeVector& outgoingEdgesOfToNode = to->getOutgoingEdges();
00280             const EdgeVector& incomingEdgesOfToNode = to->getIncomingEdges();
00281             adjacentNodes.clear();
00282             for (EdgeVector::const_iterator itOfOutgoings=outgoingEdgesOfToNode.begin(); itOfOutgoings!=outgoingEdgesOfToNode.end(); ++itOfOutgoings) {
00283                 if ((*itOfOutgoings)->getToNode() != from        // The back path
00284                         && (*itOfOutgoings)->getToNode() != to   // A loop / dummy edge
00285                    ) {
00286                     e = *itOfOutgoings; // Probably the next edge
00287                 }
00288                 adjacentNodes.insert((*itOfOutgoings)->getToNode());
00289             }
00290             for (EdgeVector::const_iterator itOfIncomings=incomingEdgesOfToNode.begin(); itOfIncomings!=incomingEdgesOfToNode.end(); ++itOfIncomings) {
00291                 adjacentNodes.insert((*itOfIncomings)->getFromNode());
00292             }
00293             adjacentNodes.erase(to);  // Omit loops / dummy edges
00294             if (adjacentNodes.size() > 2) {
00295                 hasJunction = true;
00296             }
00297         } while (!hasJunction && eOld != e);
00298         if (!hasJunction) {
00299             edgeCounter +=  int(road.size());
00300             std::string warningString = "Removed a road without junctions: ";
00301             for (EdgeVector::iterator roadIt = road.begin(); roadIt != road.end(); ++roadIt) {
00302                 if (roadIt == road.begin()) {
00303                     warningString += (*roadIt)->getID();
00304                 } else {
00305                     warningString += ", " + (*roadIt)->getID();
00306                 }
00307 
00308                 NBNode* fromNode = (*roadIt)->getFromNode();
00309                 NBNode* toNode = (*roadIt)->getToNode();
00310                 ec.erase(dc, *roadIt);
00311                 if (fromNode->getIncomingEdges().size() == 0 && fromNode->getOutgoingEdges().size() == 0) {
00312                     // Node is empty; can be removed
00313                     erase(fromNode);
00314                 }
00315                 if (toNode->getIncomingEdges().size() == 0 && toNode->getOutgoingEdges().size() == 0) {
00316                     // Node is empty; can be removed
00317                     erase(toNode);
00318                 }
00319             }
00320             WRITE_WARNING(warningString);
00321         }
00322     }
00323     if (edgeCounter > 0 && !OptionsCont::getOptions().getBool("remove-edges.isolated")) {
00324         WRITE_WARNING("Detected isolated roads. Use the option --remove-edges.isolated to get a list of all affected edges.");
00325     }
00326 }
00327 
00328 
00329 unsigned int
00330 NBNodeCont::removeUnwishedNodes(NBDistrictCont& dc, NBEdgeCont& ec,
00331                                 NBJoinedEdgesMap& je, NBTrafficLightLogicCont& tlc,
00332                                 bool removeGeometryNodes) {
00333     unsigned int no = 0;
00334     std::vector<NBNode*> toRemove;
00335     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00336         NBNode* current = (*i).second;
00337         bool remove = false;
00338         std::vector<std::pair<NBEdge*, NBEdge*> > toJoin;
00339         // check for completely empty nodes
00340         if (current->getOutgoingEdges().size()==0 && current->getIncomingEdges().size()==0) {
00341             // remove if empty
00342             remove = true;
00343         }
00344         // check for nodes which are only geometry nodes
00345         if (removeGeometryNodes) {
00346             if ((current->getOutgoingEdges().size()==1 && current->getIncomingEdges().size()==1)
00347                     ||
00348                     (current->getOutgoingEdges().size()==2 && current->getIncomingEdges().size()==2)) {
00349                 // ok, one in, one out or two in, two out
00350                 //  -> ask the node whether to join
00351                 remove = current->checkIsRemovable();
00352                 if (remove) {
00353                     toJoin = current->getEdgesToJoin();
00354                 }
00355             }
00356         }
00357         // remove the node and join the geometries when wished
00358         if (!remove) {
00359             continue;
00360         }
00361         for (std::vector<std::pair<NBEdge*, NBEdge*> >::iterator j=toJoin.begin(); j!=toJoin.end(); j++) {
00362             NBEdge* begin = (*j).first;
00363             NBEdge* continuation = (*j).second;
00364             begin->append(continuation);
00365             continuation->getToNode()->replaceIncoming(continuation, begin, 0);
00366             tlc.replaceRemoved(continuation, -1, begin, -1);
00367             je.appended(begin->getID(), continuation->getID());
00368             ec.erase(dc, continuation);
00369         }
00370         toRemove.push_back(current);
00371         no++;
00372     }
00373     // erase all
00374     for (std::vector<NBNode*>::iterator j = toRemove.begin(); j!= toRemove.end(); ++j) {
00375         erase(*j);
00376     }
00377     return no;
00378 }
00379 
00380 
00381 // ----------- (Helper) methods for joining nodes
00382 void
00383 NBNodeCont::generateNodeClusters(SUMOReal maxDist, NodeClusters& into) const {
00384     std::set<NBNode*> visited;
00385     for (NodeCont::const_iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00386         std::vector<NBNode*> toProc;
00387         if (visited.find((*i).second)!=visited.end()) {
00388             continue;
00389         }
00390         toProc.push_back((*i).second);
00391         std::set<NBNode*> c;
00392         while (!toProc.empty()) {
00393             NBNode* n = toProc.back();
00394             toProc.pop_back();
00395             if (visited.find(n)!=visited.end()) {
00396                 continue;
00397             }
00398             c.insert(n);
00399             visited.insert(n);
00400             const EdgeVector& edges = n->getEdges();
00401             for (EdgeVector::const_iterator j=edges.begin(); j!=edges.end(); ++j) {
00402                 NBEdge* e = *j;
00403                 NBNode* s = 0;
00404                 if (n->hasIncoming(e)) {
00405                     s = e->getFromNode();
00406                 } else {
00407                     s = e->getToNode();
00408                 }
00409                 if (visited.find(s)!=visited.end()) {
00410                     continue;
00411                 }
00412                 if (n->getPosition().distanceTo(s->getPosition())<maxDist) {
00413                     toProc.push_back(s);
00414                 }
00415             }
00416         }
00417         if (c.size()<2) {
00418             continue;
00419         }
00420         into.push_back(c);
00421     }
00422 }
00423 
00424 
00425 void
00426 NBNodeCont::addJoinExclusion(const std::vector<std::string> &ids, bool check) {
00427     for (std::vector<std::string>::const_iterator it=ids.begin(); it!=ids.end(); it++) {
00428         // error handling has to take place here since joinExclusions could be
00429         // loaded from multiple files / command line
00430         if (myJoined.count(*it) > 0) {
00431             WRITE_WARNING("Ignoring join exclusion for node '" + *it +  "' since it already occured in a list of nodes to be joined");
00432         } else if (check && retrieve(*it) == 0) {
00433             WRITE_WARNING("Ignoring join exclusion for unknown node '" + *it + "'");
00434         } else {
00435             myJoinExclusions.insert(*it);
00436         }
00437     }
00438 }
00439 
00440 
00441 void
00442 NBNodeCont::addCluster2Join(std::set<std::string> cluster) {
00443     // error handling has to take place here since joins could be loaded from multiple files
00444     for (std::set<std::string>::const_iterator it = cluster.begin(); it != cluster.end(); it++) {
00445         if (myJoinExclusions.count(*it) > 0) {
00446             WRITE_WARNING("Ignoring join-cluster because node '" + *it + "' was already excluded from joining");
00447             return;
00448         } else if (myJoined.count(*it) > 0) {
00449             WRITE_WARNING("Ignoring join-cluster because node '" + *it + "' already occured in another join-cluster");
00450             return;
00451         } else {
00452             myJoined.insert(*it);
00453         }
00454     }
00455     myClusters2Join.push_back(cluster);
00456 }
00457 
00458 
00459 unsigned int
00460 NBNodeCont::joinLoadedClusters(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) {
00461     NodeClusters clusters;
00462     for (std::vector<std::set<std::string> >::iterator it = myClusters2Join.begin(); it != myClusters2Join.end(); it++) {
00463         // verify loaded cluster
00464         std::set<NBNode*> cluster;
00465         for (std::set<std::string>::iterator it_id = it->begin(); it_id != it->end(); it_id++) {
00466             NBNode* node = retrieve(*it_id);
00467             if (node == 0) {
00468                 WRITE_WARNING("Ignoring unknown node '" + *it_id + "' while joining");
00469             } else {
00470                 cluster.insert(node);
00471             }
00472         }
00473         if (cluster.size() > 1) {
00474             clusters.push_back(cluster);
00475         }
00476     }
00477     joinNodeClusters(clusters, dc, ec, tlc);
00478     return (int)clusters.size();
00479 }
00480 
00481 
00482 unsigned int
00483 NBNodeCont::joinJunctions(SUMOReal maxdist, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) {
00484     NodeClusters cands;
00485     NodeClusters clusters;
00486     generateNodeClusters(maxdist, cands);
00487     for (NodeClusters::iterator i=cands.begin(); i!=cands.end(); ++i) {
00488         const std::set<NBNode*> &candCluster = (*i);
00489         std::set<NBNode*> cluster;
00490         // remove nodes with degree = 2 at fringe of the cluster (at least one edge leads to a non-cluster node)
00491         for (std::set<NBNode*>::const_iterator j=candCluster.begin(); j!=candCluster.end(); j++) {
00492             NBNode* n = *j;
00493             if (n->getIncomingEdges().size() == 1 &&
00494                     n->getOutgoingEdges().size() == 1 &&
00495                     (!cluster.count(n->getIncomingEdges()[0]->getFromNode()) ||
00496                      !cluster.count(n->getOutgoingEdges()[0]->getToNode()))) {
00497                 continue;
00498             } else if (myJoinExclusions.count(n->getID()) > 0) {
00499                 continue;
00500             } else {
00501                 cluster.insert(n);
00502             }
00503         }
00504         if (cluster.size() > 1) {
00505             clusters.push_back(cluster);
00506         }
00507     }
00508     joinNodeClusters(clusters, dc, ec, tlc);
00509     return (int)clusters.size();
00510 }
00511 
00512 
00513 void
00514 NBNodeCont::joinNodeClusters(NodeClusters clusters,
00515                              NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) {
00516     for (NodeClusters::iterator i=clusters.begin(); i!=clusters.end(); ++i) {
00517         std::set<NBNode*> cluster = *i;
00518         assert(cluster.size() > 1);
00519         Position pos;
00520         bool setTL;
00521         std::string id;
00522         analyzeCluster(cluster, id, pos, setTL);
00523         if (!insert(id, pos)) {
00524             // should not fail
00525             WRITE_WARNING("Could not join junctions " + id);
00526             continue;
00527         }
00528         NBNode* newNode = retrieve(id);
00529         if (setTL) {
00530             NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, newNode);
00531             if (!tlc.insert(tlDef)) {
00532                 // actually, nothing should fail here
00533                 delete tlDef;
00534                 throw ProcessError("Could not allocate tls '" + id + "'.");
00535             }
00536         }
00537         // perform the merging
00538         for (std::set<NBNode*>::const_iterator j=cluster.begin(); j!=cluster.end(); j++) {
00539             merge(*j, newNode, dc, ec);
00540         }
00541     }
00542 }
00543 
00544 
00545 void
00546 NBNodeCont::analyzeCluster(std::set<NBNode*> cluster, std::string& id, Position& pos, bool& hasTLS) {
00547     id = "cluster";
00548     hasTLS = false;
00549     std::vector<std::string> member_ids;
00550     for (std::set<NBNode*>::const_iterator j=cluster.begin(); j!=cluster.end(); j++) {
00551         member_ids.push_back((*j)->getID());
00552         pos.add((*j)->getPosition());
00553         // add a traffic light if any of the cluster members was controlled
00554         if ((*j)->isTLControlled()) {
00555             hasTLS = true;
00556         }
00557     }
00558     pos.mul(1.0 / cluster.size());
00559     // need to sort the member names to make the output deterministic
00560     sort(member_ids.begin(), member_ids.end());
00561     for (std::vector<std::string>::iterator j=member_ids.begin(); j!=member_ids.end(); j++) {
00562         id = id + "_" + (*j);
00563     }
00564 }
00565 
00566 
00567 void
00568 NBNodeCont::merge(NBNode* moved, NBNode* target, NBDistrictCont& dc, NBEdgeCont& ec) {
00569     // deleting edges changes in the underlying EdgeVector so we have to make a copy
00570     EdgeVector incoming = moved->getIncomingEdges();
00571     for (EdgeVector::iterator it = incoming.begin(); it != incoming.end(); it++) {
00572         remapEdge(*it, (*it)->getFromNode(), target, dc, ec);
00573     }
00574     // deleting edges changes in the underlying EdgeVector so we have to make a copy
00575     EdgeVector outgoing = moved->getOutgoingEdges();
00576     for (EdgeVector::iterator it = outgoing.begin(); it != outgoing.end(); it++) {
00577         remapEdge(*it, target, (*it)->getToNode(), dc, ec);
00578     }
00579     erase(moved);
00580 }
00581 
00582 
00583 void
00584 NBNodeCont::remapEdge(NBEdge* oldEdge, NBNode* from, NBNode* to, NBDistrictCont& dc, NBEdgeCont& ec) {
00585     if (to == from) {
00586         // @todo remap connections
00587         ec.erase(dc, oldEdge);
00588     } else {
00589         NBEdge* remapped = new NBEdge(oldEdge->getID(), from, to, oldEdge);
00590         remapped->setGeometry(oldEdge->getGeometry());
00591         ec.erase(dc, oldEdge); // erase first so we can reuse the name
00592         ec.insert(remapped);
00593     }
00594 }
00595 
00596 
00597 // ----------- (Helper) methods for guessing/computing traffic lights
00598 bool
00599 NBNodeCont::shouldBeTLSControlled(const std::set<NBNode*> &c) const {
00600     unsigned int noIncoming = 0;
00601     unsigned int noOutgoing = 0;
00602     bool tooFast = false;
00603     SUMOReal f = 0;
00604     std::set<NBEdge*> seen;
00605     for (std::set<NBNode*>::const_iterator j=c.begin(); j!=c.end(); ++j) {
00606         const EdgeVector& edges = (*j)->getEdges();
00607         for (EdgeVector::const_iterator k=edges.begin(); k!=edges.end(); ++k) {
00608             if (c.find((*k)->getFromNode())!=c.end()&&c.find((*k)->getToNode())!=c.end()) {
00609                 continue;
00610             }
00611             if ((*j)->hasIncoming(*k)) {
00612                 ++noIncoming;
00613                 f += (SUMOReal)(*k)->getNumLanes() * (*k)->getLaneSpeed(0);
00614             } else {
00615                 ++noOutgoing;
00616             }
00617             if ((*k)->getLaneSpeed(0)*3.6>79) {
00618                 tooFast = true;
00619             }
00620         }
00621     }
00622     return !tooFast && f>=150./3.6 && c.size()!=0;
00623 }
00624 
00625 
00626 void
00627 NBNodeCont::guessTLs(OptionsCont& oc, NBTrafficLightLogicCont& tlc) {
00628     // build list of definitely not tls-controlled junctions
00629     std::vector<NBNode*> ncontrolled;
00630     if (oc.isSet("tls.unset")) {
00631         std::vector<std::string> notTLControlledNodes = oc.getStringVector("tls.unset");
00632         for (std::vector<std::string>::const_iterator i=notTLControlledNodes.begin(); i!=notTLControlledNodes.end(); ++i) {
00633             NBNode* n = NBNodeCont::retrieve(*i);
00634             if (n==0) {
00635                 throw ProcessError(" The node '" + *i + "' to set as not-controlled is not known.");
00636             }
00637             std::set<NBTrafficLightDefinition*> tls = n->getControllingTLS();
00638             for (std::set<NBTrafficLightDefinition*>::const_iterator j=tls.begin(); j!=tls.end(); ++j) {
00639                 (*j)->removeNode(n);
00640             }
00641             n->removeTrafficLights();
00642             ncontrolled.push_back(n);
00643         }
00644     }
00645 
00646     // loop#1 checking whether the node shall be tls controlled,
00647     //  because it is assigned to a district
00648     if (oc.exists("tls.taz-nodes")&&oc.getBool("tls.taz-nodes")) {
00649         for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00650             NBNode* cur = (*i).second;
00651             if (cur->isNearDistrict()&&find(ncontrolled.begin(), ncontrolled.end(), cur)==ncontrolled.end()) {
00652                 setAsTLControlled(cur, tlc);
00653             }
00654         }
00655     }
00656 
00657     // maybe no tls shall be guessed
00658     if (!oc.getBool("tls.guess")) {
00659         return;
00660     }
00661 
00662     // guess joined tls first, if wished
00663     if (oc.getBool("tls-guess.joining")) {
00664         // get node clusters
00665         SUMOReal MAXDIST = 25;
00666         std::vector<std::set<NBNode*> > cands;
00667         generateNodeClusters(MAXDIST, cands);
00668         // check these candidates (clusters) whether they should be controlled by a tls
00669         for (std::vector<std::set<NBNode*> >::iterator i=cands.begin(); i!=cands.end();) {
00670             std::set<NBNode*> &c = (*i);
00671             // regard only junctions which are not yet controlled and are not
00672             //  forbidden to be controlled
00673             for (std::set<NBNode*>::iterator j=c.begin(); j!=c.end();) {
00674                 if ((*j)->isTLControlled()||find(ncontrolled.begin(), ncontrolled.end(), *j)!=ncontrolled.end()) {
00675                     c.erase(j++);
00676                 } else {
00677                     ++j;
00678                 }
00679             }
00680             // check whether the cluster should be controlled
00681             if (!shouldBeTLSControlled(c)) {
00682                 i = cands.erase(i);
00683             } else {
00684                 ++i;
00685             }
00686         }
00687         // cands now only contain sets of junctions that shall be joined into being tls-controlled
00688         unsigned int index = 0;
00689         for (std::vector<std::set<NBNode*> >::iterator i=cands.begin(); i!=cands.end(); ++i) {
00690             std::vector<NBNode*> nodes;
00691             for (std::set<NBNode*>::iterator j=(*i).begin(); j!=(*i).end(); j++) {
00692                 nodes.push_back(*j);
00693             }
00694             std::string id = "joinedG_" + toString(index++);
00695             NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes);
00696             if (!tlc.insert(tlDef)) {
00697                 // actually, nothing should fail here
00698                 WRITE_WARNING("Could not build guessed, joined tls");
00699                 delete tlDef;
00700                 return;
00701             }
00702         }
00703     }
00704 
00705     // guess tls
00706     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00707         NBNode* cur = (*i).second;
00708         //  do nothing if already is tl-controlled
00709         if (cur->isTLControlled()) {
00710             continue;
00711         }
00712         // do nothing if in the list of explicit non-controlled junctions
00713         if (find(ncontrolled.begin(), ncontrolled.end(), cur)!=ncontrolled.end()) {
00714             continue;
00715         }
00716         std::set<NBNode*> c;
00717         c.insert(cur);
00718         if (!shouldBeTLSControlled(c)||cur->getIncomingEdges().size()<3) {
00719             continue;
00720         }
00721         setAsTLControlled((*i).second, tlc);
00722     }
00723 }
00724 
00725 
00726 void
00727 NBNodeCont::joinTLS(NBTrafficLightLogicCont& tlc) {
00728     SUMOReal MAXDIST = 25;
00729     std::vector<std::set<NBNode*> > cands;
00730     generateNodeClusters(MAXDIST, cands);
00731     unsigned int index = 0;
00732     for (std::vector<std::set<NBNode*> >::iterator i=cands.begin(); i!=cands.end(); ++i) {
00733         std::set<NBNode*> &c = (*i);
00734         for (std::set<NBNode*>::iterator j=c.begin(); j!=c.end();) {
00735             if (!(*j)->isTLControlled()) {
00736                 c.erase(j++);
00737             } else {
00738                 ++j;
00739             }
00740         }
00741         if (c.size()<2) {
00742             continue;
00743         }
00744         for (std::set<NBNode*>::iterator j=c.begin(); j!=c.end(); ++j) {
00745             std::set<NBTrafficLightDefinition*> tls = (*j)->getControllingTLS();
00746             (*j)->removeTrafficLights();
00747             for (std::set<NBTrafficLightDefinition*>::iterator k=tls.begin(); k!=tls.end(); ++k) {
00748                 tlc.removeFully((*j)->getID());
00749             }
00750         }
00751         std::string id = "joinedS_" + toString(index++);
00752         std::vector<NBNode*> nodes;
00753         for (std::set<NBNode*>::iterator j=c.begin(); j!=c.end(); j++) {
00754             nodes.push_back(*j);
00755         }
00756         NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes);
00757         if (!tlc.insert(tlDef)) {
00758             // actually, nothing should fail here
00759             WRITE_WARNING("Could not build a joined tls.");
00760             delete tlDef;
00761             return;
00762         }
00763     }
00764 }
00765 
00766 
00767 void
00768 NBNodeCont::setAsTLControlled(NBNode* node, NBTrafficLightLogicCont& tlc, std::string id) {
00769     if (id=="") {
00770         id = node->getID();
00771     }
00772     NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, node);
00773     if (!tlc.insert(tlDef)) {
00774         // actually, nothing should fail here
00775         WRITE_WARNING("Building a tl-logic for node '" + id + "' twice is not possible.");
00776         delete tlDef;
00777         return;
00778     }
00779 }
00780 
00781 
00782 // -----------
00783 void
00784 NBNodeCont::computeLanes2Lanes() {
00785     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00786         (*i).second->computeLanes2Lanes();
00787     }
00788 }
00789 
00790 
00791 // computes the "wheel" of incoming and outgoing edges for every node
00792 void
00793 NBNodeCont::computeLogics(const NBEdgeCont& ec, OptionsCont& oc) {
00794     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00795         (*i).second->computeLogic(ec, oc);
00796     }
00797 }
00798 
00799 
00800 void
00801 NBNodeCont::sortNodesEdges(bool leftHand) {
00802     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00803         (*i).second->sortNodesEdges(leftHand);
00804     }
00805 }
00806 
00807 
00808 void
00809 NBNodeCont::computeNodeTypes(const NBTypeCont& tc) {
00810     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00811         (*i).second->computeType(tc);
00812     }
00813 }
00814 
00815 
00816 void
00817 NBNodeCont::computePriorities() {
00818     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00819         (*i).second->computePriorities();
00820     }
00821 }
00822 
00823 
00824 void
00825 NBNodeCont::clear() {
00826     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00827         delete((*i).second);
00828     }
00829     myNodes.clear();
00830     for (std::set<NBNode*>::iterator i = myExtractedNodes.begin(); i!= myExtractedNodes.end(); i++) {
00831         delete(*i);
00832     }
00833     myExtractedNodes.clear();
00834 }
00835 
00836 
00837 std::string
00838 NBNodeCont::getFreeID() {
00839     // !!! not guaranteed to be free
00840     std::string ret = "SUMOGenerated" + toString<int>(size());
00841     assert(retrieve(ret)==0);
00842     return ret;
00843 }
00844 
00845 
00846 void
00847 NBNodeCont::computeNodeShapes(bool leftHand) {
00848     for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
00849         (*i).second->computeNodeShape(leftHand);
00850     }
00851 }
00852 
00853 
00854 bool
00855 NBNodeCont::mayNeedOnRamp(OptionsCont& oc, NBNode* cur) const {
00856     if (cur->getIncomingEdges().size()==2&&cur->getOutgoingEdges().size()==1) {
00857         // may be an on-ramp
00858         NBEdge* pot_highway = cur->getIncomingEdges()[0];
00859         NBEdge* pot_ramp = cur->getIncomingEdges()[1];
00860         NBEdge* cont = cur->getOutgoingEdges()[0];
00861 
00862         // do not build ramps on connectors
00863         if (pot_highway->isMacroscopicConnector()||pot_ramp->isMacroscopicConnector()||cont->isMacroscopicConnector()) {
00864             return false;
00865         }
00866 
00867         // check whether a lane is missing
00868         if (pot_highway->getNumLanes()+pot_ramp->getNumLanes()<=cont->getNumLanes()) {
00869             return false;
00870         }
00871 
00872         // assign highway/ramp properly
00873         if (pot_highway->getSpeed()<pot_ramp->getSpeed()) {
00874             std::swap(pot_highway, pot_ramp);
00875         } else if (pot_highway->getSpeed()==pot_ramp->getSpeed()
00876                    &&
00877                    pot_highway->getNumLanes()<pot_ramp->getNumLanes()) {
00878 
00879             std::swap(pot_highway, pot_ramp);
00880         }
00881 
00882         // check conditions
00883         // is it really a highway?
00884         SUMOReal minHighwaySpeed = oc.getFloat("ramps.min-highway-speed");
00885         if (pot_highway->getSpeed()<minHighwaySpeed || cont->getSpeed()<minHighwaySpeed) {
00886             return false;
00887         }
00888         // is it really a ramp?
00889         SUMOReal maxRampSpeed = oc.getFloat("ramps.max-ramp-speed");
00890         if (maxRampSpeed>0 && maxRampSpeed<pot_ramp->getSpeed()) {
00891             return false;
00892         }
00893 
00894         // ok, may be
00895         return true;
00896     }
00897     return false;
00898 }
00899 
00900 
00901 bool
00902 NBNodeCont::buildOnRamp(OptionsCont& oc, NBNode* cur,
00903                         NBEdgeCont& ec, NBDistrictCont& dc,
00904                         EdgeVector& incremented) {
00905     NBEdge* pot_highway = cur->getIncomingEdges()[0];
00906     NBEdge* pot_ramp = cur->getIncomingEdges()[1];
00907     NBEdge* cont = cur->getOutgoingEdges()[0];
00908     bool bEdgeDeleted = false;
00909 
00910     // assign highway/ramp properly
00911     if (pot_highway->getSpeed()<pot_ramp->getSpeed()) {
00912         std::swap(pot_highway, pot_ramp);
00913     } else if (pot_highway->getSpeed()==pot_ramp->getSpeed()
00914                &&
00915                pot_highway->getNumLanes()<pot_ramp->getNumLanes()) {
00916 
00917         std::swap(pot_highway, pot_ramp);
00918     }
00919 
00920     // compute the number of lanes to append
00921     int toAdd = (pot_ramp->getNumLanes() + pot_highway->getNumLanes()) - cont->getNumLanes();
00922     if (toAdd<=0) {
00923         return false;
00924     }
00925 
00926     //
00927     if (cont->getGeometry().length()-POSITION_EPS<=oc.getFloat("ramps.ramp-length")) {
00928         // the edge is shorter than the wished ramp
00929         //  append a lane only
00930         if (find(incremented.begin(), incremented.end(), cont)==incremented.end()) {
00931             cont->incLaneNo(toAdd);
00932             incremented.push_back(cont);
00933             if (!pot_highway->addLane2LaneConnections(0, cont, pot_ramp->getNumLanes(),
00934                     MIN2(cont->getNumLanes()-pot_ramp->getNumLanes(), pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, true, true)) {
00935                 throw ProcessError("Could not set connection!");
00936             }
00937             if (!pot_ramp->addLane2LaneConnections(0, cont, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true, true)) {
00938                 throw ProcessError("Could not set connection!");
00939             }
00940             //
00941             cont->invalidateConnections(true);
00942             const EdgeVector& o1 = cont->getToNode()->getOutgoingEdges();
00943             if (o1.size()==1&&o1[0]->getNumLanes()<cont->getNumLanes()) {
00944                 cont->addLane2LaneConnections(cont->getNumLanes()-o1[0]->getNumLanes(),
00945                                               o1[0], 0, o1[0]->getNumLanes(), NBEdge::L2L_VALIDATED);
00946             }
00947             //
00948             if (cont->getLaneSpreadFunction()==LANESPREAD_CENTER) {
00949                 try {
00950                     PositionVector g = cont->getGeometry();
00951                     g.move2side(SUMO_const_laneWidthAndOffset);
00952                     cont->setGeometry(g);
00953                 } catch (InvalidArgument&) {
00954                     WRITE_WARNING("For edge '" + cont->getID() + "': could not compute shape.");
00955                 }
00956             }
00957         }
00958         PositionVector p = pot_ramp->getGeometry();
00959         p.pop_back();
00960         p.push_back(cont->getFromNode()->getPosition());
00961         pot_ramp->setGeometry(p);
00962     } else {
00963         bEdgeDeleted=true;
00964         // there is enough place to build a ramp; do it
00965         NBNode* rn =
00966             new NBNode(cont->getID() + "-AddedOnRampNode",
00967                        cont->getGeometry().positionAtLengthPosition(
00968                            oc.getFloat("ramps.ramp-length")));
00969         if (!insert(rn)) {
00970             throw ProcessError("Ups - could not build on-ramp for edge '" + pot_highway->getID() + "' (node could not be build)!");
00971         }
00972         std::string name = cont->getID();
00973         bool ok = ec.splitAt(dc, cont, rn,
00974                              cont->getID()+"-AddedOnRampEdge", cont->getID(),
00975                              cont->getNumLanes()+toAdd, cont->getNumLanes());
00976         if (!ok) {
00977             WRITE_ERROR("Ups - could not build on-ramp for edge '" + pot_highway->getID() + "'!");
00978             return true;
00979         } else {
00980             NBEdge* added_ramp = ec.retrieve(name+"-AddedOnRampEdge");
00981             NBEdge* added = ec.retrieve(name);
00982             incremented.push_back(added_ramp);
00983             if (added_ramp->getNumLanes()!=added->getNumLanes()) {
00984                 int off = added_ramp->getNumLanes()-added->getNumLanes();
00985                 if (!added_ramp->addLane2LaneConnections(off, added, 0, added->getNumLanes(), NBEdge::L2L_VALIDATED, true)) {
00986                     throw ProcessError("Could not set connection!");
00987                 }
00988                 if (added_ramp->getLaneSpreadFunction()==LANESPREAD_CENTER) {
00989                     try {
00990                         PositionVector g = added_ramp->getGeometry();
00991                         SUMOReal factor = SUMO_const_laneWidthAndOffset * (SUMOReal)(toAdd-1) + SUMO_const_halfLaneAndOffset * (SUMOReal)(toAdd%2);
00992                         g.move2side(factor);
00993                         added_ramp->setGeometry(g);
00994                     } catch (InvalidArgument&) {
00995                         WRITE_WARNING("For edge '" + added_ramp->getID() + "': could not compute shape.");
00996                     }
00997                 }
00998             } else {
00999                 if (!added_ramp->addLane2LaneConnections(0, added, 0, added_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true)) {
01000                     throw ProcessError("Could not set connection!");
01001                 }
01002             }
01003             if (!pot_highway->addLane2LaneConnections(0, added_ramp, pot_ramp->getNumLanes(),
01004                     MIN2(added_ramp->getNumLanes()-pot_ramp->getNumLanes(), pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, false, true)) {
01005                 throw ProcessError("Could not set connection!");
01006 
01007             }
01008             if (!pot_ramp->addLane2LaneConnections(0, added_ramp, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true, true)) {
01009                 throw ProcessError("Could not set connection!");
01010             }
01011             PositionVector p = pot_ramp->getGeometry();
01012             p.pop_back();
01013             p.push_back(added_ramp->getFromNode()->getPosition());//added_ramp->getLaneShape(0).at(0));
01014             pot_ramp->setGeometry(p);
01015         }
01016     }
01017     return bEdgeDeleted;
01018 }
01019 
01020 
01021 void
01022 NBNodeCont::buildOffRamp(OptionsCont& oc, NBNode* cur,
01023                          NBEdgeCont& ec, NBDistrictCont& dc,
01024                          EdgeVector& incremented) {
01025     NBEdge* pot_highway = cur->getOutgoingEdges()[0];
01026     NBEdge* pot_ramp = cur->getOutgoingEdges()[1];
01027     NBEdge* prev = cur->getIncomingEdges()[0];
01028     // assign highway/ramp properly
01029     if (pot_highway->getSpeed()<pot_ramp->getSpeed()) {
01030         std::swap(pot_highway, pot_ramp);
01031     } else if (pot_highway->getSpeed()==pot_ramp->getSpeed()
01032                &&
01033                pot_highway->getNumLanes()<pot_ramp->getNumLanes()) {
01034 
01035         std::swap(pot_highway, pot_ramp);
01036     }
01037     // compute the number of lanes to append
01038     int toAdd = (pot_ramp->getNumLanes() + pot_highway->getNumLanes()) - prev->getNumLanes();
01039     if (toAdd<=0) {
01040         return;
01041     }
01042     // append on-ramp
01043     if (prev->getGeometry().length()-POSITION_EPS<=oc.getFloat("ramps.ramp-length")) {
01044         // the edge is shorter than the wished ramp
01045         //  append a lane only
01046         if (find(incremented.begin(), incremented.end(), prev)==incremented.end()) {
01047             incremented.push_back(prev);
01048             prev->incLaneNo(toAdd);
01049             prev->invalidateConnections(true);
01050             if (!prev->addLane2LaneConnections(pot_ramp->getNumLanes(), pot_highway, 0,
01051                                                MIN2(prev->getNumLanes()-1, pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, true)) {
01052 
01053                 throw ProcessError("Could not set connection!");
01054 
01055             }
01056             if (!prev->addLane2LaneConnections(0, pot_ramp, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, false)) {
01057                 throw ProcessError("Could not set connection!");
01058 
01059             }
01060             if (prev->getLaneSpreadFunction()==LANESPREAD_CENTER) {
01061                 try {
01062                     PositionVector g = prev->getGeometry();
01063                     g.move2side(SUMO_const_laneWidthAndOffset);
01064                     prev->setGeometry(g);
01065                 } catch (InvalidArgument&) {
01066                     WRITE_WARNING("For edge '" + prev->getID() + "': could not compute shape.");
01067                 }
01068             }
01069         }
01070         PositionVector p = pot_ramp->getGeometry();
01071         p.pop_front();
01072         p.push_front(prev->getToNode()->getPosition());//added_ramp->getLaneShape(0).at(-1));
01073         pot_ramp->setGeometry(p);
01074     } else {
01075         Position pos =
01076             prev->getGeometry().positionAtLengthPosition(
01077                 prev->getGeometry().length()-oc.getFloat("ramps.ramp-length"));
01078         NBNode* rn = new NBNode(prev->getID() + "-AddedOffRampNode", pos);
01079         if (!insert(rn)) {
01080             throw ProcessError("Ups - could not build off-ramp for edge '" + pot_highway->getID() + "' (node could not be build)!");
01081 
01082         }
01083         std::string name = prev->getID();
01084         bool ok = ec.splitAt(dc, prev, rn,
01085                              prev->getID(), prev->getID()+"-AddedOffRampEdge",
01086                              prev->getNumLanes(), prev->getNumLanes()+toAdd);
01087         if (!ok) {
01088             WRITE_ERROR("Ups - could not build on-ramp for edge '" + pot_highway->getID() + "'!");
01089             return;
01090         } else {
01091             NBEdge* added_ramp = ec.retrieve(name+"-AddedOffRampEdge");
01092             NBEdge* added = ec.retrieve(name);
01093             if (added_ramp->getNumLanes()!=added->getNumLanes()) {
01094                 incremented.push_back(added_ramp);
01095                 int off = added_ramp->getNumLanes()-added->getNumLanes();
01096                 if (!added->addLane2LaneConnections(0, added_ramp, off, added->getNumLanes(), NBEdge::L2L_VALIDATED, true)) {
01097                     throw ProcessError("Could not set connection!");
01098 
01099                 }
01100                 if (added_ramp->getLaneSpreadFunction()==LANESPREAD_CENTER) {
01101                     try {
01102                         PositionVector g = added_ramp->getGeometry();
01103                         SUMOReal factor = SUMO_const_laneWidthAndOffset * (SUMOReal)(toAdd-1) + SUMO_const_halfLaneAndOffset * (SUMOReal)(toAdd%2);
01104                         g.move2side(factor);
01105                         added_ramp->setGeometry(g);
01106                     } catch (InvalidArgument&) {
01107                         WRITE_WARNING("For edge '" + added_ramp->getID() + "': could not compute shape.");
01108                     }
01109                 }
01110             } else {
01111                 if (!added->addLane2LaneConnections(0, added_ramp, 0, added_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true)) {
01112                     throw ProcessError("Could not set connection!");
01113                 }
01114             }
01115             if (!added_ramp->addLane2LaneConnections(pot_ramp->getNumLanes(), pot_highway, 0,
01116                     MIN2(added_ramp->getNumLanes()-pot_ramp->getNumLanes(), pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, true)) {
01117                 throw ProcessError("Could not set connection!");
01118             }
01119             if (!added_ramp->addLane2LaneConnections(0, pot_ramp, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, false)) {
01120                 throw ProcessError("Could not set connection!");
01121 
01122             }
01123             PositionVector p = pot_ramp->getGeometry();
01124             p.pop_front();
01125             p.push_front(added_ramp->getToNode()->getPosition());//added_ramp->getLaneShape(0).at(-1));
01126             pot_ramp->setGeometry(p);
01127         }
01128     }
01129 }
01130 
01131 
01132 bool
01133 NBNodeCont::mayNeedOffRamp(OptionsCont& oc, NBNode* cur) const {
01134     if (cur->getIncomingEdges().size()==1&&cur->getOutgoingEdges().size()==2) {
01135         // may be an off-ramp
01136         NBEdge* pot_highway = cur->getOutgoingEdges()[0];
01137         NBEdge* pot_ramp = cur->getOutgoingEdges()[1];
01138         NBEdge* prev = cur->getIncomingEdges()[0];
01139 
01140         // do not build ramps on connectors
01141         if (pot_highway->isMacroscopicConnector()||pot_ramp->isMacroscopicConnector()||prev->isMacroscopicConnector()) {
01142             return false;
01143         }
01144 
01145         // check whether a lane is missing
01146         if (pot_highway->getNumLanes()+pot_ramp->getNumLanes()<=prev->getNumLanes()) {
01147             return false;
01148         }
01149 
01150         // assign highway/ramp properly
01151         if (pot_highway->getSpeed()<pot_ramp->getSpeed()) {
01152             std::swap(pot_highway, pot_ramp);
01153         } else if (pot_highway->getSpeed()==pot_ramp->getSpeed()
01154                    &&
01155                    pot_highway->getNumLanes()<pot_ramp->getNumLanes()) {
01156 
01157             std::swap(pot_highway, pot_ramp);
01158         }
01159 
01160         // check conditions
01161         // is it really a highway?
01162         SUMOReal minHighwaySpeed = oc.getFloat("ramps.min-highway-speed");
01163         if (pot_highway->getSpeed()<minHighwaySpeed || prev->getSpeed()<minHighwaySpeed) {
01164             return false;
01165         }
01166         // is it really a ramp?
01167         SUMOReal maxRampSpeed = oc.getFloat("ramps.max-ramp-speed");
01168         if (maxRampSpeed>0 && maxRampSpeed<pot_ramp->getSpeed()) {
01169             return false;
01170         }
01171 
01172         return true;
01173     }
01174     return false;
01175 }
01176 
01177 
01178 void
01179 NBNodeCont::checkHighwayRampOrder(NBEdge *&pot_highway, NBEdge *&pot_ramp) {
01180     if (pot_highway->getSpeed()<pot_ramp->getSpeed()) {
01181         std::swap(pot_highway, pot_ramp);
01182     } else if (pot_highway->getSpeed()==pot_ramp->getSpeed()
01183                &&
01184                pot_highway->getNumLanes()<pot_ramp->getNumLanes()) {
01185 
01186         std::swap(pot_highway, pot_ramp);
01187     }
01188 }
01189 
01190 
01191 void
01192 NBNodeCont::guessRamps(OptionsCont& oc, NBEdgeCont& ec,
01193                        NBDistrictCont& dc) {
01194     EdgeVector incremented;
01195     bool bEdgeDeleted=false;
01196     // check whether on-off ramps shall be guessed
01197     if (oc.getBool("ramps.guess")) {
01198         for (NodeCont::iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
01199             NBNode* cur = (*i).second;
01200             if (mayNeedOnRamp(oc, cur)) {
01201                 buildOnRamp(oc, cur, ec, dc, incremented);
01202             }
01203             if (mayNeedOffRamp(oc, cur)) {
01204                 buildOffRamp(oc, cur, ec, dc, incremented);
01205             }
01206         }
01207     }
01208     // check whether on-off ramps shall be guessed
01209     if (oc.isSet("ramps.set")) {
01210         std::vector<std::string> edges = oc.getStringVector("ramps.set");
01211         for (std::vector<std::string>::iterator i=edges.begin(); i!=edges.end(); ++i) {
01212             NBEdge* e = ec.retrieve(*i);
01213             if (e==0) {
01214                 WRITE_WARNING("Can not build on ramp on edge '" + *i + "' - the edge is not known.");
01215                 continue;
01216             }
01217             NBNode* from = e->getFromNode();
01218             if (from->getIncomingEdges().size()==2&&from->getOutgoingEdges().size()==1) {
01219                 bEdgeDeleted = buildOnRamp(oc, from, ec, dc, incremented);
01220             }
01221             // load edge again to check offramps
01222             e = ec.retrieve(*i);
01223             if (e==0) {
01224                 WRITE_WARNING("Can not build off ramp on edge '" + *i + "' - the edge is not known.");
01225                 continue;
01226             }
01227             NBNode* to = e->getToNode();
01228             if (to->getIncomingEdges().size()==1&&to->getOutgoingEdges().size()==2) {
01229                 buildOffRamp(oc, to, ec, dc, incremented);
01230             }
01231         }
01232     }
01233 }
01234 
01235 
01236 void
01237 NBNodeCont::printBuiltNodesStatistics() const throw() {
01238     int numUnregulatedJunctions = 0;
01239     int numDeadEndJunctions = 0;
01240     int numPriorityJunctions = 0;
01241     int numRightBeforeLeftJunctions = 0;
01242     for (NodeCont::const_iterator i=myNodes.begin(); i!=myNodes.end(); i++) {
01243         switch ((*i).second->getType()) {
01244         case NODETYPE_NOJUNCTION:
01245             ++numUnregulatedJunctions;
01246             break;
01247         case NODETYPE_DEAD_END:
01248             ++numDeadEndJunctions;
01249             break;
01250         case NODETYPE_PRIORITY_JUNCTION:
01251         case NODETYPE_TRAFFIC_LIGHT:
01252             ++numPriorityJunctions;
01253             break;
01254         case NODETYPE_RIGHT_BEFORE_LEFT:
01255             ++numRightBeforeLeftJunctions;
01256             break;
01257         case NODETYPE_DISTRICT:
01258             ++numRightBeforeLeftJunctions;
01259             break;
01260         case NODETYPE_UNKNOWN:
01261             break;
01262         default:
01263             break;
01264         }
01265     }
01266     WRITE_MESSAGE(" Node type statistics:");
01267     WRITE_MESSAGE("  Unregulated junctions       : " + toString(numUnregulatedJunctions));
01268     if (numDeadEndJunctions > 0) {
01269         WRITE_MESSAGE("  Dead-end junctions          : " + toString(numDeadEndJunctions));
01270     }
01271     WRITE_MESSAGE("  Priority junctions          : " + toString(numPriorityJunctions));
01272     WRITE_MESSAGE("  Right-before-left junctions : " + toString(numRightBeforeLeftJunctions));
01273 }
01274 
01275 
01276 std::vector<std::string>
01277 NBNodeCont::getAllNames() const throw() {
01278     std::vector<std::string> ret;
01279     for (NodeCont::const_iterator i=myNodes.begin(); i!=myNodes.end(); ++i) {
01280         ret.push_back((*i).first);
01281     }
01282     return ret;
01283 }
01284 
01285 
01286 
01287 /****************************************************************************/
01288 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines