Path: blob/main/src/netedit/frames/network/GNEAdditionalFrame.cpp
169685 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 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) :42MFXGroupBoxModule(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// ---------------------------------------------------------------------------7879#define TLSX(string) std::string(gettext((string)))80818283GNEAdditionalFrame::HelpCreationModule::HelpCreationModule(GNEFrame* frameParent) :84MFXGroupBoxModule(frameParent, TL("Help")) {85// edge candidate86myHelpLabel = new FXLabel(getCollapsableFrame(), "", 0, GUIDesignLabelFrameInformation);87// fill map88//addTLString(TL("-Requires EntryExitDetector\n")) +89// E190myHelpMap[SUMO_TAG_INDUCTION_LOOP] = addTLString(TL("-Click over lane to create it"));91// E1 Instant92myHelpMap[SUMO_TAG_INSTANT_INDUCTION_LOOP] = addTLString(TL("-Click over lane to create it"));93// E294myHelpMap[SUMO_TAG_LANE_AREA_DETECTOR] = addTLString(TL("-Click over lane to create it"));95// E396myHelpMap[SUMO_TAG_ENTRY_EXIT_DETECTOR] = addTLString(TL("-Click over view to create it")) +97addTLString(TL("-Requires at least one Entry\n and one Exit"));98// E3 Entry99myHelpMap[SUMO_TAG_DET_ENTRY] = addTLString(TL("-Requires EntryExitDetector\n parent\n")) +100addTLString(TL("-Select EntryExitDetector\n before creating either\n clicking over one in view\n or by selecting from list"));101// E3 Exit102myHelpMap[SUMO_TAG_DET_EXIT] = addTLString(TL("-Requires EntryExitDetector\n parent\n")) +103addTLString(TL("-Select EntryExitDetector\n before creating either\n clicking over one in view\n or by selecting from list"));104}105106107GNEAdditionalFrame::HelpCreationModule::~HelpCreationModule() {}108109110void111GNEAdditionalFrame::HelpCreationModule::showHelpCreationModule(SumoXMLTag XMLTag) {112if (myHelpMap.count(XMLTag) > 0) {113myHelpLabel->setText(myHelpMap.at(XMLTag).c_str());114show();115} else {116hide();117}118}119120121void122GNEAdditionalFrame::HelpCreationModule::hideHelpCreationModule() {123hide();124}125126127std::string128GNEAdditionalFrame::HelpCreationModule::addTLString(const std::string& str) {129return std::string(str.c_str());130}131132// ---------------------------------------------------------------------------133// GNEAdditionalFrame: - methods134// ---------------------------------------------------------------------------135136GNEAdditionalFrame::GNEAdditionalFrame(GNEViewParent* viewParent, GNEViewNet* viewNet) :137GNEFrame(viewParent, viewNet, TL("Additionals")) {138139// create item Selector module for additionals140myAdditionalTagSelector = new GNETagSelector(this, GNETagProperties::Type::ADDITIONALELEMENT, SUMO_TAG_BUS_STOP);141142// Create additional parameters143myAdditionalAttributesEditor = new GNEAttributesEditor(this, GNEAttributesEditorType::EditorType::CREATOR);144145// Create selector parent146mySelectorAdditionalParent = new GNESelectorParent(this);147148// Create selector child edges149myViewObjetsSelector = new GNEViewObjectSelector(this);150151// Create list for E2Multilane lane selector152myConsecutiveLaneSelector = new GNEConsecutiveSelector(this, false);153154// create help creation module155myHelpCreationModule = new HelpCreationModule(this);156157// Create legend for E2 detector158myE2MultilaneLegendModule = new E2MultilaneLegendModule(this);159}160161162GNEAdditionalFrame::~GNEAdditionalFrame() {163// check if we have to delete base additional object164if (myBaseAdditional) {165delete myBaseAdditional;166}167}168169170void171GNEAdditionalFrame::show() {172// refresh tag selector173myAdditionalTagSelector->refreshTagSelector();174// reset last position175myLastClickedPosition = Position::INVALID;176// show frame177GNEFrame::show();178}179180181bool182GNEAdditionalFrame::addAdditional(const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {183// first check that current selected additional is valid184if (myAdditionalTagSelector->getCurrentTemplateAC() == nullptr) {185myViewNet->setStatusBarText(TL("Current selected additional isn't valid."));186return false;187}188// obtain tagproperty (only for improve code legibility)189const auto& tagProperties = myAdditionalTagSelector->getCurrentTemplateAC()->getTagProperty();190// check if toogle selection191if ((viewObjects.getAttributeCarrierFront() == viewObjects.getLaneFront()) &&192(myViewObjetsSelector->toggleSelectedLane(viewObjects.getLaneFront()))) {193return true;194}195if (myViewObjetsSelector->toggleSelectedElement(viewObjects.getAttributeCarrierFront())) {196return true;197}198// check if add a lane in consecutive lane selector199if (tagProperties->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {200return myConsecutiveLaneSelector->addLane(viewObjects.getLaneFront());201}202// disable rerouter elements (temporal)203if ((tagProperties->getTag() == SUMO_TAG_INTERVAL) ||204(tagProperties->getTag() == SUMO_TAG_DEST_PROB_REROUTE) ||205(tagProperties->getTag() == SUMO_TAG_CLOSING_REROUTE) ||206(tagProperties->getTag() == SUMO_TAG_CLOSING_LANE_REROUTE) ||207(tagProperties->getTag() == SUMO_TAG_ROUTE_PROB_REROUTE) ||208(tagProperties->getTag() == SUMO_TAG_PARKING_AREA_REROUTE)) {209WRITE_WARNING(TL("Currently unsupported. Create rerouter elements using rerouter dialog"));210return false;211}212// disable steps (temporal)213if (tagProperties->getTag() == SUMO_TAG_STEP) {214WRITE_WARNING(TL("Currently unsupported. Create VSS steps using VSS dialog"));215return false;216}217// disable flows (temporal)218if (tagProperties->getTag() == GNE_TAG_CALIBRATOR_FLOW) {219WRITE_WARNING(TL("Currently unsupported. Create calibratorFlows using calibrator dialog"));220return false;221}222// check last position223if ((myViewNet->getPositionInformation() == myLastClickedPosition) && !myViewNet->getMouseButtonKeyPressed().shiftKeyPressed()) {224WRITE_WARNING(TL("Shift + click to create two additionals in the same position"));225return false;226}227// check if additional attributes are valid228if (!myAdditionalAttributesEditor->checkAttributes(true)) {229return false;230}231// reset base additional232resetBaseAdditionalObject();233// init base additional object234if (!initBaseAdditionalObject(tagProperties, viewObjects)) {235return false;236}237// parse common attributes238if (!myViewObjetsSelector->fillSumoBaseObject(myBaseAdditional)) {239return false;240}241// add basic attributes and values242myAdditionalAttributesEditor->fillSumoBaseObject(myBaseAdditional);243// declare additional handler244GNEAdditionalHandler additionalHandler(myViewNet->getNet(), myBaseAdditional->hasStringAttribute(GNE_ATTR_ADDITIONAL_FILE) ?245myBaseAdditional->getStringAttribute(GNE_ATTR_ADDITIONAL_FILE) : "",246myViewNet->getViewParent()->getGNEAppWindows()->isUndoRedoAllowed());247// build additional248additionalHandler.parseSumoBaseObject(myBaseAdditional);249// Refresh additional Parent Selector (For additionals that have a limited number of children)250mySelectorAdditionalParent->refreshSelectorParentModule();251// clear selected view objects252myViewObjetsSelector->clearSelection();253myAdditionalAttributesEditor->refreshAttributesEditor();254return true;255}256257258GNETagSelector*259GNEAdditionalFrame::getAdditionalTagSelector() const {260return myAdditionalTagSelector;261}262263264GNEConsecutiveSelector*265GNEAdditionalFrame::getConsecutiveLaneSelector() const {266return myConsecutiveLaneSelector;267}268269270GNEAttributesEditor*271GNEAdditionalFrame::getAttributesEditor() const {272return myAdditionalAttributesEditor;273}274275276GNEViewObjectSelector*277GNEAdditionalFrame::getViewObjetsSelector() const {278return myViewObjetsSelector;279}280281282bool283GNEAdditionalFrame::createPath(const bool /* useLastRoute */) {284// obtain tagproperty (only for improve code legibility)285const auto tagProperty = myAdditionalTagSelector->getCurrentTemplateAC()->getTagProperty();286// first check that current tag is valid (currently only for E2 multilane detectors)287if (tagProperty->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {288// now check number of lanes289if (myConsecutiveLaneSelector->getLanePath().size() < 2) {290WRITE_WARNING(TL("E2 multilane detectors need at least two consecutive lanes"));291} else {292// reset base object293resetBaseAdditionalObject();294// set tag295myBaseAdditional->setTag(SUMO_TAG_LANE_AREA_DETECTOR);296// get attributes and values297myAdditionalAttributesEditor->fillSumoBaseObject(myBaseAdditional);298// add lane IDs299myBaseAdditional->addStringListAttribute(SUMO_ATTR_LANES, myConsecutiveLaneSelector->getLaneIDPath());300// set positions301myBaseAdditional->addDoubleAttribute(SUMO_ATTR_POSITION, myConsecutiveLaneSelector->getLanePath().front().second);302myBaseAdditional->addDoubleAttribute(SUMO_ATTR_ENDPOS, myConsecutiveLaneSelector->getLanePath().back().second);303// parse common attributes304if (myViewObjetsSelector->fillSumoBaseObject(myBaseAdditional)) {305// show warning dialogbox and stop check if input parameters are valid306if (myAdditionalAttributesEditor->checkAttributes(true)) {307// declare additional handler308GNEAdditionalHandler additionalHandler(myViewNet->getNet(), myBaseAdditional->hasStringAttribute(GNE_ATTR_ADDITIONAL_FILE) ?309myBaseAdditional->getStringAttribute(GNE_ATTR_ADDITIONAL_FILE) : "",310myViewNet->getViewParent()->getGNEAppWindows()->isUndoRedoAllowed());311// build additional312additionalHandler.parseSumoBaseObject(myBaseAdditional);313// Refresh additional Parent Selector (For additionals that have a limited number of children)314mySelectorAdditionalParent->refreshSelectorParentModule();315// abort E2 creation316myConsecutiveLaneSelector->abortPathCreation();317return true;318}319}320}321}322return false;323}324325326void327GNEAdditionalFrame::tagSelected() {328// get template AC329const auto templateAC = myAdditionalTagSelector->getCurrentTemplateAC();330if (templateAC) {331// show parameters332myAdditionalAttributesEditor->showAttributesEditor(templateAC, true);333// Show myAdditionalFrameParent if we're adding an slave element334if (templateAC->getTagProperty()->isChild()) {335mySelectorAdditionalParent->showSelectorParentModule(templateAC->getTagProperty()->getXMLParentTags());336} else {337mySelectorAdditionalParent->hideSelectorParentModule();338}339// Show EdgesSelector if we're adding an additional that own the attribute SUMO_ATTR_EDGES340if (templateAC->getTagProperty()->hasAttribute(SUMO_ATTR_EDGES)) {341myViewObjetsSelector->showNetworkElementsSelector(SUMO_TAG_EDGE, SUMO_ATTR_EDGES);342} else {343myViewObjetsSelector->hideNetworkElementsSelector();344}345// show help creation modul346myHelpCreationModule->showHelpCreationModule(templateAC->getTagProperty()->getTag());347// check if we must show consecutive lane selector348if (templateAC->getTagProperty()->getTag() == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {349myConsecutiveLaneSelector->showConsecutiveLaneSelectorModule();350myE2MultilaneLegendModule->showE2MultilaneLegend();351myViewObjetsSelector->hideNetworkElementsSelector();352// recompute network353myViewNet->getNet()->computeNetwork(myViewNet->getViewParent()->getGNEAppWindows());354} else if (templateAC->getTagProperty()->hasAttribute(SUMO_ATTR_LANES)) {355myConsecutiveLaneSelector->hideConsecutiveLaneSelectorModule();356myE2MultilaneLegendModule->hideE2MultilaneLegend();357myViewObjetsSelector->showNetworkElementsSelector(SUMO_TAG_LANE, SUMO_ATTR_LANES);358} else {359myConsecutiveLaneSelector->hideConsecutiveLaneSelectorModule();360myE2MultilaneLegendModule->hideE2MultilaneLegend();361}362// reset last position363myLastClickedPosition = Position::INVALID;364} else {365// hide all modules if additional isn't valid366myAdditionalAttributesEditor->hideAttributesEditor();367mySelectorAdditionalParent->hideSelectorParentModule();368myViewObjetsSelector->hideNetworkElementsSelector();369myConsecutiveLaneSelector->hideConsecutiveLaneSelectorModule();370myHelpCreationModule->hideHelpCreationModule();371myE2MultilaneLegendModule->hideE2MultilaneLegend();372}373}374375376void377GNEAdditionalFrame::resetBaseAdditionalObject() {378// check if baseAdditional exist, and if yes, delete it379if (myBaseAdditional) {380// go to base additional root381while (myBaseAdditional->getParentSumoBaseObject()) {382myBaseAdditional = myBaseAdditional->getParentSumoBaseObject();383}384// delete baseAdditional (and all children)385delete myBaseAdditional;386// reset baseAdditional387myBaseAdditional = nullptr;388}389// create an new base additional390myBaseAdditional = new CommonXMLStructure::SumoBaseObject(nullptr);391}392393394bool395GNEAdditionalFrame::initBaseAdditionalObject(const GNETagProperties* tagProperty, const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {396// declare tag for base additional397auto baseAdditionalTag = tagProperty->getTag();398// check if tag has to be updated399if (baseAdditionalTag == GNE_TAG_MULTI_LANE_AREA_DETECTOR) {400baseAdditionalTag = SUMO_TAG_LANE_AREA_DETECTOR;401} else if (baseAdditionalTag == GNE_TAG_CALIBRATOR_FLOW) {402baseAdditionalTag = SUMO_TAG_FLOW;403}404// update view objects parents405viewObjects.fillSumoBaseObject(myBaseAdditional);406// check if additional is child of other element407if (tagProperty->isChild()) {408// check if we clicked over a parent409SumoXMLTag parentTag = SUMO_TAG_NOTHING;410for (const auto& pTag : tagProperty->getXMLParentTags()) {411if (myBaseAdditional->hasParentID(pTag)) {412parentTag = pTag;413}414}415// update selector additional parent416if (parentTag != SUMO_TAG_NOTHING) {417// update parent additional selected418mySelectorAdditionalParent->setIDSelected(myBaseAdditional->getParentID(parentTag));419}420// continue depending of parents421if (mySelectorAdditionalParent->getIdSelected().empty()) {422std::string messageError = toString(tagProperty->getXMLParentTags().front());423if (tagProperty->getXMLParentTags().size() > 1) {424const int numParents = (int)tagProperty->getXMLParentTags().size();425messageError.clear();426for (int i = 0; i < numParents; i++) {427messageError.append(toString(tagProperty->getXMLParentTags().at(i)));428if (i == numParents - 2) {429messageError.append(" or ");430} else if (i < (numParents - 2)) {431messageError.append(", ");432}433}434}435WRITE_WARNING(TLF("A % must be selected before insertion of %.", messageError, tagProperty->getTagStr()));436return false;437} else {438// set parent tag // POSSIBLE ERROR WITH ACCESS AND BUSSTOPS!439myBaseAdditional->setTag(tagProperty->getXMLParentTags().front());440// add ID441myBaseAdditional->addStringAttribute(SUMO_ATTR_ID, mySelectorAdditionalParent->getIdSelected());442// create base additional again as child of current base additional443myBaseAdditional = new CommonXMLStructure::SumoBaseObject(myBaseAdditional);444}445}446// set baseAdditional tag447myBaseAdditional->setTag(baseAdditionalTag);448// Obtain position as the clicked position over view449const Position viewPosSnapped = myViewNet->snapToActiveGrid(myViewNet->getPositionInformation());450// add position and X-Y-Z attributes451myBaseAdditional->addPositionAttribute(SUMO_ATTR_POSITION, viewPosSnapped);452myBaseAdditional->addDoubleAttribute(SUMO_ATTR_X, viewPosSnapped.x());453myBaseAdditional->addDoubleAttribute(SUMO_ATTR_Y, viewPosSnapped.y());454myBaseAdditional->addDoubleAttribute(SUMO_ATTR_Z, viewPosSnapped.z());455// check if add edge attributes456if (tagProperty->hasAttribute(SUMO_ATTR_EDGE)) {457if (viewObjects.getEdgeFront() == nullptr) {458return false;459} else {460myBaseAdditional->addStringAttribute(SUMO_ATTR_EDGE, viewObjects.getEdgeFront()->getID());461// Obtain position of the mouse over lane (limited over grid)462const auto firstLane = viewObjects.getEdgeFront()->getChildLanes().front();463const double mousePositionOverLane = firstLane->getLaneShape().nearest_offset_to_point2D(viewPosSnapped) / firstLane->getLengthGeometryFactor();464myBaseAdditional->addDoubleAttribute(SUMO_ATTR_POSITION, mousePositionOverLane);465}466} else if (tagProperty->getTag() == SUMO_TAG_VAPORIZER) {467// special case for vaporizers468if (viewObjects.getEdgeFront() == nullptr) {469return false;470} else {471myBaseAdditional->addStringAttribute(SUMO_ATTR_ID, viewObjects.getEdgeFront()->getID());472}473}474// check if add lane attributes475if (tagProperty->hasAttribute(SUMO_ATTR_LANE)) {476if (viewObjects.getLaneFront() == nullptr) {477return false;478} else {479myBaseAdditional->addStringAttribute(SUMO_ATTR_LANE, viewObjects.getLaneFront()->getID());480myBaseAdditional->addDoubleAttribute(GNE_ATTR_LANELENGTH, viewObjects.getLaneFront()->getLaneShapeLength() / viewObjects.getLaneFront()->getLengthGeometryFactor());481// Obtain position of the mouse over lane (limited over grid)482const double mousePositionOverLane = viewObjects.getLaneFront()->getLaneShape().nearest_offset_to_point2D(viewPosSnapped) / viewObjects.getLaneFront()->getLengthGeometryFactor();483// special case for access484if (tagProperty->getTag() == SUMO_TAG_ACCESS) {485myBaseAdditional->addStringAttribute(SUMO_ATTR_POSITION, toString(mousePositionOverLane));486} else {487myBaseAdditional->addDoubleAttribute(SUMO_ATTR_POSITION, mousePositionOverLane);488}489}490}491// BaseAdditional created, then return true492return true;493}494495/****************************************************************************/496497498