Path: blob/main/src/netedit/frames/network/GNEAdditionalFrame.cpp
193863 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 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 GNEAdditionalFrame.cpp14/// @author Pablo Alvarez Lopez15/// @date Dec 201516///17// The Widget for add additional elements18/****************************************************************************/1920#include <netedit/GNEApplicationWindow.h>21#include <netedit/GNENet.h>22#include <netedit/GNEViewParent.h>23#include <netedit/elements/additional/GNEAdditionalHandler.h>24#include <netedit/frames/GNEAttributesEditor.h>25#include <netedit/frames/GNEConsecutiveSelector.h>26#include <netedit/frames/GNEViewObjectSelector.h>27#include <netedit/frames/GNESelectorParent.h>28#include <netedit/frames/GNETagSelector.h>29#include <utils/gui/div/GUIDesigns.h>3031#include "GNEAdditionalFrame.h"3233// ===========================================================================34// method definitions35// ===========================================================================3637// ---------------------------------------------------------------------------38// GNEAdditionalFrame::E2MultilaneLegendModule - methods39// ---------------------------------------------------------------------------4041GNEAdditionalFrame::E2MultilaneLegendModule::E2MultilaneLegendModule(GNEFrame* frameParent) :42GNEGroupBoxModule(frameParent, TL("Legend")) {43// declare label44FXLabel* legendLabel = nullptr;45// edge candidate46legendLabel = new FXLabel(getCollapsableFrame(), TL(" edge candidate"), 0, GUIDesignLabel(JUSTIFY_LEFT));47legendLabel->setBackColor(MFXUtils::getFXColor(frameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.possible));48legendLabel->setTextColor(MFXUtils::getFXColor(RGBColor::WHITE));49// last edge selected50legendLabel = new FXLabel(getCollapsableFrame(), TL(" last edge selected"), 0, GUIDesignLabel(JUSTIFY_LEFT));51legendLabel->setBackColor(MFXUtils::getFXColor(frameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.target));52// edge selected53legendLabel = new FXLabel(getCollapsableFrame(), TL(" edge selected"), 0, GUIDesignLabel(JUSTIFY_LEFT));54legendLabel->setBackColor(MFXUtils::getFXColor(frameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.source));55// edge disconnected56legendLabel = new FXLabel(getCollapsableFrame(), TL(" edge disconnected"), 0, GUIDesignLabel(JUSTIFY_LEFT));57legendLabel->setBackColor(MFXUtils::getFXColor(frameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.conflict));58}596061GNEAdditionalFrame::E2MultilaneLegendModule::~E2MultilaneLegendModule() {}626364void65GNEAdditionalFrame::E2MultilaneLegendModule::showE2MultilaneLegend() {66show();67}686970void71GNEAdditionalFrame::E2MultilaneLegendModule::hideE2MultilaneLegend() {72hide();73}7475// ---------------------------------------------------------------------------76// GNEAdditionalFrame::HelpCreationModule - methods77// ---------------------------------------------------------------------------7879GNEAdditionalFrame::HelpCreationModule::HelpCreationModule(GNEFrame* frameParent) :80GNEGroupBoxModule(frameParent, TL("Help")) {81// edge candidate82myHelpLabel = new FXLabel(getCollapsableFrame(), "", 0, GUIDesignLabelFrameInformation);83// fill map84//addTLString(TL("-Requires EntryExitDetector\n")) +85// E186myHelpMap[SUMO_TAG_INDUCTION_LOOP] = addTLString(TL("-Click over lane to create it"));87// E1 Instant88myHelpMap[SUMO_TAG_INSTANT_INDUCTION_LOOP] = addTLString(TL("-Click over lane to create it"));89// E290myHelpMap[SUMO_TAG_LANE_AREA_DETECTOR] = addTLString(TL("-Click over lane to create it"));91// E392myHelpMap[SUMO_TAG_ENTRY_EXIT_DETECTOR] = addTLString(TL("-Click over view to create it")) +93addTLString(TL("-Requires at least one Entry\n and one Exit"));94// E3 Entry95myHelpMap[SUMO_TAG_DET_ENTRY] = addTLString(TL("-Requires EntryExitDetector\n parent\n")) +96addTLString(TL("-Select EntryExitDetector\n before creating either\n clicking over one in view\n or by selecting from list"));97// E3 Exit98myHelpMap[SUMO_TAG_DET_EXIT] = addTLString(TL("-Requires EntryExitDetector\n parent\n")) +99addTLString(TL("-Select EntryExitDetector\n before creating either\n clicking over one in view\n or by selecting from list"));100}101102103GNEAdditionalFrame::HelpCreationModule::~HelpCreationModule() {}104105106void107GNEAdditionalFrame::HelpCreationModule::showHelpCreationModule(SumoXMLTag XMLTag) {108if (myHelpMap.count(XMLTag) > 0) {109myHelpLabel->setText(myHelpMap.at(XMLTag).c_str());110show();111} else {112hide();113}114}115116117void118GNEAdditionalFrame::HelpCreationModule::hideHelpCreationModule() {119hide();120}121122123std::string124GNEAdditionalFrame::HelpCreationModule::addTLString(const std::string& str) {125return std::string(str.c_str());126}127128// ---------------------------------------------------------------------------129// GNEAdditionalFrame: - methods130// ---------------------------------------------------------------------------131132GNEAdditionalFrame::GNEAdditionalFrame(GNEViewParent* viewParent, GNEViewNet* viewNet) :133GNEFrame(viewParent, viewNet, TL("Additionals")) {134135// create item Selector module for additionals136myAdditionalTagSelector = new GNETagSelector(this, GNETagProperties::Type::ADDITIONALELEMENT, SUMO_TAG_BUS_STOP);137138// Create additional parameters139myAdditionalAttributesEditor = new GNEAttributesEditor(this, GNEAttributesEditorType::EditorType::CREATOR);140141// Create selector parent142mySelectorAdditionalParent = new GNESelectorParent(this);143144// Create selector child edges145myViewObjetsSelector = new GNEViewObjectSelector(this);146147// Create list for E2Multilane lane selector148myConsecutiveLaneSelector = new GNEConsecutiveSelector(this, false);149150// create help creation module151myHelpCreationModule = new HelpCreationModule(this);152153// Create legend for E2 detector154myE2MultilaneLegendModule = new E2MultilaneLegendModule(this);155}156157158GNEAdditionalFrame::~GNEAdditionalFrame() {159// check if we have to delete base additional object160if (myBaseAdditional) {161delete myBaseAdditional;162}163}164165166void167GNEAdditionalFrame::show() {168// refresh tag selector169myAdditionalTagSelector->refreshTagSelector();170// reset last position171myLastClickedPosition = Position::INVALID;172// show frame173GNEFrame::show();174}175176177bool178GNEAdditionalFrame::addAdditional(const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {179// first check that current selected additional is valid180if (myAdditionalTagSelector->getCurrentTemplateAC() == nullptr) {181myViewNet->setStatusBarText(TL("Current selected additional isn't valid."));182return false;183}184// obtain tagproperty (only for improve code legibility)185const auto& tagProperties = myAdditionalTagSelector->getCurrentTemplateAC()->getTagProperty();186// check if toogle selection187if ((viewObjects.getAttributeCarrierFront() == viewObjects.getLaneFront()) &&188(myViewObjetsSelector->toggleSelectedLane(viewObjects.getLaneFront()))) {189return true;190}191if (myViewObjetsSelector->toggleSelectedElement(viewObjects.getAttributeCarrierFront())) {192return true;193}194// check if add a lane in consecutive lane selector195if (tagProperties->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {196return myConsecutiveLaneSelector->addLane(viewObjects.getLaneFront());197}198// disable rerouter elements (temporal)199if ((tagProperties->getTag() == SUMO_TAG_INTERVAL) ||200(tagProperties->getTag() == SUMO_TAG_DEST_PROB_REROUTE) ||201(tagProperties->getTag() == SUMO_TAG_CLOSING_REROUTE) ||202(tagProperties->getTag() == SUMO_TAG_CLOSING_LANE_REROUTE) ||203(tagProperties->getTag() == SUMO_TAG_ROUTE_PROB_REROUTE) ||204(tagProperties->getTag() == SUMO_TAG_PARKING_AREA_REROUTE)) {205WRITE_WARNING(TL("Currently unsupported. Create rerouter elements using rerouter dialog"));206return false;207}208// disable steps (temporal)209if (tagProperties->getTag() == SUMO_TAG_STEP) {210WRITE_WARNING(TL("Currently unsupported. Create VSS steps using VSS dialog"));211return false;212}213// disable flows (temporal)214if (tagProperties->getTag() == GNE_TAG_CALIBRATOR_FLOW) {215WRITE_WARNING(TL("Currently unsupported. Create calibratorFlows using calibrator dialog"));216return false;217}218// check last position219if ((myViewNet->getPositionInformation() == myLastClickedPosition) && !myViewNet->getMouseButtonKeyPressed().shiftKeyPressed()) {220WRITE_WARNING(TL("Shift + click to create two additionals in the same position"));221return false;222}223// check if additional attributes are valid224if (!myAdditionalAttributesEditor->checkAttributes(true)) {225return false;226}227// reset base additional228resetBaseAdditionalObject();229// init base additional object230if (!initBaseAdditionalObject(tagProperties, viewObjects)) {231return false;232}233// parse common attributes234if (!myViewObjetsSelector->fillSumoBaseObject(myBaseAdditional)) {235return false;236}237// add basic attributes and values238myAdditionalAttributesEditor->fillSumoBaseObject(myBaseAdditional);239// declare additional handler240GNEAdditionalHandler additionalHandler(myViewNet->getNet(), myViewNet->getNet()->getACTemplates()->getTemplateAC(tagProperties->getTag())->getFileBucket(),241myViewNet->getViewParent()->getGNEAppWindows()->isUndoRedoAllowed());242// build additional243additionalHandler.parseSumoBaseObject(myBaseAdditional);244// Refresh additional Parent Selector (For additionals that have a limited number of children)245mySelectorAdditionalParent->refreshSelectorParentModule();246// clear selected view objects247myViewObjetsSelector->clearSelection();248myAdditionalAttributesEditor->refreshAttributesEditor();249return true;250}251252253GNETagSelector*254GNEAdditionalFrame::getAdditionalTagSelector() const {255return myAdditionalTagSelector;256}257258259GNEConsecutiveSelector*260GNEAdditionalFrame::getConsecutiveLaneSelector() const {261return myConsecutiveLaneSelector;262}263264265GNEAttributesEditor*266GNEAdditionalFrame::getAttributesEditor() const {267return myAdditionalAttributesEditor;268}269270271GNEViewObjectSelector*272GNEAdditionalFrame::getViewObjetsSelector() const {273return myViewObjetsSelector;274}275276277bool278GNEAdditionalFrame::createPath(const bool /* useLastRoute */) {279// obtain tagproperty (only for improve code legibility)280const auto tagProperty = myAdditionalTagSelector->getCurrentTemplateAC()->getTagProperty();281// first check that current tag is valid (currently only for E2 multilane detectors)282if (tagProperty->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {283// now check number of lanes284if (myConsecutiveLaneSelector->getLanePath().size() < 2) {285WRITE_WARNING(TL("E2 multilane detectors need at least two consecutive lanes"));286} else {287// reset base object288resetBaseAdditionalObject();289// set tag290myBaseAdditional->setTag(SUMO_TAG_LANE_AREA_DETECTOR);291// get attributes and values292myAdditionalAttributesEditor->fillSumoBaseObject(myBaseAdditional);293// add lane IDs294myBaseAdditional->addStringListAttribute(SUMO_ATTR_LANES, myConsecutiveLaneSelector->getLaneIDPath());295// set positions296myBaseAdditional->addDoubleAttribute(SUMO_ATTR_POSITION, myConsecutiveLaneSelector->getLanePath().front().second);297myBaseAdditional->addDoubleAttribute(SUMO_ATTR_ENDPOS, myConsecutiveLaneSelector->getLanePath().back().second);298// parse common attributes299if (myViewObjetsSelector->fillSumoBaseObject(myBaseAdditional)) {300// show warning dialogbox and stop check if input parameters are valid301if (myAdditionalAttributesEditor->checkAttributes(true)) {302// declare additional handler303GNEAdditionalHandler additionalHandler(myViewNet->getNet(), myViewNet->getNet()->getACTemplates()->getTemplateAC(SUMO_TAG_LANE_AREA_DETECTOR)->getFileBucket(),304myViewNet->getViewParent()->getGNEAppWindows()->isUndoRedoAllowed());305// build additional306additionalHandler.parseSumoBaseObject(myBaseAdditional);307// Refresh additional Parent Selector (For additionals that have a limited number of children)308mySelectorAdditionalParent->refreshSelectorParentModule();309// abort E2 creation310myConsecutiveLaneSelector->abortPathCreation();311return true;312}313}314}315}316return false;317}318319320void321GNEAdditionalFrame::tagSelected() {322// get template AC323const auto templateAC = myAdditionalTagSelector->getCurrentTemplateAC();324if (templateAC) {325// show parameters326myAdditionalAttributesEditor->showAttributesEditor(templateAC, true);327// Show myAdditionalFrameParent if we're adding an slave element328if (templateAC->getTagProperty()->isChild()) {329mySelectorAdditionalParent->showSelectorParentModule(templateAC->getTagProperty()->getXMLParentTags());330} else {331mySelectorAdditionalParent->hideSelectorParentModule();332}333// Show EdgesSelector if we're adding an additional that own the attribute SUMO_ATTR_EDGES334if (templateAC->getTagProperty()->hasAttribute(SUMO_ATTR_EDGES)) {335myViewObjetsSelector->showNetworkElementsSelector(SUMO_TAG_EDGE, SUMO_ATTR_EDGES);336} else {337myViewObjetsSelector->hideNetworkElementsSelector();338}339// show help creation modul340myHelpCreationModule->showHelpCreationModule(templateAC->getTagProperty()->getTag());341// check if we must show consecutive lane selector342if (templateAC->getTagProperty()->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {343myConsecutiveLaneSelector->showConsecutiveLaneSelectorModule();344myE2MultilaneLegendModule->showE2MultilaneLegend();345myViewObjetsSelector->hideNetworkElementsSelector();346// recompute network347myViewNet->getNet()->computeNetwork(myViewNet->getViewParent()->getGNEAppWindows());348} else if (templateAC->getTagProperty()->hasAttribute(SUMO_ATTR_LANES)) {349myConsecutiveLaneSelector->hideConsecutiveLaneSelectorModule();350myE2MultilaneLegendModule->hideE2MultilaneLegend();351myViewObjetsSelector->showNetworkElementsSelector(SUMO_TAG_LANE, SUMO_ATTR_LANES);352} else {353myConsecutiveLaneSelector->hideConsecutiveLaneSelectorModule();354myE2MultilaneLegendModule->hideE2MultilaneLegend();355}356// reset last position357myLastClickedPosition = Position::INVALID;358} else {359// hide all modules if additional isn't valid360myAdditionalAttributesEditor->hideAttributesEditor();361mySelectorAdditionalParent->hideSelectorParentModule();362myViewObjetsSelector->hideNetworkElementsSelector();363myConsecutiveLaneSelector->hideConsecutiveLaneSelectorModule();364myHelpCreationModule->hideHelpCreationModule();365myE2MultilaneLegendModule->hideE2MultilaneLegend();366}367}368369370void371GNEAdditionalFrame::resetBaseAdditionalObject() {372// check if baseAdditional exist, and if yes, delete it373if (myBaseAdditional) {374// go to base additional root375while (myBaseAdditional->getParentSumoBaseObject()) {376myBaseAdditional = myBaseAdditional->getParentSumoBaseObject();377}378// delete baseAdditional (and all children)379delete myBaseAdditional;380// reset baseAdditional381myBaseAdditional = nullptr;382}383// create an new base additional384myBaseAdditional = new CommonXMLStructure::SumoBaseObject(nullptr);385}386387388bool389GNEAdditionalFrame::initBaseAdditionalObject(const GNETagProperties* tagProperty, const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {390// declare tag for base additional391auto baseAdditionalTag = tagProperty->getTag();392// check if tag has to be updated393if (baseAdditionalTag == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {394baseAdditionalTag = SUMO_TAG_LANE_AREA_DETECTOR;395} else if (baseAdditionalTag == GNE_TAG_CALIBRATOR_FLOW) {396baseAdditionalTag = SUMO_TAG_FLOW;397}398// update view objects parents399viewObjects.fillSumoBaseObject(myBaseAdditional);400// check if additional is child of other element401if (tagProperty->isChild()) {402// check if we clicked over a parent403SumoXMLTag parentTag = SUMO_TAG_NOTHING;404for (const auto& pTag : tagProperty->getXMLParentTags()) {405if (myBaseAdditional->hasParentID(pTag)) {406parentTag = pTag;407}408}409// update selector additional parent410if (parentTag != SUMO_TAG_NOTHING) {411// update parent additional selected412mySelectorAdditionalParent->setIDSelected(myBaseAdditional->getParentID(parentTag));413}414// continue depending of parents415if (mySelectorAdditionalParent->getIdSelected().empty()) {416std::string messageError = toString(tagProperty->getXMLParentTags().front());417if (tagProperty->getXMLParentTags().size() > 1) {418const int numParents = (int)tagProperty->getXMLParentTags().size();419messageError.clear();420for (int i = 0; i < numParents; i++) {421messageError.append(toString(tagProperty->getXMLParentTags().at(i)));422if (i == numParents - 2) {423messageError.append(" or ");424} else if (i < (numParents - 2)) {425messageError.append(", ");426}427}428}429WRITE_WARNING(TLF("A % must be selected before insertion of %.", messageError, tagProperty->getTagStr()));430return false;431} else {432// set parent tag // POSSIBLE ERROR WITH ACCESS AND BUSSTOPS!433myBaseAdditional->setTag(tagProperty->getXMLParentTags().front());434// add ID435myBaseAdditional->addStringAttribute(SUMO_ATTR_ID, mySelectorAdditionalParent->getIdSelected());436// create base additional again as child of current base additional437myBaseAdditional = new CommonXMLStructure::SumoBaseObject(myBaseAdditional);438}439}440// set baseAdditional tag441myBaseAdditional->setTag(baseAdditionalTag);442// Obtain position as the clicked position over view443const Position viewPosSnapped = myViewNet->snapToActiveGrid(myViewNet->getPositionInformation());444// add position and X-Y-Z attributes445myBaseAdditional->addPositionAttribute(SUMO_ATTR_POSITION, viewPosSnapped);446myBaseAdditional->addDoubleAttribute(SUMO_ATTR_X, viewPosSnapped.x());447myBaseAdditional->addDoubleAttribute(SUMO_ATTR_Y, viewPosSnapped.y());448myBaseAdditional->addDoubleAttribute(SUMO_ATTR_Z, viewPosSnapped.z());449// check if add edge attributes450if (tagProperty->hasAttribute(SUMO_ATTR_EDGE)) {451if (viewObjects.getEdgeFront() == nullptr) {452return false;453} else {454myBaseAdditional->addStringAttribute(SUMO_ATTR_EDGE, viewObjects.getEdgeFront()->getID());455// Obtain position of the mouse over lane (limited over grid)456const auto firstLane = viewObjects.getEdgeFront()->getChildLanes().front();457const double mousePositionOverLane = firstLane->getLaneShape().nearest_offset_to_point2D(viewPosSnapped) / firstLane->getLengthGeometryFactor();458myBaseAdditional->addDoubleAttribute(SUMO_ATTR_POSITION, mousePositionOverLane);459}460} else if (tagProperty->getTag() == SUMO_TAG_VAPORIZER) {461// special case for vaporizers462if (viewObjects.getEdgeFront() == nullptr) {463return false;464} else {465myBaseAdditional->addStringAttribute(SUMO_ATTR_ID, viewObjects.getEdgeFront()->getID());466}467}468// check if add lane attributes469if (tagProperty->hasAttribute(SUMO_ATTR_LANE)) {470if (viewObjects.getLaneFront() == nullptr) {471return false;472} else {473myBaseAdditional->addStringAttribute(SUMO_ATTR_LANE, viewObjects.getLaneFront()->getID());474myBaseAdditional->addDoubleAttribute(GNE_ATTR_LANELENGTH, viewObjects.getLaneFront()->getLaneShapeLength() / viewObjects.getLaneFront()->getLengthGeometryFactor());475// Obtain position of the mouse over lane (limited over grid)476const double mousePositionOverLane = viewObjects.getLaneFront()->getLaneShape().nearest_offset_to_point2D(viewPosSnapped) / viewObjects.getLaneFront()->getLengthGeometryFactor();477// special case for access478if (tagProperty->getTag() == SUMO_TAG_ACCESS) {479myBaseAdditional->addStringAttribute(SUMO_ATTR_POSITION, toString(mousePositionOverLane));480} else {481myBaseAdditional->addDoubleAttribute(SUMO_ATTR_POSITION, mousePositionOverLane);482}483}484}485// BaseAdditional created, then return true486return true;487}488489/****************************************************************************/490491492