Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/network/GNEJunction.cpp
185790 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file 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_NAME:
1368
return myNBNode->getName();
1369
default:
1370
return getCommonAttribute(key);
1371
}
1372
}
1373
1374
1375
double
1376
GNEJunction::getAttributeDouble(SumoXMLAttr key) const {
1377
return getCommonAttributeDouble(key);
1378
}
1379
1380
1381
Position
1382
GNEJunction::getAttributePosition(SumoXMLAttr key) const {
1383
return getCommonAttributePosition(key);
1384
}
1385
1386
1387
PositionVector
1388
GNEJunction::getAttributePositionVector(SumoXMLAttr key) const {
1389
switch (key) {
1390
case SUMO_ATTR_SHAPE:
1391
return myNBNode->getShape();
1392
default:
1393
return getCommonAttributePositionVector(key);
1394
}
1395
}
1396
1397
1398
void
1399
GNEJunction::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
1400
if (value == getAttribute(key)) {
1401
return; //avoid needless changes, later logic relies on the fact that attributes have changed
1402
}
1403
switch (key) {
1404
case SUMO_ATTR_ID:
1405
case GNE_ATTR_MODIFICATION_STATUS:
1406
case SUMO_ATTR_SHAPE:
1407
case SUMO_ATTR_RADIUS:
1408
case SUMO_ATTR_RIGHT_OF_WAY:
1409
case SUMO_ATTR_FRINGE:
1410
case SUMO_ATTR_NAME:
1411
GNEChange_Attribute::changeAttribute(this, key, value, undoList, true);
1412
break;
1413
case SUMO_ATTR_POSITION: {
1414
const GNEJunction* junctionToMerge = nullptr;
1415
bool alreadyAsked = false;
1416
// parse position
1417
Position newPosition = GNEAttributeCarrier::parse<Position>(value);
1418
// check if caculate new position based in edges
1419
if (newPosition == Position::INVALID) {
1420
Boundary b;
1421
// set new position of adjacent edges
1422
for (const auto& edge : myGNEIncomingEdges) {
1423
b.add(edge->getNBEdge()->getGeometry().back());
1424
}
1425
for (const auto& edge : myGNEOutgoingEdges) {
1426
b.add(edge->getNBEdge()->getGeometry().front());
1427
}
1428
newPosition = b.getCenter();
1429
}
1430
// retrieve all junctions placed in this position
1431
myNet->getViewNet()->updateObjectsInPosition(newPosition);
1432
for (const auto& junction : myNet->getViewNet()->getViewObjectsSelector().getJunctions()) {
1433
// check distance position
1434
if ((junctionToMerge == nullptr) && (junction != this) &&
1435
(junction->getPositionInView().distanceTo2D(newPosition) < myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.junctionBubbleRadius) &&
1436
myNet->getViewNet()->askMergeJunctions(this, junction, alreadyAsked)) {
1437
junctionToMerge = junction;
1438
}
1439
}
1440
// also check the merging junctions located during drawGL
1441
for (const auto& junction : myNet->getViewNet()->getViewObjectsSelector().getMergingJunctions()) {
1442
// check distance position
1443
if ((junctionToMerge == nullptr) && (junction != this) && myNet->getViewNet()->askMergeJunctions(this, junction, alreadyAsked)) {
1444
junctionToMerge = junction;
1445
}
1446
}
1447
// if we merge the junction, this junction will be removed, therefore we don't have to change the position
1448
if (junctionToMerge) {
1449
myNet->mergeJunctions(this, junctionToMerge, undoList);
1450
} else {
1451
// change Keep Clear attribute in all connections
1452
undoList->begin(this, TL("change junction position"));
1453
// obtain NBNode position
1454
const Position orig = myNBNode->getPosition();
1455
// change junction position
1456
GNEChange_Attribute::changeAttribute(this, key, toString(newPosition), undoList, true);
1457
// calculate delta using new position
1458
const bool moveOnlyCenter = myNet->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveOnlyJunctionCenter();
1459
const Position delta = myNBNode->getPosition() - (moveOnlyCenter ? myNBNode->getPosition() : orig);
1460
// set new position of adjacent edges
1461
for (const auto& edge : myGNEIncomingEdges) {
1462
const Position newEnd = edge->getNBEdge()->getGeometry().back() + delta;
1463
GNEChange_Attribute::changeAttribute(edge, GNE_ATTR_SHAPE_END, toString(newEnd), undoList, true);
1464
}
1465
for (const auto& edge : myGNEOutgoingEdges) {
1466
const Position newStart = edge->getNBEdge()->getGeometry().front() + delta;
1467
GNEChange_Attribute::changeAttribute(edge, GNE_ATTR_SHAPE_START, toString(newStart), undoList, true);
1468
}
1469
undoList->end();
1470
}
1471
break;
1472
}
1473
case SUMO_ATTR_KEEP_CLEAR:
1474
// change Keep Clear attribute in all connections
1475
undoList->begin(this, TL("change keepClear for whole junction"));
1476
for (const auto& incomingEdge : myGNEIncomingEdges) {
1477
for (const auto& junction : incomingEdge->getGNEConnections()) {
1478
GNEChange_Attribute::changeAttribute(junction, key, value, undoList, true);
1479
}
1480
}
1481
undoList->end();
1482
break;
1483
case SUMO_ATTR_TYPE: {
1484
// set junction type
1485
setJunctionType(value, undoList);
1486
break;
1487
}
1488
case SUMO_ATTR_TLTYPE: {
1489
undoList->begin(this, "change " + getTagStr() + " tl-type");
1490
// make a copy because we will modify the original
1491
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
1492
for (const auto& TLS : copyOfTls) {
1493
NBLoadedSUMOTLDef* oldLoaded = dynamic_cast<NBLoadedSUMOTLDef*>(TLS);
1494
if (oldLoaded != nullptr) {
1495
NBTrafficLightDefinition* newDef = nullptr;
1496
if (value == toString(TrafficLightType::NEMA) || oldLoaded->getType() == TrafficLightType::NEMA) {
1497
// rebuild the program because the old and new ones are incompatible
1498
newDef = new NBOwnTLDef(oldLoaded->getID(), oldLoaded->getOffset(), TrafficLightType::NEMA);
1499
newDef->setProgramID(oldLoaded->getProgramID());
1500
} else {
1501
NBLoadedSUMOTLDef* newLDef = new NBLoadedSUMOTLDef(*oldLoaded, *oldLoaded->getLogic());
1502
newLDef->guessMinMaxDuration(); // minDur and maxDur are never written for a static tls
1503
newDef = newLDef;
1504
}
1505
std::vector<NBNode*> nodes = TLS->getNodes();
1506
for (const auto& node : nodes) {
1507
GNEJunction* junction = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1508
undoList->add(new GNEChange_TLS(junction, TLS, false), true);
1509
undoList->add(new GNEChange_TLS(junction, newDef, true), true);
1510
}
1511
}
1512
}
1513
GNEChange_Attribute::changeAttribute(this, key, value, undoList, true);
1514
undoList->end();
1515
break;
1516
}
1517
case SUMO_ATTR_TLLAYOUT: {
1518
undoList->begin(this, "change " + getTagStr() + " tlLayout");
1519
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
1520
for (const auto& oldTLS : copyOfTls) {
1521
std::vector<NBNode*> copyOfNodes = oldTLS->getNodes();
1522
NBOwnTLDef* newTLS = new NBOwnTLDef(oldTLS->getID(), oldTLS->getOffset(), oldTLS->getType());
1523
newTLS->setLayout(SUMOXMLDefinitions::TrafficLightLayouts.get(value));
1524
newTLS->setProgramID(oldTLS->getProgramID());
1525
for (const auto& node : copyOfNodes) {
1526
GNEJunction* oldJunction = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1527
undoList->add(new GNEChange_TLS(oldJunction, oldTLS, false), true);
1528
}
1529
for (const auto& node : copyOfNodes) {
1530
GNEJunction* oldJunction = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1531
undoList->add(new GNEChange_TLS(oldJunction, newTLS, true), true);
1532
}
1533
}
1534
undoList->end();
1535
break;
1536
}
1537
case SUMO_ATTR_TLID: {
1538
undoList->begin(this, "change " + toString(SUMO_TAG_TRAFFIC_LIGHT) + " id");
1539
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
1540
assert(copyOfTls.size() > 0);
1541
NBTrafficLightDefinition* currentTLS = *copyOfTls.begin();
1542
NBTrafficLightDefinition* currentTLSCopy = nullptr;
1543
const bool currentIsSingle = currentTLS->getNodes().size() == 1;
1544
const bool currentIsLoaded = dynamic_cast<NBLoadedSUMOTLDef*>(currentTLS) != nullptr;
1545
if (currentIsLoaded) {
1546
currentTLSCopy = new NBLoadedSUMOTLDef(*currentTLS,
1547
*dynamic_cast<NBLoadedSUMOTLDef*>(currentTLS)->getLogic());
1548
}
1549
// remove from previous tls
1550
for (const auto& TLS : copyOfTls) {
1551
undoList->add(new GNEChange_TLS(this, TLS, false), true);
1552
}
1553
NBTrafficLightLogicCont& tlCont = myNet->getTLLogicCont();
1554
// programs to which the current node shall be added
1555
const std::map<std::string, NBTrafficLightDefinition*> programs = tlCont.getPrograms(value);
1556
if (programs.size() > 0) {
1557
for (const auto& TLSProgram : programs) {
1558
NBTrafficLightDefinition* oldTLS = TLSProgram.second;
1559
if (dynamic_cast<NBOwnTLDef*>(oldTLS) != nullptr) {
1560
undoList->add(new GNEChange_TLS(this, oldTLS, true), true);
1561
} else {
1562
// delete and re-create the definition because the loaded phases are now invalid
1563
if (dynamic_cast<NBLoadedSUMOTLDef*>(oldTLS) != nullptr &&
1564
dynamic_cast<NBLoadedSUMOTLDef*>(oldTLS)->usingSignalGroups()) {
1565
// keep the old program and add all-red state for the added links
1566
NBLoadedSUMOTLDef* newTLSJoined = new NBLoadedSUMOTLDef(*oldTLS, *dynamic_cast<NBLoadedSUMOTLDef*>(oldTLS)->getLogic());
1567
newTLSJoined->joinLogic(currentTLSCopy);
1568
undoList->add(new GNEChange_TLS(this, newTLSJoined, true, true), true);
1569
} else {
1570
undoList->add(new GNEChange_TLS(this, nullptr, true, false, value), true);
1571
}
1572
NBTrafficLightDefinition* newTLS = *myNBNode->getControllingTLS().begin();
1573
// switch from old to new definition
1574
std::vector<NBNode*> copyOfNodes = oldTLS->getNodes();
1575
for (const auto& node : copyOfNodes) {
1576
GNEJunction* oldJunction = myNet->getAttributeCarriers()->retrieveJunction(node->getID());
1577
undoList->add(new GNEChange_TLS(oldJunction, oldTLS, false), true);
1578
undoList->add(new GNEChange_TLS(oldJunction, newTLS, true), true);
1579
}
1580
}
1581
}
1582
} else {
1583
if (currentIsSingle && currentIsLoaded) {
1584
// rename the traffic light but keep everything else
1585
NBTrafficLightLogic* renamedLogic = dynamic_cast<NBLoadedSUMOTLDef*>(currentTLSCopy)->getLogic();
1586
renamedLogic->setID(value);
1587
NBLoadedSUMOTLDef* renamedTLS = new NBLoadedSUMOTLDef(*currentTLSCopy, *renamedLogic);
1588
renamedTLS->setID(value);
1589
undoList->add(new GNEChange_TLS(this, renamedTLS, true, true), true);
1590
} else {
1591
// create new traffic light
1592
undoList->add(new GNEChange_TLS(this, nullptr, true, false, value), true);
1593
}
1594
}
1595
delete currentTLSCopy;
1596
undoList->end();
1597
break;
1598
}
1599
default:
1600
setCommonAttribute(key, value, undoList);
1601
break;
1602
}
1603
}
1604
1605
1606
bool
1607
GNEJunction::isValid(SumoXMLAttr key, const std::string& value) {
1608
switch (key) {
1609
case SUMO_ATTR_ID:
1610
return SUMOXMLDefinitions::isValidNetID(value) && (myNet->getAttributeCarriers()->retrieveJunction(value, false) == nullptr);
1611
case SUMO_ATTR_TYPE:
1612
return SUMOXMLDefinitions::NodeTypes.hasString(value);
1613
case SUMO_ATTR_POSITION:
1614
if (value.empty()) {
1615
return (myGNEIncomingEdges.size() + myGNEOutgoingEdges.size()) > 0;
1616
} else {
1617
return canParse<Position>(value);
1618
}
1619
case SUMO_ATTR_SHAPE:
1620
// empty shapes are allowed
1621
return canParse<PositionVector>(value);
1622
case SUMO_ATTR_RADIUS:
1623
if (value.empty() || (value == "default")) {
1624
return true;
1625
} else {
1626
return canParse<double>(value) && ((parse<double>(value) >= 0) || (parse<double>(value) == -1));
1627
}
1628
case SUMO_ATTR_TLTYPE:
1629
return myNBNode->isTLControlled() && SUMOXMLDefinitions::TrafficLightTypes.hasString(value);
1630
case SUMO_ATTR_TLLAYOUT:
1631
return myNBNode->isTLControlled() && SUMOXMLDefinitions::TrafficLightLayouts.hasString(value);
1632
case SUMO_ATTR_TLID:
1633
return myNBNode->isTLControlled() && (value != "");
1634
case SUMO_ATTR_KEEP_CLEAR:
1635
return canParse<bool>(value);
1636
case SUMO_ATTR_RIGHT_OF_WAY:
1637
return SUMOXMLDefinitions::RightOfWayValues.hasString(value);
1638
case SUMO_ATTR_FRINGE:
1639
return SUMOXMLDefinitions::FringeTypeValues.hasString(value);
1640
case SUMO_ATTR_NAME:
1641
return true;
1642
default:
1643
return isCommonAttributeValid(key, value);
1644
}
1645
}
1646
1647
1648
bool
1649
GNEJunction::isAttributeEnabled(SumoXMLAttr key) const {
1650
switch (key) {
1651
case SUMO_ATTR_TLTYPE:
1652
case SUMO_ATTR_TLLAYOUT:
1653
case SUMO_ATTR_TLID:
1654
return myNBNode->isTLControlled();
1655
case SUMO_ATTR_KEEP_CLEAR: {
1656
// check if at least there is an incoming connection
1657
for (const auto& incomingEdge : myGNEIncomingEdges) {
1658
if (incomingEdge->getGNEConnections().size() > 0) {
1659
return true;
1660
}
1661
}
1662
return false;
1663
}
1664
case GNE_ATTR_IS_ROUNDABOUT:
1665
return false;
1666
default:
1667
return true;
1668
}
1669
}
1670
1671
1672
bool
1673
GNEJunction::isAttributeComputed(SumoXMLAttr key) const {
1674
switch (key) {
1675
case SUMO_ATTR_SHAPE:
1676
return !myNBNode->hasCustomShape();
1677
default:
1678
return false;
1679
}
1680
}
1681
1682
1683
void
1684
GNEJunction::setResponsible(bool newVal) {
1685
myAmResponsible = newVal;
1686
}
1687
1688
// ===========================================================================
1689
// private
1690
// ===========================================================================
1691
1692
bool
1693
GNEJunction::drawAsBubble(const GUIVisualizationSettings& s, const double junctionShapeArea) const {
1694
const auto& editModes = myNet->getViewNet()->getEditModes();
1695
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
1696
// check conditions
1697
if (junctionShapeArea < 4) {
1698
// force draw if this junction is a candidate
1699
if (mySourceCandidate || myTargetCandidate || mySpecialCandidate ||
1700
myPossibleCandidate || myConflictedCandidate) {
1701
return true;
1702
}
1703
// force draw if we're in person/container plan mode
1704
if (editModes.isCurrentSupermodeDemand() &&
1705
((editModes.demandEditMode == DemandEditMode::DEMAND_PERSON) ||
1706
(editModes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) ||
1707
(editModes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) ||
1708
(editModes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN))) {
1709
return true;
1710
}
1711
// force draw if we're inspecting a vehicle that start or ends in a junction
1712
if (inspectedElements.isInspectingSingleElement()) {
1713
// check if starts or ends in this junction
1714
if ((inspectedElements.getFirstAC()->hasAttribute(SUMO_ATTR_FROM_JUNCTION) &&
1715
(inspectedElements.getFirstAC()->getAttribute(SUMO_ATTR_FROM_JUNCTION) == getID())) ||
1716
(inspectedElements.getFirstAC()->hasAttribute(SUMO_ATTR_TO_JUNCTION) &&
1717
(inspectedElements.getFirstAC()->getAttribute(SUMO_ATTR_TO_JUNCTION) == getID()))) {
1718
return true;
1719
}
1720
}
1721
}
1722
if (!s.drawJunctionShape) {
1723
// don't draw bubble if it was disabled in GUIVisualizationSettings
1724
return false;
1725
}
1726
if (myNet->getViewNet()->showJunctionAsBubbles()) {
1727
// force draw bubbles if we enabled option in checkbox of viewNet
1728
return true;
1729
}
1730
if (junctionShapeArea >= 4) {
1731
// don't draw if shape area is greater than 4
1732
return false;
1733
}
1734
if (!editModes.isCurrentSupermodeNetwork()) {
1735
// only draw bubbles in network mode
1736
return false;
1737
}
1738
return true;
1739
}
1740
1741
1742
void
1743
GNEJunction::drawJunctionAsBubble(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
1744
const double exaggeration) const {
1745
// calculate bubble radius
1746
const double bubbleRadius = s.neteditSizeSettings.junctionBubbleRadius * exaggeration;
1747
// set bubble color
1748
const RGBColor bubbleColor = setColor(s, true);
1749
// push matrix
1750
GLHelper::pushMatrix();
1751
// set color
1752
GLHelper::setColor(bubbleColor);
1753
// move matrix junction center
1754
glTranslated(myNBNode->getPosition().x(), myNBNode->getPosition().y(), 1.5);
1755
// draw filled circle
1756
GLHelper::drawFilledCircleDetailled(d, bubbleRadius);
1757
// pop matrix
1758
GLHelper::popMatrix();
1759
}
1760
1761
1762
void
1763
GNEJunction::drawJunctionAsShape(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const double exaggeration) const {
1764
// first check drawing conditions
1765
if (s.drawJunctionShape && (myNBNode->getShape().size() > 0)) {
1766
// set shape color
1767
const RGBColor junctionShapeColor = setColor(s, false);
1768
// set color
1769
GLHelper::setColor(junctionShapeColor);
1770
// adjust shape to exaggeration (check)
1771
if ((exaggeration > 1 || myExaggeration > 1) && exaggeration != myExaggeration) {
1772
myExaggeration = exaggeration;
1773
myTesselation.setShape(myNBNode->getShape());
1774
myTesselation.getShapeRef().closePolygon();
1775
myTesselation.getShapeRef().scaleRelative(exaggeration);
1776
myTesselation.myTesselation.clear();
1777
}
1778
// check if draw tesselation or or polygon
1779
if (d <= GUIVisualizationSettings::Detail::DrawPolygonTesselation) {
1780
// draw shape with high detail
1781
myTesselation.drawTesselation(myTesselation.getShape());
1782
} else {
1783
// draw shape
1784
GLHelper::drawFilledPoly(myNBNode->getShape(), true);
1785
}
1786
// draw shape points only in Network supermode
1787
if (myShapeEdited && myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() &&
1788
s.drawMovingGeometryPoint(exaggeration, s.neteditSizeSettings.junctionGeometryPointRadius)) {
1789
// set color
1790
const RGBColor darkerColor = junctionShapeColor.changedBrightness(-32);
1791
// calculate geometry
1792
GUIGeometry junctionGeometry;
1793
// obtain junction Shape
1794
PositionVector junctionOpenShape = myNBNode->getShape();
1795
// adjust shape to exaggeration
1796
if (exaggeration > 1) {
1797
junctionOpenShape.scaleRelative(exaggeration);
1798
}
1799
// update geometry
1800
junctionGeometry.updateGeometry(junctionOpenShape);
1801
// set color
1802
GLHelper::setColor(darkerColor);
1803
// draw shape
1804
GUIGeometry::drawGeometry(d, junctionGeometry, s.neteditSizeSettings.junctionGeometryPointRadius * 0.5);
1805
// draw geometry points
1806
GUIGeometry::drawGeometryPoints(d, junctionOpenShape, darkerColor,
1807
s.neteditSizeSettings.junctionGeometryPointRadius, exaggeration,
1808
myNet->getViewNet()->getNetworkViewOptions().editingElevation());
1809
}
1810
}
1811
}
1812
1813
1814
void
1815
GNEJunction::drawJunctionCenter(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d) const {
1816
if (myNet->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveOnlyJunctionCenter()) {
1817
// push matrix
1818
GLHelper::pushMatrix();
1819
// set color
1820
GLHelper::setColor(setColor(s, true).changedBrightness(-20));
1821
// move matrix junction center
1822
glTranslated(myNBNode->getPosition().x(), myNBNode->getPosition().y(), 1.7);
1823
// draw filled circle
1824
GLHelper::drawFilledCircleDetailled(d, s.neteditSizeSettings.edgeGeometryPointRadius);
1825
// pop matrix
1826
GLHelper::popMatrix();
1827
}
1828
}
1829
1830
1831
void
1832
GNEJunction::drawTLSIcon(const GUIVisualizationSettings& s) const {
1833
// draw TLS icon if isn't being drawn for selecting
1834
if (myNBNode->isTLControlled() && !myAmTLSSelected &&
1835
(myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_TLS)) {
1836
GLHelper::pushMatrix();
1837
const Position pos = myNBNode->getPosition();
1838
glTranslated(pos.x(), pos.y(), 2.2);
1839
glColor3d(1, 1, 1);
1840
const double halfWidth = 32 / s.scale;
1841
const double halfHeight = 64 / s.scale;
1842
GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(GUITexture::TLS), -halfWidth, -halfHeight, halfWidth, halfHeight);
1843
GLHelper::popMatrix();
1844
}
1845
}
1846
1847
1848
void
1849
GNEJunction::drawElevation(const GUIVisualizationSettings& s) const {
1850
// check if draw elevation
1851
if (myNet->getViewNet()->getNetworkViewOptions().editingElevation()) {
1852
GLHelper::pushMatrix();
1853
// Translate to center of junction
1854
glTranslated(myNBNode->getPosition().x(), myNBNode->getPosition().y(), 0.1);
1855
// draw Z value
1856
GLHelper::drawText(toString(myNBNode->getPosition().z()), Position(), GLO_MAX - 5, s.junctionID.scaledSize(s.scale), s.junctionID.color);
1857
GLHelper::popMatrix();
1858
}
1859
}
1860
1861
1862
void
1863
GNEJunction::drawJunctionName(const GUIVisualizationSettings& s) const {
1864
drawName(myNBNode->getPosition(), s.scale, s.junctionID);
1865
if (s.junctionName.show(this) && myNBNode->getName() != "") {
1866
GLHelper::drawTextSettings(s.junctionName, myNBNode->getName(), myNBNode->getPosition(), s.scale, s.angle);
1867
}
1868
}
1869
1870
1871
void
1872
GNEJunction::drawJunctionChildren(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d) const {
1873
// check if draw junction elements
1874
if (s.drawForViewObjectsHandler || (d <= GUIVisualizationSettings::Detail::JunctionElement)) {
1875
// draw crossings
1876
for (const auto& crossing : myGNECrossings) {
1877
crossing->drawGL(s);
1878
}
1879
// draw walking areas
1880
for (const auto& walkingArea : myGNEWalkingAreas) {
1881
walkingArea->drawGL(s);
1882
}
1883
// draw internalLanes
1884
for (const auto& internalLanes : myInternalLanes) {
1885
internalLanes->drawGL(s);
1886
}
1887
// draw connections
1888
for (const auto& incomingEdge : myGNEIncomingEdges) {
1889
for (const auto& connection : incomingEdge->getGNEConnections()) {
1890
connection->drawGL(s);
1891
}
1892
}
1893
// draw child demand elements
1894
for (const auto& demandElement : getChildDemandElements()) {
1895
demandElement->drawGL(s);
1896
}
1897
// draw child demand elements
1898
for (const auto& demandElement : getChildDemandElements()) {
1899
demandElement->drawGL(s);
1900
}
1901
// draw path additional elements
1902
myNet->getNetworkPathManager()->drawJunctionPathElements(s, this);
1903
myNet->getDemandPathManager()->drawJunctionPathElements(s, this);
1904
myNet->getDataPathManager()->drawJunctionPathElements(s, this);
1905
}
1906
}
1907
1908
1909
void
1910
GNEJunction::calculateJunctioncontour(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
1911
const double exaggeration, const bool drawBubble) const {
1912
// if we're selecting using a boundary, first don't calculate contour bt check if edge boundary is within selection boundary
1913
if (gViewObjectsHandler.selectingUsingRectangle() && gViewObjectsHandler.getSelectionTriangle().isBoundaryFullWithin(myJunctionBoundary)) {
1914
// simply add object in ViewObjectsHandler with full boundary
1915
gViewObjectsHandler.selectObject(this, getType(), false, nullptr);
1916
} else {
1917
// always calculate for shape
1918
myNetworkElementContour.calculateContourClosedShape(s, d, this, myNBNode->getShape(), getType(), exaggeration, this);
1919
// check if calculate contour for bubble
1920
if (drawBubble) {
1921
myCircleContour.calculateContourCircleShape(s, d, this, myNBNode->getPosition(), s.neteditSizeSettings.junctionBubbleRadius, getType(), exaggeration, this);
1922
}
1923
// check geometry points if we're editing shape
1924
if (myShapeEdited) {
1925
myNetworkElementContour.calculateContourAllGeometryPoints(s, d, this, myNBNode->getShape(), getType(), s.neteditSizeSettings.junctionGeometryPointRadius,
1926
exaggeration, true);
1927
}
1928
}
1929
}
1930
1931
1932
void
1933
GNEJunction::setAttribute(SumoXMLAttr key, const std::string& value) {
1934
switch (key) {
1935
case SUMO_ATTR_KEEP_CLEAR: {
1936
throw InvalidArgument(toString(key) + " cannot be edited");
1937
}
1938
case SUMO_ATTR_ID: {
1939
myNet->getAttributeCarriers()->updateJunctionID(this, value);
1940
break;
1941
}
1942
case SUMO_ATTR_TYPE: {
1943
SumoXMLNodeType type = SUMOXMLDefinitions::NodeTypes.get(value);
1944
if (myNBNode->getType() == SumoXMLNodeType::PRIORITY
1945
&& (type == SumoXMLNodeType::RIGHT_BEFORE_LEFT || type == SumoXMLNodeType::LEFT_BEFORE_RIGHT)) {
1946
myNet->getNetBuilder()->getEdgeCont().removeRoundabout(myNBNode);
1947
}
1948
myNBNode->reinit(myNBNode->getPosition(), type);
1949
break;
1950
}
1951
case SUMO_ATTR_POSITION: {
1952
// set new position in NBNode updating edge boundaries
1953
moveJunctionGeometry(parse<Position>(value), true);
1954
// mark this connections and all of the junction's Neighbours as deprecated
1955
markConnectionsDeprecated(true);
1956
// update centering boundary and grid
1957
if (myGNEIncomingEdges.size() + myGNEOutgoingEdges.size() > 0) {
1958
updateCenteringBoundary(false);
1959
} else {
1960
updateCenteringBoundary(true);
1961
}
1962
break;
1963
}
1964
case GNE_ATTR_MODIFICATION_STATUS:
1965
if (myLogicStatus == FEATURE_GUESSED && value != FEATURE_GUESSED) {
1966
// clear guessed connections. previous connections will be restored
1967
myNBNode->invalidateIncomingConnections();
1968
// Clear GNEConnections of incoming edges
1969
for (const auto& i : myGNEIncomingEdges) {
1970
i->clearGNEConnections();
1971
}
1972
}
1973
myLogicStatus = value;
1974
break;
1975
case SUMO_ATTR_SHAPE: {
1976
// set new shape (without updating grid)
1977
myNBNode->setCustomShape(parse<PositionVector>(value));
1978
// mark this connections and all of the junction's neighbors as deprecated
1979
markConnectionsDeprecated(true);
1980
// update centering boundary and grid
1981
updateCenteringBoundary(true);
1982
break;
1983
}
1984
case SUMO_ATTR_RADIUS: {
1985
if (value.empty() || (value == "default")) {
1986
myNBNode->setRadius(-1);
1987
} else {
1988
myNBNode->setRadius(parse<double>(value));
1989
}
1990
break;
1991
}
1992
case SUMO_ATTR_TLTYPE: {
1993
// we need to make a copy of controlling TLS (because original will be updated)
1994
const std::set<NBTrafficLightDefinition*> copyOfTls = myNBNode->getControllingTLS();
1995
for (const auto& TLS : copyOfTls) {
1996
TLS->setType(SUMOXMLDefinitions::TrafficLightTypes.get(value));
1997
}
1998
break;
1999
}
2000
case SUMO_ATTR_TLLAYOUT:
2001
// should not be triggered (handled via GNEChange_TLS)
2002
break;
2003
case SUMO_ATTR_RIGHT_OF_WAY:
2004
myNBNode->setRightOfWay(SUMOXMLDefinitions::RightOfWayValues.get(value));
2005
break;
2006
case SUMO_ATTR_FRINGE:
2007
myNBNode->setFringeType(SUMOXMLDefinitions::FringeTypeValues.get(value));
2008
break;
2009
case SUMO_ATTR_NAME:
2010
myNBNode->setName(value);
2011
break;
2012
default:
2013
setCommonAttribute(key, value);
2014
break;
2015
}
2016
// invalidate demand path calculator
2017
myNet->getDemandPathManager()->getPathCalculator()->invalidatePathCalculator();
2018
}
2019
2020
2021
double
2022
GNEJunction::getColorValue(const GUIVisualizationSettings& /* s */, int activeScheme) const {
2023
switch (activeScheme) {
2024
case 0:
2025
if (myColorForMissingConnections) {
2026
return 3;
2027
} else {
2028
return 0;
2029
}
2030
case 1:
2031
return isAttributeCarrierSelected();
2032
case 2:
2033
switch (myNBNode->getType()) {
2034
case SumoXMLNodeType::TRAFFIC_LIGHT:
2035
return 0;
2036
case SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION:
2037
return 1;
2038
case SumoXMLNodeType::PRIORITY:
2039
return 2;
2040
case SumoXMLNodeType::PRIORITY_STOP:
2041
return 3;
2042
case SumoXMLNodeType::RIGHT_BEFORE_LEFT:
2043
return 4;
2044
case SumoXMLNodeType::ALLWAY_STOP:
2045
return 5;
2046
case SumoXMLNodeType::DISTRICT:
2047
return 6;
2048
case SumoXMLNodeType::NOJUNCTION:
2049
return 7;
2050
case SumoXMLNodeType::DEAD_END:
2051
case SumoXMLNodeType::DEAD_END_DEPRECATED:
2052
return 8;
2053
case SumoXMLNodeType::UNKNOWN:
2054
return 8; // may happen before first network computation
2055
case SumoXMLNodeType::INTERNAL:
2056
assert(false);
2057
return 8;
2058
case SumoXMLNodeType::RAIL_SIGNAL:
2059
return 9;
2060
case SumoXMLNodeType::ZIPPER:
2061
return 10;
2062
case SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED:
2063
return 11;
2064
case SumoXMLNodeType::RAIL_CROSSING:
2065
return 12;
2066
case SumoXMLNodeType::LEFT_BEFORE_RIGHT:
2067
return 13;
2068
default:
2069
assert(false);
2070
return 0;
2071
}
2072
case 3:
2073
return myNBNode->getPosition().z();
2074
default:
2075
assert(false);
2076
return 0;
2077
}
2078
}
2079
2080
void
2081
GNEJunction::checkMissingConnections() {
2082
for (auto edge : myGNEIncomingEdges) {
2083
if (edge->getGNEConnections().size() > 0) {
2084
myColorForMissingConnections = false;
2085
return;
2086
}
2087
}
2088
// no connections. Use normal color for border edges and cul-de-sac
2089
if (myGNEIncomingEdges.size() == 0 || myGNEOutgoingEdges.size() == 0) {
2090
myColorForMissingConnections = false;
2091
return;
2092
} else if (myGNEIncomingEdges.size() == 1 && myGNEOutgoingEdges.size() == 1) {
2093
NBEdge* in = myGNEIncomingEdges[0]->getNBEdge();
2094
NBEdge* out = myGNEOutgoingEdges[0]->getNBEdge();
2095
if (in->isTurningDirectionAt(out)) {
2096
myColorForMissingConnections = false;
2097
return;
2098
}
2099
}
2100
myColorForMissingConnections = true;
2101
}
2102
2103
2104
void
2105
GNEJunction::moveJunctionGeometry(const Position& pos, const bool updateEdgeBoundaries) {
2106
// reinit NBNode
2107
myNBNode->reinit(pos, myNBNode->getType());
2108
// declare three sets with all affected GNEJunctions, GNEEdges and GNEConnections
2109
std::set<GNEJunction*> affectedJunctions;
2110
std::set<GNEEdge*> affectedEdges;
2111
// Iterate over GNEEdges
2112
for (const auto& edge : getChildEdges()) {
2113
// Add source and destination junctions
2114
affectedJunctions.insert(edge->getFromJunction());
2115
affectedJunctions.insert(edge->getToJunction());
2116
// Obtain neighbors of Junction source
2117
for (const auto& junctionSourceEdge : edge->getFromJunction()->getChildEdges()) {
2118
affectedEdges.insert(junctionSourceEdge);
2119
}
2120
// Obtain neighbors of Junction destination
2121
for (const auto& junctionDestinationEdge : edge->getToJunction()->getChildEdges()) {
2122
affectedEdges.insert(junctionDestinationEdge);
2123
}
2124
}
2125
// reset walking areas of affected edges
2126
for (const auto& affectedJunction : affectedJunctions) {
2127
affectedJunction->clearWalkingAreas();
2128
}
2129
// Iterate over affected Edges
2130
for (const auto& affectedEdge : affectedEdges) {
2131
// update edge boundaries
2132
if (updateEdgeBoundaries) {
2133
affectedEdge->updateCenteringBoundary(true);
2134
}
2135
// Update edge geometry
2136
affectedEdge->updateGeometry();
2137
}
2138
}
2139
2140
2141
RGBColor
2142
GNEJunction::setColor(const GUIVisualizationSettings& s, bool bubble) const {
2143
// get active scheme
2144
const int scheme = s.junctionColorer.getActive();
2145
// first check if we're editing shape
2146
if (myShapeEdited) {
2147
return s.colorSettings.editShapeColor;
2148
}
2149
// set default color
2150
RGBColor color = s.junctionColorer.getScheme().getColor(getColorValue(s, scheme));
2151
// set special bubble color
2152
if (bubble && (scheme == 0) && !myColorForMissingConnections) {
2153
color = s.junctionColorer.getScheme().getColor(1);
2154
}
2155
// override with special colors (unless the color scheme is based on selection)
2156
if (drawUsingSelectColor() && scheme != 1) {
2157
color = s.colorSettings.selectionColor;
2158
}
2159
// overwrite color if we're in data mode
2160
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeData()) {
2161
color = s.junctionColorer.getScheme().getColor(6);
2162
}
2163
// special color for source candidate junction
2164
if (mySourceCandidate) {
2165
color = s.candidateColorSettings.source;
2166
}
2167
// special color for target candidate junction
2168
if (myTargetCandidate) {
2169
color = s.candidateColorSettings.target;
2170
}
2171
// special color for special candidate junction
2172
if (mySpecialCandidate) {
2173
color = s.candidateColorSettings.special;
2174
}
2175
// special color for possible candidate junction
2176
if (myPossibleCandidate) {
2177
color = s.candidateColorSettings.possible;
2178
}
2179
// special color for conflicted candidate junction
2180
if (myConflictedCandidate) {
2181
color = s.candidateColorSettings.conflict;
2182
}
2183
// return color
2184
return color;
2185
}
2186
2187
2188
void
2189
GNEJunction::addTrafficLight(NBTrafficLightDefinition* tlDef, bool forceInsert) {
2190
NBTrafficLightLogicCont& tlCont = myNet->getTLLogicCont();
2191
tlCont.insert(tlDef, forceInsert); // may return false for tlDef which controls multiple junctions
2192
tlDef->addNode(myNBNode);
2193
}
2194
2195
2196
void
2197
GNEJunction::removeTrafficLight(NBTrafficLightDefinition* tlDef) {
2198
NBTrafficLightLogicCont& tlCont = myNet->getTLLogicCont();
2199
if (tlDef->getNodes().size() == 1) {
2200
tlCont.extract(tlDef);
2201
}
2202
myNBNode->removeTrafficLight(tlDef);
2203
}
2204
2205
2206
/****************************************************************************/
2207
2208