SUMO - Simulation of Urban MObility
|
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