LCOV - code coverage report
Current view: top level - src/netimport - NIXMLPTHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.5 % 211 191
Test Date: 2025-11-13 15:38:19 Functions: 92.3 % 13 12

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 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    NIXMLPTHandler.cpp
      15              : /// @author  Jakob Erdmann
      16              : /// @date    Sat, 28 Jul 2018
      17              : ///
      18              : // Importer for static public transport information
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #include <string>
      23              : #include <iostream>
      24              : #include <map>
      25              : #include <cmath>
      26              : #include <utils/xml/SUMOSAXHandler.h>
      27              : #include <utils/xml/SUMOXMLDefinitions.h>
      28              : #include <utils/common/MsgHandler.h>
      29              : #include <utils/common/StringUtils.h>
      30              : #include <utils/common/StringTokenizer.h>
      31              : #include <utils/geom/GeomConvHelper.h>
      32              : #include <utils/common/ToString.h>
      33              : #include <utils/options/OptionsCont.h>
      34              : #include <utils/geom/GeoConvHelper.h>
      35              : #include <netbuild/NBNodeCont.h>
      36              : #include <netbuild/NBTypeCont.h>
      37              : #include <netbuild/NBNetBuilder.h>
      38              : #include <netbuild/NBPTStop.h>
      39              : #include "NIImporter_OpenStreetMap.h"
      40              : #include "NIXMLNodesHandler.h"
      41              : #include "NIXMLPTHandler.h"
      42              : 
      43              : 
      44              : // ===========================================================================
      45              : // method definitions
      46              : // ===========================================================================
      47         3886 : NIXMLPTHandler::NIXMLPTHandler(NBEdgeCont& ec, NBPTStopCont& sc, NBPTLineCont& lc) :
      48              :     SUMOSAXHandler("public transport - file"),
      49         3886 :     myEdgeCont(ec),
      50         3886 :     myStopCont(sc),
      51         3886 :     myLineCont(lc),
      52              :     myCurrentStop(nullptr),
      53         3886 :     myCurrentLine(nullptr),
      54         3886 :     myCurrentCompletion(0),
      55         7772 :     myCurrentStopWasIgnored(false)
      56         3886 : { }
      57              : 
      58              : 
      59        11658 : NIXMLPTHandler::~NIXMLPTHandler() {}
      60              : 
      61              : 
      62              : void
      63          218 : NIXMLPTHandler::myStartElement(int element,
      64              :                                const SUMOSAXAttributes& attrs) {
      65          218 :     switch (element) {
      66          123 :         case SUMO_TAG_BUS_STOP:
      67              :         case SUMO_TAG_TRAIN_STOP:
      68              :         case SUMO_TAG_STOP:
      69          123 :             if (myCurrentRouteID != "") {
      70            6 :                 addRouteStop(attrs);
      71          117 :             } else if (myCurrentLine == nullptr) {
      72           85 :                 addPTStop(attrs);
      73              :             } else {
      74           32 :                 addPTLineStop(attrs);
      75              :             }
      76              :             break;
      77           10 :         case SUMO_TAG_ACCESS:
      78           10 :             addAccess(attrs);
      79           10 :             break;
      80           17 :         case SUMO_TAG_PT_LINE:
      81           17 :             addPTLine(attrs);
      82           17 :             break;
      83            6 :         case SUMO_TAG_ROUTE:
      84            6 :             if (myCurrentLine == nullptr) {
      85            3 :                 addRoute(attrs);
      86              :             } else {
      87            3 :                 addPTLineRoute(attrs);
      88              :             }
      89              :             break;
      90            3 :         case SUMO_TAG_FLOW:
      91              :         case SUMO_TAG_TRIP:
      92            3 :             addPTLineFromFlow(attrs);
      93            3 :             break;
      94            7 :         case SUMO_TAG_PARAM: {
      95            7 :             bool ok = true;
      96            7 :             const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
      97            7 :             if (myCurrentLine != nullptr) {
      98            6 :                 if (key == "completeness") {
      99            3 :                     myCurrentCompletion = attrs.get<double>(SUMO_ATTR_VALUE, nullptr, ok);
     100            3 :                 } else if (key == "name") {
     101            6 :                     myCurrentLine->setName(attrs.get<std::string>(SUMO_ATTR_VALUE, nullptr, ok));
     102            0 :                 } else if (key == "missingBefore") {
     103            0 :                     myMissingBefore = attrs.get<int>(SUMO_ATTR_VALUE, nullptr, ok);
     104            0 :                 } else if (key == "missingAfter") {
     105            0 :                     myMissingAfter = attrs.get<int>(SUMO_ATTR_VALUE, nullptr, ok);
     106              :                 }
     107            1 :             } else if (myCurrentStop != nullptr) {
     108            1 :                 const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
     109            1 :                 myCurrentStop->setParameter(key, val);
     110              :             }
     111              :         }
     112            7 :         break;
     113              :         default:
     114              :             break;
     115              :     }
     116          218 : }
     117              : 
     118              : void
     119          218 : NIXMLPTHandler::myEndElement(int element) {
     120          218 :     switch (element) {
     121              :         case SUMO_TAG_BUS_STOP:
     122              :         case SUMO_TAG_TRAIN_STOP:
     123              :             myCurrentStop = nullptr;
     124          117 :             myCurrentStopWasIgnored = false;
     125          117 :             break;
     126           20 :         case SUMO_TAG_PT_LINE:
     127              :         case SUMO_TAG_FLOW:
     128              :         case SUMO_TAG_TRIP:
     129           20 :             if (myCurrentLine != nullptr) {
     130           20 :                 myCurrentLine->setNumOfStops((int)((double)myCurrentLine->getStops().size() / myCurrentCompletion), myMissingBefore, myMissingAfter);
     131              :             }
     132           20 :             myCurrentLine = nullptr;
     133           20 :             break;
     134            6 :         case SUMO_TAG_ROUTE:
     135            6 :             myCurrentRouteID = "";
     136              :             break;
     137              :         default:
     138              :             break;
     139              :     }
     140          218 : }
     141              : 
     142              : 
     143              : void
     144           85 : NIXMLPTHandler::addPTStop(const SUMOSAXAttributes& attrs) {
     145           85 :     bool ok = true;
     146           85 :     const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, "busStop", ok);
     147          170 :     const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
     148           85 :     const std::string laneID = attrs.get<std::string>(SUMO_ATTR_LANE, id.c_str(), ok);
     149           85 :     double startPos = attrs.get<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok);
     150           85 :     double endPos = attrs.get<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok);
     151           85 :     const double parkingLength = attrs.getOpt<double>(SUMO_ATTR_PARKING_LENGTH, id.c_str(), ok, 0);
     152           85 :     const RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor(false));
     153              :     //const std::string lines = attrs.get<std::string>(SUMO_ATTR_LINES, id.c_str(), ok);
     154          170 :     const int laneIndex = NBEdge::getLaneIndexFromLaneID(laneID);
     155           85 :     std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(laneID);
     156           85 :     NBEdge* edge = myEdgeCont.retrieve(edgeID);
     157           85 :     if (edge == nullptr) {
     158            6 :         edge = myEdgeCont.retrieve(edgeID, true);
     159            6 :         if (edge != nullptr && myEdgeCont.getSplit(edge) == nullptr) {
     160              :             // splits are treated later
     161              :             edge = nullptr;
     162              :         }
     163              :     }
     164            6 :     if (edge == nullptr) {
     165           10 :         if (!myEdgeCont.wasIgnored(edgeID)) {
     166            0 :             WRITE_ERRORF(TL("Edge '%' for stop '%' not found"), edgeID, id);
     167              :         } else {
     168            5 :             myCurrentStopWasIgnored = true;
     169              :             NBPTStopCont::addIgnored(id);
     170              :         }
     171            5 :         return;
     172              :     }
     173           80 :     if (edge->getNumLanes() <= laneIndex) {
     174            0 :         WRITE_ERRORF(TL("Lane '%' for stop '%' not found"), laneID, id);
     175            0 :         return;
     176              :     }
     177           80 :     SVCPermissions permissions = edge->getPermissions(laneIndex);
     178              :     // possibly the stops were written for a different network. If the lane is not a typical public transport stop lane, assume bus as the default
     179           80 :     if (!isRailway(permissions) && permissions != SVC_SHIP && permissions != SVC_TAXI) {
     180            9 :         permissions = SVC_BUS;
     181              :     }
     182           80 :     if (ok) {
     183           80 :         if (startPos < 0) {
     184            1 :             startPos += edge->getLoadedLength();
     185              :         }
     186           80 :         if (endPos < 0) {
     187            5 :             endPos += edge->getLoadedLength();
     188              :         }
     189          160 :         if (myEdgeCont.wasRemoved(edgeID) && (
     190            4 :                     startPos >= endPos || startPos < 0 || endPos < 0
     191            4 :                     || startPos >= edge->getLoadedLength()
     192            1 :                     || endPos >= edge->getLoadedLength())) {
     193            3 :             NBEdge* longest = myEdgeCont.getSplitBase(edgeID);
     194            3 :             if (longest != nullptr) {
     195              :                 edge = longest;
     196              :             }
     197              :         }
     198           80 :         Position pos = edge->geometryPositionAtOffset((startPos + endPos) / 2);
     199           80 :         myCurrentStop = std::make_shared<NBPTStop>(id, pos, edgeID, edgeID, endPos - startPos, name, permissions, parkingLength, color, startPos);
     200           85 :         while (myEdgeCont.getSplit(edge) != nullptr) {
     201              :             myCurrentStop->resetLoaded();
     202            5 :             const std::pair<NBEdge*, NBEdge*> split = *myEdgeCont.getSplit(edge);
     203            5 :             if (myCurrentStop->replaceEdge(edgeID, {split.first, split.second})) {
     204            5 :                 edge = split.first->getID() == myCurrentStop->getEdgeId() ? split.first : split.second;
     205            5 :                 edgeID = edge->getID();
     206              :             }
     207              :         }
     208          160 :         if (!myStopCont.insert(myCurrentStop)) {
     209            0 :             WRITE_ERRORF(TL("Could not add public transport stop '%' (already exists)"), id);
     210              :         }
     211              :     }
     212              : }
     213              : 
     214              : void
     215           10 : NIXMLPTHandler::addAccess(const SUMOSAXAttributes& attrs) {
     216           10 :     if (myCurrentStop == nullptr) {
     217            4 :         if (myCurrentStopWasIgnored) {
     218            5 :             return;
     219              :         } else {
     220            0 :             throw InvalidArgument("Could not add access outside a stopping place.");
     221              :         }
     222              :     }
     223            6 :     bool ok = true;
     224            6 :     const std::string laneID = attrs.get<std::string>(SUMO_ATTR_LANE, "access", ok);
     225            6 :     const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(laneID);
     226            6 :     if (myEdgeCont.retrieve(edgeID) == nullptr) {
     227            2 :         if (!myEdgeCont.wasIgnored(edgeID)) {
     228            0 :             WRITE_ERRORF(TL("Edge '%' for access to stop '%' not found"), edgeID, myCurrentStop->getID());
     229              :         }
     230              :         return;
     231              :     }
     232            5 :     const double pos = attrs.get<double>(SUMO_ATTR_POSITION, "access", ok);
     233            5 :     const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
     234            5 :     if (ok) {
     235           10 :         myCurrentStop->addAccess(laneID, pos, length);
     236              :     }
     237              : }
     238              : 
     239              : 
     240              : void
     241           17 : NIXMLPTHandler::addPTLine(const SUMOSAXAttributes& attrs) {
     242           17 :     bool ok = true;
     243           17 :     const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, "ptLine", ok);
     244           17 :     const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
     245           17 :     const std::string line = attrs.getOpt<std::string>(SUMO_ATTR_LINE, id.c_str(), ok, "");
     246           17 :     const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
     247           17 :     SUMOVehicleClass vClass = NIImporter_OpenStreetMap::interpretTransportType(type);
     248           17 :     if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
     249            0 :         vClass = getVehicleClassID(attrs.get<std::string>(SUMO_ATTR_VCLASS, id.c_str(), ok));
     250              :     }
     251           17 :     RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor(false));
     252           17 :     const int intervalS = attrs.getOpt<int>(SUMO_ATTR_PERIOD, id.c_str(), ok, -1);
     253           34 :     const std::string nightService = attrs.getStringSecure("nightService", "");
     254           34 :     myCurrentCompletion = StringUtils::toDouble(attrs.getStringSecure("completeness", "1"));
     255           34 :     myMissingBefore = StringUtils::toInt(attrs.getStringSecure("missingBefore", "0"));
     256           34 :     myMissingAfter = StringUtils::toInt(attrs.getStringSecure("missingAfter", "0"));
     257           17 :     if (ok) {
     258              :         // patching existing line?
     259           17 :         myCurrentLine = myLineCont.retrieve(id);
     260           17 :         if (myCurrentLine == nullptr) {
     261           16 :             myCurrentLine = new NBPTLine(id, name, type, line, intervalS / 60, nightService, vClass, color);
     262           16 :             myLineCont.insert(myCurrentLine);
     263              :         } else {
     264            3 :             WRITE_MESSAGEF(TL("Duplicate ptLine id occurred ('%'); assuming overwriting is wished."), id);
     265            1 :             if (name != "") {
     266            0 :                 myCurrentLine->setName(name);
     267              :             }
     268            1 :             if (line != "") {
     269            0 :                 myCurrentLine->setRef(line);
     270              :             }
     271            1 :             if (intervalS != -1) {
     272            1 :                 myCurrentLine->setPeriod(intervalS);
     273              :             }
     274              :         }
     275              :     }
     276           17 : }
     277              : 
     278              : 
     279              : void
     280            3 : NIXMLPTHandler::addPTLineFromFlow(const SUMOSAXAttributes& attrs) {
     281            3 :     bool ok = true;
     282            3 :     myMissingBefore = 0;
     283            3 :     myMissingAfter = 0;
     284            3 :     const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, "flow", ok);
     285            3 :     const std::string line = attrs.get<std::string>(SUMO_ATTR_LINE, id.c_str(), ok);
     286            3 :     const std::string type = attrs.get<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok);
     287            3 :     const std::string route = attrs.get<std::string>(SUMO_ATTR_ROUTE, id.c_str(), ok);
     288            3 :     SUMOVehicleClass vClass = NIImporter_OpenStreetMap::interpretTransportType(type);
     289            3 :     const int intervalS = attrs.getOpt<int>(SUMO_ATTR_PERIOD, id.c_str(), ok, -1);
     290            3 :     RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor(false));
     291            3 :     if (ok) {
     292            3 :         myCurrentLine = new NBPTLine(id, "", type, line, intervalS / 60, "", vClass, color);
     293            3 :         myCurrentLine->setEdges(myRouteEdges[route]);
     294            9 :         for (std::shared_ptr<NBPTStop> stop : myRouteStops[route]) {
     295           12 :             myCurrentLine->addPTStop(stop);
     296              :         }
     297            3 :         myLineCont.insert(myCurrentLine);
     298              :     }
     299            3 : }
     300              : 
     301              : 
     302              : void
     303            3 : NIXMLPTHandler::addPTLineRoute(const SUMOSAXAttributes& attrs) {
     304            3 :     if (myCurrentLine == nullptr) {
     305            0 :         WRITE_ERROR(TL("Found route outside line definition"));
     306            0 :         return;
     307              :     }
     308            3 :     bool ok = true;
     309            3 :     const std::vector<std::string>& edgeIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, nullptr, ok);
     310              :     EdgeVector edges;
     311           10 :     for (const std::string& edgeID : edgeIDs) {
     312            7 :         NBEdge* edge = myEdgeCont.retrieve(edgeID);
     313            7 :         if (edge == nullptr) {
     314            2 :             if (!myEdgeCont.wasIgnored(edgeID)) {
     315            0 :                 WRITE_ERRORF(TL("Edge '%' in route of line '%' not found"), edgeID, myCurrentLine->getName());
     316              :             }
     317              :         } else {
     318            6 :             edges.push_back(edge);
     319              :         }
     320              :     }
     321            3 :     myCurrentLine->setEdges(edges);
     322            3 : }
     323              : 
     324              : 
     325              : void
     326            3 : NIXMLPTHandler::addRoute(const SUMOSAXAttributes& attrs) {
     327            3 :     bool ok = true;
     328            6 :     myCurrentRouteID = attrs.get<std::string>(SUMO_ATTR_ID, "route", ok);
     329            3 :     const std::vector<std::string>& edgeIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, myCurrentRouteID.c_str(), ok);
     330              :     EdgeVector edges;
     331            9 :     for (const std::string& edgeID : edgeIDs) {
     332            6 :         NBEdge* edge = myEdgeCont.retrieve(edgeID);
     333            6 :         if (edge == nullptr) {
     334            0 :             if (!myEdgeCont.wasIgnored(edgeID)) {
     335            0 :                 WRITE_ERRORF(TL("Edge '%' in route of line '%' not found"), edgeID, myCurrentLine->getName());
     336              :             }
     337              :         } else {
     338            6 :             edges.push_back(edge);
     339              :         }
     340              :     }
     341            3 :     myRouteEdges[myCurrentRouteID] = edges;
     342            3 : }
     343              : 
     344              : 
     345              : void
     346           32 : NIXMLPTHandler::addPTLineStop(const SUMOSAXAttributes& attrs) {
     347           32 :     bool ok = true;
     348           32 :     const std::string id = attrs.hasAttribute(SUMO_ATTR_ID)
     349           32 :                            ? attrs.get<std::string>(SUMO_ATTR_ID, "ptLine", ok)
     350           32 :                            : attrs.get<std::string>(SUMO_ATTR_BUS_STOP, "ptline", ok);
     351           96 :     std::shared_ptr<NBPTStop> stop = myStopCont.get(id);
     352           32 :     if (stop == nullptr) {
     353            1 :         if (!NBPTStopCont::wasIgnored(id)) {
     354            0 :             WRITE_ERRORF(TL("Stop '%' within line '%' not found"), id, toString(myCurrentLine->getLineID()));
     355              :         }
     356              :         return;
     357              :     }
     358           62 :     myCurrentLine->addPTStop(stop);
     359              : }
     360              : 
     361              : void
     362            6 : NIXMLPTHandler::addRouteStop(const SUMOSAXAttributes& attrs) {
     363              :     assert(myCurrentRouteID != "");
     364            6 :     bool ok = true;
     365            6 :     const std::string id = attrs.hasAttribute(SUMO_ATTR_ID)
     366            6 :                            ? attrs.get<std::string>(SUMO_ATTR_ID, "ptLine", ok)
     367            6 :                            : attrs.get<std::string>(SUMO_ATTR_BUS_STOP, "ptline", ok);
     368           18 :     std::shared_ptr<NBPTStop> stop = myStopCont.get(id);
     369            6 :     if (stop == nullptr) {
     370            0 :         WRITE_ERRORF(TL("Stop '%' within route '%' not found"), id, toString(myCurrentRouteID));
     371              :         return;
     372              :     }
     373            6 :     myRouteStops[myCurrentRouteID].push_back(stop);
     374              : }
     375              : 
     376              : 
     377              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1