Path: blob/main/src/utils/vehicle/SUMOVehicleParserHelper.cpp
169678 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2008-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file SUMOVehicleParserHelper.cpp14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Axel Wegener17/// @author Michael Behrisch18/// @author Laura Bieker19/// @author Mirko Barthauer20/// @date Mon, 07.04.200821///22// Helper methods for parsing vehicle attributes23/****************************************************************************/24#include <config.h>2526#include <utils/common/FileHelpers.h>27#include <utils/common/MsgHandler.h>28#include <utils/common/RandHelper.h>29#include <utils/common/StringTokenizer.h>30#include <utils/common/StringUtils.h>31#include <utils/common/ToString.h>32#include <utils/common/UtilExceptions.h>33#include <utils/options/OptionsCont.h>34#include <utils/emissions/PollutantsInterface.h>35#include <utils/router/IntermodalNetwork.h>36#include <utils/vehicle/SUMOVTypeParameter.h>37#include <utils/vehicle/SUMOVehicleParameter.h>38#include <utils/xml/SUMOSAXAttributes.h>3940#include "SUMOVehicleParserHelper.h"414243// ===========================================================================44// static members45// ===========================================================================4647SUMOVehicleParserHelper::CFAttrMap SUMOVehicleParserHelper::allowedCFModelAttrs;48SUMOVehicleParserHelper::LCAttrMap SUMOVehicleParserHelper::allowedLCModelAttrs;495051// ===========================================================================52// method definitions53// ===========================================================================5455SUMOVehicleParameter*56SUMOVehicleParserHelper::parseFlowAttributes(SumoXMLTag tag, const SUMOSAXAttributes& attrs, const bool hardFail, const bool needID,57const SUMOTime beginDefault, const SUMOTime endDefault, const bool allowInternalRoutes) {58// first parse ID59const std::string id = attrs.hasAttribute(SUMO_ATTR_ID) ? parseID(attrs, tag) : "";60// check if ID is valid61if (!needID || !id.empty()) {62if (needID && !SUMOXMLDefinitions::isValidVehicleID(id)) {63return handleVehicleError(hardFail, nullptr, "Invalid flow id '" + id + "'.");64}65// declare flags66const bool hasPeriod = attrs.hasAttribute(SUMO_ATTR_PERIOD);67const bool hasVPH = attrs.hasAttribute(SUMO_ATTR_VEHSPERHOUR);68const bool hasPPH = attrs.hasAttribute(SUMO_ATTR_PERSONSPERHOUR);69const bool hasCPH = attrs.hasAttribute(SUMO_ATTR_CONTAINERSPERHOUR);70const bool hasPH = attrs.hasAttribute(SUMO_ATTR_PERHOUR);71const bool hasXPH = hasVPH || hasPPH || hasCPH || hasPH;72const bool hasProb = attrs.hasAttribute(SUMO_ATTR_PROB);73const bool hasNumber = attrs.hasAttribute(SUMO_ATTR_NUMBER);74const bool hasBegin = attrs.hasAttribute(SUMO_ATTR_BEGIN);75const bool hasEnd = attrs.hasAttribute(SUMO_ATTR_END);76SumoXMLAttr PERHOUR = SUMO_ATTR_PERHOUR;77if (hasVPH) {78PERHOUR = SUMO_ATTR_VEHSPERHOUR;79}80if (hasPPH) {81PERHOUR = SUMO_ATTR_PERSONSPERHOUR;82}83if (hasCPH) {84PERHOUR = SUMO_ATTR_CONTAINERSPERHOUR;85}86if (hasXPH && !(hasVPH ^ hasPPH ^ hasCPH ^ hasPH)) {87return handleVehicleError(hardFail, nullptr,88"At most one of '" + attrs.getName(SUMO_ATTR_PERHOUR) +89"', '" + attrs.getName(SUMO_ATTR_VEHSPERHOUR) +90"', '" + attrs.getName(SUMO_ATTR_PERSONSPERHOUR) +91"' and '" + attrs.getName(SUMO_ATTR_CONTAINERSPERHOUR) +92"' has to be given in the definition of " + toString(tag) + " '" + id + "'.");93}94if (hasPeriod && hasXPH) {95return handleVehicleError(hardFail, nullptr,96"At most one of '" + attrs.getName(SUMO_ATTR_PERIOD) +97"' and '" + attrs.getName(PERHOUR) +98"' has to be given in the definition of "99+ toString(tag) + " '" + id + "'.");100}101if (hasPeriod && hasProb) {102return handleVehicleError(hardFail, nullptr,103"At most one of '" + attrs.getName(SUMO_ATTR_PERIOD) +104"' and '" + attrs.getName(SUMO_ATTR_PROB) +105"' has to be given in the definition of "106+ toString(tag) + " '" + id + "'.");107}108if (hasProb && hasXPH) {109return handleVehicleError(hardFail, nullptr,110"At most one of '" + attrs.getName(SUMO_ATTR_PROB) +111"' and '" + attrs.getName(PERHOUR) +112"' has to be given in the definition of "113+ toString(tag) + " '" + id + "'.");114}115if (hasPeriod || hasXPH || hasProb) {116if (hasEnd && hasNumber) {117return handleVehicleError(hardFail, nullptr,118"If '" + attrs.getName(SUMO_ATTR_PERIOD) +119"', '" + attrs.getName(SUMO_ATTR_VEHSPERHOUR) +120"', '" + attrs.getName(SUMO_ATTR_PERSONSPERHOUR) +121"', '" + attrs.getName(SUMO_ATTR_CONTAINERSPERHOUR) +122"', '" + attrs.getName(SUMO_ATTR_PERHOUR) +123"' or '" + attrs.getName(SUMO_ATTR_PROB) +124"' are given at most one of '" + attrs.getName(SUMO_ATTR_END) +125"' and '" + attrs.getName(SUMO_ATTR_NUMBER) +126"' are allowed in "127+ toString(tag) + " '" + id + "'.");128}129} else {130if (!hasNumber) {131return handleVehicleError(hardFail, nullptr,132"At least one of '" + attrs.getName(SUMO_ATTR_PERIOD) +133"', '" + attrs.getName(SUMO_ATTR_VEHSPERHOUR) +134"', '" + attrs.getName(SUMO_ATTR_PERSONSPERHOUR) +135"', '" + attrs.getName(SUMO_ATTR_CONTAINERSPERHOUR) +136"', '" + attrs.getName(SUMO_ATTR_PERHOUR) +137"', '" + attrs.getName(SUMO_ATTR_PROB) +138"', and '" + attrs.getName(SUMO_ATTR_NUMBER) +139"' is needed in "140+ toString(tag) + " '" + id + "'.");141}142}143// declare flow144SUMOVehicleParameter* flowParameter = new SUMOVehicleParameter();145// set tag146flowParameter->tag = tag;147// set id148flowParameter->id = id;149if (tag == SUMO_TAG_PERSONFLOW) {150flowParameter->vtypeid = DEFAULT_PEDTYPE_ID;151}152if (tag == SUMO_TAG_CONTAINERFLOW) {153flowParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;154}155// parse common vehicle attributes156try {157parseCommonAttributes(attrs, flowParameter, tag, allowInternalRoutes);158} catch (ProcessError& attributeError) {159// check if continue handling another vehicles or stop handling160if (hardFail) {161throw ProcessError(attributeError.what());162} else {163return nullptr;164}165}166// parse period167bool poissonFlow = false;168if (hasPeriod) {169bool ok = true;170const std::string description = attrs.get<std::string>(SUMO_ATTR_PERIOD, id.c_str(), ok);171const std::string distName = description.substr(0, description.find('('));172if (distName == "exp") {173// declare rate174double rate = -1;175// parse rate176try {177rate = StringUtils::toDouble(description.substr(distName.size() + 1, description.size() - distName.size() - 2));178} catch (ProcessError& attributeError) {179// check if continue handling another vehicles or stop handling180if (hardFail) {181throw ProcessError(attributeError.what());182} else {183return nullptr;184}185}186if (rate <= 0) {187return handleVehicleError(hardFail, flowParameter, "Invalid rate parameter for exponentially distributed period in the definition of " + toString(tag) + " '" + id + "'.");188}189flowParameter->poissonRate = rate;190poissonFlow = true;191} else {192flowParameter->repetitionOffset = attrs.getSUMOTimeReporting(SUMO_ATTR_PERIOD, id.c_str(), ok);193}194if (!ok) {195return handleVehicleError(hardFail, flowParameter);196} else {197flowParameter->parametersSet |= VEHPARS_PERIOD_SET;198}199}200// parse vehicle/person/container/etc per hour201if (hasXPH) {202bool ok = true;203const double vph = attrs.get<double>(PERHOUR, id.c_str(), ok);204if (!ok) {205return handleVehicleError(hardFail, flowParameter);206} else if (vph <= 0) {207return handleVehicleError(hardFail, flowParameter, "Invalid repetition rate in the definition of " + toString(tag) + " '" + id + "'.");208} else {209if (vph != 0) {210flowParameter->repetitionOffset = TIME2STEPS(3600. / vph);211}212flowParameter->parametersSet |= VEHPARS_VPH_SET;213}214}215// parse probability216if (hasProb) {217bool ok = true;218flowParameter->repetitionProbability = attrs.get<double>(SUMO_ATTR_PROB, id.c_str(), ok);219if (!ok) {220return handleVehicleError(hardFail, flowParameter);221} else if (flowParameter->repetitionProbability <= 0 || flowParameter->repetitionProbability > 1) {222return handleVehicleError(hardFail, flowParameter, "Invalid repetition probability in the definition of " + toString(tag) + " '" + id + "'.");223} else {224flowParameter->parametersSet |= VEHPARS_PROB_SET;225}226}227// set default begin228flowParameter->depart = beginDefault;229// parse begin230if (hasBegin) {231// first get begin232bool ok = true;233const std::string begin = attrs.get<std::string>(SUMO_ATTR_BEGIN, id.c_str(), ok);234if (!ok) {235return handleVehicleError(hardFail, flowParameter);236} else {237// parse begin238std::string errorMsg;239if (!SUMOVehicleParameter::parseDepart(begin, toString(tag), id, flowParameter->depart, flowParameter->departProcedure, errorMsg, "begin")) {240return handleVehicleError(hardFail, flowParameter, errorMsg);241}242}243}244if (flowParameter->depart < 0) {245return handleVehicleError(hardFail, flowParameter, "Negative begin time in the definition of " + toString(tag) + " '" + id + "'.");246}247// set default end248flowParameter->repetitionEnd = endDefault;249if (flowParameter->repetitionEnd < 0) {250flowParameter->repetitionEnd = SUMOTime_MAX;251}252// parse end253if (hasEnd) {254bool ok = true;255flowParameter->repetitionEnd = attrs.getSUMOTimeReporting(SUMO_ATTR_END, id.c_str(), ok);256if (!ok) {257return handleVehicleError(hardFail, flowParameter);258} else {259flowParameter->parametersSet |= VEHPARS_END_SET;260}261} else if (flowParameter->departProcedure == DepartDefinition::TRIGGERED) {262if (!hasNumber) {263return handleVehicleError(hardFail, flowParameter, toString(tag) + " '" + id + "' with triggered begin must define 'number'.");264} else {265flowParameter->repetitionEnd = flowParameter->depart;266}267} else if ((endDefault == SUMOTime_MAX || endDefault < 0) && (!hasNumber || (!hasProb && !hasPeriod && !hasXPH))) {268WRITE_WARNINGF(TL("Undefined end for % '%', defaulting to 24hour duration."), toString(tag), id);269flowParameter->repetitionEnd = flowParameter->depart + TIME2STEPS(24 * 3600);270}271if (flowParameter->repetitionEnd < flowParameter->depart) {272std::string flow = toString(tag);273flow[0] = (char)::toupper((char)flow[0]);274return handleVehicleError(hardFail, flowParameter, flow + " '" + id + "' ends before its begin time.");275}276// parse number277if (hasNumber) {278bool ok = true;279flowParameter->repetitionNumber = attrs.get<int>(SUMO_ATTR_NUMBER, id.c_str(), ok);280if (!ok) {281return handleVehicleError(hardFail, flowParameter);282} else {283flowParameter->parametersSet |= VEHPARS_NUMBER_SET;284if (flowParameter->repetitionNumber == 0) {285std::string flow = toString(tag);286flow[0] = (char)::toupper((char)flow[0]);287WRITE_WARNING(flow + " '" + id + "' has no instances; will skip it.");288flowParameter->repetitionEnd = flowParameter->depart;289} else {290if (flowParameter->repetitionNumber < 0) {291return handleVehicleError(hardFail, flowParameter, "Negative repetition number in the definition of " + toString(tag) + " '" + id + "'.");292}293if (flowParameter->repetitionOffset < 0 && !hasProb) {294if (poissonFlow) {295flowParameter->repetitionEnd = SUMOTime_MAX;296} else {297flowParameter->repetitionOffset = (flowParameter->repetitionEnd - flowParameter->depart) / flowParameter->repetitionNumber;298}299}300}301}302} else {303// interpret repetitionNumber304if (flowParameter->repetitionProbability > 0) {305flowParameter->repetitionNumber = std::numeric_limits<int>::max();306} else {307if (flowParameter->repetitionOffset <= 0) {308if (poissonFlow) {309// number is random but flow has a fixed end time310flowParameter->repetitionNumber = std::numeric_limits<int>::max();311} else {312return handleVehicleError(hardFail, flowParameter, "Invalid repetition rate in the definition of " + toString(tag) + " '" + id + "'.");313}314} else {315if (flowParameter->repetitionEnd == SUMOTime_MAX) {316flowParameter->repetitionNumber = std::numeric_limits<int>::max();317} else {318const SUMOTime repLength = flowParameter->repetitionEnd - flowParameter->depart;319flowParameter->repetitionNumber = (int)ceil((double)repLength / (double)flowParameter->repetitionOffset);320}321}322}323}324// all ok, then return flow parameter325return flowParameter;326} else {327return handleVehicleError(hardFail, nullptr, toString(tag) + " cannot be created");328}329}330331332SUMOVehicleParameter*333SUMOVehicleParserHelper::parseVehicleAttributes(int element, const SUMOSAXAttributes& attrs, const bool hardFail, const bool optionalID, const bool skipDepart, const bool allowInternalRoutes) {334// declare vehicle ID335std::string id;336// for certain vehicles, ID can be optional337if (optionalID) {338bool ok = true;339id = attrs.getOpt<std::string>(SUMO_ATTR_ID, nullptr, ok, "");340if (!ok) {341return handleVehicleError(hardFail, nullptr);342}343} else {344// parse ID345id = parseID(attrs, (SumoXMLTag)element);346}347// only continue if id is valid, or if is optional348if (optionalID || !id.empty()) {349// declare vehicle parameter350SUMOVehicleParameter* vehicleParameter = new SUMOVehicleParameter();351vehicleParameter->id = id;352if (element == SUMO_TAG_PERSON) {353vehicleParameter->vtypeid = DEFAULT_PEDTYPE_ID;354} else if (element == SUMO_TAG_CONTAINER) {355vehicleParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;356}357// parse common attributes358try {359parseCommonAttributes(attrs, vehicleParameter, (SumoXMLTag)element, allowInternalRoutes);360} catch (ProcessError& attributeError) {361// check if continue handling another vehicles or stop handling362if (hardFail) {363throw ProcessError(attributeError.what());364} else {365return nullptr;366}367}368// check depart369if (!skipDepart) {370bool ok = true;371const std::string helper = attrs.get<std::string>(SUMO_ATTR_DEPART, vehicleParameter->id.c_str(), ok);372if (!ok) {373return handleVehicleError(hardFail, vehicleParameter);374}375// now parse depart376std::string departErrorMsg;377if (!SUMOVehicleParameter::parseDepart(helper, "vehicle", vehicleParameter->id, vehicleParameter->depart, vehicleParameter->departProcedure, departErrorMsg)) {378return handleVehicleError(hardFail, vehicleParameter, departErrorMsg);379}380}381// set tag382vehicleParameter->tag = (SumoXMLTag)element;383// all ok, then return vehicleParameter384return vehicleParameter;385} else {386return handleVehicleError(hardFail, nullptr, toString((SumoXMLTag)element) + " cannot be created");387}388}389390391std::string392SUMOVehicleParserHelper::parseID(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {393bool ok = true;394std::string id;395// first check if attrs contain an ID396if (attrs.hasAttribute(SUMO_ATTR_ID)) {397id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);398if (SUMOXMLDefinitions::isValidVehicleID(id)) {399return id;400} else if (id.empty()) {401// add extra information for empty IDs402WRITE_ERRORF(TL("Invalid % id '%'."), toString(element), id);403} else {404WRITE_ERRORF(TL("Invalid % id '%'. Contains invalid characters."), toString(element), id);405}406} else {407WRITE_ERROR("Attribute '" + toString(SUMO_ATTR_ID) + "' is missing in definition of " + toString(element));408}409// return empty (invalid) ID410return "";411}412413414void415SUMOVehicleParserHelper::parseCommonAttributes(const SUMOSAXAttributes& attrs, SUMOVehicleParameter* ret, SumoXMLTag tag, const bool allowInternalRoutes) {416const std::string element = toString(tag);417//ret->refid = attrs.getStringSecure(SUMO_ATTR_REFID, "");418// parse route information419if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {420bool ok = true;421std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, ret->id.c_str(), ok);422if (!allowInternalRoutes && isInternalRouteID(routeID)) {423WRITE_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);424}425ret->routeid = routeID;426if (ok) {427ret->parametersSet |= VEHPARS_ROUTE_SET; // !!! needed?428} else {429handleVehicleError(true, ret);430}431}432// parse type information433if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {434bool ok = true;435ret->vtypeid = attrs.get<std::string>(SUMO_ATTR_TYPE, ret->id.c_str(), ok);436if (ok) {437ret->parametersSet |= VEHPARS_VTYPE_SET; // !!! needed?438} else {439handleVehicleError(true, ret);440}441}442// parse line information443if (attrs.hasAttribute(SUMO_ATTR_LINE)) {444bool ok = true;445ret->line = attrs.get<std::string>(SUMO_ATTR_LINE, ret->id.c_str(), ok);446if (ok) {447ret->parametersSet |= VEHPARS_LINE_SET; // !!! needed?448} else {449handleVehicleError(true, ret);450}451}452// parse zone information453if (attrs.hasAttribute(SUMO_ATTR_FROM_TAZ)) {454bool ok = true;455ret->fromTaz = attrs.get<std::string>(SUMO_ATTR_FROM_TAZ, ret->id.c_str(), ok);456if (ok) {457ret->parametersSet |= VEHPARS_FROM_TAZ_SET;458} else {459handleVehicleError(true, ret);460}461}462if (attrs.hasAttribute(SUMO_ATTR_TO_TAZ)) {463bool ok = true;464ret->toTaz = attrs.get<std::string>(SUMO_ATTR_TO_TAZ, ret->id.c_str(), ok);465if (ok) {466ret->parametersSet |= VEHPARS_TO_TAZ_SET;467} else {468handleVehicleError(true, ret);469}470}471// parse reroute information472if (attrs.hasAttribute(SUMO_ATTR_REROUTE)) {473bool ok = true;474if (attrs.get<bool>(SUMO_ATTR_REROUTE, ret->id.c_str(), ok)) {475if (ok) {476ret->parametersSet |= VEHPARS_FORCE_REROUTE;477} else {478handleVehicleError(true, ret);479}480}481}482// parse depart lane information483if (attrs.hasAttribute(SUMO_ATTR_DEPARTLANE)) {484bool ok = true;485const std::string departLaneStr = attrs.get<std::string>(SUMO_ATTR_DEPARTLANE, ret->id.c_str(), ok);486int lane;487DepartLaneDefinition dld;488std::string error;489if (SUMOVehicleParameter::parseDepartLane(departLaneStr, element, ret->id, lane, dld, error)) {490ret->parametersSet |= VEHPARS_DEPARTLANE_SET;491ret->departLane = lane;492ret->departLaneProcedure = dld;493} else {494handleVehicleError(true, ret, error);495}496}497// parse depart position information498if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {499bool ok = true;500const std::string departPosStr = attrs.get<std::string>(SUMO_ATTR_DEPARTPOS, ret->id.c_str(), ok);501double pos;502DepartPosDefinition dpd;503std::string error;504if (SUMOVehicleParameter::parseDepartPos(departPosStr, element, ret->id, pos, dpd, error)) {505ret->parametersSet |= VEHPARS_DEPARTPOS_SET;506ret->departPos = pos;507ret->departPosProcedure = dpd;508} else {509handleVehicleError(true, ret, error);510}511}512// parse lateral depart position information513if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS_LAT)) {514bool ok = true;515const std::string departPosLatStr = attrs.get<std::string>(SUMO_ATTR_DEPARTPOS_LAT, ret->id.c_str(), ok);516double pos;517DepartPosLatDefinition dpd;518std::string error;519if (SUMOVehicleParameter::parseDepartPosLat(departPosLatStr, element, ret->id, pos, dpd, error)) {520ret->parametersSet |= VEHPARS_DEPARTPOSLAT_SET;521ret->departPosLat = pos;522ret->departPosLatProcedure = dpd;523} else {524handleVehicleError(true, ret, error);525}526}527// parse depart speed information528if (attrs.hasAttribute(SUMO_ATTR_DEPARTSPEED)) {529bool ok = true;530const std::string departSpeed = attrs.get<std::string>(SUMO_ATTR_DEPARTSPEED, ret->id.c_str(), ok);531double speed;532DepartSpeedDefinition dsd;533std::string error;534if (SUMOVehicleParameter::parseDepartSpeed(departSpeed, element, ret->id, speed, dsd, error)) {535ret->parametersSet |= VEHPARS_DEPARTSPEED_SET;536ret->departSpeed = speed;537ret->departSpeedProcedure = dsd;538} else {539handleVehicleError(true, ret, error);540}541}542// parse depart edge information543if (attrs.hasAttribute(SUMO_ATTR_DEPARTEDGE)) {544bool ok = true;545const std::string departEdgeStr = attrs.get<std::string>(SUMO_ATTR_DEPARTEDGE, ret->id.c_str(), ok);546int edgeIndex;547RouteIndexDefinition rid;548std::string error;549if (SUMOVehicleParameter::parseRouteIndex(departEdgeStr, element, ret->id, SUMO_ATTR_DEPARTEDGE, edgeIndex, rid, error)) {550ret->parametersSet |= VEHPARS_DEPARTEDGE_SET;551ret->departEdge = edgeIndex;552ret->departEdgeProcedure = rid;553} else {554handleVehicleError(true, ret, error);555}556}557// parse arrival lane information558if (attrs.hasAttribute(SUMO_ATTR_ARRIVALLANE)) {559bool ok = true;560const std::string arrivalLaneStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALLANE, ret->id.c_str(), ok);561int lane;562ArrivalLaneDefinition ald;563std::string error;564if (SUMOVehicleParameter::parseArrivalLane(arrivalLaneStr, element, ret->id, lane, ald, error)) {565ret->parametersSet |= VEHPARS_ARRIVALLANE_SET;566ret->arrivalLane = lane;567ret->arrivalLaneProcedure = ald;568} else {569handleVehicleError(true, ret, error);570}571}572// parse arrival position information573if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {574bool ok = true;575const std::string arrivalPosStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS, ret->id.c_str(), ok);576double pos;577ArrivalPosDefinition apd;578std::string error;579if (SUMOVehicleParameter::parseArrivalPos(arrivalPosStr, element, ret->id, pos, apd, error)) {580ret->parametersSet |= VEHPARS_ARRIVALPOS_SET;581ret->arrivalPos = pos;582ret->arrivalPosProcedure = apd;583} else {584handleVehicleError(true, ret, error);585}586}587// parse lateral arrival position information588if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_LAT)) {589bool ok = true;590const std::string arrivalPosLatStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS_LAT, ret->id.c_str(), ok);591double pos;592ArrivalPosLatDefinition apd;593std::string error;594if (SUMOVehicleParameter::parseArrivalPosLat(arrivalPosLatStr, element, ret->id, pos, apd, error)) {595ret->parametersSet |= VEHPARS_ARRIVALPOSLAT_SET;596ret->arrivalPosLat = pos;597ret->arrivalPosLatProcedure = apd;598} else {599handleVehicleError(true, ret, error);600}601}602// parse arrival speed information603if (attrs.hasAttribute(SUMO_ATTR_ARRIVALSPEED)) {604bool ok = true;605std::string arrivalSpeedStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALSPEED, ret->id.c_str(), ok);606double speed;607ArrivalSpeedDefinition asd;608std::string error;609if (SUMOVehicleParameter::parseArrivalSpeed(arrivalSpeedStr, element, ret->id, speed, asd, error)) {610ret->parametersSet |= VEHPARS_ARRIVALSPEED_SET;611ret->arrivalSpeed = speed;612ret->arrivalSpeedProcedure = asd;613} else {614handleVehicleError(true, ret, error);615}616}617// parse arrival edge information618if (attrs.hasAttribute(SUMO_ATTR_ARRIVALEDGE)) {619bool ok = true;620std::string arrivalEdgeStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALEDGE, ret->id.c_str(), ok);621int edgeIndex;622RouteIndexDefinition rid;623std::string error;624if (SUMOVehicleParameter::parseRouteIndex(arrivalEdgeStr, element, ret->id, SUMO_ATTR_ARRIVALEDGE, edgeIndex, rid, error)) {625ret->parametersSet |= VEHPARS_ARRIVALEDGE_SET;626ret->arrivalEdge = edgeIndex;627ret->arrivalEdgeProcedure = rid;628} else {629handleVehicleError(true, ret, error);630}631}632// parse color633if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {634bool ok = true;635ret->color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, ret->id.c_str(), ok);636if (ok) {637ret->parametersSet |= VEHPARS_COLOR_SET;638} else {639handleVehicleError(true, ret, "Invalid RGBColor format");640}641} else {642ret->color = RGBColor::DEFAULT_COLOR;643}644// parse person number645if (attrs.hasAttribute(SUMO_ATTR_PERSON_NUMBER)) {646bool ok = true;647int personNumber = attrs.get<int>(SUMO_ATTR_PERSON_NUMBER, ret->id.c_str(), ok);648if (!ok) {649handleVehicleError(true, ret);650} else if (personNumber >= 0) {651ret->parametersSet |= VEHPARS_PERSON_NUMBER_SET;652ret->personNumber = personNumber;653} else {654handleVehicleError(true, ret, toString(SUMO_ATTR_PERSON_NUMBER) + " cannot be negative");655}656}657// parse container number658if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_NUMBER)) {659bool ok = true;660int containerNumber = attrs.get<int>(SUMO_ATTR_CONTAINER_NUMBER, ret->id.c_str(), ok);661if (!ok) {662handleVehicleError(true, ret);663} else if (containerNumber >= 0) {664ret->parametersSet |= VEHPARS_CONTAINER_NUMBER_SET;665ret->containerNumber = containerNumber;666} else {667handleVehicleError(true, ret, toString(SUMO_ATTR_CONTAINER_NUMBER) + " cannot be negative");668}669}670// parse individual speedFactor671if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {672bool ok = true;673double speedFactor = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR, ret->id.c_str(), ok);674if (!ok) {675handleVehicleError(true, ret);676} else if (speedFactor > 0) {677ret->parametersSet |= VEHPARS_SPEEDFACTOR_SET;678ret->speedFactor = speedFactor;679} else {680handleVehicleError(true, ret, toString(SUMO_ATTR_SPEEDFACTOR) + " must be positive");681}682}683// parse insertion checks684if (attrs.hasAttribute(SUMO_ATTR_INSERTIONCHECKS)) {685ret->parametersSet |= VEHPARS_INSERTION_CHECKS_SET;686bool ok = true;687std::string checks = attrs.get<std::string>(SUMO_ATTR_INSERTIONCHECKS, ret->id.c_str(), ok);688if (!ok) {689handleVehicleError(true, ret);690} else {691try {692ret->insertionChecks = SUMOVehicleParameter::parseInsertionChecks(checks);693} catch (InvalidArgument& e) {694handleVehicleError(true, ret, e.what());695}696}697}698// parse parking access rights699if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {700bool ok = true;701std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, ret->id.c_str(), ok);702if (!ok) {703handleVehicleError(true, ret);704} else {705ret->parametersSet |= VEHPARS_PARKING_BADGES_SET;706ret->parkingBadges = badges;707}708}709// parse modes (transportables only)710ret->modes = 0;711if (attrs.hasAttribute(SUMO_ATTR_MODES)) {712bool ok = true;713const std::string modeString = attrs.get<std::string>(SUMO_ATTR_MODES, ret->id.c_str(), ok);714if (!ok) {715handleVehicleError(true, ret);716} else {717std::string errorMsg;718if (!SUMOVehicleParameter::parsePersonModes(modeString, toString(tag), ret->id, ret->modes, errorMsg)) {719handleVehicleError(true, ret, errorMsg);720}721}722}723// parse usable vehicle types (transportables only)724if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {725bool ok = true;726ret->vTypes = attrs.get<std::string>(SUMO_ATTR_VTYPES, ret->id.c_str(), ok);727if (!ok) {728handleVehicleError(true, ret);729}730}731// parse speed (only used by calibrators flow)732// also used by vehicle in saved state but this is parsed elsewhere733if (tag == SUMO_TAG_FLOW && attrs.hasAttribute(SUMO_ATTR_SPEED)) {734bool ok = true;735double calibratorSpeed = attrs.get<double>(SUMO_ATTR_SPEED, ret->id.c_str(), ok);736if (!ok) {737handleVehicleError(true, ret);738} else if (calibratorSpeed >= 0 || calibratorSpeed == -1) {739ret->parametersSet |= VEHPARS_CALIBRATORSPEED_SET;740ret->calibratorSpeed = calibratorSpeed;741} else {742handleVehicleError(true, ret, toString(SUMO_ATTR_SPEED) + " may not be negative");743}744}745/*/ parse via746if (attrs.hasAttribute(SUMO_ATTR_VIA)) {747ret->setParameter |= VEHPARS_VIA_SET;748SUMOSAXAttributes::parseStringVector(attrs.get<std::string>(SUMO_ATTR_VIA, ret->id.c_str(), ok), ret->via);749}750*/751}752753754SUMOVTypeParameter*755SUMOVehicleParserHelper::beginVTypeParsing(const SUMOSAXAttributes& attrs, const bool hardFail, const std::string& file) {756// first obtain ID757std::string id = parseID(attrs, SUMO_TAG_VTYPE);758// check if ID is valid759if (!id.empty()) {760SUMOVehicleClass vClass = SVC_PASSENGER;761if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {762vClass = parseVehicleClass(attrs, id);763}764// create vType765SUMOVTypeParameter* vType = new SUMOVTypeParameter(id, vClass);766// parse attributes767if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {768vType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;769}770if (attrs.hasAttribute(SUMO_ATTR_LENGTH)) {771bool ok = true;772const double length = attrs.get<double>(SUMO_ATTR_LENGTH, vType->id.c_str(), ok);773if (!ok) {774return handleVehicleTypeError(hardFail, vType);775} else if (length <= 0) {776return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LENGTH) + " must be greater than 0");777} else {778vType->length = length;779vType->parametersSet |= VTYPEPARS_LENGTH_SET;780}781}782if (attrs.hasAttribute(SUMO_ATTR_MINGAP)) {783bool ok = true;784const double minGap = attrs.get<double>(SUMO_ATTR_MINGAP, vType->id.c_str(), ok);785if (!ok) {786return handleVehicleTypeError(hardFail, vType);787} else if (minGap < 0) {788return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP) + " must be equal or greater than 0");789} else {790vType->minGap = minGap;791vType->parametersSet |= VTYPEPARS_MINGAP_SET;792}793}794if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {795bool ok = true;796const double maxSpeed = attrs.get<double>(SUMO_ATTR_MAXSPEED, vType->id.c_str(), ok);797if (!ok) {798return handleVehicleTypeError(hardFail, vType);799} else if (maxSpeed <= 0) {800return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED) + " must be greater than 0");801} else {802vType->maxSpeed = maxSpeed;803vType->parametersSet |= VTYPEPARS_MAXSPEED_SET;804}805}806if (attrs.hasAttribute(SUMO_ATTR_DESIRED_MAXSPEED)) {807bool ok = true;808const double desiredMaxSpeed = attrs.get<double>(SUMO_ATTR_DESIRED_MAXSPEED, vType->id.c_str(), ok);809if (!ok) {810return handleVehicleTypeError(hardFail, vType);811} else if (desiredMaxSpeed <= 0) {812return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_DESIRED_MAXSPEED) + " must be greater than 0");813} else {814vType->desiredMaxSpeed = desiredMaxSpeed;815vType->parametersSet |= VTYPEPARS_DESIRED_MAXSPEED_SET;816}817} else if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {818if (vClass == SVC_PEDESTRIAN) {819// backward compatibility because pedestrian maxSpeed was subject to speedFactor up to 1.14.1820vType->desiredMaxSpeed = vType->maxSpeed;;821vType->maxSpeed = MAX2(vType->maxSpeed, SUMOVTypeParameter::VClassDefaultValues(vClass).maxSpeed);822} else if (vClass == SVC_BICYCLE) {823// backward compatibility because default desired speed did not exist up to 1.14.1824vType->desiredMaxSpeed = MAX2(vType->maxSpeed, vType->desiredMaxSpeed);825}826}827828if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {829bool ok = true;830vType->speedFactor.parse(attrs.get<std::string>(SUMO_ATTR_SPEEDFACTOR, vType->id.c_str(), ok), hardFail);831if (!ok) {832return handleVehicleTypeError(hardFail, vType);833} else {834vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;835}836}837if (attrs.hasAttribute(SUMO_ATTR_SPEEDDEV)) {838bool ok = true;839const double speedDev = attrs.get<double>(SUMO_ATTR_SPEEDDEV, vType->id.c_str(), ok);840if (!ok) {841return handleVehicleTypeError(hardFail, vType);842} else if (speedDev < 0) {843return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SPEEDDEV) + " must be equal or greater than 0");844} else {845vType->speedFactor.setParameter(1, speedDev);846vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;847}848}849// validate speed distribution850const std::string& error = vType->speedFactor.isValid();851if (error != "") {852return handleVehicleTypeError(hardFail, vType, "Invalid speed distribution when parsing vType '" + vType->id + "' (" + error + ")");853}854if (attrs.hasAttribute(SUMO_ATTR_ACTIONSTEPLENGTH)) {855bool ok = true;856const double actionStepLengthSecs = attrs.get<double>(SUMO_ATTR_ACTIONSTEPLENGTH, vType->id.c_str(), ok);857if (!ok) {858return handleVehicleTypeError(hardFail, vType);859} else {860// processActionStepLength(...) function includes warnings861vType->actionStepLength = processActionStepLength(actionStepLengthSecs);862vType->parametersSet |= VTYPEPARS_ACTIONSTEPLENGTH_SET;863}864}865if (attrs.hasAttribute(SUMO_ATTR_EMISSIONCLASS)) {866bool ok = true;867const std::string parsedEmissionClass = attrs.getOpt<std::string>(SUMO_ATTR_EMISSIONCLASS, id.c_str(), ok, "");868// check if emission class is correct869try {870vType->emissionClass = PollutantsInterface::getClassByName(parsedEmissionClass);871vType->parametersSet |= VTYPEPARS_EMISSIONCLASS_SET;872} catch (...) {873return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_EMISSIONCLASS) + " with name '" + parsedEmissionClass + "' doesn't exist.");874}875}876if (attrs.hasAttribute(SUMO_ATTR_MASS)) {877bool ok = true;878const double mass = attrs.get<double>(SUMO_ATTR_MASS, vType->id.c_str(), ok);879if (!ok) {880return handleVehicleTypeError(hardFail, vType);881} else if (mass < 0) {882return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MASS) + " must be equal or greater than 0");883} else {884vType->mass = mass;885vType->parametersSet |= VTYPEPARS_MASS_SET;886}887}888if (attrs.hasAttribute(SUMO_ATTR_IMPATIENCE)) {889bool ok = true;890const std::string impatienceStr = attrs.get<std::string>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);891if (!ok) {892return handleVehicleTypeError(hardFail, vType);893} else if (impatienceStr == "off") {894vType->impatience = -std::numeric_limits<double>::max();895} else {896const double impatienceDouble = attrs.get<double>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);897if (!ok) {898return handleVehicleTypeError(hardFail, vType);899} else {900vType->impatience = impatienceDouble;901vType->parametersSet |= VTYPEPARS_IMPATIENCE_SET;902}903}904}905if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {906bool ok = true;907const double width = attrs.get<double>(SUMO_ATTR_WIDTH, vType->id.c_str(), ok);908if (!ok) {909return handleVehicleTypeError(hardFail, vType);910} else if (width <= 0) {911return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_WIDTH) + " must be greater than 0");912} else {913vType->width = width;914vType->parametersSet |= VTYPEPARS_WIDTH_SET;915if (vClass == SVC_PEDESTRIAN916&& OptionsCont::getOptions().exists("pedestrian.striping.stripe-width")917&& OptionsCont::getOptions().getString("pedestrian.model") == "striping"918&& OptionsCont::getOptions().getFloat("pedestrian.striping.stripe-width") < vType->width) {919WRITE_WARNINGF(TL("Pedestrian vType '%' width % is larger than pedestrian.striping.stripe-width and this may cause collisions with vehicles."), id, vType->width);920}921}922}923if (attrs.hasAttribute(SUMO_ATTR_HEIGHT)) {924bool ok = true;925const double height = attrs.get<double>(SUMO_ATTR_HEIGHT, vType->id.c_str(), ok);926if (!ok) {927return handleVehicleTypeError(hardFail, vType);928} else if (height < 0) {929return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_HEIGHT) + " must be equal or greater than 0");930} else {931vType->height = height;932vType->parametersSet |= VTYPEPARS_HEIGHT_SET;933}934}935if (attrs.hasAttribute(SUMO_ATTR_GUISHAPE)) {936vType->shape = parseGuiShape(attrs, vType->id);937if (vType->shape != SUMOVehicleShape::UNKNOWN) {938vType->parametersSet |= VTYPEPARS_SHAPE_SET;939}940}941if (attrs.hasAttribute(SUMO_ATTR_OSGFILE)) {942bool ok = true;943const std::string osgFile = attrs.get<std::string>(SUMO_ATTR_OSGFILE, vType->id.c_str(), ok);944if (!ok) {945return handleVehicleTypeError(hardFail, vType);946} else {947vType->osgFile = osgFile;948vType->parametersSet |= VTYPEPARS_OSGFILE_SET;949}950}951if (attrs.hasAttribute(SUMO_ATTR_IMGFILE)) {952bool ok = true;953std::string imgFile = attrs.get<std::string>(SUMO_ATTR_IMGFILE, vType->id.c_str(), ok);954if (!ok) {955return handleVehicleTypeError(hardFail, vType);956} else {957// check relative path958if ((imgFile != "") && !FileHelpers::isAbsolute(imgFile)) {959imgFile = FileHelpers::getConfigurationRelative(file, imgFile);960}961vType->imgFile = imgFile;962vType->parametersSet |= VTYPEPARS_IMGFILE_SET;963}964}965if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {966bool ok = true;967const RGBColor color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, vType->id.c_str(), ok);968if (!ok) {969return handleVehicleTypeError(hardFail, vType);970} else {971vType->color = color;972vType->parametersSet |= VTYPEPARS_COLOR_SET;973}974} else {975vType->color = RGBColor::YELLOW;976}977if (attrs.hasAttribute(SUMO_ATTR_PROB)) {978bool ok = true;979const double defaultProbability = attrs.get<double>(SUMO_ATTR_PROB, vType->id.c_str(), ok);980if (!ok) {981return handleVehicleTypeError(hardFail, vType);982} else if (defaultProbability < 0) {983return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PROB) + " must be equal or greater than 0");984} else {985vType->defaultProbability = defaultProbability;986vType->parametersSet |= VTYPEPARS_PROBABILITY_SET;987}988}989if (attrs.hasAttribute(SUMO_ATTR_LANE_CHANGE_MODEL)) {990bool ok = true;991std::string lcmS = attrs.get<std::string>(SUMO_ATTR_LANE_CHANGE_MODEL, vType->id.c_str(), ok);992if (!ok) {993return handleVehicleTypeError(hardFail, vType);994} else if (lcmS == "JE2013") {995WRITE_WARNING(TL("Lane change model 'JE2013' is deprecated. Using default model instead."));996lcmS = "default";997}998if (SUMOXMLDefinitions::LaneChangeModels.hasString(lcmS)) {999vType->lcModel = SUMOXMLDefinitions::LaneChangeModels.get(lcmS);1000vType->parametersSet |= VTYPEPARS_LANE_CHANGE_MODEL_SET;1001} else {1002return handleVehicleTypeError(hardFail, vType, "Unknown lane change model '" + lcmS + "' when parsing vType '" + vType->id + "'");1003}1004}1005if (attrs.hasAttribute(SUMO_ATTR_CAR_FOLLOW_MODEL)) {1006bool ok = true;1007const std::string cfmValue = attrs.get<std::string>(SUMO_ATTR_CAR_FOLLOW_MODEL, vType->id.c_str(), ok);1008if (!ok) {1009return handleVehicleTypeError(hardFail, vType);1010} else if (SUMOXMLDefinitions::CarFollowModels.hasString(cfmValue)) {1011vType->cfModel = SUMOXMLDefinitions::CarFollowModels.get(cfmValue);1012vType->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;1013} else {1014return handleVehicleTypeError(hardFail, vType, "Unknown car following model '" + cfmValue + "' when parsing vType '" + vType->id + "'");1015}1016}1017if (attrs.hasAttribute(SUMO_ATTR_PERSON_CAPACITY)) {1018bool ok = true;1019const int personCapacity = attrs.get<int>(SUMO_ATTR_PERSON_CAPACITY, vType->id.c_str(), ok);1020if (!ok) {1021return handleVehicleTypeError(hardFail, vType);1022} else if (personCapacity < 0) {1023return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PERSON_CAPACITY) + " must be equal or greater than 0");1024} else {1025vType->personCapacity = personCapacity;1026vType->parametersSet |= VTYPEPARS_PERSON_CAPACITY;1027}1028}1029if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_CAPACITY)) {1030bool ok = true;1031const int containerCapacity = attrs.get<int>(SUMO_ATTR_CONTAINER_CAPACITY, vType->id.c_str(), ok);1032if (!ok) {1033return handleVehicleTypeError(hardFail, vType);1034} else if (containerCapacity < 0) {1035return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_CONTAINER_CAPACITY) + " must be equal or greater than 0");1036} else {1037vType->containerCapacity = containerCapacity;1038vType->parametersSet |= VTYPEPARS_CONTAINER_CAPACITY;1039}1040}1041if (attrs.hasAttribute(SUMO_ATTR_BOARDING_DURATION)) {1042bool ok = true;1043const SUMOTime boardingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_BOARDING_DURATION, vType->id.c_str(), ok);1044if (!ok) {1045return handleVehicleTypeError(hardFail, vType);1046} else if (boardingDuration < 0) {1047return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_DURATION) + " must be equal or greater than 0");1048} else {1049vType->boardingDuration = boardingDuration;1050vType->parametersSet |= VTYPEPARS_BOARDING_DURATION;1051}1052}1053if (attrs.hasAttribute(SUMO_ATTR_LOADING_DURATION)) {1054bool ok = true;1055const SUMOTime loadingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_LOADING_DURATION, vType->id.c_str(), ok);1056if (!ok) {1057return handleVehicleTypeError(hardFail, vType);1058} else if (loadingDuration < 0) {1059return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LOADING_DURATION) + " must be equal or greater than 0");1060} else {1061vType->loadingDuration = loadingDuration;1062vType->parametersSet |= VTYPEPARS_LOADING_DURATION;1063}1064}1065if (attrs.hasAttribute(SUMO_ATTR_SCALE)) {1066bool ok = true;1067const double scale = attrs.get<double>(SUMO_ATTR_SCALE, id.c_str(), ok);1068if (!ok) {1069return handleVehicleTypeError(hardFail, vType);1070} else if (scale < 0) {1071return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SCALE) + " may be not be negative");1072} else {1073vType->scale = scale;1074vType->parametersSet |= VTYPEPARS_SCALE_SET;1075}1076}1077if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT)) {1078bool ok = true;1079const SUMOTime ttt = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT, vType->id.c_str(), ok);1080if (!ok) {1081return handleVehicleTypeError(hardFail, vType);1082} else {1083vType->timeToTeleport = ttt;1084vType->parametersSet |= VTYPEPARS_TTT_SET;1085}1086}1087if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT_BIDI)) {1088bool ok = true;1089const SUMOTime tttb = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT_BIDI, vType->id.c_str(), ok);1090if (!ok) {1091return handleVehicleTypeError(hardFail, vType);1092} else {1093vType->timeToTeleportBidi = tttb;1094vType->parametersSet |= VTYPEPARS_TTT_BIDI_SET;1095}1096}1097if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR_PREMATURE)) {1098bool ok = true;1099const double sfp = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR_PREMATURE, id.c_str(), ok);1100if (!ok) {1101return handleVehicleTypeError(hardFail, vType);1102} else {1103vType->speedFactorPremature = sfp;1104vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_PREMATURE_SET;1105}1106}1107if (attrs.hasAttribute(SUMO_ATTR_BOARDING_FACTOR)) {1108bool ok = true;1109const double bf = attrs.get<double>(SUMO_ATTR_BOARDING_FACTOR, id.c_str(), ok);1110if (!ok) {1111return handleVehicleTypeError(hardFail, vType);1112} else if (bf < 0) {1113return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_FACTOR) + " must be equal or greater than 0");1114} else {1115vType->boardingFactor = bf;1116vType->parametersSet |= VTYPEPARS_BOARDING_FACTOR_SET;1117}1118}1119if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED_LAT)) {1120bool ok = true;1121const double maxSpeedLat = attrs.get<double>(SUMO_ATTR_MAXSPEED_LAT, vType->id.c_str(), ok);1122if (!ok) {1123return handleVehicleTypeError(hardFail, vType);1124} else if (maxSpeedLat <= 0) {1125return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED_LAT) + " must be greater than 0");1126} else {1127vType->maxSpeedLat = maxSpeedLat;1128vType->parametersSet |= VTYPEPARS_MAXSPEED_LAT_SET;1129}1130}1131if (attrs.hasAttribute(SUMO_ATTR_MINGAP_LAT)) {1132bool ok = true;1133const double minGapLat = attrs.get<double>(SUMO_ATTR_MINGAP_LAT, vType->id.c_str(), ok);1134if (!ok) {1135return handleVehicleTypeError(hardFail, vType);1136} else if (minGapLat < 0) {1137return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP_LAT) + " must be equal or greater than 0");1138} else {1139vType->minGapLat = minGapLat;1140vType->parametersSet |= VTYPEPARS_MINGAP_LAT_SET;1141}1142}1143if (attrs.hasAttribute(SUMO_ATTR_LATALIGNMENT)) {1144bool ok = true;1145const std::string alignS = attrs.get<std::string>(SUMO_ATTR_LATALIGNMENT, vType->id.c_str(), ok);1146if (!ok) {1147return handleVehicleTypeError(hardFail, vType);1148} else {1149double lao;1150LatAlignmentDefinition lad;1151if (SUMOVTypeParameter::parseLatAlignment(alignS, lao, lad)) {1152vType->latAlignmentOffset = lao;1153vType->latAlignmentProcedure = lad;1154vType->parametersSet |= VTYPEPARS_LATALIGNMENT_SET;1155} else {1156return 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)");1157}1158}1159}1160if (attrs.hasAttribute(SUMO_ATTR_MANEUVER_ANGLE_TIMES)) {1161bool ok = true;1162const std::string angleTimesS = attrs.get<std::string>(SUMO_ATTR_MANEUVER_ANGLE_TIMES, vType->id.c_str(), ok);1163if (!ok) {1164return handleVehicleTypeError(hardFail, vType);1165} else if (parseAngleTimesMap(vType, angleTimesS)) {1166vType->parametersSet |= VTYPEPARS_MANEUVER_ANGLE_TIMES_SET;1167} else {1168return handleVehicleTypeError(hardFail, vType, "Invalid manoeuver angle times map for vType '" + vType->id + "'");1169}1170}1171if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {1172bool ok = true;1173std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, vType->id.c_str(), ok);1174if (!ok) {1175return handleVehicleTypeError(hardFail, vType);1176} else {1177vType->parametersSet |= VTYPEPARS_PARKING_BADGES_SET;1178vType->parkingBadges = badges;1179}1180}1181// try to parse Car Following Model params1182if (!parseCFMParams(vType, vType->cfModel, attrs, false)) {1183return handleVehicleTypeError(hardFail, vType, "Invalid parsing embedded VType");1184}1185// try to parse Lane Change Model params1186if (!parseLCParams(vType, vType->lcModel, attrs)) {1187return handleVehicleTypeError(hardFail, vType, "Invalid Lane Change Model Parameters");1188}1189// try to Junction Model params1190if (!parseJMParams(vType, attrs)) {1191return handleVehicleTypeError(hardFail, vType, "Invalid Junction Model Parameters");1192}1193// all ok, then return vType1194return vType;1195} else {1196return handleVehicleTypeError(hardFail, nullptr, "VType cannot be created");1197}1198}119912001201bool1202SUMOVehicleParserHelper::parseAngleTimesMap(SUMOVTypeParameter* vtype, const std::string atm) {1203StringTokenizer st(atm, ",");1204std::map<int, std::pair<SUMOTime, SUMOTime>> angleTimesMap;1205int tripletCount = 0;1206while (st.hasNext()) {1207StringTokenizer pos(st.next());1208if (pos.size() != 3) {1209WRITE_ERRORF(TL("maneuverAngleTimes format for vType '%' % contains an invalid triplet."), vtype->id, atm);1210return false;1211} else {1212try {1213const int angle = StringUtils::toInt(pos.next());1214const SUMOTime t1 = string2time(pos.next());1215const SUMOTime t2 = string2time(pos.next());1216angleTimesMap[angle] = std::make_pair(t1, t2);1217} catch (...) {1218WRITE_ERRORF(TL("Triplet '%' for vType '%' maneuverAngleTimes cannot be parsed as 'int double double'"), st.get(tripletCount), vtype->id);1219return false;1220}1221tripletCount++;1222}1223}1224if (angleTimesMap.size() > 0) {1225vtype->myManoeuverAngleTimes.clear();1226for (const auto& angleTime : angleTimesMap) {1227vtype->myManoeuverAngleTimes.insert(angleTime);1228}1229angleTimesMap.clear();1230return true;1231} else {1232return false;1233}1234}123512361237bool1238SUMOVehicleParserHelper::parseCFMParams(SUMOVTypeParameter* into, const SumoXMLTag element, const SUMOSAXAttributes& attrs, const bool nestedCFM) {1239const CFAttrMap& allowedCFM = getAllowedCFModelAttrs();1240CFAttrMap::const_iterator cf_it = allowedCFM.find(element);1241// check if given CFM is allowed1242if (cf_it == allowedCFM.end()) {1243if (SUMOXMLDefinitions::Tags.has((int)element)) {1244WRITE_ERRORF(TL("Unknown car-following model % when parsing vType '%'"), toString(element), into->id);1245} else {1246WRITE_ERRORF(TL("Unknown car-following model when parsing vType '%'"), into->id);1247}1248return false;1249}1250// check if we're parsing a nested CFM1251if (nestedCFM) {1252into->cfModel = cf_it->first;1253into->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;1254}1255// set CFM values1256for (const auto& it : cf_it->second) {1257if (attrs.hasAttribute(it)) {1258// first obtain CFM attribute in string format1259bool ok = true;1260std::string parsedCFMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);1261// check CFM Attribute1262if (!ok) {1263return false;1264} else if (it == SUMO_ATTR_TRAIN_TYPE) {1265// check if train value is valid1266if (!SUMOXMLDefinitions::TrainTypes.hasString(parsedCFMAttribute)) {1267WRITE_ERROR("Invalid train type '" + parsedCFMAttribute + "' used in Car-Following-Attribute " + toString(it));1268return false;1269}1270// add parsedCFMAttribute to cfParameter1271into->cfParameter[it] = parsedCFMAttribute;1272} else if (it == SUMO_ATTR_SPEED_TABLE || it == SUMO_ATTR_TRACTION_TABLE || it == SUMO_ATTR_RESISTANCE_TABLE) {1273into->cfParameter[it] = parsedCFMAttribute;1274} else if (it == SUMO_ATTR_CF_IDM_STEPPING) {1275// declare a int in wich save CFM int attribute1276double CFMDoubleAttribute = -1;1277try {1278// obtain CFM attribute in int format1279CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);1280} catch (...) {1281WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));1282return false;1283}1284if (CFMDoubleAttribute <= 0) {1285WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));1286return false;1287}1288// add parsedCFMAttribute to cfParameter1289into->cfParameter[it] = parsedCFMAttribute;1290} else if (it == SUMO_ATTR_MAXACCEL_PROFILE || it == SUMO_ATTR_DESACCEL_PROFILE) {1291if (validProfile(into, parsedCFMAttribute, it)) {1292into->cfParameter[it] = parsedCFMAttribute;1293} else {1294WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed as a vector of <speed accel> pairs"), toString(it));1295return false;1296}1297} else {1298// declare a double in wich save CFM float attribute1299double CFMDoubleAttribute = -1;1300try {1301// obtain CFM attribute in double format1302CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);1303} catch (...) {1304WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));1305return false;1306}1307// check attributes of type "positiveFloatType" (> 0)1308switch (it) {1309case SUMO_ATTR_ACCEL:1310case SUMO_ATTR_DECEL:1311case SUMO_ATTR_APPARENTDECEL:1312case SUMO_ATTR_EMERGENCYDECEL:1313case SUMO_ATTR_TAU:1314if (CFMDoubleAttribute <= 0) {1315WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));1316return false;1317}1318break;1319default:1320break;1321}1322// check attributes restricted to [0-1]1323switch (it) {1324case SUMO_ATTR_SIGMA:1325if ((CFMDoubleAttribute < 0) || (CFMDoubleAttribute > 1)) {1326WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Only values between [0-1] are allowed"), toString(it));1327return false;1328}1329break;1330default:1331break;1332}1333// add parsedCFMAttribute to cfParameter1334into->cfParameter[it] = parsedCFMAttribute;1335}1336}1337}1338// all CFM successfully parsed, then return true1339return true;1340}134113421343const SUMOVehicleParserHelper::CFAttrMap&1344SUMOVehicleParserHelper::getAllowedCFModelAttrs() {1345// init on first use1346if (allowedCFModelAttrs.size() == 0) {1347std::set<SumoXMLAttr> genericParams;1348genericParams.insert(SUMO_ATTR_TAU);1349genericParams.insert(SUMO_ATTR_ACCEL);1350genericParams.insert(SUMO_ATTR_DECEL);1351genericParams.insert(SUMO_ATTR_APPARENTDECEL);1352genericParams.insert(SUMO_ATTR_EMERGENCYDECEL);1353genericParams.insert(SUMO_ATTR_SPEED_TABLE);1354genericParams.insert(SUMO_ATTR_MAXACCEL_PROFILE);1355genericParams.insert(SUMO_ATTR_DESACCEL_PROFILE);1356genericParams.insert(SUMO_ATTR_COLLISION_MINGAP_FACTOR);1357genericParams.insert(SUMO_ATTR_STARTUP_DELAY);1358// Krauss1359std::set<SumoXMLAttr> kraussParams(genericParams);1360kraussParams.insert(SUMO_ATTR_SIGMA);1361kraussParams.insert(SUMO_ATTR_SIGMA_STEP);1362allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS] = kraussParams;1363allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_ORIG1] = kraussParams;1364allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_PLUS_SLOPE] = kraussParams;1365std::set<SumoXMLAttr> allParams(kraussParams);1366// KraussX1367std::set<SumoXMLAttr> kraussXParams(kraussParams);1368kraussXParams.insert(SUMO_ATTR_TMP1);1369kraussXParams.insert(SUMO_ATTR_TMP2);1370kraussXParams.insert(SUMO_ATTR_TMP3);1371kraussXParams.insert(SUMO_ATTR_TMP4);1372kraussXParams.insert(SUMO_ATTR_TMP5);1373allowedCFModelAttrs[SUMO_TAG_CF_KRAUSSX] = kraussXParams;1374allParams.insert(kraussXParams.begin(), kraussXParams.end());1375// SmartSK1376std::set<SumoXMLAttr> smartSKParams(genericParams);1377smartSKParams.insert(SUMO_ATTR_SIGMA);1378smartSKParams.insert(SUMO_ATTR_TMP1);1379smartSKParams.insert(SUMO_ATTR_TMP2);1380smartSKParams.insert(SUMO_ATTR_TMP3);1381smartSKParams.insert(SUMO_ATTR_TMP4);1382smartSKParams.insert(SUMO_ATTR_TMP5);1383allowedCFModelAttrs[SUMO_TAG_CF_SMART_SK] = smartSKParams;1384allParams.insert(smartSKParams.begin(), smartSKParams.end());1385// Daniel1386std::set<SumoXMLAttr> daniel1Params(genericParams);1387daniel1Params.insert(SUMO_ATTR_SIGMA);1388daniel1Params.insert(SUMO_ATTR_TMP1);1389daniel1Params.insert(SUMO_ATTR_TMP2);1390daniel1Params.insert(SUMO_ATTR_TMP3);1391daniel1Params.insert(SUMO_ATTR_TMP4);1392daniel1Params.insert(SUMO_ATTR_TMP5);1393allowedCFModelAttrs[SUMO_TAG_CF_DANIEL1] = daniel1Params;1394allParams.insert(daniel1Params.begin(), daniel1Params.end());1395// Peter Wagner1396std::set<SumoXMLAttr> pwagParams(genericParams);1397pwagParams.insert(SUMO_ATTR_SIGMA);1398pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_TAULAST);1399pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_APPROB);1400allowedCFModelAttrs[SUMO_TAG_CF_PWAGNER2009] = pwagParams;1401allParams.insert(pwagParams.begin(), pwagParams.end());1402// IDM params1403std::set<SumoXMLAttr> idmParams(genericParams);1404idmParams.insert(SUMO_ATTR_CF_IDM_DELTA);1405idmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);1406allowedCFModelAttrs[SUMO_TAG_CF_IDM] = idmParams;1407allParams.insert(idmParams.begin(), idmParams.end());1408// EIDM1409std::set<SumoXMLAttr> eidmParams(genericParams);1410eidmParams.insert(SUMO_ATTR_CF_IDM_DELTA);1411eidmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);1412eidmParams.insert(SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD);1413eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE);1414eidmParams.insert(SUMO_ATTR_CF_EIDM_T_REACTION);1415eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE);1416eidmParams.insert(SUMO_ATTR_CF_EIDM_C_COOLNESS);1417eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_LEADER);1418eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_GAP);1419eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_ERROR);1420eidmParams.insert(SUMO_ATTR_CF_EIDM_JERK_MAX);1421eidmParams.insert(SUMO_ATTR_CF_EIDM_EPSILON_ACC);1422eidmParams.insert(SUMO_ATTR_CF_EIDM_T_ACC_MAX);1423eidmParams.insert(SUMO_ATTR_CF_EIDM_M_FLATNESS);1424eidmParams.insert(SUMO_ATTR_CF_EIDM_M_BEGIN);1425eidmParams.insert(SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS);1426eidmParams.insert(SUMO_ATTR_CF_EIDM_MAX_VEH_PREVIEW);1427allowedCFModelAttrs[SUMO_TAG_CF_EIDM] = eidmParams;1428allParams.insert(eidmParams.begin(), eidmParams.end());1429// IDMM1430std::set<SumoXMLAttr> idmmParams(genericParams);1431idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR);1432idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_TIME);1433idmmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);1434allowedCFModelAttrs[SUMO_TAG_CF_IDMM] = idmmParams;1435allParams.insert(idmmParams.begin(), idmmParams.end());1436// Bieker1437std::set<SumoXMLAttr> bkernerParams(genericParams);1438bkernerParams.insert(SUMO_ATTR_K);1439bkernerParams.insert(SUMO_ATTR_CF_KERNER_PHI);1440allowedCFModelAttrs[SUMO_TAG_CF_BKERNER] = bkernerParams;1441allParams.insert(bkernerParams.begin(), bkernerParams.end());1442// Wiedemann1443std::set<SumoXMLAttr> wiedemannParams(genericParams);1444wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_SECURITY);1445wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_ESTIMATION);1446allowedCFModelAttrs[SUMO_TAG_CF_WIEDEMANN] = wiedemannParams;1447allParams.insert(wiedemannParams.begin(), wiedemannParams.end());1448// W991449std::set<SumoXMLAttr> w99Params(genericParams);1450w99Params.insert(SUMO_ATTR_CF_W99_CC1);1451w99Params.insert(SUMO_ATTR_CF_W99_CC2);1452w99Params.insert(SUMO_ATTR_CF_W99_CC3);1453w99Params.insert(SUMO_ATTR_CF_W99_CC4);1454w99Params.insert(SUMO_ATTR_CF_W99_CC5);1455w99Params.insert(SUMO_ATTR_CF_W99_CC6);1456w99Params.insert(SUMO_ATTR_CF_W99_CC7);1457w99Params.insert(SUMO_ATTR_CF_W99_CC8);1458w99Params.insert(SUMO_ATTR_CF_W99_CC9);1459allowedCFModelAttrs[SUMO_TAG_CF_W99] = w99Params;1460allParams.insert(w99Params.begin(), w99Params.end());1461// Rail1462std::set<SumoXMLAttr> railParams(genericParams);1463railParams.insert(SUMO_ATTR_TRAIN_TYPE);1464railParams.insert(SUMO_ATTR_TRACTION_TABLE);1465railParams.insert(SUMO_ATTR_RESISTANCE_TABLE);1466railParams.insert(SUMO_ATTR_MASSFACTOR);1467railParams.insert(SUMO_ATTR_MAXPOWER);1468railParams.insert(SUMO_ATTR_MAXTRACTION);1469railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_CONSTANT);1470railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_LINEAR);1471railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_QUADRATIC);1472allowedCFModelAttrs[SUMO_TAG_CF_RAIL] = railParams;1473allParams.insert(railParams.begin(), railParams.end());1474// ACC1475std::set<SumoXMLAttr> ACCParams(genericParams);1476ACCParams.insert(SUMO_ATTR_SC_GAIN);1477ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);1478ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);1479ACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);1480ACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);1481ACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);1482ACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);1483ACCParams.insert(SUMO_ATTR_CA_OVERRIDE);1484ACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);1485allowedCFModelAttrs[SUMO_TAG_CF_ACC] = ACCParams;1486allParams.insert(ACCParams.begin(), ACCParams.end());1487// CACC1488std::set<SumoXMLAttr> CACCParams(genericParams);1489CACCParams.insert(SUMO_ATTR_SC_GAIN_CACC);1490CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_CACC);1491CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_DOT_CACC);1492CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_CACC);1493CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_DOT_CACC);1494CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_CACC);1495CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_DOT_CACC);1496CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);1497CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);1498CACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);1499CACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);1500CACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);1501CACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);1502CACCParams.insert(SUMO_ATTR_CA_OVERRIDE);1503CACCParams.insert(SUMO_ATTR_HEADWAY_TIME_CACC_TO_ACC);1504CACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);1505CACCParams.insert(SUMO_ATTR_SC_MIN_GAP);1506allowedCFModelAttrs[SUMO_TAG_CF_CACC] = CACCParams;1507allParams.insert(CACCParams.begin(), CACCParams.end());1508// CC1509std::set<SumoXMLAttr> ccParams(genericParams);1510ccParams.insert(SUMO_ATTR_CF_CC_C1);1511ccParams.insert(SUMO_ATTR_CF_CC_CCDECEL);1512ccParams.insert(SUMO_ATTR_CF_CC_CONSTSPACING);1513ccParams.insert(SUMO_ATTR_CF_CC_KP);1514ccParams.insert(SUMO_ATTR_CF_CC_LAMBDA);1515ccParams.insert(SUMO_ATTR_CF_CC_OMEGAN);1516ccParams.insert(SUMO_ATTR_CF_CC_TAU);1517ccParams.insert(SUMO_ATTR_CF_CC_XI);1518ccParams.insert(SUMO_ATTR_CF_CC_LANES_COUNT);1519ccParams.insert(SUMO_ATTR_CF_CC_CCACCEL);1520ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KP);1521ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KD);1522ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_H);1523ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KA);1524ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KV);1525ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KP);1526ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_D);1527ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_H);1528allowedCFModelAttrs[SUMO_TAG_CF_CC] = ccParams;1529allParams.insert(ccParams.begin(), ccParams.end());1530// last element1531allowedCFModelAttrs[SUMO_TAG_NOTHING] = allParams;1532}1533return allowedCFModelAttrs;1534}153515361537bool1538SUMOVehicleParserHelper::parseLCParams(SUMOVTypeParameter* into, LaneChangeModel model, const SUMOSAXAttributes& attrs) {1539if (allowedLCModelAttrs.size() == 0) {1540// lc20131541std::set<SumoXMLAttr> lc2013Params;1542lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_PARAM);1543lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_PARAM);1544lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_PARAM);1545lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_PARAM);1546lc2013Params.insert(SUMO_ATTR_LCA_OPPOSITE_PARAM);1547lc2013Params.insert(SUMO_ATTR_LCA_LOOKAHEADLEFT);1548lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAINRIGHT);1549lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING);1550lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR);1551lc2013Params.insert(SUMO_ATTR_LCA_MAXDISTLATSTANDING);1552lc2013Params.insert(SUMO_ATTR_LCA_ASSERTIVE);1553lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD);1554lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD);1555lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME);1556lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_URGENCY);1557lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT);1558lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_SPEED);1559lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_RIGHT);1560lc2013Params.insert(SUMO_ATTR_LCA_SIGMA);1561lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME);1562lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR);1563lc2013Params.insert(SUMO_ATTR_LCA_CONTRIGHT);1564lc2013Params.insert(SUMO_ATTR_LCA_EXPERIMENTAL1);1565allowedLCModelAttrs[LaneChangeModel::LC2013] = lc2013Params;1566// sl2015 (extension of lc2013)1567std::set<SumoXMLAttr> sl2015Params = lc2013Params;1568sl2015Params.insert(SUMO_ATTR_LCA_PUSHY);1569sl2015Params.insert(SUMO_ATTR_LCA_PUSHYGAP);1570sl2015Params.insert(SUMO_ATTR_LCA_SUBLANE_PARAM);1571sl2015Params.insert(SUMO_ATTR_LCA_IMPATIENCE);1572sl2015Params.insert(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE);1573sl2015Params.insert(SUMO_ATTR_LCA_ACCEL_LAT);1574sl2015Params.insert(SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE);1575sl2015Params.insert(SUMO_ATTR_LCA_LANE_DISCIPLINE);1576allowedLCModelAttrs[LaneChangeModel::SL2015] = sl2015Params;1577// DK20081578std::set<SumoXMLAttr> noParams;1579allowedLCModelAttrs[LaneChangeModel::DK2008] = noParams;1580// default model may be either LC2013 or SL20151581// we allow both sets (sl2015 is a superset of lc2013Params)1582allowedLCModelAttrs[LaneChangeModel::DEFAULT] = sl2015Params;1583}1584std::set<SumoXMLAttr> allowed = allowedLCModelAttrs[model];1585// iterate over LCM attributes1586for (const auto& it : allowed) {1587if (attrs.hasAttribute(it)) {1588// first obtain CFM attribute in string format1589bool ok = true;1590std::string parsedLCMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);1591if (!ok) {1592return false;1593}1594// declare a double in wich save CFM attribute1595double LCMAttribute = -1;1596try {1597// obtain CFM attribute in double format1598LCMAttribute = StringUtils::toDouble(parsedLCMAttribute);1599} catch (...) {1600WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Cannot be parsed to float"), toString(it));1601return false;1602}1603// check attributes of type "nonNegativeFloatType" (>= 0)1604switch (it) {1605case SUMO_ATTR_LCA_PUSHYGAP:1606case SUMO_ATTR_LCA_MAXSPEEDLATSTANDING:1607case SUMO_ATTR_LCA_IMPATIENCE:1608case SUMO_ATTR_LCA_OVERTAKE_RIGHT:1609case SUMO_ATTR_LCA_ASSERTIVE:1610case SUMO_ATTR_LCA_LOOKAHEADLEFT:1611case SUMO_ATTR_LCA_SPEEDGAINRIGHT:1612case SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE:1613case SUMO_ATTR_LCA_TIME_TO_IMPATIENCE:1614case SUMO_ATTR_LCA_LANE_DISCIPLINE:1615case SUMO_ATTR_LCA_SIGMA:1616if (LCMAttribute < 0) {1617WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be equal or greater than 0"), toString(it));1618return false;1619}1620break;1621default:1622break;1623}1624// check attributes of type "positiveFloatType" (> 0)1625switch (it) {1626case SUMO_ATTR_LCA_ACCEL_LAT:1627if (LCMAttribute <= 0) {1628WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be greater than 0"), toString(it));1629return false;1630}1631break;1632default:1633break;1634}1635// check limits of attributes1636switch (it) {1637case SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR:1638if (LCMAttribute < -1 || LCMAttribute > 1) {1639WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be between -1 and 1"), toString(it));1640return false;1641}1642break;1643default:1644break;1645}1646// add parsedLCMAttribute to cfParameter1647into->lcParameter[it] = parsedLCMAttribute;1648}1649}1650// all LCM parsed ok, then return true1651return true;1652}165316541655bool1656SUMOVehicleParserHelper::parseJMParams(SUMOVTypeParameter* into, const SUMOSAXAttributes& attrs) {1657for (const auto& it : SUMOVTypeParameter::AllowedJMAttrs) {1658if (attrs.hasAttribute(it)) {1659// first obtain CFM attribute in string format1660bool ok = true;1661std::string parsedJMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);1662if (!ok) {1663return false;1664}1665// declare a double in wich save CFM attribute1666double JMAttribute = INVALID_DOUBLE;1667try {1668// obtain CFM attribute in double format1669JMAttribute = StringUtils::toDouble(parsedJMAttribute);1670} catch (...) {1671WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Cannot be parsed to float"), toString(it));1672return false;1673}1674// now continue checking other properties (-1 is the default value)1675if (JMAttribute != INVALID_DOUBLE) {1676// special case for sigma minor1677if (it == SUMO_ATTR_JM_SIGMA_MINOR) {1678// check attributes sigma minor1679if ((JMAttribute < 0) || (JMAttribute > 1)) {1680WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Only values between [0-1] are allowed"), toString(it));1681return false;1682}1683} else if (JMAttribute < 01684&& it != SUMO_ATTR_JM_TIMEGAP_MINOR1685&& it != SUMO_ATTR_JM_EXTRA_GAP) {1686// attributes with error value1687if (JMAttribute != -1 || (it != SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME1688&& it != SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME1689&& it != SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME)) {1690// check attributes of type "nonNegativeFloatType" (>= 0)1691WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Must be equal or greater than 0"), toString(it));1692return false;1693}1694}1695// add parsedJMAttribute to cfParameter1696into->jmParameter[it] = parsedJMAttribute;1697}1698}1699}1700// all JM parameters successfully parsed, then return true1701return true;1702}170317041705SUMOVehicleClass1706SUMOVehicleParserHelper::parseVehicleClass(const SUMOSAXAttributes& attrs, const std::string& id) {1707SUMOVehicleClass vclass = SVC_IGNORING;1708bool ok = true;1709std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_VCLASS, id.c_str(), ok, "");1710if (vclassS == "") {1711return vclass;1712}1713try {1714const SUMOVehicleClass result = getVehicleClassID(vclassS);1715const std::string& realName = SumoVehicleClassStrings.getString(result);1716if (realName != vclassS) {1717WRITE_WARNING("The vehicle class '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");1718}1719return result;1720} catch (...) {1721WRITE_ERRORF(TL("The vehicle class '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);1722}1723return vclass;1724}172517261727SUMOVehicleShape1728SUMOVehicleParserHelper::parseGuiShape(const SUMOSAXAttributes& attrs, const std::string& id) {1729bool ok = true;1730std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_GUISHAPE, id.c_str(), ok, "");1731if (SumoVehicleShapeStrings.hasString(vclassS)) {1732const SUMOVehicleShape result = SumoVehicleShapeStrings.get(vclassS);1733const std::string& realName = SumoVehicleShapeStrings.getString(result);1734if (realName != vclassS) {1735WRITE_WARNING("The shape '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");1736}1737return result;1738} else {1739WRITE_ERRORF(TL("The shape '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);1740return SUMOVehicleShape::UNKNOWN;1741}1742}174317441745double1746SUMOVehicleParserHelper::parseWalkPos(SumoXMLAttr attr, const bool hardFail, const std::string& id, double maxPos, const std::string& val, SumoRNG* rng) {1747double result;1748std::string error;1749ArrivalPosDefinition proc = ArrivalPosDefinition::DEFAULT;1750// only supports 'random' and 'max'1751if (!SUMOVehicleParameter::parseArrivalPos(val, toString(SUMO_TAG_WALK), id, result, proc, error)) {1752handleVehicleError(hardFail, nullptr, error);1753}1754if (proc == ArrivalPosDefinition::RANDOM) {1755result = RandHelper::rand(maxPos, rng);1756} else if (proc == ArrivalPosDefinition::CENTER) {1757result = maxPos / 2.;1758} else if (proc == ArrivalPosDefinition::MAX) {1759result = maxPos;1760}1761return SUMOVehicleParameter::interpretEdgePos(result, maxPos, attr, id);1762}176317641765SUMOTime1766SUMOVehicleParserHelper::processActionStepLength(double given) {1767const std::string defaultError = "The parameter action-step-length must be a non-negative multiple of the simulation step-length. ";1768SUMOTime result = TIME2STEPS(given);1769if (result <= 0) {1770if (result < 0) {1771WRITE_WARNING(defaultError + "Ignoring given value (=" + toString(STEPS2TIME(result)) + " s.)");1772}1773result = DELTA_T;1774} else if (result % DELTA_T != 0 && OptionsCont::getOptions().exists("step-length")) {1775result = (SUMOTime)((double)DELTA_T * floor(double(result) / double(DELTA_T)));1776result = MAX2(DELTA_T, result);1777if (fabs(given * 1000. - double(result)) > NUMERICAL_EPS) {1778WRITE_WARNING(defaultError + "Parsing given value (" + toString(given) + " s.) to the adjusted value " + toString(STEPS2TIME(result)) + " s.");1779}1780}1781return result;1782}178317841785bool1786SUMOVehicleParserHelper::isInternalRouteID(const std::string& id) {1787return id.substr(0, 1) == "!";1788}178917901791bool1792SUMOVehicleParserHelper::validProfile(SUMOVTypeParameter* vtype, const std::string data, const SumoXMLAttr attr) {1793for (std::string value : StringTokenizer(data).getVector()) {1794try {1795double v = StringUtils::toDouble(value);1796if (v < 0.) {1797WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. An acceleration profile value cannot be negative"), toString(attr));1798return false;1799}1800} catch (...) {1801WRITE_ERRORF(TL("Entry '%' of % table for vType '%' cannot be parsed as 'double'"), value, toString(attr), vtype->id);1802return false;1803}1804}1805return true;1806}180718081809int1810SUMOVehicleParserHelper::parseCarWalkTransfer(const OptionsCont& oc, const bool hasTaxi) {1811int carWalk = 0;1812for (const std::string& opt : oc.getStringVector("persontrip.transfer.car-walk")) {1813if (opt == "parkingAreas") {1814carWalk |= ModeChangeOptions::PARKING_AREAS;1815} else if (opt == "ptStops") {1816carWalk |= ModeChangeOptions::PT_STOPS;1817} else if (opt == "allJunctions") {1818carWalk |= ModeChangeOptions::ALL_JUNCTIONS;1819} else {1820WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);1821}1822}1823const StringVector taxiDropoff = oc.getStringVector("persontrip.transfer.taxi-walk");1824const StringVector taxiPickup = oc.getStringVector("persontrip.transfer.walk-taxi");1825if (taxiDropoff.empty() && hasTaxi) {1826carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;1827} else {1828for (const std::string& opt : taxiDropoff) {1829if (opt == "parkingAreas") {1830carWalk |= ModeChangeOptions::TAXI_DROPOFF_PARKING_AREAS;1831} else if (opt == "ptStops") {1832carWalk |= ModeChangeOptions::TAXI_DROPOFF_PT;1833} else if (opt == "allJunctions") {1834carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;1835} else {1836WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);1837}1838}1839}1840if (taxiPickup.empty() && hasTaxi) {1841carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;1842} else {1843for (const std::string& opt : taxiPickup) {1844if (opt == "parkingAreas") {1845carWalk |= ModeChangeOptions::TAXI_PICKUP_PARKING_AREAS;1846} else if (opt == "ptStops") {1847carWalk |= ModeChangeOptions::TAXI_PICKUP_PT;1848} else if (opt == "allJunctions") {1849carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;1850} else {1851WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);1852}1853}1854}1855return carWalk;1856}185718581859SUMOVehicleParameter*1860SUMOVehicleParserHelper::handleVehicleError(const bool hardFail, SUMOVehicleParameter* vehicleParameter, const std::string message) {1861if (vehicleParameter) {1862delete vehicleParameter;1863}1864if (hardFail) {1865throw ProcessError(message);1866} else if (message.size() > 0) {1867WRITE_ERROR(message);1868}1869return nullptr;1870}187118721873SUMOVTypeParameter*1874SUMOVehicleParserHelper::handleVehicleTypeError(const bool hardFail, SUMOVTypeParameter* vehicleTypeParameter, const std::string message) {1875if (vehicleTypeParameter) {1876delete vehicleTypeParameter;1877}1878if (hardFail) {1879throw ProcessError(message);1880} else if (message.size() > 0) {1881WRITE_ERROR(message);1882}1883return nullptr;1884}18851886/****************************************************************************/188718881889