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