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