LCOV - code coverage report
Current view: top level - src/netbuild - NBPTLineCont.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.1 % 283 272
Test Date: 2026-03-02 16:00:03 Functions: 100.0 % 15 15

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 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    NBPTLineCont.cpp
      15              : /// @author  Gregor Laemmel
      16              : /// @author  Nikita Cherednychek
      17              : /// @date    Tue, 20 Mar 2017
      18              : ///
      19              : // Container for NBPTLine during netbuild
      20              : /****************************************************************************/
      21              : #include <config.h>
      22              : 
      23              : #include <iostream>
      24              : #include <utils/common/MsgHandler.h>
      25              : #include <utils/common/ToString.h>
      26              : #include <utils/options/OptionsCont.h>
      27              : #include <utils/router/DijkstraRouter.h>
      28              : #include "NBPTLineCont.h"
      29              : #include "NBPTStop.h"
      30              : #include "NBEdge.h"
      31              : #include "NBNode.h"
      32              : #include "NBVehicle.h"
      33              : #include "NBPTStopCont.h"
      34              : 
      35              : //#define DEBUG_FIND_WAY
      36              : //#define DEBUG_CONSTRUCT_ROUTE
      37              : 
      38              : #define DEBUGLINEID ""
      39              : #define DEBUGSTOPID ""
      40              : 
      41              : // ===========================================================================
      42              : // static value definitions
      43              : // ===========================================================================
      44              : const int NBPTLineCont::FWD(1);
      45              : const int NBPTLineCont::BWD(-1);
      46              : 
      47              : 
      48              : // ===========================================================================
      49              : // method definitions
      50              : // ===========================================================================
      51         2141 : NBPTLineCont::~NBPTLineCont() {
      52         3289 :     for (auto& myPTLine : myPTLines) {
      53         1148 :         delete myPTLine.second;
      54              :     }
      55              :     myPTLines.clear();
      56         2141 : }
      57              : 
      58              : 
      59              : bool
      60         1154 : NBPTLineCont::insert(NBPTLine* ptLine) {
      61              :     if (myPTLines.count(ptLine->getLineID()) == 0) {
      62         1148 :         myPTLines[ptLine->getLineID()] = ptLine;
      63         1148 :         return true;
      64              :     }
      65              :     return false;
      66              : }
      67              : 
      68              : 
      69              : NBPTLine*
      70           17 : NBPTLineCont::retrieve(const std::string& lineID) {
      71              :     if (myPTLines.count(lineID) == 0) {
      72           16 :         return nullptr;
      73              :     } else {
      74            1 :         return myPTLines[lineID];
      75              :     }
      76              : }
      77              : 
      78              : void
      79          145 : NBPTLineCont::process(NBEdgeCont& ec, NBPTStopCont& sc, bool routeOnly) {
      80         1441 :     for (auto& item : myPTLines) {
      81         1296 :         NBPTLine* line = item.second;
      82         1296 :         if (item.second->getWays().size() > 0) {
      83              :             // loaded from OSM rather than ptline input. We can use extra
      84              :             // information to reconstruct route and stops
      85         1235 :             constructRoute(line, ec);
      86         1235 :             if (!routeOnly) {
      87              :                 // map stops to ways, using the constructed route for loose stops
      88         1103 :                 reviseStops(line, ec, sc);
      89              :             }
      90              :         }
      91              :         // fix circular line if necessary
      92         1296 :         if (line->getStops().size() > 1
      93          869 :                 && line->getStops().front() == line->getStops().back()
      94            7 :                 && line->getRoute().size() > 1
      95         1302 :                 && line->getRoute().front() != line->getRoute().back()) {
      96              :             // we need to duplicate either the first or the last edge depending on the stop locations
      97            6 :             const std::string firstStopEdge = line->getStops().front()->getEdgeId();
      98            6 :             const std::string lastStopEdge = line->getStops().back()->getEdgeId();
      99            6 :             std::vector<NBEdge*> edges = line->getRoute();
     100            6 :             if (firstStopEdge == edges.back()->getID()) {
     101            6 :                 edges.insert(edges.begin(), edges.back());
     102            0 :             } else if (lastStopEdge == edges.front()->getID()) {
     103            0 :                 edges.push_back(edges.front());
     104              :             }
     105            6 :             line->setEdges(edges);
     106            6 :         }
     107         1296 :         line->deleteInvalidStops(ec, sc);
     108              :         //line->deleteDuplicateStops();
     109              :     }
     110          145 : }
     111              : 
     112              : 
     113              : void
     114         1103 : NBPTLineCont::reviseStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
     115              :     const std::vector<std::string>& waysIds = line->getWays();
     116         1103 :     if (waysIds.size() == 1 && line->getStops().size() > 1) {
     117           33 :         reviseSingleWayStops(line, ec, sc);
     118          124 :         return;
     119              :     }
     120         1070 :     if (waysIds.size() <= 1) {
     121          144 :         WRITE_WARNINGF(TL("Cannot revise pt stop localization for pt line '%', which consist of one way only. Ignoring!"), line->getLineID());
     122           48 :         return;
     123              :     }
     124         1022 :     if (line->getRoute().size() == 0) {
     125          129 :         WRITE_WARNINGF(TL("Cannot revise pt stop localization for pt line '%', which has no route edges. Ignoring!"), line->getLineID());
     126           43 :         return;
     127              :     }
     128          979 :     std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
     129              :     std::vector<bool> stopsRevised;
     130         3730 :     for (std::shared_ptr<NBPTStop> stop : stops) {
     131         2751 :         stopsRevised.push_back(false);
     132              :         //get the corresponding and one of the two adjacent ways
     133         2751 :         stop = findWay(line, stop, ec, sc);
     134         2751 :         if (stop == nullptr) {
     135              :             // warning already given
     136            1 :             continue;
     137              :         }
     138         2750 :         auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
     139         2750 :         if (waysIdsIt == waysIds.end()) {
     140              :             // warning already given
     141           42 :             continue;
     142              :         }
     143              :         // find directional edge (OSM ways are bidirectional)
     144         2708 :         const std::vector<long long int>* const way = line->getWayNodes(stop->getOrigEdgeId());
     145         2708 :         if (way == nullptr) {
     146            0 :             WRITE_WARNINGF(TL("Cannot assign stop '%' on edge '%' to pt line '%' (wayNodes not found). Ignoring!"),
     147              :                            stop->getID(), stop->getOrigEdgeId(), line->getLineID());
     148            0 :             continue;
     149              :         }
     150              : 
     151              :         int dir;
     152              :         const std::vector<long long int>* wayPrev = nullptr;
     153         2708 :         if (waysIdsIt != waysIds.begin()) {
     154         4284 :             wayPrev = line->getWayNodes(*(waysIdsIt - 1));
     155              :         }
     156              :         const std::vector<long long int>* wayNext = nullptr;
     157         2708 :         if (waysIdsIt != (waysIds.end() - 1)) {
     158         4338 :             wayNext = line->getWayNodes(*(waysIdsIt + 1));
     159              :         }
     160         2708 :         if (wayPrev == nullptr && wayNext == nullptr) {
     161            0 :             WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
     162            0 :             continue;
     163              :         }
     164         2708 :         const long long int wayEnds = way->back();
     165         2708 :         const long long int wayBegins = way->front();
     166         2708 :         const long long int wayPrevEnds = wayPrev != nullptr ? wayPrev->back() : 0;
     167         2142 :         const long long int wayPrevBegins = wayPrev != nullptr ? wayPrev->front() : 0;
     168         2708 :         const long long int wayNextEnds = wayNext != nullptr ? wayNext->back() : 0;
     169         2169 :         const long long int wayNextBegins = wayNext != nullptr ? wayNext->front() : 0;
     170         2708 :         if (wayBegins == wayPrevEnds || wayBegins == wayPrevBegins || wayEnds == wayNextBegins || wayEnds == wayNextEnds) {
     171              :             dir = FWD;
     172          480 :         } else if (wayEnds == wayPrevBegins || wayEnds == wayPrevEnds || wayBegins == wayNextEnds || wayBegins == wayNextBegins) {
     173              :             dir = BWD;
     174              :         } else {
     175           30 :             WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
     176           10 :             continue;
     177              :         }
     178              : 
     179         2698 :         std::string edgeId = stop->getEdgeId();
     180         2698 :         NBEdge* current = ec.getByID(edgeId);
     181         2698 :         int assignedDir = edgeId.at(0) == '-' ? BWD : FWD;
     182              : 
     183         2698 :         if (dir != assignedDir) {
     184          257 :             NBEdge* reverse = NBPTStopCont::getReverseEdge(current);
     185          257 :             if (reverse == nullptr) {
     186           78 :                 const OptionsCont& oc = OptionsCont::getOptions();
     187          118 :                 if (!oc.getBool("railway.topology.repair") && oc.getBool("ptstop-output.no-bidi")) {
     188            0 :                     WRITE_WARNINGF(TL("Could not re-assign PT stop '%'. May need option --railway.topology.repair"), stop->getID());
     189              :                 }
     190              :                 continue;
     191           78 :             }
     192          179 :             if (stop->getLines().size() > 0) {
     193           98 :                 std::shared_ptr<NBPTStop> reverseStop = sc.getReverseStop(stop, ec);
     194           98 :                 sc.insert(reverseStop);
     195          147 :                 line->replaceStop(stop, reverseStop);
     196              :                 stop = reverseStop;
     197              :             } else {
     198          390 :                 WRITE_WARNINGF(TL("PT stop '%' has been moved to edge '%'."), stop->getID(), reverse->getID());
     199              :             }
     200          537 :             stop->setEdgeId(reverse->getID(), ec);
     201              :         }
     202         2620 :         stop->addLine(line->getRef());
     203              :         stopsRevised.back() = true;
     204              :     }
     205         1958 :     line->setRevised(stopsRevised);
     206          979 : }
     207              : 
     208              : 
     209           33 : void NBPTLineCont::reviseSingleWayStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
     210              :     const std::vector<std::string>& waysIds = line->getWays();
     211          134 :     for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
     212              :         //get the corresponding and one of the two adjacent ways
     213          101 :         stop = findWay(line, stop, ec, sc);
     214          101 :         if (stop == nullptr) {
     215              :             // warning already given
     216            4 :             continue;
     217              :         }
     218           97 :         auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
     219           97 :         if (waysIdsIt == waysIds.end()) {
     220              :             // warning already given
     221            0 :             continue;
     222              :         }
     223           97 :         stop->addLine(line->getRef());
     224              :     }
     225           33 : }
     226              : 
     227              : 
     228              : std::shared_ptr<NBPTStop>
     229         2852 : NBPTLineCont::findWay(NBPTLine* line, std::shared_ptr<NBPTStop> stop, const NBEdgeCont& ec, NBPTStopCont& sc) const {
     230              :     const std::vector<std::string>& waysIds = line->getWays();
     231              : #ifdef DEBUG_FIND_WAY
     232              :     if (stop->getID() == DEBUGSTOPID) {
     233              :         std::cout << " stop=" << stop->getID() << " line=" << line->getLineID() << " edgeID=" << stop->getEdgeId() << " origID=" << stop->getOrigEdgeId() << "\n";
     234              :     }
     235              : #endif
     236         2852 :     if (stop->isLoose()) {
     237              :         // find closest edge in route
     238              :         double minDist = std::numeric_limits<double>::max();
     239              :         NBEdge* best = nullptr;
     240         1361 :         for (NBEdge* edge : line->getRoute()) {
     241         1280 :             const double dist = edge->getLaneShape(0).distance2D(stop->getPosition());
     242         1280 :             if (dist < minDist) {
     243              :                 best = edge;
     244              :                 minDist = dist;
     245              :             }
     246              :         }
     247              : #ifdef DEBUG_FIND_WAY
     248              :         if (stop->getID() == DEBUGSTOPID) {
     249              :             std::cout << "   best=" << Named::getIDSecure(best) << " minDist=" << minDist << " wayID=" << getWayID(best->getID())
     250              :                       << " found=" << (std::find(waysIds.begin(), waysIds.end(), getWayID(best->getID())) != waysIds.end())
     251              :                       << " wayIDs=" << toString(waysIds) << "\n";
     252              :         }
     253              : #endif
     254          162 :         if (minDist < OptionsCont::getOptions().getFloat("ptline.match-dist")) {
     255           76 :             const std::string wayID = getWayID(best->getID());
     256           76 :             if (stop->getEdgeId() == "") {
     257          105 :                 stop->setEdgeId(best->getID(), ec);
     258              :                 stop->setOrigEdgeId(wayID);
     259           41 :             } else if (stop->getEdgeId() != best->getID()) {
     260              :                 // stop is used by multiple lines and mapped to different edges.
     261              :                 // check if an alternative stop already exists
     262            5 :                 std::shared_ptr<NBPTStop> newStop = sc.findStop(wayID, stop->getPosition());
     263            5 :                 if (newStop == nullptr) {
     264           12 :                     newStop = std::make_shared<NBPTStop>(stop->getElement(), stop->getID() + "@" + line->getLineID(), stop->getPosition(), best->getID(), wayID, stop->getLength(), stop->getName(), stop->getPermissions());
     265            9 :                     newStop->setEdgeId(best->getID(), ec);  // trigger lane assignment
     266            6 :                     sc.insert(newStop);
     267              :                 }
     268           15 :                 line->replaceStop(stop, newStop);
     269              :                 stop = newStop;
     270              :             }
     271              :         } else {
     272           20 :             WRITE_WARNINGF(TL("Could not assign stop '%' to pt line '%' (closest edge '%', distance %). Ignoring!"),
     273              :                            stop->getID(), line->getLineID(), Named::getIDSecure(best), minDist);
     274              :             return nullptr;
     275              :         }
     276              :     } else {
     277              :         // if the stop is part of an edge, find that edge among the line edges
     278              :         auto waysIdsIt = waysIds.begin();
     279        33619 :         for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
     280        33527 :             if ((*waysIdsIt) == stop->getOrigEdgeId()) {
     281              :                 break;
     282              :             }
     283              :         }
     284              : 
     285         2771 :         if (waysIdsIt == waysIds.end()) {
     286              :             // stop edge not found, try additional edges
     287          119 :             for (auto& edgeCand : stop->getAdditionalEdgeCandidates()) {
     288              :                 bool found = false;
     289              :                 waysIdsIt =  waysIds.begin();
     290          629 :                 for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
     291          602 :                     if ((*waysIdsIt) == edgeCand.first) {
     292          100 :                         if (stop->setEdgeId(edgeCand.second, ec)) {
     293              :                             stop->setOrigEdgeId(edgeCand.first);
     294              :                             found = true;
     295              :                             break;
     296              :                         }
     297              :                     }
     298              :                 }
     299              :                 if (found) {
     300              :                     break;
     301              :                 }
     302              :             }
     303           92 :             if (waysIdsIt == waysIds.end()) {
     304          126 :                 WRITE_WARNINGF(TL("Cannot assign stop % on edge '%' to pt line '%'. Ignoring!"), stop->getID(), stop->getOrigEdgeId(), line->getLineID());
     305              :             }
     306              :         }
     307              :     }
     308              :     return stop;
     309              : }
     310              : 
     311              : 
     312         1235 : void NBPTLineCont::constructRoute(NBPTLine* pTLine, const NBEdgeCont& cont) {
     313              :     std::vector<NBEdge*> edges;
     314              : 
     315              :     NBNode* first = nullptr;
     316              :     NBNode* last = nullptr;
     317              :     std::vector<NBEdge*> prevWayEdges;
     318              :     std::vector<NBEdge*> prevWayMinusEdges;
     319              :     std::vector<NBEdge*> currentWayEdges;
     320              :     std::vector<NBEdge*> currentWayMinusEdges;
     321        15467 :     for (auto it3 = pTLine->getWays().begin(); it3 != pTLine->getWays().end(); it3++) {
     322              : 
     323              :         int foundForward = 0;
     324        14232 :         if (cont.retrieve(*it3, false) != nullptr) {
     325         7228 :             currentWayEdges.push_back(cont.retrieve(*it3, false));
     326              :             foundForward++;
     327              :         } else {
     328              :             int i = 0;
     329        57672 :             while (cont.retrieve(*it3 + "#" + std::to_string(i), true) != nullptr) {
     330        43664 :                 if (cont.retrieve(*it3 + "#" + std::to_string(i), false)) {
     331        43664 :                     currentWayEdges.push_back(cont.retrieve(*it3 + "#" + std::to_string(i), false));
     332        21832 :                     foundForward++;
     333              :                 }
     334        21832 :                 i++;
     335              :             }
     336              :         }
     337              : 
     338              :         int foundReverse = 0;
     339        28464 :         if (cont.retrieve("-" + *it3, false) != nullptr) {
     340         5112 :             currentWayMinusEdges.push_back(cont.retrieve("-" + *it3, false));
     341              :             foundReverse++;
     342              :         } else {
     343              :             int i = 0;
     344        61020 :             while (cont.retrieve("-" + *it3 + "#" + std::to_string(i), true) != nullptr) {
     345        25992 :                 if (cont.retrieve("-" + *it3 + "#" + std::to_string(i), false)) {
     346         8664 :                     currentWayMinusEdges.insert(currentWayMinusEdges.end() - foundReverse,
     347        25992 :                                                 cont.retrieve("-" + *it3 + "#" + std::to_string(i), false));
     348         8664 :                     foundReverse++;
     349              :                 }
     350         8664 :                 i++;
     351              :             }
     352              :         }
     353              :         bool fakeMinus = false;
     354        14232 :         if (foundReverse == 0 && foundForward > 0 && isRailway(pTLine->getVClass())) {
     355              :             // rail tracks may be used in both directions and are often not tagged as such.
     356              :             // This can be repaired later with option --railway.topology.repair
     357         5508 :             currentWayMinusEdges.insert(currentWayMinusEdges.begin(), currentWayEdges.rbegin(), currentWayEdges.rbegin() + foundForward);
     358              :             fakeMinus = true;
     359              :         }
     360              : #ifdef DEBUG_CONSTRUCT_ROUTE
     361              :         if (pTLine->getLineID() == DEBUGLINEID) {
     362              :             std::cout << " way=" << (*it3)
     363              :                       << " done=" << toString(edges)
     364              :                       << " first=" << Named::getIDSecure(first)
     365              :                       << " last=" << Named::getIDSecure(last)
     366              :                       << "\n    +=" << toString(currentWayEdges)
     367              :                       << "\n    -=" << toString(currentWayMinusEdges)
     368              :                       << "\n   p+=" << toString(prevWayEdges)
     369              :                       << "\n   p-=" << toString(prevWayMinusEdges)
     370              :                       << "\n";
     371              :         }
     372              : #endif
     373        14232 :         if (currentWayEdges.empty()) {
     374          194 :             continue;
     375              :         }
     376        14038 :         if (last == currentWayEdges.front()->getFromNode() && last != nullptr) {
     377        10848 :             if (!prevWayEdges.empty()) {
     378          894 :                 edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
     379              :                 prevWayEdges.clear();
     380              :                 prevWayMinusEdges.clear();
     381              :             }
     382        10848 :             edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
     383        10848 :             last = currentWayEdges.back()->getToNode();
     384         3190 :         } else if (last == currentWayEdges.back()->getToNode() && last != nullptr) {
     385         1692 :             if (!prevWayEdges.empty()) {
     386           64 :                 edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
     387              :                 prevWayEdges.clear();
     388              :                 prevWayMinusEdges.clear();
     389              :             }
     390         1692 :             if (currentWayMinusEdges.empty()) {
     391              :                 currentWayEdges.clear();
     392              :                 last = nullptr;
     393            3 :                 continue;
     394              :             } else {
     395         1689 :                 edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
     396         1689 :                 if (fakeMinus) {
     397          172 :                     last = currentWayMinusEdges.back()->getFromNode();
     398              :                 } else {
     399         1517 :                     last = currentWayMinusEdges.back()->getToNode();
     400              :                 }
     401              :             }
     402         1498 :         } else if (first == currentWayEdges.front()->getFromNode() && first != nullptr) {
     403           28 :             edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
     404           28 :             edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
     405           28 :             last = currentWayEdges.back()->getToNode();
     406              :             prevWayEdges.clear();
     407              :             prevWayMinusEdges.clear();
     408         1470 :         } else if (first == currentWayEdges.back()->getToNode() && first != nullptr) {
     409          177 :             edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
     410          177 :             if (currentWayMinusEdges.empty()) {
     411              :                 currentWayEdges.clear();
     412              :                 last = nullptr;
     413              :                 prevWayEdges.clear();
     414              :                 prevWayMinusEdges.clear();
     415            1 :                 continue;
     416              :             } else {
     417          176 :                 edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
     418          176 :                 last = currentWayMinusEdges.back()->getToNode();
     419              :                 prevWayEdges.clear();
     420              :                 prevWayMinusEdges.clear();
     421              :             }
     422              :         } else {
     423         1293 :             if (it3 != pTLine->getWays().begin()) {
     424              : #ifdef DEBUG_CONSTRUCT_ROUTE
     425              :                 if (pTLine->getLineID() == DEBUGLINEID) {
     426              :                     std::cout << " way " << (*it3)
     427              :                               << " is not the start of ptline " << pTLine->getLineID()
     428              :                               << " (" + pTLine->getName() + ")\n";
     429              :                 }
     430              : #endif
     431         1155 :             } else if (pTLine->getWays().size() == 1) {
     432              :                 if (currentWayEdges.size() > 0) {
     433           71 :                     edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
     434              :                 } else {
     435              :                     edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
     436              :                 }
     437              :             }
     438         1293 :             prevWayEdges = currentWayEdges;
     439         1293 :             prevWayMinusEdges = currentWayMinusEdges;
     440         1293 :             if (!prevWayEdges.empty()) {
     441         1293 :                 first = prevWayEdges.front()->getFromNode();
     442         1293 :                 last = prevWayEdges.back()->getToNode();
     443              :             } else {
     444              :                 first = nullptr;
     445              :                 last = nullptr;
     446              :             }
     447              :         }
     448              :         currentWayEdges.clear();
     449              :         currentWayMinusEdges.clear();
     450              :     }
     451         1235 :     pTLine->setEdges(edges);
     452         1235 : }
     453              : 
     454              : 
     455              : void
     456         5570 : NBPTLineCont::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
     457              :     //std::cout << " replaceEdge " << edgeID << " replacement=" << toString(replacement) << "\n";
     458         5570 :     if (myPTLines.size() > 0 && myPTLineLookup.size() == 0) {
     459              :         // init lookup once
     460         1148 :         for (auto& item : myPTLines) {
     461        18579 :             for (const NBEdge* e : item.second->getRoute()) {
     462        17531 :                 myPTLineLookup[e->getID()].insert(item.second);
     463              :             }
     464              :         }
     465              :     }
     466        10731 :     for (NBPTLine* line : myPTLineLookup[edgeID]) {
     467         5161 :         line->replaceEdge(edgeID, replacement);
     468        10824 :         for (const NBEdge* e : replacement) {
     469         5663 :             myPTLineLookup[e->getID()].insert(line);
     470              :         }
     471              :     }
     472              :     myPTLineLookup.erase(edgeID);
     473         5570 : }
     474              : 
     475              : 
     476              : std::set<std::string>
     477            4 : NBPTLineCont::getServedPTStops() {
     478              :     std::set<std::string> result;
     479          118 :     for (auto& item : myPTLines) {
     480          114 :         NBPTLine* line = item.second;
     481          484 :         for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
     482          740 :             result.insert(stop->getID());
     483              :         }
     484              :     }
     485            4 :     return result;
     486              : }
     487              : 
     488              : 
     489              : void
     490           76 : NBPTLineCont::fixBidiStops(const NBEdgeCont& ec) {
     491              :     std::map<std::string, SUMOVehicleClass> types;
     492           76 :     types["bus"] = SVC_BUS;
     493           76 :     types["minibus"] = SVC_BUS;
     494           76 :     types["trolleybus"] = SVC_BUS;
     495           76 :     types["tram"] = SVC_TRAM;
     496           76 :     types["train"] = SVC_RAIL;
     497           76 :     types["subway"] = SVC_RAIL_URBAN;
     498           76 :     types["light_rail"] = SVC_RAIL_URBAN;
     499           76 :     types["monorail"] = SVC_RAIL_URBAN;
     500           76 :     types["aerialway"] = SVC_RAIL_URBAN;
     501           76 :     types["ferry"] = SVC_SHIP;
     502              : 
     503              :     SUMOAbstractRouter<NBRouterEdge, NBVehicle>* const router = new DijkstraRouter<NBRouterEdge, NBVehicle>(
     504           76 :         ec.getAllRouterEdges(), true, &NBRouterEdge::getTravelTimeStatic, nullptr, true);
     505              : 
     506          752 :     for (auto& item : myPTLines) {
     507          676 :         NBPTLine* line = item.second;
     508          676 :         std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
     509          676 :         if (stops.size() < 2) {
     510          169 :             continue;
     511              :         }
     512            0 :         if (types.count(line->getType()) == 0) {
     513            0 :             WRITE_WARNINGF(TL("Could not determine vehicle class for public transport line of type '%'."), line->getType());
     514            0 :             continue;
     515              :         }
     516          507 :         NBVehicle veh(line->getRef(), types[line->getType()]);
     517              :         std::vector<std::shared_ptr<NBPTStop> > newStops;
     518              :         std::shared_ptr<NBPTStop> from = nullptr;
     519          507 :         std::vector<NBPTLine::PTStopInfo> stopInfos = line->getStopEdges(ec);
     520              :         assert(stopInfos.size() == stops.size());
     521         2532 :         for (auto it = stops.begin(); it != stops.end(); ++it) {
     522              :             std::shared_ptr<NBPTStop> to = *it;
     523              :             std::shared_ptr<NBPTStop> used = *it;
     524         2025 :             bool isRevised = stopInfos[it - stops.begin()].revised;
     525         4050 :             if (to->getBidiStop() != nullptr && !isRevised) {
     526              :                 double best = std::numeric_limits<double>::max();
     527              :                 std::shared_ptr<NBPTStop> to2 = to->getBidiStop();
     528           82 :                 if (from == nullptr) {
     529           24 :                     if ((it + 1) != stops.end()) {
     530              :                         from = to;
     531              :                         std::shared_ptr<NBPTStop> from2 = to2;
     532              :                         to = *(it + 1);
     533           72 :                         const double c1 = getCost(ec, *router, from, to, &veh);
     534           72 :                         const double c2 = getCost(ec, *router, from2, to, &veh);
     535              :                         //std::cout << " from=" << from->getID() << " to=" << to->getID() << " c1=" << MIN2(10000.0, c1) << "\n";
     536              :                         //std::cout << " from2=" << from2->getID() << " to=" << to->getID() << " c2=" << MIN2(10000.0, c2) << "\n";
     537              :                         best = c1;
     538           24 :                         if (to->getBidiStop() != nullptr) {
     539           20 :                             to2 = to->getBidiStop();
     540           60 :                             const double c3 = getCost(ec, *router, from, to2, &veh);
     541           40 :                             const double c4 = getCost(ec, *router, from2, to2, &veh);
     542              :                             //std::cout << " from=" << from->getID() << " to2=" << to2->getID() << " c3=" << MIN2(10000.0, c3) << "\n";
     543              :                             //std::cout << " from2=" << from2->getID() << " to2=" << to2->getID() << " c4=" << MIN2(10000.0, c4) << "\n";
     544           20 :                             if (c2 < best) {
     545              :                                 used = from2;
     546              :                                 best = c2;
     547              :                             }
     548           20 :                             if (c3 < best) {
     549              :                                 used = from;
     550              :                                 best = c3;
     551              :                             }
     552           20 :                             if (c4 < best) {
     553              :                                 used = from2;
     554              :                                 best = c4;
     555              :                             }
     556              :                         } else {
     557            4 :                             if (c2 < c1) {
     558              :                                 used = from2;
     559              :                                 best = c2;
     560              :                             } else {
     561              :                                 best = c1;
     562              :                             }
     563              :                         }
     564              :                     }
     565              :                 } else {
     566          174 :                     const double c1 = getCost(ec, *router, from, to, &veh);
     567          116 :                     const double c2 = getCost(ec, *router, from, to2, &veh);
     568              :                     //std::cout << " from=" << from->getID() << " to=" << to->getID() << " c1=" << MIN2(10000.0, c1) << "\n";
     569              :                     //std::cout << " from=" << from->getID() << " t2o=" << to2->getID() << " c2=" << MIN2(10000.0, c2) << "\n";
     570           58 :                     if (c2 < c1) {
     571              :                         used = to2;
     572              :                         best = c2;
     573              :                     } else {
     574              :                         best = c1;
     575              :                     }
     576              : 
     577              :                 }
     578           82 :                 if (best < std::numeric_limits<double>::max()) {
     579              :                     from = used;
     580              :                 } else {
     581           12 :                     WRITE_WARNINGF(TL("Could not determine direction for line '%' at stop '%'."), line->getLineID(), used->getID());
     582              :                 }
     583              :             }
     584              :             from = used;
     585         2025 :             newStops.push_back(used);
     586              :         }
     587              :         assert(stops.size() == newStops.size());
     588         1014 :         line->replaceStops(newStops);
     589         1690 :     }
     590           76 :     delete router;
     591           76 : }
     592              : 
     593              : 
     594              : void
     595         1840 : NBPTLineCont::removeInvalidEdges(const NBEdgeCont& ec) {
     596         2987 :     for (auto& item : myPTLines) {
     597         1147 :         item.second->removeInvalidEdges(ec);
     598              :     }
     599         1840 : }
     600              : 
     601              : 
     602              : void
     603         1840 : NBPTLineCont::fixPermissions() {
     604         2987 :     for (auto& item : myPTLines) {
     605         1147 :         NBPTLine* line = item.second;
     606         1147 :         const std::vector<NBEdge*>& route = line->getRoute();
     607              :         const SUMOVehicleClass svc = line->getVClass();
     608        17038 :         for (int i = 1; i < (int)route.size(); i++) {
     609        15891 :             NBEdge* e1 = route[i - 1];
     610        15891 :             NBEdge* e2 = route[i];
     611        15891 :             std::vector<NBEdge::Connection> cons = e1->getConnectionsFromLane(-1, e2, -1);
     612        15891 :             if (cons.size() == 0) {
     613              :                 //WRITE_WARNINGF(TL("Disconnected ptline '%' between edge '%' and edge '%'"), line->getLineID(), e1->getID(), e2->getID());
     614              :             } else {
     615              :                 bool ok = false;
     616        16227 :                 for (const auto& c : cons) {
     617        16225 :                     if ((e1->getPermissions(c.fromLane) & svc) == svc) {
     618              :                         ok = true;
     619              :                         break;
     620              :                     }
     621              :                 }
     622        15579 :                 if (!ok) {
     623            2 :                     int lane = cons[0].fromLane;
     624            2 :                     e1->setPermissions(e1->getPermissions(lane) | svc, lane);
     625              :                 }
     626              :             }
     627        15891 :         }
     628              :     }
     629         1840 : }
     630              : 
     631              : 
     632              : double
     633          204 : NBPTLineCont::getCost(const NBEdgeCont& ec, SUMOAbstractRouter<NBRouterEdge, NBVehicle>& router,
     634              :                       const std::shared_ptr<NBPTStop> from, const std::shared_ptr<NBPTStop> to, const NBVehicle* veh) {
     635          204 :     NBEdge* fromEdge = ec.getByID(from->getEdgeId());
     636          204 :     NBEdge* toEdge = ec.getByID(to->getEdgeId());
     637          204 :     if (fromEdge == nullptr || toEdge == nullptr) {
     638              :         return std::numeric_limits<double>::max();
     639          204 :     } else if (fromEdge == toEdge) {
     640           33 :         if (from->getEndPos() <= to->getEndPos()) {
     641           27 :             return to->getEndPos() - from->getEndPos();
     642              :         } else {
     643              :             return std::numeric_limits<double>::max();
     644              :         }
     645          171 :     } else if (fromEdge->getBidiEdge() == toEdge) {
     646              :         return std::numeric_limits<double>::max();
     647              :     }
     648              :     std::vector<const NBRouterEdge*> route;
     649          142 :     router.compute(fromEdge, toEdge, veh, 0, route);
     650          142 :     if (route.size() == 0) {
     651              :         return std::numeric_limits<double>::max();
     652              :     } else {
     653          120 :         return router.recomputeCosts(route, veh, 0);
     654              :     }
     655          142 : }
     656              : 
     657              : 
     658              : std::string
     659           76 : NBPTLineCont::getWayID(const std::string& edgeID) {
     660              :     std::size_t found = edgeID.rfind("#");
     661              :     std::string result = edgeID;
     662           76 :     if (found != std::string::npos) {
     663          124 :         result = edgeID.substr(0, found);
     664              :     }
     665           76 :     if (result[0] == '-') {
     666           46 :         result = result.substr(1);
     667              :     }
     668           76 :     return result;
     669              : }
     670              : 
     671              : 
     672              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1