Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/network/GNEEdge.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 GNEEdge.cpp
15
/// @author Jakob Erdmann
16
/// @date Feb 2011
17
///
18
// A road/street connecting two junctions (netedit-version, adapted from GUIEdge)
19
// Basically a container for an NBEdge with drawing and editing capabilities
20
/****************************************************************************/
21
22
#include <netedit/changes/GNEChange_Attribute.h>
23
#include <netedit/changes/GNEChange_Lane.h>
24
#include <netedit/elements/additional/GNERouteProbe.h>
25
#include <netedit/elements/demand/GNEPlanParents.h>
26
#include <netedit/elements/demand/GNERoute.h>
27
#include <netedit/elements/moving/GNEMoveElementEdge.h>
28
#include <netedit/frames/common/GNEDeleteFrame.h>
29
#include <netedit/frames/common/GNEInspectorFrame.h>
30
#include <netedit/frames/common/GNEMoveFrame.h>
31
#include <netedit/frames/data/GNEEdgeDataFrame.h>
32
#include <netedit/frames/data/GNEEdgeRelDataFrame.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/GNEElementTree.h>
39
#include <netedit/frames/GNEViewObjectSelector.h>
40
#include <netedit/frames/network/GNEAdditionalFrame.h>
41
#include <netedit/GNENet.h>
42
#include <netedit/GNETagPropertiesDatabase.h>
43
#include <netedit/GNEUndoList.h>
44
#include <netedit/GNEViewParent.h>
45
#include <utils/gui/div/GLHelper.h>
46
#include <utils/options/OptionsCont.h>
47
48
#include "GNEConnection.h"
49
#include "GNECrossing.h"
50
#include "GNEEdge.h"
51
#include "GNEEdgeType.h"
52
#include "GNELaneType.h"
53
#include "GNEEdgeTemplate.h"
54
#include "GNELaneTemplate.h"
55
56
// ===========================================================================
57
// defines
58
// ===========================================================================
59
60
//#define DEBUG_SMOOTH_GEOM
61
//#define DEBUGCOND(obj) (true)
62
#define VEHICLE_GAP 1
63
#define ENDPOINT_TOLERANCE 2
64
65
// ===========================================================================
66
// static
67
// ===========================================================================
68
69
const double GNEEdge::SNAP_RADIUS = SUMO_const_halfLaneWidth;
70
const double GNEEdge::SNAP_RADIUS_SQUARED = (SUMO_const_halfLaneWidth* SUMO_const_halfLaneWidth);
71
72
// ===========================================================================
73
// members methods
74
// ===========================================================================
75
76
GNEEdge::GNEEdge(GNENet* net, NBEdge* nbe, bool wasSplit, bool loaded):
77
GNENetworkElement(net, nbe->getID(), SUMO_TAG_EDGE),
78
myNBEdge(nbe),
79
myAmResponsible(false),
80
myWasSplit(wasSplit),
81
myConnectionStatus(loaded ? FEATURE_LOADED : FEATURE_GUESSED),
82
myMoveElementEdge(new GNEMoveElementEdge(this)),
83
myUpdateGeometry(true) {
84
// set parents
85
setParents<GNEJunction*>({
86
net->getAttributeCarriers()->retrieveJunction(nbe->getFromNode()->getID()),
87
net->getAttributeCarriers()->retrieveJunction(nbe->getToNode()->getID())
88
});
89
// Create lanes
90
for (int i = 0; i < myNBEdge->getNumLanes(); i++) {
91
auto lane = new GNELane(this, i);
92
lane->incRef("GNEEdge::GNEEdge");
93
addChildElement(lane);
94
}
95
// update Lane geometries
96
for (const auto& lane : getChildLanes()) {
97
lane->updateGeometry();
98
}
99
// update centering boundary without updating grid
100
updateCenteringBoundary(false);
101
}
102
103
104
GNEEdge::~GNEEdge() {
105
// Delete references to this edge in lanes
106
for (const auto& lane : getChildLanes()) {
107
lane->decRef("GNEEdge::~GNEEdge");
108
if (lane->unreferenced()) {
109
// check if remove it from Attribute Carriers
110
if (myNet->getAttributeCarriers()->getLanes().count(lane) > 0) {
111
myNet->getAttributeCarriers()->deleteLane(lane);
112
}
113
delete lane;
114
}
115
}
116
// delete references to this edge in connections
117
for (const auto& connection : myGNEConnections) {
118
connection->decRef("GNEEdge::~GNEEdge");
119
if (connection->unreferenced()) {
120
// check if remove it from Attribute Carriers
121
if (myNet->getAttributeCarriers()->getConnections().count(connection) > 0) {
122
myNet->getAttributeCarriers()->deleteConnection(connection);
123
}
124
delete connection;
125
}
126
}
127
if (myAmResponsible) {
128
delete myNBEdge;
129
}
130
}
131
132
133
GNEMoveElement*
134
GNEEdge::getMoveElement() const {
135
return myMoveElementEdge;
136
}
137
138
139
Parameterised*
140
GNEEdge::getParameters() {
141
return myNBEdge;
142
}
143
144
145
const Parameterised*
146
GNEEdge::getParameters() const {
147
return myNBEdge;
148
}
149
150
151
bool
152
GNEEdge::isNetworkElementValid() const {
153
if (getFromJunction()->getNBNode()->getPosition() != getToJunction()->getNBNode()->getPosition()) {
154
return true;
155
} else {
156
return false;
157
}
158
}
159
160
161
std::string
162
GNEEdge::getNetworkElementProblem() const {
163
return TLF("Parent junctions are in the same position: %, %",
164
toString(getFromJunction()->getNBNode()->getPosition().x()),
165
toString(getFromJunction()->getNBNode()->getPosition().y()));
166
}
167
168
169
void
170
GNEEdge::updateGeometry() {
171
// first check if myUpdateGeometry flag is enabled
172
if (myUpdateGeometry) {
173
// Update geometry of lanes
174
for (const auto& lane : getChildLanes()) {
175
lane->updateGeometry();
176
}
177
// Update geometry of connections
178
for (const auto& connection : myGNEConnections) {
179
connection->updateGeometry();
180
}
181
// Update geometry of additionals children vinculated to this edge
182
for (const auto& childAdditional : getChildAdditionals()) {
183
childAdditional->updateGeometry();
184
}
185
// Update geometry of additionals demand elements vinculated to this edge
186
for (const auto& childDemandElement : getChildDemandElements()) {
187
childDemandElement->updateGeometry();
188
}
189
// Update geometry of additionals generic datas vinculated to this edge
190
for (const auto& childGenericData : getChildGenericDatas()) {
191
childGenericData->updateGeometry();
192
}
193
// compute geometry of path elements elements vinculated with this edge (depending of showDemandElements)
194
if (myNet->getViewNet() && myNet->getViewNet()->getNetworkViewOptions().showDemandElements()) {
195
for (const auto& childAdditional : getChildAdditionals()) {
196
childAdditional->computePathElement();
197
}
198
for (const auto& childDemandElement : getChildDemandElements()) {
199
childDemandElement->computePathElement();
200
}
201
for (const auto& childGenericData : getChildGenericDatas()) {
202
childGenericData->computePathElement();
203
}
204
}
205
}
206
// update vehicle geometry
207
updateVehicleSpreadGeometries();
208
// update stack labels
209
updateVehicleStackLabels();
210
updatePersonStackLabels();
211
updateContainerStackLabels();
212
}
213
214
215
Position
216
GNEEdge::getPositionInView() const {
217
return getChildLanes().front()->getPositionInView();
218
}
219
220
221
bool
222
GNEEdge::checkDrawFromContour() const {
223
// get modes and viewParent (for code legibility)
224
const auto& modes = myNet->getViewNet()->getEditModes();
225
const auto& viewParent = myNet->getViewParent();
226
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
227
// continue depending of current status
228
if (inspectedElements.isInspectingSingleElement()) {
229
// check if starts in this edge
230
if (inspectedElements.getFirstAC()->getTagProperty()->vehicleEdges() &&
231
inspectedElements.getFirstAC()->hasAttribute(SUMO_ATTR_FROM) &&
232
(inspectedElements.getFirstAC()->getAttribute(SUMO_ATTR_FROM) == getID())) {
233
return true;
234
}
235
} else if (modes.isCurrentSupermodeDemand()) {
236
// get current GNEPlanCreator
237
GNEPlanCreator* planCreator = nullptr;
238
if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {
239
planCreator = viewParent->getPersonFrame()->getPlanCreator();
240
} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {
241
planCreator = viewParent->getPersonPlanFrame()->getPlanCreator();
242
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {
243
planCreator = viewParent->getContainerFrame()->getPlanCreator();
244
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {
245
planCreator = viewParent->getContainerPlanFrame()->getPlanCreator();
246
}
247
// continue depending of planCreator
248
if (planCreator) {
249
if (planCreator->getPlanParameteres().fromEdge == getID()) {
250
return true;
251
} else if ((planCreator->getPlanParameteres().consecutiveEdges.size() > 0) &&
252
(planCreator->getPlanParameteres().consecutiveEdges.front() == getID())) {
253
return true;
254
}
255
} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {
256
const auto& selectedEdges = viewParent->getVehicleFrame()->getPathCreator()->getSelectedEdges();
257
// check if this is the first selected edge
258
if ((selectedEdges.size() > 0) && (selectedEdges.front() == this)) {
259
return true;
260
}
261
}
262
} else if (modes.isCurrentSupermodeData()) {
263
// get TAZRelDataFrame
264
const auto& edgeRelDataFrame = viewParent->getEdgeRelDataFrame();
265
if (edgeRelDataFrame->shown()) {
266
// check first Edge
267
if (edgeRelDataFrame->getPathCreator()->getSelectedEdges().empty()) {
268
return false;
269
} else {
270
return edgeRelDataFrame->getPathCreator()->getSelectedEdges().front() == this;
271
}
272
}
273
}
274
// nothing to draw
275
return false;
276
}
277
278
279
bool
280
GNEEdge::checkDrawToContour() const {
281
// get modes and viewParent (for code legibility)
282
const auto& modes = myNet->getViewNet()->getEditModes();
283
const auto& viewParent = myNet->getViewParent();
284
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
285
// continue depending of current status
286
if (inspectedElements.isInspectingSingleElement()) {
287
// check if starts in this edge
288
if (inspectedElements.getFirstAC()->getTagProperty()->vehicleEdges() &&
289
inspectedElements.getFirstAC()->hasAttribute(SUMO_ATTR_TO) &&
290
(inspectedElements.getFirstAC()->getAttribute(SUMO_ATTR_TO) == getID())) {
291
return true;
292
}
293
} else if (modes.isCurrentSupermodeDemand()) {
294
// get current GNEPlanCreator
295
GNEPlanCreator* planCreator = nullptr;
296
if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {
297
planCreator = viewParent->getPersonFrame()->getPlanCreator();
298
} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {
299
planCreator = viewParent->getPersonPlanFrame()->getPlanCreator();
300
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {
301
planCreator = viewParent->getContainerFrame()->getPlanCreator();
302
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {
303
planCreator = viewParent->getContainerPlanFrame()->getPlanCreator();
304
}
305
// continue depending of planCreator
306
if (planCreator) {
307
if (planCreator->getPlanParameteres().toEdge == getID()) {
308
return true;
309
} else if ((planCreator->getPlanParameteres().consecutiveEdges.size() > 1) &&
310
(planCreator->getPlanParameteres().consecutiveEdges.back() == getID())) {
311
return true;
312
}
313
} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {
314
const auto& selectedEdges = viewParent->getVehicleFrame()->getPathCreator()->getSelectedEdges();
315
// check if this is the last selected edge
316
if ((selectedEdges.size() > 1) && (selectedEdges.back() == this)) {
317
return true;
318
}
319
}
320
} else if (modes.isCurrentSupermodeData()) {
321
// get TAZRelDataFrame
322
const auto& edgeRelDataFrame = viewParent->getEdgeRelDataFrame();
323
if (edgeRelDataFrame->shown()) {
324
// check last Edge
325
if (edgeRelDataFrame->getPathCreator()->getSelectedEdges().empty()) {
326
return false;
327
} else {
328
return edgeRelDataFrame->getPathCreator()->getSelectedEdges().back() == this;
329
}
330
}
331
}
332
// nothing to draw
333
return false;
334
}
335
336
337
bool
338
GNEEdge::checkDrawRelatedContour() const {
339
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
340
// continue depending of inspected elements
341
if (inspectedElements.isInspectingSingleElement() &&
342
inspectedElements.getFirstAC()->getTagProperty()->getTag() == SUMO_TAG_TAZ) {
343
// check if one of the sourceSink child is placed in this edge
344
for (const auto& sourceSink : getChildTAZSourceSinks()) {
345
if (sourceSink->getParentAdditionals().front() == inspectedElements.getFirstAC()) {
346
return true;
347
}
348
}
349
}
350
if (myNet->getViewNet()->getPopup()) {
351
return myNet->getViewNet()->getPopup()->getGLObject() == this;
352
}
353
return false;
354
}
355
356
357
bool
358
GNEEdge::checkDrawOverContour() const {
359
// get modes and viewParent (for code legibility)
360
const auto& modes = myNet->getViewNet()->getEditModes();
361
const auto& viewParent = myNet->getViewParent();
362
const auto& viewObjectsSelector = myNet->getViewNet()->getViewObjectsSelector();
363
// check if we're selecting edges in additional mode
364
if (modes.isCurrentSupermodeNetwork() && (modes.networkEditMode == NetworkEditMode::NETWORK_ADDITIONAL)) {
365
if (viewParent->getAdditionalFrame()->getViewObjetsSelector()->isNetworkElementSelected(this)) {
366
return true;
367
} else if (viewParent->getAdditionalFrame()->getViewObjetsSelector()->getTag() == myTagProperty->getTag()) {
368
return viewObjectsSelector.getEdgeFront() == this;
369
} else {
370
return false;
371
}
372
}
373
// check if this is the edge under cursor
374
if (viewObjectsSelector.getEdgeFront() != this) {
375
return false;
376
} else {
377
// continue depending of modes
378
if (modes.isCurrentSupermodeDemand()) {
379
// get current plan selector
380
GNEPlanSelector* planSelector = nullptr;
381
if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {
382
planSelector = viewParent->getPersonFrame()->getPlanSelector();
383
} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {
384
planSelector = viewParent->getPersonPlanFrame()->getPlanSelector();
385
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {
386
planSelector = viewParent->getContainerFrame()->getPlanSelector();
387
} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {
388
planSelector = viewParent->getContainerPlanFrame()->getPlanSelector();
389
}
390
// continue depending of plan selector
391
if (planSelector && planSelector->markEdges()) {
392
return (viewObjectsSelector.getAttributeCarrierFront()->getTagProperty()->getTag() == SUMO_TAG_LANE);
393
} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {
394
// get current vehicle template
395
const auto& vehicleTemplate = viewParent->getVehicleFrame()->getVehicleTagSelector()->getCurrentTemplateAC();
396
// check if vehicle can be placed over from-to TAZs
397
if (vehicleTemplate && vehicleTemplate->getTagProperty()->vehicleEdges()) {
398
return (viewObjectsSelector.getAttributeCarrierFront()->getTagProperty()->getTag() == SUMO_TAG_LANE);
399
}
400
}
401
} else if (modes.isCurrentSupermodeData()) {
402
// get frames
403
const auto& edgeDataFrame = viewParent->getEdgeDataFrame();
404
const auto& edgeRelDataFrame = viewParent->getEdgeRelDataFrame();
405
if (edgeDataFrame->shown()) {
406
return true;
407
} else if (edgeRelDataFrame->shown()) {
408
// check edges
409
if (edgeRelDataFrame->getPathCreator()->getSelectedEdges().empty()) {
410
return true;
411
} else if (edgeRelDataFrame->getPathCreator()->getSelectedEdges().size() == 2) {
412
return false;
413
} else if (edgeRelDataFrame->getPathCreator()->getSelectedEdges().front() == this) {
414
return false;
415
} else if (edgeRelDataFrame->getPathCreator()->getSelectedEdges().back() == this) {
416
return false;
417
} else {
418
return true;
419
}
420
}
421
422
}
423
// nothing to draw
424
return false;
425
}
426
}
427
428
429
bool
430
GNEEdge::checkDrawDeleteContour() const {
431
// first check if we're selecting edges or lanes
432
if (myNet->getViewNet()->checkSelectEdges()) {
433
// get edit modes
434
const auto& editModes = myNet->getViewNet()->getEditModes();
435
// check if we're in delete mode
436
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_DELETE)) {
437
// check lanes
438
for (const auto& lane : getChildLanes()) {
439
if (myNet->getViewNet()->checkOverLockedElement(lane, mySelected) &&
440
(myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == lane)) {
441
return true;
442
}
443
}
444
// check edge
445
if (myNet->getViewNet()->checkOverLockedElement(this, mySelected) &&
446
(myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this)) {
447
return true;
448
}
449
// nothing to draw
450
return false;
451
} else {
452
return false;
453
}
454
} else {
455
return false;
456
}
457
}
458
459
460
bool
461
GNEEdge::checkDrawDeleteContourSmall() const {
462
// get edit modes
463
const auto& editModes = myNet->getViewNet()->getEditModes();
464
// check if we're in delete mode
465
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_DELETE)) {
466
const auto junction = myNet->getViewNet()->getViewObjectsSelector().getJunctionFront();
467
if (junction == myNet->getViewNet()->getViewObjectsSelector().getAttributeCarrierFront()) {
468
return ((getFromJunction() == junction) || (getToJunction() == junction));
469
}
470
}
471
return false;
472
}
473
474
475
bool
476
GNEEdge::checkDrawSelectContour() const {
477
// first check if we're selecting edges or lanes
478
if (myNet->getViewNet()->checkSelectEdges()) {
479
// get edit modes
480
const auto& editModes = myNet->getViewNet()->getEditModes();
481
// check if we're in select mode
482
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_SELECT)) {
483
// check lanes
484
for (const auto& lane : getChildLanes()) {
485
if (myNet->getViewNet()->checkOverLockedElement(lane, mySelected) &&
486
(myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == lane)) {
487
return true;
488
}
489
}
490
// check edge
491
if (myNet->getViewNet()->checkOverLockedElement(this, mySelected) &&
492
(myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this)) {
493
return true;
494
}
495
// nothing to draw
496
return false;
497
} else {
498
return false;
499
}
500
} else {
501
return false;
502
}
503
}
504
505
506
bool
507
GNEEdge::checkDrawMoveContour() const {
508
// get edit modes
509
const auto& editModes = myNet->getViewNet()->getEditModes();
510
// get move element edge
511
const auto moveElementEdge = dynamic_cast<GNEMoveElementEdge*>(myNet->getViewNet()->getMoveSingleElementValues().getMovedElement());
512
// check if we're in move mode
513
if ((!myNet->getViewNet()->isCurrentlyMovingElements() || (moveElementEdge && (moveElementEdge->getEdge() == this))) && editModes.isCurrentSupermodeNetwork() &&
514
(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE)) {
515
// check if we're editing this network element
516
const GNENetworkElement* editedNetworkElement = myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement();
517
if (editedNetworkElement) {
518
if (editedNetworkElement == this) {
519
return true;
520
} else {
521
// check lanes
522
for (const auto& lane : getChildLanes()) {
523
if (editedNetworkElement == lane) {
524
return true;
525
}
526
}
527
}
528
} else {
529
// check lanes
530
for (const auto& lane : getChildLanes()) {
531
if (myNet->getViewNet()->checkOverLockedElement(lane, mySelected) &&
532
(myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == lane)) {
533
return true;
534
}
535
}
536
// check edge
537
if (myNet->getViewNet()->checkOverLockedElement(this, mySelected) &&
538
(myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this)) {
539
return true;
540
}
541
}
542
// nothing to draw
543
return false;
544
} else {
545
return false;
546
}
547
}
548
549
550
bool
551
GNEEdge::hasCustomEndPoints() const {
552
if (myNBEdge->getGeometry().front().distanceSquaredTo2D(getFromJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE) {
553
return true;
554
} else if (myNBEdge->getGeometry().back().distanceSquaredTo2D(getToJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE) {
555
return true;
556
} else {
557
return false;
558
}
559
}
560
561
562
bool
563
GNEEdge::clickedOverShapeStart(const Position& pos) const {
564
// get geometry point radius
565
const double geometryPointRadius = getGeometryPointRadius();
566
if (myNBEdge->getGeometry().front().distanceSquaredTo2D(getFromJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE) {
567
return (myNBEdge->getGeometry().front().distanceSquaredTo2D(pos) < (geometryPointRadius * geometryPointRadius));
568
} else {
569
return false;
570
}
571
}
572
573
574
bool
575
GNEEdge::clickedOverShapeEnd(const Position& pos) const {
576
// get geometry point radius
577
const double geometryPointRadius = getGeometryPointRadius();
578
if (myNBEdge->getGeometry().back().distanceSquaredTo2D(getToJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE) {
579
return (myNBEdge->getGeometry().back().distanceSquaredTo2D(pos) < (geometryPointRadius * geometryPointRadius));
580
} else {
581
return false;
582
}
583
}
584
585
586
bool
587
GNEEdge::clickedOverGeometryPoint(const Position& pos) const {
588
// get geometry point radius
589
const auto geometryPointRadius = getGeometryPointRadius();
590
// first check inner geometry
591
const PositionVector innenShape = myNBEdge->getInnerGeometry();
592
// iterate over geometry point
593
for (const auto& geometryPoint : innenShape) {
594
if (geometryPoint.distanceSquaredTo2D(pos) < (geometryPointRadius * geometryPointRadius)) {
595
return true;
596
}
597
}
598
// check start and end shapes
599
if (clickedOverShapeStart(pos) || clickedOverShapeEnd(pos)) {
600
return true;
601
} else {
602
return false;
603
}
604
}
605
606
607
void
608
GNEEdge::updateJunctionPosition(GNEJunction* junction, const Position& origPos) {
609
Position delta = junction->getNBNode()->getPosition() - origPos;
610
PositionVector geom = myNBEdge->getGeometry();
611
// geometry endpoint need not equal junction position hence we modify it with delta
612
if (junction == getFromJunction()) {
613
geom[0].add(delta);
614
} else {
615
geom[-1].add(delta);
616
}
617
setGeometry(geom, false);
618
}
619
620
621
double
622
GNEEdge::getExaggeration(const GUIVisualizationSettings& s) const {
623
return s.addSize.getExaggeration(s, this);
624
}
625
626
627
Boundary
628
GNEEdge::getCenteringBoundary() const {
629
return myEdgeBoundary;
630
}
631
632
633
void
634
GNEEdge::updateCenteringBoundary(const bool updateGrid) {
635
// Remove object from net
636
if (updateGrid) {
637
myNet->removeGLObjectFromGrid(this);
638
}
639
// first add edge boundary
640
myEdgeBoundary = myNBEdge->getGeometry().getBoxBoundary();
641
// add lane boundaries
642
for (const auto& lane : getChildLanes()) {
643
const auto laneBoundary = lane->getCenteringBoundary();
644
if (laneBoundary.isInitialised()) {
645
myEdgeBoundary.add(laneBoundary);
646
// add additional and demand boundaries
647
for (const auto& additional : lane->getChildAdditionals()) {
648
const auto additionalBoundary = additional->getCenteringBoundary();
649
if (additionalBoundary.isInitialised()) {
650
myEdgeBoundary.add(additional->getCenteringBoundary());
651
}
652
}
653
}
654
}
655
// add additional and demand boundaries
656
for (const auto& additional : getChildAdditionals()) {
657
const auto additionalBoundary = additional->getCenteringBoundary();
658
if (additionalBoundary.isInitialised()) {
659
myEdgeBoundary.add(additionalBoundary);
660
}
661
}
662
// add junction positions
663
myEdgeBoundary.add(getFromJunction()->getCenteringBoundary());
664
myEdgeBoundary.add(getToJunction()->getCenteringBoundary());
665
// grow boundary
666
myEdgeBoundary.grow(5);
667
// add object into net
668
if (updateGrid) {
669
myNet->addGLObjectIntoGrid(this);
670
}
671
}
672
673
674
const std::string
675
GNEEdge::getOptionalName() const {
676
return myNBEdge->getStreetName();
677
}
678
679
680
GUIGLObjectPopupMenu*
681
GNEEdge::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
682
// if we call this function, that's mean that we're clicked over a edge geometry point, then
683
// open the popup dialog of the lane[0] (back)
684
return getChildLanes().back()->getPopUpMenu(app, parent);
685
}
686
687
688
std::vector<GNEEdge*>
689
GNEEdge::getOppositeEdges() const {
690
return myNet->getAttributeCarriers()->retrieveEdges(getToJunction(), getFromJunction());
691
}
692
693
694
void
695
GNEEdge::drawGL(const GUIVisualizationSettings& s) const {
696
// check drawing boundary selection and size boundary
697
if (checkDrawingBoundarySelection() && s.checkDrawEdge(myEdgeBoundary)) {
698
// draw boundary
699
GLHelper::drawBoundary(s, getCenteringBoundary());
700
// get detail level from the first lane
701
const auto d = getChildLanes().front()->getDrawingConstants()->getDetail();
702
// calculate layer
703
double layer = GLO_EDGE;
704
if (myDrawInFront) {
705
layer = GLO_FRONTELEMENT;
706
} else if (getChildLanes().front()->getLaneShape().length2D() <= (s.neteditSizeSettings.junctionBubbleRadius * 2)) {
707
layer = GLO_JUNCTION + 1.8;
708
}
709
// check if draw details
710
if (!s.drawForViewObjectsHandler) {
711
// draw geometry points
712
drawEdgeGeometryPoints(s, d, layer);
713
// draw edge shape (a red line only visible if lane shape is strange)
714
drawEdgeShape(s, d, layer);
715
// draw edge stopOffset
716
drawLaneStopOffset(s, d, layer);
717
// draw edge name
718
drawEdgeName(s);
719
// draw lock icon
720
GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), getPositionInView(), 1);
721
// draw dotted contour
722
myNetworkElementContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);
723
}
724
// calculate edge contour (always before children)
725
calculateEdgeContour(s, d, layer);
726
// draw lanes
727
for (const auto& lane : getChildLanes()) {
728
lane->drawGL(s);
729
}
730
// draw junctions
731
getFromJunction()->drawGL(s);
732
getToJunction()->drawGL(s);
733
// draw childrens
734
drawChildrens(s);
735
}
736
}
737
738
739
void
740
GNEEdge::deleteGLObject() {
741
// Check if edge can be deleted
742
if (GNEDeleteFrame::SubordinatedElements(this).checkElements(myNet->getViewParent()->getDeleteFrame()->getProtectElements())) {
743
myNet->deleteEdge(this, myNet->getUndoList(), false);
744
}
745
}
746
747
748
void
749
GNEEdge::updateGLObject() {
750
updateGeometry();
751
}
752
753
754
NBEdge*
755
GNEEdge::getNBEdge() const {
756
return myNBEdge;
757
}
758
759
760
Position
761
GNEEdge::getSplitPos(const Position& clickPos) {
762
// get geometry point radius
763
const double geometryPointRadius = getGeometryPointRadius();
764
const PositionVector& geom = myNBEdge->getGeometry();
765
int index = geom.indexOfClosest(clickPos, true);
766
if (geom[index].distanceSquaredTo2D(clickPos) < (geometryPointRadius * geometryPointRadius)) {
767
// split at existing geometry point
768
return myNet->getViewNet()->snapToActiveGrid(geom[index]);
769
} else {
770
// split straight between the next two points
771
return myNet->getViewNet()->snapToActiveGrid(geom.positionAtOffset(geom.nearest_offset_to_point2D(clickPos)));
772
}
773
}
774
775
776
void
777
GNEEdge::editEndpoint(Position pos, GNEUndoList* undoList) {
778
// get geometry point radius
779
const double geometryPointRadius = getGeometryPointRadius();
780
if ((myNBEdge->getGeometry().front().distanceSquaredTo2D(getFromJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE) &&
781
(myNBEdge->getGeometry().front().distanceSquaredTo2D(pos) < (geometryPointRadius * geometryPointRadius))) {
782
undoList->begin(this, "remove endpoint");
783
setAttribute(GNE_ATTR_SHAPE_START, "", undoList);
784
undoList->end();
785
} else if ((myNBEdge->getGeometry().back().distanceSquaredTo2D(getToJunction()->getNBNode()->getPosition()) > ENDPOINT_TOLERANCE) &&
786
(myNBEdge->getGeometry().back().distanceSquaredTo2D(pos) < (geometryPointRadius * geometryPointRadius))) {
787
undoList->begin(this, "remove endpoint");
788
setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
789
undoList->end();
790
} else {
791
// we need to create new Start/End position over Edge shape, not over clicked position
792
double offset = myNBEdge->getGeometry().nearest_offset_to_point2D(myNet->getViewNet()->snapToActiveGrid(pos), true);
793
if (offset != GeomHelper::INVALID_OFFSET) {
794
PositionVector geom = myNBEdge->getGeometry();
795
// calculate position over edge shape relative to clicked position
796
Position newPos = geom.positionAtOffset2D(offset);
797
// snap new position to grid
798
newPos = myNet->getViewNet()->snapToActiveGrid(newPos);
799
undoList->begin(this, "set endpoint");
800
const int index = geom.indexOfClosest(pos, true);
801
const Position destPos = getToJunction()->getNBNode()->getPosition();
802
const Position sourcePos = getFromJunction()->getNBNode()->getPosition();
803
if (pos.distanceTo2D(destPos) < pos.distanceTo2D(sourcePos)) {
804
// check if snap to existing geometrypoint
805
if (geom[index].distanceSquaredTo2D(pos) < (geometryPointRadius * geometryPointRadius)) {
806
newPos = geom[index];
807
// remove existent geometry point to avoid double points
808
myMoveElementEdge->removeGeometryPoint(newPos, undoList);
809
}
810
setAttribute(GNE_ATTR_SHAPE_END, toString(newPos), undoList);
811
getToJunction()->invalidateShape();
812
} else {
813
// check if snap to existing geometry point
814
if (geom[index].distanceSquaredTo2D(pos) < (geometryPointRadius * geometryPointRadius)) {
815
newPos = geom[index];
816
// remove existent geometry point to avoid double points
817
myMoveElementEdge->removeGeometryPoint(newPos, undoList);
818
}
819
setAttribute(GNE_ATTR_SHAPE_START, toString(newPos), undoList);
820
getFromJunction()->invalidateShape();
821
}
822
undoList->end();
823
}
824
}
825
}
826
827
828
void
829
GNEEdge::resetEndpoint(const Position& pos, GNEUndoList* undoList) {
830
Position destPos = getToJunction()->getNBNode()->getPosition();
831
Position sourcePos = getFromJunction()->getNBNode()->getPosition();
832
if (pos.distanceTo2D(destPos) < pos.distanceTo2D(sourcePos)) {
833
setAttribute(GNE_ATTR_SHAPE_END, toString(destPos), undoList);
834
getToJunction()->invalidateShape();
835
} else {
836
setAttribute(GNE_ATTR_SHAPE_START, toString(sourcePos), undoList);
837
getFromJunction()->invalidateShape();
838
}
839
}
840
841
842
void
843
GNEEdge::resetBothEndpoint(GNEUndoList* undoList) {
844
// reset shape start
845
setAttribute(GNE_ATTR_SHAPE_END, "", undoList);
846
getToJunction()->invalidateShape();
847
// reset shape end
848
setAttribute(GNE_ATTR_SHAPE_START, "", undoList);
849
getFromJunction()->invalidateShape();
850
}
851
852
void
853
GNEEdge::setGeometry(PositionVector geom, bool inner) {
854
// set new geometry
855
const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
856
if (lefthand) {
857
geom.mirrorX();
858
myNBEdge->mirrorX();
859
}
860
myNBEdge->setGeometry(geom, inner);
861
if (lefthand) {
862
myNBEdge->mirrorX();
863
}
864
// update geometry
865
updateGeometry();
866
// invalidate junction source shape
867
getFromJunction()->invalidateShape();
868
// iterate over first parent junction edges and update geometry
869
for (const auto& edge : getFromJunction()->getGNEIncomingEdges()) {
870
edge->updateGeometry();
871
}
872
for (const auto& edge : getFromJunction()->getGNEOutgoingEdges()) {
873
edge->updateGeometry();
874
}
875
// invalidate junction destination shape
876
getToJunction()->invalidateShape();
877
// iterate over second parent junction edges and update geometry
878
for (const auto& edge : getToJunction()->getGNEIncomingEdges()) {
879
edge->updateGeometry();
880
}
881
for (const auto& edge : getToJunction()->getGNEOutgoingEdges()) {
882
edge->updateGeometry();
883
}
884
}
885
886
887
const Position
888
GNEEdge::getFrontUpShapePosition() const {
889
PositionVector laneShape = getChildLanes().front()->getLaneShape();
890
laneShape.move2side(getChildLanes().front()->getParentEdge()->getNBEdge()->getLaneWidth(getChildLanes().front()->getIndex()) / 2);
891
return laneShape.front();
892
}
893
894
895
const Position
896
GNEEdge::getFrontDownShapePosition() const {
897
PositionVector laneShape = getChildLanes().back()->getLaneShape();
898
laneShape.move2side(-1 * getChildLanes().back()->getParentEdge()->getNBEdge()->getLaneWidth(getChildLanes().back()->getIndex()) / 2);
899
return laneShape.front();
900
}
901
902
903
const Position
904
GNEEdge::getBackUpShapePosition() const {
905
PositionVector laneShape = getChildLanes().front()->getLaneShape();
906
laneShape.move2side(getChildLanes().front()->getParentEdge()->getNBEdge()->getLaneWidth(getChildLanes().front()->getIndex()) / 2);
907
return laneShape.back();
908
}
909
910
911
const Position
912
GNEEdge::getBackDownShapePosition() const {
913
PositionVector laneShape = getChildLanes().back()->getLaneShape();
914
laneShape.move2side(-1 * getChildLanes().back()->getParentEdge()->getNBEdge()->getLaneWidth(getChildLanes().back()->getIndex()) / 2);
915
return laneShape.back();
916
}
917
918
void
919
GNEEdge::remakeGNEConnections(bool junctionsReady) {
920
// create new and removed unused GNEConnections
921
const std::vector<NBEdge::Connection>& connections = myNBEdge->getConnections();
922
// create a vector to keep retrieved and created connections
923
std::vector<GNEConnection*> retrievedConnections;
924
// iterate over NBEdge::Connections of GNEEdge
925
for (const auto& connection : connections) {
926
// retrieve existent GNEConnection, or create it
927
GNEConnection* retrievedGNEConnection = retrieveGNEConnection(connection.fromLane, connection.toEdge, connection.toLane);
928
if (junctionsReady) {
929
retrievedGNEConnection->updateLinkState();
930
}
931
retrievedConnections.push_back(retrievedGNEConnection);
932
// check if previously this GNEConnections exists, and if true, remove it from myGNEConnections
933
std::vector<GNEConnection*>::iterator retrievedExists = std::find(myGNEConnections.begin(), myGNEConnections.end(), retrievedGNEConnection);
934
if (retrievedExists != myGNEConnections.end()) {
935
myGNEConnections.erase(retrievedExists);
936
} else {
937
// include reference to created GNEConnection
938
retrievedGNEConnection->incRef("GNEEdge::remakeGNEConnections");
939
}
940
// mark it as deprecated
941
retrievedGNEConnection->markConnectionGeometryDeprecated();
942
}
943
// delete non retrieved GNEConnections
944
for (const auto& connection : myGNEConnections) {
945
// decrease reference
946
connection->decRef();
947
// remove it from network
948
myNet->removeGLObjectFromGrid(connection);
949
// and from AttributeCarriers
950
if (myNet->getAttributeCarriers()->getConnections().count(connection) > 0) {
951
myNet->getAttributeCarriers()->deleteConnection(connection);
952
}
953
// delete GNEConnection if is unreferenced
954
if (connection->unreferenced()) {
955
delete connection;
956
}
957
}
958
// copy retrieved (existent and created) GNECrossings to myGNEConnections
959
myGNEConnections = retrievedConnections;
960
}
961
962
963
void
964
GNEEdge::clearGNEConnections() {
965
// Drop all existents connections that aren't referenced anymore
966
for (const auto& connection : myGNEConnections) {
967
// check if connection is selected
968
if (connection->isAttributeCarrierSelected()) {
969
connection->unselectAttributeCarrier();
970
}
971
// Dec reference of connection
972
connection->decRef("GNEEdge::clearGNEConnections");
973
// remove it from network
974
myNet->removeGLObjectFromGrid(connection);
975
// and from AttributeCarriers
976
if (myNet->getAttributeCarriers()->getConnections().count(connection) > 0) {
977
myNet->getAttributeCarriers()->deleteConnection(connection);
978
}
979
// Delete GNEConnectionToErase if is unreferenced
980
if (connection->unreferenced()) {
981
delete connection;
982
}
983
}
984
myGNEConnections.clear();
985
}
986
987
988
int
989
GNEEdge::getRouteProbeRelativePosition(GNERouteProbe* routeProbe) const {
990
std::vector<GNEAdditional*> routeProbes;
991
for (const auto& additional : getChildAdditionals()) {
992
if (additional->getTagProperty()->getTag() == routeProbe->getTagProperty()->getTag()) {
993
routeProbes.push_back(additional);
994
}
995
}
996
// return index of routeProbe in routeProbes vector
997
auto it = std::find(routeProbes.begin(), routeProbes.end(), routeProbe);
998
if (it == routeProbes.end()) {
999
return -1;
1000
} else {
1001
return (int)(it - routeProbes.begin());
1002
}
1003
}
1004
1005
1006
std::vector<GNECrossing*>
1007
GNEEdge::getGNECrossings() {
1008
std::vector<GNECrossing*> crossings;
1009
for (auto i : getFromJunction()->getGNECrossings()) {
1010
if (i->checkEdgeBelong(this)) {
1011
crossings.push_back(i);
1012
}
1013
}
1014
for (auto i : getToJunction()->getGNECrossings()) {
1015
if (i->checkEdgeBelong(this)) {
1016
crossings.push_back(i);
1017
}
1018
}
1019
return crossings;
1020
}
1021
1022
1023
void
1024
GNEEdge::copyTemplate(const GNEEdgeTemplate* edgeTemplate, GNEUndoList* undoList) {
1025
// copy edge-specific attributes
1026
for (const auto& attProperty : myTagProperty->getAttributeProperties()) {
1027
if (attProperty->isCopyable() && isValid(attProperty->getAttr(), edgeTemplate->getAttribute(attProperty->getAttr()))) {
1028
setAttribute(attProperty->getAttr(), edgeTemplate->getAttribute(attProperty->getAttr()), undoList);
1029
}
1030
}
1031
// also copy parameters
1032
setAttribute(GNE_ATTR_PARAMETERS, edgeTemplate->getAttribute(GNE_ATTR_PARAMETERS), undoList);
1033
// copy lane attributes as well
1034
for (int i = 0; i < (int)getChildLanes().size(); i++) {
1035
for (const auto& attProperty : edgeTemplate->getLaneTemplates().at(i)->getTagProperty()->getAttributeProperties()) {
1036
if (attProperty->isCopyable() && getChildLanes()[i]->isValid(attProperty->getAttr(), edgeTemplate->getLaneTemplates().at(i)->getAttribute(attProperty->getAttr()))) {
1037
getChildLanes()[i]->setAttribute(attProperty->getAttr(), edgeTemplate->getLaneTemplates().at(i)->getAttribute(attProperty->getAttr()), undoList);
1038
}
1039
}
1040
// also copy parameters
1041
getChildLanes()[i]->setAttribute(GNE_ATTR_PARAMETERS, edgeTemplate->getLaneTemplates().at(i)->getAttribute(GNE_ATTR_PARAMETERS), undoList);
1042
}
1043
}
1044
1045
1046
void
1047
GNEEdge::copyEdgeType(const GNEEdgeType* edgeType, GNEUndoList* undoList) {
1048
const auto tagPropertiesDatabase = myNet->getTagPropertiesDatabase();
1049
// get tag properties
1050
const auto edgeProperties = tagPropertiesDatabase->getTagProperty(SUMO_TAG_EDGE, true);
1051
const auto laneProperties = tagPropertiesDatabase->getTagProperty(SUMO_TAG_LANE, true);
1052
const auto edgeTypeProperties = tagPropertiesDatabase->getTagProperty(SUMO_TAG_TYPE, true);
1053
const auto laneTypeProperties = tagPropertiesDatabase->getTagProperty(SUMO_TAG_LANETYPE, true);
1054
// set type (only for info)
1055
setAttribute(SUMO_ATTR_TYPE, edgeType->getAttribute(SUMO_ATTR_ID), undoList);
1056
// copy attributes
1057
for (const auto& attrProperty : edgeTypeProperties->getAttributeProperties()) {
1058
if (attrProperty->isCopyable() && edgeProperties->hasAttribute(attrProperty->getAttr())) {
1059
setAttribute(attrProperty->getAttr(), edgeType->getAttribute(attrProperty->getAttr()), undoList);
1060
}
1061
}
1062
setAttribute(GNE_ATTR_PARAMETERS, edgeType->getAttribute(GNE_ATTR_PARAMETERS), undoList);
1063
// copy lane attributes as well
1064
for (int i = 0; i < (int)getChildLanes().size(); i++) {
1065
for (const auto& attrProperty : laneTypeProperties->getAttributeProperties()) {
1066
if (attrProperty->isCopyable() && laneProperties->hasAttribute(attrProperty->getAttr()) &&
1067
(edgeType->getLaneTypes().at(i)->getAttribute(attrProperty->getAttr()) != laneTypeProperties->getAttributeProperties(attrProperty->getAttr())->getDefaultStringValue())) {
1068
getChildLanes()[i]->setAttribute(attrProperty->getAttr(), edgeType->getLaneTypes().at(i)->getAttribute(attrProperty->getAttr()), undoList);
1069
}
1070
}
1071
if (edgeType->getLaneTypes().at(i)->getAttribute(GNE_ATTR_PARAMETERS).size() > 0) {
1072
getChildLanes()[i]->setAttribute(GNE_ATTR_PARAMETERS, edgeType->getLaneTypes().at(i)->getAttribute(GNE_ATTR_PARAMETERS), undoList);
1073
}
1074
}
1075
}
1076
1077
1078
std::set<GUIGlID>
1079
GNEEdge::getLaneGlIDs() const {
1080
std::set<GUIGlID> result;
1081
for (const auto glID : getChildLanes()) {
1082
result.insert(glID->getGlID());
1083
}
1084
return result;
1085
}
1086
1087
1088
const std::vector<GNEConnection*>&
1089
GNEEdge::getGNEConnections() const {
1090
return myGNEConnections;
1091
}
1092
1093
1094
bool
1095
GNEEdge::wasSplit() {
1096
return myWasSplit;
1097
}
1098
1099
1100
std::string
1101
GNEEdge::getAttribute(SumoXMLAttr key) const {
1102
switch (key) {
1103
case SUMO_ATTR_ID:
1104
return getMicrosimID();
1105
case SUMO_ATTR_FROM:
1106
case SUMO_ATTR_FROM_JUNCTION:
1107
return getFromJunction()->getID();
1108
case SUMO_ATTR_TO:
1109
case SUMO_ATTR_TO_JUNCTION:
1110
return getToJunction()->getID();
1111
case SUMO_ATTR_NUMLANES:
1112
return toString(myNBEdge->getNumLanes());
1113
case SUMO_ATTR_PRIORITY:
1114
return toString(myNBEdge->getPriority());
1115
case SUMO_ATTR_LENGTH:
1116
return toString(myNBEdge->getFinalLength());
1117
case SUMO_ATTR_TYPE:
1118
return myNBEdge->getTypeID();
1119
case SUMO_ATTR_SHAPE:
1120
return toString(myNBEdge->getInnerGeometry());
1121
case SUMO_ATTR_SPREADTYPE:
1122
return SUMOXMLDefinitions::LaneSpreadFunctions.getString(myNBEdge->getLaneSpreadFunction());
1123
case SUMO_ATTR_NAME:
1124
return myNBEdge->getStreetName();
1125
case SUMO_ATTR_ALLOW:
1126
return (getVehicleClassNames(myNBEdge->getPermissions()) + (myNBEdge->hasLaneSpecificPermissions() ? " (combined!)" : ""));
1127
case SUMO_ATTR_DISALLOW: {
1128
return (getVehicleClassNames(invertPermissions(myNBEdge->getPermissions())) + (myNBEdge->hasLaneSpecificPermissions() ? " (combined!)" : ""));
1129
}
1130
case SUMO_ATTR_SPEED:
1131
if (myNBEdge->hasLaneSpecificSpeed()) {
1132
return "lane specific";
1133
} else {
1134
return toString(myNBEdge->getSpeed());
1135
}
1136
case SUMO_ATTR_FRICTION:
1137
if (myNBEdge->hasLaneSpecificFriction()) {
1138
return "lane specific";
1139
} else {
1140
return toString(myNBEdge->getFriction());
1141
}
1142
case SUMO_ATTR_WIDTH:
1143
if (myNBEdge->hasLaneSpecificWidth()) {
1144
return "lane specific";
1145
} else if (myNBEdge->getLaneWidth() == NBEdge::UNSPECIFIED_WIDTH) {
1146
return "default";
1147
} else {
1148
return toString(myNBEdge->getLaneWidth());
1149
}
1150
case SUMO_ATTR_ENDOFFSET:
1151
if (myNBEdge->hasLaneSpecificEndOffset()) {
1152
return "lane specific";
1153
} else {
1154
return toString(myNBEdge->getEndOffset());
1155
}
1156
case SUMO_ATTR_DISTANCE:
1157
return toString(myNBEdge->getDistance());
1158
case GNE_ATTR_MODIFICATION_STATUS:
1159
return myConnectionStatus;
1160
case GNE_ATTR_SHAPE_START:
1161
if (getParentJunctions().empty()) {
1162
return "";
1163
} else if (myNBEdge->getGeometry().front().distanceSquaredTo2D(getFromJunction()->getNBNode()->getPosition()) <= ENDPOINT_TOLERANCE) {
1164
return "";
1165
} else {
1166
return toString(myNBEdge->getGeometry().front());
1167
}
1168
case GNE_ATTR_SHAPE_END:
1169
if (getParentJunctions().empty()) {
1170
return "";
1171
} else if (myNBEdge->getGeometry().back().distanceSquaredTo2D(getToJunction()->getNBNode()->getPosition()) <= ENDPOINT_TOLERANCE) {
1172
return "";
1173
} else {
1174
return toString(myNBEdge->getGeometry().back());
1175
}
1176
case GNE_ATTR_BIDIR:
1177
return toString(myNBEdge->getBidiEdge() != nullptr);
1178
case GNE_ATTR_STOPOFFSET:
1179
return toString(myNBEdge->myEdgeStopOffset.getOffset());
1180
case GNE_ATTR_STOPOEXCEPTION:
1181
if (myNBEdge->myEdgeStopOffset.isDefined()) {
1182
return toString(myNBEdge->myEdgeStopOffset.getExceptions());
1183
} else {
1184
return "";
1185
}
1186
case GNE_ATTR_IS_ROUNDABOUT:
1187
return myNBEdge->getFromNode()->isRoundabout() && myNBEdge->getToNode()->isRoundabout() ? TRUE_STR : FALSE_STR;
1188
default:
1189
return getCommonAttribute(key);
1190
}
1191
}
1192
1193
1194
double
1195
GNEEdge::getAttributeDouble(SumoXMLAttr key) const {
1196
return getCommonAttributeDouble(key);
1197
}
1198
1199
1200
Position
1201
GNEEdge::getAttributePosition(SumoXMLAttr key) const {
1202
return getCommonAttributePosition(key);
1203
}
1204
1205
1206
PositionVector
1207
GNEEdge::getAttributePositionVector(SumoXMLAttr key) const {
1208
switch (key) {
1209
case SUMO_ATTR_SHAPE:
1210
return myNBEdge->getInnerGeometry();
1211
default:
1212
return getCommonAttributePositionVector(key);
1213
}
1214
}
1215
1216
1217
std::string
1218
GNEEdge::getAttributeForSelection(SumoXMLAttr key) const {
1219
std::string result = getAttribute(key);
1220
if ((key == SUMO_ATTR_ALLOW || key == SUMO_ATTR_DISALLOW) && result.find("all") != std::string::npos) {
1221
result += " " + getVehicleClassNames(SVCAll, true);
1222
}
1223
return result;
1224
}
1225
1226
1227
void
1228
GNEEdge::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
1229
// get template editor
1230
GNEInspectorFrame::TemplateEditor* templateEditor = myNet->getViewParent()->getInspectorFrame()->getTemplateEditor();
1231
// check if we have to update template
1232
const bool updateTemplate = templateEditor->getEdgeTemplate() ? (templateEditor->getEdgeTemplate()->getID() == getID()) : false;
1233
switch (key) {
1234
case SUMO_ATTR_WIDTH:
1235
case SUMO_ATTR_ENDOFFSET:
1236
case SUMO_ATTR_SPEED:
1237
case SUMO_ATTR_FRICTION:
1238
case SUMO_ATTR_ALLOW:
1239
case SUMO_ATTR_DISALLOW: {
1240
undoList->begin(this, "change " + getTagStr() + " attribute");
1241
const std::string origValue = getChildLanes().at(0)->getAttribute(key); // will have intermediate value of "lane specific"
1242
// lane specific attributes need to be changed via lanes to allow undo
1243
for (auto it : getChildLanes()) {
1244
it->setAttribute(key, value, undoList);
1245
}
1246
// ensure that the edge value is also changed. Actually this sets the lane attributes again but it does not matter
1247
GNEChange_Attribute::changeAttribute(this, key, value, origValue, undoList);
1248
undoList->end();
1249
break;
1250
}
1251
case SUMO_ATTR_FROM: {
1252
if (value != getAttribute(key)) {
1253
undoList->begin(this, "change " + getTagStr() + " attribute");
1254
// Remove edge from crossings of junction source
1255
removeEdgeFromCrossings(getFromJunction(), undoList);
1256
// continue changing from junction
1257
GNEJunction* originalFirstParentJunction = getFromJunction();
1258
getFromJunction()->setLogicValid(false, undoList);
1259
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
1260
getFromJunction()->setLogicValid(false, undoList);
1261
myNet->getAttributeCarriers()->retrieveJunction(value)->setLogicValid(false, undoList);
1262
setAttribute(GNE_ATTR_SHAPE_START, toString(getFromJunction()->getNBNode()->getPosition()), undoList);
1263
getFromJunction()->invalidateShape();
1264
undoList->end();
1265
// update geometries of all implicated junctions
1266
originalFirstParentJunction->updateGeometry();
1267
getFromJunction()->updateGeometry();
1268
getToJunction()->updateGeometry();
1269
}
1270
break;
1271
}
1272
case SUMO_ATTR_TO: {
1273
if (value != getAttribute(key)) {
1274
undoList->begin(this, "change " + getTagStr() + " attribute");
1275
// Remove edge from crossings of junction destination
1276
removeEdgeFromCrossings(getToJunction(), undoList);
1277
// continue changing destination junction
1278
GNEJunction* originalSecondParentJunction = getToJunction();
1279
getToJunction()->setLogicValid(false, undoList);
1280
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
1281
getToJunction()->setLogicValid(false, undoList);
1282
myNet->getAttributeCarriers()->retrieveJunction(value)->setLogicValid(false, undoList);
1283
setAttribute(GNE_ATTR_SHAPE_END, toString(getToJunction()->getNBNode()->getPosition()), undoList);
1284
getToJunction()->invalidateShape();
1285
undoList->end();
1286
// update geometries of all implicated junctions
1287
originalSecondParentJunction->updateGeometry();
1288
getToJunction()->updateGeometry();
1289
getFromJunction()->updateGeometry();
1290
}
1291
break;
1292
}
1293
case SUMO_ATTR_ID:
1294
case SUMO_ATTR_PRIORITY:
1295
case SUMO_ATTR_LENGTH:
1296
case SUMO_ATTR_TYPE:
1297
case SUMO_ATTR_SPREADTYPE:
1298
case SUMO_ATTR_DISTANCE:
1299
case GNE_ATTR_MODIFICATION_STATUS:
1300
case GNE_ATTR_STOPOEXCEPTION:
1301
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
1302
break;
1303
case GNE_ATTR_STOPOFFSET:
1304
// special case for stop offset, because affects to stopOffsetExceptions (#15297)
1305
if (canParse<double>(value) && (parse<double>(value) == 0)) {
1306
GNEChange_Attribute::changeAttribute(this, GNE_ATTR_STOPOEXCEPTION, "", undoList);
1307
}
1308
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
1309
break;
1310
case GNE_ATTR_SHAPE_START:
1311
case GNE_ATTR_SHAPE_END: {
1312
// due to ENDPOINT_TOLERANCE, force change
1313
GNEChange_Attribute::changeAttribute(this, key, value, undoList, true);
1314
break;
1315
}
1316
case SUMO_ATTR_NAME:
1317
// user cares about street names. Make sure they appear in the output
1318
OptionsCont::getOptions().resetWritable();
1319
OptionsCont::getOptions().set("output.street-names", "true");
1320
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
1321
break;
1322
case SUMO_ATTR_NUMLANES:
1323
if (value != getAttribute(key)) {
1324
// set num lanes
1325
setNumLanes(parse<int>(value), undoList);
1326
}
1327
break;
1328
case GNE_ATTR_BIDIR:
1329
undoList->begin(this, "change " + getTagStr() + " attribute");
1330
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
1331
if (myNBEdge->getTurnDestination(true) != nullptr) {
1332
GNEEdge* bidi = myNet->getAttributeCarriers()->retrieveEdge(myNBEdge->getTurnDestination(true)->getID());
1333
GNEChange_Attribute::changeAttribute(bidi, key, value, undoList);
1334
if (myNBEdge->getGeometry() != bidi->getNBEdge()->getGeometry().reverse()
1335
&& myNBEdge->getGeometry().size() == 2
1336
&& bidi->getNBEdge()->getGeometry().size() == 2
1337
&& myNBEdge->getBidiEdge() == nullptr) {
1338
// NBEdge::avoidOverlap was already active so we need to reset the
1339
// geometry to its default
1340
resetBothEndpoint(undoList);
1341
bidi->resetBothEndpoint(undoList);
1342
}
1343
}
1344
undoList->end();
1345
break;
1346
case SUMO_ATTR_SHAPE:
1347
// @note: assumes value of inner geometry!
1348
// actually the geometry is already updated (incrementally
1349
// during mouse movement). We set the restore point to the end
1350
// of the last change-set
1351
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
1352
break;
1353
default:
1354
setCommonAttribute(key, value, undoList);
1355
break;
1356
}
1357
// update template
1358
if (updateTemplate) {
1359
templateEditor->setEdgeTemplate(this);
1360
}
1361
}
1362
1363
1364
bool
1365
GNEEdge::isValid(SumoXMLAttr key, const std::string& value) {
1366
switch (key) {
1367
case SUMO_ATTR_ID:
1368
return SUMOXMLDefinitions::isValidNetID(value) && (myNet->getAttributeCarriers()->retrieveEdge(value, false) == nullptr);
1369
case SUMO_ATTR_FROM: {
1370
// check that is a valid ID and is different of ID of junction destination
1371
if (value == getFromJunction()->getID()) {
1372
return true;
1373
} else if (SUMOXMLDefinitions::isValidNetID(value) && (value != getToJunction()->getID())) {
1374
return (myNet->getAttributeCarriers()->retrieveJunction(value, false) != nullptr);
1375
} else {
1376
return false;
1377
}
1378
}
1379
case SUMO_ATTR_TO: {
1380
// check that is a valid ID and is different of ID of junction Source
1381
if (value == getToJunction()->getID()) {
1382
return true;
1383
} else if (SUMOXMLDefinitions::isValidNetID(value) && (value != getFromJunction()->getID())) {
1384
return (myNet->getAttributeCarriers()->retrieveJunction(value, false) != nullptr);
1385
} else {
1386
return false;
1387
}
1388
}
1389
case SUMO_ATTR_SPEED:
1390
return canParse<double>(value) && (parse<double>(value) > 0);
1391
case SUMO_ATTR_FRICTION:
1392
return canParse<double>(value) && (parse<double>(value) > 0);
1393
case SUMO_ATTR_NUMLANES:
1394
return canParse<int>(value) && (parse<double>(value) > 0);
1395
case SUMO_ATTR_PRIORITY:
1396
return canParse<int>(value);
1397
case SUMO_ATTR_LENGTH:
1398
if (value.empty()) {
1399
return true;
1400
} else {
1401
return canParse<double>(value) && ((parse<double>(value) > 0) || (parse<double>(value) == NBEdge::UNSPECIFIED_LOADED_LENGTH));
1402
}
1403
case SUMO_ATTR_ALLOW:
1404
case SUMO_ATTR_DISALLOW:
1405
return canParseVehicleClasses(value);
1406
case SUMO_ATTR_TYPE:
1407
return true;
1408
case SUMO_ATTR_SHAPE:
1409
// empty shapes are allowed
1410
return canParse<PositionVector>(value);
1411
case SUMO_ATTR_SPREADTYPE:
1412
return SUMOXMLDefinitions::LaneSpreadFunctions.hasString(value);
1413
case SUMO_ATTR_NAME:
1414
return true;
1415
case SUMO_ATTR_WIDTH:
1416
if (value.empty() || (value == "default")) {
1417
return true;
1418
} else {
1419
return canParse<double>(value) && ((parse<double>(value) >= -1) || (parse<double>(value) == NBEdge::UNSPECIFIED_WIDTH));
1420
}
1421
case SUMO_ATTR_ENDOFFSET:
1422
return canParse<double>(value) && parse<double>(value) >= 0 && parse<double>(value) < myNBEdge->getLoadedLength();
1423
case SUMO_ATTR_DISTANCE:
1424
if (value.empty()) {
1425
return true;
1426
} else {
1427
return canParse<double>(value);
1428
}
1429
case GNE_ATTR_SHAPE_START: {
1430
if (value.empty()) {
1431
return true;
1432
} else if (canParse<Position>(value)) {
1433
Position shapeStart = parse<Position>(value);
1434
return (shapeStart != myNBEdge->getGeometry()[-1]);
1435
} else {
1436
return false;
1437
}
1438
}
1439
case GNE_ATTR_SHAPE_END: {
1440
if (value.empty()) {
1441
return true;
1442
} else if (canParse<Position>(value)) {
1443
Position shapeEnd = parse<Position>(value);
1444
return (shapeEnd != myNBEdge->getGeometry()[0]);
1445
} else {
1446
return false;
1447
}
1448
}
1449
case GNE_ATTR_BIDIR:
1450
return canParse<bool>(value) && (!parse<bool>(value) || myNBEdge->isBidiEdge(true));
1451
case GNE_ATTR_STOPOFFSET:
1452
if (value.empty()) {
1453
return true;
1454
} else {
1455
return canParse<double>(value) && (parse<double>(value) >= 0);
1456
}
1457
case GNE_ATTR_STOPOEXCEPTION:
1458
return canParseVehicleClasses(value);
1459
default:
1460
return isCommonAttributeValid(key, value);
1461
}
1462
}
1463
1464
1465
bool
1466
GNEEdge::isAttributeEnabled(SumoXMLAttr key) const {
1467
switch (key) {
1468
case GNE_ATTR_BIDIR:
1469
return myNBEdge->isBidiEdge(true);
1470
case GNE_ATTR_STOPOEXCEPTION:
1471
return myNBEdge->myEdgeStopOffset.getOffset() > 0;
1472
case GNE_ATTR_IS_ROUNDABOUT:
1473
return false;
1474
default:
1475
return true;
1476
}
1477
}
1478
1479
1480
bool
1481
GNEEdge::isAttributeComputed(SumoXMLAttr key) const {
1482
switch (key) {
1483
case SUMO_ATTR_LENGTH:
1484
return !myNBEdge->hasLoadedLength();
1485
case SUMO_ATTR_WIDTH:
1486
if (myNBEdge->hasLaneSpecificWidth()) {
1487
return false;
1488
} else {
1489
return (myNBEdge->getLaneWidth() == NBEdge::UNSPECIFIED_WIDTH);
1490
}
1491
default:
1492
return false;
1493
}
1494
}
1495
1496
1497
void
1498
GNEEdge::setResponsible(bool newVal) {
1499
myAmResponsible = newVal;
1500
}
1501
1502
1503
GNELane*
1504
GNEEdge::getLaneByAllowedVClass(const SUMOVehicleClass vClass) const {
1505
// iterate over all NBEdge lanes
1506
for (int i = 0; i < (int)myNBEdge->getLanes().size(); i++) {
1507
// if given VClass is in permissions, return lane
1508
if (myNBEdge->getLanes().at(i).permissions & vClass) {
1509
// return GNELane
1510
return getChildLanes().at(i);
1511
}
1512
}
1513
// return first lane
1514
return getChildLanes().front();
1515
}
1516
1517
1518
GNELane*
1519
GNEEdge::getLaneByDisallowedVClass(const SUMOVehicleClass vClass) const {
1520
// iterate over all NBEdge lanes
1521
for (int i = 0; i < (int)myNBEdge->getLanes().size(); i++) {
1522
// if given VClass isn't in permissions, return lane
1523
if (~(myNBEdge->getLanes().at(i).permissions) & vClass) {
1524
// return GNELane
1525
return getChildLanes().at(i);
1526
}
1527
}
1528
// return first lane
1529
return getChildLanes().front();
1530
}
1531
1532
1533
void
1534
GNEEdge::updateVehicleSpreadGeometries() {
1535
// get lane vehicles map
1536
const std::map<const GNELane*, std::vector<GNEDemandElement*> > laneVehiclesMap = getVehiclesOverEdgeMap();
1537
// iterate over every lane
1538
for (const auto& laneVehicle : laneVehiclesMap) {
1539
// obtain total length
1540
double totalLength = 0;
1541
for (const auto& vehicle : laneVehicle.second) {
1542
totalLength += vehicle->getAttributeDouble(SUMO_ATTR_LENGTH) + VEHICLE_GAP;
1543
}
1544
// calculate multiplier for vehicle positions
1545
double multiplier = 1;
1546
const double laneShapeLength = laneVehicle.first->getLaneShape().length();
1547
if (laneShapeLength == 0) {
1548
multiplier = 0;
1549
} else if (totalLength > laneShapeLength) {
1550
multiplier = (laneShapeLength / totalLength);
1551
}
1552
// declare current length
1553
double length = 0;
1554
// iterate over vehicles to calculate position and rotations
1555
for (const auto& vehicle : laneVehicle.second) {
1556
vehicle->updateDemandElementSpreadGeometry(laneVehicle.first, length * multiplier);
1557
// update length
1558
length += vehicle->getAttributeDouble(SUMO_ATTR_LENGTH) + VEHICLE_GAP;
1559
}
1560
}
1561
}
1562
1563
1564
void
1565
GNEEdge::updateVehicleStackLabels() {
1566
// get lane vehicles map
1567
const std::map<const GNELane*, std::vector<GNEDemandElement*> > laneVehiclesMap = getVehiclesOverEdgeMap();
1568
// iterate over laneVehiclesMap and obtain a vector with
1569
for (const auto& vehicleMap : laneVehiclesMap) {
1570
// declare map for sort vehicles using their departpos+length position (StackPosition)
1571
std::vector<std::pair<GNEEdge::StackPosition, GNEDemandElement*> > departPosVehicles;
1572
// declare vector of stack demand elements
1573
std::vector<GNEEdge::StackDemandElements> stackedVehicles;
1574
// iterate over vehicles
1575
for (const auto& vehicle : vehicleMap.second) {
1576
// get vehicle's depart pos and length
1577
const double departPos = vehicle->getAttributeDouble(SUMO_ATTR_DEPARTPOS);
1578
const double length = vehicle->getAttributeDouble(SUMO_ATTR_LENGTH);
1579
double posOverLane = vehicle->getAttributeDouble(SUMO_ATTR_DEPARTPOS);
1580
// check if we have to adapt posOverLane
1581
if (posOverLane < 0) {
1582
posOverLane += vehicleMap.first->getLaneShape().length();
1583
}
1584
// make a stack position using departPos and length
1585
departPosVehicles.push_back(std::make_pair(StackPosition(departPos, length), vehicle));
1586
// update depart element geometry
1587
vehicle->updateDemandElementGeometry(vehicleMap.first, posOverLane);
1588
// reset vehicle stack label
1589
vehicle->updateDemandElementStackLabel(0);
1590
}
1591
1592
// sort departPosVehicles
1593
std::sort(departPosVehicles.begin(), departPosVehicles.end());
1594
// iterate over departPosVehicles
1595
for (const auto& departPosVehicle : departPosVehicles) {
1596
// obtain stack position and vehicle
1597
const GNEEdge::StackPosition& vehicleStackPosition = departPosVehicle.first;
1598
GNEDemandElement* vehicle = departPosVehicle.second;
1599
// if stackedVehicles is empty, add a new StackDemandElements
1600
if (stackedVehicles.empty()) {
1601
stackedVehicles.push_back(GNEEdge::StackDemandElements(vehicleStackPosition, vehicle));
1602
} else if (areStackPositionOverlapped(vehicleStackPosition, stackedVehicles.back().getStackPosition())) {
1603
// add new vehicle to last inserted stackDemandElements
1604
stackedVehicles[stackedVehicles.size() - 1].addDemandElements(vehicle);
1605
} else {
1606
// No overlapping, then add a new StackDemandElements
1607
stackedVehicles.push_back(GNEEdge::StackDemandElements(vehicleStackPosition, vehicle));
1608
}
1609
}
1610
// iterate over stackedVehicles
1611
for (const auto& vehicle : stackedVehicles) {
1612
// only update vehicles with one or more stack
1613
if (vehicle.getDemandElements().size() > 1) {
1614
// set stack labels
1615
vehicle.getDemandElements().front()->updateDemandElementStackLabel((int)vehicle.getDemandElements().size());
1616
}
1617
}
1618
}
1619
}
1620
1621
1622
void
1623
GNEEdge::updatePersonStackLabels() {
1624
// get lane persons map
1625
const std::map<const GNELane*, std::vector<GNEDemandElement*> > lanePersonsMap = getPersonsOverEdgeMap();
1626
// iterate over lanePersonsMap and obtain a vector with
1627
for (const auto& personMap : lanePersonsMap) {
1628
// declare map for sort persons using their departpos+length position (StackPosition)
1629
std::vector<std::pair<GNEEdge::StackPosition, GNEDemandElement*> > departPosPersons;
1630
// declare vector of stack demand elements
1631
std::vector<GNEEdge::StackDemandElements> stackedPersons;
1632
// iterate over persons
1633
for (const auto& person : personMap.second) {
1634
// get person's depart pos and length
1635
const double departPos = person->getAttributeDouble(SUMO_ATTR_DEPARTPOS);
1636
// make a stack position using departPos and length
1637
departPosPersons.push_back(std::make_pair(StackPosition(departPos, 1.8), person));
1638
// update depart element geometry
1639
person->updateDemandElementGeometry(personMap.first, departPos);
1640
// reset person stack label
1641
person->updateDemandElementStackLabel(0);
1642
}
1643
1644
// sort departPosPersons
1645
std::sort(departPosPersons.begin(), departPosPersons.end());
1646
// iterate over departPosPersons
1647
for (const auto& departPosPerson : departPosPersons) {
1648
// obtain stack position and person
1649
const GNEEdge::StackPosition& personStackPosition = departPosPerson.first;
1650
GNEDemandElement* person = departPosPerson.second;
1651
// if stackedPersons is empty, add a new StackDemandElements
1652
if (stackedPersons.empty()) {
1653
stackedPersons.push_back(GNEEdge::StackDemandElements(personStackPosition, person));
1654
} else if (areStackPositionOverlapped(personStackPosition, stackedPersons.back().getStackPosition())) {
1655
// add new person to last inserted stackDemandElements
1656
stackedPersons[stackedPersons.size() - 1].addDemandElements(person);
1657
} else {
1658
// No overlapping, then add a new StackDemandElements
1659
stackedPersons.push_back(GNEEdge::StackDemandElements(personStackPosition, person));
1660
}
1661
}
1662
// iterate over stackedPersons
1663
for (const auto& person : stackedPersons) {
1664
// only update persons with one or more stack
1665
if (person.getDemandElements().size() > 1) {
1666
// set stack labels
1667
person.getDemandElements().front()->updateDemandElementStackLabel((int)person.getDemandElements().size());
1668
}
1669
}
1670
}
1671
}
1672
1673
1674
void
1675
GNEEdge::updateContainerStackLabels() {
1676
// get lane containers map
1677
const std::map<const GNELane*, std::vector<GNEDemandElement*> > laneContainersMap = getContainersOverEdgeMap();
1678
// iterate over laneContainersMap and obtain a vector with
1679
for (const auto& containerMap : laneContainersMap) {
1680
// declare map for sort containers using their departpos+length position (StackPosition)
1681
std::vector<std::pair<GNEEdge::StackPosition, GNEDemandElement*> > departPosContainers;
1682
// declare vector of stack demand elements
1683
std::vector<GNEEdge::StackDemandElements> stackedContainers;
1684
// iterate over containers
1685
for (const auto& container : containerMap.second) {
1686
// get container's depart pos and length
1687
const double departPos = container->getAttributeDouble(SUMO_ATTR_DEPARTPOS);
1688
// make a stack position using departPos and length
1689
departPosContainers.push_back(std::make_pair(StackPosition(departPos, 1.8), container));
1690
// update depart element geometry
1691
container->updateDemandElementGeometry(containerMap.first, departPos);
1692
// reset container stack label
1693
container->updateDemandElementStackLabel(0);
1694
}
1695
1696
// sort departPosContainers
1697
std::sort(departPosContainers.begin(), departPosContainers.end());
1698
// iterate over departPosContainers
1699
for (const auto& departPosContainer : departPosContainers) {
1700
// obtain stack position and container
1701
const GNEEdge::StackPosition& containerStackPosition = departPosContainer.first;
1702
GNEDemandElement* container = departPosContainer.second;
1703
// if stackedContainers is empty, add a new StackDemandElements
1704
if (stackedContainers.empty()) {
1705
stackedContainers.push_back(GNEEdge::StackDemandElements(containerStackPosition, container));
1706
} else if (areStackPositionOverlapped(containerStackPosition, stackedContainers.back().getStackPosition())) {
1707
// add new container to last inserted stackDemandElements
1708
stackedContainers[stackedContainers.size() - 1].addDemandElements(container);
1709
} else {
1710
// No overlapping, then add a new StackDemandElements
1711
stackedContainers.push_back(GNEEdge::StackDemandElements(containerStackPosition, container));
1712
}
1713
}
1714
// iterate over stackedContainers
1715
for (const auto& container : stackedContainers) {
1716
// only update containers with one or more stack
1717
if (container.getDemandElements().size() > 1) {
1718
// set stack labels
1719
container.getDemandElements().front()->updateDemandElementStackLabel((int)container.getDemandElements().size());
1720
}
1721
}
1722
}
1723
}
1724
1725
1726
bool
1727
GNEEdge::isConvexAngle() const {
1728
// calculate angle between both junction positions
1729
double edgeAngle = RAD2DEG(getFromJunction()->getPositionInView().angleTo2D(getToJunction()->getPositionInView()));
1730
// adjust to 360 degrees
1731
while (edgeAngle < 0) {
1732
edgeAngle += 360;
1733
}
1734
// fmod round towards zero which is not want we want for negative numbers
1735
edgeAngle = fmod(edgeAngle, 360);
1736
// check angle
1737
return edgeAngle >= 0 && edgeAngle < 180;
1738
}
1739
1740
1741
bool
1742
GNEEdge::hasPredecessors() const {
1743
// get incoming edges
1744
const auto incomingEdges = getFromJunction()->getGNEIncomingEdges();
1745
// iterate over connections
1746
for (const auto& incomingEdge : incomingEdges) {
1747
for (const auto& connection : incomingEdge->getGNEConnections()) {
1748
if (connection->getEdgeTo() == this) {
1749
return true;
1750
}
1751
}
1752
}
1753
return false;
1754
}
1755
1756
1757
bool
1758
GNEEdge::hasSuccessors() const {
1759
return (myGNEConnections.size() > 0);
1760
}
1761
1762
1763
GNEEdge*
1764
GNEEdge::getReverseEdge() const {
1765
for (const auto& outgoingEdge : getParentJunctions().back()->getGNEOutgoingEdges()) {
1766
if (outgoingEdge->getToJunction() == getFromJunction()) {
1767
return outgoingEdge;
1768
}
1769
}
1770
return nullptr;
1771
}
1772
1773
// ===========================================================================
1774
// private
1775
// ===========================================================================
1776
1777
GNEEdge::StackPosition::StackPosition(const double departPos, const double length) :
1778
pair(departPos, departPos + length) {
1779
}
1780
1781
1782
double
1783
GNEEdge::StackPosition::beginPosition() const {
1784
return first;
1785
}
1786
1787
1788
double
1789
GNEEdge::StackPosition::endPosition() const {
1790
return second;
1791
}
1792
1793
1794
GNEEdge::StackDemandElements::StackDemandElements(const StackPosition stackedPosition, GNEDemandElement* demandElement) :
1795
pair(stackedPosition, {
1796
demandElement
1797
}) {
1798
}
1799
1800
1801
void
1802
GNEEdge::StackDemandElements::addDemandElements(GNEDemandElement* demandElement) {
1803
second.push_back(demandElement);
1804
}
1805
1806
1807
const GNEEdge::StackPosition&
1808
GNEEdge::StackDemandElements::getStackPosition() const {
1809
return first;
1810
}
1811
1812
1813
const std::vector<GNEDemandElement*>&
1814
GNEEdge::StackDemandElements::getDemandElements() const {
1815
return second;
1816
}
1817
1818
1819
void
1820
GNEEdge::setAttribute(SumoXMLAttr key, const std::string& value) {
1821
switch (key) {
1822
case SUMO_ATTR_ID:
1823
myNet->getAttributeCarriers()->updateEdgeID(this, value);
1824
// enable save demand elements if there are stops
1825
for (const auto& stop : getChildDemandElements()) {
1826
if (stop->getTagProperty()->isVehicleStop()) {
1827
myNet->getSavingStatus()->requireSaveDemandElements();
1828
}
1829
}
1830
// also for lanes
1831
for (const auto& lane : getChildLanes()) {
1832
for (const auto& stop : lane->getChildDemandElements()) {
1833
if (stop->getTagProperty()->isVehicleStop()) {
1834
myNet->getSavingStatus()->requireSaveDemandElements();
1835
}
1836
}
1837
}
1838
break;
1839
case SUMO_ATTR_FROM:
1840
myNet->changeEdgeEndpoints(this, value, getToJunction()->getID());
1841
// update this edge of list of outgoings edges of the old first parent junction
1842
getFromJunction()->removeOutgoingGNEEdge(this);
1843
// update first parent junction
1844
updateFirstParentJunction(value);
1845
// update this edge of list of outgoings edges of the new first parent junction
1846
getFromJunction()->addOutgoingGNEEdge(this);
1847
// update centering boundary and grid
1848
updateCenteringBoundary(true);
1849
break;
1850
case SUMO_ATTR_TO:
1851
myNet->changeEdgeEndpoints(this, getFromJunction()->getID(), value);
1852
// update this edge of list of incomings edges of the old second parent junction
1853
getToJunction()->removeIncomingGNEEdge(this);
1854
// update second parent junction
1855
updateSecondParentJunction(value);
1856
// update this edge of list of incomings edges of the new second parent junction
1857
getToJunction()->addIncomingGNEEdge(this);
1858
// update centering boundary and grid
1859
updateCenteringBoundary(true);
1860
break;
1861
case SUMO_ATTR_NUMLANES:
1862
throw InvalidArgument("GNEEdge::setAttribute (private) called for attr SUMO_ATTR_NUMLANES. This should never happen");
1863
case SUMO_ATTR_PRIORITY:
1864
myNBEdge->myPriority = parse<int>(value);
1865
break;
1866
case SUMO_ATTR_LENGTH:
1867
if (value.empty()) {
1868
myNBEdge->setLoadedLength(NBEdge::UNSPECIFIED_LOADED_LENGTH);
1869
} else {
1870
myNBEdge->setLoadedLength(parse<double>(value));
1871
}
1872
break;
1873
case SUMO_ATTR_TYPE:
1874
myNBEdge->myType = value;
1875
break;
1876
case SUMO_ATTR_SHAPE:
1877
// set new geometry
1878
setGeometry(parse<PositionVector>(value), true);
1879
// update centering boundary and grid
1880
updateCenteringBoundary(true);
1881
break;
1882
case SUMO_ATTR_SPREADTYPE:
1883
myNBEdge->setLaneSpreadFunction(SUMOXMLDefinitions::LaneSpreadFunctions.get(value));
1884
break;
1885
case SUMO_ATTR_NAME:
1886
myNBEdge->setStreetName(value);
1887
break;
1888
case SUMO_ATTR_SPEED:
1889
myNBEdge->setSpeed(-1, parse<double>(value));
1890
break;
1891
case SUMO_ATTR_FRICTION:
1892
myNBEdge->setFriction(-1, parse<double>(value));
1893
break;
1894
case SUMO_ATTR_WIDTH:
1895
if (value.empty() || (value == "default")) {
1896
myNBEdge->setLaneWidth(-1, NBEdge::UNSPECIFIED_WIDTH);
1897
} else {
1898
myNBEdge->setLaneWidth(-1, parse<double>(value));
1899
}
1900
break;
1901
case SUMO_ATTR_ENDOFFSET:
1902
myNBEdge->setEndOffset(-1, parse<double>(value));
1903
break;
1904
case SUMO_ATTR_ALLOW:
1905
break; // no edge value
1906
case SUMO_ATTR_DISALLOW:
1907
break; // no edge value
1908
case SUMO_ATTR_DISTANCE:
1909
if (value.empty()) {
1910
myNBEdge->setDistance(0.0);
1911
} else {
1912
myNBEdge->setDistance(parse<double>(value));
1913
}
1914
break;
1915
case GNE_ATTR_MODIFICATION_STATUS:
1916
myConnectionStatus = value;
1917
if (value == FEATURE_GUESSED) {
1918
myNBEdge->invalidateConnections(true);
1919
clearGNEConnections();
1920
} else if (value != FEATURE_GUESSED) {
1921
myNBEdge->declareConnectionsAsLoaded();
1922
}
1923
break;
1924
case GNE_ATTR_SHAPE_START: {
1925
// get geometry of NBEdge, remove FIRST element with the new value (or with the Junction Source position) and set it back to edge
1926
Position newShapeStart;
1927
if (value == "") {
1928
newShapeStart = getFromJunction()->getNBNode()->getPosition();
1929
} else {
1930
newShapeStart = parse<Position>(value);
1931
}
1932
// set shape start position
1933
setShapeStartPos(newShapeStart);
1934
// update centering boundary and grid
1935
updateCenteringBoundary(true);
1936
break;
1937
}
1938
case GNE_ATTR_SHAPE_END: {
1939
// get geometry of NBEdge, remove LAST element with the new value (or with the Junction Destination position) and set it back to edge
1940
Position newShapeEnd;
1941
if (value == "") {
1942
newShapeEnd = getToJunction()->getNBNode()->getPosition();
1943
} else {
1944
newShapeEnd = parse<Position>(value);
1945
}
1946
// set shape end position
1947
setShapeEndPos(newShapeEnd);
1948
// update centering boundary and grid
1949
updateCenteringBoundary(true);
1950
break;
1951
}
1952
case GNE_ATTR_BIDIR:
1953
myNBEdge->setBidi(parse<bool>(value));
1954
break;
1955
case GNE_ATTR_STOPOFFSET:
1956
if (value.empty()) {
1957
myNBEdge->myEdgeStopOffset.setOffset(0);
1958
} else {
1959
myNBEdge->myEdgeStopOffset.setOffset(parse<double>(value));
1960
}
1961
break;
1962
case GNE_ATTR_STOPOEXCEPTION:
1963
myNBEdge->myEdgeStopOffset.setExceptions(value);
1964
break;
1965
default:
1966
setCommonAttribute(key, value);
1967
break;
1968
}
1969
// get template editor
1970
GNEInspectorFrame::TemplateEditor* templateEditor = myNet->getViewParent()->getInspectorFrame()->getTemplateEditor();
1971
// check if update template (except for modification status)
1972
if (templateEditor->getEdgeTemplate() && (templateEditor->getEdgeTemplate()->getID() == getID()) &&
1973
(key != GNE_ATTR_MODIFICATION_STATUS)) {
1974
myNet->getViewParent()->getInspectorFrame()->getTemplateEditor()->updateEdgeTemplate();
1975
}
1976
// invalidate demand path calculator
1977
myNet->getDemandPathManager()->getPathCalculator()->invalidatePathCalculator();
1978
}
1979
1980
1981
void
1982
GNEEdge::setNumLanes(int numLanes, GNEUndoList* undoList) {
1983
// begin undo list
1984
undoList->begin(this, "change number of " + toString(SUMO_TAG_LANE) + "s");
1985
// invalidate logic of source/destination edges
1986
getFromJunction()->setLogicValid(false, undoList);
1987
getToJunction()->setLogicValid(false, undoList);
1988
// disable update geometry (see #6336)
1989
myUpdateGeometry = false;
1990
// remove edge from grid
1991
myNet->removeGLObjectFromGrid(this);
1992
// save old number of lanes
1993
const int oldNumLanes = (int)getChildLanes().size();
1994
// get opposite ID
1995
const auto oppositeID = getChildLanes().back()->getAttribute(GNE_ATTR_OPPOSITE);
1996
if (oppositeID != "") {
1997
// we'll have a different leftmost lane after adding/removing lanes
1998
GNEChange_Attribute::changeAttribute(getChildLanes().back(), GNE_ATTR_OPPOSITE, "", undoList);
1999
}
2000
for (int i = oldNumLanes; i < numLanes; i++) {
2001
// since the GNELane does not exist yet, it cannot have yet been referenced so we only pass a zero-pointer
2002
undoList->add(new GNEChange_Lane(this, myNBEdge->getLaneStruct(oldNumLanes - 1)), true);
2003
}
2004
for (int i = (oldNumLanes - 1); i > (numLanes - 1); i--) {
2005
myNet->deleteLane(getChildLanes().at(i), undoList, false);
2006
}
2007
if (oppositeID != "") {
2008
GNEChange_Attribute::changeAttribute(getChildLanes().back(), GNE_ATTR_OPPOSITE, oppositeID, undoList);
2009
}
2010
// enable updateGeometry again
2011
myUpdateGeometry = true;
2012
// update geometry of entire edge
2013
updateGeometry();
2014
// end undo list
2015
undoList->end();
2016
// update centering boundary (without updating RTREE)
2017
updateCenteringBoundary(false);
2018
// insert edge in grid again
2019
myNet->addGLObjectIntoGrid(this);
2020
}
2021
2022
2023
void
2024
GNEEdge::updateFirstParentJunction(const std::string& value) {
2025
auto newJunction = myNet->getAttributeCarriers()->retrieveJunction(value);
2026
GNEHierarchicalElement::updateParent(this, 0, newJunction);
2027
}
2028
2029
2030
void
2031
GNEEdge::updateSecondParentJunction(const std::string& value) {
2032
auto newJunction = myNet->getAttributeCarriers()->retrieveJunction(value);
2033
GNEHierarchicalElement::updateParent(this, 1, newJunction);
2034
}
2035
2036
2037
void
2038
GNEEdge::addLane(GNELane* lane, const NBEdge::Lane& laneAttrs, bool recomputeConnections) {
2039
const int index = lane ? lane->getIndex() : myNBEdge->getNumLanes();
2040
// the laneStruct must be created first to ensure we have some geometry
2041
// unless the connections are fully recomputed, existing indices must be shifted
2042
myNBEdge->addLane(index, true, recomputeConnections, !recomputeConnections);
2043
if (lane) {
2044
// restore a previously deleted lane
2045
GNEHierarchicalContainerChildren<GNELane*> newParentLanes = getChildLanes();
2046
newParentLanes.insert(newParentLanes.begin() + index, lane);
2047
while (getChildLanes().size() > 0) {
2048
removeChild(this, getChildLanes().front());
2049
}
2050
for (const auto newParentLane : newParentLanes) {
2051
insertChild(this, newParentLane);
2052
}
2053
} else {
2054
// create a new lane by copying leftmost lane
2055
lane = new GNELane(this, index);
2056
getHierarchicalElement()->addChildElement(lane);
2057
}
2058
lane->incRef("GNEEdge::addLane");
2059
// add in attributeCarriers
2060
myNet->getAttributeCarriers()->insertLane(lane);
2061
// check if lane is selected
2062
if (lane->isAttributeCarrierSelected()) {
2063
lane->selectAttributeCarrier();
2064
}
2065
// we copy all attributes except shape since this is recomputed from edge shape
2066
myNBEdge->setSpeed(lane->getIndex(), laneAttrs.speed);
2067
myNBEdge->setFriction(lane->getIndex(), laneAttrs.friction);
2068
myNBEdge->setPermissions(laneAttrs.permissions, lane->getIndex());
2069
myNBEdge->setPreferredVehicleClass(laneAttrs.preferred, lane->getIndex());
2070
myNBEdge->setEndOffset(lane->getIndex(), laneAttrs.endOffset);
2071
myNBEdge->setLaneWidth(lane->getIndex(), laneAttrs.width);
2072
// update indices
2073
for (int i = 0; i < (int)getChildLanes().size(); ++i) {
2074
getChildLanes()[i]->setIndex(i);
2075
}
2076
/* while technically correct, this looks ugly
2077
getFromJunction()->invalidateShape();
2078
getToJunction()->invalidateShape();
2079
*/
2080
// Remake connections for this edge and all edges that target this lane
2081
remakeGNEConnections();
2082
// remake connections of all edges of junction source and destination
2083
for (const auto& fromEdge : getFromJunction()->getChildEdges()) {
2084
fromEdge->remakeGNEConnections();
2085
}
2086
// remake connections of all edges of junction source and destination
2087
for (const auto& toEdge : getToJunction()->getChildEdges()) {
2088
toEdge->remakeGNEConnections();
2089
}
2090
// Update geometry with the new lane
2091
updateGeometry();
2092
// update boundary and grid
2093
updateCenteringBoundary(myUpdateGeometry);
2094
}
2095
2096
2097
void
2098
GNEEdge::removeLane(GNELane* lane, bool recomputeConnections) {
2099
if (getChildLanes().size() == 0) {
2100
throw ProcessError("Should not remove the last " + toString(SUMO_TAG_LANE) + " from an " + getTagStr());
2101
}
2102
if (lane == nullptr) {
2103
lane = getChildLanes().back();
2104
}
2105
// check if lane is selected
2106
if (lane->isAttributeCarrierSelected()) {
2107
lane->unselectAttributeCarrier();
2108
}
2109
// before removing, check that lane isn't being inspected
2110
myNet->getViewNet()->getInspectedElements().uninspectAC(lane);
2111
myNet->getViewParent()->getInspectorFrame()->getHierarchicalElementTree()->removeCurrentEditedAttributeCarrier(lane);
2112
// Delete lane of edge's container
2113
// unless the connections are fully recomputed, existing indices must be shifted
2114
myNBEdge->deleteLane(lane->getIndex(), recomputeConnections, !recomputeConnections);
2115
lane->decRef("GNEEdge::removeLane");
2116
// delete lane from edge
2117
GNEHierarchicalElement::removeChild(this, lane);
2118
// remove from attributeCarriers
2119
myNet->getAttributeCarriers()->deleteLane(lane);
2120
// Delete lane if is unreferenced
2121
if (lane->unreferenced()) {
2122
delete lane;
2123
}
2124
// update indices
2125
for (int i = 0; i < (int)getChildLanes().size(); ++i) {
2126
getChildLanes()[i]->setIndex(i);
2127
}
2128
/* while technically correct, this looks ugly
2129
getFromJunction()->invalidateShape();
2130
getToJunction()->invalidateShape();
2131
*/
2132
// Remake connections of this edge
2133
remakeGNEConnections();
2134
// remake connections of all edges of junction source and destination
2135
for (const auto& fromEdge : getFromJunction()->getChildEdges()) {
2136
fromEdge->remakeGNEConnections();
2137
}
2138
// remake connections of all edges of junction source and destination
2139
for (const auto& toEdge : getToJunction()->getChildEdges()) {
2140
toEdge->remakeGNEConnections();
2141
}
2142
// Update element
2143
updateGeometry();
2144
// update boundary and grid
2145
updateCenteringBoundary(myUpdateGeometry);
2146
}
2147
2148
2149
void
2150
GNEEdge::addConnection(NBEdge::Connection nbCon, bool selectAfterCreation) {
2151
// If a new connection was successfully created
2152
if (myNBEdge->setConnection(nbCon.fromLane, nbCon.toEdge, nbCon.toLane, NBEdge::Lane2LaneInfoType::USER, true, nbCon.mayDefinitelyPass,
2153
nbCon.keepClear, nbCon.contPos, nbCon.visibility,
2154
nbCon.speed, nbCon.friction, nbCon.customLength, nbCon.customShape, nbCon.uncontrolled)) {
2155
// Create or retrieve existent GNEConnection
2156
GNEConnection* con = retrieveGNEConnection(nbCon.fromLane, nbCon.toEdge, nbCon.toLane);
2157
// add it to GNEConnection container
2158
myGNEConnections.push_back(con);
2159
// Add reference
2160
myGNEConnections.back()->incRef("GNEEdge::addConnection");
2161
// select GNEConnection if needed
2162
if (selectAfterCreation) {
2163
con->selectAttributeCarrier();
2164
}
2165
// update geometry
2166
con->updateGeometry();
2167
}
2168
// actually we only do this to force a redraw
2169
updateGeometry();
2170
}
2171
2172
2173
void
2174
GNEEdge::removeConnection(NBEdge::Connection nbCon) {
2175
// check if is a explicit turnaround
2176
if (nbCon.toEdge == myNBEdge->getTurnDestination()) {
2177
myNet->removeExplicitTurnaround(getID());
2178
}
2179
// remove NBEdge::connection from NBEdge
2180
myNBEdge->removeFromConnections(nbCon);
2181
// remove their associated GNEConnection
2182
GNEConnection* connection = retrieveGNEConnection(nbCon.fromLane, nbCon.toEdge, nbCon.toLane, false);
2183
if (connection != nullptr) {
2184
// before removing, check that the connection isn't being inspected
2185
myNet->getViewNet()->getInspectedElements().uninspectAC(connection);
2186
myNet->getViewParent()->getInspectorFrame()->getHierarchicalElementTree()->removeCurrentEditedAttributeCarrier(connection);
2187
connection->decRef("GNEEdge::removeConnection");
2188
myGNEConnections.erase(std::find(myGNEConnections.begin(), myGNEConnections.end(), connection));
2189
// check if connection is selected
2190
if (connection->isAttributeCarrierSelected()) {
2191
connection->unselectAttributeCarrier();
2192
}
2193
// remove it from network
2194
myNet->removeGLObjectFromGrid(connection);
2195
// check if remove it from Attribute Carriers
2196
if (myNet->getAttributeCarriers()->getConnections().count(connection) > 0) {
2197
myNet->getAttributeCarriers()->deleteConnection(connection);
2198
}
2199
if (connection->unreferenced()) {
2200
// actually we only do this to force a redraw
2201
updateGeometry();
2202
}
2203
}
2204
}
2205
2206
2207
GNEConnection*
2208
GNEEdge::retrieveGNEConnection(int fromLane, NBEdge* to, int toLane, bool createIfNoExist) {
2209
for (const auto& connection : myGNEConnections) {
2210
if ((connection->getFromLaneIndex() == fromLane) && (connection->getEdgeTo()->getNBEdge() == to) && (connection->getToLaneIndex() == toLane)) {
2211
return connection;
2212
}
2213
}
2214
if (createIfNoExist) {
2215
// create new connection. Will be added to the rTree on first geometry computation
2216
GNEConnection* connection = new GNEConnection(getChildLanes()[fromLane], myNet->getAttributeCarriers()->retrieveEdge(to->getID())->getChildLanes()[toLane]);
2217
// add it into network
2218
myNet->addGLObjectIntoGrid(connection);
2219
// add it in attributeCarriers
2220
myNet->getAttributeCarriers()->insertConnection(connection);
2221
return connection;
2222
} else {
2223
return nullptr;
2224
}
2225
}
2226
2227
2228
void
2229
GNEEdge::setEdgeID(const std::string& newID) {
2230
setNetworkElementID(newID);
2231
for (const auto& lane : getChildLanes()) {
2232
lane->setNetworkElementID(getNBEdge()->getLaneID(lane->getIndex()));
2233
}
2234
}
2235
2236
2237
bool
2238
GNEEdge::hasRestrictedLane(SUMOVehicleClass vclass) const {
2239
for (const auto& lane : getChildLanes()) {
2240
if (lane->isRestricted(vclass)) {
2241
return true;
2242
}
2243
}
2244
return false;
2245
}
2246
2247
2248
void
2249
GNEEdge::removeEdgeFromCrossings(GNEJunction* junction, GNEUndoList* undoList) {
2250
// Remove all crossings that contain this edge in parameter "edges"
2251
for (const auto& crossing : junction->getGNECrossings()) {
2252
if (crossing->checkEdgeBelong(this)) {
2253
myNet->deleteCrossing(crossing, undoList);
2254
}
2255
}
2256
}
2257
2258
2259
void
2260
GNEEdge::straightenElevation(GNEUndoList* undoList) {
2261
PositionVector modifiedShape = myNBEdge->getGeometry().interpolateZ(
2262
myNBEdge->getFromNode()->getPosition().z(),
2263
myNBEdge->getToNode()->getPosition().z());
2264
PositionVector innerShape(modifiedShape.begin() + 1, modifiedShape.end() - 1);
2265
setAttribute(SUMO_ATTR_SHAPE, toString(innerShape), undoList);
2266
}
2267
2268
2269
PositionVector
2270
GNEEdge::smoothShape(const PositionVector& old, bool forElevation) {
2271
const auto& neteditOptions = OptionsCont::getOptions();
2272
// distinguish 3 cases:
2273
// a) if the edge has exactly 3 or 4 points, use these as control points
2274
// b) if the edge has more than 4 points, use the first 2 and the last 2 as control points
2275
// c) if the edge is straight and both nodes are geometry-like nodes, use geometry of the continuation edges as control points
2276
PositionVector init;
2277
#ifdef DEBUG_SMOOTH_GEOM
2278
if (DEBUGCOND(this)) std::cout << getID()
2279
<< " forElevation=" << forElevation
2280
<< " fromGeometryLike=" << myNBEdge->getFromNode()->geometryLike()
2281
<< " toGeometryLike=" << myNBEdge->getToNode()->geometryLike()
2282
<< " smoothShape old=" << old << "\n";
2283
#endif
2284
if (old.size() == 3 || old.size() == 4) {
2285
init = old;
2286
} else if (old.size() > 4 && !forElevation) {
2287
// for elevation, the initial segments are not useful
2288
init.push_back(old[0]);
2289
init.push_back(old[1]);
2290
init.push_back(old[-2]);
2291
init.push_back(old[-1]);
2292
} else if (myNBEdge->getFromNode()->geometryLike() && myNBEdge->getToNode()->geometryLike()) {
2293
PositionVector begShape;
2294
PositionVector endShape;
2295
const EdgeVector& incoming = myNBEdge->getFromNode()->getIncomingEdges();
2296
const EdgeVector& outgoing = myNBEdge->getToNode()->getOutgoingEdges();
2297
if (incoming.size() == 1) {
2298
begShape = incoming[0]->getGeometry();
2299
} else {
2300
assert(incoming.size() == 2);
2301
begShape = myNBEdge->isTurningDirectionAt(incoming[0]) ? incoming[1]->getGeometry() : incoming[0]->getGeometry();
2302
}
2303
if (outgoing.size() == 1) {
2304
endShape = outgoing[0]->getGeometry();
2305
} else {
2306
assert(outgoing.size() == 2);
2307
endShape = myNBEdge->isTurningDirectionAt(outgoing[0]) ? outgoing[1]->getGeometry() : outgoing[0]->getGeometry();
2308
}
2309
const double dist = MIN2(old.length2D(), MAX2(old.length2D() / 8, fabs(old[0].z() - old[-1].z()) * OptionsCont::getOptions().getFloat("geometry.max-grade") / 3));
2310
if (forElevation) {
2311
// initialize control point elevation for smooth continuation
2312
init.push_back(old[0]);
2313
init.push_back(old.positionAtOffset2D(dist));
2314
init.push_back(old.positionAtOffset2D(old.length2D() - dist));
2315
init.push_back(old[-1]);
2316
double begZ = begShape.positionAtOffset2D(MAX2(0.0, begShape.length2D() - dist)).z();
2317
double endZ = endShape.positionAtOffset2D(MIN2(begShape.length2D(), dist)).z();
2318
// continue incline
2319
init[1].setz(2 * init[0].z() - begZ);
2320
init[2].setz(2 * init[-1].z() - endZ);
2321
} else {
2322
bool ok = true;
2323
const double straightThresh = DEG2RAD(neteditOptions.getFloat("opendrive-output.straight-threshold"));
2324
init = NBNode::bezierControlPoints(begShape, endShape, false, dist, dist, ok, nullptr, straightThresh);
2325
}
2326
#ifdef DEBUG_SMOOTH_GEOM
2327
if (DEBUGCOND(this)) {
2328
std::cout << " begShape=" << begShape << " endShape=" << endShape << " forElevation=" << forElevation << " dist=" << dist << " ok=" << ok << " init=" << init << "\n";
2329
}
2330
#endif
2331
}
2332
if (init.size() == 0) {
2333
return PositionVector::EMPTY;
2334
} else {
2335
const int numPoints = MAX2(neteditOptions.getInt("junctions.internal-link-detail"),
2336
int(old.length2D() / neteditOptions.getFloat("opendrive.curve-resolution")));
2337
return init.bezier(numPoints);
2338
}
2339
}
2340
2341
2342
void
2343
GNEEdge::smooth(GNEUndoList* undoList) {
2344
PositionVector modifiedShape = smoothShape(myNBEdge->getGeometry(), false);
2345
if (modifiedShape.size() < 2) {
2346
WRITE_WARNINGF(TL("Could not compute smooth shape for edge '%'"), getID());
2347
} else {
2348
PositionVector innerShape(modifiedShape.begin() + 1, modifiedShape.end() - 1);
2349
setAttribute(SUMO_ATTR_SHAPE, toString(innerShape), undoList);
2350
}
2351
}
2352
2353
2354
void
2355
GNEEdge::smoothElevation(GNEUndoList* undoList) {
2356
PositionVector elevationBase;
2357
for (const Position& pos : myNBEdge->getGeometry()) {
2358
if (elevationBase.size() == 0 || elevationBase[-1].z() != pos.z()) {
2359
elevationBase.push_back(pos);
2360
}
2361
}
2362
PositionVector elevation = smoothShape(elevationBase, true);
2363
if (elevation.size() <= 2) {
2364
WRITE_WARNINGF(TL("Could not compute smooth elevation for edge '%'"), getID());
2365
} else {
2366
PositionVector modifiedShape = myNBEdge->getGeometry();
2367
if (modifiedShape.size() < 5) {
2368
modifiedShape = modifiedShape.resample(OptionsCont::getOptions().getFloat("opendrive.curve-resolution"), false);
2369
}
2370
const double scale = elevation.length2D() / modifiedShape.length2D();
2371
//std::cout << " elevation=" << elevation << "\n mod1=" << modifiedShape << " scale=" << scale << "\n";
2372
double seen = 0;
2373
for (int i = 1; i < (int)modifiedShape.size(); ++i) {
2374
seen += modifiedShape[i - 1].distanceTo2D(modifiedShape[i]);
2375
modifiedShape[i].setz(elevation.positionAtOffset2D(seen * scale).z());
2376
}
2377
//std::cout << " mod2=" << modifiedShape << "\n";
2378
PositionVector innerShape(modifiedShape.begin() + 1, modifiedShape.end() - 1);
2379
setAttribute(SUMO_ATTR_SHAPE, toString(innerShape), undoList);
2380
}
2381
}
2382
2383
2384
void
2385
GNEEdge::setShapeStartPos(const Position& pos) {
2386
// remove start position and add it the new position
2387
PositionVector geom = myNBEdge->getGeometry();
2388
geom.pop_front();
2389
geom.push_front(pos);
2390
// restore modified shape
2391
setGeometry(geom, false);
2392
}
2393
2394
2395
void
2396
GNEEdge::setShapeEndPos(const Position& pos) {
2397
// remove end position and add it the new position
2398
PositionVector geom = myNBEdge->getGeometry();
2399
geom.pop_back();
2400
geom.push_back(pos);
2401
// restore modified shape
2402
setGeometry(geom, false);
2403
}
2404
2405
2406
const std::map<const GNELane*, std::vector<GNEDemandElement*> >
2407
GNEEdge::getVehiclesOverEdgeMap() const {
2408
// declare vehicles over edge vector
2409
std::vector<GNEDemandElement*> vehiclesOverEdge;
2410
// declare solution map
2411
std::map<const GNELane*, std::vector<GNEDemandElement*> > vehiclesOverEdgeMap;
2412
// declare a set of vehicles (to avoid duplicates)
2413
std::set<std::pair<double, GNEDemandElement*> > vehicles;
2414
// first obtain all vehicles of this edge
2415
for (const auto& edgeChild : getChildDemandElements()) {
2416
if (((edgeChild->getTagProperty()->getTag() == SUMO_TAG_TRIP) || (edgeChild->getTagProperty()->getTag() == SUMO_TAG_FLOW)) &&
2417
(edgeChild->getParentEdges().front() == this)) {
2418
vehicles.insert(std::make_pair(edgeChild->getAttributeDouble(SUMO_ATTR_DEPART), edgeChild));
2419
vehicles.insert(std::make_pair(edgeChild->getAttributeDouble(SUMO_ATTR_DEPART), edgeChild));
2420
} else if ((edgeChild->getTagProperty()->getTag() == SUMO_TAG_ROUTE) && (edgeChild->getParentEdges().front() == this)) {
2421
for (const auto& routeChild : edgeChild->getChildDemandElements()) {
2422
if (routeChild->getTagProperty()->vehicleRoute()) {
2423
vehicles.insert(std::make_pair(routeChild->getAttributeDouble(SUMO_ATTR_DEPART), routeChild));
2424
}
2425
}
2426
} else if ((edgeChild->getTagProperty()->getTag() == GNE_TAG_ROUTE_EMBEDDED) && (edgeChild->getParentEdges().front() == this) && (edgeChild->getParentDemandElements().size() > 0)) {
2427
vehicles.insert(std::make_pair(edgeChild->getParentDemandElements().front()->getAttributeDouble(SUMO_ATTR_DEPART), edgeChild->getParentDemandElements().front()));
2428
}
2429
}
2430
// reserve
2431
vehiclesOverEdge.reserve(vehicles.size());
2432
// iterate over vehicles
2433
for (const auto& vehicle : vehicles) {
2434
// add it over vehiclesOverEdge;
2435
vehiclesOverEdge.push_back(vehicle.second);
2436
}
2437
// now split vehicles by lanes
2438
for (const auto& vehicle : vehiclesOverEdge) {
2439
const GNELane* vehicleLane = vehicle->getFirstPathLane();
2440
if (vehicleLane) {
2441
vehiclesOverEdgeMap[vehicleLane].push_back(vehicle);
2442
}
2443
}
2444
return vehiclesOverEdgeMap;
2445
}
2446
2447
2448
const std::map<const GNELane*, std::vector<GNEDemandElement*> >
2449
GNEEdge::getPersonsOverEdgeMap() const {
2450
// declare persons over edge vector
2451
std::vector<GNEDemandElement*> personsOverEdge;
2452
// declare solution map
2453
std::map<const GNELane*, std::vector<GNEDemandElement*> > personsOverEdgeMap;
2454
// declare a set of persons (to avoid duplicates)
2455
std::set<std::pair<double, GNEDemandElement*> > persons;
2456
// first obtain all persons of this edge
2457
for (const auto& edgeChild : getChildDemandElements()) {
2458
if (edgeChild->getTagProperty()->isPlanPerson() && (edgeChild->getParentDemandElements().size() > 0)) {
2459
persons.insert(std::make_pair(edgeChild->getParentDemandElements().front()->getAttributeDouble(SUMO_ATTR_DEPARTPOS), edgeChild->getParentDemandElements().front()));
2460
}
2461
}
2462
// reserve
2463
personsOverEdge.reserve(persons.size());
2464
// iterate over persons
2465
for (const auto& person : persons) {
2466
// add it over personsOverEdge;
2467
personsOverEdge.push_back(person.second);
2468
}
2469
// now split persons by lanes
2470
for (const auto& person : personsOverEdge) {
2471
const GNELane* personLane = person->getFirstPathLane();
2472
if (personLane) {
2473
personsOverEdgeMap[personLane].push_back(person);
2474
}
2475
}
2476
return personsOverEdgeMap;
2477
}
2478
2479
2480
2481
const std::map<const GNELane*, std::vector<GNEDemandElement*> >
2482
GNEEdge::getContainersOverEdgeMap() const {
2483
// declare containers over edge vector
2484
std::vector<GNEDemandElement*> containersOverEdge;
2485
// declare solution map
2486
std::map<const GNELane*, std::vector<GNEDemandElement*> > containersOverEdgeMap;
2487
// declare a set of containers (to avoid duplicates)
2488
std::set<std::pair<double, GNEDemandElement*> > containers;
2489
// first obtain all containers of this edge
2490
for (const auto& edgeChild : getChildDemandElements()) {
2491
if (edgeChild->getTagProperty()->isPlanContainer() && (edgeChild->getParentDemandElements().size() > 0)) {
2492
containers.insert(std::make_pair(edgeChild->getParentDemandElements().front()->getAttributeDouble(SUMO_ATTR_DEPARTPOS), edgeChild->getParentDemandElements().front()));
2493
}
2494
}
2495
// reserve
2496
containersOverEdge.reserve(containers.size());
2497
// iterate over containers
2498
for (const auto& container : containers) {
2499
// add it over containersOverEdge;
2500
containersOverEdge.push_back(container.second);
2501
}
2502
// now split containers by lanes
2503
for (const auto& container : containersOverEdge) {
2504
const GNELane* containerLane = container->getFirstPathLane();
2505
if (containerLane) {
2506
containersOverEdgeMap[containerLane].push_back(container);
2507
}
2508
}
2509
return containersOverEdgeMap;
2510
}
2511
2512
2513
void
2514
GNEEdge::drawEdgeGeometryPoints(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const double layer) const {
2515
// first check conditions
2516
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork() && (d <= GUIVisualizationSettings::Detail::GeometryPoint)) {
2517
// check if draw geometry points
2518
const bool bigGeometryPoints = drawBigGeometryPoints();
2519
// Obtain exaggeration of the draw
2520
const double exaggeration = getExaggeration(s);
2521
// get geometry point radius
2522
const double geometryPointRadius = getGeometryPointRadius();
2523
// obtain geometry point color
2524
RGBColor geometryPointColor = s.junctionColorer.getSchemes()[0].getColor(2);
2525
if (drawUsingSelectColor() && s.laneColorer.getActive() != 1) {
2526
// override with special colors (unless the color scheme is based on selection)
2527
geometryPointColor = s.colorSettings.selectedEdgeColor.changedBrightness(-20);
2528
}
2529
// draw geometry points except initial and final
2530
for (int i = 1; i < (int)myNBEdge->getGeometry().size() - 1; i++) {
2531
// obtain geometry point
2532
const auto geometryPointPos = myNBEdge->getGeometry()[i];
2533
// push geometry point drawing matrix
2534
GLHelper::pushMatrix();
2535
// set color
2536
GLHelper::setColor(geometryPointColor);
2537
// move geometry point geometryPointPos
2538
glTranslated(geometryPointPos.x(), geometryPointPos.y(), bigGeometryPoints ? GLO_GEOMETRYPOINT : GLO_LANE + 1);
2539
// draw filled circle (resolution of drawn circle depending of the zoom, to improve smoothness)
2540
GLHelper::drawFilledCircleDetailled(d, geometryPointRadius);
2541
// draw elevation or special symbols (Start, End and Block)
2542
if ((d <= GUIVisualizationSettings::Detail::Text) && myNet->getViewNet()->getNetworkViewOptions().editingElevation()) {
2543
// Translate to top
2544
glTranslated(0, 0, 0.2);
2545
// draw Z value
2546
GLHelper::drawText(toString(geometryPointPos.z()), Position(), 0, s.edgeValue.scaledSize(s.scale) / 2, s.edgeValue.color);
2547
}
2548
// pop geometry point drawing matrix
2549
GLHelper::popMatrix();
2550
}
2551
// draw start and end points
2552
if (bigGeometryPoints) {
2553
drawStartGeometryPoint(s, d, geometryPointRadius, layer, exaggeration);
2554
drawEndGeometryPoint(s, d, geometryPointRadius, layer, exaggeration);
2555
}
2556
// draw dotted contour geometry points
2557
myNetworkElementContour.drawDottedContourGeometryPoints(s, d, this, myNBEdge->getGeometry(), geometryPointRadius,
2558
exaggeration, s.dottedContourSettings.segmentWidthSmall);
2559
}
2560
}
2561
2562
2563
void
2564
GNEEdge::drawStartGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
2565
const double geometryPointRadius, const double layer, const double exaggeration) const {
2566
// check detail level
2567
if (d <= GUIVisualizationSettings::Detail::GeometryPoint) {
2568
// get first geometry point
2569
const auto& startGeometryPointPos = myNBEdge->getGeometry().front();
2570
// get flags
2571
const bool startPosEdited = (startGeometryPointPos != getParentJunctions().front()->getPositionInView());
2572
const bool forceDraw = myNet->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getForceDrawGeometryPoints();
2573
// check drawing conditions
2574
if (startPosEdited || forceDraw) {
2575
// calculate angle betwen first and second geometry point
2576
const double angle = RAD2DEG(startGeometryPointPos.angleTo2D(myNBEdge->getGeometry()[1])) * -1;
2577
// get selected geometry points
2578
const auto selectedGeometryPoints = gViewObjectsHandler.getSelectedGeometryPoints(this);
2579
// override with special colors (unless the color scheme is based on selection)
2580
if (drawUsingSelectColor() && s.laneColorer.getActive() != 1) {
2581
GLHelper::setColor(s.colorSettings.selectedEdgeColor.changedBrightness(-20));
2582
} else {
2583
GLHelper::setColor(s.junctionColorer.getSchemes()[0].getColor(2));
2584
}
2585
// push drawing matrix
2586
GLHelper::pushMatrix();
2587
// move to point position
2588
glTranslated(startGeometryPointPos.x(), startGeometryPointPos.y(), GLO_GEOMETRYPOINT);
2589
// resolution of drawn circle depending of detail
2590
GLHelper::drawFilledCircleDetailled(d, geometryPointRadius, angle + 90, angle + 270);
2591
// pop drawing matrix
2592
GLHelper::popMatrix();
2593
// draw a "s" over last point depending of detail level
2594
if (d <= GUIVisualizationSettings::Detail::Text) {
2595
// push drawing matrix
2596
GLHelper::pushMatrix();
2597
// move top
2598
glTranslated(0, 0, GLO_GEOMETRYPOINT + 0.1);
2599
// draw S
2600
GLHelper::drawText("S", startGeometryPointPos, 0, geometryPointRadius, RGBColor(0, 50, 255));
2601
// pop drawing matrix
2602
GLHelper::popMatrix();
2603
// check if draw line between junctions
2604
if ((selectedGeometryPoints.size() > 0) && (selectedGeometryPoints.front() == 0)) {
2605
// set base color
2606
GLHelper::setColor(RGBColor::ORANGE);
2607
// push drawing matrix
2608
GLHelper::pushMatrix();
2609
// draw line between geometry point and from junction
2610
const PositionVector lineA = {startGeometryPointPos, getFromJunction()->getNBNode()->getPosition()};
2611
GLHelper::drawBoxLine(lineA[1], RAD2DEG(lineA[0].angleTo2D(lineA[1])) - 90, lineA[0].distanceTo2D(lineA[1]), .1);
2612
// draw line between begin point of last lane shape and the first edge shape point
2613
const PositionVector lineB = {startGeometryPointPos, myNBEdge->getLanes().back().shape.front()};
2614
GLHelper::drawBoxLine(lineB[1], RAD2DEG(lineB[0].angleTo2D(lineB[1])) - 90, lineB[0].distanceTo2D(lineB[1]), .1);
2615
// pop drawing matrix
2616
GLHelper::popMatrix();
2617
}
2618
}
2619
// draw dotted contour geometry points
2620
myNetworkElementContour.calculateContourFirstGeometryPoint(s, d, this, myNBEdge->getInnerGeometry(), layer,
2621
geometryPointRadius, exaggeration);
2622
}
2623
}
2624
}
2625
2626
2627
void
2628
GNEEdge::drawEndGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,
2629
const double geometryPointRadius, const double layer, const double exaggeration) const {
2630
// check detail level
2631
if (d <= GUIVisualizationSettings::Detail::GeometryPoint) {
2632
// get first geometry point
2633
const auto& geometryPointPos = myNBEdge->getGeometry().back();
2634
// get flags
2635
const bool endPosEdited = (geometryPointPos != getParentJunctions().back()->getPositionInView());
2636
const bool forceDraw = myNet->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getForceDrawGeometryPoints();
2637
// check drawing conditions
2638
if (endPosEdited || forceDraw) {
2639
// calculate angle last and previous geometry point
2640
const double angle = RAD2DEG(geometryPointPos.angleTo2D(myNBEdge->getGeometry()[-2])) * -1;
2641
// get selected geometry points
2642
const auto selectedGeometryPoints = gViewObjectsHandler.getSelectedGeometryPoints(this);
2643
// override with special colors (unless the color scheme is based on selection)
2644
if (drawUsingSelectColor() && s.laneColorer.getActive() != 1) {
2645
GLHelper::setColor(s.colorSettings.selectedEdgeColor.changedBrightness(-20));
2646
} else {
2647
GLHelper::setColor(s.junctionColorer.getSchemes()[0].getColor(2));
2648
}
2649
// push drawing matrix
2650
GLHelper::pushMatrix();
2651
// move to point position
2652
glTranslated(geometryPointPos.x(), geometryPointPos.y(), GLO_GEOMETRYPOINT);
2653
// resolution of drawn circle depending of detail
2654
GLHelper::drawFilledCircleDetailled(d, geometryPointRadius, angle + 90, angle + 270);
2655
// pop drawing matrix
2656
GLHelper::popMatrix();
2657
// draw a "s" over last point depending of detail level
2658
if (d <= GUIVisualizationSettings::Detail::Text) {
2659
// push drawing matrix
2660
GLHelper::pushMatrix();
2661
// move top
2662
glTranslated(0, 0, GLO_GEOMETRYPOINT + 0.1);
2663
// draw S
2664
GLHelper::drawText("E", geometryPointPos, 0, geometryPointRadius, RGBColor(0, 50, 255));
2665
// pop drawing matrix
2666
GLHelper::popMatrix();
2667
// check if draw line between junctions
2668
if ((selectedGeometryPoints.size() > 0) && (selectedGeometryPoints.back() == ((int)myNBEdge->getGeometry().size() - 1))) {
2669
// set base color
2670
GLHelper::setColor(RGBColor::ORANGE);
2671
// push drawing matrix
2672
GLHelper::pushMatrix();
2673
// draw line between geometry point and from junction
2674
const PositionVector lineA = {geometryPointPos, getToJunction()->getNBNode()->getPosition()};
2675
GLHelper::drawBoxLine(lineA[1], RAD2DEG(lineA[0].angleTo2D(lineA[1])) - 90, lineA[0].distanceTo2D(lineA[1]), .1);
2676
// draw line between begin point of last lane shape and the first edge shape point
2677
const PositionVector lineB = {geometryPointPos, myNBEdge->getLanes().back().shape.back()};
2678
GLHelper::drawBoxLine(lineB[1], RAD2DEG(lineB[0].angleTo2D(lineB[1])) - 90, lineB[0].distanceTo2D(lineB[1]), .1);
2679
// pop drawing matrix
2680
GLHelper::popMatrix();
2681
}
2682
}
2683
// draw dotted contour geometry points
2684
myNetworkElementContour.calculateContourFirstGeometryPoint(s, d, this, myNBEdge->getInnerGeometry(), layer,
2685
geometryPointRadius, exaggeration);
2686
}
2687
}
2688
}
2689
2690
2691
void
2692
GNEEdge::drawEdgeName(const GUIVisualizationSettings& s) const {
2693
// draw the name and/or the street name
2694
const bool drawStreetName = s.streetName.show(this) && (myNBEdge->getStreetName() != "");
2695
const bool spreadSuperposed = s.spreadSuperposed && myNBEdge->getBidiEdge() != nullptr;
2696
// check conditions
2697
if (s.edgeName.show(this) || drawStreetName || s.edgeValue.show(this)) {
2698
// get first and last lanes
2699
const GNELane* firstLane = getChildLanes()[0];
2700
const GNELane* lastLane = getChildLanes()[getChildLanes().size() - 1];
2701
// calculate draw position
2702
Position drawPosition = firstLane->getLaneShape().positionAtOffset(firstLane->getLaneShape().length() / (double) 2.);
2703
drawPosition.add(lastLane->getLaneShape().positionAtOffset(lastLane->getLaneShape().length() / (double) 2.));
2704
drawPosition.mul(.5);
2705
if (spreadSuperposed) {
2706
// move name to the right of the edge and towards its beginning
2707
const double dist = 0.6 * s.edgeName.scaledSize(s.scale);
2708
const double shiftA = firstLane->getLaneShape().rotationAtOffset(firstLane->getLaneShape().length() / (double) 2.) - DEG2RAD(135);
2709
const Position shift(dist * cos(shiftA), dist * sin(shiftA));
2710
drawPosition.add(shift);
2711
}
2712
// calculate drawing angle
2713
double drawAngle = firstLane->getLaneShape().rotationDegreeAtOffset(firstLane->getLaneShape().length() / (double) 2.);
2714
drawAngle += 90;
2715
// avoid draw inverted text
2716
if (drawAngle > 90 && drawAngle < 270) {
2717
drawAngle -= 180;
2718
}
2719
// draw edge name
2720
if (s.edgeName.show(this)) {
2721
drawName(drawPosition, s.scale, s.edgeName, drawAngle);
2722
}
2723
// draw street name
2724
if (drawStreetName) {
2725
GLHelper::drawTextSettings(s.streetName, myNBEdge->getStreetName(), drawPosition, s.scale, drawAngle);
2726
}
2727
// draw edge values
2728
if (s.edgeValue.show(this)) {
2729
// get current scheme
2730
const int activeScheme = s.laneColorer.getActive();
2731
// calculate value depending of active scheme
2732
std::string value;
2733
if (activeScheme == 12) {
2734
// edge param, could be non-numerical
2735
value = getNBEdge()->getParameter(s.edgeParam, "");
2736
} else if (activeScheme == 13) {
2737
// lane param, could be non-numerical
2738
value = getNBEdge()->getLaneStruct(lastLane->getIndex()).getParameter(s.laneParam, "");
2739
} else {
2740
// use numerical value value of leftmost lane to hopefully avoid sidewalks, bikelanes etc
2741
const double doubleValue = lastLane->getColorValue(s, activeScheme);
2742
const RGBColor color = s.laneColorer.getScheme().getColor(doubleValue);
2743
value = color.alpha() == 0 ? "" : toString(doubleValue);
2744
}
2745
// check if value is empty
2746
if (value != "") {
2747
GLHelper::drawTextSettings(s.edgeValue, value, drawPosition, s.scale, drawAngle);
2748
}
2749
}
2750
}
2751
}
2752
2753
2754
void
2755
GNEEdge::drawLaneStopOffset(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const double layer) const {
2756
// draw geometry only if we'rent in drawForObjectUnderCursor mode
2757
if (d <= GUIVisualizationSettings::Detail::LaneDetails) {
2758
// Push stopOffset matrix
2759
GLHelper::pushMatrix();
2760
// translate to front (note: Special case)
2761
drawInLayer(layer + 1);
2762
if (myNBEdge->myEdgeStopOffset.isDefined() && (myNBEdge->myEdgeStopOffset.getPermissions() & SVC_PASSENGER) != 0) {
2763
for (const auto& lane : getChildLanes()) {
2764
lane->drawLaneStopOffset(s);
2765
}
2766
}
2767
// Push stopOffset matrix
2768
GLHelper::popMatrix();
2769
}
2770
}
2771
2772
2773
void
2774
GNEEdge::drawChildrens(const GUIVisualizationSettings& s) const {
2775
// draw child additional
2776
for (const auto& additional : getChildAdditionals()) {
2777
if (!additional->getTagProperty()->isListedElement()) {
2778
additional->drawGL(s);
2779
}
2780
}
2781
// draw person stops
2782
if (myNet->getViewNet()->getNetworkViewOptions().showDemandElements() && myNet->getViewNet()->getDataViewOptions().showDemandElements()) {
2783
for (const auto& stopEdge : getChildDemandElements()) {
2784
if ((stopEdge->getTagProperty()->getTag() == GNE_TAG_STOPPERSON_EDGE) || (stopEdge->getTagProperty()->getTag() == GNE_TAG_STOPCONTAINER_EDGE)) {
2785
stopEdge->drawGL(s);
2786
}
2787
}
2788
}
2789
// draw vehicles
2790
const std::map<const GNELane*, std::vector<GNEDemandElement*> > vehiclesMap = getVehiclesOverEdgeMap();
2791
for (const auto& vehicleMap : vehiclesMap) {
2792
for (const auto& vehicle : vehicleMap.second) {
2793
vehicle->drawGL(s);
2794
}
2795
}
2796
// draw TAZ elements
2797
drawTAZElements(s);
2798
}
2799
2800
2801
void
2802
GNEEdge::calculateEdgeContour(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const double layer) const {
2803
// if we're selecting using a boundary, first don't calculate contour bt check if edge boundary is within selection boundary
2804
if (gViewObjectsHandler.selectingUsingRectangle() && gViewObjectsHandler.getSelectionTriangle().isBoundaryFullWithin(myEdgeBoundary)) {
2805
// simply add object in ViewObjectsHandler with full boundary
2806
gViewObjectsHandler.selectObject(this, layer, false, nullptr);
2807
} else {
2808
// get geometry point radius
2809
const auto geometryPointRadius = getGeometryPointRadius();
2810
// check if edit extrems
2811
const bool forceDrawExtrems = myNet->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getForceDrawGeometryPoints();
2812
const bool firstExtrem = forceDrawExtrems || (myNBEdge->getGeometry().front() != getParentJunctions().front()->getPositionInView());
2813
const bool lastExtrem = forceDrawExtrems || (myNBEdge->getGeometry().back() != getParentJunctions().back()->getPositionInView());
2814
// check if we're in move mode
2815
const bool moveMode = (myNet->getViewNet()->getEditModes().networkEditMode == NetworkEditMode::NETWORK_MOVE);
2816
// calculate contour
2817
myNetworkElementContour.calculateContourEdge(s, d, this, this, layer, true, true);
2818
// calculate edge geometry points
2819
myNetworkElementContour.calculateContourEdgeGeometryPoints(s, d, this, geometryPointRadius, moveMode, firstExtrem, lastExtrem);
2820
}
2821
}
2822
2823
2824
void
2825
GNEEdge::drawTAZElements(const GUIVisualizationSettings& s) const {
2826
// first check if draw TAZ Elements is enabled
2827
if (myNet->getViewNet()->getNetworkViewOptions().showTAZElements()) {
2828
if (getChildTAZSourceSinks().size() > 0) {
2829
// check if TAZ Source/sink is selected
2830
bool selected = false;
2831
for (const auto& TAZSourceSink : getChildTAZSourceSinks()) {
2832
if (TAZSourceSink->isAttributeCarrierSelected()) {
2833
selected = true;
2834
}
2835
}
2836
// iterate over lanes
2837
for (const auto& lane : getChildLanes()) {
2838
// Push layer matrix
2839
GLHelper::pushMatrix();
2840
// translate to front (note: Special case)
2841
if (myDrawInFront) {
2842
glTranslated(0, 0, GLO_FRONTELEMENT);
2843
} else if (lane->getLaneShape().length2D() <= (s.neteditSizeSettings.junctionBubbleRadius * 2)) {
2844
drawInLayer(GLO_JUNCTION + 0.5);
2845
} else {
2846
drawInLayer(GLO_LANE);
2847
}
2848
// move to front
2849
glTranslated(0, 0, 0.1);
2850
// set color
2851
if (selected) {
2852
GLHelper::setColor(RGBColor::BLUE);
2853
} else {
2854
GLHelper::setColor(RGBColor::CYAN);
2855
}
2856
// draw as box lines
2857
GUIGeometry::drawGeometry(GUIVisualizationSettings::Detail::Level0, lane->getLaneGeometry(),
2858
lane->getDrawingConstants()->getDrawingWidth());
2859
// Pop layer matrix
2860
GLHelper::popMatrix();
2861
}
2862
/*
2863
// check if curently we're inspecting a TAZ Source/Sink
2864
for (const auto& TAZSourceSink : TAZSourceSinks) {
2865
if (myNet->getViewNet()->isAttributeCarrierInspected(TAZSourceSink)) {
2866
drawDottedContourEdge(s, GUIDottedGeometry::DottedContourType::INSPECT, this, true, true);
2867
} else if (TAZSourceSink == markAC) {
2868
drawDottedContourEdge(s, GUIDottedGeometry::DottedContourType::FRONT, this, true, true);
2869
}
2870
}
2871
*/
2872
}
2873
}
2874
}
2875
2876
2877
void
2878
GNEEdge::drawEdgeShape(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const double layer) const {
2879
// avoid draw for railways
2880
if ((d <= GUIVisualizationSettings::Detail::LaneDetails) && !getChildLanes().front()->getDrawingConstants()->drawAsRailway() &&
2881
(gViewObjectsHandler.markedFirstGeometryPoint == this)) {
2882
// push draw matrix
2883
GLHelper::pushMatrix();
2884
// translate to front depending of big points
2885
if (drawBigGeometryPoints()) {
2886
glTranslated(0, 0, GLO_GEOMETRYPOINT - 1);
2887
} else {
2888
glTranslated(0, 0, layer);
2889
}
2890
// obtain color
2891
RGBColor geometryPointColor = s.junctionColorer.getSchemes()[0].getColor(2);
2892
if (drawUsingSelectColor() && s.laneColorer.getActive() != 1) {
2893
// override with special colors (unless the color scheme is based on selection)
2894
geometryPointColor = s.colorSettings.selectedEdgeColor.changedBrightness(-20);
2895
}
2896
// set color
2897
GLHelper::setColor(geometryPointColor);
2898
// iterate over NBEdge geometry
2899
for (int i = 1; i < (int)myNBEdge->getGeometry().size(); i++) {
2900
// calculate line between previous and current geometry point
2901
PositionVector line = {myNBEdge->getGeometry()[i - 1], myNBEdge->getGeometry()[i]};
2902
line.move2side(0.2);
2903
// draw box line
2904
GLHelper::drawBoxLine(line[1], RAD2DEG(line[0].angleTo2D(line[1])) - 90, line[0].distanceTo2D(line[1]), .1);
2905
}
2906
// pop draw matrix
2907
GLHelper::popMatrix();
2908
}
2909
}
2910
2911
2912
bool
2913
GNEEdge::drawBigGeometryPoints() const {
2914
// get edit modes
2915
const auto& editModes = myNet->getViewNet()->getEditModes();
2916
// continue depending of conditions
2917
if (!editModes.isCurrentSupermodeNetwork()) {
2918
return false;
2919
} else if (editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) {
2920
return true;
2921
} else if ((editModes.networkEditMode == NetworkEditMode::NETWORK_DELETE) &&
2922
(myNet->getViewParent()->getDeleteFrame()->getDeleteOptions()->deleteOnlyGeometryPoints())) {
2923
return true;
2924
} else {
2925
return false;
2926
}
2927
}
2928
2929
2930
bool
2931
GNEEdge::areStackPositionOverlapped(const GNEEdge::StackPosition& vehicleA, const GNEEdge::StackPosition& vehicleB) const {
2932
if ((vehicleA.beginPosition() == vehicleB.beginPosition()) && (vehicleA.endPosition() == vehicleB.endPosition())) {
2933
return true;
2934
} else if ((vehicleA.beginPosition() < vehicleB.beginPosition()) && (vehicleA.endPosition() > vehicleB.endPosition())) {
2935
return true;
2936
} else if ((vehicleA.beginPosition() < vehicleB.beginPosition()) && (vehicleA.endPosition() > vehicleB.beginPosition())) {
2937
return true;
2938
} else if ((vehicleA.beginPosition() < vehicleB.endPosition()) && (vehicleA.endPosition() > vehicleB.endPosition())) {
2939
return true;
2940
} else {
2941
return false;
2942
}
2943
}
2944
2945
2946
double
2947
GNEEdge::getGeometryPointRadius() const {
2948
return drawBigGeometryPoints() ? SNAP_RADIUS * MIN2(1.0, myNet->getViewNet()->getVisualisationSettings().laneWidthExaggeration) : 0.5;
2949
}
2950
2951
/****************************************************************************/
2952
2953