Path: blob/main/src/netedit/elements/demand/GNEVehicle.cpp
185790 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 GNEVehicle.cpp14/// @author Pablo Alvarez Lopez15/// @date Jan 201916///17// Representation of vehicles in netedit18/****************************************************************************/1920#include <microsim/devices/MSDevice_BTreceiver.h>21#include <netedit/changes/GNEChange_Attribute.h>22#include <netedit/changes/GNEChange_DemandElement.h>23#include <netedit/elements/moving/GNEMoveElementVehicle.h>24#include <netedit/elements/moving/GNEMoveElementView.h>25#include <netedit/frames/demand/GNETypeFrame.h>26#include <netedit/GNENet.h>27#include <netedit/GNESegment.h>28#include <netedit/GNETagProperties.h>29#include <netedit/GNEUndoList.h>30#include <netedit/GNEViewParent.h>31#include <utils/gui/div/GLHelper.h>32#include <utils/gui/div/GUIBaseVehicleHelper.h>33#include <utils/gui/div/GUIDesigns.h>34#include <utils/gui/windows/GUIAppEnum.h>35#include <utils/xml/NamespaceIDs.h>3637#include "GNEVehicle.h"38#include "GNERoute.h"39#include "GNERouteHandler.h"4041// ===========================================================================42// FOX callback mapping43// ===========================================================================4445FXDEFMAP(GNEVehicle::GNESingleVehiclePopupMenu) GNESingleVehiclePopupMenuMap[] = {46FXMAPFUNCS(SEL_COMMAND, MID_GNE_VEHICLE_TRANSFORM_TRIP, MID_GNE_VEHICLE_TRANSFORM_FLOW_TAZS, GNEVehicle::GNESingleVehiclePopupMenu::onCmdTransform),47};4849FXDEFMAP(GNEVehicle::GNESelectedVehiclesPopupMenu) GNESelectedVehiclesPopupMenuMap[] = {50FXMAPFUNCS(SEL_COMMAND, MID_GNE_VEHICLE_TRANSFORM_TRIP, MID_GNE_VEHICLE_TRANSFORM_FLOW_TAZS, GNEVehicle::GNESelectedVehiclesPopupMenu::onCmdTransform),51};5253// Object implementation54FXIMPLEMENT(GNEVehicle::GNESingleVehiclePopupMenu, GUIGLObjectPopupMenu, GNESingleVehiclePopupMenuMap, ARRAYNUMBER(GNESingleVehiclePopupMenuMap))55FXIMPLEMENT(GNEVehicle::GNESelectedVehiclesPopupMenu, GUIGLObjectPopupMenu, GNESelectedVehiclesPopupMenuMap, ARRAYNUMBER(GNESelectedVehiclesPopupMenuMap))5657// ===========================================================================58// GNEVehicle::GNESingleVehiclePopupMenu59// ===========================================================================6061GNEVehicle::GNESingleVehiclePopupMenu::GNESingleVehiclePopupMenu(GNEVehicle* vehicle, GUIMainWindow& app, GUISUMOAbstractView& parent) :62GUIGLObjectPopupMenu(app, parent, vehicle),63myVehicle(vehicle) {64// build common options65vehicle->buildPopUpMenuCommonOptions(this, app, vehicle->myNet->getViewNet(), vehicle->getTagProperty()->getTag(), vehicle->isAttributeCarrierSelected());66// route length67vehicle->buildMenuCommandRouteLength(this);68// add transform functions only in demand mode69if (myVehicle->getNet()->getViewNet()->getEditModes().isCurrentSupermodeDemand()) {70// add reverse71vehicle->buildMenuAddReverse(this);72// continue depending of type73if (myVehicle->getTagProperty()->vehicleJunctions()) {74// create menu pane for transform operations75FXMenuPane* transformOperation = new FXMenuPane(this);76this->insertMenuPaneChild(transformOperation);77new FXMenuCascade(this, TL("transform to"), nullptr, transformOperation);78// Create menu commands for all transform79GUIDesigns::buildFXMenuCommand(transformOperation,80TL("Trip (over junctions)"),81GUIIconSubSys::getIcon(GUIIcon::TRIP_JUNCTIONS), this, MID_GNE_VEHICLE_TRANSFORM_TRIP_JUNCTIONS,82(myVehicle->getTagProperty()->getTag() == GNE_TAG_TRIP_JUNCTIONS));83GUIDesigns::buildFXMenuCommand(transformOperation,84TL("Flow (over junctions)"),85GUIIconSubSys::getIcon(GUIIcon::FLOW_JUNCTIONS), this, MID_GNE_VEHICLE_TRANSFORM_FLOW_JUNCTIONS,86(myVehicle->getTagProperty()->getTag() == GNE_TAG_FLOW_JUNCTIONS));87} else if (myVehicle->getTagProperty()->vehicleTAZs()) {88// create menu pane for transform operations89FXMenuPane* transformOperation = new FXMenuPane(this);90this->insertMenuPaneChild(transformOperation);91new FXMenuCascade(this, TL("transform to"), nullptr, transformOperation);92// Create menu commands for all transform93GUIDesigns::buildFXMenuCommand(transformOperation,94TL("Trip (over TAZs)"),95GUIIconSubSys::getIcon(GUIIcon::TRIP_TAZS), this, MID_GNE_VEHICLE_TRANSFORM_TRIP_TAZS,96(myVehicle->getTagProperty()->getTag() == GNE_TAG_TRIP_TAZS));97GUIDesigns::buildFXMenuCommand(transformOperation,98TL("Flow (over TAZs)"),99GUIIconSubSys::getIcon(GUIIcon::FLOW_TAZS), this, MID_GNE_VEHICLE_TRANSFORM_FLOW_TAZS,100(myVehicle->getTagProperty()->getTag() == GNE_TAG_FLOW_TAZS));101} else {102// create menu pane for transform operations103FXMenuPane* transformOperation = new FXMenuPane(this);104this->insertMenuPaneChild(transformOperation);105new FXMenuCascade(this, TL("transform to"), nullptr, transformOperation);106// Create menu commands for all transform107GUIDesigns::buildFXMenuCommand(transformOperation,108TL("Vehicle"),109GUIIconSubSys::getIcon(GUIIcon::VEHICLE), this, MID_GNE_VEHICLE_TRANSFORM_VEHICLE,110(myVehicle->getTagProperty()->getTag() == SUMO_TAG_VEHICLE));111GUIDesigns::buildFXMenuCommand(transformOperation,112TL("Vehicle (embedded route)"),113GUIIconSubSys::getIcon(GUIIcon::VEHICLE), this, MID_GNE_VEHICLE_TRANSFORM_VEHICLE_EMBEDDED,114(myVehicle->getTagProperty()->getTag() == GNE_TAG_VEHICLE_WITHROUTE));115GUIDesigns::buildFXMenuCommand(transformOperation,116TL("RouteFlow"),117GUIIconSubSys::getIcon(GUIIcon::ROUTEFLOW), this, MID_GNE_VEHICLE_TRANSFORM_ROUTEFLOW,118(myVehicle->getTagProperty()->getTag() == GNE_TAG_FLOW_ROUTE));119GUIDesigns::buildFXMenuCommand(transformOperation,120TL("RouteFlow (embedded route)"),121GUIIconSubSys::getIcon(GUIIcon::ROUTEFLOW), this, MID_GNE_VEHICLE_TRANSFORM_FLOW_EMBEDDED,122(myVehicle->getTagProperty()->getTag() == GNE_TAG_FLOW_WITHROUTE));123GUIDesigns::buildFXMenuCommand(transformOperation,124TL("Trip"),125GUIIconSubSys::getIcon(GUIIcon::TRIP), this, MID_GNE_VEHICLE_TRANSFORM_TRIP,126(myVehicle->getTagProperty()->getTag() == SUMO_TAG_TRIP));127GUIDesigns::buildFXMenuCommand(transformOperation,128TL("Flow"),129GUIIconSubSys::getIcon(GUIIcon::FLOW), this, MID_GNE_VEHICLE_TRANSFORM_FLOW,130(myVehicle->getTagProperty()->getTag() == SUMO_TAG_FLOW));131}132}133}134135136GNEVehicle::GNESingleVehiclePopupMenu::~GNESingleVehiclePopupMenu() {}137138139long140GNEVehicle::GNESingleVehiclePopupMenu::onCmdTransform(FXObject*, FXSelector sel, void*) {141switch (FXSELID(sel)) {142case MID_GNE_VEHICLE_TRANSFORM_TRIP:143GNERouteHandler::transformToTrip(myVehicle);144break;145case MID_GNE_VEHICLE_TRANSFORM_FLOW:146GNERouteHandler::transformToFlow(myVehicle);147break;148case MID_GNE_VEHICLE_TRANSFORM_VEHICLE:149GNERouteHandler::transformToVehicle(myVehicle, false);150break;151case MID_GNE_VEHICLE_TRANSFORM_ROUTEFLOW:152GNERouteHandler::transformToRouteFlow(myVehicle, false);153break;154case MID_GNE_VEHICLE_TRANSFORM_VEHICLE_EMBEDDED:155GNERouteHandler::transformToVehicle(myVehicle, true);156break;157case MID_GNE_VEHICLE_TRANSFORM_FLOW_EMBEDDED:158GNERouteHandler::transformToRouteFlow(myVehicle, true);159break;160case MID_GNE_VEHICLE_TRANSFORM_TRIP_JUNCTIONS:161GNERouteHandler::transformToTripJunctions(myVehicle);162break;163case MID_GNE_VEHICLE_TRANSFORM_FLOW_JUNCTIONS:164GNERouteHandler::transformToFlowJunctions(myVehicle);165break;166case MID_GNE_VEHICLE_TRANSFORM_TRIP_TAZS:167GNERouteHandler::transformToTripTAZs(myVehicle);168break;169case MID_GNE_VEHICLE_TRANSFORM_FLOW_TAZS:170GNERouteHandler::transformToFlowTAZs(myVehicle);171break;172default:173break;174}175return 1;176}177178// ===========================================================================179// GNEVehicle::GNESelectedVehiclesPopupMenu180// ===========================================================================181182GNEVehicle::GNESelectedVehiclesPopupMenu::GNESelectedVehiclesPopupMenu(GNEVehicle* vehicle, const std::vector<GNEVehicle*>& selectedVehicle, GUIMainWindow& app, GUISUMOAbstractView& parent) :183GUIGLObjectPopupMenu(app, parent, vehicle),184mySelectedVehicles(selectedVehicle),185myVehicleTag(vehicle->getTagProperty()->getTag()) {186// build common options187vehicle->buildPopUpMenuCommonOptions(this, app, vehicle->myNet->getViewNet(), vehicle->getTagProperty()->getTag(), vehicle->isAttributeCarrierSelected());188// route length189vehicle->buildMenuCommandRouteLength(this);190// add transform functions only in demand mode191if (vehicle->getNet()->getViewNet()->getEditModes().isCurrentSupermodeDemand()) {192// add reverse193vehicle->buildMenuAddReverse(this);194// continue depending of type195if (vehicle->getTagProperty()->vehicleJunctions()) {196// create menu pane for transform operations197FXMenuPane* transformOperation = new FXMenuPane(this);198this->insertMenuPaneChild(transformOperation);199new FXMenuCascade(this, TL("transform selected to"), nullptr, transformOperation);200// Create menu commands for restricted transforms201myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,202TLF("Trips (over junctions) (only %)", toString(GNE_TAG_TRIP_JUNCTIONS)),203GUIIconSubSys::getIcon(GUIIcon::TRIP_JUNCTIONS), this, MID_GNE_VEHICLE_TRANSFORM_TRIP_JUNCTIONS)] = GNE_TAG_TRIP_JUNCTIONS;204myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,205TLF("Flows (over junctions) (only %)", toString(GNE_TAG_FLOW_JUNCTIONS)),206GUIIconSubSys::getIcon(GUIIcon::FLOW_JUNCTIONS), this, MID_GNE_VEHICLE_TRANSFORM_FLOW_JUNCTIONS)] = GNE_TAG_FLOW_JUNCTIONS;207// create separator208new FXMenuSeparator(transformOperation);209// Create menu commands for all transform210GUIDesigns::buildFXMenuCommand(transformOperation,211TL("Trips (over junctions)"),212GUIIconSubSys::getIcon(GUIIcon::TRIP_JUNCTIONS), this, MID_GNE_VEHICLE_TRANSFORM_TRIP_JUNCTIONS);213GUIDesigns::buildFXMenuCommand(transformOperation,214TL("Flows (over junctions)"),215GUIIconSubSys::getIcon(GUIIcon::FLOW_JUNCTIONS), this, MID_GNE_VEHICLE_TRANSFORM_FLOW_JUNCTIONS);216} else if (vehicle->getTagProperty()->vehicleTAZs()) {217// create menu pane for transform operations218FXMenuPane* transformOperation = new FXMenuPane(this);219this->insertMenuPaneChild(transformOperation);220new FXMenuCascade(this, TL("transform selected to"), nullptr, transformOperation);221// Create menu commands for all transform222myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,223TLF("Trips (over TAZs) (only %)", toString(GNE_TAG_TRIP_TAZS)),224GUIIconSubSys::getIcon(GUIIcon::TRIP_TAZS), this, MID_GNE_VEHICLE_TRANSFORM_TRIP_TAZS)] = GNE_TAG_TRIP_TAZS;225myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,226TLF("Flows (over TAZs) (only %)", toString(GNE_TAG_FLOW_TAZS)),227GUIIconSubSys::getIcon(GUIIcon::FLOW_TAZS), this, MID_GNE_VEHICLE_TRANSFORM_FLOW_TAZS)] = GNE_TAG_FLOW_TAZS;228// create separator229new FXMenuSeparator(transformOperation);230// Create menu commands for all transform231GUIDesigns::buildFXMenuCommand(transformOperation,232TL("Trips (over TAZs)"),233GUIIconSubSys::getIcon(GUIIcon::TRIP_TAZS), this, MID_GNE_VEHICLE_TRANSFORM_TRIP_TAZS);234GUIDesigns::buildFXMenuCommand(transformOperation,235TL("Flows (over TAZs)"),236GUIIconSubSys::getIcon(GUIIcon::FLOW_TAZS), this, MID_GNE_VEHICLE_TRANSFORM_FLOW_TAZS);237} else {238// create menu pane for transform operations239FXMenuPane* transformOperation = new FXMenuPane(this);240this->insertMenuPaneChild(transformOperation);241new FXMenuCascade(this, TL("transform selected to"), nullptr, transformOperation);242// Create menu commands for all transform243myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,244TLF("Vehicles (only %)", toString(SUMO_TAG_VEHICLE)),245GUIIconSubSys::getIcon(GUIIcon::VEHICLE), this, MID_GNE_VEHICLE_TRANSFORM_VEHICLE)] = SUMO_TAG_VEHICLE;246myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,247TLF("Vehicles (embedded route) (only %)", toString(GNE_TAG_VEHICLE_WITHROUTE)),248GUIIconSubSys::getIcon(GUIIcon::VEHICLE), this, MID_GNE_VEHICLE_TRANSFORM_VEHICLE_EMBEDDED)] = GNE_TAG_VEHICLE_WITHROUTE;249myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,250TLF("RouteFlows (only %)", toString(GNE_TAG_FLOW_ROUTE)),251GUIIconSubSys::getIcon(GUIIcon::ROUTEFLOW), this, MID_GNE_VEHICLE_TRANSFORM_ROUTEFLOW)] = GNE_TAG_FLOW_ROUTE;252myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,253TLF("RouteFlows (embedded route) (only %)", toString(GNE_TAG_FLOW_WITHROUTE)),254GUIIconSubSys::getIcon(GUIIcon::ROUTEFLOW), this, MID_GNE_VEHICLE_TRANSFORM_FLOW_EMBEDDED)] = GNE_TAG_FLOW_WITHROUTE;255myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,256TLF("Trips (only %)", toString(SUMO_TAG_TRIP)),257GUIIconSubSys::getIcon(GUIIcon::TRIP), this, MID_GNE_VEHICLE_TRANSFORM_TRIP)] = SUMO_TAG_TRIP;258myRestrictedMenuCommands[GUIDesigns::buildFXMenuCommand(transformOperation,259TLF("Flows (only %)", toString(SUMO_TAG_FLOW)),260GUIIconSubSys::getIcon(GUIIcon::FLOW), this, MID_GNE_VEHICLE_TRANSFORM_FLOW)] = SUMO_TAG_FLOW;261// create separator262new FXMenuSeparator(transformOperation);263// Create menu commands for all transform264GUIDesigns::buildFXMenuCommand(transformOperation,265TL("Vehicles"),266GUIIconSubSys::getIcon(GUIIcon::VEHICLE), this, MID_GNE_VEHICLE_TRANSFORM_VEHICLE);267GUIDesigns::buildFXMenuCommand(transformOperation,268TL("Vehicles (embedded route)"),269GUIIconSubSys::getIcon(GUIIcon::VEHICLE), this, MID_GNE_VEHICLE_TRANSFORM_VEHICLE_EMBEDDED);270GUIDesigns::buildFXMenuCommand(transformOperation,271TL("RouteFlows"),272GUIIconSubSys::getIcon(GUIIcon::ROUTEFLOW), this, MID_GNE_VEHICLE_TRANSFORM_ROUTEFLOW);273GUIDesigns::buildFXMenuCommand(transformOperation,274TL("RouteFlows (embedded route)"),275GUIIconSubSys::getIcon(GUIIcon::ROUTEFLOW), this, MID_GNE_VEHICLE_TRANSFORM_FLOW_EMBEDDED);276GUIDesigns::buildFXMenuCommand(transformOperation,277TL("Trips"),278GUIIconSubSys::getIcon(GUIIcon::TRIP), this, MID_GNE_VEHICLE_TRANSFORM_TRIP);279GUIDesigns::buildFXMenuCommand(transformOperation,280TL("Flows"),281GUIIconSubSys::getIcon(GUIIcon::FLOW), this, MID_GNE_VEHICLE_TRANSFORM_FLOW);282}283}284}285286287GNEVehicle::GNESelectedVehiclesPopupMenu::~GNESelectedVehiclesPopupMenu() {}288289290long291GNEVehicle::GNESelectedVehiclesPopupMenu::onCmdTransform(FXObject* obj, FXSelector sel, void*) {292// iterate over all selected vehicles293for (const auto& vehicle : mySelectedVehicles) {294switch (FXSELID(sel)) {295case MID_GNE_VEHICLE_TRANSFORM_TRIP:296if (!vehicle->getTagProperty()->vehicleJunctions() && !vehicle->getTagProperty()->vehicleTAZs()) {297if (myRestrictedMenuCommands.count(obj) > 0) {298if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {299GNERouteHandler::transformToTrip(vehicle);300}301} else {302GNERouteHandler::transformToTrip(vehicle);303}304}305break;306case MID_GNE_VEHICLE_TRANSFORM_FLOW:307if (!vehicle->getTagProperty()->vehicleJunctions() && !vehicle->getTagProperty()->vehicleTAZs()) {308if (myRestrictedMenuCommands.count(obj) > 0) {309if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {310GNERouteHandler::transformToFlow(vehicle);311}312} else {313GNERouteHandler::transformToFlow(vehicle);314}315}316break;317case MID_GNE_VEHICLE_TRANSFORM_VEHICLE:318if (!vehicle->getTagProperty()->vehicleJunctions() && !vehicle->getTagProperty()->vehicleTAZs()) {319if (myRestrictedMenuCommands.count(obj) > 0) {320if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {321GNERouteHandler::transformToVehicle(vehicle, false);322}323} else {324GNERouteHandler::transformToVehicle(vehicle, false);325}326}327break;328case MID_GNE_VEHICLE_TRANSFORM_ROUTEFLOW:329if (!vehicle->getTagProperty()->vehicleJunctions() && !vehicle->getTagProperty()->vehicleTAZs()) {330if (myRestrictedMenuCommands.count(obj) > 0) {331if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {332GNERouteHandler::transformToRouteFlow(vehicle, false);333}334} else {335GNERouteHandler::transformToRouteFlow(vehicle, false);336}337}338break;339case MID_GNE_VEHICLE_TRANSFORM_VEHICLE_EMBEDDED:340if (!vehicle->getTagProperty()->vehicleJunctions() && !vehicle->getTagProperty()->vehicleTAZs()) {341if (myRestrictedMenuCommands.count(obj) > 0) {342if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {343GNERouteHandler::transformToVehicle(vehicle, true);344}345} else {346GNERouteHandler::transformToVehicle(vehicle, true);347}348}349break;350case MID_GNE_VEHICLE_TRANSFORM_FLOW_EMBEDDED:351if (!vehicle->getTagProperty()->vehicleJunctions() && !vehicle->getTagProperty()->vehicleTAZs()) {352if (myRestrictedMenuCommands.count(obj) > 0) {353if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {354GNERouteHandler::transformToRouteFlow(vehicle, true);355}356} else {357GNERouteHandler::transformToRouteFlow(vehicle, true);358}359}360break;361case MID_GNE_VEHICLE_TRANSFORM_TRIP_JUNCTIONS:362if (vehicle->getTagProperty()->vehicleJunctions()) {363if (myRestrictedMenuCommands.count(obj) > 0) {364if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {365GNERouteHandler::transformToTripJunctions(vehicle);366}367} else {368GNERouteHandler::transformToTripJunctions(vehicle);369}370}371break;372case MID_GNE_VEHICLE_TRANSFORM_FLOW_JUNCTIONS:373if (vehicle->getTagProperty()->vehicleJunctions()) {374if (myRestrictedMenuCommands.count(obj) > 0) {375if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {376GNERouteHandler::transformToFlowJunctions(vehicle);377}378} else {379GNERouteHandler::transformToFlowJunctions(vehicle);380}381}382break;383case MID_GNE_VEHICLE_TRANSFORM_TRIP_TAZS:384if (vehicle->getTagProperty()->vehicleTAZs()) {385if (myRestrictedMenuCommands.count(obj) > 0) {386if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {387GNERouteHandler::transformToTripTAZs(vehicle);388}389} else {390GNERouteHandler::transformToTripTAZs(vehicle);391}392}393break;394case MID_GNE_VEHICLE_TRANSFORM_FLOW_TAZS:395if (vehicle->getTagProperty()->vehicleTAZs()) {396if (myRestrictedMenuCommands.count(obj) > 0) {397if (vehicle->getTagProperty()->getTag() == myRestrictedMenuCommands.at(obj)) {398GNERouteHandler::transformToFlowTAZs(vehicle);399}400} else {401GNERouteHandler::transformToFlowTAZs(vehicle);402}403}404break;405default:406break;407}408}409return 1;410}411412// ===========================================================================413// member method definitions414// ===========================================================================415#ifdef _MSC_VER416#pragma warning(push)417#pragma warning(disable: 4355) // mask warning about "this" in initializers418#endif419GNEVehicle::GNEVehicle(SumoXMLTag tag, GNENet* net) :420GNEDemandElement(net, tag),421GNEDemandElementFlow(this),422myMoveElementView(new GNEMoveElementView(this, GNEMoveElementView::AttributesFormat::POSITION,423SUMO_ATTR_POSITION, myPosOverView)) {424// set end and vehPerHours as default flow values425toggleAttribute(SUMO_ATTR_END, true);426toggleAttribute(SUMO_ATTR_VEHSPERHOUR, true);427}428429430GNEVehicle::GNEVehicle(SumoXMLTag tag, const std::string& vehicleID, GNENet* net, FileBucket* fileBucket,431GNEDemandElement* vehicleType, GNEDemandElement* route) :432GNEDemandElement(vehicleID, net, tag, fileBucket),433GNEDemandElementFlow(this),434myMoveElementView(new GNEMoveElementView(this, GNEMoveElementView::AttributesFormat::POSITION,435SUMO_ATTR_POSITION, myPosOverView)) {436// set parents437setParents<GNEDemandElement*>({vehicleType, route});438// SUMOVehicleParameter ID has to be set manually439id = vehicleID;440// set manually vtypeID (needed for saving)441vtypeid = vehicleType->getID();442}443444445GNEVehicle::GNEVehicle(SumoXMLTag tag, GNENet* net, FileBucket* fileBucket, GNEDemandElement* vehicleType,446GNEDemandElement* route, const SUMOVehicleParameter& vehicleParameters) :447GNEDemandElement(vehicleParameters.id, net, tag, fileBucket),448GNEDemandElementFlow(this, vehicleParameters),449myMoveElementView(new GNEMoveElementView(this, GNEMoveElementView::AttributesFormat::POSITION,450SUMO_ATTR_POSITION, myPosOverView)) {451// set parents452setParents<GNEDemandElement*>({vehicleType, route});453// SUMOVehicleParameter ID has to be set manually454id = vehicleParameters.id;455// set manually vtypeID (needed for saving)456vtypeid = vehicleType->getID();457}458459460GNEVehicle::GNEVehicle(SumoXMLTag tag, GNENet* net, FileBucket* fileBucket, GNEDemandElement* vehicleType,461const SUMOVehicleParameter& vehicleParameters) :462GNEDemandElement(vehicleParameters.id, net, tag, fileBucket),463GNEDemandElementFlow(this, vehicleParameters),464myMoveElementView(new GNEMoveElementView(this, GNEMoveElementView::AttributesFormat::POSITION,465SUMO_ATTR_POSITION, myPosOverView)) {466// set parents467setParent<GNEDemandElement*>(vehicleType);468// SUMOVehicleParameter ID has to be set manually469id = vehicleParameters.id;470// reset routeid471routeid.clear();472// set manually vtypeID (needed for saving)473vtypeid = vehicleType->getID();474}475476477GNEVehicle::GNEVehicle(SumoXMLTag tag, const std::string& vehicleID, GNENet* net, FileBucket* fileBucket,478GNEDemandElement* vehicleType, GNEEdge* fromEdge, GNEEdge* toEdge) :479GNEDemandElement(vehicleID, net, tag, fileBucket),480GNEDemandElementFlow(this),481myMoveElementVehicle(new GNEMoveElementVehicle(this, fromEdge, toEdge)),482myMoveElementView(new GNEMoveElementView(this, GNEMoveElementView::AttributesFormat::POSITION,483SUMO_ATTR_POSITION, myPosOverView)) {484// set parents485setParents<GNEEdge*>({fromEdge, toEdge});486setParent<GNEDemandElement*>(vehicleType);487}488489490GNEVehicle::GNEVehicle(SumoXMLTag tag, GNENet* net, FileBucket* fileBucket, GNEDemandElement* vehicleType,491GNEEdge* fromEdge, GNEEdge* toEdge, const SUMOVehicleParameter& vehicleParameters) :492GNEDemandElement(vehicleParameters.id, net, tag, fileBucket),493GNEDemandElementFlow(this, vehicleParameters),494myMoveElementVehicle(new GNEMoveElementVehicle(this, fromEdge, toEdge)),495myMoveElementView(new GNEMoveElementView(this, GNEMoveElementView::AttributesFormat::POSITION,496SUMO_ATTR_POSITION, myPosOverView)) {497// set parents498setParents<GNEEdge*>({fromEdge, toEdge});499setParent<GNEDemandElement*>(vehicleType);500}501502503GNEVehicle::GNEVehicle(SumoXMLTag tag, const std::string& vehicleID, GNENet* net, FileBucket* fileBucket,504GNEDemandElement* vehicleType, GNEJunction* fromJunction, GNEJunction* toJunction) :505GNEDemandElement(vehicleID, net, tag, fileBucket),506GNEDemandElementFlow(this),507myMoveElementView(new GNEMoveElementView(this, GNEMoveElementView::AttributesFormat::POSITION,508SUMO_ATTR_POSITION, myPosOverView)) {509// set parents510setParents<GNEJunction*>({fromJunction, toJunction});511setParent<GNEDemandElement*>(vehicleType);512}513514515GNEVehicle::GNEVehicle(SumoXMLTag tag, GNENet* net, FileBucket* fileBucket, GNEDemandElement* vehicleType,516GNEJunction* fromJunction, GNEJunction* toJunction, const SUMOVehicleParameter& vehicleParameters) :517GNEDemandElement(vehicleParameters.id, net, tag, fileBucket),518GNEDemandElementFlow(this, vehicleParameters),519myMoveElementView(new GNEMoveElementView(this, GNEMoveElementView::AttributesFormat::POSITION,520SUMO_ATTR_POSITION, myPosOverView)) {521// set parents522setParents<GNEJunction*>({fromJunction, toJunction});523setParent<GNEDemandElement*>(vehicleType);524}525526527GNEVehicle::GNEVehicle(SumoXMLTag tag, GNENet* net, FileBucket* fileBucket, GNEDemandElement* vehicleType,528GNEAdditional* fromTAZ, GNEAdditional* toTAZ, const SUMOVehicleParameter& vehicleParameters) :529GNEDemandElement(vehicleParameters.id, net, tag, fileBucket),530GNEDemandElementFlow(this, vehicleParameters),531myMoveElementView(new GNEMoveElementView(this, GNEMoveElementView::AttributesFormat::POSITION,532SUMO_ATTR_POSITION, myPosOverView)) {533// set parents534setParents<GNEAdditional*>({fromTAZ, toTAZ});535setParent<GNEDemandElement*>(vehicleType);536// mark taz parameters as set537parametersSet |= VEHPARS_FROM_TAZ_SET;538parametersSet |= VEHPARS_TO_TAZ_SET;539fromTaz = fromTAZ->getID();540toTaz = toTAZ->getID();541}542#ifdef _MSC_VER543#pragma warning(pop)544#endif545546547GNEVehicle::~GNEVehicle() {}548549550GNEMoveElement*551GNEVehicle::getMoveElement() const {552return myMoveElementVehicle;553}554555556Parameterised*557GNEVehicle::getParameters() {558return this;559}560561562const Parameterised*563GNEVehicle::getParameters() const {564return this;565}566567568void569GNEVehicle::writeDemandElement(OutputDevice& device) const {570// attribute VType must not be written if is DEFAULT_VTYPE_ID571if (getTypeParent()->getID() == DEFAULT_VTYPE_ID) {572// unset VType parameter573parametersSet &= ~VEHPARS_VTYPE_SET;574// write vehicle attributes (VType will not be written)575write(device, OptionsCont::getOptions(), myTagProperty->getXMLTag());576// set VType parameter again577parametersSet |= VEHPARS_VTYPE_SET;578} else {579// write vehicle attributes, including type/distribution580write(device, OptionsCont::getOptions(), myTagProperty->getXMLTag(), getParentDemandElements().front()->getID());581}582// write route583if (myTagProperty->vehicleRoute()) {584// write route585device.writeAttr(SUMO_ATTR_ROUTE, getRouteParent()->getID());586}587// write from, to and edge vias588if (myTagProperty->vehicleEdges()) {589// write manually from/to edges (it correspond to front and back parent edges)590device.writeAttr(SUMO_ATTR_FROM, getParentEdges().front()->getID());591device.writeAttr(SUMO_ATTR_TO, getParentEdges().back()->getID());592// only write via if there isn't empty593if (via.size() > 0) {594device.writeAttr(SUMO_ATTR_VIA, via);595}596}597// write from and to junctions598if (myTagProperty->vehicleJunctions()) {599// write manually from/to junctions (it correspond to front and back parent junctions)600device.writeAttr(SUMO_ATTR_FROM_JUNCTION, getParentJunctions().front()->getID());601device.writeAttr(SUMO_ATTR_TO_JUNCTION, getParentJunctions().back()->getID());602}603// write parameters604writeParams(device);605// write route elements associated to this vehicle (except for calibrator FLows)606if ((getChildDemandElements().size() > 0) && !myTagProperty->isCalibrator()) {607if (getChildDemandElements().front()->getTagProperty()->getTag() == GNE_TAG_ROUTE_EMBEDDED) {608// write embedded route609getChildDemandElements().front()->writeDemandElement(device);610// write stops611for (const auto& demandElement : getChildDemandElements()) {612if (demandElement->getTagProperty()->isVehicleStop()) {613demandElement->writeDemandElement(device);614}615}616} else {617for (const auto& route : getChildDemandElements()) {618route->writeDemandElement(device);619}620}621}622// close vehicle tag623device.closeTag();624}625626627GNEDemandElement::Problem628GNEVehicle::isDemandElementValid() const {629// check conditions630if (myTagProperty->vehicleTAZs()) {631// vehicles and flows over tazs are always valid632return Problem::OK;633} else if (myTagProperty->vehicleEdges()) {634// check vehicles and flows paths635if (getParentEdges().front() == getParentEdges().back()) {636return Problem::OK;637} else if (myNet->getDemandPathManager()->isPathValid(this)) {638return Problem::OK;639} else {640return Problem::INVALID_PATH;641}642} else if (myTagProperty->vehicleJunctions()) {643// check vehicles and flows paths644if (getParentJunctions().front() == getParentJunctions().back()) {645return Problem::OK;646} else if (myNet->getDemandPathManager()->isPathValid(this)) {647return Problem::OK;648} else {649return Problem::INVALID_PATH;650}651} else if (myTagProperty->vehicleRoute()) {652// check if routeParent is a distribution653if (getRouteParent()->getTagProperty()->isRouteDistribution()) {654return Problem::OK;655} else {656// check if exist a valid path using route parent edges657if (myNet->getDemandPathManager()->getPathCalculator()->calculateDijkstraPath(getTypeParent()->getVClass(), getRouteParent()->getParentEdges()).size() > 0) {658return Problem::OK;659} else {660return Problem::INVALID_PATH;661}662}663} else if (myTagProperty->vehicleRouteEmbedded()) {664// check if exist a valid path using route child edges665if (myNet->getDemandPathManager()->getPathCalculator()->calculateDijkstraPath(getTypeParent()->getVClass(), getChildDemandElements().at(0)->getParentEdges()).size() > 0) {666return Problem::OK;667} else {668return Problem::INVALID_PATH;669}670} else {671return Problem::INVALID_ELEMENT;672}673}674675676std::string677GNEVehicle::getDemandElementProblem() const {678// only trips or flows can have problems679if (myTagProperty->vehicleEdges()) {680// check if exist at least a connection between every edge681for (int i = 1; i < (int)getParentEdges().size(); i++) {682if (myNet->getDemandPathManager()->getPathCalculator()->consecutiveEdgesConnected(getTypeParent()->getVClass(), getParentEdges().at((int)i - 1), getParentEdges().at(i)) == false) {683return ("There is no valid path between edges '" + getParentEdges().at((int)i - 1)->getID() + "' and '" + getParentEdges().at(i)->getID() + "'");684}685}686// if there are connections between all edges, then all is ok687return "";688} else if (myTagProperty->vehicleJunctions()) {689return ("No path between junction '" + getParentJunctions().front()->getID() + "' and '" + getParentJunctions().back()->getID() + "'");690} else if (myTagProperty->vehicleRoute()) {691// get route parent edges692const std::vector<GNEEdge*>& routeEdges = getRouteParent()->getParentEdges();693// check if exist at least a connection between every edge694for (int i = 1; i < (int)routeEdges.size(); i++) {695if (myNet->getDemandPathManager()->getPathCalculator()->consecutiveEdgesConnected(getTypeParent()->getVClass(), routeEdges.at((int)i - 1), routeEdges.at(i)) == false) {696return ("There is no valid path between route edges '" + routeEdges.at((int)i - 1)->getID() + "' and '" + routeEdges.at(i)->getID() + "'");697}698}699// if there are connections between all edges, then all is ok700return "";701} else if (myTagProperty->vehicleRouteEmbedded()) {702// get route parent edges703const std::vector<GNEEdge*>& routeEdges = getChildDemandElements().at(0)->getParentEdges();704// check if exist at least a connection between every edge705for (int i = 1; i < (int)routeEdges.size(); i++) {706if (myNet->getDemandPathManager()->getPathCalculator()->consecutiveEdgesConnected(getTypeParent()->getVClass(), routeEdges.at((int)i - 1), routeEdges.at(i)) == false) {707return ("There is no valid path between embedded route edges '" + routeEdges.at((int)i - 1)->getID() + "' and '" + routeEdges.at(i)->getID() + "'");708}709}710// if there are connections between all edges, then all is ok711return "";712} else {713return "";714}715}716717718void719GNEVehicle::fixDemandElementProblem() {720//721}722723724SUMOVehicleClass725GNEVehicle::getVClass() const {726return getParentDemandElements().front()->getVClass();727}728729730const RGBColor&731GNEVehicle::getColor() const {732return color;733}734735736void737GNEVehicle::updateGeometry() {738if (myTagProperty->vehicleRoute() && getRouteParent()->getTagProperty()->isRouteDistribution()) {739// remove vehicle from grid740myNet->removeGLObjectFromGrid(this);741// reset view position to 0742myPosOverView = Position(0, 0);743// continue depending if the routeDistribution have references744for (auto routeRef : getParentDemandElements().at(1)->getChildDemandElements()) {745if (routeRef->getTagProperty()->isDistributionReference()) {746myPosOverView = routeRef->getParentDemandElements().at(1)->getParentEdges().front()->getChildLanes().at(0)->getLaneShape().front();747break;748}749}750// update vehicle geometry751myDemandElementGeometry.updateGeometry({myPosOverView - Position(1, 0), myPosOverView + Position(1, 0)});752// add object in grid again753myNet->addGLObjectIntoGrid(this);754} else if (getParentJunctions().size() > 0) {755// calculate rotation between both junctions756const Position posA = getParentJunctions().front()->getPositionInView();757const Position posB = getParentJunctions().back()->getPositionInView();758const double rot = ((double)atan2((posB.x() - posA.x()), (posA.y() - posB.y())) * (double) -180.0 / (double)M_PI);759// update Geometry760myDemandElementGeometry.updateSinglePosGeometry(getParentJunctions().front()->getPositionInView(), rot);761} else if (getParentAdditionals().size() > 0) {762// calculate rotation between both TAZs763const Position posA = getParentAdditionals().front()->getAttribute(SUMO_ATTR_CENTER).empty() ?764getParentAdditionals().front()->getAttributePosition(GNE_ATTR_TAZ_CENTROID) :765getParentAdditionals().front()->getAttributePosition(SUMO_ATTR_CENTER);766const Position posB = getParentAdditionals().back()->getAttribute(SUMO_ATTR_CENTER).empty() ?767getParentAdditionals().back()->getAttributePosition(GNE_ATTR_TAZ_CENTROID) :768getParentAdditionals().back()->getAttributePosition(SUMO_ATTR_CENTER);769const double rot = ((double)atan2((posB.x() - posA.x()), (posA.y() - posB.y())) * (double) -180.0 / (double)M_PI);770// update Geometry771myDemandElementGeometry.updateSinglePosGeometry(posA, rot);772} else {773// get first path lane774const GNELane* firstPathLane = getFirstPathLane();775// check path lane776if (firstPathLane) {777// declare departPos778double posOverLane = 0;779if (wasSet(VEHPARS_DEPARTPOS_SET) && (departPosProcedure == DepartPosDefinition::GIVEN)) {780posOverLane = departPos;781}782// update Geometry783myDemandElementGeometry.updateGeometry(firstPathLane->getLaneShape(), posOverLane, 0 /*myMovingLateralOffset*/);784// compute route embedded associated with this vehicle785for (const auto& demandElement : getChildDemandElements()) {786if (demandElement->getTagProperty()->getTag() == GNE_TAG_ROUTE_EMBEDDED) {787demandElement->computePathElement();788}789demandElement->updateGeometry();790}791}792}793}794795796Position797GNEVehicle::getPositionInView() const {798if (myTagProperty->vehicleRouteEmbedded()) {799return myPosOverView;800} else {801return myDemandElementGeometry.getShape().front();802}803}804805806bool807GNEVehicle::checkDrawRelatedContour() const {808// get edit modes809const auto& editModes = myNet->getViewNet()->getEditModes();810// check if we're editing a type811if (editModes.isCurrentSupermodeDemand() && (editModes.demandEditMode == DemandEditMode::DEMAND_TYPE) &&812(myNet->getViewParent()->getTypeFrame()->getTypeSelector()->getCurrentType() == getParentDemandElements().front())) {813return true;814}815// check opened popup816if (myNet->getViewNet()->getPopup()) {817return myNet->getViewNet()->getPopup()->getGLObject() == this;818}819return false;820}821822823GUIGLObjectPopupMenu*824GNEVehicle::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {825if (isAttributeCarrierSelected()) {826// obtain all selected vehicles827const auto selectedDemandElements = myNet->getAttributeCarriers()->getSelectedDemandElements();828std::vector<GNEVehicle*> selectedVehicles;829selectedVehicles.reserve(selectedDemandElements.size());830for (const auto& selectedDemandElement : selectedDemandElements) {831if (selectedDemandElement->getTagProperty()->isVehicle()) {832selectedVehicles.push_back(dynamic_cast<GNEVehicle*>(selectedDemandElement));833}834}835// return a GNESelectedVehiclesPopupMenu836return new GNESelectedVehiclesPopupMenu(this, selectedVehicles, app, parent);837} else {838// return a GNESingleVehiclePopupMenu839return new GNESingleVehiclePopupMenu(this, app, parent);840}841}842843844std::string845GNEVehicle::getParentName() const {846if (myTagProperty->vehicleRoute()) {847return getRouteParent()->getID();848} else if (myTagProperty->vehicleEdges()) {849return getParentEdges().front()->getID();850} else if (myTagProperty->vehicleJunctions()) {851return getParentJunctions().front()->getID();852} else if (myTagProperty->vehicleTAZs()) {853return getParentAdditionals().front()->getID();854} else {855throw ProcessError(TL("Invalid vehicle tag"));856}857}858859860double861GNEVehicle::getExaggeration(const GUIVisualizationSettings& s) const {862return s.vehicleSize.getExaggeration(s, this);863}864865866Boundary867GNEVehicle::getCenteringBoundary() const {868Boundary vehicleBoundary;869if (myTagProperty->vehicleRoute() && getRouteParent()->getTagProperty()->isRouteDistribution()) {870vehicleBoundary.add(myPosOverView);871} else {872vehicleBoundary.add(myDemandElementGeometry.getShape().front());873}874vehicleBoundary.grow(20);875return vehicleBoundary;876}877878879void880GNEVehicle::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {881// geometry of this element cannot be splitted882}883884885void886GNEVehicle::drawGL(const GUIVisualizationSettings& s) const {887// only drawn in super mode demand888if (myNet->getViewNet()->getNetworkViewOptions().showDemandElements() &&889myNet->getViewNet()->getDataViewOptions().showDemandElements() &&890myNet->getViewNet()->getDemandViewOptions().showNonInspectedDemandElements(this)) {891// declare common attributes892const bool drawSpreadVehicles = (myNet->getViewNet()->getNetworkViewOptions().drawSpreadVehicles() || myNet->getViewNet()->getDemandViewOptions().drawSpreadVehicles());893const double exaggeration = getExaggeration(s);894const double width = getTypeParent()->getAttributeDouble(SUMO_ATTR_WIDTH);895const double length = getTypeParent()->getAttributeDouble(SUMO_ATTR_LENGTH);896// obtain Position an rotation (depending of draw spread vehicles)897if ((!drawSpreadVehicles || (mySpreadGeometry.getShape().size() > 0)) && (myDemandElementGeometry.getShape().size() > 0)) {898const Position vehiclePosition = drawSpreadVehicles ? mySpreadGeometry.getShape().front() : myDemandElementGeometry.getShape().front();899const double vehicleRotation = drawSpreadVehicles ? mySpreadGeometry.getShapeRotations().front() : myDemandElementGeometry.getShapeRotations().front();900// check that position is valid901if (vehiclePosition == Position::INVALID) {902return;903}904// get detail level905const auto d = s.getDetailLevel(exaggeration);906// draw geometry only if we'rent in drawForObjectUnderCursor mode907if (s.checkDrawVehicle(d, isAttributeCarrierSelected())) {908SUMOVehicleShape shape = getVehicleShapeID(getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE));909// push draw matrix910GLHelper::pushMatrix();911// Start with the drawing of the area translating matrix to origin912drawInLayer(getType());913// translate to drawing position914glTranslated(vehiclePosition.x(), vehiclePosition.y(), 0);915glRotated(vehicleRotation, 0, 0, -1);916// extra translation needed to draw vehicle over edge (to avoid selecting problems)917glTranslated(0, (-1) * length * exaggeration, 0);918// set lane color919GLHelper::setColor(getDrawingColor(s));920double upscaleLength = exaggeration;921if ((exaggeration > 1) && (length > 5)) {922// reduce the length/width ratio because this is not useful at high zoom923upscaleLength = MAX2(1.0, upscaleLength * (5 + sqrt(length - 5)) / length);924}925glScaled(exaggeration, upscaleLength, 1);926// draw the vehicle depending of detail level927if (d <= GUIVisualizationSettings::Detail::VehiclePoly) {928GUIBaseVehicleHelper::drawAction_drawVehicleAsPoly(s, shape, width, length);929} else if (d <= GUIVisualizationSettings::Detail::VehicleBox) {930GUIBaseVehicleHelper::drawAction_drawVehicleAsBoxPlus(width, length);931} else if (d <= GUIVisualizationSettings::Detail::VehicleTriangle) {932GUIBaseVehicleHelper::drawAction_drawVehicleAsTrianglePlus(width, length);933}934// check if min gap has to be drawn935if (s.drawMinGap) {936const double minGap = -1 * getTypeParent()->getAttributeDouble(SUMO_ATTR_MINGAP);937glColor3d(0., 1., 0.);938glBegin(GL_LINES);939glVertex2d(0., 0);940glVertex2d(0., minGap);941glVertex2d(-.5, minGap);942glVertex2d(.5, minGap);943glEnd();944}945// drawing name at GLO_MAX fails unless translating z946glTranslated(0, MIN2(length / 2, double(5)), -getType());947glScaled(1 / exaggeration, 1 / upscaleLength, 1);948glRotated(-vehicleRotation, 0, 0, -1);949drawName(Position(0, 0), s.scale, getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE) == "pedestrian" ? s.personName : s.vehicleName, s.angle);950// draw line951if (s.vehicleName.show(this) && line != "") {952glTranslated(0, 0.6 * s.vehicleName.scaledSize(s.scale), 0);953GLHelper::drawTextSettings(s.vehicleName, "line:" + line, Position(0, 0), s.scale, s.angle);954}955// pop draw matrix956GLHelper::popMatrix();957// draw line between junctions if path isn't valid958if ((getParentJunctions().size() > 0) && !myNet->getDemandPathManager()->isPathValid(this)) {959drawJunctionLine(this);960}961// draw lock icon962GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), vehiclePosition, exaggeration);963// draw stack label964if ((myStackedLabelNumber > 0) && !drawSpreadVehicles) {965drawStackLabel(myStackedLabelNumber, "Vehicle", vehiclePosition, vehicleRotation, width, length, exaggeration);966}967// draw flow label968if (myTagProperty->isFlow()) {969drawFlowLabel(vehiclePosition, vehicleRotation, width, length, exaggeration);970}971// draw dotted contour972myVehicleContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);973}974// draw squared shape975myVehicleContour.calculateContourRectangleShape(s, d, this, vehiclePosition, length * 0.5, width * 0.5, getType(),976length * -0.5, 0, vehicleRotation, exaggeration, nullptr);977}978}979}980981982void983GNEVehicle::computePathElement() {984// calculate path (only for flows and trips)985if (myTagProperty->vehicleJunctions()) {986// calculate path987myNet->getDemandPathManager()->calculatePath(this, getVClass(), getParentJunctions().front(), getParentJunctions().back());988} else if (myTagProperty->vehicleEdges()) {989// save edges in wich this vehicle has to stop990std::vector<GNEEdge*> edgeStops;991// iterate over child demand elements992for (const auto& demandElement : getChildDemandElements()) {993// extract lanes994if (demandElement->getTagProperty()->isVehicleStop()) {995GNEEdge* edgeStop = nullptr;996if (demandElement->getParentAdditionals().size() > 0) {997edgeStop = demandElement->getParentAdditionals().front()->getParentLanes().front()->getParentEdge();998} else {999edgeStop = demandElement->getParentLanes().front()->getParentEdge();1000}1001if (edgeStop) {1002// avoid double edge stops1003if (stops.empty()) {1004edgeStops.push_back(edgeStop);1005} else if (edgeStops.back() != edgeStop) {1006edgeStops.push_back(edgeStop);1007}1008}1009}1010}1011// declare edge vector1012std::vector<GNEEdge*> edgePath;1013// get first and last lanes1014const auto firstLane = getFirstPathLane();1015const auto lastLane = getLastPathLane();1016// check first and last lanes1017if (firstLane && lastLane) {1018// add first lane1019edgePath.push_back(firstLane->getParentEdge());1020// give more priority to stops instead via1021if (edgeStops.size() > 0) {1022// add stops only if they're accesibles1023for (const auto& edgeStop : edgeStops) {1024// check if exist a valid path that includes the last edge1025auto edgePathStop = edgePath;1026edgePathStop.push_back(edgeStop);1027edgePathStop.push_back(lastLane->getParentEdge());1028auto path = myNet->getDemandPathManager()->getPathCalculator()->calculateDijkstraPath(getVClass(), edgePathStop);1029if (path.size() > 0) {1030edgePath.push_back(edgeStop);1031}1032}1033} else {1034// add via lanes1035for (const auto& edgeViaID : via) {1036const auto edgeVia = myNet->getAttributeCarriers()->retrieveEdge(edgeViaID, false);1037if (edgeVia) {1038// check if exist a valid path that includes the last edge1039auto edgePathStop = edgePath;1040edgePathStop.push_back(edgeVia);1041edgePathStop.push_back(lastLane->getParentEdge());1042if (myNet->getDemandPathManager()->getPathCalculator()->calculateDijkstraPath(getVClass(), edgePathStop).size() > 0) {1043edgePath.push_back(edgeVia);1044}1045}1046}1047}1048// add last lane1049edgePath.push_back(lastLane->getParentEdge());1050// calculate path1051myNet->getDemandPathManager()->calculatePath(this, getVClass(), edgePath);1052}1053}1054// update geometry1055updateGeometry();1056}105710581059void1060GNEVehicle::drawLanePartialGL(const GUIVisualizationSettings& s, const GNESegment* segment, const double offsetFront) const {1061// conditions for draw always in network mode1062const bool drawInNetworkMode = myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() &&1063myNet->getViewNet()->getNetworkViewOptions().showDemandElements() &&1064myNet->getViewNet()->getDemandViewOptions().showAllTrips();1065// conditions for draw always in demand mode1066const bool drawInDemandMode = myNet->getViewNet()->getEditModes().isCurrentSupermodeDemand() &&1067myNet->getViewNet()->getDemandViewOptions().showAllTrips();1068// conditions for draw if is selected1069const bool isSelected = myNet->getViewNet()->getEditModes().isCurrentSupermodeDemand() &&1070isAttributeCarrierSelected();1071// conditions for draw if is inspected1072const bool isInspected = myNet->getViewNet()->getEditModes().isCurrentSupermodeDemand() &&1073myNet->getViewNet()->getInspectedElements().isACInspected(this);1074// check drawing conditions1075if (segment->getLane() && (drawInNetworkMode || drawInDemandMode || isSelected || isInspected) &&1076myNet->getDemandPathManager()->getPathDraw()->checkDrawPathGeometry(s, segment->getLane(), myTagProperty->getTag(), false)) {1077// get detail level1078const auto d = s.getDetailLevel(1);1079// calculate width1080const double width = s.vehicleSize.getExaggeration(s, segment->getLane()) * s.widthSettings.tripWidth;1081// calculate startPos1082const double geometryDepartPos = (getParentJunctions().size() > 0) ? 0 : getAttributeDouble(SUMO_ATTR_DEPARTPOS) + getTypeParent()->getAttributeDouble(SUMO_ATTR_LENGTH);1083// get endPos1084const double geometryEndPos = (getParentJunctions().size() > 0) ? segment->getLane()->getLaneGeometry().getShape().length2D() : getAttributeDouble(SUMO_ATTR_ARRIVALPOS);1085// declare path geometry1086GUIGeometry vehicleGeometry;1087// update pathGeometry depending of first and last segment1088if (segment->isFirstSegment() && segment->isLastSegment()) {1089vehicleGeometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),1090geometryDepartPos,1091Position::INVALID,1092geometryEndPos,1093Position::INVALID);1094} else if (segment->isFirstSegment()) {1095vehicleGeometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),1096geometryDepartPos,1097Position::INVALID,1098-1,1099Position::INVALID);1100} else if (segment->isLastSegment()) {1101vehicleGeometry.updateGeometry(segment->getLane()->getLaneGeometry().getShape(),1102-1,1103Position::INVALID,1104geometryEndPos,1105Position::INVALID);1106} else {1107vehicleGeometry = segment->getLane()->getLaneGeometry();1108}1109// draw geometry only if we'rent in drawForObjectUnderCursor mode1110if (s.checkDrawVehicle(d, isAttributeCarrierSelected())) {1111// obtain color1112const RGBColor pathColor = drawUsingSelectColor() ? s.colorSettings.selectedVehicleColor : s.colorSettings.vehicleTripColor;1113// Add a draw matrix1114GLHelper::pushMatrix();1115// Start with the drawing of the area translating matrix to origin1116glTranslated(0, 0, getType() + offsetFront);1117// Set color1118GLHelper::setColor(pathColor);1119// draw geometry1120GUIGeometry::drawGeometry(d, vehicleGeometry, width);1121// show index over every edge1122if (isInspected && s.showRouteIndex) {1123const double textSize = s.vehicleName.size / s.scale;1124std::string label = toString(segment->getLaneIndex());1125Position pos = segment->getLane()->getLaneShape().front() - Position(0, textSize * 1);1126GLHelper::drawTextSettings(s.vehicleName, label, pos, s.scale, s.angle, 1.0);1127}1128// Pop last matrix1129GLHelper::popMatrix();1130// check if we have to draw a red line to the next segment (if next segment isnt' a junction1131if (segment->getNextLane()) {1132// push draw matrix1133GLHelper::pushMatrix();1134// Start with the drawing of the area translating matrix to origin1135drawInLayer(getType());1136// Set red color1137GLHelper::setColor(RGBColor::RED);1138// get firstPosition (last position of current lane shape)1139const Position& firstPosition = segment->getLane()->getLaneShape().back();1140// get lastPosition (first position of next lane shape)1141const Position& arrivalPosition = segment->getNextLane()->getLaneShape().front();1142// draw box line1143GLHelper::drawBoxLine(arrivalPosition,1144RAD2DEG(firstPosition.angleTo2D(arrivalPosition)) - 90,1145firstPosition.distanceTo2D(arrivalPosition), .05);1146// pop draw matrix1147GLHelper::popMatrix();1148}1149// check if this is the last segment1150if (segment->isLastSegment() && (getParentJunctions().size() == 0)) {1151// get geometryEndPos1152const Position geometryEndPosition = getAttributePosition(GNE_ATTR_PLAN_GEOMETRY_ENDPOS);1153// check if endPos can be drawn1154if (myNet->getViewNet()->getPositionInformation().distanceSquaredTo2D(geometryEndPosition) <= ((GNEMoveElementVehicle::arrivalPositionDiameter * GNEMoveElementVehicle::arrivalPositionDiameter) + 2)) {1155// push draw matrix1156GLHelper::pushMatrix();1157// Start with the drawing of the area translating matrix to origin1158drawInLayer(getType());1159// translate to geometryEndPos1160glTranslated(geometryEndPosition.x(), geometryEndPosition.y(), 0);1161// Set person plan color1162GLHelper::setColor(pathColor);1163// resolution of drawn circle depending of the zoom (To improve smoothness)1164GLHelper::drawFilledCircleDetailled(d, GNEMoveElementVehicle::arrivalPositionDiameter);1165// pop draw matrix1166GLHelper::popMatrix();1167}1168}1169// draw dotted contour1170segment->getContour()->drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);1171}1172// calculate contour and draw dotted geometry1173if (segment->isFirstSegment() || segment->isLastSegment()) {1174segment->getContour()->calculateContourExtrudedShape(s, d, this, vehicleGeometry.getShape(), getType(), width, 1, false, segment->isLastSegment(),11750, segment, segment->getLane()->getParentEdge());1176} else {1177segment->getContour()->calculateContourExtrudedShape(s, d, this, segment->getLane()->getLaneShape(), getType(), width, 1, false, segment->isLastSegment(),11780, segment, segment->getLane()->getParentEdge());1179}1180// check if add this path element to redraw buffer1181if (!gViewObjectsHandler.isPathElementMarkForRedraw(this) && segment->getContour()->checkDrawPathContour(s, d, this)) {1182gViewObjectsHandler.addToRedrawPathElements(this);1183}1184}1185}118611871188void1189GNEVehicle::drawJunctionPartialGL(const GUIVisualizationSettings& s, const GNESegment* segment, const double offsetFront) const {1190// conditions for draw always in network mode1191const bool drawInNetworkMode = myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() &&1192myNet->getViewNet()->getNetworkViewOptions().showDemandElements() &&1193myNet->getViewNet()->getDemandViewOptions().showAllTrips();1194// conditions for draw always in demand mode1195const bool drawInDemandMode = myNet->getViewNet()->getEditModes().isCurrentSupermodeDemand() &&1196myNet->getViewNet()->getDemandViewOptions().showAllTrips();1197// conditions for draw if is selected1198const bool isSelected = myNet->getViewNet()->getEditModes().isCurrentSupermodeDemand() &&1199isAttributeCarrierSelected();1200// conditions for draw if is inspected1201const bool isInspected = myNet->getViewNet()->getEditModes().isCurrentSupermodeDemand() &&1202myNet->getViewNet()->getInspectedElements().isACInspected(this);1203// check drawing conditions1204if (segment->getJunction() && (drawInNetworkMode || drawInDemandMode || isSelected || isInspected) &&1205myNet->getDemandPathManager()->getPathDraw()->checkDrawPathGeometry(s, segment, myTagProperty->getTag(), false)) {1206// get detail level1207const auto d = s.getDetailLevel(1);1208// calculate width1209const double width = s.vehicleSize.getExaggeration(s, segment->getPreviousLane()) * s.widthSettings.tripWidth;1210// draw geometry only if we'rent in drawForObjectUnderCursor mode1211if (s.checkDrawVehicle(d, isAttributeCarrierSelected())) {1212// Add a draw matrix1213GLHelper::pushMatrix();1214// Start with the drawing of the area translating matrix to origin1215glTranslated(0, 0, getType() + offsetFront);1216// Set color of the base1217if (drawUsingSelectColor()) {1218GLHelper::setColor(s.colorSettings.selectedVehicleColor);1219} else {1220GLHelper::setColor(s.colorSettings.vehicleTripColor);1221}1222// continue depending if we're in the middle of two lanes or in the begin/end of a junction route1223if (segment->getPreviousLane() && segment->getNextLane()) {1224// draw lane2lane1225GUIGeometry::drawGeometry(d, segment->getPreviousLane()->getLane2laneConnections().getLane2laneGeometry(segment->getNextLane()), width);1226} else if (segment->getPreviousLane() && myTagProperty->vehicleJunctions()) {1227// draw line between center of junction and last lane shape1228GLHelper::drawBoxLines({segment->getPreviousLane()->getLaneShape().back(), getParentJunctions().back()->getPositionInView()}, width);1229} else if (segment->getNextLane() && myTagProperty->vehicleJunctions()) {1230// draw line between center of junction and first lane shape1231GLHelper::drawBoxLines({getParentJunctions().front()->getPositionInView(), segment->getNextLane()->getLaneShape().front()}, width);1232}1233// Pop last matrix1234GLHelper::popMatrix();1235// draw dotted contour1236segment->getContour()->drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);1237}1238// continue depending if we're in the middle of two lanes or in the begin/end of a junction route1239if (segment->getPreviousLane() && segment->getNextLane()) {1240// calculate contour and draw dotted geometry1241segment->getContour()->calculateContourExtrudedShape(s, d, this, segment->getPreviousLane()->getLane2laneConnections().getLane2laneGeometry(segment->getNextLane()).getShape(),1242getType(), width, 1, false, false, 0, segment, segment->getJunction());1243} else if (segment->getPreviousLane() && myTagProperty->vehicleJunctions()) {1244segment->getContour()->calculateContourExtrudedShape(s, d, this, {segment->getPreviousLane()->getLaneShape().back(), getParentJunctions().back()->getPositionInView()},1245getType(), width, 1, true, true, 0, segment, segment->getJunction());1246} else if (segment->getNextLane() && myTagProperty->vehicleJunctions()) {1247segment->getContour()->calculateContourExtrudedShape(s, d, this, {getParentJunctions().front()->getPositionInView(), segment->getNextLane()->getLaneShape().front()},1248getType(), width, 1, true, true, 0, segment, segment->getJunction());1249}1250// check if add this path element to redraw buffer1251if (!gViewObjectsHandler.isPathElementMarkForRedraw(this) && segment->getContour()->checkDrawPathContour(s, d, this)) {1252gViewObjectsHandler.addToRedrawPathElements(this);1253}1254}1255}125612571258GNELane*1259GNEVehicle::getFirstPathLane() const {1260// declare first edge1261GNEEdge* firstEdge = nullptr;1262// continue depending of tags1263if (myTagProperty->vehicleRoute()) {1264// check departEdge1265if ((departEdge > 0) && (departEdge < (int)getRouteParent()->getParentEdges().size())) {1266// use departEdge1267firstEdge = getRouteParent()->getParentEdges().at(departEdge);1268} else {1269// use first route edge1270firstEdge = getRouteParent()->getParentEdges().front();1271}1272} else if (myTagProperty->vehicleRouteEmbedded()) {1273// check if embedded route exist (due during loading embedded route doesn't exist)1274if (getChildDemandElements().empty()) {1275return nullptr;1276}1277// check departEdge1278if ((departEdge > 0) && (departEdge < (int)getChildDemandElements().front()->getParentEdges().size())) {1279// use depart edge1280firstEdge = getChildDemandElements().front()->getParentEdges().at(departEdge);1281} else if (getChildDemandElements().front()->getParentEdges().size() > 0) {1282firstEdge = getChildDemandElements().front()->getParentEdges().front();1283} else if (getChildDemandElements().front()->getParentLanes().size() > 0) {1284firstEdge = getChildDemandElements().front()->getParentLanes().front()->getParentEdge();1285} else {1286return nullptr;1287}1288} else if (getParentEdges().size() > 0) {1289// use first parent edge1290firstEdge = getParentEdges().front();1291} else {1292// defined over junctions1293return nullptr;1294}1295// get departLane index1296const int departLaneIndex = (int)getAttributeDouble(SUMO_ATTR_DEPARTLANE);1297// check departLane index1298if ((departLaneIndex >= 0) && (departLaneIndex < (int)firstEdge->getChildLanes().size())) {1299return firstEdge->getChildLanes().at(departLaneIndex);1300} else {1301// get first allowed VClass1302return firstEdge->getLaneByAllowedVClass(getVClass());1303}1304}130513061307GNELane*1308GNEVehicle::getLastPathLane() const {1309// declare last edge1310GNEEdge* lastEdge = nullptr;1311// continue depending of tags1312if (myTagProperty->vehicleRoute()) {1313// check arrivalEdge1314if ((arrivalEdge > 0) && (arrivalEdge < (int)getRouteParent()->getParentEdges().size())) {1315// use arrival edge1316lastEdge = getRouteParent()->getParentEdges().at(arrivalEdge);1317} else {1318// use last route edge1319lastEdge = getRouteParent()->getParentEdges().back();1320}1321} else if (myTagProperty->vehicleRouteEmbedded()) {1322// check if embedded route exist (due during loading embedded route doesn't exist)1323if (getChildDemandElements().empty()) {1324return nullptr;1325}1326// check arrivalEdge1327if ((arrivalEdge > 0) && (arrivalEdge < (int)getChildDemandElements().front()->getParentEdges().size())) {1328// use arrival edge1329lastEdge = getChildDemandElements().front()->getParentEdges().at(arrivalEdge);1330} else if (getChildDemandElements().front()->getParentEdges().size() > 0) {1331// use last route edge1332lastEdge = getChildDemandElements().front()->getParentEdges().back();1333} else if (getChildDemandElements().front()->getParentLanes().size() > 0) {1334// use lane1335lastEdge = getChildDemandElements().front()->getParentLanes().back()->getParentEdge();1336} else {1337return nullptr;1338}1339} else if (getParentEdges().size() > 0) {1340// use last parent edge1341lastEdge = getParentEdges().back();1342} else {1343// defined over junctions1344return nullptr;1345}1346// get arrivalLane index1347const int arrivalLaneIndex = (int)getAttributeDouble(SUMO_ATTR_ARRIVALLANE);1348// check arrivalLane index1349if ((arrivalLaneIndex >= 0) && (arrivalLaneIndex < (int)lastEdge->getChildLanes().size())) {1350return lastEdge->getChildLanes().at(arrivalLaneIndex);1351} else {1352// get last allowed VClass1353return lastEdge->getLaneByAllowedVClass(getVClass());1354}1355}135613571358std::string1359GNEVehicle::getAttribute(SumoXMLAttr key) const {1360switch (key) {1361case SUMO_ATTR_ID:1362return getMicrosimID();1363case SUMO_ATTR_TYPE:1364return vtypeid;1365case SUMO_ATTR_COLOR:1366if (wasSet(VEHPARS_COLOR_SET)) {1367return toString(color);1368} else {1369return myTagProperty->getDefaultStringValue(SUMO_ATTR_COLOR);1370}1371case SUMO_ATTR_DEPARTLANE:1372if (wasSet(VEHPARS_DEPARTLANE_SET)) {1373return getDepartLane();1374} else {1375return myTagProperty->getDefaultStringValue(SUMO_ATTR_DEPARTLANE);1376}1377case SUMO_ATTR_DEPARTPOS:1378if (wasSet(VEHPARS_DEPARTPOS_SET)) {1379return getDepartPos();1380} else {1381return myTagProperty->getDefaultStringValue(SUMO_ATTR_DEPARTPOS);1382}1383case SUMO_ATTR_DEPARTSPEED:1384if (wasSet(VEHPARS_DEPARTSPEED_SET)) {1385return getDepartSpeed();1386} else {1387return myTagProperty->getDefaultStringValue(SUMO_ATTR_DEPARTSPEED);1388}1389case SUMO_ATTR_ARRIVALLANE:1390if (wasSet(VEHPARS_ARRIVALLANE_SET)) {1391return getArrivalLane();1392} else {1393return myTagProperty->getDefaultStringValue(SUMO_ATTR_ARRIVALLANE);1394}1395case SUMO_ATTR_ARRIVALPOS:1396if (wasSet(VEHPARS_ARRIVALPOS_SET)) {1397return getArrivalPos();1398} else {1399return myTagProperty->getDefaultStringValue(SUMO_ATTR_ARRIVALPOS);1400}1401case SUMO_ATTR_ARRIVALSPEED:1402if (wasSet(VEHPARS_ARRIVALSPEED_SET)) {1403return getArrivalSpeed();1404} else {1405return myTagProperty->getDefaultStringValue(SUMO_ATTR_ARRIVALSPEED);1406}1407case SUMO_ATTR_LINE:1408if (wasSet(VEHPARS_LINE_SET)) {1409return line;1410} else {1411return myTagProperty->getDefaultStringValue(SUMO_ATTR_LINE);1412}1413case SUMO_ATTR_PERSON_NUMBER:1414if (wasSet(VEHPARS_PERSON_NUMBER_SET)) {1415return toString(personNumber);1416} else {1417return myTagProperty->getDefaultStringValue(SUMO_ATTR_PERSON_NUMBER);1418}1419case SUMO_ATTR_CONTAINER_NUMBER:1420if (wasSet(VEHPARS_CONTAINER_NUMBER_SET)) {1421return toString(containerNumber);1422} else {1423return myTagProperty->getDefaultStringValue(SUMO_ATTR_CONTAINER_NUMBER);1424}1425case SUMO_ATTR_REROUTE:1426if (wasSet(VEHPARS_CONTAINER_NUMBER_SET)) {1427return "true";1428} else {1429return "false";1430}1431case SUMO_ATTR_DEPARTPOS_LAT:1432if (wasSet(VEHPARS_DEPARTPOSLAT_SET)) {1433return getDepartPosLat();1434} else {1435return myTagProperty->getDefaultStringValue(SUMO_ATTR_DEPARTPOS_LAT);1436}1437case SUMO_ATTR_ARRIVALPOS_LAT:1438if (wasSet(VEHPARS_ARRIVALPOSLAT_SET)) {1439return getArrivalPosLat();1440} else {1441return myTagProperty->getDefaultStringValue(SUMO_ATTR_ARRIVALPOS_LAT);1442}1443case SUMO_ATTR_INSERTIONCHECKS:1444return getInsertionChecks();1445// Specific of vehicles over routes1446case SUMO_ATTR_ROUTE:1447if (getParentDemandElements().size() == 2) {1448return getRouteParent()->getID();1449} else {1450return "";1451}1452// Specific of from-to edge1453case SUMO_ATTR_FROM:1454return getParentEdges().front()->getID();1455case SUMO_ATTR_TO:1456return getParentEdges().back()->getID();1457case SUMO_ATTR_VIA:1458return toString(via);1459case SUMO_ATTR_DEPARTEDGE:1460if (departEdge == -1) {1461return "";1462} else {1463return toString(departEdge);1464}1465case SUMO_ATTR_ARRIVALEDGE:1466if (arrivalEdge == -1) {1467return "";1468} else {1469return toString(arrivalEdge);1470}1471// Specific of from-to junctions1472case SUMO_ATTR_FROM_JUNCTION:1473return getParentJunctions().front()->getID();1474case SUMO_ATTR_TO_JUNCTION:1475return getParentJunctions().back()->getID();1476// Specific of from-to tazs1477case SUMO_ATTR_FROM_TAZ:1478return getParentAdditionals().front()->getID();1479case SUMO_ATTR_TO_TAZ:1480return getParentAdditionals().back()->getID();1481// other1482case GNE_ATTR_FLOWPARAMETERS:1483return toString(parametersSet);1484default:1485return getFlowAttribute(this, key);1486}1487}148814891490double1491GNEVehicle::getAttributeDouble(SumoXMLAttr key) const {1492switch (key) {1493case SUMO_ATTR_DEPARTLANE:1494if (wasSet(VEHPARS_DEPARTLANE_SET) && (departLaneProcedure == DepartLaneDefinition::GIVEN)) {1495return departLane;1496} else {1497return -1;1498}1499case SUMO_ATTR_DEPARTPOS:1500// only return departPos it if is given1501if (departPosProcedure == DepartPosDefinition::GIVEN) {1502return departPos;1503} else {1504return 0;1505}1506case SUMO_ATTR_ARRIVALLANE:1507if (wasSet(VEHPARS_ARRIVALLANE_SET) && (arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN)) {1508return arrivalLane;1509} else {1510return -1;1511}1512case SUMO_ATTR_ARRIVALPOS:1513// only return departPos it if is given1514if (arrivalPosProcedure == ArrivalPosDefinition::GIVEN) {1515return arrivalPos;1516} else {1517return -1;1518}1519case SUMO_ATTR_WIDTH:1520case SUMO_ATTR_LENGTH:1521case SUMO_ATTR_MINGAP:1522return getTypeParent()->getAttributeDouble(key);1523default:1524return getFlowAttributeDouble(key);1525}1526}152715281529Position1530GNEVehicle::getAttributePosition(SumoXMLAttr key) const {1531switch (key) {1532case GNE_ATTR_PLAN_GEOMETRY_STARTPOS: {1533// check if this vehicle was defined over junctions1534if (getParentJunctions().size() > 0) {1535return getParentJunctions().front()->getPositionInView();1536} else {1537// get first path lane shape1538const PositionVector& laneShape = getFirstPathLane()->getLaneShape();1539// check arrivalPosProcedure1540if (departPosProcedure == DepartPosDefinition::GIVEN) {1541if (departPos < 0) {1542return laneShape.front();1543} else if (departPos > laneShape.length2D()) {1544return laneShape.back();1545} else {1546return laneShape.positionAtOffset2D(departPos);1547}1548} else {1549return laneShape.front();1550}1551}1552}1553case GNE_ATTR_PLAN_GEOMETRY_ENDPOS: {1554// check if this vehicle was defined over junctions1555if (getParentJunctions().size() > 0) {1556return getParentJunctions().back()->getPositionInView();1557} else {1558// get last path lane shape1559const PositionVector& laneShape = getLastPathLane()->getLaneShape();1560// check arrivalPosProcedure1561if (arrivalPosProcedure == ArrivalPosDefinition::GIVEN) {1562if (arrivalPos < 0) {1563return laneShape.front();1564} else if (arrivalPos > laneShape.length2D()) {1565return laneShape.back();1566} else {1567return laneShape.positionAtOffset2D(arrivalPos);1568}1569} else {1570return laneShape.back();1571}1572}1573}1574default:1575return getCommonAttributePosition(key);1576}1577}157815791580void1581GNEVehicle::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {1582if (value == getAttribute(key)) {1583return; //avoid needless changes, later logic relies on the fact that attributes have changed1584}1585switch (key) {1586case SUMO_ATTR_ID:1587case SUMO_ATTR_TYPE:1588case SUMO_ATTR_COLOR:1589case SUMO_ATTR_DEPARTLANE:1590case SUMO_ATTR_DEPARTPOS:1591case SUMO_ATTR_DEPARTSPEED:1592case SUMO_ATTR_ARRIVALLANE:1593case SUMO_ATTR_ARRIVALPOS:1594case SUMO_ATTR_ARRIVALSPEED:1595case SUMO_ATTR_LINE:1596case SUMO_ATTR_PERSON_NUMBER:1597case SUMO_ATTR_CONTAINER_NUMBER:1598case SUMO_ATTR_REROUTE:1599case SUMO_ATTR_DEPARTPOS_LAT:1600case SUMO_ATTR_ARRIVALPOS_LAT:1601case SUMO_ATTR_INSERTIONCHECKS:1602// Specific of vehicles over routes1603case SUMO_ATTR_ROUTE:1604// Specific of from-to edges1605case SUMO_ATTR_FROM:1606case SUMO_ATTR_TO:1607case SUMO_ATTR_VIA:1608case SUMO_ATTR_DEPARTEDGE:1609case SUMO_ATTR_ARRIVALEDGE:1610// Specific of from-to junctions1611case SUMO_ATTR_FROM_JUNCTION:1612case SUMO_ATTR_TO_JUNCTION:1613// Specific of from-to taz1614case SUMO_ATTR_FROM_TAZ:1615case SUMO_ATTR_TO_TAZ:1616GNEChange_Attribute::changeAttribute(this, key, value, undoList);1617break;1618default:1619setFlowAttribute(this, key, value, undoList);1620break;1621}1622}162316241625bool1626GNEVehicle::isValid(SumoXMLAttr key, const std::string& value) {1627// get ACs1628const auto ACs = myNet->getAttributeCarriers();1629// declare string error1630std::string error;1631switch (key) {1632case SUMO_ATTR_ID:1633return isValidDemandElementID(NamespaceIDs::vehicles, value);1634case SUMO_ATTR_TYPE:1635return (myNet->getAttributeCarriers()->retrieveDemandElements(NamespaceIDs::types, value, false) != nullptr);1636case SUMO_ATTR_COLOR:1637return canParse<RGBColor>(value);1638case SUMO_ATTR_DEPARTLANE: {1639int dummyDepartLane;1640DepartLaneDefinition dummyDepartLaneProcedure;1641parseDepartLane(value, myTagProperty->getTagStr(), id, dummyDepartLane, dummyDepartLaneProcedure, error);1642// if error is empty, check if depart lane is correct1643if (error.empty()) {1644if (dummyDepartLaneProcedure != DepartLaneDefinition::GIVEN) {1645return true;1646} else if (isTemplate()) {1647return true;1648} else if (getParentJunctions().size() > 0) {1649return (dummyDepartLane == 0);1650} else if (getParentAdditionals().size() > 0) {1651return (dummyDepartLane == 0);1652} else {1653return dummyDepartLane < (int)getFirstPathLane()->getParentEdge()->getChildLanes().size();1654}1655} else {1656return false;1657}1658}1659case SUMO_ATTR_DEPARTPOS: {1660double dummyDepartPos;1661DepartPosDefinition dummyDepartPosProcedure;1662parseDepartPos(value, myTagProperty->getTagStr(), id, dummyDepartPos, dummyDepartPosProcedure, error);1663// if error is empty, given value is valid1664return error.empty();1665}1666case SUMO_ATTR_DEPARTSPEED: {1667double dummyDepartSpeed;1668DepartSpeedDefinition dummyDepartSpeedProcedure;1669parseDepartSpeed(value, myTagProperty->getTagStr(), id, dummyDepartSpeed, dummyDepartSpeedProcedure, error);1670// if error is empty, check if depart speed is correct1671if (error.empty()) {1672if (dummyDepartSpeedProcedure != DepartSpeedDefinition::GIVEN) {1673return true;1674} else if (isTemplate()) {1675return true;1676} else {1677return (dummyDepartSpeed <= getTypeParent()->getAttributeDouble(SUMO_ATTR_MAXSPEED));1678}1679} else {1680return false;1681}1682}1683case SUMO_ATTR_ARRIVALLANE: {1684int dummyArrivalLane;1685ArrivalLaneDefinition dummyArrivalLaneProcedure;1686parseArrivalLane(value, myTagProperty->getTagStr(), id, dummyArrivalLane, dummyArrivalLaneProcedure, error);1687// if error is empty, given value is valid1688if (error.empty()) {1689if (dummyArrivalLaneProcedure != ArrivalLaneDefinition::GIVEN) {1690return true;1691} else if (isTemplate()) {1692return true;1693} else if (getParentJunctions().size() > 0) {1694return (dummyArrivalLane == 0);1695} else if (getParentAdditionals().size() > 0) {1696return (dummyArrivalLane == 0);1697} else {1698return dummyArrivalLane < (int)getLastPathLane()->getParentEdge()->getChildLanes().size();1699}1700} else {1701return false;1702}1703}1704case SUMO_ATTR_ARRIVALPOS: {1705double dummyArrivalPos;1706ArrivalPosDefinition dummyArrivalPosProcedure;1707parseArrivalPos(value, myTagProperty->getTagStr(), id, dummyArrivalPos, dummyArrivalPosProcedure, error);1708// if error is empty, given value is valid1709return error.empty();1710}1711case SUMO_ATTR_ARRIVALSPEED: {1712double dummyArrivalSpeed;1713ArrivalSpeedDefinition dummyArrivalSpeedProcedure;1714parseArrivalSpeed(value, myTagProperty->getTagStr(), id, dummyArrivalSpeed, dummyArrivalSpeedProcedure, error);1715// if error is empty, given value is valid1716return error.empty();1717}1718case SUMO_ATTR_LINE:1719return true;1720case SUMO_ATTR_PERSON_NUMBER:1721return canParse<int>(value) && parse<int>(value) >= 0;1722case SUMO_ATTR_CONTAINER_NUMBER:1723return canParse<int>(value) && parse<int>(value) >= 0;1724case SUMO_ATTR_REROUTE:1725return true; // check1726case SUMO_ATTR_DEPARTPOS_LAT: {1727double dummyDepartPosLat;1728DepartPosLatDefinition dummyDepartPosLatProcedure;1729parseDepartPosLat(value, myTagProperty->getTagStr(), id, dummyDepartPosLat, dummyDepartPosLatProcedure, error);1730// if error is empty, given value is valid1731return error.empty();1732}1733case SUMO_ATTR_ARRIVALPOS_LAT: {1734double dummyArrivalPosLat;1735ArrivalPosLatDefinition dummyArrivalPosLatProcedure;1736parseArrivalPosLat(value, myTagProperty->getTagStr(), id, dummyArrivalPosLat, dummyArrivalPosLatProcedure, error);1737// if error is empty, given value is valid1738return error.empty();1739}1740case SUMO_ATTR_INSERTIONCHECKS:1741return areInsertionChecksValid(value);1742// Specific of vehicles over routes1743case SUMO_ATTR_ROUTE:1744if (getParentDemandElements().size() == 2) {1745return (myNet->getAttributeCarriers()->retrieveDemandElements(NamespaceIDs::routes, value, false) != nullptr);1746} else {1747return true;1748}1749// Specific of from-to edges1750case SUMO_ATTR_FROM:1751case SUMO_ATTR_TO:1752return (ACs->retrieveEdge(value, false) != nullptr);1753case SUMO_ATTR_DEPARTEDGE:1754case SUMO_ATTR_ARRIVALEDGE: {1755if (value.empty()) {1756return true;1757} else if (canParse<int>(value)) {1758// get index1759const int index = parse<int>(value);1760// check conditions1761if (index < 0) {1762return false;1763} else if (myTagProperty->vehicleRoute()) {1764// check parent route1765return (index < (int)getRouteParent()->getParentEdges().size());1766} else {1767// check embedded route1768return (index < (int)getChildDemandElements().front()->getParentEdges().size());1769}1770} else {1771return false;1772}1773}1774case SUMO_ATTR_VIA:1775return canParse<std::vector<GNEEdge*> >(myNet, value, false);1776// Specific of from-to junctions1777case SUMO_ATTR_FROM_JUNCTION:1778case SUMO_ATTR_TO_JUNCTION:1779return (ACs->retrieveJunction(value, false) != nullptr);1780// Specific of from-to taz1781case SUMO_ATTR_FROM_TAZ:1782case SUMO_ATTR_TO_TAZ:1783return (ACs->retrieveAdditional(SUMO_TAG_TAZ, value, false) != nullptr);1784default:1785return isValidFlowAttribute(this, key, value);1786}1787}178817891790void1791GNEVehicle::enableAttribute(SumoXMLAttr key, GNEUndoList* undoList) {1792enableFlowAttribute(this, key, undoList);1793}179417951796void1797GNEVehicle::disableAttribute(SumoXMLAttr key, GNEUndoList* undoList) {1798disableFlowAttribute(this, key, undoList);1799}180018011802bool1803GNEVehicle::isAttributeEnabled(SumoXMLAttr key) const {1804return isFlowAttributeEnabled(key);1805}180618071808std::string1809GNEVehicle::getPopUpID() const {1810return getTagStr();1811}181218131814std::string1815GNEVehicle::getHierarchyName() const {1816const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();1817// special case for Trips and flow1818if (myTagProperty->vehicleEdges()) {1819// check if we're inspecting a Edge1820if (inspectedElements.getFirstAC() && (inspectedElements.getFirstAC()->getTagProperty()->getTag() == SUMO_TAG_EDGE)) {1821// check if edge correspond to a "from", "to" or "via" edge1822if (inspectedElements.isACInspected(getParentEdges().front())) {1823return getTagStr() + ": " + getAttribute(SUMO_ATTR_ID) + " (from)";1824} else if (inspectedElements.isACInspected(getParentEdges().front())) {1825return getTagStr() + ": " + getAttribute(SUMO_ATTR_ID) + " (to)";1826} else {1827// iterate over via1828for (const auto& viaEdgeID : via) {1829if (viaEdgeID == inspectedElements.getFirstAC()->getID()) {1830return getTagStr() + ": " + getAttribute(SUMO_ATTR_ID) + " (via)";1831}1832}1833}1834}1835}1836return getTagStr() + ": " + getAttribute(SUMO_ATTR_ID);1837}183818391840GNEDemandElement*1841GNEVehicle::copyVehicle(const GNEVehicle* originalVehicle) {1842// get net and undoList1843const auto net = originalVehicle->getNet();1844auto undoList = net->getViewNet()->getUndoList();1845// declare new route, vehicle and embedded route1846GNERoute* newRoute = nullptr;1847GNEVehicle* newVehicle = nullptr;1848GNERoute* newEmbeddedRoute = nullptr;1849// generate new vehicle ID1850const std::string newRouteID = net->getAttributeCarriers()->generateDemandElementID(SUMO_TAG_ROUTE);1851const std::string newVehicleID = net->getAttributeCarriers()->generateDemandElementID(originalVehicle->getTagProperty()->getTag());1852// extract vehicle parameters and update ID1853auto newVehicleParameters = originalVehicle->getSUMOVehicleParameter();1854newVehicleParameters.id = newVehicleID;1855// create vehicle using vehicleParameters1856if (originalVehicle->getTagProperty()->vehicleRoute()) {1857newRoute = new GNERoute(newRouteID, originalVehicle->getParentDemandElements().at(1));1858newVehicle = new GNEVehicle(originalVehicle->getTagProperty()->getTag(), net,1859originalVehicle->getFileBucket(),1860originalVehicle->getParentDemandElements().at(0), newRoute,1861newVehicleParameters);1862} else if (originalVehicle->getTagProperty()->vehicleRouteEmbedded()) {1863newVehicle = new GNEVehicle(originalVehicle->getTagProperty()->getTag(), net,1864originalVehicle->getFileBucket(),1865originalVehicle->getParentDemandElements().at(0),1866newVehicleParameters);1867newEmbeddedRoute = new GNERoute(newVehicle, originalVehicle->getChildDemandElements().front());1868} else if (originalVehicle->getTagProperty()->vehicleEdges()) {1869newVehicle = new GNEVehicle(originalVehicle->getTagProperty()->getTag(), net,1870originalVehicle->getFileBucket(),1871originalVehicle->getParentDemandElements().at(0),1872originalVehicle->getParentEdges().front(),1873originalVehicle->getParentEdges().back(),1874newVehicleParameters);1875} else if (originalVehicle->getTagProperty()->vehicleJunctions()) {1876newVehicle = new GNEVehicle(originalVehicle->getTagProperty()->getTag(), net,1877originalVehicle->getFileBucket(),1878originalVehicle->getParentDemandElements().at(0),1879originalVehicle->getParentJunctions().front(),1880originalVehicle->getParentJunctions().back(),1881newVehicleParameters);1882} else if (originalVehicle->getTagProperty()->vehicleTAZs()) {1883newVehicle = new GNEVehicle(originalVehicle->getTagProperty()->getTag(), net,1884originalVehicle->getFileBucket(),1885originalVehicle->getParentDemandElements().at(0),1886originalVehicle->getParentAdditionals().front(),1887originalVehicle->getParentAdditionals().back(),1888newVehicleParameters);1889}1890// add new vehicle1891undoList->begin(originalVehicle, TLF("copy % '%'", newVehicle->getTagStr(), newVehicleID));1892if (newRoute) {1893net->getViewNet()->getUndoList()->add(new GNEChange_DemandElement(newRoute, true), true);1894}1895undoList->add(new GNEChange_DemandElement(newVehicle, true), true);1896if (newEmbeddedRoute) {1897net->getViewNet()->getUndoList()->add(new GNEChange_DemandElement(newEmbeddedRoute, true), true);1898}1899undoList->end();1900return newVehicle;1901}19021903// ===========================================================================1904// protected1905// ===========================================================================19061907RGBColor1908GNEVehicle::getDrawingColor(const GUIVisualizationSettings& s) const {1909// change color1910if (drawUsingSelectColor()) {1911return s.colorSettings.selectedVehicleColor;1912} else {1913return getColorByScheme(s.vehicleColorer, this);1914}1915}191619171918const SUMOVehicleParameter&1919GNEVehicle::getSUMOVehicleParameter() const {1920return *this;1921}19221923// ===========================================================================1924// private1925// ===========================================================================19261927void1928GNEVehicle::setAttribute(SumoXMLAttr key, const std::string& value) {1929// declare string error1930std::string error;1931// flag to upate stack label1932bool updateSpreadStackGeometry = false;1933switch (key) {1934case SUMO_ATTR_ID:1935// update microsimID1936setDemandElementID(value);1937// set manually vehicle ID (needed for saving)1938id = value;1939break;1940case SUMO_ATTR_TYPE:1941if (getID().size() > 0) {1942replaceDemandElementParent(NamespaceIDs::types, value, 0);1943// set manually vtypeID (needed for saving)1944vtypeid = value;1945}1946break;1947case SUMO_ATTR_COLOR:1948if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {1949color = parse<RGBColor>(value);1950// mark parameter as set1951parametersSet |= VEHPARS_COLOR_SET;1952} else {1953// set default value1954color = myTagProperty->getDefaultColorValue(key);1955// unset parameter1956parametersSet &= ~VEHPARS_COLOR_SET;1957}1958break;1959case SUMO_ATTR_DEPARTLANE:1960if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {1961parseDepartLane(value, myTagProperty->getTagStr(), id, departLane, departLaneProcedure, error);1962// mark parameter as set1963parametersSet |= VEHPARS_DEPARTLANE_SET;1964} else {1965// set default value1966parseDepartLane(myTagProperty->getDefaultStringValue(key), myTagProperty->getTagStr(), id, departLane, departLaneProcedure, error);1967// unset parameter1968parametersSet &= ~VEHPARS_DEPARTLANE_SET;1969}1970break;1971case SUMO_ATTR_DEPARTPOS:1972if (value == toString(INVALID_DOUBLE)) {1973parseDepartPos(value, myTagProperty->getTagStr(), id, departPos, departPosProcedure, error);1974// mark parameter as set1975parametersSet |= VEHPARS_DEPARTPOS_SET;1976} else if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {1977parseDepartPos(value, myTagProperty->getTagStr(), id, departPos, departPosProcedure, error);1978// mark parameter as set1979parametersSet |= VEHPARS_DEPARTPOS_SET;1980} else {1981// set default value1982parseDepartPos(myTagProperty->getDefaultStringValue(key), myTagProperty->getTagStr(), id, departPos, departPosProcedure, error);1983// unset parameter1984parametersSet &= ~VEHPARS_DEPARTPOS_SET;1985}1986if (getID().size() > 0) {1987updateGeometry();1988updateSpreadStackGeometry = true;1989}1990break;1991case SUMO_ATTR_DEPARTSPEED:1992if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {1993parseDepartSpeed(value, myTagProperty->getTagStr(), id, departSpeed, departSpeedProcedure, error);1994// mark parameter as set1995parametersSet |= VEHPARS_DEPARTSPEED_SET;1996} else {1997// set default value1998parseDepartSpeed(myTagProperty->getDefaultStringValue(key), myTagProperty->getTagStr(), id, departSpeed, departSpeedProcedure, error);1999// unset parameter2000parametersSet &= ~VEHPARS_DEPARTSPEED_SET;2001}2002break;2003case SUMO_ATTR_ARRIVALLANE:2004if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {2005parseArrivalLane(value, myTagProperty->getTagStr(), id, arrivalLane, arrivalLaneProcedure, error);2006// mark parameter as set2007parametersSet |= VEHPARS_ARRIVALLANE_SET;2008} else {2009// set default value2010parseArrivalLane(myTagProperty->getDefaultStringValue(key), myTagProperty->getTagStr(), id, arrivalLane, arrivalLaneProcedure, error);2011// unset parameter2012parametersSet &= ~VEHPARS_ARRIVALLANE_SET;2013}2014break;2015case SUMO_ATTR_ARRIVALPOS:2016if (value == toString(INVALID_DOUBLE)) {2017parseArrivalPos("max", myTagProperty->getTagStr(), id, arrivalPos, arrivalPosProcedure, error);2018// mark parameter as set2019parametersSet |= VEHPARS_ARRIVALPOS_SET;2020} else if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {2021parseArrivalPos(value, myTagProperty->getTagStr(), id, arrivalPos, arrivalPosProcedure, error);2022// mark parameter as set2023parametersSet |= VEHPARS_ARRIVALPOS_SET;2024} else {2025// set default value2026parseArrivalPos(myTagProperty->getDefaultStringValue(key), myTagProperty->getTagStr(), id, arrivalPos, arrivalPosProcedure, error);2027// unset parameter2028parametersSet &= ~VEHPARS_ARRIVALPOS_SET;2029}2030if (getID().size() > 0) {2031updateGeometry();2032updateSpreadStackGeometry = true;2033}2034break;2035case SUMO_ATTR_ARRIVALSPEED:2036if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {2037parseArrivalSpeed(value, myTagProperty->getTagStr(), id, arrivalSpeed, arrivalSpeedProcedure, error);2038// mark parameter as set2039parametersSet |= VEHPARS_ARRIVALSPEED_SET;2040} else {2041// set default value2042parseArrivalSpeed(myTagProperty->getDefaultStringValue(key), myTagProperty->getTagStr(), id, arrivalSpeed, arrivalSpeedProcedure, error);2043// unset parameter2044parametersSet &= ~VEHPARS_ARRIVALSPEED_SET;2045}2046break;2047case SUMO_ATTR_LINE:2048if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {2049line = value;2050// mark parameter as set2051parametersSet |= VEHPARS_LINE_SET;2052} else {2053// set default value2054line = myTagProperty->getDefaultStringValue(key);2055// unset parameter2056parametersSet &= ~VEHPARS_LINE_SET;2057}2058break;2059case SUMO_ATTR_PERSON_NUMBER:2060if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {2061personNumber = parse<int>(value);2062// mark parameter as set2063parametersSet |= VEHPARS_PERSON_NUMBER_SET;2064} else {2065// set default value2066personNumber = myTagProperty->getDefaultIntValue(key);2067// unset parameter2068parametersSet &= ~VEHPARS_PERSON_NUMBER_SET;2069}2070break;2071case SUMO_ATTR_CONTAINER_NUMBER:2072if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {2073containerNumber = parse<int>(value);2074// mark parameter as set2075parametersSet |= VEHPARS_CONTAINER_NUMBER_SET;2076} else {2077// set default value2078containerNumber = myTagProperty->getDefaultIntValue(key);2079// unset parameter2080parametersSet &= ~VEHPARS_CONTAINER_NUMBER_SET;2081}2082break;2083case SUMO_ATTR_REROUTE:2084if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {2085// mark parameter as set2086parametersSet |= VEHPARS_ROUTE_SET;2087} else {2088// unset parameter2089parametersSet &= ~VEHPARS_ROUTE_SET;2090}2091break;2092case SUMO_ATTR_DEPARTPOS_LAT:2093if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {2094parseDepartPosLat(value, myTagProperty->getTagStr(), id, departPosLat, departPosLatProcedure, error);2095// mark parameter as set2096parametersSet |= VEHPARS_DEPARTPOSLAT_SET;2097} else {2098// set default value2099parseDepartPosLat(myTagProperty->getDefaultStringValue(key), myTagProperty->getTagStr(), id, departPosLat, departPosLatProcedure, error);2100// unset parameter2101parametersSet &= ~VEHPARS_DEPARTPOSLAT_SET;2102}2103break;2104case SUMO_ATTR_ARRIVALPOS_LAT:2105if (!value.empty() && (value != myTagProperty->getDefaultStringValue(key))) {2106parseArrivalPosLat(value, myTagProperty->getTagStr(), id, arrivalPosLat, arrivalPosLatProcedure, error);2107// mark parameter as set2108parametersSet |= VEHPARS_ARRIVALPOSLAT_SET;2109} else {2110// set default value2111parseArrivalPosLat(myTagProperty->getDefaultStringValue(key), myTagProperty->getTagStr(), id, arrivalPosLat, arrivalPosLatProcedure, error);2112// unset parameter2113parametersSet &= ~VEHPARS_ARRIVALPOSLAT_SET;2114}2115parseArrivalPosLat(value, myTagProperty->getTagStr(), id, arrivalPosLat, arrivalPosLatProcedure, error);2116break;2117case SUMO_ATTR_INSERTIONCHECKS:2118if (value.empty() || (value == "all")) {2119// unset parameter2120parametersSet &= ~VEHPARS_INSERTION_CHECKS_SET;2121} else {2122// mark parameter as set2123parametersSet |= VEHPARS_INSERTION_CHECKS_SET;2124}2125insertionChecks = parseInsertionChecks(value);2126break;2127// Specific of vehicles over routes2128case SUMO_ATTR_ROUTE:2129if (getParentDemandElements().size() == 2) {2130replaceDemandElementParent(NamespaceIDs::routes, value, 1);2131}2132updateGeometry();2133updateSpreadStackGeometry = true;2134break;2135// Specific of from-to edges2136case SUMO_ATTR_FROM: {2137// change first edge2138replaceFirstParentEdge(value);2139// compute vehicle2140computePathElement();2141updateSpreadStackGeometry = true;2142break;2143}2144case SUMO_ATTR_TO: {2145// change last edge2146replaceLastParentEdge(value);2147// compute vehicle2148computePathElement();2149updateSpreadStackGeometry = true;2150break;2151}2152case SUMO_ATTR_VIA: {2153if (!value.empty()) {2154// set new via edges2155via = parse< std::vector<std::string> >(value);2156// mark parameter as set2157parametersSet |= VEHPARS_VIA_SET;2158} else {2159// clear via2160via.clear();2161// unset parameter2162parametersSet &= ~VEHPARS_VIA_SET;2163}2164// compute vehicle2165computePathElement();2166updateSpreadStackGeometry = true;2167break;2168}2169case SUMO_ATTR_DEPARTEDGE: {2170// update depart edge2171if (value.empty()) {2172// unset parameter2173parametersSet &= ~VEHPARS_DEPARTEDGE_SET;2174departEdge = -1;2175departEdgeProcedure = RouteIndexDefinition::DEFAULT;2176} else {2177// mark parameter as set2178parametersSet |= VEHPARS_DEPARTEDGE_SET;2179departEdge = parse<int>(value);2180departEdgeProcedure = RouteIndexDefinition::GIVEN;2181}2182// compute vehicle2183if (getID().size() > 0) {2184computePathElement();2185updateSpreadStackGeometry = true;2186}2187break;2188}2189case SUMO_ATTR_ARRIVALEDGE: {2190// update arrival edge2191if (value.empty()) {2192// unset parameter2193parametersSet &= ~VEHPARS_ARRIVALEDGE_SET;2194arrivalEdge = -1;2195arrivalEdgeProcedure = RouteIndexDefinition::DEFAULT;2196} else {2197// mark parameter as set2198parametersSet |= VEHPARS_ARRIVALEDGE_SET;2199arrivalEdge = parse<int>(value);2200arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;2201}2202if (getID().size() > 0) {2203// compute vehicle2204computePathElement();2205updateSpreadStackGeometry = true;2206}2207break;2208}2209// Specific of from-to junctions2210case SUMO_ATTR_FROM_JUNCTION: {2211// change first junction2212replaceFirstParentJunction(value);2213// compute vehicle2214computePathElement();2215updateSpreadStackGeometry = true;2216break;2217}2218case SUMO_ATTR_TO_JUNCTION: {2219// change last junction2220replaceLastParentJunction(value);2221// compute vehicle2222computePathElement();2223updateSpreadStackGeometry = true;2224break;2225}2226// Specific of from-to TAZs2227case SUMO_ATTR_FROM_TAZ: {2228// change first additional2229replaceFirstParentAdditional(SUMO_TAG_TAZ, value);2230// set taz manually2231fromTaz = value;2232// compute vehicle2233computePathElement();2234updateSpreadStackGeometry = true;2235break;2236}2237case SUMO_ATTR_TO_TAZ: {2238// change last additional2239replaceLastParentAdditional(SUMO_TAG_TAZ, value);2240// set taz manually2241toTaz = value;2242// compute vehicle2243computePathElement();2244updateSpreadStackGeometry = true;2245break;2246}2247default:2248setFlowAttribute(this, key, value);2249break;2250}2251// check if stack label has to be updated2252if (updateSpreadStackGeometry) {2253if (myTagProperty->vehicleEdges()) {2254getParentEdges().front()->updateVehicleStackLabels();2255getParentEdges().front()->updateVehicleSpreadGeometries();2256} else if (myTagProperty->vehicleRoute() && !getRouteParent()->getTagProperty()->isRouteDistribution()) {2257getRouteParent()->getParentEdges().front()->updateVehicleStackLabels();2258getRouteParent()->getParentEdges().front()->updateVehicleSpreadGeometries();2259} else if (myTagProperty->vehicleRouteEmbedded()) {2260getChildDemandElements().front()->getParentEdges().front()->updateVehicleStackLabels();2261getChildDemandElements().front()->getParentEdges().front()->updateVehicleSpreadGeometries();2262}2263}2264}226522662267void2268GNEVehicle::toggleAttribute(SumoXMLAttr key, const bool value) {2269// toggle flow attributes2270toggleFlowAttribute(key, value);2271}22722273/****************************************************************************/227422752276