Path: blob/main/src/netedit/frames/network/GNEConnectorFrame.cpp
193889 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2011-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 GNEConnectorFrame.cpp14/// @author Jakob Erdmann15/// @date May 201116///17// The Widget for modifying lane-to-lane connections18/****************************************************************************/1920#include <netedit/changes/GNEChange_Connection.h>21#include <netedit/dialogs/basic/GNEWarningBasicDialog.h>22#include <netedit/elements/network/GNEConnection.h>23#include <netedit/frames/common/GNESelectorFrame.h>24#include <netedit/GNEApplicationWindow.h>25#include <netedit/GNENet.h>26#include <netedit/GNEUndoList.h>27#include <netedit/GNEViewParent.h>28#include <utils/foxtools/MFXDynamicLabel.h>29#include <utils/gui/div/GUIDesigns.h>30#include <utils/gui/windows/GUIAppEnum.h>3132#include "GNEConnectorFrame.h"3334// ===========================================================================35// FOX callback mapping36// ===========================================================================3738FXDEFMAP(GNEConnectorFrame::ConnectionModifications) ConnectionModificationsMap[] = {39FXMAPFUNC(SEL_COMMAND, MID_CANCEL, GNEConnectorFrame::ConnectionModifications::onCmdCancelModifications),40FXMAPFUNC(SEL_COMMAND, MID_OK, GNEConnectorFrame::ConnectionModifications::onCmdSaveModifications),41};4243FXDEFMAP(GNEConnectorFrame::ConnectionOperations) ConnectionOperationsMap[] = {44FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_CLEAR, GNEConnectorFrame::ConnectionOperations::onCmdClearSelectedConnections),45FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_RESET, GNEConnectorFrame::ConnectionOperations::onCmdResetSelectedConnections),46FXMAPFUNC(SEL_COMMAND, MID_GNE_CONNECTORFRAME_SELECTDEADENDS, GNEConnectorFrame::ConnectionOperations::onCmdSelectDeadEnds),47FXMAPFUNC(SEL_COMMAND, MID_GNE_CONNECTORFRAME_SELECTDEADSTARTS, GNEConnectorFrame::ConnectionOperations::onCmdSelectDeadStarts),48FXMAPFUNC(SEL_COMMAND, MID_GNE_CONNECTORFRAME_SELECTCONFLICTS, GNEConnectorFrame::ConnectionOperations::onCmdSelectConflicts),49FXMAPFUNC(SEL_COMMAND, MID_GNE_CONNECTORFRAME_SELECTPASS, GNEConnectorFrame::ConnectionOperations::onCmdSelectPass),50};5152// Object implementation53FXIMPLEMENT(GNEConnectorFrame::ConnectionModifications, GNEGroupBoxModule, ConnectionModificationsMap, ARRAYNUMBER(ConnectionModificationsMap))54FXIMPLEMENT(GNEConnectorFrame::ConnectionOperations, GNEGroupBoxModule, ConnectionOperationsMap, ARRAYNUMBER(ConnectionOperationsMap))555657// ===========================================================================58// method definitions59// ===========================================================================6061// ---------------------------------------------------------------------------62// GNEConnectorFrame::CurrentLane - methods63// ---------------------------------------------------------------------------6465GNEConnectorFrame::CurrentLane::CurrentLane(GNEConnectorFrame* connectorFrameParent) :66GNEGroupBoxModule(connectorFrameParent, TL("Lane")) {67// create lane label68myCurrentLaneLabel = new FXLabel(getCollapsableFrame(), TL("No lane selected"), 0, GUIDesignLabel(JUSTIFY_LEFT));69}707172GNEConnectorFrame::CurrentLane::~CurrentLane() {}737475void76GNEConnectorFrame::CurrentLane::updateCurrentLaneLabel(const std::string& laneID) {77if (laneID.empty()) {78myCurrentLaneLabel->setText(TL("No lane selected"));79} else {80myCurrentLaneLabel->setText((std::string(TL("Current Lane: ")) + laneID).c_str());81}82}8384// ---------------------------------------------------------------------------85// GNEConnectorFrame::ConnectionModifications - methods86// ---------------------------------------------------------------------------8788GNEConnectorFrame::ConnectionModifications::ConnectionModifications(GNEConnectorFrame* connectorFrameParent) :89GNEGroupBoxModule(connectorFrameParent, TL("Modifications")),90myConnectorFrameParent(connectorFrameParent) {9192// Create "Cancel" button93myCancelButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Cancel"), "", TL("Discard connection modifications (Esc)"),94GUIIconSubSys::getIcon(GUIIcon::CANCEL), this, MID_CANCEL, GUIDesignButton);95// Create "OK" button96mySaveButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("OK"), "", TL("Save connection modifications (Enter)"),97GUIIconSubSys::getIcon(GUIIcon::ACCEPT), this, MID_OK, GUIDesignButton);9899// Create checkbox for protect routes100myProtectRoutesCheckBox = new FXCheckButton(getCollapsableFrame(), TL("Protect routes"), this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);101}102103104GNEConnectorFrame::ConnectionModifications::~ConnectionModifications() {}105106107long108GNEConnectorFrame::ConnectionModifications::onCmdCancelModifications(FXObject*, FXSelector, void*) {109if (myConnectorFrameParent->myCurrentEditedLane != 0) {110myConnectorFrameParent->getViewNet()->getUndoList()->abortAllChangeGroups();111if (myConnectorFrameParent->myNumChanges) {112myConnectorFrameParent->getViewNet()->setStatusBarText(TL("Changes reverted"));113}114myConnectorFrameParent->cleanup();115myConnectorFrameParent->getViewNet()->updateViewNet();116}117return 1;118}119120121long122GNEConnectorFrame::ConnectionModifications::onCmdSaveModifications(FXObject*, FXSelector, void*) {123if (myConnectorFrameParent->myCurrentEditedLane != 0) {124// check if routes has to be protected125if (myProtectRoutesCheckBox->isEnabled() && (myProtectRoutesCheckBox->getCheck() == TRUE)) {126for (const auto& demandElement : myConnectorFrameParent->myCurrentEditedLane->getParentEdge()->getChildDemandElements()) {127if (demandElement->isDemandElementValid() != GNEDemandElement::Problem::OK) {128// open warning dialog129GNEWarningBasicDialog(myConnectorFrameParent->getViewNet()->getViewParent()->getGNEAppWindows(),130TL("Error saving connection operations"),131TLF("Connection edition cannot be saved because route '%s' is broken.", demandElement->getID()));132return 1;133}134}135}136// finish route editing137myConnectorFrameParent->getViewNet()->getUndoList()->end();138if (myConnectorFrameParent->myNumChanges) {139myConnectorFrameParent->getViewNet()->setStatusBarText(TL("Changes accepted"));140}141myConnectorFrameParent->cleanup();142// mark network for recomputing143myConnectorFrameParent->getViewNet()->getNet()->requireRecompute();144}145return 1;146}147148// ---------------------------------------------------------------------------149// GNEConnectorFrame::ConnectionOperations - methods150// ---------------------------------------------------------------------------151152GNEConnectorFrame::ConnectionOperations::ConnectionOperations(GNEConnectorFrame* connectorFrameParent) :153GNEGroupBoxModule(connectorFrameParent, TL("Operations")),154myConnectorFrameParent(connectorFrameParent) {155156// Create "Select Dead Ends" button157mySelectDeadEndsButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Select Dead Ends"), "", TL("Selects all lanes that have no outgoing connection (clears previous selection)"),1580, this, MID_GNE_CONNECTORFRAME_SELECTDEADENDS, GUIDesignButton);159// Create "Select Dead Starts" button160mySelectDeadStartsButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Select Dead Starts"), "", TL("Selects all lanes that have no incoming connection (clears previous selection)"),1610, this, MID_GNE_CONNECTORFRAME_SELECTDEADSTARTS, GUIDesignButton);162// Create "Select Conflicts" button163mySelectConflictsButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Select Conflicts"), "", TL("Selects all lanes with more than one incoming connection from the same edge (clears previous selection)"),1640, this, MID_GNE_CONNECTORFRAME_SELECTCONFLICTS, GUIDesignButton);165// Create "Select Edges which may always pass" button166mySelectPassingButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Select Passing"), "", TL("Selects all lanes with a connection that has the 'pass' attribute set"),1670, this, MID_GNE_CONNECTORFRAME_SELECTPASS, GUIDesignButton);168// Create "Clear Selected" button169myClearSelectedButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Clear Selected"), "", TL("Clears all connections of all selected objects"),1700, this, MID_CHOOSEN_CLEAR, GUIDesignButton);171// Create "Reset Selected" button172myResetSelectedButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Reset Selected"), "", TL("Recomputes connections at all selected junctions"),1730, this, MID_CHOOSEN_RESET, GUIDesignButton);174}175176177GNEConnectorFrame::ConnectionOperations::~ConnectionOperations() {}178179180long181GNEConnectorFrame::ConnectionOperations::onCmdSelectDeadEnds(FXObject*, FXSelector, void*) {182// select all lanes that have no successor lane183std::vector<GNEAttributeCarrier*> deadEnds;184// every edge knows its outgoing connections so we can look at each edge in isolation185for (const auto& edge : myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {186for (const auto& lane : edge.second->getChildLanes()) {187if (edge.second->getNBEdge()->getConnectionsFromLane(lane->getIndex()).size() == 0) {188deadEnds.push_back(lane);189}190}191}192myConnectorFrameParent->getViewNet()->getViewParent()->getSelectorFrame()->handleIDs(deadEnds, GNESelectorFrame::ModificationMode::Operation::REPLACE);193myConnectorFrameParent->getViewNet()->updateViewNet();194return 1;195}196197198long199GNEConnectorFrame::ConnectionOperations::onCmdSelectDeadStarts(FXObject*, FXSelector, void*) {200// select all lanes that have no predecessor lane201std::set<GNEAttributeCarrier*> deadStarts;202GNENet* net = myConnectorFrameParent->getViewNet()->getNet();203// every edge knows only its outgoing connections so we look at whole junctions204for (const auto& junction : myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getJunctions()) {205// first collect all outgoing lanes206for (const auto& outgoingEdge : junction.second->getGNEOutgoingEdges()) {207for (const auto& lane : outgoingEdge->getChildLanes()) {208deadStarts.insert(lane);209}210}211// then remove all approached lanes212for (const auto& incomingEdge : junction.second->getGNEIncomingEdges()) {213for (const auto& connection : incomingEdge->getNBEdge()->getConnections()) {214deadStarts.erase(net->getAttributeCarriers()->retrieveEdge(connection.toEdge->getID())->getChildLanes()[connection.toLane]);215}216}217}218std::vector<GNEAttributeCarrier*> selectObjects(deadStarts.begin(), deadStarts.end());219myConnectorFrameParent->getViewNet()->getViewParent()->getSelectorFrame()->handleIDs(selectObjects, GNESelectorFrame::ModificationMode::Operation::REPLACE);220myConnectorFrameParent->getViewNet()->updateViewNet();221return 1;222}223224225long226GNEConnectorFrame::ConnectionOperations::onCmdSelectConflicts(FXObject*, FXSelector, void*) {227std::vector<GNEAttributeCarrier*> conflicts;228// conflicts happen per edge so we can look at each edge in isolation229for (const auto& edge : myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {230const EdgeVector destinations = edge.second->getNBEdge()->getConnectedEdges();231for (const auto& destination : destinations) {232GNEEdge* dest = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveEdge(destination->getID());233for (const auto& lane : dest->getChildLanes()) {234const bool isConflicted = count_if(edge.second->getNBEdge()->getConnections().begin(), edge.second->getNBEdge()->getConnections().end(),235NBEdge::connections_toedgelane_finder(destination, (int)lane->getIndex(), -1)) > 1;236if (isConflicted) {237conflicts.push_back(lane);238}239}240}241242}243myConnectorFrameParent->getViewNet()->getViewParent()->getSelectorFrame()->handleIDs(conflicts, GNESelectorFrame::ModificationMode::Operation::REPLACE);244myConnectorFrameParent->getViewNet()->updateViewNet();245return 1;246}247248249long250GNEConnectorFrame::ConnectionOperations::onCmdSelectPass(FXObject*, FXSelector, void*) {251std::vector<GNEAttributeCarrier*> pass;252for (const auto& edge : myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {253for (const auto& connection : edge.second->getNBEdge()->getConnections()) {254if (connection.mayDefinitelyPass) {255pass.push_back(edge.second->getChildLanes()[connection.fromLane]);256}257}258}259myConnectorFrameParent->getViewNet()->getViewParent()->getSelectorFrame()->handleIDs(pass, GNESelectorFrame::ModificationMode::Operation::REPLACE);260myConnectorFrameParent->getViewNet()->updateViewNet();261return 1;262}263264265long266GNEConnectorFrame::ConnectionOperations::onCmdClearSelectedConnections(FXObject*, FXSelector, void*) {267myConnectorFrameParent->myConnectionModifications->onCmdCancelModifications(0, 0, 0);268myConnectorFrameParent->getViewNet()->getUndoList()->begin(GUIIcon::CONNECTION, TL("clear connections from selected lanes, edges and junctions"));269// clear junction's connection270const auto selectedJunctions = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getSelectedJunctions();271for (const auto& junction : selectedJunctions) {272junction->setLogicValid(false, myConnectorFrameParent->getViewNet()->getUndoList()); // clear connections273junction->setLogicValid(false, myConnectorFrameParent->getViewNet()->getUndoList(), GNEAttributeCarrier::FEATURE_MODIFIED); // prevent re-guessing274}275// clear edge's connection276const auto selectedEdges = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getSelectedEdges();277for (const auto& edge : selectedEdges) {278for (const auto& lane : edge->getChildLanes()) {279myConnectorFrameParent->removeConnections(lane);280}281}282// clear lane's connection283const auto selectedLanes = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getSelectedLanes();284for (const auto& lane : selectedLanes) {285myConnectorFrameParent->removeConnections(lane);286}287myConnectorFrameParent->getViewNet()->getUndoList()->end();288myConnectorFrameParent->getViewNet()->updateViewNet();289return 1;290}291292293long294GNEConnectorFrame::ConnectionOperations::onCmdResetSelectedConnections(FXObject*, FXSelector, void*) {295myConnectorFrameParent->myConnectionModifications->onCmdCancelModifications(0, 0, 0);296myConnectorFrameParent->getViewNet()->getUndoList()->begin(GUIIcon::CONNECTION, TL("reset connections from selected lanes"));297const auto selectedJunctions = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getSelectedJunctions();298for (const auto& junction : selectedJunctions) {299junction->setLogicValid(false, myConnectorFrameParent->getViewNet()->getUndoList());300}301myConnectorFrameParent->getViewNet()->getUndoList()->end();302if (selectedJunctions.size() > 0) {303auto viewNet = myConnectorFrameParent->getViewNet();304viewNet->getNet()->requireRecompute();305viewNet->getNet()->computeNetwork(viewNet->getViewParent()->getGNEAppWindows());306}307myConnectorFrameParent->getViewNet()->updateViewNet();308return 1;309}310311// ---------------------------------------------------------------------------312// GNEConnectorFrame::ConnectionSelection - methods313// ---------------------------------------------------------------------------314315GNEConnectorFrame::ConnectionSelection::ConnectionSelection(GNEConnectorFrame* connectorFrameParent) :316GNEGroupBoxModule(connectorFrameParent, TL("Selection")) {317// create label318new MFXDynamicLabel(getCollapsableFrame(), (std::string("- ") + TL("Hold <SHIFT> while clicking to create unyielding connections (pass=true).")).c_str(), 0, GUIDesignLabelFrameInformation);319new MFXDynamicLabel(getCollapsableFrame(), (std::string("- ") + TL("Hold <CTRL> while clicking to create conflicting connections (i.e. at zipper nodes or with incompatible permissions)")).c_str(), 0, GUIDesignLabelFrameInformation);320}321322323GNEConnectorFrame::ConnectionSelection::~ConnectionSelection() {}324325// ---------------------------------------------------------------------------326// GNEConnectorFrame::ConnectionLegend - methods327// ---------------------------------------------------------------------------328329GNEConnectorFrame::Legend::Legend(GNEConnectorFrame* connectorFrameParent) :330GNEGroupBoxModule(connectorFrameParent, TL("Information")) {331332// create possible target label333FXLabel* possibleTargetLabel = new FXLabel(getCollapsableFrame(), TL("Possible Target"), 0, GUIDesignLabel(JUSTIFY_LEFT));334possibleTargetLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.possible));335possibleTargetLabel->setTextColor(MFXUtils::getFXColor(RGBColor::WHITE));336337// create source label338FXLabel* sourceLabel = new FXLabel(getCollapsableFrame(), TL("Source lane"), 0, GUIDesignLabel(JUSTIFY_LEFT));339sourceLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.source));340341// create target label342FXLabel* targetLabel = new FXLabel(getCollapsableFrame(), TL("Target lane"), 0, GUIDesignLabel(JUSTIFY_LEFT));343targetLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.target));344345// create target (pass) label346FXLabel* targetPassLabel = new FXLabel(getCollapsableFrame(), TL("Target (pass)"), 0, GUIDesignLabel(JUSTIFY_LEFT));347targetPassLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.special));348349// create conflict label350FXLabel* conflictLabel = new FXLabel(getCollapsableFrame(), TL("Conflict"), 0, GUIDesignLabel(JUSTIFY_LEFT));351conflictLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.conflict));352}353354355GNEConnectorFrame::Legend::~Legend() {}356357// ---------------------------------------------------------------------------358// GNEConnectorFrame - methods359// ---------------------------------------------------------------------------360361GNEConnectorFrame::GNEConnectorFrame(GNEViewParent* viewParent, GNEViewNet* viewNet):362GNEFrame(viewParent, viewNet, TL("Edit Connections")),363myCurrentEditedLane(0),364myNumChanges(0) {365// create current lane module366myCurrentLane = new CurrentLane(this);367368// create connection modifications module369myConnectionModifications = new ConnectionModifications(this);370371// create connection operations module372myConnectionOperations = new ConnectionOperations(this);373374// create connection selection module375myConnectionSelection = new ConnectionSelection(this);376377// create connection legend module378myLegend = new Legend(this);379}380381382GNEConnectorFrame::~GNEConnectorFrame() {}383384385void386GNEConnectorFrame::handleLaneClick(const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {387// get lane front388GNELane* clickedLane = viewObjects.getLaneFrontNonLocked();389// iterate over lanes390for (const auto& lane : viewObjects.getLanes()) {391// if parent edge of lane is front element, update clickedLane392if (lane->getParentEdge()->isMarkedForDrawingFront()) {393clickedLane = lane;394}395}396// build connection397buildConnection(clickedLane, myViewNet->getMouseButtonKeyPressed().shiftKeyPressed(), myViewNet->getMouseButtonKeyPressed().controlKeyPressed(), true);398}399400401GNEConnectorFrame::ConnectionModifications*402GNEConnectorFrame::getConnectionModifications() const {403return myConnectionModifications;404}405406407void408GNEConnectorFrame::removeConnections(GNELane* lane) {409// select lane as current lane410buildConnection(lane, false, false, true); // select as current lane411// iterate over all potential targets412for (const auto& potentialTarget : myPotentialTargets) {413// remove connections using the appropiate parameters in function "buildConnection"414buildConnection(potentialTarget, false, false, false);415}416// save modifications417myConnectionModifications->onCmdSaveModifications(0, 0, 0);418}419420421void422GNEConnectorFrame::buildConnection(GNELane* lane, const bool mayDefinitelyPass, const bool allowConflict, const bool toggle) {423if (myCurrentEditedLane == 0) {424myCurrentEditedLane = lane;425myCurrentEditedLane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.source);426initTargets();427myNumChanges = 0;428myViewNet->getUndoList()->begin(GUIIcon::CONNECTION, TL("modify connections"));429} else if (myPotentialTargets.count(lane)430|| (allowConflict && lane->getParentEdge()->getFromJunction() == myCurrentEditedLane->getParentEdge()->getToJunction())) {431const int fromIndex = myCurrentEditedLane->getIndex();432GNEEdge* srcEdge = myCurrentEditedLane->getParentEdge();433GNEEdge* destEdge = lane->getParentEdge();434std::vector<NBEdge::Connection> connections = srcEdge->getNBEdge()->getConnectionsFromLane(fromIndex);435bool changed = false;436// get lane status437LaneStatus status = getLaneStatus(connections, lane);438if (status == LaneStatus::CONFLICTED && allowConflict) {439status = LaneStatus::UNCONNECTED;440}441// create depending of status442switch (status) {443case LaneStatus::UNCONNECTED:444if (toggle) {445// create new connection446NBEdge::Connection newCon(fromIndex, destEdge->getNBEdge(), lane->getIndex(), mayDefinitelyPass);447// if the connection was previously deleted (by clicking the same lane twice), restore all values448for (NBEdge::Connection& c : myDeletedConnections) {449// fromLane must be the same, only check toLane450if (c.toEdge == destEdge->getNBEdge() && c.toLane == lane->getIndex()) {451newCon = c;452newCon.mayDefinitelyPass = mayDefinitelyPass;453}454}455NBConnection newNBCon(srcEdge->getNBEdge(), fromIndex, destEdge->getNBEdge(), lane->getIndex(), newCon.tlLinkIndex);456myViewNet->getUndoList()->add(new GNEChange_Connection(srcEdge, newCon, false, true), true);457if (mayDefinitelyPass) {458lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.special);459} else {460lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.target);461}462srcEdge->getToJunction()->invalidateTLS(myViewNet->getUndoList(), NBConnection::InvalidConnection, newNBCon);463}464break;465case LaneStatus::CONNECTED:466case LaneStatus::CONNECTED_PASS: {467// remove connection468GNEConnection* con = srcEdge->retrieveGNEConnection(fromIndex, destEdge->getNBEdge(), lane->getIndex());469myDeletedConnections.push_back(con->getNBEdgeConnection());470myViewNet->getNet()->deleteConnection(con, myViewNet->getUndoList());471lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.possible);472changed = true;473break;474}475case LaneStatus::CONFLICTED: {476SVCPermissions fromPermissions = srcEdge->getNBEdge()->getPermissions(fromIndex);477SVCPermissions toPermissions = destEdge->getNBEdge()->getPermissions(lane->getIndex());478if ((fromPermissions & toPermissions) == SVC_PEDESTRIAN) {479myViewNet->setStatusBarText(TL("Pedestrian connections are generated automatically"));480} else if ((fromPermissions & toPermissions) == 0) {481myViewNet->setStatusBarText(TL("Incompatible vehicle class permissions"));482} else {483myViewNet->setStatusBarText(TL("Another lane from the same edge already connects to that lane"));484}485break;486}487default:488break;489}490if (changed) {491myNumChanges += 1;492}493} else {494myViewNet->setStatusBarText(TL("Invalid target for connection"));495}496myCurrentLane->updateCurrentLaneLabel(myCurrentEditedLane->getID());497}498499500void501GNEConnectorFrame::initTargets() {502// gather potential targets503NBNode* nbn = myCurrentEditedLane->getParentEdge()->getToJunction()->getNBNode();504// get potential targets505for (const auto& NBEEdge : nbn->getOutgoingEdges()) {506GNEEdge* edge = myViewNet->getNet()->getAttributeCarriers()->retrieveEdge(NBEEdge->getID());507for (const auto& lane : edge->getChildLanes()) {508myPotentialTargets.insert(lane);509}510}511// set color for existing connections512std::vector<NBEdge::Connection> connections = myCurrentEditedLane->getParentEdge()->getNBEdge()->getConnectionsFromLane(myCurrentEditedLane->getIndex());513for (const auto& lane : myPotentialTargets) {514switch (getLaneStatus(connections, lane)) {515case LaneStatus::CONNECTED:516lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.target);517break;518case LaneStatus::CONNECTED_PASS:519lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.special);520break;521case LaneStatus::CONFLICTED:522lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.conflict);523break;524case LaneStatus::UNCONNECTED:525lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.possible);526break;527}528}529}530531532void533GNEConnectorFrame::cleanup() {534// restore colors of potential targets535for (auto it : myPotentialTargets) {536it->setSpecialColor(0);537}538// clear attributes539myPotentialTargets.clear();540myNumChanges = 0;541myCurrentEditedLane->setSpecialColor(0);542myCurrentEditedLane = nullptr;543myDeletedConnections.clear();544myCurrentLane->updateCurrentLaneLabel("");545}546547548GNEConnectorFrame::LaneStatus549GNEConnectorFrame::getLaneStatus(const std::vector<NBEdge::Connection>& connections, const GNELane* targetLane) const {550NBEdge* srcEdge = myCurrentEditedLane->getParentEdge()->getNBEdge();551const int fromIndex = myCurrentEditedLane->getIndex();552NBEdge* destEdge = targetLane->getParentEdge()->getNBEdge();553const int toIndex = targetLane->getIndex();554std::vector<NBEdge::Connection>::const_iterator con_it = find_if(555connections.begin(), connections.end(),556NBEdge::connections_finder(fromIndex, destEdge, toIndex));557const bool isConnected = con_it != connections.end();558if (isConnected) {559if (con_it->mayDefinitelyPass) {560return LaneStatus::CONNECTED_PASS;561} else {562return LaneStatus::CONNECTED;563}564} else if (srcEdge->hasConnectionTo(destEdge, toIndex)565|| (srcEdge->getPermissions(fromIndex) & destEdge->getPermissions(toIndex) & ~SVC_PEDESTRIAN) == 0) {566return LaneStatus::CONFLICTED;567} else {568return LaneStatus::UNCONNECTED;569}570}571572573/****************************************************************************/574575576