Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/network/GNEJunction.cpp
193871 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-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 GNEJunction.cpp
15
/// @author Jakob Erdmann
16
/// @date Feb 2011
17
///
18
// A class for visualizing and editing junctions in netedit (adapted from
19
// GUIJunctionWrapper)
20
/****************************************************************************/
21
22
#include <netbuild/NBAlgorithms.h>
23
#include <netbuild/NBLoadedSUMOTLDef.h>
24
#include <netbuild/NBNetBuilder.h>
25
#include <netbuild/NBOwnTLDef.h>
26
#include <netedit/changes/GNEChange_Attribute.h>
27
#include <netedit/changes/GNEChange_Connection.h>
28
#include <netedit/changes/GNEChange_TLS.h>
29
#include <netedit/elements/demand/GNEPlanParents.h>
30
#include <netedit/elements/moving/GNEMoveElementJunction.h>
31
#include <netedit/frames/common/GNEDeleteFrame.h>
32
#include <netedit/frames/common/GNEMoveFrame.h>
33
#include <netedit/frames/demand/GNEContainerFrame.h>
34
#include <netedit/frames/demand/GNEContainerPlanFrame.h>
35
#include <netedit/frames/demand/GNEPersonFrame.h>
36
#include <netedit/frames/demand/GNEPersonPlanFrame.h>
37
#include <netedit/frames/demand/GNEVehicleFrame.h>
38
#include <netedit/frames/network/GNECreateEdgeFrame.h>
39
#include <netedit/frames/network/GNECrossingFrame.h>
40
#include <netedit/frames/network/GNETLSEditorFrame.h>
41
#include <netedit/GNENet.h>
42
#include <netedit/GNEApplicationWindow.h>
43
#include <netedit/GNEUndoList.h>
44
#include <netedit/GNEViewParent.h>
45
#include <utils/gui/div/GLHelper.h>
46
#include <utils/gui/div/GUIDesigns.h>
47
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
48
#include <utils/gui/images/GUITextureSubSys.h>
49
#include <utils/gui/windows/GUIAppEnum.h>
50
#include <utils/options/OptionsCont.h>
51
52
#include "GNEConnection.h"
53
#include "GNEJunction.h"
54
#include "GNECrossing.h"
55
#include "GNEWalkingArea.h"
56
#include "GNEInternalLane.h"
57
58
// ===========================================================================
59
// method definitions
60
// ===========================================================================
61
62
GNEJunction::GNEJunction(GNENet* net, NBNode* nbn, bool loaded) :
63
GNENetworkElement(net, nbn->getID(), SUMO_TAG_JUNCTION),
64
myMoveElementJunction(new GNEMoveElementJunction(this)),
65
myNBNode(nbn),
66
myDrawingToggle(new int),
67
myLogicStatus(loaded ? FEATURE_LOADED : FEATURE_GUESSED),
68
myHasValidLogic(loaded),
69
myTesselation(nbn->getID(), "", RGBColor::MAGENTA, nbn->getShape(), false, true, 0) {
70
// update centering boundary without updating grid
71
updateCenteringBoundary(false);
72
}
73
74
75
GNEJunction::~GNEJunction() {
76
// delete drawing toggle
77
delete myDrawingToggle;
78
// delete all GNECrossing
79
for (const auto& crossing : myGNECrossings) {
80
crossing->decRef();
81
if (crossing->unreferenced()) {
82
// check if remove it from Attribute Carriers
83
if (myNet->getAttributeCarriers()->getCrossings().count(crossing) > 0) {
84
myNet->getAttributeCarriers()->deleteCrossing(crossing);
85
}
86
delete crossing;
87
}
88
}
89
// delete all GNEWalkingArea
90
for (const auto& walkingArea : myGNEWalkingAreas) {
91
walkingArea->decRef();
92
if (walkingArea->unreferenced()) {
93
// check if remove it from Attribute Carriers
94
if (myNet->getAttributeCarriers()->getWalkingAreas().count(walkingArea) > 0) {
95
myNet->getAttributeCarriers()->deleteWalkingArea(walkingArea);
96
}
97
delete walkingArea;
98
}
99
}
100
if (myAmResponsible) {
101
delete myNBNode;
102
}
103
}
104
105
106
GNEMoveElement*
107
GNEJunction::getMoveElement() const {
108
return myMoveElementJunction;
109
}
110
111
112
Parameterised*
113
GNEJunction::getParameters() {
114
return myNBNode;
115
}
116
117
118
const Parameterised*
119
GNEJunction::getParameters() const {
120
return myNBNode;
121
}
122
123
124
const PositionVector&
125
GNEJunction::getJunctionShape() const {
126
return myNBNode->getShape();
127
}
128
129
130
void
131
GNEJunction::updateGeometry() {
132
updateGeometryAfterNetbuild(true);
133
// trigger rebuilding tesselation
134
myExaggeration = 2;
135
}
136
137
138
void
139
GNEJunction::updateGeometryAfterNetbuild(bool rebuildNBNodeCrossings) {
140
// rebuild crossings
141
rebuildGNECrossings(rebuildNBNodeCrossings);
142
// clear walking areas
143
clearWalkingAreas();
144
// clear missing connections
145
checkMissingConnections();
146
}
147
148
149
Position
150
GNEJunction::getPositionInView() const {
151
return myNBNode->getPosition();
152
}
153
154
155
bool
156
GNEJunction::checkDrawFromContour() const {
157
// get modes and viewParent (for code legibility)
158
const auto& modes = myNet->getViewNet()->getEditModes();
159
const auto& viewParent = myNet->getViewParent();
160
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
161
// continue depending of current status
162
if (inspectedElements.isInspectingSingleElement()) {
163
const auto inspectedAC = inspectedElements.getFirstAC();
164
// check if starts in this junction
165
if (inspectedAC->hasAttribute(SUMO_ATTR_FROM_JUNCTION) &&
166
(inspectedAC->getAttribute(SUMO_ATTR_FROM_JUNCTION) == getID())) {
167
return true;
168
} else if ((inspectedAC->getTagProperty()->getTag() == SUMO_TAG_EDGE) &&
169
(inspectedAC->getAttribute(SUMO_ATTR_FROM) == getID())) {
170
return true;
171
} else if ((inspectedAC->getTagProperty()->getTag() == SUMO_TAG_LANE) &&
172
(inspectedAC->getAttribute(SUMO_ATTR_FROM_JUNCTION) == getID())) {
173
return true;
174
}
175
} else if (modes.isCurrentSupermodeNetwork()) {
176
if (modes.networkEditMode == NetworkEditMode::NETWORK_CREATE_EDGE) {
177
if (viewParent->getCreateEdgeFrame()->getJunctionSource()) {
178
return viewParent->getCreateEdgeFrame()->getJunctionSource() == this;
179
} else {
180
return myNet->getViewNet()->getViewObjectsSelector().getJunctionFront() == this;
181
}
182
} else if ((modes.networkEditMode == NetworkEditMode::NETWORK_TLS) &&
183
viewParent->getTLSEditorFrame()->getTLSJunction()->isJoiningJunctions()) {
184
for (const auto& id : viewParent->getTLSEditorFrame()->getTLSJunction()->getSelectedJunctionIDs()) {
185
if (id == getMicrosimID()) {
186
return true;
187
}
188
}
189
}
190
} else if (modes.isCurrentSupermodeDemand()) {
191
// get current GNEPlanCreator
192
GNEPlanCreator* planCreator = nullptr;
193
if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {
194
planCreator = viewParent->getPersonFrame()->getPlanCreator();
195
} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {
196
planCreator = viewParent->getPersonPlanFrame()->getPlanCreator();
197
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {
198
planCreator = viewParent->getContainerFrame()->getPlanCreator();
199
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {
200
planCreator = viewParent->getContainerPlanFrame()->getPlanCreator();
201
}
202
// continue depending of planCreator
203
if (planCreator) {
204
if (planCreator->getPlanParameteres().fromJunction == getID()) {
205
return true;
206
}
207
} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {
208
const auto& selectedJunctions = viewParent->getVehicleFrame()->getPathCreator()->getSelectedJunctions();
209
// check if this is the first selected junction
210
if ((selectedJunctions.size() > 0) && (selectedJunctions.front() == this)) {
211
return true;
212
}
213
}
214
}
215
// nothing to draw
216
return false;
217
}
218
219
220
bool
221
GNEJunction::checkDrawToContour() const {
222
// get modes and viewParent (for code legibility)
223
const auto& modes = myNet->getViewNet()->getEditModes();
224
const auto& viewParent = myNet->getViewParent();
225
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
226
// continue depending of current status
227
if (inspectedElements.isInspectingSingleElement()) {
228
const auto inspectedAC = inspectedElements.getFirstAC();
229
// check if ends in this junction
230
if (inspectedAC->getTagProperty()->vehicleJunctions() &&
231
(inspectedAC->getAttribute(SUMO_ATTR_TO_JUNCTION) == getID())) {
232
return true;
233
} else if ((inspectedAC->getTagProperty()->getTag() == SUMO_TAG_EDGE) &&
234
(inspectedAC->getAttribute(SUMO_ATTR_TO) == getID())) {
235
return true;
236
} else if ((inspectedAC->getTagProperty()->getTag() == SUMO_TAG_LANE) &&
237
(inspectedAC->getAttribute(SUMO_ATTR_TO_JUNCTION) == getID())) {
238
return true;
239
}
240
} else if (modes.isCurrentSupermodeNetwork()) {
241
if (modes.networkEditMode == NetworkEditMode::NETWORK_CREATE_EDGE) {
242
if (viewParent->getCreateEdgeFrame()->getJunctionSource() &&
243
(viewParent->getCreateEdgeFrame()->getJunctionSource() != this)) {
244
return myNet->getViewNet()->getViewObjectsSelector().getJunctionFront() == this;
245
}
246
} else if (modes.networkEditMode == NetworkEditMode::NETWORK_MOVE) {
247
// check if we're moving a junction
248
const auto moveElementJunction = dynamic_cast<GNEMoveElementJunction*>(myNet->getViewNet()->getMoveSingleElementValues().getMovedElement());
249
if (moveElementJunction && (moveElementJunction->getJunction() != this)) {
250
// continue depending of junction shape
251
if (myNBNode->getShape().area() < 4) {
252
// calculate distance between both centers
253
const double junctionBubbleRadius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.junctionBubbleRadius;
254
const double radiusTo = getExaggeration(myNet->getViewNet()->getVisualisationSettings()) * junctionBubbleRadius;
255
if (myNBNode->getPosition().distanceSquaredTo2D(moveElementJunction->getJunction()->getPositionInView()) < (radiusTo * radiusTo)) {
256
// add both it in the list of merging junction
257
gViewObjectsHandler.addMergingJunctions(moveElementJunction->getJunction());
258
gViewObjectsHandler.addMergingJunctions(this);
259
return true;
260
}
261
} else if (myNBNode->getShape().around(moveElementJunction->getJunction()->getNBNode()->getPosition())) {
262
// add both it in the list of merging junction
263
gViewObjectsHandler.addMergingJunctions(moveElementJunction->getJunction());
264
gViewObjectsHandler.addMergingJunctions(this);
265
return true;
266
}
267
}
268
}
269
} else if (modes.isCurrentSupermodeDemand()) {
270
// get current GNEPlanCreator
271
GNEPlanCreator* planCreator = nullptr;
272
if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {
273
planCreator = viewParent->getPersonFrame()->getPlanCreator();
274
} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {
275
planCreator = viewParent->getPersonPlanFrame()->getPlanCreator();
276
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {
277
planCreator = viewParent->getContainerFrame()->getPlanCreator();
278
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {
279
planCreator = viewParent->getContainerPlanFrame()->getPlanCreator();
280
}
281
// continue depending of planCreator
282
if (planCreator) {
283
if (planCreator->getPlanParameteres().toJunction == getID()) {
284
return true;
285
}
286
} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {
287
const auto& selectedJunctions = viewParent->getVehicleFrame()->getPathCreator()->getSelectedJunctions();
288
// check if this is the first selected junction
289
if ((selectedJunctions.size() > 1) && (selectedJunctions.back() == this)) {
290
return true;
291
}
292
}
293
}
294
// nothing to draw
295
return false;
296
}
297
298
299
bool
300
GNEJunction::checkDrawRelatedContour() const {
301
if (myNet->getViewParent()->getCrossingFrame()->getEdgesSelector()->getCurrentJunction() == this) {
302
return true;
303
}
304
// check opened popup
305
if (myNet->getViewNet()->getPopup()) {
306
return myNet->getViewNet()->getPopup()->getGLObject() == this;
307
}
308
return false;
309
}
310
311
312
bool
313
GNEJunction::checkDrawOverContour() const {
314
// get modes and viewParent (for code legibility)
315
const auto& modes = myNet->getViewNet()->getEditModes();
316
const auto& viewParent = myNet->getViewParent();
317
const auto& viewObjectsSelector = myNet->getViewNet()->getViewObjectsSelector();
318
if (viewObjectsSelector.getJunctionFront() != this) {
319
return false;
320
} else {
321
if (modes.isCurrentSupermodeNetwork()) {
322
if (modes.networkEditMode == NetworkEditMode::NETWORK_CROSSING) {
323
return (viewObjectsSelector.getJunctionFront() == this);
324
}
325
} else if (modes.isCurrentSupermodeDemand()) {
326
// get current plan selector
327
GNEPlanSelector* planSelector = nullptr;
328
if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {
329
planSelector = viewParent->getPersonFrame()->getPlanSelector();
330
} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {
331
planSelector = viewParent->getPersonPlanFrame()->getPlanSelector();
332
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {
333
planSelector = viewParent->getContainerFrame()->getPlanSelector();
334
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {
335
planSelector = viewParent->getContainerPlanFrame()->getPlanSelector();
336
}
337
// continue depending of plan selector
338
if (planSelector && planSelector->markJunctions()) {
339
return (viewObjectsSelector.getAttributeCarrierFront() == viewObjectsSelector.getJunctionFront());
340
} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {
341
// get current vehicle template
342
const auto& vehicleTemplate = viewParent->getVehicleFrame()->getVehicleTagSelector()->getCurrentTemplateAC();
343
// check if vehicle can be placed over from-to TAZs
344
if (vehicleTemplate && vehicleTemplate->getTagProperty()->vehicleJunctions()) {
345
return (viewObjectsSelector.getAttributeCarrierFront() == viewObjectsSelector.getJunctionFront());
346
}
347
}
348
}
349
return false;
350
}
351
}
352
353
354
bool
355
GNEJunction::checkDrawDeleteContour() const {
356
// get edit modes
357
const auto& editModes = myNet->getViewNet()->getEditModes();
358
// check if we're in delete mode
359
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_DELETE)) {
360
return myNet->getViewNet()->checkOverLockedElement(this, mySelected);
361
} else {
362
return false;
363
}
364
}
365
366
367
bool
368
GNEJunction::checkDrawDeleteContourSmall() const {
369
return false;
370
}
371
372
373
bool
374
GNEJunction::checkDrawSelectContour() const {
375
// get edit modes
376
const auto& editModes = myNet->getViewNet()->getEditModes();
377
// check if we're in select mode
378
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_SELECT)) {
379
return myNet->getViewNet()->checkOverLockedElement(this, mySelected);
380
} else {
381
return false;
382
}
383
}
384
385
386
bool
387
GNEJunction::checkDrawMoveContour() const {
388
// get edit modes
389
const auto& editModes = myNet->getViewNet()->getEditModes();
390
// check if we're in move mode
391
if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&
392
(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {
393
// check if we're editing this network element
394
const GNENetworkElement* editedNetworkElement = myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement();
395
if (editedNetworkElement) {
396
return editedNetworkElement == this;
397
} else {
398
// only move the first element
399
return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;
400
}
401
} else {
402
return false;
403
}
404
}
405
406
407
void
408
GNEJunction::rebuildGNECrossings(bool rebuildNBNodeCrossings) {
409
// rebuild GNECrossings only if create crossings and walkingAreas in net is enabled
410
if (myNet->getNetBuilder()->haveNetworkCrossings()) {
411
if (rebuildNBNodeCrossings) {
412
// build new NBNode::Crossings and walking areas
413
mirrorXLeftHand();
414
myNBNode->buildCrossingsAndWalkingAreas();
415
mirrorXLeftHand();
416
}
417
// create a vector to keep retrieved and created crossings
418
std::vector<GNECrossing*> retrievedCrossings;
419
// iterate over NBNode::Crossings of GNEJunction
420
for (const auto& crossing : myNBNode->getCrossingsIncludingInvalid()) {
421
// retrieve existent GNECrossing, or create it
422
GNECrossing* retrievedGNECrossing = retrieveGNECrossing(crossing.get());
423
retrievedCrossings.push_back(retrievedGNECrossing);
424
// check if previously this GNECrossings exists, and if true, remove it from myGNECrossings and insert in tree again
425
std::vector<GNECrossing*>::iterator retrievedExists = std::find(myGNECrossings.begin(), myGNECrossings.end(), retrievedGNECrossing);
426
if (retrievedExists != myGNECrossings.end()) {
427
myGNECrossings.erase(retrievedExists);
428
// update geometry of retrieved crossing
429
retrievedGNECrossing->updateGeometry();
430
// update boundary
431
retrievedGNECrossing->updateCenteringBoundary(false);
432
} else {
433
// include reference to created GNECrossing
434
retrievedGNECrossing->incRef();
435
}
436
}
437
// delete non retrieved GNECrossings (we don't need to extract if from Tree two times)
438
for (const auto& crossing : myGNECrossings) {
439
crossing->decRef();
440
// check if crossing is selected
441
if (crossing->isAttributeCarrierSelected()) {
442
crossing->unselectAttributeCarrier();
443
}
444
// remove it from inspected ACS
445
if (myNet->getViewNet()) {
446
myNet->getViewNet()->getInspectedElements().uninspectAC(crossing);
447
}
448
// remove it from net
449
myNet->removeGLObjectFromGrid(crossing);
450
// remove it from attributeCarriers
451
myNet->getAttributeCarriers()->deleteCrossing(crossing);
452
if (crossing->unreferenced()) {
453
delete crossing;
454
}
455
}
456
// copy retrieved (existent and created) GNECrossings to myGNECrossings
457
myGNECrossings = retrievedCrossings;
458
}
459
}
460
461
462
void
463
GNEJunction::mirrorXLeftHand() {
464
if (OptionsCont::getOptions().getBool("lefthand")) {
465
myNBNode->mirrorX();
466
for (NBEdge* e : myNBNode->getEdges()) {
467
e->mirrorX();
468
469
}
470
}
471
}
472
473
474
void
475
GNEJunction::buildTLSOperations(GUISUMOAbstractView& parent, GUIGLObjectPopupMenu* ret, const int numSelectedJunctions) {
476
// create menu pane for edge operations
477
FXMenuPane* TLSOperations = new FXMenuPane(ret);
478
ret->insertMenuPaneChild(TLSOperations);
479
new FXMenuCascade(ret, TL("TLS operations"), GUIIconSubSys::getIcon(GUIIcon::MODETLS), TLSOperations);
480
// create menu commands for all TLS operations
481
FXMenuCommand* mcAddTLS = GUIDesigns::buildFXMenuCommand(TLSOperations, TL("Add TLS"), nullptr, &parent, MID_GNE_JUNCTION_ADDTLS);
482
FXMenuCommand* mcAddJoinedTLS = GUIDesigns::buildFXMenuCommand(TLSOperations, TL("Add joined TLS"), nullptr, &parent, MID_GNE_JUNCTION_ADDJOINTLS);
483
// check if disable create TLS
484
if (myNBNode->getControllingTLS().size() > 0) {
485
mcAddTLS->disable();
486
mcAddJoinedTLS->disable();
487
} else {
488
mcAddTLS->enable();
489
// check if add joined TLS
490
if (isAttributeCarrierSelected() && (numSelectedJunctions > 1)) {
491
mcAddJoinedTLS->enable();
492
} else {
493
mcAddJoinedTLS->disable();
494
}
495
}
496
}
497
498
499
GUIGLObjectPopupMenu*
500
GNEJunction::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
501
if (myShapeEdited) {
502
return getShapeEditedPopUpMenu(app, parent, myNBNode->getShape());
503
} else {
504
// create popup
505
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
506
// build common options
507
buildPopUpMenuCommonOptions(ret, app, myNet->getViewNet(), myTagProperty->getTag(), mySelected, myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork());
508
// check if we're in supermode network
509
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork()) {
510
const int numSelectedJunctions = myNet->getAttributeCarriers()->getNumberOfSelectedJunctions();
511
const int numEndpoints = (int)myNBNode->getEndPoints().size();
512
// check if we're handling a selection
513
bool handlingSelection = isAttributeCarrierSelected() && (numSelectedJunctions > 1);
514
// check if menu commands has to be disabled
515
const bool invalidMode = (myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_CONNECT) ||
516
(myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_TLS) ||
517
(myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_CREATE_EDGE);
518
// build TLS operation
519
if (!invalidMode) {
520
buildTLSOperations(parent, ret, numSelectedJunctions);
521
}
522
// create menu commands
523
GUIDesigns::buildFXMenuCommand(ret, TL("Reset edge endpoints"), nullptr, &parent, MID_GNE_JUNCTION_RESET_EDGE_ENDPOINTS);
524
FXMenuCommand* mcCustomShape = GUIDesigns::buildFXMenuCommand(ret, TL("Set custom junction shape"), nullptr, &parent, MID_GNE_JUNCTION_EDIT_SHAPE);
525
FXMenuCommand* mcResetCustomShape = GUIDesigns::buildFXMenuCommand(ret, TL("Reset junction shape"), nullptr, &parent, MID_GNE_JUNCTION_RESET_SHAPE);
526
FXMenuCommand* mcReplaceByGeometryPoint = GUIDesigns::buildFXMenuCommand(ret, TL("Replace junction by geometry point"), nullptr, &parent, MID_GNE_JUNCTION_REPLACE);
527
FXMenuCommand* mcSplitJunction = GUIDesigns::buildFXMenuCommand(ret, TLF("Split junction (% end points)", numEndpoints), nullptr, &parent, MID_GNE_JUNCTION_SPLIT);
528
FXMenuCommand* mcSplitJunctionAndReconnect = GUIDesigns::buildFXMenuCommand(ret, TL("Split junction and reconnect"), nullptr, &parent, MID_GNE_JUNCTION_SPLIT_RECONNECT);
529
// check if is a roundabout
530
if (myNBNode->isRoundabout()) {
531
GUIDesigns::buildFXMenuCommand(ret, TL("Select roundabout"), nullptr, &parent, MID_GNE_JUNCTION_SELECT_ROUNDABOUT);
532
} else {
533
// get radius
534
const double radius = (myNBNode->getRadius() == NBNode::UNSPECIFIED_RADIUS) ? OptionsCont::getOptions().getFloat("default.junctions.radius") : myNBNode->getRadius();
535
const std::string menuEntryInfo = TLF("Convert to roundabout (using junction attribute radius %)", toString(radius));
536
FXMenuCommand* mcRoundabout = GUIDesigns::buildFXMenuCommand(ret, menuEntryInfo.c_str(), nullptr, &parent, MID_GNE_JUNCTION_CONVERT_ROUNDABOUT);
537
// check if disable depending of number of edges
538
if ((getChildEdges().size() < 2) ||
539
((myGNEIncomingEdges.size() == 1) && (myGNEOutgoingEdges.size() == 1) && (myGNEIncomingEdges[0]->getFromJunction() == myGNEOutgoingEdges[0]->getToJunction()))) {
540
mcRoundabout->disable();
541
}
542
}
543
// check multijunctions
544
const std::string multi = ((numSelectedJunctions > 1) && isAttributeCarrierSelected()) ? TLF(" of % junctions", numSelectedJunctions) : "";
545
FXMenuCommand* mcClearConnections = GUIDesigns::buildFXMenuCommand(ret, TL("Clear connections") + multi, nullptr, &parent, MID_GNE_JUNCTION_CLEAR_CONNECTIONS);
546
FXMenuCommand* mcResetConnections = GUIDesigns::buildFXMenuCommand(ret, TL("Reset connections") + multi, nullptr, &parent, MID_GNE_JUNCTION_RESET_CONNECTIONS);
547
// check if current mode is correct
548
if (invalidMode) {
549
mcCustomShape->disable();
550
mcClearConnections->disable();
551
mcResetConnections->disable();
552
}
553
// check if we're handling a selection
554
if (handlingSelection) {
555
mcResetCustomShape->setText(TL("Reset junction shapes"));
556
}
557
// disable mcClearConnections if junction hasn't connections
558
if (getGNEConnections().empty()) {
559
mcClearConnections->disable();
560
}
561
// disable mcResetCustomShape if junction doesn't have a custom shape
562
if (myNBNode->getShape().size() == 0) {
563
mcResetCustomShape->disable();
564
}
565
// checkIsRemovable requires turnarounds to be computed. This is ugly
566
if ((myNBNode->getIncomingEdges().size() == 2) && (myNBNode->getOutgoingEdges().size() == 2)) {
567
NBTurningDirectionsComputer::computeTurnDirectionsForNode(myNBNode, false);
568
}
569
std::string reason = TL("wrong edit mode");
570
if (invalidMode || !myNBNode->checkIsRemovableReporting(reason)) {
571
mcReplaceByGeometryPoint->setText(mcReplaceByGeometryPoint->getText() + " (" + reason.c_str() + ")");
572
mcReplaceByGeometryPoint->disable();
573
}
574
// check if disable split junctions
575
if (numEndpoints == 1) {
576
mcSplitJunction->disable();
577
mcSplitJunctionAndReconnect->disable();
578
}
579
}
580
return ret;
581
}
582
}
583
584
585
double
586
GNEJunction::getExaggeration(const GUIVisualizationSettings& s) const {
587
return s.junctionSize.getExaggeration(s, this, 4);
588
}
589
590
591
Boundary
592
GNEJunction::getCenteringBoundary() const {
593
return myJunctionBoundary;
594
}
595
596
597
void
598
GNEJunction::updateCenteringBoundary(const bool updateGrid) {
599
// Remove object from grid
600
if (updateGrid) {
601
myNet->removeGLObjectFromGrid(this);
602
}
603
// calculate boundary using a radius bigger than geometry point
604
myJunctionBoundary = Boundary(myNBNode->getPosition().x() - 1, myNBNode->getPosition().y() - 1,
605
myNBNode->getPosition().x() + 1, myNBNode->getPosition().y() + 1);
606
myJunctionBoundary.grow(10);
607
// add shape
608
if (myNBNode->getShape().size() > 0) {
609
myJunctionBoundary.add(myNBNode->getShape().getBoxBoundary());
610
myJunctionBoundary.grow(5);
611
}
612
// add boundaries of all connections, walking areas and crossings
613
for (const auto& edge : myGNEIncomingEdges) {
614
for (const auto& connection : edge->getGNEConnections()) {
615
const auto boundary = connection->getCenteringBoundary();
616
if (boundary.isInitialised()) {
617
myJunctionBoundary.add(boundary);
618
}
619
}
620
}
621
for (const auto& crossing : myGNECrossings) {
622
const auto boundary = crossing->getCenteringBoundary();
623
if (boundary.isInitialised()) {
624
myJunctionBoundary.add(boundary);
625
}
626
}
627
for (const auto& walkingArea : myGNEWalkingAreas) {
628
const auto boundary = walkingArea->getCenteringBoundary();
629
if (boundary.isInitialised()) {
630
myJunctionBoundary.add(boundary);
631
}
632
}
633
634
// add object into grid
635
if (updateGrid) {
636
// if junction has at least one edge, then don't add in grid (because uses the edge's grid)
637
if (myGNEIncomingEdges.size() + myGNEOutgoingEdges.size() == 0) {
638
myNet->addGLObjectIntoGrid(this);
639
}
640
}
641
// trigger rebuilding tesselation
642
myExaggeration = 2;
643
}
644
645
646
void
647
GNEJunction::drawGL(const GUIVisualizationSettings& s) const {
648
// first check drawing toggle and boundary selection
649
if ((*myDrawingToggle != myNet->getViewNet()->getDrawingToggle()) && checkDrawingBoundarySelection()) {
650
// draw boundaries
651
if (inGrid()) {
652
GLHelper::drawBoundary(s, getCenteringBoundary());
653
}
654
// get junction exaggeration
655
const double junctionExaggeration = getExaggeration(s);
656
// only continue if exaggeration is greater than 0
657
if (junctionExaggeration > 0) {
658
// get detail level
659
const auto d = s.getDetailLevel(junctionExaggeration);
660
// get shape area
661
const double junctionShapeArea = myNBNode->getShape().area();
662
// check if draw junction as shape
663
const bool drawBubble = drawAsBubble(s, junctionShapeArea);
664
// draw geometry only if we'rent in drawForObjectUnderCursor mode
665
if (!s.drawForViewObjectsHandler) {
666
// push layer matrix
667
GLHelper::pushMatrix();
668
// translate to front
669
drawInLayer(GLO_JUNCTION);
670
if (drawBubble) {
671
// draw junction as bubble
672
drawJunctionAsBubble(s, d, junctionExaggeration);
673
} else {
674
// draw junction as shape
675
drawJunctionAsShape(s, d, junctionExaggeration);
676
}
677
// draw junction center (only in move mode)
678
drawJunctionCenter(s, d);
679
// draw TLS
680
drawTLSIcon(s);
681
// draw elevation
682
drawElevation(s);
683
// pop layer Matrix
684
GLHelper::popMatrix();
685
// draw lock icon
686
GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), getPositionInView(), 1);
687
// draw junction name
688
drawJunctionName(s);
689
// draw dotted contour depending if we're editing the custom shape
690
const GNENetworkElement* editedNetworkElement = myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement();
691
if (editedNetworkElement && (editedNetworkElement == this)) {
692
// draw dotted contour geometry points
693
myNetworkElementContour.drawDottedContourGeometryPoints(s, d, this, myNBNode->getShape(), s.neteditSizeSettings.junctionGeometryPointRadius,
694
junctionExaggeration, s.dottedContourSettings.segmentWidthSmall);
695
} else {
696
if (drawBubble) {
697
// draw dotted contour for bubble
698
myCircleContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);
699
} else {
700
// draw dotted contour for shape
701
if (junctionShapeArea >= 4) {
702
myNetworkElementContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);
703
}
704
}
705
}
706
}
707
// calculate junction contour (always before children)
708
calculateJunctioncontour(s, d, junctionExaggeration, drawBubble);
709
// draw Junction childs
710
drawJunctionChildren(s, d);
711
}
712
// update drawing toggle
713
*myDrawingToggle = myNet->getViewNet()->getDrawingToggle();
714
}
715
}
716
717
718
void
719
GNEJunction::deleteGLObject() {
720
// Check if edge can be deleted
721
if (GNEDeleteFrame::SubordinatedElements(this).checkElements(myNet->getViewParent()->getDeleteFrame()->getProtectElements())) {
722
myNet->deleteJunction(this, myNet->getUndoList());
723
}
724
}
725
726
727
void
728
GNEJunction::updateGLObject() {
729
updateGeometry();
730
}
731
732
733
NBNode*
734
GNEJunction::getNBNode() const {
735
return myNBNode;
736
}
737
738
739
std::vector<GNEJunction*>
740
GNEJunction::getJunctionNeighbours() const {
741
// use set to avoid duplicates junctions
742
std::set<GNEJunction*> junctions;
743
for (const auto& incomingEdge : myGNEIncomingEdges) {
744
junctions.insert(incomingEdge->getFromJunction());
745
}
746
for (const auto& outgoingEdge : myGNEOutgoingEdges) {
747
junctions.insert(outgoingEdge->getToJunction());
748
}
749
return std::vector<GNEJunction*>(junctions.begin(), junctions.end());
750
}
751
752
753
void
754
GNEJunction::addIncomingGNEEdge(GNEEdge* edge) {
755
// Check if incoming edge was already inserted
756
std::vector<GNEEdge*>::iterator i = std::find(myGNEIncomingEdges.begin(), myGNEIncomingEdges.end(), edge);
757
if (i != myGNEIncomingEdges.end()) {
758
throw InvalidArgument("Incoming " + toString(SUMO_TAG_EDGE) + " with ID '" + edge->getID() + "' was already inserted into " + getTagStr() + " with ID " + getID() + "'");
759
} else {
760
// Add edge into containers
761
myGNEIncomingEdges.push_back(edge);
762
}
763
}
764
765
766
767
void
768
GNEJunction::addOutgoingGNEEdge(GNEEdge* edge) {
769
// Check if outgoing edge was already inserted
770
const auto i = std::find(myGNEOutgoingEdges.begin(), myGNEOutgoingEdges.end(), edge);
771
if (i != myGNEOutgoingEdges.end()) {
772
throw InvalidArgument("Outgoing " + toString(SUMO_TAG_EDGE) + " with ID '" + edge->getID() + "' was already inserted into " + getTagStr() + " with ID " + getID() + "'");
773
} else {
774
// Add edge into containers
775
myGNEOutgoingEdges.push_back(edge);
776
}
777
// update centering boundary and grid
778
updateCenteringBoundary(true);
779
}
780
781
782
void
783
GNEJunction::removeIncomingGNEEdge(GNEEdge* edge) {
784
// Check if incoming edge was already inserted
785
auto i = std::find(myGNEIncomingEdges.begin(), myGNEIncomingEdges.end(), edge);
786
if (i == myGNEIncomingEdges.end()) {
787
throw InvalidArgument("Incoming " + toString(SUMO_TAG_EDGE) + " with ID '" + edge->getID() + "' doesn't found into " + getTagStr() + " with ID " + getID() + "'");
788
} else {
789
// remove edge from containers
790
myGNEIncomingEdges.erase(i);
791
}
792
// update centering boundary and grid
793
updateCenteringBoundary(true);
794
}
795
796
797
void
798
GNEJunction::removeOutgoingGNEEdge(GNEEdge* edge) {
799
// Check if outgoing edge was already inserted
800
std::vector<GNEEdge*>::iterator i = std::find(myGNEOutgoingEdges.begin(), myGNEOutgoingEdges.end(), edge);
801
if (i == myGNEOutgoingEdges.end()) {
802
throw InvalidArgument("Outgoing " + toString(SUMO_TAG_EDGE) + " with ID '" + edge->getID() + "' doesn't found into " + getTagStr() + " with ID " + getID() + "'");
803
} else {
804
// remove edge from containers
805
myGNEOutgoingEdges.erase(i);
806
}
807
}
808
809
810
const std::vector<GNEEdge*>&
811
GNEJunction::getGNEIncomingEdges() const {
812
return myGNEIncomingEdges;
813
}
814
815
816
const std::vector<GNEEdge*>&
817
GNEJunction::getGNEOutgoingEdges() const {
818
return myGNEOutgoingEdges;
819
}
820
821
822
const std::vector<GNECrossing*>&
823
GNEJunction::getGNECrossings() const {
824
return myGNECrossings;
825
}
826
827
828
const std::vector<GNEWalkingArea*>&
829
GNEJunction::getGNEWalkingAreas() const {
830
return myGNEWalkingAreas;
831
}
832
833
834
std::vector<GNEConnection*>
835
GNEJunction::getGNEConnections() const {
836
std::vector<GNEConnection*> connections;
837
for (const auto& incomingEdge : myGNEIncomingEdges) {
838
for (const auto& connection : incomingEdge->getGNEConnections()) {
839
connections.push_back(connection);
840
}
841
}
842
return connections;
843
}
844
845
846
void
847
GNEJunction::markAsCreateEdgeSource() {
848
myAmCreateEdgeSource = true;
849
}
850
851
852
void
853
GNEJunction::unMarkAsCreateEdgeSource() {
854
myAmCreateEdgeSource = false;
855
}
856
857
858
void
859
GNEJunction::selectTLS(bool selected) {
860
myAmTLSSelected = selected;
861
}
862
863
864
void
865
GNEJunction::invalidateShape() {
866
if (!myNBNode->hasCustomShape()) {
867
if (myNBNode->myPoly.size() > 0) {
868
// clear poly
869
myNBNode->myPoly.clear();
870
// update centering boundary
871
updateCenteringBoundary(true);
872
}
873
myNet->requireRecompute();
874
}
875
}
876
877
878
void
879
GNEJunction::setLogicValid(bool valid, GNEUndoList* undoList, const std::string& status) {
880
myHasValidLogic = valid;
881
if (!valid) {
882
assert(undoList != 0);
883
assert(undoList->hasCommandGroup());
884
NBTurningDirectionsComputer::computeTurnDirectionsForNode(myNBNode, false);
885
EdgeVector incoming = myNBNode->getIncomingEdges();
886
for (EdgeVector::iterator it = incoming.begin(); it != incoming.end(); it++) {
887
GNEEdge* srcEdge = myNet->getAttributeCarriers()->retrieveEdge((*it)->getID());
888
removeConnectionsFrom(srcEdge, undoList, false); // false, because the whole tls will be invalidated at the end
889
GNEChange_Attribute::changeAttribute(srcEdge, GNE_ATTR_MODIFICATION_STATUS, status, undoList, true);
890
}
891
GNEChange_Attribute::changeAttribute(this, GNE_ATTR_MODIFICATION_STATUS, status, undoList, true);
892
invalidateTLS(undoList);
893
} else {
894
// logic valed, then rebuild GNECrossings to adapt it to the new logic
895
// (but don't rebuild the crossings in NBNode because they are already finished)
896
rebuildGNECrossings(false);
897
}
898
}
899
900
901
void
902
GNEJunction::removeConnectionsFrom(GNEEdge* edge, GNEUndoList* undoList, bool updateTLS, int lane) {
903
NBEdge* srcNBE = edge->getNBEdge();
904
NBEdge* turnEdge = srcNBE->getTurnDestination();
905
// Make a copy of connections
906
std::vector<NBEdge::Connection> connections = srcNBE->getConnections();
907
// delete in reverse so that undoing will add connections in the original order
908
for (std::vector<NBEdge::Connection>::reverse_iterator con_it = connections.rbegin(); con_it != connections.rend(); con_it++) {
909
if (lane >= 0 && (*con_it).fromLane != lane) {
910
continue;
911
}
912
bool hasTurn = con_it->toEdge == turnEdge;
913
undoList->add(new GNEChange_Connection(edge, *con_it, false, false), true);
914
// needs to come after GNEChange_Connection
915
// XXX bug: this code path will not be used on a redo!
916
if (hasTurn) {
917
myNet->addExplicitTurnaround(srcNBE->getID());
918
}
919
}
920
if (updateTLS) {
921
std::vector<NBConnection> removeConnections;
922
for (NBEdge::Connection con : connections) {
923
removeConnections.push_back(NBConnection(srcNBE, con.fromLane, con.toEdge, con.toLane));
924
}
925
removeTLSConnections(removeConnections, undoList);
926
}
927
}
928
929
930
void
931
GNEJunction::removeConnectionsTo(GNEEdge* edge, GNEUndoList* undoList, bool updateTLS, int lane) {
932
NBEdge* destNBE = edge->getNBEdge();
933
std::vector<NBConnection> removeConnections;
934
for (NBEdge* srcNBE : myNBNode->getIncomingEdges()) {
935
GNEEdge* srcEdge = myNet->getAttributeCarriers()->retrieveEdge(srcNBE->getID());
936
std::vector<NBEdge::Connection> connections = srcNBE->getConnections();
937
for (std::vector<NBEdge::Connection>::reverse_iterator con_it = connections.rbegin(); con_it != connections.rend(); con_it++) {
938
if ((*con_it).toEdge == destNBE) {
939
if (lane >= 0 && (*con_it).toLane != lane) {
940
continue;
941
}
942
bool hasTurn = srcNBE->getTurnDestination() == destNBE;
943
undoList->add(new GNEChange_Connection(srcEdge, *con_it, false, false), true);
944
// needs to come after GNEChange_Connection
945
// XXX bug: this code path will not be used on a redo!
946
if (hasTurn) {
947
myNet->addExplicitTurnaround(srcNBE->getID());
948
}
949
removeConnections.push_back(NBConnection(srcNBE, (*con_it).fromLane, destNBE, (*con_it).toLane));
950
}
951
}
952
}
953
if (updateTLS) {
954
removeTLSConnections(removeConnections, undoList);
955
}
956
}
957
958
959
void
960
GNEJunction::removeTLSConnections(std::vector<NBConnection>& connections, GNEUndoList* undoList) {
961
if (connections.size() > 0) {
962
const std::set<NBTrafficLightDefinition*> coypOfTls = myNBNode->getControllingTLS(); // make a copy!
963
for (const auto& TLS : coypOfTls) {
964
NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(TLS);
965
// guessed TLS (NBOwnTLDef) do not need to be updated
966
if (tlDef != nullptr) {
967
std::string newID = tlDef->getID();
968
// create replacement before deleting the original because deletion will mess up saving original nodes
969
NBLoadedSUMOTLDef* replacementDef = new NBLoadedSUMOTLDef(*tlDef, *tlDef->getLogic());
970
for (NBConnection& con : connections) {
971
replacementDef->removeConnection(con);
972
}
973
undoList->add(new GNEChange_TLS(this, tlDef, false), true);
974
undoList->add(new GNEChange_TLS(this, replacementDef, true, false, newID), true);
975
// the removed traffic light may have controlled more than one junction. These too have become invalid now
976
const std::vector<NBNode*> copyOfNodes = tlDef->getNodes(); // make a copy!
977
for (const auto& node : copyOfNodes) {
978
GNEJunction* sharing = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
979
undoList->add(new GNEChange_TLS(sharing, tlDef, false), true);
980
undoList->add(new GNEChange_TLS(sharing, replacementDef, true, false, newID), true);
981
}
982
}
983
}
984
}
985
}
986
987
988
void
989
GNEJunction::replaceIncomingConnections(GNEEdge* which, GNEEdge* by, GNEUndoList* undoList) {
990
// remap connections of the edge
991
assert(which->getChildLanes().size() == by->getChildLanes().size());
992
std::vector<NBEdge::Connection> connections = which->getNBEdge()->getConnections();
993
for (NBEdge::Connection& c : connections) {
994
undoList->add(new GNEChange_Connection(which, c, false, false), true);
995
undoList->add(new GNEChange_Connection(by, c, false, true), true);
996
}
997
// also remap tls connections
998
const std::set<NBTrafficLightDefinition*> coypOfTls = myNBNode->getControllingTLS(); // make a copy!
999
for (const auto& TLS : coypOfTls) {
1000
NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(TLS);
1001
// guessed TLS (NBOwnTLDef) do not need to be updated
1002
if (tlDef != nullptr) {
1003
std::string newID = tlDef->getID();
1004
// create replacement before deleting the original because deletion will mess up saving original nodes
1005
NBLoadedSUMOTLDef* replacementDef = new NBLoadedSUMOTLDef(*tlDef, *tlDef->getLogic());
1006
for (int i = 0; i < (int)which->getChildLanes().size(); ++i) {
1007
replacementDef->replaceRemoved(which->getNBEdge(), i, by->getNBEdge(), i, true);
1008
}
1009
undoList->add(new GNEChange_TLS(this, tlDef, false), true);
1010
undoList->add(new GNEChange_TLS(this, replacementDef, true, false, newID), true);
1011
// the removed traffic light may have controlled more than one junction. These too have become invalid now
1012
const std::vector<NBNode*> copyOfNodes = tlDef->getNodes(); // make a copy!
1013
for (const auto& node : copyOfNodes) {
1014
GNEJunction* sharing = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1015
undoList->add(new GNEChange_TLS(sharing, tlDef, false), true);
1016
undoList->add(new GNEChange_TLS(sharing, replacementDef, true, false, newID), true);
1017
}
1018
}
1019
}
1020
}
1021
1022
1023
void
1024
GNEJunction::markAsModified(GNEUndoList* undoList) {
1025
EdgeVector incoming = myNBNode->getIncomingEdges();
1026
for (EdgeVector::iterator it = incoming.begin(); it != incoming.end(); it++) {
1027
NBEdge* srcNBE = *it;
1028
GNEEdge* srcEdge = myNet->getAttributeCarriers()->retrieveEdge(srcNBE->getID());
1029
GNEChange_Attribute::changeAttribute(srcEdge, GNE_ATTR_MODIFICATION_STATUS, FEATURE_MODIFIED, undoList, true);
1030
}
1031
}
1032
1033
1034
void
1035
GNEJunction::invalidateTLS(GNEUndoList* undoList, const NBConnection& deletedConnection, const NBConnection& addedConnection) {
1036
assert(undoList->hasCommandGroup());
1037
// NBLoadedSUMOTLDef becomes invalid, replace with NBOwnTLDef which will be dynamically recomputed
1038
const std::set<NBTrafficLightDefinition*> coypOfTls = myNBNode->getControllingTLS(); // make a copy!
1039
for (const auto& TLS : coypOfTls) {
1040
NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(TLS);
1041
if (tlDef != nullptr) {
1042
// the removed traffic light may have controlled more than one junction. These too have become invalid now
1043
const std::vector<NBNode*> copyOfNodes = tlDef->getNodes(); // make a copy!
1044
if (myGNECrossings.size() == 0 && getNBNode()->getCrossings().size() != 0) {
1045
// crossings were not computed yet. We need them as netedit elements to manage tlIndex resetting
1046
myNet->getNetBuilder()->setHaveNetworkCrossings(true);
1047
rebuildGNECrossings();
1048
for (const auto& node : copyOfNodes) {
1049
GNEJunction* sharing = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1050
if (sharing != this) {
1051
sharing->rebuildGNECrossings();
1052
}
1053
}
1054
}
1055
NBTrafficLightDefinition* replacementDef = nullptr;
1056
std::string newID = tlDef->getID(); // + "_reguessed"; // changes due to reguessing will be visible in diff
1057
if (deletedConnection != NBConnection::InvalidConnection) {
1058
// create replacement before deleting the original because deletion will mess up saving original nodes
1059
NBLoadedSUMOTLDef* repl = new NBLoadedSUMOTLDef(*tlDef, *tlDef->getLogic());
1060
repl->removeConnection(deletedConnection);
1061
replacementDef = repl;
1062
} else if (addedConnection != NBConnection::InvalidConnection) {
1063
if (addedConnection.getTLIndex() == NBConnection::InvalidTlIndex) {
1064
// custom tl indices of crossings might become invalid upon recomputation so we must save them
1065
// however, they could remain valid so we register a change but keep them at their old value
1066
for (const auto& crossing : myGNECrossings) {
1067
const std::string oldValue = crossing->getAttribute(SUMO_ATTR_TLLINKINDEX);
1068
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX, toString(NBConnection::InvalidTlIndex), undoList, true);
1069
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX, oldValue, undoList, true);
1070
const std::string oldValue2 = crossing->getAttribute(SUMO_ATTR_TLLINKINDEX2);
1071
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX2, toString(NBConnection::InvalidTlIndex), undoList, true);
1072
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX2, oldValue2, undoList, true);
1073
}
1074
}
1075
NBLoadedSUMOTLDef* repl = new NBLoadedSUMOTLDef(*tlDef, *tlDef->getLogic());
1076
repl->addConnection(addedConnection.getFrom(), addedConnection.getTo(),
1077
addedConnection.getFromLane(), addedConnection.getToLane(), addedConnection.getTLIndex(), addedConnection.getTLIndex2());
1078
replacementDef = repl;
1079
} else {
1080
// recompute crossing indices along with everything else
1081
for (const auto& crossing : myGNECrossings) {
1082
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX, toString(NBConnection::InvalidTlIndex), undoList, true);
1083
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX2, toString(NBConnection::InvalidTlIndex), undoList, true);
1084
}
1085
replacementDef = new NBOwnTLDef(newID, tlDef->getOffset(), tlDef->getType());
1086
replacementDef->setProgramID(tlDef->getProgramID());
1087
}
1088
undoList->add(new GNEChange_TLS(this, tlDef, false), true);
1089
undoList->add(new GNEChange_TLS(this, replacementDef, true, false, newID), true);
1090
// reset nodes of joint tls
1091
for (const auto& node : copyOfNodes) {
1092
GNEJunction* sharing = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1093
if (sharing != this) {
1094
if (deletedConnection == NBConnection::InvalidConnection && addedConnection == NBConnection::InvalidConnection) {
1095
// recompute crossing indices for shared
1096
// (they won't do this on subsequent call to invalidateTLS if they received an NBOwnTLDef)
1097
for (const auto& crossing : sharing->getGNECrossings()) {
1098
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX, toString(NBConnection::InvalidTlIndex), undoList, true);
1099
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX2, toString(NBConnection::InvalidTlIndex), undoList, true);
1100
}
1101
}
1102
undoList->add(new GNEChange_TLS(sharing, tlDef, false), true);
1103
undoList->add(new GNEChange_TLS(sharing, replacementDef, true, false, newID), true);
1104
}
1105
}
1106
}
1107
}
1108
}
1109
1110
void
1111
GNEJunction::removeEdgeFromCrossings(GNEEdge* edge, GNEUndoList* undoList) {
1112
// obtain a copy of GNECrossing of junctions
1113
const auto copyOfGNECrossings = myGNECrossings;
1114
// iterate over copy of GNECrossings
1115
for (const auto& crossing : copyOfGNECrossings) {
1116
// obtain the set of edges vinculated with the crossing (due it works as ID)
1117
EdgeSet edgeSet(crossing->getCrossingEdges().begin(), crossing->getCrossingEdges().end());
1118
// If this edge is part of the set of edges of crossing
1119
if (edgeSet.count(edge->getNBEdge()) == 1) {
1120
// delete crossing if this is their last edge
1121
if ((crossing->getCrossingEdges().size() == 1) && (crossing->getCrossingEdges().front() == edge->getNBEdge())) {
1122
myNet->deleteCrossing(crossing, undoList);
1123
} else {
1124
// remove this edge of the edge's attribute of crossing (note: This can invalidate the crossing)
1125
std::vector<std::string> edges = GNEAttributeCarrier::parse<std::vector<std::string>>(crossing->getAttribute(SUMO_ATTR_EDGES));
1126
edges.erase(std::find(edges.begin(), edges.end(), edge->getID()));
1127
crossing->setAttribute(SUMO_ATTR_EDGES, joinToString(edges, " "), undoList);
1128
}
1129
}
1130
}
1131
}
1132
1133
1134
bool
1135
GNEJunction::isLogicValid() {
1136
return myHasValidLogic;
1137
}
1138
1139
1140
GNECrossing*
1141
GNEJunction::retrieveGNECrossing(NBNode::Crossing* NBNodeCrossing, bool createIfNoExist) {
1142
// iterate over all crossing
1143
for (const auto& crossing : myGNECrossings) {
1144
// if found, return it
1145
if (crossing->getCrossingEdges() == NBNodeCrossing->edges) {
1146
return crossing;
1147
}
1148
}
1149
if (createIfNoExist) {
1150
// create new GNECrossing
1151
GNECrossing* createdGNECrossing = new GNECrossing(this, NBNodeCrossing->edges);
1152
// update geometry after creating
1153
createdGNECrossing->updateGeometry();
1154
// add it in Network
1155
myNet->addGLObjectIntoGrid(createdGNECrossing);
1156
// add it in attributeCarriers
1157
myNet->getAttributeCarriers()->insertCrossing(createdGNECrossing);
1158
return createdGNECrossing;
1159
} else {
1160
return nullptr;
1161
}
1162
}
1163
1164
1165
GNEWalkingArea*
1166
GNEJunction::retrieveGNEWalkingArea(const std::string& NBNodeWalkingAreaID, bool createIfNoExist) {
1167
// iterate over all walkingArea
1168
for (const auto& walkingArea : myGNEWalkingAreas) {
1169
// if found, return it
1170
if (walkingArea->getID() == NBNodeWalkingAreaID) {
1171
return walkingArea;
1172
}
1173
}
1174
if (createIfNoExist) {
1175
// create new GNEWalkingArea
1176
GNEWalkingArea* createdGNEWalkingArea = new GNEWalkingArea(this, NBNodeWalkingAreaID);
1177
// update geometry after creating
1178
createdGNEWalkingArea->updateGeometry();
1179
// add it in Network
1180
myNet->addGLObjectIntoGrid(createdGNEWalkingArea);
1181
// add it in attributeCarriers
1182
myNet->getAttributeCarriers()->insertWalkingArea(createdGNEWalkingArea);
1183
return createdGNEWalkingArea;
1184
} else {
1185
return nullptr;
1186
}
1187
}
1188
1189
1190
void
1191
GNEJunction::markConnectionsDeprecated(bool includingNeighbours) {
1192
// only it's needed to mark the connections of incoming edges
1193
for (const auto& i : myGNEIncomingEdges) {
1194
for (const auto& j : i->getGNEConnections()) {
1195
j->markConnectionGeometryDeprecated();
1196
}
1197
if (includingNeighbours) {
1198
i->getFromJunction()->markConnectionsDeprecated(false);
1199
}
1200
}
1201
}
1202
1203
1204
void
1205
GNEJunction::setJunctionType(const std::string& value, GNEUndoList* undoList) {
1206
undoList->begin(this, "change " + getTagStr() + " type");
1207
if (NBNode::isTrafficLight(SUMOXMLDefinitions::NodeTypes.get(value))) {
1208
if (getNBNode()->isTLControlled() &&
1209
// if switching changing from or to traffic_light_right_on_red we need to remove the old plan
1210
(getNBNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED
1211
|| SUMOXMLDefinitions::NodeTypes.get(value) == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED)
1212
) {
1213
// make a copy because we will modify the original
1214
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
1215
for (const auto& TLS : copyOfTls) {
1216
undoList->add(new GNEChange_TLS(this, TLS, false), true);
1217
}
1218
}
1219
if (!getNBNode()->isTLControlled()) {
1220
// create new traffic light
1221
undoList->add(new GNEChange_TLS(this, nullptr, true), true);
1222
}
1223
} else if (getNBNode()->isTLControlled()) {
1224
// delete old traffic light
1225
// make a copy because we will modify the original
1226
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
1227
for (const auto& TLS : copyOfTls) {
1228
undoList->add(new GNEChange_TLS(this, TLS, false, false), true);
1229
const std::vector<NBNode*> copyOfNodes = TLS->getNodes(); // make a copy!
1230
for (const auto& node : copyOfNodes) {
1231
GNEJunction* sharing = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1232
sharing->invalidateTLS(undoList);
1233
}
1234
}
1235
}
1236
// must be the final step, otherwise we do not know which traffic lights to remove via GNEChange_TLS
1237
GNEChange_Attribute::changeAttribute(this, SUMO_ATTR_TYPE, value, undoList, true);
1238
for (const auto& crossing : myGNECrossings) {
1239
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX, "-1", undoList, true);
1240
GNEChange_Attribute::changeAttribute(crossing, SUMO_ATTR_TLLINKINDEX2, "-1", undoList, true);
1241
}
1242
undoList->end();
1243
}
1244
1245
1246
void
1247
GNEJunction::clearWalkingAreas() {
1248
// delete non retrieved GNEWalkingAreas (we don't need to extract if from Tree two times)
1249
for (const auto& walkingArea : myGNEWalkingAreas) {
1250
walkingArea->decRef();
1251
// check if walkingArea is selected
1252
if (walkingArea->isAttributeCarrierSelected()) {
1253
walkingArea->unselectAttributeCarrier();
1254
}
1255
// remove it from inspected ACS
1256
myNet->getViewNet()->getInspectedElements().uninspectAC(walkingArea);
1257
// remove it from net
1258
myNet->removeGLObjectFromGrid(walkingArea);
1259
// remove it from attributeCarriers
1260
myNet->getAttributeCarriers()->deleteWalkingArea(walkingArea);
1261
if (walkingArea->unreferenced()) {
1262
delete walkingArea;
1263
}
1264
}
1265
myGNEWalkingAreas.clear();
1266
}
1267
1268
1269
void
1270
GNEJunction::rebuildGNEWalkingAreas() {
1271
// first clear GNEWalkingAreas
1272
clearWalkingAreas();
1273
// iterate over NBNode::WalkingAreas of GNEJunction
1274
for (const auto& walkingArea : myNBNode->getWalkingAreas()) {
1275
// retrieve existent GNEWalkingArea, or create it
1276
GNEWalkingArea* retrievedGNEWalkingArea = retrieveGNEWalkingArea(walkingArea.id, true);
1277
// include reference to created GNEWalkingArea
1278
retrievedGNEWalkingArea->incRef();
1279
// update geometry of retrieved walkingArea
1280
retrievedGNEWalkingArea->updateGeometry();
1281
// update boundary
1282
retrievedGNEWalkingArea->updateCenteringBoundary(false);
1283
// add in walkingAreas
1284
myGNEWalkingAreas.push_back(retrievedGNEWalkingArea);
1285
}
1286
}
1287
1288
1289
1290
void
1291
GNEJunction::addInternalLane(const GNEInternalLane* internalLane) {
1292
if (std::find(myInternalLanes.begin(), myInternalLanes.end(), internalLane) != myInternalLanes.end()) {
1293
throw ProcessError(internalLane->getTagStr() + " with ID='" + internalLane->getID() + "' already exist");
1294
} else {
1295
myInternalLanes.push_back(internalLane);
1296
}
1297
}
1298
1299
1300
void
1301
GNEJunction::removeInternalLane(const GNEInternalLane* internalLane) {
1302
const auto finder = std::find(myInternalLanes.begin(), myInternalLanes.end(), internalLane);
1303
if (finder == myInternalLanes.end()) {
1304
throw ProcessError(internalLane->getTagStr() + " with ID='" + internalLane->getID() + "' wasn't previously inserted");
1305
} else {
1306
myInternalLanes.erase(finder);
1307
}
1308
}
1309
1310
1311
std::string
1312
GNEJunction::getAttribute(SumoXMLAttr key) const {
1313
switch (key) {
1314
case SUMO_ATTR_ID:
1315
return getMicrosimID();
1316
case SUMO_ATTR_POSITION:
1317
return toString(myNBNode->getPosition());
1318
case SUMO_ATTR_TYPE:
1319
return toString(myNBNode->getType());
1320
case GNE_ATTR_MODIFICATION_STATUS:
1321
return myLogicStatus;
1322
case SUMO_ATTR_SHAPE:
1323
return toString(myNBNode->getShape());
1324
case SUMO_ATTR_RADIUS:
1325
if (myNBNode->getRadius() < 0) {
1326
return "default";
1327
} else {
1328
return toString(myNBNode->getRadius());
1329
}
1330
case SUMO_ATTR_TLTYPE:
1331
if (isAttributeEnabled(SUMO_ATTR_TLTYPE)) {
1332
// @todo this causes problems if the node were to have multiple programs of different type (plausible)
1333
return toString((*myNBNode->getControllingTLS().begin())->getType());
1334
} else {
1335
return "No TLS";
1336
}
1337
case SUMO_ATTR_TLLAYOUT:
1338
if (isAttributeEnabled(SUMO_ATTR_TLLAYOUT)) {
1339
return toString((*myNBNode->getControllingTLS().begin())->getLayout());
1340
} else {
1341
return "No TLS";
1342
}
1343
case SUMO_ATTR_TLID:
1344
if (isAttributeEnabled(SUMO_ATTR_TLID)) {
1345
return toString((*myNBNode->getControllingTLS().begin())->getID());
1346
} else {
1347
return "No TLS";
1348
}
1349
case GNE_ATTR_IS_ROUNDABOUT:
1350
return myNBNode->isRoundabout() ? TRUE_STR : FALSE_STR;
1351
case SUMO_ATTR_KEEP_CLEAR:
1352
// keep clear is only used as a convenience feature in plain xml
1353
// input. When saving to .net.xml the status is saved only for the connections
1354
// to show the correct state we must check all connections
1355
for (const auto& i : myGNEIncomingEdges) {
1356
for (const auto& j : i->getGNEConnections()) {
1357
if (j->getNBEdgeConnection().keepClear) {
1358
return TRUE_STR;
1359
}
1360
}
1361
}
1362
return FALSE_STR;
1363
case SUMO_ATTR_RIGHT_OF_WAY:
1364
return SUMOXMLDefinitions::RightOfWayValues.getString(myNBNode->getRightOfWay());
1365
case SUMO_ATTR_FRINGE:
1366
return SUMOXMLDefinitions::FringeTypeValues.getString(myNBNode->getFringeType());
1367
case SUMO_ATTR_ROUNDABOUT:
1368
return SUMOXMLDefinitions::RoundaboutTypeValues.getString(myNBNode->getRoundaboutType());
1369
case SUMO_ATTR_NAME:
1370
return myNBNode->getName();
1371
default:
1372
return getCommonAttribute(key);
1373
}
1374
}
1375
1376
1377
double
1378
GNEJunction::getAttributeDouble(SumoXMLAttr key) const {
1379
return getCommonAttributeDouble(key);
1380
}
1381
1382
1383
Position
1384
GNEJunction::getAttributePosition(SumoXMLAttr key) const {
1385
return getCommonAttributePosition(key);
1386
}
1387
1388
1389
PositionVector
1390
GNEJunction::getAttributePositionVector(SumoXMLAttr key) const {
1391
switch (key) {
1392
case SUMO_ATTR_SHAPE:
1393
return myNBNode->getShape();
1394
default:
1395
return getCommonAttributePositionVector(key);
1396
}
1397
}
1398
1399
1400
void
1401
GNEJunction::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
1402
if (value == getAttribute(key)) {
1403
return; //avoid needless changes, later logic relies on the fact that attributes have changed
1404
}
1405
switch (key) {
1406
case SUMO_ATTR_ID:
1407
case GNE_ATTR_MODIFICATION_STATUS:
1408
case SUMO_ATTR_SHAPE:
1409
case SUMO_ATTR_RADIUS:
1410
case SUMO_ATTR_RIGHT_OF_WAY:
1411
case SUMO_ATTR_FRINGE:
1412
case SUMO_ATTR_ROUNDABOUT:
1413
case SUMO_ATTR_NAME:
1414
GNEChange_Attribute::changeAttribute(this, key, value, undoList, true);
1415
break;
1416
case SUMO_ATTR_POSITION: {
1417
const GNEJunction* junctionToMerge = nullptr;
1418
bool alreadyAsked = false;
1419
// parse position
1420
Position newPosition = GNEAttributeCarrier::parse<Position>(value);
1421
// check if caculate new position based in edges
1422
if (newPosition == Position::INVALID) {
1423
Boundary b;
1424
// set new position of adjacent edges
1425
for (const auto& edge : myGNEIncomingEdges) {
1426
b.add(edge->getNBEdge()->getGeometry().back());
1427
}
1428
for (const auto& edge : myGNEOutgoingEdges) {
1429
b.add(edge->getNBEdge()->getGeometry().front());
1430
}
1431
newPosition = b.getCenter();
1432
}
1433
// retrieve all junctions placed in this position
1434
myNet->getViewNet()->updateObjectsInPosition(newPosition);
1435
for (const auto& junction : myNet->getViewNet()->getViewObjectsSelector().getJunctions()) {
1436
// check distance position
1437
if ((junctionToMerge == nullptr) && (junction != this) &&
1438
(junction->getPositionInView().distanceTo2D(newPosition) < myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.junctionBubbleRadius) &&
1439
myNet->getViewNet()->askMergeJunctions(this, junction, alreadyAsked)) {
1440
junctionToMerge = junction;
1441
}
1442
}
1443
// also check the merging junctions located during drawGL
1444
for (const auto& junction : myNet->getViewNet()->getViewObjectsSelector().getMergingJunctions()) {
1445
// check distance position
1446
if ((junctionToMerge == nullptr) && (junction != this) && myNet->getViewNet()->askMergeJunctions(this, junction, alreadyAsked)) {
1447
junctionToMerge = junction;
1448
}
1449
}
1450
// if we merge the junction, this junction will be removed, therefore we don't have to change the position
1451
if (junctionToMerge) {
1452
myNet->mergeJunctions(this, junctionToMerge, undoList);
1453
} else {
1454
// change Keep Clear attribute in all connections
1455
undoList->begin(this, TL("change junction position"));
1456
// obtain NBNode position
1457
const Position orig = myNBNode->getPosition();
1458
// change junction position
1459
GNEChange_Attribute::changeAttribute(this, key, toString(newPosition), undoList, true);
1460
// calculate delta using new position
1461
const bool moveOnlyCenter = myNet->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveOnlyJunctionCenter();
1462
const Position delta = myNBNode->getPosition() - (moveOnlyCenter ? myNBNode->getPosition() : orig);
1463
// set new position of adjacent edges
1464
for (const auto& edge : myGNEIncomingEdges) {
1465
const Position newEnd = edge->getNBEdge()->getGeometry().back() + delta;
1466
GNEChange_Attribute::changeAttribute(edge, GNE_ATTR_SHAPE_END, toString(newEnd), undoList, true);
1467
}
1468
for (const auto& edge : myGNEOutgoingEdges) {
1469
const Position newStart = edge->getNBEdge()->getGeometry().front() + delta;
1470
GNEChange_Attribute::changeAttribute(edge, GNE_ATTR_SHAPE_START, toString(newStart), undoList, true);
1471
}
1472
undoList->end();
1473
}
1474
break;
1475
}
1476
case SUMO_ATTR_KEEP_CLEAR:
1477
// change Keep Clear attribute in all connections
1478
undoList->begin(this, TL("change keepClear for whole junction"));
1479
for (const auto& incomingEdge : myGNEIncomingEdges) {
1480
for (const auto& junction : incomingEdge->getGNEConnections()) {
1481
GNEChange_Attribute::changeAttribute(junction, key, value, undoList, true);
1482
}
1483
}
1484
undoList->end();
1485
break;
1486
case SUMO_ATTR_TYPE: {
1487
// set junction type
1488
setJunctionType(value, undoList);
1489
break;
1490
}
1491
case SUMO_ATTR_TLTYPE: {
1492
undoList->begin(this, "change " + getTagStr() + " tl-type");
1493
// make a copy because we will modify the original
1494
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
1495
for (const auto& TLS : copyOfTls) {
1496
NBLoadedSUMOTLDef* oldLoaded = dynamic_cast<NBLoadedSUMOTLDef*>(TLS);
1497
if (oldLoaded != nullptr) {
1498
NBTrafficLightDefinition* newDef = nullptr;
1499
if (value == toString(TrafficLightType::NEMA) || oldLoaded->getType() == TrafficLightType::NEMA) {
1500
// rebuild the program because the old and new ones are incompatible
1501
newDef = new NBOwnTLDef(oldLoaded->getID(), oldLoaded->getOffset(), TrafficLightType::NEMA);
1502
newDef->setProgramID(oldLoaded->getProgramID());
1503
} else {
1504
NBLoadedSUMOTLDef* newLDef = new NBLoadedSUMOTLDef(*oldLoaded, *oldLoaded->getLogic());
1505
newLDef->guessMinMaxDuration(); // minDur and maxDur are never written for a static tls
1506
newDef = newLDef;
1507
}
1508
std::vector<NBNode*> nodes = TLS->getNodes();
1509
for (const auto& node : nodes) {
1510
GNEJunction* junction = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1511
undoList->add(new GNEChange_TLS(junction, TLS, false), true);
1512
undoList->add(new GNEChange_TLS(junction, newDef, true), true);
1513
}
1514
}
1515
}
1516
GNEChange_Attribute::changeAttribute(this, key, value, undoList, true);
1517
undoList->end();
1518
break;
1519
}
1520
case SUMO_ATTR_TLLAYOUT: {
1521
undoList->begin(this, "change " + getTagStr() + " tlLayout");
1522
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
1523
for (const auto& oldTLS : copyOfTls) {
1524
std::vector<NBNode*> copyOfNodes = oldTLS->getNodes();
1525
NBOwnTLDef* newTLS = new NBOwnTLDef(oldTLS->getID(), oldTLS->getOffset(), oldTLS->getType());
1526
newTLS->setLayout(SUMOXMLDefinitions::TrafficLightLayouts.get(value));
1527
newTLS->setProgramID(oldTLS->getProgramID());
1528
for (const auto& node : copyOfNodes) {
1529
GNEJunction* oldJunction = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1530
undoList->add(new GNEChange_TLS(oldJunction, oldTLS, false), true);
1531
}
1532
for (const auto& node : copyOfNodes) {
1533
GNEJunction* oldJunction = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1534
undoList->add(new GNEChange_TLS(oldJunction, newTLS, true), true);
1535
}
1536
}
1537
undoList->end();
1538
break;
1539
}
1540
case SUMO_ATTR_TLID: {
1541
undoList->begin(this, "change " + toString(SUMO_TAG_TRAFFIC_LIGHT) + " id");
1542
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
1543
assert(copyOfTls.size() > 0);
1544
NBTrafficLightDefinition* currentTLS = *copyOfTls.begin();
1545
NBTrafficLightDefinition* currentTLSCopy = nullptr;
1546
const bool currentIsSingle = currentTLS->getNodes().size() == 1;
1547
const bool currentIsLoaded = dynamic_cast<NBLoadedSUMOTLDef*>(currentTLS) != nullptr;
1548
if (currentIsLoaded) {
1549
currentTLSCopy = new NBLoadedSUMOTLDef(*currentTLS,
1550
*dynamic_cast<NBLoadedSUMOTLDef*>(currentTLS)->getLogic());
1551
}
1552
// remove from previous tls
1553
for (const auto& TLS : copyOfTls) {
1554
undoList->add(new GNEChange_TLS(this, TLS, false), true);
1555
}
1556
NBTrafficLightLogicCont& tlCont = myNet->getTLLogicCont();
1557
// programs to which the current node shall be added
1558
const std::map<std::string, NBTrafficLightDefinition*> programs = tlCont.getPrograms(value);
1559
if (programs.size() > 0) {
1560
for (const auto& TLSProgram : programs) {
1561
NBTrafficLightDefinition* oldTLS = TLSProgram.second;
1562
if (dynamic_cast<NBOwnTLDef*>(oldTLS) != nullptr) {
1563
undoList->add(new GNEChange_TLS(this, oldTLS, true), true);
1564
} else {
1565
// delete and re-create the definition because the loaded phases are now invalid
1566
if (dynamic_cast<NBLoadedSUMOTLDef*>(oldTLS) != nullptr &&
1567
dynamic_cast<NBLoadedSUMOTLDef*>(oldTLS)->usingSignalGroups()) {
1568
// keep the old program and add all-red state for the added links
1569
NBLoadedSUMOTLDef* newTLSJoined = new NBLoadedSUMOTLDef(*oldTLS, *dynamic_cast<NBLoadedSUMOTLDef*>(oldTLS)->getLogic());
1570
newTLSJoined->joinLogic(currentTLSCopy);
1571
undoList->add(new GNEChange_TLS(this, newTLSJoined, true, true), true);
1572
} else {
1573
undoList->add(new GNEChange_TLS(this, nullptr, true, false, value), true);
1574
}
1575
NBTrafficLightDefinition* newTLS = *myNBNode->getControllingTLS().begin();
1576
// switch from old to new definition
1577
std::vector<NBNode*> copyOfNodes = oldTLS->getNodes();
1578
for (const auto& node : copyOfNodes) {
1579
GNEJunction* oldJunction = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1580
undoList->add(new GNEChange_TLS(oldJunction, oldTLS, false), true);
1581
undoList->add(new GNEChange_TLS(oldJunction, newTLS, true), true);
1582
}
1583
}
1584
}
1585
} else {
1586
if (currentIsSingle && currentIsLoaded) {
1587
// rename the traffic light but keep everything else
1588
NBTrafficLightLogic* renamedLogic = dynamic_cast<NBLoadedSUMOTLDef*>(currentTLSCopy)->getLogic();
1589
renamedLogic->setID(value);
1590
NBLoadedSUMOTLDef* renamedTLS = new NBLoadedSUMOTLDef(*currentTLSCopy, *renamedLogic);
1591
renamedTLS->setID(value);
1592
undoList->add(new GNEChange_TLS(this, renamedTLS, true, true), true);
1593
} else {
1594
// create new traffic light
1595
undoList->add(new GNEChange_TLS(this, nullptr, true, false, value), true);
1596
}
1597
}
1598
delete currentTLSCopy;
1599
undoList->end();
1600
break;
1601
}
1602
default:
1603
setCommonAttribute(key, value, undoList);
1604
break;
1605
}
1606
}
1607
1608
1609
bool
1610
GNEJunction::isValid(SumoXMLAttr key, const std::string& value) {
1611
switch (key) {
1612
case SUMO_ATTR_ID:
1613
return SUMOXMLDefinitions::isValidNetID(value) && (myNet->getAttributeCarriers()->retrieveJunction(value, false) == nullptr);
1614
case SUMO_ATTR_TYPE:
1615
return SUMOXMLDefinitions::NodeTypes.hasString(value);
1616
case SUMO_ATTR_POSITION:
1617
if (value.empty()) {
1618
return (myGNEIncomingEdges.size() + myGNEOutgoingEdges.size()) > 0;
1619
} else {
1620
return canParse<Position>(value);
1621
}
1622
case SUMO_ATTR_SHAPE:
1623
// empty shapes are allowed
1624
return canParse<PositionVector>(value);
1625
case SUMO_ATTR_RADIUS:
1626
if (value.empty() || (value == "default")) {
1627
return true;
1628
} else {
1629
return canParse<double>(value) && ((parse<double>(value) >= 0) || (parse<double>(value) == -1));
1630
}
1631
case SUMO_ATTR_TLTYPE:
1632
return myNBNode->isTLControlled() && SUMOXMLDefinitions::TrafficLightTypes.hasString(value);
1633
case SUMO_ATTR_TLLAYOUT:
1634
return myNBNode->isTLControlled() && SUMOXMLDefinitions::TrafficLightLayouts.hasString(value);
1635
case SUMO_ATTR_TLID:
1636
return myNBNode->isTLControlled() && (value != "");
1637
case SUMO_ATTR_KEEP_CLEAR:
1638
return canParse<bool>(value);
1639
case SUMO_ATTR_RIGHT_OF_WAY:
1640
return SUMOXMLDefinitions::RightOfWayValues.hasString(value);
1641
case SUMO_ATTR_FRINGE:
1642
return SUMOXMLDefinitions::FringeTypeValues.hasString(value);
1643
case SUMO_ATTR_ROUNDABOUT:
1644
return SUMOXMLDefinitions::RoundaboutTypeValues.hasString(value);
1645
case SUMO_ATTR_NAME:
1646
return true;
1647
default:
1648
return isCommonAttributeValid(key, value);
1649
}
1650
}
1651
1652
1653
bool
1654
GNEJunction::isAttributeEnabled(SumoXMLAttr key) const {
1655
switch (key) {
1656
case SUMO_ATTR_TLTYPE:
1657
case SUMO_ATTR_TLLAYOUT:
1658
case SUMO_ATTR_TLID:
1659
return myNBNode->isTLControlled();
1660
case SUMO_ATTR_KEEP_CLEAR: {
1661
// check if at least there is an incoming connection
1662
for (const auto& incomingEdge : myGNEIncomingEdges) {
1663
if (incomingEdge->getGNEConnections().size() > 0) {
1664
return true;
1665
}
1666
}
1667
return false;
1668
}
1669
case GNE_ATTR_IS_ROUNDABOUT:
1670
return false;
1671
default:
1672
return true;
1673
}
1674
}
1675
1676
1677
bool
1678
GNEJunction::isAttributeComputed(SumoXMLAttr key) const {
1679
switch (key) {
1680
case SUMO_ATTR_SHAPE:
1681
return !myNBNode->hasCustomShape();
1682
default:
1683
return false;
1684
}
1685
}
1686
1687
1688
void
1689
GNEJunction::setResponsible(bool newVal) {
1690
myAmResponsible = newVal;
1691
}
1692
1693
// ===========================================================================
1694
// private
1695
// ===========================================================================
1696
1697
bool
1698
GNEJunction::drawAsBubble(const GUIVisualizationSettings& s, const double junctionShapeArea) const {
1699
const auto& editModes = myNet->getViewNet()->getEditModes();
1700
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
1701
// check conditions
1702
if (junctionShapeArea < 4) {
1703
// force draw if this junction is a candidate
1704
if (mySourceCandidate || myTargetCandidate || mySpecialCandidate ||
1705
myPossibleCandidate || myConflictedCandidate) {
1706
return true;
1707
}
1708
// force draw if we're in person/container plan mode
1709
if (editModes.isCurrentSupermodeDemand() &&
1710
((editModes.demandEditMode == DemandEditMode::DEMAND_PERSON) ||
1711
(editModes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) ||
1712
(editModes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) ||
1713
(editModes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN))) {
1714
return true;
1715
}
1716
// force draw if we're inspecting a vehicle that start or ends in a junction
1717
if (inspectedElements.isInspectingSingleElement()) {
1718
// check if starts or ends in this junction
1719
if ((inspectedElements.getFirstAC()->hasAttribute(SUMO_ATTR_FROM_JUNCTION) &&
1720
(inspectedElements.getFirstAC()->getAttribute(SUMO_ATTR_FROM_JUNCTION) == getID())) ||
1721
(inspectedElements.getFirstAC()->hasAttribute(SUMO_ATTR_TO_JUNCTION) &&
1722
(inspectedElements.getFirstAC()->getAttribute(SUMO_ATTR_TO_JUNCTION) == getID()))) {
1723
return true;
1724
}
1725
}
1726
}
1727
if (!s.drawJunctionShape) {
1728
// don't draw bubble if it was disabled in GUIVisualizationSettings
1729
return false;
1730
}
1731
if (myNet->getViewNet()->showJunctionAsBubbles()) {
1732
// force draw bubbles if we enabled option in checkbox of viewNet
1733
return true;
1734
}
1735
if (junctionShapeArea >= 4) {
1736
// don't draw if shape area is greater than 4
1737
return false;
1738
}
1739
if (!editModes.isCurrentSupermodeNetwork()) {
1740
// only draw bubbles in network mode
1741
return false;
1742
}
1743
return true;
1744
}
1745
1746
1747
void
1748
GNEJunction::drawJunctionAsBubble(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
1749
const double exaggeration) const {
1750
// calculate bubble radius
1751
const double bubbleRadius = s.neteditSizeSettings.junctionBubbleRadius * exaggeration;
1752
// set bubble color
1753
const RGBColor bubbleColor = setColor(s, true);
1754
// push matrix
1755
GLHelper::pushMatrix();
1756
// set color
1757
GLHelper::setColor(bubbleColor);
1758
// move matrix junction center
1759
glTranslated(myNBNode->getPosition().x(), myNBNode->getPosition().y(), 1.5);
1760
// draw filled circle
1761
GLHelper::drawFilledCircleDetailled(d, bubbleRadius);
1762
// pop matrix
1763
GLHelper::popMatrix();
1764
}
1765
1766
1767
void
1768
GNEJunction::drawJunctionAsShape(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const double exaggeration) const {
1769
// first check drawing conditions
1770
if (s.drawJunctionShape && (myNBNode->getShape().size() > 0)) {
1771
// set shape color
1772
const RGBColor junctionShapeColor = setColor(s, false);
1773
// set color
1774
GLHelper::setColor(junctionShapeColor);
1775
// adjust shape to exaggeration (check)
1776
if ((exaggeration > 1 || myExaggeration > 1) && exaggeration != myExaggeration) {
1777
myExaggeration = exaggeration;
1778
myTesselation.setShape(myNBNode->getShape());
1779
myTesselation.getShapeRef().closePolygon();
1780
myTesselation.getShapeRef().scaleRelative(exaggeration);
1781
myTesselation.myTesselation.clear();
1782
}
1783
// check if draw tesselation or or polygon
1784
if (d <= GUIVisualizationSettings::Detail::DrawPolygonTesselation) {
1785
// draw shape with high detail
1786
myTesselation.drawTesselation(myTesselation.getShape());
1787
} else {
1788
// draw shape
1789
GLHelper::drawFilledPoly(myNBNode->getShape(), true);
1790
}
1791
// draw shape points only in Network supermode
1792
if (myShapeEdited && myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() &&
1793
s.drawMovingGeometryPoint(exaggeration, s.neteditSizeSettings.junctionGeometryPointRadius)) {
1794
// set color
1795
const RGBColor darkerColor = junctionShapeColor.changedBrightness(-32);
1796
// calculate geometry
1797
GUIGeometry junctionGeometry;
1798
// obtain junction Shape
1799
PositionVector junctionOpenShape = myNBNode->getShape();
1800
// adjust shape to exaggeration
1801
if (exaggeration > 1) {
1802
junctionOpenShape.scaleRelative(exaggeration);
1803
}
1804
// update geometry
1805
junctionGeometry.updateGeometry(junctionOpenShape);
1806
// set color
1807
GLHelper::setColor(darkerColor);
1808
// draw shape
1809
GUIGeometry::drawGeometry(d, junctionGeometry, s.neteditSizeSettings.junctionGeometryPointRadius * 0.5);
1810
// draw geometry points
1811
GUIGeometry::drawGeometryPoints(d, junctionOpenShape, darkerColor,
1812
s.neteditSizeSettings.junctionGeometryPointRadius, exaggeration,
1813
myNet->getViewNet()->getNetworkViewOptions().editingElevation());
1814
}
1815
}
1816
}
1817
1818
1819
void
1820
GNEJunction::drawJunctionCenter(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d) const {
1821
if (myNet->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveOnlyJunctionCenter()) {
1822
// push matrix
1823
GLHelper::pushMatrix();
1824
// set color
1825
GLHelper::setColor(setColor(s, true).changedBrightness(-20));
1826
// move matrix junction center
1827
glTranslated(myNBNode->getPosition().x(), myNBNode->getPosition().y(), 1.7);
1828
// draw filled circle
1829
GLHelper::drawFilledCircleDetailled(d, s.neteditSizeSettings.edgeGeometryPointRadius);
1830
// pop matrix
1831
GLHelper::popMatrix();
1832
}
1833
}
1834
1835
1836
void
1837
GNEJunction::drawTLSIcon(const GUIVisualizationSettings& s) const {
1838
// draw TLS icon if isn't being drawn for selecting
1839
if (myNBNode->isTLControlled() && !myAmTLSSelected &&
1840
(myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_TLS)) {
1841
GLHelper::pushMatrix();
1842
const Position pos = myNBNode->getPosition();
1843
glTranslated(pos.x(), pos.y(), 2.2);
1844
glColor3d(1, 1, 1);
1845
const double halfWidth = 32 / s.scale;
1846
const double halfHeight = 64 / s.scale;
1847
GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(GUITexture::TLS), -halfWidth, -halfHeight, halfWidth, halfHeight);
1848
GLHelper::popMatrix();
1849
}
1850
}
1851
1852
1853
void
1854
GNEJunction::drawElevation(const GUIVisualizationSettings& s) const {
1855
// check if draw elevation
1856
if (myNet->getViewNet()->getNetworkViewOptions().editingElevation()) {
1857
GLHelper::pushMatrix();
1858
// Translate to center of junction
1859
glTranslated(myNBNode->getPosition().x(), myNBNode->getPosition().y(), 0.1);
1860
// draw Z value
1861
GLHelper::drawText(toString(myNBNode->getPosition().z()), Position(), GLO_MAX - 5, s.junctionID.scaledSize(s.scale), s.junctionID.color);
1862
GLHelper::popMatrix();
1863
}
1864
}
1865
1866
1867
void
1868
GNEJunction::drawJunctionName(const GUIVisualizationSettings& s) const {
1869
drawName(myNBNode->getPosition(), s.scale, s.junctionID);
1870
if (s.junctionName.show(this) && myNBNode->getName() != "") {
1871
GLHelper::drawTextSettings(s.junctionName, myNBNode->getName(), myNBNode->getPosition(), s.scale, s.angle);
1872
}
1873
}
1874
1875
1876
void
1877
GNEJunction::drawJunctionChildren(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d) const {
1878
// check if draw junction elements
1879
if (s.drawForViewObjectsHandler || (d <= GUIVisualizationSettings::Detail::JunctionElement)) {
1880
// draw crossings
1881
for (const auto& crossing : myGNECrossings) {
1882
crossing->drawGL(s);
1883
}
1884
// draw walking areas
1885
for (const auto& walkingArea : myGNEWalkingAreas) {
1886
walkingArea->drawGL(s);
1887
}
1888
// draw internalLanes
1889
for (const auto& internalLanes : myInternalLanes) {
1890
internalLanes->drawGL(s);
1891
}
1892
// draw connections
1893
for (const auto& incomingEdge : myGNEIncomingEdges) {
1894
for (const auto& connection : incomingEdge->getGNEConnections()) {
1895
connection->drawGL(s);
1896
}
1897
}
1898
// draw child demand elements
1899
for (const auto& demandElement : getChildDemandElements()) {
1900
demandElement->drawGL(s);
1901
}
1902
// draw child demand elements
1903
for (const auto& demandElement : getChildDemandElements()) {
1904
demandElement->drawGL(s);
1905
}
1906
// draw path additional elements
1907
myNet->getNetworkPathManager()->drawJunctionPathElements(s, this);
1908
myNet->getDemandPathManager()->drawJunctionPathElements(s, this);
1909
myNet->getDataPathManager()->drawJunctionPathElements(s, this);
1910
}
1911
}
1912
1913
1914
void
1915
GNEJunction::calculateJunctioncontour(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
1916
const double exaggeration, const bool drawBubble) const {
1917
// if we're selecting using a boundary, first don't calculate contour bt check if edge boundary is within selection boundary
1918
if (gViewObjectsHandler.selectingUsingRectangle() && gViewObjectsHandler.getSelectionTriangle().isBoundaryFullWithin(myJunctionBoundary)) {
1919
// simply add object in ViewObjectsHandler with full boundary
1920
gViewObjectsHandler.selectObject(this, getType(), false, nullptr);
1921
} else {
1922
// always calculate for shape
1923
myNetworkElementContour.calculateContourClosedShape(s, d, this, myNBNode->getShape(), getType(), exaggeration, this);
1924
// check if calculate contour for bubble
1925
if (drawBubble) {
1926
myCircleContour.calculateContourCircleShape(s, d, this, myNBNode->getPosition(), s.neteditSizeSettings.junctionBubbleRadius, getType(), exaggeration, this);
1927
}
1928
// check geometry points if we're editing shape
1929
if (myShapeEdited) {
1930
myNetworkElementContour.calculateContourAllGeometryPoints(s, d, this, myNBNode->getShape(), getType(), s.neteditSizeSettings.junctionGeometryPointRadius,
1931
exaggeration, true);
1932
}
1933
}
1934
}
1935
1936
1937
void
1938
GNEJunction::setAttribute(SumoXMLAttr key, const std::string& value) {
1939
switch (key) {
1940
case SUMO_ATTR_KEEP_CLEAR: {
1941
throw InvalidArgument(toString(key) + " cannot be edited");
1942
}
1943
case SUMO_ATTR_ID: {
1944
myNet->getAttributeCarriers()->updateJunctionID(this, value);
1945
break;
1946
}
1947
case SUMO_ATTR_TYPE: {
1948
SumoXMLNodeType type = SUMOXMLDefinitions::NodeTypes.get(value);
1949
if (myNBNode->getType() == SumoXMLNodeType::PRIORITY
1950
&& (type == SumoXMLNodeType::RIGHT_BEFORE_LEFT || type == SumoXMLNodeType::LEFT_BEFORE_RIGHT)) {
1951
myNet->getNetBuilder()->getEdgeCont().removeRoundabout(myNBNode);
1952
}
1953
myNBNode->reinit(myNBNode->getPosition(), type);
1954
break;
1955
}
1956
case SUMO_ATTR_POSITION: {
1957
// set new position in NBNode updating edge boundaries
1958
moveJunctionGeometry(parse<Position>(value), true);
1959
// mark this connections and all of the junction's Neighbours as deprecated
1960
markConnectionsDeprecated(true);
1961
// update centering boundary and grid
1962
if (myGNEIncomingEdges.size() + myGNEOutgoingEdges.size() > 0) {
1963
updateCenteringBoundary(false);
1964
} else {
1965
updateCenteringBoundary(true);
1966
}
1967
break;
1968
}
1969
case GNE_ATTR_MODIFICATION_STATUS:
1970
if (myLogicStatus == FEATURE_GUESSED && value != FEATURE_GUESSED) {
1971
// clear guessed connections. previous connections will be restored
1972
myNBNode->invalidateIncomingConnections();
1973
// Clear GNEConnections of incoming edges
1974
for (const auto& i : myGNEIncomingEdges) {
1975
i->clearGNEConnections();
1976
}
1977
}
1978
myLogicStatus = value;
1979
break;
1980
case SUMO_ATTR_SHAPE: {
1981
// set new shape (without updating grid)
1982
myNBNode->setCustomShape(parse<PositionVector>(value));
1983
// mark this connections and all of the junction's neighbors as deprecated
1984
markConnectionsDeprecated(true);
1985
// update centering boundary and grid
1986
updateCenteringBoundary(true);
1987
break;
1988
}
1989
case SUMO_ATTR_RADIUS: {
1990
if (value.empty() || (value == "default")) {
1991
myNBNode->setRadius(-1);
1992
} else {
1993
myNBNode->setRadius(parse<double>(value));
1994
}
1995
break;
1996
}
1997
case SUMO_ATTR_TLTYPE: {
1998
// we need to make a copy of controlling TLS (because original will be updated)
1999
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
2000
for (const auto& TLS : copyOfTls) {
2001
TLS->setType(SUMOXMLDefinitions::TrafficLightTypes.get(value));
2002
}
2003
break;
2004
}
2005
case SUMO_ATTR_TLLAYOUT:
2006
// should not be triggered (handled via GNEChange_TLS)
2007
break;
2008
case SUMO_ATTR_RIGHT_OF_WAY:
2009
myNBNode->setRightOfWay(SUMOXMLDefinitions::RightOfWayValues.get(value));
2010
break;
2011
case SUMO_ATTR_FRINGE:
2012
myNBNode->setFringeType(SUMOXMLDefinitions::FringeTypeValues.get(value));
2013
break;
2014
case SUMO_ATTR_ROUNDABOUT:
2015
myNBNode->setRoundaboutType(SUMOXMLDefinitions::RoundaboutTypeValues.get(value));
2016
break;
2017
case SUMO_ATTR_NAME:
2018
myNBNode->setName(value);
2019
break;
2020
default:
2021
setCommonAttribute(key, value);
2022
break;
2023
}
2024
// invalidate demand path calculator
2025
myNet->getDemandPathManager()->getPathCalculator()->invalidatePathCalculator();
2026
}
2027
2028
2029
double
2030
GNEJunction::getColorValue(const GUIVisualizationSettings& /* s */, int activeScheme) const {
2031
switch (activeScheme) {
2032
case 0:
2033
if (myColorForMissingConnections) {
2034
return 3;
2035
} else {
2036
return 0;
2037
}
2038
case 1:
2039
return isAttributeCarrierSelected();
2040
case 2:
2041
switch (myNBNode->getType()) {
2042
case SumoXMLNodeType::TRAFFIC_LIGHT:
2043
return 0;
2044
case SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION:
2045
return 1;
2046
case SumoXMLNodeType::PRIORITY:
2047
return 2;
2048
case SumoXMLNodeType::PRIORITY_STOP:
2049
return 3;
2050
case SumoXMLNodeType::RIGHT_BEFORE_LEFT:
2051
return 4;
2052
case SumoXMLNodeType::ALLWAY_STOP:
2053
return 5;
2054
case SumoXMLNodeType::DISTRICT:
2055
return 6;
2056
case SumoXMLNodeType::NOJUNCTION:
2057
return 7;
2058
case SumoXMLNodeType::DEAD_END:
2059
case SumoXMLNodeType::DEAD_END_DEPRECATED:
2060
return 8;
2061
case SumoXMLNodeType::UNKNOWN:
2062
return 8; // may happen before first network computation
2063
case SumoXMLNodeType::INTERNAL:
2064
assert(false);
2065
return 8;
2066
case SumoXMLNodeType::RAIL_SIGNAL:
2067
return 9;
2068
case SumoXMLNodeType::ZIPPER:
2069
return 10;
2070
case SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED:
2071
return 11;
2072
case SumoXMLNodeType::RAIL_CROSSING:
2073
return 12;
2074
case SumoXMLNodeType::LEFT_BEFORE_RIGHT:
2075
return 13;
2076
default:
2077
assert(false);
2078
return 0;
2079
}
2080
case 3:
2081
return myNBNode->getPosition().z();
2082
default:
2083
assert(false);
2084
return 0;
2085
}
2086
}
2087
2088
void
2089
GNEJunction::checkMissingConnections() {
2090
for (auto edge : myGNEIncomingEdges) {
2091
if (edge->getGNEConnections().size() > 0) {
2092
myColorForMissingConnections = false;
2093
return;
2094
}
2095
}
2096
// no connections. Use normal color for border edges and cul-de-sac
2097
if (myGNEIncomingEdges.size() == 0 || myGNEOutgoingEdges.size() == 0) {
2098
myColorForMissingConnections = false;
2099
return;
2100
} else if (myGNEIncomingEdges.size() == 1 && myGNEOutgoingEdges.size() == 1) {
2101
NBEdge* in = myGNEIncomingEdges[0]->getNBEdge();
2102
NBEdge* out = myGNEOutgoingEdges[0]->getNBEdge();
2103
if (in->isTurningDirectionAt(out)) {
2104
myColorForMissingConnections = false;
2105
return;
2106
}
2107
}
2108
myColorForMissingConnections = true;
2109
}
2110
2111
2112
void
2113
GNEJunction::moveJunctionGeometry(const Position& pos, const bool updateEdgeBoundaries) {
2114
// reinit NBNode
2115
myNBNode->reinit(pos, myNBNode->getType());
2116
// declare three sets with all affected GNEJunctions, GNEEdges and GNEConnections
2117
std::set<GNEJunction*> affectedJunctions;
2118
std::set<GNEEdge*> affectedEdges;
2119
// Iterate over GNEEdges
2120
for (const auto& edge : getChildEdges()) {
2121
// Add source and destination junctions
2122
affectedJunctions.insert(edge->getFromJunction());
2123
affectedJunctions.insert(edge->getToJunction());
2124
// Obtain neighbors of Junction source
2125
for (const auto& junctionSourceEdge : edge->getFromJunction()->getChildEdges()) {
2126
affectedEdges.insert(junctionSourceEdge);
2127
}
2128
// Obtain neighbors of Junction destination
2129
for (const auto& junctionDestinationEdge : edge->getToJunction()->getChildEdges()) {
2130
affectedEdges.insert(junctionDestinationEdge);
2131
}
2132
}
2133
// reset walking areas of affected edges
2134
for (const auto& affectedJunction : affectedJunctions) {
2135
affectedJunction->clearWalkingAreas();
2136
}
2137
// Iterate over affected Edges
2138
for (const auto& affectedEdge : affectedEdges) {
2139
// update edge boundaries
2140
if (updateEdgeBoundaries) {
2141
affectedEdge->updateCenteringBoundary(true);
2142
}
2143
// Update edge geometry
2144
affectedEdge->updateGeometry();
2145
}
2146
}
2147
2148
2149
RGBColor
2150
GNEJunction::setColor(const GUIVisualizationSettings& s, bool bubble) const {
2151
// get active scheme
2152
const int scheme = s.junctionColorer.getActive();
2153
// first check if we're editing shape
2154
if (myShapeEdited) {
2155
return s.colorSettings.editShapeColor;
2156
}
2157
// set default color
2158
RGBColor color = s.junctionColorer.getScheme().getColor(getColorValue(s, scheme));
2159
// set special bubble color
2160
if (bubble && (scheme == 0) && !myColorForMissingConnections) {
2161
color = s.junctionColorer.getScheme().getColor(1);
2162
}
2163
// override with special colors (unless the color scheme is based on selection)
2164
if (drawUsingSelectColor() && scheme != 1) {
2165
color = s.colorSettings.selectionColor;
2166
}
2167
// overwrite color if we're in data mode
2168
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeData()) {
2169
color = s.junctionColorer.getScheme().getColor(6);
2170
}
2171
// special color for source candidate junction
2172
if (mySourceCandidate) {
2173
color = s.candidateColorSettings.source;
2174
}
2175
// special color for target candidate junction
2176
if (myTargetCandidate) {
2177
color = s.candidateColorSettings.target;
2178
}
2179
// special color for special candidate junction
2180
if (mySpecialCandidate) {
2181
color = s.candidateColorSettings.special;
2182
}
2183
// special color for possible candidate junction
2184
if (myPossibleCandidate) {
2185
color = s.candidateColorSettings.possible;
2186
}
2187
// special color for conflicted candidate junction
2188
if (myConflictedCandidate) {
2189
color = s.candidateColorSettings.conflict;
2190
}
2191
// return color
2192
return color;
2193
}
2194
2195
2196
void
2197
GNEJunction::addTrafficLight(NBTrafficLightDefinition* tlDef, bool forceInsert) {
2198
NBTrafficLightLogicCont& tlCont = myNet->getTLLogicCont();
2199
tlCont.insert(tlDef, forceInsert); // may return false for tlDef which controls multiple junctions
2200
tlDef->addNode(myNBNode);
2201
}
2202
2203
2204
void
2205
GNEJunction::removeTrafficLight(NBTrafficLightDefinition* tlDef) {
2206
NBTrafficLightLogicCont& tlCont = myNet->getTLLogicCont();
2207
if (tlDef->getNodes().size() == 1) {
2208
tlCont.extract(tlDef);
2209
}
2210
myNBNode->removeTrafficLight(tlDef);
2211
}
2212
2213
2214
/****************************************************************************/
2215
2216