LCOV - code coverage report
Current view: top level - src/utils/vehicle - SUMOVehicleParserHelper.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 85.0 % 1129 960
Test Date: 2025-11-13 15:38:19 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-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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        23226 : 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        23226 :     const std::string id = attrs.hasAttribute(SUMO_ATTR_ID) ? parseID(attrs, tag) : "";
      61              :     // check if ID is valid
      62        23226 :     if (!needID || !id.empty()) {
      63        23219 :         if (needID && !SUMOXMLDefinitions::isValidVehicleID(id)) {
      64            0 :             return handleVehicleError(hardFail, nullptr, "Invalid flow id '" + id + "'.");
      65              :         }
      66              :         // declare flags
      67        23219 :         const bool hasPeriod = attrs.hasAttribute(SUMO_ATTR_PERIOD);
      68        23219 :         const bool hasVPH = attrs.hasAttribute(SUMO_ATTR_VEHSPERHOUR);
      69        23219 :         const bool hasPPH = attrs.hasAttribute(SUMO_ATTR_PERSONSPERHOUR);
      70        23219 :         const bool hasCPH = attrs.hasAttribute(SUMO_ATTR_CONTAINERSPERHOUR);
      71        23219 :         const bool hasPH = attrs.hasAttribute(SUMO_ATTR_PERHOUR);
      72        23219 :         const bool hasXPH = hasVPH || hasPPH || hasCPH || hasPH;
      73        23219 :         const bool hasProb = attrs.hasAttribute(SUMO_ATTR_PROB);
      74        23219 :         const bool hasNumber = attrs.hasAttribute(SUMO_ATTR_NUMBER);
      75        23219 :         const bool hasBegin = attrs.hasAttribute(SUMO_ATTR_BEGIN);
      76        23219 :         const bool hasEnd = attrs.hasAttribute(SUMO_ATTR_END);
      77              :         SumoXMLAttr PERHOUR = SUMO_ATTR_PERHOUR;
      78        23219 :         if (hasVPH) {
      79              :             PERHOUR = SUMO_ATTR_VEHSPERHOUR;
      80              :         }
      81        23219 :         if (hasPPH) {
      82              :             PERHOUR = SUMO_ATTR_PERSONSPERHOUR;
      83              :         }
      84        23219 :         if (hasCPH) {
      85              :             PERHOUR = SUMO_ATTR_CONTAINERSPERHOUR;
      86              :         }
      87        23219 :         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         4284 :         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        23212 :         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        23212 :         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        23212 :         if (hasPeriod || hasXPH || hasProb) {
     117        18543 :             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         4669 :             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        23198 :         SUMOVehicleParameter* flowParameter = new SUMOVehicleParameter();
     146              :         // set tag
     147        23198 :         flowParameter->tag = tag;
     148              :         // set id
     149        23198 :         flowParameter->id = id;
     150        23198 :         if (tag == SUMO_TAG_PERSONFLOW) {
     151         1927 :             flowParameter->vtypeid = DEFAULT_PEDTYPE_ID;
     152              :         }
     153        23198 :         if (tag == SUMO_TAG_CONTAINERFLOW) {
     154          365 :             flowParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
     155              :         }
     156              :         // parse common vehicle attributes
     157              :         try {
     158        23198 :             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        23150 :         if (hasPeriod) {
     170         9857 :             bool ok = true;
     171         9857 :             const std::string description = attrs.get<std::string>(SUMO_ATTR_PERIOD, id.c_str(), ok);
     172         9857 :             const std::string distName = description.substr(0, description.find('('));
     173         9857 :             if (distName == "exp") {
     174              :                 // declare rate
     175              :                 double rate = -1;
     176              :                 // parse rate
     177              :                 try {
     178          721 :                     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          721 :                 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          714 :                 flowParameter->poissonRate = rate;
     191              :                 poissonFlow = true;
     192              :             } else {
     193         9136 :                 flowParameter->repetitionOffset = attrs.getSUMOTimeReporting(SUMO_ATTR_PERIOD, id.c_str(), ok);
     194              :             }
     195         9850 :             if (!ok) {
     196            7 :                 return handleVehicleError(hardFail, flowParameter);
     197              :             } else {
     198         9850 :                 flowParameter->parametersSet |= VEHPARS_PERIOD_SET;
     199              :             }
     200              :         }
     201              :         // parse vehicle/person/container/etc per hour
     202        23143 :         if (hasXPH) {
     203         4277 :             bool ok = true;
     204         4277 :             const double vph = attrs.get<double>(PERHOUR, id.c_str(), ok);
     205         4277 :             if (!ok) {
     206            0 :                 return handleVehicleError(hardFail, flowParameter);
     207         4277 :             } 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         4277 :                     flowParameter->repetitionOffset = TIME2STEPS(3600. / vph);
     212              :                 }
     213         4277 :                 flowParameter->parametersSet |= VEHPARS_VPH_SET;
     214              :             }
     215              :         }
     216              :         // parse probability
     217        23143 :         if (hasProb) {
     218         4402 :             bool ok = true;
     219         4402 :             flowParameter->repetitionProbability = attrs.get<double>(SUMO_ATTR_PROB, id.c_str(), ok);
     220         4402 :             if (!ok) {
     221            0 :                 return handleVehicleError(hardFail, flowParameter);
     222         4402 :             } 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         4402 :                 flowParameter->parametersSet |= VEHPARS_PROB_SET;
     226              :             }
     227              :         }
     228              :         // set default begin
     229        23143 :         flowParameter->depart = beginDefault;
     230              :         // parse begin
     231        23143 :         if (hasBegin) {
     232              :             // first get begin
     233        22930 :             bool ok = true;
     234        22930 :             const std::string begin = attrs.get<std::string>(SUMO_ATTR_BEGIN, id.c_str(), ok);
     235        22930 :             if (!ok) {
     236            7 :                 return handleVehicleError(hardFail, flowParameter);
     237              :             } else {
     238              :                 // parse begin
     239              :                 std::string errorMsg;
     240        45860 :                 if (!SUMOVehicleParameter::parseDepart(begin, toString(tag), id, flowParameter->depart, flowParameter->departProcedure, errorMsg, "begin")) {
     241           14 :                     return handleVehicleError(hardFail, flowParameter, errorMsg);
     242              :                 }
     243              :             }
     244              :         }
     245        23136 :         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        23136 :         flowParameter->repetitionEnd = endDefault;
     250        23136 :         if (flowParameter->repetitionEnd < 0) {
     251        13807 :             flowParameter->repetitionEnd = SUMOTime_MAX;
     252              :         }
     253              :         // parse end
     254        23136 :         if (hasEnd) {
     255        20614 :             bool ok = true;
     256        20614 :             flowParameter->repetitionEnd = attrs.getSUMOTimeReporting(SUMO_ATTR_END, id.c_str(), ok);
     257        20614 :             if (!ok) {
     258            0 :                 return handleVehicleError(hardFail, flowParameter);
     259              :             } else {
     260        20614 :                 flowParameter->parametersSet |= VEHPARS_END_SET;
     261              :             }
     262         2522 :         } else if (flowParameter->departProcedure == DepartDefinition::TRIGGERED) {
     263           47 :             if (!hasNumber) {
     264            0 :                 return handleVehicleError(hardFail, flowParameter, toString(tag) + " '" + id + "' with triggered begin must define 'number'.");
     265              :             } else {
     266           47 :                 flowParameter->repetitionEnd = flowParameter->depart;
     267              :             }
     268         2475 :         } 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        23136 :         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        23129 :         if (hasNumber) {
     279         6821 :             bool ok = true;
     280         6821 :             flowParameter->repetitionNumber = attrs.get<int>(SUMO_ATTR_NUMBER, id.c_str(), ok);
     281         6821 :             if (!ok) {
     282            0 :                 return handleVehicleError(hardFail, flowParameter);
     283              :             } else {
     284         6821 :                 flowParameter->parametersSet |= VEHPARS_NUMBER_SET;
     285         6821 :                 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         6813 :                     if (flowParameter->repetitionNumber < 0) {
     292           14 :                         return handleVehicleError(hardFail, flowParameter, "Negative repetition number in the definition of " + toString(tag) + " '" + id + "'.");
     293              :                     }
     294         6806 :                     if (flowParameter->repetitionOffset < 0 && !hasProb) {
     295         4649 :                         if (poissonFlow) {
     296           43 :                             flowParameter->repetitionEnd = SUMOTime_MAX;
     297              :                         } else {
     298         4606 :                             flowParameter->repetitionOffset = (flowParameter->repetitionEnd - flowParameter->depart) / flowParameter->repetitionNumber;
     299              :                         }
     300              :                     }
     301              :                 }
     302              :             }
     303              :         } else {
     304              :             // interpret repetitionNumber
     305        16308 :             if (flowParameter->repetitionProbability > 0) {
     306         4360 :                 flowParameter->repetitionNumber = std::numeric_limits<int>::max();
     307              :             } else {
     308        11948 :                 if (flowParameter->repetitionOffset <= 0) {
     309          685 :                     if (poissonFlow) {
     310              :                         // number is random but flow has a fixed end time
     311          671 :                         flowParameter->repetitionNumber = std::numeric_limits<int>::max();
     312              :                     } else {
     313           28 :                         return handleVehicleError(hardFail, flowParameter, "Invalid repetition rate in the definition of " + toString(tag) + " '" + id + "'.");
     314              :                     }
     315              :                 } else {
     316        11263 :                     if (flowParameter->repetitionEnd == SUMOTime_MAX) {
     317            0 :                         flowParameter->repetitionNumber = std::numeric_limits<int>::max();
     318              :                     } else {
     319        11263 :                         const SUMOTime repLength = flowParameter->repetitionEnd - flowParameter->depart;
     320        11263 :                         flowParameter->repetitionNumber = (int)ceil((double)repLength / (double)flowParameter->repetitionOffset);
     321              :                     }
     322              :                 }
     323              :             }
     324              :         }
     325              :         // all ok, then return flow parameter
     326        23108 :         return flowParameter;
     327              :     } else {
     328          132 :         return handleVehicleError(hardFail, nullptr, toString(tag) + " cannot be created");
     329              :     }
     330              : }
     331              : 
     332              : 
     333              : SUMOVehicleParameter*
     334       637708 : 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       637708 :     if (optionalID) {
     339          682 :         bool ok = true;
     340          682 :         id = attrs.getOpt<std::string>(SUMO_ATTR_ID, nullptr, ok, "");
     341          682 :         if (!ok) {
     342            0 :             return handleVehicleError(hardFail, nullptr);
     343              :         }
     344              :     } else {
     345              :         // parse ID
     346      1274052 :         id = parseID(attrs, (SumoXMLTag)element);
     347              :     }
     348              :     // only continue if id is valid, or if is optional
     349       637708 :     if (optionalID || !id.empty()) {
     350              :         // declare vehicle parameter
     351       637692 :         SUMOVehicleParameter* vehicleParameter = new SUMOVehicleParameter();
     352       637692 :         vehicleParameter->id = id;
     353       637692 :         if (element == SUMO_TAG_PERSON) {
     354        43718 :             vehicleParameter->vtypeid = DEFAULT_PEDTYPE_ID;
     355       593974 :         } else if (element == SUMO_TAG_CONTAINER) {
     356          865 :             vehicleParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
     357              :         }
     358              :         // parse common attributes
     359              :         try {
     360       637692 :             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       637418 :         if (!skipDepart) {
     371       636736 :             bool ok = true;
     372       636736 :             const std::string helper = attrs.get<std::string>(SUMO_ATTR_DEPART, vehicleParameter->id.c_str(), ok);
     373       636736 :             if (!ok) {
     374           40 :                 return handleVehicleError(hardFail, vehicleParameter);
     375              :             }
     376              :             // now parse depart
     377              :             std::string departErrorMsg;
     378      1273440 :             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       637394 :         vehicleParameter->tag = (SumoXMLTag)element;
     384              :         // all ok, then return vehicleParameter
     385       637394 :         return vehicleParameter;
     386              :     } else {
     387          346 :         return handleVehicleError(hardFail, nullptr, toString((SumoXMLTag)element) + " cannot be created");
     388              :     }
     389              : }
     390              : 
     391              : 
     392              : std::string
     393       722776 : SUMOVehicleParserHelper::parseID(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
     394       722776 :     bool ok = true;
     395              :     std::string id;
     396              :     // first check if attrs contain an ID
     397       722776 :     if (attrs.hasAttribute(SUMO_ATTR_ID)) {
     398       722764 :         id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     399       722764 :         if (SUMOXMLDefinitions::isValidVehicleID(id)) {
     400       722756 :             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       660890 : SUMOVehicleParserHelper::parseCommonAttributes(const SUMOSAXAttributes& attrs, SUMOVehicleParameter* ret, SumoXMLTag tag, const bool allowInternalRoutes) {
     417       660890 :     const std::string element = toString(tag);
     418              :     //ret->refid = attrs.getStringSecure(SUMO_ATTR_REFID, "");
     419              :     // parse route information
     420       660890 :     if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
     421       165686 :         bool ok = true;
     422       165686 :         std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, ret->id.c_str(), ok);
     423       165686 :         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       165686 :         ret->routeid = routeID;
     427       165686 :         if (ok) {
     428       165676 :             ret->parametersSet |= VEHPARS_ROUTE_SET; // !!! needed?
     429              :         } else {
     430           20 :             handleVehicleError(true, ret);
     431              :         }
     432              :     }
     433              :     // parse type information
     434       660880 :     if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
     435       218418 :         bool ok = true;
     436       218418 :         ret->vtypeid = attrs.get<std::string>(SUMO_ATTR_TYPE, ret->id.c_str(), ok);
     437       218418 :         if (ok) {
     438       218418 :             ret->parametersSet |= VEHPARS_VTYPE_SET; // !!! needed?
     439              :         } else {
     440            0 :             handleVehicleError(true, ret);
     441              :         }
     442              :     }
     443              :     // parse line information
     444       660880 :     if (attrs.hasAttribute(SUMO_ATTR_LINE)) {
     445         3265 :         bool ok = true;
     446         3265 :         ret->line = attrs.get<std::string>(SUMO_ATTR_LINE, ret->id.c_str(), ok);
     447         3265 :         if (ok) {
     448         3259 :             ret->parametersSet |= VEHPARS_LINE_SET; // !!! needed?
     449              :         } else {
     450            6 :             handleVehicleError(true, ret);
     451              :         }
     452              :     }
     453              :     // parse zone information
     454       660874 :     if (attrs.hasAttribute(SUMO_ATTR_FROM_TAZ)) {
     455        21585 :         bool ok = true;
     456        21585 :         ret->fromTaz = attrs.get<std::string>(SUMO_ATTR_FROM_TAZ, ret->id.c_str(), ok);
     457        21585 :         if (ok) {
     458        21585 :             ret->parametersSet |= VEHPARS_FROM_TAZ_SET;
     459              :         } else {
     460            0 :             handleVehicleError(true, ret);
     461              :         }
     462              :     }
     463       660874 :     if (attrs.hasAttribute(SUMO_ATTR_TO_TAZ)) {
     464        21585 :         bool ok = true;
     465        21585 :         ret->toTaz = attrs.get<std::string>(SUMO_ATTR_TO_TAZ, ret->id.c_str(), ok);
     466        21585 :         if (ok) {
     467        21585 :             ret->parametersSet |= VEHPARS_TO_TAZ_SET;
     468              :         } else {
     469            0 :             handleVehicleError(true, ret);
     470              :         }
     471              :     }
     472              :     // parse reroute information
     473       660874 :     if (attrs.hasAttribute(SUMO_ATTR_REROUTE)) {
     474         4480 :         bool ok = true;
     475         4480 :         if (attrs.get<bool>(SUMO_ATTR_REROUTE, ret->id.c_str(), ok)) {
     476         4480 :             if (ok) {
     477         4480 :                 ret->parametersSet |= VEHPARS_FORCE_REROUTE;
     478              :             } else {
     479            0 :                 handleVehicleError(true, ret);
     480              :             }
     481              :         }
     482              :     }
     483              :     // parse depart lane information
     484       660874 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTLANE)) {
     485       111379 :         bool ok = true;
     486       111379 :         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       111379 :         if (SUMOVehicleParameter::parseDepartLane(departLaneStr, element, ret->id, lane, dld, error)) {
     491       111331 :             ret->parametersSet |= VEHPARS_DEPARTLANE_SET;
     492       111331 :             ret->departLane = lane;
     493       111331 :             ret->departLaneProcedure = dld;
     494              :         } else {
     495           96 :             handleVehicleError(true, ret, error);
     496              :         }
     497              :     }
     498              :     // parse depart position information
     499       660826 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
     500        89907 :         bool ok = true;
     501        89907 :         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        89907 :         if (SUMOVehicleParameter::parseDepartPos(departPosStr, element, ret->id, pos, dpd, error)) {
     506        89859 :             ret->parametersSet |= VEHPARS_DEPARTPOS_SET;
     507        89859 :             ret->departPos = pos;
     508        89859 :             ret->departPosProcedure = dpd;
     509              :         } else {
     510           96 :             handleVehicleError(true, ret, error);
     511              :         }
     512              :     }
     513              :     // parse lateral depart position information
     514       660778 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS_LAT)) {
     515         8715 :         bool ok = true;
     516         8715 :         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         8715 :         if (SUMOVehicleParameter::parseDepartPosLat(departPosLatStr, element, ret->id, pos, dpd, error)) {
     521         8715 :             ret->parametersSet |= VEHPARS_DEPARTPOSLAT_SET;
     522         8715 :             ret->departPosLat = pos;
     523         8715 :             ret->departPosLatProcedure = dpd;
     524              :         } else {
     525            0 :             handleVehicleError(true, ret, error);
     526              :         }
     527              :     }
     528              :     // parse depart speed information
     529       660778 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTSPEED)) {
     530       242417 :         bool ok = true;
     531       242417 :         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       242417 :         if (SUMOVehicleParameter::parseDepartSpeed(departSpeed, element, ret->id, speed, dsd, error)) {
     536       242369 :             ret->parametersSet |= VEHPARS_DEPARTSPEED_SET;
     537       242369 :             ret->departSpeed = speed;
     538       242369 :             ret->departSpeedProcedure = dsd;
     539              :         } else {
     540           96 :             handleVehicleError(true, ret, error);
     541              :         }
     542              :     }
     543              :     // parse depart edge information
     544       660730 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTEDGE)) {
     545          262 :         bool ok = true;
     546          262 :         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          262 :         if (SUMOVehicleParameter::parseRouteIndex(departEdgeStr, element, ret->id, SUMO_ATTR_DEPARTEDGE, edgeIndex, rid, error)) {
     551          255 :             ret->parametersSet |= VEHPARS_DEPARTEDGE_SET;
     552          255 :             ret->departEdge = edgeIndex;
     553          255 :             ret->departEdgeProcedure = rid;
     554              :         } else {
     555           14 :             handleVehicleError(true, ret, error);
     556              :         }
     557              :     }
     558              :     // parse arrival lane information
     559       660723 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALLANE)) {
     560         3263 :         bool ok = true;
     561         3263 :         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         3263 :         if (SUMOVehicleParameter::parseArrivalLane(arrivalLaneStr, element, ret->id, lane, ald, error)) {
     566         3215 :             ret->parametersSet |= VEHPARS_ARRIVALLANE_SET;
     567         3215 :             ret->arrivalLane = lane;
     568         3215 :             ret->arrivalLaneProcedure = ald;
     569              :         } else {
     570           96 :             handleVehicleError(true, ret, error);
     571              :         }
     572              :     }
     573              :     // parse arrival position information
     574       660675 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
     575         8292 :         bool ok = true;
     576         8292 :         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         8292 :         if (SUMOVehicleParameter::parseArrivalPos(arrivalPosStr, element, ret->id, pos, apd, error)) {
     581         8244 :             ret->parametersSet |= VEHPARS_ARRIVALPOS_SET;
     582         8244 :             ret->arrivalPos = pos;
     583         8244 :             ret->arrivalPosProcedure = apd;
     584              :         } else {
     585           96 :             handleVehicleError(true, ret, error);
     586              :         }
     587              :     }
     588              :     // parse lateral arrival position information
     589       660627 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_LAT)) {
     590         1069 :         bool ok = true;
     591         1069 :         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         1069 :         if (SUMOVehicleParameter::parseArrivalPosLat(arrivalPosLatStr, element, ret->id, pos, apd, error)) {
     596         1069 :             ret->parametersSet |= VEHPARS_ARRIVALPOSLAT_SET;
     597         1069 :             ret->arrivalPosLat = pos;
     598         1069 :             ret->arrivalPosLatProcedure = apd;
     599              :         } else {
     600            0 :             handleVehicleError(true, ret, error);
     601              :         }
     602              :     }
     603              :     // parse arrival speed information
     604       660627 :     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       660579 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALEDGE)) {
     620           90 :         bool ok = true;
     621           90 :         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           90 :         if (SUMOVehicleParameter::parseRouteIndex(arrivalEdgeStr, element, ret->id, SUMO_ATTR_ARRIVALEDGE, edgeIndex, rid, error)) {
     626           83 :             ret->parametersSet |= VEHPARS_ARRIVALEDGE_SET;
     627           83 :             ret->arrivalEdge = edgeIndex;
     628           83 :             ret->arrivalEdgeProcedure = rid;
     629              :         } else {
     630           14 :             handleVehicleError(true, ret, error);
     631              :         }
     632              :     }
     633              :     // parse color
     634       660572 :     if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
     635         9677 :         bool ok = true;
     636         9677 :         ret->color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, ret->id.c_str(), ok);
     637         9677 :         if (ok) {
     638         9677 :             ret->parametersSet |= VEHPARS_COLOR_SET;
     639              :         } else {
     640            0 :             handleVehicleError(true, ret, "Invalid RGBColor format");
     641              :         }
     642              :     } else {
     643       650895 :         ret->color = RGBColor::DEFAULT_COLOR;
     644              :     }
     645              :     // parse person number
     646       660572 :     if (attrs.hasAttribute(SUMO_ATTR_PERSON_NUMBER)) {
     647          984 :         bool ok = true;
     648          984 :         int personNumber = attrs.get<int>(SUMO_ATTR_PERSON_NUMBER, ret->id.c_str(), ok);
     649          984 :         if (!ok) {
     650            0 :             handleVehicleError(true, ret);
     651          984 :         } else if (personNumber >= 0) {
     652          984 :             ret->parametersSet |= VEHPARS_PERSON_NUMBER_SET;
     653          984 :             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       660572 :     if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_NUMBER)) {
     660          978 :         bool ok = true;
     661          978 :         int containerNumber = attrs.get<int>(SUMO_ATTR_CONTAINER_NUMBER, ret->id.c_str(), ok);
     662          978 :         if (!ok) {
     663            0 :             handleVehicleError(true, ret);
     664          978 :         } else if (containerNumber >= 0) {
     665          978 :             ret->parametersSet |= VEHPARS_CONTAINER_NUMBER_SET;
     666          978 :             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       660572 :     if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
     673        11801 :         bool ok = true;
     674        11801 :         double speedFactor = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR, ret->id.c_str(), ok);
     675        11801 :         if (!ok) {
     676            0 :             handleVehicleError(true, ret);
     677        11801 :         } else if (speedFactor > 0) {
     678        11801 :             ret->parametersSet |= VEHPARS_SPEEDFACTOR_SET;
     679        11801 :             ret->speedFactor = speedFactor;
     680              :         } else {
     681            0 :             handleVehicleError(true, ret, toString(SUMO_ATTR_SPEEDFACTOR) + " must be positive");
     682              :         }
     683              :     }
     684              :     // parse insertion checks
     685       660572 :     if (attrs.hasAttribute(SUMO_ATTR_INSERTIONCHECKS)) {
     686         1009 :         ret->parametersSet |= VEHPARS_INSERTION_CHECKS_SET;
     687         1009 :         bool ok = true;
     688         1009 :         std::string checks = attrs.get<std::string>(SUMO_ATTR_INSERTIONCHECKS, ret->id.c_str(), ok);
     689         1009 :         if (!ok) {
     690            4 :             handleVehicleError(true, ret);
     691              :         } else {
     692              :             try {
     693         1009 :                 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       660568 :     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       660568 :     ret->modes = 0;
     712       660568 :     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       660568 :     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       660568 :     if (tag == SUMO_TAG_FLOW && attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     735          221 :         bool ok = true;
     736          221 :         double calibratorSpeed = attrs.get<double>(SUMO_ATTR_SPEED, ret->id.c_str(), ok);
     737          221 :         if (!ok) {
     738            0 :             handleVehicleError(true, ret);
     739          221 :         } else if (calibratorSpeed >= 0 || calibratorSpeed == -1) {
     740          221 :             ret->parametersSet |= VEHPARS_CALIBRATORSPEED_SET;
     741          221 :             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       660568 : }
     753              : 
     754              : 
     755              : SUMOVTypeParameter*
     756        62531 : SUMOVehicleParserHelper::beginVTypeParsing(const SUMOSAXAttributes& attrs, const bool hardFail, const std::string& file) {
     757              :     // first obtain ID
     758        62531 :     std::string id = parseID(attrs, SUMO_TAG_VTYPE);
     759              :     // check if ID is valid
     760        62531 :     if (!id.empty()) {
     761              :         SUMOVehicleClass vClass = SVC_PASSENGER;
     762        62527 :         if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
     763        36691 :             vClass = parseVehicleClass(attrs, id);
     764              :         }
     765              :         // create vType
     766        62527 :         SUMOVTypeParameter* vType = new SUMOVTypeParameter(id, vClass);
     767              :         // parse attributes
     768        62527 :         if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
     769        36691 :             vType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     770              :         }
     771        62527 :         if (attrs.hasAttribute(SUMO_ATTR_LENGTH)) {
     772        37879 :             bool ok = true;
     773        37879 :             const double length = attrs.get<double>(SUMO_ATTR_LENGTH, vType->id.c_str(), ok);
     774        37879 :             if (!ok) {
     775            0 :                 return handleVehicleTypeError(hardFail, vType);
     776        37879 :             } else if (length <= 0) {
     777            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LENGTH) + " must be greater than 0");
     778              :             } else {
     779        37879 :                 vType->length = length;
     780        37879 :                 vType->parametersSet |= VTYPEPARS_LENGTH_SET;
     781              :             }
     782              :         }
     783        62527 :         if (attrs.hasAttribute(SUMO_ATTR_MINGAP)) {
     784        35851 :             bool ok = true;
     785        35851 :             const double minGap = attrs.get<double>(SUMO_ATTR_MINGAP, vType->id.c_str(), ok);
     786        35851 :             if (!ok) {
     787            0 :                 return handleVehicleTypeError(hardFail, vType);
     788        35851 :             } else if (minGap < 0) {
     789            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP) + " must be equal or greater than 0");
     790              :             } else {
     791        35851 :                 vType->minGap = minGap;
     792        35851 :                 vType->parametersSet |= VTYPEPARS_MINGAP_SET;
     793              :             }
     794              :         }
     795        62527 :         if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
     796        37085 :             bool ok = true;
     797        37085 :             const double maxSpeed = attrs.get<double>(SUMO_ATTR_MAXSPEED, vType->id.c_str(), ok);
     798        37085 :             if (!ok) {
     799            0 :                 return handleVehicleTypeError(hardFail, vType);
     800        37085 :             } else if (maxSpeed <= 0) {
     801            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED) + " must be greater than 0");
     802              :             } else {
     803        37085 :                 vType->maxSpeed = maxSpeed;
     804        37085 :                 vType->parametersSet |= VTYPEPARS_MAXSPEED_SET;
     805              :             }
     806              :         }
     807        62527 :         if (attrs.hasAttribute(SUMO_ATTR_DESIRED_MAXSPEED)) {
     808           88 :             bool ok = true;
     809           88 :             const double desiredMaxSpeed = attrs.get<double>(SUMO_ATTR_DESIRED_MAXSPEED, vType->id.c_str(), ok);
     810           88 :             if (!ok) {
     811            0 :                 return handleVehicleTypeError(hardFail, vType);
     812           88 :             } else if (desiredMaxSpeed <= 0) {
     813            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_DESIRED_MAXSPEED) + " must be greater than 0");
     814              :             } else {
     815           88 :                 vType->desiredMaxSpeed = desiredMaxSpeed;
     816           88 :                 vType->parametersSet |= VTYPEPARS_DESIRED_MAXSPEED_SET;
     817              :             }
     818        62439 :         } else if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
     819        37064 :             if (vClass == SVC_PEDESTRIAN) {
     820              :                 // backward compatibility because pedestrian maxSpeed was subject to speedFactor up to 1.14.1
     821        25878 :                 vType->desiredMaxSpeed = vType->maxSpeed;;
     822        77630 :                 vType->maxSpeed = MAX2(vType->maxSpeed, SUMOVTypeParameter::VClassDefaultValues(vClass).maxSpeed);
     823        11186 :             } else if (vClass == SVC_BICYCLE) {
     824              :                 // backward compatibility because default desired speed did not exist up to 1.14.1
     825          192 :                 vType->desiredMaxSpeed = MAX2(vType->maxSpeed, vType->desiredMaxSpeed);
     826              :             }
     827              :         }
     828              : 
     829        62527 :         if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
     830         2451 :             bool ok = true;
     831         2451 :             vType->speedFactor.parse(attrs.get<std::string>(SUMO_ATTR_SPEEDFACTOR, vType->id.c_str(), ok), hardFail);
     832         2451 :             if (!ok) {
     833            0 :                 return handleVehicleTypeError(hardFail, vType);
     834              :             } else {
     835         2451 :                 vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
     836              :             }
     837              :         }
     838        62527 :         if (attrs.hasAttribute(SUMO_ATTR_SPEEDDEV)) {
     839         2606 :             bool ok = true;
     840         2606 :             const double speedDev = attrs.get<double>(SUMO_ATTR_SPEEDDEV, vType->id.c_str(), ok);
     841         2606 :             if (!ok) {
     842            0 :                 return handleVehicleTypeError(hardFail, vType);
     843         2606 :             } else if (speedDev < 0) {
     844            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SPEEDDEV) + " must be equal or greater than 0");
     845              :             } else {
     846         2606 :                 vType->speedFactor.setParameter(1, speedDev);
     847         2606 :                 vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
     848              :             }
     849              :         }
     850              :         // validate speed distribution
     851        62527 :         const std::string& error = vType->speedFactor.isValid();
     852        62527 :         if (error != "") {
     853           14 :             return handleVehicleTypeError(hardFail, vType, "Invalid speed distribution when parsing vType '" + vType->id + "' (" + error + ")");
     854              :         }
     855        62520 :         if (attrs.hasAttribute(SUMO_ATTR_ACTIONSTEPLENGTH)) {
     856          226 :             bool ok = true;
     857          226 :             const double actionStepLengthSecs = attrs.get<double>(SUMO_ATTR_ACTIONSTEPLENGTH, vType->id.c_str(), ok);
     858          226 :             if (!ok) {
     859            0 :                 return handleVehicleTypeError(hardFail, vType);
     860              :             } else {
     861              :                 // processActionStepLength(...) function includes warnings
     862          226 :                 vType->actionStepLength = processActionStepLength(actionStepLengthSecs);
     863          226 :                 vType->parametersSet |= VTYPEPARS_ACTIONSTEPLENGTH_SET;
     864              :             }
     865              :         }
     866        62520 :         if (attrs.hasAttribute(SUMO_ATTR_EMISSIONCLASS)) {
     867         1849 :             bool ok = true;
     868         1849 :             const std::string parsedEmissionClass = attrs.getOpt<std::string>(SUMO_ATTR_EMISSIONCLASS, id.c_str(), ok, "");
     869              :             // check if emission class is correct
     870              :             try {
     871         1849 :                 vType->emissionClass = PollutantsInterface::getClassByName(parsedEmissionClass);
     872         1849 :                 vType->parametersSet |= VTYPEPARS_EMISSIONCLASS_SET;
     873            0 :             } catch (...) {
     874            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_EMISSIONCLASS) + " with name '" + parsedEmissionClass + "' doesn't exist.");
     875            0 :             }
     876              :         }
     877        62520 :         if (attrs.hasAttribute(SUMO_ATTR_MASS)) {
     878          304 :             bool ok = true;
     879          304 :             const double mass = attrs.get<double>(SUMO_ATTR_MASS, vType->id.c_str(), ok);
     880          304 :             if (!ok) {
     881            0 :                 return handleVehicleTypeError(hardFail, vType);
     882          304 :             } else if (mass < 0) {
     883            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MASS) + " must be equal or greater than 0");
     884              :             } else {
     885          304 :                 vType->mass = mass;
     886          304 :                 vType->parametersSet |= VTYPEPARS_MASS_SET;
     887              :             }
     888              :         }
     889        62520 :         if (attrs.hasAttribute(SUMO_ATTR_IMPATIENCE)) {
     890          243 :             bool ok = true;
     891          243 :             const std::string impatienceStr = attrs.get<std::string>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
     892          243 :             if (!ok) {
     893            0 :                 return handleVehicleTypeError(hardFail, vType);
     894          243 :             } else if (impatienceStr == "off") {
     895           12 :                 vType->impatience = -std::numeric_limits<double>::max();
     896              :             } else {
     897          231 :                 const double impatienceDouble = attrs.get<double>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
     898          231 :                 if (!ok) {
     899            0 :                     return handleVehicleTypeError(hardFail, vType);
     900              :                 } else {
     901          231 :                     vType->impatience = impatienceDouble;
     902          231 :                     vType->parametersSet |= VTYPEPARS_IMPATIENCE_SET;
     903              :                 }
     904              :             }
     905              :         }
     906        62520 :         if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
     907        26755 :             bool ok = true;
     908        26755 :             const double width = attrs.get<double>(SUMO_ATTR_WIDTH, vType->id.c_str(), ok);
     909        26755 :             if (!ok) {
     910            0 :                 return handleVehicleTypeError(hardFail, vType);
     911        26755 :             } else if (width <= 0) {
     912            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_WIDTH) + " must be greater than 0");
     913              :             } else {
     914        26755 :                 vType->width = width;
     915        26755 :                 vType->parametersSet |= VTYPEPARS_WIDTH_SET;
     916        26755 :                 if (vClass == SVC_PEDESTRIAN
     917        52862 :                         && OptionsCont::getOptions().exists("pedestrian.striping.stripe-width")
     918        78969 :                         && OptionsCont::getOptions().getString("pedestrian.model") == "striping"
     919        82152 :                         && OptionsCont::getOptions().getFloat("pedestrian.striping.stripe-width") < vType->width) {
     920           12 :                     WRITE_WARNINGF(TL("Pedestrian vType '%' width % is larger than pedestrian.striping.stripe-width and this may cause collisions with vehicles."), id, vType->width);
     921              :                 }
     922              :             }
     923              :         }
     924        62520 :         if (attrs.hasAttribute(SUMO_ATTR_HEIGHT)) {
     925          359 :             bool ok = true;
     926          359 :             const double height = attrs.get<double>(SUMO_ATTR_HEIGHT, vType->id.c_str(), ok);
     927          359 :             if (!ok) {
     928            0 :                 return handleVehicleTypeError(hardFail, vType);
     929          359 :             } else if (height < 0) {
     930            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_HEIGHT) + " must be equal or greater than 0");
     931              :             } else {
     932          359 :                 vType->height = height;
     933          359 :                 vType->parametersSet |= VTYPEPARS_HEIGHT_SET;
     934              :             }
     935              :         }
     936        62520 :         if (attrs.hasAttribute(SUMO_ATTR_GUISHAPE)) {
     937        27193 :             vType->shape = parseGuiShape(attrs, vType->id);
     938        27193 :             if (vType->shape != SUMOVehicleShape::UNKNOWN) {
     939        27193 :                 vType->parametersSet |= VTYPEPARS_SHAPE_SET;
     940              :             }
     941              :         }
     942        62520 :         if (attrs.hasAttribute(SUMO_ATTR_OSGFILE)) {
     943           21 :             bool ok = true;
     944           21 :             const std::string osgFile = attrs.get<std::string>(SUMO_ATTR_OSGFILE, vType->id.c_str(), ok);
     945           21 :             if (!ok) {
     946            0 :                 return handleVehicleTypeError(hardFail, vType);
     947              :             } else {
     948           21 :                 vType->osgFile = osgFile;
     949           21 :                 vType->parametersSet |= VTYPEPARS_OSGFILE_SET;
     950              :             }
     951              :         }
     952        62520 :         if (attrs.hasAttribute(SUMO_ATTR_IMGFILE)) {
     953           28 :             bool ok = true;
     954           28 :             std::string imgFile = attrs.get<std::string>(SUMO_ATTR_IMGFILE, vType->id.c_str(), ok);
     955           28 :             if (!ok) {
     956            0 :                 return handleVehicleTypeError(hardFail, vType);
     957              :             } else {
     958              :                 // check relative path
     959           28 :                 if ((imgFile != "") && !FileHelpers::isAbsolute(imgFile)) {
     960           56 :                     imgFile = FileHelpers::getConfigurationRelative(file, imgFile);
     961              :                 }
     962           28 :                 vType->imgFile = imgFile;
     963           28 :                 vType->parametersSet |= VTYPEPARS_IMGFILE_SET;
     964              :             }
     965              :         }
     966        62520 :         if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
     967        22781 :             bool ok = true;
     968        22781 :             const RGBColor color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, vType->id.c_str(), ok);
     969        22781 :             if (!ok) {
     970            8 :                 return handleVehicleTypeError(hardFail, vType);
     971              :             } else {
     972        22773 :                 vType->color = color;
     973        22773 :                 vType->parametersSet |= VTYPEPARS_COLOR_SET;
     974              :             }
     975              :         } else {
     976        39739 :             vType->color = RGBColor::YELLOW;
     977              :         }
     978        62512 :         if (attrs.hasAttribute(SUMO_ATTR_PROB)) {
     979          615 :             bool ok = true;
     980          615 :             const double defaultProbability = attrs.get<double>(SUMO_ATTR_PROB, vType->id.c_str(), ok);
     981          615 :             if (!ok) {
     982            0 :                 return handleVehicleTypeError(hardFail, vType);
     983          615 :             } else if (defaultProbability < 0) {
     984            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PROB) + " must be equal or greater than 0");
     985              :             } else {
     986          615 :                 vType->defaultProbability = defaultProbability;
     987          615 :                 vType->parametersSet |= VTYPEPARS_PROBABILITY_SET;
     988              :             }
     989              :         }
     990        62512 :         if (attrs.hasAttribute(SUMO_ATTR_LANE_CHANGE_MODEL)) {
     991          477 :             bool ok = true;
     992          477 :             std::string lcmS = attrs.get<std::string>(SUMO_ATTR_LANE_CHANGE_MODEL, vType->id.c_str(), ok);
     993          477 :             if (!ok) {
     994            0 :                 return handleVehicleTypeError(hardFail, vType);
     995          477 :             } else if (lcmS == "JE2013") {
     996            0 :                 WRITE_WARNING(TL("Lane change model 'JE2013' is deprecated. Using default model instead."));
     997              :                 lcmS = "default";
     998              :             }
     999              :             if (SUMOXMLDefinitions::LaneChangeModels.hasString(lcmS)) {
    1000          472 :                 vType->lcModel = SUMOXMLDefinitions::LaneChangeModels.get(lcmS);
    1001          472 :                 vType->parametersSet |= VTYPEPARS_LANE_CHANGE_MODEL_SET;
    1002              :             } else {
    1003           15 :                 return handleVehicleTypeError(hardFail, vType, "Unknown lane change model '" + lcmS + "' when parsing vType '" + vType->id + "'");
    1004              :             }
    1005              :         }
    1006        62507 :         if (attrs.hasAttribute(SUMO_ATTR_CAR_FOLLOW_MODEL)) {
    1007         1289 :             bool ok = true;
    1008         1289 :             const std::string cfmValue = attrs.get<std::string>(SUMO_ATTR_CAR_FOLLOW_MODEL, vType->id.c_str(), ok);
    1009         1289 :             if (!ok) {
    1010            0 :                 return handleVehicleTypeError(hardFail, vType);
    1011              :             } else if (SUMOXMLDefinitions::CarFollowModels.hasString(cfmValue)) {
    1012         1283 :                 vType->cfModel = SUMOXMLDefinitions::CarFollowModels.get(cfmValue);
    1013         1283 :                 vType->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
    1014              :             } else {
    1015           18 :                 return handleVehicleTypeError(hardFail, vType, "Unknown car following model '" + cfmValue + "' when parsing vType '" + vType->id + "'");
    1016              :             }
    1017              :         }
    1018        62501 :         if (attrs.hasAttribute(SUMO_ATTR_PERSON_CAPACITY)) {
    1019          402 :             bool ok = true;
    1020          402 :             const int personCapacity = attrs.get<int>(SUMO_ATTR_PERSON_CAPACITY, vType->id.c_str(), ok);
    1021          402 :             if (!ok) {
    1022            0 :                 return handleVehicleTypeError(hardFail, vType);
    1023          402 :             } else if (personCapacity < 0) {
    1024            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PERSON_CAPACITY) + " must be equal or greater than 0");
    1025              :             } else {
    1026          402 :                 vType->personCapacity = personCapacity;
    1027          402 :                 vType->parametersSet |= VTYPEPARS_PERSON_CAPACITY;
    1028              :             }
    1029              :         }
    1030        62501 :         if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_CAPACITY)) {
    1031          382 :             bool ok = true;
    1032          382 :             const int containerCapacity = attrs.get<int>(SUMO_ATTR_CONTAINER_CAPACITY, vType->id.c_str(), ok);
    1033          382 :             if (!ok) {
    1034            0 :                 return handleVehicleTypeError(hardFail, vType);
    1035          382 :             } else if (containerCapacity < 0) {
    1036            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_CONTAINER_CAPACITY) + " must be equal or greater than 0");
    1037              :             } else {
    1038          382 :                 vType->containerCapacity = containerCapacity;
    1039          382 :                 vType->parametersSet |= VTYPEPARS_CONTAINER_CAPACITY;
    1040              :             }
    1041              :         }
    1042        62501 :         if (attrs.hasAttribute(SUMO_ATTR_BOARDING_DURATION)) {
    1043          101 :             bool ok = true;
    1044          101 :             const SUMOTime boardingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_BOARDING_DURATION, vType->id.c_str(), ok);
    1045          101 :             if (!ok) {
    1046            0 :                 return handleVehicleTypeError(hardFail, vType);
    1047          101 :             } else if (boardingDuration < 0) {
    1048            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_DURATION) + " must be equal or greater than 0");
    1049              :             } else {
    1050          101 :                 vType->boardingDuration = boardingDuration;
    1051          101 :                 vType->parametersSet |= VTYPEPARS_BOARDING_DURATION;
    1052              :             }
    1053              :         }
    1054        62501 :         if (attrs.hasAttribute(SUMO_ATTR_LOADING_DURATION)) {
    1055           72 :             bool ok = true;
    1056           72 :             const SUMOTime loadingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_LOADING_DURATION, vType->id.c_str(), ok);
    1057           72 :             if (!ok) {
    1058            0 :                 return handleVehicleTypeError(hardFail, vType);
    1059           72 :             } else if (loadingDuration < 0) {
    1060            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LOADING_DURATION) + " must be equal or greater than 0");
    1061              :             } else {
    1062           72 :                 vType->loadingDuration = loadingDuration;
    1063           72 :                 vType->parametersSet |= VTYPEPARS_LOADING_DURATION;
    1064              :             }
    1065              :         }
    1066        62501 :         if (attrs.hasAttribute(SUMO_ATTR_SCALE)) {
    1067           40 :             bool ok = true;
    1068           40 :             const double scale = attrs.get<double>(SUMO_ATTR_SCALE, id.c_str(), ok);
    1069           40 :             if (!ok) {
    1070            0 :                 return handleVehicleTypeError(hardFail, vType);
    1071           40 :             } else if (scale < 0) {
    1072            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SCALE) + " may be not be negative");
    1073              :             } else {
    1074           40 :                 vType->scale = scale;
    1075           40 :                 vType->parametersSet |= VTYPEPARS_SCALE_SET;
    1076              :             }
    1077              :         }
    1078        62501 :         if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT)) {
    1079           13 :             bool ok = true;
    1080           13 :             const SUMOTime ttt = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT, vType->id.c_str(), ok);
    1081           13 :             if (!ok) {
    1082            0 :                 return handleVehicleTypeError(hardFail, vType);
    1083              :             } else {
    1084           13 :                 vType->timeToTeleport = ttt;
    1085           13 :                 vType->parametersSet |= VTYPEPARS_TTT_SET;
    1086              :             }
    1087              :         }
    1088        62501 :         if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT_BIDI)) {
    1089            5 :             bool ok = true;
    1090            5 :             const SUMOTime tttb = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT_BIDI, vType->id.c_str(), ok);
    1091            5 :             if (!ok) {
    1092            0 :                 return handleVehicleTypeError(hardFail, vType);
    1093              :             } else {
    1094            5 :                 vType->timeToTeleportBidi = tttb;
    1095            5 :                 vType->parametersSet |= VTYPEPARS_TTT_BIDI_SET;
    1096              :             }
    1097              :         }
    1098        62501 :         if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR_PREMATURE)) {
    1099           63 :             bool ok = true;
    1100           63 :             const double sfp = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR_PREMATURE, id.c_str(), ok);
    1101           63 :             if (!ok) {
    1102            0 :                 return handleVehicleTypeError(hardFail, vType);
    1103              :             } else {
    1104           63 :                 vType->speedFactorPremature = sfp;
    1105           63 :                 vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_PREMATURE_SET;
    1106              :             }
    1107              :         }
    1108        62501 :         if (attrs.hasAttribute(SUMO_ATTR_BOARDING_FACTOR)) {
    1109            8 :             bool ok = true;
    1110            8 :             const double bf = attrs.get<double>(SUMO_ATTR_BOARDING_FACTOR, id.c_str(), ok);
    1111            8 :             if (!ok) {
    1112            0 :                 return handleVehicleTypeError(hardFail, vType);
    1113            8 :             } else if (bf < 0) {
    1114            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_FACTOR) + " must be equal or greater than 0");
    1115              :             } else {
    1116            8 :                 vType->boardingFactor = bf;
    1117            8 :                 vType->parametersSet |= VTYPEPARS_BOARDING_FACTOR_SET;
    1118              :             }
    1119              :         }
    1120        62501 :         if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED_LAT)) {
    1121           73 :             bool ok = true;
    1122           73 :             const double maxSpeedLat = attrs.get<double>(SUMO_ATTR_MAXSPEED_LAT, vType->id.c_str(), ok);
    1123           73 :             if (!ok) {
    1124            0 :                 return handleVehicleTypeError(hardFail, vType);
    1125           73 :             } else if (maxSpeedLat <= 0) {
    1126            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED_LAT) + " must be greater than 0");
    1127              :             } else {
    1128           73 :                 vType->maxSpeedLat = maxSpeedLat;
    1129           73 :                 vType->parametersSet |= VTYPEPARS_MAXSPEED_LAT_SET;
    1130              :             }
    1131              :         }
    1132        62501 :         if (attrs.hasAttribute(SUMO_ATTR_MINGAP_LAT)) {
    1133          577 :             bool ok = true;
    1134          577 :             const double minGapLat = attrs.get<double>(SUMO_ATTR_MINGAP_LAT, vType->id.c_str(), ok);
    1135          577 :             if (!ok) {
    1136            0 :                 return handleVehicleTypeError(hardFail, vType);
    1137          577 :             } else if (minGapLat < 0) {
    1138            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP_LAT) + " must be equal or greater than 0");
    1139              :             } else {
    1140          577 :                 vType->minGapLat = minGapLat;
    1141          577 :                 vType->parametersSet |= VTYPEPARS_MINGAP_LAT_SET;
    1142              :             }
    1143              :         }
    1144        62501 :         if (attrs.hasAttribute(SUMO_ATTR_LATALIGNMENT)) {
    1145         1716 :             bool ok = true;
    1146         1716 :             const std::string alignS = attrs.get<std::string>(SUMO_ATTR_LATALIGNMENT, vType->id.c_str(), ok);
    1147         1716 :             if (!ok) {
    1148            0 :                 return handleVehicleTypeError(hardFail, vType);
    1149              :             } else {
    1150              :                 double lao;
    1151              :                 LatAlignmentDefinition lad;
    1152         1716 :                 if (SUMOVTypeParameter::parseLatAlignment(alignS, lao, lad)) {
    1153         1716 :                     vType->latAlignmentOffset = lao;
    1154         1716 :                     vType->latAlignmentProcedure = lad;
    1155         1716 :                     vType->parametersSet |= VTYPEPARS_LATALIGNMENT_SET;
    1156              :                 } else {
    1157            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)");
    1158              :                 }
    1159              :             }
    1160              :         }
    1161        62501 :         if (attrs.hasAttribute(SUMO_ATTR_MANEUVER_ANGLE_TIMES)) {
    1162            5 :             bool ok = true;
    1163            5 :             const std::string angleTimesS = attrs.get<std::string>(SUMO_ATTR_MANEUVER_ANGLE_TIMES, vType->id.c_str(), ok);
    1164            5 :             if (!ok) {
    1165            0 :                 return handleVehicleTypeError(hardFail, vType);
    1166           10 :             } else if (parseAngleTimesMap(vType, angleTimesS)) {
    1167            5 :                 vType->parametersSet |= VTYPEPARS_MANEUVER_ANGLE_TIMES_SET;
    1168              :             } else {
    1169            0 :                 return handleVehicleTypeError(hardFail, vType, "Invalid manoeuver angle times map for vType '" + vType->id + "'");
    1170              :             }
    1171              :         }
    1172        62501 :         if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {
    1173           12 :             bool ok = true;
    1174           12 :             std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, vType->id.c_str(), ok);
    1175           12 :             if (!ok) {
    1176            0 :                 return handleVehicleTypeError(hardFail, vType);
    1177              :             } else {
    1178           12 :                 vType->parametersSet |= VTYPEPARS_PARKING_BADGES_SET;
    1179           12 :                 vType->parkingBadges = badges;
    1180              :             }
    1181           12 :         }
    1182              :         // try to parse Car Following Model params
    1183        62501 :         if (!parseCFMParams(vType, vType->cfModel, attrs, false)) {
    1184            0 :             return handleVehicleTypeError(hardFail, vType, "Invalid parsing embedded VType");
    1185              :         }
    1186              :         // try to parse Lane Change Model params
    1187        62501 :         if (!parseLCParams(vType, vType->lcModel, attrs)) {
    1188            0 :             return handleVehicleTypeError(hardFail, vType, "Invalid Lane Change Model Parameters");
    1189              :         }
    1190              :         // try to Junction Model params
    1191        62501 :         if (!parseJMParams(vType, attrs)) {
    1192           26 :             return handleVehicleTypeError(hardFail, vType, "Invalid Junction Model Parameters");
    1193              :         }
    1194              :         // all ok, then return vType
    1195              :         return vType;
    1196              :     } else {
    1197           34 :         return handleVehicleTypeError(hardFail, nullptr, "VType cannot be created");
    1198              :     }
    1199              : }
    1200              : 
    1201              : 
    1202              : bool
    1203            5 : SUMOVehicleParserHelper::parseAngleTimesMap(SUMOVTypeParameter* vtype, const std::string atm) {
    1204           15 :     StringTokenizer st(atm, ",");
    1205              :     std::map<int, std::pair<SUMOTime, SUMOTime>> angleTimesMap;
    1206              :     int tripletCount = 0;
    1207           30 :     while (st.hasNext()) {
    1208           25 :         StringTokenizer pos(st.next());
    1209           25 :         if (pos.size() != 3) {
    1210            0 :             WRITE_ERRORF(TL("maneuverAngleTimes format for vType '%' % contains an invalid triplet."), vtype->id, atm);
    1211            0 :             return false;
    1212              :         } else {
    1213              :             try {
    1214           25 :                 const int angle = StringUtils::toInt(pos.next());
    1215           25 :                 const SUMOTime t1 = string2time(pos.next());
    1216           25 :                 const SUMOTime t2 = string2time(pos.next());
    1217           25 :                 angleTimesMap[angle] = std::make_pair(t1, t2);
    1218            0 :             } catch (...) {
    1219            0 :                 WRITE_ERRORF(TL("Triplet '%' for vType '%' maneuverAngleTimes cannot be parsed as 'int double double'"), st.get(tripletCount), vtype->id);
    1220              :                 return false;
    1221            0 :             }
    1222           25 :             tripletCount++;
    1223              :         }
    1224           25 :     }
    1225            5 :     if (angleTimesMap.size() > 0) {
    1226              :         vtype->myManoeuverAngleTimes.clear();
    1227           30 :         for (const auto& angleTime : angleTimesMap) {
    1228              :             vtype->myManoeuverAngleTimes.insert(angleTime);
    1229              :         }
    1230              :         angleTimesMap.clear();
    1231            5 :         return true;
    1232              :     } else {
    1233              :         return false;
    1234              :     }
    1235            5 : }
    1236              : 
    1237              : 
    1238              : bool
    1239        62517 : SUMOVehicleParserHelper::parseCFMParams(SUMOVTypeParameter* into, const SumoXMLTag element, const SUMOSAXAttributes& attrs, const bool nestedCFM) {
    1240        62517 :     const CFAttrMap& allowedCFM = getAllowedCFModelAttrs();
    1241              :     CFAttrMap::const_iterator cf_it = allowedCFM.find(element);
    1242              :     // check if given CFM is allowed
    1243        62517 :     if (cf_it == allowedCFM.end()) {
    1244            0 :         if (SUMOXMLDefinitions::Tags.has((int)element)) {
    1245            0 :             WRITE_ERRORF(TL("Unknown car-following model % when parsing vType '%'"), toString(element), into->id);
    1246              :         } else {
    1247            0 :             WRITE_ERRORF(TL("Unknown car-following model when parsing vType '%'"), into->id);
    1248              :         }
    1249            0 :         return false;
    1250              :     }
    1251              :     // check if we're parsing a nested CFM
    1252        62517 :     if (nestedCFM) {
    1253           16 :         into->cfModel = cf_it->first;
    1254           16 :         into->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
    1255              :     }
    1256              :     // set CFM values
    1257       821438 :     for (const auto& it : cf_it->second) {
    1258       758921 :         if (attrs.hasAttribute(it)) {
    1259              :             // first obtain  CFM attribute in string format
    1260        45609 :             bool ok = true;
    1261        45609 :             std::string parsedCFMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
    1262              :             // check CFM Attribute
    1263        45609 :             if (!ok) {
    1264              :                 return false;
    1265        45609 :             } else if (it == SUMO_ATTR_TRAIN_TYPE) {
    1266              :                 // check if train value is valid
    1267          235 :                 if (!SUMOXMLDefinitions::TrainTypes.hasString(parsedCFMAttribute)) {
    1268            0 :                     WRITE_ERROR("Invalid train type '" + parsedCFMAttribute + "' used in Car-Following-Attribute " + toString(it));
    1269            0 :                     return false;
    1270              :                 }
    1271              :                 // add parsedCFMAttribute to cfParameter
    1272          235 :                 into->cfParameter[it] = parsedCFMAttribute;
    1273        45374 :             } else if (it == SUMO_ATTR_SPEED_TABLE || it == SUMO_ATTR_TRACTION_TABLE || it == SUMO_ATTR_RESISTANCE_TABLE) {
    1274           36 :                 into->cfParameter[it] = parsedCFMAttribute;
    1275        45338 :             } else if (it == SUMO_ATTR_CF_IDM_STEPPING) {
    1276              :                 // declare a int in wich save CFM int attribute
    1277              :                 double CFMDoubleAttribute = -1;
    1278              :                 try {
    1279              :                     // obtain CFM attribute in int format
    1280            6 :                     CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
    1281            0 :                 } catch (...) {
    1282            0 :                     WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
    1283              :                     return false;
    1284            0 :                 }
    1285            6 :                 if (CFMDoubleAttribute <= 0) {
    1286            0 :                     WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
    1287            0 :                     return false;
    1288              :                 }
    1289              :                 // add parsedCFMAttribute to cfParameter
    1290            6 :                 into->cfParameter[it] = parsedCFMAttribute;
    1291        45332 :             } else if (it == SUMO_ATTR_MAXACCEL_PROFILE || it == SUMO_ATTR_DESACCEL_PROFILE) {
    1292           24 :                 if (validProfile(into, parsedCFMAttribute, it)) {
    1293           12 :                     into->cfParameter[it] = parsedCFMAttribute;
    1294              :                 } else {
    1295            0 :                     WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed as a vector of <speed accel> pairs"), toString(it));
    1296            0 :                     return false;
    1297              :                 }
    1298              :             } else {
    1299              :                 // declare a double in wich save CFM float attribute
    1300              :                 double CFMDoubleAttribute = -1;
    1301              :                 try {
    1302              :                     // obtain CFM attribute in double format
    1303        45320 :                     CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
    1304            0 :                 } catch (...) {
    1305            0 :                     WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
    1306              :                     return false;
    1307            0 :                 }
    1308              :                 // check attributes of type "positiveFloatType" (> 0)
    1309        45320 :                 switch (it) {
    1310        21008 :                     case SUMO_ATTR_ACCEL:
    1311              :                     case SUMO_ATTR_DECEL:
    1312              :                     case SUMO_ATTR_APPARENTDECEL:
    1313              :                     case SUMO_ATTR_EMERGENCYDECEL:
    1314              :                     case SUMO_ATTR_TAU:
    1315        21008 :                         if (CFMDoubleAttribute <= 0) {
    1316            0 :                             WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
    1317            0 :                             return false;
    1318              :                         }
    1319              :                         break;
    1320              :                     default:
    1321              :                         break;
    1322              :                 }
    1323              :                 // check attributes restricted to [0-1]
    1324        45320 :                 switch (it) {
    1325        23704 :                     case SUMO_ATTR_SIGMA:
    1326        23704 :                         if ((CFMDoubleAttribute < 0) || (CFMDoubleAttribute > 1)) {
    1327            0 :                             WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
    1328            0 :                             return false;
    1329              :                         }
    1330              :                         break;
    1331              :                     default:
    1332              :                         break;
    1333              :                 }
    1334              :                 // add parsedCFMAttribute to cfParameter
    1335        45320 :                 into->cfParameter[it] = parsedCFMAttribute;
    1336              :             }
    1337              :         }
    1338              :     }
    1339              :     // all CFM successfully parsed, then return true
    1340              :     return true;
    1341              : }
    1342              : 
    1343              : 
    1344              : const SUMOVehicleParserHelper::CFAttrMap&
    1345        62517 : SUMOVehicleParserHelper::getAllowedCFModelAttrs() {
    1346              :     // init on first use
    1347        62517 :     if (allowedCFModelAttrs.size() == 0) {
    1348              :         std::set<SumoXMLAttr> genericParams;
    1349        25969 :         genericParams.insert(SUMO_ATTR_TAU);
    1350        25969 :         genericParams.insert(SUMO_ATTR_ACCEL);
    1351        25969 :         genericParams.insert(SUMO_ATTR_DECEL);
    1352        25969 :         genericParams.insert(SUMO_ATTR_APPARENTDECEL);
    1353        25969 :         genericParams.insert(SUMO_ATTR_EMERGENCYDECEL);
    1354        25969 :         genericParams.insert(SUMO_ATTR_SPEED_TABLE);
    1355        25969 :         genericParams.insert(SUMO_ATTR_MAXACCEL_PROFILE);
    1356        25969 :         genericParams.insert(SUMO_ATTR_DESACCEL_PROFILE);
    1357        25969 :         genericParams.insert(SUMO_ATTR_COLLISION_MINGAP_FACTOR);
    1358        25969 :         genericParams.insert(SUMO_ATTR_STARTUP_DELAY);
    1359              :         // Krauss
    1360              :         std::set<SumoXMLAttr> kraussParams(genericParams);
    1361        25969 :         kraussParams.insert(SUMO_ATTR_SIGMA);
    1362        25969 :         kraussParams.insert(SUMO_ATTR_SIGMA_STEP);
    1363        25969 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS] = kraussParams;
    1364        25969 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_ORIG1] = kraussParams;
    1365        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_PLUS_SLOPE] = kraussParams;
    1366              :         std::set<SumoXMLAttr> allParams(kraussParams);
    1367              :         // KraussX
    1368              :         std::set<SumoXMLAttr> kraussXParams(kraussParams);
    1369        25969 :         kraussXParams.insert(SUMO_ATTR_TMP1);
    1370        25969 :         kraussXParams.insert(SUMO_ATTR_TMP2);
    1371        25969 :         kraussXParams.insert(SUMO_ATTR_TMP3);
    1372        25969 :         kraussXParams.insert(SUMO_ATTR_TMP4);
    1373        25969 :         kraussXParams.insert(SUMO_ATTR_TMP5);
    1374        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSSX] = kraussXParams;
    1375        25969 :         allParams.insert(kraussXParams.begin(), kraussXParams.end());
    1376              :         // SmartSK
    1377              :         std::set<SumoXMLAttr> smartSKParams(genericParams);
    1378        25969 :         smartSKParams.insert(SUMO_ATTR_SIGMA);
    1379        25969 :         smartSKParams.insert(SUMO_ATTR_TMP1);
    1380        25969 :         smartSKParams.insert(SUMO_ATTR_TMP2);
    1381        25969 :         smartSKParams.insert(SUMO_ATTR_TMP3);
    1382        25969 :         smartSKParams.insert(SUMO_ATTR_TMP4);
    1383        25969 :         smartSKParams.insert(SUMO_ATTR_TMP5);
    1384        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_SMART_SK] = smartSKParams;
    1385        25969 :         allParams.insert(smartSKParams.begin(), smartSKParams.end());
    1386              :         // Daniel
    1387              :         std::set<SumoXMLAttr> daniel1Params(genericParams);
    1388        25969 :         daniel1Params.insert(SUMO_ATTR_SIGMA);
    1389        25969 :         daniel1Params.insert(SUMO_ATTR_TMP1);
    1390        25969 :         daniel1Params.insert(SUMO_ATTR_TMP2);
    1391        25969 :         daniel1Params.insert(SUMO_ATTR_TMP3);
    1392        25969 :         daniel1Params.insert(SUMO_ATTR_TMP4);
    1393        25969 :         daniel1Params.insert(SUMO_ATTR_TMP5);
    1394        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_DANIEL1] = daniel1Params;
    1395        25969 :         allParams.insert(daniel1Params.begin(), daniel1Params.end());
    1396              :         // Peter Wagner
    1397              :         std::set<SumoXMLAttr> pwagParams(genericParams);
    1398        25969 :         pwagParams.insert(SUMO_ATTR_SIGMA);
    1399        25969 :         pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_TAULAST);
    1400        25969 :         pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_APPROB);
    1401        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_PWAGNER2009] = pwagParams;
    1402        25969 :         allParams.insert(pwagParams.begin(), pwagParams.end());
    1403              :         // IDM params
    1404              :         std::set<SumoXMLAttr> idmParams(genericParams);
    1405        25969 :         idmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
    1406        25969 :         idmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
    1407        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_IDM] = idmParams;
    1408        25969 :         allParams.insert(idmParams.begin(), idmParams.end());
    1409              :         // EIDM
    1410              :         std::set<SumoXMLAttr> eidmParams(genericParams);
    1411        25969 :         eidmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
    1412        25969 :         eidmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
    1413        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD);
    1414        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE);
    1415        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_REACTION);
    1416        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE);
    1417        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_C_COOLNESS);
    1418        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_LEADER);
    1419        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_GAP);
    1420        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_ERROR);
    1421        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_JERK_MAX);
    1422        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_EPSILON_ACC);
    1423        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_ACC_MAX);
    1424        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_M_FLATNESS);
    1425        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_M_BEGIN);
    1426        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS);
    1427        25969 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_MAX_VEH_PREVIEW);
    1428        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_EIDM] = eidmParams;
    1429        25969 :         allParams.insert(eidmParams.begin(), eidmParams.end());
    1430              :         // IDMM
    1431              :         std::set<SumoXMLAttr> idmmParams(genericParams);
    1432        25969 :         idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR);
    1433        25969 :         idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_TIME);
    1434        25969 :         idmmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
    1435        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_IDMM] = idmmParams;
    1436        25969 :         allParams.insert(idmmParams.begin(), idmmParams.end());
    1437              :         // Bieker
    1438              :         std::set<SumoXMLAttr> bkernerParams(genericParams);
    1439        25969 :         bkernerParams.insert(SUMO_ATTR_K);
    1440        25969 :         bkernerParams.insert(SUMO_ATTR_CF_KERNER_PHI);
    1441        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_BKERNER] = bkernerParams;
    1442        25969 :         allParams.insert(bkernerParams.begin(), bkernerParams.end());
    1443              :         // Wiedemann
    1444              :         std::set<SumoXMLAttr> wiedemannParams(genericParams);
    1445        25969 :         wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_SECURITY);
    1446        25969 :         wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_ESTIMATION);
    1447        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_WIEDEMANN] = wiedemannParams;
    1448        25969 :         allParams.insert(wiedemannParams.begin(), wiedemannParams.end());
    1449              :         // W99
    1450              :         std::set<SumoXMLAttr> w99Params(genericParams);
    1451        25969 :         w99Params.insert(SUMO_ATTR_CF_W99_CC1);
    1452        25969 :         w99Params.insert(SUMO_ATTR_CF_W99_CC2);
    1453        25969 :         w99Params.insert(SUMO_ATTR_CF_W99_CC3);
    1454        25969 :         w99Params.insert(SUMO_ATTR_CF_W99_CC4);
    1455        25969 :         w99Params.insert(SUMO_ATTR_CF_W99_CC5);
    1456        25969 :         w99Params.insert(SUMO_ATTR_CF_W99_CC6);
    1457        25969 :         w99Params.insert(SUMO_ATTR_CF_W99_CC7);
    1458        25969 :         w99Params.insert(SUMO_ATTR_CF_W99_CC8);
    1459        25969 :         w99Params.insert(SUMO_ATTR_CF_W99_CC9);
    1460        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_W99] = w99Params;
    1461        25969 :         allParams.insert(w99Params.begin(), w99Params.end());
    1462              :         // Rail
    1463              :         std::set<SumoXMLAttr> railParams(genericParams);
    1464        25969 :         railParams.insert(SUMO_ATTR_TRAIN_TYPE);
    1465        25969 :         railParams.insert(SUMO_ATTR_TRACTION_TABLE);
    1466        25969 :         railParams.insert(SUMO_ATTR_RESISTANCE_TABLE);
    1467        25969 :         railParams.insert(SUMO_ATTR_MASSFACTOR);
    1468        25969 :         railParams.insert(SUMO_ATTR_MAXPOWER);
    1469        25969 :         railParams.insert(SUMO_ATTR_MAXTRACTION);
    1470        25969 :         railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_CONSTANT);
    1471        25969 :         railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_LINEAR);
    1472        25969 :         railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_QUADRATIC);
    1473        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_RAIL] = railParams;
    1474        25969 :         allParams.insert(railParams.begin(), railParams.end());
    1475              :         // ACC
    1476              :         std::set<SumoXMLAttr> ACCParams(genericParams);
    1477        25969 :         ACCParams.insert(SUMO_ATTR_SC_GAIN);
    1478        25969 :         ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
    1479        25969 :         ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
    1480        25969 :         ACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
    1481        25969 :         ACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
    1482        25969 :         ACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
    1483        25969 :         ACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
    1484        25969 :         ACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
    1485        25969 :         ACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
    1486        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_ACC] = ACCParams;
    1487        25969 :         allParams.insert(ACCParams.begin(), ACCParams.end());
    1488              :         // CACC
    1489              :         std::set<SumoXMLAttr> CACCParams(genericParams);
    1490        25969 :         CACCParams.insert(SUMO_ATTR_SC_GAIN_CACC);
    1491        25969 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_CACC);
    1492        25969 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_DOT_CACC);
    1493        25969 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_CACC);
    1494        25969 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_DOT_CACC);
    1495        25969 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_CACC);
    1496        25969 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_DOT_CACC);
    1497        25969 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
    1498        25969 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
    1499        25969 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
    1500        25969 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
    1501        25969 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
    1502        25969 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
    1503        25969 :         CACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
    1504        25969 :         CACCParams.insert(SUMO_ATTR_HEADWAY_TIME_CACC_TO_ACC);
    1505        25969 :         CACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
    1506        25969 :         CACCParams.insert(SUMO_ATTR_SC_MIN_GAP);
    1507        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_CACC] = CACCParams;
    1508        25969 :         allParams.insert(CACCParams.begin(), CACCParams.end());
    1509              :         // CC
    1510              :         std::set<SumoXMLAttr> ccParams(genericParams);
    1511        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_C1);
    1512        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_CCDECEL);
    1513        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_CONSTSPACING);
    1514        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_KP);
    1515        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_LAMBDA);
    1516        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_OMEGAN);
    1517        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_TAU);
    1518        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_XI);
    1519        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_LANES_COUNT);
    1520        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_CCACCEL);
    1521        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KP);
    1522        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KD);
    1523        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_H);
    1524        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KA);
    1525        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KV);
    1526        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KP);
    1527        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_D);
    1528        25969 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_H);
    1529        51938 :         allowedCFModelAttrs[SUMO_TAG_CF_CC] = ccParams;
    1530        25969 :         allParams.insert(ccParams.begin(), ccParams.end());
    1531              :         // last element
    1532        51938 :         allowedCFModelAttrs[SUMO_TAG_NOTHING] = allParams;
    1533              :     }
    1534        62517 :     return allowedCFModelAttrs;
    1535              : }
    1536              : 
    1537              : 
    1538              : bool
    1539        62501 : SUMOVehicleParserHelper::parseLCParams(SUMOVTypeParameter* into, LaneChangeModel model, const SUMOSAXAttributes& attrs) {
    1540        62501 :     if (allowedLCModelAttrs.size() == 0) {
    1541              :         // lc2013
    1542              :         std::set<SumoXMLAttr> lc2013Params;
    1543        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_PARAM);
    1544        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_PARAM);
    1545        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_PARAM);
    1546        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_PARAM);
    1547        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_OPPOSITE_PARAM);
    1548        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_LOOKAHEADLEFT);
    1549        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAINRIGHT);
    1550        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING);
    1551        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR);
    1552        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_MAXDISTLATSTANDING);
    1553        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_ASSERTIVE);
    1554        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD);
    1555        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD);
    1556        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME);
    1557        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_URGENCY);
    1558        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT);
    1559        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_SPEED);
    1560        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_RIGHT);
    1561        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_SIGMA);
    1562        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME);
    1563        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR);
    1564        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_CONTRIGHT);
    1565        25969 :         lc2013Params.insert(SUMO_ATTR_LCA_EXPERIMENTAL1);
    1566        51938 :         allowedLCModelAttrs[LaneChangeModel::LC2013] = lc2013Params;
    1567              :         // sl2015 (extension of lc2013)
    1568              :         std::set<SumoXMLAttr> sl2015Params = lc2013Params;
    1569        25969 :         sl2015Params.insert(SUMO_ATTR_LCA_PUSHY);
    1570        25969 :         sl2015Params.insert(SUMO_ATTR_LCA_PUSHYGAP);
    1571        25969 :         sl2015Params.insert(SUMO_ATTR_LCA_SUBLANE_PARAM);
    1572        25969 :         sl2015Params.insert(SUMO_ATTR_LCA_IMPATIENCE);
    1573        25969 :         sl2015Params.insert(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE);
    1574        25969 :         sl2015Params.insert(SUMO_ATTR_LCA_ACCEL_LAT);
    1575        25969 :         sl2015Params.insert(SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE);
    1576        25969 :         sl2015Params.insert(SUMO_ATTR_LCA_LANE_DISCIPLINE);
    1577        51938 :         allowedLCModelAttrs[LaneChangeModel::SL2015] = sl2015Params;
    1578              :         // DK2008
    1579              :         std::set<SumoXMLAttr> noParams;
    1580        25969 :         allowedLCModelAttrs[LaneChangeModel::DK2008] = noParams;
    1581              :         // default model may be either LC2013 or SL2015
    1582              :         // we allow both sets (sl2015 is a superset of lc2013Params)
    1583        51938 :         allowedLCModelAttrs[LaneChangeModel::DEFAULT] = sl2015Params;
    1584              :     }
    1585        62501 :     std::set<SumoXMLAttr> allowed = allowedLCModelAttrs[model];
    1586              :     // iterate over LCM attributes
    1587      1999233 :     for (const auto& it : allowed) {
    1588      1936732 :         if (attrs.hasAttribute(it)) {
    1589              :             // first obtain  CFM attribute in string format
    1590         4061 :             bool ok = true;
    1591         4061 :             std::string parsedLCMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
    1592         4061 :             if (!ok) {
    1593              :                 return false;
    1594              :             }
    1595              :             // declare a double in wich save CFM attribute
    1596              :             double LCMAttribute = -1;
    1597              :             try {
    1598              :                 // obtain CFM attribute in double format
    1599         4061 :                 LCMAttribute = StringUtils::toDouble(parsedLCMAttribute);
    1600            0 :             } catch (...) {
    1601            0 :                 WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Cannot be parsed to float"), toString(it));
    1602              :                 return false;
    1603            0 :             }
    1604              :             // check attributes of type "nonNegativeFloatType" (>= 0)
    1605         4061 :             switch (it) {
    1606         1448 :                 case SUMO_ATTR_LCA_PUSHYGAP:
    1607              :                 case SUMO_ATTR_LCA_MAXSPEEDLATSTANDING:
    1608              :                 case SUMO_ATTR_LCA_IMPATIENCE:
    1609              :                 case SUMO_ATTR_LCA_OVERTAKE_RIGHT:
    1610              :                 case SUMO_ATTR_LCA_ASSERTIVE:
    1611              :                 case SUMO_ATTR_LCA_LOOKAHEADLEFT:
    1612              :                 case SUMO_ATTR_LCA_SPEEDGAINRIGHT:
    1613              :                 case SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE:
    1614              :                 case SUMO_ATTR_LCA_TIME_TO_IMPATIENCE:
    1615              :                 case SUMO_ATTR_LCA_LANE_DISCIPLINE:
    1616              :                 case SUMO_ATTR_LCA_SIGMA:
    1617         1448 :                     if (LCMAttribute < 0) {
    1618            0 :                         WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be equal or greater than 0"), toString(it));
    1619            0 :                         return false;
    1620              :                     }
    1621              :                     break;
    1622              :                 default:
    1623              :                     break;
    1624              :             }
    1625              :             // check attributes of type "positiveFloatType" (> 0)
    1626         4061 :             switch (it) {
    1627           10 :                 case SUMO_ATTR_LCA_ACCEL_LAT:
    1628           10 :                     if (LCMAttribute <= 0) {
    1629            0 :                         WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be greater than 0"), toString(it));
    1630            0 :                         return false;
    1631              :                     }
    1632              :                     break;
    1633              :                 default:
    1634              :                     break;
    1635              :             }
    1636              :             // check limits of attributes
    1637         4061 :             switch (it) {
    1638           90 :                 case SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR:
    1639           90 :                     if (LCMAttribute < -1 || LCMAttribute > 1) {
    1640            0 :                         WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be between -1 and 1"), toString(it));
    1641            0 :                         return false;
    1642              :                     }
    1643              :                     break;
    1644              :                 default:
    1645              :                     break;
    1646              :             }
    1647              :             // add parsedLCMAttribute to cfParameter
    1648         4061 :             into->lcParameter[it] = parsedLCMAttribute;
    1649              :         }
    1650              :     }
    1651              :     // all LCM parsed ok, then return true
    1652              :     return true;
    1653              : }
    1654              : 
    1655              : 
    1656              : bool
    1657        62501 : SUMOVehicleParserHelper::parseJMParams(SUMOVTypeParameter* into, const SUMOSAXAttributes& attrs) {
    1658      1062517 :     for (const auto& it : SUMOVTypeParameter::AllowedJMAttrs) {
    1659      1000016 :         if (attrs.hasAttribute(it)) {
    1660              :             // first obtain  CFM attribute in string format
    1661         1075 :             bool ok = true;
    1662         1075 :             std::string parsedJMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
    1663         1075 :             if (!ok) {
    1664              :                 return false;
    1665              :             }
    1666              :             // declare a double in wich save CFM attribute
    1667              :             double JMAttribute = INVALID_DOUBLE;
    1668              :             try {
    1669              :                 // obtain CFM attribute in double format
    1670         1075 :                 JMAttribute = StringUtils::toDouble(parsedJMAttribute);
    1671            0 :             } catch (...) {
    1672            0 :                 WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Cannot be parsed to float"), toString(it));
    1673              :                 return false;
    1674            0 :             }
    1675              :             // now continue checking other properties (-1 is the default value)
    1676         1075 :             if (JMAttribute != INVALID_DOUBLE) {
    1677              :                 // special case for sigma minor
    1678         1075 :                 if (it == SUMO_ATTR_JM_SIGMA_MINOR) {
    1679              :                     // check attributes sigma minor
    1680          126 :                     if ((JMAttribute < 0) || (JMAttribute > 1)) {
    1681            0 :                         WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
    1682            0 :                         return false;
    1683              :                     }
    1684          949 :                 } else if (JMAttribute < 0
    1685           25 :                            && it != SUMO_ATTR_JM_TIMEGAP_MINOR
    1686           18 :                            && it != SUMO_ATTR_JM_EXTRA_GAP) {
    1687              :                     // attributes with error value
    1688           18 :                     if (JMAttribute != -1 || (it != SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME
    1689              :                                               && it != SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME
    1690           18 :                                               && it != SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME)) {
    1691              :                         // check attributes of type "nonNegativeFloatType" (>= 0)
    1692            0 :                         WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Must be equal or greater than 0"), toString(it));
    1693            0 :                         return false;
    1694              :                     }
    1695              :                 }
    1696              :                 // add parsedJMAttribute to cfParameter
    1697         1075 :                 into->jmParameter[it] = parsedJMAttribute;
    1698              :             }
    1699              :         }
    1700              :     }
    1701              :     // all JM parameters successfully parsed, then return true
    1702              :     return true;
    1703              : }
    1704              : 
    1705              : 
    1706              : SUMOVehicleClass
    1707        36691 : SUMOVehicleParserHelper::parseVehicleClass(const SUMOSAXAttributes& attrs, const std::string& id) {
    1708              :     SUMOVehicleClass vclass = SVC_IGNORING;
    1709        36691 :     bool ok = true;
    1710        36691 :     std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_VCLASS, id.c_str(), ok, "");
    1711        36691 :     if (vclassS == "") {
    1712              :         return vclass;
    1713              :     }
    1714              :     try {
    1715        36667 :         const SUMOVehicleClass result = getVehicleClassID(vclassS);
    1716        36659 :         const std::string& realName = SumoVehicleClassStrings.getString(result);
    1717        36659 :         if (realName != vclassS) {
    1718           12 :             WRITE_WARNING("The vehicle class '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
    1719              :         }
    1720              :         return result;
    1721            8 :     } catch (...) {
    1722           24 :         WRITE_ERRORF(TL("The vehicle class '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
    1723            8 :     }
    1724              :     return vclass;
    1725              : }
    1726              : 
    1727              : 
    1728              : SUMOVehicleShape
    1729        27193 : SUMOVehicleParserHelper::parseGuiShape(const SUMOSAXAttributes& attrs, const std::string& id) {
    1730        27193 :     bool ok = true;
    1731        54386 :     std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_GUISHAPE, id.c_str(), ok, "");
    1732              :     if (SumoVehicleShapeStrings.hasString(vclassS)) {
    1733        27193 :         const SUMOVehicleShape result = SumoVehicleShapeStrings.get(vclassS);
    1734        27193 :         const std::string& realName = SumoVehicleShapeStrings.getString(result);
    1735        27193 :         if (realName != vclassS) {
    1736            0 :             WRITE_WARNING("The shape '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
    1737              :         }
    1738        27193 :         return result;
    1739              :     } else {
    1740            0 :         WRITE_ERRORF(TL("The shape '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
    1741            0 :         return SUMOVehicleShape::UNKNOWN;
    1742              :     }
    1743              : }
    1744              : 
    1745              : 
    1746              : double
    1747        31983 : SUMOVehicleParserHelper::parseWalkPos(SumoXMLAttr attr, const bool hardFail, const std::string& id, double maxPos, const std::string& val, SumoRNG* rng) {
    1748              :     double result;
    1749              :     std::string error;
    1750        31983 :     ArrivalPosDefinition proc = ArrivalPosDefinition::DEFAULT;
    1751              :     // only supports 'random' and 'max'
    1752        63966 :     if (!SUMOVehicleParameter::parseArrivalPos(val, toString(SUMO_TAG_WALK), id, result, proc, error)) {
    1753            0 :         handleVehicleError(hardFail, nullptr, error);
    1754              :     }
    1755        31983 :     if (proc == ArrivalPosDefinition::RANDOM) {
    1756         1076 :         result = RandHelper::rand(maxPos, rng);
    1757        30907 :     } else if (proc == ArrivalPosDefinition::CENTER) {
    1758            0 :         result = maxPos / 2.;
    1759        30907 :     } else if (proc == ArrivalPosDefinition::MAX) {
    1760            0 :         result = maxPos;
    1761              :     }
    1762        63966 :     return SUMOVehicleParameter::interpretEdgePos(result, maxPos, attr, id);
    1763              : }
    1764              : 
    1765              : 
    1766              : SUMOTime
    1767       446095 : SUMOVehicleParserHelper::processActionStepLength(double given) {
    1768       446095 :     const std::string defaultError = "The parameter action-step-length must be a non-negative multiple of the simulation step-length. ";
    1769       446095 :     SUMOTime result = TIME2STEPS(given);
    1770       446095 :     if (result <= 0) {
    1771        38536 :         if (result < 0) {
    1772           36 :             WRITE_WARNING(defaultError + "Ignoring given value (=" + toString(STEPS2TIME(result)) + " s.)");
    1773              :         }
    1774        38536 :         result = DELTA_T;
    1775       407589 :     } else if (result % DELTA_T != 0 && OptionsCont::getOptions().exists("step-length")) {
    1776           26 :         result = (SUMOTime)((double)DELTA_T * floor(double(result) / double(DELTA_T)));
    1777              :         result = MAX2(DELTA_T, result);
    1778           26 :         if (fabs(given * 1000. - double(result)) > NUMERICAL_EPS) {
    1779          104 :             WRITE_WARNING(defaultError + "Parsing given value (" + toString(given) + " s.) to the adjusted value " + toString(STEPS2TIME(result)) + " s.");
    1780              :         }
    1781              :     }
    1782       446095 :     return result;
    1783              : }
    1784              : 
    1785              : 
    1786              : bool
    1787       183030 : SUMOVehicleParserHelper::isInternalRouteID(const std::string& id) {
    1788       183030 :     return id.substr(0, 1) == "!";
    1789              : }
    1790              : 
    1791              : 
    1792              : bool
    1793           12 : SUMOVehicleParserHelper::validProfile(SUMOVTypeParameter* vtype, const std::string data, const SumoXMLAttr attr) {
    1794           48 :     for (std::string value : StringTokenizer(data).getVector()) {
    1795              :         try {
    1796           24 :             double v = StringUtils::toDouble(value);
    1797           24 :             if (v < 0.) {
    1798            0 :                 WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. An acceleration profile value cannot be negative"), toString(attr));
    1799            0 :                 return false;
    1800              :             }
    1801            0 :         } catch (...) {
    1802            0 :             WRITE_ERRORF(TL("Entry '%' of % table for vType '%' cannot be parsed as 'double'"), value, toString(attr), vtype->id);
    1803              :             return false;
    1804            0 :         }
    1805           12 :     }
    1806           12 :     return true;
    1807              : }
    1808              : 
    1809              : 
    1810              : int
    1811        13537 : SUMOVehicleParserHelper::parseCarWalkTransfer(const OptionsCont& oc, const bool hasTaxi) {
    1812              :     int carWalk = 0;
    1813        40611 :     for (const std::string& opt : oc.getStringVector("persontrip.transfer.car-walk")) {
    1814        13537 :         if (opt == "parkingAreas") {
    1815        13337 :             carWalk |= ModeChangeOptions::PARKING_AREAS;
    1816          200 :         } else if (opt == "ptStops") {
    1817          150 :             carWalk |= ModeChangeOptions::PT_STOPS;
    1818           50 :         } else if (opt == "allJunctions") {
    1819           50 :             carWalk |= ModeChangeOptions::ALL_JUNCTIONS;
    1820              :         } else {
    1821            0 :             WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
    1822              :         }
    1823              :     }
    1824        13537 :     const StringVector taxiDropoff = oc.getStringVector("persontrip.transfer.taxi-walk");
    1825        27074 :     const StringVector taxiPickup = oc.getStringVector("persontrip.transfer.walk-taxi");
    1826        13537 :     if (taxiDropoff.empty() && hasTaxi) {
    1827         3444 :         carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
    1828              :     } else {
    1829        10231 :         for (const std::string& opt : taxiDropoff) {
    1830          138 :             if (opt == "parkingAreas") {
    1831           14 :                 carWalk |= ModeChangeOptions::TAXI_DROPOFF_PARKING_AREAS;
    1832          124 :             } else if (opt == "ptStops") {
    1833           80 :                 carWalk |= ModeChangeOptions::TAXI_DROPOFF_PT;
    1834           44 :             } else if (opt == "allJunctions") {
    1835           44 :                 carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
    1836              :             } else {
    1837            0 :                 WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
    1838              :             }
    1839              :         }
    1840              :     }
    1841        13537 :     if (taxiPickup.empty() && hasTaxi) {
    1842         3424 :         carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
    1843              :     } else {
    1844        10271 :         for (const std::string& opt : taxiPickup) {
    1845          158 :             if (opt == "parkingAreas") {
    1846           14 :                 carWalk |= ModeChangeOptions::TAXI_PICKUP_PARKING_AREAS;
    1847          144 :             } else if (opt == "ptStops") {
    1848           96 :                 carWalk |= ModeChangeOptions::TAXI_PICKUP_PT;
    1849           48 :             } else if (opt == "allJunctions") {
    1850           48 :                 carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
    1851              :             } else {
    1852            0 :                 WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
    1853              :             }
    1854              :         }
    1855              :     }
    1856        13537 :     return carWalk;
    1857        13537 : }
    1858              : 
    1859              : 
    1860              : SUMOVehicleParameter*
    1861          432 : SUMOVehicleParserHelper::handleVehicleError(const bool hardFail, SUMOVehicleParameter* vehicleParameter, const std::string message) {
    1862          432 :     if (vehicleParameter) {
    1863          388 :         delete vehicleParameter;
    1864              :     }
    1865          432 :     if (hardFail) {
    1866          432 :         throw ProcessError(message);
    1867            0 :     } else if (message.size() > 0) {
    1868            0 :         WRITE_ERROR(message);
    1869              :     }
    1870            0 :     return nullptr;
    1871              : }
    1872              : 
    1873              : 
    1874              : SUMOVTypeParameter*
    1875           30 : SUMOVehicleParserHelper::handleVehicleTypeError(const bool hardFail, SUMOVTypeParameter* vehicleTypeParameter, const std::string message) {
    1876           30 :     if (vehicleTypeParameter) {
    1877           26 :         delete vehicleTypeParameter;
    1878              :     }
    1879           30 :     if (hardFail) {
    1880           30 :         throw ProcessError(message);
    1881            0 :     } else if (message.size() > 0) {
    1882            0 :         WRITE_ERROR(message);
    1883              :     }
    1884            0 :     return nullptr;
    1885              : }
    1886              : 
    1887              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1