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