LCOV - code coverage report
Current view: top level - src/netbuild - NBPTLine.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 146 164 89.0 %
Date: 2024-05-06 15:32:35 Functions: 17 18 94.4 %

          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    NBPTLine.cpp
      15             : /// @author  Gregor Laemmel
      16             : /// @author  Nikita Cherednychek
      17             : /// @date    Tue, 20 Mar 2017
      18             : ///
      19             : // The representation of one direction of a single pt line
      20             : /****************************************************************************/
      21             : #include <utils/iodevices/OutputDevice.h>
      22             : 
      23             : #include <utility>
      24             : #include <utils/common/ToString.h>
      25             : #include <utils/common/StringUtils.h>
      26             : #include <utils/common/MsgHandler.h>
      27             : #include "NBEdge.h"
      28             : #include "NBEdgeCont.h"
      29             : #include "NBPTStop.h"
      30             : #include "NBPTStopCont.h"
      31             : #include "NBPTLine.h"
      32             : 
      33             : 
      34             : // ===========================================================================
      35             : // method definitions
      36             : // ===========================================================================
      37        1764 : NBPTLine::NBPTLine(const std::string& id, const std::string& name, const std::string& type, const std::string& ref, int interval, const std::string& nightService,
      38        1764 :                    SUMOVehicleClass vClass, RGBColor color) :
      39        1764 :     myName(name),
      40        1764 :     myType(type),
      41        1764 :     myPTLineId(id),
      42        1764 :     myRef(ref != "" ? ref : name),
      43        1764 :     myColor(color),
      44        1764 :     myInterval(interval),
      45        1764 :     myNightService(nightService),
      46        1764 :     myVClass(vClass),
      47        1764 :     myNumOfStops(0),
      48        1764 :     myMissingStopsBefore(0),
      49        1764 :     myMissingStopsAfter(0)
      50        1764 : { }
      51             : 
      52             : 
      53             : void
      54        4300 : NBPTLine::addPTStop(std::shared_ptr<NBPTStop> pStop) {
      55       18330 :     if (!myPTStops.empty() && pStop->getName() != "" && myPTStops.back()->getName() == pStop->getName()) {
      56             :         // avoid duplicate stop when both platform and stop_position are given as nodes
      57         118 :         if (myPTStops.back()->isPlatform() && !pStop->isPlatform()) {
      58             :             myPTStops.pop_back();
      59         108 :         } else if (pStop->isPlatform()) {
      60             :             return;
      61             :         }
      62             :     }
      63        4214 :     myPTStops.push_back(pStop);
      64             : }
      65             : 
      66             : 
      67             : const std::vector<std::shared_ptr<NBPTStop> >&
      68       51540 : NBPTLine::getStops() {
      69       51540 :     return myPTStops;
      70             : }
      71             : 
      72             : 
      73             : void
      74         437 : NBPTLine::write(OutputDevice& device) {
      75         437 :     device.openTag(SUMO_TAG_PT_LINE);
      76         437 :     device.writeAttr(SUMO_ATTR_ID, myPTLineId);
      77         437 :     if (!myName.empty()) {
      78         870 :         device.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(myName));
      79             :     }
      80             : 
      81         437 :     device.writeAttr(SUMO_ATTR_LINE, StringUtils::escapeXML(myRef));
      82         437 :     device.writeAttr(SUMO_ATTR_TYPE, myType);
      83         437 :     device.writeAttr(SUMO_ATTR_VCLASS, toString(myVClass));
      84         437 :     if (myInterval > 0) {
      85             :         // write seconds
      86         306 :         device.writeAttr(SUMO_ATTR_PERIOD, 60 * myInterval);
      87             :     }
      88         437 :     if (myNightService != "") {
      89          20 :         device.writeAttr("nightService", myNightService);
      90             :     }
      91             : 
      92         437 :     if (myColor.isValid()) {
      93             :         device.writeAttr(SUMO_ATTR_COLOR, myColor);
      94             :     }
      95         437 :     device.writeAttr("completeness", (double)myPTStops.size() / myNumOfStops);
      96         437 :     if (myMissingStopsBefore != 0) {
      97         670 :         device.writeAttr("missingBefore", myMissingStopsBefore);
      98             :     }
      99         437 :     if (myMissingStopsAfter != 0) {
     100         686 :         device.writeAttr("missingAfter", myMissingStopsAfter);
     101             :     }
     102             : 
     103         437 :     if (!myRoute.empty()) {
     104         394 :         device.openTag(SUMO_TAG_ROUTE);
     105         394 :         device.writeAttr(SUMO_ATTR_EDGES, myRoute);
     106         788 :         device.closeTag();
     107             :     }
     108             : 
     109        1811 :     for (auto& myPTStop : myPTStops) {
     110        1374 :         device.openTag(SUMO_TAG_BUS_STOP);
     111        2748 :         device.writeAttr(SUMO_ATTR_ID, myPTStop->getID());
     112        2748 :         device.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(myPTStop->getName()));
     113        2748 :         device.closeTag();
     114             :     }
     115         437 :     device.closeTag();
     116             : 
     117         437 : }
     118             : 
     119             : 
     120             : void
     121      138896 : NBPTLine::addWayNode(long long int way, long long int node) {
     122      138896 :     std::string wayStr = toString(way);
     123      138896 :     if (wayStr != myCurrentWay) {
     124             :         myCurrentWay = wayStr;
     125       22138 :         myWays.push_back(wayStr);
     126             :     }
     127      138896 :     myWayNodes[wayStr].push_back(node);
     128      138896 : }
     129             : 
     130             : 
     131             : const std::vector<long long int>*
     132       10275 : NBPTLine::getWayNodes(std::string wayId) {
     133       10275 :     if (myWayNodes.find(wayId) != myWayNodes.end()) {
     134       10275 :         return &myWayNodes[wayId];
     135             :     }
     136             :     return nullptr;
     137             : }
     138             : 
     139             : 
     140             : void
     141        1636 : NBPTLine::setEdges(const std::vector<NBEdge*>& edges) {
     142        1636 :     myRoute = edges;
     143             :     // ensure permissions
     144       49037 :     for (NBEdge* e : edges) {
     145       47401 :         SVCPermissions permissions = e->getPermissions();
     146       47401 :         if ((permissions & myVClass) != myVClass) {
     147             :             SVCPermissions nVuln = ~(SVC_PEDESTRIAN | SVC_BICYCLE);
     148          78 :             if (permissions != 0 && (permissions & nVuln) == 0) {
     149             :                 // this is a footpath or sidewalk. Add another lane
     150           7 :                 e->addRestrictedLane(SUMO_const_laneWidth, myVClass);
     151             :             } else {
     152             :                 // add permissions to the rightmost lane that is not exclusively used for pedestrians / bicycles
     153          71 :                 for (int i = 0; i < (int)e->getNumLanes(); i++) {
     154          71 :                     if ((e->getPermissions(i) & nVuln) != 0) {
     155          71 :                         e->allowVehicleClass(i, myVClass);
     156             :                         break;
     157             :                     }
     158             :                 }
     159             :             }
     160             :         }
     161             :     }
     162        1636 : }
     163             : 
     164             : 
     165             : void
     166        1765 : NBPTLine::setNumOfStops(int numStops, int missingBefore, int missingAfter) {
     167        1765 :     myNumOfStops = numStops;
     168        1765 :     myMissingStopsBefore = missingBefore;
     169        1765 :     myMissingStopsAfter = missingAfter;
     170        1765 : }
     171             : 
     172             : 
     173             : const std::vector<NBEdge*>&
     174        4314 : NBPTLine::getRoute() const {
     175        4314 :     return myRoute;
     176             : }
     177             : 
     178             : 
     179             : std::vector<std::pair<NBEdge*, std::string> >
     180         240 : NBPTLine::getStopEdges(const NBEdgeCont& ec) const {
     181             :     std::vector<std::pair<NBEdge*, std::string> > result;
     182        1201 :     for (std::shared_ptr<NBPTStop> stop : myPTStops) {
     183         961 :         NBEdge* e = ec.retrieve(stop->getEdgeId());
     184         961 :         if (e != nullptr) {
     185        1922 :             result.push_back({e, stop->getID()});
     186             :         }
     187             :     }
     188         240 :     return result;
     189           0 : }
     190             : 
     191             : 
     192             : NBEdge*
     193         240 : NBPTLine::getRouteStart(const NBEdgeCont& ec) const {
     194             :     std::vector<NBEdge*> validEdges;
     195             :     // filter out edges that have been removed due to joining junctions
     196        8924 :     for (NBEdge* e : myRoute) {
     197        8684 :         if (ec.retrieve(e->getID())) {
     198        8684 :             validEdges.push_back(e);
     199             :         }
     200             :     }
     201         240 :     if (validEdges.size() == 0) {
     202             :         return nullptr;
     203             :     }
     204             :     // filter out edges after the first stop
     205         228 :     if (myPTStops.size() > 0) {
     206         227 :         NBEdge* firstStopEdge = ec.retrieve(myPTStops.front()->getEdgeId());
     207         227 :         if (firstStopEdge == nullptr) {
     208           0 :             WRITE_WARNINGF(TL("Could not retrieve edge '%' for first stop of line '%'."), myPTStops.front()->getEdgeId(), myPTLineId);
     209          10 :             return nullptr;
     210             : 
     211             :         }
     212         227 :         auto it = std::find(validEdges.begin(), validEdges.end(), firstStopEdge);
     213         227 :         if (it == validEdges.end()) {
     214          40 :             WRITE_WARNINGF(TL("First stop edge '%' is not part of the route of line '%'."), firstStopEdge->getID(), myPTLineId);
     215          10 :             return nullptr;
     216             :         }
     217             :     }
     218         218 :     return validEdges.front();
     219             : }
     220             : 
     221             : 
     222             : NBEdge*
     223         240 : NBPTLine::getRouteEnd(const NBEdgeCont& ec) const {
     224             :     std::vector<NBEdge*> validEdges;
     225             :     // filter out edges that have been removed due to joining junctions
     226        8924 :     for (NBEdge* e : myRoute) {
     227        8684 :         if (ec.retrieve(e->getID())) {
     228        8684 :             validEdges.push_back(e);
     229             :         }
     230             :     }
     231         240 :     if (validEdges.size() == 0) {
     232             :         return nullptr;
     233             :     }
     234             :     // filter out edges after the last stop
     235         228 :     if (myPTStops.size() > 0) {
     236         227 :         NBEdge* lastStopEdge = ec.retrieve(myPTStops.back()->getEdgeId());
     237         227 :         if (lastStopEdge == nullptr) {
     238           0 :             WRITE_WARNINGF(TL("Could not retrieve edge '%' for last stop of line '%'."), myPTStops.back()->getEdgeId(), myPTLineId);
     239          15 :             return nullptr;
     240             : 
     241             :         }
     242         227 :         auto it = std::find(validEdges.begin(), validEdges.end(), lastStopEdge);
     243         227 :         if (it == validEdges.end()) {
     244          60 :             WRITE_WARNINGF(TL("Last stop edge '%' is not part of the route of line '%'."), lastStopEdge->getID(), myPTLineId);
     245          15 :             return nullptr;
     246             :         }
     247             :     }
     248         213 :     return validEdges.back();
     249             : }
     250             : 
     251             : 
     252             : bool
     253         233 : NBPTLine::isConsistent(std::vector<NBEdge*> stops) const {
     254         233 :     if (myRoute.empty() || stops.empty()) {
     255             :         return true;
     256             :     }
     257         220 :     if (stops.size() > 1 && stops.front() == stops.back()) {
     258             :         // circular route where we don't expect the route edges to occur twice
     259          11 :         if (myRoute.front() == stops.front()) {
     260             :             stops.pop_back();
     261           2 :         } else if (myRoute.back() == stops.back()) {
     262             :             stops.erase(stops.begin());
     263             :         }
     264             :     }
     265             :     std::vector<NBEdge*>::const_iterator stopIt = stops.begin();
     266        7812 :     for (const NBEdge* const e : myRoute) {
     267        8700 :         while (stopIt != stops.end() && e == *stopIt) {
     268             :             ++stopIt;
     269             :         }
     270        7799 :         if (stopIt == stops.end()) {
     271             :             return true;
     272             :         }
     273             :     }
     274             :     return false;
     275             : }
     276             : 
     277             : 
     278             : void
     279          54 : NBPTLine::replaceStop(std::shared_ptr<NBPTStop> oldStop, std::shared_ptr<NBPTStop> newStop) {
     280         404 :     for (int i = 0; i < (int)myPTStops.size(); i++) {
     281         350 :         if (myPTStops[i] == oldStop) {
     282             :             myPTStops[i] = newStop;
     283             :         }
     284             :     }
     285          54 : }
     286             : 
     287             : 
     288             : void
     289        9628 : NBPTLine::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
     290        9628 :     EdgeVector oldRoute = myRoute;
     291             :     myRoute.clear();
     292      393216 :     for (NBEdge* e : oldRoute) {
     293      383588 :         if (e->getID() == edgeID) {
     294       19818 :             for (NBEdge* e2 : replacement) {
     295       10160 :                 if (myRoute.empty() || myRoute.back() != e2) {
     296         880 :                     myRoute.push_back(e2);
     297             :                 }
     298             :             }
     299             :         } else {
     300      373930 :             myRoute.push_back(e);
     301             :         }
     302             :     }
     303        9628 : }
     304             : 
     305             : 
     306             : void
     307        1685 : NBPTLine::deleteInvalidStops(const NBEdgeCont& ec, const NBPTStopCont& sc) {
     308             :     // delete stops that are missing or have no edge
     309        6811 :     for (auto it = myPTStops.begin(); it != myPTStops.end();) {
     310             :         std::shared_ptr<NBPTStop> stop = *it;
     311       15379 :         if (sc.get(stop->getID()) == nullptr ||
     312        5122 :                 ec.getByID(stop->getEdgeId()) == nullptr) {
     313         462 :             WRITE_WARNINGF(TL("Removed invalid stop '%' from line '%'."), stop->getID(), getLineID());
     314         154 :             it = myPTStops.erase(it);
     315             :         } else {
     316             :             it++;
     317             :         }
     318             : 
     319             :     }
     320        1685 : }
     321             : 
     322             : 
     323             : void
     324           0 : NBPTLine::deleteDuplicateStops() {
     325             :     // delete subsequent stops that belong to the same stopArea
     326           0 :     long long int lastAreaID = -1;
     327           0 :     std::string lastName = "";
     328           0 :     for (auto it = myPTStops.begin(); it != myPTStops.end();) {
     329             :         std::shared_ptr<NBPTStop> stop = *it;
     330           0 :         if (lastAreaID != -1 && stop->getAreaID() == lastAreaID) {
     331           0 :             WRITE_WARNINGF(TL("Removed duplicate stop '%' at area '%' from line '%'."), stop->getID(), toString(lastAreaID), getLineID());
     332           0 :             it = myPTStops.erase(it);
     333           0 :         } else if (lastName != "" && stop->getName() == lastName) {
     334           0 :             WRITE_WARNINGF(TL("Removed duplicate stop '%' named '%' from line '%'."), stop->getID(), lastName, getLineID());
     335           0 :             it = myPTStops.erase(it);
     336             :         } else {
     337             :             it++;
     338             :         }
     339           0 :         lastAreaID = stop->getAreaID();
     340           0 :         lastName = stop->getName();
     341             :     }
     342           0 : }
     343             : 
     344             : 
     345             : void
     346        1462 : NBPTLine::removeInvalidEdges(const NBEdgeCont& ec) {
     347       29791 :     for (int i = 0; i < (int)myRoute.size();) {
     348       28329 :         const std::pair<NBEdge*, NBEdge*>* split = ec.getSplit(myRoute[i]);
     349             :         if (split != nullptr) {
     350           0 :             myRoute[i] = split->first;
     351           0 :             myRoute.insert(myRoute.begin() + i + 1, split->second);
     352       28329 :         } else if (ec.retrieve(myRoute[i]->getID()) == nullptr) {
     353        4010 :             myRoute.erase(myRoute.begin() + i);
     354             :         } else {
     355       24319 :             i++;
     356             :         }
     357             :     }
     358        1462 : }
     359             : 
     360             : 
     361             : /****************************************************************************/

Generated by: LCOV version 1.14