LCOV - code coverage report
Current view: top level - src/netbuild - NBAlgorithms_Ramps.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 88.8 % 259 230
Test Date: 2024-11-21 15:56:26 Functions: 85.7 % 14 12

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2012-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    NBAlgorithms_Ramps.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    29. March 2012
      19              : ///
      20              : // Algorithms for highway on-/off-ramps computation
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <cassert>
      25              : #include <utils/options/OptionsCont.h>
      26              : #include <utils/common/MsgHandler.h>
      27              : #include <utils/common/ToString.h>
      28              : #include "NBNetBuilder.h"
      29              : #include "NBNodeCont.h"
      30              : #include "NBNode.h"
      31              : #include "NBEdge.h"
      32              : #include "NBAlgorithms_Ramps.h"
      33              : 
      34              : #define OFFRAMP_LOOKBACK 500
      35              : #define MIN_SPLIT_LENGTH POSITION_EPS
      36              : 
      37              : //#define DEBUG_RAMPS
      38              : #define DEBUGNODEID  ""
      39              : #define DEBUGCOND(obj) ((obj != 0 && (obj)->getID() == DEBUGNODEID))
      40              : //#define DEBUGCOND(obj) true
      41              : 
      42              : // ===========================================================================
      43              : // static members
      44              : // ===========================================================================
      45              : const std::string NBRampsComputer::ADDED_ON_RAMP_EDGE("-AddedOnRampEdge");
      46              : 
      47              : // ===========================================================================
      48              : // method definitions
      49              : // ===========================================================================
      50              : // ---------------------------------------------------------------------------
      51              : // NBRampsComputer
      52              : // ---------------------------------------------------------------------------
      53              : 
      54         1608 : NBRampsComputer::NBRampsComputer() { }
      55              : 
      56              : void
      57         1608 : NBRampsComputer::computeRamps(NBNetBuilder& nb, OptionsCont& oc, bool mayAddOrRemove) {
      58         1608 :     const bool guessAndAdd = oc.getBool("ramps.guess") && mayAddOrRemove;
      59         1608 :     const double minHighwaySpeed = oc.getFloat("ramps.min-highway-speed");
      60         1608 :     const double maxRampSpeed = oc.getFloat("ramps.max-ramp-speed");
      61         1608 :     const double rampLength = oc.getFloat("ramps.ramp-length");
      62         1608 :     const double minWeaveLength = oc.getFloat("ramps.min-weave-length");
      63         3216 :     const bool dontSplit = oc.getBool("ramps.no-split");
      64              :     NBNodeCont& nc = nb.getNodeCont();
      65              :     NBEdgeCont& ec = nb.getEdgeCont();
      66              :     NBDistrictCont& dc = nb.getDistrictCont();
      67              :     std::set<NBEdge*> incremented;
      68              :     // collect join exclusions
      69              :     std::set<std::string> noramps;
      70         3216 :     if (oc.isSet("ramps.unset")) {
      71            2 :         std::vector<std::string> edges = oc.getStringVector("ramps.unset");
      72              :         noramps.insert(edges.begin(), edges.end());
      73            1 :     }
      74              :     // exclude roundabouts
      75         1669 :     for (const EdgeSet& round : ec.getRoundabouts()) {
      76          391 :         for (NBEdge* const edge : round) {
      77          330 :             noramps.insert(edge->getID());
      78              :         }
      79              :     }
      80              :     // exclude public transport edges
      81         1608 :     nb.getPTStopCont().addEdges2Keep(oc, noramps);
      82         1608 :     nb.getParkingCont().addEdges2Keep(oc, noramps);
      83              : 
      84              :     // check whether on-off ramps shall be guessed
      85         3165 :     if (guessAndAdd || oc.getBool("ramps.guess-acceleration-lanes")) {
      86        77089 :         for (const auto& it : ec) {
      87        75481 :             it.second->markOffRamp(false);
      88              :         }
      89              : 
      90              :         // if an edge is part of two ramps, ordering is important
      91              :         std::set<NBNode*, ComparatorIdLess> potOnRamps;
      92              :         std::set<NBNode*, ComparatorIdLess> potOffRamps;
      93        46865 :         for (const auto& i : nc) {
      94        45257 :             NBNode* cur = i.second;
      95              : #ifdef DEBUG_RAMPS
      96              :             if (DEBUGCOND(cur)) {
      97              :                 std::cout << "check ramps cur=" << cur->getID() << "\n";
      98              :             }
      99              : #endif
     100        45257 :             if (mayNeedOnRamp(cur, minHighwaySpeed, maxRampSpeed, noramps, minWeaveLength)) {
     101              :                 potOnRamps.insert(cur);
     102              :             }
     103        45257 :             if (mayNeedOffRamp(cur, minHighwaySpeed, maxRampSpeed, noramps)) {
     104              :                 potOffRamps.insert(cur);
     105              :             }
     106              :         }
     107         1690 :         for (std::set<NBNode*, ComparatorIdLess>::const_iterator i = potOnRamps.begin(); i != potOnRamps.end(); ++i) {
     108           82 :             buildOnRamp(*i, nc, ec, dc, rampLength, dontSplit || !guessAndAdd, guessAndAdd);
     109              :         }
     110         1716 :         for (std::set<NBNode*, ComparatorIdLess>::const_iterator i = potOffRamps.begin(); i != potOffRamps.end(); ++i) {
     111          108 :             buildOffRamp(*i, nc, ec, dc, rampLength, dontSplit || !guessAndAdd, guessAndAdd, potOnRamps);
     112              :         }
     113              :     }
     114              :     // check whether on-off ramps are specified
     115         3216 :     if (oc.isSet("ramps.set") && mayAddOrRemove) {
     116           16 :         std::vector<std::string> edges = oc.getStringVector("ramps.set");
     117              :         std::set<NBNode*, ComparatorIdLess> potOnRamps;
     118           18 :         for (const std::string& i : edges) {
     119           10 :             NBEdge* e = ec.retrieve(i);
     120            0 :             if (noramps.count(i) != 0) {
     121            0 :                 WRITE_WARNINGF(TL("Can not build ramp on edge '%' - the edge is unsuitable."), i);
     122            0 :                 continue;
     123              :             }
     124           10 :             if (e == nullptr) {
     125            0 :                 WRITE_WARNINGF(TL("Can not build on ramp on edge '%' - the edge is not known."), i);
     126            0 :                 continue;
     127              :             }
     128           10 :             NBNode* from = e->getFromNode();
     129           10 :             if (from->getIncomingEdges().size() == 2 && from->getOutgoingEdges().size() == 1) {
     130            6 :                 buildOnRamp(from, nc, ec, dc, rampLength, dontSplit, true);
     131              :                 potOnRamps.insert(from);
     132              :             }
     133              :             // load edge again to check offramps
     134           10 :             e = ec.retrieve(i);
     135           10 :             if (e == nullptr) {
     136            0 :                 WRITE_WARNINGF(TL("Can not build off ramp on edge '%' - the edge is not known."), i);
     137            0 :                 continue;
     138              :             }
     139              :             NBNode* to = e->getToNode();
     140           10 :             if (to->getIncomingEdges().size() == 1 && to->getOutgoingEdges().size() == 2) {
     141            3 :                 buildOffRamp(to, nc, ec, dc, rampLength, dontSplit, true, potOnRamps);
     142              :             }
     143              :         }
     144            8 :     }
     145         1608 : }
     146              : 
     147              : 
     148              : bool
     149        45257 : NBRampsComputer::mayNeedOnRamp(NBNode* cur, double minHighwaySpeed, double maxRampSpeed, const std::set<std::string>& noramps, double minWeaveLength) {
     150        45257 :     if (cur->getOutgoingEdges().size() != 1 || cur->getIncomingEdges().size() != 2) {
     151              :         return false;
     152              :     }
     153              :     NBEdge* potHighway, *potRamp, *cont;
     154         2919 :     getOnRampEdges(cur, &potHighway, &potRamp, &cont);
     155              :     // may be an on-ramp
     156              : #ifdef DEBUG_RAMPS
     157              :     if (DEBUGCOND(cur)) {
     158              :         std::cout << "check on ramp hw=" << potHighway->getID() << " ramp=" << potRamp->getID() << " cont=" << cont->getID() << std::endl;
     159              :     }
     160              : #endif
     161         2919 :     if (fulfillsRampConstraints(potHighway, potRamp, cont, minHighwaySpeed, maxRampSpeed, noramps)) {
     162              :         // prevent short weaving section
     163           91 :         double seen = cont->getLength();
     164          107 :         while (seen < minWeaveLength) {
     165           31 :             if (cont->getToNode()->getOutgoingEdges().size() > 1) {
     166              :                 return false;
     167           22 :             } else if (cont->getToNode()->getOutgoingEdges().size() == 0) {
     168              :                 return true;
     169              :             }
     170           16 :             cont = cont->getToNode()->getOutgoingEdges().front();
     171           16 :             seen += cont->getLength();
     172              :         }
     173              :         return true;
     174              :     } else {
     175              :         return false;
     176              :     }
     177              : }
     178              : 
     179              : 
     180              : bool
     181        45257 : NBRampsComputer::mayNeedOffRamp(NBNode* cur, double minHighwaySpeed, double maxRampSpeed, const std::set<std::string>& noramps) {
     182        45257 :     if (cur->getIncomingEdges().size() != 1 || cur->getOutgoingEdges().size() != 2) {
     183              :         return false;
     184              :     }
     185              :     // may be an off-ramp
     186              :     NBEdge* potHighway, *potRamp, *prev;
     187         3728 :     getOffRampEdges(cur, &potHighway, &potRamp, &prev);
     188              : #ifdef DEBUG_RAMPS
     189              :     if (DEBUGCOND(cur)) {
     190              :         std::cout << "check off ramp hw=" << potHighway->getID() << " ramp=" << potRamp->getID() << " prev=" << prev->getID() << std::endl;
     191              :     }
     192              : #endif
     193         3728 :     return fulfillsRampConstraints(potHighway, potRamp, prev, minHighwaySpeed, maxRampSpeed, noramps);
     194              : }
     195              : 
     196              : 
     197              : void
     198           88 : NBRampsComputer::buildOnRamp(NBNode* cur, NBNodeCont& nc, NBEdgeCont& ec, NBDistrictCont& dc, double rampLength, bool dontSplit, bool addLanes) {
     199              :     NBEdge* potHighway, *potRamp, *cont;
     200           88 :     getOnRampEdges(cur, &potHighway, &potRamp, &cont);
     201              : #ifdef DEBUG_RAMPS
     202              :     if (DEBUGCOND(cur)) {
     203              :         std::cout << "buildOnRamp cur=" << cur->getID() << " hw=" << potHighway->getID() << " ramp=" << potRamp->getID() << " cont=" << cont->getID() << "\n";
     204              :     }
     205              : #endif
     206              :     // compute the number of lanes to append
     207           88 :     const int firstLaneNumber = cont->getNumLanes();
     208           88 :     const int toAdd = (potRamp->getNumLanes() + potHighway->getNumLanes()) - firstLaneNumber;
     209              :     NBEdge* first = cont;
     210              :     NBEdge* last = cont;
     211           88 :     NBEdge* curr = cont;
     212              :     std::set<NBEdge*> incremented;
     213           88 :     if (addLanes && toAdd > 0 && std::find(incremented.begin(), incremented.end(), cont) == incremented.end()) {
     214              :         double currLength = 0;
     215           53 :         while (curr != nullptr && currLength + curr->getGeometry().length() - POSITION_EPS < rampLength) {
     216           20 :             if (find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
     217           20 :                 curr->incLaneNo(toAdd);
     218              :                 // we need to distinguish between loading a .net.xml (connections are defined and applicable)
     219              :                 // and manual connection patches (should be post-prcess because the lane wasn't added yet)
     220           22 :                 if (curr->getStep() < NBEdge::EdgeBuildingStep::LANES2LANES_USER || !ec.hasPostProcessConnection(curr->getID())) {
     221           20 :                     curr->invalidateConnections(true);
     222              :                 }
     223              :                 incremented.insert(curr);
     224           20 :                 moveRampRight(curr, toAdd);
     225           20 :                 currLength += curr->getGeometry().length(); // !!! loaded length?
     226           20 :                 last = curr;
     227              :                 // mark acceleration lanes
     228           46 :                 for (int i = 0; i < curr->getNumLanes() - potHighway->getNumLanes(); ++i) {
     229           26 :                     curr->setAcceleration(i, true);
     230              :                 }
     231              :             }
     232           20 :             NBNode* nextN = curr->getToNode();
     233           20 :             if (nextN->getOutgoingEdges().size() == 1 && nextN->getIncomingEdges().size() == 1) {
     234           11 :                 curr = nextN->getOutgoingEdges()[0];
     235           11 :                 if (curr->getNumLanes() != firstLaneNumber) {
     236              :                     // the number of lanes changes along the computation; we'll stop...
     237            4 :                     curr = nullptr;
     238            7 :                 } else if (curr->isTurningDirectionAt(last)) {
     239              :                     // turnarounds certainly should not be included in a ramp
     240            0 :                     curr = nullptr;
     241            7 :                 } else if (curr == potHighway || curr == potRamp) {
     242              :                     // circular connectivity. do not split!
     243            0 :                     curr = nullptr;
     244              :                 }
     245              :             } else {
     246              :                 // ambiguous; and, in fact, what should it be? ...stop
     247            9 :                 curr = nullptr;
     248              :             }
     249              :         }
     250              :         // check whether a further split is necessary
     251           53 :         if (curr != nullptr && !dontSplit && currLength + MIN_SPLIT_LENGTH < rampLength && curr->getNumLanes() == firstLaneNumber && std::find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
     252              :             // there is enough place to build a ramp; do it
     253              :             bool wasFirst = first == curr;
     254           20 :             std::string newNodeID = getUnusedID(curr->getID() + "-AddedOnRampNode", nc);
     255           40 :             std::string newEdgeID = getUnusedID(curr->getID() + ADDED_ON_RAMP_EDGE, ec);
     256           20 :             NBNode* rn = new NBNode(newNodeID, curr->getGeometry().positionAtOffset(rampLength - currLength));
     257           20 :             nc.insert(rn);
     258           20 :             std::string name = curr->getID();
     259           20 :             const double currShift = myShiftedEdges[curr];
     260           20 :             if (!ec.splitAt(dc, curr, rn, newEdgeID, curr->getID(), curr->getNumLanes() + toAdd, curr->getNumLanes())) {
     261            0 :                 WRITE_WARNING("Could not build on-ramp for edge '"  + curr->getID() + "' for unknown reason");
     262              :                 return;
     263              :             }
     264              :             //ec.retrieve(name)->invalidateConnections();
     265           20 :             curr = ec.retrieve(newEdgeID);
     266              :             // copy shift over
     267           20 :             myShiftedEdges[curr] = currShift;
     268              :             incremented.insert(curr);
     269              :             last = curr;
     270           20 :             moveRampRight(curr, toAdd);
     271           20 :             if (wasFirst) {
     272           19 :                 first = curr;
     273              :             }
     274              :             // mark acceleration lanes
     275           47 :             for (int i = 0; i < curr->getNumLanes() - potHighway->getNumLanes(); ++i) {
     276           27 :                 curr->setAcceleration(i, true);
     277              :             }
     278              :         }
     279           33 :         if (curr == cont && dontSplit && addLanes) {
     280            0 :             WRITE_WARNING("Could not build on-ramp for edge '"  + curr->getID() + "' due to option '--ramps.no-split'");
     281            0 :             return;
     282              :         }
     283              :     } else {
     284              :         // mark acceleration lanes
     285           77 :         for (int i = 0; i < firstLaneNumber - potHighway->getNumLanes(); ++i) {
     286           22 :             cont->setAcceleration(i, true);
     287              :         }
     288              :     }
     289              :     // set connections from ramp/highway to added ramp
     290           88 :     if (addLanes) {
     291           37 :         if (potHighway->getStep() < NBEdge::EdgeBuildingStep::LANES2LANES_USER) {
     292           36 :             if (!potHighway->addLane2LaneConnections(0, first, potRamp->getNumLanes(), MIN2(first->getNumLanes() - potRamp->getNumLanes(), potHighway->getNumLanes()), NBEdge::Lane2LaneInfoType::VALIDATED, true)) {
     293            0 :                 throw ProcessError(TL("Could not set connection!"));
     294              :             }
     295              :         }
     296           37 :         if (potRamp->getStep() < NBEdge::EdgeBuildingStep::LANES2LANES_USER) {
     297           36 :             if (!potRamp->addLane2LaneConnections(0, first, 0, potRamp->getNumLanes(), NBEdge::Lane2LaneInfoType::VALIDATED, true)) {
     298            0 :                 throw ProcessError(TL("Could not set connection!"));
     299              :             }
     300              :         }
     301           37 :         patchRampGeometry(potRamp, first, potHighway, false);
     302              :     }
     303              : }
     304              : 
     305              : 
     306              : void
     307          111 : NBRampsComputer::buildOffRamp(NBNode* cur, NBNodeCont& nc, NBEdgeCont& ec, NBDistrictCont& dc, double rampLength, bool dontSplit, bool addLanes,
     308              :                               const std::set<NBNode*, ComparatorIdLess>& potOnRamps) {
     309              :     NBEdge* potHighway, *potRamp, *prev;
     310          111 :     getOffRampEdges(cur, &potHighway, &potRamp, &prev);
     311              : #ifdef DEBUG_RAMPS
     312              :     if (DEBUGCOND(cur)) {
     313              :         std::cout << "buildOffRamp cur=" << cur->getID() << " hw=" << potHighway->getID() << " ramp=" << potRamp->getID() << " prev=" << prev->getID() << "\n";
     314              :     }
     315              : #endif
     316              :     // compute the number of lanes to append
     317          111 :     const int firstLaneNumber = prev->getNumLanes();
     318          111 :     const int toAdd = (potRamp->getNumLanes() + potHighway->getNumLanes()) - firstLaneNumber;
     319              :     NBEdge* first = prev;
     320              :     NBEdge* last = prev;
     321          111 :     NBEdge* curr = prev;
     322              :     std::set<NBEdge*> incremented;
     323          111 :     if (addLanes && toAdd > 0 && std::find(incremented.begin(), incremented.end(), prev) == incremented.end()) {
     324              :         double currLength = 0;
     325           57 :         while (curr != nullptr && currLength + curr->getGeometry().length() - POSITION_EPS < rampLength) {
     326           21 :             if (find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
     327           21 :                 curr->incLaneNo(toAdd);
     328              :                 // we need to distinguish between loading a .net.xml (connections are defined and applicable)
     329              :                 // and manual connection patches (should be post-prcess because the lane wasn't added yet)
     330           24 :                 if (curr->getStep() < NBEdge::EdgeBuildingStep::LANES2LANES_USER || !ec.hasPostProcessConnection(curr->getID())) {
     331           20 :                     curr->invalidateConnections(true);
     332              :                 }
     333              :                 incremented.insert(curr);
     334           21 :                 moveRampRight(curr, toAdd);
     335           21 :                 currLength += curr->getGeometry().length(); // !!! loaded length?
     336           21 :                 last = curr;
     337              :             }
     338           21 :             NBNode* prevN = curr->getFromNode();
     339           21 :             if (prevN->getIncomingEdges().size() == 1 && prevN->getOutgoingEdges().size() == 1) {
     340           15 :                 curr = prevN->getIncomingEdges()[0];
     341           15 :                 if (curr->getStep() < NBEdge::EdgeBuildingStep::LANES2LANES_USER || !ec.hasPostProcessConnection(curr->getID())) {
     342              :                     // curr might be an onRamp. In this case connections need to be rebuilt
     343           15 :                     curr->invalidateConnections();
     344              :                 }
     345           15 :                 if (curr->getNumLanes() != firstLaneNumber) {
     346              :                     // the number of lanes changes along the computation; we'll stop...
     347            3 :                     curr = nullptr;
     348           12 :                 } else if (last->isTurningDirectionAt(curr)) {
     349              :                     // turnarounds certainly should not be included in a ramp
     350            0 :                     curr = nullptr;
     351           12 :                 } else if (curr == potHighway || curr == potRamp) {
     352              :                     // circular connectivity. do not split!
     353            0 :                     curr = nullptr;
     354              :                 }
     355              :             } else {
     356              :                 // ambiguous; and, in fact, what should it be? ...stop
     357            6 :                 curr = nullptr;
     358              :             }
     359              :         }
     360              :         // check whether a further split is necessary
     361           61 :         if (curr != nullptr && !dontSplit && currLength + MIN_SPLIT_LENGTH < rampLength && curr->getNumLanes() == firstLaneNumber && std::find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
     362              :             // there is enough place to build a ramp; do it
     363              :             bool wasFirst = first == curr;
     364           25 :             Position pos = curr->getGeometry().positionAtOffset(curr->getGeometry().length() - (rampLength  - currLength));
     365           25 :             std::string newNodeID = getUnusedID(curr->getID() + "-AddedOffRampNode", nc);
     366           25 :             std::string newEdgeID = getUnusedID(curr->getID() + "-AddedOffRampEdge", ec);
     367           25 :             NBNode* rn = new NBNode(newNodeID, pos);
     368           25 :             nc.insert(rn);
     369           25 :             std::string name = curr->getID();
     370           25 :             const double currShift = myShiftedEdges[curr];
     371           25 :             if (!ec.splitAt(dc, curr, rn, curr->getID(), newEdgeID, curr->getNumLanes(), curr->getNumLanes() + toAdd)) {
     372            0 :                 WRITE_WARNING("Could not build off-ramp for edge '"  + curr->getID() + "' for unknown reason");
     373              :                 return;
     374              :             }
     375           25 :             curr = ec.retrieve(newEdgeID);
     376              :             // copy shift over
     377           25 :             myShiftedEdges[curr] = currShift;
     378              :             incremented.insert(curr);
     379              :             last = curr;
     380           25 :             moveRampRight(curr, toAdd);
     381           25 :             if (wasFirst) {
     382           18 :                 first = curr;
     383              :             }
     384              :         }
     385           36 :         if (curr == prev && dontSplit && addLanes) {
     386            2 :             WRITE_WARNING("Could not build off-ramp for edge '"  + curr->getID() + "' due to option '--ramps.no-split'");
     387            1 :             return;
     388              :         }
     389              :     }
     390          110 :     NBEdge* toMark = first;
     391              :     toMark->markOffRamp(true);
     392              :     double markedLength = toMark->getLoadedLength();
     393          187 :     while (markedLength < OFFRAMP_LOOKBACK) {
     394          136 :         if (toMark != first && toMark->getToNode()->getOutgoingEdges().size() != 1) {
     395              :             break;
     396              :         }
     397          126 :         NBNode* from = toMark->getFromNode();
     398          126 :         if (from->getIncomingEdges().size() == 1) {
     399           66 :             toMark = from->getIncomingEdges()[0];
     400              :         } else if (potOnRamps.count(from) == 1) {
     401              :             NBEdge* potOnRamp, *cont;
     402           11 :             getOnRampEdges(from, &toMark, &potOnRamp, &cont);
     403              :         } else {
     404              :             break;
     405              :         }
     406           77 :         toMark->markOffRamp(true);
     407           77 :         markedLength += toMark->getLoadedLength();
     408              :     }
     409              :     // set connections from added ramp to ramp/highway
     410          110 :     if (addLanes) {
     411           43 :         if (first->getStep() < NBEdge::EdgeBuildingStep::LANES2LANES_USER) {
     412           42 :             if (!first->addLane2LaneConnections(potRamp->getNumLanes(), potHighway, 0, MIN2(first->getNumLanes() - 1, potHighway->getNumLanes()), NBEdge::Lane2LaneInfoType::VALIDATED, true)) {
     413            0 :                 throw ProcessError(TL("Could not set connection!"));
     414              :             }
     415           42 :             if (!first->addLane2LaneConnections(0, potRamp, 0, potRamp->getNumLanes(), NBEdge::Lane2LaneInfoType::VALIDATED, false)) {
     416            0 :                 throw ProcessError(TL("Could not set connection!"));
     417              :             }
     418              :         }
     419           43 :         patchRampGeometry(potRamp, first, potHighway, true);
     420              :     }
     421              : }
     422              : 
     423              : 
     424              : void
     425           86 : NBRampsComputer::moveRampRight(NBEdge* ramp, int addedLanes) {
     426           86 :     if (ramp->getLaneSpreadFunction() != LaneSpreadFunction::CENTER) {
     427              :         return;
     428              :     }
     429              :     try {
     430           59 :         PositionVector g = ramp->getGeometry();
     431           59 :         double offset = (0.5 * addedLanes *
     432           59 :                          (ramp->getLaneWidth() == NBEdge::UNSPECIFIED_WIDTH ? SUMO_const_laneWidth : ramp->getLaneWidth()));
     433              :         if (myShiftedEdges.count(ramp) != 0) {
     434           26 :             offset -= myShiftedEdges[ramp];
     435              :         }
     436           59 :         g.move2side(offset);
     437           59 :         ramp->setGeometry(g);
     438           59 :         myShiftedEdges[ramp] = offset;
     439           59 :     } catch (InvalidArgument&) {
     440            0 :         WRITE_WARNINGF(TL("For edge '%': could not compute shape."), ramp->getID());
     441            0 :     }
     442              : }
     443              : 
     444              : 
     445              : bool
     446            0 : NBRampsComputer::determinedBySpeed(NBEdge** potHighway, NBEdge** potRamp) {
     447            0 :     if (fabs((*potHighway)->getSpeed() - (*potRamp)->getSpeed()) < .1) {
     448              :         return false;
     449              :     }
     450            0 :     if ((*potHighway)->getSpeed() < (*potRamp)->getSpeed()) {
     451              :         std::swap(*potHighway, *potRamp);
     452              :     }
     453              :     return true;
     454              : }
     455              : 
     456              : 
     457              : bool
     458            0 : NBRampsComputer::determinedByLaneNumber(NBEdge** potHighway, NBEdge** potRamp) {
     459            0 :     if ((*potHighway)->getNumLanes() == (*potRamp)->getNumLanes()) {
     460              :         return false;
     461              :     }
     462            0 :     if ((*potHighway)->getNumLanes() < (*potRamp)->getNumLanes()) {
     463              :         std::swap(*potHighway, *potRamp);
     464              :     }
     465              :     return true;
     466              : }
     467              : 
     468              : 
     469              : void
     470         3018 : NBRampsComputer::getOnRampEdges(NBNode* n, NBEdge** potHighway, NBEdge** potRamp, NBEdge** other) {
     471         3018 :     *other = n->getOutgoingEdges()[0];
     472              :     const std::vector<NBEdge*>& edges = n->getIncomingEdges();
     473              :     assert(edges.size() == 2);
     474         3018 :     *potHighway = edges[0];
     475         3018 :     *potRamp = edges[1];
     476              :     /*
     477              :     // heuristic: highway is faster than ramp
     478              :     if(determinedBySpeed(potHighway, potRamp)) {
     479              :         return;
     480              :     }
     481              :     // heuristic: highway has more lanes than ramp
     482              :     if(determinedByLaneNumber(potHighway, potRamp)) {
     483              :         return;
     484              :     }
     485              :     */
     486              :     // heuristic: ramp comes from right
     487         3018 :     if (NBContHelper::relative_incoming_edge_sorter(*other)(*potRamp, *potHighway)) {
     488              :         std::swap(*potHighway, *potRamp);
     489              :     }
     490         3018 : }
     491              : 
     492              : 
     493              : void
     494         3839 : NBRampsComputer::getOffRampEdges(NBNode* n, NBEdge** potHighway, NBEdge** potRamp, NBEdge** other) {
     495         3839 :     *other = n->getIncomingEdges()[0];
     496              :     const std::vector<NBEdge*>& edges = n->getOutgoingEdges();
     497         3839 :     *potHighway = edges[0];
     498         3839 :     *potRamp = edges[1];
     499              :     assert(edges.size() == 2);
     500              :     /*
     501              :     // heuristic: highway is faster than ramp
     502              :     if(determinedBySpeed(potHighway, potRamp)) {
     503              :         return;
     504              :     }
     505              :     // heuristic: highway has more lanes than ramp
     506              :     if(determinedByLaneNumber(potHighway, potRamp)) {
     507              :         return;
     508              :     }
     509              :     */
     510              :     // heuristic: ramp goes to right
     511              :     const std::vector<NBEdge*>& edges2 = n->getEdges();
     512              : #ifdef DEBUG_RAMPS
     513              :     if (DEBUGCOND(n)) {
     514              :         std::cout << "  edges=" << toString(edges) << " edges2=" << toString(edges2) << "\n";
     515              :     }
     516              : #endif
     517         3839 :     std::vector<NBEdge*>::const_iterator i = std::find(edges2.begin(), edges2.end(), *other);
     518         3839 :     NBContHelper::nextCW(edges2, i);
     519         3839 :     if ((*i) == *potRamp) {
     520              :         std::swap(*potHighway, *potRamp);
     521              :     }
     522              :     // the following would be better but runs afoul of misleading angles when both edges
     523              :     // have the same geometry start point but different references lanes are
     524              :     // chosen for NBEdge::computeAngle()
     525              :     //if (NBContHelper::relative_outgoing_edge_sorter(*other)(*potHighway, *potRamp)) {
     526              :     //    std::swap(*potHighway, *potRamp);
     527              :     //}
     528         3839 : }
     529              : 
     530              : 
     531              : bool
     532         6647 : NBRampsComputer::fulfillsRampConstraints(
     533              :     NBEdge* potHighway, NBEdge* potRamp, NBEdge* other, double minHighwaySpeed, double maxRampSpeed,
     534              :     const std::set<std::string>& noramps) {
     535              :     // check modes that are not appropriate for rampsdo not build ramps on rail edges
     536         6647 :     if (hasWrongMode(potHighway) || hasWrongMode(potRamp) || hasWrongMode(other)) {
     537         4789 :         return false;
     538              :     }
     539              :     // do not build ramps at traffic lights
     540         1858 :     if (NBNode::isTrafficLight(potRamp->getToNode()->getType())) {
     541              :         return false;
     542              :     }
     543              :     // do not build ramps on connectors
     544         1571 :     if (potHighway->isMacroscopicConnector() || potRamp->isMacroscopicConnector() || other->isMacroscopicConnector()) {
     545              :         return false;
     546              :     }
     547              :     // check whether a lane is missing
     548         1571 :     if (potHighway->getNumLanes() + potRamp->getNumLanes() < other->getNumLanes()) {
     549              :         return false;
     550              :     }
     551              :     // is it really a highway?
     552         1542 :     double maxSpeed = MAX3(potHighway->getSpeed(), other->getSpeed(), potRamp->getSpeed());
     553         1542 :     if (maxSpeed < minHighwaySpeed) {
     554              :         return false;
     555              :     }
     556              :     // is any of the connections a turnaround?
     557          272 :     if (other->getToNode() == potHighway->getFromNode()) {
     558              :         // off ramp
     559          298 :         if (other->isTurningDirectionAt(potHighway) ||
     560          147 :                 other->isTurningDirectionAt(potRamp)) {
     561            4 :             return false;
     562              :         }
     563              :     } else {
     564              :         // on ramp
     565          242 :         if (other->isTurningDirectionAt(potHighway) ||
     566          121 :                 other->isTurningDirectionAt(potRamp)) {
     567            2 :             return false;
     568              :         }
     569              :     }
     570              :     // are the angles between highway and other / ramp and other more or less straight?
     571          122 :     const NBNode* node = ((potHighway->getToNode() == potRamp->getToNode() && potHighway->getToNode() == other->getFromNode())
     572          266 :                           ? potHighway->getToNode() : potHighway->getFromNode());
     573          266 :     double angle = fabs(NBHelpers::relAngle(potHighway->getAngleAtNode(node), other->getAngleAtNode(node)));
     574          266 :     if (angle >= 60) {
     575              :         return false;
     576              :     }
     577          231 :     angle = fabs(NBHelpers::relAngle(potRamp->getAngleAtNode(node), other->getAngleAtNode(node)));
     578          231 :     if (angle >= 60) {
     579              :         return false;
     580              :     }
     581              :     /*
     582              :     if (potHighway->getSpeed() < minHighwaySpeed || other->getSpeed() < minHighwaySpeed) {
     583              :         return false;
     584              :     }
     585              :     */
     586              :     // is it really a ramp?
     587          214 :     if (maxRampSpeed > 0 && maxRampSpeed < potRamp->getSpeed()) {
     588              :         return false;
     589              :     }
     590          214 :     if (noramps.find(other->getID()) != noramps.end()) {
     591              :         return false;
     592              :     }
     593              :     return true;
     594              : }
     595              : 
     596              : 
     597              : bool
     598        10773 : NBRampsComputer::hasWrongMode(NBEdge* edge) {
     599              :     // must allow passenger vehicles
     600        10773 :     if ((edge->getPermissions() & SVC_PASSENGER) == 0) {
     601              :         return true;
     602              :     }
     603              :     // must not have a green verge or a lane that is only for soft modes
     604        16431 :     for (int i = 0; i < (int)edge->getNumLanes(); ++i) {
     605        10447 :         if ((edge->getPermissions(i) & ~(SVC_PEDESTRIAN | SVC_BICYCLE)) == 0) {
     606              :             return true;
     607              :         }
     608              :     }
     609              :     return false;
     610              : }
     611              : 
     612              : void
     613           80 : NBRampsComputer::patchRampGeometry(NBEdge* potRamp, NBEdge* first, NBEdge* potHighway, bool onRamp) {
     614              :     // geometry of first and highway should allign on the left side
     615           80 :     if (first->getLaneSpreadFunction() == LaneSpreadFunction::CENTER && first->hasDefaultGeometryEndpoints()) {
     616            5 :         const NBNode* n = onRamp ? potHighway->getToNode() : potHighway->getFromNode();
     617            5 :         if (potHighway->hasDefaultGeometryEndpointAtNode(n)) {
     618              :             PositionVector p2 = first->getGeometry();
     619              :             try {
     620            5 :                 p2.move2side((first->getNumLanes() - potHighway->getNumLanes()) * first->getLaneWidth(0) * 0.5);
     621            5 :                 first->setGeometry(p2);
     622            0 :             } catch (InvalidArgument&) {}
     623            5 :         }
     624              :     }
     625              : 
     626              :     // ramp should merge smoothly with first
     627              :     PositionVector p = potRamp->getGeometry();
     628              :     double offset = 0;
     629           80 :     int firstIndex = MAX2(0, MIN2(potRamp->getNumLanes(), first->getNumLanes()) - 1);
     630           80 :     if (potRamp->getLaneSpreadFunction() == LaneSpreadFunction::RIGHT) {
     631           28 :         offset = -first->getLaneWidth(firstIndex) / 2;
     632              :     } else {
     633           52 :         if (firstIndex % 2 == 1) {
     634              :             // even number of lanes
     635            9 :             offset = -first->getLaneWidth(firstIndex / 2) / 2;
     636              :         }
     637           52 :         firstIndex /= 2; // integer division
     638              :     }
     639              :     // reset lane shape (might be affected by earlier junctions.join step. see #947)
     640           80 :     first->resetLaneShapes();
     641           80 :     PositionVector l = first->getLaneShape(firstIndex);
     642              :     try {
     643           80 :         l.move2side(offset);
     644            0 :     } catch (InvalidArgument&) {}
     645              :     //std::cout << " ramp=" << potRamp->getID() << " firstIndex=" << firstIndex << " offset=" << offset << " l=" << l << "\n";
     646              : 
     647           80 :     if (onRamp) {
     648           43 :         p[0] = l[-1];
     649              :     } else {
     650              :         p.pop_back();
     651           37 :         p.push_back(l[0]);
     652              :     }
     653           80 :     potRamp->setGeometry(p);
     654              : 
     655           80 : }
     656              : 
     657              : 
     658              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1