Path: blob/main/src/netedit/frames/GNEConsecutiveSelector.cpp
169678 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 GNEConsecutiveSelector.cpp14/// @author Pablo Alvarez Lopez15/// @date Mar 202216///17// Consecutive lane selector module18/****************************************************************************/1920#include <netedit/GNEApplicationWindow.h>21#include <netedit/GNENet.h>22#include <netedit/GNEViewNet.h>23#include <netedit/GNEViewParent.h>24#include <netedit/elements/network/GNEConnection.h>25#include <utils/gui/div/GLHelper.h>26#include <utils/gui/div/GUIDesigns.h>27#include <utils/gui/globjects/GLIncludes.h>28#include <utils/gui/windows/GUIAppEnum.h>2930#include "GNEConsecutiveSelector.h"31#include "GNEFrame.h"3233// ===========================================================================34// FOX callback mapping35// ===========================================================================3637FXDEFMAP(GNEConsecutiveSelector) ConsecutiveLaneSelectorMap[] = {38FXMAPFUNC(SEL_COMMAND, MID_GNE_ABORT, GNEConsecutiveSelector::onCmdAbortPathCreation),39FXMAPFUNC(SEL_COMMAND, MID_GNE_FINISH, GNEConsecutiveSelector::onCmdCreatePath),40FXMAPFUNC(SEL_COMMAND, MID_GNE_REMOVELAST, GNEConsecutiveSelector::onCmdRemoveLastElement),41FXMAPFUNC(SEL_COMMAND, MID_GNE_SHOWCANDIDATES, GNEConsecutiveSelector::onCmdShowCandidateLanes)42};4344// Object implementation45FXIMPLEMENT(GNEConsecutiveSelector, MFXGroupBoxModule, ConsecutiveLaneSelectorMap, ARRAYNUMBER(ConsecutiveLaneSelectorMap))4647// ---------------------------------------------------------------------------48// GNEConsecutiveSelector - methods49// ---------------------------------------------------------------------------5051GNEConsecutiveSelector::GNEConsecutiveSelector(GNEFrame* frameParent, const bool allowOneLane) :52MFXGroupBoxModule(frameParent, TL("Consecutive lane selector")),53myFrameParent(frameParent),54myAllowOneLane(allowOneLane) {55// create label for route info56myInfoPathLabel = new FXLabel(getCollapsableFrame(), TL("No lanes selected"), 0, GUIDesignLabelThick(JUSTIFY_LEFT));57// create button for finish route creation58myFinishCreationButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Finish path creation"), "", "", nullptr, this, MID_GNE_FINISH, GUIDesignButton);59myFinishCreationButton->disable();60// create button for abort route creation61myAbortCreationButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Abort path creation"), "", "", nullptr, this, MID_GNE_ABORT, GUIDesignButton);62myAbortCreationButton->disable();63// create button for remove last inserted lane64myRemoveLastInsertedElement = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Remove last lane"), "", "", nullptr, this, MID_GNE_REMOVELAST, GUIDesignButton);65myRemoveLastInsertedElement->disable();66// create check button67myShowCandidateLanes = new FXCheckButton(getCollapsableFrame(), TL("Show candidate lanes"), this, MID_GNE_SHOWCANDIDATES, GUIDesignCheckButton);68myShowCandidateLanes->setCheck(TRUE);69// create information label70new FXLabel(this, (TL("-BACKSPACE: undo click") + std::string("\n") + TL("-ESC: Abort path creation")).c_str(), 0, GUIDesignLabelFrameInformation);71}727374GNEConsecutiveSelector::~GNEConsecutiveSelector() {}757677void78GNEConsecutiveSelector::showConsecutiveLaneSelectorModule() {79// first abort creation80abortPathCreation();81// disable buttons82myFinishCreationButton->disable();83myAbortCreationButton->disable();84myRemoveLastInsertedElement->disable();85// update lane colors86updateLaneColors();87// recalc before show (to avoid graphic problems)88recalc();89// show modul90show();91}929394void95GNEConsecutiveSelector::hideConsecutiveLaneSelectorModule() {96// clear path97clearPath();98// hide modul99hide();100}101102103const std::vector<std::pair<GNELane*, double> >&104GNEConsecutiveSelector::getLanePath() const {105return myLanePath;106}107108109const std::vector<std::string>110GNEConsecutiveSelector::getLaneIDPath() const {111std::vector<std::string> laneIDs;112for (const auto& lane : myLanePath) {113if (laneIDs.empty() || (laneIDs.back() != lane.first->getID())) {114laneIDs.push_back(lane.first->getID());115}116}117return laneIDs;118}119120121bool122GNEConsecutiveSelector::addLane(GNELane* lane) {123// first check if lane is valid124if (lane == nullptr) {125return false;126}127// check candidate lane128if ((myShowCandidateLanes->getCheck() == TRUE) && !lane->isPossibleCandidate()) {129if (lane->isSpecialCandidate() || lane->isConflictedCandidate()) {130// Write warning131WRITE_WARNING(TL("Invalid lane"));132// abort add lane133return false;134}135}136// get mouse position137const Position mousePos = myFrameParent->getViewNet()->snapToActiveGrid(myFrameParent->getViewNet()->getPositionInformation());138// calculate lane offset139const double posOverLane = lane->getLaneShape().nearest_offset_to_point2D(mousePos);140// All checks ok, then add it in selected elements141if (myLanePath.empty()) {142myLanePath.push_back(std::make_pair(lane, posOverLane));143} else if ((myLanePath.size() == 1) && (myLanePath.front().first == lane)) {144if (myAllowOneLane) {145myLanePath.push_back(std::make_pair(lane, posOverLane));146} else {147// Write warning148WRITE_WARNING(TL("Lane path needs at least two lanes"));149// abort add lane150return false;151}152} else if (myLanePath.back().first == lane) {153// only change last position154myLanePath.back().second = posOverLane;155} else {156myLanePath.push_back(std::make_pair(lane, posOverLane));157// special case if we clicked over a new lane after a previous double lane158if ((myLanePath.size() == 3) && (myLanePath.at(0).first == myLanePath.at(1).first)) {159// remove second lane160myLanePath.erase(myLanePath.begin() + 1);161}162}163// enable abort route button164myAbortCreationButton->enable();165// enable finish button166myFinishCreationButton->enable();167// disable undo/redo temporally168myFrameParent->getViewNet()->getViewParent()->getGNEAppWindows()->disableUndoRedoTemporally(TL("route creation"));169// enable or disable remove last lane button170if (myLanePath.size() > 1) {171myRemoveLastInsertedElement->enable();172} else {173myRemoveLastInsertedElement->disable();174}175// update info route label176updateInfoRouteLabel();177// update lane colors178updateLaneColors();179return true;180}181182183bool184GNEConsecutiveSelector::drawCandidateLanesWithSpecialColor() const {185return (myShowCandidateLanes->getCheck() == TRUE);186}187188189void190GNEConsecutiveSelector::updateLaneColors() {191// reset all flags192for (const auto& edge : myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {193for (const auto& lane : edge.second->getChildLanes()) {194lane->resetCandidateFlags();195}196}197// set reachability198if (myLanePath.size() > 0 && (myShowCandidateLanes->getCheck() == TRUE)) {199// first mark all lanes as invalid200for (const auto& edge : myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {201for (const auto& lane : edge.second->getChildLanes()) {202lane->setConflictedCandidate(true);203}204}205// now mark lane paths as valid206for (const auto& lane : myLanePath) {207// disable conflicted candidate208lane.first->setConflictedCandidate(false);209if (lane == myLanePath.back()) {210lane.first->setSourceCandidate(true);211} else {212lane.first->setTargetCandidate(true);213}214}215// get parent edge216const GNEEdge* edge = myLanePath.back().first->getParentEdge();217// iterate over connections218for (const auto& connection : edge->getGNEConnections()) {219// mark possible candidates220if (connection->getLaneFrom() == myLanePath.back().first) {221connection->getLaneTo()->setConflictedCandidate(false);222connection->getLaneTo()->setPossibleCandidate(true);223}224}225}226// update view net227myFrameParent->getViewNet()->updateViewNet();228}229230231void232GNEConsecutiveSelector::drawTemporalConsecutiveLanePath() const {233// Only draw if there is at least one lane234if (myLanePath.size() > 0) {235// get widths236const double lineWidth = 0.35;237const double lineWidthin = 0.25;238// declare vector with shapes239std::vector<PositionVector> shapes;240// iterate over lanes (only if there is more than one)241if ((myLanePath.size() == 2) && (myLanePath.front().first == myLanePath.back().first)) {242// only add first lane shape243shapes.push_back(myLanePath.front().first->getLaneShape());244// adjust shape245shapes.front() = shapes.front().getSubpart(myLanePath.front().second, myLanePath.back().second);246} else if (myLanePath.size() > 1) {247// get shapes248for (int i = 0; i < (int)myLanePath.size(); i++) {249// get lane250const GNELane* lane = myLanePath.at(i).first;251// add lane shape252shapes.push_back(lane->getLaneShape());253// draw connection between lanes254if ((i + 1) < (int)myLanePath.size()) {255// get next lane256const GNELane* nextLane = myLanePath.at(i + 1).first;257if (lane->getLane2laneConnections().exist(nextLane)) {258shapes.push_back(lane->getLane2laneConnections().getLane2laneGeometry(nextLane).getShape());259} else {260shapes.push_back({lane->getLaneShape().back(), nextLane->getLaneShape().front()});261}262}263}264// adjust first and last shape265shapes.front() = shapes.front().splitAt(myLanePath.front().second).second;266shapes.back() = shapes.back().splitAt(myLanePath.back().second).first;267}268// Add a draw matrix269GLHelper::pushMatrix();270// move to temporal shape271glTranslated(0, 0, GLO_TEMPORALSHAPE);272// iterate over shapes273for (const auto& shape : shapes) {274// set extern275GLHelper::setColor(RGBColor::GREY);276// draw extern shape277GLHelper::drawBoxLines(shape, lineWidth);278// push matrix279GLHelper::pushMatrix();280// move to front281glTranslated(0, 0, 0.1);282// set orange color283GLHelper::setColor(RGBColor::ORANGE);284// draw intern shape285GLHelper::drawBoxLines(shape, lineWidthin);286// Pop matrix287GLHelper::popMatrix();288}289// draw points290if (shapes.size() > 0) {291// draw geometry points292GUIGeometry::drawGeometryPoints(GUIVisualizationSettings::Detail::AdditionalDetails,293{shapes.front().front(), shapes.back().back()}, RGBColor::RED,294myFrameParent->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius, 1, false);295}296// Pop last matrix297GLHelper::popMatrix();298}299}300301302void303GNEConsecutiveSelector::abortPathCreation() {304// first check that there is elements305if (myLanePath.size() > 0) {306// unblock undo/redo307myFrameParent->getViewNet()->getViewParent()->getGNEAppWindows()->enableUndoRedoTemporally();308// clear lanes309clearPath();310// disable buttons311myFinishCreationButton->disable();312myAbortCreationButton->disable();313myRemoveLastInsertedElement->disable();314// update info route label315updateInfoRouteLabel();316// update reachability317updateLaneColors();318// update view (to see the new route)319myFrameParent->getViewNet()->updateViewNet();320}321}322323324void325GNEConsecutiveSelector::removeLastElement() {326if (myLanePath.size() > 1) {327// remove special color of last selected lane328myLanePath.back().first->resetCandidateFlags();329// remove last lane330myLanePath.pop_back();331// change last lane flag332if ((myLanePath.size() > 0) && myLanePath.back().first->isSourceCandidate()) {333myLanePath.back().first->setSourceCandidate(false);334myLanePath.back().first->setTargetCandidate(true);335}336// enable or disable remove last lane button337if (myLanePath.size() > 1) {338myRemoveLastInsertedElement->enable();339} else {340myRemoveLastInsertedElement->disable();341}342// update info route label343updateInfoRouteLabel();344// update reachability345updateLaneColors();346// update view347myFrameParent->getViewNet()->updateViewNet();348}349}350351352long353GNEConsecutiveSelector::onCmdCreatePath(FXObject*, FXSelector, void*) {354myFrameParent->createPath(false);355return 1;356}357358359long360GNEConsecutiveSelector::onCmdAbortPathCreation(FXObject*, FXSelector, void*) {361// just call abort path creation362abortPathCreation();363return 1;364}365366367long368GNEConsecutiveSelector::onCmdRemoveLastElement(FXObject*, FXSelector, void*) {369// just call remove last element370removeLastElement();371return 1;372}373374375long376GNEConsecutiveSelector::onCmdShowCandidateLanes(FXObject*, FXSelector, void*) {377// recalc frame378recalc();379// update lane colors (view will be updated within function)380updateLaneColors();381return 1;382}383384385GNEConsecutiveSelector::GNEConsecutiveSelector() :386myFrameParent(nullptr),387myAllowOneLane(false) {388}389390391void392GNEConsecutiveSelector::updateInfoRouteLabel() {393if (myLanePath.size() > 0) {394// declare variables for route info395double length = 0;396for (const auto& lane : myLanePath) {397length += lane.first->getParentEdge()->getNBEdge()->getLength();398}399// declare ostringstream for label and fill it400std::ostringstream information;401information402<< TL("- Selected lanes: ") << toString(myLanePath.size()) << "\n"403<< TL("- Length: ") << toString(length);404// set new label405myInfoPathLabel->setText(information.str().c_str());406} else {407myInfoPathLabel->setText(TL("No lanes selected"));408}409}410411412void413GNEConsecutiveSelector::clearPath() {414// reset all flags415for (const auto& edge : myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {416for (const auto& lane : edge.second->getChildLanes()) {417lane->resetCandidateFlags();418}419}420// clear path421myLanePath.clear();422// update info route label423updateInfoRouteLabel();424}425426/****************************************************************************/427428429