LCOV - code coverage report
Current view: top level - src/utils/vehicle - SUMOVehicleParserHelper.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 85.2 % 1106 942
Test Date: 2024-12-21 15:45:41 Functions: 100.0 % 18 18

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2008-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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        24866 : 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        24866 :     const std::string id = attrs.hasAttribute(SUMO_ATTR_ID) ? parseID(attrs, tag) : "";
      61              :     // check if ID is valid
      62        24866 :     if (!needID || !id.empty()) {
      63        24859 :         if (needID && !SUMOXMLDefinitions::isValidVehicleID(id)) {
      64            0 :             return handleVehicleError(hardFail, nullptr, "Invalid flow id '" + id + "'.");
      65              :         }
      66              :         // declare flags
      67        24859 :         const bool hasPeriod = attrs.hasAttribute(SUMO_ATTR_PERIOD);
      68        24859 :         const bool hasVPH = attrs.hasAttribute(SUMO_ATTR_VEHSPERHOUR);
      69        24859 :         const bool hasPPH = attrs.hasAttribute(SUMO_ATTR_PERSONSPERHOUR);
      70        24859 :         const bool hasCPH = attrs.hasAttribute(SUMO_ATTR_CONTAINERSPERHOUR);
      71        24859 :         const bool hasPH = attrs.hasAttribute(SUMO_ATTR_PERHOUR);
      72        24859 :         const bool hasXPH = hasVPH || hasPPH || hasCPH || hasPH;
      73        24859 :         const bool hasProb = attrs.hasAttribute(SUMO_ATTR_PROB);
      74        24859 :         const bool hasNumber = attrs.hasAttribute(SUMO_ATTR_NUMBER);
      75        24859 :         const bool hasBegin = attrs.hasAttribute(SUMO_ATTR_BEGIN);
      76        24859 :         const bool hasEnd = attrs.hasAttribute(SUMO_ATTR_END);
      77              :         SumoXMLAttr PERHOUR = SUMO_ATTR_PERHOUR;
      78        24859 :         if (hasVPH) {
      79              :             PERHOUR = SUMO_ATTR_VEHSPERHOUR;
      80              :         }
      81        24859 :         if (hasPPH) {
      82              :             PERHOUR = SUMO_ATTR_PERSONSPERHOUR;
      83              :         }
      84        24859 :         if (hasCPH) {
      85              :             PERHOUR = SUMO_ATTR_CONTAINERSPERHOUR;
      86              :         }
      87        24859 :         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         3890 :         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        24852 :         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        24852 :         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        24852 :         if (hasPeriod || hasXPH || hasProb) {
     117        16380 :             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         8472 :             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        24838 :         SUMOVehicleParameter* flowParameter = new SUMOVehicleParameter();
     146              :         // set tag
     147        24838 :         flowParameter->tag = tag;
     148              :         // set id
     149        24838 :         flowParameter->id = id;
     150        24838 :         if (tag == SUMO_TAG_PERSONFLOW) {
     151         1719 :             flowParameter->vtypeid = DEFAULT_PEDTYPE_ID;
     152              :         }
     153        24838 :         if (tag == SUMO_TAG_CONTAINERFLOW) {
     154          322 :             flowParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
     155              :         }
     156              :         // parse common vehicle attributes
     157              :         try {
     158        24838 :             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        24790 :         if (hasPeriod) {
     170         8497 :             bool ok = true;
     171         8497 :             const std::string description = attrs.get<std::string>(SUMO_ATTR_PERIOD, id.c_str(), ok);
     172         8497 :             const std::string distName = description.substr(0, description.find('('));
     173         8497 :             if (distName == "exp") {
     174              :                 // declare rate
     175              :                 double rate = -1;
     176              :                 // parse rate
     177              :                 try {
     178          551 :                     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          551 :                 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          544 :                 flowParameter->poissonRate = rate;
     191              :                 poissonFlow = true;
     192              :             } else {
     193         7946 :                 flowParameter->repetitionOffset = attrs.getSUMOTimeReporting(SUMO_ATTR_PERIOD, id.c_str(), ok);
     194              :             }
     195         8490 :             if (!ok) {
     196            7 :                 return handleVehicleError(hardFail, flowParameter);
     197              :             } else {
     198         8490 :                 flowParameter->parametersSet |= VEHPARS_PERIOD_SET;
     199              :             }
     200              :         }
     201              :         // parse vehicle/person/container/etc per hour
     202        24783 :         if (hasXPH) {
     203         3883 :             bool ok = true;
     204         3883 :             const double vph = attrs.get<double>(PERHOUR, id.c_str(), ok);
     205         3883 :             if (!ok) {
     206            0 :                 return handleVehicleError(hardFail, flowParameter);
     207         3883 :             } 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         3883 :                     flowParameter->repetitionOffset = TIME2STEPS(3600. / vph);
     212              :                 }
     213         3883 :                 flowParameter->parametersSet |= VEHPARS_VPH_SET;
     214              :             }
     215              :         }
     216              :         // parse probability
     217        24783 :         if (hasProb) {
     218         3993 :             bool ok = true;
     219         3993 :             flowParameter->repetitionProbability = attrs.get<double>(SUMO_ATTR_PROB, id.c_str(), ok);
     220         3993 :             if (!ok) {
     221            0 :                 return handleVehicleError(hardFail, flowParameter);
     222         3993 :             } 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         3993 :                 flowParameter->parametersSet |= VEHPARS_PROB_SET;
     226              :             }
     227              :         }
     228              :         // set default begin
     229        24783 :         flowParameter->depart = beginDefault;
     230              :         // parse begin
     231        24783 :         if (hasBegin) {
     232              :             // first get begin
     233        24601 :             bool ok = true;
     234        24601 :             const std::string begin = attrs.get<std::string>(SUMO_ATTR_BEGIN, id.c_str(), ok);
     235        24601 :             if (!ok) {
     236            7 :                 return handleVehicleError(hardFail, flowParameter);
     237              :             } else {
     238              :                 // parse begin
     239              :                 std::string errorMsg;
     240        49202 :                 if (!SUMOVehicleParameter::parseDepart(begin, toString(tag), id, flowParameter->depart, flowParameter->departProcedure, errorMsg, "begin")) {
     241           14 :                     return handleVehicleError(hardFail, flowParameter, errorMsg);
     242              :                 }
     243              :             }
     244              :         }
     245        24776 :         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        24776 :         flowParameter->repetitionEnd = endDefault;
     250        24776 :         if (flowParameter->repetitionEnd < 0) {
     251        17196 :             flowParameter->repetitionEnd = SUMOTime_MAX;
     252              :         }
     253              :         // parse end
     254        24776 :         if (hasEnd) {
     255        22479 :             bool ok = true;
     256        22479 :             flowParameter->repetitionEnd = attrs.getSUMOTimeReporting(SUMO_ATTR_END, id.c_str(), ok);
     257        22479 :             if (!ok) {
     258            0 :                 return handleVehicleError(hardFail, flowParameter);
     259              :             } else {
     260        22479 :                 flowParameter->parametersSet |= VEHPARS_END_SET;
     261              :             }
     262         2297 :         } 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         2250 :         } 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        24776 :         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        24769 :         if (hasNumber) {
     279        10401 :             bool ok = true;
     280        10401 :             flowParameter->repetitionNumber = attrs.get<int>(SUMO_ATTR_NUMBER, id.c_str(), ok);
     281        10401 :             if (!ok) {
     282            0 :                 return handleVehicleError(hardFail, flowParameter);
     283              :             } else {
     284        10401 :                 flowParameter->parametersSet |= VEHPARS_NUMBER_SET;
     285        10401 :                 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        10393 :                     if (flowParameter->repetitionNumber < 0) {
     292           14 :                         return handleVehicleError(hardFail, flowParameter, "Negative repetition number in the definition of " + toString(tag) + " '" + id + "'.");
     293              :                     }
     294        10386 :                     if (flowParameter->repetitionOffset < 0 && !hasProb) {
     295         8452 :                         if (poissonFlow) {
     296           43 :                             flowParameter->repetitionEnd = SUMOTime_MAX;
     297              :                         } else {
     298         8409 :                             flowParameter->repetitionOffset = (flowParameter->repetitionEnd - flowParameter->depart) / flowParameter->repetitionNumber;
     299              :                         }
     300              :                     }
     301              :                 }
     302              :             }
     303              :         } else {
     304              :             // interpret repetitionNumber
     305        14368 :             if (flowParameter->repetitionProbability > 0) {
     306         3951 :                 flowParameter->repetitionNumber = std::numeric_limits<int>::max();
     307              :             } else {
     308        10417 :                 if (flowParameter->repetitionOffset <= 0) {
     309          515 :                     if (poissonFlow) {
     310              :                         // number is random but flow has a fixed end time
     311          501 :                         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         9902 :                     if (flowParameter->repetitionEnd == SUMOTime_MAX) {
     317            0 :                         flowParameter->repetitionNumber = std::numeric_limits<int>::max();
     318              :                     } else {
     319         9902 :                         const SUMOTime repLength = flowParameter->repetitionEnd - flowParameter->depart;
     320         9902 :                         flowParameter->repetitionNumber = (int)ceil((double)repLength / (double)flowParameter->repetitionOffset);
     321              :                     }
     322              :                 }
     323              :             }
     324              :         }
     325              :         // all ok, then return flow parameter
     326        24748 :         return flowParameter;
     327              :     } else {
     328          132 :         return handleVehicleError(hardFail, nullptr, toString(tag) + " cannot be created");
     329              :     }
     330              : }
     331              : 
     332              : 
     333              : SUMOVehicleParameter*
     334       472779 : 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       472779 :     if (optionalID) {
     339          673 :         bool ok = true;
     340          673 :         id = attrs.getOpt<std::string>(SUMO_ATTR_ID, nullptr, ok, "");
     341          673 :         if (!ok) {
     342            0 :             return handleVehicleError(hardFail, nullptr);
     343              :         }
     344              :     } else {
     345              :         // parse ID
     346       944212 :         id = parseID(attrs, (SumoXMLTag)element);
     347              :     }
     348              :     // only continue if id is valid, or if is optional
     349       472779 :     if (optionalID || !id.empty()) {
     350              :         // declare vehicle parameter
     351       472763 :         SUMOVehicleParameter* vehicleParameter = new SUMOVehicleParameter();
     352       472763 :         vehicleParameter->id = id;
     353       472763 :         if (element == SUMO_TAG_PERSON) {
     354        41429 :             vehicleParameter->vtypeid = DEFAULT_PEDTYPE_ID;
     355       431334 :         } else if (element == SUMO_TAG_CONTAINER) {
     356          820 :             vehicleParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
     357              :         }
     358              :         // parse common attributes
     359              :         try {
     360       472763 :             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       472489 :         if (!skipDepart) {
     371       471816 :             bool ok = true;
     372       471816 :             const std::string helper = attrs.get<std::string>(SUMO_ATTR_DEPART, vehicleParameter->id.c_str(), ok);
     373       471816 :             if (!ok) {
     374           40 :                 return handleVehicleError(hardFail, vehicleParameter);
     375              :             }
     376              :             // now parse depart
     377              :             std::string departErrorMsg;
     378       943600 :             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       472465 :         vehicleParameter->tag = (SumoXMLTag)element;
     384              :         // all ok, then return vehicleParameter
     385       472465 :         return vehicleParameter;
     386              :     } else {
     387          346 :         return handleVehicleError(hardFail, nullptr, toString((SumoXMLTag)element) + " cannot be created");
     388              :     }
     389              : }
     390              : 
     391              : 
     392              : std::string
     393       557623 : SUMOVehicleParserHelper::parseID(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
     394       557623 :     bool ok = true;
     395              :     std::string id;
     396              :     // first check if attrs contain an ID
     397       557623 :     if (attrs.hasAttribute(SUMO_ATTR_ID)) {
     398       557611 :         id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     399       557611 :         if (SUMOXMLDefinitions::isValidVehicleID(id)) {
     400       557603 :             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       497601 : SUMOVehicleParserHelper::parseCommonAttributes(const SUMOSAXAttributes& attrs, SUMOVehicleParameter* ret, SumoXMLTag tag, const bool allowInternalRoutes) {
     417       497601 :     const std::string element = toString(tag);
     418              :     //ret->refid = attrs.getStringSecure(SUMO_ATTR_REFID, "");
     419              :     // parse route information
     420       497601 :     if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
     421       167014 :         bool ok = true;
     422       167014 :         std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, ret->id.c_str(), ok);
     423       167014 :         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       167014 :         ret->routeid = routeID;
     427       167014 :         if (ok) {
     428       167004 :             ret->parametersSet |= VEHPARS_ROUTE_SET; // !!! needed?
     429              :         } else {
     430           20 :             handleVehicleError(true, ret);
     431              :         }
     432              :     }
     433              :     // parse type information
     434       497591 :     if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
     435       214109 :         bool ok = true;
     436       214109 :         ret->vtypeid = attrs.get<std::string>(SUMO_ATTR_TYPE, ret->id.c_str(), ok);
     437       214109 :         if (ok) {
     438       214109 :             ret->parametersSet |= VEHPARS_VTYPE_SET; // !!! needed?
     439              :         } else {
     440            0 :             handleVehicleError(true, ret);
     441              :         }
     442              :     }
     443              :     // parse line information
     444       497591 :     if (attrs.hasAttribute(SUMO_ATTR_LINE)) {
     445         2924 :         bool ok = true;
     446         2924 :         ret->line = attrs.get<std::string>(SUMO_ATTR_LINE, ret->id.c_str(), ok);
     447         2924 :         if (ok) {
     448         2918 :             ret->parametersSet |= VEHPARS_LINE_SET; // !!! needed?
     449              :         } else {
     450            6 :             handleVehicleError(true, ret);
     451              :         }
     452              :     }
     453              :     // parse zone information
     454       497585 :     if (attrs.hasAttribute(SUMO_ATTR_FROM_TAZ)) {
     455        26128 :         bool ok = true;
     456        26128 :         ret->fromTaz = attrs.get<std::string>(SUMO_ATTR_FROM_TAZ, ret->id.c_str(), ok);
     457        26128 :         if (ok) {
     458        26128 :             ret->parametersSet |= VEHPARS_FROM_TAZ_SET;
     459              :         } else {
     460            0 :             handleVehicleError(true, ret);
     461              :         }
     462              :     }
     463       497585 :     if (attrs.hasAttribute(SUMO_ATTR_TO_TAZ)) {
     464        26128 :         bool ok = true;
     465        26128 :         ret->toTaz = attrs.get<std::string>(SUMO_ATTR_TO_TAZ, ret->id.c_str(), ok);
     466        26128 :         if (ok) {
     467        26128 :             ret->parametersSet |= VEHPARS_TO_TAZ_SET;
     468              :         } else {
     469            0 :             handleVehicleError(true, ret);
     470              :         }
     471              :     }
     472              :     // parse reroute information
     473       497585 :     if (attrs.hasAttribute(SUMO_ATTR_REROUTE)) {
     474         3841 :         bool ok = true;
     475         3841 :         if (attrs.get<bool>(SUMO_ATTR_REROUTE, ret->id.c_str(), ok)) {
     476         3841 :             if (ok) {
     477         3841 :                 ret->parametersSet |= VEHPARS_FORCE_REROUTE;
     478              :             } else {
     479            0 :                 handleVehicleError(true, ret);
     480              :             }
     481              :         }
     482              :     }
     483              :     // parse depart lane information
     484       497585 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTLANE)) {
     485       110254 :         bool ok = true;
     486       110254 :         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       110254 :         if (SUMOVehicleParameter::parseDepartLane(departLaneStr, element, ret->id, lane, dld, error)) {
     491       110206 :             ret->parametersSet |= VEHPARS_DEPARTLANE_SET;
     492       110206 :             ret->departLane = lane;
     493       110206 :             ret->departLaneProcedure = dld;
     494              :         } else {
     495           96 :             handleVehicleError(true, ret, error);
     496              :         }
     497              :     }
     498              :     // parse depart position information
     499       497537 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
     500        86973 :         bool ok = true;
     501        86973 :         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        86973 :         if (SUMOVehicleParameter::parseDepartPos(departPosStr, element, ret->id, pos, dpd, error)) {
     506        86925 :             ret->parametersSet |= VEHPARS_DEPARTPOS_SET;
     507        86925 :             ret->departPos = pos;
     508        86925 :             ret->departPosProcedure = dpd;
     509              :         } else {
     510           96 :             handleVehicleError(true, ret, error);
     511              :         }
     512              :     }
     513              :     // parse lateral depart position information
     514       497489 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS_LAT)) {
     515         8717 :         bool ok = true;
     516         8717 :         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         8717 :         if (SUMOVehicleParameter::parseDepartPosLat(departPosLatStr, element, ret->id, pos, dpd, error)) {
     521         8717 :             ret->parametersSet |= VEHPARS_DEPARTPOSLAT_SET;
     522         8717 :             ret->departPosLat = pos;
     523         8717 :             ret->departPosLatProcedure = dpd;
     524              :         } else {
     525            0 :             handleVehicleError(true, ret, error);
     526              :         }
     527              :     }
     528              :     // parse depart speed information
     529       497489 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTSPEED)) {
     530       240885 :         bool ok = true;
     531       240885 :         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       240885 :         if (SUMOVehicleParameter::parseDepartSpeed(departSpeed, element, ret->id, speed, dsd, error)) {
     536       240837 :             ret->parametersSet |= VEHPARS_DEPARTSPEED_SET;
     537       240837 :             ret->departSpeed = speed;
     538       240837 :             ret->departSpeedProcedure = dsd;
     539              :         } else {
     540           96 :             handleVehicleError(true, ret, error);
     541              :         }
     542              :     }
     543              :     // parse depart edge information
     544       497441 :     if (attrs.hasAttribute(SUMO_ATTR_DEPARTEDGE)) {
     545          151 :         bool ok = true;
     546          151 :         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          151 :         if (SUMOVehicleParameter::parseRouteIndex(departEdgeStr, element, ret->id, SUMO_ATTR_DEPARTEDGE, edgeIndex, rid, error)) {
     551          144 :             ret->parametersSet |= VEHPARS_DEPARTEDGE_SET;
     552          144 :             ret->departEdge = edgeIndex;
     553          144 :             ret->departEdgeProcedure = rid;
     554              :         } else {
     555           14 :             handleVehicleError(true, ret, error);
     556              :         }
     557              :     }
     558              :     // parse arrival lane information
     559       497434 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALLANE)) {
     560         3162 :         bool ok = true;
     561         3162 :         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         3162 :         if (SUMOVehicleParameter::parseArrivalLane(arrivalLaneStr, element, ret->id, lane, ald, error)) {
     566         3114 :             ret->parametersSet |= VEHPARS_ARRIVALLANE_SET;
     567         3114 :             ret->arrivalLane = lane;
     568         3114 :             ret->arrivalLaneProcedure = ald;
     569              :         } else {
     570           96 :             handleVehicleError(true, ret, error);
     571              :         }
     572              :     }
     573              :     // parse arrival position information
     574       497386 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
     575         8062 :         bool ok = true;
     576         8062 :         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         8062 :         if (SUMOVehicleParameter::parseArrivalPos(arrivalPosStr, element, ret->id, pos, apd, error)) {
     581         8014 :             ret->parametersSet |= VEHPARS_ARRIVALPOS_SET;
     582         8014 :             ret->arrivalPos = pos;
     583         8014 :             ret->arrivalPosProcedure = apd;
     584              :         } else {
     585           96 :             handleVehicleError(true, ret, error);
     586              :         }
     587              :     }
     588              :     // parse lateral arrival position information
     589       497338 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_LAT)) {
     590         1065 :         bool ok = true;
     591         1065 :         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         1065 :         if (SUMOVehicleParameter::parseArrivalPosLat(arrivalPosLatStr, element, ret->id, pos, apd, error)) {
     596         1065 :             ret->parametersSet |= VEHPARS_ARRIVALPOSLAT_SET;
     597         1065 :             ret->arrivalPosLat = pos;
     598         1065 :             ret->arrivalPosLatProcedure = apd;
     599              :         } else {
     600            0 :             handleVehicleError(true, ret, error);
     601              :         }
     602              :     }
     603              :     // parse arrival speed information
     604       497338 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALSPEED)) {
     605         3792 :         bool ok = true;
     606         3792 :         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         3792 :         if (SUMOVehicleParameter::parseArrivalSpeed(arrivalSpeedStr, element, ret->id, speed, asd, error)) {
     611         3744 :             ret->parametersSet |= VEHPARS_ARRIVALSPEED_SET;
     612         3744 :             ret->arrivalSpeed = speed;
     613         3744 :             ret->arrivalSpeedProcedure = asd;
     614              :         } else {
     615           96 :             handleVehicleError(true, ret, error);
     616              :         }
     617              :     }
     618              :     // parse arrival edge information
     619       497290 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALEDGE)) {
     620           81 :         bool ok = true;
     621           81 :         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           81 :         if (SUMOVehicleParameter::parseRouteIndex(arrivalEdgeStr, element, ret->id, SUMO_ATTR_ARRIVALEDGE, edgeIndex, rid, error)) {
     626           74 :             ret->parametersSet |= VEHPARS_ARRIVALEDGE_SET;
     627           74 :             ret->arrivalEdge = edgeIndex;
     628           74 :             ret->arrivalEdgeProcedure = rid;
     629              :         } else {
     630           14 :             handleVehicleError(true, ret, error);
     631              :         }
     632              :     }
     633              :     // parse color
     634       497283 :     if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
     635         8677 :         bool ok = true;
     636         8677 :         ret->color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, ret->id.c_str(), ok);
     637         8677 :         if (ok) {
     638         8677 :             ret->parametersSet |= VEHPARS_COLOR_SET;
     639              :         } else {
     640            0 :             handleVehicleError(true, ret, "Invalid RGBColor format");
     641              :         }
     642              :     } else {
     643       488606 :         ret->color = RGBColor::DEFAULT_COLOR;
     644              :     }
     645              :     // parse person number
     646       497283 :     if (attrs.hasAttribute(SUMO_ATTR_PERSON_NUMBER)) {
     647          986 :         bool ok = true;
     648          986 :         int personNumber = attrs.get<int>(SUMO_ATTR_PERSON_NUMBER, ret->id.c_str(), ok);
     649          986 :         if (!ok) {
     650            0 :             handleVehicleError(true, ret);
     651          986 :         } else if (personNumber >= 0) {
     652          986 :             ret->parametersSet |= VEHPARS_PERSON_NUMBER_SET;
     653          986 :             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       497283 :     if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_NUMBER)) {
     660          980 :         bool ok = true;
     661          980 :         int containerNumber = attrs.get<int>(SUMO_ATTR_CONTAINER_NUMBER, ret->id.c_str(), ok);
     662          980 :         if (!ok) {
     663            0 :             handleVehicleError(true, ret);
     664          980 :         } else if (containerNumber >= 0) {
     665          980 :             ret->parametersSet |= VEHPARS_CONTAINER_NUMBER_SET;
     666          980 :             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       497283 :     if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
     673        10661 :         bool ok = true;
     674        10661 :         double speedFactor = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR, ret->id.c_str(), ok);
     675        10661 :         if (!ok) {
     676            0 :             handleVehicleError(true, ret);
     677        10661 :         } else if (speedFactor > 0) {
     678        10661 :             ret->parametersSet |= VEHPARS_SPEEDFACTOR_SET;
     679        10661 :             ret->speedFactor = speedFactor;
     680              :         } else {
     681            0 :             handleVehicleError(true, ret, toString(SUMO_ATTR_SPEEDFACTOR) + " must be positive");
     682              :         }
     683              :     }
     684              :     // parse insertion checks
     685       497283 :     if (attrs.hasAttribute(SUMO_ATTR_INSERTIONCHECKS)) {
     686         1022 :         ret->parametersSet |= VEHPARS_INSERTION_CHECKS_SET;
     687         1022 :         bool ok = true;
     688         1022 :         std::string checks = attrs.get<std::string>(SUMO_ATTR_INSERTIONCHECKS, ret->id.c_str(), ok);
     689         1022 :         if (!ok) {
     690            4 :             handleVehicleError(true, ret);
     691              :         } else {
     692              :             try {
     693         1022 :                 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       497279 :     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       497279 :     ret->modes = 0;
     712       497279 :     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       497279 :     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       497279 :     if (tag == SUMO_TAG_FLOW && attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     735          216 :         bool ok = true;
     736          216 :         double calibratorSpeed = attrs.get<double>(SUMO_ATTR_SPEED, ret->id.c_str(), ok);
     737          216 :         if (!ok) {
     738            0 :             handleVehicleError(true, ret);
     739          216 :         } else if (calibratorSpeed >= 0 || calibratorSpeed == -1) {
     740          216 :             ret->parametersSet |= VEHPARS_CALIBRATORSPEED_SET;
     741          216 :             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       497279 : }
     753              : 
     754              : 
     755              : SUMOVTypeParameter*
     756        60658 : SUMOVehicleParserHelper::beginVTypeParsing(const SUMOSAXAttributes& attrs, const bool hardFail, const std::string& file) {
     757              :     // first obtain ID
     758        60658 :     std::string id = parseID(attrs, SUMO_TAG_VTYPE);
     759              :     // check if ID is valid
     760        60658 :     if (!id.empty()) {
     761              :         SUMOVehicleClass vClass = SVC_PASSENGER;
     762        60654 :         if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
     763        35626 :             vClass = parseVehicleClass(attrs, id);
     764              :         }
     765              :         // create vType
     766        60654 :         SUMOVTypeParameter* vType = new SUMOVTypeParameter(id, vClass);
     767              :         // parse attributes
     768        60654 :         if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
     769        35626 :             vType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     770              :         }
     771        60654 :         if (attrs.hasAttribute(SUMO_ATTR_LENGTH)) {
     772        37269 :             bool ok = true;
     773        37269 :             const double length = attrs.get<double>(SUMO_ATTR_LENGTH, vType->id.c_str(), ok);
     774        37269 :             if (!ok) {
     775            0 :                 return handleVehicleTypeError(hardFail, vType);
     776        37269 :             } else if (length <= 0) {
     777            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LENGTH) + " must be greater than 0");
     778              :             } else {
     779        37269 :                 vType->length = length;
     780        37269 :                 vType->parametersSet |= VTYPEPARS_LENGTH_SET;
     781              :             }
     782              :         }
     783        60654 :         if (attrs.hasAttribute(SUMO_ATTR_MINGAP)) {
     784        35691 :             bool ok = true;
     785        35691 :             const double minGap = attrs.get<double>(SUMO_ATTR_MINGAP, vType->id.c_str(), ok);
     786        35691 :             if (!ok) {
     787            0 :                 return handleVehicleTypeError(hardFail, vType);
     788        35691 :             } else if (minGap < 0) {
     789            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP) + " must be equal or greater than 0");
     790              :             } else {
     791        35691 :                 vType->minGap = minGap;
     792        35691 :                 vType->parametersSet |= VTYPEPARS_MINGAP_SET;
     793              :             }
     794              :         }
     795        60654 :         if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
     796        36808 :             bool ok = true;
     797        36808 :             const double maxSpeed = attrs.get<double>(SUMO_ATTR_MAXSPEED, vType->id.c_str(), ok);
     798        36808 :             if (!ok) {
     799            0 :                 return handleVehicleTypeError(hardFail, vType);
     800        36808 :             } else if (maxSpeed <= 0) {
     801            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED) + " must be greater than 0");
     802              :             } else {
     803        36808 :                 vType->maxSpeed = maxSpeed;
     804        36808 :                 vType->parametersSet |= VTYPEPARS_MAXSPEED_SET;
     805              :             }
     806              :         }
     807        60654 :         if (attrs.hasAttribute(SUMO_ATTR_DESIRED_MAXSPEED)) {
     808           48 :             bool ok = true;
     809           48 :             const double desiredMaxSpeed = attrs.get<double>(SUMO_ATTR_DESIRED_MAXSPEED, vType->id.c_str(), ok);
     810           48 :             if (!ok) {
     811            0 :                 return handleVehicleTypeError(hardFail, vType);
     812           48 :             } else if (desiredMaxSpeed <= 0) {
     813            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_DESIRED_MAXSPEED) + " must be greater than 0");
     814              :             } else {
     815           48 :                 vType->desiredMaxSpeed = desiredMaxSpeed;
     816           48 :                 vType->parametersSet |= VTYPEPARS_DESIRED_MAXSPEED_SET;
     817              :             }
     818        60606 :         } else if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
     819        36795 :             if (vClass == SVC_PEDESTRIAN) {
     820              :                 // backward compatibility because pedestrian maxSpeed was subject to speedFactor up to 1.14.1
     821        25876 :                 vType->desiredMaxSpeed = vType->maxSpeed;;
     822        77624 :                 vType->maxSpeed = MAX2(vType->maxSpeed, SUMOVTypeParameter::VClassDefaultValues(vClass).maxSpeed);
     823        10919 :             } 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        60654 :         if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
     830         2388 :             bool ok = true;
     831         2388 :             vType->speedFactor.parse(attrs.get<std::string>(SUMO_ATTR_SPEEDFACTOR, vType->id.c_str(), ok), hardFail);
     832         2388 :             if (!ok) {
     833            0 :                 return handleVehicleTypeError(hardFail, vType);
     834              :             } else {
     835         2388 :                 vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
     836              :             }
     837              :         }
     838        60654 :         if (attrs.hasAttribute(SUMO_ATTR_SPEEDDEV)) {
     839         2353 :             bool ok = true;
     840         2353 :             const double speedDev = attrs.get<double>(SUMO_ATTR_SPEEDDEV, vType->id.c_str(), ok);
     841         2353 :             if (!ok) {
     842            0 :                 return handleVehicleTypeError(hardFail, vType);
     843         2353 :             } else if (speedDev < 0) {
     844            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SPEEDDEV) + " must be equal or greater than 0");
     845              :             } else {
     846         2353 :                 vType->speedFactor.getParameter()[1] = speedDev;
     847         2353 :                 vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
     848              :             }
     849              :         }
     850              :         // validate speed distribution
     851        60654 :         const std::string& error = vType->speedFactor.isValid();
     852        60654 :         if (error != "") {
     853           14 :             return handleVehicleTypeError(hardFail, vType, "Invalid speed distribution when parsing vType '" + vType->id + "' (" + error + ")");
     854              :         }
     855        60647 :         if (attrs.hasAttribute(SUMO_ATTR_ACTIONSTEPLENGTH)) {
     856          220 :             bool ok = true;
     857          220 :             const double actionStepLengthSecs = attrs.get<double>(SUMO_ATTR_ACTIONSTEPLENGTH, vType->id.c_str(), ok);
     858          220 :             if (!ok) {
     859            0 :                 return handleVehicleTypeError(hardFail, vType);
     860              :             } else {
     861              :                 // processActionStepLength(...) function includes warnings
     862          220 :                 vType->actionStepLength = processActionStepLength(actionStepLengthSecs);
     863          220 :                 vType->parametersSet |= VTYPEPARS_ACTIONSTEPLENGTH_SET;
     864              :             }
     865              :         }
     866        60647 :         if (attrs.hasAttribute(SUMO_ATTR_EMISSIONCLASS)) {
     867         1772 :             bool ok = true;
     868         1772 :             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         1772 :                 vType->emissionClass = PollutantsInterface::getClassByName(parsedEmissionClass);
     872         1772 :                 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        60647 :         if (attrs.hasAttribute(SUMO_ATTR_MASS)) {
     878          261 :             bool ok = true;
     879          261 :             const double mass = attrs.get<double>(SUMO_ATTR_MASS, vType->id.c_str(), ok);
     880          261 :             if (!ok) {
     881            0 :                 return handleVehicleTypeError(hardFail, vType);
     882          261 :             } else if (mass < 0) {
     883            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MASS) + " must be equal or greater than 0");
     884              :             } else {
     885          261 :                 vType->mass = mass;
     886          261 :                 vType->parametersSet |= VTYPEPARS_MASS_SET;
     887              :             }
     888              :         }
     889        60647 :         if (attrs.hasAttribute(SUMO_ATTR_IMPATIENCE)) {
     890          231 :             bool ok = true;
     891          231 :             const std::string impatienceStr = attrs.get<std::string>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
     892          231 :             if (!ok) {
     893            0 :                 return handleVehicleTypeError(hardFail, vType);
     894          231 :             } else if (impatienceStr == "off") {
     895           12 :                 vType->impatience = -std::numeric_limits<double>::max();
     896              :             } else {
     897          219 :                 const double impatienceDouble = attrs.get<double>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
     898          219 :                 if (!ok) {
     899            0 :                     return handleVehicleTypeError(hardFail, vType);
     900              :                 } else {
     901          219 :                     vType->impatience = impatienceDouble;
     902          219 :                     vType->parametersSet |= VTYPEPARS_IMPATIENCE_SET;
     903              :                 }
     904              :             }
     905              :         }
     906        60647 :         if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
     907        26731 :             bool ok = true;
     908        26731 :             const double width = attrs.get<double>(SUMO_ATTR_WIDTH, vType->id.c_str(), ok);
     909        26731 :             if (!ok) {
     910            0 :                 return handleVehicleTypeError(hardFail, vType);
     911        26731 :             } else if (width <= 0) {
     912            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_WIDTH) + " must be greater than 0");
     913              :             } else {
     914        26731 :                 vType->width = width;
     915        26731 :                 vType->parametersSet |= VTYPEPARS_WIDTH_SET;
     916        26731 :                 if (vClass == SVC_PEDESTRIAN
     917        52838 :                         && OptionsCont::getOptions().exists("pedestrian.striping.stripe-width")
     918        78945 :                         && OptionsCont::getOptions().getString("pedestrian.model") == "striping"
     919        82128 :                         && 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        60647 :         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        60647 :         if (attrs.hasAttribute(SUMO_ATTR_GUISHAPE)) {
     937        27140 :             vType->shape = parseGuiShape(attrs, vType->id);
     938        27140 :             if (vType->shape != SUMOVehicleShape::UNKNOWN) {
     939        27140 :                 vType->parametersSet |= VTYPEPARS_SHAPE_SET;
     940              :             }
     941              :         }
     942        60647 :         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        60647 :         if (attrs.hasAttribute(SUMO_ATTR_IMGFILE)) {
     953           25 :             bool ok = true;
     954           25 :             std::string imgFile = attrs.get<std::string>(SUMO_ATTR_IMGFILE, vType->id.c_str(), ok);
     955           25 :             if (!ok) {
     956            0 :                 return handleVehicleTypeError(hardFail, vType);
     957              :             } else {
     958              :                 // check relative path
     959           25 :                 if ((imgFile != "") && !FileHelpers::isAbsolute(imgFile)) {
     960           46 :                     imgFile = FileHelpers::getConfigurationRelative(file, imgFile);
     961              :                 }
     962           25 :                 vType->imgFile = imgFile;
     963           25 :                 vType->parametersSet |= VTYPEPARS_IMGFILE_SET;
     964              :             }
     965              :         }
     966        60647 :         if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
     967        22734 :             bool ok = true;
     968        22734 :             const RGBColor color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, vType->id.c_str(), ok);
     969        22734 :             if (!ok) {
     970            8 :                 return handleVehicleTypeError(hardFail, vType);
     971              :             } else {
     972        22726 :                 vType->color = color;
     973        22726 :                 vType->parametersSet |= VTYPEPARS_COLOR_SET;
     974              :             }
     975              :         } else {
     976        37913 :             vType->color = RGBColor::YELLOW;
     977              :         }
     978        60639 :         if (attrs.hasAttribute(SUMO_ATTR_PROB)) {
     979          611 :             bool ok = true;
     980          611 :             const double defaultProbability = attrs.get<double>(SUMO_ATTR_PROB, vType->id.c_str(), ok);
     981          611 :             if (!ok) {
     982            0 :                 return handleVehicleTypeError(hardFail, vType);
     983          611 :             } else if (defaultProbability < 0) {
     984            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PROB) + " must be equal or greater than 0");
     985              :             } else {
     986          611 :                 vType->defaultProbability = defaultProbability;
     987          611 :                 vType->parametersSet |= VTYPEPARS_PROBABILITY_SET;
     988              :             }
     989              :         }
     990        60639 :         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        60634 :         if (attrs.hasAttribute(SUMO_ATTR_CAR_FOLLOW_MODEL)) {
    1007         1240 :             bool ok = true;
    1008         1240 :             const std::string cfmValue = attrs.get<std::string>(SUMO_ATTR_CAR_FOLLOW_MODEL, vType->id.c_str(), ok);
    1009         1240 :             if (!ok) {
    1010            0 :                 return handleVehicleTypeError(hardFail, vType);
    1011              :             } else if (SUMOXMLDefinitions::CarFollowModels.hasString(cfmValue)) {
    1012         1234 :                 vType->cfModel = SUMOXMLDefinitions::CarFollowModels.get(cfmValue);
    1013         1234 :                 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        60628 :         if (attrs.hasAttribute(SUMO_ATTR_PERSON_CAPACITY)) {
    1019          347 :             bool ok = true;
    1020          347 :             const int personCapacity = attrs.get<int>(SUMO_ATTR_PERSON_CAPACITY, vType->id.c_str(), ok);
    1021          347 :             if (!ok) {
    1022            0 :                 return handleVehicleTypeError(hardFail, vType);
    1023          347 :             } 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          347 :                 vType->personCapacity = personCapacity;
    1027          347 :                 vType->parametersSet |= VTYPEPARS_PERSON_CAPACITY;
    1028              :             }
    1029              :         }
    1030        60628 :         if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_CAPACITY)) {
    1031          346 :             bool ok = true;
    1032          346 :             const int containerCapacity = attrs.get<int>(SUMO_ATTR_CONTAINER_CAPACITY, vType->id.c_str(), ok);
    1033          346 :             if (!ok) {
    1034            0 :                 return handleVehicleTypeError(hardFail, vType);
    1035          346 :             } 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          346 :                 vType->containerCapacity = containerCapacity;
    1039          346 :                 vType->parametersSet |= VTYPEPARS_CONTAINER_CAPACITY;
    1040              :             }
    1041              :         }
    1042        60628 :         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        60628 :         if (attrs.hasAttribute(SUMO_ATTR_LOADING_DURATION)) {
    1055           49 :             bool ok = true;
    1056           49 :             const SUMOTime loadingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_LOADING_DURATION, vType->id.c_str(), ok);
    1057           49 :             if (!ok) {
    1058            0 :                 return handleVehicleTypeError(hardFail, vType);
    1059           49 :             } 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           49 :                 vType->loadingDuration = loadingDuration;
    1063           49 :                 vType->parametersSet |= VTYPEPARS_LOADING_DURATION;
    1064              :             }
    1065              :         }
    1066        60628 :         if (attrs.hasAttribute(SUMO_ATTR_SCALE)) {
    1067           32 :             bool ok = true;
    1068           32 :             const double scale = attrs.get<double>(SUMO_ATTR_SCALE, id.c_str(), ok);
    1069           32 :             if (!ok) {
    1070            0 :                 return handleVehicleTypeError(hardFail, vType);
    1071           32 :             } else if (scale < 0) {
    1072            0 :                 return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SCALE) + " may be not be negative");
    1073              :             } else {
    1074           32 :                 vType->scale = scale;
    1075           32 :                 vType->parametersSet |= VTYPEPARS_SCALE_SET;
    1076              :             }
    1077              :         }
    1078        60628 :         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        60628 :         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        60628 :         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        60628 :         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        60628 :         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        60628 :         if (attrs.hasAttribute(SUMO_ATTR_MINGAP_LAT)) {
    1133          575 :             bool ok = true;
    1134          575 :             const double minGapLat = attrs.get<double>(SUMO_ATTR_MINGAP_LAT, vType->id.c_str(), ok);
    1135          575 :             if (!ok) {
    1136            0 :                 return handleVehicleTypeError(hardFail, vType);
    1137          575 :             } 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          575 :                 vType->minGapLat = minGapLat;
    1141          575 :                 vType->parametersSet |= VTYPEPARS_MINGAP_LAT_SET;
    1142              :             }
    1143              :         }
    1144        60628 :         if (attrs.hasAttribute(SUMO_ATTR_LATALIGNMENT)) {
    1145         1704 :             bool ok = true;
    1146         1704 :             const std::string alignS = attrs.get<std::string>(SUMO_ATTR_LATALIGNMENT, vType->id.c_str(), ok);
    1147         1704 :             if (!ok) {
    1148            0 :                 return handleVehicleTypeError(hardFail, vType);
    1149              :             } else {
    1150              :                 double lao;
    1151              :                 LatAlignmentDefinition lad;
    1152         1704 :                 if (SUMOVTypeParameter::parseLatAlignment(alignS, lao, lad)) {
    1153         1704 :                     vType->latAlignmentOffset = lao;
    1154         1704 :                     vType->latAlignmentProcedure = lad;
    1155         1704 :                     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        60628 :         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        60628 :         if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {
    1173            7 :             bool ok = true;
    1174            7 :             std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, vType->id.c_str(), ok);
    1175            7 :             if (!ok) {
    1176            0 :                 return handleVehicleTypeError(hardFail, vType);
    1177              :             } else {
    1178            7 :                 vType->parametersSet |= VTYPEPARS_PARKING_BADGES_SET;
    1179            7 :                 vType->parkingBadges = badges;
    1180              :             }
    1181            7 :         }
    1182              :         // try to parse Car Following Model params
    1183        60628 :         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        60628 :         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        60628 :         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        60644 : SUMOVehicleParserHelper::parseCFMParams(SUMOVTypeParameter* into, const SumoXMLTag element, const SUMOSAXAttributes& attrs, const bool nestedCFM) {
    1240        60644 :     const CFAttrMap& allowedCFM = getAllowedCFModelAttrs();
    1241              :     CFAttrMap::const_iterator cf_it = allowedCFM.find(element);
    1242              :     // check if given CFM is allowed
    1243        60644 :     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        60644 :     if (nestedCFM) {
    1253           16 :         into->cfModel = cf_it->first;
    1254           16 :         into->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
    1255              :     }
    1256              :     // set CFM values
    1257       615132 :     for (const auto& it : cf_it->second) {
    1258       554488 :         if (attrs.hasAttribute(it)) {
    1259              :             // first obtain  CFM attribute in string format
    1260        44650 :             bool ok = true;
    1261        44650 :             std::string parsedCFMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
    1262              :             // check CFM Attribute
    1263        44650 :             if (!ok) {
    1264              :                 return false;
    1265        44650 :             } else if (it == SUMO_ATTR_TRAIN_TYPE) {
    1266              :                 // check if train value is valid
    1267          223 :                 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          223 :                 into->cfParameter[it] = parsedCFMAttribute;
    1273        44427 :             } else if (it == SUMO_ATTR_SPEED_TABLE || it == SUMO_ATTR_TRACTION_TABLE || it == SUMO_ATTR_RESISTANCE_TABLE) {
    1274           24 :                 into->cfParameter[it] = parsedCFMAttribute;
    1275        44403 :             } 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              :             } else {
    1292              :                 // declare a double in wich save CFM float attribute
    1293              :                 double CFMDoubleAttribute = -1;
    1294              :                 try {
    1295              :                     // obtain CFM attribute in double format
    1296        44397 :                     CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
    1297            0 :                 } catch (...) {
    1298            0 :                     WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
    1299              :                     return false;
    1300            0 :                 }
    1301              :                 // check attributes of type "positiveFloatType" (> 0)
    1302        44397 :                 switch (it) {
    1303        20758 :                     case SUMO_ATTR_ACCEL:
    1304              :                     case SUMO_ATTR_DECEL:
    1305              :                     case SUMO_ATTR_APPARENTDECEL:
    1306              :                     case SUMO_ATTR_EMERGENCYDECEL:
    1307              :                     case SUMO_ATTR_TAU:
    1308        20758 :                         if (CFMDoubleAttribute <= 0) {
    1309            0 :                             WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
    1310            0 :                             return false;
    1311              :                         }
    1312              :                         break;
    1313              :                     default:
    1314              :                         break;
    1315              :                 }
    1316              :                 // check attributes restricted to [0-1]
    1317        44397 :                 switch (it) {
    1318        23035 :                     case SUMO_ATTR_SIGMA:
    1319        23035 :                         if ((CFMDoubleAttribute < 0) || (CFMDoubleAttribute > 1)) {
    1320            0 :                             WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
    1321            0 :                             return false;
    1322              :                         }
    1323              :                         break;
    1324              :                     default:
    1325              :                         break;
    1326              :                 }
    1327              :                 // add parsedCFMAttribute to cfParameter
    1328        44397 :                 into->cfParameter[it] = parsedCFMAttribute;
    1329              :             }
    1330              :         }
    1331              :     }
    1332              :     // all CFM successfully parsed, then return true
    1333              :     return true;
    1334              : }
    1335              : 
    1336              : 
    1337              : const SUMOVehicleParserHelper::CFAttrMap&
    1338        60644 : SUMOVehicleParserHelper::getAllowedCFModelAttrs() {
    1339              :     // init on first use
    1340        60644 :     if (allowedCFModelAttrs.size() == 0) {
    1341              :         std::set<SumoXMLAttr> genericParams;
    1342        24650 :         genericParams.insert(SUMO_ATTR_TAU);
    1343        24650 :         genericParams.insert(SUMO_ATTR_ACCEL);
    1344        24650 :         genericParams.insert(SUMO_ATTR_DECEL);
    1345        24650 :         genericParams.insert(SUMO_ATTR_APPARENTDECEL);
    1346        24650 :         genericParams.insert(SUMO_ATTR_EMERGENCYDECEL);
    1347        24650 :         genericParams.insert(SUMO_ATTR_COLLISION_MINGAP_FACTOR);
    1348        24650 :         genericParams.insert(SUMO_ATTR_STARTUP_DELAY);
    1349              :         // Krauss
    1350              :         std::set<SumoXMLAttr> kraussParams(genericParams);
    1351        24650 :         kraussParams.insert(SUMO_ATTR_SIGMA);
    1352        24650 :         kraussParams.insert(SUMO_ATTR_SIGMA_STEP);
    1353        24650 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS] = kraussParams;
    1354        24650 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_ORIG1] = kraussParams;
    1355        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_PLUS_SLOPE] = kraussParams;
    1356              :         std::set<SumoXMLAttr> allParams(kraussParams);
    1357              :         // KraussX
    1358              :         std::set<SumoXMLAttr> kraussXParams(kraussParams);
    1359        24650 :         kraussXParams.insert(SUMO_ATTR_TMP1);
    1360        24650 :         kraussXParams.insert(SUMO_ATTR_TMP2);
    1361        24650 :         kraussXParams.insert(SUMO_ATTR_TMP3);
    1362        24650 :         kraussXParams.insert(SUMO_ATTR_TMP4);
    1363        24650 :         kraussXParams.insert(SUMO_ATTR_TMP5);
    1364        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_KRAUSSX] = kraussXParams;
    1365        24650 :         allParams.insert(kraussXParams.begin(), kraussXParams.end());
    1366              :         // SmartSK
    1367              :         std::set<SumoXMLAttr> smartSKParams(genericParams);
    1368        24650 :         smartSKParams.insert(SUMO_ATTR_SIGMA);
    1369        24650 :         smartSKParams.insert(SUMO_ATTR_TMP1);
    1370        24650 :         smartSKParams.insert(SUMO_ATTR_TMP2);
    1371        24650 :         smartSKParams.insert(SUMO_ATTR_TMP3);
    1372        24650 :         smartSKParams.insert(SUMO_ATTR_TMP4);
    1373        24650 :         smartSKParams.insert(SUMO_ATTR_TMP5);
    1374        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_SMART_SK] = smartSKParams;
    1375        24650 :         allParams.insert(smartSKParams.begin(), smartSKParams.end());
    1376              :         // Daniel
    1377              :         std::set<SumoXMLAttr> daniel1Params(genericParams);
    1378        24650 :         daniel1Params.insert(SUMO_ATTR_SIGMA);
    1379        24650 :         daniel1Params.insert(SUMO_ATTR_TMP1);
    1380        24650 :         daniel1Params.insert(SUMO_ATTR_TMP2);
    1381        24650 :         daniel1Params.insert(SUMO_ATTR_TMP3);
    1382        24650 :         daniel1Params.insert(SUMO_ATTR_TMP4);
    1383        24650 :         daniel1Params.insert(SUMO_ATTR_TMP5);
    1384        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_DANIEL1] = daniel1Params;
    1385        24650 :         allParams.insert(daniel1Params.begin(), daniel1Params.end());
    1386              :         // Peter Wagner
    1387              :         std::set<SumoXMLAttr> pwagParams(genericParams);
    1388        24650 :         pwagParams.insert(SUMO_ATTR_SIGMA);
    1389        24650 :         pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_TAULAST);
    1390        24650 :         pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_APPROB);
    1391        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_PWAGNER2009] = pwagParams;
    1392        24650 :         allParams.insert(pwagParams.begin(), pwagParams.end());
    1393              :         // IDM params
    1394              :         std::set<SumoXMLAttr> idmParams(genericParams);
    1395        24650 :         idmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
    1396        24650 :         idmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
    1397        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_IDM] = idmParams;
    1398        24650 :         allParams.insert(idmParams.begin(), idmParams.end());
    1399              :         // EIDM
    1400              :         std::set<SumoXMLAttr> eidmParams(genericParams);
    1401        24650 :         eidmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
    1402        24650 :         eidmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
    1403        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD);
    1404        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE);
    1405        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_REACTION);
    1406        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE);
    1407        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_C_COOLNESS);
    1408        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_LEADER);
    1409        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_GAP);
    1410        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_ERROR);
    1411        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_JERK_MAX);
    1412        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_EPSILON_ACC);
    1413        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_T_ACC_MAX);
    1414        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_M_FLATNESS);
    1415        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_M_BEGIN);
    1416        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS);
    1417        24650 :         eidmParams.insert(SUMO_ATTR_CF_EIDM_MAX_VEH_PREVIEW);
    1418        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_EIDM] = eidmParams;
    1419        24650 :         allParams.insert(eidmParams.begin(), eidmParams.end());
    1420              :         // IDMM
    1421              :         std::set<SumoXMLAttr> idmmParams(genericParams);
    1422        24650 :         idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR);
    1423        24650 :         idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_TIME);
    1424        24650 :         idmmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
    1425        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_IDMM] = idmmParams;
    1426        24650 :         allParams.insert(idmmParams.begin(), idmmParams.end());
    1427              :         // Bieker
    1428              :         std::set<SumoXMLAttr> bkernerParams(genericParams);
    1429        24650 :         bkernerParams.insert(SUMO_ATTR_K);
    1430        24650 :         bkernerParams.insert(SUMO_ATTR_CF_KERNER_PHI);
    1431        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_BKERNER] = bkernerParams;
    1432        24650 :         allParams.insert(bkernerParams.begin(), bkernerParams.end());
    1433              :         // Wiedemann
    1434              :         std::set<SumoXMLAttr> wiedemannParams(genericParams);
    1435        24650 :         wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_SECURITY);
    1436        24650 :         wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_ESTIMATION);
    1437        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_WIEDEMANN] = wiedemannParams;
    1438        24650 :         allParams.insert(wiedemannParams.begin(), wiedemannParams.end());
    1439              :         // W99
    1440              :         std::set<SumoXMLAttr> w99Params(genericParams);
    1441        24650 :         w99Params.insert(SUMO_ATTR_CF_W99_CC1);
    1442        24650 :         w99Params.insert(SUMO_ATTR_CF_W99_CC2);
    1443        24650 :         w99Params.insert(SUMO_ATTR_CF_W99_CC3);
    1444        24650 :         w99Params.insert(SUMO_ATTR_CF_W99_CC4);
    1445        24650 :         w99Params.insert(SUMO_ATTR_CF_W99_CC5);
    1446        24650 :         w99Params.insert(SUMO_ATTR_CF_W99_CC6);
    1447        24650 :         w99Params.insert(SUMO_ATTR_CF_W99_CC7);
    1448        24650 :         w99Params.insert(SUMO_ATTR_CF_W99_CC8);
    1449        24650 :         w99Params.insert(SUMO_ATTR_CF_W99_CC9);
    1450        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_W99] = w99Params;
    1451        24650 :         allParams.insert(w99Params.begin(), w99Params.end());
    1452              :         // Rail
    1453              :         std::set<SumoXMLAttr> railParams(genericParams);
    1454        24650 :         railParams.insert(SUMO_ATTR_TRAIN_TYPE);
    1455        24650 :         railParams.insert(SUMO_ATTR_SPEED_TABLE);
    1456        24650 :         railParams.insert(SUMO_ATTR_TRACTION_TABLE);
    1457        24650 :         railParams.insert(SUMO_ATTR_RESISTANCE_TABLE);
    1458        24650 :         railParams.insert(SUMO_ATTR_MASSFACTOR);
    1459        24650 :         railParams.insert(SUMO_ATTR_MAXPOWER);
    1460        24650 :         railParams.insert(SUMO_ATTR_MAXTRACTION);
    1461        24650 :         railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_CONSTANT);
    1462        24650 :         railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_LINEAR);
    1463        24650 :         railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_QUADRATIC);
    1464        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_RAIL] = railParams;
    1465        24650 :         allParams.insert(railParams.begin(), railParams.end());
    1466              :         // ACC
    1467              :         std::set<SumoXMLAttr> ACCParams(genericParams);
    1468        24650 :         ACCParams.insert(SUMO_ATTR_SC_GAIN);
    1469        24650 :         ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
    1470        24650 :         ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
    1471        24650 :         ACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
    1472        24650 :         ACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
    1473        24650 :         ACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
    1474        24650 :         ACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
    1475        24650 :         ACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
    1476        24650 :         ACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
    1477        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_ACC] = ACCParams;
    1478        24650 :         allParams.insert(ACCParams.begin(), ACCParams.end());
    1479              :         // CACC
    1480              :         std::set<SumoXMLAttr> CACCParams(genericParams);
    1481        24650 :         CACCParams.insert(SUMO_ATTR_SC_GAIN_CACC);
    1482        24650 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_CACC);
    1483        24650 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_DOT_CACC);
    1484        24650 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_CACC);
    1485        24650 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_DOT_CACC);
    1486        24650 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_CACC);
    1487        24650 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_DOT_CACC);
    1488        24650 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
    1489        24650 :         CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
    1490        24650 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
    1491        24650 :         CACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
    1492        24650 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
    1493        24650 :         CACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
    1494        24650 :         CACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
    1495        24650 :         CACCParams.insert(SUMO_ATTR_HEADWAY_TIME_CACC_TO_ACC);
    1496        24650 :         CACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
    1497        24650 :         CACCParams.insert(SUMO_ATTR_SC_MIN_GAP);
    1498        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_CACC] = CACCParams;
    1499        24650 :         allParams.insert(CACCParams.begin(), CACCParams.end());
    1500              :         // CC
    1501              :         std::set<SumoXMLAttr> ccParams(genericParams);
    1502        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_C1);
    1503        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_CCDECEL);
    1504        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_CONSTSPACING);
    1505        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_KP);
    1506        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_LAMBDA);
    1507        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_OMEGAN);
    1508        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_TAU);
    1509        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_XI);
    1510        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_LANES_COUNT);
    1511        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_CCACCEL);
    1512        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KP);
    1513        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KD);
    1514        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_H);
    1515        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KA);
    1516        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KV);
    1517        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KP);
    1518        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_D);
    1519        24650 :         ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_H);
    1520        49300 :         allowedCFModelAttrs[SUMO_TAG_CF_CC] = ccParams;
    1521        24650 :         allParams.insert(ccParams.begin(), ccParams.end());
    1522              :         // last element
    1523        49300 :         allowedCFModelAttrs[SUMO_TAG_NOTHING] = allParams;
    1524              :     }
    1525        60644 :     return allowedCFModelAttrs;
    1526              : }
    1527              : 
    1528              : 
    1529              : bool
    1530        60628 : SUMOVehicleParserHelper::parseLCParams(SUMOVTypeParameter* into, LaneChangeModel model, const SUMOSAXAttributes& attrs) {
    1531        60628 :     if (allowedLCModelAttrs.size() == 0) {
    1532              :         // lc2013
    1533              :         std::set<SumoXMLAttr> lc2013Params;
    1534        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_PARAM);
    1535        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_PARAM);
    1536        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_PARAM);
    1537        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_PARAM);
    1538        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_OPPOSITE_PARAM);
    1539        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_LOOKAHEADLEFT);
    1540        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAINRIGHT);
    1541        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING);
    1542        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR);
    1543        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_MAXDISTLATSTANDING);
    1544        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_ASSERTIVE);
    1545        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD);
    1546        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD);
    1547        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME);
    1548        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT);
    1549        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_SPEED);
    1550        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_RIGHT);
    1551        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_SIGMA);
    1552        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME);
    1553        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR);
    1554        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_CONTRIGHT);
    1555        24650 :         lc2013Params.insert(SUMO_ATTR_LCA_EXPERIMENTAL1);
    1556        49300 :         allowedLCModelAttrs[LaneChangeModel::LC2013] = lc2013Params;
    1557              :         // sl2015 (extension of lc2013)
    1558              :         std::set<SumoXMLAttr> sl2015Params = lc2013Params;
    1559        24650 :         sl2015Params.insert(SUMO_ATTR_LCA_PUSHY);
    1560        24650 :         sl2015Params.insert(SUMO_ATTR_LCA_PUSHYGAP);
    1561        24650 :         sl2015Params.insert(SUMO_ATTR_LCA_SUBLANE_PARAM);
    1562        24650 :         sl2015Params.insert(SUMO_ATTR_LCA_IMPATIENCE);
    1563        24650 :         sl2015Params.insert(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE);
    1564        24650 :         sl2015Params.insert(SUMO_ATTR_LCA_ACCEL_LAT);
    1565        24650 :         sl2015Params.insert(SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE);
    1566        24650 :         sl2015Params.insert(SUMO_ATTR_LCA_LANE_DISCIPLINE);
    1567        49300 :         allowedLCModelAttrs[LaneChangeModel::SL2015] = sl2015Params;
    1568              :         // DK2008
    1569              :         std::set<SumoXMLAttr> noParams;
    1570        24650 :         allowedLCModelAttrs[LaneChangeModel::DK2008] = noParams;
    1571              :         // default model may be either LC2013 or SL2015
    1572              :         // we allow both sets (sl2015 is a superset of lc2013Params)
    1573        49300 :         allowedLCModelAttrs[LaneChangeModel::DEFAULT] = sl2015Params;
    1574              :     }
    1575        60628 :     std::set<SumoXMLAttr> allowed = allowedLCModelAttrs[model];
    1576              :     // iterate over LCM attributes
    1577      1878678 :     for (const auto& it : allowed) {
    1578      1818050 :         if (attrs.hasAttribute(it)) {
    1579              :             // first obtain  CFM attribute in string format
    1580         4002 :             bool ok = true;
    1581         4002 :             std::string parsedLCMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
    1582         4002 :             if (!ok) {
    1583              :                 return false;
    1584              :             }
    1585              :             // declare a double in wich save CFM attribute
    1586              :             double LCMAttribute = -1;
    1587              :             try {
    1588              :                 // obtain CFM attribute in double format
    1589         4002 :                 LCMAttribute = StringUtils::toDouble(parsedLCMAttribute);
    1590            0 :             } catch (...) {
    1591            0 :                 WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Cannot be parsed to float"), toString(it));
    1592              :                 return false;
    1593            0 :             }
    1594              :             // check attributes of type "nonNegativeFloatType" (>= 0)
    1595         4002 :             switch (it) {
    1596         1437 :                 case SUMO_ATTR_LCA_PUSHYGAP:
    1597              :                 case SUMO_ATTR_LCA_MAXSPEEDLATSTANDING:
    1598              :                 case SUMO_ATTR_LCA_IMPATIENCE:
    1599              :                 case SUMO_ATTR_LCA_OVERTAKE_RIGHT:
    1600              :                 case SUMO_ATTR_LCA_ASSERTIVE:
    1601              :                 case SUMO_ATTR_LCA_LOOKAHEADLEFT:
    1602              :                 case SUMO_ATTR_LCA_SPEEDGAINRIGHT:
    1603              :                 case SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE:
    1604              :                 case SUMO_ATTR_LCA_TIME_TO_IMPATIENCE:
    1605              :                 case SUMO_ATTR_LCA_LANE_DISCIPLINE:
    1606              :                 case SUMO_ATTR_LCA_SIGMA:
    1607         1437 :                     if (LCMAttribute < 0) {
    1608            0 :                         WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be equal or greater than 0"), toString(it));
    1609            0 :                         return false;
    1610              :                     }
    1611              :                     break;
    1612              :                 default:
    1613              :                     break;
    1614              :             }
    1615              :             // check attributes of type "positiveFloatType" (> 0)
    1616         4002 :             switch (it) {
    1617           10 :                 case SUMO_ATTR_LCA_ACCEL_LAT:
    1618           10 :                     if (LCMAttribute <= 0) {
    1619            0 :                         WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be greater than 0"), toString(it));
    1620            0 :                         return false;
    1621              :                     }
    1622              :                     break;
    1623              :                 default:
    1624              :                     break;
    1625              :             }
    1626              :             // check limits of attributes
    1627         4002 :             switch (it) {
    1628           90 :                 case SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR:
    1629           90 :                     if (LCMAttribute < -1 || LCMAttribute > 1) {
    1630            0 :                         WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be between -1 and 1"), toString(it));
    1631            0 :                         return false;
    1632              :                     }
    1633              :                     break;
    1634              :                 default:
    1635              :                     break;
    1636              :             }
    1637              :             // add parsedLCMAttribute to cfParameter
    1638         4002 :             into->lcParameter[it] = parsedLCMAttribute;
    1639              :         }
    1640              :     }
    1641              :     // all LCM parsed ok, then return true
    1642              :     return true;
    1643              : }
    1644              : 
    1645              : 
    1646              : bool
    1647        60628 : SUMOVehicleParserHelper::parseJMParams(SUMOVTypeParameter* into, const SUMOSAXAttributes& attrs) {
    1648      1030676 :     for (const auto& it : SUMOVTypeParameter::AllowedJMAttrs) {
    1649       970048 :         if (attrs.hasAttribute(it)) {
    1650              :             // first obtain  CFM attribute in string format
    1651         1024 :             bool ok = true;
    1652         1024 :             std::string parsedJMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
    1653         1024 :             if (!ok) {
    1654              :                 return false;
    1655              :             }
    1656              :             // declare a double in wich save CFM attribute
    1657              :             double JMAttribute = -1;
    1658              :             try {
    1659              :                 // obtain CFM attribute in double format
    1660         1024 :                 JMAttribute = StringUtils::toDouble(parsedJMAttribute);
    1661            0 :             } catch (...) {
    1662            0 :                 WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Cannot be parsed to float"), toString(it));
    1663              :                 return false;
    1664            0 :             }
    1665              :             // now continue checking other properties (-1 is the default value)
    1666         1024 :             if (JMAttribute != -1) {
    1667              :                 // special case for sigma minor
    1668         1006 :                 if (it == SUMO_ATTR_JM_SIGMA_MINOR) {
    1669              :                     // check attributes sigma minor
    1670          126 :                     if ((JMAttribute < 0) || (JMAttribute > 1)) {
    1671            0 :                         WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
    1672            0 :                         return false;
    1673              :                     }
    1674              :                 } else {
    1675              :                     // check attributes of type "nonNegativeFloatType" (>= 0)
    1676          880 :                     if (JMAttribute < 0) {
    1677            0 :                         WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Must be equal or greater than 0"), toString(it));
    1678            0 :                         return false;
    1679              :                     }
    1680              :                 }
    1681              :                 // add parsedJMAttribute to cfParameter
    1682         1006 :                 into->jmParameter[it] = parsedJMAttribute;
    1683              :             }
    1684              :         }
    1685              :     }
    1686              :     // all JM parameters successfully parsed, then return true
    1687              :     return true;
    1688              : }
    1689              : 
    1690              : 
    1691              : SUMOVehicleClass
    1692        35626 : SUMOVehicleParserHelper::parseVehicleClass(const SUMOSAXAttributes& attrs, const std::string& id) {
    1693              :     SUMOVehicleClass vclass = SVC_IGNORING;
    1694        35626 :     bool ok = true;
    1695        35626 :     std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_VCLASS, id.c_str(), ok, "");
    1696        35626 :     if (vclassS == "") {
    1697              :         return vclass;
    1698              :     }
    1699              :     try {
    1700        35602 :         const SUMOVehicleClass result = getVehicleClassID(vclassS);
    1701        35594 :         const std::string& realName = SumoVehicleClassStrings.getString(result);
    1702        35594 :         if (realName != vclassS) {
    1703           12 :             WRITE_WARNING("The vehicle class '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
    1704              :         }
    1705              :         return result;
    1706            8 :     } catch (...) {
    1707           24 :         WRITE_ERRORF(TL("The vehicle class '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
    1708            8 :     }
    1709              :     return vclass;
    1710              : }
    1711              : 
    1712              : 
    1713              : SUMOVehicleShape
    1714        27140 : SUMOVehicleParserHelper::parseGuiShape(const SUMOSAXAttributes& attrs, const std::string& id) {
    1715        27140 :     bool ok = true;
    1716        54280 :     std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_GUISHAPE, id.c_str(), ok, "");
    1717              :     if (SumoVehicleShapeStrings.hasString(vclassS)) {
    1718        27140 :         const SUMOVehicleShape result = SumoVehicleShapeStrings.get(vclassS);
    1719        27140 :         const std::string& realName = SumoVehicleShapeStrings.getString(result);
    1720        27140 :         if (realName != vclassS) {
    1721            0 :             WRITE_WARNING("The shape '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
    1722              :         }
    1723        27140 :         return result;
    1724              :     } else {
    1725            0 :         WRITE_ERRORF(TL("The shape '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
    1726            0 :         return SUMOVehicleShape::UNKNOWN;
    1727              :     }
    1728              : }
    1729              : 
    1730              : 
    1731              : double
    1732        31764 : SUMOVehicleParserHelper::parseWalkPos(SumoXMLAttr attr, const bool hardFail, const std::string& id, double maxPos, const std::string& val, SumoRNG* rng) {
    1733              :     double result;
    1734              :     std::string error;
    1735        31764 :     ArrivalPosDefinition proc = ArrivalPosDefinition::DEFAULT;
    1736              :     // only supports 'random' and 'max'
    1737        63528 :     if (!SUMOVehicleParameter::parseArrivalPos(val, toString(SUMO_TAG_WALK), id, result, proc, error)) {
    1738            0 :         handleVehicleError(hardFail, nullptr, error);
    1739              :     }
    1740        31764 :     if (proc == ArrivalPosDefinition::RANDOM) {
    1741          888 :         result = RandHelper::rand(maxPos, rng);
    1742        30876 :     } else if (proc == ArrivalPosDefinition::CENTER) {
    1743            0 :         result = maxPos / 2.;
    1744        30876 :     } else if (proc == ArrivalPosDefinition::MAX) {
    1745            0 :         result = maxPos;
    1746              :     }
    1747        63528 :     return SUMOVehicleParameter::interpretEdgePos(result, maxPos, attr, id);
    1748              : }
    1749              : 
    1750              : 
    1751              : SUMOTime
    1752       300134 : SUMOVehicleParserHelper::processActionStepLength(double given) {
    1753       300134 :     const std::string defaultError = "The parameter action-step-length must be a non-negative multiple of the simulation step-length. ";
    1754       300134 :     SUMOTime result = TIME2STEPS(given);
    1755       300134 :     if (result <= 0) {
    1756        42757 :         if (result < 0) {
    1757           36 :             WRITE_WARNING(defaultError + "Ignoring given value (=" + toString(STEPS2TIME(result)) + " s.)");
    1758              :         }
    1759        42757 :         result = DELTA_T;
    1760       257377 :     } else if (result % DELTA_T != 0) {
    1761           25 :         result = (SUMOTime)((double)DELTA_T * floor(double(result) / double(DELTA_T)));
    1762              :         result = MAX2(DELTA_T, result);
    1763           25 :         if (fabs(given * 1000. - double(result)) > NUMERICAL_EPS) {
    1764          100 :             WRITE_WARNING(defaultError + "Parsing given value (" + toString(given) + " s.) to the adjusted value " + toString(STEPS2TIME(result)) + " s.");
    1765              :         }
    1766              :     }
    1767       300134 :     return result;
    1768              : }
    1769              : 
    1770              : 
    1771              : bool
    1772       185459 : SUMOVehicleParserHelper::isInternalRouteID(const std::string& id) {
    1773       185459 :     return id.substr(0, 1) == "!";
    1774              : }
    1775              : 
    1776              : 
    1777              : int
    1778        17444 : SUMOVehicleParserHelper::parseCarWalkTransfer(const OptionsCont& oc, const bool hasTaxi) {
    1779              :     int carWalk = 0;
    1780        52332 :     for (const std::string& opt : oc.getStringVector("persontrip.transfer.car-walk")) {
    1781        17444 :         if (opt == "parkingAreas") {
    1782        17244 :             carWalk |= ModeChangeOptions::PARKING_AREAS;
    1783          200 :         } else if (opt == "ptStops") {
    1784          150 :             carWalk |= ModeChangeOptions::PT_STOPS;
    1785           50 :         } else if (opt == "allJunctions") {
    1786           50 :             carWalk |= ModeChangeOptions::ALL_JUNCTIONS;
    1787              :         } else {
    1788            0 :             WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
    1789              :         }
    1790              :     }
    1791        17444 :     const StringVector taxiDropoff = oc.getStringVector("persontrip.transfer.taxi-walk");
    1792        34888 :     const StringVector taxiPickup = oc.getStringVector("persontrip.transfer.walk-taxi");
    1793        17444 :     if (taxiDropoff.empty() && hasTaxi) {
    1794           87 :         carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
    1795              :     } else {
    1796        17465 :         for (const std::string& opt : taxiDropoff) {
    1797          108 :             if (opt == "parkingAreas") {
    1798            0 :                 carWalk |= ModeChangeOptions::TAXI_DROPOFF_PARKING_AREAS;
    1799          108 :             } else if (opt == "ptStops") {
    1800           76 :                 carWalk |= ModeChangeOptions::TAXI_DROPOFF_PT;
    1801           32 :             } else if (opt == "allJunctions") {
    1802           32 :                 carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
    1803              :             } else {
    1804            0 :                 WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
    1805              :             }
    1806              :         }
    1807              :     }
    1808        17444 :     if (taxiPickup.empty() && hasTaxi) {
    1809           81 :         carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
    1810              :     } else {
    1811        17483 :         for (const std::string& opt : taxiPickup) {
    1812          120 :             if (opt == "parkingAreas") {
    1813            0 :                 carWalk |= ModeChangeOptions::TAXI_PICKUP_PARKING_AREAS;
    1814          120 :             } else if (opt == "ptStops") {
    1815           88 :                 carWalk |= ModeChangeOptions::TAXI_PICKUP_PT;
    1816           32 :             } else if (opt == "allJunctions") {
    1817           32 :                 carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
    1818              :             } else {
    1819            0 :                 WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
    1820              :             }
    1821              :         }
    1822              :     }
    1823        17444 :     return carWalk;
    1824        17444 : }
    1825              : 
    1826              : 
    1827              : SUMOVehicleParameter*
    1828          432 : SUMOVehicleParserHelper::handleVehicleError(const bool hardFail, SUMOVehicleParameter* vehicleParameter, const std::string message) {
    1829          432 :     if (vehicleParameter) {
    1830          388 :         delete vehicleParameter;
    1831              :     }
    1832          432 :     if (hardFail) {
    1833          864 :         throw ProcessError(message);
    1834            0 :     } else if (message.size() > 0) {
    1835            0 :         WRITE_ERROR(message);
    1836              :     }
    1837            0 :     return nullptr;
    1838              : }
    1839              : 
    1840              : 
    1841              : SUMOVTypeParameter*
    1842           30 : SUMOVehicleParserHelper::handleVehicleTypeError(const bool hardFail, SUMOVTypeParameter* vehicleTypeParameter, const std::string message) {
    1843           30 :     if (vehicleTypeParameter) {
    1844           26 :         delete vehicleTypeParameter;
    1845              :     }
    1846           30 :     if (hardFail) {
    1847           60 :         throw ProcessError(message);
    1848            0 :     } else if (message.size() > 0) {
    1849            0 :         WRITE_ERROR(message);
    1850              :     }
    1851            0 :     return nullptr;
    1852              : }
    1853              : 
    1854              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1