Path: blob/main/src/utils/vehicle/SUMOVehicleParameter.cpp
169678 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-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 SUMOVehicleParameter.cpp14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Michael Behrisch17/// @date Tue, 31.03.200918///19// Structure representing possible vehicle parameter20/****************************************************************************/21#include <config.h>22#include <utils/common/MsgHandler.h>23#include <utils/common/StringTokenizer.h>24#include <utils/common/StringUtils.h>25#include <utils/common/ToString.h>26#include <utils/common/RandHelper.h>27#include <utils/iodevices/OutputDevice.h>28#include <utils/options/OptionsCont.h>2930#include "SUMOVehicleParameter.h"3132// ===========================================================================33// member method definitions34// ===========================================================================3536SUMOVehicleParameter::SUMOVehicleParameter()37: tag(SUMO_TAG_NOTHING), vtypeid(DEFAULT_VTYPE_ID), color(RGBColor::DEFAULT_COLOR),38depart(-1), departProcedure(DepartDefinition::GIVEN),39departLane(0), departLaneProcedure(DepartLaneDefinition::DEFAULT),40departPos(0), departPosProcedure(DepartPosDefinition::DEFAULT),41departPosLat(0), departPosLatProcedure(DepartPosLatDefinition::DEFAULT),42departSpeed(-1), departSpeedProcedure(DepartSpeedDefinition::DEFAULT),43departEdge(0), departEdgeProcedure(RouteIndexDefinition::DEFAULT),44arrivalLane(0), arrivalLaneProcedure(ArrivalLaneDefinition::DEFAULT),45arrivalPos(0), arrivalPosProcedure(ArrivalPosDefinition::DEFAULT),46arrivalPosLat(0), arrivalPosLatProcedure(ArrivalPosLatDefinition::DEFAULT),47arrivalSpeed(-1), arrivalSpeedProcedure(ArrivalSpeedDefinition::DEFAULT),48arrivalEdge(-1), arrivalEdgeProcedure(RouteIndexDefinition::DEFAULT),49repetitionNumber(-1),50repetitionsDone(-1),51repetitionOffset(-1),52repetitionTotalOffset(0),53repetitionProbability(-1),54poissonRate(0),55repetitionEnd(-1),56line(), fromTaz(), toTaz(), personNumber(0), containerNumber(0),57speedFactor(-1),58calibratorSpeed(-1),59insertionChecks((int)InsertionCheck::ALL),60parametersSet(0)61{ }626364SUMOVehicleParameter::~SUMOVehicleParameter() {65}666768bool69SUMOVehicleParameter::defaultOptionOverrides(const OptionsCont& oc, const std::string& optionName) const {70return oc.exists(optionName) && oc.isSet(optionName) && oc.getBool("defaults-override");71}727374void75SUMOVehicleParameter::write(OutputDevice& dev, const OptionsCont& oc, const SumoXMLTag altTag, const std::string& typeID) const {76if (!id.empty()) {77// only used by calibrator flows78dev.openTag(altTag).writeAttr(SUMO_ATTR_ID, id);79}80if (typeID == "") {81if (wasSet(VEHPARS_VTYPE_SET)) {82dev.writeAttr(SUMO_ATTR_TYPE, vtypeid);83}84} else {85dev.writeAttr(SUMO_ATTR_TYPE, typeID);86}87// write depart depending of tag88if (altTag == SUMO_TAG_FLOW89|| altTag == SUMO_TAG_PERSONFLOW90|| altTag == SUMO_TAG_CONTAINERFLOW91|| altTag == GNE_TAG_FLOW_ROUTE92|| altTag == GNE_TAG_FLOW_WITHROUTE93|| altTag == SUMO_TAG_FLOWSTATE) {94dev.writeAttr(SUMO_ATTR_BEGIN, getDepart());95} else {96dev.writeAttr(SUMO_ATTR_DEPART, getDepart());97}98// optional parameter99// departlane100if (wasSet(VEHPARS_DEPARTLANE_SET) && !defaultOptionOverrides(oc, "departlane")) {101dev.writeNonEmptyAttr(SUMO_ATTR_DEPARTLANE, getDepartLane());102} else if (oc.exists("departlane") && oc.isSet("departlane")) {103dev.writeNonEmptyAttr(SUMO_ATTR_DEPARTLANE, oc.getString("departlane"));104}105// departpos106if (wasSet(VEHPARS_DEPARTPOS_SET) && !defaultOptionOverrides(oc, "departpos")) {107dev.writeNonEmptyAttr(SUMO_ATTR_DEPARTPOS, getDepartPos());108} else if (oc.exists("departpos") && oc.isSet("departpos")) {109dev.writeNonEmptyAttr(SUMO_ATTR_DEPARTPOS, oc.getString("departpos"));110}111// departPosLat112if (wasSet(VEHPARS_DEPARTPOSLAT_SET)) {113dev.writeNonEmptyAttr(SUMO_ATTR_DEPARTPOS_LAT, getDepartPosLat());114}115// departspeed116if (wasSet(VEHPARS_DEPARTSPEED_SET) && !defaultOptionOverrides(oc, "departspeed")) {117dev.writeNonEmptyAttr(SUMO_ATTR_DEPARTSPEED, getDepartSpeed());118} else if (oc.exists("departspeed") && oc.isSet("departspeed")) {119dev.writeNonEmptyAttr(SUMO_ATTR_DEPARTSPEED, oc.getString("departspeed"));120}121// departedge122if (wasSet(VEHPARS_DEPARTEDGE_SET) && !defaultOptionOverrides(oc, "departedge")) {123dev.writeNonEmptyAttr(SUMO_ATTR_DEPARTEDGE, getDepartEdge());124} else if (oc.exists("departedge") && oc.isSet("departedge")) {125dev.writeNonEmptyAttr(SUMO_ATTR_DEPARTEDGE, oc.getString("departedge"));126}127// arrivallane128if (wasSet(VEHPARS_ARRIVALLANE_SET) && !defaultOptionOverrides(oc, "arrivallane")) {129dev.writeNonEmptyAttr(SUMO_ATTR_ARRIVALLANE, getArrivalLane());130} else if (oc.exists("arrivallane") && oc.isSet("arrivallane")) {131dev.writeNonEmptyAttr(SUMO_ATTR_ARRIVALLANE, oc.getString("arrivallane"));132}133// arrivalpos134if (wasSet(VEHPARS_ARRIVALPOS_SET) && !defaultOptionOverrides(oc, "arrivalpos")) {135dev.writeNonEmptyAttr(SUMO_ATTR_ARRIVALPOS, getArrivalPos());136} else if (oc.exists("arrivalpos") && oc.isSet("arrivalpos")) {137dev.writeNonEmptyAttr(SUMO_ATTR_ARRIVALPOS, oc.getString("arrivalpos"));138}139// arrivalPosLat140if (wasSet(VEHPARS_ARRIVALPOSLAT_SET)) {141dev.writeNonEmptyAttr(SUMO_ATTR_ARRIVALPOS_LAT, getArrivalPosLat());142}143// arrivalspeed144if (wasSet(VEHPARS_ARRIVALSPEED_SET) && !defaultOptionOverrides(oc, "arrivalspeed")) {145dev.writeNonEmptyAttr(SUMO_ATTR_ARRIVALSPEED, getArrivalSpeed());146} else if (oc.exists("arrivalspeed") && oc.isSet("arrivalspeed")) {147dev.writeNonEmptyAttr(SUMO_ATTR_ARRIVALSPEED, oc.getString("arrivalspeed"));148}149// arrivalEdge150if (wasSet(VEHPARS_ARRIVALEDGE_SET) && !defaultOptionOverrides(oc, "arrivaledge") && arrivalEdge >= 0) {151dev.writeNonEmptyAttr(SUMO_ATTR_ARRIVALEDGE, getArrivalEdge());152} else if (oc.exists("arrivaledge") && oc.isSet("arrivaledge")) {153dev.writeNonEmptyAttr(SUMO_ATTR_ARRIVALEDGE, oc.getString("arrivaledge"));154}155// color156if (wasSet(VEHPARS_COLOR_SET)) {157dev.writeAttr(SUMO_ATTR_COLOR, color);158}159// line160if (wasSet(VEHPARS_LINE_SET)) {161dev.writeAttr(SUMO_ATTR_LINE, line);162}163// from TAZ164if (wasSet(VEHPARS_FROM_TAZ_SET)) {165dev.writeAttr(SUMO_ATTR_FROM_TAZ, fromTaz);166}167// to TAZ168if (wasSet(VEHPARS_TO_TAZ_SET)) {169dev.writeAttr(SUMO_ATTR_TO_TAZ, toTaz);170}171// person number172if (wasSet(VEHPARS_PERSON_NUMBER_SET)) {173dev.writeAttr(SUMO_ATTR_PERSON_NUMBER, personNumber);174}175// container number176if (wasSet(VEHPARS_CONTAINER_NUMBER_SET)) {177dev.writeAttr(SUMO_ATTR_CONTAINER_NUMBER, containerNumber);178}179// individual speedFactor180if (wasSet(VEHPARS_SPEEDFACTOR_SET)) {181// might be saving state with custom precision182const int precision = dev.getPrecision();183dev.setPrecision(MAX2(gPrecisionRandom, precision));184dev.writeAttr(SUMO_ATTR_SPEEDFACTOR, speedFactor);185dev.setPrecision(precision);186}187// speed (only used by calibrators)188if (wasSet(VEHPARS_CALIBRATORSPEED_SET)) {189dev.writeAttr(SUMO_ATTR_SPEED, calibratorSpeed);190}191// insertionChecks192if (wasSet(VEHPARS_INSERTION_CHECKS_SET) && insertionChecks != (int)InsertionCheck::ALL) {193std::vector<std::string> checks;194if (insertionChecks == (int)InsertionCheck::NONE) {195checks.push_back(toString(InsertionCheck::NONE));196} else {197for (auto it : SUMOXMLDefinitions::InsertionChecks.getValues()) {198if (((int)it & insertionChecks) != 0) {199checks.push_back(toString(it));200}201}202}203dev.writeAttr(SUMO_ATTR_INSERTIONCHECKS, checks);204}205// parking access rights206if (wasSet(VEHPARS_PARKING_BADGES_SET)) {207dev.writeNonEmptyAttr(SUMO_ATTR_PARKING_BADGES, joinToString(parkingBadges, " "));208}209}210211212void213SUMOVehicleParameter::Stop::write(OutputDevice& dev, const bool close, const bool writeTagAndParents) const {214if (writeTagAndParents) {215dev.openTag(SUMO_TAG_STOP);216if (busstop != "") {217dev.writeAttr(SUMO_ATTR_BUS_STOP, busstop);218}219if (containerstop != "") {220dev.writeAttr(SUMO_ATTR_CONTAINER_STOP, containerstop);221}222if (chargingStation != "") {223dev.writeAttr(SUMO_ATTR_CHARGING_STATION, chargingStation);224}225if (parkingarea != "") {226dev.writeAttr(SUMO_ATTR_PARKING_AREA, parkingarea);227}228if ((busstop == "") && (containerstop == "") && (parkingarea == "") && (chargingStation == "")) {229if (lane != "") {230dev.writeAttr(SUMO_ATTR_LANE, lane);231} else {232dev.writeAttr(SUMO_ATTR_EDGE, edge);233}234if ((parametersSet & STOP_START_SET) != 0) {235dev.writeAttr(SUMO_ATTR_STARTPOS, startPos);236}237if ((parametersSet & STOP_END_SET) != 0) {238dev.writeAttr(SUMO_ATTR_ENDPOS, endPos);239}240}241}242if (index > 0) {243dev.writeAttr(SUMO_ATTR_INDEX, index);244}245if ((parametersSet & STOP_POSLAT_SET) != 0 && posLat != INVALID_DOUBLE) {246dev.writeAttr(SUMO_ATTR_POSITION_LAT, posLat);247}248if ((parametersSet & STOP_ARRIVAL_SET) && (arrival >= 0)) {249dev.writeAttr(SUMO_ATTR_ARRIVAL, time2string(arrival));250}251if ((parametersSet & STOP_DURATION_SET) && (duration >= 0)) {252dev.writeAttr(SUMO_ATTR_DURATION, time2string(duration));253}254if ((parametersSet & STOP_UNTIL_SET) && (until >= 0)) {255dev.writeAttr(SUMO_ATTR_UNTIL, time2string(until));256}257if ((parametersSet & STOP_STARTED_SET) && (started >= 0)) {258dev.writeAttr(SUMO_ATTR_STARTED, time2string(started));259}260if ((parametersSet & STOP_ENDED_SET) && (ended >= 0)) {261dev.writeAttr(SUMO_ATTR_ENDED, time2string(ended));262}263if ((parametersSet & STOP_EXTENSION_SET) && (extension >= 0)) {264dev.writeAttr(SUMO_ATTR_EXTENSION, time2string(extension));265}266if ((parametersSet & STOP_TRIGGER_SET) != 0) {267const std::vector<std::string> triggers = getTriggers();268if (triggers.size() > 0) {269dev.writeAttr(SUMO_ATTR_TRIGGERED, triggers);270}271}272if ((parametersSet & STOP_PARKING_SET) != 0) {273dev.writeAttr(SUMO_ATTR_PARKING, parking);274}275if ((parametersSet & STOP_EXPECTED_SET) != 0 && awaitedPersons.size() > 0) {276dev.writeAttr(SUMO_ATTR_EXPECTED, awaitedPersons);277}278if ((parametersSet & STOP_PERMITTED_SET) != 0 && permitted.size() > 0) {279dev.writeAttr(SUMO_ATTR_PERMITTED, permitted);280}281if ((parametersSet & STOP_EXPECTED_CONTAINERS_SET) != 0 && awaitedContainers.size() > 0) {282dev.writeAttr(SUMO_ATTR_EXPECTED_CONTAINERS, awaitedContainers);283}284if ((parametersSet & STOP_TRIP_ID_SET) != 0) {285dev.writeAttr(SUMO_ATTR_TRIP_ID, tripId);286}287if ((parametersSet & STOP_LINE_SET) != 0) {288dev.writeAttr(SUMO_ATTR_LINE, line);289}290if ((parametersSet & STOP_SPLIT_SET) != 0) {291dev.writeAttr(SUMO_ATTR_SPLIT, split);292}293if ((parametersSet & STOP_JOIN_SET) != 0) {294dev.writeAttr(SUMO_ATTR_JOIN, join);295}296if ((parametersSet & STOP_SPEED_SET) != 0) {297dev.writeAttr(SUMO_ATTR_SPEED, speed);298}299if ((parametersSet & STOP_ONDEMAND_SET) != 0) {300dev.writeAttr(SUMO_ATTR_ONDEMAND, onDemand);301}302if ((parametersSet & STOP_JUMP_SET) != 0 && jump >= 0) {303dev.writeAttr(SUMO_ATTR_JUMP, time2string(jump));304}305if ((parametersSet & STOP_JUMP_UNTIL_SET) != 0 && jumpUntil >= 0) {306dev.writeAttr(SUMO_ATTR_JUMP_UNTIL, time2string(jumpUntil));307}308if ((parametersSet & STOP_PRIORITY_SET) != 0 && priority >= 0) {309dev.writeAttr(SUMO_ATTR_PRIORITY, priority);310}311if (collision) {312dev.writeAttr(SUMO_ATTR_COLLISION, collision);313}314// only write friendly position if is true315if (friendlyPos) {316dev.writeAttr(SUMO_ATTR_FRIENDLY_POS, friendlyPos);317}318// only write act type if isn't empty319if (!actType.empty()) {320dev.writeAttr(SUMO_ATTR_ACTTYPE, actType);321}322if (close) {323// the user is closing the stop it is responsible for writing params324writeParams(dev);325dev.closeTag();326}327}328329std::vector<std::string>330SUMOVehicleParameter::Stop::getStoppingPlaceIDs() const {331std::vector<std::string> result;332if (busstop != "") {333result.push_back(busstop);334}335if (containerstop != "") {336result.push_back(containerstop);337}338if (chargingStation != "") {339result.push_back(chargingStation);340}341if (parkingarea != "") {342result.push_back(parkingarea);343}344return result;345}346347bool348SUMOVehicleParameter::parseDepart(const std::string& val, const std::string& element, const std::string& id,349SUMOTime& depart, DepartDefinition& dd, std::string& error, const std::string& attr) {350if (val == "triggered") {351dd = DepartDefinition::TRIGGERED;352} else if (val == "containerTriggered") {353dd = DepartDefinition::CONTAINER_TRIGGERED;354} else if (val == "now") {355// only used via TraCI. depart must be set by the calling code356dd = DepartDefinition::NOW;357} else if (val == "split") {358dd = DepartDefinition::SPLIT;359} else if (val == "begin") {360dd = DepartDefinition::BEGIN;361} else {362try {363depart = string2time(val);364dd = DepartDefinition::GIVEN;365if (depart < 0) {366error = "Negative " + attr + " time in the definition of " + element + " '" + id + "'.";367return false;368}369} catch (...) {370if (id.empty()) {371error = "Invalid " + attr + " time for " + element + ". Must be one of (\"triggered\", \"containerTriggered\", \"now\", or a float >= 0)";372} else {373error = "Invalid " + attr + " time for " + element + " '" + id + "';\n must be one of (\"triggered\", \"containerTriggered\", \"now\", or a float >= 0)";374}375return false;376}377}378return true;379}380381382bool383SUMOVehicleParameter::parseDepartLane(const std::string& val, const std::string& element, const std::string& id,384int& lane, DepartLaneDefinition& dld, std::string& error) {385bool ok = true;386lane = 0;387dld = DepartLaneDefinition::GIVEN;388if (val == "random") {389dld = DepartLaneDefinition::RANDOM;390} else if (val == "free") {391dld = DepartLaneDefinition::FREE;392} else if (val == "allowed") {393dld = DepartLaneDefinition::ALLOWED_FREE;394} else if (val == "best") {395dld = DepartLaneDefinition::BEST_FREE;396} else if (val == "best_prob") {397dld = DepartLaneDefinition::BEST_PROB;398} else if (val == "first") {399dld = DepartLaneDefinition::FIRST_ALLOWED;400} else {401try {402lane = StringUtils::toInt(val);403if (lane < 0) {404ok = false;405}406} catch (...) {407ok = false;408}409}410if (!ok) {411if (id.empty()) {412error = "Invalid departLane definition for " + element + ". Must be one of (\"random\", \"free\", \"allowed\", \"best\", \"best_prob\", \"first\", or an int>=0)";413} else {414error = "Invalid departLane definition for " + element + " '" + id + "';\n must be one of (\"random\", \"free\", \"allowed\", \"best\", \"best_prob\", \"first\", or an int>=0)";415}416}417return ok;418}419420421bool422SUMOVehicleParameter::parseDepartPos(const std::string& val, const std::string& element, const std::string& id,423double& pos, DepartPosDefinition& dpd, std::string& error) {424bool ok = true;425pos = 0.;426dpd = DepartPosDefinition::GIVEN;427if (val == "random") {428dpd = DepartPosDefinition::RANDOM;429} else if (val == "random_free") {430dpd = DepartPosDefinition::RANDOM_FREE;431} else if (val == "random_location") {432dpd = DepartPosDefinition::RANDOM_LOCATION;433} else if (val == "free") {434dpd = DepartPosDefinition::FREE;435} else if (val == "base") {436dpd = DepartPosDefinition::BASE;437} else if (val == "last") {438dpd = DepartPosDefinition::LAST;439} else if (val == "splitFront") {440dpd = DepartPosDefinition::SPLIT_FRONT;441} else if (val == "stop") {442dpd = DepartPosDefinition::STOP;443} else {444try {445pos = StringUtils::toDouble(val);446} catch (...) {447ok = false;448}449}450if (!ok) {451if (id.empty()) {452error = "Invalid departPos definition for " + element + ". Must be one of (\"random\", \"random_free\", \"free\", \"base\", \"last\" or a float)";453} else {454error = "Invalid departPos definition for " + element + " '" + id + "';\n must be one of (\"random\", \"random_free\", \"free\", \"base\", \"last\" or a float)";455}456}457return ok;458}459460461bool462SUMOVehicleParameter::parseDepartPosLat(const std::string& val, const std::string& element, const std::string& id,463double& pos, DepartPosLatDefinition& dpd, std::string& error) {464bool ok = true;465pos = 0.;466dpd = DepartPosLatDefinition::GIVEN;467if (val == "random") {468dpd = DepartPosLatDefinition::RANDOM;469} else if (val == "random_free") {470dpd = DepartPosLatDefinition::RANDOM_FREE;471} else if (val == "free") {472dpd = DepartPosLatDefinition::FREE;473} else if (val == "right") {474dpd = DepartPosLatDefinition::RIGHT;475} else if (val == "center") {476dpd = DepartPosLatDefinition::CENTER;477} else if (val == "left") {478dpd = DepartPosLatDefinition::LEFT;479} else {480try {481pos = StringUtils::toDouble(val);482} catch (...) {483ok = false;484}485}486if (!ok) {487if (id.empty()) {488error = "Invalid departPosLat definition for " + element + ". Must be one of (\"random\", \"random_free\", \"free\", \"right\", \"center\", \"left\", or a float)";489} else {490error = "Invalid departPosLat definition for " + element + " '" + id + "';\n must be one of (\"random\", \"random_free\", \"free\", \"right\", \"center\", \"left\", or a float)";491}492}493return ok;494}495496497bool498SUMOVehicleParameter::parseDepartSpeed(const std::string& val, const std::string& element, const std::string& id,499double& speed, DepartSpeedDefinition& dsd, std::string& error) {500bool ok = true;501speed = -1.;502dsd = DepartSpeedDefinition::GIVEN;503if (val == "random") {504dsd = DepartSpeedDefinition::RANDOM;505} else if (val == "max") {506dsd = DepartSpeedDefinition::MAX;507} else if (val == "desired") {508dsd = DepartSpeedDefinition::DESIRED;509} else if (val == "speedLimit") {510dsd = DepartSpeedDefinition::LIMIT;511} else if (val == "last") {512dsd = DepartSpeedDefinition::LAST;513} else if (val == "avg") {514dsd = DepartSpeedDefinition::AVG;515} else {516try {517speed = StringUtils::toDouble(val);518if (speed < 0) {519ok = false;520}521} catch (...) {522ok = false;523}524}525if (!ok) {526if (id.empty()) {527error = "Invalid departSpeed definition for " + element + ". Must be one of (\"random\", \"max\", or a float>=0)";528} else {529error = "Invalid departSpeed definition for " + element + " '" + id + "';\n must be one of (\"random\", \"max\", or a float>=0)";530}531}532return ok;533}534535536bool537SUMOVehicleParameter::parseRouteIndex(const std::string& val, const std::string& element, const std::string& id,538const SumoXMLAttr attr, int& edgeIndex, RouteIndexDefinition& rid, std::string& error) {539bool ok = true;540edgeIndex = -1;541rid = RouteIndexDefinition::GIVEN;542if (val == "random") {543rid = RouteIndexDefinition::RANDOM;544} else {545try {546edgeIndex = StringUtils::toInt(val);547if (edgeIndex < 0) {548ok = false;549}550} catch (...) {551ok = false;552}553}554if (!ok) {555if (id.empty()) {556error = "Invalid " + toString(attr) + " definition for " + element + ". Must be one of (\"random\", \"free\", or an int>=0)";557} else {558error = "Invalid " + toString(attr) + " definition for " + element + " '" + id + "';\n must be one of (\"random\", \"free\", or an int>=0)";559}560}561return ok;562}563564565bool566SUMOVehicleParameter::parseArrivalLane(const std::string& val, const std::string& element, const std::string& id,567int& lane, ArrivalLaneDefinition& ald, std::string& error) {568bool ok = true;569lane = 0;570ald = ArrivalLaneDefinition::GIVEN;571if (val == "current") {572ald = ArrivalLaneDefinition::CURRENT;573} else if (val == "random") {574ald = ArrivalLaneDefinition::RANDOM;575} else if (val == "first") {576ald = ArrivalLaneDefinition::FIRST_ALLOWED;577} else {578try {579lane = StringUtils::toInt(val);580if (lane < 0) {581ok = false;582}583} catch (...) {584ok = false;585}586}587if (!ok) {588if (id.empty()) {589error = "Invalid arrivalLane definition for " + element + ". Must be one of (\"current\", or an int>=0)";590} else {591error = "Invalid arrivalLane definition for " + element + " '" + id + "';\n must be one of (\"current\", or an int>=0)";592}593}594return ok;595}596597598bool599SUMOVehicleParameter::parseArrivalPos(const std::string& val, const std::string& element, const std::string& id,600double& pos, ArrivalPosDefinition& apd, std::string& error) {601bool ok = true;602pos = 0.;603apd = ArrivalPosDefinition::GIVEN;604if (val == "random") {605apd = ArrivalPosDefinition::RANDOM;606} else if (val == "center") {607apd = ArrivalPosDefinition::CENTER;608} else if (val == "max") {609apd = ArrivalPosDefinition::MAX;610} else {611try {612pos = StringUtils::toDouble(val);613} catch (...) {614ok = false;615}616}617if (!ok) {618if (id.empty()) {619error = "Invalid arrivalPos definition for " + element + ". Must be one of (\"random\", \"max\", or a float)";620} else {621error = "Invalid arrivalPos definition for " + element + " '" + id + "';\n must be one of (\"random\", \"max\", or a float)";622}623}624return ok;625}626627628bool629SUMOVehicleParameter::parseArrivalPosLat(const std::string& val, const std::string& element, const std::string& id,630double& pos, ArrivalPosLatDefinition& apd, std::string& error) {631bool ok = true;632pos = 0.;633apd = ArrivalPosLatDefinition::GIVEN;634if (val == "right") {635apd = ArrivalPosLatDefinition::RIGHT;636} else if (val == "center") {637apd = ArrivalPosLatDefinition::CENTER;638} else if (val == "left") {639apd = ArrivalPosLatDefinition::LEFT;640} else {641try {642pos = StringUtils::toDouble(val);643} catch (...) {644ok = false;645}646}647if (!ok) {648if (id.empty()) {649error = "Invalid arrivalPosLat definition for " + element + ". Must be one of (\"right\", \"center\", \"left\", or a float)";650} else {651error = "Invalid arrivalPosLat definition for " + element + " '" + id + "';\n must be one of (\"right\", \"center\", \"left\", or a float)";652}653}654return ok;655}656657658bool659SUMOVehicleParameter::parseArrivalSpeed(const std::string& val, const std::string& element, const std::string& id,660double& speed, ArrivalSpeedDefinition& asd, std::string& error) {661bool ok = true;662speed = -1.;663asd = ArrivalSpeedDefinition::GIVEN;664if (val == "current") {665asd = ArrivalSpeedDefinition::CURRENT;666} else {667try {668speed = StringUtils::toDouble(val);669if (speed < 0) {670ok = false;671}672} catch (...) {673ok = false;674}675}676if (!ok) {677if (id.empty()) {678error = "Invalid arrivalSpeed definition for " + element + ". Must be one of (\"current\", or a float>=0)";679} else {680error = "Invalid arrivalSpeed definition for " + element + " '" + id + "';\n must be one of (\"current\", or a float>=0)";681}682}683return ok;684}685686687double688SUMOVehicleParameter::interpretEdgePos(double pos, double maximumValue, SumoXMLAttr attr, const std::string& id, bool silent) {689if (pos < 0) {690pos = maximumValue + pos;691}692if (pos > maximumValue && pos != std::numeric_limits<double>::infinity()) {693if (!silent) {694WRITE_WARNINGF(TL("Invalid % % given for %. Using edge end instead."), toString(attr), toString(pos), id);695}696pos = maximumValue;697}698return pos;699}700701702bool703SUMOVehicleParameter::parsePersonModes(const std::string& modes, const std::string& element, const std::string& id, SVCPermissions& modeSet, std::string& error) {704// separte modes in different strings, and check if modes are valid705for (StringTokenizer st(modes); st.hasNext();) {706const std::string mode = st.next();707if (mode == "car") {708modeSet |= SVC_PASSENGER;709} else if (mode == "taxi") {710modeSet |= SVC_TAXI;711} else if (mode == "bicycle") {712modeSet |= SVC_BICYCLE;713} else if (mode == "public") {714modeSet |= SVC_BUS;715} else {716if (id.empty()) {717error = "Unknown person mode '" + mode + "'. Must be a combination of (\"car\", \"taxi\", \"bicycle\" or \"public\")";718} else {719error = "Unknown person mode '" + mode + "' for " + element + " '" + id + "';\n must be a combination of (\"car\", \"taxi\", \"bicycle\" or \"public\")";720}721return false;722}723}724return true;725}726727728void729SUMOVehicleParameter::parseStopTriggers(const std::vector<std::string>& triggers, bool expectTrigger, Stop& stop) {730if (triggers.size() == 0 && expectTrigger) {731stop.triggered = true;732}733for (std::string val : triggers) {734if (val == toString(SUMO_TAG_PERSON)) {735stop.triggered = true;736} else if (val == toString(SUMO_TAG_CONTAINER)) {737stop.containerTriggered = true;738} else if (val == toString(SUMO_ATTR_JOIN)) {739stop.joinTriggered = true;740} else {741try {742stop.triggered = StringUtils::toBool(val);743} catch (BoolFormatException&) {744WRITE_ERROR(TL("Value of stop attribute 'trigger' must be 'person', 'container', 'join' or a boolean"));745}746}747}748}749750751ParkingType752SUMOVehicleParameter::parseParkingType(const std::string& value) {753if (value == toString(ParkingType::OPPORTUNISTIC)) {754return ParkingType::OPPORTUNISTIC;755} else {756return StringUtils::toBool(value) ? ParkingType::OFFROAD : ParkingType::ONROAD;757}758}759760761std::vector<std::string>762SUMOVehicleParameter::Stop::getTriggers() const {763std::vector<std::string> triggers;764if (triggered) {765triggers.push_back(toString(SUMO_TAG_PERSON));766}767if (containerTriggered) {768triggers.push_back(toString(SUMO_TAG_CONTAINER));769}770if (joinTriggered) {771triggers.push_back(toString(SUMO_ATTR_JOIN));772}773return triggers;774}775776int777SUMOVehicleParameter::Stop::getFlags() const {778return (((parking == ParkingType::OFFROAD) ? 1 : 0) +779(triggered ? 2 : 0) +780(containerTriggered ? 4 : 0) +781(busstop != "" ? 8 : 0) +782(containerstop != "" ? 16 : 0) +783(chargingStation != "" ? 32 : 0) +784(parkingarea != "" ? 64 : 0) +785(overheadWireSegment != "" ? 128 : 0));786}787788789std::string790SUMOVehicleParameter::getDepart() const {791if (departProcedure == DepartDefinition::TRIGGERED) {792return "triggered";793} else if (departProcedure == DepartDefinition::CONTAINER_TRIGGERED) {794return "containerTriggered";795// } else if (departProcedure == DepartDefinition::NOW) { // TODO check whether this is useful in XML input (currently TraCI only)796// return "now";797} else if (departProcedure == DepartDefinition::SPLIT) {798return "split";799} else if (departProcedure == DepartDefinition::BEGIN) {800return "begin";801} else {802return time2string(depart);803}804}805806807std::string808SUMOVehicleParameter::getDepartLane() const {809std::string val;810switch (departLaneProcedure) {811case DepartLaneDefinition::GIVEN:812val = toString(departLane);813break;814case DepartLaneDefinition::RANDOM:815val = "random";816break;817case DepartLaneDefinition::FREE:818val = "free";819break;820case DepartLaneDefinition::ALLOWED_FREE:821val = "allowed";822break;823case DepartLaneDefinition::BEST_FREE:824val = "best";825break;826case DepartLaneDefinition::BEST_PROB:827val = "best_prob";828break;829case DepartLaneDefinition::FIRST_ALLOWED:830val = "first";831break;832case DepartLaneDefinition::DEFAULT:833default:834break;835}836return val;837}838839840std::string841SUMOVehicleParameter::getDepartPos() const {842std::string val;843switch (departPosProcedure) {844case DepartPosDefinition::GIVEN:845val = toString(departPos);846break;847case DepartPosDefinition::GIVEN_VEHROUTE:848val = StringUtils::pruneZeros(toString(departPos, MAX2(gPrecisionRandom, gPrecision)), 2);849break;850case DepartPosDefinition::RANDOM:851val = "random";852break;853case DepartPosDefinition::RANDOM_FREE:854val = "random_free";855break;856case DepartPosDefinition::RANDOM_LOCATION:857val = "random_location";858break;859case DepartPosDefinition::FREE:860val = "free";861break;862case DepartPosDefinition::LAST:863val = "last";864break;865case DepartPosDefinition::BASE:866val = "base";867break;868case DepartPosDefinition::SPLIT_FRONT:869val = "splitFront";870break;871case DepartPosDefinition::STOP:872val = "stop";873break;874case DepartPosDefinition::DEFAULT:875default:876break;877}878return val;879}880881882std::string883SUMOVehicleParameter::getDepartPosLat() const {884std::string val;885switch (departPosLatProcedure) {886case DepartPosLatDefinition::GIVEN:887val = toString(departPosLat);888break;889case DepartPosLatDefinition::GIVEN_VEHROUTE:890val = StringUtils::pruneZeros(toString(departPosLat, MAX2(gPrecisionRandom, gPrecision)), 2);891break;892case DepartPosLatDefinition::RANDOM:893val = "random";894break;895case DepartPosLatDefinition::RANDOM_FREE:896val = "random_free";897break;898case DepartPosLatDefinition::FREE:899val = "free";900break;901case DepartPosLatDefinition::RIGHT:902val = "right";903break;904case DepartPosLatDefinition::CENTER:905val = "center";906break;907case DepartPosLatDefinition::LEFT:908val = "left";909break;910case DepartPosLatDefinition::DEFAULT:911default:912break;913}914return val;915}916917918std::string919SUMOVehicleParameter::getDepartSpeed() const {920std::string val;921switch (departSpeedProcedure) {922case DepartSpeedDefinition::GIVEN:923val = toString(departSpeed);924break;925case DepartSpeedDefinition::GIVEN_VEHROUTE:926val = StringUtils::pruneZeros(toString(departSpeed, MAX2(gPrecisionRandom, gPrecision)), 2);927break;928case DepartSpeedDefinition::RANDOM:929val = "random";930break;931case DepartSpeedDefinition::MAX:932val = "max";933break;934case DepartSpeedDefinition::DESIRED:935val = "desired";936break;937case DepartSpeedDefinition::LIMIT:938val = "speedLimit";939break;940case DepartSpeedDefinition::LAST:941val = "last";942break;943case DepartSpeedDefinition::AVG:944val = "avg";945break;946case DepartSpeedDefinition::DEFAULT:947default:948break;949}950return val;951}952953954std::string955SUMOVehicleParameter::getDepartEdge() const {956std::string val;957switch (departEdgeProcedure) {958case RouteIndexDefinition::GIVEN:959val = toString(departEdge);960break;961case RouteIndexDefinition::RANDOM:962val = "random";963break;964case RouteIndexDefinition::DEFAULT:965default:966break;967}968return val;969}970971std::string972SUMOVehicleParameter::getArrivalEdge() const {973std::string val;974switch (arrivalEdgeProcedure) {975case RouteIndexDefinition::GIVEN:976val = toString(arrivalEdge);977break;978case RouteIndexDefinition::RANDOM:979val = "random";980break;981case RouteIndexDefinition::DEFAULT:982default:983break;984}985return val;986}987988989990991std::string992SUMOVehicleParameter::getArrivalLane() const {993std::string val;994switch (arrivalLaneProcedure) {995case ArrivalLaneDefinition::GIVEN:996val = toString(arrivalLane);997break;998case ArrivalLaneDefinition::CURRENT:999val = "current";1000break;1001case ArrivalLaneDefinition::RANDOM:1002val = "random";1003break;1004case ArrivalLaneDefinition::FIRST_ALLOWED:1005val = "first";1006break;1007case ArrivalLaneDefinition::DEFAULT:1008default:1009break;1010}1011return val;1012}101310141015std::string1016SUMOVehicleParameter::getArrivalPos() const {1017std::string val;1018switch (arrivalPosProcedure) {1019case ArrivalPosDefinition::GIVEN:1020val = toString(arrivalPos);1021break;1022case ArrivalPosDefinition::RANDOM:1023val = "random";1024break;1025case ArrivalPosDefinition::CENTER:1026val = "center";1027break;1028case ArrivalPosDefinition::MAX:1029val = "max";1030break;1031case ArrivalPosDefinition::DEFAULT:1032default:1033break;1034}1035return val;1036}103710381039std::string1040SUMOVehicleParameter::getArrivalPosLat() const {1041std::string val;1042switch (arrivalPosLatProcedure) {1043case ArrivalPosLatDefinition::GIVEN:1044val = toString(arrivalPosLat);1045break;1046case ArrivalPosLatDefinition::RIGHT:1047val = "right";1048break;1049case ArrivalPosLatDefinition::CENTER:1050val = "center";1051break;1052case ArrivalPosLatDefinition::LEFT:1053val = "left";1054break;1055case ArrivalPosLatDefinition::DEFAULT:1056default:1057break;1058}1059return val;1060}106110621063std::string1064SUMOVehicleParameter::getArrivalSpeed() const {1065std::string val;1066switch (arrivalSpeedProcedure) {1067case ArrivalSpeedDefinition::GIVEN:1068val = toString(arrivalSpeed);1069break;1070case ArrivalSpeedDefinition::CURRENT:1071val = "current";1072break;1073case ArrivalSpeedDefinition::DEFAULT:1074default:1075break;1076}1077return val;1078}107910801081void1082SUMOVehicleParameter::incrementFlow(double scale, SumoRNG* rng) {1083repetitionsDone++;1084// equidistant or exponential offset (for poisson distributed arrivals)1085if (repetitionProbability < 0) {1086if (repetitionOffset >= 0) {1087repetitionTotalOffset += (SUMOTime)((double)repetitionOffset / scale);1088} else {1089assert(poissonRate > 0);1090// we need to cache this do avoid double generation of the rng in the TIME2STEPS macro1091const double r = RandHelper::randExp(poissonRate, rng);1092repetitionTotalOffset += TIME2STEPS(r / scale);1093}1094}1095}109610971098std::string1099SUMOVehicleParameter::getInsertionChecks() const {1100if ((insertionChecks == 0) || (insertionChecks == (int)InsertionCheck::ALL)) {1101return SUMOXMLDefinitions::InsertionChecks.getString(InsertionCheck::ALL);1102} else {1103std::vector<std::string> insertionChecksStrs;1104const auto insertionCheckValues = SUMOXMLDefinitions::InsertionChecks.getValues();1105// iterate over values1106for (const auto insertionCheckValue : insertionCheckValues) {1107if ((insertionCheckValue != InsertionCheck::ALL) && (insertionChecks & (int)insertionCheckValue) != 0) {1108insertionChecksStrs.push_back(SUMOXMLDefinitions::InsertionChecks.getString(insertionCheckValue));1109}1110}1111return toString(insertionChecksStrs);1112}1113}111411151116bool1117SUMOVehicleParameter::areInsertionChecksValid(const std::string& value) const {1118if (value.empty()) {1119return true;1120} else {1121// split value in substrinsg1122StringTokenizer valueStrs(value, " ");1123// iterate over values1124while (valueStrs.hasNext()) {1125if (!SUMOXMLDefinitions::InsertionChecks.hasString(valueStrs.next())) {1126return false;1127}1128}1129return true;1130}1131}113211331134int1135SUMOVehicleParameter::parseInsertionChecks(const std::string& value) {1136// first reset insertionChecks1137int result = 0;1138if (value.empty()) {1139return (int)InsertionCheck::ALL;1140} else {1141// split value in substrinsg1142StringTokenizer insertionCheckStrs(value, " ");1143while (insertionCheckStrs.hasNext()) {1144std::string val = insertionCheckStrs.next();1145if (SUMOXMLDefinitions::InsertionChecks.hasString(val)) {1146result |= (int)SUMOXMLDefinitions::InsertionChecks.get(val);1147} else {1148throw InvalidArgument("Unknown value '" + val + "' in " + toString(SUMO_ATTR_INSERTIONCHECKS) + ".");1149}1150}1151}1152return result;1153}11541155/****************************************************************************/115611571158