|
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 return (int)clusters.size(); 00485 } 00486 00487 00488 unsigned int 00489 NBNodeCont::joinJunctions(SUMOReal maxdist, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) { 00490 NodeClusters cands; 00491 NodeClusters clusters; 00492 generateNodeClusters(maxdist, cands); 00493 for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) { 00494 const std::set<NBNode*> &candCluster = (*i); 00495 std::set<NBNode*> cluster; 00496 // remove nodes with degree = 2 at fringe of the cluster (at least one edge leads to a non-cluster node) 00497 for (std::set<NBNode*>::const_iterator j = candCluster.begin(); j != candCluster.end(); j++) { 00498 NBNode* n = *j; 00499 if (n->getIncomingEdges().size() == 1 && 00500 n->getOutgoingEdges().size() == 1 && 00501 (!cluster.count(n->getIncomingEdges()[0]->getFromNode()) || 00502 !cluster.count(n->getOutgoingEdges()[0]->getToNode()))) { 00503 continue; 00504 } else if (myJoinExclusions.count(n->getID()) > 0) { 00505 continue; 00506 } else { 00507 cluster.insert(n); 00508 } 00509 } 00510 if (cluster.size() > 1) { 00511 clusters.push_back(cluster); 00512 } 00513 } 00514 joinNodeClusters(clusters, dc, ec, tlc); 00515 return (int)clusters.size(); 00516 } 00517 00518 00519 void 00520 NBNodeCont::joinNodeClusters(NodeClusters clusters, 00521 NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) { 00522 for (NodeClusters::iterator i = clusters.begin(); i != clusters.end(); ++i) { 00523 std::set<NBNode*> cluster = *i; 00524 assert(cluster.size() > 1); 00525 Position pos; 00526 bool setTL; 00527 std::string id; 00528 analyzeCluster(cluster, id, pos, setTL); 00529 if (!insert(id, pos)) { 00530 // should not fail 00531 WRITE_WARNING("Could not join junctions " + id); 00532 continue; 00533 } 00534 NBNode* newNode = retrieve(id); 00535 if (setTL) { 00536 NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, newNode); 00537 if (!tlc.insert(tlDef)) { 00538 // actually, nothing should fail here 00539 delete tlDef; 00540 throw ProcessError("Could not allocate tls '" + id + "'."); 00541 } 00542 } 00543 // collect edges 00544 std::set<NBEdge*> allEdges; 00545 for (std::set<NBNode*>::const_iterator j=cluster.begin(); j!=cluster.end(); ++j) { 00546 const std::vector<NBEdge*> &edges = (*j)->getEdges(); 00547 allEdges.insert(edges.begin(), edges.end()); 00548 } 00549 00550 // remap and remove edges which are completely within the new intersection 00551 for(std::set<NBEdge*>::iterator j=allEdges.begin(); j!=allEdges.end();) { 00552 NBEdge *e = (*j); 00553 NBNode *from = e->getFromNode(); 00554 NBNode *to = e->getToNode(); 00555 if(cluster.count(from) > 0 && cluster.count(to) > 0) { 00556 for(std::set<NBEdge*>::iterator l=allEdges.begin(); l!=allEdges.end(); ++l) { 00557 if(e != *l) { 00558 (*l)->replaceInConnections(e, e->getConnections()); 00559 } 00560 } 00561 ec.erase(dc, e); 00562 allEdges.erase(j++); // erase does not invalidate the other iterators 00563 } else { 00564 ++j; 00565 } 00566 } 00567 00568 // remap edges which are incoming / outgoing 00569 for(std::set<NBEdge*>::iterator j=allEdges.begin(); j!=allEdges.end(); ++j) { 00570 NBEdge *e = (*j); 00571 std::vector<NBEdge::Connection> conns = e->getConnections(); 00572 PositionVector g = e->getGeometry(); 00573 const bool outgoing = cluster.count(e->getFromNode()) > 0; 00574 NBNode *from = outgoing ? newNode : e->getFromNode(); 00575 NBNode *to = outgoing ? e->getToNode() : newNode; 00576 e->reinit(from, to, e->getTypeID(), e->getSpeed(), 00577 e->getNumLanes(), e->getPriority(), e->getGeometry(), 00578 e->getWidth(), e->getOffset(), e->getStreetName(), e->getLaneSpreadFunction()); 00579 e->setGeometry(g); 00580 for(std::vector<NBEdge::Connection>::iterator k=conns.begin(); k!=conns.end(); ++k) { 00581 e->addLane2LaneConnection((*k).fromLane, (*k).toEdge, (*k).toLane, NBEdge::L2L_USER, false, (*k).mayDefinitelyPass); 00582 } 00583 } 00584 } 00585 } 00586 00587 00588 void 00589 NBNodeCont::analyzeCluster(std::set<NBNode*> cluster, std::string& id, Position& pos, bool& hasTLS) { 00590 id = "cluster"; 00591 hasTLS = false; 00592 std::vector<std::string> member_ids; 00593 for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); j++) { 00594 member_ids.push_back((*j)->getID()); 00595 pos.add((*j)->getPosition()); 00596 // add a traffic light if any of the cluster members was controlled 00597 if ((*j)->isTLControlled()) { 00598 hasTLS = true; 00599 } 00600 } 00601 pos.mul(1.0 / cluster.size()); 00602 // need to sort the member names to make the output deterministic 00603 sort(member_ids.begin(), member_ids.end()); 00604 for (std::vector<std::string>::iterator j = member_ids.begin(); j != member_ids.end(); j++) { 00605 id = id + "_" + (*j); 00606 } 00607 } 00608 00609 00610 // ----------- (Helper) methods for guessing/computing traffic lights 00611 bool 00612 NBNodeCont::shouldBeTLSControlled(const std::set<NBNode*> &c) const { 00613 unsigned int noIncoming = 0; 00614 unsigned int noOutgoing = 0; 00615 bool tooFast = false; 00616 SUMOReal f = 0; 00617 std::set<NBEdge*> seen; 00618 for (std::set<NBNode*>::const_iterator j = c.begin(); j != c.end(); ++j) { 00619 const EdgeVector& edges = (*j)->getEdges(); 00620 for (EdgeVector::const_iterator k = edges.begin(); k != edges.end(); ++k) { 00621 if (c.find((*k)->getFromNode()) != c.end() && c.find((*k)->getToNode()) != c.end()) { 00622 continue; 00623 } 00624 if ((*j)->hasIncoming(*k)) { 00625 ++noIncoming; 00626 f += (SUMOReal)(*k)->getNumLanes() * (*k)->getLaneSpeed(0); 00627 } else { 00628 ++noOutgoing; 00629 } 00630 if ((*k)->getLaneSpeed(0) * 3.6 > 79) { 00631 tooFast = true; 00632 } 00633 } 00634 } 00635 return !tooFast && f >= 150. / 3.6 && c.size() != 0; 00636 } 00637 00638 00639 void 00640 NBNodeCont::guessTLs(OptionsCont& oc, NBTrafficLightLogicCont& tlc) { 00641 // build list of definitely not tls-controlled junctions 00642 std::vector<NBNode*> ncontrolled; 00643 if (oc.isSet("tls.unset")) { 00644 std::vector<std::string> notTLControlledNodes = oc.getStringVector("tls.unset"); 00645 for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) { 00646 NBNode* n = NBNodeCont::retrieve(*i); 00647 if (n == 0) { 00648 throw ProcessError(" The node '" + *i + "' to set as not-controlled is not known."); 00649 } 00650 std::set<NBTrafficLightDefinition*> tls = n->getControllingTLS(); 00651 for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) { 00652 (*j)->removeNode(n); 00653 } 00654 n->removeTrafficLights(); 00655 ncontrolled.push_back(n); 00656 } 00657 } 00658 00659 // loop#1 checking whether the node shall be tls controlled, 00660 // because it is assigned to a district 00661 if (oc.exists("tls.taz-nodes") && oc.getBool("tls.taz-nodes")) { 00662 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 00663 NBNode* cur = (*i).second; 00664 if (cur->isNearDistrict() && find(ncontrolled.begin(), ncontrolled.end(), cur) == ncontrolled.end()) { 00665 setAsTLControlled(cur, tlc); 00666 } 00667 } 00668 } 00669 00670 // maybe no tls shall be guessed 00671 if (!oc.getBool("tls.guess")) { 00672 return; 00673 } 00674 00675 // guess joined tls first, if wished 00676 if (oc.getBool("tls-guess.joining")) { 00677 // get node clusters 00678 SUMOReal MAXDIST = 25; 00679 std::vector<std::set<NBNode*> > cands; 00680 generateNodeClusters(MAXDIST, cands); 00681 // check these candidates (clusters) whether they should be controlled by a tls 00682 for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end();) { 00683 std::set<NBNode*> &c = (*i); 00684 // regard only junctions which are not yet controlled and are not 00685 // forbidden to be controlled 00686 for (std::set<NBNode*>::iterator j = c.begin(); j != c.end();) { 00687 if ((*j)->isTLControlled() || find(ncontrolled.begin(), ncontrolled.end(), *j) != ncontrolled.end()) { 00688 c.erase(j++); 00689 } else { 00690 ++j; 00691 } 00692 } 00693 // check whether the cluster should be controlled 00694 if (!shouldBeTLSControlled(c)) { 00695 i = cands.erase(i); 00696 } else { 00697 ++i; 00698 } 00699 } 00700 // cands now only contain sets of junctions that shall be joined into being tls-controlled 00701 unsigned int index = 0; 00702 for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end(); ++i) { 00703 std::vector<NBNode*> nodes; 00704 for (std::set<NBNode*>::iterator j = (*i).begin(); j != (*i).end(); j++) { 00705 nodes.push_back(*j); 00706 } 00707 std::string id = "joinedG_" + toString(index++); 00708 NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes); 00709 if (!tlc.insert(tlDef)) { 00710 // actually, nothing should fail here 00711 WRITE_WARNING("Could not build guessed, joined tls"); 00712 delete tlDef; 00713 return; 00714 } 00715 } 00716 } 00717 00718 // guess tls 00719 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 00720 NBNode* cur = (*i).second; 00721 // do nothing if already is tl-controlled 00722 if (cur->isTLControlled()) { 00723 continue; 00724 } 00725 // do nothing if in the list of explicit non-controlled junctions 00726 if (find(ncontrolled.begin(), ncontrolled.end(), cur) != ncontrolled.end()) { 00727 continue; 00728 } 00729 std::set<NBNode*> c; 00730 c.insert(cur); 00731 if (!shouldBeTLSControlled(c) || cur->getIncomingEdges().size() < 3) { 00732 continue; 00733 } 00734 setAsTLControlled((*i).second, tlc); 00735 } 00736 } 00737 00738 00739 void 00740 NBNodeCont::joinTLS(NBTrafficLightLogicCont& tlc) { 00741 SUMOReal MAXDIST = 25; 00742 std::vector<std::set<NBNode*> > cands; 00743 generateNodeClusters(MAXDIST, cands); 00744 unsigned int index = 0; 00745 for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end(); ++i) { 00746 std::set<NBNode*> &c = (*i); 00747 for (std::set<NBNode*>::iterator j = c.begin(); j != c.end();) { 00748 if (!(*j)->isTLControlled()) { 00749 c.erase(j++); 00750 } else { 00751 ++j; 00752 } 00753 } 00754 if (c.size() < 2) { 00755 continue; 00756 } 00757 for (std::set<NBNode*>::iterator j = c.begin(); j != c.end(); ++j) { 00758 std::set<NBTrafficLightDefinition*> tls = (*j)->getControllingTLS(); 00759 (*j)->removeTrafficLights(); 00760 for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) { 00761 tlc.removeFully((*j)->getID()); 00762 } 00763 } 00764 std::string id = "joinedS_" + toString(index++); 00765 std::vector<NBNode*> nodes; 00766 for (std::set<NBNode*>::iterator j = c.begin(); j != c.end(); j++) { 00767 nodes.push_back(*j); 00768 } 00769 NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes); 00770 if (!tlc.insert(tlDef)) { 00771 // actually, nothing should fail here 00772 WRITE_WARNING("Could not build a joined tls."); 00773 delete tlDef; 00774 return; 00775 } 00776 } 00777 } 00778 00779 00780 void 00781 NBNodeCont::setAsTLControlled(NBNode* node, NBTrafficLightLogicCont& tlc, std::string id) { 00782 if (id == "") { 00783 id = node->getID(); 00784 } 00785 NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, node); 00786 if (!tlc.insert(tlDef)) { 00787 // actually, nothing should fail here 00788 WRITE_WARNING("Building a tl-logic for node '" + id + "' twice is not possible."); 00789 delete tlDef; 00790 return; 00791 } 00792 } 00793 00794 00795 // ----------- 00796 void 00797 NBNodeCont::computeLanes2Lanes() { 00798 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 00799 (*i).second->computeLanes2Lanes(); 00800 } 00801 } 00802 00803 00804 // computes the "wheel" of incoming and outgoing edges for every node 00805 void 00806 NBNodeCont::computeLogics(const NBEdgeCont& ec, OptionsCont& oc) { 00807 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 00808 (*i).second->computeLogic(ec, oc); 00809 } 00810 } 00811 00812 00813 void 00814 NBNodeCont::sortNodesEdges(bool leftHand) { 00815 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 00816 (*i).second->sortNodesEdges(leftHand); 00817 } 00818 } 00819 00820 00821 void 00822 NBNodeCont::computeNodeTypes(const NBTypeCont& tc) { 00823 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 00824 (*i).second->computeType(tc); 00825 } 00826 } 00827 00828 00829 void 00830 NBNodeCont::computePriorities() { 00831 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 00832 (*i).second->computePriorities(); 00833 } 00834 } 00835 00836 00837 void 00838 NBNodeCont::clear() { 00839 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 00840 delete((*i).second); 00841 } 00842 myNodes.clear(); 00843 for (std::set<NBNode*>::iterator i = myExtractedNodes.begin(); i != myExtractedNodes.end(); i++) { 00844 delete(*i); 00845 } 00846 myExtractedNodes.clear(); 00847 } 00848 00849 00850 std::string 00851 NBNodeCont::getFreeID() { 00852 // !!! not guaranteed to be free 00853 std::string ret = "SUMOGenerated" + toString<int>(size()); 00854 assert(retrieve(ret) == 0); 00855 return ret; 00856 } 00857 00858 00859 void 00860 NBNodeCont::computeNodeShapes(bool leftHand) { 00861 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 00862 (*i).second->computeNodeShape(leftHand); 00863 } 00864 } 00865 00866 00867 bool 00868 NBNodeCont::mayNeedOnRamp(OptionsCont& oc, NBNode* cur) const { 00869 if (cur->getIncomingEdges().size() == 2 && cur->getOutgoingEdges().size() == 1) { 00870 // may be an on-ramp 00871 NBEdge* pot_highway = cur->getIncomingEdges()[0]; 00872 NBEdge* pot_ramp = cur->getIncomingEdges()[1]; 00873 NBEdge* cont = cur->getOutgoingEdges()[0]; 00874 00875 // do not build ramps on connectors 00876 if (pot_highway->isMacroscopicConnector() || pot_ramp->isMacroscopicConnector() || cont->isMacroscopicConnector()) { 00877 return false; 00878 } 00879 00880 // check whether a lane is missing 00881 if (pot_highway->getNumLanes() + pot_ramp->getNumLanes() <= cont->getNumLanes()) { 00882 return false; 00883 } 00884 00885 // assign highway/ramp properly 00886 if (pot_highway->getSpeed() < pot_ramp->getSpeed()) { 00887 std::swap(pot_highway, pot_ramp); 00888 } else if (pot_highway->getSpeed() == pot_ramp->getSpeed() 00889 && 00890 pot_highway->getNumLanes() < pot_ramp->getNumLanes()) { 00891 00892 std::swap(pot_highway, pot_ramp); 00893 } 00894 00895 // check conditions 00896 // is it really a highway? 00897 SUMOReal minHighwaySpeed = oc.getFloat("ramps.min-highway-speed"); 00898 if (pot_highway->getSpeed() < minHighwaySpeed || cont->getSpeed() < minHighwaySpeed) { 00899 return false; 00900 } 00901 // is it really a ramp? 00902 SUMOReal maxRampSpeed = oc.getFloat("ramps.max-ramp-speed"); 00903 if (maxRampSpeed > 0 && maxRampSpeed < pot_ramp->getSpeed()) { 00904 return false; 00905 } 00906 00907 // ok, may be 00908 return true; 00909 } 00910 return false; 00911 } 00912 00913 00914 bool 00915 NBNodeCont::buildOnRamp(OptionsCont& oc, NBNode* cur, 00916 NBEdgeCont& ec, NBDistrictCont& dc, 00917 EdgeVector& incremented) { 00918 NBEdge* pot_highway = cur->getIncomingEdges()[0]; 00919 NBEdge* pot_ramp = cur->getIncomingEdges()[1]; 00920 NBEdge* cont = cur->getOutgoingEdges()[0]; 00921 bool bEdgeDeleted = false; 00922 00923 // assign highway/ramp properly 00924 if (pot_highway->getSpeed() < pot_ramp->getSpeed()) { 00925 std::swap(pot_highway, pot_ramp); 00926 } else if (pot_highway->getSpeed() == pot_ramp->getSpeed() 00927 && 00928 pot_highway->getNumLanes() < pot_ramp->getNumLanes()) { 00929 00930 std::swap(pot_highway, pot_ramp); 00931 } 00932 00933 // compute the number of lanes to append 00934 int toAdd = (pot_ramp->getNumLanes() + pot_highway->getNumLanes()) - cont->getNumLanes(); 00935 if (toAdd <= 0) { 00936 return false; 00937 } 00938 00939 // 00940 if (cont->getGeometry().length() - POSITION_EPS <= oc.getFloat("ramps.ramp-length")) { 00941 // the edge is shorter than the wished ramp 00942 // append a lane only 00943 if (find(incremented.begin(), incremented.end(), cont) == incremented.end()) { 00944 cont->incLaneNo(toAdd); 00945 incremented.push_back(cont); 00946 if (!pot_highway->addLane2LaneConnections(0, cont, pot_ramp->getNumLanes(), 00947 MIN2(cont->getNumLanes() - pot_ramp->getNumLanes(), pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, true, true)) { 00948 throw ProcessError("Could not set connection!"); 00949 } 00950 if (!pot_ramp->addLane2LaneConnections(0, cont, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true, true)) { 00951 throw ProcessError("Could not set connection!"); 00952 } 00953 // 00954 cont->invalidateConnections(true); 00955 const EdgeVector& o1 = cont->getToNode()->getOutgoingEdges(); 00956 if (o1.size() == 1 && o1[0]->getNumLanes() < cont->getNumLanes()) { 00957 cont->addLane2LaneConnections(cont->getNumLanes() - o1[0]->getNumLanes(), 00958 o1[0], 0, o1[0]->getNumLanes(), NBEdge::L2L_VALIDATED); 00959 } 00960 // 00961 if (cont->getLaneSpreadFunction() == LANESPREAD_CENTER) { 00962 try { 00963 PositionVector g = cont->getGeometry(); 00964 g.move2side(SUMO_const_laneWidthAndOffset); 00965 cont->setGeometry(g); 00966 } catch (InvalidArgument&) { 00967 WRITE_WARNING("For edge '" + cont->getID() + "': could not compute shape."); 00968 } 00969 } 00970 } 00971 PositionVector p = pot_ramp->getGeometry(); 00972 p.pop_back(); 00973 p.push_back(cont->getFromNode()->getPosition()); 00974 pot_ramp->setGeometry(p); 00975 } else { 00976 bEdgeDeleted = true; 00977 // there is enough place to build a ramp; do it 00978 NBNode* rn = 00979 new NBNode(cont->getID() + "-AddedOnRampNode", 00980 cont->getGeometry().positionAtLengthPosition( 00981 oc.getFloat("ramps.ramp-length"))); 00982 if (!insert(rn)) { 00983 throw ProcessError("Ups - could not build on-ramp for edge '" + pot_highway->getID() + "' (node could not be build)!"); 00984 } 00985 std::string name = cont->getID(); 00986 bool ok = ec.splitAt(dc, cont, rn, 00987 cont->getID() + "-AddedOnRampEdge", cont->getID(), 00988 cont->getNumLanes() + toAdd, cont->getNumLanes()); 00989 if (!ok) { 00990 WRITE_ERROR("Ups - could not build on-ramp for edge '" + pot_highway->getID() + "'!"); 00991 return true; 00992 } else { 00993 NBEdge* added_ramp = ec.retrieve(name + "-AddedOnRampEdge"); 00994 NBEdge* added = ec.retrieve(name); 00995 incremented.push_back(added_ramp); 00996 if (added_ramp->getNumLanes() != added->getNumLanes()) { 00997 int off = added_ramp->getNumLanes() - added->getNumLanes(); 00998 if (!added_ramp->addLane2LaneConnections(off, added, 0, added->getNumLanes(), NBEdge::L2L_VALIDATED, true)) { 00999 throw ProcessError("Could not set connection!"); 01000 } 01001 if (added_ramp->getLaneSpreadFunction() == LANESPREAD_CENTER) { 01002 try { 01003 PositionVector g = added_ramp->getGeometry(); 01004 SUMOReal factor = SUMO_const_laneWidthAndOffset * (SUMOReal)(toAdd - 1) + SUMO_const_halfLaneAndOffset * (SUMOReal)(toAdd % 2); 01005 g.move2side(factor); 01006 added_ramp->setGeometry(g); 01007 } catch (InvalidArgument&) { 01008 WRITE_WARNING("For edge '" + added_ramp->getID() + "': could not compute shape."); 01009 } 01010 } 01011 } else { 01012 if (!added_ramp->addLane2LaneConnections(0, added, 0, added_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true)) { 01013 throw ProcessError("Could not set connection!"); 01014 } 01015 } 01016 if (!pot_highway->addLane2LaneConnections(0, added_ramp, pot_ramp->getNumLanes(), 01017 MIN2(added_ramp->getNumLanes() - pot_ramp->getNumLanes(), pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, false, true)) { 01018 throw ProcessError("Could not set connection!"); 01019 01020 } 01021 if (!pot_ramp->addLane2LaneConnections(0, added_ramp, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true, true)) { 01022 throw ProcessError("Could not set connection!"); 01023 } 01024 PositionVector p = pot_ramp->getGeometry(); 01025 p.pop_back(); 01026 p.push_back(added_ramp->getFromNode()->getPosition());//added_ramp->getLaneShape(0).at(0)); 01027 pot_ramp->setGeometry(p); 01028 } 01029 } 01030 return bEdgeDeleted; 01031 } 01032 01033 01034 void 01035 NBNodeCont::buildOffRamp(OptionsCont& oc, NBNode* cur, 01036 NBEdgeCont& ec, NBDistrictCont& dc, 01037 EdgeVector& incremented) { 01038 NBEdge* pot_highway = cur->getOutgoingEdges()[0]; 01039 NBEdge* pot_ramp = cur->getOutgoingEdges()[1]; 01040 NBEdge* prev = cur->getIncomingEdges()[0]; 01041 // assign highway/ramp properly 01042 if (pot_highway->getSpeed() < pot_ramp->getSpeed()) { 01043 std::swap(pot_highway, pot_ramp); 01044 } else if (pot_highway->getSpeed() == pot_ramp->getSpeed() 01045 && 01046 pot_highway->getNumLanes() < pot_ramp->getNumLanes()) { 01047 01048 std::swap(pot_highway, pot_ramp); 01049 } 01050 // compute the number of lanes to append 01051 int toAdd = (pot_ramp->getNumLanes() + pot_highway->getNumLanes()) - prev->getNumLanes(); 01052 if (toAdd <= 0) { 01053 return; 01054 } 01055 // append on-ramp 01056 if (prev->getGeometry().length() - POSITION_EPS <= oc.getFloat("ramps.ramp-length")) { 01057 // the edge is shorter than the wished ramp 01058 // append a lane only 01059 if (find(incremented.begin(), incremented.end(), prev) == incremented.end()) { 01060 incremented.push_back(prev); 01061 prev->incLaneNo(toAdd); 01062 prev->invalidateConnections(true); 01063 if (!prev->addLane2LaneConnections(pot_ramp->getNumLanes(), pot_highway, 0, 01064 MIN2(prev->getNumLanes() - 1, pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, true)) { 01065 01066 throw ProcessError("Could not set connection!"); 01067 01068 } 01069 if (!prev->addLane2LaneConnections(0, pot_ramp, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, false)) { 01070 throw ProcessError("Could not set connection!"); 01071 01072 } 01073 if (prev->getLaneSpreadFunction() == LANESPREAD_CENTER) { 01074 try { 01075 PositionVector g = prev->getGeometry(); 01076 g.move2side(SUMO_const_laneWidthAndOffset); 01077 prev->setGeometry(g); 01078 } catch (InvalidArgument&) { 01079 WRITE_WARNING("For edge '" + prev->getID() + "': could not compute shape."); 01080 } 01081 } 01082 } 01083 PositionVector p = pot_ramp->getGeometry(); 01084 p.pop_front(); 01085 p.push_front(prev->getToNode()->getPosition());//added_ramp->getLaneShape(0).at(-1)); 01086 pot_ramp->setGeometry(p); 01087 } else { 01088 Position pos = 01089 prev->getGeometry().positionAtLengthPosition( 01090 prev->getGeometry().length() - oc.getFloat("ramps.ramp-length")); 01091 NBNode* rn = new NBNode(prev->getID() + "-AddedOffRampNode", pos); 01092 if (!insert(rn)) { 01093 throw ProcessError("Ups - could not build off-ramp for edge '" + pot_highway->getID() + "' (node could not be build)!"); 01094 01095 } 01096 std::string name = prev->getID(); 01097 bool ok = ec.splitAt(dc, prev, rn, 01098 prev->getID(), prev->getID() + "-AddedOffRampEdge", 01099 prev->getNumLanes(), prev->getNumLanes() + toAdd); 01100 if (!ok) { 01101 WRITE_ERROR("Ups - could not build on-ramp for edge '" + pot_highway->getID() + "'!"); 01102 return; 01103 } else { 01104 NBEdge* added_ramp = ec.retrieve(name + "-AddedOffRampEdge"); 01105 NBEdge* added = ec.retrieve(name); 01106 if (added_ramp->getNumLanes() != added->getNumLanes()) { 01107 incremented.push_back(added_ramp); 01108 int off = added_ramp->getNumLanes() - added->getNumLanes(); 01109 if (!added->addLane2LaneConnections(0, added_ramp, off, added->getNumLanes(), NBEdge::L2L_VALIDATED, true)) { 01110 throw ProcessError("Could not set connection!"); 01111 01112 } 01113 if (added_ramp->getLaneSpreadFunction() == LANESPREAD_CENTER) { 01114 try { 01115 PositionVector g = added_ramp->getGeometry(); 01116 SUMOReal factor = SUMO_const_laneWidthAndOffset * (SUMOReal)(toAdd - 1) + SUMO_const_halfLaneAndOffset * (SUMOReal)(toAdd % 2); 01117 g.move2side(factor); 01118 added_ramp->setGeometry(g); 01119 } catch (InvalidArgument&) { 01120 WRITE_WARNING("For edge '" + added_ramp->getID() + "': could not compute shape."); 01121 } 01122 } 01123 } else { 01124 if (!added->addLane2LaneConnections(0, added_ramp, 0, added_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, true)) { 01125 throw ProcessError("Could not set connection!"); 01126 } 01127 } 01128 if (!added_ramp->addLane2LaneConnections(pot_ramp->getNumLanes(), pot_highway, 0, 01129 MIN2(added_ramp->getNumLanes() - pot_ramp->getNumLanes(), pot_highway->getNumLanes()), NBEdge::L2L_VALIDATED, true)) { 01130 throw ProcessError("Could not set connection!"); 01131 } 01132 if (!added_ramp->addLane2LaneConnections(0, pot_ramp, 0, pot_ramp->getNumLanes(), NBEdge::L2L_VALIDATED, false)) { 01133 throw ProcessError("Could not set connection!"); 01134 01135 } 01136 PositionVector p = pot_ramp->getGeometry(); 01137 p.pop_front(); 01138 p.push_front(added_ramp->getToNode()->getPosition());//added_ramp->getLaneShape(0).at(-1)); 01139 pot_ramp->setGeometry(p); 01140 } 01141 } 01142 } 01143 01144 01145 bool 01146 NBNodeCont::mayNeedOffRamp(OptionsCont& oc, NBNode* cur) const { 01147 if (cur->getIncomingEdges().size() == 1 && cur->getOutgoingEdges().size() == 2) { 01148 // may be an off-ramp 01149 NBEdge* pot_highway = cur->getOutgoingEdges()[0]; 01150 NBEdge* pot_ramp = cur->getOutgoingEdges()[1]; 01151 NBEdge* prev = cur->getIncomingEdges()[0]; 01152 01153 // do not build ramps on connectors 01154 if (pot_highway->isMacroscopicConnector() || pot_ramp->isMacroscopicConnector() || prev->isMacroscopicConnector()) { 01155 return false; 01156 } 01157 01158 // check whether a lane is missing 01159 if (pot_highway->getNumLanes() + pot_ramp->getNumLanes() <= prev->getNumLanes()) { 01160 return false; 01161 } 01162 01163 // assign highway/ramp properly 01164 if (pot_highway->getSpeed() < pot_ramp->getSpeed()) { 01165 std::swap(pot_highway, pot_ramp); 01166 } else if (pot_highway->getSpeed() == pot_ramp->getSpeed() 01167 && 01168 pot_highway->getNumLanes() < pot_ramp->getNumLanes()) { 01169 01170 std::swap(pot_highway, pot_ramp); 01171 } 01172 01173 // check conditions 01174 // is it really a highway? 01175 SUMOReal minHighwaySpeed = oc.getFloat("ramps.min-highway-speed"); 01176 if (pot_highway->getSpeed() < minHighwaySpeed || prev->getSpeed() < minHighwaySpeed) { 01177 return false; 01178 } 01179 // is it really a ramp? 01180 SUMOReal maxRampSpeed = oc.getFloat("ramps.max-ramp-speed"); 01181 if (maxRampSpeed > 0 && maxRampSpeed < pot_ramp->getSpeed()) { 01182 return false; 01183 } 01184 01185 return true; 01186 } 01187 return false; 01188 } 01189 01190 01191 void 01192 NBNodeCont::checkHighwayRampOrder(NBEdge *&pot_highway, NBEdge *&pot_ramp) { 01193 if (pot_highway->getSpeed() < pot_ramp->getSpeed()) { 01194 std::swap(pot_highway, pot_ramp); 01195 } else if (pot_highway->getSpeed() == pot_ramp->getSpeed() 01196 && 01197 pot_highway->getNumLanes() < pot_ramp->getNumLanes()) { 01198 01199 std::swap(pot_highway, pot_ramp); 01200 } 01201 } 01202 01203 01204 void 01205 NBNodeCont::guessRamps(OptionsCont& oc, NBEdgeCont& ec, 01206 NBDistrictCont& dc) { 01207 EdgeVector incremented; 01208 bool bEdgeDeleted = false; 01209 // check whether on-off ramps shall be guessed 01210 if (oc.getBool("ramps.guess")) { 01211 for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { 01212 NBNode* cur = (*i).second; 01213 if (mayNeedOnRamp(oc, cur)) { 01214 buildOnRamp(oc, cur, ec, dc, incremented); 01215 } 01216 if (mayNeedOffRamp(oc, cur)) { 01217 buildOffRamp(oc, cur, ec, dc, incremented); 01218 } 01219 } 01220 } 01221 // check whether on-off ramps shall be guessed 01222 if (oc.isSet("ramps.set")) { 01223 std::vector<std::string> edges = oc.getStringVector("ramps.set"); 01224 for (std::vector<std::string>::iterator i = edges.begin(); i != edges.end(); ++i) { 01225 NBEdge* e = ec.retrieve(*i); 01226 if (e == 0) { 01227 WRITE_WARNING("Can not build on ramp on edge '" + *i + "' - the edge is not known."); 01228 continue; 01229 } 01230 NBNode* from = e->getFromNode(); 01231 if (from->getIncomingEdges().size() == 2 && from->getOutgoingEdges().size() == 1) { 01232 bEdgeDeleted = buildOnRamp(oc, from, ec, dc, incremented); 01233 } 01234 // load edge again to check offramps 01235 e = ec.retrieve(*i); 01236 if (e == 0) { 01237 WRITE_WARNING("Can not build off ramp on edge '" + *i + "' - the edge is not known."); 01238 continue; 01239 } 01240 NBNode* to = e->getToNode(); 01241 if (to->getIncomingEdges().size() == 1 && to->getOutgoingEdges().size() == 2) { 01242 buildOffRamp(oc, to, ec, dc, incremented); 01243 } 01244 } 01245 } 01246 } 01247 01248 01249 void 01250 NBNodeCont::printBuiltNodesStatistics() const { 01251 int numUnregulatedJunctions = 0; 01252 int numDeadEndJunctions = 0; 01253 int numPriorityJunctions = 0; 01254 int numRightBeforeLeftJunctions = 0; 01255 for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) { 01256 switch ((*i).second->getType()) { 01257 case NODETYPE_NOJUNCTION: 01258 ++numUnregulatedJunctions; 01259 break; 01260 case NODETYPE_DEAD_END: 01261 ++numDeadEndJunctions; 01262 break; 01263 case NODETYPE_PRIORITY_JUNCTION: 01264 case NODETYPE_TRAFFIC_LIGHT: 01265 ++numPriorityJunctions; 01266 break; 01267 case NODETYPE_RIGHT_BEFORE_LEFT: 01268 ++numRightBeforeLeftJunctions; 01269 break; 01270 case NODETYPE_DISTRICT: 01271 ++numRightBeforeLeftJunctions; 01272 break; 01273 case NODETYPE_UNKNOWN: 01274 break; 01275 default: 01276 break; 01277 } 01278 } 01279 WRITE_MESSAGE(" Node type statistics:"); 01280 WRITE_MESSAGE(" Unregulated junctions : " + toString(numUnregulatedJunctions)); 01281 if (numDeadEndJunctions > 0) { 01282 WRITE_MESSAGE(" Dead-end junctions : " + toString(numDeadEndJunctions)); 01283 } 01284 WRITE_MESSAGE(" Priority junctions : " + toString(numPriorityJunctions)); 01285 WRITE_MESSAGE(" Right-before-left junctions : " + toString(numRightBeforeLeftJunctions)); 01286 } 01287 01288 01289 std::vector<std::string> 01290 NBNodeCont::getAllNames() const { 01291 std::vector<std::string> ret; 01292 for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) { 01293 ret.push_back((*i).first); 01294 } 01295 return ret; 01296 } 01297 01298 01299 01300 /****************************************************************************/ 01301