Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/frames/network/GNEConnectorFrame.cpp
193889 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2011-2026 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GNEConnectorFrame.cpp
15
/// @author Jakob Erdmann
16
/// @date May 2011
17
///
18
// The Widget for modifying lane-to-lane connections
19
/****************************************************************************/
20
21
#include <netedit/changes/GNEChange_Connection.h>
22
#include <netedit/dialogs/basic/GNEWarningBasicDialog.h>
23
#include <netedit/elements/network/GNEConnection.h>
24
#include <netedit/frames/common/GNESelectorFrame.h>
25
#include <netedit/GNEApplicationWindow.h>
26
#include <netedit/GNENet.h>
27
#include <netedit/GNEUndoList.h>
28
#include <netedit/GNEViewParent.h>
29
#include <utils/foxtools/MFXDynamicLabel.h>
30
#include <utils/gui/div/GUIDesigns.h>
31
#include <utils/gui/windows/GUIAppEnum.h>
32
33
#include "GNEConnectorFrame.h"
34
35
// ===========================================================================
36
// FOX callback mapping
37
// ===========================================================================
38
39
FXDEFMAP(GNEConnectorFrame::ConnectionModifications) ConnectionModificationsMap[] = {
40
FXMAPFUNC(SEL_COMMAND, MID_CANCEL, GNEConnectorFrame::ConnectionModifications::onCmdCancelModifications),
41
FXMAPFUNC(SEL_COMMAND, MID_OK, GNEConnectorFrame::ConnectionModifications::onCmdSaveModifications),
42
};
43
44
FXDEFMAP(GNEConnectorFrame::ConnectionOperations) ConnectionOperationsMap[] = {
45
FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_CLEAR, GNEConnectorFrame::ConnectionOperations::onCmdClearSelectedConnections),
46
FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_RESET, GNEConnectorFrame::ConnectionOperations::onCmdResetSelectedConnections),
47
FXMAPFUNC(SEL_COMMAND, MID_GNE_CONNECTORFRAME_SELECTDEADENDS, GNEConnectorFrame::ConnectionOperations::onCmdSelectDeadEnds),
48
FXMAPFUNC(SEL_COMMAND, MID_GNE_CONNECTORFRAME_SELECTDEADSTARTS, GNEConnectorFrame::ConnectionOperations::onCmdSelectDeadStarts),
49
FXMAPFUNC(SEL_COMMAND, MID_GNE_CONNECTORFRAME_SELECTCONFLICTS, GNEConnectorFrame::ConnectionOperations::onCmdSelectConflicts),
50
FXMAPFUNC(SEL_COMMAND, MID_GNE_CONNECTORFRAME_SELECTPASS, GNEConnectorFrame::ConnectionOperations::onCmdSelectPass),
51
};
52
53
// Object implementation
54
FXIMPLEMENT(GNEConnectorFrame::ConnectionModifications, GNEGroupBoxModule, ConnectionModificationsMap, ARRAYNUMBER(ConnectionModificationsMap))
55
FXIMPLEMENT(GNEConnectorFrame::ConnectionOperations, GNEGroupBoxModule, ConnectionOperationsMap, ARRAYNUMBER(ConnectionOperationsMap))
56
57
58
// ===========================================================================
59
// method definitions
60
// ===========================================================================
61
62
// ---------------------------------------------------------------------------
63
// GNEConnectorFrame::CurrentLane - methods
64
// ---------------------------------------------------------------------------
65
66
GNEConnectorFrame::CurrentLane::CurrentLane(GNEConnectorFrame* connectorFrameParent) :
67
GNEGroupBoxModule(connectorFrameParent, TL("Lane")) {
68
// create lane label
69
myCurrentLaneLabel = new FXLabel(getCollapsableFrame(), TL("No lane selected"), 0, GUIDesignLabel(JUSTIFY_LEFT));
70
}
71
72
73
GNEConnectorFrame::CurrentLane::~CurrentLane() {}
74
75
76
void
77
GNEConnectorFrame::CurrentLane::updateCurrentLaneLabel(const std::string& laneID) {
78
if (laneID.empty()) {
79
myCurrentLaneLabel->setText(TL("No lane selected"));
80
} else {
81
myCurrentLaneLabel->setText((std::string(TL("Current Lane: ")) + laneID).c_str());
82
}
83
}
84
85
// ---------------------------------------------------------------------------
86
// GNEConnectorFrame::ConnectionModifications - methods
87
// ---------------------------------------------------------------------------
88
89
GNEConnectorFrame::ConnectionModifications::ConnectionModifications(GNEConnectorFrame* connectorFrameParent) :
90
GNEGroupBoxModule(connectorFrameParent, TL("Modifications")),
91
myConnectorFrameParent(connectorFrameParent) {
92
93
// Create "Cancel" button
94
myCancelButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Cancel"), "", TL("Discard connection modifications (Esc)"),
95
GUIIconSubSys::getIcon(GUIIcon::CANCEL), this, MID_CANCEL, GUIDesignButton);
96
// Create "OK" button
97
mySaveButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("OK"), "", TL("Save connection modifications (Enter)"),
98
GUIIconSubSys::getIcon(GUIIcon::ACCEPT), this, MID_OK, GUIDesignButton);
99
100
// Create checkbox for protect routes
101
myProtectRoutesCheckBox = new FXCheckButton(getCollapsableFrame(), TL("Protect routes"), this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);
102
}
103
104
105
GNEConnectorFrame::ConnectionModifications::~ConnectionModifications() {}
106
107
108
long
109
GNEConnectorFrame::ConnectionModifications::onCmdCancelModifications(FXObject*, FXSelector, void*) {
110
if (myConnectorFrameParent->myCurrentEditedLane != 0) {
111
myConnectorFrameParent->getViewNet()->getUndoList()->abortAllChangeGroups();
112
if (myConnectorFrameParent->myNumChanges) {
113
myConnectorFrameParent->getViewNet()->setStatusBarText(TL("Changes reverted"));
114
}
115
myConnectorFrameParent->cleanup();
116
myConnectorFrameParent->getViewNet()->updateViewNet();
117
}
118
return 1;
119
}
120
121
122
long
123
GNEConnectorFrame::ConnectionModifications::onCmdSaveModifications(FXObject*, FXSelector, void*) {
124
if (myConnectorFrameParent->myCurrentEditedLane != 0) {
125
// check if routes has to be protected
126
if (myProtectRoutesCheckBox->isEnabled() && (myProtectRoutesCheckBox->getCheck() == TRUE)) {
127
for (const auto& demandElement : myConnectorFrameParent->myCurrentEditedLane->getParentEdge()->getChildDemandElements()) {
128
if (demandElement->isDemandElementValid() != GNEDemandElement::Problem::OK) {
129
// open warning dialog
130
GNEWarningBasicDialog(myConnectorFrameParent->getViewNet()->getViewParent()->getGNEAppWindows(),
131
TL("Error saving connection operations"),
132
TLF("Connection edition cannot be saved because route '%s' is broken.", demandElement->getID()));
133
return 1;
134
}
135
}
136
}
137
// finish route editing
138
myConnectorFrameParent->getViewNet()->getUndoList()->end();
139
if (myConnectorFrameParent->myNumChanges) {
140
myConnectorFrameParent->getViewNet()->setStatusBarText(TL("Changes accepted"));
141
}
142
myConnectorFrameParent->cleanup();
143
// mark network for recomputing
144
myConnectorFrameParent->getViewNet()->getNet()->requireRecompute();
145
}
146
return 1;
147
}
148
149
// ---------------------------------------------------------------------------
150
// GNEConnectorFrame::ConnectionOperations - methods
151
// ---------------------------------------------------------------------------
152
153
GNEConnectorFrame::ConnectionOperations::ConnectionOperations(GNEConnectorFrame* connectorFrameParent) :
154
GNEGroupBoxModule(connectorFrameParent, TL("Operations")),
155
myConnectorFrameParent(connectorFrameParent) {
156
157
// Create "Select Dead Ends" button
158
mySelectDeadEndsButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Select Dead Ends"), "", TL("Selects all lanes that have no outgoing connection (clears previous selection)"),
159
0, this, MID_GNE_CONNECTORFRAME_SELECTDEADENDS, GUIDesignButton);
160
// Create "Select Dead Starts" button
161
mySelectDeadStartsButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Select Dead Starts"), "", TL("Selects all lanes that have no incoming connection (clears previous selection)"),
162
0, this, MID_GNE_CONNECTORFRAME_SELECTDEADSTARTS, GUIDesignButton);
163
// Create "Select Conflicts" button
164
mySelectConflictsButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Select Conflicts"), "", TL("Selects all lanes with more than one incoming connection from the same edge (clears previous selection)"),
165
0, this, MID_GNE_CONNECTORFRAME_SELECTCONFLICTS, GUIDesignButton);
166
// Create "Select Edges which may always pass" button
167
mySelectPassingButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Select Passing"), "", TL("Selects all lanes with a connection that has the 'pass' attribute set"),
168
0, this, MID_GNE_CONNECTORFRAME_SELECTPASS, GUIDesignButton);
169
// Create "Clear Selected" button
170
myClearSelectedButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Clear Selected"), "", TL("Clears all connections of all selected objects"),
171
0, this, MID_CHOOSEN_CLEAR, GUIDesignButton);
172
// Create "Reset Selected" button
173
myResetSelectedButton = GUIDesigns::buildFXButton(getCollapsableFrame(), TL("Reset Selected"), "", TL("Recomputes connections at all selected junctions"),
174
0, this, MID_CHOOSEN_RESET, GUIDesignButton);
175
}
176
177
178
GNEConnectorFrame::ConnectionOperations::~ConnectionOperations() {}
179
180
181
long
182
GNEConnectorFrame::ConnectionOperations::onCmdSelectDeadEnds(FXObject*, FXSelector, void*) {
183
// select all lanes that have no successor lane
184
std::vector<GNEAttributeCarrier*> deadEnds;
185
// every edge knows its outgoing connections so we can look at each edge in isolation
186
for (const auto& edge : myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {
187
for (const auto& lane : edge.second->getChildLanes()) {
188
if (edge.second->getNBEdge()->getConnectionsFromLane(lane->getIndex()).size() == 0) {
189
deadEnds.push_back(lane);
190
}
191
}
192
}
193
myConnectorFrameParent->getViewNet()->getViewParent()->getSelectorFrame()->handleIDs(deadEnds, GNESelectorFrame::ModificationMode::Operation::REPLACE);
194
myConnectorFrameParent->getViewNet()->updateViewNet();
195
return 1;
196
}
197
198
199
long
200
GNEConnectorFrame::ConnectionOperations::onCmdSelectDeadStarts(FXObject*, FXSelector, void*) {
201
// select all lanes that have no predecessor lane
202
std::set<GNEAttributeCarrier*> deadStarts;
203
GNENet* net = myConnectorFrameParent->getViewNet()->getNet();
204
// every edge knows only its outgoing connections so we look at whole junctions
205
for (const auto& junction : myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getJunctions()) {
206
// first collect all outgoing lanes
207
for (const auto& outgoingEdge : junction.second->getGNEOutgoingEdges()) {
208
for (const auto& lane : outgoingEdge->getChildLanes()) {
209
deadStarts.insert(lane);
210
}
211
}
212
// then remove all approached lanes
213
for (const auto& incomingEdge : junction.second->getGNEIncomingEdges()) {
214
for (const auto& connection : incomingEdge->getNBEdge()->getConnections()) {
215
deadStarts.erase(net->getAttributeCarriers()->retrieveEdge(connection.toEdge->getID())->getChildLanes()[connection.toLane]);
216
}
217
}
218
}
219
std::vector<GNEAttributeCarrier*> selectObjects(deadStarts.begin(), deadStarts.end());
220
myConnectorFrameParent->getViewNet()->getViewParent()->getSelectorFrame()->handleIDs(selectObjects, GNESelectorFrame::ModificationMode::Operation::REPLACE);
221
myConnectorFrameParent->getViewNet()->updateViewNet();
222
return 1;
223
}
224
225
226
long
227
GNEConnectorFrame::ConnectionOperations::onCmdSelectConflicts(FXObject*, FXSelector, void*) {
228
std::vector<GNEAttributeCarrier*> conflicts;
229
// conflicts happen per edge so we can look at each edge in isolation
230
for (const auto& edge : myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {
231
const EdgeVector destinations = edge.second->getNBEdge()->getConnectedEdges();
232
for (const auto& destination : destinations) {
233
GNEEdge* dest = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveEdge(destination->getID());
234
for (const auto& lane : dest->getChildLanes()) {
235
const bool isConflicted = count_if(edge.second->getNBEdge()->getConnections().begin(), edge.second->getNBEdge()->getConnections().end(),
236
NBEdge::connections_toedgelane_finder(destination, (int)lane->getIndex(), -1)) > 1;
237
if (isConflicted) {
238
conflicts.push_back(lane);
239
}
240
}
241
}
242
243
}
244
myConnectorFrameParent->getViewNet()->getViewParent()->getSelectorFrame()->handleIDs(conflicts, GNESelectorFrame::ModificationMode::Operation::REPLACE);
245
myConnectorFrameParent->getViewNet()->updateViewNet();
246
return 1;
247
}
248
249
250
long
251
GNEConnectorFrame::ConnectionOperations::onCmdSelectPass(FXObject*, FXSelector, void*) {
252
std::vector<GNEAttributeCarrier*> pass;
253
for (const auto& edge : myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getEdges()) {
254
for (const auto& connection : edge.second->getNBEdge()->getConnections()) {
255
if (connection.mayDefinitelyPass) {
256
pass.push_back(edge.second->getChildLanes()[connection.fromLane]);
257
}
258
}
259
}
260
myConnectorFrameParent->getViewNet()->getViewParent()->getSelectorFrame()->handleIDs(pass, GNESelectorFrame::ModificationMode::Operation::REPLACE);
261
myConnectorFrameParent->getViewNet()->updateViewNet();
262
return 1;
263
}
264
265
266
long
267
GNEConnectorFrame::ConnectionOperations::onCmdClearSelectedConnections(FXObject*, FXSelector, void*) {
268
myConnectorFrameParent->myConnectionModifications->onCmdCancelModifications(0, 0, 0);
269
myConnectorFrameParent->getViewNet()->getUndoList()->begin(GUIIcon::CONNECTION, TL("clear connections from selected lanes, edges and junctions"));
270
// clear junction's connection
271
const auto selectedJunctions = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getSelectedJunctions();
272
for (const auto& junction : selectedJunctions) {
273
junction->setLogicValid(false, myConnectorFrameParent->getViewNet()->getUndoList()); // clear connections
274
junction->setLogicValid(false, myConnectorFrameParent->getViewNet()->getUndoList(), GNEAttributeCarrier::FEATURE_MODIFIED); // prevent re-guessing
275
}
276
// clear edge's connection
277
const auto selectedEdges = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getSelectedEdges();
278
for (const auto& edge : selectedEdges) {
279
for (const auto& lane : edge->getChildLanes()) {
280
myConnectorFrameParent->removeConnections(lane);
281
}
282
}
283
// clear lane's connection
284
const auto selectedLanes = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getSelectedLanes();
285
for (const auto& lane : selectedLanes) {
286
myConnectorFrameParent->removeConnections(lane);
287
}
288
myConnectorFrameParent->getViewNet()->getUndoList()->end();
289
myConnectorFrameParent->getViewNet()->updateViewNet();
290
return 1;
291
}
292
293
294
long
295
GNEConnectorFrame::ConnectionOperations::onCmdResetSelectedConnections(FXObject*, FXSelector, void*) {
296
myConnectorFrameParent->myConnectionModifications->onCmdCancelModifications(0, 0, 0);
297
myConnectorFrameParent->getViewNet()->getUndoList()->begin(GUIIcon::CONNECTION, TL("reset connections from selected lanes"));
298
const auto selectedJunctions = myConnectorFrameParent->getViewNet()->getNet()->getAttributeCarriers()->getSelectedJunctions();
299
for (const auto& junction : selectedJunctions) {
300
junction->setLogicValid(false, myConnectorFrameParent->getViewNet()->getUndoList());
301
}
302
myConnectorFrameParent->getViewNet()->getUndoList()->end();
303
if (selectedJunctions.size() > 0) {
304
auto viewNet = myConnectorFrameParent->getViewNet();
305
viewNet->getNet()->requireRecompute();
306
viewNet->getNet()->computeNetwork(viewNet->getViewParent()->getGNEAppWindows());
307
}
308
myConnectorFrameParent->getViewNet()->updateViewNet();
309
return 1;
310
}
311
312
// ---------------------------------------------------------------------------
313
// GNEConnectorFrame::ConnectionSelection - methods
314
// ---------------------------------------------------------------------------
315
316
GNEConnectorFrame::ConnectionSelection::ConnectionSelection(GNEConnectorFrame* connectorFrameParent) :
317
GNEGroupBoxModule(connectorFrameParent, TL("Selection")) {
318
// create label
319
new MFXDynamicLabel(getCollapsableFrame(), (std::string("- ") + TL("Hold <SHIFT> while clicking to create unyielding connections (pass=true).")).c_str(), 0, GUIDesignLabelFrameInformation);
320
new 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);
321
}
322
323
324
GNEConnectorFrame::ConnectionSelection::~ConnectionSelection() {}
325
326
// ---------------------------------------------------------------------------
327
// GNEConnectorFrame::ConnectionLegend - methods
328
// ---------------------------------------------------------------------------
329
330
GNEConnectorFrame::Legend::Legend(GNEConnectorFrame* connectorFrameParent) :
331
GNEGroupBoxModule(connectorFrameParent, TL("Information")) {
332
333
// create possible target label
334
FXLabel* possibleTargetLabel = new FXLabel(getCollapsableFrame(), TL("Possible Target"), 0, GUIDesignLabel(JUSTIFY_LEFT));
335
possibleTargetLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.possible));
336
possibleTargetLabel->setTextColor(MFXUtils::getFXColor(RGBColor::WHITE));
337
338
// create source label
339
FXLabel* sourceLabel = new FXLabel(getCollapsableFrame(), TL("Source lane"), 0, GUIDesignLabel(JUSTIFY_LEFT));
340
sourceLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.source));
341
342
// create target label
343
FXLabel* targetLabel = new FXLabel(getCollapsableFrame(), TL("Target lane"), 0, GUIDesignLabel(JUSTIFY_LEFT));
344
targetLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.target));
345
346
// create target (pass) label
347
FXLabel* targetPassLabel = new FXLabel(getCollapsableFrame(), TL("Target (pass)"), 0, GUIDesignLabel(JUSTIFY_LEFT));
348
targetPassLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.special));
349
350
// create conflict label
351
FXLabel* conflictLabel = new FXLabel(getCollapsableFrame(), TL("Conflict"), 0, GUIDesignLabel(JUSTIFY_LEFT));
352
conflictLabel->setBackColor(MFXUtils::getFXColor(connectorFrameParent->getViewNet()->getVisualisationSettings().candidateColorSettings.conflict));
353
}
354
355
356
GNEConnectorFrame::Legend::~Legend() {}
357
358
// ---------------------------------------------------------------------------
359
// GNEConnectorFrame - methods
360
// ---------------------------------------------------------------------------
361
362
GNEConnectorFrame::GNEConnectorFrame(GNEViewParent* viewParent, GNEViewNet* viewNet):
363
GNEFrame(viewParent, viewNet, TL("Edit Connections")),
364
myCurrentEditedLane(0),
365
myNumChanges(0) {
366
// create current lane module
367
myCurrentLane = new CurrentLane(this);
368
369
// create connection modifications module
370
myConnectionModifications = new ConnectionModifications(this);
371
372
// create connection operations module
373
myConnectionOperations = new ConnectionOperations(this);
374
375
// create connection selection module
376
myConnectionSelection = new ConnectionSelection(this);
377
378
// create connection legend module
379
myLegend = new Legend(this);
380
}
381
382
383
GNEConnectorFrame::~GNEConnectorFrame() {}
384
385
386
void
387
GNEConnectorFrame::handleLaneClick(const GNEViewNetHelper::ViewObjectsSelector& viewObjects) {
388
// get lane front
389
GNELane* clickedLane = viewObjects.getLaneFrontNonLocked();
390
// iterate over lanes
391
for (const auto& lane : viewObjects.getLanes()) {
392
// if parent edge of lane is front element, update clickedLane
393
if (lane->getParentEdge()->isMarkedForDrawingFront()) {
394
clickedLane = lane;
395
}
396
}
397
// build connection
398
buildConnection(clickedLane, myViewNet->getMouseButtonKeyPressed().shiftKeyPressed(), myViewNet->getMouseButtonKeyPressed().controlKeyPressed(), true);
399
}
400
401
402
GNEConnectorFrame::ConnectionModifications*
403
GNEConnectorFrame::getConnectionModifications() const {
404
return myConnectionModifications;
405
}
406
407
408
void
409
GNEConnectorFrame::removeConnections(GNELane* lane) {
410
// select lane as current lane
411
buildConnection(lane, false, false, true); // select as current lane
412
// iterate over all potential targets
413
for (const auto& potentialTarget : myPotentialTargets) {
414
// remove connections using the appropiate parameters in function "buildConnection"
415
buildConnection(potentialTarget, false, false, false);
416
}
417
// save modifications
418
myConnectionModifications->onCmdSaveModifications(0, 0, 0);
419
}
420
421
422
void
423
GNEConnectorFrame::buildConnection(GNELane* lane, const bool mayDefinitelyPass, const bool allowConflict, const bool toggle) {
424
if (myCurrentEditedLane == 0) {
425
myCurrentEditedLane = lane;
426
myCurrentEditedLane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.source);
427
initTargets();
428
myNumChanges = 0;
429
myViewNet->getUndoList()->begin(GUIIcon::CONNECTION, TL("modify connections"));
430
} else if (myPotentialTargets.count(lane)
431
|| (allowConflict && lane->getParentEdge()->getFromJunction() == myCurrentEditedLane->getParentEdge()->getToJunction())) {
432
const int fromIndex = myCurrentEditedLane->getIndex();
433
GNEEdge* srcEdge = myCurrentEditedLane->getParentEdge();
434
GNEEdge* destEdge = lane->getParentEdge();
435
std::vector<NBEdge::Connection> connections = srcEdge->getNBEdge()->getConnectionsFromLane(fromIndex);
436
bool changed = false;
437
// get lane status
438
LaneStatus status = getLaneStatus(connections, lane);
439
if (status == LaneStatus::CONFLICTED && allowConflict) {
440
status = LaneStatus::UNCONNECTED;
441
}
442
// create depending of status
443
switch (status) {
444
case LaneStatus::UNCONNECTED:
445
if (toggle) {
446
// create new connection
447
NBEdge::Connection newCon(fromIndex, destEdge->getNBEdge(), lane->getIndex(), mayDefinitelyPass);
448
// if the connection was previously deleted (by clicking the same lane twice), restore all values
449
for (NBEdge::Connection& c : myDeletedConnections) {
450
// fromLane must be the same, only check toLane
451
if (c.toEdge == destEdge->getNBEdge() && c.toLane == lane->getIndex()) {
452
newCon = c;
453
newCon.mayDefinitelyPass = mayDefinitelyPass;
454
}
455
}
456
NBConnection newNBCon(srcEdge->getNBEdge(), fromIndex, destEdge->getNBEdge(), lane->getIndex(), newCon.tlLinkIndex);
457
myViewNet->getUndoList()->add(new GNEChange_Connection(srcEdge, newCon, false, true), true);
458
if (mayDefinitelyPass) {
459
lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.special);
460
} else {
461
lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.target);
462
}
463
srcEdge->getToJunction()->invalidateTLS(myViewNet->getUndoList(), NBConnection::InvalidConnection, newNBCon);
464
}
465
break;
466
case LaneStatus::CONNECTED:
467
case LaneStatus::CONNECTED_PASS: {
468
// remove connection
469
GNEConnection* con = srcEdge->retrieveGNEConnection(fromIndex, destEdge->getNBEdge(), lane->getIndex());
470
myDeletedConnections.push_back(con->getNBEdgeConnection());
471
myViewNet->getNet()->deleteConnection(con, myViewNet->getUndoList());
472
lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.possible);
473
changed = true;
474
break;
475
}
476
case LaneStatus::CONFLICTED: {
477
SVCPermissions fromPermissions = srcEdge->getNBEdge()->getPermissions(fromIndex);
478
SVCPermissions toPermissions = destEdge->getNBEdge()->getPermissions(lane->getIndex());
479
if ((fromPermissions & toPermissions) == SVC_PEDESTRIAN) {
480
myViewNet->setStatusBarText(TL("Pedestrian connections are generated automatically"));
481
} else if ((fromPermissions & toPermissions) == 0) {
482
myViewNet->setStatusBarText(TL("Incompatible vehicle class permissions"));
483
} else {
484
myViewNet->setStatusBarText(TL("Another lane from the same edge already connects to that lane"));
485
}
486
break;
487
}
488
default:
489
break;
490
}
491
if (changed) {
492
myNumChanges += 1;
493
}
494
} else {
495
myViewNet->setStatusBarText(TL("Invalid target for connection"));
496
}
497
myCurrentLane->updateCurrentLaneLabel(myCurrentEditedLane->getID());
498
}
499
500
501
void
502
GNEConnectorFrame::initTargets() {
503
// gather potential targets
504
NBNode* nbn = myCurrentEditedLane->getParentEdge()->getToJunction()->getNBNode();
505
// get potential targets
506
for (const auto& NBEEdge : nbn->getOutgoingEdges()) {
507
GNEEdge* edge = myViewNet->getNet()->getAttributeCarriers()->retrieveEdge(NBEEdge->getID());
508
for (const auto& lane : edge->getChildLanes()) {
509
myPotentialTargets.insert(lane);
510
}
511
}
512
// set color for existing connections
513
std::vector<NBEdge::Connection> connections = myCurrentEditedLane->getParentEdge()->getNBEdge()->getConnectionsFromLane(myCurrentEditedLane->getIndex());
514
for (const auto& lane : myPotentialTargets) {
515
switch (getLaneStatus(connections, lane)) {
516
case LaneStatus::CONNECTED:
517
lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.target);
518
break;
519
case LaneStatus::CONNECTED_PASS:
520
lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.special);
521
break;
522
case LaneStatus::CONFLICTED:
523
lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.conflict);
524
break;
525
case LaneStatus::UNCONNECTED:
526
lane->setSpecialColor(&myViewNet->getVisualisationSettings().candidateColorSettings.possible);
527
break;
528
}
529
}
530
}
531
532
533
void
534
GNEConnectorFrame::cleanup() {
535
// restore colors of potential targets
536
for (auto it : myPotentialTargets) {
537
it->setSpecialColor(0);
538
}
539
// clear attributes
540
myPotentialTargets.clear();
541
myNumChanges = 0;
542
myCurrentEditedLane->setSpecialColor(0);
543
myCurrentEditedLane = nullptr;
544
myDeletedConnections.clear();
545
myCurrentLane->updateCurrentLaneLabel("");
546
}
547
548
549
GNEConnectorFrame::LaneStatus
550
GNEConnectorFrame::getLaneStatus(const std::vector<NBEdge::Connection>& connections, const GNELane* targetLane) const {
551
NBEdge* srcEdge = myCurrentEditedLane->getParentEdge()->getNBEdge();
552
const int fromIndex = myCurrentEditedLane->getIndex();
553
NBEdge* destEdge = targetLane->getParentEdge()->getNBEdge();
554
const int toIndex = targetLane->getIndex();
555
std::vector<NBEdge::Connection>::const_iterator con_it = find_if(
556
connections.begin(), connections.end(),
557
NBEdge::connections_finder(fromIndex, destEdge, toIndex));
558
const bool isConnected = con_it != connections.end();
559
if (isConnected) {
560
if (con_it->mayDefinitelyPass) {
561
return LaneStatus::CONNECTED_PASS;
562
} else {
563
return LaneStatus::CONNECTED;
564
}
565
} else if (srcEdge->hasConnectionTo(destEdge, toIndex)
566
|| (srcEdge->getPermissions(fromIndex) & destEdge->getPermissions(toIndex) & ~SVC_PEDESTRIAN) == 0) {
567
return LaneStatus::CONFLICTED;
568
} else {
569
return LaneStatus::UNCONNECTED;
570
}
571
}
572
573
574
/****************************************************************************/
575
576