SUMO - Simulation of Urban MObility

NBEdge.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00007 // Methods for the representation of a single edge
00008 /****************************************************************************/
00009 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00010 // Copyright (C) 2001-2011 DLR (http://www.dlr.de/) and contributors
00011 /****************************************************************************/
00012 //
00013 //   This program is free software; you can redistribute it and/or modify
00014 //   it under the terms of the GNU General Public License as published by
00015 //   the Free Software Foundation; either version 2 of the License, or
00016 //   (at your option) any later version.
00017 //
00018 /****************************************************************************/
00019 
00020 
00021 // ===========================================================================
00022 // included modules
00023 // ===========================================================================
00024 #ifdef _MSC_VER
00025 #include <windows_config.h>
00026 #else
00027 #include <config.h>
00028 #endif
00029 
00030 #include <vector>
00031 #include <string>
00032 #include <algorithm>
00033 #include <cassert>
00034 #include "NBEdgeCont.h"
00035 #include "NBNode.h"
00036 #include "NBNodeCont.h"
00037 #include "NBContHelper.h"
00038 #include "NBHelpers.h"
00039 #include <cmath>
00040 #include <iomanip>
00041 #include "NBTypeCont.h"
00042 #include <utils/geom/GeomHelper.h>
00043 #include <utils/common/MsgHandler.h>
00044 #include <utils/common/StringUtils.h>
00045 #include <utils/common/ToString.h>
00046 #include <utils/common/UtilExceptions.h>
00047 #include <utils/common/StdDefs.h>
00048 #include "NBEdge.h"
00049 #include <utils/options/OptionsCont.h>
00050 #include <utils/iodevices/OutputDevice.h>
00051 
00052 #ifdef CHECK_MEMORY_LEAKS
00053 #include <foreign/nvwa/debug_new.h>
00054 #endif // CHECK_MEMORY_LEAKS
00055 
00056 // ===========================================================================
00057 // static members
00058 // ===========================================================================
00059 const SUMOReal NBEdge::UNSPECIFIED_WIDTH = -1;
00060 const SUMOReal NBEdge::UNSPECIFIED_LOADED_LENGTH = -1;
00061 const SUMOReal NBEdge::UNSPECIFIED_OFFSET = 0;
00062 
00063 // ===========================================================================
00064 // method definitions
00065 // ===========================================================================
00066 /* -------------------------------------------------------------------------
00067  * NBEdge::ToEdgeConnectionsAdder-methods
00068  * ----------------------------------------------------------------------- */
00069 void
00070 NBEdge::ToEdgeConnectionsAdder::execute(const unsigned int lane, const unsigned int virtEdge) throw() {
00071     // check
00072     assert(myTransitions.size() > virtEdge);
00073     // get the approached edge
00074     NBEdge* succEdge = myTransitions[virtEdge];
00075     std::vector<unsigned int> lanes;
00076 
00077     // check whether the currently regarded, approached edge has already
00078     //  a connection starting at the edge which is currently being build
00079     std::map<NBEdge*, std::vector<unsigned int> >::iterator i=myConnections.find(succEdge);
00080     if (i!=myConnections.end()) {
00081         // if there were already lanes assigned, get them
00082         lanes = (*i).second;
00083     }
00084 
00085     // check whether the current lane was already used to connect the currently
00086     //  regarded approached edge
00087     std::vector<unsigned int>::iterator j=find(lanes.begin(), lanes.end(), lane);
00088     if (j==lanes.end()) {
00089         // if not, add it to the list
00090         lanes.push_back(lane);
00091     }
00092     // set information about connecting lanes
00093     myConnections[succEdge] = lanes;
00094 }
00095 
00096 
00097 
00098 /* -------------------------------------------------------------------------
00099  * NBEdge::MainDirections-methods
00100  * ----------------------------------------------------------------------- */
00101 NBEdge::MainDirections::MainDirections(const EdgeVector& outgoing,
00102                                        NBEdge* parent, NBNode* to) {
00103     if (outgoing.size()==0) {
00104         return;
00105     }
00106     // check whether the right turn has a higher priority
00107     assert(outgoing.size()>0);
00108     if (outgoing[0]->getJunctionPriority(to)==1) {
00109         myDirs.push_back(MainDirections::DIR_RIGHTMOST);
00110     }
00111     // check whether the left turn has a higher priority
00112     if (outgoing.back()->getJunctionPriority(to)==1) {
00113         // ok, the left turn belongs to the higher priorised edges on the junction
00114         //  let's check, whether it has also a higher priority (lane number/speed)
00115         //  than the current
00116         EdgeVector tmp(outgoing);
00117         sort(tmp.begin(), tmp.end(), NBContHelper::edge_similar_direction_sorter(parent));
00118         if (outgoing.back()->getPriority()>tmp[0]->getPriority()) {
00119             myDirs.push_back(MainDirections::DIR_LEFTMOST);
00120         } else {
00121             if (outgoing.back()->getNumLanes()>tmp[0]->getNumLanes()) {
00122                 myDirs.push_back(MainDirections::DIR_LEFTMOST);
00123             }
00124         }
00125     }
00126     // check whether the forward direction has a higher priority
00127     //  try to get the forward direction
00128     EdgeVector tmp(outgoing);
00129     sort(tmp.begin(), tmp.end(), NBContHelper::edge_similar_direction_sorter(parent));
00130     NBEdge* edge = *(tmp.begin());
00131     // check whether it has a higher priority and is going straight
00132     if (edge->getJunctionPriority(to)==1 && to->getDirection(parent, edge)==LINKDIR_STRAIGHT) {
00133         myDirs.push_back(MainDirections::DIR_FORWARD);
00134     }
00135 }
00136 
00137 
00138 NBEdge::MainDirections::~MainDirections() {}
00139 
00140 
00141 bool
00142 NBEdge::MainDirections::empty() const {
00143     return myDirs.empty();
00144 }
00145 
00146 
00147 bool
00148 NBEdge::MainDirections::includes(Direction d) const {
00149     return find(myDirs.begin(), myDirs.end(), d)!=myDirs.end();
00150 }
00151 
00152 
00153 
00154 /* -------------------------------------------------------------------------
00155  * NBEdge-methods
00156  * ----------------------------------------------------------------------- */
00157 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
00158                std::string type, SUMOReal speed, unsigned int nolanes,
00159                int priority, SUMOReal width, SUMOReal offset,
00160                const std::string& streetName,
00161                LaneSpreadFunction spread) throw(ProcessError) :
00162     Named(StringUtils::convertUmlaute(id)),
00163     myStep(INIT),
00164     myType(StringUtils::convertUmlaute(type)),
00165     myFrom(from), myTo(to), myAngle(0),
00166     myPriority(priority), mySpeed(speed),
00167     myTurnDestination(0),
00168     myFromJunctionPriority(-1), myToJunctionPriority(-1),
00169     myLaneSpreadFunction(spread), myOffset(offset), myWidth(width),
00170     myLoadedLength(UNSPECIFIED_LOADED_LENGTH), myAmLeftHand(false), myAmTurningWithAngle(0), myAmTurningOf(0),
00171     myAmInnerEdge(false), myAmMacroscopicConnector(false),
00172     myStreetName(streetName) {
00173     init(nolanes, false);
00174 }
00175 
00176 
00177 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
00178                std::string type, SUMOReal speed, unsigned int nolanes,
00179                int priority, SUMOReal width, SUMOReal offset,
00180                PositionVector geom,
00181                const std::string& streetName,
00182                LaneSpreadFunction spread, bool tryIgnoreNodePositions) throw(ProcessError) :
00183     Named(StringUtils::convertUmlaute(id)),
00184     myStep(INIT),
00185     myType(StringUtils::convertUmlaute(type)),
00186     myFrom(from), myTo(to), myAngle(0),
00187     myPriority(priority), mySpeed(speed),
00188     myTurnDestination(0),
00189     myFromJunctionPriority(-1), myToJunctionPriority(-1),
00190     myGeom(geom), myLaneSpreadFunction(spread), myOffset(offset), myWidth(width),
00191     myLoadedLength(UNSPECIFIED_LOADED_LENGTH), myAmLeftHand(false), myAmTurningWithAngle(0), myAmTurningOf(0),
00192     myAmInnerEdge(false), myAmMacroscopicConnector(false),
00193     myStreetName(streetName) {
00194     init(nolanes, tryIgnoreNodePositions);
00195 }
00196 
00197 
00198 NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to, NBEdge* tpl) :
00199     Named(StringUtils::convertUmlaute(id)),
00200     myStep(INIT),
00201     myType(tpl->getTypeID()),
00202     myFrom(from), myTo(to), myAngle(0),
00203     myPriority(tpl->getPriority()), mySpeed(tpl->getSpeed()),
00204     myTurnDestination(0),
00205     myFromJunctionPriority(-1), myToJunctionPriority(-1),
00206     myLaneSpreadFunction(tpl->getLaneSpreadFunction()),
00207     myOffset(tpl->getOffset()),
00208     myWidth(tpl->getWidth()),
00209     myLoadedLength(UNSPECIFIED_LOADED_LENGTH), myAmLeftHand(false), myAmTurningWithAngle(0), myAmTurningOf(0),
00210     myAmInnerEdge(false), myAmMacroscopicConnector(false),
00211     myStreetName(tpl->getStreetName()) {
00212     init(tpl->getNumLanes(), false);
00213     for (unsigned int i = 0; i < getNumLanes(); i++) {
00214         setLaneSpeed(i, tpl->getLaneSpeed(i));
00215         setVehicleClasses(tpl->getAllowedVehicleClasses(i), tpl->getDisallowedVehicleClasses(i), i);
00216     }
00217 }
00218 
00219 
00220 void
00221 NBEdge::reinit(NBNode* from, NBNode* to, const std::string& type,
00222                SUMOReal speed, unsigned int nolanes, int priority,
00223                PositionVector geom, SUMOReal width, SUMOReal offset,
00224                LaneSpreadFunction spread,
00225                bool tryIgnoreNodePositions) throw(ProcessError) {
00226     // connections may still be valid
00227     if (myFrom!=from) {
00228         myFrom->removeEdge(this, false);
00229     }
00230     if (myTo!=to) {
00231         myTo->removeEdge(this, false);
00232     }
00233     myType = StringUtils::convertUmlaute(type);
00234     myFrom = from;
00235     myTo = to;
00236     myPriority = priority;
00237     mySpeed = speed;
00238     //?myTurnDestination(0),
00239     //?myFromJunctionPriority(-1), myToJunctionPriority(-1),
00240     myGeom = geom;
00241     myLaneSpreadFunction = spread;
00242     myOffset = offset;
00243     myWidth = width;
00244     myLoadedLength = UNSPECIFIED_LOADED_LENGTH;
00245     //?, myAmTurningWithAngle(0), myAmTurningOf(0),
00246     //?myAmInnerEdge(false), myAmMacroscopicConnector(false)
00247     init(nolanes, tryIgnoreNodePositions);
00248 }
00249 
00250 
00251 void
00252 NBEdge::init(unsigned int noLanes, bool tryIgnoreNodePositions) throw(ProcessError) {
00253     if (noLanes==0) {
00254         throw ProcessError("Edge '" + myID + "' needs at least one lane.");
00255     }
00256     if (myFrom==0||myTo==0) {
00257         throw ProcessError("At least one of edge's '" + myID + "' nodes is not known.");
00258     }
00259     // revisit geometry
00260     //  should have at least two points at the end...
00261     //  and in dome cases, the node positions must be added
00262     myGeom.removeDoublePoints();
00263     if (!tryIgnoreNodePositions||myGeom.size()<2) {
00264         if (myGeom.size()==0) {
00265             myGeom.push_back(myTo->getPosition());
00266             myGeom.push_front(myFrom->getPosition());
00267         } else {
00268             myGeom.push_back_noDoublePos(myTo->getPosition());
00269             myGeom.push_front_noDoublePos(myFrom->getPosition());
00270         }
00271     }
00272     if (myGeom.size()<2) {
00273         myGeom.clear();
00274         myGeom.push_back(myTo->getPosition());
00275         myGeom.push_front(myFrom->getPosition());
00276     }
00277     if (myGeom.size()==2&&myGeom[0]==myGeom[1]) {
00278         WRITE_ERROR("Edge's '" + myID + "' from- and to-node are at the same position.");
00279         myGeom[1].add(Position(POSITION_EPS, POSITION_EPS));
00280     }
00281     //
00282     myAngle = NBHelpers::angle(
00283                   myFrom->getPosition().x(), myFrom->getPosition().y(),
00284                   myTo->getPosition().x(), myTo->getPosition().y()
00285               );
00286     myFrom->addOutgoingEdge(this);
00287     myTo->addIncomingEdge(this);
00288     // prepare container
00289     myLength = myFrom->getPosition().distanceTo(myTo->getPosition());
00290     assert(myGeom.size()>=2);
00291     myLanes.clear();
00292     for (unsigned int i=0; i<noLanes; i++) {
00293         Lane l;
00294         l.speed = mySpeed;
00295         l.offset = myOffset;
00296         l.width = myWidth;
00297         myLanes.push_back(l);
00298     }
00299     computeLaneShapes();
00300 }
00301 
00302 
00303 NBEdge::~NBEdge() throw() {}
00304 
00305 
00306 // -----------  Applying offset
00307 void
00308 NBEdge::reshiftPosition(SUMOReal xoff, SUMOReal yoff) throw() {
00309     myGeom.reshiftRotate(xoff, yoff, 0);
00310     for (unsigned int i=0; i<myLanes.size(); i++) {
00311         myLanes[i].shape.reshiftRotate(xoff, yoff, 0);
00312     }
00313 }
00314 
00315 
00316 // ----------- Edge geometry access and computation
00317 const PositionVector
00318 NBEdge::getInnerGeometry() const {
00319     PositionVector result = getGeometry();
00320     result.pop_front();
00321     result.pop_back();
00322     return result;
00323 }
00324 
00325 
00326 bool
00327 NBEdge::hasDefaultGeometry() const {
00328     return myGeom.size() == 2 && hasDefaultGeometryEndpoints();
00329 }
00330 
00331 
00332 bool
00333 NBEdge::hasDefaultGeometryEndpoints() const {
00334     return myGeom.getBegin() == myFrom->getPosition() &&
00335            myGeom.getEnd() == myTo->getPosition();
00336 }
00337 
00338 
00339 void
00340 NBEdge::setGeometry(const PositionVector& s, bool inner) throw() {
00341     Position begin = myGeom.getBegin(); // may differ from node position
00342     Position end = myGeom.getEnd(); // may differ from node position
00343     myGeom = s;
00344     if (inner) {
00345         myGeom.push_front(begin);
00346         myGeom.push_back(end);
00347     }
00348     computeLaneShapes();
00349 }
00350 
00351 
00352 void
00353 NBEdge::computeEdgeShape() throw() {
00354     unsigned int i;
00355     for (i=0; i<myLanes.size(); i++) {
00356         PositionVector& shape = myLanes[i].shape;
00357         // get lane begin and end
00358         Line lb = Line(shape[0], shape[1]);
00359         Line le = Line(shape[-1], shape[-2]);
00360         lb.extrapolateBy(100.0);
00361         le.extrapolateBy(100.0);
00362         //
00363         PositionVector old = shape;
00364         Position nb, ne;
00365         // lane begin
00366         if (myFrom->getShape().intersects(shape)) {
00367             // get the intersection position with the junction
00368             DoubleVector pbv = shape.intersectsAtLengths(myFrom->getShape());
00369             if (pbv.size()>0) {
00370                 SUMOReal pb = VectorHelper<SUMOReal>::maxValue(pbv);
00371                 if (pb>=0&&pb<=shape.length()) {
00372                     shape = shape.getSubpart(pb, shape.length());
00373                 }
00374             }
00375         } else if (myFrom->getShape().intersects(lb.p1(), lb.p2())) {
00376             DoubleVector pbv = lb.intersectsAtLengths(myFrom->getShape());
00377             if (pbv.size()>0) {
00378                 SUMOReal pb = VectorHelper<SUMOReal>::maxValue(pbv);
00379                 if (pb>=0) {
00380                     shape.eraseAt(0);
00381                     shape.push_front_noDoublePos(lb.getPositionAtDistance(pb));
00382                 }
00383             }
00384         }
00385         // lane end
00386         if (myTo->getShape().intersects(shape)) {
00387             // get the intersection position with the junction
00388             DoubleVector pev = shape.intersectsAtLengths(myTo->getShape());
00389             if (pev.size()>0) {
00390                 SUMOReal pe = VectorHelper<SUMOReal>::minValue(pev);
00391                 if (pe>=0&&pe<=shape.length()) {
00392                     shape = shape.getSubpart(0, pe);
00393                 }
00394             }
00395         } else if (myTo->getShape().intersects(le.p1(), le.p2())) {
00396             DoubleVector pev = le.intersectsAtLengths(myTo->getShape());
00397             if (pev.size()>0) {
00398                 SUMOReal pe = VectorHelper<SUMOReal>::maxValue(pev);
00399                 if (pe>=0) {
00400                     shape.eraseAt((int) shape.size()-1);
00401                     shape.push_back(le.getPositionAtDistance(pe));
00402                 }
00403             }
00404         }
00405         if (shape.length() < POSITION_EPS) {
00406             WRITE_MESSAGE("Lane '" + myID + "' has calculated shape length near zero. Revert it back to old shape.");
00407             shape = old;
00408         } else {
00409             Line lc(shape[0], shape[-1]);
00410             Line lo(old[0], old[-1]);
00411             if (135<GeomHelper::getMinAngleDiff(lc.atan2DegreeAngle(), lo.atan2DegreeAngle())) {
00412                 shape = shape.reverse();
00413             }
00414         }
00415     }
00416     // recompute edge's length
00417     SUMOReal length = 0;
00418     for (i=0; i<myLanes.size(); i++) {
00419         assert(myLanes[i].shape.length()>0);
00420         length += myLanes[i].shape.length();
00421     }
00422     myLength = length / (SUMOReal) myLanes.size();
00423 }
00424 
00425 
00426 const PositionVector&
00427 NBEdge::getLaneShape(unsigned int i) const throw() {
00428     return myLanes[i].shape;
00429 }
00430 
00431 
00432 void
00433 NBEdge::setLaneSpreadFunction(LaneSpreadFunction spread) throw() {
00434     myLaneSpreadFunction = spread;
00435 }
00436 
00437 
00438 void
00439 NBEdge::addGeometryPoint(int index, const Position& p) throw() {
00440     myGeom.insertAt(index, p);
00441 }
00442 
00443 
00444 bool
00445 NBEdge::splitGeometry(NBEdgeCont& ec, NBNodeCont& nc) {
00446     // check whether there any splits to perform
00447     if (myGeom.size()<3) {
00448         return false;
00449     }
00450     // ok, split
00451     NBNode* newFrom = myFrom;
00452     NBNode* myLastNode = myTo;
00453     NBNode* newTo = 0;
00454     NBEdge* currentEdge = this;
00455     for (int i=1; i<(int) myGeom.size()-1; i++) {
00456         // build the node first
00457         if (i!=static_cast<int>(myGeom.size()-2)) {
00458             std::string nodename = myID + "_in_between#" + toString(i);
00459             if (!nc.insert(nodename, myGeom[i])) {
00460                 throw ProcessError("Error on adding in-between node '" + nodename + "'.");
00461             }
00462             newTo = nc.retrieve(nodename);
00463         } else {
00464             newTo = myLastNode;
00465         }
00466         if (i==1) {
00467             currentEdge->myTo->removeEdge(this);
00468             currentEdge->myTo = newTo;
00469             newTo->addIncomingEdge(currentEdge);
00470         } else {
00471             std::string edgename = myID + "[" + toString(i-1) + "]";
00472             // @bug lane-specific width, speed, overall offset and restrictions are ignored
00473             currentEdge = new NBEdge(edgename, newFrom, newTo, myType, mySpeed, (unsigned int) myLanes.size(),
00474                                      myPriority, myWidth, UNSPECIFIED_OFFSET, myStreetName, myLaneSpreadFunction);
00475             if (!ec.insert(currentEdge, true)) {
00476                 throw ProcessError("Error on adding splitted edge '" + edgename + "'.");
00477             }
00478         }
00479         newFrom = newTo;
00480     }
00481     myGeom.clear();
00482     myGeom.push_back(myFrom->getPosition());
00483     myGeom.push_back(myTo->getPosition());
00484     myStep = INIT;
00485     return true;
00486 }
00487 
00488 
00489 // ----------- Setting and getting connections
00490 bool
00491 NBEdge::addEdge2EdgeConnection(NBEdge* dest) throw() {
00492     if (myStep==INIT_REJECT_CONNECTIONS) {
00493         return true;
00494     }
00495     // check whether the node was merged and now a connection between
00496     //  not matching edges is tried to be added
00497     //  This happens f.e. within the ptv VISSIM-example "Beijing"
00498     if (dest!=0 && myTo!=dest->myFrom) {
00499         return false;
00500     }
00501     if (dest == 0) {
00502         invalidateConnections();
00503         myConnections.push_back(Connection(-1, dest, -1));
00504     } else if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(dest))==myConnections.end()) {
00505         myConnections.push_back(Connection(-1, dest, -1));
00506     }
00507     if (myStep<EDGE2EDGES) {
00508         myStep = EDGE2EDGES;
00509     }
00510     return true;
00511 }
00512 
00513 
00514 bool
00515 NBEdge::addLane2LaneConnection(unsigned int from, NBEdge* dest,
00516                                unsigned int toLane, Lane2LaneInfoType type,
00517                                bool mayUseSameDestination,
00518                                bool mayDefinitelyPass) throw() {
00519     if (myStep==INIT_REJECT_CONNECTIONS) {
00520         return true;
00521     }
00522     // check whether the node was merged and now a connection between
00523     //  not matching edges is tried to be added
00524     //  This happens f.e. within the ptv VISSIM-example "Beijing"
00525     if (myTo!=dest->myFrom) {
00526         return false;
00527     }
00528     if (!addEdge2EdgeConnection(dest)) {
00529         return false;
00530     }
00531     setConnection(from, dest, toLane, type, mayUseSameDestination, mayDefinitelyPass);
00532     return true;
00533 }
00534 
00535 
00536 bool
00537 NBEdge::addLane2LaneConnections(unsigned int fromLane,
00538                                 NBEdge* dest, unsigned int toLane,
00539                                 unsigned int no, Lane2LaneInfoType type,
00540                                 bool invalidatePrevious,
00541                                 bool mayDefinitelyPass) throw() {
00542     if (invalidatePrevious) {
00543         invalidateConnections(true);
00544     }
00545     bool ok = true;
00546     for (unsigned int i=0; i<no&&ok; i++) {
00547         ok &= addLane2LaneConnection(fromLane+i, dest, toLane+i, type, false, mayDefinitelyPass);
00548     }
00549     return ok;
00550 }
00551 
00552 
00553 void
00554 NBEdge::setConnection(unsigned int lane, NBEdge* destEdge,
00555                       unsigned int destLane, Lane2LaneInfoType type,
00556                       bool mayUseSameDestination,
00557                       bool mayDefinitelyPass) throw() {
00558     if (myStep==INIT_REJECT_CONNECTIONS) {
00559         return;
00560     }
00561     // some kind of a misbehaviour which may occure when the junction's outgoing
00562     //  edge priorities were not properly computed, what may happen due to
00563     //  an incomplete or not proper input
00564     // what happens is that under some circumstances a single lane may set to
00565     //  be approached more than once by the one of our lanes.
00566     //  This must not be!
00567     // we test whether it is the case and do nothing if so - the connection
00568     //  will be refused
00569     //
00570     if (!mayUseSameDestination && hasConnectionTo(destEdge, destLane)) {
00571         return;
00572     }
00573     if (find_if(myConnections.begin(), myConnections.end(), connections_finder(lane, destEdge, destLane))!=myConnections.end()) {
00574         return;
00575     }
00576     if (myLanes.size()<=lane) {
00577         WRITE_ERROR("Could not set connection from '" + getLaneID(lane) + "' to '" + destEdge->getLaneID(destLane) + "'.");
00578         return;
00579     }
00580     for (std::vector<Connection>::iterator i=myConnections.begin(); i!=myConnections.end();) {
00581         if ((*i).toEdge==destEdge && ((*i).fromLane==-1 || (*i).toLane==-1)) {
00582             i = myConnections.erase(i);
00583         } else {
00584             ++i;
00585         }
00586     }
00587     myConnections.push_back(Connection(lane, destEdge, destLane));
00588     if (mayDefinitelyPass) {
00589         myConnections.back().mayDefinitelyPass = true;
00590     }
00591     if (type==L2L_USER) {
00592         myStep = LANES2LANES_USER;
00593     } else {
00594         // check whether we have to take another look at it later
00595         if (type==L2L_COMPUTED) {
00596             // yes, the connection was set using an algorithm which requires a recheck
00597             myStep = LANES2LANES_RECHECK;
00598         } else {
00599             // ok, let's only not recheck it if we did no add something that has to be recheked
00600             if (myStep!=LANES2LANES_RECHECK) {
00601                 myStep = LANES2LANES_DONE;
00602             }
00603         }
00604     }
00605 }
00606 
00607 
00608 std::vector<NBEdge::Connection>
00609 NBEdge::getConnectionsFromLane(unsigned int lane) const throw() {
00610     std::vector<NBEdge::Connection> ret;
00611     for (std::vector<Connection>::const_iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
00612         if ((*i).fromLane==static_cast<int>(lane)) {
00613             ret.push_back(*i);
00614         }
00615     }
00616     return ret;
00617 }
00618 
00619 
00620 bool
00621 NBEdge::hasConnectionTo(NBEdge* destEdge, unsigned int destLane) const throw() {
00622     return destEdge!=0&&find_if(myConnections.begin(), myConnections.end(), connections_toedgelane_finder(destEdge, destLane))!=myConnections.end();
00623 }
00624 
00625 
00626 void
00627 NBEdge::buildInnerEdges(const NBNode& n, unsigned int noInternalNoSplits, unsigned int& lno, unsigned int& splitNo) {
00628     std::string innerID = ":" + n.getID();
00629     for (std::vector<Connection>::iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
00630         if ((*i).toEdge==0) {
00631             continue;
00632         }
00633 
00634         PositionVector shape = n.computeInternalLaneShape(this, (*i).fromLane, (*i).toEdge, (*i).toLane);
00635 
00636         LinkDirection dir = n.getDirection(this, (*i).toEdge);
00637         std::pair<SUMOReal, std::vector<unsigned int> > crossingPositions(-1, std::vector<unsigned int>());
00638         std::string crossingNames;
00639         std::set<std::string> tmpSourceNames;
00640         switch (dir) {
00641         case LINKDIR_LEFT:
00642         case LINKDIR_PARTLEFT:
00643         case LINKDIR_TURN: {
00644             unsigned int index = 0;
00645             const std::vector<NBEdge*> &incoming = n.getIncomingEdges();
00646             for (EdgeVector::const_iterator i2=incoming.begin(); i2!=incoming.end(); ++i2) {
00647                 const std::vector<Connection> &elv = (*i2)->getConnections();
00648                 for (std::vector<NBEdge::Connection>::const_iterator k2=elv.begin(); k2!=elv.end(); k2++) {
00649                     if ((*k2).toEdge==0) {
00650                         continue;
00651                     }
00652                     bool needsCont = n.needsCont(this, (*i).toEdge, *i2, (*k2).toEdge, *k2);
00653                     // compute the crossing point
00654                     if (needsCont) {
00655                         crossingPositions.second.push_back(index);
00656                         PositionVector otherShape = n.computeInternalLaneShape(*i2, (*k2).fromLane, (*k2).toEdge, (*k2).toLane);
00657                         if (shape.intersects(otherShape)) {
00658                             DoubleVector dv = shape.intersectsAtLengths(otherShape);
00659                             SUMOReal minDV = dv[0];
00660                             if (minDV<shape.length()-.1&&minDV>.1) { // !!!?
00661                                 assert(minDV>=0);
00662                                 if (crossingPositions.first<0||crossingPositions.first>minDV) {
00663                                     crossingPositions.first = minDV;
00664                                 }
00665                             }
00666                         }
00667                     }
00668                     // compute crossing ids
00669                     NBEdge* e = getToNode()->getOppositeIncoming(this);
00670                     if (e!=*i2) {
00671                         index++;
00672                         continue;
00673                     }
00674                     if (needsCont) {
00675                         if (crossingNames.length()!=0) {
00676                             crossingNames += " ";
00677                         }
00678                         crossingNames += (":" + n.getID() + "_" + toString(index) + "_0");
00679                     }
00680 
00681                     // compute source ids
00682                     if ((*k2).mayDefinitelyPass) {
00683                         index++;
00684                         continue;
00685                     }
00686                     if (needsCont) {
00687                         tmpSourceNames.insert((*i2)->getID() + "_" + toString((*k2).fromLane));
00688                     }
00689                     index++;
00690                 }
00691             }
00692             if (dir==LINKDIR_TURN&&crossingPositions.first<0&&crossingPositions.second.size()!=0) {
00693                 // let turnarounds wait at the begin if no other crossing point was found
00694                 crossingPositions.first = (SUMOReal) shape.length() / 2.;
00695             }
00696         }
00697         break;
00698         default:
00699             break;
00700         }
00701 
00702 
00703         // compute the maximum speed allowed
00704         //  see !!! for an explanation (with a_lat_mean ~0.3)
00705         SUMOReal vmax = (SUMOReal) 0.3 * (SUMOReal) 9.80778 *
00706                         getLaneShape((*i).fromLane).getEnd().distanceTo(
00707                             (*i).toEdge->getLaneShape((*i).toLane).getBegin())
00708                         / (SUMOReal) 2.0 / (SUMOReal) PI;
00709         vmax = MIN2(vmax, ((getSpeed()+(*i).toEdge->getSpeed())/(SUMOReal) 2.0));
00710         vmax = (getSpeed()+(*i).toEdge->getSpeed())/(SUMOReal) 2.0;
00711         //
00712         Position end = (*i).toEdge->getLaneShape((*i).toLane).getBegin();
00713         Position beg = getLaneShape((*i).fromLane).getEnd();
00714 
00715         assert(shape.size() >= 2);
00716         // get internal splits if any
00717         if (crossingPositions.first>=0) {
00718             std::pair<PositionVector, PositionVector> split = shape.splitAt(crossingPositions.first);
00719             (*i).id = innerID + "_" + toString(lno);
00720             (*i).vmax = vmax;
00721             (*i).shape = split.first;
00722             (*i).crossingNames = crossingNames;
00723             for (std::set<std::string>::iterator q=tmpSourceNames.begin(); q!=tmpSourceNames.end(); ++q) {
00724                 if ((*i).sourceNames.length()!=0) {
00725                     (*i).sourceNames += " ";
00726                 }
00727                 (*i).sourceNames += *q;
00728             }
00729             (*i).viaID = innerID + "_" + toString(splitNo+noInternalNoSplits);
00730             (*i).viaVmax = vmax;
00731             (*i).viaShape = split.second;
00732             (*i).haveVia = true;
00733             splitNo++;
00734         } else {
00735             (*i).id = innerID + "_" + toString(lno);
00736             (*i).vmax = vmax;
00737             (*i).shape = shape;
00738         }
00739 
00740 
00741         lno++;
00742     }
00743 }
00744 
00745 // -----------
00746 
00747 
00748 int
00749 NBEdge::getJunctionPriority(const NBNode* const node) const {
00750     if (node==myFrom) {
00751         return myFromJunctionPriority;
00752     } else {
00753         return myToJunctionPriority;
00754     }
00755 }
00756 
00757 
00758 void
00759 NBEdge::setJunctionPriority(const NBNode* const node, int prio) {
00760     if (node==myFrom) {
00761         myFromJunctionPriority = prio;
00762     } else {
00763         myToJunctionPriority = prio;
00764     }
00765 }
00766 
00767 
00768 void
00769 NBEdge::computeTurningDirections() {
00770     myTurnDestination = 0;
00771     EdgeVector outgoing = myTo->getOutgoingEdges();
00772     for (EdgeVector::iterator i=outgoing.begin(); i!=outgoing.end(); i++) {
00773         NBEdge* outedge = *i;
00774         if (myConnections.size()!=0&&!isConnectedTo(outedge)) {
00775             continue;
00776         }
00777         SUMOReal relAngle =
00778             NBHelpers::relAngle(getAngle(*myTo), outedge->getAngle(*myTo));
00779         // do not append the turnaround
00780         if (fabs(relAngle)>160) {
00781             setTurningDestination(outedge);
00782         }
00783     }
00784 }
00785 
00786 
00787 SUMOReal
00788 NBEdge::getAngle(const NBNode& atNode) const {
00789     if (&atNode==myFrom) {
00790         return myGeom.getBegLine().atan2DegreeAngle();
00791     } else {
00792         assert(&atNode==myTo);
00793         return myGeom.getEndLine().atan2DegreeAngle();
00794     }
00795 }
00796 
00797 
00798 void
00799 NBEdge::setTurningDestination(NBEdge* e) {
00800     SUMOReal cur = fabs(NBHelpers::relAngle(getAngle(), e->getAngle()));
00801     SUMOReal old =
00802         myTurnDestination==0
00803         ? 0
00804         : fabs(NBHelpers::relAngle(getAngle(), myTurnDestination->getAngle()));
00805     if (cur>old
00806             &&
00807             e->acceptBeingTurning(this)) {
00808 
00809         myTurnDestination = e;
00810     }
00811 }
00812 
00813 
00814 bool
00815 NBEdge::acceptBeingTurning(NBEdge* e) {
00816     if (e==myAmTurningOf) {
00817         return true;
00818     }
00819     SUMOReal angle = fabs(NBHelpers::relAngle(getAngle(), e->getAngle()));
00820     if (myAmTurningWithAngle>angle) {
00821         return false;
00822     }
00823     if (myAmTurningWithAngle==angle) {
00824         return false; // !!! ok, this happens only within a cell-network (backgrnd), we have to take a further look sometime
00825     }
00826     NBEdge* previous = myAmTurningOf;
00827     myAmTurningWithAngle = angle;
00828     myAmTurningOf = e;
00829     if (previous!=0) {
00830         previous->computeTurningDirections();
00831     }
00832     return true;
00833 }
00834 
00835 
00836 void
00837 NBEdge::setLaneSpeed(unsigned int lane, SUMOReal speed) {
00838     myLanes[lane].speed = speed;
00839 }
00840 
00841 
00842 SUMOReal
00843 NBEdge::getLaneSpeed(unsigned int lane) const {
00844     return myLanes[lane].speed;
00845 }
00846 
00847 
00848 void
00849 NBEdge::computeLaneShapes() throw() {
00850     // vissim needs this
00851     if (myFrom==myTo) {
00852         return;
00853     }
00854     // build the shape of each lane
00855     for (unsigned int i=0; i<myLanes.size(); i++) {
00856         try {
00857             myLanes[i].shape = computeLaneShape(i);
00858         } catch (InvalidArgument& e) {
00859             WRITE_WARNING("In edge '" + getID() + "': lane shape could not been determined (" + e.what() + ")");
00860             myLanes[i].shape = myGeom;
00861         }
00862     }
00863 }
00864 
00865 
00866 PositionVector
00867 NBEdge::computeLaneShape(unsigned int lane) throw(InvalidArgument) {
00868     PositionVector shape;
00869     bool haveWarned = false;
00870     for (int i=0; i<(int) myGeom.size(); i++) {
00871         if (i==0) {
00872             Position from = myGeom[i];
00873             Position to = myGeom[i+1];
00874             std::pair<SUMOReal, SUMOReal> offsets = laneOffset(from, to, SUMO_const_laneWidthAndOffset, (unsigned int)(myLanes.size()-1-lane));
00875             shape.push_back(
00876                 // (methode umbenennen; was heisst hier "-")
00877                 Position(from.x()-offsets.first, from.y()-offsets.second, from.z()));
00878         } else if (i==static_cast<int>(myGeom.size()-1)) {
00879             Position from = myGeom[i-1];
00880             Position to = myGeom[i];
00881             std::pair<SUMOReal, SUMOReal> offsets = laneOffset(from, to, SUMO_const_laneWidthAndOffset, (unsigned int)(myLanes.size()-1-lane));
00882             shape.push_back(
00883                 // (methode umbenennen; was heisst hier "-")
00884                 Position(to.x()-offsets.first, to.y()-offsets.second, to.z()));
00885         } else {
00886             Position from = myGeom[i-1];
00887             Position me = myGeom[i];
00888             Position to = myGeom[i+1];
00889             std::pair<SUMOReal, SUMOReal> offsets = laneOffset(from, me, SUMO_const_laneWidthAndOffset, (unsigned int)(myLanes.size()-1-lane));
00890             std::pair<SUMOReal, SUMOReal> offsets2 = laneOffset(me, to, SUMO_const_laneWidthAndOffset, (unsigned int)(myLanes.size()-1-lane));
00891             Line l1(
00892                 Position(from.x()-offsets.first, from.y()-offsets.second),
00893                 Position(me.x()-offsets.first, me.y()-offsets.second));
00894             l1.extrapolateBy(100);
00895             Line l2(
00896                 Position(me.x()-offsets2.first, me.y()-offsets2.second),
00897                 Position(to.x()-offsets2.first, to.y()-offsets2.second));
00898             const SUMOReal angle = GeomHelper::getCWAngleDiff(l1.atan2DegreeAngle(), l2.atan2DegreeAngle());
00899             if (angle<10.||angle>350.) {
00900                 shape.push_back(
00901                     // (methode umbenennen; was heisst hier "-")
00902                     Position(me.x()-offsets.first, me.y()-offsets.second, me.z()));
00903                 continue;
00904             }
00905             l2.extrapolateBy(100);
00906             if (l1.intersects(l2)) {
00907                 Position intersetion = l1.intersectsAt(l2);
00908                 shape.push_back(Position(intersetion.x(), intersetion.y(), me.z()));
00909             } else {
00910                 if (!haveWarned) {
00911                     WRITE_WARNING("In lane '" + getLaneID(lane) + "': Could not build shape.");
00912                     haveWarned = true;
00913                 }
00914             }
00915         }
00916     }
00917     return shape;
00918 }
00919 
00920 
00921 std::pair<SUMOReal, SUMOReal>
00922 NBEdge::laneOffset(const Position& from, const Position& to,
00923                    SUMOReal lanewidth, unsigned int lane) throw(InvalidArgument) {
00924     return laneOffset(from, to, lanewidth, lane,
00925                       myLanes.size(), myLaneSpreadFunction, myAmLeftHand);
00926 }
00927 
00928 
00929 std::pair<SUMOReal, SUMOReal>
00930 NBEdge::laneOffset(const Position& from, const Position& to,
00931                    SUMOReal lanewidth, unsigned int lane,
00932                    size_t noLanes, LaneSpreadFunction lsf, bool leftHand) {
00933     std::pair<SUMOReal, SUMOReal> offsets =
00934         GeomHelper::getNormal90D_CW(from, to, lanewidth);
00935     SUMOReal xoff = offsets.first / (SUMOReal) 2.0;
00936     SUMOReal yoff = offsets.second / (SUMOReal) 2.0;
00937     if (lsf==LANESPREAD_RIGHT) {
00938         xoff += (offsets.first * (SUMOReal) lane);
00939         yoff += (offsets.second * (SUMOReal) lane);
00940     } else {
00941         xoff += (offsets.first * (SUMOReal) lane) - (offsets.first * (SUMOReal) noLanes / (SUMOReal) 2.0);
00942         yoff += (offsets.second * (SUMOReal) lane) - (offsets.second * (SUMOReal) noLanes / (SUMOReal) 2.0);
00943     }
00944     if (leftHand) {
00945         return std::pair<SUMOReal, SUMOReal>(-xoff, -yoff);
00946     } else {
00947         return std::pair<SUMOReal, SUMOReal>(xoff, yoff);
00948     }
00949 }
00950 
00951 
00952 bool
00953 NBEdge::hasRestrictions() const {
00954     for (std::vector<Lane>::const_iterator i=myLanes.begin(); i!=myLanes.end(); ++i) {
00955         if ((*i).allowed.size()!=0 || (*i).notAllowed.size()!=0) {
00956             return true;
00957         }
00958     }
00959     return false;
00960 }
00961 
00962 
00963 bool
00964 NBEdge::hasLaneSpecificAllow() const {
00965     std::vector<Lane>::const_iterator i=myLanes.begin();
00966     const SUMOVehicleClasses& allowed = i->allowed;
00967     i++;
00968     for (; i!=myLanes.end(); ++i) {
00969         if (i->allowed != allowed) {
00970             return true;
00971         }
00972     }
00973     return false;
00974 }
00975 
00976 
00977 bool
00978 NBEdge::hasLaneSpecificDisallow() const {
00979     std::vector<Lane>::const_iterator i=myLanes.begin();
00980     const SUMOVehicleClasses& notAllowed = i->notAllowed;
00981     i++;
00982     for (; i!=myLanes.end(); ++i) {
00983         if (i->notAllowed != notAllowed) {
00984             return true;
00985         }
00986     }
00987     return false;
00988 }
00989 
00990 
00991 bool
00992 NBEdge::hasLaneSpecificWidth() const {
00993     for (std::vector<Lane>::const_iterator i=myLanes.begin(); i!=myLanes.end(); ++i) {
00994         if (i->width != getWidth()) {
00995             return true;
00996         }
00997     }
00998     return false;
00999 }
01000 
01001 
01002 bool
01003 NBEdge::hasLaneSpecificSpeed() const {
01004     for (std::vector<Lane>::const_iterator i=myLanes.begin(); i!=myLanes.end(); ++i) {
01005         if (i->speed != getSpeed()) {
01006             return true;
01007         }
01008     }
01009     return false;
01010 }
01011 
01012 
01013 bool
01014 NBEdge::hasLaneSpecificOffset() const {
01015     for (std::vector<Lane>::const_iterator i=myLanes.begin(); i!=myLanes.end(); ++i) {
01016         if (i->offset != getOffset()) {
01017             return true;
01018         }
01019     }
01020     return false;
01021 }
01022 
01023 
01024 bool
01025 NBEdge::needsLaneSpecificOutput() const {
01026     return hasRestrictions() || hasLaneSpecificSpeed() || hasLaneSpecificWidth() || hasLaneSpecificOffset();
01027 }
01028 
01029 
01030 
01031 bool
01032 NBEdge::computeEdge2Edges(bool noLeftMovers) {
01033     // return if this relationship has been build in previous steps or
01034     //  during the import
01035     if (myStep>=EDGE2EDGES) {
01036         return true;
01037     }
01038     if (myConnections.size()==0) {
01039         const EdgeVector& o = myTo->getOutgoingEdges();
01040         for (EdgeVector::const_iterator i=o.begin(); i!=o.end(); ++i) {
01041             if (noLeftMovers&&myTo->isLeftMover(this, *i)) {
01042                 continue;
01043             }
01044             myConnections.push_back(Connection(-1, *i, -1));
01045         }
01046     }
01047     myStep = EDGE2EDGES;
01048     return true;
01049 }
01050 
01051 
01052 bool
01053 NBEdge::computeLanes2Edges() {
01054     // return if this relationship has been build in previous steps or
01055     //  during the import
01056     if (myStep>=LANES2EDGES) {
01057         return true;
01058     }
01059     assert(myStep==EDGE2EDGES);
01060     // get list of possible outgoing edges sorted by direction clockwise
01061     //  the edge in the backward direction (turnaround) is not in the list
01062     const EdgeVector* edges = getConnectedSorted();
01063     if (myConnections.size()!=0&&edges->size()==0) {
01064         // dead end per definition!?
01065         myConnections.clear();
01066     } else {
01067         // divide the lanes on reachable edges
01068         divideOnEdges(edges);
01069     }
01070     delete edges;
01071     myStep = LANES2EDGES;
01072     return true;
01073 }
01074 
01075 
01076 bool
01077 NBEdge::recheckLanes() {
01078     std::vector<unsigned int> connNumbersPerLane(myLanes.size(), 0);
01079     for (std::vector<Connection>::iterator i=myConnections.begin(); i!=myConnections.end();) {
01080         if ((*i).toEdge==0||(*i).fromLane<0||(*i).toLane<0) {
01081             i = myConnections.erase(i);
01082         } else {
01083             if ((*i).fromLane>=0) {
01084                 ++connNumbersPerLane[(*i).fromLane];
01085             }
01086             ++i;
01087         }
01088     }
01089     if (myStep!=LANES2LANES_DONE&&myStep!=LANES2LANES_USER) {
01090         // check #1:
01091         // If there is a lane with no connections and any neighbour lane has
01092         //  more than one connections, try to move one of them.
01093         // This check is only done for edges which connections were assigned
01094         //  using the standard algorithm.
01095         for (unsigned int i=0; i<myLanes.size(); i++) {
01096             if (connNumbersPerLane[i]==0) {
01097                 if (i>0&&connNumbersPerLane[i-1]>1) {
01098                     moveConnectionToLeft(i-1);
01099                 } else if (i<myLanes.size()-1&&connNumbersPerLane[i+1]>1) {
01100                     moveConnectionToRight(i+1);
01101                 }
01102             }
01103         }
01104     }
01105     return true;
01106 }
01107 
01108 
01109 void
01110 NBEdge::moveConnectionToLeft(unsigned int lane) {
01111     unsigned int index = 0;
01112     if (myAmLeftHand) {
01113         for (int i=(int) myConnections.size()-1; i>=0; --i) {
01114             if (myConnections[i].fromLane==static_cast<int>(lane)&&getTurnDestination()!=myConnections[i].toEdge) {
01115                 index = i;
01116             }
01117         }
01118     } else {
01119         for (unsigned int i=0; i<myConnections.size(); ++i) {
01120             if (myConnections[i].fromLane==static_cast<int>(lane)) {
01121                 index = i;
01122             }
01123         }
01124     }
01125     std::vector<Connection>::iterator i = myConnections.begin() + index;
01126     Connection c = *i;
01127     myConnections.erase(i);
01128     setConnection(lane+1, c.toEdge, c.toLane, L2L_VALIDATED, false);
01129 }
01130 
01131 
01132 void
01133 NBEdge::moveConnectionToRight(unsigned int lane) {
01134     if (myAmLeftHand) {
01135         for (int i=(int) myConnections.size()-1; i>=0; --i) {
01136             if (myConnections[i].fromLane==static_cast<int>(lane)&&getTurnDestination()!=myConnections[i].toEdge) {
01137                 Connection c = myConnections[i];
01138                 myConnections.erase(myConnections.begin() + i);
01139                 setConnection(lane-1, c.toEdge, c.toLane, L2L_VALIDATED, false);
01140                 return;
01141             }
01142         }
01143     } else {
01144         for (std::vector<Connection>::iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
01145             if ((*i).fromLane==static_cast<int>(lane)) {
01146                 Connection c = *i;
01147                 i = myConnections.erase(i);
01148                 setConnection(lane-1, c.toEdge, c.toLane, L2L_VALIDATED, false);
01149                 return;
01150             }
01151         }
01152     }
01153 }
01154 
01155 
01156 std::vector<int>
01157 NBEdge::getConnectionLanes(NBEdge* currentOutgoing) const {
01158     std::vector<int> ret;
01159     if (currentOutgoing!=myTurnDestination) {
01160         for (std::vector<Connection>::const_iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
01161             if ((*i).toEdge==currentOutgoing) {
01162                 ret.push_back((*i).fromLane);
01163             }
01164         }
01165     }
01166     return ret;
01167 }
01168 
01169 
01170 const EdgeVector*
01171 NBEdge::getConnectedSorted() {
01172     // check whether connections exist and if not, use edges from the node
01173     EdgeVector outgoing;
01174     if (myConnections.size()==0) {
01175         outgoing = myTo->getOutgoingEdges();
01176     } else {
01177         for (std::vector<Connection>::const_iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
01178             if (find(outgoing.begin(), outgoing.end(), (*i).toEdge)==outgoing.end()) {
01179                 outgoing.push_back((*i).toEdge);
01180             }
01181         }
01182     }
01183     // allocate the sorted container
01184     unsigned int size = (unsigned int) outgoing.size();
01185     EdgeVector* edges = new EdgeVector();
01186     edges->reserve(size);
01187     for (EdgeVector::const_iterator i=outgoing.begin(); i!=outgoing.end(); i++) {
01188         NBEdge* outedge = *i;
01189         if (outedge!=0&&outedge!=myTurnDestination) {
01190             edges->push_back(outedge);
01191         }
01192     }
01193     sort(edges->begin(), edges->end(), NBContHelper::relative_edge_sorter(this, myTo));
01194     return edges;
01195 }
01196 
01197 
01198 void
01199 NBEdge::divideOnEdges(const EdgeVector* outgoing) {
01200     if (outgoing->size()==0) {
01201         // we have to do this, because the turnaround may have been added before
01202         myConnections.clear();
01203         return;
01204     }
01205     // precompute priorities; needed as some kind of assumptions for
01206     //  priorities of directions (see preparePriorities)
01207     std::vector<unsigned int> *priorities = preparePriorities(outgoing);
01208 
01209     // compute the sum of priorities (needed for normalisation)
01210     unsigned int prioSum = computePrioritySum(priorities);
01211     // compute the resulting number of lanes that should be used to
01212     //  reach the following edge
01213     unsigned int size = (unsigned int) outgoing->size();
01214     std::vector<SUMOReal> resultingLanes;
01215     resultingLanes.reserve(size);
01216     SUMOReal sumResulting = 0; // the sum of resulting lanes
01217     SUMOReal minResulting = 10000; // the least number of lanes to reach an edge
01218     unsigned int i;
01219     for (i=0; i<size; i++) {
01220         // res will be the number of lanes which are meant to reach the
01221         //  current outgoing edge
01222         SUMOReal res =
01223             (SUMOReal)(*priorities)[i] *
01224             (SUMOReal) myLanes.size() / (SUMOReal) prioSum;
01225         // do not let this number be greater than the number of available lanes
01226         if (res>myLanes.size()) {
01227             res = (SUMOReal) myLanes.size();
01228         }
01229         // add it to the list
01230         resultingLanes.push_back(res);
01231         sumResulting += res;
01232         if (minResulting>res) {
01233             minResulting = res;
01234         }
01235     }
01236     // compute the number of virtual edges
01237     //  a virtual edge is used as a replacement for a real edge from now on
01238     //  it shall ollow to divide the existing lanes on this structure without
01239     //  regarding the structure of outgoing edges
01240     sumResulting += minResulting / (SUMOReal) 2.;
01241     unsigned int noVirtual = (unsigned int)(sumResulting / minResulting);
01242     // compute the transition from virtual to real edges
01243     EdgeVector transition;
01244     transition.reserve(size);
01245     for (i=0; i<size; i++) {
01246         // tmpNo will be the number of connections from this edge
01247         //  to the next edge
01248         assert(i<resultingLanes.size());
01249         SUMOReal tmpNo = (SUMOReal) resultingLanes[i] / (SUMOReal) minResulting;
01250         for (SUMOReal j=0; j<tmpNo; j++) {
01251             assert(outgoing->size()>i);
01252             transition.push_back((*outgoing)[i]);
01253         }
01254     }
01255 
01256     // assign lanes to edges
01257     //  (conversion from virtual to real edges is done)
01258     ToEdgeConnectionsAdder adder(transition);
01259     Bresenham::compute(&adder, static_cast<unsigned int>(myLanes.size()), noVirtual);
01260     const std::map<NBEdge*, std::vector<unsigned int> > &l2eConns = adder.getBuiltConnections();
01261     myConnections.clear();
01262     for (std::map<NBEdge*, std::vector<unsigned int> >::const_iterator i=l2eConns.begin(); i!=l2eConns.end(); ++i) {
01263         const std::vector<unsigned int> lanes = (*i).second;
01264         for (std::vector<unsigned int>::const_iterator j=lanes.begin(); j!=lanes.end(); ++j) {
01265             if (myAmLeftHand) {
01266                 myConnections.push_back(Connection(int(myLanes.size() - 1 - *j), (*i).first, -1));
01267             } else {
01268                 myConnections.push_back(Connection(int(*j), (*i).first, -1));
01269             }
01270         }
01271     }
01272     delete priorities;
01273 }
01274 
01275 
01276 std::vector<unsigned int> *
01277 NBEdge::preparePriorities(const EdgeVector* outgoing) {
01278     // copy the priorities first
01279     std::vector<unsigned int> *priorities = new std::vector<unsigned int>();
01280     if (outgoing->size()==0) {
01281         return priorities;
01282     }
01283     priorities->reserve(outgoing->size());
01284     EdgeVector::const_iterator i;
01285     for (i=outgoing->begin(); i!=outgoing->end(); i++) {
01286         int prio = (*i)->getJunctionPriority(myTo);
01287         assert((prio+1)*2>0);
01288         prio = (prio+1) * 2;
01289         priorities->push_back(prio);
01290     }
01291     // when the right turning direction has not a higher priority, divide
01292     //  the importance by 2 due to the possibility to leave the junction
01293     //  faster from this lane
01294     MainDirections mainDirections(*outgoing, this, myTo);
01295     EdgeVector tmp(*outgoing);
01296     sort(tmp.begin(), tmp.end(), NBContHelper::edge_similar_direction_sorter(this));
01297     i=find(outgoing->begin(), outgoing->end(), *(tmp.begin()));
01298     unsigned int dist = (unsigned int) distance(outgoing->begin(), i);
01299     if (dist!=0&&!mainDirections.includes(MainDirections::DIR_RIGHTMOST)) {
01300         assert(priorities->size()>0);
01301         (*priorities)[0] = (*priorities)[0] / 2;
01302     }
01303     // HEURISTIC:
01304     // when no higher priority exists, let the forward direction be
01305     //  the main direction
01306     if (mainDirections.empty()) {
01307         assert(dist<priorities->size());
01308         (*priorities)[dist] = (*priorities)[dist] * 2;
01309     }
01310     if (mainDirections.includes(MainDirections::DIR_FORWARD)&&myLanes.size()>2) {
01311         (*priorities)[dist] = (*priorities)[dist] * 2;
01312     }
01313     // return
01314     return priorities;
01315 }
01316 
01317 
01318 unsigned int
01319 NBEdge::computePrioritySum(std::vector<unsigned int> *priorities) {
01320     unsigned int sum = 0;
01321     for (std::vector<unsigned int>::iterator i=priorities->begin(); i!=priorities->end(); i++) {
01322         sum += int(*i);
01323     }
01324     return sum;
01325 }
01326 
01327 
01328 void
01329 NBEdge::appendTurnaround(bool noTLSControlled) throw() {
01330     // do nothing if no turnaround is known
01331     if (myTurnDestination==0) {
01332         return;
01333     }
01334     // do nothing if the destination node is controlled by a tls and no turnarounds
01335     //  shall be appended for such junctions
01336     if (noTLSControlled&&myTo->isTLControlled()) {
01337         return;
01338     }
01339     setConnection((unsigned int)(myLanes.size()-1), myTurnDestination, myTurnDestination->getNumLanes()-1, L2L_VALIDATED);
01340 }
01341 
01342 
01343 void
01344 NBEdge::sortOutgoingConnectionsByAngle() {
01345     sort(myConnections.begin(), myConnections.end(), connections_relative_edgelane_sorter(this, myTo));
01346 }
01347 
01348 
01349 void
01350 NBEdge::sortOutgoingConnectionsByIndex() {
01351     sort(myConnections.begin(), myConnections.end(), connections_sorter);
01352 }
01353 
01354 
01355 bool
01356 NBEdge::isTurningDirectionAt(const NBNode* n, const NBEdge* const edge) const throw() {
01357     // maybe it was already set as the turning direction
01358     if (edge == myTurnDestination) {
01359         return true;
01360     } else if (myTurnDestination!=0) {
01361         // otherwise - it's not if a turning direction exists
01362         return false;
01363     }
01364     // if the same nodes are connected
01365     if (myFrom==edge->myTo &&myTo==edge->myFrom) {
01366         return true;
01367     }
01368     // we have to checke whether the connection between the nodes is
01369     //  geometrically similar
01370     SUMOReal thisFromAngle2 = getAngle(*n);
01371     SUMOReal otherToAngle2 = edge->getAngle(*n);
01372     if (thisFromAngle2<otherToAngle2) {
01373         std::swap(thisFromAngle2, otherToAngle2);
01374     }
01375     if (thisFromAngle2-otherToAngle2>170&&thisFromAngle2-otherToAngle2<190) {
01376         return true;
01377     }
01378     return false;
01379 }
01380 
01381 
01382 
01383 NBNode*
01384 NBEdge::tryGetNodeAtPosition(SUMOReal pos, SUMOReal tolerance) const {
01385     // return the from-node when the position is at the begin of the edge
01386     if (pos<tolerance) {
01387         return myFrom;
01388     }
01389     // return the to-node when the position is at the end of the edge
01390     if (pos>myLength-tolerance) {
01391         return myTo;
01392     }
01393     return 0;
01394 }
01395 
01396 
01397 void
01398 NBEdge::replaceInConnections(NBEdge* which, NBEdge* by, unsigned int laneOff) {
01399     UNUSED_PARAMETER(laneOff);
01400     // replace in "_connectedEdges"
01401     for (std::vector<Connection>::iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
01402         if ((*i).toEdge==which) {
01403             (*i).toEdge = by;
01404         }
01405     }
01406     // check whether it was the turn destination
01407     if (myTurnDestination==which) {
01408         myTurnDestination = by;
01409     }
01410 }
01411 
01412 
01413 void
01414 NBEdge::moveOutgoingConnectionsFrom(NBEdge* e, unsigned int laneOff) {
01415     unsigned int lanes = e->getNumLanes();
01416     for (unsigned int i=0; i<lanes; i++) {
01417         std::vector<NBEdge::Connection> elv = e->getConnectionsFromLane(i);
01418         for (std::vector<NBEdge::Connection>::iterator j=elv.begin(); j!=elv.end(); j++) {
01419             NBEdge::Connection el = *j;
01420             assert(el.tlID=="");
01421             bool ok = addLane2LaneConnection(i+laneOff, el.toEdge, el.toLane, L2L_COMPUTED);
01422             assert(ok);
01423         }
01424     }
01425 }
01426 
01427 
01428 bool
01429 NBEdge::isConnectedTo(NBEdge* e) {
01430     if (e==myTurnDestination) {
01431         return true;
01432     }
01433     return
01434         find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(e))
01435         !=
01436         myConnections.end();
01437 
01438 }
01439 
01440 
01441 EdgeVector
01442 NBEdge::getConnectedEdges() const throw() {
01443     EdgeVector ret;
01444     for (std::vector<Connection>::const_iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
01445         if (find(ret.begin(), ret.end(), (*i).toEdge)==ret.end()) {
01446             ret.push_back((*i).toEdge);
01447         }
01448     }
01449     return ret;
01450 }
01451 
01452 
01453 void
01454 NBEdge::remapConnections(const EdgeVector& incoming) {
01455     EdgeVector connected = getConnectedEdges();
01456     for (EdgeVector::const_iterator i=incoming.begin(); i!=incoming.end(); i++) {
01457         NBEdge* inc = *i;
01458         // We have to do this
01459         inc->myStep = EDGE2EDGES;
01460         // add all connections
01461         for (EdgeVector::iterator j=connected.begin(); j!=connected.end(); j++) {
01462             inc->addEdge2EdgeConnection(*j);
01463         }
01464         inc->removeFromConnections(this);
01465     }
01466 }
01467 
01468 
01469 void
01470 NBEdge::removeFromConnections(NBEdge* toEdge, int fromLane, int toLane) {
01471     // remove from "myConnections"
01472     for (std::vector<Connection>::iterator i=myConnections.begin(); i!=myConnections.end();) {
01473         Connection& c = *i;
01474         if (c.toEdge==toEdge
01475                 && (fromLane<0 || c.fromLane==fromLane)
01476                 && (toLane<0 || c.toLane==toLane)) {
01477             i = myConnections.erase(i);
01478         } else {
01479             ++i;
01480         }
01481     }
01482     // check whether it was the turn destination
01483     if (myTurnDestination==toEdge && fromLane<0) {
01484         myTurnDestination = 0;
01485     }
01486 }
01487 
01488 
01489 void
01490 NBEdge::invalidateConnections(bool reallowSetting) {
01491     myTurnDestination = 0;
01492     myConnections.clear();
01493     if (reallowSetting) {
01494         myStep = INIT;
01495     } else {
01496         myStep = INIT_REJECT_CONNECTIONS;
01497     }
01498 }
01499 
01500 
01501 bool
01502 NBEdge::lanesWereAssigned() const {
01503     return myStep==LANES2LANES_DONE||myStep==LANES2LANES_USER;
01504 }
01505 
01506 
01507 SUMOReal
01508 NBEdge::getMaxLaneOffset() {
01509     return (SUMOReal) SUMO_const_laneWidthAndOffset * myLanes.size();
01510 }
01511 
01512 
01513 Position
01514 NBEdge::getMinLaneOffsetPositionAt(NBNode* node, SUMOReal width) const {
01515     const PositionVector& shape0 = myLanes[0].shape;
01516     const PositionVector& shapel = myLanes.back().shape;
01517     width = width < shape0.length()/(SUMOReal) 2.0
01518             ? width
01519             : shape0.length()/(SUMOReal) 2.0;
01520     if (node==myFrom) {
01521         Position pos =  shapel.positionAtLengthPosition(width);
01522         GeomHelper::transfer_to_side(pos, shapel[0], shapel[-1], SUMO_const_halfLaneAndOffset);
01523         return pos;
01524     } else {
01525         Position pos = shape0.positionAtLengthPosition(shape0.length() - width);
01526         GeomHelper::transfer_to_side(pos, shape0[-1], shape0[0], SUMO_const_halfLaneAndOffset);
01527         return pos;
01528     }
01529 }
01530 
01531 
01532 Position
01533 NBEdge::getMaxLaneOffsetPositionAt(NBNode* node, SUMOReal width) const {
01534     const PositionVector& shape0 = myLanes[0].shape;
01535     const PositionVector& shapel = myLanes.back().shape;
01536     width = width < shape0.length()/(SUMOReal) 2.0
01537             ? width
01538             : shape0.length()/(SUMOReal) 2.0;
01539     if (node==myFrom) {
01540         Position pos = shape0.positionAtLengthPosition(width);
01541         GeomHelper::transfer_to_side(pos, shape0[0], shape0[-1], -SUMO_const_halfLaneAndOffset);
01542         return pos;
01543     } else {
01544         Position pos = shapel.positionAtLengthPosition(shapel.length() - width);
01545         GeomHelper::transfer_to_side(pos, shapel[-1], shapel[0], -SUMO_const_halfLaneAndOffset);
01546         return pos;
01547     }
01548 }
01549 
01550 
01551 bool
01552 NBEdge::mayBeTLSControlled(int fromLane, NBEdge* toEdge, int toLane) const throw() {
01553     TLSDisabledConnection tpl;
01554     tpl.fromLane = fromLane;
01555     tpl.to = toEdge;
01556     tpl.toLane = toLane;
01557     std::vector<TLSDisabledConnection>::const_iterator i = find_if(myTLSDisabledConnections.begin(), myTLSDisabledConnections.end(), tls_disable_finder(tpl));
01558     return i==myTLSDisabledConnections.end();
01559 }
01560 
01561 
01562 bool
01563 NBEdge::setControllingTLInformation(const NBConnection& c, const std::string& tlID) {
01564     int fromLane = c.getFromLane();
01565     NBEdge* toEdge = c.getTo();
01566     int toLane = c.getToLane();
01567     int tlIndex = c.getTLIndex();
01568     // check whether the connection was not set as not to be controled previously
01569     TLSDisabledConnection tpl;
01570     tpl.fromLane = fromLane;
01571     tpl.to = toEdge;
01572     tpl.toLane = toLane;
01573     std::vector<TLSDisabledConnection>::iterator i = find_if(myTLSDisabledConnections.begin(), myTLSDisabledConnections.end(), tls_disable_finder(tpl));
01574     if (i!=myTLSDisabledConnections.end()) {
01575         return false;
01576     }
01577 
01578     assert(fromLane<0||fromLane<(int) myLanes.size());
01579     // try to use information about the connections if given
01580     if (fromLane>=0&&toLane>=0) {
01581         // find the specified connection
01582         std::vector<Connection>::iterator i =
01583             find_if(myConnections.begin(), myConnections.end(), connections_finder(fromLane, toEdge, toLane));
01584         // ok, we have to test this as on the removal of dummy edges some connections
01585         //  will be reassigned
01586         if (i!=myConnections.end()) {
01587             // get the connection
01588             Connection& connection = *i;
01589             // set the information about the tl
01590             connection.tlID = tlID;
01591             connection.tlLinkNo = tlIndex;
01592             return true;
01593         }
01594     }
01595     // if the original connection was not found, set the information for all
01596     //  connections
01597     unsigned int no = 0;
01598     bool hadError = false;
01599     for (std::vector<Connection>::iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
01600         if ((*i).toEdge!=toEdge) {
01601             continue;
01602         }
01603         if (fromLane>=0&&fromLane!=(*i).fromLane) {
01604             continue;
01605         }
01606         if (toLane>=0&&toLane!=(*i).toLane) {
01607             continue;
01608         }
01609         if ((*i).tlID=="") {
01610             (*i).tlID = tlID;
01611             (*i).tlLinkNo = tlIndex;
01612             no++;
01613         } else {
01614             if ((*i).tlID!=tlID&&(*i).tlLinkNo==tlIndex) {
01615                 WRITE_WARNING("The lane " + toString<int>((*i).fromLane)+ " on edge " + getID()+ " already had a traffic light signal.");
01616                 hadError = true;
01617             }
01618         }
01619     }
01620     if (hadError&&no==0) {
01621         WRITE_WARNING("Could not set any signal of the traffic light '" + tlID + "' (unknown group)");
01622     }
01623     return true;
01624 }
01625 
01626 
01627 void
01628 NBEdge::clearControllingTLInformation() {
01629     for (std::vector<Connection>::iterator it=myConnections.begin(); it!=myConnections.end(); it++) {
01630         it->tlID = "";
01631     }
01632 }
01633 
01634 
01635 void
01636 NBEdge::disableConnection4TLS(int fromLane, NBEdge* toEdge, int toLane) {
01637     TLSDisabledConnection c;
01638     c.fromLane = fromLane;
01639     c.to = toEdge;
01640     c.toLane = toLane;
01641     myTLSDisabledConnections.push_back(c);
01642 }
01643 
01644 
01645 PositionVector
01646 NBEdge::getCWBoundaryLine(const NBNode& n, SUMOReal offset) const {
01647     PositionVector ret;
01648     if (myFrom==(&n)) {
01649         // outgoing
01650         ret = !myAmLeftHand ? myLanes[0].shape : myLanes.back().shape;
01651     } else {
01652         // incoming
01653         ret = !myAmLeftHand ? myLanes.back().shape.reverse() : myLanes[0].shape.reverse();
01654     }
01655     ret.move2side(offset);
01656     return ret;
01657 }
01658 
01659 
01660 PositionVector
01661 NBEdge::getCCWBoundaryLine(const NBNode& n, SUMOReal offset) const {
01662     PositionVector ret;
01663     if (myFrom==(&n)) {
01664         // outgoing
01665         ret = !myAmLeftHand ? myLanes.back().shape : myLanes[0].shape;
01666     } else {
01667         // incoming
01668         ret = !myAmLeftHand ? myLanes[0].shape.reverse() : myLanes.back().shape.reverse();
01669     }
01670     ret.move2side(-offset);
01671     return ret;
01672 }
01673 
01674 
01675 SUMOReal
01676 NBEdge::width() const {
01677     return (SUMOReal) myLanes.size() * SUMO_const_laneWidth + (SUMOReal)(myLanes.size()-1) * SUMO_const_laneOffset;
01678 }
01679 
01680 
01681 bool
01682 NBEdge::expandableBy(NBEdge* possContinuation) const {
01683     // ok, the number of lanes must match
01684     if (myLanes.size()!=possContinuation->myLanes.size()) {
01685         return false;
01686     }
01687     // the priority, too (?)
01688     if (getPriority()!=possContinuation->getPriority()) {
01689         return false;
01690     }
01691     // the speed allowed
01692     if (mySpeed!=possContinuation->mySpeed) {
01693         return false;
01694     }
01695     // the vehicle class constraints, too
01703     // also, check whether the connections - if any exit do allow to join
01704     //  both edges
01705     // This edge must have a one-to-one connection to the following lanes
01706     switch (myStep) {
01707     case INIT_REJECT_CONNECTIONS:
01708         break;
01709     case INIT:
01710         break;
01711     case EDGE2EDGES: {
01712         // the following edge must be connected
01713         const EdgeVector& conn = getConnectedEdges();
01714         if (find(conn.begin(), conn.end(), possContinuation)
01715                 ==conn.end()) {
01716 
01717             return false;
01718         }
01719     }
01720     break;
01721     case LANES2EDGES:
01722     case LANES2LANES_RECHECK:
01723     case LANES2LANES_DONE:
01724     case LANES2LANES_USER: {
01725         // the possible continuation must be connected
01726         if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(possContinuation))==myConnections.end()) {
01727             return false;
01728         }
01729         // all lanes must go to the possible continuation
01730         std::vector<int> conns = getConnectionLanes(possContinuation);
01731         if (conns.size()!=myLanes.size()) {
01732             return false;
01733         }
01734     }
01735     break;
01736     default:
01737         break;
01738     }
01739     return true;
01740 }
01741 
01742 
01743 void
01744 NBEdge::append(NBEdge* e) {
01745     // append geometry
01746     myGeom.appendWithCrossingPoint(e->myGeom);
01747     for (unsigned int i=0; i<myLanes.size(); i++) {
01748         myLanes[i].shape.appendWithCrossingPoint(e->myLanes[i].shape);
01749     }
01750     // recompute length
01751     myLength += e->myLength;
01752     // copy the connections and the building step if given
01753     myStep = e->myStep;
01754     myConnections = e->myConnections;
01755     myTurnDestination = e->myTurnDestination;
01756     // set the node
01757     myTo = e->myTo;
01758 }
01759 
01760 
01761 
01762 
01763 
01764 bool
01765 NBEdge::hasSignalisedConnectionTo(const NBEdge* const e) const throw() {
01766     for (std::vector<Connection>::const_iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
01767         if ((*i).toEdge==e && (*i).tlID!="") {
01768             return true;
01769         }
01770     }
01771     return false;
01772 }
01773 
01774 
01775 NBEdge*
01776 NBEdge::getTurnDestination() const {
01777     return myTurnDestination;
01778 }
01779 
01780 
01781 std::string
01782 NBEdge::getLaneID(unsigned int lane) const {
01783     assert(lane<myLanes.size());
01784     return myID + "_" + toString(lane);
01785 }
01786 
01787 
01788 bool
01789 NBEdge::isNearEnough2BeJoined2(NBEdge* e, SUMOReal threshold) const {
01790     DoubleVector distances = myGeom.distances(e->getGeometry());
01791     assert(distances.size() > 0);
01792     return VectorHelper<SUMOReal>::maxValue(distances) < threshold;
01793 }
01794 
01795 
01796 SUMOReal
01797 NBEdge::getNormedAngle(const NBNode& atNode) const {
01798     SUMOReal angle = getAngle(atNode);
01799     if (angle<0) {
01800         angle = 360 + angle;
01801     }
01802     assert(angle>=0&&angle<=360);
01803     return angle;
01804 }
01805 
01806 
01807 SUMOReal
01808 NBEdge::getNormedAngle() const {
01809     SUMOReal angle = myAngle;
01810     if (angle<0) {
01811         angle = 360 + angle;
01812     }
01813     assert(angle>=0&&angle<360);
01814     return angle;
01815 }
01816 
01817 
01818 void
01819 NBEdge::incLaneNo(unsigned int by) {
01820     unsigned int newLaneNo = (unsigned int) myLanes.size() + by;
01821     while (myLanes.size()<newLaneNo) {
01822         Lane l;
01823         l.speed = mySpeed;
01824         l.offset = myOffset;
01825         l.width = myWidth;
01826         myLanes.push_back(l);
01827     }
01828     computeLaneShapes();
01829     const EdgeVector& incs = myFrom->getIncomingEdges();
01830     for (EdgeVector::const_iterator i=incs.begin(); i!=incs.end(); ++i) {
01831         (*i)->invalidateConnections(true);
01832     }
01833     invalidateConnections(true);
01834 }
01835 
01836 
01837 void
01838 NBEdge::decLaneNo(unsigned int by, int dir) {
01839     unsigned int newLaneNo = (unsigned int) myLanes.size() - by;
01840     while (myLanes.size()>newLaneNo) {
01841         myLanes.pop_back();
01842     }
01843     computeLaneShapes();
01844     const EdgeVector& incs = myFrom->getIncomingEdges();
01845     for (EdgeVector::const_iterator i=incs.begin(); i!=incs.end(); ++i) {
01846         (*i)->invalidateConnections(true);
01847     }
01848     if (dir==0) {
01849         invalidateConnections(true);
01850     } else {
01851         const EdgeVector& outs = myTo->getOutgoingEdges();
01852         assert(outs.size()==1);
01853         NBEdge* out = outs[0];
01854         if (dir<0) {
01855             removeFromConnections(out, 0);
01856         } else {
01857             removeFromConnections(out, (int) myLanes.size());
01858         }
01859     }
01860 }
01861 
01862 
01863 void
01864 NBEdge::copyConnectionsFrom(NBEdge* src) {
01865     myStep = src->myStep;
01866     myConnections = src->myConnections;
01867 }
01868 
01869 
01870 void
01871 NBEdge::markAsInLane2LaneState() {
01872     assert(myTo->getOutgoingEdges().size()==0);
01873     myStep = LANES2LANES_DONE;
01874 }
01875 
01876 
01877 void
01878 NBEdge::allowVehicleClass(int lane, SUMOVehicleClass vclass) {
01879     if (lane<0) {
01880         // if all lanes are meant...
01881         for (unsigned int i=0; i<myLanes.size(); i++) {
01882             // ... do it for each lane
01883             allowVehicleClass((int) i, vclass);
01884         }
01885         return;
01886     }
01887     assert(lane<(int) myLanes.size());
01888     myLanes[lane].allowed.insert(vclass);
01889     if (myLanes[lane].notAllowed.count(vclass) > 0) {
01890         // overrride earlier disallow
01891         myLanes[lane].notAllowed.erase(vclass);
01892         WRITE_WARNING("Overriding previous '" + toString(SUMO_ATTR_DISALLOW) + "=" +
01893                       toString(vclass) + "' for lane '" + getLaneID(lane) + "'.")
01894     }
01895 }
01896 
01897 
01898 void
01899 NBEdge::disallowVehicleClass(int lane, SUMOVehicleClass vclass) {
01900     if (lane<0) {
01901         // if all lanes are meant...
01902         for (unsigned int i=0; i<myLanes.size(); i++) {
01903             // ... do it for each lane
01904             disallowVehicleClass((int) i, vclass);
01905         }
01906         return;
01907     }
01908     assert(lane<(int) myLanes.size());
01909     myLanes[lane].notAllowed.insert(vclass);
01910     if (myLanes[lane].allowed.count(vclass) > 0) {
01911         // overrride earlier allow
01912         myLanes[lane].allowed.erase(vclass);
01913         WRITE_WARNING("Overriding previous '" + toString(SUMO_ATTR_ALLOW) + "=" +
01914                       toString(vclass) + "' for lane '" + getLaneID(lane) + "'.")
01915     }
01916 }
01917 
01918 
01919 void
01920 NBEdge::preferVehicleClass(int lane, SUMOVehicleClass vclass) {
01921     if (lane<0) {
01922         // if all lanes are meant...
01923         for (unsigned int i=0; i<myLanes.size(); i++) {
01924             // ... do it for each lane
01925             preferVehicleClass((int) i, vclass);
01926         }
01927         return;
01928     }
01929     assert(lane<(int) myLanes.size());
01930     myLanes[lane].preferred.insert(vclass);
01931 }
01932 
01933 
01934 void
01935 NBEdge::setWidth(int lane, SUMOReal width) {
01936     if (lane<0) {
01937         // all lanes are meant...
01938         myWidth = width;
01939         for (unsigned int i=0; i<myLanes.size(); i++) {
01940             // ... do it for each lane
01941             setWidth((int) i, width);
01942         }
01943         return;
01944     }
01945     assert(lane<(int) myLanes.size());
01946     myLanes[lane].width = width;
01947 }
01948 
01949 
01950 void
01951 NBEdge::setOffset(int lane, SUMOReal offset) {
01952     if (lane<0) {
01953         // all lanes are meant...
01954         myOffset = offset;
01955         for (unsigned int i=0; i<myLanes.size(); i++) {
01956             // ... do it for each lane
01957             setOffset((int) i, offset);
01958         }
01959         return;
01960     }
01961     assert(lane<(int) myLanes.size());
01962     myLanes[lane].offset = offset;
01963 }
01964 
01965 
01966 void
01967 NBEdge::setSpeed(int lane, SUMOReal speed) {
01968     if (lane<0) {
01969         // all lanes are meant...
01970         mySpeed = speed;
01971         for (unsigned int i=0; i<myLanes.size(); i++) {
01972             // ... do it for each lane
01973             setOffset((int) i, speed);
01974         }
01975         return;
01976     }
01977     assert(lane<(int) myLanes.size());
01978     myLanes[lane].speed = speed;
01979 }
01980 
01981 
01982 void
01983 NBEdge::setVehicleClasses(const SUMOVehicleClasses& allowed, const SUMOVehicleClasses& disallowed, int lane) {
01984     for (SUMOVehicleClasses::const_iterator i=allowed.begin(); i!=allowed.end(); ++i) {
01985         allowVehicleClass(lane, *i);
01986     }
01987     for (SUMOVehicleClasses::const_iterator i=disallowed.begin(); i!=disallowed.end(); ++i) {
01988         disallowVehicleClass(lane, *i);
01989     }
01990 }
01991 
01992 
01993 SUMOVehicleClasses
01994 NBEdge::getAllowedVehicleClasses() const {
01995     SUMOVehicleClasses ret;
01996     for (std::vector<Lane>::const_iterator i=myLanes.begin(); i!=myLanes.end(); ++i) {
01997         const SUMOVehicleClasses& allowed = (*i).allowed;
01998         ret.insert(allowed.begin(), allowed.end());
01999     }
02000     return ret;
02001 }
02002 
02003 
02004 SUMOVehicleClasses
02005 NBEdge::getDisallowedVehicleClasses() const {
02006     SUMOVehicleClasses ret;
02007     for (std::vector<Lane>::const_iterator i=myLanes.begin(); i!=myLanes.end(); ++i) {
02008         const SUMOVehicleClasses& notAllowed = (*i).notAllowed;
02009         ret.insert(notAllowed.begin(), notAllowed.end());
02010     }
02011     return ret;
02012 }
02013 
02014 
02015 SUMOVehicleClasses
02016 NBEdge::getAllowedVehicleClasses(unsigned int lane) const {
02017     assert(lane < myLanes.size());
02018     return myLanes[lane].allowed;
02019 }
02020 
02021 
02022 SUMOVehicleClasses
02023 NBEdge::getDisallowedVehicleClasses(unsigned int lane) const {
02024     assert(lane < myLanes.size());
02025     return myLanes[lane].notAllowed;
02026 }
02027 
02028 
02029 int
02030 NBEdge::getMinConnectedLane(NBEdge* of) const {
02031     int ret = -1;
02032     for (std::vector<Connection>::const_iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
02033         if ((*i).toEdge==of && (ret==-1 || (*i).toLane<ret)) {
02034             ret = (*i).toLane;
02035         }
02036     }
02037     return ret;
02038 }
02039 
02040 
02041 int
02042 NBEdge::getMaxConnectedLane(NBEdge* of) const {
02043     int ret = -1;
02044     for (std::vector<Connection>::const_iterator i=myConnections.begin(); i!=myConnections.end(); ++i) {
02045         if ((*i).toEdge==of && (*i).toLane>ret) {
02046             ret = (*i).toLane;
02047         }
02048     }
02049     return ret;
02050 }
02051 
02052 
02053 void
02054 NBEdge::setLoadedLength(SUMOReal val) {
02055     myLoadedLength = val;
02056 }
02057 
02058 
02059 void
02060 NBEdge::dismissVehicleClassInformation() {
02061     for (std::vector<Lane>::iterator i=myLanes.begin(); i!=myLanes.end(); ++i) {
02062         (*i).allowed.clear();
02063         (*i).notAllowed.clear();
02064         (*i).preferred.clear();
02065     }
02066 }
02067 
02068 
02069 /****************************************************************************/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines