Path: blob/main/src/netedit/elements/demand/GNEDemandElementFlow.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 GNEDemandElementFlow.cpp14/// @author Pablo Alvarez Lopez15/// @date Jul 202316///17// An auxiliar, asbtract class for flow elements (vehicles, person and containers)18/****************************************************************************/1920#include <netedit/GNETagProperties.h>21#include <netedit/GNEUndoList.h>22#include <netedit/changes/GNEChange_Attribute.h>23#include <netedit/changes/GNEChange_ToggleAttribute.h>24#include <utils/gui/div/GLHelper.h>2526#include "GNEDemandElementFlow.h"2728// ===========================================================================29// member method definitions30// ===========================================================================3132GNEDemandElementFlow::GNEDemandElementFlow(GNEDemandElement* flowElement) {33// set default flow attributes34setDefaultFlowAttributes(flowElement);35}363738GNEDemandElementFlow::GNEDemandElementFlow(GNEDemandElement* flowElement, const SUMOVehicleParameter& vehicleParameters) :39SUMOVehicleParameter(vehicleParameters) {40// set default flow attributes41setDefaultFlowAttributes(flowElement);42}434445GNEDemandElementFlow::~GNEDemandElementFlow() {}464748void49GNEDemandElementFlow::drawFlowLabel(const Position& position, const double rotation, const double width,50const double length, const double exaggeration) const {51// declare contour width52const double contourWidth = (0.05 * exaggeration);53// Push matrix54GLHelper::pushMatrix();55// Traslate to bot56glTranslated(position.x(), position.y(), GLO_VEHICLELABELS);57// glTranslated(position.x(), position.y(), GLO_ROUTE + getType() + 0.1 + GLO_PERSONFLOW + 0.1);58glRotated(rotation, 0, 0, -1);59glTranslated(-1 * ((width * 0.5 * exaggeration) + (0.35 * exaggeration)) - 0.05, 0, 0);60// draw external box61GLHelper::setColor(RGBColor::GREY);62GLHelper::drawBoxLine(Position(), Position(), 0, (length * exaggeration), 0.3 * exaggeration);63// draw internal box64glTranslated(0, 0, 0.1);65GLHelper::setColor(RGBColor::CYAN);66GLHelper::drawBoxLine(Position(0, -contourWidth), Position(0, -contourWidth), 0, (length * exaggeration) - (contourWidth * 2), (0.3 * exaggeration) - contourWidth);67// draw stack label68GLHelper::drawText("Flow", Position(0, length * exaggeration * -0.5), (.1 * exaggeration), (0.6 * exaggeration), RGBColor::BLACK, 90, 0, -1);69// pop draw matrix70GLHelper::popMatrix();71}727374std::string75GNEDemandElementFlow::getFlowAttribute(const GNEDemandElement* flowElement, SumoXMLAttr key) const {76switch (key) {77case SUMO_ATTR_DEPART:78case SUMO_ATTR_BEGIN:79if (departProcedure == DepartDefinition::TRIGGERED) {80return "triggered";81} else if (departProcedure == DepartDefinition::CONTAINER_TRIGGERED) {82return "containerTriggered";83} else if (departProcedure == DepartDefinition::NOW) {84return "now";85} else if (departProcedure == DepartDefinition::SPLIT) {86return "split";87} else if (departProcedure == DepartDefinition::BEGIN) {88return "begin";89} else {90return time2string(depart);91}92case SUMO_ATTR_END:93return time2string(repetitionEnd);94case SUMO_ATTR_VEHSPERHOUR:95case SUMO_ATTR_PERSONSPERHOUR:96case SUMO_ATTR_CONTAINERSPERHOUR:97return StringUtils::adjustDecimalValue(3600 / STEPS2TIME(repetitionOffset), 2);98case SUMO_ATTR_PERIOD:99return time2string(repetitionOffset);100case GNE_ATTR_POISSON:101return StringUtils::adjustDecimalValue(poissonRate, 10);102case SUMO_ATTR_PROB:103return StringUtils::adjustDecimalValue(repetitionProbability, 20);104case SUMO_ATTR_NUMBER:105return toString(repetitionNumber);106case GNE_ATTR_FLOW_TERMINATE:107if (isFlowAttributeEnabled(SUMO_ATTR_END)) {108if (isFlowAttributeEnabled(SUMO_ATTR_NUMBER)) {109return toString(SUMO_ATTR_END) + "-" + toString(SUMO_ATTR_NUMBER);110} else {111return toString(SUMO_ATTR_END);112}113} else if (isFlowAttributeEnabled(SUMO_ATTR_NUMBER)) {114return toString(SUMO_ATTR_NUMBER);115} else {116return "invalid terminate";117}118case GNE_ATTR_FLOW_SPACING:119if (flowElement->getTagProperty()->hasAttribute(SUMO_ATTR_VEHSPERHOUR) && isFlowAttributeEnabled(SUMO_ATTR_VEHSPERHOUR)) {120return toString(SUMO_ATTR_VEHSPERHOUR);121} else if (flowElement->getTagProperty()->hasAttribute(SUMO_ATTR_PERSONSPERHOUR) && isFlowAttributeEnabled(SUMO_ATTR_PERSONSPERHOUR)) {122return toString(SUMO_ATTR_PERSONSPERHOUR);123} else if (flowElement->getTagProperty()->hasAttribute(SUMO_ATTR_CONTAINERSPERHOUR) && isFlowAttributeEnabled(SUMO_ATTR_CONTAINERSPERHOUR)) {124return toString(SUMO_ATTR_CONTAINERSPERHOUR);125} else if (isFlowAttributeEnabled(SUMO_ATTR_PERIOD)) {126return toString(SUMO_ATTR_PERIOD);127} else if (isFlowAttributeEnabled(SUMO_ATTR_PROB)) {128return toString(SUMO_ATTR_PROB);129} else if (isFlowAttributeEnabled(GNE_ATTR_POISSON)) {130return toString(GNE_ATTR_POISSON);131} else {132return "invalid flow spacing";133}134default:135return flowElement->getCommonAttribute(key);136}137}138139140double141GNEDemandElementFlow::getFlowAttributeDouble(SumoXMLAttr key) const {142switch (key) {143case SUMO_ATTR_DEPART:144case SUMO_ATTR_BEGIN:145return STEPS2TIME(depart);146default:147throw InvalidArgument("Flow doesn't have a double attribute of type '" + toString(key) + "'");148}149}150151152void153GNEDemandElementFlow::setFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {154switch (key) {155case SUMO_ATTR_DEPART:156case SUMO_ATTR_BEGIN:157case SUMO_ATTR_END:158case SUMO_ATTR_NUMBER:159case SUMO_ATTR_VEHSPERHOUR:160case SUMO_ATTR_PERSONSPERHOUR:161case SUMO_ATTR_CONTAINERSPERHOUR:162case SUMO_ATTR_PERIOD:163case GNE_ATTR_POISSON:164case SUMO_ATTR_PROB:165case GNE_ATTR_FLOW_TERMINATE:166case GNE_ATTR_FLOW_SPACING:167GNEChange_Attribute::changeAttribute(flowElement, key, value, undoList);168break;169default:170return flowElement->setCommonAttribute(key, value, undoList);171}172}173174175bool176GNEDemandElementFlow::isValidFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, const std::string& value) {177// declare string error178std::string error;179switch (key) {180case SUMO_ATTR_DEPART:181case SUMO_ATTR_BEGIN: {182SUMOTime dummyDepart;183DepartDefinition dummyDepartProcedure;184parseDepart(value, flowElement->getTagProperty()->getTagStr(), id, dummyDepart, dummyDepartProcedure, error);185// if error is empty, given value is valid186return error.empty();187}188case SUMO_ATTR_END:189if (GNEAttributeCarrier::canParse<SUMOTime>(value)) {190return (GNEAttributeCarrier::parse<SUMOTime>(value) >= 0);191} else {192return false;193}194case SUMO_ATTR_VEHSPERHOUR:195case SUMO_ATTR_PERSONSPERHOUR:196case SUMO_ATTR_CONTAINERSPERHOUR:197case SUMO_ATTR_PERIOD:198case GNE_ATTR_POISSON:199if (GNEAttributeCarrier::canParse<double>(value)) {200return (GNEAttributeCarrier::parse<double>(value) > 0);201} else {202return false;203}204case SUMO_ATTR_PROB:205if (GNEAttributeCarrier::canParse<double>(value)) {206const double prob = GNEAttributeCarrier::parse<double>(value);207return ((prob >= 0) && (prob <= 1));208} else {209return false;210}211case SUMO_ATTR_NUMBER:212if (GNEAttributeCarrier::canParse<int>(value)) {213return (GNEAttributeCarrier::parse<int>(value) >= 0);214} else {215return false;216}217case GNE_ATTR_FLOW_TERMINATE:218case GNE_ATTR_FLOW_SPACING: {219const auto& flowValues = flowElement->getTagProperty()->getAttributeProperties(key)->getDiscreteValues();220if (std::find(flowValues.begin(), flowValues.end(), value) != flowValues.end()) {221return true;222} else {223return false;224}225}226default:227return flowElement->isCommonAttributeValid(key, value);228}229}230231232void233GNEDemandElementFlow::enableFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, GNEUndoList* undoList) {234switch (key) {235case SUMO_ATTR_END:236case SUMO_ATTR_NUMBER:237case SUMO_ATTR_VEHSPERHOUR:238case SUMO_ATTR_PERSONSPERHOUR:239case SUMO_ATTR_CONTAINERSPERHOUR:240case SUMO_ATTR_PERIOD:241case GNE_ATTR_POISSON:242case SUMO_ATTR_PROB:243undoList->add(new GNEChange_ToggleAttribute(flowElement, key, true), true);244return;245default:246throw InvalidArgument(flowElement->getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");247}248}249250251void252GNEDemandElementFlow::disableFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, GNEUndoList* undoList) {253switch (key) {254case SUMO_ATTR_END:255case SUMO_ATTR_NUMBER:256case SUMO_ATTR_VEHSPERHOUR:257case SUMO_ATTR_PERSONSPERHOUR:258case SUMO_ATTR_CONTAINERSPERHOUR:259case SUMO_ATTR_PERIOD:260case GNE_ATTR_POISSON:261case SUMO_ATTR_PROB:262undoList->add(new GNEChange_ToggleAttribute(flowElement, key, false), true);263return;264default:265throw InvalidArgument(flowElement->getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");266}267}268269270bool271GNEDemandElementFlow::isFlowAttributeEnabled(SumoXMLAttr key) const {272switch (key) {273case SUMO_ATTR_END:274return (parametersSet & VEHPARS_END_SET) != 0;275case SUMO_ATTR_NUMBER:276return (parametersSet & VEHPARS_NUMBER_SET) != 0;277case SUMO_ATTR_VEHSPERHOUR:278case SUMO_ATTR_PERSONSPERHOUR:279case SUMO_ATTR_CONTAINERSPERHOUR:280return (parametersSet & VEHPARS_VPH_SET) != 0;281case SUMO_ATTR_PERIOD:282return (parametersSet & VEHPARS_PERIOD_SET) != 0;283case GNE_ATTR_POISSON:284return (parametersSet & VEHPARS_POISSON_SET) != 0;285case SUMO_ATTR_PROB:286return (parametersSet & VEHPARS_PROB_SET) != 0;287case GNE_ATTR_FLOW_SPACING:288return !isFlowAttributeEnabled(SUMO_ATTR_END) || !isFlowAttributeEnabled(SUMO_ATTR_NUMBER);289default:290return true;291}292}293294295void296GNEDemandElementFlow::setFlowAttribute(GNEDemandElement* flowElement, SumoXMLAttr key, const std::string& value) {297// declare string error298std::string error;299switch (key) {300case SUMO_ATTR_DEPART:301case SUMO_ATTR_BEGIN: {302parseDepart(value, flowElement->getTagProperty()->getTagStr(), id, depart, departProcedure, error);303break;304}305case SUMO_ATTR_END:306repetitionEnd = string2time(value);307break;308case SUMO_ATTR_VEHSPERHOUR:309case SUMO_ATTR_PERSONSPERHOUR:310case SUMO_ATTR_CONTAINERSPERHOUR:311repetitionOffset = TIME2STEPS(3600 / GNEAttributeCarrier::parse<double>(value));312poissonRate = GNEAttributeCarrier::parse<double>(value) / 3600;313break;314case SUMO_ATTR_PERIOD:315repetitionOffset = string2time(value);316poissonRate = 1 / STEPS2TIME(repetitionOffset);317break;318case GNE_ATTR_POISSON:319poissonRate = GNEAttributeCarrier::parse<double>(value);320repetitionOffset = TIME2STEPS(1 / poissonRate);321break;322case SUMO_ATTR_PROB:323repetitionProbability = GNEAttributeCarrier::parse<double>(value);324break;325case SUMO_ATTR_NUMBER:326repetitionNumber = GNEAttributeCarrier::parse<int>(value);327break;328case GNE_ATTR_FLOW_TERMINATE:329if (value == (toString(SUMO_ATTR_END) + "-" + toString(SUMO_ATTR_NUMBER))) {330toggleFlowAttribute(SUMO_ATTR_END, true);331toggleFlowAttribute(SUMO_ATTR_NUMBER, true);332// in this special case, disable other spacing333toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, false);334toggleFlowAttribute(SUMO_ATTR_PERIOD, false);335toggleFlowAttribute(GNE_ATTR_POISSON, false);336toggleFlowAttribute(SUMO_ATTR_PROB, false);337} else {338// if previously end-number was enabled, enable perHour339if (isFlowAttributeEnabled(SUMO_ATTR_END) && isFlowAttributeEnabled(SUMO_ATTR_NUMBER)) {340toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, true);341}342if (value == toString(SUMO_ATTR_END)) {343toggleFlowAttribute(SUMO_ATTR_END, true);344toggleFlowAttribute(SUMO_ATTR_NUMBER, false);345} else if (value == toString(SUMO_ATTR_NUMBER)) {346toggleFlowAttribute(SUMO_ATTR_END, false);347toggleFlowAttribute(SUMO_ATTR_NUMBER, true);348}349}350break;351case GNE_ATTR_FLOW_SPACING:352if ((value == toString(SUMO_ATTR_VEHSPERHOUR)) ||353(value == toString(SUMO_ATTR_PERSONSPERHOUR)) ||354(value == toString(SUMO_ATTR_CONTAINERSPERHOUR))) {355toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, true);356toggleFlowAttribute(SUMO_ATTR_PERIOD, false);357toggleFlowAttribute(GNE_ATTR_POISSON, false);358toggleFlowAttribute(SUMO_ATTR_PROB, false);359} else if (value == toString(SUMO_ATTR_PERIOD)) {360toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, false);361toggleFlowAttribute(SUMO_ATTR_PERIOD, true);362toggleFlowAttribute(GNE_ATTR_POISSON, false);363toggleFlowAttribute(SUMO_ATTR_PROB, false);364} else if (value == toString(GNE_ATTR_POISSON)) {365toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, false);366toggleFlowAttribute(SUMO_ATTR_PERIOD, false);367toggleFlowAttribute(GNE_ATTR_POISSON, true);368toggleFlowAttribute(SUMO_ATTR_PROB, false);369} else if (value == toString(SUMO_ATTR_PROB)) {370toggleFlowAttribute(SUMO_ATTR_VEHSPERHOUR, false);371toggleFlowAttribute(SUMO_ATTR_PERIOD, false);372toggleFlowAttribute(GNE_ATTR_POISSON, false);373toggleFlowAttribute(SUMO_ATTR_PROB, true);374}375break;376default:377flowElement->setCommonAttribute(key, value);378break;379}380}381382383void384GNEDemandElementFlow::toggleFlowAttribute(const SumoXMLAttr attribute, const bool value) {385// modify parameters depending of given Flow attribute386if (value) {387switch (attribute) {388case SUMO_ATTR_END:389parametersSet |= VEHPARS_END_SET;390break;391case SUMO_ATTR_NUMBER:392parametersSet |= VEHPARS_NUMBER_SET;393break;394case SUMO_ATTR_VEHSPERHOUR:395case SUMO_ATTR_PERSONSPERHOUR:396case SUMO_ATTR_CONTAINERSPERHOUR:397parametersSet |= VEHPARS_VPH_SET;398break;399case SUMO_ATTR_PERIOD:400parametersSet |= VEHPARS_PERIOD_SET;401break;402case GNE_ATTR_POISSON:403parametersSet |= VEHPARS_POISSON_SET;404break;405case SUMO_ATTR_PROB:406parametersSet |= VEHPARS_PROB_SET;407break;408default:409break;410}411} else {412switch (attribute) {413case SUMO_ATTR_END:414parametersSet &= ~VEHPARS_END_SET;415break;416case SUMO_ATTR_NUMBER:417parametersSet &= ~VEHPARS_NUMBER_SET;418break;419case SUMO_ATTR_VEHSPERHOUR:420case SUMO_ATTR_PERSONSPERHOUR:421case SUMO_ATTR_CONTAINERSPERHOUR:422parametersSet &= ~VEHPARS_VPH_SET;423break;424case SUMO_ATTR_PERIOD:425parametersSet &= ~VEHPARS_PERIOD_SET;426break;427case GNE_ATTR_POISSON:428parametersSet &= ~VEHPARS_POISSON_SET;429break;430case SUMO_ATTR_PROB:431parametersSet &= ~VEHPARS_PROB_SET;432break;433default:434break;435}436}437}438439440void441GNEDemandElementFlow::setDefaultFlowAttributes(GNEDemandElement* flowElement) {442// first check that this demand element is a flow443if (flowElement->getTagProperty()->isFlow()) {444// end445if ((parametersSet & VEHPARS_END_SET) == 0) {446setFlowAttribute(flowElement, SUMO_ATTR_END, flowElement->getTagProperty()->getDefaultStringValue(SUMO_ATTR_END));447}448// number449if ((parametersSet & VEHPARS_NUMBER_SET) == 0) {450setFlowAttribute(flowElement, SUMO_ATTR_NUMBER, flowElement->getTagProperty()->getDefaultStringValue(SUMO_ATTR_NUMBER));451}452// vehicles/person/container per hour453if (((parametersSet & VEHPARS_PERIOD_SET) == 0) &&454((parametersSet & VEHPARS_POISSON_SET) == 0) &&455((parametersSet & VEHPARS_VPH_SET) == 0)) {456setFlowAttribute(flowElement, SUMO_ATTR_PERIOD, flowElement->getTagProperty()->getDefaultStringValue(SUMO_ATTR_PERIOD));457}458// probability459if ((parametersSet & VEHPARS_PROB_SET) == 0) {460setFlowAttribute(flowElement, SUMO_ATTR_PROB, flowElement->getTagProperty()->getDefaultStringValue(SUMO_ATTR_PROB));461}462// poisson463if (repetitionOffset < 0) {464toggleFlowAttribute(SUMO_ATTR_PERIOD, false);465toggleFlowAttribute(GNE_ATTR_POISSON, true);466setFlowAttribute(flowElement, GNE_ATTR_POISSON, toString(poissonRate));467} else {468setFlowAttribute(flowElement, SUMO_ATTR_PERIOD, time2string(repetitionOffset));469}470}471}472473/****************************************************************************/474475476