Path: blob/main/src/netedit/elements/additional/GNERerouter.cpp
169684 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 GNERerouter.cpp14/// @author Pablo Alvarez Lopez15/// @date Nov 201516///17//18/****************************************************************************/19#include <config.h>2021#include <netedit/GNENet.h>22#include <netedit/GNETagProperties.h>23#include <netedit/GNEUndoList.h>24#include <netedit/GNEViewNet.h>25#include <netedit/changes/GNEChange_Additional.h>26#include <netedit/changes/GNEChange_Attribute.h>27#include <netedit/dialogs/elements/GNERerouterDialog.h>2829#include "GNERerouter.h"30#include "GNERerouterSymbol.h"3132// ===========================================================================33// member method definitions34// ===========================================================================3536GNERerouter::GNERerouter(GNENet* net) :37GNEAdditional("", net, "", SUMO_TAG_REROUTER, ""),38myProbability(0),39myOff(false),40myOptional(false),41myTimeThreshold(0) {42}434445GNERerouter::GNERerouter(const std::string& id, GNENet* net, const std::string& filename, const Position& pos, const std::string& name,46double probability, bool off, bool optional, SUMOTime timeThreshold, const std::vector<std::string>& vTypes,47const Parameterised::Map& parameters) :48GNEAdditional(id, net, filename, SUMO_TAG_REROUTER, name),49Parameterised(parameters),50myPosition(pos),51myProbability(probability),52myOff(off),53myOptional(optional),54myTimeThreshold(timeThreshold),55myVTypes(vTypes) {56// update centering boundary without updating grid57updateCenteringBoundary(false);58}596061GNERerouter::~GNERerouter() {62}636465void66GNERerouter::writeAdditional(OutputDevice& device) const {67// avoid write rerouters without edges68if (getAttribute(SUMO_ATTR_EDGES).size() > 0) {69device.openTag(SUMO_TAG_REROUTER);70device.writeAttr(SUMO_ATTR_ID, getID());71device.writeAttr(SUMO_ATTR_EDGES, getAttribute(SUMO_ATTR_EDGES));72device.writeAttr(SUMO_ATTR_POSITION, myPosition);73if (!myAdditionalName.empty()) {74device.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(myAdditionalName));75}76if (myProbability != 1.0) {77device.writeAttr(SUMO_ATTR_PROB, myProbability);78}79if (time2string(myTimeThreshold) != "0.00") {80device.writeAttr(SUMO_ATTR_HALTING_TIME_THRESHOLD, time2string(myTimeThreshold));81}82if (!myVTypes.empty()) {83device.writeAttr(SUMO_ATTR_VTYPES, myVTypes);84}85if (myOff) {86device.writeAttr(SUMO_ATTR_OFF, myOff);87}88if (myOptional) {89device.writeAttr(SUMO_ATTR_OPTIONAL, myOptional);90}91// write all rerouter interval92for (const auto& rerouterInterval : getChildAdditionals()) {93if (!rerouterInterval->getTagProperty()->isSymbol()) {94rerouterInterval->writeAdditional(device);95}96}97// write parameters (Always after children to avoid problems with additionals.xsd)98writeParams(device);99device.closeTag();100} else {101WRITE_WARNING("Rerouter '" + getID() + TL("' needs at least one edge"));102}103}104105106bool107GNERerouter::isAdditionalValid() const {108return true;109}110111112std::string GNERerouter::getAdditionalProblem() const {113return "";114}115116117void118GNERerouter::fixAdditionalProblem() {119// nothing to fix120}121122123bool124GNERerouter::checkDrawMoveContour() const {125// get edit modes126const auto& editModes = myNet->getViewNet()->getEditModes();127// check if we're in move mode128if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&129!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&130(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {131// only move the first element132return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;133} else {134return false;135}136}137138139GNEMoveOperation*140GNERerouter::getMoveOperation() {141// return move operation for additional placed in view142return new GNEMoveOperation(this, myPosition);143}144145146void147GNERerouter::updateGeometry() {148// update additional geometry149myAdditionalGeometry.updateSinglePosGeometry(myPosition, 0);150// update geometries (boundaries of all children)151for (const auto& additionalChildren : getChildAdditionals()) {152additionalChildren->updateGeometry();153for (const auto& rerouterElement : additionalChildren->getChildAdditionals()) {154rerouterElement->updateGeometry();155}156}157}158159160Position161GNERerouter::getPositionInView() const {162return myPosition;163}164165166void167GNERerouter::updateCenteringBoundary(const bool updateGrid) {168// remove additional from grid169if (updateGrid) {170myNet->removeGLObjectFromGrid(this);171}172// now update geometry173updateGeometry();174// add shape boundary175myAdditionalBoundary = myAdditionalGeometry.getShape().getBoxBoundary();176/*177// add positions of all childrens (intervals and symbols)178for (const auto& additionalChildren : getChildAdditionals()) {179myAdditionalBoundary.add(additionalChildren->getPositionInView());180for (const auto& rerouterElement : additionalChildren->getChildAdditionals()) {181myAdditionalBoundary.add(rerouterElement->getPositionInView());182// special case for parking area rerouter183if (rerouterElement->getTagProperty()->getTag() == SUMO_TAG_PARKING_AREA_REROUTE) {184myAdditionalBoundary.add(rerouterElement->getParentAdditionals().at(1)->getCenteringBoundary());185}186}187}188*/189// grow190myAdditionalBoundary.grow(5);191// add additional into RTREE again192if (updateGrid) {193myNet->addGLObjectIntoGrid(this);194}195}196197198void199GNERerouter::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {200// geometry of this element cannot be splitted201}202203204void205GNERerouter::openAdditionalDialog() {206// Open rerouter dialog207GNERerouterDialog(this);208}209210211std::string212GNERerouter::getParentName() const {213return myNet->getMicrosimID();214}215216217void218GNERerouter::drawGL(const GUIVisualizationSettings& s) const {219const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();220// first check if additional has to be drawn221if (myNet->getViewNet()->getDataViewOptions().showAdditionals()) {222// draw parent and child lines223drawParentChildLines(s, s.additionalSettings.connectionColor, true);224// draw Rerouter225drawSquaredAdditional(s, myPosition, s.additionalSettings.rerouterSize, GUITexture::REROUTER, GUITexture::REROUTER_SELECTED);226// iterate over additionals and check if drawn227for (const auto& interval : getChildAdditionals()) {228// if rerouter or their intevals are selected, then draw229if (myNet->getViewNet()->getNetworkViewOptions().showSubAdditionals() ||230isAttributeCarrierSelected() || inspectedElements.isACInspected(this) ||231interval->isAttributeCarrierSelected() || inspectedElements.isACInspected(interval) ||232interval->isMarkedForDrawingFront()) {233interval->drawGL(s);234} else {235// if rerouterElements are inspected or selected, then draw236for (const auto& rerouterElement : interval->getChildAdditionals()) {237if (rerouterElement->isAttributeCarrierSelected() || inspectedElements.isACInspected(rerouterElement) ||238rerouterElement->isMarkedForDrawingFront()) {239interval->drawGL(s);240}241}242}243}244}245}246247248std::string249GNERerouter::getAttribute(SumoXMLAttr key) const {250switch (key) {251case SUMO_ATTR_ID:252return getMicrosimID();253case SUMO_ATTR_EDGES: {254std::vector<std::string> edges;255for (const auto& rerouterSymbol : getChildAdditionals()) {256if (rerouterSymbol->getTagProperty()->isSymbol()) {257edges.push_back(rerouterSymbol->getAttribute(SUMO_ATTR_EDGE));258}259}260return toString(edges);261}262case SUMO_ATTR_POSITION:263return toString(myPosition);264case SUMO_ATTR_NAME:265return myAdditionalName;266case SUMO_ATTR_PROB:267return toString(myProbability);268case SUMO_ATTR_HALTING_TIME_THRESHOLD:269return time2string(myTimeThreshold);270case SUMO_ATTR_VTYPES:271return toString(myVTypes);272case SUMO_ATTR_OFF:273return toString(myOff);274case SUMO_ATTR_OPTIONAL:275return toString(myOptional);276default:277return getCommonAttribute(this, key);278}279}280281282double283GNERerouter::getAttributeDouble(SumoXMLAttr key) const {284switch (key) {285case SUMO_ATTR_PROB:286return myProbability;287default:288throw InvalidArgument(getTagStr() + " doesn't have a double attribute of type '" + toString(key) + "'");289}290}291292293const Parameterised::Map&294GNERerouter::getACParametersMap() const {295return getParametersMap();296}297298299void300GNERerouter::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {301if (value == getAttribute(key)) {302return; //avoid needless changes, later logic relies on the fact that attributes have changed303}304switch (key) {305// special case for lanes due rerouter Symbols306case SUMO_ATTR_EDGES:307// rebuild rerouter Symbols308rebuildRerouterSymbols(value, undoList);309break;310case SUMO_ATTR_ID:311case SUMO_ATTR_POSITION:312case SUMO_ATTR_NAME:313case SUMO_ATTR_PROB:314case SUMO_ATTR_HALTING_TIME_THRESHOLD:315case SUMO_ATTR_VTYPES:316case SUMO_ATTR_OFF:317case SUMO_ATTR_OPTIONAL:318GNEChange_Attribute::changeAttribute(this, key, value, undoList);319break;320default:321setCommonAttribute(key, value, undoList);322break;323}324}325326327bool328GNERerouter::isValid(SumoXMLAttr key, const std::string& value) {329switch (key) {330case SUMO_ATTR_ID:331return isValidAdditionalID(value);332case SUMO_ATTR_EDGES:333return canParse<std::vector<GNEEdge*> >(myNet, value, false);334case SUMO_ATTR_POSITION:335return canParse<Position>(value);336case SUMO_ATTR_NAME:337return SUMOXMLDefinitions::isValidAttribute(value);338case SUMO_ATTR_PROB:339return canParse<double>(value) && (parse<double>(value) >= 0) && (parse<double>(value) <= 1);340case SUMO_ATTR_HALTING_TIME_THRESHOLD:341return canParse<SUMOTime>(value);342case SUMO_ATTR_VTYPES:343if (value.empty()) {344return true;345} else {346return SUMOXMLDefinitions::isValidListOfTypeID(value);347}348case SUMO_ATTR_OFF:349return canParse<bool>(value);350case SUMO_ATTR_OPTIONAL:351return canParse<bool>(value);352default:353return isCommonValid(key, value);354}355}356357358std::string359GNERerouter::getPopUpID() const {360return getTagStr() + ": " + getID();361}362363364std::string365GNERerouter::getHierarchyName() const {366return getTagStr();367}368369// ===========================================================================370// private371// ===========================================================================372373void374GNERerouter::setAttribute(SumoXMLAttr key, const std::string& value) {375switch (key) {376case SUMO_ATTR_EDGES:377throw InvalidArgument(getTagStr() + " cannot be edited");378case SUMO_ATTR_ID:379// update microsimID380setAdditionalID(value);381break;382case SUMO_ATTR_POSITION:383myPosition = parse<Position>(value);384// update boundary (except for template)385if (getID().size() > 0) {386updateCenteringBoundary(true);387}388break;389case SUMO_ATTR_NAME:390myAdditionalName = value;391break;392case SUMO_ATTR_PROB:393myProbability = parse<double>(value);394break;395case SUMO_ATTR_HALTING_TIME_THRESHOLD:396myTimeThreshold = parse<SUMOTime>(value);397break;398case SUMO_ATTR_VTYPES:399myVTypes = parse<std::vector<std::string> >(value);400break;401case SUMO_ATTR_OFF:402myOff = parse<bool>(value);403break;404case SUMO_ATTR_OPTIONAL:405myOptional = parse<bool>(value);406break;407default:408setCommonAttribute(this, key, value);409break;410}411}412413414void415GNERerouter::setMoveShape(const GNEMoveResult& moveResult) {416// update position417myPosition = moveResult.shapeToUpdate.front();418// update geometry419updateGeometry();420}421422423void424GNERerouter::commitMoveShape(const GNEMoveResult& moveResult, GNEUndoList* undoList) {425undoList->begin(this, "position of " + getTagStr());426GNEChange_Attribute::changeAttribute(this, SUMO_ATTR_POSITION, toString(moveResult.shapeToUpdate.front()), undoList);427undoList->end();428}429430431void432GNERerouter::rebuildRerouterSymbols(const std::string& value, GNEUndoList* undoList) {433undoList->begin(this, ("change " + getTagStr() + " attribute").c_str());434// drop all additional children435while (getChildAdditionals().size() > 0) {436undoList->add(new GNEChange_Additional(getChildAdditionals().front(), false), true);437}438// get edge vector439const std::vector<GNEEdge*> edges = parse<std::vector<GNEEdge*> >(myNet, value);440// create new VSS Symbols441for (const auto& edge : edges) {442// create VSS Symbol443GNEAdditional* VSSSymbol = new GNERerouterSymbol(this, edge);444// add it using GNEChange_Additional445myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(VSSSymbol, true), true);446}447undoList->end();448}449450451/****************************************************************************/452453454