LCOV - code coverage report
Current view: top level - src/netbuild - NBPTLineCont.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 263 270 97.4 %
Date: 2024-05-07 15:28:01 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-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    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        2337 : NBPTLineCont::~NBPTLineCont() {
      52        3799 :     for (auto& myPTLine : myPTLines) {
      53        1462 :         delete myPTLine.second;
      54             :     }
      55             :     myPTLines.clear();
      56        2337 : }
      57             : 
      58             : 
      59             : bool
      60        1468 : NBPTLineCont::insert(NBPTLine* ptLine) {
      61             :     if (myPTLines.count(ptLine->getLineID()) == 0) {
      62        1462 :         myPTLines[ptLine->getLineID()] = ptLine;
      63        1462 :         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         141 : NBPTLineCont::process(NBEdgeCont& ec, NBPTStopCont& sc, bool routeOnly) {
      80        1826 :     for (auto& item : myPTLines) {
      81        1685 :         NBPTLine* line = item.second;
      82        1685 :         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        1624 :             constructRoute(line, ec);
      86        1624 :             if (!routeOnly) {
      87             :                 // map stops to ways, using the constructed route for loose stops
      88        1418 :                 reviseStops(line, ec, sc);
      89             :             }
      90             :         }
      91             :         // fix circular line if necessary
      92        1685 :         if (line->getStops().size() > 1
      93        1203 :                 && line->getStops().front() == line->getStops().back()
      94           6 :                 && line->getRoute().size() > 1
      95        1691 :                 && 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             :         }
     107        1685 :         line->deleteInvalidStops(ec, sc);
     108             :         //line->deleteDuplicateStops();
     109        6657 :         for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
     110        9944 :             myServedPTStops.insert(stop->getID());
     111             :         }
     112             :     }
     113         141 : }
     114             : 
     115             : 
     116             : void
     117        1418 : NBPTLineCont::reviseStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
     118             :     const std::vector<std::string>& waysIds = line->getWays();
     119        1418 :     if (waysIds.size() == 1 && line->getStops().size() > 1) {
     120          23 :         reviseSingleWayStops(line, ec, sc);
     121         128 :         return;
     122             :     }
     123        1395 :     if (waysIds.size() <= 1) {
     124         144 :         WRITE_WARNINGF(TL("Cannot revise pt stop localization for pt line '%', which consist of one way only. Ignoring!"), line->getLineID());
     125          48 :         return;
     126             :     }
     127        1347 :     if (line->getRoute().size() == 0) {
     128         171 :         WRITE_WARNINGF(TL("Cannot revise pt stop localization for pt line '%', which has no route edges. Ignoring!"), line->getLineID());
     129          57 :         return;
     130             :     }
     131        1290 :     std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
     132        5187 :     for (std::shared_ptr<NBPTStop> stop : stops) {
     133             :         //get the corresponding and one of the two adjacent ways
     134        7794 :         stop = findWay(line, stop, ec, sc);
     135        3897 :         if (stop == nullptr) {
     136             :             // warning already given
     137           1 :             continue;
     138             :         }
     139        3896 :         auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
     140        3896 :         if (waysIdsIt == waysIds.end()) {
     141             :             // warning already given
     142          50 :             continue;
     143             :         }
     144             :         // find directional edge (OSM ways are bidirectional)
     145        3846 :         const std::vector<long long int>* const way = line->getWayNodes(stop->getOrigEdgeId());
     146        3846 :         if (way == nullptr) {
     147           0 :             WRITE_WARNINGF(TL("Cannot assign stop '%' on edge '%' to pt line '%' (wayNodes not found). Ignoring!"),
     148             :                            stop->getID(), stop->getOrigEdgeId(), line->getLineID());
     149           0 :             continue;
     150             :         }
     151             : 
     152             :         int dir;
     153             :         const std::vector<long long int>* wayPrev = nullptr;
     154        3846 :         if (waysIdsIt != waysIds.begin()) {
     155        6382 :             wayPrev = line->getWayNodes(*(waysIdsIt - 1));
     156             :         }
     157             :         const std::vector<long long int>* wayNext = nullptr;
     158        3846 :         if (waysIdsIt != (waysIds.end() - 1)) {
     159        6476 :             wayNext = line->getWayNodes(*(waysIdsIt + 1));
     160             :         }
     161        3846 :         if (wayPrev == nullptr && wayNext == nullptr) {
     162           0 :             WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
     163           0 :             continue;
     164             :         }
     165        3846 :         const long long int wayEnds = way->back();
     166        3846 :         const long long int wayBegins = way->front();
     167        3846 :         const long long int wayPrevEnds = wayPrev != nullptr ? wayPrev->back() : 0;
     168        3846 :         const long long int wayPrevBegins = wayPrev != nullptr ? wayPrev->front() : 0;
     169        3846 :         const long long int wayNextEnds = wayNext != nullptr ? wayNext->back() : 0;
     170        3846 :         const long long int wayNextBegins = wayNext != nullptr ? wayNext->front() : 0;
     171        3846 :         if (wayBegins == wayPrevEnds || wayBegins == wayPrevBegins || wayEnds == wayNextBegins || wayEnds == wayNextEnds) {
     172             :             dir = FWD;
     173         613 :         } else if (wayEnds == wayPrevBegins || wayEnds == wayPrevEnds || wayBegins == wayNextEnds || wayBegins == wayNextBegins) {
     174             :             dir = BWD;
     175             :         } else {
     176          60 :             WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
     177          20 :             continue;
     178             :         }
     179             : 
     180        3826 :         std::string edgeId = stop->getEdgeId();
     181        3826 :         NBEdge* current = ec.getByID(edgeId);
     182        3826 :         int assignedTo = edgeId.at(0) == '-' ? BWD : FWD;
     183             : 
     184        3826 :         if (dir != assignedTo) {
     185         320 :             NBEdge* reverse = NBPTStopCont::getReverseEdge(current);
     186         320 :             if (reverse == nullptr) {
     187         208 :                 WRITE_WARNINGF(TL("Could not re-assign PT stop '%', probably broken osm file."), stop->getID());
     188             :                 continue;
     189             :             }
     190         217 :             if (stop->getLines().size() > 0) {
     191          98 :                 std::shared_ptr<NBPTStop> reverseStop = sc.getReverseStop(stop, ec);
     192          98 :                 sc.insert(reverseStop);
     193         147 :                 line->replaceStop(stop, reverseStop);
     194             :                 stop = reverseStop;
     195             :             } else {
     196         504 :                 WRITE_WARNINGF(TL("PT stop '%' has been moved to edge '%'."), stop->getID(), reverse->getID());
     197             :             }
     198         651 :             stop->setEdgeId(reverse->getID(), ec);
     199             :         }
     200        3723 :         stop->addLine(line->getRef());
     201             :     }
     202        1290 : }
     203             : 
     204             : 
     205          23 : void NBPTLineCont::reviseSingleWayStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
     206             :     const std::vector<std::string>& waysIds = line->getWays();
     207          83 :     for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
     208             :         //get the corresponding and one of the two adjacent ways
     209         120 :         stop = findWay(line, stop, ec, sc);
     210          60 :         if (stop == nullptr) {
     211             :             // warning already given
     212           4 :             continue;
     213             :         }
     214          56 :         auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
     215          56 :         if (waysIdsIt == waysIds.end()) {
     216             :             // warning already given
     217           0 :             continue;
     218             :         }
     219          56 :         stop->addLine(line->getRef());
     220             :     }
     221          23 : }
     222             : 
     223             : 
     224             : std::shared_ptr<NBPTStop>
     225        3957 : NBPTLineCont::findWay(NBPTLine* line, std::shared_ptr<NBPTStop> stop, const NBEdgeCont& ec, NBPTStopCont& sc) const {
     226             :     const std::vector<std::string>& waysIds = line->getWays();
     227             : #ifdef DEBUG_FIND_WAY
     228             :     if (stop->getID() == DEBUGSTOPID) {
     229             :         std::cout << " stop=" << stop->getID() << " line=" << line->getLineID() << " edgeID=" << stop->getEdgeId() << " origID=" << stop->getOrigEdgeId() << "\n";
     230             :     }
     231             : #endif
     232        3957 :     if (stop->isLoose()) {
     233             :         // find closest edge in route
     234             :         double minDist = std::numeric_limits<double>::max();
     235             :         NBEdge* best = nullptr;
     236        1037 :         for (NBEdge* edge : line->getRoute()) {
     237         967 :             const double dist = edge->getLaneShape(0).distance2D(stop->getPosition());
     238         967 :             if (dist < minDist) {
     239             :                 best = edge;
     240             :                 minDist = dist;
     241             :             }
     242             :         }
     243             : #ifdef DEBUG_FIND_WAY
     244             :         if (stop->getID() == DEBUGSTOPID) {
     245             :             std::cout << "   best=" << Named::getIDSecure(best) << " minDist=" << minDist << " wayID=" << getWayID(best->getID())
     246             :                       << " found=" << (std::find(waysIds.begin(), waysIds.end(), getWayID(best->getID())) != waysIds.end())
     247             :                       << " wayIDs=" << toString(waysIds) << "\n";
     248             :         }
     249             : #endif
     250         140 :         if (minDist < OptionsCont::getOptions().getFloat("ptline.match-dist")) {
     251          65 :             const std::string wayID = getWayID(best->getID());
     252         130 :             if (stop->getEdgeId() == "") {
     253          90 :                 stop->setEdgeId(best->getID(), ec);
     254             :                 stop->setOrigEdgeId(wayID);
     255          35 :             } else if (stop->getEdgeId() != best->getID()) {
     256             :                 // stop is used by multiple lines and mapped to different edges.
     257             :                 // check if an alternative stop already exists
     258           5 :                 std::shared_ptr<NBPTStop> newStop = sc.findStop(wayID, stop->getPosition());
     259           5 :                 if (newStop == nullptr) {
     260           9 :                     newStop = std::make_shared<NBPTStop>(stop->getID() + "@" + line->getLineID(), stop->getPosition(), best->getID(), wayID, stop->getLength(), stop->getName(), stop->getPermissions());
     261           9 :                     newStop->setEdgeId(best->getID(), ec);  // trigger lane assignment
     262           6 :                     sc.insert(newStop);
     263             :                 }
     264          15 :                 line->replaceStop(stop, newStop);
     265             :                 stop = newStop;
     266             :             }
     267             :         } else {
     268          15 :             WRITE_WARNINGF(TL("Could not assign stop '%' to pt line '%' (closest edge '%', distance %). Ignoring!"),
     269             :                            stop->getID(), line->getLineID(), Named::getIDSecure(best), minDist);
     270             :             return nullptr;
     271             :         }
     272             :     } else {
     273             :         // if the stop is part of an edge, find that edge among the line edges
     274             :         auto waysIdsIt = waysIds.begin();
     275       47677 :         for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
     276       47550 :             if ((*waysIdsIt) == stop->getOrigEdgeId()) {
     277             :                 break;
     278             :             }
     279             :         }
     280             : 
     281        3887 :         if (waysIdsIt == waysIds.end()) {
     282             :             // stop edge not found, try additional edges
     283         162 :             for (auto& edgeCand : stop->getAdditionalEdgeCandidates()) {
     284             :                 bool found = false;
     285             :                 waysIdsIt =  waysIds.begin();
     286        1040 :                 for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
     287        1005 :                     if ((*waysIdsIt) == edgeCand.first) {
     288         154 :                         if (stop->setEdgeId(edgeCand.second, ec)) {
     289             :                             stop->setOrigEdgeId(edgeCand.first);
     290             :                             found = true;
     291             :                             break;
     292             :                         }
     293             :                     }
     294             :                 }
     295             :                 if (found) {
     296             :                     break;
     297             :                 }
     298             :             }
     299         127 :             if (waysIdsIt == waysIds.end()) {
     300         150 :                 WRITE_WARNINGF(TL("Cannot assign stop % on edge '%' to pt line '%'. Ignoring!"), stop->getID(), stop->getOrigEdgeId(), line->getLineID());
     301             :             }
     302             :         }
     303             :     }
     304             :     return stop;
     305             : }
     306             : 
     307             : 
     308        1624 : void NBPTLineCont::constructRoute(NBPTLine* pTLine, const NBEdgeCont& cont) {
     309             :     std::vector<NBEdge*> edges;
     310             : 
     311             :     NBNode* first = nullptr;
     312             :     NBNode* last = nullptr;
     313             :     std::vector<NBEdge*> prevWayEdges;
     314             :     std::vector<NBEdge*> prevWayMinusEdges;
     315             :     std::vector<NBEdge*> currentWayEdges;
     316             :     std::vector<NBEdge*> currentWayMinusEdges;
     317       23779 :     for (auto it3 = pTLine->getWays().begin(); it3 != pTLine->getWays().end(); it3++) {
     318             : 
     319             :         int foundForward = 0;
     320       22155 :         if (cont.retrieve(*it3, false) != nullptr) {
     321       11130 :             currentWayEdges.push_back(cont.retrieve(*it3, false));
     322             :             foundForward++;
     323             :         } else {
     324             :             int i = 0;
     325       91508 :             while (cont.retrieve(*it3 + "#" + std::to_string(i), true) != nullptr) {
     326       69458 :                 if (cont.retrieve(*it3 + "#" + std::to_string(i), false)) {
     327       34729 :                     currentWayEdges.push_back(cont.retrieve(*it3 + "#" + std::to_string(i), false));
     328       34729 :                     foundForward++;
     329             :                 }
     330       34729 :                 i++;
     331             :             }
     332             :         }
     333             : 
     334             :         int foundReverse = 0;
     335       44310 :         if (cont.retrieve("-" + *it3, false) != nullptr) {
     336        3497 :             currentWayMinusEdges.push_back(cont.retrieve("-" + *it3, false));
     337             :             foundReverse++;
     338             :         } else {
     339             :             int i = 0;
     340       62096 :             while (cont.retrieve("-" + *it3 + "#" + std::to_string(i), true) != nullptr) {
     341       24780 :                 if (cont.retrieve("-" + *it3 + "#" + std::to_string(i), false)) {
     342       12390 :                     currentWayMinusEdges.insert(currentWayMinusEdges.end() - foundReverse,
     343       12390 :                                                 cont.retrieve("-" + *it3 + "#" + std::to_string(i), false));
     344       12390 :                     foundReverse++;
     345             :                 }
     346       12390 :                 i++;
     347             :             }
     348             :         }
     349             :         bool fakeMinus = false;
     350       22155 :         if (foundReverse == 0 && foundForward > 0 && isRailway(pTLine->getVClass())) {
     351             :             // rail tracks may be used in both directions and are often not tagged as such.
     352             :             // This can be repaired later with option --railway.topology.repair
     353        9020 :             currentWayMinusEdges.insert(currentWayMinusEdges.begin(), currentWayEdges.rbegin(), currentWayEdges.rbegin() + foundForward);
     354             :             fakeMinus = true;
     355             :         }
     356             : #ifdef DEBUG_CONSTRUCT_ROUTE
     357             :         if (pTLine->getLineID() == DEBUGLINEID) {
     358             :             std::cout << " way=" << (*it3)
     359             :                       << " done=" << toString(edges)
     360             :                       << " first=" << Named::getIDSecure(first)
     361             :                       << " last=" << Named::getIDSecure(last)
     362             :                       << "\n    +=" << toString(currentWayEdges)
     363             :                       << "\n    -=" << toString(currentWayMinusEdges)
     364             :                       << "\n   p+=" << toString(prevWayEdges)
     365             :                       << "\n   p-=" << toString(prevWayMinusEdges)
     366             :                       << "\n";
     367             :         }
     368             : #endif
     369       22155 :         if (currentWayEdges.empty()) {
     370         239 :             continue;
     371             :         }
     372       21916 :         if (last == currentWayEdges.front()->getFromNode() && last != nullptr) {
     373       17499 :             if (!prevWayEdges.empty()) {
     374        1248 :                 edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
     375             :                 prevWayEdges.clear();
     376             :                 prevWayMinusEdges.clear();
     377             :             }
     378       17499 :             edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
     379       17499 :             last = currentWayEdges.back()->getToNode();
     380        4417 :         } else if (last == currentWayEdges.back()->getToNode() && last != nullptr) {
     381        2475 :             if (!prevWayEdges.empty()) {
     382          78 :                 edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
     383             :                 prevWayEdges.clear();
     384             :                 prevWayMinusEdges.clear();
     385             :             }
     386        2475 :             if (currentWayMinusEdges.empty()) {
     387             :                 currentWayEdges.clear();
     388             :                 last = nullptr;
     389           3 :                 continue;
     390             :             } else {
     391        2472 :                 edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
     392        2472 :                 if (fakeMinus) {
     393         302 :                     last = currentWayMinusEdges.back()->getFromNode();
     394             :                 } else {
     395        2170 :                     last = currentWayMinusEdges.back()->getToNode();
     396             :                 }
     397             :             }
     398        1942 :         } else if (first == currentWayEdges.front()->getFromNode() && first != nullptr) {
     399          41 :             edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
     400          41 :             edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
     401          41 :             last = currentWayEdges.back()->getToNode();
     402             :             prevWayEdges.clear();
     403             :             prevWayMinusEdges.clear();
     404        1901 :         } else if (first == currentWayEdges.back()->getToNode() && first != nullptr) {
     405         195 :             edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
     406         195 :             if (currentWayMinusEdges.empty()) {
     407             :                 currentWayEdges.clear();
     408             :                 last = nullptr;
     409             :                 prevWayEdges.clear();
     410             :                 prevWayMinusEdges.clear();
     411           1 :                 continue;
     412             :             } else {
     413         194 :                 edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
     414         194 :                 last = currentWayMinusEdges.back()->getToNode();
     415             :                 prevWayEdges.clear();
     416             :                 prevWayMinusEdges.clear();
     417             :             }
     418             :         } else {
     419        1706 :             if (it3 != pTLine->getWays().begin()) {
     420             : #ifdef DEBUG_CONSTRUCT_ROUTE
     421             :                 if (pTLine->getLineID() == DEBUGLINEID) {
     422             :                     std::cout << " way " << (*it3)
     423             :                               << " is not the start of ptline " << pTLine->getLineID()
     424             :                               << " (" + pTLine->getName() + ")\n";
     425             :                 }
     426             : #endif
     427        1519 :             } else if (pTLine->getWays().size() == 1) {
     428             :                 if (currentWayEdges.size() > 0) {
     429          47 :                     edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
     430             :                 } else {
     431             :                     edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
     432             :                 }
     433             :             }
     434        1706 :             prevWayEdges = currentWayEdges;
     435        1706 :             prevWayMinusEdges = currentWayMinusEdges;
     436        1706 :             if (!prevWayEdges.empty()) {
     437        1706 :                 first = prevWayEdges.front()->getFromNode();
     438        1706 :                 last = prevWayEdges.back()->getToNode();
     439             :             } else {
     440             :                 first = nullptr;
     441             :                 last = nullptr;
     442             :             }
     443             :         }
     444             :         currentWayEdges.clear();
     445             :         currentWayMinusEdges.clear();
     446             :     }
     447        1624 :     pTLine->setEdges(edges);
     448        1624 : }
     449             : 
     450             : 
     451             : void
     452        9409 : NBPTLineCont::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
     453             :     //std::cout << " replaceEdge " << edgeID << " replacement=" << toString(replacement) << "\n";
     454        9409 :     if (myPTLines.size() > 0 && myPTLineLookup.size() == 0) {
     455             :         // init lookup once
     456        1517 :         for (auto& item : myPTLines) {
     457       32650 :             for (const NBEdge* e : item.second->getRoute()) {
     458       31239 :                 myPTLineLookup[e->getID()].insert(item.second);
     459             :             }
     460             :         }
     461             :     }
     462       19037 :     for (NBPTLine* line : myPTLineLookup[edgeID]) {
     463        9628 :         line->replaceEdge(edgeID, replacement);
     464       19758 :         for (const NBEdge* e : replacement) {
     465       10130 :             myPTLineLookup[e->getID()].insert(line);
     466             :         }
     467             :     }
     468             :     myPTLineLookup.erase(edgeID);
     469        9409 : }
     470             : 
     471             : 
     472             : std::set<std::string>&
     473           2 : NBPTLineCont::getServedPTStops() {
     474           2 :     return myServedPTStops;
     475             : }
     476             : 
     477             : 
     478             : void
     479          69 : NBPTLineCont::fixBidiStops(const NBEdgeCont& ec) {
     480             :     std::map<std::string, SUMOVehicleClass> types;
     481          69 :     types["bus"] = SVC_BUS;
     482          69 :     types["tram"] = SVC_TRAM;
     483          69 :     types["train"] = SVC_RAIL;
     484          69 :     types["subway"] = SVC_RAIL_URBAN;
     485          69 :     types["light_rail"] = SVC_RAIL_URBAN;
     486          69 :     types["monorail"] = SVC_RAIL_URBAN;
     487          69 :     types["aerialway"] = SVC_RAIL_URBAN;
     488          69 :     types["ferry"] = SVC_SHIP;
     489             : 
     490             :     SUMOAbstractRouter<NBRouterEdge, NBVehicle>* const router = new DijkstraRouter<NBRouterEdge, NBVehicle>(
     491         138 :         ec.getAllRouterEdges(), true, &NBRouterEdge::getTravelTimeStatic, nullptr, true);
     492             : 
     493        1106 :     for (auto& item : myPTLines) {
     494        1037 :         NBPTLine* line = item.second;
     495        1037 :         std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
     496        1037 :         if (stops.size() < 2) {
     497         249 :             continue;
     498             :         }
     499           4 :         if (types.count(line->getType()) == 0) {
     500          12 :             WRITE_WARNINGF(TL("Could not determine vehicle class for public transport line of type '%'."), line->getType());
     501           4 :             continue;
     502             :         }
     503         784 :         NBVehicle veh(line->getRef(), types[line->getType()]);
     504             :         std::vector<std::shared_ptr<NBPTStop> > newStops;
     505             :         std::shared_ptr<NBPTStop> from = nullptr;
     506        3877 :         for (auto it = stops.begin(); it != stops.end(); ++it) {
     507             :             std::shared_ptr<NBPTStop> to = *it;
     508             :             std::shared_ptr<NBPTStop> used = *it;
     509        3093 :             if (to->getBidiStop() != nullptr) {
     510             :                 double best = std::numeric_limits<double>::max();
     511             :                 std::shared_ptr<NBPTStop> to2 = to->getBidiStop();
     512         331 :                 if (from == nullptr) {
     513          83 :                     if ((it + 1) != stops.end()) {
     514             :                         from = to;
     515             :                         std::shared_ptr<NBPTStop> from2 = to2;
     516             :                         to = *(it + 1);
     517         249 :                         const double c1 = getCost(ec, *router, from, to, &veh);
     518         249 :                         const double c2 = getCost(ec, *router, from2, to, &veh);
     519             :                         //std::cout << " from=" << from->getID() << " to=" << to->getID() << " c1=" << MIN2(10000.0, c1) << "\n";
     520             :                         //std::cout << " from2=" << from2->getID() << " to=" << to->getID() << " c2=" << MIN2(10000.0, c2) << "\n";
     521             :                         best = c1;
     522          83 :                         if (to->getBidiStop() != nullptr) {
     523          61 :                             to2 = to->getBidiStop();
     524         183 :                             const double c3 = getCost(ec, *router, from, to2, &veh);
     525         122 :                             const double c4 = getCost(ec, *router, from2, to2, &veh);
     526             :                             //std::cout << " from=" << from->getID() << " to2=" << to2->getID() << " c3=" << MIN2(10000.0, c3) << "\n";
     527             :                             //std::cout << " from2=" << from2->getID() << " to2=" << to2->getID() << " c4=" << MIN2(10000.0, c4) << "\n";
     528          61 :                             if (c2 < best) {
     529             :                                 used = from2;
     530             :                                 best = c2;
     531             :                             }
     532          61 :                             if (c3 < best) {
     533             :                                 used = from;
     534             :                                 best = c3;
     535             :                             }
     536          61 :                             if (c4 < best) {
     537             :                                 used = from2;
     538             :                                 best = c4;
     539             :                             }
     540             :                         } else {
     541          22 :                             if (c2 < c1) {
     542             :                                 used = from2;
     543             :                                 best = c2;
     544             :                             } else {
     545             :                                 best = c1;
     546             :                             }
     547             :                         }
     548             :                     }
     549             :                 } else {
     550         744 :                     const double c1 = getCost(ec, *router, from, to, &veh);
     551         496 :                     const double c2 = getCost(ec, *router, from, to2, &veh);
     552             :                     //std::cout << " from=" << from->getID() << " to=" << to->getID() << " c1=" << MIN2(10000.0, c1) << "\n";
     553             :                     //std::cout << " from=" << from->getID() << " t2o=" << to2->getID() << " c2=" << MIN2(10000.0, c2) << "\n";
     554         248 :                     if (c2 < c1) {
     555             :                         used = to2;
     556             :                         best = c2;
     557             :                     } else {
     558             :                         best = c1;
     559             :                     }
     560             : 
     561             :                 }
     562         331 :                 if (best < std::numeric_limits<double>::max()) {
     563             :                     from = used;
     564             :                 } else {
     565          12 :                     WRITE_WARNINGF(TL("Could not determine direction for line '%' at stop '%'."), line->getLineID(), used->getID());
     566             :                 }
     567             :             }
     568             :             from = used;
     569        3093 :             newStops.push_back(used);
     570             :         }
     571             :         assert(stops.size() == newStops.size());
     572        1568 :         line->replaceStops(newStops);
     573        1821 :     }
     574          69 :     delete router;
     575          69 : }
     576             : 
     577             : 
     578             : void
     579        1835 : NBPTLineCont::removeInvalidEdges(const NBEdgeCont& ec) {
     580        3297 :     for (auto& item : myPTLines) {
     581        1462 :         item.second->removeInvalidEdges(ec);
     582             :     }
     583        1835 : }
     584             : 
     585             : 
     586             : void
     587        1835 : NBPTLineCont::fixPermissions() {
     588        3297 :     for (auto& item : myPTLines) {
     589        1462 :         NBPTLine* line = item.second;
     590        1462 :         const std::vector<NBEdge*>& route = line->getRoute();
     591             :         const SUMOVehicleClass svc = line->getVClass();
     592       24442 :         for (int i = 1; i < (int)route.size(); i++) {
     593       22980 :             NBEdge* e1 = route[i - 1];
     594       22980 :             NBEdge* e2 = route[i];
     595       22980 :             std::vector<NBEdge::Connection> cons = e1->getConnectionsFromLane(-1, e2, -1);
     596       22980 :             if (cons.size() == 0) {
     597             :                 //WRITE_WARNINGF(TL("Disconnected ptline '%' between edge '%' and edge '%'"), line->getLineID(), e1->getID(), e2->getID());
     598             :             } else {
     599             :                 bool ok = false;
     600       23409 :                 for (const auto& c : cons) {
     601       23407 :                     if ((e1->getPermissions(c.fromLane) & svc) == svc) {
     602             :                         ok = true;
     603             :                         break;
     604             :                     }
     605             :                 }
     606       22439 :                 if (!ok) {
     607           2 :                     int lane = cons[0].fromLane;
     608           2 :                     e1->setPermissions(e1->getPermissions(lane) | svc, lane);
     609             :                 }
     610             :             }
     611       22980 :         }
     612             :     }
     613        1835 : }
     614             : 
     615             : 
     616             : double
     617         784 : NBPTLineCont::getCost(const NBEdgeCont& ec, SUMOAbstractRouter<NBRouterEdge, NBVehicle>& router,
     618             :                       const std::shared_ptr<NBPTStop> from, const std::shared_ptr<NBPTStop> to, const NBVehicle* veh) {
     619         784 :     NBEdge* fromEdge = ec.getByID(from->getEdgeId());
     620         784 :     NBEdge* toEdge = ec.getByID(to->getEdgeId());
     621         784 :     if (fromEdge == nullptr || toEdge == nullptr) {
     622             :         return std::numeric_limits<double>::max();
     623         784 :     } else if (fromEdge == toEdge) {
     624          34 :         if (from->getEndPos() <= to->getEndPos()) {
     625          29 :             return to->getEndPos() - from->getEndPos();
     626             :         } else {
     627             :             return std::numeric_limits<double>::max();
     628             :         }
     629         750 :     } else if (fromEdge->getBidiEdge() == toEdge) {
     630             :         return std::numeric_limits<double>::max();
     631             :     }
     632             :     std::vector<const NBRouterEdge*> route;
     633         720 :     router.compute(fromEdge, toEdge, veh, 0, route);
     634         720 :     if (route.size() == 0) {
     635             :         return std::numeric_limits<double>::max();
     636             :     } else {
     637         624 :         return router.recomputeCosts(route, veh, 0);
     638             :     }
     639             : }
     640             : 
     641             : 
     642             : std::string
     643          65 : NBPTLineCont::getWayID(const std::string& edgeID) {
     644             :     std::size_t found = edgeID.rfind("#");
     645             :     std::string result = edgeID;
     646          65 :     if (found != std::string::npos) {
     647         102 :         result = edgeID.substr(0, found);
     648             :     }
     649          65 :     if (result[0] == '-') {
     650          44 :         result = result.substr(1);
     651             :     }
     652          65 :     return result;
     653             : }
     654             : 
     655             : 
     656             : /****************************************************************************/

Generated by: LCOV version 1.14