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