Path: blob/main/src/netedit/elements/network/GNENetworkElement.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 GNENetworkElement.cpp14/// @author Pablo Alvarez Lopez15/// @date Jun 201616///17// A abstract class for networkElements18/****************************************************************************/1920#include <netedit/frames/common/GNESelectorFrame.h>21#include <netedit/GNEApplicationWindow.h>22#include <netedit/GNENet.h>23#include <netedit/GNETagPropertiesDatabase.h>24#include <netedit/GNEViewParent.h>25#include <utils/foxtools/MFXMenuHeader.h>26#include <utils/gui/div/GUIDesigns.h>27#include <utils/gui/div/GUIParameterTableWindow.h>28#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>29#include <utils/gui/windows/GUIMainWindow.h>30#include <utils/options/OptionsCont.h>3132#include "GNENetworkElement.h"3334// ===========================================================================35// method definitions36// ===========================================================================3738GNENetworkElement::GNENetworkElement(GNENet* net, SumoXMLTag tag) :39GNEAttributeCarrier(tag, net, net->getGNEApplicationWindow()->getFileBucketHandler()->getDefaultBucket(FileBucket::Type::NETWORK)),40GUIGlObject(myTagProperty->getGLType(), "", GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),41myShapeEdited(false) {42}434445GNENetworkElement::GNENetworkElement(GNENet* net, const std::string& id, SumoXMLTag tag) :46GNEAttributeCarrier(tag, net, net->getGNEApplicationWindow()->getFileBucketHandler()->getDefaultBucket(FileBucket::Type::NETWORK)),47GUIGlObject(myTagProperty->getGLType(), id,48GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),49myShapeEdited(false) {50}515253GNENetworkElement::~GNENetworkElement() {}545556GNEHierarchicalElement*57GNENetworkElement::getHierarchicalElement() {58return this;59}606162GUIGlObject*63GNENetworkElement::getGUIGlObject() {64return this;65}666768const GUIGlObject*69GNENetworkElement::getGUIGlObject() const {70return this;71}727374FileBucket*75GNENetworkElement::getFileBucket() const {76return myFileBucket;77}787980bool81GNENetworkElement::GNENetworkElement::isNetworkElementValid() const {82// implement in children83return true;84}858687std::string88GNENetworkElement::GNENetworkElement::getNetworkElementProblem() const {89// implement in children90return "";91}929394GUIParameterTableWindow*95GNENetworkElement::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {96// Create table97GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);98// Iterate over attributes99for (const auto& attributeProperty : myTagProperty->getAttributeProperties()) {100// Add attribute and set it dynamic if aren't unique101if (attributeProperty->isUnique()) {102ret->mkItem(attributeProperty->getAttrStr().c_str(), false, getAttribute(attributeProperty->getAttr()));103} else {104ret->mkItem(attributeProperty->getAttrStr().c_str(), true, getAttribute(attributeProperty->getAttr()));105}106}107// close building108ret->closeBuilding();109return ret;110}111112113bool114GNENetworkElement::isGLObjectLocked() const {115if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork()) {116return myNet->getViewNet()->getLockManager().isObjectLocked(getType(), isAttributeCarrierSelected());117} else {118return true;119}120}121122123void124GNENetworkElement::markAsFrontElement() {125markForDrawingFront();126}127128129void130GNENetworkElement::selectGLObject() {131if (isAttributeCarrierSelected()) {132unselectAttributeCarrier();133} else {134selectAttributeCarrier();135}136// update information label137myNet->getViewParent()->getSelectorFrame()->getSelectionInformation()->updateInformationLabel();138}139140141const std::string142GNENetworkElement::getOptionalName() const {143try {144return getAttribute(SUMO_ATTR_NAME);145} catch (InvalidArgument&) {146return "";147}148}149150151std::string152GNENetworkElement::getPopUpID() const {153if (myTagProperty->getTag() == SUMO_TAG_CONNECTION) {154return getAttribute(SUMO_ATTR_FROM) + "_" + getAttribute(SUMO_ATTR_FROM_LANE) + " -> " + getAttribute(SUMO_ATTR_TO) + "_" + getAttribute(SUMO_ATTR_TO_LANE);155} else {156return getTagStr() + ": " + getID();157}158}159160161std::string162GNENetworkElement::getHierarchyName() const {163if (myTagProperty->getTag() == SUMO_TAG_LANE) {164return toString(SUMO_TAG_LANE) + " " + getAttribute(SUMO_ATTR_INDEX);165} else if (myTagProperty->getTag() == SUMO_TAG_CONNECTION) {166return getAttribute(SUMO_ATTR_FROM_LANE) + " -> " + getAttribute(SUMO_ATTR_TO_LANE);167} else if ((myTagProperty->getTag() == SUMO_TAG_EDGE) || (myTagProperty->getTag() == SUMO_TAG_CROSSING)) {168return getPopUpID();169} else {170return getTagStr();171}172}173174175void176GNENetworkElement::setShapeEdited(const bool value) {177myShapeEdited = value;178}179180181bool182GNENetworkElement::isShapeEdited() const {183return myShapeEdited;184}185186187int188GNENetworkElement::getGeometryPointUnderCursorShapeEdited() const {189const auto& s = myNet->getViewNet()->getVisualisationSettings();190// calculate squared geometry point radius depending of edited item191double geometryPointRadius = s.neteditSizeSettings.polygonGeometryPointRadius;192if (myTagProperty->getTag() == SUMO_TAG_JUNCTION) {193geometryPointRadius = s.neteditSizeSettings.junctionGeometryPointRadius;194} else if (myTagProperty->getTag() == SUMO_TAG_EDGE) {195geometryPointRadius = s.neteditSizeSettings.edgeGeometryPointRadius;196} else if (myTagProperty->getTag() == SUMO_TAG_LANE) {197geometryPointRadius = s.neteditSizeSettings.laneGeometryPointRadius;198} else if (myTagProperty->getTag() == SUMO_TAG_CONNECTION) {199geometryPointRadius = s.neteditSizeSettings.connectionGeometryPointRadius;200} else if (myTagProperty->getTag() == SUMO_TAG_CROSSING) {201geometryPointRadius = s.neteditSizeSettings.crossingGeometryPointRadius;202}203const auto geometryPointRadiusSquared = (geometryPointRadius * geometryPointRadius);204const auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);205const auto mousePos = myNet->getViewNet()->getPositionInformation();206for (int i = 0; i < (int)shape.size(); i++) {207if (shape[i].distanceSquaredTo2D(mousePos) < geometryPointRadiusSquared) {208return i;209}210}211return -1;212}213214215void216GNENetworkElement::simplifyShapeEdited(GNEUndoList* undoList) {217auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);218const Boundary b = shape.getBoxBoundary();219// create a square as simplified shape220PositionVector simplifiedShape;221simplifiedShape.push_back(Position(b.xmin(), b.ymin()));222simplifiedShape.push_back(Position(b.xmin(), b.ymax()));223simplifiedShape.push_back(Position(b.xmax(), b.ymax()));224simplifiedShape.push_back(Position(b.xmax(), b.ymin()));225if (shape.isClosed()) {226simplifiedShape.push_back(simplifiedShape[0]);227}228setAttribute(SUMO_ATTR_SHAPE, toString(simplifiedShape), undoList);229}230231232void233GNENetworkElement::straigthenShapeEdited(GNEUndoList* undoList) {234const auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);235PositionVector straigthenShape;236straigthenShape.push_front(shape.front());237straigthenShape.push_back(shape.back());238setAttribute(SUMO_ATTR_SHAPE, toString(straigthenShape), undoList);239}240241242void243GNENetworkElement::closeShapeEdited(GNEUndoList* undoList) {244auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);245shape.closePolygon();246setAttribute(SUMO_ATTR_SHAPE, toString(shape), undoList);247}248249250void251GNENetworkElement::openShapeEdited(GNEUndoList* undoList) {252auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);253shape.pop_back();254setAttribute(SUMO_ATTR_SHAPE, toString(shape), undoList);255}256257258void259GNENetworkElement::setFirstGeometryPointShapeEdited(int index, GNEUndoList* undoList) {260const auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);261PositionVector newShape;262for (int i = index; i < (int)shape.size(); i++) {263newShape.push_back(shape[i]);264}265for (int i = 0; i < index; i++) {266newShape.push_back(shape[i]);267}268setAttribute(SUMO_ATTR_SHAPE, toString(newShape), undoList);269}270271272void273GNENetworkElement::deleteGeometryPointShapeEdited(int index, GNEUndoList* undoList) {274const auto shape = getAttributePositionVector(SUMO_ATTR_SHAPE);275PositionVector newShape;276for (int i = 0; i < (int)shape.size(); i++) {277if (i != index) {278newShape.push_back(shape[i]);279}280}281setAttribute(SUMO_ATTR_SHAPE, toString(newShape), undoList);282}283284285void286GNENetworkElement::resetShapeEdited(GNEUndoList* /*undoList*/) {287288}289290291void292GNENetworkElement::setNetworkElementID(const std::string& newID) {293// set microsim ID294setMicrosimID(newID);295// enable save add elements if this network element has children296if ((getChildAdditionals().size() > 0) || (getChildTAZSourceSinks().size() > 0)) {297myNet->getSavingStatus()->requireSaveAdditionals();298}299// enable save demand elements if this network element has children300if (getChildDemandElements().size() > 0) {301myNet->getSavingStatus()->requireSaveDemandElements();302}303// enable save data elements if this network element has children304if (getChildGenericDatas().size() > 0) {305myNet->getSavingStatus()->requireSaveDataElements();306}307}308309310bool311GNENetworkElement::checkDrawingBoundarySelection() const {312if (!gViewObjectsHandler.selectingUsingRectangle()) {313return true;314} else if (!gViewObjectsHandler.isObjectSelected(this)) {315return true;316} else {317return false;318}319}320321322GUIGLObjectPopupMenu*323GNENetworkElement::getShapeEditedPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent, const PositionVector& shape) {324GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);325const std::string headerName = TLF("% (Edited shape)", getFullName());326new MFXMenuHeader(ret, app.getBoldFont(), headerName.c_str(), getGLIcon(), nullptr, 0);327if (OptionsCont::getOptions().getBool("gui-testing")) {328GUIDesigns::buildFXMenuCommand(ret, TL("Copy test coordinates to clipboard"), nullptr, ret, MID_COPY_TEST_COORDINATES);329}330// add separator331new FXMenuSeparator(ret);332// only allow open/close for junctions333if (myTagProperty->getTag() == SUMO_TAG_JUNCTION) {334FXMenuCommand* simplifyShape = GUIDesigns::buildFXMenuCommand(ret, TL("Simplify shape"), TL("Replace current shape with a rectangle"), nullptr, &parent, MID_GNE_SHAPEEDITED_SIMPLIFY);335// disable simplify shape if polygon is only a line336if (shape.size() <= 2) {337simplifyShape->disable();338}339if (shape.isClosed()) {340GUIDesigns::buildFXMenuCommand(ret, TL("Open shape"), TL("Open junction's shape"), nullptr, &parent, MID_GNE_SHAPEEDITED_OPEN);341} else {342GUIDesigns::buildFXMenuCommand(ret, TL("Close shape"), TL("Close junction's shape"), nullptr, &parent, MID_GNE_SHAPEEDITED_CLOSE);343}344} else {345FXMenuCommand* straightenShape = GUIDesigns::buildFXMenuCommand(ret, TL("Straighten shape"), TL("Replace current shape with a rectangle"), nullptr, &parent, MID_GNE_SHAPEEDITED_STRAIGHTEN);346// disable straighten shape if polygon is already straight347if (shape.size() <= 2) {348straightenShape->disable();349}350}351// create a extra FXMenuCommand if mouse is over a vertex352const int index = getGeometryPointUnderCursorShapeEdited();353if (index != -1) {354FXMenuCommand* removeGeometryPoint = GUIDesigns::buildFXMenuCommand(ret, TL("Remove geometry point (shift+click)"), TL("Remove geometry point under mouse"), nullptr, &parent, MID_GNE_SHAPEEDITED_DELETE_GEOMETRY_POINT);355FXMenuCommand* setFirstPoint = GUIDesigns::buildFXMenuCommand(ret, TL("Set first geometry point"), TL("Set first geometry point"), nullptr, &parent, MID_GNE_SHAPEEDITED_SET_FIRST_POINT);356// disable setFirstPoint if shape only have three points357if ((shape.isClosed() && (shape.size() <= 4)) || (!shape.isClosed() && (shape.size() <= 2))) {358removeGeometryPoint->disable();359}360// disable setFirstPoint if mouse is over first point361if (index == 0) {362setFirstPoint->disable();363}364}365// add separator366new FXMenuSeparator(ret);367// add finish368GUIDesigns::buildFXMenuCommand(ret, TL("Finish editing (Enter)"), nullptr, &parent, MID_GNE_SHAPEEDITED_FINISH);369return ret;370}371372373int374GNENetworkElement::getVertexIndex(const PositionVector& shape, const Position& pos) {375// first check if vertex already exists376for (const auto& shapePosition : shape) {377if (shapePosition.distanceTo2D(pos) < myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.polygonGeometryPointRadius) {378return shape.indexOfClosest(shapePosition);379}380}381return -1;382}383384/****************************************************************************/385386387