LCOV - code coverage report
Current view: top level - src/utils/vehicle - SUMORouteHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.5 % 347 335
Test Date: 2026-07-25 16:16:11 Functions: 91.7 % 12 11

            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    SUMORouteHandler.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Sascha Krieg
      18              : /// @author  Michael Behrisch
      19              : /// @date    Mon, 9 Jul 2001
      20              : ///
      21              : // Parser for routes during their loading
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <utils/common/MsgHandler.h>
      26              : #include <utils/common/FileHelpers.h>
      27              : #include <utils/options/OptionsCont.h>
      28              : #include <utils/vehicle/SUMOVTypeParameter.h>
      29              : #include <utils/vehicle/SUMOVehicleParserHelper.h>
      30              : #include <utils/xml/XMLSubSys.h>
      31              : 
      32              : #include "SUMORouteHandler.h"
      33              : 
      34              : 
      35              : // ===========================================================================
      36              : // method definitions
      37              : // ===========================================================================
      38              : 
      39        83449 : SUMORouteHandler::SUMORouteHandler(const std::string& file, const std::string& expectedRoot, const bool hardFail) :
      40              :     SUMOSAXHandler(file, expectedRoot),
      41        83449 :     myHardFail(hardFail),
      42        83449 :     myVehicleParameter(nullptr),
      43        83449 :     myLastDepart(-1),
      44        83449 :     myActiveRouteColor(nullptr),
      45        83449 :     myCurrentCosts(0.),
      46        83449 :     myCurrentVType(nullptr),
      47        83449 :     myCurrentVTypeProbability(-1),
      48       250345 :     myBeginDefault(OptionsCont::getOptions().exists("begin") ? string2time(OptionsCont::getOptions().getString("begin")) : 0),
      49       250345 :     myEndDefault(OptionsCont::getOptions().exists("end") ? string2time(OptionsCont::getOptions().getString("end")) : -1),
      50        83449 :     myFirstDepart(-1),
      51        83449 :     myInsertStopEdgesAt(-1),
      52       166898 :     myAllowInternalRoutes(false) {
      53        83449 : }
      54              : 
      55              : 
      56        83005 : SUMORouteHandler::~SUMORouteHandler() {
      57        83005 :     delete myVehicleParameter;
      58        83005 :     delete myCurrentVType;
      59        83005 : }
      60              : 
      61              : 
      62              : bool
      63       613477 : SUMORouteHandler::checkLastDepart() {
      64       613477 :     if (myVehicleParameter->departProcedure == DepartDefinition::GIVEN) {
      65       612537 :         if (myVehicleParameter->depart < myLastDepart) {
      66           16 :             WRITE_WARNINGF(TL("Route file should be sorted by departure time, ignoring '%'!"), myVehicleParameter->id);
      67            8 :             return false;
      68              :         }
      69              :     }
      70              :     return true;
      71              : }
      72              : 
      73              : 
      74              : void
      75       661980 : SUMORouteHandler::registerLastDepart() {
      76              :     // register only non public transport to parse all public transport lines in advance
      77       661980 :     if (myVehicleParameter && myVehicleParameter->line == "" && myVehicleParameter->departProcedure == DepartDefinition::GIVEN) {
      78       656122 :         myLastDepart = myVehicleParameter->depart;
      79       656122 :         if (myFirstDepart == -1) {
      80        42020 :             myFirstDepart = myLastDepart;
      81              :         }
      82              :     }
      83              :     // else: we don't know when this vehicle will depart. keep the previous known depart time
      84       661980 : }
      85              : 
      86              : 
      87              : void
      88     11669317 : SUMORouteHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
      89     11669317 :     myElementStack.push_back(element);
      90     11669317 :     switch (element) {
      91       404395 :         case SUMO_TAG_VEHICLE:
      92              :         case SUMO_TAG_PERSON:
      93              :         case SUMO_TAG_CONTAINER:
      94              :             // if myVehicleParameter is nullptr this will do nothing
      95       404395 :             delete myVehicleParameter;
      96              :             // we set to nullptr to have a consistent state if the parsing fails
      97       404395 :             myVehicleParameter = nullptr;
      98       404395 :             myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(element, attrs, myHardFail, false, false, myAllowInternalRoutes);
      99       404135 :             myParamStack.push_back(myVehicleParameter);
     100       404135 :             if (element != SUMO_TAG_VEHICLE) {
     101        47096 :                 addTransportable(attrs, element == SUMO_TAG_PERSON);
     102              :             }
     103              :             break;
     104        22314 :         case SUMO_TAG_FLOW:
     105              :             // delete if myVehicleParameter isn't null
     106        22314 :             if (myVehicleParameter) {
     107            0 :                 delete myVehicleParameter;
     108            0 :                 myVehicleParameter = nullptr;
     109              :             }
     110              :             // parse vehicle parameters
     111              :             // might be called to parse vehicles from additional file in the
     112              :             // context of quickReload. In this case, rerouter flows must be ignored
     113        22314 :             if (myElementStack.size() == 1 || myElementStack[myElementStack.size() - 2] != SUMO_TAG_CALIBRATOR) {
     114        22314 :                 myVehicleParameter = SUMOVehicleParserHelper::parseFlowAttributes(SUMO_TAG_FLOW, attrs, myHardFail, true, myBeginDefault, myEndDefault, myAllowInternalRoutes);
     115              :             }
     116              :             // check if myVehicleParameter was successfully created
     117        22196 :             if (myVehicleParameter) {
     118              :                 // check tag
     119        22196 :                 if (myVehicleParameter->routeid.empty()) {
     120              :                     // open a route flow (It could be a flow with embedded route)
     121        12754 :                     openFlow(attrs);
     122              :                 } else {
     123              :                     // open a route flow
     124         9442 :                     openRouteFlow(attrs);
     125              :                 }
     126        22196 :                 myParamStack.push_back(myVehicleParameter);
     127              :             }
     128              :             break;
     129         2322 :         case SUMO_TAG_PERSONFLOW:
     130              :         case SUMO_TAG_CONTAINERFLOW:
     131              :             // delete if myVehicleParameter isn't null
     132         2322 :             if (myVehicleParameter) {
     133            0 :                 delete myVehicleParameter;
     134            0 :                 myVehicleParameter = nullptr;
     135              :             }
     136              :             // create a new flow
     137         2322 :             myVehicleParameter = SUMOVehicleParserHelper::parseFlowAttributes((SumoXMLTag)element, attrs, myHardFail, true, myBeginDefault, myEndDefault, myAllowInternalRoutes);
     138         2322 :             myParamStack.push_back(myVehicleParameter);
     139         2322 :             break;
     140        64436 :         case SUMO_TAG_VTYPE:
     141              :             // delete if myCurrentVType isn't null
     142        64436 :             if (myCurrentVType != nullptr) {
     143            4 :                 delete myCurrentVType;
     144            4 :                 myCurrentVType = nullptr;
     145              :             }
     146              :             // create a new vType
     147        64436 :             if (attrs.hasAttribute(SUMO_ATTR_REFID) && !attrs.hasAttribute(SUMO_ATTR_ID)) {
     148          122 :                 bool ok = true;
     149          244 :                 myCurrentVTypeRef = attrs.get<std::string>(SUMO_ATTR_REFID, nullptr, ok);
     150          122 :                 myCurrentVTypeProbability = attrs.getOpt<double>(SUMO_ATTR_PROB, myCurrentVTypeRef.c_str(), ok, -1);
     151              :             } else {
     152       128598 :                 myCurrentVType = SUMOVehicleParserHelper::beginVTypeParsing(attrs, myHardFail, getFileName(), getVTypeParameter(attrs.getStringSecure(SUMO_ATTR_REFID, "")));
     153              :             }
     154        64406 :             myParamStack.push_back(myCurrentVType);
     155        64406 :             break;
     156          619 :         case SUMO_TAG_VTYPE_DISTRIBUTION:
     157          619 :             openVehicleTypeDistribution(attrs);
     158          619 :             break;
     159       387558 :         case SUMO_TAG_ROUTE:
     160       387558 :             openRoute(attrs);
     161       387506 :             break;
     162        92418 :         case SUMO_TAG_ROUTE_DISTRIBUTION:
     163        92418 :             openRouteDistribution(attrs);
     164        92418 :             break;
     165        40955 :         case SUMO_TAG_STOP:
     166        40955 :             myParamStack.push_back(addStop(attrs));
     167        40887 :             break;
     168       236479 :         case SUMO_TAG_TRIP: {
     169              :             // delete if myVehicleParameter isn't null
     170       236479 :             if (myVehicleParameter) {
     171            0 :                 delete myVehicleParameter;
     172            0 :                 myVehicleParameter = nullptr;
     173              :             }
     174              :             // parse vehicle parameters
     175       236479 :             myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(element, attrs, myHardFail, false, false, myAllowInternalRoutes);
     176              :             // check if myVehicleParameter was successfully created
     177       236425 :             if (myVehicleParameter) {
     178       236425 :                 myVehicleParameter->parametersSet |= VEHPARS_FORCE_REROUTE;
     179       236425 :                 myActiveRouteID = "!" + myVehicleParameter->id;
     180              :                 // open trip
     181       236425 :                 openTrip(attrs);
     182       236425 :                 myParamStack.push_back(myVehicleParameter);
     183              :             }
     184              :             break;
     185              :         }
     186         5062 :         case SUMO_TAG_PERSONTRIP:
     187         5062 :             addPersonTrip(attrs);
     188         5047 :             break;
     189        40483 :         case SUMO_TAG_WALK:
     190        40483 :             addWalk(attrs);
     191        40463 :             break;
     192           23 :         case SUMO_TAG_INTERVAL: {
     193              :             bool ok;
     194           23 :             myBeginDefault = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok);
     195           23 :             myEndDefault = attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok);
     196              :             break;
     197              :         }
     198         5523 :         case SUMO_TAG_RIDE:
     199         5523 :             addRide(attrs);
     200         5483 :             break;
     201         1875 :         case SUMO_TAG_TRANSPORT:
     202         1875 :             addTransport(attrs);
     203         1859 :             break;
     204         1584 :         case SUMO_TAG_TRANSHIP:
     205         1584 :             addTranship(attrs);
     206         1584 :             break;
     207        57642 :         case SUMO_TAG_PARAM:
     208        57642 :             addParam(attrs);
     209        57642 :             break;
     210     10305629 :         default:
     211              :             // parse embedded car following model information
     212     10305629 :             if (myCurrentVType != nullptr) {
     213           32 :                 WRITE_WARNINGF(TL("Defining car-following parameters in a nested element is deprecated in vType '%', use attributes instead!"), myCurrentVType->id);
     214           16 :                 if (!SUMOVehicleParserHelper::parseCFMParams(myCurrentVType, (SumoXMLTag)element, attrs, true)) {
     215            0 :                     if (myHardFail) {
     216            0 :                         throw ProcessError(TL("Invalid parsing embedded VType"));
     217              :                     } else {
     218            0 :                         WRITE_ERROR(TL("Invalid parsing embedded VType"));
     219              :                     }
     220              :                 }
     221              :             }
     222              :             break;
     223              :     }
     224     11668644 : }
     225              : 
     226              : 
     227              : void
     228     11661512 : SUMORouteHandler::myEndElement(int element) {
     229     11661512 :     switch (element) {
     230        40887 :         case SUMO_TAG_STOP:
     231              :             myParamStack.pop_back();
     232              :             break;
     233       387506 :         case SUMO_TAG_ROUTE:
     234       387506 :             closeRoute();
     235       387452 :             break;
     236        64402 :         case SUMO_TAG_VTYPE:
     237        64402 :             closeVType();
     238        64378 :             if (myCurrentVTypeRef.empty()) {
     239        64256 :                 delete myCurrentVType;
     240              :             }
     241        64378 :             myCurrentVType = nullptr;
     242        64378 :             myCurrentVTypeRef = "";
     243        64378 :             myCurrentVTypeProbability = -1;
     244              :             myParamStack.pop_back();
     245              :             break;
     246        44899 :         case SUMO_TAG_PERSON:
     247        44899 :             closePerson();
     248        44873 :             delete myVehicleParameter;
     249        44873 :             myVehicleParameter = nullptr;
     250              :             myParamStack.pop_back();
     251              :             break;
     252         1979 :         case SUMO_TAG_PERSONFLOW:
     253         1979 :             closePersonFlow();
     254         1967 :             delete myVehicleParameter;
     255         1967 :             myVehicleParameter = nullptr;
     256              :             myParamStack.pop_back();
     257              :             break;
     258         2095 :         case SUMO_TAG_CONTAINER:
     259         2095 :             closeContainer();
     260         2087 :             delete myVehicleParameter;
     261         2087 :             myVehicleParameter = nullptr;
     262              :             myParamStack.pop_back();
     263              :             break;
     264          331 :         case SUMO_TAG_CONTAINERFLOW:
     265          331 :             closeContainerFlow();
     266          331 :             delete myVehicleParameter;
     267          331 :             myVehicleParameter = nullptr;
     268              :             myParamStack.pop_back();
     269              :             break;
     270       356929 :         case SUMO_TAG_VEHICLE:
     271       356929 :             if (myVehicleParameter == nullptr) {
     272              :                 break;
     273              :             }
     274       356929 :             if (myVehicleParameter->repetitionNumber <= 0) {
     275       356929 :                 closeVehicle();
     276       356800 :                 delete myVehicleParameter;
     277       356800 :                 myVehicleParameter = nullptr;
     278              :                 myParamStack.pop_back();
     279              :                 break;
     280              :             }
     281            0 :             myVehicleParameter->repetitionNumber++; // for backwards compatibility
     282              :             // it is a flow, thus no break here
     283              :             FALLTHROUGH;
     284        22196 :         case SUMO_TAG_FLOW:
     285        22196 :             if (myVehicleParameter) {
     286        22196 :                 closeFlow();
     287        22189 :                 delete myVehicleParameter;
     288              :                 myParamStack.pop_back();
     289              :             }
     290        22189 :             myVehicleParameter = nullptr;
     291        22189 :             myInsertStopEdgesAt = -1;
     292        22189 :             break;
     293       236384 :         case SUMO_TAG_TRIP:
     294       236384 :             closeTrip();
     295       236367 :             delete myVehicleParameter;
     296       236367 :             myVehicleParameter = nullptr;
     297              :             myParamStack.pop_back();
     298       236367 :             myInsertStopEdgesAt = -1;
     299       236367 :             break;
     300          619 :         case SUMO_TAG_VTYPE_DISTRIBUTION:
     301          619 :             closeVehicleTypeDistribution();
     302          619 :             break;
     303        92388 :         case SUMO_TAG_ROUTE_DISTRIBUTION:
     304        92388 :             closeRouteDistribution();
     305        92386 :             break;
     306        54432 :         case SUMO_TAG_PERSONTRIP:
     307              :         case SUMO_TAG_RIDE:
     308              :         case SUMO_TAG_TRANSPORT:
     309              :         case SUMO_TAG_TRANSHIP:
     310              :         case SUMO_TAG_WALK:
     311        54432 :             if (myParamStack.size() == 2) {
     312              :                 myParamStack.pop_back();
     313              :             }
     314              :             break;
     315           23 :         case SUMO_TAG_INTERVAL:
     316           23 :             myBeginDefault = string2time(OptionsCont::getOptions().getString("begin"));
     317           23 :             myEndDefault = string2time(OptionsCont::getOptions().getString("end"));
     318           23 :             break;
     319              :         default:
     320              :             break;
     321              :     }
     322              :     myElementStack.pop_back();
     323     11661233 : }
     324              : 
     325              : 
     326              : SUMORouteHandler::StopPos
     327       101860 : SUMORouteHandler::checkStopPos(double& startPos, double& endPos, const double laneLength, const double minLength, const bool friendlyPos) {
     328       101860 :     if (minLength > laneLength) {
     329              :         return STOPPOS_INVALID_LANELENGTH;
     330              :     }
     331       101860 :     if (startPos < 0) {
     332          161 :         startPos += laneLength;
     333              :     }
     334       101860 :     if (endPos < 0) {
     335         1512 :         endPos += laneLength;
     336              :     }
     337       101860 :     if ((endPos < minLength) || (endPos > laneLength)) {
     338          113 :         if (!friendlyPos) {
     339              :             return STOPPOS_INVALID_ENDPOS;
     340              :         }
     341          108 :         if (endPos < minLength) {
     342            3 :             endPos = minLength;
     343              :         }
     344          108 :         if (endPos > laneLength) {
     345          105 :             endPos = laneLength;
     346              :         }
     347              :     }
     348       101855 :     if ((startPos < 0) || (startPos > (endPos - minLength))) {
     349           37 :         if (!friendlyPos) {
     350              :             return STOPPOS_INVALID_STARTPOS;
     351              :         }
     352           37 :         if (startPos < 0) {
     353           13 :             startPos = 0;
     354              :         }
     355           37 :         if (startPos > (endPos - minLength)) {
     356           24 :             startPos = endPos - minLength;
     357              :         }
     358              :     }
     359              :     return STOPPOS_VALID;
     360              : }
     361              : 
     362              : 
     363              : SUMOTime
     364       102336 : SUMORouteHandler::getFirstDepart() const {
     365       102336 :     return myFirstDepart;
     366              : }
     367              : 
     368              : 
     369              : SUMOTime
     370      3274413 : SUMORouteHandler::getLastDepart() const {
     371      3274413 :     return myLastDepart;
     372              : }
     373              : 
     374              : 
     375              : void
     376        57642 : SUMORouteHandler::addParam(const SUMOSAXAttributes& attrs) {
     377        57642 :     bool ok = true;
     378        57642 :     const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
     379              :     // only continue if key isn't empty
     380        57642 :     if (ok && (key.size() > 0)) {
     381              :         // circumventing empty string test
     382        57642 :         std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
     383              :         // check special params that must be interpreted as relative paths
     384        48716 :         if ((myVehicleParameter != nullptr || myCurrentVType != nullptr)
     385        64198 :                 && (key == "device.toc.file" || key == "device.ssm.file")) {
     386          786 :             val = FileHelpers::checkForRelativity(val, getFileName());
     387              :         }
     388              :         // add parameter in current created element
     389        57642 :         if (!myParamStack.empty()) {
     390        15482 :             if (!myCurrentVTypeRef.empty() && myParamStack.back() == myCurrentVType) {
     391            0 :                 WRITE_WARNINGF(TL("Ignoring param for referenced vType %"), myCurrentVType->id);
     392              :             } else {
     393        15482 :                 myParamStack.back()->setParameter(key, val);
     394              :             }
     395              :         }
     396              :     }
     397        57642 : }
     398              : 
     399              : 
     400              : bool
     401        40939 : SUMORouteHandler::parseStop(SUMOVehicleParameter::Stop& stop, const SUMOSAXAttributes& attrs, std::string errorSuffix, MsgHandler* const errorOutput) {
     402        40939 :     stop.parametersSet = 0;
     403        40939 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVAL)) {
     404          415 :         stop.parametersSet |= STOP_ARRIVAL_SET;
     405              :     }
     406        40939 :     if (attrs.hasAttribute(SUMO_ATTR_DURATION)) {
     407        22658 :         stop.parametersSet |= STOP_DURATION_SET;
     408              :     }
     409        40939 :     if (attrs.hasAttribute(SUMO_ATTR_UNTIL)) {
     410        20045 :         stop.parametersSet |= STOP_UNTIL_SET;
     411              :     }
     412        40939 :     if (attrs.hasAttribute(SUMO_ATTR_STARTED)) {
     413         6742 :         stop.parametersSet |= STOP_STARTED_SET;
     414              :     }
     415        40939 :     if (attrs.hasAttribute(SUMO_ATTR_ENDED)) {
     416         6224 :         stop.parametersSet |= STOP_ENDED_SET;
     417              :     }
     418        40939 :     if (attrs.hasAttribute(SUMO_ATTR_EXTENSION)) {
     419          464 :         stop.parametersSet |= STOP_EXTENSION_SET;
     420              :     }
     421        40939 :     if (attrs.hasAttribute(SUMO_ATTR_ENDPOS)) {
     422         9079 :         stop.parametersSet |= STOP_END_SET;
     423              :     }
     424        40939 :     if (attrs.hasAttribute(SUMO_ATTR_STARTPOS)) {
     425         1491 :         stop.parametersSet |= STOP_START_SET;
     426              :     }
     427        40939 :     if (attrs.hasAttribute(SUMO_ATTR_POSITION_LAT)) {
     428          125 :         stop.parametersSet |= STOP_POSLAT_SET;
     429              :     }
     430        40939 :     if (attrs.hasAttribute(SUMO_ATTR_TRIGGERED)) {
     431         1588 :         stop.parametersSet |= STOP_TRIGGER_SET;
     432              :     }
     433              :     // legacy attribute
     434        40939 :     if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_TRIGGERED)) {
     435           56 :         stop.parametersSet |= STOP_TRIGGER_SET;
     436              :     }
     437        40939 :     if (attrs.hasAttribute(SUMO_ATTR_PARKING)) {
     438          980 :         stop.parametersSet |= STOP_PARKING_SET;
     439              :     }
     440        40939 :     if (attrs.hasAttribute(SUMO_ATTR_EXPECTED)) {
     441          242 :         stop.parametersSet |= STOP_EXPECTED_SET;
     442              :     }
     443        40939 :     if (attrs.hasAttribute(SUMO_ATTR_PERMITTED)) {
     444          369 :         stop.parametersSet |= STOP_PERMITTED_SET;
     445              :     }
     446        40939 :     if (attrs.hasAttribute(SUMO_ATTR_EXPECTED_CONTAINERS)) {
     447           77 :         stop.parametersSet |= STOP_EXPECTED_CONTAINERS_SET;
     448              :     }
     449        40939 :     if (attrs.hasAttribute(SUMO_ATTR_TRIP_ID)) {
     450          432 :         stop.parametersSet |= STOP_TRIP_ID_SET;
     451              :     }
     452        40939 :     if (attrs.hasAttribute(SUMO_ATTR_SPLIT)) {
     453          356 :         stop.parametersSet |= STOP_SPLIT_SET;
     454              :     }
     455        40939 :     if (attrs.hasAttribute(SUMO_ATTR_JOIN)) {
     456          116 :         stop.parametersSet |= STOP_JOIN_SET;
     457              :     }
     458        40939 :     if (attrs.hasAttribute(SUMO_ATTR_LINE)) {
     459          387 :         stop.parametersSet |= STOP_LINE_SET;
     460              :     }
     461        40939 :     if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     462          673 :         stop.parametersSet |= STOP_SPEED_SET;
     463              :     }
     464        40939 :     if (attrs.hasAttribute(SUMO_ATTR_ONDEMAND)) {
     465          178 :         stop.parametersSet |= STOP_ONDEMAND_SET;
     466              :     }
     467        40939 :     if (attrs.hasAttribute(SUMO_ATTR_PRIORITY)) {
     468          321 :         stop.parametersSet |= STOP_PRIORITY_SET;
     469              :     }
     470        40939 :     if (attrs.hasAttribute(SUMO_ATTR_JUMP)) {
     471          545 :         stop.parametersSet |= STOP_JUMP_SET;
     472              :     }
     473        40939 :     if (attrs.hasAttribute(SUMO_ATTR_JUMP_UNTIL)) {
     474            7 :         stop.parametersSet |= STOP_JUMP_UNTIL_SET;
     475              :     }
     476        40939 :     bool ok = true;
     477        81878 :     stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
     478        40939 :     stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_TRAIN_STOP, nullptr, ok, stop.busstop);
     479        40939 :     stop.chargingStation = attrs.getOpt<std::string>(SUMO_ATTR_CHARGING_STATION, nullptr, ok, "");
     480        40939 :     stop.overheadWireSegment = attrs.getOpt<std::string>(SUMO_ATTR_OVERHEAD_WIRE_SEGMENT, nullptr, ok, "");
     481        40939 :     stop.containerstop = attrs.getOpt<std::string>(SUMO_ATTR_CONTAINER_STOP, nullptr, ok, "");
     482        81878 :     stop.parkingarea = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, nullptr, ok, "");
     483        40939 :     if (stop.busstop != "") {
     484        34698 :         errorSuffix = " at '" + stop.busstop + "'" + errorSuffix;
     485        29373 :     } else if (stop.chargingStation != "") {
     486         3624 :         errorSuffix = " at '" + stop.chargingStation + "'" + errorSuffix;
     487        28165 :     } else if (stop.overheadWireSegment != "") {
     488            0 :         errorSuffix = " at '" + stop.overheadWireSegment + "'" + errorSuffix;
     489        28165 :     } else if (stop.containerstop != "") {
     490         1908 :         errorSuffix = " at '" + stop.containerstop + "'" + errorSuffix;
     491        27529 :     } else if (stop.parkingarea != "") {
     492        46674 :         errorSuffix = " at '" + stop.parkingarea + "'" + errorSuffix;
     493        11971 :     } else if (attrs.hasAttribute(SUMO_ATTR_LANE)) {
     494        30048 :         errorSuffix = " on lane '" + attrs.get<std::string>(SUMO_ATTR_LANE, nullptr, ok) + "'" + errorSuffix;
     495         1955 :     } else if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
     496         5565 :         errorSuffix = " on edge '" + attrs.get<std::string>(SUMO_ATTR_EDGE, nullptr, ok) + "'" + errorSuffix;
     497              :     } else {
     498          200 :         errorSuffix = " at undefined location" + errorSuffix;
     499              :     }
     500              :     // speed for counting as stopped
     501        40939 :     stop.speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, 0);
     502        40939 :     if (stop.speed < 0) {
     503           12 :         errorOutput->inform(TLF("Speed cannot be negative for stop%.", errorSuffix));
     504            6 :         return false;
     505              :     }
     506              : 
     507              :     // get the standing duration
     508        40933 :     bool expectTrigger = !attrs.hasAttribute(SUMO_ATTR_DURATION) && !attrs.hasAttribute(SUMO_ATTR_UNTIL) && !attrs.hasAttribute(SUMO_ATTR_SPEED);
     509        40933 :     std::vector<std::string> triggers = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_TRIGGERED, nullptr, ok);
     510              :     // legacy
     511        40933 :     if (attrs.getOpt<bool>(SUMO_ATTR_CONTAINER_TRIGGERED, nullptr, ok, false)) {
     512          112 :         triggers.push_back(toString(SUMO_TAG_CONTAINER));
     513              :     }
     514        40933 :     SUMOVehicleParameter::parseStopTriggers(triggers, expectTrigger, stop);
     515        40933 :     stop.arrival = attrs.getOptSUMOTimeReporting(SUMO_ATTR_ARRIVAL, nullptr, ok, -1);
     516        40933 :     stop.duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, nullptr, ok, -1);
     517        40933 :     stop.until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, -1);
     518        40933 :     if (!expectTrigger && (!ok || (stop.duration < 0 && stop.until < 0 && stop.speed == 0))) {
     519           36 :         errorOutput->inform(TLF("Invalid duration or end time is given for a stop%.", errorSuffix));
     520           12 :         return false;
     521              :     }
     522        40921 :     if (triggers.size() > 0 && stop.speed > 0) {
     523            9 :         errorOutput->inform(TLF("Triggers and waypoints cannot be combined%.", errorSuffix));
     524            3 :         return false;
     525              :     }
     526        40918 :     stop.extension = attrs.getOptSUMOTimeReporting(SUMO_ATTR_EXTENSION, nullptr, ok, -1);
     527        40918 :     const bool defaultParking = (stop.triggered || stop.containerTriggered || stop.parkingarea != "");
     528        40918 :     stop.parking = attrs.getOpt<ParkingType>(SUMO_ATTR_PARKING, nullptr, ok, defaultParking ? ParkingType::OFFROAD : ParkingType::ONROAD);
     529        40918 :     if ((stop.parkingarea != "") && (stop.parking == ParkingType::ONROAD)) {
     530           21 :         WRITE_WARNINGF(TL("Stop at parkingArea overrides attribute 'parking' for stop%."), errorSuffix);
     531            7 :         stop.parking = ParkingType::OFFROAD;
     532              :     }
     533              : 
     534              :     // expected persons
     535        40918 :     const std::vector<std::string>& expected = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_EXPECTED, nullptr, ok);
     536              :     stop.awaitedPersons.insert(expected.begin(), expected.end());
     537        40918 :     if (stop.awaitedPersons.size() > 0) {
     538          242 :         stop.triggered = true;
     539          242 :         if ((stop.parametersSet & STOP_PARKING_SET) == 0) {
     540          123 :             stop.parking = ParkingType::OFFROAD;
     541              :         }
     542              :     }
     543              : 
     544              :     // permitted transportables
     545        40918 :     const std::vector<std::string>& permitted = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_PERMITTED, nullptr, ok);
     546              :     stop.permitted.insert(permitted.begin(), permitted.end());
     547              : 
     548              :     // expected containers
     549        40918 :     const std::vector<std::string>& expectedContainers = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_EXPECTED_CONTAINERS, nullptr, ok);
     550              :     stop.awaitedContainers.insert(expectedContainers.begin(), expectedContainers.end());
     551        40918 :     if (stop.awaitedContainers.size() > 0) {
     552           77 :         stop.containerTriggered = true;
     553           77 :         if ((stop.parametersSet & STOP_PARKING_SET) == 0) {
     554           67 :             stop.parking = ParkingType::OFFROAD;
     555              :         }
     556              :     }
     557              :     // public transport trip id
     558        40918 :     stop.tripId = attrs.getOpt<std::string>(SUMO_ATTR_TRIP_ID, nullptr, ok, "");
     559        40918 :     stop.split = attrs.getOpt<std::string>(SUMO_ATTR_SPLIT, nullptr, ok, "");
     560        40918 :     stop.join = attrs.getOpt<std::string>(SUMO_ATTR_JOIN, nullptr, ok, "");
     561        40918 :     stop.line = attrs.getOpt<std::string>(SUMO_ATTR_LINE, nullptr, ok, "");
     562              : 
     563        40918 :     const std::string idx = attrs.getOpt<std::string>(SUMO_ATTR_INDEX, nullptr, ok, "end");
     564        40918 :     if (idx == "end") {
     565        40685 :         stop.index = STOP_INDEX_END;
     566          233 :     } else if (idx == "fit") {
     567           14 :         stop.index = STOP_INDEX_FIT;
     568              :     } else {
     569          219 :         stop.index = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
     570          219 :         if (!ok || stop.index < 0) {
     571           18 :             errorOutput->inform(TLF("Invalid 'index' for stop%.", errorSuffix));
     572            6 :             return false;
     573              :         }
     574              :     }
     575        40912 :     stop.started = attrs.getOptSUMOTimeReporting(SUMO_ATTR_STARTED, nullptr, ok, -1);
     576        40912 :     stop.ended = attrs.getOptSUMOTimeReporting(SUMO_ATTR_ENDED, nullptr, ok, -1);
     577        40912 :     stop.posLat = attrs.getOpt<double>(SUMO_ATTR_POSITION_LAT, nullptr, ok, INVALID_DOUBLE);
     578        40912 :     stop.actType = attrs.getOpt<std::string>(SUMO_ATTR_ACTTYPE, nullptr, ok, "");
     579        40912 :     stop.onDemand = attrs.getOpt<bool>(SUMO_ATTR_ONDEMAND, nullptr, ok, false);
     580        40912 :     stop.priority = attrs.getOpt<double>(SUMO_ATTR_PRIORITY, nullptr, ok, -1);
     581        40912 :     stop.jump = attrs.getOptSUMOTimeReporting(SUMO_ATTR_JUMP, nullptr, ok, -1);
     582        40912 :     stop.jumpUntil = attrs.getOptSUMOTimeReporting(SUMO_ATTR_JUMP_UNTIL, nullptr, ok, -1);
     583        40912 :     stop.collision = attrs.getOpt<bool>(SUMO_ATTR_COLLISION, nullptr, ok, false);
     584        40912 :     return true;
     585        40933 : }
     586              : 
     587              : 
     588              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1