Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netedit/elements/network/GNELane.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 GNELane.cpp
15
/// @author Jakob Erdmann
16
/// @author Mirko Barthauer
17
/// @date Feb 2011
18
///
19
// A class for visualizing Lane geometry (adapted from GNELaneWrapper)
20
/****************************************************************************/
21
22
#include <netbuild/NBEdgeCont.h>
23
#include <netedit/changes/GNEChange_Attribute.h>
24
#include <netedit/elements/moving/GNEMoveElementLane.h>
25
#include <netedit/frames/common/GNEDeleteFrame.h>
26
#include <netedit/frames/common/GNEInspectorFrame.h>
27
#include <netedit/frames/demand/GNERouteFrame.h>
28
#include <netedit/frames/GNEPathCreator.h>
29
#include <netedit/frames/GNEPlanCreator.h>
30
#include <netedit/frames/GNEViewObjectSelector.h>
31
#include <netedit/frames/network/GNEAdditionalFrame.h>
32
#include <netedit/frames/network/GNETLSEditorFrame.h>
33
#include <netedit/GNENet.h>
34
#include <netedit/GNEViewParent.h>
35
#include <utils/gui/div/GLHelper.h>
36
#include <utils/gui/div/GUIDesigns.h>
37
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
38
#include <utils/gui/images/GUITextureSubSys.h>
39
#include <utils/gui/images/VClassIcons.h>
40
#include <utils/gui/windows/GUIAppEnum.h>
41
42
#include "GNELane.h"
43
#include "GNEInternalLane.h"
44
#include "GNEConnection.h"
45
#include "GNEEdgeTemplate.h"
46
47
// ===========================================================================
48
// FOX callback mapping
49
// ===========================================================================
50
51
// Object implementation
52
FXIMPLEMENT(GNELane, FXDelegator, 0, 0)
53
54
// ===========================================================================
55
// method definitions
56
// ===========================================================================
57
58
// ---------------------------------------------------------------------------
59
// GNELane::LaneDrawingConstants - methods
60
// ---------------------------------------------------------------------------
61
62
GNELane::DrawingConstants::DrawingConstants(const GNELane* lane) :
63
myLane(lane) {
64
}
65
66
67
void
68
GNELane::DrawingConstants::update(const GUIVisualizationSettings& s) {
69
// get NBEdge
70
const auto& NBEdge = myLane->getParentEdge()->getNBEdge();
71
// get lane struct
72
const auto& laneStruct = myLane->getParentEdges().front()->getNBEdge()->getLaneStruct(myLane->getIndex());
73
// get selection scale
74
const double selectionScale = myLane->isAttributeCarrierSelected() || myLane->getParentEdges().front()->isAttributeCarrierSelected() ? s.selectorFrameScale : 1;
75
// get lane width
76
const double laneWidth = (laneStruct.width == -1 ? SUMO_const_laneWidth : laneStruct.width);
77
// calculate exaggeration
78
myExaggeration = selectionScale * s.laneWidthExaggeration;
79
// get detail level
80
myDetail = s.getDetailLevel(myExaggeration);
81
// check if draw lane as railway
82
myDrawAsRailway = isRailway(laneStruct.permissions) && ((laneStruct.permissions & SVC_BUS) == 0) && s.showRails;
83
// adjust rest of parameters depending if draw as railway
84
if (myDrawAsRailway) {
85
// draw as railway: assume standard gauge of 1435mm when lane width is not set
86
myDrawingWidth = (laneWidth == SUMO_const_laneWidth ? 1.4350 : laneWidth) * myExaggeration;
87
// calculate internal drawing width
88
myInternalDrawingWidth = myDrawingWidth * 0.8;
89
} else {
90
// calculate exaggerated drawing width
91
myDrawingWidth = laneWidth * myExaggeration * 0.5;
92
// calculate internal drawing width
93
myInternalDrawingWidth = myDrawingWidth - (2 * SUMO_const_laneMarkWidth);
94
}
95
// check if draw superposed
96
myDrawSuperposed = (s.spreadSuperposed && (NBEdge->isBidiRail() || NBEdge->isBidiEdge()));
97
// adjust parameters depending of superposing
98
if (myDrawSuperposed) {
99
// apply offset
100
myOffset = myDrawingWidth * 0.5;
101
// reduce width
102
myDrawingWidth *= 0.4;
103
myInternalDrawingWidth *= 0.4;
104
} else {
105
// restore offset
106
myOffset = 0;
107
}
108
}
109
110
111
double
112
GNELane::DrawingConstants::getExaggeration() const {
113
return myExaggeration;
114
}
115
116
117
double
118
GNELane::DrawingConstants::getDrawingWidth() const {
119
return myDrawingWidth;
120
}
121
122
123
double
124
GNELane::DrawingConstants::getInternalDrawingWidth() const {
125
return myInternalDrawingWidth;
126
}
127
128
129
double
130
GNELane::DrawingConstants::getOffset() const {
131
return myOffset;
132
}
133
134
135
GUIVisualizationSettings::Detail
136
GNELane::DrawingConstants::getDetail() const {
137
return myDetail;
138
}
139
140
141
bool
142
GNELane::DrawingConstants::drawAsRailway() const {
143
return myDrawAsRailway;
144
}
145
146
147
bool
148
GNELane::DrawingConstants::drawSuperposed() const {
149
return myDrawSuperposed;
150
}
151
152
153
// ---------------------------------------------------------------------------
154
// GNELane - methods
155
// ---------------------------------------------------------------------------
156
#ifdef _MSC_VER
157
#pragma warning(push)
158
#pragma warning(disable: 4355) // mask warning about "this" in initializers
159
#endif
160
GNELane::GNELane(GNEEdge* edge, const int index) :
161
GNENetworkElement(edge->getNet(), edge->getNBEdge()->getLaneID(index), SUMO_TAG_LANE),
162
myMoveElementLane(new GNEMoveElementLane(this)),
163
myIndex(index),
164
myDrawingConstants(new DrawingConstants(this)),
165
mySpecialColor(nullptr),
166
mySpecialColorValue(-1),
167
myLane2laneConnections(this) {
168
// set parents
169
setParent<GNEEdge*>(edge);
170
// update centering boundary without updating grid
171
updateCenteringBoundary(false);
172
}
173
174
175
GNELane::GNELane() :
176
GNENetworkElement(nullptr, "dummyConstructorGNELane", SUMO_TAG_LANE),
177
myMoveElementLane(new GNEMoveElementLane(this)),
178
myIndex(-1),
179
myDrawingConstants(nullptr),
180
mySpecialColor(nullptr),
181
mySpecialColorValue(-1),
182
myLane2laneConnections(this) {
183
}
184
#ifdef _MSC_VER
185
#pragma warning(pop)
186
#endif
187
188
GNELane::~GNELane() {
189
if (myDrawingConstants) {
190
delete myDrawingConstants;
191
}
192
}
193
194
195
GNEMoveElement*
196
GNELane::getMoveElement() const {
197
return myMoveElementLane;
198
}
199
200
201
Parameterised*
202
GNELane::getParameters() {
203
return &(getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex));
204
}
205
206
207
const Parameterised*
208
GNELane::getParameters() const {
209
return &(getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex));
210
}
211
212
213
GNEEdge*
214
GNELane::getParentEdge() const {
215
return getParentEdges().front();
216
}
217
218
219
bool
220
GNELane::allowPedestrians() const {
221
return (getParentEdges().front()->getNBEdge()->getPermissions(myIndex) & SVC_PEDESTRIAN) > 0;
222
}
223
224
225
const GUIGeometry&
226
GNELane::getLaneGeometry() const {
227
return myLaneGeometry;
228
}
229
230
231
const PositionVector&
232
GNELane::getLaneShape() const {
233
if (getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).customShape.size() > 0) {
234
return getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).customShape;
235
} else {
236
return getParentEdges().front()->getNBEdge()->getLaneShape(myIndex);
237
}
238
}
239
240
241
const std::vector<double>&
242
GNELane::getShapeRotations() const {
243
return myLaneGeometry.getShapeRotations();
244
}
245
246
247
const std::vector<double>&
248
GNELane::getShapeLengths() const {
249
return myLaneGeometry.getShapeLengths();
250
}
251
252
253
const GNELane::DrawingConstants*
254
GNELane::getDrawingConstants() const {
255
return myDrawingConstants;
256
}
257
258
259
void
260
GNELane::updateGeometry() {
261
// Clear texture containers
262
myLaneRestrictedTexturePositions.clear();
263
myLaneRestrictedTextureRotations.clear();
264
// get lane shape and extend if is too short
265
auto laneShape = getLaneShape();
266
if (laneShape.length2D() < 1) {
267
laneShape.extrapolate2D(1 - laneShape.length2D());
268
}
269
// Obtain lane shape of NBEdge
270
myLaneGeometry.updateGeometry(laneShape);
271
// update connections
272
myLane2laneConnections.updateLane2laneConnection();
273
// update additionals children associated with this lane
274
for (const auto& additional : getParentAdditionals()) {
275
additional->updateGeometry();
276
}
277
// update additionals parents associated with this lane
278
for (const auto& additional : getChildAdditionals()) {
279
additional->updateGeometry();
280
}
281
// update partial demand elements parents associated with this lane
282
for (const auto& demandElement : getParentDemandElements()) {
283
demandElement->updateGeometry();
284
}
285
// update partial demand elements children associated with this lane
286
for (const auto& demandElement : getChildDemandElements()) {
287
demandElement->updateGeometry();
288
}
289
// Update geometry of parent generic datas that have this edge as parent
290
for (const auto& additionalParent : getParentGenericDatas()) {
291
additionalParent->updateGeometry();
292
}
293
// Update geometry of additionals generic datas vinculated to this edge
294
for (const auto& childAdditionals : getChildGenericDatas()) {
295
childAdditionals->updateGeometry();
296
}
297
// compute geometry of path elements elements vinculated with this lane (depending of showDemandElements)
298
if (myNet->getViewNet() && myNet->getViewNet()->getNetworkViewOptions().showDemandElements()) {
299
for (const auto& childAdditional : getChildAdditionals()) {
300
childAdditional->computePathElement();
301
}
302
for (const auto& childDemandElement : getChildDemandElements()) {
303
childDemandElement->computePathElement();
304
}
305
for (const auto& childGenericData : getChildGenericDatas()) {
306
childGenericData->computePathElement();
307
}
308
}
309
// in Move mode, connections aren't updated
310
if (myNet->getViewNet() && myNet->getViewNet()->getEditModes().networkEditMode != NetworkEditMode::NETWORK_MOVE) {
311
// Update incoming connections of this lane
312
const auto incomingConnections = getGNEIncomingConnections();
313
for (const auto& connection : incomingConnections) {
314
connection->updateGeometry();
315
}
316
// Update outgoings connections of this lane
317
const auto outGoingConnections = getGNEOutcomingConnections();
318
for (const auto& connection : outGoingConnections) {
319
connection->updateGeometry();
320
}
321
}
322
// if lane has enought length for show textures of restricted lanes
323
if ((getLaneShapeLength() > 4)) {
324
// if lane is restricted
325
if (isRestricted(SVC_PEDESTRIAN) || isRestricted(SVC_BICYCLE) || isRestricted(SVC_BUS)) {
326
// get values for position and rotation of icons
327
for (int i = 2; i < getLaneShapeLength() - 1; i += 15) {
328
myLaneRestrictedTexturePositions.push_back(myLaneGeometry.getShape().positionAtOffset(i));
329
myLaneRestrictedTextureRotations.push_back(myLaneGeometry.getShape().rotationDegreeAtOffset(i));
330
}
331
}
332
}
333
}
334
335
336
Position
337
GNELane::getPositionInView() const {
338
return getLaneShape().positionAtOffset2D(getLaneShape().length2D() * 0.5);
339
}
340
341
342
bool
343
GNELane::checkDrawFromContour() const {
344
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
345
// check if we're inspecting a connection
346
if (inspectedElements.isInspectingSingleElement() && (inspectedElements.getFirstAC()->getTagProperty()->getTag() == SUMO_TAG_CONNECTION) &&
347
inspectedElements.getFirstAC()->getAttribute(GNE_ATTR_FROM_LANEID) == getID()) {
348
return true;
349
} else {
350
return false;
351
}
352
}
353
354
355
bool
356
GNELane::checkDrawToContour() const {
357
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
358
// check if we're inspecting a connection
359
if (inspectedElements.isInspectingSingleElement() && (inspectedElements.getFirstAC()->getTagProperty()->getTag() == SUMO_TAG_CONNECTION) &&
360
inspectedElements.getFirstAC()->getAttribute(GNE_ATTR_TO_LANEID) == getID()) {
361
return true;
362
} else {
363
return false;
364
}
365
}
366
367
368
bool
369
GNELane::checkDrawRelatedContour() const {
370
// check opened popup
371
if (myNet->getViewNet()->getPopup()) {
372
return myNet->getViewNet()->getPopup()->getGLObject() == this;
373
}
374
return false;
375
}
376
377
378
bool
379
GNELane::checkDrawOverContour() const {
380
// get modes and viewParent (for code legibility)
381
const auto& modes = myNet->getViewNet()->getEditModes();
382
const auto& viewParent = myNet->getViewParent();
383
// check if we're selecting edges in additional mode
384
if (modes.isCurrentSupermodeNetwork() && (modes.networkEditMode == NetworkEditMode::NETWORK_ADDITIONAL)) {
385
if (viewParent->getAdditionalFrame()->getViewObjetsSelector()->isNetworkElementSelected(this)) {
386
return true;
387
} else if (viewParent->getAdditionalFrame()->getViewObjetsSelector()->getTag() == myTagProperty->getTag()) {
388
return myNet->getViewNet()->getViewObjectsSelector().getLaneFront() == this;
389
} else {
390
return false;
391
}
392
} else {
393
return false;
394
}
395
}
396
397
398
bool
399
GNELane::checkDrawDeleteContour() const {
400
// first check if we're selecting edges or lanes
401
if (myNet->getViewNet()->checkSelectEdges()) {
402
return false;
403
} else {
404
// get edit modes
405
const auto& editModes = myNet->getViewNet()->getEditModes();
406
// check if we're in delete mode
407
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_DELETE)) {
408
return myNet->getViewNet()->checkOverLockedElement(this, mySelected);
409
} else {
410
return false;
411
}
412
}
413
}
414
415
416
bool
417
GNELane::checkDrawDeleteContourSmall() const {
418
return false;
419
}
420
421
422
bool
423
GNELane::checkDrawSelectContour() const {
424
// first check if we're selecting edges or lanes
425
if (myNet->getViewNet()->checkSelectEdges()) {
426
return false;
427
} else {
428
// get edit modes
429
const auto& editModes = myNet->getViewNet()->getEditModes();
430
// check if we're in select mode
431
if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_SELECT)) {
432
return myNet->getViewNet()->checkOverLockedElement(this, mySelected);
433
} else {
434
return false;
435
}
436
}
437
}
438
439
440
bool
441
GNELane::checkDrawMoveContour() const {
442
// check if we're editing this network element
443
const GNENetworkElement* editedNetworkElement = myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement();
444
if (editedNetworkElement) {
445
return editedNetworkElement == this;
446
} else {
447
return false;
448
}
449
}
450
451
452
void
453
GNELane::drawGL(const GUIVisualizationSettings& s) const {
454
// update lane drawing constan
455
myDrawingConstants->update(s);
456
// calculate layer
457
double layer = GLO_LANE;
458
if (getParentEdges().front()->isMarkedForDrawingFront()) {
459
layer = GLO_FRONTELEMENT;
460
} else if (myLaneGeometry.getShape().length2D() <= (s.neteditSizeSettings.junctionBubbleRadius * 2)) {
461
layer = GLO_JUNCTION + 2;
462
}
463
// check drawing conditions
464
if (!s.drawForViewObjectsHandler) {
465
// draw lane
466
drawLane(s, layer);
467
// draw lock icon
468
GNEViewNetHelper::LockIcon::drawLockIcon(myDrawingConstants->getDetail(), this, getType(), getPositionInView(), 1);
469
// draw dotted contour
470
myNetworkElementContour.drawDottedContours(s, myDrawingConstants->getDetail(), this, s.dottedContourSettings.segmentWidth, true);
471
}
472
// calculate contour (always before children)
473
calculateLaneContour(s, layer);
474
// draw children
475
drawChildren(s);
476
}
477
478
479
void
480
GNELane::deleteGLObject() {
481
// Check if edge can be deleted
482
if (GNEDeleteFrame::SubordinatedElements(this).checkElements(myNet->getViewParent()->getDeleteFrame()->getProtectElements())) {
483
myNet->deleteLane(this, myNet->getUndoList(), false);
484
}
485
}
486
487
488
void
489
GNELane::updateGLObject() {
490
updateGeometry();
491
}
492
493
494
495
GUIGLObjectPopupMenu*
496
GNELane::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
497
// first obtain edit mode (needed because certain Commands depend of current edit mode)
498
const NetworkEditMode editMode = myNet->getViewNet()->getEditModes().networkEditMode;
499
// get mouse position
500
const auto mousePosition = myNet->getViewNet()->getPositionInformation();
501
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
502
buildPopupHeader(ret, app);
503
buildCenterPopupEntry(ret);
504
// build copy names entry
505
if (editMode != NetworkEditMode::NETWORK_TLS) {
506
GUIDesigns::buildFXMenuCommand(ret, TL("Copy parent edge name to clipboard"), nullptr, ret, MID_COPY_EDGE_NAME);
507
buildNameCopyPopupEntry(ret);
508
}
509
// stop if we're in data mode
510
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeData()) {
511
return ret;
512
}
513
// build lane selection
514
if (isAttributeCarrierSelected()) {
515
GUIDesigns::buildFXMenuCommand(ret, TL("Remove Lane From Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), myNet->getViewNet(), MID_REMOVESELECT);
516
} else {
517
GUIDesigns::buildFXMenuCommand(ret, TL("Add Lane To Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_PLUS), myNet->getViewNet(), MID_ADDSELECT);
518
}
519
// build edge selection
520
if (getParentEdges().front()->isAttributeCarrierSelected()) {
521
GUIDesigns::buildFXMenuCommand(ret, TL("Remove Edge From Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), myNet->getViewNet(), MID_GNE_REMOVESELECT_EDGE);
522
} else {
523
GUIDesigns::buildFXMenuCommand(ret, TL("Add Edge To Selected"), GUIIconSubSys::getIcon(GUIIcon::FLAG_PLUS), myNet->getViewNet(), MID_GNE_ADDSELECT_EDGE);
524
}
525
// stop if we're in data mode
526
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeDemand()) {
527
return ret;
528
}
529
// add separator
530
new FXMenuSeparator(ret);
531
if (editMode != NetworkEditMode::NETWORK_TLS) {
532
// build show parameters menu
533
buildShowParamsPopupEntry(ret);
534
// build position copy entry
535
buildPositionCopyEntry(ret, app);
536
}
537
// check if we're in supermode network
538
if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork()) {
539
// create end point
540
FXMenuCommand* resetEndPoints = GUIDesigns::buildFXMenuCommand(ret, TL("Reset edge end points"), nullptr, &parent, MID_GNE_RESET_GEOMETRYPOINT);
541
// enable or disable reset end points
542
if (getParentEdges().front()->hasCustomEndPoints()) {
543
resetEndPoints->enable();
544
} else {
545
resetEndPoints->disable();
546
}
547
// check if we clicked over a geometry point
548
if ((editMode == NetworkEditMode::NETWORK_MOVE) && getParentEdges().front()->clickedOverGeometryPoint(mousePosition)) {
549
GUIDesigns::buildFXMenuCommand(ret, TL("Set custom Geometry Point"), nullptr, &parent, MID_GNE_CUSTOM_GEOMETRYPOINT);
550
}
551
// add separator
552
new FXMenuSeparator(ret);
553
//build operations
554
if ((editMode != NetworkEditMode::NETWORK_CONNECT) && (editMode != NetworkEditMode::NETWORK_TLS)) {
555
// build edge operations
556
buildEdgeOperations(parent, ret);
557
// build lane operations
558
buildLaneOperations(parent, ret);
559
// build template operations
560
buildTemplateOperations(parent, ret);
561
// add separator
562
new FXMenuSeparator(ret);
563
// build rechable operations
564
buildRechableOperations(parent, ret);
565
} else if (editMode == NetworkEditMode::NETWORK_TLS) {
566
if (myNet->getViewParent()->getTLSEditorFrame()->controlsEdge(getParentEdges().front())) {
567
GUIDesigns::buildFXMenuCommand(ret, TL("Select state for all links from this edge:"), nullptr, nullptr, 0);
568
const std::vector<std::string> names = GNEInternalLane::LinkStateNames.getStrings();
569
for (auto it : names) {
570
FXuint state = GNEInternalLane::LinkStateNames.get(it);
571
FXMenuRadio* mc = new FXMenuRadio(ret, it.c_str(), this, FXDataTarget::ID_OPTION + state);
572
mc->setSelBackColor(MFXUtils::getFXColor(GNEInternalLane::colorForLinksState(state)));
573
mc->setBackColor(MFXUtils::getFXColor(GNEInternalLane::colorForLinksState(state)));
574
}
575
}
576
} else {
577
FXMenuCommand* mc = GUIDesigns::buildFXMenuCommand(ret, TL("Additional options available in 'Inspect Mode'"), nullptr, nullptr, 0);
578
mc->handle(&parent, FXSEL(SEL_COMMAND, FXWindow::ID_DISABLE), nullptr);
579
}
580
// build shape positions menu
581
if (editMode != NetworkEditMode::NETWORK_TLS) {
582
new FXMenuSeparator(ret);
583
// get lane shape
584
const auto& laneShape = myLaneGeometry.getShape();
585
// get variables
586
const double pos = laneShape.nearest_offset_to_point2D(mousePosition);
587
const Position firstAnglePos = laneShape.positionAtOffset2D(pos - 0.001);
588
const Position secondAnglePos = laneShape.positionAtOffset2D(pos);
589
const double angle = firstAnglePos.angleTo2D(secondAnglePos);
590
591
// build menu commands
592
GUIDesigns::buildFXMenuCommand(ret, TL("Shape pos: ") + toString(pos), nullptr, nullptr, 0);
593
GUIDesigns::buildFXMenuCommand(ret, TL("Length pos: ") + toString(pos * getLaneParametricLength() / getLaneShapeLength()), nullptr, nullptr, 0);
594
if (getParentEdges().front()->getNBEdge()->getDistance() != 0) {
595
GUIDesigns::buildFXMenuCommand(ret, TL("Distance: ") + toString(getParentEdges().front()->getNBEdge()->getDistancAt(pos)), nullptr, nullptr, 0);
596
}
597
GUIDesigns::buildFXMenuCommand(ret, TL("Height: ") + toString(firstAnglePos.z()), nullptr, nullptr, 0);
598
GUIDesigns::buildFXMenuCommand(ret, TL("Angle: ") + toString((GeomHelper::naviDegree(angle))), nullptr, nullptr, 0);
599
}
600
}
601
return ret;
602
}
603
604
605
double
606
GNELane::getExaggeration(const GUIVisualizationSettings& s) const {
607
return s.addSize.getExaggeration(s, this);
608
}
609
610
611
Boundary
612
GNELane::getCenteringBoundary() const {
613
return myNetworkElementContour.getContourBoundary();
614
}
615
616
617
void
618
GNELane::updateCenteringBoundary(const bool /*updateGrid*/) {
619
// nothing to update
620
}
621
622
623
int
624
GNELane::getIndex() const {
625
return myIndex;
626
}
627
628
629
void
630
GNELane::setIndex(int index) {
631
myIndex = index;
632
setNetworkElementID(getParentEdges().front()->getNBEdge()->getLaneID(index));
633
}
634
635
636
double
637
GNELane::getSpeed() const {
638
return getParentEdges().front()->getNBEdge()->getLaneSpeed(myIndex);
639
}
640
641
642
double
643
GNELane::getLaneParametricLength() const {
644
double laneParametricLength = getParentEdges().front()->getNBEdge()->getLoadedLength();
645
if (laneParametricLength > 0) {
646
return laneParametricLength;
647
} else {
648
throw ProcessError(TL("Lane Parametric Length cannot be never 0"));
649
}
650
}
651
652
653
double
654
GNELane::getLaneShapeLength() const {
655
return myLaneGeometry.getShape().length();
656
}
657
658
659
bool
660
GNELane::isRestricted(SUMOVehicleClass vclass) const {
661
return getParentEdges().front()->getNBEdge()->getPermissions(myIndex) == vclass;
662
}
663
664
665
const GNELane2laneConnection&
666
GNELane::getLane2laneConnections() const {
667
return myLane2laneConnections;
668
}
669
670
671
std::string
672
GNELane::getAttribute(SumoXMLAttr key) const {
673
const NBEdge* edge = getParentEdges().front()->getNBEdge();
674
switch (key) {
675
case SUMO_ATTR_ID:
676
return getMicrosimID();
677
case SUMO_ATTR_FROM_JUNCTION:
678
return getParentEdges().front()->getFromJunction()->getID();
679
case SUMO_ATTR_TO_JUNCTION:
680
return getParentEdges().front()->getToJunction()->getID();
681
case SUMO_ATTR_SPEED:
682
return toString(edge->getLaneSpeed(myIndex));
683
case SUMO_ATTR_ALLOW:
684
return getVehicleClassNames(edge->getPermissions(myIndex));
685
case SUMO_ATTR_DISALLOW:
686
return getVehicleClassNames(invertPermissions(edge->getPermissions(myIndex)));
687
case SUMO_ATTR_CHANGE_LEFT:
688
return getVehicleClassNames(edge->getLaneStruct(myIndex).changeLeft);
689
case SUMO_ATTR_CHANGE_RIGHT:
690
return getVehicleClassNames(edge->getLaneStruct(myIndex).changeRight);
691
case SUMO_ATTR_WIDTH:
692
if (edge->getLaneStruct(myIndex).width == NBEdge::UNSPECIFIED_WIDTH) {
693
return "default";
694
} else {
695
return toString(edge->getLaneStruct(myIndex).width);
696
}
697
case SUMO_ATTR_FRICTION:
698
return toString(edge->getLaneStruct(myIndex).friction);
699
case SUMO_ATTR_ENDOFFSET:
700
return toString(edge->getLaneStruct(myIndex).endOffset);
701
case SUMO_ATTR_ACCELERATION:
702
return toString(edge->getLaneStruct(myIndex).accelRamp);
703
case SUMO_ATTR_SHAPE:
704
case SUMO_ATTR_CUSTOMSHAPE:
705
return toString(edge->getLaneStruct(myIndex).customShape);
706
case GNE_ATTR_OPPOSITE:
707
return toString(edge->getLaneStruct(myIndex).oppositeID);
708
case SUMO_ATTR_TYPE:
709
return edge->getLaneStruct(myIndex).type;
710
case SUMO_ATTR_INDEX:
711
return toString(myIndex);
712
case GNE_ATTR_STOPOFFSET:
713
return toString(edge->getLaneStruct(myIndex).laneStopOffset.getOffset());
714
case GNE_ATTR_STOPOEXCEPTION:
715
if (edge->getLaneStruct(myIndex).laneStopOffset.isDefined()) {
716
return toString(edge->getLaneStruct(myIndex).laneStopOffset.getExceptions());
717
} else {
718
return "";
719
}
720
case GNE_ATTR_PARENT:
721
return getParentEdges().front()->getID();
722
default:
723
return getCommonAttribute(key);
724
}
725
}
726
727
728
double
729
GNELane::getAttributeDouble(SumoXMLAttr key) const {
730
return getCommonAttributeDouble(key);
731
}
732
733
734
Position
735
GNELane::getAttributePosition(SumoXMLAttr key) const {
736
return getCommonAttributePosition(key);
737
}
738
739
740
PositionVector
741
GNELane::getAttributePositionVector(SumoXMLAttr key) const {
742
switch (key) {
743
case SUMO_ATTR_SHAPE:
744
case SUMO_ATTR_CUSTOMSHAPE:
745
return getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).customShape;
746
default:
747
return getCommonAttributePositionVector(key);
748
}
749
}
750
751
752
std::string
753
GNELane::getAttributeForSelection(SumoXMLAttr key) const {
754
std::string result = getAttribute(key);
755
if ((key == SUMO_ATTR_ALLOW || key == SUMO_ATTR_DISALLOW) && result.find("all") != std::string::npos) {
756
result += " " + getVehicleClassNames(SVCAll, true);
757
}
758
return result;
759
}
760
761
762
void
763
GNELane::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {
764
switch (key) {
765
case SUMO_ATTR_ID:
766
throw InvalidArgument("Modifying attribute '" + toString(key) + "' of " + getTagStr() + " isn't allowed");
767
case SUMO_ATTR_SPEED:
768
case SUMO_ATTR_ALLOW:
769
case SUMO_ATTR_DISALLOW:
770
case SUMO_ATTR_CHANGE_LEFT:
771
case SUMO_ATTR_CHANGE_RIGHT:
772
case SUMO_ATTR_WIDTH:
773
case SUMO_ATTR_FRICTION:
774
case SUMO_ATTR_ENDOFFSET:
775
case SUMO_ATTR_ACCELERATION:
776
case SUMO_ATTR_SHAPE:
777
case SUMO_ATTR_CUSTOMSHAPE:
778
case GNE_ATTR_OPPOSITE:
779
case SUMO_ATTR_TYPE:
780
case SUMO_ATTR_INDEX:
781
case GNE_ATTR_STOPOFFSET:
782
// special case for stop offset, because affects to stopOffsetExceptions (#15297)
783
if (canParse<double>(value) && (parse<double>(value) == 0)) {
784
GNEChange_Attribute::changeAttribute(this, GNE_ATTR_STOPOEXCEPTION, "", undoList);
785
}
786
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
787
break;
788
case GNE_ATTR_STOPOEXCEPTION:
789
GNEChange_Attribute::changeAttribute(this, key, value, undoList);
790
break;
791
default:
792
setCommonAttribute(key, value, undoList);
793
break;
794
}
795
}
796
797
798
bool
799
GNELane::isValid(SumoXMLAttr key, const std::string& value) {
800
switch (key) {
801
case SUMO_ATTR_ID:
802
case SUMO_ATTR_INDEX:
803
return false;
804
case SUMO_ATTR_SPEED:
805
return canParse<double>(value);
806
case SUMO_ATTR_ALLOW:
807
case SUMO_ATTR_DISALLOW:
808
case SUMO_ATTR_CHANGE_LEFT:
809
case SUMO_ATTR_CHANGE_RIGHT:
810
return canParseVehicleClasses(value);
811
case SUMO_ATTR_WIDTH:
812
if (value.empty() || (value == "default")) {
813
return true;
814
} else {
815
return canParse<double>(value) && ((parse<double>(value) > 0) || (parse<double>(value) == NBEdge::UNSPECIFIED_WIDTH));
816
}
817
case SUMO_ATTR_FRICTION:
818
case SUMO_ATTR_ENDOFFSET:
819
return canParse<double>(value) && (parse<double>(value) >= 0);
820
case SUMO_ATTR_ACCELERATION:
821
return canParse<bool>(value);
822
case SUMO_ATTR_SHAPE:
823
case SUMO_ATTR_CUSTOMSHAPE:
824
// A lane shape can either be empty or have more than 1 element
825
if (value.empty()) {
826
return true;
827
} else if (canParse<PositionVector>(value)) {
828
return parse<PositionVector>(value).size() > 1;
829
}
830
return false;
831
case GNE_ATTR_OPPOSITE: {
832
if (value.empty()) {
833
return true;
834
} else {
835
NBEdge* oppEdge = myNet->getEdgeCont().retrieve(value.substr(0, value.rfind("_")));
836
if (oppEdge == nullptr || oppEdge->getLaneID(oppEdge->getNumLanes() - 1) != value) {
837
return false;
838
}
839
NBEdge* edge = getParentEdges().front()->getNBEdge();
840
if (oppEdge->getFromNode() != edge->getToNode() || oppEdge->getToNode() != edge->getFromNode()) {
841
WRITE_WARNINGF(TL("Opposite lane '%' does not connect the same nodes as edge '%'!"), value, edge->getID());
842
return false;
843
}
844
return true;
845
}
846
}
847
case SUMO_ATTR_TYPE:
848
return true;
849
case GNE_ATTR_STOPOFFSET:
850
return canParse<double>(value) && (parse<double>(value) >= 0);
851
case GNE_ATTR_STOPOEXCEPTION:
852
return canParseVehicleClasses(value);
853
default:
854
return isCommonAttributeValid(key, value);
855
}
856
}
857
858
859
bool
860
GNELane::isAttributeEnabled(SumoXMLAttr key) const {
861
switch (key) {
862
case SUMO_ATTR_ID:
863
case SUMO_ATTR_INDEX:
864
return false;
865
case GNE_ATTR_STOPOEXCEPTION:
866
return getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).laneStopOffset.getOffset() > 0;
867
default:
868
return true;
869
}
870
}
871
872
873
bool
874
GNELane::isAttributeComputed(SumoXMLAttr key) const {
875
const NBEdge* edge = getParentEdges().front()->getNBEdge();
876
switch (key) {
877
case SUMO_ATTR_WIDTH:
878
return (edge->getLaneStruct(myIndex).width == NBEdge::UNSPECIFIED_WIDTH);
879
default:
880
return false;
881
}
882
}
883
884
885
void
886
GNELane::setSpecialColor(const RGBColor* color, double colorValue) {
887
mySpecialColor = color;
888
mySpecialColorValue = colorValue;
889
}
890
891
// ===========================================================================
892
// private
893
// ===========================================================================
894
895
void
896
GNELane::setAttribute(SumoXMLAttr key, const std::string& value) {
897
// get parent edge
898
NBEdge* edge = getParentEdges().front()->getNBEdge();
899
// get template editor
900
GNEInspectorFrame::TemplateEditor* templateEditor = myNet->getViewParent()->getInspectorFrame()->getTemplateEditor();
901
// check if we have to update template
902
const bool updateTemplate = templateEditor->getEdgeTemplate() ? (templateEditor->getEdgeTemplate()->getID() == getParentEdges().front()->getID()) : false;
903
switch (key) {
904
case SUMO_ATTR_ID:
905
case SUMO_ATTR_INDEX:
906
throw InvalidArgument("Modifying attribute '" + toString(key) + "' of " + getTagStr() + " isn't allowed");
907
case SUMO_ATTR_SPEED:
908
edge->setSpeed(myIndex, parse<double>(value));
909
break;
910
case SUMO_ATTR_ALLOW:
911
edge->setPermissions(parseVehicleClasses(value), myIndex);
912
break;
913
case SUMO_ATTR_DISALLOW:
914
edge->setPermissions(invertPermissions(parseVehicleClasses(value)), myIndex);
915
break;
916
case SUMO_ATTR_CHANGE_LEFT:
917
edge->setPermittedChanging(myIndex, parseVehicleClasses(value), edge->getLaneStruct(myIndex).changeRight);
918
break;
919
case SUMO_ATTR_CHANGE_RIGHT:
920
edge->setPermittedChanging(myIndex, edge->getLaneStruct(myIndex).changeLeft, parseVehicleClasses(value));
921
break;
922
case SUMO_ATTR_WIDTH:
923
if (value.empty() || (value == "default")) {
924
edge->setLaneWidth(myIndex, NBEdge::UNSPECIFIED_WIDTH);
925
} else {
926
edge->setLaneWidth(myIndex, parse<double>(value));
927
}
928
// update edge parent boundary
929
getParentEdges().front()->updateCenteringBoundary(true);
930
break;
931
case SUMO_ATTR_FRICTION:
932
edge->setFriction(myIndex, parse<double>(value));
933
break;
934
case SUMO_ATTR_ENDOFFSET:
935
edge->setEndOffset(myIndex, parse<double>(value));
936
break;
937
case SUMO_ATTR_ACCELERATION:
938
edge->setAcceleration(myIndex, parse<bool>(value));
939
break;
940
case SUMO_ATTR_SHAPE:
941
case SUMO_ATTR_CUSTOMSHAPE:
942
// set new shape
943
edge->setLaneShape(myIndex, parse<PositionVector>(value));
944
// update edge parent boundary
945
getParentEdges().front()->updateCenteringBoundary(true);
946
break;
947
case GNE_ATTR_OPPOSITE: {
948
if (value != "") {
949
NBEdge* oppEdge = myNet->getEdgeCont().retrieve(value.substr(0, value.rfind("_")));
950
oppEdge->getLaneStruct(oppEdge->getNumLanes() - 1).oppositeID = getID();
951
} else {
952
// reset prior oppEdge if existing
953
const std::string oldValue = getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).oppositeID;
954
NBEdge* oppEdge = myNet->getEdgeCont().retrieve(oldValue.substr(0, oldValue.rfind("_")));
955
if (oppEdge != nullptr) {
956
oppEdge->getLaneStruct(oppEdge->getNumLanes() - 1).oppositeID = "";
957
}
958
}
959
getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).oppositeID = value;
960
break;
961
}
962
case SUMO_ATTR_TYPE:
963
edge->getLaneStruct(myIndex).type = value;
964
break;
965
case GNE_ATTR_STOPOFFSET:
966
if (value.empty()) {
967
edge->getLaneStruct(myIndex).laneStopOffset.setOffset(0);
968
} else {
969
edge->getLaneStruct(myIndex).laneStopOffset.setOffset(parse<double>(value));
970
}
971
break;
972
case GNE_ATTR_STOPOEXCEPTION:
973
edge->getLaneStruct(myIndex).laneStopOffset.setExceptions(value);
974
break;
975
default:
976
setCommonAttribute(key, value);
977
break;
978
}
979
// update template
980
if (updateTemplate) {
981
templateEditor->setEdgeTemplate(getParentEdges().front());
982
}
983
// invalidate demand path calculator
984
myNet->getDemandPathManager()->getPathCalculator()->invalidatePathCalculator();
985
}
986
987
988
void
989
GNELane::drawLane(const GUIVisualizationSettings& s, const double layer) const {
990
// Push layer matrix
991
GLHelper::pushMatrix();
992
// translate to layer
993
drawInLayer(layer);
994
// set lane colors
995
setLaneColor(s);
996
// Check if lane has to be draw as railway and if isn't being drawn for selecting
997
if (myDrawingConstants->drawAsRailway()) {
998
// draw as railway
999
drawLaneAsRailway();
1000
} else if (myShapeColors.size() > 0) {
1001
// draw geometry with own colors
1002
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, myShapeColors,
1003
myDrawingConstants->getDrawingWidth(), myDrawingConstants->getOffset());
1004
} else {
1005
// draw geometry with current color
1006
const GUIVisualizationSettings::Detail d = myDrawingConstants->getDetail();
1007
double drawingWidth = myDrawingConstants->getDrawingWidth();
1008
if (d > GUIVisualizationSettings::Detail::GeometryBoxLines && d < GUIVisualizationSettings::Detail::GeometryBoxSimpleLine) {
1009
drawingWidth = myNet->getViewNet()->m2p(drawingWidth);
1010
}
1011
GUIGeometry::drawGeometry(d, myLaneGeometry, drawingWidth,
1012
myDrawingConstants->getOffset());
1013
}
1014
// if lane is selected, draw a second lane over it
1015
drawSelectedLane(s);
1016
// draw start end shape points
1017
drawStartEndGeometryPoints(s);
1018
// check if draw details
1019
if (myDrawingConstants->getDetail() <= GUIVisualizationSettings::Detail::LaneDetails) {
1020
// draw markings
1021
drawMarkingsAndBoundings(s);
1022
// Draw direction indicators
1023
drawDirectionIndicators(s);
1024
// draw lane textures
1025
drawTextures(s);
1026
// draw lane arrows
1027
drawArrows(s);
1028
// draw link numbers
1029
drawLinkNo(s);
1030
// draw TLS link numbers
1031
drawTLSLinkNo(s);
1032
// draw stopOffsets
1033
drawLaneStopOffset(s);
1034
}
1035
// draw shape edited
1036
drawShapeEdited(s);
1037
// Pop layer matrix
1038
GLHelper::popMatrix();
1039
}
1040
1041
1042
void
1043
GNELane::drawSelectedLane(const GUIVisualizationSettings& s) const {
1044
// only draw if lane is selected
1045
if (drawUsingSelectColor()) {
1046
// Push matrix
1047
GLHelper::pushMatrix();
1048
// move back
1049
glTranslated(0, 0, 0.1);
1050
// set selected edge color
1051
GLHelper::setColor(s.colorSettings.selectedLaneColor);
1052
// draw geometry with current color
1053
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, myDrawingConstants->getDrawingWidth(),
1054
myDrawingConstants->getOffset());
1055
// Pop matrix
1056
GLHelper::popMatrix();
1057
}
1058
}
1059
1060
1061
void
1062
GNELane::drawShapeEdited(const GUIVisualizationSettings& s) const {
1063
// if shape is being edited, draw point and green line
1064
if (myShapeEdited) {
1065
// push shape edited matrix
1066
GLHelper::pushMatrix();
1067
// translate
1068
drawInLayer(GLO_JUNCTION + 1);
1069
// set selected edge color
1070
GLHelper::setColor(s.colorSettings.editShapeColor);
1071
// draw shape around
1072
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, 0.25,
1073
myDrawingConstants->getOffset());
1074
// move front
1075
glTranslated(0, 0, 1);
1076
// draw geometry points
1077
GUIGeometry::drawGeometryPoints(myDrawingConstants->getDetail(), myLaneGeometry.getShape(),
1078
s.colorSettings.editShapeColor.changedBrightness(-32),
1079
s.neteditSizeSettings.laneGeometryPointRadius, 1,
1080
myNet->getViewNet()->getNetworkViewOptions().editingElevation());
1081
// Pop shape edited matrix
1082
GLHelper::popMatrix();
1083
}
1084
}
1085
1086
1087
void
1088
GNELane::drawChildren(const GUIVisualizationSettings& s) const {
1089
// draw additional children
1090
for (const auto& additional : getChildAdditionals()) {
1091
if (!additional->getTagProperty()->isListedElement()) {
1092
additional->drawGL(s);
1093
}
1094
}
1095
// draw demand element children
1096
for (const auto& demandElement : getChildDemandElements()) {
1097
if (!demandElement->getTagProperty()->isPlacedInRTree()) {
1098
demandElement->drawGL(s);
1099
}
1100
}
1101
// draw path additional elements
1102
myNet->getNetworkPathManager()->drawLanePathElements(s, this);
1103
myNet->getDemandPathManager()->drawLanePathElements(s, this);
1104
myNet->getDataPathManager()->drawLanePathElements(s, this);
1105
}
1106
1107
1108
void
1109
GNELane::drawMarkingsAndBoundings(const GUIVisualizationSettings& s) const {
1110
// check conditions
1111
if (s.laneShowBorders && !myDrawingConstants->drawAsRailway()) {
1112
// check if this is the last lane (note: First lane is the lane more far of the edge's center)
1113
const bool firstlane = (myIndex == 0);
1114
const bool lastLane = (myIndex == (getParentEdges().front()->getNBEdge()->getNumLanes() - 1));
1115
// declare separator width
1116
const auto separatorWidth = SUMO_const_laneMarkWidth * 0.5;
1117
// get passengers change left and right for previous, current and next lane
1118
const bool changeRightTop = lastLane ? true : getParentEdges().front()->getNBEdge()->allowsChangingRight(myIndex + 1, SVC_PASSENGER);
1119
const bool changeLeftCurrent = lastLane ? true : getParentEdges().front()->getNBEdge()->allowsChangingLeft(myIndex, SVC_PASSENGER);
1120
const bool changeRightCurrent = firstlane ? true : getParentEdges().front()->getNBEdge()->allowsChangingRight(myIndex, SVC_PASSENGER);
1121
const bool changeLeftBot = firstlane ? true : getParentEdges().front()->getNBEdge()->allowsChangingLeft(myIndex - 1, SVC_PASSENGER);
1122
// save current color
1123
const auto currentColor = GLHelper::getColor();
1124
// separator offsets
1125
const double topSeparatorOffset = myDrawingConstants->getOffset() + (myDrawingConstants->getDrawingWidth() * -1) + separatorWidth;
1126
const double botSeparatorOffset = myDrawingConstants->getOffset() + myDrawingConstants->getDrawingWidth() - separatorWidth;
1127
// push matrix
1128
GLHelper::pushMatrix();
1129
// translate
1130
glTranslated(0, 0, 0.1);
1131
// continue depending of lanes
1132
if (myDrawingConstants->drawSuperposed() || (firstlane && lastLane)) {
1133
// draw top and bot separator only
1134
GLHelper::setColor(RGBColor::WHITE);
1135
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, separatorWidth, topSeparatorOffset);
1136
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, separatorWidth, botSeparatorOffset);
1137
} else if (firstlane) {
1138
// draw top separator
1139
GLHelper::setColor((changeLeftCurrent && changeRightTop) ? RGBColor::WHITE : RGBColor::ORANGE);
1140
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, separatorWidth, topSeparatorOffset);
1141
// check if draw inverse marking
1142
if (changeLeftCurrent) {
1143
GLHelper::setColor(currentColor);
1144
GLHelper::drawInverseMarkings(myLaneGeometry.getShape(), myLaneGeometry.getShapeRotations(), myLaneGeometry.getShapeLengths(),
1145
3, 6, topSeparatorOffset, true, true, s.lefthand, 1);
1146
}
1147
// draw bot separator
1148
GLHelper::setColor(RGBColor::WHITE);
1149
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, separatorWidth, botSeparatorOffset);
1150
} else if (lastLane) {
1151
// draw top separator
1152
GLHelper::setColor(RGBColor::WHITE);
1153
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, separatorWidth, topSeparatorOffset);
1154
// draw bot separator
1155
GLHelper::setColor((changeRightCurrent && changeLeftBot) ? RGBColor::WHITE : RGBColor::ORANGE);
1156
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, separatorWidth, botSeparatorOffset);
1157
// check if draw inverse marking
1158
if (changeRightCurrent) {
1159
GLHelper::setColor(currentColor);
1160
GLHelper::drawInverseMarkings(myLaneGeometry.getShape(), myLaneGeometry.getShapeRotations(), myLaneGeometry.getShapeLengths(),
1161
3, 6, botSeparatorOffset, true, true, s.lefthand, 1);
1162
}
1163
} else {
1164
// draw top separator
1165
GLHelper::setColor((changeLeftCurrent && changeRightTop) ? RGBColor::WHITE : RGBColor::ORANGE);
1166
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, separatorWidth, topSeparatorOffset);
1167
// check if draw inverse marking
1168
if (changeLeftCurrent) {
1169
GLHelper::setColor(currentColor);
1170
GLHelper::drawInverseMarkings(myLaneGeometry.getShape(), myLaneGeometry.getShapeRotations(), myLaneGeometry.getShapeLengths(),
1171
3, 6, topSeparatorOffset, true, true, s.lefthand, 1);
1172
}
1173
// draw bot separator
1174
GLHelper::setColor((changeRightCurrent && changeLeftBot) ? RGBColor::WHITE : RGBColor::ORANGE);
1175
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, separatorWidth, botSeparatorOffset);
1176
// check if draw inverse marking
1177
if (changeRightCurrent) {
1178
GLHelper::setColor(currentColor);
1179
GLHelper::drawInverseMarkings(myLaneGeometry.getShape(), myLaneGeometry.getShapeRotations(), myLaneGeometry.getShapeLengths(),
1180
3, 6, botSeparatorOffset, true, true, s.lefthand, 1);
1181
}
1182
}
1183
// pop matrix
1184
GLHelper::popMatrix();
1185
}
1186
}
1187
1188
1189
void
1190
GNELane::drawLinkNo(const GUIVisualizationSettings& s) const {
1191
// check draw conditions
1192
if (s.drawLinkJunctionIndex.show(getParentEdges().front()->getToJunction())) {
1193
// get connections
1194
const auto& connections = getParentEdges().front()->getNBEdge()->getConnectionsFromLane(myIndex);
1195
// get number of links
1196
const int noLinks = (int)connections.size();
1197
// only continue if there is links
1198
if (noLinks > 0) {
1199
// push link matrix
1200
GLHelper::pushMatrix();
1201
// move front
1202
glTranslated(0, 0, GLO_TEXTNAME);
1203
// calculate width
1204
const double width = getParentEdges().front()->getNBEdge()->getLaneWidth(myIndex) / (double) noLinks;
1205
// get X1
1206
double x1 = getParentEdges().front()->getNBEdge()->getLaneWidth(myIndex) / 2;
1207
// iterate over links
1208
for (int i = noLinks - 1; i >= 0; i--) {
1209
// calculate x2
1210
const double x2 = x1 - (double)(width / 2.);
1211
// get link index
1212
const int linkIndex = getParentEdges().front()->getNBEdge()->getToNode()->getConnectionIndex(getParentEdges().front()->getNBEdge(),
1213
connections[s.lefthand ? noLinks - 1 - i : i]);
1214
// draw link index
1215
GLHelper::drawTextAtEnd(toString(linkIndex), myLaneGeometry.getShape(), x2, s.drawLinkJunctionIndex, s.scale);
1216
// update x1
1217
x1 -= width;
1218
}
1219
// pop link matrix
1220
GLHelper::popMatrix();
1221
}
1222
}
1223
}
1224
1225
1226
void
1227
GNELane::drawTLSLinkNo(const GUIVisualizationSettings& s) const {
1228
// check conditions
1229
if ((myDrawingConstants->getDetail() <= GUIVisualizationSettings::Detail::LaneDetails) && s.drawLinkTLIndex.show(getParentEdges().front()->getToJunction()) &&
1230
(getParentEdges().front()->getToJunction()->getNBNode()->getControllingTLS().size() > 0)) {
1231
// get connections
1232
const auto& connections = getParentEdges().front()->getNBEdge()->getConnectionsFromLane(myIndex);
1233
// get numer of links
1234
const int noLinks = (int)connections.size();
1235
// only continue if there are links
1236
if (noLinks > 0) {
1237
// push link matrix
1238
GLHelper::pushMatrix();
1239
// move t front
1240
glTranslated(0, 0, GLO_TEXTNAME);
1241
// calculate width
1242
const double w = getParentEdges().front()->getNBEdge()->getLaneWidth(myIndex) / (double) noLinks;
1243
// calculate x1
1244
double x1 = getParentEdges().front()->getNBEdge()->getLaneWidth(myIndex) / 2;
1245
// iterate over links
1246
for (int i = noLinks - 1; i >= 0; --i) {
1247
// calculate x2
1248
const double x2 = x1 - (double)(w / 2.);
1249
// get link number
1250
const int linkNo = connections[s.lefthand ? noLinks - 1 - i : i].tlLinkIndex;
1251
// draw link number
1252
GLHelper::drawTextAtEnd(toString(linkNo), myLaneGeometry.getShape(), x2, s.drawLinkTLIndex, s.scale);
1253
// update x1
1254
x1 -= w;
1255
}
1256
// pop link matrix
1257
GLHelper::popMatrix();
1258
}
1259
}
1260
}
1261
1262
1263
void
1264
GNELane::drawArrows(const GUIVisualizationSettings& s) const {
1265
if (s.showLinkDecals && getParentEdges().front()->getToJunction()->isLogicValid()) {
1266
// calculate begin, end and rotation
1267
const Position& begin = myLaneGeometry.getShape()[-2];
1268
const Position& end = myLaneGeometry.getShape().back();
1269
const double rot = GUIGeometry::calculateRotation(begin, end);
1270
// push arrow matrix
1271
GLHelper::pushMatrix();
1272
// move front (note: must draw on top of junction shape?
1273
glTranslated(0, 0, 3);
1274
// change color depending of spreadSuperposed
1275
if (myDrawingConstants->drawSuperposed()) {
1276
GLHelper::setColor(RGBColor::CYAN);
1277
} else {
1278
GLHelper::setColor(RGBColor::WHITE);
1279
}
1280
// move to end
1281
glTranslated(end.x(), end.y(), 0);
1282
// rotate
1283
glRotated(rot, 0, 0, 1);
1284
const double width = getParentEdges().front()->getNBEdge()->getLaneWidth(myIndex);
1285
if (width < SUMO_const_laneWidth) {
1286
glScaled(myDrawingConstants->getDrawingWidth() / SUMO_const_laneWidth, 1, 1);
1287
}
1288
// apply offset
1289
glTranslated(myDrawingConstants->getOffset() * -1, 0, 0);
1290
// get destination node
1291
const NBNode* dest = getParentEdges().front()->getNBEdge()->myTo;
1292
// draw all links iterating over connections
1293
for (const auto& connection : getParentEdges().front()->getNBEdge()->myConnections) {
1294
if (connection.fromLane == myIndex) {
1295
// get link direction
1296
LinkDirection dir = dest->getDirection(getParentEdges().front()->getNBEdge(), connection.toEdge, s.lefthand);
1297
// draw depending of link direction
1298
switch (dir) {
1299
case LinkDirection::STRAIGHT:
1300
GLHelper::drawBoxLine(Position(0, 4), 0, 2, .05);
1301
GLHelper::drawTriangleAtEnd(Position(0, 4), Position(0, 1), (double) 1, (double) .25);
1302
break;
1303
case LinkDirection::LEFT:
1304
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
1305
GLHelper::drawBoxLine(Position(0, 2.5), 90, 1, .05);
1306
GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(1.5, 2.5), (double) 1, (double) .25);
1307
break;
1308
case LinkDirection::RIGHT:
1309
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
1310
GLHelper::drawBoxLine(Position(0, 2.5), -90, 1, .05);
1311
GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(-1.5, 2.5), (double) 1, (double) .25);
1312
break;
1313
case LinkDirection::TURN:
1314
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
1315
GLHelper::drawBoxLine(Position(0, 2.5), 90, .5, .05);
1316
GLHelper::drawBoxLine(Position(0.5, 2.5), 180, 1, .05);
1317
GLHelper::drawTriangleAtEnd(Position(0.5, 2.5), Position(0.5, 4), (double) 1, (double) .25);
1318
break;
1319
case LinkDirection::TURN_LEFTHAND:
1320
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
1321
GLHelper::drawBoxLine(Position(0, 2.5), -90, 1, .05);
1322
GLHelper::drawBoxLine(Position(-0.5, 2.5), -180, 1, .05);
1323
GLHelper::drawTriangleAtEnd(Position(-0.5, 2.5), Position(-0.5, 4), (double) 1, (double) .25);
1324
break;
1325
case LinkDirection::PARTLEFT:
1326
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
1327
GLHelper::drawBoxLine(Position(0, 2.5), 45, .7, .05);
1328
GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(1.2, 1.3), (double) 1, (double) .25);
1329
break;
1330
case LinkDirection::PARTRIGHT:
1331
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
1332
GLHelper::drawBoxLine(Position(0, 2.5), -45, .7, .05);
1333
GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(-1.2, 1.3), (double) 1, (double) .25);
1334
break;
1335
case LinkDirection::NODIR:
1336
GLHelper::drawBoxLine(Position(1, 5.8), 245, 2, .05);
1337
GLHelper::drawBoxLine(Position(-1, 5.8), 115, 2, .05);
1338
glTranslated(0, 5, 0);
1339
GLHelper::drawOutlineCircle(0.9, 0.8, 32);
1340
glTranslated(0, -5, 0);
1341
break;
1342
default:
1343
break;
1344
}
1345
}
1346
}
1347
// pop arrow matrix
1348
GLHelper::popMatrix();
1349
}
1350
}
1351
1352
1353
void
1354
GNELane::drawLane2LaneConnections() const {
1355
GLHelper::pushMatrix();
1356
glTranslated(0, 0, 0.1); // must draw on top of junction shape
1357
std::vector<NBEdge::Connection> connections = getParentEdges().front()->getNBEdge()->getConnectionsFromLane(myIndex);
1358
NBNode* node = getParentEdges().front()->getNBEdge()->getToNode();
1359
const Position& startPos = myLaneGeometry.getShape()[-1];
1360
for (auto it : connections) {
1361
const LinkState state = node->getLinkState(getParentEdges().front()->getNBEdge(), it.toEdge, it.fromLane, it.toLane, it.mayDefinitelyPass, it.tlID);
1362
switch (state) {
1363
case LINKSTATE_TL_OFF_NOSIGNAL:
1364
glColor3d(1, 1, 0);
1365
break;
1366
case LINKSTATE_TL_OFF_BLINKING:
1367
glColor3d(0, 1, 1);
1368
break;
1369
case LINKSTATE_MAJOR:
1370
glColor3d(1, 1, 1);
1371
break;
1372
case LINKSTATE_MINOR:
1373
glColor3d(.4, .4, .4);
1374
break;
1375
case LINKSTATE_STOP:
1376
glColor3d(.7, .4, .4);
1377
break;
1378
case LINKSTATE_EQUAL:
1379
glColor3d(.7, .7, .7);
1380
break;
1381
case LINKSTATE_ALLWAY_STOP:
1382
glColor3d(.7, .7, 1);
1383
break;
1384
case LINKSTATE_ZIPPER:
1385
glColor3d(.75, .5, 0.25);
1386
break;
1387
default:
1388
throw ProcessError(TLF("Unexpected LinkState '%'", toString(state)));
1389
}
1390
const Position& endPos = it.toEdge->getLaneShape(it.toLane)[0];
1391
glBegin(GL_LINES);
1392
glVertex2d(startPos.x(), startPos.y());
1393
glVertex2d(endPos.x(), endPos.y());
1394
glEnd();
1395
GLHelper::drawTriangleAtEnd(startPos, endPos, (double) 1.5, (double) .2);
1396
}
1397
GLHelper::popMatrix();
1398
}
1399
1400
1401
void
1402
GNELane::calculateLaneContour(const GUIVisualizationSettings& s, const double layer) const {
1403
// first check if edge parent was inserted with full boundary
1404
if (!gViewObjectsHandler.checkBoundaryParentObject(this, layer, getParentEdges().front())) {
1405
// calculate contour
1406
myNetworkElementContour.calculateContourExtrudedShape(s, myDrawingConstants->getDetail(),
1407
this, myLaneGeometry.getShape(), layer, myDrawingConstants->getDrawingWidth(), 1,
1408
true, true, myDrawingConstants->getOffset(), nullptr, getParentEdges().front());
1409
// calculate geometry points contour if we're editing shape
1410
if (myShapeEdited) {
1411
myNetworkElementContour.calculateContourAllGeometryPoints(s, myDrawingConstants->getDetail(),
1412
this, myLaneGeometry.getShape(), layer, s.neteditSizeSettings.laneGeometryPointRadius,
1413
myDrawingConstants->getExaggeration(), true);
1414
}
1415
}
1416
}
1417
1418
1419
RGBColor
1420
GNELane::setLaneColor(const GUIVisualizationSettings& s) const {
1421
const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();
1422
// declare a RGBColor variable
1423
RGBColor color;
1424
// we need to draw lanes with a special color if we're inspecting a Trip or Flow and this lane belongs to a via's edge.
1425
if (inspectedElements.getFirstAC() &&
1426
!inspectedElements.getFirstAC()->isAttributeCarrierSelected() &&
1427
inspectedElements.getFirstAC()->getTagProperty()->vehicleEdges()) {
1428
// obtain attribute "via"
1429
std::vector<std::string> viaEdges = parse<std::vector<std::string> >(inspectedElements.getFirstAC()->getAttribute(SUMO_ATTR_VIA));
1430
// iterate over viaEdges
1431
for (const auto& edge : viaEdges) {
1432
// check if parent edge is in the via edges
1433
if (getParentEdges().front()->getID() == edge) {
1434
// set green color in GLHelper and return it
1435
color = RGBColor::GREEN;
1436
}
1437
}
1438
}
1439
if (mySpecialColor != nullptr) {
1440
// If special color is enabled, set it
1441
color = *mySpecialColor;
1442
} else if (getParentEdges().front()->drawUsingSelectColor() && s.laneColorer.getActive() != 1) {
1443
// override with special colors (unless the color scheme is based on selection)
1444
color = s.colorSettings.selectedEdgeColor;
1445
} else {
1446
// Get normal lane color
1447
const GUIColorer& c = s.laneColorer;
1448
if (!setFunctionalColor(c.getActive(), color) && !setMultiColor(s, c, color)) {
1449
color = c.getScheme().getColor(getColorValue(s, c.getActive()));
1450
}
1451
}
1452
// special color for conflicted candidate edges
1453
if (getParentEdges().front()->isConflictedCandidate()) {
1454
// extra check for route frame
1455
if (myNet->getViewParent()->getRouteFrame()->getPathCreator()->drawCandidateEdgesWithSpecialColor()) {
1456
color = s.candidateColorSettings.conflict;
1457
}
1458
}
1459
// special color for special candidate edges
1460
if (getParentEdges().front()->isSpecialCandidate()) {
1461
// extra check for route frame
1462
if (myNet->getViewParent()->getRouteFrame()->getPathCreator()->drawCandidateEdgesWithSpecialColor()) {
1463
color = s.candidateColorSettings.special;
1464
}
1465
}
1466
// special color for candidate edges
1467
if (getParentEdges().front()->isPossibleCandidate()) {
1468
// extra check for route frame
1469
if (myNet->getViewParent()->getRouteFrame()->getPathCreator()->drawCandidateEdgesWithSpecialColor()) {
1470
color = s.candidateColorSettings.possible;
1471
}
1472
}
1473
// special color for source candidate edges
1474
if (getParentEdges().front()->isSourceCandidate()) {
1475
color = s.candidateColorSettings.source;
1476
}
1477
// special color for target candidate edges
1478
if (getParentEdges().front()->isTargetCandidate()) {
1479
color = s.candidateColorSettings.target;
1480
}
1481
// special color for invalid candidate edges
1482
if (getParentEdges().front()->isInvalidCandidate()) {
1483
color = s.candidateColorSettings.invalid;
1484
}
1485
// special color for source candidate lanes
1486
if (mySourceCandidate) {
1487
color = s.candidateColorSettings.source;
1488
}
1489
// special color for target candidate lanes
1490
if (myTargetCandidate) {
1491
color = s.candidateColorSettings.target;
1492
}
1493
// special color for special candidate lanes
1494
if (mySpecialCandidate) {
1495
color = s.candidateColorSettings.special;
1496
}
1497
// special color for possible candidate lanes
1498
if (myPossibleCandidate) {
1499
color = s.candidateColorSettings.possible;
1500
}
1501
// special color for conflicted candidate lanes
1502
if (myConflictedCandidate) {
1503
color = s.candidateColorSettings.conflict;
1504
}
1505
// special color for invalid candidate lanes
1506
if (myInvalidCandidate) {
1507
color = s.candidateColorSettings.invalid;
1508
}
1509
// set color in GLHelper
1510
GLHelper::setColor(color);
1511
return color;
1512
}
1513
1514
1515
bool
1516
GNELane::setFunctionalColor(int activeScheme, RGBColor& col) const {
1517
switch (activeScheme) {
1518
case 6: {
1519
double hue = GeomHelper::naviDegree(myLaneGeometry.getShape().beginEndAngle()); // [0-360]
1520
col = RGBColor::fromHSV(hue, 1., 1.);
1521
return true;
1522
}
1523
default:
1524
return false;
1525
}
1526
}
1527
1528
1529
bool
1530
GNELane::setMultiColor(const GUIVisualizationSettings& s, const GUIColorer& c, RGBColor& col) const {
1531
const int activeScheme = c.getActive();
1532
myShapeColors.clear();
1533
switch (activeScheme) {
1534
case 9: // color by height at segment start
1535
for (PositionVector::const_iterator ii = myLaneGeometry.getShape().begin(); ii != myLaneGeometry.getShape().end() - 1; ++ii) {
1536
myShapeColors.push_back(c.getScheme().getColor(ii->z()));
1537
}
1538
col = c.getScheme().getColor(getColorValue(s, 8));
1539
return true;
1540
case 11: // color by inclination at segment start
1541
for (int ii = 1; ii < (int)myLaneGeometry.getShape().size(); ++ii) {
1542
const double inc = (myLaneGeometry.getShape()[ii].z() - myLaneGeometry.getShape()[ii - 1].z()) / MAX2(POSITION_EPS, myLaneGeometry.getShape()[ii].distanceTo2D(myLaneGeometry.getShape()[ii - 1]));
1543
myShapeColors.push_back(c.getScheme().getColor(inc));
1544
}
1545
col = c.getScheme().getColor(getColorValue(s, 10));
1546
return true;
1547
default:
1548
return false;
1549
}
1550
}
1551
1552
1553
double
1554
GNELane::getColorValue(const GUIVisualizationSettings& s, int activeScheme) const {
1555
const SVCPermissions myPermissions = getParentEdges().front()->getNBEdge()->getPermissions(myIndex);
1556
if (mySpecialColor != nullptr && mySpecialColorValue != std::numeric_limits<double>::max()) {
1557
return mySpecialColorValue;
1558
}
1559
switch (activeScheme) {
1560
case 0:
1561
switch (myPermissions) {
1562
case SVC_PEDESTRIAN:
1563
return 1;
1564
case SVC_BICYCLE:
1565
return 2;
1566
case 0:
1567
// forbidden road or green verge
1568
return getParentEdges().front()->getNBEdge()->getPermissions() == 0 ? 10 : 3;
1569
case SVC_SHIP:
1570
return 4;
1571
case SVC_AUTHORITY:
1572
return 8;
1573
case SVC_AIRCRAFT:
1574
case SVC_DRONE:
1575
return 12;
1576
default:
1577
break;
1578
}
1579
if (getParentEdges().front()->getNBEdge()->isMacroscopicConnector()) {
1580
return 9;
1581
} else if (isRailway(myPermissions)) {
1582
return 5;
1583
} else if ((myPermissions & SVC_PASSENGER) != 0) {
1584
if ((myPermissions & (SVC_RAIL_CLASSES & ~SVC_RAIL_FAST)) != 0 && (myPermissions & SVC_SHIP) == 0) {
1585
return 6;
1586
} else {
1587
return 0;
1588
}
1589
} else {
1590
if ((myPermissions & SVC_RAIL_CLASSES) != 0 && (myPermissions & SVC_SHIP) == 0) {
1591
return 6;
1592
} else {
1593
return 7;
1594
}
1595
}
1596
case 1:
1597
return isAttributeCarrierSelected() || getParentEdges().front()->isAttributeCarrierSelected();
1598
case 2:
1599
return (double)myPermissions;
1600
case 3:
1601
return getParentEdges().front()->getNBEdge()->getLaneSpeed(myIndex);
1602
case 4:
1603
return getParentEdges().front()->getNBEdge()->getNumLanes();
1604
case 5: {
1605
return getParentEdges().front()->getNBEdge()->getLoadedLength() / getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).shape.length();
1606
}
1607
// case 6: by angle (functional)
1608
case 7: {
1609
return getParentEdges().front()->getNBEdge()->getPriority();
1610
}
1611
case 8: {
1612
// color by z of first shape point
1613
return myLaneGeometry.getShape()[0].z();
1614
}
1615
// case 9: by segment height
1616
case 10: {
1617
// color by incline
1618
return (myLaneGeometry.getShape()[-1].z() - myLaneGeometry.getShape()[0].z()) / getParentEdges().front()->getNBEdge()->getLength();
1619
}
1620
// case 11: by segment incline
1621
1622
case 12: {
1623
// by numerical edge param value
1624
if (getParentEdges().front()->getNBEdge()->hasParameter(s.edgeParam)) {
1625
try {
1626
return StringUtils::toDouble(getParentEdges().front()->getNBEdge()->getParameter(s.edgeParam, "0"));
1627
} catch (NumberFormatException&) {
1628
try {
1629
return StringUtils::toBool(getParentEdges().front()->getNBEdge()->getParameter(s.edgeParam, "0"));
1630
} catch (BoolFormatException&) {
1631
return -1;
1632
}
1633
}
1634
} else {
1635
return GUIVisualizationSettings::MISSING_DATA;
1636
}
1637
}
1638
case 13: {
1639
// by numerical lane param value
1640
if (getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).hasParameter(s.laneParam)) {
1641
try {
1642
return StringUtils::toDouble(getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).getParameter(s.laneParam, "0"));
1643
} catch (NumberFormatException&) {
1644
try {
1645
return StringUtils::toBool(getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).getParameter(s.laneParam, "0"));
1646
} catch (BoolFormatException&) {
1647
return -1;
1648
}
1649
}
1650
} else {
1651
return GUIVisualizationSettings::MISSING_DATA;
1652
}
1653
}
1654
case 14: {
1655
return getParentEdges().front()->getNBEdge()->getDistance();
1656
}
1657
case 15: {
1658
return fabs(getParentEdges().front()->getNBEdge()->getDistance());
1659
}
1660
}
1661
return 0;
1662
}
1663
1664
1665
void
1666
GNELane::drawOverlappedRoutes(const int numRoutes) const {
1667
// get middle point and angle
1668
const Position center = myLaneGeometry.getShape().positionAtOffset2D(myLaneGeometry.getShape().length2D() * 0.5);
1669
const double angle = myLaneGeometry.getShape().rotationDegreeAtOffset(myLaneGeometry.getShape().length2D() * 0.5);
1670
// Push route matrix
1671
GLHelper::pushMatrix();
1672
// translate to front
1673
glTranslated(0, 0, GLO_ROUTE + 1);
1674
// get middle
1675
GLHelper::drawText(toString(numRoutes) + " routes", center, 0, 1.8, RGBColor::BLACK, angle + 90);
1676
// pop route matrix
1677
GLHelper::popMatrix();
1678
1679
}
1680
1681
1682
void
1683
GNELane::drawLaneStopOffset(const GUIVisualizationSettings& s) const {
1684
const auto& laneStopOffset = getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).laneStopOffset;
1685
// check conditions
1686
if (laneStopOffset.isDefined() && (laneStopOffset.getPermissions() & SVC_PASSENGER) != 0) {
1687
const Position& end = getLaneShape().back();
1688
const Position& f = getLaneShape()[-2];
1689
const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
1690
GLHelper::setColor(s.getLinkColor(LINKSTATE_MAJOR));
1691
GLHelper::pushMatrix();
1692
glTranslated(end.x(), end.y(), 1);
1693
glRotated(rot, 0, 0, 1);
1694
glTranslated(0, laneStopOffset.getOffset(), 0);
1695
glBegin(GL_QUADS);
1696
glVertex2d(-myDrawingConstants->getDrawingWidth(), 0.0);
1697
glVertex2d(-myDrawingConstants->getDrawingWidth(), 0.2);
1698
glVertex2d(myDrawingConstants->getDrawingWidth(), 0.2);
1699
glVertex2d(myDrawingConstants->getDrawingWidth(), 0.0);
1700
glEnd();
1701
GLHelper::popMatrix();
1702
}
1703
}
1704
1705
1706
bool
1707
GNELane::drawAsWaterway(const GUIVisualizationSettings& s) const {
1708
return isWaterway(getParentEdges().front()->getNBEdge()->getPermissions(myIndex)) && s.showRails; // reusing the showRails setting
1709
}
1710
1711
1712
void
1713
GNELane::drawDirectionIndicators(const GUIVisualizationSettings& s) const {
1714
// Draw direction indicators if the correspondient option is enabled
1715
if (s.showLaneDirection) {
1716
// improve visibility of superposed rail edges
1717
if (!myDrawingConstants->drawAsRailway()) {
1718
glColor3d(0.3, 0.3, 0.3);
1719
}
1720
// get width and sideOffset
1721
const double width = MAX2(NUMERICAL_EPS, (myDrawingConstants->getDrawingWidth() * 2 * myDrawingConstants->getExaggeration()));
1722
// push direction indicator matrix
1723
GLHelper::pushMatrix();
1724
// move to front
1725
glTranslated(0, 0, 0.1);
1726
// iterate over shape
1727
for (int i = 0; i < (int) myLaneGeometry.getShape().size() - 1; ++i) {
1728
// push triangle matrix
1729
GLHelper::pushMatrix();
1730
// move front
1731
glTranslated(myLaneGeometry.getShape()[i].x(), myLaneGeometry.getShape()[i].y(), 0.1);
1732
// rotate
1733
glRotated(myLaneGeometry.getShapeRotations()[i], 0, 0, 1);
1734
// calculate subwidth
1735
for (double subWidth = 0; subWidth < myLaneGeometry.getShapeLengths()[i]; subWidth += width) {
1736
// calculate length
1737
const double length = MIN2(width * 0.5, myLaneGeometry.getShapeLengths()[i] - subWidth);
1738
// draw triangle
1739
glBegin(GL_TRIANGLES);
1740
glVertex2d(-myDrawingConstants->getOffset(), -subWidth - length);
1741
glVertex2d(-myDrawingConstants->getOffset() - width * 0.25, -subWidth);
1742
glVertex2d(-myDrawingConstants->getOffset() + width * 0.25, -subWidth);
1743
glEnd();
1744
}
1745
// pop triangle matrix
1746
GLHelper::popMatrix();
1747
}
1748
// pop direction indicator matrix
1749
GLHelper::popMatrix();
1750
}
1751
}
1752
1753
1754
void
1755
GNELane::drawLaneAsRailway() const {
1756
// draw foot width 150mm, assume that distance between rail feet inner sides is reduced on both sides by 39mm with regard to the gauge
1757
// assume crosstie length of 181% gauge (2600mm for standard gauge)
1758
// first save current color (obtained from view configuration)
1759
const auto currentLaneColor = GLHelper::getColor();
1760
// Set current color
1761
GLHelper::setColor(currentLaneColor);
1762
// continue depending of detail
1763
if (myDrawingConstants->getDetail() <= GUIVisualizationSettings::Detail::LaneDetails) {
1764
// move
1765
glTranslated(0, 0, 0.1);
1766
// draw external crossbar
1767
const double crossbarWidth = 0.2 * myDrawingConstants->getExaggeration();
1768
// draw geometry
1769
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry,
1770
myDrawingConstants->getDrawingWidth() * 0.8,
1771
myDrawingConstants->getOffset());
1772
// move
1773
glTranslated(0, 0, 0.01);
1774
// Set color gray
1775
glColor3d(0.8, 0.8, 0.8);
1776
// draw geometry
1777
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry,
1778
myDrawingConstants->getDrawingWidth() * 0.6,
1779
myDrawingConstants->getOffset());
1780
// move
1781
glTranslated(0, 0, 0.01);
1782
// Set current color
1783
GLHelper::setColor(currentLaneColor);
1784
// Draw crossties
1785
GLHelper::drawCrossTies(myLaneGeometry.getShape(), myLaneGeometry.getShapeRotations(), myLaneGeometry.getShapeLengths(),
1786
crossbarWidth, 0.6 * myDrawingConstants->getExaggeration(), myDrawingConstants->getDrawingWidth(),
1787
myDrawingConstants->getOffset(), false);
1788
} else if (myShapeColors.size() > 0) {
1789
// draw colored box lines
1790
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, myShapeColors,
1791
myDrawingConstants->getDrawingWidth(), myDrawingConstants->getOffset());
1792
} else {
1793
// draw geometry with current color
1794
GUIGeometry::drawGeometry(myDrawingConstants->getDetail(), myLaneGeometry, myDrawingConstants->getDrawingWidth(),
1795
myDrawingConstants->getOffset());
1796
}
1797
}
1798
1799
1800
void
1801
GNELane::drawTextures(const GUIVisualizationSettings& s) const {
1802
// check all conditions for drawing textures
1803
if (!s.disableLaneIcons && (myLaneRestrictedTexturePositions.size() > 0)) {
1804
// Declare default width of icon (3)
1805
const double iconWidth = myDrawingConstants->getDrawingWidth() * 0.6;
1806
// Draw list of icons
1807
for (int i = 0; i < (int)myLaneRestrictedTexturePositions.size(); i++) {
1808
// Push draw matrix 2
1809
GLHelper::pushMatrix();
1810
// Set white color
1811
glColor3d(1, 1, 1);
1812
// Translate matrix 2
1813
glTranslated(myLaneRestrictedTexturePositions.at(i).x(), myLaneRestrictedTexturePositions.at(i).y(), 0.1);
1814
// Rotate matrix 2
1815
glRotated(myLaneRestrictedTextureRotations.at(i), 0, 0, -1);
1816
glRotated(90, 0, 0, 1);
1817
// draw texture box depending of type of restriction
1818
if (isRestricted(SVC_PEDESTRIAN)) {
1819
GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(GUITexture::LANE_PEDESTRIAN), iconWidth);
1820
} else if (isRestricted(SVC_BICYCLE)) {
1821
GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(GUITexture::LANE_BIKE), iconWidth);
1822
} else if (isRestricted(SVC_BUS)) {
1823
GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(GUITexture::LANE_BUS), iconWidth);
1824
}
1825
// Pop draw matrix 2
1826
GLHelper::popMatrix();
1827
}
1828
}
1829
}
1830
1831
1832
void
1833
GNELane::drawStartEndGeometryPoints(const GUIVisualizationSettings& s) const {
1834
// draw a Start/endPoints if lane has a custom shape
1835
if ((myDrawingConstants->getDetail() <= GUIVisualizationSettings::Detail::GeometryPoint) && (getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).customShape.size() > 1)) {
1836
// obtain circle width and resolution
1837
const double circleWidth = GNEEdge::SNAP_RADIUS * MIN2((double)1, s.laneWidthExaggeration) / 2;
1838
// obtain custom shape
1839
const PositionVector& customShape = getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).customShape;
1840
// set color (override with special colors unless the color scheme is based on selection)
1841
if (drawUsingSelectColor() && s.laneColorer.getActive() != 1) {
1842
GLHelper::setColor(s.colorSettings.selectedEdgeColor.changedBrightness(-20));
1843
} else {
1844
GLHelper::setColor(s.junctionColorer.getSchemes()[0].getColor(2));
1845
}
1846
// push start matrix
1847
GLHelper::pushMatrix();
1848
// move to shape start position
1849
glTranslated(customShape.front().x(), customShape.front().y(), 0.1);
1850
// draw circle
1851
GLHelper::drawFilledCircleDetailled(myDrawingConstants->getDetail(), circleWidth);
1852
// draw s depending of detail
1853
if (myDrawingConstants->getDetail() <= GUIVisualizationSettings::Detail::Text) {
1854
// move top
1855
glTranslated(0, 0, 0.1);
1856
// draw "S"
1857
GLHelper::drawText("S", Position(), 0.1, circleWidth, RGBColor::WHITE);
1858
}
1859
// pop start matrix
1860
GLHelper::popMatrix();
1861
// draw line between junction and start position
1862
GLHelper::pushMatrix();
1863
// move top
1864
glTranslated(0, 0, 0.1);
1865
// set line width
1866
glLineWidth(4);
1867
// draw line
1868
GLHelper::drawLine(customShape.front(), getParentEdges().front()->getFromJunction()->getPositionInView());
1869
// pop line matrix
1870
GLHelper::popMatrix();
1871
// push start matrix
1872
GLHelper::pushMatrix();
1873
// move to end position
1874
glTranslated(customShape.back().x(), customShape.back().y(), 0.1);
1875
// draw filled circle
1876
GLHelper::drawFilledCircleDetailled(myDrawingConstants->getDetail(), circleWidth);
1877
// draw "e" depending of detail
1878
if (myDrawingConstants->getDetail() <= GUIVisualizationSettings::Detail::Text) {
1879
// move top
1880
glTranslated(0, 0, 0.1);
1881
// draw "E"
1882
GLHelper::drawText("E", Position(), 0, circleWidth, RGBColor::WHITE);
1883
}
1884
// pop start matrix
1885
GLHelper::popMatrix();
1886
// draw line between Junction and end position
1887
GLHelper::pushMatrix();
1888
// move top
1889
glTranslated(0, 0, 0.1);
1890
// set line width
1891
glLineWidth(4);
1892
// draw line
1893
GLHelper::drawLine(customShape.back(), getParentEdges().front()->getToJunction()->getPositionInView());
1894
// pop line matrix
1895
GLHelper::popMatrix();
1896
}
1897
}
1898
1899
1900
std::string
1901
GNELane::getParentName() const {
1902
return getParentEdges().front()->getID();
1903
}
1904
1905
1906
long
1907
GNELane::onDefault(FXObject* obj, FXSelector sel, void* data) {
1908
myNet->getViewParent()->getTLSEditorFrame()->handleMultiChange(this, obj, sel, data);
1909
return 1;
1910
}
1911
1912
1913
std::vector<GNEConnection*>
1914
GNELane::getGNEIncomingConnections() {
1915
// Declare a vector to save incoming connections
1916
std::vector<GNEConnection*> incomingConnections;
1917
// Obtain incoming edges if junction source was already created
1918
GNEJunction* junctionSource = getParentEdges().front()->getFromJunction();
1919
if (junctionSource) {
1920
// Iterate over incoming GNEEdges of junction
1921
for (const auto& incomingEdge : junctionSource->getGNEIncomingEdges()) {
1922
// Iterate over connection of incoming edges
1923
for (const auto& connection : incomingEdge->getGNEConnections()) {
1924
if (connection->getLaneTo()->getIndex() == getIndex()) {
1925
incomingConnections.push_back(connection);
1926
}
1927
}
1928
}
1929
}
1930
return incomingConnections;
1931
}
1932
1933
1934
std::vector<GNEConnection*>
1935
GNELane::getGNEOutcomingConnections() {
1936
// Obtain GNEConnection of parent edge
1937
const std::vector<GNEConnection*>& edgeConnections = getParentEdges().front()->getGNEConnections();
1938
std::vector<GNEConnection*> outcomingConnections;
1939
// Obtain outgoing connections
1940
for (const auto& connection : edgeConnections) {
1941
if (connection->getLaneFrom()->getIndex() == getIndex()) {
1942
outcomingConnections.push_back(connection);
1943
}
1944
}
1945
return outcomingConnections;
1946
}
1947
1948
1949
void
1950
GNELane::updateConnectionIDs() {
1951
// update incoming connections of lane
1952
std::vector<GNEConnection*> incomingConnections = getGNEIncomingConnections();
1953
for (const auto& incomingConnection : incomingConnections) {
1954
incomingConnection->updateConnectionID();
1955
}
1956
// update outcoming connections of lane
1957
std::vector<GNEConnection*> outcomingConnections = getGNEOutcomingConnections();
1958
for (const auto& outcomingConnection : outcomingConnections) {
1959
outcomingConnection->updateConnectionID();
1960
}
1961
}
1962
1963
1964
double
1965
GNELane::getLengthGeometryFactor() const {
1966
// factor should not be 0
1967
if (getParentEdges().front()->getNBEdge()->getFinalLength() > 0) {
1968
return MAX2(POSITION_EPS, (getLaneShape().length() / getParentEdges().front()->getNBEdge()->getFinalLength()));
1969
} else {
1970
return POSITION_EPS;
1971
};
1972
}
1973
1974
1975
void
1976
GNELane::buildEdgeOperations(GUISUMOAbstractView& parent, GUIGLObjectPopupMenu* ret) {
1977
// Create basic commands
1978
std::string edgeDescPossibleMulti = toString(SUMO_TAG_EDGE);
1979
const int edgeSelSize = getParentEdges().front()->isAttributeCarrierSelected() ? myNet->getAttributeCarriers()->getNumberOfSelectedEdges() : 0;
1980
if (edgeSelSize && getParentEdges().front()->isAttributeCarrierSelected() && (edgeSelSize > 1)) {
1981
edgeDescPossibleMulti = toString(edgeSelSize) + " " + toString(SUMO_TAG_EDGE) + "s";
1982
}
1983
// create menu pane for edge operations
1984
FXMenuPane* edgeOperations = new FXMenuPane(ret);
1985
ret->insertMenuPaneChild(edgeOperations);
1986
if (edgeSelSize > 0) {
1987
new FXMenuCascade(ret, TLF("Edge operations (% selected)", toString(edgeSelSize)).c_str(), nullptr, edgeOperations);
1988
} else {
1989
new FXMenuCascade(ret, TL("Edge operations"), nullptr, edgeOperations);
1990
}
1991
// create menu commands for all edge operations
1992
GUIDesigns::buildFXMenuCommand(edgeOperations, TL("Split edge here"), nullptr, &parent, MID_GNE_EDGE_SPLIT);
1993
auto splitBothDirections = GUIDesigns::buildFXMenuCommand(edgeOperations, TL("Split edge in both directions here (no symmetric opposite edge)"), nullptr, &parent, MID_GNE_EDGE_SPLIT_BIDI);
1994
// check if allow split edge in both directions
1995
splitBothDirections->disable();
1996
const auto oppositeEdges = getParentEdges().front()->getOppositeEdges();
1997
if (oppositeEdges.size() == 0) {
1998
splitBothDirections->setText(TL("Split edge in both directions here (no opposite edge)"));
1999
} else {
2000
for (const auto& oppositeEdge : oppositeEdges) {
2001
// get reverse inner geometry
2002
const auto reverseGeometry = oppositeEdge->getNBEdge()->getInnerGeometry().reverse();
2003
if (reverseGeometry == getParentEdges().front()->getNBEdge()->getInnerGeometry()) {
2004
splitBothDirections->enable();
2005
splitBothDirections->setText(TL("Split edge in both directions here"));
2006
}
2007
}
2008
}
2009
GUIDesigns::buildFXMenuCommand(edgeOperations, TL("Set geometry endpoint here (shift-click)"), nullptr, &parent, MID_GNE_EDGE_EDIT_ENDPOINT);
2010
// restore geometry points depending of selection status
2011
if (getParentEdges().front()->isAttributeCarrierSelected()) {
2012
if (edgeSelSize == 1) {
2013
GUIDesigns::buildFXMenuCommand(edgeOperations, TL("Restore both geometry endpoints"), nullptr, &parent, MID_GNE_EDGE_RESET_ENDPOINT);
2014
} else {
2015
GUIDesigns::buildFXMenuCommand(edgeOperations, TL("Restore geometry endpoints of all selected edges"), nullptr, &parent, MID_GNE_EDGE_RESET_ENDPOINT);
2016
}
2017
} else {
2018
GUIDesigns::buildFXMenuCommand(edgeOperations, TL("Restore geometry endpoint (shift-click)"), nullptr, &parent, MID_GNE_EDGE_RESET_ENDPOINT);
2019
}
2020
GUIDesigns::buildFXMenuCommand(edgeOperations, TLF("Reverse %", edgeDescPossibleMulti), nullptr, &parent, MID_GNE_EDGE_REVERSE);
2021
auto reverse = GUIDesigns::buildFXMenuCommand(edgeOperations, TLF("Add reverse direction for %", edgeDescPossibleMulti), nullptr, &parent, MID_GNE_EDGE_ADD_REVERSE);
2022
if (getParentEdges().front()->getReverseEdge() != nullptr) {
2023
reverse->disable();
2024
}
2025
GUIDesigns::buildFXMenuCommand(edgeOperations, TLF("Add reverse disconnected direction for %", edgeDescPossibleMulti), nullptr, &parent, MID_GNE_EDGE_ADD_REVERSE_DISCONNECTED);
2026
GUIDesigns::buildFXMenuCommand(edgeOperations, TLF("Reset lengths for %", edgeDescPossibleMulti), nullptr, &parent, MID_GNE_EDGE_RESET_LENGTH);
2027
GUIDesigns::buildFXMenuCommand(edgeOperations, TLF("Straighten %", edgeDescPossibleMulti), nullptr, &parent, MID_GNE_EDGE_STRAIGHTEN);
2028
GUIDesigns::buildFXMenuCommand(edgeOperations, TLF("Smooth %", edgeDescPossibleMulti), nullptr, &parent, MID_GNE_EDGE_SMOOTH);
2029
GUIDesigns::buildFXMenuCommand(edgeOperations, TLF("Straighten elevation of %", edgeDescPossibleMulti), nullptr, &parent, MID_GNE_EDGE_STRAIGHTEN_ELEVATION);
2030
GUIDesigns::buildFXMenuCommand(edgeOperations, TLF("Smooth elevation of %", edgeDescPossibleMulti), nullptr, &parent, MID_GNE_EDGE_SMOOTH_ELEVATION);
2031
}
2032
2033
2034
void
2035
GNELane::buildLaneOperations(GUISUMOAbstractView& parent, GUIGLObjectPopupMenu* ret) {
2036
// Get icons
2037
FXIcon* pedestrianIcon = GUIIconSubSys::getIcon(GUIIcon::LANE_PEDESTRIAN);
2038
FXIcon* bikeIcon = GUIIconSubSys::getIcon(GUIIcon::LANE_BIKE);
2039
FXIcon* busIcon = GUIIconSubSys::getIcon(GUIIcon::LANE_BUS);
2040
FXIcon* greenVergeIcon = GUIIconSubSys::getIcon(GUIIcon::LANEGREENVERGE);
2041
// declare number of selected lanes
2042
int numSelectedLanes = 0;
2043
// if lane is selected, calculate number of restricted lanes
2044
bool edgeHasSidewalk = false;
2045
bool edgeHasBikelane = false;
2046
bool edgeHasBuslane = false;
2047
bool differentLaneShapes = false;
2048
if (isAttributeCarrierSelected()) {
2049
const auto selectedLanes = myNet->getAttributeCarriers()->getSelectedLanes();
2050
// update numSelectedLanes
2051
numSelectedLanes = (int)selectedLanes.size();
2052
// iterate over selected lanes
2053
for (const auto& selectedLane : selectedLanes) {
2054
if (selectedLane->getParentEdges().front()->hasRestrictedLane(SVC_PEDESTRIAN)) {
2055
edgeHasSidewalk = true;
2056
}
2057
if (selectedLane->getParentEdges().front()->hasRestrictedLane(SVC_BICYCLE)) {
2058
edgeHasBikelane = true;
2059
}
2060
if (selectedLane->getParentEdges().front()->hasRestrictedLane(SVC_BUS)) {
2061
edgeHasBuslane = true;
2062
}
2063
if (selectedLane->getParentEdges().front()->getNBEdge()->getLaneStruct(selectedLane->getIndex()).customShape.size() != 0) {
2064
differentLaneShapes = true;
2065
}
2066
}
2067
} else {
2068
edgeHasSidewalk = getParentEdges().front()->hasRestrictedLane(SVC_PEDESTRIAN);
2069
edgeHasBikelane = getParentEdges().front()->hasRestrictedLane(SVC_BICYCLE);
2070
edgeHasBuslane = getParentEdges().front()->hasRestrictedLane(SVC_BUS);
2071
differentLaneShapes = getParentEdges().front()->getNBEdge()->getLaneStruct(myIndex).customShape.size() != 0;
2072
}
2073
// create menu pane for lane operations
2074
FXMenuPane* laneOperations = new FXMenuPane(ret);
2075
ret->insertMenuPaneChild(laneOperations);
2076
if (numSelectedLanes > 0) {
2077
new FXMenuCascade(ret, TLF("Lane operations (% selected)", toString(numSelectedLanes)).c_str(), nullptr, laneOperations);
2078
} else {
2079
new FXMenuCascade(ret, TL("Lane operations"), nullptr, laneOperations);
2080
}
2081
GUIDesigns::buildFXMenuCommand(laneOperations, TL("Duplicate lane"), nullptr, &parent, MID_GNE_LANE_DUPLICATE);
2082
GUIDesigns::buildFXMenuCommand(laneOperations, TL("Set custom lane shape"), nullptr, &parent, MID_GNE_LANE_EDIT_SHAPE);
2083
FXMenuCommand* resetCustomShape = GUIDesigns::buildFXMenuCommand(laneOperations, TL("Reset custom shape"), nullptr, &parent, MID_GNE_LANE_RESET_CUSTOMSHAPE);
2084
if (!differentLaneShapes) {
2085
resetCustomShape->disable();
2086
}
2087
FXMenuCommand* resetOppositeLane = GUIDesigns::buildFXMenuCommand(laneOperations, TL("Reset opposite lane"), nullptr, &parent, MID_GNE_LANE_RESET_OPPOSITELANE);
2088
if (getAttribute(GNE_ATTR_OPPOSITE).empty()) {
2089
resetOppositeLane->disable();
2090
}
2091
// Create panel for lane operations and insert it in ret
2092
FXMenuPane* addSpecialLanes = new FXMenuPane(laneOperations);
2093
ret->insertMenuPaneChild(addSpecialLanes);
2094
FXMenuPane* removeSpecialLanes = new FXMenuPane(laneOperations);
2095
ret->insertMenuPaneChild(removeSpecialLanes);
2096
FXMenuPane* transformSlanes = new FXMenuPane(laneOperations);
2097
ret->insertMenuPaneChild(transformSlanes);
2098
// Create menu comands for all add special lanes
2099
FXMenuCommand* addSidewalk = GUIDesigns::buildFXMenuCommand(addSpecialLanes, TL("Sidewalk"), pedestrianIcon, &parent, MID_GNE_LANE_ADD_SIDEWALK);
2100
FXMenuCommand* addBikelane = GUIDesigns::buildFXMenuCommand(addSpecialLanes, TL("Bike lane"), bikeIcon, &parent, MID_GNE_LANE_ADD_BIKE);
2101
FXMenuCommand* addBuslane = GUIDesigns::buildFXMenuCommand(addSpecialLanes, TL("Bus lane"), busIcon, &parent, MID_GNE_LANE_ADD_BUS);
2102
// if parent edge is selected, always add greenverge in front
2103
if (getParentEdges().front()->isAttributeCarrierSelected()) {
2104
GUIDesigns::buildFXMenuCommand(addSpecialLanes, TL("Green verge"), greenVergeIcon, &parent, MID_GNE_LANE_ADD_GREENVERGE_FRONT);
2105
} else {
2106
GUIDesigns::buildFXMenuCommand(addSpecialLanes, TL("Green verge (front)"), greenVergeIcon, &parent, MID_GNE_LANE_ADD_GREENVERGE_FRONT);
2107
GUIDesigns::buildFXMenuCommand(addSpecialLanes, TL("Green verge (back)"), greenVergeIcon, &parent, MID_GNE_LANE_ADD_GREENVERGE_BACK);
2108
}
2109
// Create menu comands for all remove special lanes and disable it
2110
FXMenuCommand* removeSidewalk = GUIDesigns::buildFXMenuCommand(removeSpecialLanes, TL("Sidewalk"), pedestrianIcon, &parent, MID_GNE_LANE_REMOVE_SIDEWALK);
2111
removeSidewalk->disable();
2112
FXMenuCommand* removeBikelane = GUIDesigns::buildFXMenuCommand(removeSpecialLanes, TL("Bike lane"), bikeIcon, &parent, MID_GNE_LANE_REMOVE_BIKE);
2113
removeBikelane->disable();
2114
FXMenuCommand* removeBuslane = GUIDesigns::buildFXMenuCommand(removeSpecialLanes, TL("Bus lane"), busIcon, &parent, MID_GNE_LANE_REMOVE_BUS);
2115
removeBuslane->disable();
2116
FXMenuCommand* removeGreenVerge = GUIDesigns::buildFXMenuCommand(removeSpecialLanes, TL("Green verge"), greenVergeIcon, &parent, MID_GNE_LANE_REMOVE_GREENVERGE);
2117
removeGreenVerge->disable();
2118
// Create menu comands for all transform special lanes and disable it
2119
FXMenuCommand* transformLaneToSidewalk = GUIDesigns::buildFXMenuCommand(transformSlanes, TL("Sidewalk"), pedestrianIcon, &parent, MID_GNE_LANE_TRANSFORM_SIDEWALK);
2120
FXMenuCommand* transformLaneToBikelane = GUIDesigns::buildFXMenuCommand(transformSlanes, TL("Bike lane"), bikeIcon, &parent, MID_GNE_LANE_TRANSFORM_BIKE);
2121
FXMenuCommand* transformLaneToBuslane = GUIDesigns::buildFXMenuCommand(transformSlanes, TL("Bus lane"), busIcon, &parent, MID_GNE_LANE_TRANSFORM_BUS);
2122
FXMenuCommand* transformLaneToGreenVerge = GUIDesigns::buildFXMenuCommand(transformSlanes, TL("Green verge"), greenVergeIcon, &parent, MID_GNE_LANE_TRANSFORM_GREENVERGE);
2123
// add menuCascade for lane operations
2124
new FXMenuCascade(laneOperations, TLF("Add restricted %", toString(SUMO_TAG_LANE)).c_str(), nullptr, addSpecialLanes);
2125
FXMenuCascade* cascadeRemoveSpecialLane = new FXMenuCascade(laneOperations, TLF("Remove restricted %", toString(SUMO_TAG_LANE)).c_str(), nullptr, removeSpecialLanes);
2126
new FXMenuCascade(laneOperations, TLF("Transform to restricted %", toString(SUMO_TAG_LANE)).c_str(), nullptr, transformSlanes);
2127
// Enable and disable options depending of current transform of the lane
2128
if (edgeHasSidewalk) {
2129
transformLaneToSidewalk->disable();
2130
addSidewalk->disable();
2131
removeSidewalk->enable();
2132
}
2133
if (edgeHasBikelane) {
2134
transformLaneToBikelane->disable();
2135
addBikelane->disable();
2136
removeBikelane->enable();
2137
}
2138
if (edgeHasBuslane) {
2139
transformLaneToBuslane->disable();
2140
addBuslane->disable();
2141
removeBuslane->enable();
2142
}
2143
if (isRestricted(SVC_IGNORING)) {
2144
transformLaneToGreenVerge->disable();
2145
removeGreenVerge->enable();
2146
}
2147
// Check if cascade menu must be disabled
2148
if (!edgeHasSidewalk && !edgeHasBikelane && !edgeHasBuslane && !isRestricted(SVC_IGNORING)) {
2149
cascadeRemoveSpecialLane->disable();
2150
}
2151
// for whatever reason, sonar complains in the next line that cascadeRemoveSpecialLane may leak, but fox does the cleanup
2152
} // NOSONAR
2153
2154
2155
void
2156
GNELane::buildTemplateOperations(GUISUMOAbstractView& parent, GUIGLObjectPopupMenu* ret) {
2157
// Create basic commands
2158
std::string edgeDescPossibleMulti = toString(SUMO_TAG_EDGE);
2159
const int numSelectedEdges = getParentEdges().front()->isAttributeCarrierSelected() ? myNet->getAttributeCarriers()->getNumberOfSelectedEdges() : 0;
2160
if ((numSelectedEdges > 0) && getParentEdges().front()->isAttributeCarrierSelected() && (numSelectedEdges > 1)) {
2161
edgeDescPossibleMulti = toString(numSelectedEdges) + " " + toString(SUMO_TAG_EDGE) + "s";
2162
}
2163
// create menu pane for edge operations
2164
FXMenuPane* edgeOperations = new FXMenuPane(ret);
2165
ret->insertMenuPaneChild(edgeOperations);
2166
if (numSelectedEdges > 0) {
2167
new FXMenuCascade(ret, TLF("Template operations (% selected)", toString(numSelectedEdges)).c_str(), nullptr, edgeOperations);
2168
} else {
2169
new FXMenuCascade(ret, TL("Template operations"), nullptr, edgeOperations);
2170
}
2171
// create menu commands for all edge operations
2172
GUIDesigns::buildFXMenuCommand(edgeOperations, TL("Use edge as template"), nullptr, &parent, MID_GNE_EDGE_USEASTEMPLATE);
2173
auto applyTemplate = GUIDesigns::buildFXMenuCommand(edgeOperations, TL("Apply template"), nullptr, &parent, MID_GNE_EDGE_APPLYTEMPLATE);
2174
// check if disable apply template
2175
if (myNet->getViewParent()->getInspectorFrame()->getTemplateEditor()->getEdgeTemplate() == nullptr) {
2176
applyTemplate->disable();
2177
}
2178
}
2179
2180
2181
void
2182
GNELane::buildRechableOperations(GUISUMOAbstractView& parent, GUIGLObjectPopupMenu* ret) {
2183
// addreachability menu
2184
FXMenuPane* reachableByClass = new FXMenuPane(ret);
2185
ret->insertMenuPaneChild(reachableByClass);
2186
if (myNet->isNetRecomputed()) {
2187
new FXMenuCascade(ret, TL("Select reachable"), GUIIconSubSys::getIcon(GUIIcon::MODEVEHICLE), reachableByClass);
2188
for (const auto& vClass : SumoVehicleClassStrings.getStrings()) {
2189
GUIDesigns::buildFXMenuCommand(reachableByClass, vClass.c_str(), VClassIcons::getVClassIcon(SumoVehicleClassStrings.get(vClass)), &parent, MID_REACHABILITY);
2190
}
2191
} else {
2192
FXMenuCommand* menuCommand = GUIDesigns::buildFXMenuCommand(ret, TL("Select reachable (compute junctions)"), nullptr, nullptr, 0);
2193
menuCommand->handle(&parent, FXSEL(SEL_COMMAND, FXWindow::ID_DISABLE), nullptr);
2194
}
2195
}
2196
2197
/****************************************************************************/
2198
2199