LCOV - code coverage report
Current view: top level - src/utils/vehicle - SUMOVehicleParserHelper.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 85.3 % 1148 979
Test Date: 2026-08-24 15:52:21 Functions: 100.0 % 19 19

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2008-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    SUMOVehicleParserHelper.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Axel Wegener
      18              : /// @author  Michael Behrisch
      19              : /// @author  Laura Bieker
      20              : /// @author  Mirko Barthauer
      21              : /// @date    Mon, 07.04.2008
      22              : ///
      23              : // Helper methods for parsing vehicle attributes
      24              : /****************************************************************************/
      25              : #include <config.h>
      26              : 
      27              : #include <utils/common/FileHelpers.h>
      28              : #include <utils/common/MsgHandler.h>
      29              : #include <utils/common/RandHelper.h>
      30              : #include <utils/common/StringTokenizer.h>
      31              : #include <utils/common/StringUtils.h>
      32              : #include <utils/common/ToString.h>
      33              : #include <utils/common/UtilExceptions.h>
      34              : #include <utils/options/OptionsCont.h>
      35              : #include <utils/emissions/PollutantsInterface.h>
      36              : #include <utils/router/IntermodalNetwork.h>
      37              : #include <utils/vehicle/SUMOVTypeParameter.h>
      38              : #include <utils/vehicle/SUMOVehicleParameter.h>
      39              : #include <utils/xml/SUMOSAXAttributes.h>
      40              : 
      41              : #include "SUMOVehicleParserHelper.h"
      42              : 
      43              : 
      44              : // ===========================================================================
      45              : // static members
      46              : // ===========================================================================
      47              : 
      48              : SUMOVehicleParserHelper::CFAttrMap SUMOVehicleParserHelper::allowedCFModelAttrs;
      49              : SUMOVehicleParserHelper::LCAttrMap SUMOVehicleParserHelper::allowedLCModelAttrs;
      50              : 
      51              : 
      52              : // ===========================================================================
      53              : // method definitions
      54              : // ===========================================================================
      55              : 
      56              : SUMOVehicleParameter*
      57        25120 : SUMOVehicleParserHelper::parseFlowAttributes(SumoXMLTag tag, const SUMOSAXAttributes& attrs, const bool hardFail, const bool needID,
      58              :         const SUMOTime beginDefault, const SUMOTime endDefault, const bool allowInternalRoutes) {
      59              :     // first parse ID
      60        25120 :     const std::string id = attrs.hasAttribute(SUMO_ATTR_ID) ? parseID(attrs, tag) : "";
      61              :     // check if ID is valid
      62        25120 :     if (!needID || !id.empty()) {
      63        25113 :         if (needID && !SUMOXMLDefinitions::isValidVehicleID(id)) {
      64            0 :             return handleVehicleError(hardFail, nullptr, "Invalid flow id '" + id + "'.");
      65              :         }
      66              :         // declare flags
      67        25113 :         const bool hasPeriod = attrs.hasAttribute(SUMO_ATTR_PERIOD);
      68        25113 :         const bool hasVPH = attrs.hasAttribute(SUMO_ATTR_VEHSPERHOUR);
      69        25113 :         const bool hasPPH = attrs.hasAttribute(SUMO_ATTR_PERSONSPERHOUR);
      70        25113 :         const bool hasCPH = attrs.hasAttribute(SUMO_ATTR_CONTAINERSPERHOUR);
      71        25113 :         const bool hasPH = attrs.hasAttribute(SUMO_ATTR_PERHOUR);
      72        25113 :         const bool hasXPH = hasVPH || hasPPH || hasCPH || hasPH;
      73        25113 :         const bool hasProb = attrs.hasAttribute(SUMO_ATTR_PROB);
      74        25113 :         const bool hasNumber = attrs.hasAttribute(SUMO_ATTR_NUMBER);
      75        25113 :         const bool hasBegin = attrs.hasAttribute(SUMO_ATTR_BEGIN);
      76        25113 :         const bool hasEnd = attrs.hasAttribute(SUMO_ATTR_END);
      77              :         SumoXMLAttr PERHOUR = SUMO_ATTR_PERHOUR;
      78        25113 :         if (hasVPH) {
      79              :             PERHOUR = SUMO_ATTR_VEHSPERHOUR;
      80              :         }
      81        25113 :         if (hasPPH) {
      82              :             PERHOUR = SUMO_ATTR_PERSONSPERHOUR;
      83              :         }
      84        25113 :         if (hasCPH) {
      85              :             PERHOUR = SUMO_ATTR_CONTAINERSPERHOUR;
      86              :         }
      87        25113 :         if (hasXPH && !(hasVPH ^ hasPPH ^ hasCPH ^ hasPH)) {
      88            0 :             return handleVehicleError(hardFail, nullptr,
      89            0 :                                       "At most one of '" + attrs.getName(SUMO_ATTR_PERHOUR) +
      90            0 :                                       "', '" + attrs.getName(SUMO_ATTR_VEHSPERHOUR) +
      91            0 :                                       "', '" + attrs.getName(SUMO_ATTR_PERSONSPERHOUR) +
      92            0 :                                       "' and '" + attrs.getName(SUMO_ATTR_CONTAINERSPERHOUR) +
      93            0 :                                       "' has to be given in the definition of " + toString(tag) + " '" + id + "'.");
      94              :         }
      95         4093 :         if (hasPeriod && hasXPH) {
      96            7 :             return handleVehicleError(hardFail, nullptr,
      97           14 :                                       "At most one of '" + attrs.getName(SUMO_ATTR_PERIOD) +
      98           21 :                                       "' and '" + attrs.getName(PERHOUR) +
      99              :                                       "' has to be given in the definition of "
     100           14 :                                       + toString(tag) + " '" + id + "'.");
     101              :         }
     102        25106 :         if (hasPeriod && hasProb) {
     103            0 :             return handleVehicleError(hardFail, nullptr,
     104            0 :                                       "At most one of '" + attrs.getName(SUMO_ATTR_PERIOD) +
     105            0 :                                       "' and '" + attrs.getName(SUMO_ATTR_PROB) +
     106              :                                       "' has to be given in the definition of "
     107            0 :                                       + toString(tag) + " '" + id + "'.");
     108              :         }
     109        25106 :         if (hasProb && hasXPH) {
     110            0 :             return handleVehicleError(hardFail, nullptr,
     111            0 :                                       "At most one of '" + attrs.getName(SUMO_ATTR_PROB) +
     112            0 :                                       "' and '" + attrs.getName(PERHOUR) +
     113              :                                       "' has to be given in the definition of "
     114            0 :                                       + toString(tag) + " '" + id + "'.");
     115              :         }
     116        25106 :         if (hasPeriod || hasXPH || hasProb) {
     117        20121 :             if (hasEnd && hasNumber) {
     118            7 :                 return handleVehicleError(hardFail, nullptr,
     119           14 :                                           "If '" + attrs.getName(SUMO_ATTR_PERIOD) +
     120           21 :                                           "', '" + attrs.getName(SUMO_ATTR_VEHSPERHOUR) +
     121           21 :                                           "', '" + attrs.getName(SUMO_ATTR_PERSONSPERHOUR) +
     122           21 :                                           "', '" + attrs.getName(SUMO_ATTR_CONTAINERSPERHOUR) +
     123           21 :                                           "', '" + attrs.getName(SUMO_ATTR_PERHOUR) +
     124           21 :                                           "' or '" + attrs.getName(SUMO_ATTR_PROB) +
     125           21 :                                           "' are given at most one of '" + attrs.getName(SUMO_ATTR_END) +
     126           21 :                                           "' and '" + attrs.getName(SUMO_ATTR_NUMBER) +
     127              :                                           "' are allowed in "
     128           14 :                                           + toString(tag) + " '" + id + "'.");
     129              :             }
     130              :         } else {
     131         4985 :             if (!hasNumber) {
     132            7 :                 return handleVehicleError(hardFail, nullptr,
     133           14 :                                           "At least one of '" + attrs.getName(SUMO_ATTR_PERIOD) +
     134           21 :                                           "', '" + attrs.getName(SUMO_ATTR_VEHSPERHOUR) +
     135           21 :                                           "', '" + attrs.getName(SUMO_ATTR_PERSONSPERHOUR) +
     136           21 :                                           "', '" + attrs.getName(SUMO_ATTR_CONTAINERSPERHOUR) +
     137           21 :                                           "', '" + attrs.getName(SUMO_ATTR_PERHOUR) +
     138           21 :                                           "', '" + attrs.getName(SUMO_ATTR_PROB) +
     139           21 :                                           "', and '" + attrs.getName(SUMO_ATTR_NUMBER) +
     140              :                                           "' is needed in "
     141           14 :                                           + toString(tag) + " '" + id + "'.");
     142              :             }
     143              :         }
     144              :         // declare flow
     145        25092 :         SUMOVehicleParameter* flowParameter = new SUMOVehicleParameter();
     146              :         // set tag
     147        25092 :         flowParameter->tag = tag;
     148              :         // set id
     149        25092 :         flowParameter->id = id;
     150        25092 :         if (tag == SUMO_TAG_PERSONFLOW) {
     151         2057 :             flowParameter->vtypeid = DEFAULT_PEDTYPE_ID;
     152              :         }
     153        25092 :         if (tag == SUMO_TAG_CONTAINERFLOW) {
     154          332 :             flowParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
     155              :         }
     156              :         // parse common vehicle attributes
     157              :         try {
     158        25092 :             parseCommonAttributes(attrs, flowParameter, tag, allowInternalRoutes);
     159           48 :         } catch (ProcessError& attributeError) {
     160              :             // check if continue handling another vehicles or stop handling
     161           48 :             if (hardFail) {
     162           96 :                 throw ProcessError(attributeError.what());
     163              :             } else {
     164              :                 return nullptr;
     165              :             }
     166           48 :         }
     167              :         // parse period
     168              :         bool poissonFlow = false;
     169        25044 :         if (hasPeriod) {
     170        11339 :             bool ok = true;
     171        11339 :             const std::string description = attrs.get<std::string>(SUMO_ATTR_PERIOD, id.c_str(), ok);
     172        11339 :             const std::string distName = description.substr(0, description.find('('));
     173        11339 :             if (distName == "exp") {
     174              :                 // declare rate
     175              :                 double rate = -1;
     176              :                 // parse rate
     177              :                 try {
     178          936 :                     rate = StringUtils::toDouble(description.substr(distName.size() + 1, description.size() - distName.size() - 2));
     179            0 :                 } catch (ProcessError& attributeError) {
     180              :                     // check if continue handling another vehicles or stop handling
     181            0 :                     if (hardFail) {
     182            0 :                         throw ProcessError(attributeError.what());
     183              :                     } else {
     184              :                         return nullptr;
     185              :                     }
     186            0 :                 }
     187          936 :                 if (rate <= 0) {
     188           14 :                     return handleVehicleError(hardFail, flowParameter, "Invalid rate parameter for exponentially distributed period in the definition of " + toString(tag) + " '" + id + "'.");
     189              :                 }
     190          929 :                 flowParameter->poissonRate = rate;
     191              :                 poissonFlow = true;
     192              :             } else {
     193        10403 :                 flowParameter->repetitionOffset = attrs.getSUMOTimeReporting(SUMO_ATTR_PERIOD, id.c_str(), ok);
     194              :             }
     195        11332 :             if (!ok) {
     196            7 :                 return handleVehicleError(hardFail, flowParameter);
     197              :             } else {
     198        11332 :                 flowParameter->parametersSet |= VEHPARS_PERIOD_SET;
     199              :             }
     200              :         }
     201              :         // parse vehicle/person/container/etc per hour
     202        25037 :         if (hasXPH) {
     203         4086 :             bool ok = true;
     204         4086 :             const double vph = attrs.get<double>(PERHOUR, id.c_str(), ok);
     205         4086 :             if (!ok) {
     206            0 :                 return handleVehicleError(hardFail, flowParameter);
     207         4086 :             } else if (vph <= 0) {
     208            0 :                 return handleVehicleError(hardFail, flowParameter, "Invalid repetition rate in the definition of " + toString(tag) + " '" + id + "'.");
     209              :             } else {
     210              :                 if (vph != 0) {
     211         4086 :                     flowParameter->repetitionOffset = TIME2STEPS(3600. / vph);
     212              :                 }
     213         4086 :                 flowParameter->parametersSet |= VEHPARS_VPH_SET;
     214              :             }
     215              :         }
     216              :         // parse probability
     217        25037 :         if (hasProb) {
     218         4689 :             bool ok = true;
     219         4689 :             flowParameter->repetitionProbability = attrs.get<double>(SUMO_ATTR_PROB, id.c_str(), ok);
     220         4689 :             if (!ok) {
     221            0 :                 return handleVehicleError(hardFail, flowParameter);
     222         4689 :             } else if (flowParameter->repetitionProbability <= 0 || flowParameter->repetitionProbability > 1) {
     223            0 :                 return handleVehicleError(hardFail, flowParameter, "Invalid repetition probability in the definition of " + toString(tag) + " '" + id + "'.");
     224              :             } else {
     225         4689 :                 flowParameter->parametersSet |= VEHPARS_PROB_SET;
     226              :             }
     227              :         }
     228              :         // set default begin
     229        25037 :         flowParameter->depart = beginDefault;
     230              :         // parse begin
     231        25037 :         if (hasBegin) {
     232              :             // first get begin
     233        24818 :             bool ok = true;
     234        24818 :             const std::string begin = attrs.get<std::string>(SUMO_ATTR_BEGIN, id.c_str(), ok);
     235        24818 :             if (!ok) {
     236            7 :                 return handleVehicleError(hardFail, flowParameter);
     237              :             } else {
     238              :                 // parse begin
     239              :                 std::string errorMsg;
     240        49636 :                 if (!SUMOVehicleParameter::parseDepart(begin, toString(tag), id, flowParameter->depart, flowParameter->departProcedure, errorMsg, "begin")) {
     241           14 :                     return handleVehicleError(hardFail, flowParameter, errorMsg);
     242              :                 }
     243              :             }
     244              :         }
     245        25030 :         if (flowParameter->depart < 0) {
     246            0 :             return handleVehicleError(hardFail, flowParameter, "Negative begin time in the definition of " + toString(tag) + " '" + id + "'.");
     247              :         }
     248              :         // set default end
     249        25030 :         flowParameter->repetitionEnd = endDefault;
     250        25030 :         if (flowParameter->repetitionEnd < 0) {
     251        19205 :             flowParameter->repetitionEnd = SUMOTime_MAX;
     252              :         }
     253              :         // parse end
     254        25030 :         if (hasEnd) {
     255        22046 :             bool ok = true;
     256        22046 :             flowParameter->repetitionEnd = attrs.getSUMOTimeReporting(SUMO_ATTR_END, id.c_str(), ok);
     257        22046 :             if (!ok) {
     258            0 :                 return handleVehicleError(hardFail, flowParameter);
     259              :             } else {
     260        22046 :                 flowParameter->parametersSet |= VEHPARS_END_SET;
     261              :             }
     262         2984 :         } else if (flowParameter->departProcedure == DepartDefinition::TRIGGERED) {
     263           55 :             if (!hasNumber) {
     264            0 :                 return handleVehicleError(hardFail, flowParameter, toString(tag) + " '" + id + "' with triggered begin must define 'number'.");
     265              :             } else {
     266           55 :                 flowParameter->repetitionEnd = flowParameter->depart;
     267              :             }
     268         2929 :         } else if ((endDefault == SUMOTime_MAX || endDefault < 0) && (!hasNumber || (!hasProb && !hasPeriod && !hasXPH))) {
     269          156 :             WRITE_WARNINGF(TL("Undefined end for % '%', defaulting to 24hour duration."), toString(tag), id);
     270           52 :             flowParameter->repetitionEnd = flowParameter->depart + TIME2STEPS(24 * 3600);
     271              :         }
     272        25030 :         if (flowParameter->repetitionEnd < flowParameter->depart) {
     273            7 :             std::string flow = toString(tag);
     274            7 :             flow[0] = (char)::toupper((char)flow[0]);
     275           21 :             return handleVehicleError(hardFail, flowParameter, flow + " '" + id + "' ends before its begin time.");
     276              :         }
     277              :         // parse number
     278        25023 :         if (hasNumber) {
     279         7599 :             bool ok = true;
     280         7599 :             flowParameter->repetitionNumber = attrs.get<long long int>(SUMO_ATTR_NUMBER, id.c_str(), ok);
     281         7599 :             if (!ok) {
     282            0 :                 return handleVehicleError(hardFail, flowParameter);
     283              :             } else {
     284         7599 :                 flowParameter->parametersSet |= VEHPARS_NUMBER_SET;
     285         7599 :                 if (flowParameter->repetitionNumber == 0) {
     286            8 :                     std::string flow = toString(tag);
     287            8 :                     flow[0] = (char)::toupper((char)flow[0]);
     288           16 :                     WRITE_WARNING(flow + " '" + id + "' has no instances; will skip it.");
     289            8 :                     flowParameter->repetitionEnd = flowParameter->depart;
     290              :                 } else {
     291         7591 :                     if (flowParameter->repetitionNumber < 0) {
     292           14 :                         return handleVehicleError(hardFail, flowParameter, "Negative repetition number in the definition of " + toString(tag) + " '" + id + "'.");
     293              :                     }
     294         7584 :                     if (flowParameter->repetitionOffset < 0 && !hasProb) {
     295         5061 :                         if (poissonFlow) {
     296          139 :                             flowParameter->repetitionEnd = SUMOTime_MAX;
     297              :                         } else {
     298         4922 :                             flowParameter->repetitionOffset = (flowParameter->repetitionEnd - flowParameter->depart) / flowParameter->repetitionNumber;
     299              :                         }
     300              :                     }
     301              :                 }
     302              :             }
     303              :         } else {
     304              :             // interpret repetitionNumber
     305        17424 :             if (flowParameter->repetitionProbability > 0) {
     306         4647 :                 flowParameter->repetitionNumber = std::numeric_limits<long long int>::max();
     307              :             } else {
     308        12777 :                 if (flowParameter->repetitionOffset <= 0) {
     309          804 :                     if (poissonFlow) {
     310              :                         // number is random but flow has a fixed end time
     311          790 :                         flowParameter->repetitionNumber = std::numeric_limits<long long int>::max();
     312              :                     } else {
     313           28 :                         return handleVehicleError(hardFail, flowParameter, "Invalid repetition rate in the definition of " + toString(tag) + " '" + id + "'.");
     314              :                     }
     315              :                 } else {
     316        11973 :                     if (flowParameter->repetitionEnd == SUMOTime_MAX) {
     317            0 :                         flowParameter->repetitionNumber = std::numeric_limits<long long int>::max();
     318              :                     } else {
     319        11973 :                         const SUMOTime repLength = flowParameter->repetitionEnd - flowParameter->depart;
     320        11973 :                         flowParameter->repetitionNumber = (long long int)ceil((double)repLength / (double)flowParameter->repetitionOffset);
     321              :                     }
     322              :                 }
     323              :             }
     324              :         }
     325              :         // all ok, then return flow parameter
     326        25002 :         return flowParameter;
     327              :     } else {
     328          132 :         return handleVehicleError(hardFail, nullptr, toString(tag) + " cannot be created");
     329              :     }
     330              : }
     331              : 
     332              : 
     333              : SUMOVehicleParameter*
     334       642783 : SUMOVehicleParserHelper::parseVehicleAttributes(int element, const SUMOSAXAttributes& attrs, const bool hardFail, const bool optionalID, const bool skipDepart, const bool allowInternalRoutes) {
     335              :     // declare vehicle ID
     336              :     std::string id;
     337              :     // for certain vehicles, ID can be optional
     338       642783 :     if (optionalID) {
     339          696 :         bool ok = true;
     340          696 :         id = attrs.getOpt<std::string>(SUMO_ATTR_ID, nullptr, ok, "");
     341          696 :         if (!ok) {
     342            0 :             return handleVehicleError(hardFail, nullptr);
     343              :         }
     344              :     } else {
     345              :         // parse ID
     346      1284174 :         id = parseID(attrs, (SumoXMLTag)element);
     347              :     }
     348              :     // only continue if id is valid, or if is optional
     349       642783 :     if (optionalID || !id.empty()) {
     350              :         // declare vehicle parameter
     351       642767 :         SUMOVehicleParameter* vehicleParameter = new SUMOVehicleParameter();
     352       642767 :         vehicleParameter->id = id;
     353       642767 :         if (element == SUMO_TAG_PERSON) {
     354        44979 :             vehicleParameter->vtypeid = DEFAULT_PEDTYPE_ID;
     355       597788 :         } else if (element == SUMO_TAG_CONTAINER) {
     356         2113 :             vehicleParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
     357              :         }
     358              :         // parse common attributes
     359              :         try {
     360       642767 :             parseCommonAttributes(attrs, vehicleParameter, (SumoXMLTag)element, allowInternalRoutes);
     361          274 :         } catch (ProcessError& attributeError) {
     362              :             // check if continue handling another vehicles or stop handling
     363          274 :             if (hardFail) {
     364          548 :                 throw ProcessError(attributeError.what());
     365              :             } else {
     366              :                 return nullptr;
     367              :             }
     368          274 :         }
     369              :         // check depart
     370       642493 :         if (!skipDepart) {
     371       641797 :             bool ok = true;
     372       641797 :             const std::string helper = attrs.get<std::string>(SUMO_ATTR_DEPART, vehicleParameter->id.c_str(), ok);
     373       641797 :             if (!ok) {
     374           40 :                 return handleVehicleError(hardFail, vehicleParameter);
     375              :             }
     376              :             // now parse depart
     377              :             std::string departErrorMsg;
     378      1283562 :             if (!SUMOVehicleParameter::parseDepart(helper, "vehicle", vehicleParameter->id, vehicleParameter->depart, vehicleParameter->departProcedure, departErrorMsg)) {
     379           16 :                 return handleVehicleError(hardFail, vehicleParameter, departErrorMsg);
     380              :             }
     381              :         }
     382              :         // set tag
     383       642469 :         vehicleParameter->tag = (SumoXMLTag)element;
     384              :         // all ok, then return vehicleParameter
     385       642469 :         return vehicleParameter;
     386              :     } else {
     387          346 :         return handleVehicleError(hardFail, nullptr, toString((SumoXMLTag)element) + " cannot be created");
     388              :     }
     389              : }
     390              : 
     391              : 
     392              : std::string
     393       731603 : SUMOVehicleParserHelper::parseID(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
     394       731603 :     bool ok = true;
     395              :     std::string id;
     396              :     // first check if attrs contain an ID
     397       731603 :     if (attrs.hasAttribute(SUMO_ATTR_ID)) {
     398       731591 :         id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     399       731591 :         if (SUMOXMLDefinitions::isValidVehicleID(id)) {
     400       731583 :             return id;
     401            8 :         } else if (id.empty()) {
     402              :             // add extra information for empty IDs
     403           24 :             WRITE_ERRORF(TL("Invalid % id '%'."), toString(element), id);
     404              :         } else {
     405            0 :             WRITE_ERRORF(TL("Invalid % id '%'. Contains invalid characters."), toString(element), id);
     406              :         }
     407              :     } else {
     408           36 :         WRITE_ERROR("Attribute '" + toString(SUMO_ATTR_ID) + "' is missing in definition of " + toString(element));
     409              :     }
     410              :     // return empty (invalid) ID
     411           20 :     return "";
     412              : }
     413              : 
     414              : 
     415              : void
     416       667859 : SUMOVehicleParserHelper::parseCommonAttributes(const SUMOSAXAttributes& attrs, SUMOVehicleParameter* ret, SumoXMLTag tag, const bool allowInternalRoutes) {
     417       667859 :     const std::string element = toString(tag);
     418              :     //ret->refid = attrs.getStringSecure(SUMO_ATTR_REFID, "");
     419              :     // parse route information
     420       667859 :     if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
     421       167902 :         bool ok = true;
     422       167902 :         std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, ret->id.c_str(), ok);
     423       167902 :         if (!allowInternalRoutes && isInternalRouteID(routeID)) {
     424            0 :             WRITE_WARNINGF(TL("Internal routes receive an ID starting with '!' and must not be referenced in other vehicle or flow definitions. Please remove all references to route '%' in case it is internal."), routeID);
     425              :         }
     426       167902 :         ret->routeid = routeID;
     427       167902 :         if (ok) {
     428       167892 :             ret->parametersSet |= VEHPARS_ROUTE_SET; // !!! needed?
     429              :         } else {
     430           20 :             handleVehicleError(true, ret);
     431              :         }
     432              :     }
     433              :     // parse type information
     434       667849 :     if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
     435       220641 :         bool ok = true;
     436       220641 :         ret->vtypeid = attrs.get<std::string>(SUMO_ATTR_TYPE, ret->id.c_str(), ok);
     437       220641 :         if (ok) {
     438       220641 :             ret->parametersSet |= VEHPARS_VTYPE_SET; // !!! needed?
     439              :         } else {
     440            0 :             handleVehicleError(true, ret);
     441              :         }
     442              :     }
     443              :     // parse line information
     444       667849 :     if (attrs.hasAttribute(SUMO_ATTR_LINE)) {
     445         3327 :         bool ok = true;
     446         3327 :         ret->line = attrs.get<std::string>(SUMO_ATTR_LINE, ret->id.c_str(), ok);
     447         3327 :         if (ok) {
     448         3321 :             ret->parametersSet |= VEHPARS_LINE_SET; // !!! needed?
     449              :         } else {
     450            6 :             handleVehicleError(true, ret);
     451              :         }
     452              :     }
     453              :     // parse zone information
     454       667843 :     if (attrs.hasAttribute(SUMO_ATTR_FROM_TAZ)) {
     455        21507 :         bool ok = true;
     456        21507 :         ret->fromTaz = attrs.get<std::string>(SUMO_ATTR_FROM_TAZ, ret->id.c_str(), ok);
     457        21507 :         if (ok) {
     458        21507 :             ret->parametersSet |= VEHPARS_FROM_TAZ_SET;
     459              :         } else {
     460            0 :             handleVehicleError(true, ret);
     461              :         }
     462              :     }
     463       667843 :     if (attrs.hasAttribute(SUMO_ATTR_TO_TAZ)) {
     464        21513 :         bool ok = true;
     465        21513 :         ret->toTaz = attrs.get<std::string>(SUMO_ATTR_TO_TAZ, ret->id.c_str(), ok);
     466        21513 :         if (ok) {
     467        21513 :             ret->parametersSet |= VEHPARS_TO_TAZ_SET;
     468              :         } else {
     469            0 :             handleVehicleError(true, ret);
     470              :         }
     471              :     }
     472              :     // parse reroute information
     473       667843 :     if (attrs.hasAttribute(SUMO_ATTR_REROUTE)) {
     474         3687 :         bool ok = true;
     475         3687 :         if (attrs.get<bool>(SUMO_ATTR_REROUTE, ret->id.c_str(), ok)) {
     476         3687 :             if (ok) {
     477         3687 :                 ret->parametersSet |= VEHPARS_FORCE_REROUTE;
     478              :             } else {
     479            0 :                 handleVehicleError(true, ret);
     480              :             }
     481              :         }
     482              :     }
     483              :     // parse depart lane information
     484       667843 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTLANE)) {
     485       111986 :         bool ok = true;
     486       111986 :         const std::string departLaneStr = attrs.get<std::string>(SUMO_ATTR_DEPARTLANE, ret->id.c_str(), ok);
     487              :         int lane;
     488              :         DepartLaneDefinition dld;
     489              :         std::string error;
     490       111986 :         if (SUMOVehicleParameter::parseDepartLane(departLaneStr, element, ret->id, lane, dld, error)) {
     491       111938 :             ret->parametersSet |= VEHPARS_DEPARTLANE_SET;
     492       111938 :             ret->departLane = lane;
     493       111938 :             ret->departLaneProcedure = dld;
     494              :         } else {
     495           96 :             handleVehicleError(true, ret, error);
     496              :         }
     497              :     }
     498              :     // parse depart position information
     499       667795 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
     500        91638 :         bool ok = true;
     501        91638 :         const std::string departPosStr = attrs.get<std::string>(SUMO_ATTR_DEPARTPOS, ret->id.c_str(), ok);
     502              :         double pos;
     503              :         DepartPosDefinition dpd;
     504              :         std::string error;
     505        91638 :         if (SUMOVehicleParameter::parseDepartPos(departPosStr, element, ret->id, pos, dpd, error)) {
     506        91590 :             ret->parametersSet |= VEHPARS_DEPARTPOS_SET;
     507        91590 :             ret->departPos = pos;
     508        91590 :             ret->departPosProcedure = dpd;
     509              :         } else {
     510           96 :             handleVehicleError(true, ret, error);
     511              :         }
     512              :     }
     513              :     // parse lateral depart position information
     514       667747 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS_LAT)) {
     515         8719 :         bool ok = true;
     516         8719 :         const std::string departPosLatStr = attrs.get<std::string>(SUMO_ATTR_DEPARTPOS_LAT, ret->id.c_str(), ok);
     517              :         double pos;
     518              :         DepartPosLatDefinition dpd;
     519              :         std::string error;
     520         8719 :         if (SUMOVehicleParameter::parseDepartPosLat(departPosLatStr, element, ret->id, pos, dpd, error)) {
     521         8719 :             ret->parametersSet |= VEHPARS_DEPARTPOSLAT_SET;
     522         8719 :             ret->departPosLat = pos;
     523         8719 :             ret->departPosLatProcedure = dpd;
     524              :         } else {
     525            0 :             handleVehicleError(true, ret, error);
     526              :         }
     527              :     }
     528              :     // parse depart speed information
     529       667747 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTSPEED)) {
     530       243846 :         bool ok = true;
     531       243846 :         const std::string departSpeed = attrs.get<std::string>(SUMO_ATTR_DEPARTSPEED, ret->id.c_str(), ok);
     532              :         double speed;
     533              :         DepartSpeedDefinition dsd;
     534              :         std::string error;
     535       243846 :         if (SUMOVehicleParameter::parseDepartSpeed(departSpeed, element, ret->id, speed, dsd, error)) {
     536       243798 :             ret->parametersSet |= VEHPARS_DEPARTSPEED_SET;
     537       243798 :             ret->departSpeed = speed;
     538       243798 :             ret->departSpeedProcedure = dsd;
     539              :         } else {
     540           96 :             handleVehicleError(true, ret, error);
     541              :         }
     542              :     }
     543              :     // parse depart edge information
     544       667699 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTEDGE)) {
     545          296 :         bool ok = true;
     546          296 :         const std::string departEdgeStr = attrs.get<std::string>(SUMO_ATTR_DEPARTEDGE, ret->id.c_str(), ok);
     547              :         int edgeIndex;
     548              :         RouteIndexDefinition rid;
     549              :         std::string error;
     550          296 :         if (SUMOVehicleParameter::parseRouteIndex(departEdgeStr, element, ret->id, SUMO_ATTR_DEPARTEDGE, edgeIndex, rid, error)) {
     551          289 :             ret->parametersSet |= VEHPARS_DEPARTEDGE_SET;
     552          289 :             ret->departEdge = edgeIndex;
     553          289 :             ret->departEdgeProcedure = rid;
     554              :         } else {
     555           14 :             handleVehicleError(true, ret, error);
     556              :         }
     557              :     }
     558              :     // parse arrival lane information
     559       667692 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALLANE)) {
     560         3286 :         bool ok = true;
     561         3286 :         const std::string arrivalLaneStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALLANE, ret->id.c_str(), ok);
     562              :         int lane;
     563              :         ArrivalLaneDefinition ald;
     564              :         std::string error;
     565         3286 :         if (SUMOVehicleParameter::parseArrivalLane(arrivalLaneStr, element, ret->id, lane, ald, error)) {
     566         3238 :             ret->parametersSet |= VEHPARS_ARRIVALLANE_SET;
     567         3238 :             ret->arrivalLane = lane;
     568         3238 :             ret->arrivalLaneProcedure = ald;
     569              :         } else {
     570           96 :             handleVehicleError(true, ret, error);
     571              :         }
     572              :     }
     573              :     // parse arrival position information
     574       667644 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
     575         8333 :         bool ok = true;
     576         8333 :         const std::string arrivalPosStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS, ret->id.c_str(), ok);
     577              :         double pos;
     578              :         ArrivalPosDefinition apd;
     579              :         std::string error;
     580         8333 :         if (SUMOVehicleParameter::parseArrivalPos(arrivalPosStr, element, ret->id, pos, apd, error)) {
     581         8285 :             ret->parametersSet |= VEHPARS_ARRIVALPOS_SET;
     582         8285 :             ret->arrivalPos = pos;
     583         8285 :             ret->arrivalPosProcedure = apd;
     584              :         } else {
     585           96 :             handleVehicleError(true, ret, error);
     586              :         }
     587              :     }
     588              :     // parse lateral arrival position information
     589       667596 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_LAT)) {
     590         1072 :         bool ok = true;
     591         1072 :         const std::string arrivalPosLatStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS_LAT, ret->id.c_str(), ok);
     592              :         double pos;
     593              :         ArrivalPosLatDefinition apd;
     594              :         std::string error;
     595         1072 :         if (SUMOVehicleParameter::parseArrivalPosLat(arrivalPosLatStr, element, ret->id, pos, apd, error)) {
     596         1072 :             ret->parametersSet |= VEHPARS_ARRIVALPOSLAT_SET;
     597         1072 :             ret->arrivalPosLat = pos;
     598         1072 :             ret->arrivalPosLatProcedure = apd;
     599              :         } else {
     600            0 :             handleVehicleError(true, ret, error);
     601              :         }
     602              :     }
     603              :     // parse arrival speed information
     604       667596 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALSPEED)) {
     605         3793 :         bool ok = true;
     606         3793 :         std::string arrivalSpeedStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALSPEED, ret->id.c_str(), ok);
     607              :         double speed;
     608              :         ArrivalSpeedDefinition asd;
     609              :         std::string error;
     610         3793 :         if (SUMOVehicleParameter::parseArrivalSpeed(arrivalSpeedStr, element, ret->id, speed, asd, error)) {
     611         3745 :             ret->parametersSet |= VEHPARS_ARRIVALSPEED_SET;
     612         3745 :             ret->arrivalSpeed = speed;
     613         3745 :             ret->arrivalSpeedProcedure = asd;
     614              :         } else {
     615           96 :             handleVehicleError(true, ret, error);
     616              :         }
     617              :     }
     618              :     // parse arrival edge information
     619       667548 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALEDGE)) {
     620          105 :         bool ok = true;
     621          105 :         std::string arrivalEdgeStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALEDGE, ret->id.c_str(), ok);
     622              :         int edgeIndex;
     623              :         RouteIndexDefinition rid;
     624              :         std::string error;
     625          105 :         if (SUMOVehicleParameter::parseRouteIndex(arrivalEdgeStr, element, ret->id, SUMO_ATTR_ARRIVALEDGE, edgeIndex, rid, error)) {
     626           98 :             ret->parametersSet |= VEHPARS_ARRIVALEDGE_SET;
     627           98 :             ret->arrivalEdge = edgeIndex;
     628           98 :             ret->arrivalEdgeProcedure = rid;
     629              :         } else {
     630           14 :             handleVehicleError(true, ret, error);
     631              :         }
     632              :     }
     633              :     // parse color
     634       667541 :     if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
     635        10141 :         bool ok = true;
     636        10141 :         ret->color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, ret->id.c_str(), ok);
     637        10141 :         if (ok) {
     638        10141 :             ret->parametersSet |= VEHPARS_COLOR_SET;
     639              :         } else {
     640            0 :             handleVehicleError(true, ret, "Invalid RGBColor format");
     641              :         }
     642              :     } else {
     643       657400 :         ret->color = RGBColor::DEFAULT_COLOR;
     644              :     }
     645              :     // parse person number
     646       667541 :     if (attrs.hasAttribute(SUMO_ATTR_PERSON_NUMBER)) {
     647          982 :         bool ok = true;
     648          982 :         int personNumber = attrs.get<int>(SUMO_ATTR_PERSON_NUMBER, ret->id.c_str(), ok);
     649          982 :         if (!ok) {
     650            0 :             handleVehicleError(true, ret);
     651          982 :         } else if (personNumber >= 0) {
     652          982 :             ret->parametersSet |= VEHPARS_PERSON_NUMBER_SET;
     653          982 :             ret->personNumber = personNumber;
     654              :         } else {
     655            0 :             handleVehicleError(true, ret, toString(SUMO_ATTR_PERSON_NUMBER) + " cannot be negative");
     656              :         }
     657              :     }
     658              :     // parse container number
     659       667541 :     if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_NUMBER)) {
     660          976 :         bool ok = true;
     661          976 :         int containerNumber = attrs.get<int>(SUMO_ATTR_CONTAINER_NUMBER, ret->id.c_str(), ok);
     662          976 :         if (!ok) {
     663            0 :             handleVehicleError(true, ret);
     664          976 :         } else if (containerNumber >= 0) {
     665          976 :             ret->parametersSet |= VEHPARS_CONTAINER_NUMBER_SET;
     666          976 :             ret->containerNumber = containerNumber;
     667              :         } else {
     668            0 :             handleVehicleError(true, ret, toString(SUMO_ATTR_CONTAINER_NUMBER) + " cannot be negative");
     669              :         }
     670              :     }
     671              :     // parse individual speedFactor
     672       667541 :     if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
     673        11380 :         bool ok = true;
     674        11380 :         double speedFactor = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR, ret->id.c_str(), ok);
     675        11380 :         if (!ok) {
     676            0 :             handleVehicleError(true, ret);
     677        11380 :         } else if (speedFactor > 0) {
     678        11380 :             ret->parametersSet |= VEHPARS_SPEEDFACTOR_SET;
     679        11380 :             ret->speedFactor = speedFactor;
     680              :         } else {
     681            0 :             handleVehicleError(true, ret, toString(SUMO_ATTR_SPEEDFACTOR) + " must be positive");
     682              :         }
     683              :     }
     684              :     // parse insertion checks
     685       667541 :     if (attrs.hasAttribute(SUMO_ATTR_INSERTIONCHECKS)) {
     686         1013 :         ret->parametersSet |= VEHPARS_INSERTION_CHECKS_SET;
     687         1013 :         bool ok = true;
     688         1013 :         std::string checks = attrs.get<std::string>(SUMO_ATTR_INSERTIONCHECKS, ret->id.c_str(), ok);
     689         1013 :         if (!ok) {
     690            4 :             handleVehicleError(true, ret);
     691              :         } else {
     692              :             try {
     693         1013 :                 ret->insertionChecks = SUMOVehicleParameter::parseInsertionChecks(checks);
     694            4 :             } catch (InvalidArgument& e) {
     695            4 :                 handleVehicleError(true, ret, e.what());
     696            4 :             }
     697              :         }
     698              :     }
     699              :     // parse parking access rights
     700       667537 :     if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {
     701            7 :         bool ok = true;
     702            7 :         std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, ret->id.c_str(), ok);
     703            7 :         if (!ok) {
     704            0 :             handleVehicleError(true, ret);
     705              :         } else {
     706            7 :             ret->parametersSet |= VEHPARS_PARKING_BADGES_SET;
     707            7 :             ret->parkingBadges = badges;
     708              :         }
     709            7 :     }
     710              :     // parse modes (transportables only)
     711       667537 :     ret->modes = 0;
     712       667537 :     if (attrs.hasAttribute(SUMO_ATTR_MODES)) {
     713            4 :         bool ok = true;
     714            4 :         const std::string modeString = attrs.get<std::string>(SUMO_ATTR_MODES, ret->id.c_str(), ok);
     715            4 :         if (!ok) {
     716            0 :             handleVehicleError(true, ret);
     717              :         } else {
     718              :             std::string errorMsg;
     719            8 :             if (!SUMOVehicleParameter::parsePersonModes(modeString, toString(tag), ret->id, ret->modes, errorMsg)) {
     720            0 :                 handleVehicleError(true, ret, errorMsg);
     721              :             }
     722              :         }
     723              :     }
     724              :     // parse usable vehicle types (transportables only)
     725       667537 :     if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
     726            0 :         bool ok = true;
     727            0 :         ret->vTypes = attrs.get<std::string>(SUMO_ATTR_VTYPES, ret->id.c_str(), ok);
     728            0 :         if (!ok) {
     729            0 :             handleVehicleError(true, ret);
     730              :         }
     731              :     }
     732              :     // parse speed (only used by calibrators flow)
     733              :     // also used by vehicle in saved state but this is parsed elsewhere
     734       667537 :     if (tag == SUMO_TAG_FLOW && attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     735          223 :         bool ok = true;
     736          223 :         double calibratorSpeed = attrs.get<double>(SUMO_ATTR_SPEED, ret->id.c_str(), ok);
     737          223 :         if (!ok) {
     738            0 :             handleVehicleError(true, ret);
     739          223 :         } else if (calibratorSpeed >= 0 || calibratorSpeed == -1) {
     740          223 :             ret->parametersSet |= VEHPARS_CALIBRATORSPEED_SET;
     741          223 :             ret->calibratorSpeed = calibratorSpeed;
     742              :         } else {
     743          322 :             handleVehicleError(true, ret, toString(SUMO_ATTR_SPEED) + " may not be negative");
     744              :         }
     745              :     }
     746              :     /*/ parse via
     747              :     if (attrs.hasAttribute(SUMO_ATTR_VIA)) {
     748              :         ret->setParameter |= VEHPARS_VIA_SET;
     749              :         SUMOSAXAttributes::parseStringVector(attrs.get<std::string>(SUMO_ATTR_VIA, ret->id.c_str(), ok), ret->via);
     750              :     }
     751              :     */
     752       667537 : }
     753              : 
     754              : 
     755              : SUMOVTypeParameter*
     756        64403 : SUMOVehicleParserHelper::beginVTypeParsing(const SUMOSAXAttributes& attrs, const bool hardFail, const std::string& file, const SUMOVTypeParameter* const base) {
     757        64403 :     const std::string id = (attrs.hasAttribute(SUMO_ATTR_ID) || base == nullptr) ? parseID(attrs, SUMO_TAG_VTYPE) : "";
     758        64403 :     if (!id.empty()) {
     759              :         // create vType
     760        64399 :         SUMOVehicleClass vClass = base == nullptr ? SVC_PASSENGER : base->vehicleClass;
     761        64399 :         if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
     762        37153 :             vClass = parseVehicleClass(attrs, id);
     763              :         }
     764              :         SUMOVTypeParameter* vType;
     765        64399 :         if (base == nullptr) {
     766        64349 :             vType = new SUMOVTypeParameter(id, vClass);
     767              :         } else {
     768           50 :             vType = new SUMOVTypeParameter(*base);
     769           50 :             vType->id = id;
     770           50 :             vType->vehicleClass = vClass;
     771              :         }
     772              :         // parse attributes
     773        64399 :         if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
     774        37153 :             vType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     775              :         }
     776        64399 :         if (attrs.hasAttribute(SUMO_ATTR_LENGTH)) {
     777        38324 :             bool ok = true;
     778        38324 :             const double length = attrs.get<double>(SUMO_ATTR_LENGTH, vType->id.c_str(), ok);
     779        38324 :             if (!ok) {
     780            0 :                 return handleVehicleTypeError(hardFail, vType);
     781        38324 :             } else if (length <= 0) {
     782            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LENGTH) + " must be greater than 0");
     783              :             } else {
     784        38324 :                 vType->length = length;
     785        38324 :                 vType->parametersSet |= VTYPEPARS_LENGTH_SET;
     786              :             }
     787              :         }
     788        64399 :         if (attrs.hasAttribute(SUMO_ATTR_MINGAP)) {
     789        36122 :             bool ok = true;
     790        36122 :             const double minGap = attrs.get<double>(SUMO_ATTR_MINGAP, vType->id.c_str(), ok);
     791        36122 :             if (!ok) {
     792            0 :                 return handleVehicleTypeError(hardFail, vType);
     793        36122 :             } else if (minGap < 0) {
     794            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP) + " must be equal or greater than 0");
     795              :             } else {
     796        36122 :                 vType->minGap = minGap;
     797        36122 :                 vType->parametersSet |= VTYPEPARS_MINGAP_SET;
     798              :             }
     799              :         }
     800        64399 :         if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
     801        37545 :             bool ok = true;
     802        37545 :             const double maxSpeed = attrs.get<double>(SUMO_ATTR_MAXSPEED, vType->id.c_str(), ok);
     803        37545 :             if (!ok) {
     804            0 :                 return handleVehicleTypeError(hardFail, vType);
     805        37545 :             } else if (maxSpeed <= 0) {
     806            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED) + " must be greater than 0");
     807              :             } else {
     808        37545 :                 vType->maxSpeed = maxSpeed;
     809        37545 :                 vType->parametersSet |= VTYPEPARS_MAXSPEED_SET;
     810              :             }
     811              :         }
     812        64399 :         if (attrs.hasAttribute(SUMO_ATTR_DESIRED_MAXSPEED)) {
     813           87 :             bool ok = true;
     814           87 :             const double desiredMaxSpeed = attrs.get<double>(SUMO_ATTR_DESIRED_MAXSPEED, vType->id.c_str(), ok);
     815           87 :             if (!ok) {
     816            0 :                 return handleVehicleTypeError(hardFail, vType);
     817           87 :             } else if (desiredMaxSpeed <= 0) {
     818            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_DESIRED_MAXSPEED) + " must be greater than 0");
     819              :             } else {
     820           87 :                 vType->desiredMaxSpeed = desiredMaxSpeed;
     821           87 :                 vType->parametersSet |= VTYPEPARS_DESIRED_MAXSPEED_SET;
     822              :             }
     823        64312 :         } else if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
     824        37524 :             if (vClass == SVC_PEDESTRIAN) {
     825              :                 // backward compatibility because pedestrian maxSpeed was subject to speedFactor up to 1.14.1
     826        25880 :                 vType->desiredMaxSpeed = vType->maxSpeed;;
     827        77636 :                 vType->maxSpeed = MAX2(vType->maxSpeed, SUMOVTypeParameter::VClassDefaultValues(vClass).maxSpeed);
     828        11644 :             } else if (vClass == SVC_BICYCLE) {
     829              :                 // backward compatibility because default desired speed did not exist up to 1.14.1
     830          192 :                 vType->desiredMaxSpeed = MAX2(vType->maxSpeed, vType->desiredMaxSpeed);
     831              :             }
     832              :         }
     833              : 
     834        64399 :         if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
     835         2509 :             bool ok = true;
     836         2509 :             vType->speedFactor.parse(attrs.get<std::string>(SUMO_ATTR_SPEEDFACTOR, vType->id.c_str(), ok), hardFail);
     837         2509 :             if (!ok) {
     838            0 :                 return handleVehicleTypeError(hardFail, vType);
     839              :             } else {
     840         2509 :                 vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
     841              :             }
     842              :         }
     843        64399 :         if (attrs.hasAttribute(SUMO_ATTR_SPEEDDEV)) {
     844         2676 :             bool ok = true;
     845         2676 :             const double speedDev = attrs.get<double>(SUMO_ATTR_SPEEDDEV, vType->id.c_str(), ok);
     846         2676 :             if (!ok) {
     847            0 :                 return handleVehicleTypeError(hardFail, vType);
     848         2676 :             } else if (speedDev < 0) {
     849            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SPEEDDEV) + " must be equal or greater than 0");
     850              :             } else {
     851         2676 :                 vType->speedFactor.setParameter(1, speedDev);
     852         2676 :                 vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
     853              :             }
     854              :         }
     855              :         // validate speed distribution
     856        64399 :         const std::string& error = vType->speedFactor.isValid();
     857        64399 :         if (error != "") {
     858           14 :             return handleVehicleTypeError(hardFail, vType, "Invalid speed distribution when parsing vType '" + vType->id + "' (" + error + ")");
     859              :         }
     860        64392 :         if (attrs.hasAttribute(SUMO_ATTR_ACTIONSTEPLENGTH)) {
     861          226 :             bool ok = true;
     862          226 :             const double actionStepLengthSecs = attrs.get<double>(SUMO_ATTR_ACTIONSTEPLENGTH, vType->id.c_str(), ok);
     863          226 :             if (!ok) {
     864            0 :                 return handleVehicleTypeError(hardFail, vType);
     865              :             } else {
     866              :                 // processActionStepLength(...) function includes warnings
     867          226 :                 vType->actionStepLength = processActionStepLength(actionStepLengthSecs);
     868          226 :                 vType->parametersSet |= VTYPEPARS_ACTIONSTEPLENGTH_SET;
     869              :             }
     870              :         }
     871        64392 :         if (attrs.hasAttribute(SUMO_ATTR_EMISSIONCLASS)) {
     872         1876 :             bool ok = true;
     873         1876 :             const std::string parsedEmissionClass = attrs.getOpt<std::string>(SUMO_ATTR_EMISSIONCLASS, id.c_str(), ok, "");
     874              :             // check if emission class is correct
     875              :             try {
     876         1876 :                 vType->emissionClass = PollutantsInterface::getClassByName(parsedEmissionClass);
     877         1876 :                 vType->parametersSet |= VTYPEPARS_EMISSIONCLASS_SET;
     878            0 :             } catch (...) {
     879            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_EMISSIONCLASS) + " with name '" + parsedEmissionClass + "' doesn't exist.");
     880            0 :             }
     881              :         }
     882        64392 :         if (attrs.hasAttribute(SUMO_ATTR_MASS)) {
     883          341 :             bool ok = true;
     884          341 :             const double mass = attrs.get<double>(SUMO_ATTR_MASS, vType->id.c_str(), ok);
     885          341 :             if (!ok) {
     886            0 :                 return handleVehicleTypeError(hardFail, vType);
     887          341 :             } else if (mass < 0) {
     888            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MASS) + " must be equal or greater than 0");
     889              :             } else {
     890          341 :                 vType->mass = mass;
     891          341 :                 vType->parametersSet |= VTYPEPARS_MASS_SET;
     892              :             }
     893              :         }
     894        64392 :         if (attrs.hasAttribute(SUMO_ATTR_IMPATIENCE)) {
     895          247 :             bool ok = true;
     896          247 :             const std::string impatienceStr = attrs.get<std::string>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
     897          247 :             if (!ok) {
     898            0 :                 return handleVehicleTypeError(hardFail, vType);
     899          247 :             } else if (impatienceStr == "off") {
     900           12 :                 vType->impatience = -std::numeric_limits<double>::max();
     901              :             } else {
     902          235 :                 const double impatienceDouble = attrs.get<double>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
     903          235 :                 if (!ok) {
     904            0 :                     return handleVehicleTypeError(hardFail, vType);
     905              :                 } else {
     906          235 :                     vType->impatience = impatienceDouble;
     907          235 :                     vType->parametersSet |= VTYPEPARS_IMPATIENCE_SET;
     908              :                 }
     909              :             }
     910              :         }
     911        64392 :         if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
     912        26760 :             bool ok = true;
     913        26760 :             const double width = attrs.get<double>(SUMO_ATTR_WIDTH, vType->id.c_str(), ok);
     914        26760 :             if (!ok) {
     915            0 :                 return handleVehicleTypeError(hardFail, vType);
     916        26760 :             } else if (width <= 0) {
     917            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_WIDTH) + " must be greater than 0");
     918              :             } else {
     919        26760 :                 vType->width = width;
     920        26760 :                 vType->parametersSet |= VTYPEPARS_WIDTH_SET;
     921        26760 :                 if (vClass == SVC_PEDESTRIAN
     922        52867 :                         && OptionsCont::getOptions().exists("pedestrian.striping.stripe-width")
     923        78974 :                         && OptionsCont::getOptions().getString("pedestrian.model") == "striping"
     924        82155 :                         && OptionsCont::getOptions().getFloat("pedestrian.striping.stripe-width") < vType->width) {
     925           12 :                     WRITE_WARNINGF(TL("Pedestrian vType '%' width % is larger than pedestrian.striping.stripe-width and this may cause collisions with vehicles."), id, vType->width);
     926              :                 }
     927              :             }
     928              :         }
     929        64392 :         if (attrs.hasAttribute(SUMO_ATTR_HEIGHT)) {
     930          355 :             bool ok = true;
     931          355 :             const double height = attrs.get<double>(SUMO_ATTR_HEIGHT, vType->id.c_str(), ok);
     932          355 :             if (!ok) {
     933            0 :                 return handleVehicleTypeError(hardFail, vType);
     934          355 :             } else if (height < 0) {
     935            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_HEIGHT) + " must be equal or greater than 0");
     936              :             } else {
     937          355 :                 vType->height = height;
     938          355 :                 vType->parametersSet |= VTYPEPARS_HEIGHT_SET;
     939              :             }
     940              :         }
     941        64392 :         if (attrs.hasAttribute(SUMO_ATTR_GUISHAPE)) {
     942        27190 :             vType->shape = parseGuiShape(attrs, vType->id);
     943        27190 :             if (vType->shape != SUMOVehicleShape::UNKNOWN) {
     944        27190 :                 vType->parametersSet |= VTYPEPARS_SHAPE_SET;
     945              :             }
     946              :         }
     947        64392 :         if (attrs.hasAttribute(SUMO_ATTR_OSGFILE)) {
     948           21 :             bool ok = true;
     949           21 :             const std::string osgFile = attrs.get<std::string>(SUMO_ATTR_OSGFILE, vType->id.c_str(), ok);
     950           21 :             if (!ok) {
     951            0 :                 return handleVehicleTypeError(hardFail, vType);
     952              :             } else {
     953           21 :                 vType->osgFile = osgFile;
     954           21 :                 vType->parametersSet |= VTYPEPARS_OSGFILE_SET;
     955              :             }
     956              :         }
     957        64392 :         if (attrs.hasAttribute(SUMO_ATTR_IMGFILE)) {
     958           28 :             bool ok = true;
     959           28 :             std::string imgFile = attrs.get<std::string>(SUMO_ATTR_IMGFILE, vType->id.c_str(), ok);
     960           28 :             if (!ok) {
     961            0 :                 return handleVehicleTypeError(hardFail, vType);
     962              :             } else {
     963              :                 // check relative path
     964           28 :                 if ((imgFile != "") && !FileHelpers::isAbsolute(imgFile)) {
     965           56 :                     imgFile = FileHelpers::getConfigurationRelative(file, imgFile);
     966              :                 }
     967           28 :                 vType->imgFile = imgFile;
     968           28 :                 vType->parametersSet |= VTYPEPARS_IMGFILE_SET;
     969              :             }
     970              :         }
     971        64392 :         if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
     972        22824 :             bool ok = true;
     973        22824 :             const RGBColor color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, vType->id.c_str(), ok);
     974        22824 :             if (!ok) {
     975            8 :                 return handleVehicleTypeError(hardFail, vType);
     976              :             } else {
     977        22816 :                 vType->color = color;
     978        22816 :                 vType->parametersSet |= VTYPEPARS_COLOR_SET;
     979              :             }
     980              :         } else {
     981        41568 :             vType->color = RGBColor::YELLOW;
     982              :         }
     983        64384 :         if (attrs.hasAttribute(SUMO_ATTR_PROB)) {
     984          705 :             bool ok = true;
     985          705 :             const double defaultProbability = attrs.get<double>(SUMO_ATTR_PROB, vType->id.c_str(), ok);
     986          705 :             if (!ok) {
     987            0 :                 return handleVehicleTypeError(hardFail, vType);
     988          705 :             } else if (defaultProbability < 0) {
     989            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PROB) + " must be equal or greater than 0");
     990              :             } else {
     991          705 :                 vType->defaultProbability = defaultProbability;
     992          705 :                 vType->parametersSet |= VTYPEPARS_PROBABILITY_SET;
     993              :             }
     994              :         }
     995        64384 :         if (attrs.hasAttribute(SUMO_ATTR_LANE_CHANGE_MODEL)) {
     996          476 :             bool ok = true;
     997          476 :             std::string lcmS = attrs.get<std::string>(SUMO_ATTR_LANE_CHANGE_MODEL, vType->id.c_str(), ok);
     998          476 :             if (!ok) {
     999            0 :                 return handleVehicleTypeError(hardFail, vType);
    1000          476 :             } else if (lcmS == "JE2013") {
    1001            0 :                 WRITE_WARNING(TL("Lane change model 'JE2013' is deprecated. Using default model instead."));
    1002              :                 lcmS = "default";
    1003              :             }
    1004              :             if (SUMOXMLDefinitions::LaneChangeModels.hasString(lcmS)) {
    1005          471 :                 vType->lcModel = SUMOXMLDefinitions::LaneChangeModels.get(lcmS);
    1006          471 :                 vType->parametersSet |= VTYPEPARS_LANE_CHANGE_MODEL_SET;
    1007              :             } else {
    1008           15 :                 return handleVehicleTypeError(hardFail, vType, "Unknown lane change model '" + lcmS + "' when parsing vType '" + vType->id + "'");
    1009              :             }
    1010              :         }
    1011        64379 :         if (attrs.hasAttribute(SUMO_ATTR_CAR_FOLLOW_MODEL)) {
    1012         1343 :             bool ok = true;
    1013         1343 :             const std::string cfmValue = attrs.get<std::string>(SUMO_ATTR_CAR_FOLLOW_MODEL, vType->id.c_str(), ok);
    1014         1343 :             if (!ok) {
    1015            0 :                 return handleVehicleTypeError(hardFail, vType);
    1016              :             } else if (SUMOXMLDefinitions::CarFollowModels.hasString(cfmValue)) {
    1017         1337 :                 vType->cfModel = SUMOXMLDefinitions::CarFollowModels.get(cfmValue);
    1018         1337 :                 vType->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
    1019              :             } else {
    1020           18 :                 return handleVehicleTypeError(hardFail, vType, "Unknown car following model '" + cfmValue + "' when parsing vType '" + vType->id + "'");
    1021              :             }
    1022              :         }
    1023        64373 :         if (attrs.hasAttribute(SUMO_ATTR_PERSON_CAPACITY)) {
    1024          410 :             bool ok = true;
    1025          410 :             const int personCapacity = attrs.get<int>(SUMO_ATTR_PERSON_CAPACITY, vType->id.c_str(), ok);
    1026          410 :             if (!ok) {
    1027            0 :                 return handleVehicleTypeError(hardFail, vType);
    1028          410 :             } else if (personCapacity < 0) {
    1029            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PERSON_CAPACITY) + " must be equal or greater than 0");
    1030              :             } else {
    1031          410 :                 vType->personCapacity = personCapacity;
    1032          410 :                 vType->parametersSet |= VTYPEPARS_PERSON_CAPACITY;
    1033              :             }
    1034              :         }
    1035        64373 :         if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_CAPACITY)) {
    1036          380 :             bool ok = true;
    1037          380 :             const int containerCapacity = attrs.get<int>(SUMO_ATTR_CONTAINER_CAPACITY, vType->id.c_str(), ok);
    1038          380 :             if (!ok) {
    1039            0 :                 return handleVehicleTypeError(hardFail, vType);
    1040          380 :             } else if (containerCapacity < 0) {
    1041            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_CONTAINER_CAPACITY) + " must be equal or greater than 0");
    1042              :             } else {
    1043          380 :                 vType->containerCapacity = containerCapacity;
    1044          380 :                 vType->parametersSet |= VTYPEPARS_CONTAINER_CAPACITY;
    1045              :             }
    1046              :         }
    1047        64373 :         if (attrs.hasAttribute(SUMO_ATTR_BOARDING_DURATION)) {
    1048          121 :             bool ok = true;
    1049          121 :             const SUMOTime boardingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_BOARDING_DURATION, vType->id.c_str(), ok);
    1050          121 :             if (!ok) {
    1051            0 :                 return handleVehicleTypeError(hardFail, vType);
    1052          121 :             } else if (boardingDuration < 0) {
    1053            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_DURATION) + " must be equal or greater than 0");
    1054              :             } else {
    1055          121 :                 vType->boardingDuration = boardingDuration;
    1056          121 :                 vType->parametersSet |= VTYPEPARS_BOARDING_DURATION;
    1057              :             }
    1058              :         }
    1059        64373 :         if (attrs.hasAttribute(SUMO_ATTR_LOADING_DURATION)) {
    1060           83 :             bool ok = true;
    1061           83 :             const SUMOTime loadingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_LOADING_DURATION, vType->id.c_str(), ok);
    1062           83 :             if (!ok) {
    1063            0 :                 return handleVehicleTypeError(hardFail, vType);
    1064           83 :             } else if (loadingDuration < 0) {
    1065            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LOADING_DURATION) + " must be equal or greater than 0");
    1066              :             } else {
    1067           83 :                 vType->loadingDuration = loadingDuration;
    1068           83 :                 vType->parametersSet |= VTYPEPARS_LOADING_DURATION;
    1069              :             }
    1070              :         }
    1071        64373 :         if (attrs.hasAttribute(SUMO_ATTR_SCALE)) {
    1072           40 :             bool ok = true;
    1073           40 :             const double scale = attrs.get<double>(SUMO_ATTR_SCALE, id.c_str(), ok);
    1074           40 :             if (!ok) {
    1075            0 :                 return handleVehicleTypeError(hardFail, vType);
    1076           40 :             } else if (scale < 0) {
    1077            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SCALE) + " may be not be negative");
    1078              :             } else {
    1079           40 :                 vType->scale = scale;
    1080           40 :                 vType->parametersSet |= VTYPEPARS_SCALE_SET;
    1081              :             }
    1082              :         }
    1083        64373 :         if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT)) {
    1084           25 :             bool ok = true;
    1085           25 :             const SUMOTime ttt = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT, vType->id.c_str(), ok);
    1086           25 :             if (!ok) {
    1087            0 :                 return handleVehicleTypeError(hardFail, vType);
    1088              :             } else {
    1089           25 :                 vType->timeToTeleport = ttt;
    1090           25 :                 vType->parametersSet |= VTYPEPARS_TTT_SET;
    1091              :             }
    1092              :         }
    1093        64373 :         if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT_BIDI)) {
    1094            5 :             bool ok = true;
    1095            5 :             const SUMOTime tttb = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT_BIDI, vType->id.c_str(), ok);
    1096            5 :             if (!ok) {
    1097            0 :                 return handleVehicleTypeError(hardFail, vType);
    1098              :             } else {
    1099            5 :                 vType->timeToTeleportBidi = tttb;
    1100            5 :                 vType->parametersSet |= VTYPEPARS_TTT_BIDI_SET;
    1101              :             }
    1102              :         }
    1103        64373 :         if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR_PREMATURE)) {
    1104           63 :             bool ok = true;
    1105           63 :             const double sfp = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR_PREMATURE, id.c_str(), ok);
    1106           63 :             if (!ok) {
    1107            0 :                 return handleVehicleTypeError(hardFail, vType);
    1108              :             } else {
    1109           63 :                 vType->speedFactorPremature = sfp;
    1110           63 :                 vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_PREMATURE_SET;
    1111              :             }
    1112              :         }
    1113        64373 :         if (attrs.hasAttribute(SUMO_ATTR_BOARDING_FACTOR)) {
    1114            8 :             bool ok = true;
    1115            8 :             const double bf = attrs.get<double>(SUMO_ATTR_BOARDING_FACTOR, id.c_str(), ok);
    1116            8 :             if (!ok) {
    1117            0 :                 return handleVehicleTypeError(hardFail, vType);
    1118            8 :             } else if (bf < 0) {
    1119            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_FACTOR) + " must be equal or greater than 0");
    1120              :             } else {
    1121            8 :                 vType->boardingFactor = bf;
    1122            8 :                 vType->parametersSet |= VTYPEPARS_BOARDING_FACTOR_SET;
    1123              :             }
    1124              :         }
    1125        64373 :         if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED_LAT)) {
    1126           72 :             bool ok = true;
    1127           72 :             const double maxSpeedLat = attrs.get<double>(SUMO_ATTR_MAXSPEED_LAT, vType->id.c_str(), ok);
    1128           72 :             if (!ok) {
    1129            0 :                 return handleVehicleTypeError(hardFail, vType);
    1130           72 :             } else if (maxSpeedLat <= 0) {
    1131            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED_LAT) + " must be greater than 0");
    1132              :             } else {
    1133           72 :                 vType->maxSpeedLat = maxSpeedLat;
    1134           72 :                 vType->parametersSet |= VTYPEPARS_MAXSPEED_LAT_SET;
    1135              :             }
    1136              :         }
    1137        64373 :         if (attrs.hasAttribute(SUMO_ATTR_MINGAP_LAT)) {
    1138          593 :             bool ok = true;
    1139          593 :             const double minGapLat = attrs.get<double>(SUMO_ATTR_MINGAP_LAT, vType->id.c_str(), ok);
    1140          593 :             if (!ok) {
    1141            0 :                 return handleVehicleTypeError(hardFail, vType);
    1142          593 :             } else if (minGapLat < 0) {
    1143            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP_LAT) + " must be equal or greater than 0");
    1144              :             } else {
    1145          593 :                 vType->minGapLat = minGapLat;
    1146          593 :                 vType->parametersSet |= VTYPEPARS_MINGAP_LAT_SET;
    1147              :             }
    1148              :         }
    1149        64373 :         if (attrs.hasAttribute(SUMO_ATTR_LATALIGNMENT)) {
    1150         1704 :             bool ok = true;
    1151         1704 :             const std::string alignS = attrs.get<std::string>(SUMO_ATTR_LATALIGNMENT, vType->id.c_str(), ok);
    1152         1704 :             if (!ok) {
    1153            0 :                 return handleVehicleTypeError(hardFail, vType);
    1154              :             } else {
    1155              :                 double lao;
    1156              :                 LatAlignmentDefinition lad;
    1157         1704 :                 if (SUMOVTypeParameter::parseLatAlignment(alignS, lao, lad)) {
    1158         1704 :                     vType->latAlignmentOffset = lao;
    1159         1704 :                     vType->latAlignmentProcedure = lad;
    1160         1704 :                     vType->parametersSet |= VTYPEPARS_LATALIGNMENT_SET;
    1161              :                 } else {
    1162            0 :                     return handleVehicleTypeError(hardFail, vType, "Unknown lateral alignment '" + alignS + "' when parsing vType '" + vType->id + "';\n must be one of (\"right\", \"center\", \"arbitrary\", \"nice\", \"compact\", \"left\" or a float)");
    1163              :                 }
    1164              :             }
    1165              :         }
    1166        64373 :         if (attrs.hasAttribute(SUMO_ATTR_MANEUVER_ANGLE_TIMES)) {
    1167            5 :             bool ok = true;
    1168            5 :             const std::string angleTimesS = attrs.get<std::string>(SUMO_ATTR_MANEUVER_ANGLE_TIMES, vType->id.c_str(), ok);
    1169            5 :             if (!ok) {
    1170            0 :                 return handleVehicleTypeError(hardFail, vType);
    1171           10 :             } else if (parseAngleTimesMap(vType, angleTimesS)) {
    1172            5 :                 vType->parametersSet |= VTYPEPARS_MANEUVER_ANGLE_TIMES_SET;
    1173              :             } else {
    1174            0 :                 return handleVehicleTypeError(hardFail, vType, "Invalid manoeuver angle times map for vType '" + vType->id + "'");
    1175              :             }
    1176              :         }
    1177        64373 :         if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {
    1178           12 :             bool ok = true;
    1179           12 :             std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, vType->id.c_str(), ok);
    1180           12 :             if (!ok) {
    1181            0 :                 return handleVehicleTypeError(hardFail, vType);
    1182              :             } else {
    1183           12 :                 vType->parametersSet |= VTYPEPARS_PARKING_BADGES_SET;
    1184           12 :                 vType->parkingBadges = badges;
    1185              :             }
    1186           12 :         }
    1187              :         // try to parse Car Following Model params
    1188        64373 :         if (!parseCFMParams(vType, vType->cfModel, attrs, false)) {
    1189            0 :             return handleVehicleTypeError(hardFail, vType, "Invalid parsing embedded VType");
    1190              :         }
    1191              :         // try to parse Lane Change Model params
    1192        64373 :         if (!parseLCParams(vType, vType->lcModel, attrs)) {
    1193            0 :             return handleVehicleTypeError(hardFail, vType, "Invalid Lane Change Model Parameters");
    1194              :         }
    1195              :         // try to Junction Model params
    1196        64373 :         if (!parseJMParams(vType, attrs)) {
    1197           26 :             return handleVehicleTypeError(hardFail, vType, "Invalid Junction Model Parameters");
    1198              :         }
    1199              :         // all ok, then return vType
    1200              :         return vType;
    1201            4 :     } else if (base != nullptr) {
    1202              :         return const_cast<SUMOVTypeParameter*>(base);
    1203              :     } else {
    1204           34 :         return handleVehicleTypeError(hardFail, nullptr, "VType cannot be created");
    1205              :     }
    1206              : }
    1207              : 
    1208              : 
    1209              : bool
    1210            5 : SUMOVehicleParserHelper::parseAngleTimesMap(SUMOVTypeParameter* vtype, const std::string atm) {
    1211           15 :     StringTokenizer st(atm, ",");
    1212              :     std::map<int, std::pair<SUMOTime, SUMOTime>> angleTimesMap;
    1213              :     int tripletCount = 0;
    1214           30 :     while (st.hasNext()) {
    1215           25 :         StringTokenizer pos(st.next());
    1216           25 :         if (pos.size() != 3) {
    1217            0 :             WRITE_ERRORF(TL("maneuverAngleTimes format for vType '%' % contains an invalid triplet."), vtype->id, atm);
    1218            0 :             return false;
    1219              :         } else {
    1220              :             try {
    1221           25 :                 const int angle = StringUtils::toInt(pos.next());
    1222           25 :                 const SUMOTime t1 = string2time(pos.next());
    1223           25 :                 const SUMOTime t2 = string2time(pos.next());
    1224           25 :                 angleTimesMap[angle] = std::make_pair(t1, t2);
    1225            0 :             } catch (...) {
    1226            0 :                 WRITE_ERRORF(TL("Triplet '%' for vType '%' maneuverAngleTimes cannot be parsed as 'int double double'"), st.get(tripletCount), vtype->id);
    1227              :                 return false;
    1228            0 :             }
    1229           25 :             tripletCount++;
    1230              :         }
    1231           25 :     }
    1232            5 :     if (angleTimesMap.size() > 0) {
    1233              :         vtype->myManoeuverAngleTimes.clear();
    1234           30 :         for (const auto& angleTime : angleTimesMap) {
    1235              :             vtype->myManoeuverAngleTimes.insert(angleTime);
    1236              :         }
    1237              :         angleTimesMap.clear();
    1238            5 :         return true;
    1239              :     } else {
    1240              :         return false;
    1241              :     }
    1242            5 : }
    1243              : 
    1244              : 
    1245              : bool
    1246        64389 : SUMOVehicleParserHelper::parseCFMParams(SUMOVTypeParameter* into, const SumoXMLTag element, const SUMOSAXAttributes& attrs, const bool nestedCFM) {
    1247        64389 :     const CFAttrMap& allowedCFM = getAllowedCFModelAttrs();
    1248              :     CFAttrMap::const_iterator cf_it = allowedCFM.find(element);
    1249              :     // check if given CFM is allowed
    1250        64389 :     if (cf_it == allowedCFM.end()) {
    1251            0 :         if (SUMOXMLDefinitions::Tags.has((int)element)) {
    1252            0 :             WRITE_ERRORF(TL("Unknown car-following model % when parsing vType '%'"), toString(element), into->id);
    1253              :         } else {
    1254            0 :             WRITE_ERRORF(TL("Unknown car-following model when parsing vType '%'"), into->id);
    1255              :         }
    1256            0 :         return false;
    1257              :     }
    1258              :     // check if we're parsing a nested CFM
    1259        64389 :     if (nestedCFM) {
    1260           16 :         into->cfModel = cf_it->first;
    1261           16 :         into->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
    1262              :     }
    1263              :     // set CFM values
    1264       848413 :     for (const auto& it : cf_it->second) {
    1265       784024 :         if (attrs.hasAttribute(it)) {
    1266              :             // first obtain  CFM attribute in string format
    1267        47409 :             bool ok = true;
    1268        47409 :             std::string parsedCFMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
    1269              :             // check CFM Attribute
    1270        47409 :             if (!ok) {
    1271              :                 return false;
    1272        47409 :             } else if (it == SUMO_ATTR_TRAIN_TYPE) {
    1273              :                 // check if train value is valid
    1274          271 :                 if (!SUMOXMLDefinitions::TrainTypes.hasString(parsedCFMAttribute)) {
    1275            0 :                     WRITE_ERROR("Invalid train type '" + parsedCFMAttribute + "' used in Car-Following-Attribute " + toString(it));
    1276            0 :                     return false;
    1277              :                 }
    1278              :                 // add parsedCFMAttribute to cfParameter
    1279          271 :                 into->cfParameter[it] = parsedCFMAttribute;
    1280        47138 :             } else if (it == SUMO_ATTR_SPEED_TABLE || it == SUMO_ATTR_TRACTION_TABLE || it == SUMO_ATTR_RESISTANCE_TABLE) {
    1281           52 :                 into->cfParameter[it] = parsedCFMAttribute;
    1282        47086 :             } else if (it == SUMO_ATTR_CF_IDM_STEPPING) {
    1283              :                 // declare a int in wich save CFM int attribute
    1284              :                 double CFMDoubleAttribute = -1;
    1285              :                 try {
    1286              :                     // obtain CFM attribute in int format
    1287            6 :                     CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
    1288            0 :                 } catch (...) {
    1289            0 :                     WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
    1290              :                     return false;
    1291            0 :                 }
    1292            6 :                 if (CFMDoubleAttribute <= 0) {
    1293            0 :                     WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
    1294            0 :                     return false;
    1295              :                 }
    1296              :                 // add parsedCFMAttribute to cfParameter
    1297            6 :                 into->cfParameter[it] = parsedCFMAttribute;
    1298        47080 :             } else if (it == SUMO_ATTR_MAXACCEL_PROFILE || it == SUMO_ATTR_DESACCEL_PROFILE) {
    1299           32 :                 if (validProfile(into, parsedCFMAttribute, it)) {
    1300           16 :                     into->cfParameter[it] = parsedCFMAttribute;
    1301              :                 } else {
    1302            0 :                     WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed as a vector of <speed accel> pairs"), toString(it));
    1303            0 :                     return false;
    1304              :                 }
    1305              :             } else {
    1306              :                 // declare a double in wich save CFM float attribute
    1307              :                 double CFMDoubleAttribute = -1;
    1308              :                 try {
    1309              :                     // obtain CFM attribute in double format
    1310        47064 :                     CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
    1311            0 :                 } catch (...) {
    1312            0 :                     WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
    1313              :                     return false;
    1314            0 :                 }
    1315              :                 // check attributes of type "positiveFloatType" (> 0)
    1316        47064 :                 switch (it) {
    1317        21640 :                     case SUMO_ATTR_ACCEL:
    1318              :                     case SUMO_ATTR_DECEL:
    1319              :                     case SUMO_ATTR_APPARENTDECEL:
    1320              :                     case SUMO_ATTR_EMERGENCYDECEL:
    1321              :                     case SUMO_ATTR_TAU:
    1322        21640 :                         if (CFMDoubleAttribute <= 0) {
    1323            0 :                             WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
    1324            0 :                             return false;
    1325              :                         }
    1326              :                         break;
    1327              :                     default:
    1328              :                         break;
    1329              :                 }
    1330              :                 // check attributes restricted to [0-1]
    1331        47064 :                 switch (it) {
    1332        24783 :                     case SUMO_ATTR_SIGMA:
    1333        24783 :                         if ((CFMDoubleAttribute < 0) || (CFMDoubleAttribute > 1)) {
    1334            0 :                             WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
    1335            0 :                             return false;
    1336              :                         }
    1337              :                         break;
    1338              :                     default:
    1339              :                         break;
    1340              :                 }
    1341              :                 // add parsedCFMAttribute to cfParameter
    1342        47064 :                 into->cfParameter[it] = parsedCFMAttribute;
    1343              :             }
    1344              :         }
    1345              :     }
    1346              :     // all CFM successfully parsed, then return true
    1347              :     return true;
    1348              : }
    1349              : 
    1350              : 
    1351              : const SUMOVehicleParserHelper::CFAttrMap&
    1352        64389 : SUMOVehicleParserHelper::getAllowedCFModelAttrs() {
    1353              :     // init on first use
    1354        64389 :     if (allowedCFModelAttrs.size() == 0) {
    1355              :         std::set<SumoXMLAttr> genericParams;
    1356        27514 :         genericParams.insert(SUMO_ATTR_TAU);
    1357        27514 :         genericParams.insert(SUMO_ATTR_ACCEL);
    1358        27514 :         genericParams.insert(SUMO_ATTR_DECEL);
    1359        27514 :         genericParams.insert(SUMO_ATTR_APPARENTDECEL);
    1360        27514 :         genericParams.insert(SUMO_ATTR_EMERGENCYDECEL);
    1361        27514 :         genericParams.insert(SUMO_ATTR_SPEED_TABLE);
    1362        27514 :         genericParams.insert(SUMO_ATTR_MAXACCEL_PROFILE);
    1363        27514 :         genericParams.insert(SUMO_ATTR_DESACCEL_PROFILE);
    1364        27514 :         genericParams.insert(SUMO_ATTR_COLLISION_MINGAP_FACTOR);
    1365        27514 :         genericParams.insert(SUMO_ATTR_STARTUP_DELAY);
    1366              :         // Krauss
    1367              :         std::set<SumoXMLAttr> kraussParams(genericParams);
    1368        27514 :         kraussParams.insert(SUMO_ATTR_SIGMA);
    1369        27514 :         kraussParams.insert(SUMO_ATTR_SIGMA_STEP);
    1370        27514 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS] = kraussParams;
    1371        27514 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_ORIG1] = kraussParams;
    1372        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_PLUS_SLOPE] = kraussParams;
    1373              :         std::set<SumoXMLAttr> allParams(kraussParams);
    1374              :         // KraussX
    1375              :         std::set<SumoXMLAttr> kraussXParams(kraussParams);
    1376        27514 :         kraussXParams.insert(SUMO_ATTR_TMP1);
    1377        27514 :         kraussXParams.insert(SUMO_ATTR_TMP2);
    1378        27514 :         kraussXParams.insert(SUMO_ATTR_TMP3);
    1379        27514 :         kraussXParams.insert(SUMO_ATTR_TMP4);
    1380        27514 :         kraussXParams.insert(SUMO_ATTR_TMP5);
    1381        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSSX] = kraussXParams;
    1382        27514 :         allParams.insert(kraussXParams.begin(), kraussXParams.end());
    1383              :         // SmartSK
    1384              :         std::set<SumoXMLAttr> smartSKParams(genericParams);
    1385        27514 :         smartSKParams.insert(SUMO_ATTR_SIGMA);
    1386        27514 :         smartSKParams.insert(SUMO_ATTR_TMP1);
    1387        27514 :         smartSKParams.insert(SUMO_ATTR_TMP2);
    1388        27514 :         smartSKParams.insert(SUMO_ATTR_TMP3);
    1389        27514 :         smartSKParams.insert(SUMO_ATTR_TMP4);
    1390        27514 :         smartSKParams.insert(SUMO_ATTR_TMP5);
    1391        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_SMART_SK] = smartSKParams;
    1392        27514 :         allParams.insert(smartSKParams.begin(), smartSKParams.end());
    1393              :         // Daniel
    1394              :         std::set<SumoXMLAttr> daniel1Params(genericParams);
    1395        27514 :         daniel1Params.insert(SUMO_ATTR_SIGMA);
    1396        27514 :         daniel1Params.insert(SUMO_ATTR_TMP1);
    1397        27514 :         daniel1Params.insert(SUMO_ATTR_TMP2);
    1398        27514 :         daniel1Params.insert(SUMO_ATTR_TMP3);
    1399        27514 :         daniel1Params.insert(SUMO_ATTR_TMP4);
    1400        27514 :         daniel1Params.insert(SUMO_ATTR_TMP5);
    1401        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_DANIEL1] = daniel1Params;
    1402        27514 :         allParams.insert(daniel1Params.begin(), daniel1Params.end());
    1403              :         // Peter Wagner
    1404              :         std::set<SumoXMLAttr> pwagParams(genericParams);
    1405        27514 :         pwagParams.insert(SUMO_ATTR_SIGMA);
    1406        27514 :         pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_TAULAST);
    1407        27514 :         pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_APPROB);
    1408        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_PWAGNER2009] = pwagParams;
    1409        27514 :         allParams.insert(pwagParams.begin(), pwagParams.end());
    1410              :         // IDM params
    1411              :         std::set<SumoXMLAttr> idmParams(genericParams);
    1412        27514 :         idmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
    1413        27514 :         idmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
    1414        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_IDM] = idmParams;
    1415        27514 :         allParams.insert(idmParams.begin(), idmParams.end());
    1416              :         // EIDM
    1417              :         std::set<SumoXMLAttr> eidmParams(genericParams);
    1418        27514 :         eidmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
    1419        27514 :         eidmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
    1420        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD);
    1421        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE);
    1422        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_REACTION);
    1423        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE);
    1424        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_C_COOLNESS);
    1425        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_LEADER);
    1426        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_GAP);
    1427        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_ERROR);
    1428        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_JERK_MAX);
    1429        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_EPSILON_ACC);
    1430        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_ACC_MAX);
    1431        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_M_FLATNESS);
    1432        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_M_BEGIN);
    1433        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS);
    1434        27514 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_MAX_VEH_PREVIEW);
    1435        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_EIDM] = eidmParams;
    1436        27514 :         allParams.insert(eidmParams.begin(), eidmParams.end());
    1437              :         // IDMM
    1438              :         std::set<SumoXMLAttr> idmmParams(genericParams);
    1439        27514 :         idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR);
    1440        27514 :         idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_TIME);
    1441        27514 :         idmmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
    1442        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_IDMM] = idmmParams;
    1443        27514 :         allParams.insert(idmmParams.begin(), idmmParams.end());
    1444              :         // Bieker
    1445              :         std::set<SumoXMLAttr> bkernerParams(genericParams);
    1446        27514 :         bkernerParams.insert(SUMO_ATTR_K);
    1447        27514 :         bkernerParams.insert(SUMO_ATTR_CF_KERNER_PHI);
    1448        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_BKERNER] = bkernerParams;
    1449        27514 :         allParams.insert(bkernerParams.begin(), bkernerParams.end());
    1450              :         // Wiedemann
    1451              :         std::set<SumoXMLAttr> wiedemannParams(genericParams);
    1452        27514 :         wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_SECURITY);
    1453        27514 :         wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_ESTIMATION);
    1454        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_WIEDEMANN] = wiedemannParams;
    1455        27514 :         allParams.insert(wiedemannParams.begin(), wiedemannParams.end());
    1456              :         // W99
    1457              :         std::set<SumoXMLAttr> w99Params(genericParams);
    1458        27514 :         w99Params.insert(SUMO_ATTR_CF_W99_CC1);
    1459        27514 :         w99Params.insert(SUMO_ATTR_CF_W99_CC2);
    1460        27514 :         w99Params.insert(SUMO_ATTR_CF_W99_CC3);
    1461        27514 :         w99Params.insert(SUMO_ATTR_CF_W99_CC4);
    1462        27514 :         w99Params.insert(SUMO_ATTR_CF_W99_CC5);
    1463        27514 :         w99Params.insert(SUMO_ATTR_CF_W99_CC6);
    1464        27514 :         w99Params.insert(SUMO_ATTR_CF_W99_CC7);
    1465        27514 :         w99Params.insert(SUMO_ATTR_CF_W99_CC8);
    1466        27514 :         w99Params.insert(SUMO_ATTR_CF_W99_CC9);
    1467        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_W99] = w99Params;
    1468        27514 :         allParams.insert(w99Params.begin(), w99Params.end());
    1469              :         // Rail
    1470              :         std::set<SumoXMLAttr> railParams(genericParams);
    1471        27514 :         railParams.insert(SUMO_ATTR_TRAIN_TYPE);
    1472        27514 :         railParams.insert(SUMO_ATTR_TRACTION_TABLE);
    1473        27514 :         railParams.insert(SUMO_ATTR_RESISTANCE_TABLE);
    1474        27514 :         railParams.insert(SUMO_ATTR_MASSFACTOR);
    1475        27514 :         railParams.insert(SUMO_ATTR_MAXPOWER);
    1476        27514 :         railParams.insert(SUMO_ATTR_MAXTRACTION);
    1477        27514 :         railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_CONSTANT);
    1478        27514 :         railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_LINEAR);
    1479        27514 :         railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_QUADRATIC);
    1480        27514 :         railParams.insert(SUMO_ATTR_CURVE_RESISTANCE);
    1481        27514 :         railParams.insert(SUMO_ATTR_CURVE_INTEGRATION);
    1482        27514 :         railParams.insert(SUMO_ATTR_ROECKL_SHARP_RADIUS);
    1483        27514 :         railParams.insert(SUMO_ATTR_ROECKL_NUMERATOR);
    1484        27514 :         railParams.insert(SUMO_ATTR_ROECKL_NUMERATOR_SHARP);
    1485        27514 :         railParams.insert(SUMO_ATTR_ROECKL_OFFSET);
    1486        27514 :         railParams.insert(SUMO_ATTR_ROECKL_OFFSET_SHARP);
    1487        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_RAIL] = railParams;
    1488        27514 :         allParams.insert(railParams.begin(), railParams.end());
    1489              :         // ACC
    1490              :         std::set<SumoXMLAttr> ACCParams(genericParams);
    1491        27514 :         ACCParams.insert(SUMO_ATTR_SC_GAIN);
    1492        27514 :         ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
    1493        27514 :         ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
    1494        27514 :         ACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
    1495        27514 :         ACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
    1496        27514 :         ACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
    1497        27514 :         ACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
    1498        27514 :         ACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
    1499        27514 :         ACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
    1500        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_ACC] = ACCParams;
    1501        27514 :         allParams.insert(ACCParams.begin(), ACCParams.end());
    1502              :         // CACC
    1503              :         std::set<SumoXMLAttr> CACCParams(genericParams);
    1504        27514 :         CACCParams.insert(SUMO_ATTR_SC_GAIN_CACC);
    1505        27514 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_CACC);
    1506        27514 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_DOT_CACC);
    1507        27514 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_CACC);
    1508        27514 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_DOT_CACC);
    1509        27514 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_CACC);
    1510        27514 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_DOT_CACC);
    1511        27514 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
    1512        27514 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
    1513        27514 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
    1514        27514 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
    1515        27514 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
    1516        27514 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
    1517        27514 :         CACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
    1518        27514 :         CACCParams.insert(SUMO_ATTR_HEADWAY_TIME_CACC_TO_ACC);
    1519        27514 :         CACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
    1520        27514 :         CACCParams.insert(SUMO_ATTR_SC_MIN_GAP);
    1521        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_CACC] = CACCParams;
    1522        27514 :         allParams.insert(CACCParams.begin(), CACCParams.end());
    1523              :         // CC
    1524              :         std::set<SumoXMLAttr> ccParams(genericParams);
    1525        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_C1);
    1526        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_CCDECEL);
    1527        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_CONSTSPACING);
    1528        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_KP);
    1529        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_LAMBDA);
    1530        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_OMEGAN);
    1531        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_TAU);
    1532        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_XI);
    1533        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_LANES_COUNT);
    1534        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_CCACCEL);
    1535        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KP);
    1536        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KD);
    1537        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_H);
    1538        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KA);
    1539        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KV);
    1540        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KP);
    1541        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_D);
    1542        27514 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_H);
    1543        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_CC] = ccParams;
    1544        27514 :         allParams.insert(ccParams.begin(), ccParams.end());
    1545              :         // NaSch
    1546              :         std::set<SumoXMLAttr> naschParams(genericParams);
    1547        27514 :         naschParams.insert(SUMO_ATTR_SIGMA);
    1548        55028 :         allowedCFModelAttrs[SUMO_TAG_CF_NASCH] = naschParams;
    1549        27514 :         allParams.insert(naschParams.begin(), naschParams.end());
    1550              :         // last element
    1551        55028 :         allowedCFModelAttrs[SUMO_TAG_NOTHING] = allParams;
    1552              :     }
    1553        64389 :     return allowedCFModelAttrs;
    1554              : }
    1555              : 
    1556              : 
    1557              : bool
    1558        64373 : SUMOVehicleParserHelper::parseLCParams(SUMOVTypeParameter* into, LaneChangeModel model, const SUMOSAXAttributes& attrs) {
    1559        64373 :     if (allowedLCModelAttrs.size() == 0) {
    1560              :         // lc2013
    1561              :         std::set<SumoXMLAttr> lc2013Params;
    1562        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_PARAM);
    1563        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_PARAM);
    1564        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_PARAM);
    1565        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_PARAM);
    1566        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_OPPOSITE_PARAM);
    1567        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_LOOKAHEADLEFT);
    1568        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAINRIGHT);
    1569        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING);
    1570        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR);
    1571        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_MAXDISTLATSTANDING);
    1572        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_ASSERTIVE);
    1573        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD);
    1574        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD);
    1575        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME);
    1576        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_URGENCY);
    1577        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT);
    1578        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_SPEED);
    1579        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_HELPTIME);
    1580        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_HELPTHRESHOLD);
    1581        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_MINSPEED);
    1582        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_RIGHT);
    1583        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_SIGMA);
    1584        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME);
    1585        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR);
    1586        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_CONTRIGHT);
    1587        27514 :         lc2013Params.insert(SUMO_ATTR_LCA_EXPERIMENTAL1);
    1588        55028 :         allowedLCModelAttrs[LaneChangeModel::LC2013] = lc2013Params;
    1589              :         // sl2015 (extension of lc2013)
    1590              :         std::set<SumoXMLAttr> sl2015Params = lc2013Params;
    1591        27514 :         sl2015Params.insert(SUMO_ATTR_LCA_PUSHY);
    1592        27514 :         sl2015Params.insert(SUMO_ATTR_LCA_PUSHYGAP);
    1593        27514 :         sl2015Params.insert(SUMO_ATTR_LCA_SUBLANE_PARAM);
    1594        27514 :         sl2015Params.insert(SUMO_ATTR_LCA_IMPATIENCE);
    1595        27514 :         sl2015Params.insert(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE);
    1596        27514 :         sl2015Params.insert(SUMO_ATTR_LCA_ACCEL_LAT);
    1597        27514 :         sl2015Params.insert(SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE);
    1598        27514 :         sl2015Params.insert(SUMO_ATTR_LCA_LANE_DISCIPLINE);
    1599        55028 :         allowedLCModelAttrs[LaneChangeModel::SL2015] = sl2015Params;
    1600              :         // DK2008
    1601              :         std::set<SumoXMLAttr> noParams;
    1602        27514 :         allowedLCModelAttrs[LaneChangeModel::DK2008] = noParams;
    1603              :         // default model may be either LC2013 or SL2015
    1604              :         // we allow both sets (sl2015 is a superset of lc2013Params)
    1605        55028 :         allowedLCModelAttrs[LaneChangeModel::DEFAULT] = sl2015Params;
    1606              :     }
    1607        64373 :     std::set<SumoXMLAttr> allowed = allowedLCModelAttrs[model];
    1608              :     // iterate over LCM attributes
    1609      2252229 :     for (const auto& it : allowed) {
    1610      2187856 :         if (attrs.hasAttribute(it)) {
    1611              :             // first obtain  CFM attribute in string format
    1612         4161 :             bool ok = true;
    1613         4161 :             std::string parsedLCMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
    1614         4161 :             if (!ok) {
    1615              :                 return false;
    1616              :             }
    1617              :             // declare a double in wich save CFM attribute
    1618              :             double LCMAttribute = -1;
    1619              :             try {
    1620              :                 // obtain CFM attribute in double format
    1621         4161 :                 LCMAttribute = StringUtils::toDouble(parsedLCMAttribute);
    1622            0 :             } catch (...) {
    1623            0 :                 WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Cannot be parsed to float"), toString(it));
    1624              :                 return false;
    1625            0 :             }
    1626              :             // check attributes of type "nonNegativeFloatType" (>= 0)
    1627         4161 :             switch (it) {
    1628         1446 :                 case SUMO_ATTR_LCA_PUSHYGAP:
    1629              :                 case SUMO_ATTR_LCA_MAXSPEEDLATSTANDING:
    1630              :                 case SUMO_ATTR_LCA_IMPATIENCE:
    1631              :                 case SUMO_ATTR_LCA_OVERTAKE_RIGHT:
    1632              :                 case SUMO_ATTR_LCA_ASSERTIVE:
    1633              :                 case SUMO_ATTR_LCA_LOOKAHEADLEFT:
    1634              :                 case SUMO_ATTR_LCA_SPEEDGAINRIGHT:
    1635              :                 case SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE:
    1636              :                 case SUMO_ATTR_LCA_TIME_TO_IMPATIENCE:
    1637              :                 case SUMO_ATTR_LCA_LANE_DISCIPLINE:
    1638              :                 case SUMO_ATTR_LCA_SIGMA:
    1639         1446 :                     if (LCMAttribute < 0) {
    1640            0 :                         WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be equal or greater than 0"), toString(it));
    1641            0 :                         return false;
    1642              :                     }
    1643              :                     break;
    1644              :                 default:
    1645              :                     break;
    1646              :             }
    1647              :             // check attributes of type "positiveFloatType" (> 0)
    1648         4161 :             switch (it) {
    1649           10 :                 case SUMO_ATTR_LCA_ACCEL_LAT:
    1650           10 :                     if (LCMAttribute <= 0) {
    1651            0 :                         WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be greater than 0"), toString(it));
    1652            0 :                         return false;
    1653              :                     }
    1654              :                     break;
    1655              :                 default:
    1656              :                     break;
    1657              :             }
    1658              :             // check limits of attributes
    1659         4161 :             switch (it) {
    1660           90 :                 case SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR:
    1661           90 :                     if (LCMAttribute < -1 || LCMAttribute > 1) {
    1662            0 :                         WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be between -1 and 1"), toString(it));
    1663            0 :                         return false;
    1664              :                     }
    1665              :                     break;
    1666              :                 default:
    1667              :                     break;
    1668              :             }
    1669              :             // add parsedLCMAttribute to cfParameter
    1670         4161 :             into->lcParameter[it] = parsedLCMAttribute;
    1671              :         }
    1672              :     }
    1673              :     // all LCM parsed ok, then return true
    1674              :     return true;
    1675              : }
    1676              : 
    1677              : 
    1678              : bool
    1679        64373 : SUMOVehicleParserHelper::parseJMParams(SUMOVTypeParameter* into, const SUMOSAXAttributes& attrs) {
    1680      1094341 :     for (const auto& it : SUMOVTypeParameter::AllowedJMAttrs) {
    1681      1029968 :         if (attrs.hasAttribute(it)) {
    1682              :             // first obtain  CFM attribute in string format
    1683         1081 :             bool ok = true;
    1684         1081 :             std::string parsedJMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
    1685         1081 :             if (!ok) {
    1686              :                 return false;
    1687              :             }
    1688              :             // declare a double in wich save CFM attribute
    1689              :             double JMAttribute = INVALID_DOUBLE;
    1690              :             try {
    1691              :                 // obtain CFM attribute in double format
    1692         1081 :                 JMAttribute = StringUtils::toDouble(parsedJMAttribute);
    1693            0 :             } catch (...) {
    1694            0 :                 WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Cannot be parsed to float"), toString(it));
    1695              :                 return false;
    1696            0 :             }
    1697              :             // now continue checking other properties (-1 is the default value)
    1698         1081 :             if (JMAttribute != INVALID_DOUBLE) {
    1699              :                 // special case for sigma minor
    1700         1081 :                 if (it == SUMO_ATTR_JM_SIGMA_MINOR) {
    1701              :                     // check attributes sigma minor
    1702          126 :                     if ((JMAttribute < 0) || (JMAttribute > 1)) {
    1703            0 :                         WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
    1704            0 :                         return false;
    1705              :                     }
    1706          955 :                 } else if (JMAttribute < 0
    1707           25 :                            && it != SUMO_ATTR_JM_TIMEGAP_MINOR
    1708           18 :                            && it != SUMO_ATTR_JM_EXTRA_GAP) {
    1709              :                     // attributes with error value
    1710           18 :                     if (JMAttribute != -1 || (it != SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME
    1711              :                                               && it != SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME
    1712           18 :                                               && it != SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME)) {
    1713              :                         // check attributes of type "nonNegativeFloatType" (>= 0)
    1714            0 :                         WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Must be equal or greater than 0"), toString(it));
    1715            0 :                         return false;
    1716              :                     }
    1717              :                 }
    1718              :                 // add parsedJMAttribute to cfParameter
    1719         1081 :                 into->jmParameter[it] = parsedJMAttribute;
    1720              :             }
    1721              :         }
    1722              :     }
    1723              :     // all JM parameters successfully parsed, then return true
    1724              :     return true;
    1725              : }
    1726              : 
    1727              : 
    1728              : SUMOVehicleClass
    1729        37153 : SUMOVehicleParserHelper::parseVehicleClass(const SUMOSAXAttributes& attrs, const std::string& id) {
    1730              :     SUMOVehicleClass vclass = SVC_IGNORING;
    1731        37153 :     bool ok = true;
    1732        37153 :     std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_VCLASS, id.c_str(), ok, "");
    1733        37153 :     if (vclassS == "") {
    1734              :         return vclass;
    1735              :     }
    1736              :     try {
    1737        37129 :         const SUMOVehicleClass result = getVehicleClassID(vclassS);
    1738        37121 :         const std::string& realName = SumoVehicleClassStrings.getString(result);
    1739        37121 :         if (realName != vclassS) {
    1740           12 :             WRITE_WARNING("The vehicle class '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
    1741              :         }
    1742              :         return result;
    1743            8 :     } catch (...) {
    1744           24 :         WRITE_ERRORF(TL("The vehicle class '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
    1745            8 :     }
    1746              :     return vclass;
    1747              : }
    1748              : 
    1749              : 
    1750              : SUMOVehicleShape
    1751        27190 : SUMOVehicleParserHelper::parseGuiShape(const SUMOSAXAttributes& attrs, const std::string& id) {
    1752        27190 :     bool ok = true;
    1753        54380 :     std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_GUISHAPE, id.c_str(), ok, "");
    1754              :     if (SumoVehicleShapeStrings.hasString(vclassS)) {
    1755        27190 :         const SUMOVehicleShape result = SumoVehicleShapeStrings.get(vclassS);
    1756        27190 :         const std::string& realName = SumoVehicleShapeStrings.getString(result);
    1757        27190 :         if (realName != vclassS) {
    1758            0 :             WRITE_WARNING("The shape '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
    1759              :         }
    1760        27190 :         return result;
    1761              :     } else {
    1762            0 :         WRITE_ERRORF(TL("The shape '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
    1763            0 :         return SUMOVehicleShape::UNKNOWN;
    1764              :     }
    1765              : }
    1766              : 
    1767              : 
    1768              : double
    1769        32005 : SUMOVehicleParserHelper::parseWalkPos(SumoXMLAttr attr, const bool hardFail, const std::string& id, double maxPos, const std::string& val, SumoRNG* rng) {
    1770              :     double result;
    1771              :     std::string error;
    1772        32005 :     ArrivalPosDefinition proc = ArrivalPosDefinition::DEFAULT;
    1773              :     // only supports 'random' and 'max'
    1774        64010 :     if (!SUMOVehicleParameter::parseArrivalPos(val, toString(SUMO_TAG_WALK), id, result, proc, error)) {
    1775            0 :         handleVehicleError(hardFail, nullptr, error);
    1776              :     }
    1777        32005 :     if (proc == ArrivalPosDefinition::RANDOM) {
    1778         1076 :         result = RandHelper::rand(maxPos, rng);
    1779        30929 :     } else if (proc == ArrivalPosDefinition::CENTER) {
    1780            0 :         result = maxPos / 2.;
    1781        30929 :     } else if (proc == ArrivalPosDefinition::MAX) {
    1782            0 :         result = maxPos;
    1783              :     }
    1784        64010 :     return SUMOVehicleParameter::interpretEdgePos(result, maxPos, attr, id);
    1785              : }
    1786              : 
    1787              : 
    1788              : SUMOTime
    1789       494683 : SUMOVehicleParserHelper::processActionStepLength(double given) {
    1790       494683 :     const std::string defaultError = "The parameter action-step-length must be a non-negative multiple of the simulation step-length. ";
    1791       494683 :     SUMOTime result = TIME2STEPS(given);
    1792       494683 :     if (result <= 0) {
    1793        42391 :         if (result < 0) {
    1794           36 :             WRITE_WARNING(defaultError + "Ignoring given value (=" + toString(STEPS2TIME(result)) + " s.)");
    1795              :         }
    1796        42391 :         result = DELTA_T;
    1797       452321 :     } else if (result % DELTA_T != 0 && OptionsCont::getOptions().exists("step-length")) {
    1798           25 :         result = (SUMOTime)((double)DELTA_T * floor(double(result) / double(DELTA_T)));
    1799              :         result = MAX2(DELTA_T, result);
    1800           25 :         if (fabs(given * 1000. - double(result)) > NUMERICAL_EPS) {
    1801          100 :             WRITE_WARNING(defaultError + "Parsing given value (" + toString(given) + " s.) to the adjusted value " + toString(STEPS2TIME(result)) + " s.");
    1802              :         }
    1803              :     }
    1804       494683 :     return result;
    1805              : }
    1806              : 
    1807              : 
    1808              : bool
    1809       185883 : SUMOVehicleParserHelper::isInternalRouteID(const std::string& id) {
    1810       185883 :     return id.substr(0, 1) == "!";
    1811              : }
    1812              : 
    1813              : 
    1814              : bool
    1815           16 : SUMOVehicleParserHelper::validProfile(SUMOVTypeParameter* vtype, const std::string data, const SumoXMLAttr attr) {
    1816           68 :     for (std::string value : StringTokenizer(data).getVector()) {
    1817              :         try {
    1818           36 :             double v = StringUtils::toDouble(value);
    1819           36 :             if (v < 0.) {
    1820            0 :                 WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. An acceleration profile value cannot be negative"), toString(attr));
    1821            0 :                 return false;
    1822              :             }
    1823            0 :         } catch (...) {
    1824            0 :             WRITE_ERRORF(TL("Entry '%' of % table for vType '%' cannot be parsed as 'double'"), value, toString(attr), vtype->id);
    1825              :             return false;
    1826            0 :         }
    1827           16 :     }
    1828           16 :     return true;
    1829              : }
    1830              : 
    1831              : 
    1832              : int
    1833        14460 : SUMOVehicleParserHelper::parseCarWalkTransfer(const OptionsCont& oc, const bool hasTaxi) {
    1834              :     int carWalk = 0;
    1835        43380 :     for (const std::string& opt : oc.getStringVector("persontrip.transfer.car-walk")) {
    1836        14460 :         if (opt == "parkingAreas") {
    1837        14260 :             carWalk |= ModeChangeOptions::PARKING_AREAS;
    1838          200 :         } else if (opt == "ptStops") {
    1839          150 :             carWalk |= ModeChangeOptions::PT_STOPS;
    1840           50 :         } else if (opt == "allJunctions") {
    1841           50 :             carWalk |= ModeChangeOptions::ALL_JUNCTIONS;
    1842              :         } else {
    1843            0 :             WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
    1844              :         }
    1845              :     }
    1846        14460 :     const StringVector taxiDropoff = oc.getStringVector("persontrip.transfer.taxi-walk");
    1847        28920 :     const StringVector taxiPickup = oc.getStringVector("persontrip.transfer.walk-taxi");
    1848        14460 :     if (taxiDropoff.empty() && hasTaxi) {
    1849         3681 :         carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
    1850              :     } else {
    1851        10991 :         for (const std::string& opt : taxiDropoff) {
    1852          212 :             if (opt == "parkingAreas") {
    1853           14 :                 carWalk |= ModeChangeOptions::TAXI_DROPOFF_PARKING_AREAS;
    1854          198 :             } else if (opt == "ptStops") {
    1855          152 :                 carWalk |= ModeChangeOptions::TAXI_DROPOFF_PT;
    1856           46 :             } else if (opt == "allJunctions") {
    1857           46 :                 carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
    1858              :             } else {
    1859            0 :                 WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
    1860              :             }
    1861              :         }
    1862              :     }
    1863        14460 :     if (taxiPickup.empty() && hasTaxi) {
    1864         3659 :         carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
    1865              :     } else {
    1866        11035 :         for (const std::string& opt : taxiPickup) {
    1867          234 :             if (opt == "parkingAreas") {
    1868           14 :                 carWalk |= ModeChangeOptions::TAXI_PICKUP_PARKING_AREAS;
    1869          220 :             } else if (opt == "ptStops") {
    1870          170 :                 carWalk |= ModeChangeOptions::TAXI_PICKUP_PT;
    1871           50 :             } else if (opt == "allJunctions") {
    1872           50 :                 carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
    1873              :             } else {
    1874            0 :                 WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
    1875              :             }
    1876              :         }
    1877              :     }
    1878        14460 :     return carWalk;
    1879        14460 : }
    1880              : 
    1881              : 
    1882              : SUMOVehicleParameter*
    1883          432 : SUMOVehicleParserHelper::handleVehicleError(const bool hardFail, SUMOVehicleParameter* vehicleParameter, const std::string message) {
    1884          432 :     if (vehicleParameter) {
    1885          388 :         delete vehicleParameter;
    1886              :     }
    1887          432 :     if (hardFail) {
    1888          432 :         throw ProcessError(message);
    1889            0 :     } else if (message.size() > 0) {
    1890            0 :         WRITE_ERROR(message);
    1891              :     }
    1892            0 :     return nullptr;
    1893              : }
    1894              : 
    1895              : 
    1896              : SUMOVTypeParameter*
    1897           30 : SUMOVehicleParserHelper::handleVehicleTypeError(const bool hardFail, SUMOVTypeParameter* vehicleTypeParameter, const std::string message) {
    1898           30 :     if (vehicleTypeParameter) {
    1899           26 :         delete vehicleTypeParameter;
    1900              :     }
    1901           30 :     if (hardFail) {
    1902           30 :         throw ProcessError(message);
    1903            0 :     } else if (message.size() > 0) {
    1904            0 :         WRITE_ERROR(message);
    1905              :     }
    1906            0 :     return nullptr;
    1907              : }
    1908              : 
    1909              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1