SUMO - Simulation of Urban MObility
NBNode.cpp
Go to the documentation of this file.
00001 /****************************************************************************/
00010 // The representation of a single node
00011 /****************************************************************************/
00012 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00013 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
00014 /****************************************************************************/
00015 //
00016 //   This file is part of SUMO.
00017 //   SUMO is free software: you can redistribute it and/or modify
00018 //   it under the terms of the GNU General Public License as published by
00019 //   the Free Software Foundation, either version 3 of the License, or
00020 //   (at your option) any later version.
00021 //
00022 /****************************************************************************/
00023 
00024 
00025 // ===========================================================================
00026 // included modules
00027 // ===========================================================================
00028 #ifdef _MSC_VER
00029 #include <windows_config.h>
00030 #else
00031 #include <config.h>
00032 #endif
00033 
00034 #include <string>
00035 #include <map>
00036 #include <cassert>
00037 #include <algorithm>
00038 #include <vector>
00039 #include <deque>
00040 #include <set>
00041 #include <cmath>
00042 #include <iterator>
00043 #include <utils/common/UtilExceptions.h>
00044 #include <utils/common/StringUtils.h>
00045 #include <utils/options/OptionsCont.h>
00046 #include <utils/geom/Line.h>
00047 #include <utils/geom/GeomHelper.h>
00048 #include <utils/geom/bezier.h>
00049 #include <utils/common/MsgHandler.h>
00050 #include <utils/common/StdDefs.h>
00051 #include <utils/common/ToString.h>
00052 #include <utils/geom/GeoConvHelper.h>
00053 #include <utils/iodevices/OutputDevice.h>
00054 #include <iomanip>
00055 #include "NBNode.h"
00056 #include "NBNodeCont.h"
00057 #include "NBNodeShapeComputer.h"
00058 #include "NBEdgeCont.h"
00059 #include "NBTypeCont.h"
00060 #include "NBHelpers.h"
00061 #include "NBDistrict.h"
00062 #include "NBContHelper.h"
00063 #include "NBRequest.h"
00064 #include "NBOwnTLDef.h"
00065 #include "NBTrafficLightLogicCont.h"
00066 
00067 #ifdef CHECK_MEMORY_LEAKS
00068 #include <foreign/nvwa/debug_new.h>
00069 #endif // CHECK_MEMORY_LEAKS
00070 
00071 
00072 // ===========================================================================
00073 // static members
00074 // ===========================================================================
00075 
00076 // ===========================================================================
00077 // method definitions
00078 // ===========================================================================
00079 /* -------------------------------------------------------------------------
00080  * NBNode::ApproachingDivider-methods
00081  * ----------------------------------------------------------------------- */
00082 NBNode::ApproachingDivider::ApproachingDivider(
00083     EdgeVector* approaching, NBEdge* currentOutgoing) :
00084     myApproaching(approaching), myCurrentOutgoing(currentOutgoing) {
00085     // check whether origin lanes have been given
00086     assert(myApproaching != 0);
00087 }
00088 
00089 
00090 NBNode::ApproachingDivider::~ApproachingDivider() {}
00091 
00092 
00093 void
00094 NBNode::ApproachingDivider::execute(const unsigned int src, const unsigned int dest) {
00095     assert(myApproaching->size() > src);
00096     // get the origin edge
00097     NBEdge* incomingEdge = (*myApproaching)[src];
00098     if (incomingEdge->getStep() == NBEdge::LANES2LANES_DONE || incomingEdge->getStep() == NBEdge::LANES2LANES_USER) {
00099         return;
00100     }
00101     std::vector<int> approachingLanes =
00102         incomingEdge->getConnectionLanes(myCurrentOutgoing);
00103     assert(approachingLanes.size() != 0);
00104     std::deque<int> *approachedLanes = spread(approachingLanes, dest);
00105     assert(approachedLanes->size() <= myCurrentOutgoing->getNumLanes());
00106     // set lanes
00107     for (unsigned int i = 0; i < approachedLanes->size(); i++) {
00108         unsigned int approached = (*approachedLanes)[i];
00109         assert(approachedLanes->size() > i);
00110         assert(approachingLanes.size() > i);
00111         incomingEdge->setConnection((unsigned int) approachingLanes[i], myCurrentOutgoing,
00112                                     approached, NBEdge::L2L_COMPUTED);
00113     }
00114     delete approachedLanes;
00115 }
00116 
00117 
00118 std::deque<int> *
00119 NBNode::ApproachingDivider::spread(const std::vector<int> &approachingLanes,
00120                                    int dest) const {
00121     std::deque<int> *ret = new std::deque<int>();
00122     unsigned int noLanes = (unsigned int) approachingLanes.size();
00123     // when only one lane is approached, we check, whether the SUMOReal-value
00124     //  is assigned more to the left or right lane
00125     if (noLanes == 1) {
00126         ret->push_back(dest);
00127         return ret;
00128     }
00129 
00130     unsigned int noOutgoingLanes = myCurrentOutgoing->getNumLanes();
00131     //
00132     ret->push_back(dest);
00133     unsigned int noSet = 1;
00134     int roffset = 1;
00135     int loffset = 1;
00136     while (noSet < noLanes) {
00137         // It may be possible, that there are not enough lanes the source
00138         //  lanes may be divided on
00139         //  In this case, they remain unset
00140         //  !!! this is only a hack. It is possible, that this yields in
00141         //   uncommon divisions
00142         if (noOutgoingLanes == noSet) {
00143             return ret;
00144         }
00145 
00146         // as due to the conversion of SUMOReal->uint the numbers will be lower
00147         //  than they should be, we try to append to the left side first
00148         //
00149         // check whether the left boundary of the approached street has
00150         //  been overridden; if so, move all lanes to the right
00151         if (dest + loffset >= static_cast<int>(noOutgoingLanes)) {
00152             loffset -= 1;
00153             roffset += 1;
00154             for (unsigned int i = 0; i < ret->size(); i++) {
00155                 (*ret)[i] = (*ret)[i] - 1;
00156             }
00157         }
00158         // append the next lane to the left of all edges
00159         //  increase the position (destination edge)
00160         ret->push_back(dest + loffset);
00161         noSet++;
00162         loffset += 1;
00163 
00164         // as above
00165         if (noOutgoingLanes == noSet) {
00166             return ret;
00167         }
00168 
00169         // now we try to append the next lane to the right side, when needed
00170         if (noSet < noLanes) {
00171             // check whether the right boundary of the approached street has
00172             //  been overridden; if so, move all lanes to the right
00173             if (dest < roffset) {
00174                 loffset += 1;
00175                 roffset -= 1;
00176                 for (unsigned int i = 0; i < ret->size(); i++) {
00177                     (*ret)[i] = (*ret)[i] + 1;
00178                 }
00179             }
00180             ret->push_front(dest - roffset);
00181             noSet++;
00182             roffset += 1;
00183         }
00184     }
00185     return ret;
00186 }
00187 
00188 
00189 
00190 
00191 /* -------------------------------------------------------------------------
00192  * NBNode-methods
00193  * ----------------------------------------------------------------------- */
00194 NBNode::NBNode(const std::string& id, const Position& position) :
00195     Named(StringUtils::convertUmlaute(id)),
00196     myPosition(position),
00197     myType(NODETYPE_UNKNOWN), myDistrict(0), myRequest(0)
00198 { }
00199 
00200 
00201 NBNode::NBNode(const std::string& id, const Position& position,
00202                SumoXMLNodeType type) :
00203     Named(StringUtils::convertUmlaute(id)),
00204     myPosition(position),
00205     myType(type), myDistrict(0), myRequest(0)
00206 { }
00207 
00208 
00209 NBNode::NBNode(const std::string& id, const Position& position, NBDistrict* district) :
00210     Named(StringUtils::convertUmlaute(id)),
00211     myPosition(position),
00212     myType(NODETYPE_DISTRICT), myDistrict(district), myRequest(0)
00213 { }
00214 
00215 
00216 NBNode::~NBNode() {
00217     delete myRequest;
00218 }
00219 
00220 
00221 void
00222 NBNode::reinit(const Position& position, SumoXMLNodeType type,
00223                bool updateEdgeGeometries) {
00224     myPosition = position;
00225     // patch type
00226     myType = type;
00227     if (myType != NODETYPE_TRAFFIC_LIGHT) {
00228         removeTrafficLights();
00229     }
00230     if (updateEdgeGeometries) {
00231         for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
00232             PositionVector geom = (*i)->getGeometry();
00233             geom[-1] = myPosition;
00234             (*i)->setGeometry(geom);
00235         }
00236         for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
00237             PositionVector geom = (*i)->getGeometry();
00238             geom[0] = myPosition;
00239             (*i)->setGeometry(geom);
00240         }
00241     }
00242 }
00243 
00244 
00245 
00246 // -----------  Applying offset
00247 void
00248 NBNode::reshiftPosition(SUMOReal xoff, SUMOReal yoff) {
00249     myPosition.add(xoff, yoff, 0);
00250     myPoly.add(xoff, yoff, 0);
00251 }
00252 
00253 
00254 // -----------  Methods for dealing with assigned traffic lights
00255 void
00256 NBNode::addTrafficLight(NBTrafficLightDefinition* tlDef) {
00257     myTrafficLights.insert(tlDef);
00258     myType = NODETYPE_TRAFFIC_LIGHT;
00259 }
00260 
00261 
00262 void
00263 NBNode::removeTrafficLight(NBTrafficLightDefinition* tlDef) {
00264     tlDef->removeNode(this);
00265     myTrafficLights.erase(tlDef);
00266 }
00267 
00268 
00269 void
00270 NBNode::removeTrafficLights() {
00271     std::set<NBTrafficLightDefinition*> trafficLights = myTrafficLights; // make a copy because we will modify the original
00272     for (std::set<NBTrafficLightDefinition*>::const_iterator i = trafficLights.begin(); i != trafficLights.end(); ++i) {
00273         removeTrafficLight(*i);
00274     }
00275 }
00276 
00277 
00278 bool
00279 NBNode::isJoinedTLSControlled() const {
00280     if (!isTLControlled()) {
00281         return false;
00282     }
00283     for (std::set<NBTrafficLightDefinition*>::const_iterator i = myTrafficLights.begin(); i != myTrafficLights.end(); ++i) {
00284         if ((*i)->getID().find("joined") == 0) {
00285             return true;
00286         }
00287     }
00288     return false;
00289 }
00290 
00291 
00292 // ----------- Prunning the input
00293 unsigned int
00294 NBNode::removeSelfLoops(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tc) {
00295     unsigned int ret = 0;
00296     unsigned int pos = 0;
00297     EdgeVector::const_iterator j = myIncomingEdges.begin();
00298     while (j != myIncomingEdges.end()) {
00299         // skip edges which are only incoming and not outgoing
00300         if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), *j) == myOutgoingEdges.end()) {
00301             ++j;
00302             ++pos;
00303             continue;
00304         }
00305         // an edge with both its origin and destination being the current
00306         //  node should be removed
00307         NBEdge* dummy = *j;
00308         WRITE_WARNING(" Removing self-looping edge '" + dummy->getID() + "'");
00309         // get the list of incoming edges connected to the self-loop
00310         EdgeVector incomingConnected;
00311         for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
00312             if ((*i)->isConnectedTo(dummy) && *i != dummy) {
00313                 incomingConnected.push_back(*i);
00314             }
00315         }
00316         // get the list of outgoing edges connected to the self-loop
00317         EdgeVector outgoingConnected;
00318         for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
00319             if (dummy->isConnectedTo(*i) && *i != dummy) {
00320                 outgoingConnected.push_back(*i);
00321             }
00322         }
00323         // let the self-loop remap its connections
00324         dummy->remapConnections(incomingConnected);
00325         remapRemoved(tc, dummy, incomingConnected, outgoingConnected);
00326         // delete the self-loop
00327         ec.erase(dc, dummy);
00328         j = myIncomingEdges.begin() + pos;
00329         ++ret;
00330     }
00331     return ret;
00332 }
00333 
00334 
00335 // -----------
00336 void
00337 NBNode::addIncomingEdge(NBEdge* edge) {
00338     assert(edge != 0);
00339     if (find(myIncomingEdges.begin(), myIncomingEdges.end(), edge) == myIncomingEdges.end()) {
00340         myIncomingEdges.push_back(edge);
00341         myAllEdges.push_back(edge);
00342     }
00343 }
00344 
00345 
00346 void
00347 NBNode::addOutgoingEdge(NBEdge* edge) {
00348     assert(edge != 0);
00349     if (find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge) == myOutgoingEdges.end()) {
00350         myOutgoingEdges.push_back(edge);
00351         myAllEdges.push_back(edge);
00352     }
00353 }
00354 
00355 
00356 bool
00357 NBNode::isSimpleContinuation() const {
00358     // one in, one out->continuation
00359     if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1) {
00360         // both must have the same number of lanes
00361         return (*(myIncomingEdges.begin()))->getNumLanes() == (*(myOutgoingEdges.begin()))->getNumLanes();
00362     }
00363     // two in and two out and both in reverse direction
00364     if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 2) {
00365         for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
00366             NBEdge* in = *i;
00367             EdgeVector::const_iterator opposite = find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(), NBContHelper::opposite_finder(in, this));
00368             // must have an opposite edge
00369             if (opposite == myOutgoingEdges.end()) {
00370                 return false;
00371             }
00372             // both must have the same number of lanes
00373             NBContHelper::nextCW(myOutgoingEdges, opposite);
00374             if (in->getNumLanes() != (*opposite)->getNumLanes()) {
00375                 return false;
00376             }
00377         }
00378         return true;
00379     }
00380     // nope
00381     return false;
00382 }
00383 
00384 
00385 PositionVector
00386 NBNode::computeInternalLaneShape(NBEdge* fromE, int fromL,
00387                                  NBEdge* toE, int toL, int numPoints) const {
00388     if (fromL >= (int) fromE->getNumLanes()) {
00389         throw ProcessError("Connection '" + fromE->getID() + "_" + toString(fromL) + "->" + toE->getID() + "_" + toString(toL) + "' starts at a not existing lane.");
00390     }
00391     if (toL >= (int) toE->getNumLanes()) {
00392         throw ProcessError("Connection '" + fromE->getID() + "_" + toString(fromL) + "->" + toE->getID() + "_" + toString(toL) + "' yields in a not existing lane.");
00393     }
00394     bool noSpline = false;
00395     PositionVector ret;
00396     PositionVector init;
00397     Position beg = fromE->getLaneShape(fromL).getEnd();
00398     Position end = toE->getLaneShape(toL).getBegin();
00399     Position intersection;
00400     unsigned int noInitialPoints = 0;
00401     if (beg.distanceTo(end) <= POSITION_EPS) {
00402         noSpline = true;
00403     } else {
00404         if (fromE->getTurnDestination() == toE) {
00405             // turnarounds:
00406             //  - end of incoming lane
00407             //  - position between incoming/outgoing end/begin shifted by the distance orthogonally
00408             //  - begin of outgoing lane
00409             noInitialPoints = 3;
00410             init.push_back(beg);
00411             Line straightConn(fromE->getLaneShape(fromL)[-1], toE->getLaneShape(toL)[0]);
00412             Position straightCenter = straightConn.getPositionAtDistance((SUMOReal) straightConn.length() / (SUMOReal) 2.);
00413             Position center = straightCenter;//.add(straightCenter);
00414             Line cross(straightConn);
00415             cross.sub(cross.p1().x(), cross.p1().y());
00416             cross.rotateAtP1(PI / 2);
00417             center.sub(cross.p2());
00418             init.push_back(center);
00419             init.push_back(end);
00420         } else {
00421             const SUMOReal angle = fabs(fromE->getLaneShape(fromL).getEndLine().atan2Angle() - toE->getLaneShape(toL).getBegLine().atan2Angle());
00422             if (angle < PI / 4. || angle > 7. / 4.*PI) {
00423                 // very low angle: almost straight
00424                 noInitialPoints = 4;
00425                 init.push_back(beg);
00426                 Line begL = fromE->getLaneShape(fromL).getEndLine();
00427                 begL.extrapolateSecondBy(100);
00428                 Line endL = toE->getLaneShape(toL).getBegLine();
00429                 endL.extrapolateFirstBy(100);
00430                 SUMOReal distance = beg.distanceTo(end);
00431                 if (distance > 10) {
00432                     {
00433                         SUMOReal off1 = fromE->getLaneShape(fromL).getEndLine().length() + (SUMOReal) 5. * (SUMOReal) fromE->getNumLanes();
00434                         off1 = MIN2(off1, (SUMOReal)(fromE->getLaneShape(fromL).getEndLine().length() + distance / 2.));
00435                         Position tmp = begL.getPositionAtDistance(off1);
00436                         init.push_back(tmp);
00437                     }
00438                     {
00439                         SUMOReal off1 = (SUMOReal) 100. - (SUMOReal) 5. * (SUMOReal) toE->getNumLanes();
00440                         off1 = MAX2(off1, (SUMOReal)(100. - distance / 2.));
00441                         Position tmp = endL.getPositionAtDistance(off1);
00442                         init.push_back(tmp);
00443                     }
00444                 } else {
00445                     noSpline = true;
00446                 }
00447                 init.push_back(end);
00448             } else {
00449                 // turning
00450                 //  - end of incoming lane
00451                 //  - intersection of the extrapolated lanes
00452                 //  - begin of outgoing lane
00453                 // attention: if there is no intersection, use a straight line
00454                 noInitialPoints = 3;
00455                 init.push_back(beg);
00456                 Line begL = fromE->getLaneShape(fromL).getEndLine();
00457                 Line endL = toE->getLaneShape(toL).getBegLine();
00458                 bool check = !begL.p1().almostSame(begL.p2()) && !endL.p1().almostSame(endL.p2());
00459                 if (check) {
00460                     begL.extrapolateSecondBy(100);
00461                     endL.extrapolateFirstBy(100);
00462                 } else {
00463                     WRITE_WARNING("Could not use edge geometry for internal lane, node '" + getID() + "'.");
00464                 }
00465                 if (!check || !begL.intersects(endL)) {
00466                     noSpline = true;
00467                 } else {
00468                     init.push_back(begL.intersectsAt(endL));
00469                 }
00470                 init.push_back(end);
00471             }
00472         }
00473     }
00474     //
00475     if (noSpline) {
00476         ret.push_back(fromE->getLaneShape(fromL).getEnd());
00477         ret.push_back(toE->getLaneShape(toL).getBegin());
00478     } else {
00479         SUMOReal* def = new SUMOReal[1 + noInitialPoints * 3];
00480         for (int i = 0; i < (int) init.size(); ++i) {
00481             // starts at index 1
00482             def[i * 3 + 1] = init[i].x();
00483             def[i * 3 + 2] = 0;
00484             def[i * 3 + 3] = init[i].y();
00485         }
00486         SUMOReal* ret_buf = new SUMOReal[numPoints * 3 + 1];
00487         bezier(noInitialPoints, def, numPoints, ret_buf);
00488         delete[] def;
00489         Position prev;
00490         for (int i = 0; i < (int) numPoints; i++) {
00491             Position current(ret_buf[i * 3 + 1], ret_buf[i * 3 + 3]);
00492             if (prev != current) {
00493                 ret.push_back(current);
00494             }
00495             prev = current;
00496         }
00497         delete[] ret_buf;
00498     }
00499     const NBEdge::Lane& lane = fromE->getLaneStruct(fromL);
00500     if (lane.offset > 0) {
00501         PositionVector beg = lane.shape.getSubpart(lane.shape.length() - lane.offset, lane.shape.length());;
00502         beg.appendWithCrossingPoint(ret);
00503         ret = beg;
00504     }
00505     return ret;
00506 }
00507 
00508 
00509 bool
00510 NBNode::needsCont(NBEdge* fromE, NBEdge* toE, NBEdge* otherFromE, NBEdge* otherToE, const NBEdge::Connection& c) const {
00511     if (myType == NODETYPE_RIGHT_BEFORE_LEFT) {
00512         return false;
00513     }
00514     if (fromE == otherFromE) {
00515         // ignore same edge links
00516         return false;
00517     }
00518     if (!foes(otherFromE, otherToE, fromE, toE)) {
00519         // if they do not cross, no waiting place is needed
00520         return false;
00521     }
00522     LinkDirection d1 = getDirection(fromE, toE);
00523     LinkDirection d2 = getDirection(otherFromE, otherToE);
00524     bool thisLeft = (d1 == LINKDIR_LEFT || d1 == LINKDIR_TURN);
00525     bool otherLeft = (d2 == LINKDIR_LEFT || d2 == LINKDIR_TURN);
00526     bool bothLeft = thisLeft && otherLeft;
00527     if (c.tlID != "" && !bothLeft) {
00528         // tls-controlled links will have space
00529         return true;
00530     }
00531     if (fromE->getJunctionPriority(this) > 0 && otherFromE->getJunctionPriority(this) > 0) {
00532         return mustBrake(fromE, toE, c.toLane);
00533     }
00534     return false;
00535 }
00536 
00537 
00538 void
00539 NBNode::computeLogic(const NBEdgeCont& ec, OptionsCont& oc) {
00540     delete myRequest; // possibly recomputation step
00541     myRequest = 0;
00542     if (myIncomingEdges.size() == 0 || myOutgoingEdges.size() == 0) {
00543         // no logic if nothing happens here
00544         myType = NODETYPE_NOJUNCTION;
00545         return;
00546     }
00547     // check whether the node was set to be unregulated by the user
00548     if (oc.getBool("keep-nodes-unregulated") || oc.isInStringVector("keep-nodes-unregulated.explicit", getID())
00549             || (oc.getBool("keep-nodes-unregulated.district-nodes") && (isNearDistrict() || isDistrict()))) {
00550         myType = NODETYPE_NOJUNCTION;
00551         return;
00552     }
00553     // compute the logic if necessary or split the junction
00554     if (myType != NODETYPE_NOJUNCTION && myType != NODETYPE_DISTRICT) {
00555         // build the request
00556         myRequest = new NBRequest(ec, this,
00557                                   myAllEdges, myIncomingEdges, myOutgoingEdges, myBlockedConnections);
00558         // check whether it is not too large
00559         unsigned int numConnections = myRequest->getSizes().second;
00560         if (numConnections >= 64) {
00561             // yep -> make it untcontrolled, warn
00562             WRITE_WARNING("Junction '" + getID() + "' is too complicated (#links>64); will be set to unregulated.");
00563             delete myRequest;
00564             myRequest = 0;
00565             myType = NODETYPE_NOJUNCTION;
00566         } else if (numConnections == 0) {
00567             delete myRequest;
00568             myRequest = 0;
00569             myType = NODETYPE_DEAD_END;
00570         } else {
00571             myRequest->buildBitfieldLogic(ec.isLeftHanded());
00572         }
00573     }
00574 }
00575 
00576 
00577 bool
00578 NBNode::writeLogic(OutputDevice& into) const {
00579     if (myRequest) {
00580         myRequest->writeLogic(myID, into);
00581         return true;
00582     }
00583     return false;
00584 }
00585 
00586 
00587 void
00588 NBNode::computeNodeShape(bool leftHand) {
00589     if (myIncomingEdges.size() == 0 && myOutgoingEdges.size() == 0) {
00590         return;
00591     }
00592     try {
00593         NBNodeShapeComputer computer(*this);
00594         myPoly = computer.compute(leftHand);
00595     } catch (InvalidArgument&) {
00596         WRITE_WARNING("For node '" + getID() + "': could not compute shape.");
00597     }
00598 }
00599 
00600 
00601 void
00602 NBNode::computeLanes2Lanes() {
00603     // special case a):
00604     //  one in, one out, the outgoing has one lane more
00605     if (myIncomingEdges.size() == 1 && myOutgoingEdges.size() == 1
00606             && myIncomingEdges[0]->getNumLanes() == myOutgoingEdges[0]->getNumLanes() - 1
00607             && myIncomingEdges[0] != myOutgoingEdges[0]
00608             && myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[0])) {
00609 
00610         NBEdge* incoming = myIncomingEdges[0];
00611         NBEdge* outgoing = myOutgoingEdges[0];
00612         // check if it's not the turnaround
00613         if (incoming->getTurnDestination() == outgoing) {
00614             // will be added later or not...
00615             return;
00616         }
00617         for (int i = 0; i < (int) incoming->getNumLanes(); ++i) {
00618             incoming->setConnection(i, outgoing, i + 1, NBEdge::L2L_COMPUTED);
00619         }
00620         incoming->setConnection(0, outgoing, 0, NBEdge::L2L_COMPUTED);
00621         return;
00622     }
00623     // special case b):
00624     //  two in, one out, the outgoing has the same number of lanes as the sum of the incoming
00625     //  and a high speed, too
00626     //  --> highway on-ramp
00627     bool check = false;
00628     if (myIncomingEdges.size() == 2 && myOutgoingEdges.size() == 1) {
00629         check = myIncomingEdges[0]->getNumLanes() + myIncomingEdges[1]->getNumLanes() == myOutgoingEdges[0]->getNumLanes();
00630         check &= (myIncomingEdges[0]->getStep() <= NBEdge::LANES2EDGES);
00631         check &= (myIncomingEdges[1]->getStep() <= NBEdge::LANES2EDGES);
00632     }
00633     if (check
00634             && myIncomingEdges[0] != myOutgoingEdges[0]
00635             && myIncomingEdges[0]->isConnectedTo(myOutgoingEdges[0])) {
00636         NBEdge* inc1 = myIncomingEdges[0];
00637         NBEdge* inc2 = myIncomingEdges[1];
00638         // for internal: check which one is the rightmost
00639         SUMOReal a1 = inc1->getAngleAtNode(this);
00640         SUMOReal a2 = inc2->getAngleAtNode(this);
00641         SUMOReal ccw = GeomHelper::getCCWAngleDiff(a1, a2);
00642         SUMOReal cw = GeomHelper::getCWAngleDiff(a1, a2);
00643         if (ccw < cw) {
00644             std::swap(inc1, inc2);
00645         }
00646         //
00647         inc1->addLane2LaneConnections(0, myOutgoingEdges[0], 0, inc1->getNumLanes(), NBEdge::L2L_VALIDATED, true, true);
00648         inc2->addLane2LaneConnections(0, myOutgoingEdges[0], inc1->getNumLanes(), inc2->getNumLanes(), NBEdge::L2L_VALIDATED, true, true);
00649         return;
00650     }
00651 
00652     // go through this node's outgoing edges
00653     //  for every outgoing edge, compute the distribution of the node's
00654     //  incoming edges on this edge when approaching this edge
00655     // the incoming edges' steps will then also be marked as LANE2LANE_RECHECK...
00656     EdgeVector::reverse_iterator i;
00657     for (i = myOutgoingEdges.rbegin(); i != myOutgoingEdges.rend(); i++) {
00658         NBEdge* currentOutgoing = *i;
00659         // get the information about edges that do approach this edge
00660         EdgeVector* approaching = getEdgesThatApproach(currentOutgoing);
00661         if (approaching->size() != 0) {
00662             ApproachingDivider divider(approaching, currentOutgoing);
00663             Bresenham::compute(&divider, static_cast<unsigned int>(approaching->size()),
00664                                currentOutgoing->getNumLanes());
00665         }
00666         delete approaching;
00667     }
00668     // ... but we may have the case that there are no outgoing edges
00669     //  In this case, we have to mark the incoming edges as being in state
00670     //   LANE2LANE( not RECHECK) by hand
00671     if (myOutgoingEdges.size() == 0) {
00672         for (i = myIncomingEdges.rbegin(); i != myIncomingEdges.rend(); i++) {
00673             (*i)->markAsInLane2LaneState();
00674         }
00675     }
00676 }
00677 
00678 
00679 EdgeVector*
00680 NBNode::getEdgesThatApproach(NBEdge* currentOutgoing) {
00681     // get the position of the node to get the approaching nodes of
00682     EdgeVector::const_iterator i = find(myAllEdges.begin(),
00683                                         myAllEdges.end(), currentOutgoing);
00684     // get the first possible approaching edge
00685     NBContHelper::nextCW(myAllEdges, i);
00686     // go through the list of edges clockwise and add the edges
00687     EdgeVector* approaching = new EdgeVector();
00688     for (; *i != currentOutgoing;) {
00689         // check only incoming edges
00690         if ((*i)->getToNode() == this && (*i)->getTurnDestination() != currentOutgoing) {
00691             std::vector<int> connLanes = (*i)->getConnectionLanes(currentOutgoing);
00692             if (connLanes.size() != 0) {
00693                 approaching->push_back(*i);
00694             }
00695         }
00696         NBContHelper::nextCW(myAllEdges, i);
00697     }
00698     return approaching;
00699 }
00700 
00701 
00702 void
00703 NBNode::replaceOutgoing(NBEdge* which, NBEdge* by, unsigned int laneOff) {
00704     // replace the edge in the list of outgoing nodes
00705     EdgeVector::iterator i = find(myOutgoingEdges.begin(), myOutgoingEdges.end(), which);
00706     if (i != myOutgoingEdges.end()) {
00707         (*i) = by;
00708         i = find(myAllEdges.begin(), myAllEdges.end(), which);
00709         (*i) = by;
00710     }
00711     // replace the edge in connections of incoming edges
00712     for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); ++i) {
00713         (*i)->replaceInConnections(which, by, laneOff);
00714     }
00715     // replace within the connetion prohibition dependencies
00716     replaceInConnectionProhibitions(which, by, 0, laneOff);
00717 }
00718 
00719 
00720 void
00721 NBNode::replaceOutgoing(const EdgeVector& which, NBEdge* by) {
00722     // replace edges
00723     unsigned int laneOff = 0;
00724     for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
00725         replaceOutgoing(*i, by, laneOff);
00726         laneOff += (*i)->getNumLanes();
00727     }
00728     // removed SUMOReal occurences
00729     removeDoubleEdges();
00730     // check whether this node belongs to a district and the edges
00731     //  must here be also remapped
00732     if (myDistrict != 0) {
00733         myDistrict->replaceOutgoing(which, by);
00734     }
00735 }
00736 
00737 
00738 void
00739 NBNode::replaceIncoming(NBEdge* which, NBEdge* by, unsigned int laneOff) {
00740     // replace the edge in the list of incoming nodes
00741     EdgeVector::iterator i = find(myIncomingEdges.begin(), myIncomingEdges.end(), which);
00742     if (i != myIncomingEdges.end()) {
00743         (*i) = by;
00744         i = find(myAllEdges.begin(), myAllEdges.end(), which);
00745         (*i) = by;
00746     }
00747     // replace within the connetion prohibition dependencies
00748     replaceInConnectionProhibitions(which, by, laneOff, 0);
00749 }
00750 
00751 
00752 void
00753 NBNode::replaceIncoming(const EdgeVector& which, NBEdge* by) {
00754     // replace edges
00755     unsigned int laneOff = 0;
00756     for (EdgeVector::const_iterator i = which.begin(); i != which.end(); i++) {
00757         replaceIncoming(*i, by, laneOff);
00758         laneOff += (*i)->getNumLanes();
00759     }
00760     // removed SUMOReal occurences
00761     removeDoubleEdges();
00762     // check whether this node belongs to a district and the edges
00763     //  must here be also remapped
00764     if (myDistrict != 0) {
00765         myDistrict->replaceIncoming(which, by);
00766     }
00767 }
00768 
00769 
00770 
00771 void
00772 NBNode::replaceInConnectionProhibitions(NBEdge* which, NBEdge* by,
00773                                         unsigned int whichLaneOff, unsigned int byLaneOff) {
00774     // replace in keys
00775     NBConnectionProhibits::iterator j = myBlockedConnections.begin();
00776     while (j != myBlockedConnections.end()) {
00777         bool changed = false;
00778         NBConnection c = (*j).first;
00779         if (c.replaceFrom(which, whichLaneOff, by, byLaneOff)) {
00780             changed = true;
00781         }
00782         if (c.replaceTo(which, whichLaneOff, by, byLaneOff)) {
00783             changed = true;
00784         }
00785         if (changed) {
00786             myBlockedConnections[c] = (*j).second;
00787             myBlockedConnections.erase(j);
00788             j = myBlockedConnections.begin();
00789         } else {
00790             j++;
00791         }
00792     }
00793     // replace in values
00794     for (j = myBlockedConnections.begin(); j != myBlockedConnections.end(); j++) {
00795         NBConnectionVector& prohibiting = (*j).second;
00796         for (NBConnectionVector::iterator k = prohibiting.begin(); k != prohibiting.end(); k++) {
00797             NBConnection& sprohibiting = *k;
00798             sprohibiting.replaceFrom(which, whichLaneOff, by, byLaneOff);
00799             sprohibiting.replaceTo(which, whichLaneOff, by, byLaneOff);
00800         }
00801     }
00802 }
00803 
00804 
00805 
00806 void
00807 NBNode::removeDoubleEdges() {
00808     unsigned int i, j;
00809     // check incoming
00810     for (i = 0; myIncomingEdges.size() > 0 && i < myIncomingEdges.size() - 1; i++) {
00811         j = i + 1;
00812         while (j < myIncomingEdges.size()) {
00813             if (myIncomingEdges[i] == myIncomingEdges[j]) {
00814                 myIncomingEdges.erase(myIncomingEdges.begin() + j);
00815             } else {
00816                 j++;
00817             }
00818         }
00819     }
00820     // check outgoing
00821     for (i = 0; myOutgoingEdges.size() > 0 && i < myOutgoingEdges.size() - 1; i++) {
00822         j = i + 1;
00823         while (j < myOutgoingEdges.size()) {
00824             if (myOutgoingEdges[i] == myOutgoingEdges[j]) {
00825                 myOutgoingEdges.erase(myOutgoingEdges.begin() + j);
00826             } else {
00827                 j++;
00828             }
00829         }
00830     }
00831     // check all
00832     for (i = 0; myAllEdges.size() > 0 && i < myAllEdges.size() - 1; i++) {
00833         j = i + 1;
00834         while (j < myAllEdges.size()) {
00835             if (myAllEdges[i] == myAllEdges[j]) {
00836                 myAllEdges.erase(myAllEdges.begin() + j);
00837             } else {
00838                 j++;
00839             }
00840         }
00841     }
00842 }
00843 
00844 
00845 bool
00846 NBNode::hasIncoming(const NBEdge* const e) const {
00847     return find(myIncomingEdges.begin(), myIncomingEdges.end(), e) != myIncomingEdges.end();
00848 }
00849 
00850 
00851 bool
00852 NBNode::hasOutgoing(const NBEdge* const e) const {
00853     return find(myOutgoingEdges.begin(), myOutgoingEdges.end(), e) != myOutgoingEdges.end();
00854 }
00855 
00856 
00857 NBEdge*
00858 NBNode::getOppositeIncoming(NBEdge* e) const {
00859     EdgeVector edges = myIncomingEdges;
00860     if (find(edges.begin(), edges.end(), e) != edges.end()) {
00861         edges.erase(find(edges.begin(), edges.end(), e));
00862     }
00863     if (e->getToNode() == this) {
00864         sort(edges.begin(), edges.end(), NBContHelper::edge_opposite_direction_sorter(e, this));
00865     } else {
00866         sort(edges.begin(), edges.end(), NBContHelper::edge_similar_direction_sorter(e));
00867     }
00868     return edges[0];
00869 }
00870 
00871 
00872 void
00873 NBNode::addSortedLinkFoes(const NBConnection& mayDrive,
00874                           const NBConnection& mustStop) {
00875     if (mayDrive.getFrom() == 0 ||
00876             mayDrive.getTo() == 0 ||
00877             mustStop.getFrom() == 0 ||
00878             mustStop.getTo() == 0) {
00879 
00880         WRITE_WARNING("Something went wrong during the building of a connection...");
00881         return; // !!! mark to recompute connections
00882     }
00883     NBConnectionVector conn = myBlockedConnections[mustStop];
00884     conn.push_back(mayDrive);
00885     myBlockedConnections[mustStop] = conn;
00886 }
00887 
00888 
00889 NBEdge*
00890 NBNode::getPossiblySplittedIncoming(const std::string& edgeid) {
00891     unsigned int size = (unsigned int) edgeid.length();
00892     for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
00893         std::string id = (*i)->getID();
00894         if (id.substr(0, size) == edgeid) {
00895             return *i;
00896         }
00897     }
00898     return 0;
00899 }
00900 
00901 
00902 NBEdge*
00903 NBNode::getPossiblySplittedOutgoing(const std::string& edgeid) {
00904     unsigned int size = (unsigned int) edgeid.length();
00905     for (EdgeVector::iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
00906         std::string id = (*i)->getID();
00907         if (id.substr(0, size) == edgeid) {
00908             return *i;
00909         }
00910     }
00911     return 0;
00912 }
00913 
00914 
00915 void
00916 NBNode::removeEdge(NBEdge* edge, bool removeFromConnections) {
00917     EdgeVector::iterator i = find(myAllEdges.begin(), myAllEdges.end(), edge);
00918     if (i != myAllEdges.end()) {
00919         myAllEdges.erase(i);
00920         i = find(myOutgoingEdges.begin(), myOutgoingEdges.end(), edge);
00921         if (i != myOutgoingEdges.end()) {
00922             myOutgoingEdges.erase(i);
00923         } else {
00924             i = find(myIncomingEdges.begin(), myIncomingEdges.end(), edge);
00925             if (i != myIncomingEdges.end()) {
00926                 myIncomingEdges.erase(i);
00927             } else {
00928                 // edge must have been either incoming or outgoing
00929                 assert(false);
00930             }
00931         }
00932         if (removeFromConnections) {
00933             for (i = myAllEdges.begin(); i != myAllEdges.end(); ++i) {
00934                 (*i)->removeFromConnections(edge);
00935             }
00936         }
00937     }
00938 }
00939 
00940 
00941 Position
00942 NBNode::getEmptyDir() const {
00943     Position pos(0, 0);
00944     EdgeVector::const_iterator i;
00945     for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
00946         NBNode* conn = (*i)->getFromNode();
00947         Position toAdd = conn->getPosition();
00948         toAdd.sub(myPosition);
00949         toAdd.mul((SUMOReal) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
00950         pos.add(toAdd);
00951     }
00952     for (i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
00953         NBNode* conn = (*i)->getToNode();
00954         Position toAdd = conn->getPosition();
00955         toAdd.sub(myPosition);
00956         toAdd.mul((SUMOReal) 1.0 / sqrt(toAdd.x()*toAdd.x() + toAdd.y()*toAdd.y()));
00957         pos.add(toAdd);
00958     }
00959     pos.mul((SUMOReal) - 1.0 / (myIncomingEdges.size() + myOutgoingEdges.size()));
00960     if (pos.x() == 0 && pos.y() == 0) {
00961         pos = Position(1, 0);
00962     }
00963     pos.norm2d();
00964     return pos;
00965 }
00966 
00967 
00968 
00969 void
00970 NBNode::invalidateIncomingConnections() {
00971     for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
00972         (*i)->invalidateConnections();
00973     }
00974 }
00975 
00976 
00977 void
00978 NBNode::invalidateOutgoingConnections() {
00979     for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
00980         (*i)->invalidateConnections();
00981     }
00982 }
00983 
00984 
00985 bool
00986 NBNode::mustBrake(const NBEdge* const from, const NBEdge* const to, int toLane) const {
00987     // check whether it is participant to a traffic light
00988     //  - controlled links are set by the traffic lights, not the normal
00989     //    right-of-way rules
00990     //  - uncontrolled participants (spip lanes etc.) should always break
00991     if (myTrafficLights.size() != 0) {
00992         // ok, we have a traffic light, return true by now, it will be later
00993         //  controlled by the tls
00994         return true;
00995     }
00996     // unregulated->does not need to brake
00997     if (myRequest == 0) {
00998         return false;
00999     }
01000     // vehicles which do not have a following lane must always decelerate to the end
01001     if (to == 0) {
01002         return true;
01003     }
01004     // check whether any other connection on this node prohibits this connection
01005     bool try1 = myRequest->mustBrake(from, to);
01006     if (!try1 || toLane == -1) {
01007         return try1;
01008     }
01009     if (from->getSpeed() < 70. / 3.6) {
01010         return try1;
01011     }
01012     // on highways (on-ramps, in fact):
01013     // check whether any other connection uses the same destination edge
01014     for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
01015         if ((*i) == from) {
01016             continue;
01017         }
01018         const std::vector<NBEdge::Connection> &connections = (*i)->getConnections();
01019         for (std::vector<NBEdge::Connection>::const_iterator j = connections.begin(); j != connections.end(); ++j) {
01020             if ((*j).toEdge == to && ((*j).toLane < 0 || (*j).toLane == toLane)) {
01021                 return true;
01022             }
01023         }
01024     }
01025     return false;
01026 }
01027 
01028 
01029 bool
01030 NBNode::isLeftMover(const NBEdge* const from, const NBEdge* const to) const {
01031     // when the junction has only one incoming edge, there are no
01032     //  problems caused by left blockings
01033     if (myIncomingEdges.size() == 1 || myOutgoingEdges.size() == 1) {
01034         return false;
01035     }
01036     SUMOReal fromAngle = from->getAngleAtNode(this);
01037     SUMOReal toAngle = to->getAngleAtNode(this);
01038     SUMOReal cw = GeomHelper::getCWAngleDiff(fromAngle, toAngle);
01039     SUMOReal ccw = GeomHelper::getCCWAngleDiff(fromAngle, toAngle);
01040     std::vector<NBEdge*>::const_iterator i = std::find(myAllEdges.begin(), myAllEdges.end(), from);
01041     do {
01042         NBContHelper::nextCW(myAllEdges, i);
01043     } while ((!hasOutgoing(*i) || from->isTurningDirectionAt(this, *i)) && *i != from);
01044     return cw < ccw && (*i) == to && myOutgoingEdges.size() > 2;
01045 }
01046 
01047 
01048 bool
01049 NBNode::forbids(const NBEdge* const possProhibitorFrom, const NBEdge* const possProhibitorTo,
01050                 const NBEdge* const possProhibitedFrom, const NBEdge* const possProhibitedTo,
01051                 bool regardNonSignalisedLowerPriority) const {
01052     return myRequest != 0 && myRequest->forbids(possProhibitorFrom, possProhibitorTo,
01053             possProhibitedFrom, possProhibitedTo,
01054             regardNonSignalisedLowerPriority);
01055 }
01056 
01057 
01058 bool
01059 NBNode::foes(const NBEdge* const from1, const NBEdge* const to1,
01060              const NBEdge* const from2, const NBEdge* const to2) const {
01061     return myRequest != 0 && myRequest->foes(from1, to1, from2, to2);
01062 }
01063 
01064 
01065 void
01066 NBNode::remapRemoved(NBTrafficLightLogicCont& tc,
01067                      NBEdge* removed, const EdgeVector& incoming,
01068                      const EdgeVector& outgoing) {
01069     assert(find(incoming.begin(), incoming.end(), removed) == incoming.end());
01070     bool changed = true;
01071     while (changed) {
01072         changed = false;
01073         NBConnectionProhibits blockedConnectionsTmp = myBlockedConnections;
01074         NBConnectionProhibits blockedConnectionsNew;
01075         // remap in connections
01076         for (NBConnectionProhibits::iterator i = blockedConnectionsTmp.begin(); i != blockedConnectionsTmp.end(); i++) {
01077             const NBConnection& blocker = (*i).first;
01078             const NBConnectionVector& blocked = (*i).second;
01079             // check the blocked connections first
01080             // check whether any of the blocked must be changed
01081             bool blockedChanged = false;
01082             NBConnectionVector newBlocked;
01083             NBConnectionVector::const_iterator j;
01084             for (j = blocked.begin(); j != blocked.end(); j++) {
01085                 const NBConnection& sblocked = *j;
01086                 if (sblocked.getFrom() == removed || sblocked.getTo() == removed) {
01087                     blockedChanged = true;
01088                 }
01089             }
01090             // adapt changes if so
01091             for (j = blocked.begin(); blockedChanged && j != blocked.end(); j++) {
01092                 const NBConnection& sblocked = *j;
01093                 if (sblocked.getFrom() == removed && sblocked.getTo() == removed) {
01094                     /*                    for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
01095                     !!!                        newBlocked.push_back(NBConnection(*k, *k));
01096                                         }*/
01097                 } else if (sblocked.getFrom() == removed) {
01098                     assert(sblocked.getTo() != removed);
01099                     for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
01100                         newBlocked.push_back(NBConnection(*k, sblocked.getTo()));
01101                     }
01102                 } else if (sblocked.getTo() == removed) {
01103                     assert(sblocked.getFrom() != removed);
01104                     for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
01105                         newBlocked.push_back(NBConnection(sblocked.getFrom(), *k));
01106                     }
01107                 } else {
01108                     newBlocked.push_back(NBConnection(sblocked.getFrom(), sblocked.getTo()));
01109                 }
01110             }
01111             if (blockedChanged) {
01112                 blockedConnectionsNew[blocker] = newBlocked;
01113                 changed = true;
01114             }
01115             // if the blocked were kept
01116             else {
01117                 if (blocker.getFrom() == removed && blocker.getTo() == removed) {
01118                     changed = true;
01119                     /*                    for(EdgeVector::const_iterator k=incoming.begin(); k!=incoming.end(); k++) {
01120                     !!!                        blockedConnectionsNew[NBConnection(*k, *k)] = blocked;
01121                                         }*/
01122                 } else if (blocker.getFrom() == removed) {
01123                     assert(blocker.getTo() != removed);
01124                     changed = true;
01125                     for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); k++) {
01126                         blockedConnectionsNew[NBConnection(*k, blocker.getTo())] = blocked;
01127                     }
01128                 } else if (blocker.getTo() == removed) {
01129                     assert(blocker.getFrom() != removed);
01130                     changed = true;
01131                     for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); k++) {
01132                         blockedConnectionsNew[NBConnection(blocker.getFrom(), *k)] = blocked;
01133                     }
01134                 } else {
01135                     blockedConnectionsNew[blocker] = blocked;
01136                 }
01137             }
01138         }
01139         myBlockedConnections = blockedConnectionsNew;
01140     }
01141     // remap in traffic lights
01142     tc.remapRemoved(removed, incoming, outgoing);
01143 }
01144 
01145 
01146 LinkDirection
01147 NBNode::getDirection(const NBEdge* const incoming, const NBEdge* const outgoing) const {
01148     // ok, no connection at all -> dead end
01149     if (outgoing == 0) {
01150         return LINKDIR_NODIR;
01151     }
01152     // turning direction
01153     if (incoming->isTurningDirectionAt(this, outgoing)) {
01154         return LINKDIR_TURN;
01155     }
01156     // get the angle between incoming/outgoing at the junction
01157     SUMOReal angle =
01158         NBHelpers::normRelAngle(incoming->getAngleAtNode(this), outgoing->getAngleAtNode(this));
01159     // ok, should be a straight connection
01160     if (abs((int) angle) + 1 < 45) {
01161         return LINKDIR_STRAIGHT;
01162     }
01163 
01164     // check for left and right, first
01165     if (angle > 0) {
01166         // check whether any other edge goes further to the right
01167         EdgeVector::const_iterator i =
01168             find(myAllEdges.begin(), myAllEdges.end(), outgoing);
01169         NBContHelper::nextCW(myAllEdges, i);
01170         while ((*i) != incoming) {
01171             if ((*i)->getFromNode() == this) {
01172                 return LINKDIR_PARTRIGHT;
01173             }
01174             NBContHelper::nextCW(myAllEdges, i);
01175         }
01176         return LINKDIR_RIGHT;
01177     }
01178     // check whether any other edge goes further to the left
01179     EdgeVector::const_iterator i =
01180         find(myAllEdges.begin(), myAllEdges.end(), outgoing);
01181     NBContHelper::nextCCW(myAllEdges, i);
01182     while ((*i) != incoming) {
01183         if ((*i)->getFromNode() == this && !incoming->isTurningDirectionAt(this, *i)) {
01184             return LINKDIR_PARTLEFT;
01185         }
01186         NBContHelper::nextCCW(myAllEdges, i);
01187     }
01188     return LINKDIR_LEFT;
01189 }
01190 
01191 
01192 std::string
01193 NBNode::stateCode(const NBEdge* incoming, NBEdge* outgoing, int fromlane, bool mayDefinitelyPass) const {
01194     if (outgoing == 0) { // always off
01195         return toString(LINKSTATE_TL_OFF_NOSIGNAL);
01196     }
01197     if (myType == NODETYPE_RIGHT_BEFORE_LEFT) {
01198         return toString(LINKSTATE_EQUAL); // all the same
01199     }
01200     if ((!incoming->isInnerEdge() && mustBrake(incoming, outgoing, fromlane)) && !mayDefinitelyPass) {
01201         return toString(LINKSTATE_MINOR); // minor road
01202     }
01203     // traffic lights are not regardedm here
01204     return toString(LINKSTATE_MAJOR);
01205 }
01206 
01207 
01208 bool
01209 NBNode::checkIsRemovable() const {
01210     // check whether this node is included in a traffic light
01211     if (myTrafficLights.size() != 0) {
01212         return false;
01213     }
01214     EdgeVector::const_iterator i;
01215     // one in, one out -> just a geometry ...
01216     if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
01217         // ... if types match ...
01218         if (!myIncomingEdges[0]->expandableBy(myOutgoingEdges[0])) {
01219             return false;
01220         }
01221         //
01222         return myIncomingEdges[0]->getFromNode() != myOutgoingEdges[0]->getToNode();
01223     }
01224     // two in, two out -> may be something else
01225     if (myOutgoingEdges.size() == 2 && myIncomingEdges.size() == 2) {
01226         // check whether the origin nodes of the incoming edges differ
01227         std::set<NBNode*> origSet;
01228         for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
01229             origSet.insert((*i)->getFromNode());
01230         }
01231         if (origSet.size() < 2) {
01232             return false;
01233         }
01234         // check whether this node is an intermediate node of
01235         //  a two-directional street
01236         for (i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
01237             // try to find the opposite direction
01238             NBNode* origin = (*i)->getFromNode();
01239             // find the back direction of the current edge
01240             EdgeVector::const_iterator j =
01241                 find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(),
01242                         NBContHelper::edge_with_destination_finder(origin));
01243             // check whether the back direction exists
01244             if (j != myOutgoingEdges.end()) {
01245                 // check whether the edge from the backdirection (must be
01246                 //  the counter-clockwise one) may be joined with the current
01247                 NBContHelper::nextCCW(myOutgoingEdges, j);
01248                 // check whether the types allow joining
01249                 if (!(*i)->expandableBy(*j)) {
01250                     return false;
01251                 }
01252             } else {
01253                 // ok, at least one outgoing edge is not an opposite
01254                 //  of an incoming one
01255                 return false;
01256             }
01257         }
01258         return true;
01259     }
01260     // ok, a real node
01261     return false;
01262 }
01263 
01264 
01265 std::vector<std::pair<NBEdge*, NBEdge*> >
01266 NBNode::getEdgesToJoin() const {
01267     assert(checkIsRemovable());
01268     std::vector<std::pair<NBEdge*, NBEdge*> > ret;
01269     // one in, one out-case
01270     if (myOutgoingEdges.size() == 1 && myIncomingEdges.size() == 1) {
01271         ret.push_back(
01272             std::pair<NBEdge*, NBEdge*>(
01273                 myIncomingEdges[0], myOutgoingEdges[0]));
01274         return ret;
01275     }
01276     // two in, two out-case
01277     for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
01278         NBNode* origin = (*i)->getFromNode();
01279         EdgeVector::const_iterator j =
01280             find_if(myOutgoingEdges.begin(), myOutgoingEdges.end(),
01281                     NBContHelper::edge_with_destination_finder(origin));
01282         NBContHelper::nextCCW(myOutgoingEdges, j);
01283         ret.push_back(std::pair<NBEdge*, NBEdge*>(*i, *j));
01284     }
01285     return ret;
01286 }
01287 
01288 
01289 const PositionVector&
01290 NBNode::getShape() const {
01291     return myPoly;
01292 }
01293 
01294 
01295 SUMOReal
01296 NBNode::getMaxEdgeWidth() const {
01297     EdgeVector::const_iterator i = myAllEdges.begin();
01298     assert(i != myAllEdges.end());
01299     SUMOReal ret = (*i)->width();
01300     ++i;
01301     for (; i != myAllEdges.end(); i++) {
01302         ret = ret > (*i)->width() ? ret : (*i)->width();
01303     }
01304     return ret;
01305 }
01306 
01307 
01308 NBEdge*
01309 NBNode::getConnectionTo(NBNode* n) const {
01310     for (EdgeVector::const_iterator i = myOutgoingEdges.begin(); i != myOutgoingEdges.end(); i++) {
01311         if ((*i)->getToNode() == n) {
01312             return (*i);
01313         }
01314     }
01315     return 0;
01316 }
01317 
01318 
01319 bool
01320 NBNode::isNearDistrict() const {
01321     if (isDistrict()) {
01322         return false;
01323     }
01324     EdgeVector edges;
01325     copy(getIncomingEdges().begin(), getIncomingEdges().end(),
01326          back_inserter(edges));
01327     copy(getOutgoingEdges().begin(), getOutgoingEdges().end(),
01328          back_inserter(edges));
01329     for (EdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) {
01330         NBEdge* t = *j;
01331         NBNode* other = 0;
01332         if (t->getToNode() == this) {
01333             other = t->getFromNode();
01334         } else {
01335             other = t->getToNode();
01336         }
01337         EdgeVector edges2;
01338         copy(other->getIncomingEdges().begin(), other->getIncomingEdges().end(), back_inserter(edges2));
01339         copy(other->getOutgoingEdges().begin(), other->getOutgoingEdges().end(), back_inserter(edges2));
01340         for (EdgeVector::const_iterator k = edges2.begin(); k != edges2.end(); ++k) {
01341             if ((*k)->getFromNode()->isDistrict() || (*k)->getToNode()->isDistrict()) {
01342                 return true;
01343             }
01344         }
01345     }
01346     return false;
01347 }
01348 
01349 
01350 bool
01351 NBNode::isDistrict() const {
01352     return myType == NODETYPE_DISTRICT;
01353 }
01354 
01355 
01356 void
01357 NBNode::buildInnerEdges() {
01358     unsigned int noInternalNoSplits = 0;
01359     for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
01360         const std::vector<NBEdge::Connection> &elv = (*i)->getConnections();
01361         for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
01362             if ((*k).toEdge == 0) {
01363                 continue;
01364             }
01365             noInternalNoSplits++;
01366         }
01367     }
01368     unsigned int lno = 0;
01369     unsigned int splitNo = 0;
01370     for (EdgeVector::const_iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
01371         (*i)->buildInnerEdges(*this, noInternalNoSplits, lno, splitNo);
01372     }
01373 }
01374 
01375 
01376 /****************************************************************************/
01377 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines