Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/guisim/GUILane.cpp
193696 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GUILane.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @date Sept 2002
19
///
20
// Representation of a lane in the micro simulation (gui-version)
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <string>
25
#include <utility>
26
#include <utils/foxtools/fxheader.h>
27
#include <utils/geom/GeomHelper.h>
28
#include <utils/geom/Position.h>
29
#include <microsim/logging/FunctionBinding.h>
30
#include <utils/options/OptionsCont.h>
31
#include <utils/common/MsgHandler.h>
32
#include <utils/common/StdDefs.h>
33
#include <utils/geom/GeomHelper.h>
34
#include <utils/gui/div/GLHelper.h>
35
#include <utils/gui/div/GUIParameterTableWindow.h>
36
#include <utils/gui/div/GUIGlobalSelection.h>
37
#include <utils/gui/globjects/GLIncludes.h>
38
#include <utils/gui/globjects/GUIPolygon.h>
39
#include <utils/gui/images/VClassIcons.h>
40
#include <utils/gui/windows/GUISUMOAbstractView.h>
41
#include <utils/gui/windows/GUIAppEnum.h>
42
#include <gui/GUIGlobals.h>
43
#include <microsim/MSGlobals.h>
44
#include <microsim/MSLane.h>
45
#include <microsim/MSLink.h>
46
#include <microsim/MSVehicleControl.h>
47
#include <microsim/MSInsertionControl.h>
48
#include <microsim/MSVehicleTransfer.h>
49
#include <microsim/MSNet.h>
50
#include <microsim/MSEdgeWeightsStorage.h>
51
#include <microsim/MSParkingArea.h>
52
#include <microsim/devices/MSDevice_Routing.h>
53
#include <microsim/traffic_lights/MSRailSignal.h>
54
#include <microsim/traffic_lights/MSDriveWay.h>
55
#include <mesosim/MELoop.h>
56
#include <mesosim/MESegment.h>
57
#include "GUILane.h"
58
#include "GUIEdge.h"
59
#include "GUIVehicle.h"
60
#include "GUINet.h"
61
#include <utils/gui/div/GUIDesigns.h>
62
63
#include <osgview/GUIOSGHeader.h>
64
65
#define RENDERING_BUFFER 10
66
67
//#define GUILane_DEBUG_DRAW_FOE_INTERSECTIONS
68
//#define GUILane_DEBUG_DRAW_CROSSING_OUTLINE
69
70
// ===========================================================================
71
// static member declaration
72
// ===========================================================================
73
const RGBColor GUILane::MESO_USE_LANE_COLOR(0, 0, 0, 0);
74
GUIVisualizationSettings* GUILane::myCachedGUISettings(nullptr);
75
76
77
// ===========================================================================
78
// method definitions
79
// ===========================================================================
80
GUILane::GUILane(const std::string& id, double maxSpeed, double friction, double length,
81
MSEdge* const edge, int numericalID,
82
const PositionVector& shape, double width,
83
SVCPermissions permissions,
84
SVCPermissions changeLeft, SVCPermissions changeRight,
85
int index, bool isRampAccel,
86
const std::string& type,
87
const PositionVector& outlineShape) :
88
MSLane(id, maxSpeed, friction, length, edge, numericalID, shape, width, permissions, changeLeft, changeRight, index, isRampAccel, type, outlineShape),
89
GUIGlObject(GLO_LANE, id, GUIIconSubSys::getIcon(GUIIcon::LANE)),
90
myParkingAreas(nullptr),
91
myTesselation(nullptr),
92
#ifdef HAVE_OSG
93
myGeom(0),
94
#endif
95
myAmClosed(false),
96
myLengthGeometryFactor2(myLengthGeometryFactor),
97
myLock(true) {
98
initRotations(myShape, myShapeRotations, myShapeLengths, myShapeColors);
99
//
100
myHalfLaneWidth = myWidth / 2.;
101
myQuarterLaneWidth = myWidth / 4.;
102
}
103
104
105
GUILane::~GUILane() {
106
// just to quit cleanly on a failure
107
if (myLock.locked()) {
108
myLock.unlock();
109
}
110
delete myParkingAreas;
111
delete myTesselation;
112
}
113
114
115
void
116
GUILane::updateMesoGUISegments() {
117
#ifdef _DEBUG
118
const double origLength = myShape.length();
119
#endif
120
myShape = splitAtSegments(myShape);
121
assert(fabs(myShape.length() - origLength) < POSITION_EPS);
122
assert(myShapeSegments.size() == myShape.size());
123
initRotations(myShape, myShapeRotations, myShapeLengths, myShapeColors);
124
}
125
126
127
void
128
GUILane::initRotations(const PositionVector& shape,
129
std::vector<double>& rotations,
130
std::vector<double>& lengths,
131
std::vector<RGBColor>& colors) {
132
rotations.clear();
133
lengths.clear();
134
colors.clear();
135
rotations.reserve(shape.size() - 1);
136
lengths.reserve(shape.size() - 1);
137
colors.reserve(shape.size() - 1);
138
int e = (int) shape.size() - 1;
139
for (int i = 0; i < e; ++i) {
140
const Position& f = shape[i];
141
const Position& s = shape[i + 1];
142
lengths.push_back(f.distanceTo2D(s));
143
rotations.push_back(RAD2DEG(atan2(s.x() - f.x(), f.y() - s.y())));
144
}
145
}
146
147
148
void
149
GUILane::addSecondaryShape(const PositionVector& shape) {
150
myShape2 = shape;
151
initRotations(myShape2, myShapeRotations2, myShapeLengths2, myShapeColors2);
152
myLengthGeometryFactor2 = MAX2(POSITION_EPS, myShape2.length()) / myLength;
153
}
154
155
156
// ------ Vehicle insertion ------
157
void
158
GUILane::incorporateVehicle(MSVehicle* veh, double pos, double speed, double posLat,
159
const MSLane::VehCont::iterator& at,
160
MSMoveReminder::Notification notification) {
161
FXMutexLock locker(myLock);
162
MSLane::incorporateVehicle(veh, pos, speed, posLat, at, notification);
163
}
164
165
166
// ------ Access to vehicles ------
167
const MSLane::VehCont&
168
GUILane::getVehiclesSecure() const {
169
myLock.lock();
170
return myVehicles;
171
}
172
173
174
void
175
GUILane::releaseVehicles() const {
176
myLock.unlock();
177
}
178
179
180
void
181
GUILane::planMovements(const SUMOTime t) {
182
FXMutexLock locker(myLock);
183
MSLane::planMovements(t);
184
}
185
186
void
187
GUILane::setJunctionApproaches() const {
188
FXMutexLock locker(myLock);
189
MSLane::setJunctionApproaches();
190
}
191
192
193
void
194
GUILane::executeMovements(const SUMOTime t) {
195
FXMutexLock locker(myLock);
196
MSLane::executeMovements(t);
197
}
198
199
200
MSVehicle*
201
GUILane::removeVehicle(MSVehicle* remVehicle, MSMoveReminder::Notification notification, bool notify) {
202
FXMutexLock locker(myLock);
203
return MSLane::removeVehicle(remVehicle, notification, notify);
204
}
205
206
207
void
208
GUILane::removeParking(MSBaseVehicle* remVehicle) {
209
FXMutexLock locker(myLock);
210
return MSLane::removeParking(remVehicle);
211
}
212
213
214
void
215
GUILane::swapAfterLaneChange(SUMOTime t) {
216
FXMutexLock locker(myLock);
217
MSLane::swapAfterLaneChange(t);
218
}
219
220
221
void
222
GUILane::integrateNewVehicles() {
223
FXMutexLock locker(myLock);
224
MSLane::integrateNewVehicles();
225
}
226
227
228
void
229
GUILane::detectCollisions(SUMOTime timestep, const std::string& stage) {
230
FXMutexLock locker(myLock);
231
MSLane::detectCollisions(timestep, stage);
232
}
233
234
235
double
236
GUILane::setPartialOccupation(MSVehicle* v) {
237
FXMutexLock locker(myLock);
238
return MSLane::setPartialOccupation(v);
239
}
240
241
242
void
243
GUILane::resetPartialOccupation(MSVehicle* v) {
244
FXMutexLock locker(myLock);
245
MSLane::resetPartialOccupation(v);
246
}
247
248
249
// ------ Drawing methods ------
250
void
251
GUILane::drawLinkNo(const GUIVisualizationSettings& s) const {
252
int noLinks = (int)myLinks.size();
253
if (noLinks == 0) {
254
return;
255
}
256
// draw all links
257
if (isCrossing()) {
258
// draw indices at the start and end of the crossing
259
const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
260
PositionVector shape = getShape(s.secondaryShape);
261
shape.extrapolate(0.5); // draw on top of the walking area
262
GLHelper::drawTextAtEnd(toString(link->getIndex()), shape, 0, s.drawLinkJunctionIndex, s.scale);
263
GLHelper::drawTextAtEnd(toString(link->getIndex()), shape.reverse(), 0, s.drawLinkJunctionIndex, s.scale);
264
return;
265
}
266
// draw all links
267
double w = myWidth / (double) noLinks;
268
double x1 = myHalfLaneWidth;
269
for (int i = noLinks; --i >= 0;) {
270
double x2 = x1 - (double)(w / 2.);
271
GLHelper::drawTextAtEnd(toString(myLinks[MSGlobals::gLefthand ? noLinks - 1 - i : i]->getIndex()), getShape(s.secondaryShape), x2, s.drawLinkJunctionIndex, s.scale);
272
x1 -= w;
273
}
274
}
275
276
277
void
278
GUILane::drawTLSLinkNo(const GUIVisualizationSettings& s, const GUINet& net) const {
279
int noLinks = (int)myLinks.size();
280
if (noLinks == 0) {
281
return;
282
}
283
if (isCrossing()) {
284
// draw indices at the start and end of the crossing
285
const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
286
int linkNo = net.getLinkTLIndex(link);
287
// maybe the reverse link is controlled separately
288
int linkNo2 = net.getLinkTLIndex(myLinks.front());
289
// otherwise, use the same index as the forward link
290
if (linkNo2 < 0) {
291
linkNo2 = linkNo;
292
}
293
if (linkNo >= 0) {
294
PositionVector shape = getShape(s.secondaryShape);
295
shape.extrapolate(0.5); // draw on top of the walking area
296
GLHelper::drawTextAtEnd(toString(linkNo2), shape, 0, s.drawLinkTLIndex, s.scale);
297
GLHelper::drawTextAtEnd(toString(linkNo), shape.reverse(), 0, s.drawLinkTLIndex, s.scale);
298
}
299
return;
300
}
301
// draw all links
302
double w = myWidth / (double) noLinks;
303
double x1 = myHalfLaneWidth;
304
for (int i = noLinks; --i >= 0;) {
305
double x2 = x1 - (double)(w / 2.);
306
int linkNo = net.getLinkTLIndex(myLinks[MSGlobals::gLefthand ? noLinks - 1 - i : i]);
307
if (linkNo < 0) {
308
continue;
309
}
310
GLHelper::drawTextAtEnd(toString(linkNo), getShape(s.secondaryShape), x2, s.drawLinkTLIndex, s.scale);
311
x1 -= w;
312
}
313
}
314
315
316
void
317
GUILane::drawLinkRules(const GUIVisualizationSettings& s, const GUINet& net) const {
318
int noLinks = (int)myLinks.size();
319
const PositionVector& shape = getShape(s.secondaryShape);
320
if (noLinks == 0) {
321
drawLinkRule(s, net, nullptr, shape, 0, 0);
322
return;
323
}
324
if (isCrossing()) {
325
// draw rules at the start and end of the crossing
326
const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
327
const MSLink* link2 = myLinks.front();
328
if (link2->getTLLogic() == nullptr) {
329
link2 = link;
330
}
331
PositionVector tmp = shape;
332
tmp.extrapolate(0.5); // draw on top of the walking area
333
drawLinkRule(s, net, link2, tmp, 0, myWidth);
334
drawLinkRule(s, net, link, tmp.reverse(), 0, myWidth);
335
return;
336
}
337
// draw all links
338
const double isRailSignal = myEdge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL;
339
double w = myWidth / (double) noLinks;
340
if (isRailSignal && noLinks > 1 && myLinks.back()->isTurnaround() && s.showRails) {
341
w = myWidth / (double)(noLinks - 1);
342
}
343
double x1 = isRailSignal ? -myWidth * 0.5 : 0;
344
for (int i = 0; i < noLinks; ++i) {
345
double x2 = x1 + w;
346
drawLinkRule(s, net, myLinks[MSGlobals::gLefthand ? noLinks - 1 - i : i], shape, x1, x2);
347
x1 = x2;
348
}
349
// draw stopOffset for passenger cars
350
if (myLaneStopOffset.isDefined() && (myLaneStopOffset.getPermissions() & SVC_PASSENGER) != 0) {
351
const double stopOffsetPassenger = myLaneStopOffset.getOffset();
352
const Position& end = shape.back();
353
const Position& f = shape[-2];
354
const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
355
GLHelper::setColor(s.getLinkColor(LINKSTATE_MAJOR));
356
GLHelper::pushMatrix();
357
glTranslated(end.x(), end.y(), 0);
358
glRotated(rot, 0, 0, 1);
359
glTranslated(0, stopOffsetPassenger, 0);
360
glBegin(GL_QUADS);
361
glVertex2d(-myHalfLaneWidth, 0.0);
362
glVertex2d(-myHalfLaneWidth, 0.2);
363
glVertex2d(myHalfLaneWidth, 0.2);
364
glVertex2d(myHalfLaneWidth, 0.0);
365
glEnd();
366
GLHelper::popMatrix();
367
}
368
}
369
370
371
void
372
GUILane::drawLinkRule(const GUIVisualizationSettings& s, const GUINet& net, const MSLink* link, const PositionVector& shape, double x1, double x2) const {
373
const Position& end = shape.back();
374
const Position& f = shape[-2];
375
const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
376
if (link == nullptr) {
377
if (static_cast<GUIEdge*>(myEdge)->showDeadEnd()) {
378
GLHelper::setColor(GUIVisualizationColorSettings::SUMO_color_DEADEND_SHOW);
379
} else {
380
GLHelper::setColor(GUIVisualizationSettings::getLinkColor(LINKSTATE_DEADEND));
381
}
382
GLHelper::pushMatrix();
383
glTranslated(end.x(), end.y(), 0);
384
glRotated(rot, 0, 0, 1);
385
glBegin(GL_QUADS);
386
glVertex2d(-myHalfLaneWidth, 0.0);
387
glVertex2d(-myHalfLaneWidth, 0.5);
388
glVertex2d(myHalfLaneWidth, 0.5);
389
glVertex2d(myHalfLaneWidth, 0.0);
390
glEnd();
391
GLHelper::popMatrix();
392
} else {
393
GLHelper::pushMatrix();
394
glTranslated(end.x(), end.y(), 0);
395
glRotated(rot, 0, 0, 1);
396
// select glID
397
398
switch (link->getState()) {
399
case LINKSTATE_ALLWAY_STOP:
400
case LINKSTATE_STOP: {
401
// might be a traffic light link
402
int tlID = net.getLinkTLID(link);
403
GLHelper::pushName(tlID != 0 ? tlID : getGlID());
404
break;
405
}
406
case LINKSTATE_TL_GREEN_MAJOR:
407
case LINKSTATE_TL_GREEN_MINOR:
408
case LINKSTATE_TL_RED:
409
case LINKSTATE_TL_REDYELLOW:
410
case LINKSTATE_TL_YELLOW_MAJOR:
411
case LINKSTATE_TL_YELLOW_MINOR:
412
case LINKSTATE_TL_OFF_BLINKING:
413
case LINKSTATE_TL_OFF_NOSIGNAL:
414
GLHelper::pushName(net.getLinkTLID(link));
415
break;
416
case LINKSTATE_MAJOR:
417
case LINKSTATE_MINOR:
418
case LINKSTATE_EQUAL:
419
default:
420
GLHelper::pushName(getGlID());
421
break;
422
}
423
GLHelper::setColor(GUIVisualizationSettings::getLinkColor(link->getState(), s.realisticLinkRules));
424
if (!(drawAsRailway(s) || drawAsWaterway(s)) || link->getState() != LINKSTATE_MAJOR) {
425
// the white bar should be the default for most railway
426
// links and looks ugly so we do not draw it
427
double scale = isInternal() ? 0.5 : 1;
428
if (myEdge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
429
scale *= MAX2(s.laneWidthExaggeration, s.junctionSize.getExaggeration(s, this, 10));
430
}
431
glScaled(scale, scale, 1);
432
glBegin(GL_QUADS);
433
glVertex2d(x1 - myHalfLaneWidth, 0.0);
434
glVertex2d(x1 - myHalfLaneWidth, 0.5);
435
glVertex2d(x2 - myHalfLaneWidth, 0.5);
436
glVertex2d(x2 - myHalfLaneWidth, 0.0);
437
glEnd();
438
if (s.gaming && link->haveGreen()) {
439
const MSLane* lane = link->getLane();
440
// exaggerate green signals for railway game
441
if (isRailway(lane->getPermissions())) {
442
GLHelper::drawFilledCircle(lane->getWidth() / 2., 8, 90, 270);
443
}
444
}
445
}
446
GLHelper::popName();
447
GLHelper::popMatrix();
448
}
449
}
450
451
void
452
GUILane::drawArrows(bool secondaryShape) const {
453
if (myLinks.size() == 0) {
454
return;
455
}
456
// draw all links
457
const Position& end = getShape(secondaryShape).back();
458
const Position& f = getShape(secondaryShape)[-2];
459
const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
460
GLHelper::pushMatrix();
461
glColor3d(1, 1, 1);
462
glTranslated(end.x(), end.y(), 0);
463
glRotated(rot, 0, 0, 1);
464
if (myWidth < SUMO_const_laneWidth) {
465
glScaled(myWidth / SUMO_const_laneWidth, 1, 1);
466
}
467
for (const MSLink* const link : myLinks) {
468
LinkDirection dir = link->getDirection();
469
LinkState state = link->getState();
470
if (state == LINKSTATE_DEADEND || dir == LinkDirection::NODIR) {
471
continue;
472
}
473
switch (dir) {
474
case LinkDirection::STRAIGHT:
475
GLHelper::drawBoxLine(Position(0, 4), 0, 2, .05);
476
GLHelper::drawTriangleAtEnd(Position(0, 4), Position(0, 1), (double) 1, (double) .25);
477
break;
478
case LinkDirection::TURN:
479
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
480
GLHelper::drawBoxLine(Position(0, 2.5), 90, .5, .05);
481
GLHelper::drawBoxLine(Position(0.5, 2.5), 180, 1, .05);
482
GLHelper::drawTriangleAtEnd(Position(0.5, 2.5), Position(0.5, 4), (double) 1, (double) .25);
483
break;
484
case LinkDirection::TURN_LEFTHAND:
485
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
486
GLHelper::drawBoxLine(Position(0, 2.5), -90, .5, .05);
487
GLHelper::drawBoxLine(Position(-0.5, 2.5), -180, 1, .05);
488
GLHelper::drawTriangleAtEnd(Position(-0.5, 2.5), Position(-0.5, 4), (double) 1, (double) .25);
489
break;
490
case LinkDirection::LEFT:
491
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
492
GLHelper::drawBoxLine(Position(0, 2.5), 90, 1, .05);
493
GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(1.5, 2.5), (double) 1, (double) .25);
494
break;
495
case LinkDirection::RIGHT:
496
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
497
GLHelper::drawBoxLine(Position(0, 2.5), -90, 1, .05);
498
GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(-1.5, 2.5), (double) 1, (double) .25);
499
break;
500
case LinkDirection::PARTLEFT:
501
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
502
GLHelper::drawBoxLine(Position(0, 2.5), 45, .7, .05);
503
GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(1.2, 1.3), (double) 1, (double) .25);
504
break;
505
case LinkDirection::PARTRIGHT:
506
GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
507
GLHelper::drawBoxLine(Position(0, 2.5), -45, .7, .05);
508
GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(-1.2, 1.3), (double) 1, (double) .25);
509
break;
510
default:
511
break;
512
}
513
}
514
GLHelper::popMatrix();
515
}
516
517
518
void
519
GUILane::drawLane2LaneConnections(double exaggeration, bool s2) const {
520
Position centroid;
521
if (exaggeration > 1) {
522
centroid = myEdge->getToJunction()->getShape().getCentroid();
523
}
524
for (const MSLink* const link : myLinks) {
525
const GUILane* connected = dynamic_cast<GUILane*>(link->getLane());
526
if (connected == nullptr) {
527
continue;
528
}
529
GLHelper::setColor(GUIVisualizationSettings::getLinkColor(link->getState()));
530
glBegin(GL_LINES);
531
Position p1 = myEdge->isWalkingArea() ? getShape(s2).getCentroid() : getShape(s2)[-1];
532
Position p2 = connected->isWalkingArea() ? connected->getShape(s2).getCentroid() : connected->getShape(s2)[0];
533
if (exaggeration > 1) {
534
p1 = centroid + ((p1 - centroid) * exaggeration);
535
p2 = centroid + ((p2 - centroid) * exaggeration);
536
}
537
glVertex2d(p1.x(), p1.y());
538
glVertex2d(p2.x(), p2.y());
539
glEnd();
540
GLHelper::drawTriangleAtEnd(p1, p2, (double) .4, (double) .2);
541
}
542
}
543
544
545
void
546
GUILane::drawGL(const GUIVisualizationSettings& s) const {
547
GLHelper::pushMatrix();
548
GLHelper::pushName(getGlID());
549
const bool s2 = s.secondaryShape;
550
double exaggeration = s.laneWidthExaggeration;
551
if (MSGlobals::gUseMesoSim) {
552
GUIEdge* myGUIEdge = dynamic_cast<GUIEdge*>(myEdge);
553
exaggeration *= s.edgeScaler.getScheme().getColor(myGUIEdge->getScaleValue(s, s.edgeScaler.getActive()));
554
} else {
555
exaggeration *= s.laneScaler.getScheme().getColor(getScaleValue(s, s.laneScaler.getActive(), s2));
556
}
557
// set lane color
558
const RGBColor color = setColor(s);
559
// recognize full transparency and simply don't draw
560
if (color.alpha() != 0 && s.scale * exaggeration > s.laneMinSize) {
561
562
const bool isCrossing = myEdge->isCrossing();
563
const bool isWalkingArea = myEdge->isWalkingArea();
564
const bool isInternal = isCrossing || isWalkingArea || myEdge->isInternal();
565
const PositionVector& baseShape = getShape(s2);
566
const bool hasRailSignal = myEdge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL;
567
if (s.trueZ) {
568
glTranslated(0, 0, baseShape.getMinZ());
569
} else {
570
if (isCrossing) {
571
// draw internal lanes on top of junctions
572
glTranslated(0, 0, GLO_JUNCTION + 0.1);
573
} else if (isWalkingArea) {
574
// draw internal lanes on top of junctions
575
glTranslated(0, 0, GLO_JUNCTION + 0.3);
576
} else if (isWaterway(myPermissions)) {
577
// draw waterways below normal roads
578
glTranslated(0, 0, getType() - 0.2);
579
} else if (myPermissions == SVC_SUBWAY) {
580
// draw subways further below
581
glTranslated(0, 0, getType() - 0.4);
582
} else {
583
glTranslated(0, 0, getType());
584
}
585
}
586
auto& shapeColors = getShapeColors(s2);
587
if (MSGlobals::gUseMesoSim) {
588
shapeColors.clear();
589
const std::vector<RGBColor>& segmentColors = static_cast<const GUIEdge*>(myEdge)->getSegmentColors();
590
if (segmentColors.size() > 0) {
591
// apply segment specific shape colors
592
//std::cout << getID() << " shape=" << myShape << " shapeSegs=" << toString(myShapeSegments) << "\n";
593
for (int ii = 0; ii < (int)baseShape.size() - 1; ++ii) {
594
shapeColors.push_back(segmentColors[myShapeSegments[ii]]);
595
}
596
}
597
}
598
599
// scale tls-controlled lane2lane-arrows along with their junction shapes
600
double junctionExaggeration = 1;
601
if (!isInternal
602
&& myEdge->getToJunction()->getType() <= SumoXMLNodeType::RAIL_CROSSING
603
&& (s.junctionSize.constantSize || s.junctionSize.exaggeration > 1)) {
604
junctionExaggeration = MAX2(1.001, s.junctionSize.getExaggeration(s, this, 4));
605
}
606
// draw lane
607
// check whether it is not too small
608
if (s.scale * exaggeration < 1. && junctionExaggeration == 1 && s.junctionSize.minSize != 0) {
609
if (!isInternal || hasRailSignal) {
610
if (shapeColors.size() > 0) {
611
GLHelper::drawLine(baseShape, shapeColors);
612
} else {
613
GLHelper::drawLine(baseShape);
614
}
615
}
616
GLHelper::popMatrix();
617
618
} else {
619
620
GUINet* net = (GUINet*) MSNet::getInstance();
621
bool mustDrawMarkings = false;
622
bool hiddenBidi = getBidiLane() != nullptr && myEdge->getNumericalID() > myEdge->getBidiEdge()->getNumericalID();
623
const bool detailZoom = s.scale * exaggeration > 5;
624
const bool drawDetails = (detailZoom || s.junctionSize.minSize == 0 || hasRailSignal);
625
const bool drawRails = drawAsRailway(s);
626
const bool spreadSuperposed = s.spreadSuperposed && myBidiLane != nullptr;
627
if (hiddenBidi && !spreadSuperposed) {
628
// do not draw shape
629
mustDrawMarkings = !isInternal && myPermissions != 0 && myPermissions != SVC_PEDESTRIAN && exaggeration == 1.0 && !isWaterway(myPermissions) && neighLaneNotBidi();
630
} else if (drawRails) {
631
// draw as railway: assume standard gauge of 1435mm when lane width is not set
632
// draw foot width 150mm, assume that distance between rail feet inner sides is reduced on both sides by 39mm with regard to the gauge
633
// assume crosstie length of 181% gauge (2600mm for standard gauge)
634
PositionVector shape = baseShape;
635
const double width = myWidth;
636
double halfGauge = 0.5 * (width == SUMO_const_laneWidth ? 1.4350 : width) * exaggeration;
637
if (spreadSuperposed) {
638
try {
639
shape.move2side(halfGauge * 0.8);
640
} catch (InvalidArgument&) {}
641
halfGauge *= 0.4;
642
}
643
const double halfInnerFeetWidth = halfGauge - 0.039 * exaggeration;
644
const double halfRailWidth = detailZoom ? (halfInnerFeetWidth + 0.15 * exaggeration) : SUMO_const_halfLaneWidth * exaggeration;
645
const double halfCrossTieWidth = halfGauge * 1.81;
646
if (shapeColors.size() > 0) {
647
GLHelper::drawBoxLines(shape, getShapeRotations(s2), getShapeLengths(s2), getShapeColors(s2), halfRailWidth);
648
} else {
649
GLHelper::drawBoxLines(shape, getShapeRotations(s2), getShapeLengths(s2), halfRailWidth);
650
}
651
// Draw white on top with reduced width (the area between the two tracks)
652
if (detailZoom) {
653
glColor3d(1, 1, 1);
654
glTranslated(0, 0, .1);
655
GLHelper::drawBoxLines(shape, getShapeRotations(s2), getShapeLengths(s2), halfInnerFeetWidth);
656
setColor(s);
657
GLHelper::drawCrossTies(shape, getShapeRotations(s2), getShapeLengths(s2), 0.26 * exaggeration, 0.6 * exaggeration,
658
halfCrossTieWidth, 0, s.forceDrawForRectangleSelection);
659
}
660
} else if (isCrossing) {
661
if (s.drawCrossingsAndWalkingareas && (s.scale > 3.0 || s.junctionSize.minSize == 0)) {
662
glTranslated(0, 0, .2);
663
GLHelper::drawCrossTies(baseShape, getShapeRotations(s2), getShapeLengths(s2), 0.5, 1.0, getWidth() * 0.5,
664
0, s.drawForRectangleSelection);
665
#ifdef GUILane_DEBUG_DRAW_CROSSING_OUTLINE
666
if (myOutlineShape != nullptr) {
667
GLHelper::setColor(RGBColor::BLUE);
668
glTranslated(0, 0, 0.4);
669
GLHelper::drawBoxLines(*myOutlineShape, 0.1);
670
glTranslated(0, 0, -0.4);
671
if (s.geometryIndices.show(this)) {
672
GLHelper::debugVertices(*myOutlineShape, s.geometryIndices, s.scale);
673
}
674
}
675
#endif
676
glTranslated(0, 0, -.2);
677
}
678
} else if (isWalkingArea) {
679
if (s.drawCrossingsAndWalkingareas && (s.scale > 3.0 || s.junctionSize.minSize == 0)) {
680
glTranslated(0, 0, .2);
681
if (myTesselation == nullptr) {
682
myTesselation = new TesselatedPolygon(getID(), "", RGBColor::MAGENTA, PositionVector(), false, true, 0);
683
}
684
myTesselation->drawTesselation(baseShape);
685
glTranslated(0, 0, -.2);
686
if (s.geometryIndices.show(this)) {
687
GLHelper::debugVertices(baseShape, s.geometryIndices, s.scale);
688
}
689
}
690
} else {
691
// we draw the lanes with reduced width so that the lane markings below are visible
692
// (this avoids artifacts at geometry corners without having to
693
// compute lane-marking intersection points)
694
double halfWidth = isInternal ? myQuarterLaneWidth : (myHalfLaneWidth - SUMO_const_laneMarkWidth / 2);
695
mustDrawMarkings = !isInternal && myPermissions != 0 && myPermissions != SVC_PEDESTRIAN && exaggeration == 1.0 && !isWaterway(myPermissions) && !isAirway(myPermissions);
696
const int cornerDetail = drawDetails && !isInternal ? (s.drawForRectangleSelection ? 4 : MIN2(32, (int)(s.scale * exaggeration))) : 0;
697
double offset = halfWidth * MAX2(0., (exaggeration - 1)) * (MSGlobals::gLefthand ? -1 : 1);
698
if (spreadSuperposed) {
699
offset += halfWidth * 0.5 * (MSGlobals::gLefthand ? -1 : 1);
700
halfWidth *= 0.4; // create visible gap
701
}
702
if (shapeColors.size() > 0) {
703
GLHelper::drawBoxLines(baseShape, getShapeRotations(s2), getShapeLengths(s2), shapeColors, halfWidth * exaggeration, cornerDetail, offset);
704
} else {
705
GLHelper::drawBoxLines(baseShape, getShapeRotations(s2), getShapeLengths(s2), halfWidth * exaggeration, cornerDetail, offset);
706
}
707
}
708
GLHelper::popMatrix();
709
#ifdef GUILane_DEBUG_DRAW_FOE_INTERSECTIONS
710
if (myEdge->isInternal() && gSelected.isSelected(getType(), getGlID())) {
711
debugDrawFoeIntersections();
712
}
713
#endif
714
if (s.geometryIndices.show(this)) {
715
GLHelper::debugVertices(baseShape, s.geometryIndices, s.scale);
716
}
717
// draw details
718
if ((!isInternal || isCrossing || !s.drawJunctionShape) && (drawDetails || junctionExaggeration > 1)) {
719
GLHelper::pushMatrix();
720
glTranslated(0, 0, GLO_JUNCTION); // must draw on top of junction shape
721
glTranslated(0, 0, .5);
722
if (drawDetails) {
723
if (s.showLaneDirection) {
724
if (drawRails) {
725
// improve visibility of superposed rail edges
726
GLHelper::setColor(setColor(s).changedBrightness(100));
727
} else {
728
glColor3d(0.3, 0.3, 0.3);
729
}
730
if (!isCrossing || s.drawCrossingsAndWalkingareas) {
731
drawDirectionIndicators(exaggeration, spreadSuperposed, s.secondaryShape);
732
}
733
}
734
if (!isInternal || isCrossing
735
// controlled internal junction
736
|| (getLinkCont().size() != 0 && getLinkCont()[0]->isInternalJunctionLink() && getLinkCont()[0]->getTLLogic() != nullptr)) {
737
if (MSGlobals::gLateralResolution > 0 && s.showSublanes && !hiddenBidi && (myPermissions & ~(SVC_PEDESTRIAN | SVC_RAIL_CLASSES)) != 0) {
738
// draw sublane-borders
739
const double offsetSign = MSGlobals::gLefthand ? -1 : 1;
740
GLHelper::setColor(color.changedBrightness(51));
741
for (double offset = -myHalfLaneWidth; offset < myHalfLaneWidth; offset += MSGlobals::gLateralResolution) {
742
GLHelper::drawBoxLines(baseShape, getShapeRotations(s2), getShapeLengths(s2), 0.01, 0, -offset * offsetSign);
743
}
744
}
745
if (MSGlobals::gUseMesoSim && mySegmentStartIndex.size() > 0 && (myPermissions & ~SVC_PEDESTRIAN) != 0) {
746
// draw segment borders
747
GLHelper::setColor(color.changedBrightness(51));
748
for (int i : mySegmentStartIndex) {
749
if (shapeColors.size() > 0) {
750
GLHelper::setColor(shapeColors[i].changedBrightness(51));
751
}
752
GLHelper::drawBoxLine(baseShape[i], getShapeRotations(s2)[i] + 90, myWidth / 3, 0.2, 0);
753
GLHelper::drawBoxLine(baseShape[i], getShapeRotations(s2)[i] - 90, myWidth / 3, 0.2, 0);
754
}
755
}
756
if (s.showLinkDecals && !drawRails && !drawAsWaterway(s) && myPermissions != SVC_PEDESTRIAN) {
757
drawArrows(s.secondaryShape);
758
}
759
glTranslated(0, 0, 1000);
760
if (s.drawLinkJunctionIndex.show(nullptr)) {
761
drawLinkNo(s);
762
}
763
if (s.drawLinkTLIndex.show(nullptr)) {
764
drawTLSLinkNo(s, *net);
765
}
766
glTranslated(0, 0, -1000);
767
}
768
glTranslated(0, 0, .1);
769
}
770
if ((drawDetails || junctionExaggeration > 1) && s.showLane2Lane) {
771
// draw from end of first to the begin of second but respect junction scaling
772
drawLane2LaneConnections(junctionExaggeration, s.secondaryShape);
773
}
774
GLHelper::popMatrix();
775
// make sure link rules are drawn so tls can be selected via right-click
776
if (s.showLinkRules && drawDetails && !isWalkingArea &&
777
(!myEdge->isInternal() || (getLinkCont().size() > 0 && getLinkCont()[0]->isInternalJunctionLink()))) {
778
GLHelper::pushMatrix();
779
glTranslated(0, 0, GLO_SHAPE); // must draw on top of junction shape and additionals
780
drawLinkRules(s, *net);
781
GLHelper::popMatrix();
782
}
783
}
784
if (mustDrawMarkings && drawDetails && s.laneShowBorders) { // needs matrix reset
785
drawMarkings(s, exaggeration);
786
}
787
if (drawDetails && isInternal && s.showBikeMarkings && myPermissions == SVC_BICYCLE && exaggeration == 1.0 && s.showLinkDecals && s.laneShowBorders && !hiddenBidi
788
&& MSGlobals::gUsingInternalLanes
789
&& getNormalSuccessorLane()->getPermissions() == SVC_BICYCLE && getNormalPredecessorLane()->getPermissions() == SVC_BICYCLE) {
790
drawBikeMarkings();
791
}
792
if (drawDetails && isInternal && exaggeration == 1.0 && s.showLinkDecals && s.laneShowBorders && !hiddenBidi && myIndex > 0
793
&& !(myEdge->getLanes()[myIndex - 1]->allowsChangingLeft(SVC_PASSENGER) && allowsChangingRight(SVC_PASSENGER))) {
794
// draw lane changing prohibitions on junction
795
drawJunctionChangeProhibitions();
796
}
797
}
798
} else {
799
GLHelper::popMatrix();
800
}
801
// draw vehicles
802
if (s.scale * s.vehicleSize.getExaggeration(s, nullptr) > s.vehicleSize.minSize) {
803
// retrieve vehicles from lane; disallow simulation
804
const MSLane::VehCont& vehicles = getVehiclesSecure();
805
for (MSLane::VehCont::const_iterator v = vehicles.begin(); v != vehicles.end(); ++v) {
806
if ((*v)->getLane() == this) {
807
static_cast<const GUIVehicle*>(*v)->drawGL(s);
808
} // else: this is the shadow during a continuous lane change
809
}
810
// draw long partial vehicles (#14342)
811
for (const MSVehicle* veh : myPartialVehicles) {
812
if (veh->getLength() > RENDERING_BUFFER) {
813
// potential double rendering taken into account
814
static_cast<const GUIVehicle*>(veh)->drawGL(s);
815
}
816
}
817
// draw parking vehicles
818
for (const MSBaseVehicle* const v : myParkingVehicles) {
819
dynamic_cast<const GUIBaseVehicle*>(v)->drawGL(s);
820
}
821
// allow lane simulation
822
releaseVehicles();
823
}
824
GLHelper::popName();
825
}
826
827
bool
828
GUILane::neighLaneNotBidi() const {
829
const MSLane* right = getParallelLane(-1, false);
830
if (right && right->getBidiLane() == nullptr) {
831
return true;
832
}
833
const MSLane* left = getParallelLane(1, false);
834
if (left && left->getBidiLane() == nullptr) {
835
return true;
836
}
837
return false;
838
}
839
840
void
841
GUILane::drawMarkings(const GUIVisualizationSettings& s, double scale) const {
842
GLHelper::pushMatrix();
843
glTranslated(0, 0, GLO_EDGE);
844
setColor(s);
845
// optionally draw inverse markings
846
const bool s2 = s.secondaryShape;
847
if (myIndex > 0 && (myEdge->getLanes()[myIndex - 1]->getPermissions() & myPermissions) != 0) {
848
const bool cl = myEdge->getLanes()[myIndex - 1]->allowsChangingLeft(SVC_PASSENGER);
849
const bool cr = allowsChangingRight(SVC_PASSENGER);
850
GLHelper::drawInverseMarkings(getShape(s2), getShapeRotations(s2), getShapeLengths(s2), 3, 6, myHalfLaneWidth, cl, cr, MSGlobals::gLefthand, scale);
851
}
852
// draw white boundings and white markings
853
glColor3d(1, 1, 1);
854
GLHelper::drawBoxLines(
855
getShape(s2),
856
getShapeRotations(s2),
857
getShapeLengths(s2),
858
(myHalfLaneWidth + SUMO_const_laneMarkWidth) * scale);
859
GLHelper::popMatrix();
860
}
861
862
863
void
864
GUILane::drawBikeMarkings() const {
865
// draw bike lane markings onto the intersection
866
glColor3d(1, 1, 1);
867
/// fixme
868
const bool s2 = false;
869
const int e = (int) getShape(s2).size() - 1;
870
const double markWidth = 0.1;
871
const double mw = myHalfLaneWidth;
872
for (int i = 0; i < e; ++i) {
873
GLHelper::pushMatrix();
874
glTranslated(getShape(s2)[i].x(), getShape(s2)[i].y(), GLO_JUNCTION + 0.4);
875
glRotated(getShapeRotations(s2)[i], 0, 0, 1);
876
for (double t = 0; t < getShapeLengths(s2)[i]; t += 0.5) {
877
// left and right marking
878
for (int side = -1; side <= 1; side += 2) {
879
glBegin(GL_QUADS);
880
glVertex2d(side * mw, -t);
881
glVertex2d(side * mw, -t - 0.35);
882
glVertex2d(side * (mw + markWidth), -t - 0.35);
883
glVertex2d(side * (mw + markWidth), -t);
884
glEnd();
885
}
886
}
887
GLHelper::popMatrix();
888
}
889
}
890
891
892
void
893
GUILane::drawJunctionChangeProhibitions() const {
894
// fixme
895
const bool s2 = false;
896
// draw white markings
897
if (myIndex > 0 && (myEdge->getLanes()[myIndex - 1]->getPermissions() & myPermissions) != 0) {
898
glColor3d(1, 1, 1);
899
const bool cl = myEdge->getLanes()[myIndex - 1]->allowsChangingLeft(SVC_PASSENGER);
900
const bool cr = allowsChangingRight(SVC_PASSENGER);
901
// solid line marking
902
double mw, mw2;
903
// optional broken line marking
904
double mw3, mw4;
905
if (!cl && !cr) {
906
// draw a single solid line
907
mw = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.4;
908
mw2 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.4;
909
mw3 = myHalfLaneWidth;
910
mw4 = myHalfLaneWidth;
911
} else {
912
// draw one solid and one broken line
913
if (cl) {
914
mw = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.2;
915
mw2 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.6;
916
mw3 = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.2;
917
mw4 = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.6;
918
} else {
919
mw = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.2;
920
mw2 = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.6;
921
mw3 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.2;
922
mw4 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.6;
923
}
924
}
925
if (MSGlobals::gLefthand) {
926
mw *= -1;
927
mw2 *= -1;
928
}
929
int e = (int) getShape(s2).size() - 1;
930
for (int i = 0; i < e; ++i) {
931
GLHelper::pushMatrix();
932
glTranslated(getShape(s2)[i].x(), getShape(s2)[i].y(), GLO_JUNCTION + 0.4);
933
glRotated(getShapeRotations(s2)[i], 0, 0, 1);
934
for (double t = 0; t < getShapeLengths(s2)[i]; t += 6) {
935
const double lengthSolid = MIN2(6.0, getShapeLengths(s2)[i] - t);
936
glBegin(GL_QUADS);
937
glVertex2d(-mw, -t);
938
glVertex2d(-mw, -t - lengthSolid);
939
glVertex2d(-mw2, -t - lengthSolid);
940
glVertex2d(-mw2, -t);
941
glEnd();
942
if (cl || cr) {
943
const double lengthBroken = MIN2(3.0, getShapeLengths(s2)[i] - t);
944
glBegin(GL_QUADS);
945
glVertex2d(-mw3, -t);
946
glVertex2d(-mw3, -t - lengthBroken);
947
glVertex2d(-mw4, -t - lengthBroken);
948
glVertex2d(-mw4, -t);
949
glEnd();
950
}
951
}
952
GLHelper::popMatrix();
953
}
954
}
955
}
956
957
void
958
GUILane::drawDirectionIndicators(double exaggeration, bool spreadSuperposed, bool s2) const {
959
GLHelper::pushMatrix();
960
glTranslated(0, 0, GLO_EDGE);
961
int e = (int) getShape(s2).size() - 1;
962
const double widthFactor = spreadSuperposed ? 0.4 : 1;
963
const double w = MAX2(POSITION_EPS, myWidth * widthFactor);
964
const double w2 = MAX2(POSITION_EPS, myHalfLaneWidth * widthFactor);
965
const double w4 = MAX2(POSITION_EPS, myQuarterLaneWidth * widthFactor);
966
const double sideOffset = spreadSuperposed ? w * -0.5 : 0;
967
for (int i = 0; i < e; ++i) {
968
GLHelper::pushMatrix();
969
glTranslated(getShape(s2)[i].x(), getShape(s2)[i].y(), 0.1);
970
glRotated(getShapeRotations(s2)[i], 0, 0, 1);
971
for (double t = 0; t < getShapeLengths(s2)[i]; t += w) {
972
const double length = MIN2(w2, getShapeLengths(s2)[i] - t) * exaggeration;
973
glBegin(GL_TRIANGLES);
974
glVertex2d(sideOffset, -t - length);
975
glVertex2d(sideOffset - w4 * exaggeration, -t);
976
glVertex2d(sideOffset + w4 * exaggeration, -t);
977
glEnd();
978
}
979
GLHelper::popMatrix();
980
}
981
GLHelper::popMatrix();
982
}
983
984
985
void
986
GUILane::debugDrawFoeIntersections() const {
987
GLHelper::pushMatrix();
988
glTranslated(0, 0, 5);
989
glColor3d(1.0, 0.3, 0.3);
990
const double orthoLength = 0.5;
991
const MSLink* link = getLinkCont().front();
992
const std::vector<const MSLane*>& foeLanes = link->getFoeLanes();
993
const auto& conflicts = link->getConflicts();
994
if (foeLanes.size() == conflicts.size()) {
995
for (int i = 0; i < (int)foeLanes.size(); ++i) {
996
const MSLane* l = foeLanes[i];
997
Position pos = l->geometryPositionAtOffset(l->getLength() - conflicts[i].lengthBehindCrossing);
998
PositionVector ortho = l->getShape().getOrthogonal(pos, 10, true, orthoLength);
999
if (ortho.length() < orthoLength) {
1000
ortho.extrapolate(orthoLength - ortho.length(), false, true);
1001
}
1002
GLHelper::drawLine(ortho);
1003
//std::cout << "foe=" << l->getID() << " lanePos=" << l->getLength() - conflicts[i].lengthBehindCrossing << " pos=" << pos << "\n";
1004
}
1005
}
1006
GLHelper::popMatrix();
1007
}
1008
1009
1010
// ------ inherited from GUIGlObject
1011
GUIGLObjectPopupMenu*
1012
GUILane::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
1013
GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
1014
buildPopupHeader(ret, app);
1015
buildCenterPopupEntry(ret);
1016
//
1017
GUIDesigns::buildFXMenuCommand(ret, TL("Copy edge name to clipboard"), nullptr, ret, MID_COPY_EDGE_NAME);
1018
buildNameCopyPopupEntry(ret);
1019
buildSelectionPopupEntry(ret);
1020
//
1021
buildShowParamsPopupEntry(ret, false);
1022
const PositionVector& baseShape = getShape(parent.getVisualisationSettings().secondaryShape);
1023
const double pos = interpolateGeometryPosToLanePos(baseShape.nearest_offset_to_point25D(parent.getPositionInformation()));
1024
const double height = baseShape.positionAtOffset(pos).z();
1025
GUIDesigns::buildFXMenuCommand(ret, (TL("pos: ") + toString(pos) + " " + TL("height: ") + toString(height)).c_str(), nullptr, nullptr, 0);
1026
if (getEdge().hasDistance()) {
1027
GUIDesigns::buildFXMenuCommand(ret, ("distance: " + toString(getEdge().getDistanceAt(pos))).c_str(), nullptr, nullptr, 0);
1028
}
1029
new FXMenuSeparator(ret);
1030
buildPositionCopyEntry(ret, app);
1031
new FXMenuSeparator(ret);
1032
if (myAmClosed) {
1033
if (myPermissionChanges.empty()) {
1034
GUIDesigns::buildFXMenuCommand(ret, TL("Reopen lane"), nullptr, &parent, MID_CLOSE_LANE);
1035
GUIDesigns::buildFXMenuCommand(ret, TL("Reopen edge"), nullptr, &parent, MID_CLOSE_EDGE);
1036
} else {
1037
GUIDesigns::buildFXMenuCommand(ret, TL("Reopen lane (override rerouter)"), nullptr, &parent, MID_CLOSE_LANE);
1038
GUIDesigns::buildFXMenuCommand(ret, TL("Reopen edge (override rerouter)"), nullptr, &parent, MID_CLOSE_EDGE);
1039
}
1040
} else {
1041
GUIDesigns::buildFXMenuCommand(ret, TL("Close lane"), nullptr, &parent, MID_CLOSE_LANE);
1042
GUIDesigns::buildFXMenuCommand(ret, TL("Close edge"), nullptr, &parent, MID_CLOSE_EDGE);
1043
}
1044
GUIDesigns::buildFXMenuCommand(ret, TL("Add rerouter"), nullptr, &parent, MID_ADD_REROUTER);
1045
new FXMenuSeparator(ret);
1046
// reachability menu
1047
FXMenuPane* reachableByClass = new FXMenuPane(ret);
1048
ret->insertMenuPaneChild(reachableByClass);
1049
new FXMenuCascade(ret, TL("Select reachable"), GUIIconSubSys::getIcon(GUIIcon::FLAG), reachableByClass);
1050
for (auto i : SumoVehicleClassStrings.getStrings()) {
1051
GUIDesigns::buildFXMenuCommand(reachableByClass, i.c_str(), VClassIcons::getVClassIcon(SumoVehicleClassStrings.get(i)), &parent, MID_REACHABILITY);
1052
}
1053
return ret;
1054
}
1055
1056
1057
GUIParameterTableWindow*
1058
GUILane::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView& view) {
1059
myCachedGUISettings = view.editVisualisationSettings();
1060
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
1061
// add items
1062
ret->mkItem(TL("allowed speed [m/s]"), false, getSpeedLimit());
1063
const std::map<SUMOVehicleClass, double>* restrictions = MSNet::getInstance()->getRestrictions(myEdge->getEdgeType());
1064
if (restrictions != nullptr) {
1065
for (const auto& elem : *restrictions) {
1066
ret->mkItem((std::string(" ") + TL("allowed speed [m/s]") + std::string(": ") + toString(elem.first)).c_str(), false, elem.second);
1067
}
1068
}
1069
ret->mkItem(TL("length [m]"), false, myLength);
1070
ret->mkItem(TL("width [m]"), false, myWidth);
1071
ret->mkItem(TL("street name"), false, myEdge->getStreetName());
1072
ret->mkItem(TL("stored travel time [s]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getStoredEdgeTravelTime));
1073
ret->mkItem(TL("loaded weight"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getLoadedEdgeWeight));
1074
ret->mkItem(TL("routing speed [m/s]"), true, new FunctionBinding<MSEdge, double>(myEdge, &MSEdge::getRoutingSpeed));
1075
ret->mkItem(TL("lane friction coefficient [%]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getFrictionCoefficient));
1076
ret->mkItem(TL("time penalty [s]"), true, new FunctionBinding<MSEdge, double>(myEdge, &MSEdge::getTimePenalty));
1077
ret->mkItem(TL("brutto occupancy [%]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getBruttoOccupancy, 100.));
1078
ret->mkItem(TL("netto occupancy [%]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getNettoOccupancy, 100.));
1079
ret->mkItem(TL("pending insertions [#]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getPendingEmits));
1080
ret->mkItem(TL("edge type"), false, myEdge->getEdgeType());
1081
ret->mkItem(TL("routing type"), false, myEdge->getRoutingType());
1082
ret->mkItem(TL("type"), false, myLaneType);
1083
ret->mkItem(TL("priority"), false, myEdge->getPriority());
1084
ret->mkItem(TL("distance [km]"), false, myEdge->getDistance() / 1000);
1085
ret->mkItem(TL("allowed vehicle class"), false, StringUtils::wrapText(getVehicleClassNames(myPermissions), 60));
1086
ret->mkItem(TL("disallowed vehicle class"), false, StringUtils::wrapText(getVehicleClassNames(~myPermissions), 60));
1087
ret->mkItem(TL("permission code"), false, myPermissions);
1088
ret->mkItem(TL("color value"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getColorValueForTracker));
1089
if (myBidiLane != nullptr) {
1090
ret->mkItem(TL("bidi-lane"), false, myBidiLane->getID());
1091
}
1092
// info for blocked departDriveWay
1093
for (auto item : getParametersMap()) {
1094
if (StringUtils::startsWith(item.first, "insertionBlocked:")) {
1095
const MSDriveWay* dw = MSDriveWay::retrieveDepartDriveWay(myEdge, item.second);
1096
if (dw != nullptr) {
1097
ret->mkItem(("blocking " + dw->getID()).c_str(), false, toString(MSRailSignal::getBlockingVehicles(dw)));
1098
ret->mkItem(("driveWays blocking " + dw->getID()).c_str(), false, toString(MSRailSignal::getBlockingDriveWays(dw)));
1099
}
1100
}
1101
}
1102
1103
for (const auto& kv : myEdge->getParametersMap()) {
1104
ret->mkItem(("edgeParam:" + kv.first).c_str(), false, kv.second);
1105
}
1106
ret->checkFont(myEdge->getStreetName());
1107
ret->closeBuilding();
1108
return ret;
1109
}
1110
1111
1112
Boundary
1113
GUILane::getCenteringBoundary() const {
1114
const PositionVector& shape = GUIGlobals::gSecondaryShape && myShape2.size() > 0 ? myShape2 : myShape;
1115
Boundary b;
1116
b.add(shape[0]);
1117
b.add(shape[-1]);
1118
b.grow(RENDERING_BUFFER);
1119
// ensure that vehicles and persons on the side are drawn even if the edge
1120
// is outside the view
1121
return b;
1122
}
1123
1124
1125
const PositionVector&
1126
GUILane::getShape(bool secondary) const {
1127
return secondary && myShape2.size() > 0 ? myShape2 : myShape;
1128
}
1129
1130
1131
const std::vector<double>&
1132
GUILane::getShapeRotations(bool secondary) const {
1133
return secondary && myShapeRotations2.size() > 0 ? myShapeRotations2 : myShapeRotations;
1134
}
1135
1136
1137
const std::vector<double>&
1138
GUILane::getShapeLengths(bool secondary) const {
1139
return secondary && myShapeLengths2.size() > 0 ? myShapeLengths2 : myShapeLengths;
1140
}
1141
1142
1143
std::vector<RGBColor>&
1144
GUILane::getShapeColors(bool secondary) const {
1145
return secondary && myShapeColors2.size() > 0 ? myShapeColors2 : myShapeColors;
1146
}
1147
1148
1149
double
1150
GUILane::firstWaitingTime() const {
1151
return myVehicles.size() == 0 ? 0 : myVehicles.back()->getWaitingSeconds();
1152
}
1153
1154
1155
double
1156
GUILane::getEdgeLaneNumber() const {
1157
return (double) myEdge->getLanes().size();
1158
}
1159
1160
1161
double
1162
GUILane::getStoredEdgeTravelTime() const {
1163
MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
1164
if (!ews.knowsTravelTime(myEdge)) {
1165
return -1;
1166
} else {
1167
double value(0);
1168
ews.retrieveExistingTravelTime(myEdge, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()), value);
1169
return value;
1170
}
1171
}
1172
1173
1174
double
1175
GUILane::getLoadedEdgeWeight() const {
1176
MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
1177
if (!ews.knowsEffort(myEdge)) {
1178
return -1;
1179
} else {
1180
double value(-1);
1181
ews.retrieveExistingEffort(myEdge, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()), value);
1182
return value;
1183
}
1184
}
1185
1186
1187
double
1188
GUILane::getColorValueWithFunctional(const GUIVisualizationSettings& s, int activeScheme) const {
1189
switch (activeScheme) {
1190
case 18: {
1191
return GeomHelper::naviDegree(getShape(s.secondaryShape).beginEndAngle()); // [0-360]
1192
}
1193
default:
1194
return getColorValue(s, activeScheme);
1195
}
1196
1197
}
1198
1199
1200
RGBColor
1201
GUILane::setColor(const GUIVisualizationSettings& s) const {
1202
// setting and retrieving the color does not work in OSGView so we return it explicitliy
1203
RGBColor col;
1204
if (MSGlobals::gUseMesoSim && static_cast<const GUIEdge*>(myEdge)->getMesoColor() != MESO_USE_LANE_COLOR) {
1205
col = static_cast<const GUIEdge*>(myEdge)->getMesoColor();
1206
} else {
1207
const GUIColorer& c = s.laneColorer;
1208
if (!setFunctionalColor(c, col) && !setMultiColor(s, c, col)) {
1209
col = c.getScheme().getColor(getColorValue(s, c.getActive()));
1210
}
1211
}
1212
GLHelper::setColor(col);
1213
return col;
1214
}
1215
1216
1217
bool
1218
GUILane::setFunctionalColor(const GUIColorer& c, RGBColor& col, int activeScheme) const {
1219
if (activeScheme < 0) {
1220
activeScheme = c.getActive();
1221
}
1222
switch (activeScheme) {
1223
case 0:
1224
if (myEdge->isCrossing()) {
1225
// determine priority to decide color
1226
const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
1227
if (link->havePriority() || link->getTLLogic() != nullptr) {
1228
col = RGBColor(230, 230, 230);
1229
} else {
1230
col = RGBColor(26, 26, 26);
1231
}
1232
GLHelper::setColor(col);
1233
return true;
1234
} else {
1235
return false;
1236
}
1237
case 18: {
1238
double hue = GeomHelper::naviDegree(myShape.beginEndAngle()); // [0-360]
1239
col = RGBColor::fromHSV(hue, 1., 1.);
1240
GLHelper::setColor(col);
1241
return true;
1242
}
1243
case 30: { // taz color
1244
col = c.getScheme().getColor(0);
1245
std::vector<RGBColor> tazColors;
1246
for (MSEdge* e : myEdge->getPredecessors()) {
1247
if (e->isTazConnector() && e->hasParameter("tazColor")) {
1248
tazColors.push_back(RGBColor::parseColor(e->getParameter("tazColor")));
1249
}
1250
}
1251
for (MSEdge* e : myEdge->getSuccessors()) {
1252
if (e->isTazConnector() && e->hasParameter("tazColor")) {
1253
tazColors.push_back(RGBColor::parseColor(e->getParameter("tazColor")));
1254
}
1255
}
1256
if (tazColors.size() > 0) {
1257
int randColor = RandHelper::rand((int)tazColors.size(), RGBColor::getColorRNG());
1258
col = tazColors[randColor];
1259
}
1260
GLHelper::setColor(col);
1261
return true;
1262
}
1263
default:
1264
return false;
1265
}
1266
}
1267
1268
1269
bool
1270
GUILane::setMultiColor(const GUIVisualizationSettings& s, const GUIColorer& c, RGBColor& col) const {
1271
const int activeScheme = c.getActive();
1272
auto& shapeColors = getShapeColors(s.secondaryShape);
1273
const PositionVector& shape = getShape(s.secondaryShape);
1274
shapeColors.clear();
1275
switch (activeScheme) {
1276
case 22: // color by height at segment start
1277
for (PositionVector::const_iterator ii = shape.begin(); ii != shape.end() - 1; ++ii) {
1278
shapeColors.push_back(c.getScheme().getColor(ii->z()));
1279
}
1280
// osg fallback (edge height at start)
1281
col = c.getScheme().getColor(getColorValue(s, 21));
1282
return true;
1283
case 24: // color by inclination at segment start
1284
for (int ii = 1; ii < (int)shape.size(); ++ii) {
1285
const double inc = (shape[ii].z() - shape[ii - 1].z()) / MAX2(POSITION_EPS, shape[ii].distanceTo2D(shape[ii - 1]));
1286
shapeColors.push_back(c.getScheme().getColor(inc));
1287
}
1288
col = c.getScheme().getColor(getColorValue(s, 23));
1289
return true;
1290
default:
1291
return false;
1292
}
1293
}
1294
1295
double
1296
GUILane::getColorValueForTracker() const {
1297
if (myCachedGUISettings != nullptr) {
1298
const GUIVisualizationSettings& s = *myCachedGUISettings;
1299
const GUIColorer& c = s.laneColorer;
1300
double val = getColorValueWithFunctional(s, c.getActive());
1301
if (val == GUIVisualizationSettings::MISSING_DATA) {
1302
// blowing up the dialog or plot isn't helpful. At least 0 may be understood as neutral
1303
return 0;
1304
} else {
1305
return val;
1306
}
1307
} else {
1308
return 0;
1309
}
1310
}
1311
1312
1313
double
1314
GUILane::getColorValue(const GUIVisualizationSettings& s, int activeScheme) const {
1315
switch (activeScheme) {
1316
case 0:
1317
switch (myPermissions) {
1318
case SVC_PEDESTRIAN:
1319
return 1;
1320
case SVC_BICYCLE:
1321
return 2;
1322
case 0:
1323
// forbidden road or green verge
1324
return myEdge->getPermissions() == 0 ? 10 : 3;
1325
case SVC_SHIP:
1326
return 4;
1327
case SVC_AUTHORITY:
1328
return 8;
1329
case SVC_AIRCRAFT:
1330
case SVC_DRONE:
1331
return 11;
1332
default:
1333
break;
1334
}
1335
if (myEdge->isTazConnector()) {
1336
return 9;
1337
} else if (isRailway(myPermissions)) {
1338
return 5;
1339
} else if ((myPermissions & SVC_PASSENGER) != 0) {
1340
if ((myPermissions & (SVC_RAIL_CLASSES & ~SVC_RAIL_FAST)) != 0 && (myPermissions & SVC_SHIP) == 0) {
1341
return 6;
1342
} else {
1343
return 0;
1344
}
1345
} else {
1346
if ((myPermissions & SVC_RAIL_CLASSES) != 0 && (myPermissions & SVC_SHIP) == 0) {
1347
return 6;
1348
} else {
1349
return 7;
1350
}
1351
}
1352
case 1:
1353
return isLaneOrEdgeSelected();
1354
case 2:
1355
return (double)myPermissions;
1356
case 3:
1357
return getSpeedLimit();
1358
case 4:
1359
return getBruttoOccupancy();
1360
case 5:
1361
return getNettoOccupancy();
1362
case 6:
1363
return firstWaitingTime();
1364
case 7:
1365
return getEdgeLaneNumber();
1366
case 8:
1367
return getEmissions<PollutantsInterface::CO2>() / myLength;
1368
case 9:
1369
return getEmissions<PollutantsInterface::CO>() / myLength;
1370
case 10:
1371
return getEmissions<PollutantsInterface::PM_X>() / myLength;
1372
case 11:
1373
return getEmissions<PollutantsInterface::NO_X>() / myLength;
1374
case 12:
1375
return getEmissions<PollutantsInterface::HC>() / myLength;
1376
case 13:
1377
return getEmissions<PollutantsInterface::FUEL>() / myLength;
1378
case 14:
1379
return getHarmonoise_NoiseEmissions();
1380
case 15: {
1381
return getStoredEdgeTravelTime();
1382
}
1383
case 16: {
1384
MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
1385
if (!ews.knowsTravelTime(myEdge)) {
1386
return -1;
1387
} else {
1388
double value(0);
1389
ews.retrieveExistingTravelTime(myEdge, 0, value);
1390
return 100 * myLength / value / getSpeedLimit();
1391
}
1392
}
1393
case 17: {
1394
// geometrical length has no meaning for walkingAreas since it describes the outer boundary
1395
return myEdge->isWalkingArea() ? 1 : 1 / getLengthGeometryFactor(s.secondaryShape);
1396
}
1397
case 19: {
1398
return getLoadedEdgeWeight();
1399
}
1400
case 20: {
1401
return myEdge->getPriority();
1402
}
1403
case 21: {
1404
// color by z of first shape point
1405
return getShape(s.secondaryShape)[0].z();
1406
}
1407
case 23: {
1408
// color by incline
1409
return (getShape(s.secondaryShape)[-1].z() - getShape(s.secondaryShape)[0].z()) / getLength();
1410
}
1411
case 25: {
1412
// color by average speed
1413
return getMeanSpeed();
1414
}
1415
case 26: {
1416
// color by average relative speed
1417
return getMeanSpeed() / myMaxSpeed;
1418
}
1419
case 27: {
1420
// color by routing device assumed speed
1421
return myEdge->getRoutingSpeed();
1422
}
1423
case 28:
1424
return getEmissions<PollutantsInterface::ELEC>() / myLength;
1425
case 29:
1426
return getPendingEmits();
1427
case 31: {
1428
// by numerical edge param value
1429
if (myEdge->hasParameter(s.edgeParam)) {
1430
try {
1431
return StringUtils::toDouble(myEdge->getParameter(s.edgeParam, "0"));
1432
} catch (NumberFormatException&) {
1433
try {
1434
return StringUtils::toBool(myEdge->getParameter(s.edgeParam, "0"));
1435
} catch (BoolFormatException&) {
1436
return GUIVisualizationSettings::MISSING_DATA;
1437
}
1438
}
1439
} else {
1440
return GUIVisualizationSettings::MISSING_DATA;
1441
}
1442
}
1443
case 32: {
1444
// by numerical lane param value
1445
if (hasParameter(s.laneParam)) {
1446
try {
1447
return StringUtils::toDouble(getParameter(s.laneParam, "0"));
1448
} catch (NumberFormatException&) {
1449
try {
1450
return StringUtils::toBool(getParameter(s.laneParam, "0"));
1451
} catch (BoolFormatException&) {
1452
return GUIVisualizationSettings::MISSING_DATA;
1453
}
1454
}
1455
} else {
1456
return GUIVisualizationSettings::MISSING_DATA;
1457
}
1458
}
1459
case 33: {
1460
// by edge data value
1461
return GUINet::getGUIInstance()->getEdgeData(myEdge, s.edgeData);
1462
}
1463
case 34: {
1464
return myEdge->getDistance();
1465
}
1466
case 35: {
1467
return fabs(myEdge->getDistance());
1468
}
1469
case 36: {
1470
return myReachability;
1471
}
1472
case 37: {
1473
return myRNGIndex % MSGlobals::gNumSimThreads;
1474
}
1475
case 38: {
1476
if (myParkingAreas == nullptr) {
1477
// init
1478
myParkingAreas = new std::vector<MSParkingArea*>();
1479
for (auto& item : MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_PARKING_AREA)) {
1480
if (&item.second->getLane().getEdge() == myEdge) {
1481
myParkingAreas->push_back(dynamic_cast<MSParkingArea*>(item.second));
1482
}
1483
}
1484
}
1485
int capacity = 0;
1486
for (MSParkingArea* pa : *myParkingAreas) {
1487
capacity += pa->getCapacity() - pa->getOccupancy();
1488
}
1489
return capacity;
1490
}
1491
case 39: {
1492
// by live edge data value
1493
return GUINet::getGUIInstance()->getMeanData(this, s.edgeDataID, s.edgeData);
1494
}
1495
}
1496
return 0;
1497
}
1498
1499
1500
double
1501
GUILane::getScaleValue(const GUIVisualizationSettings& s, int activeScheme, bool s2) const {
1502
switch (activeScheme) {
1503
case 0:
1504
return 0;
1505
case 1:
1506
return isLaneOrEdgeSelected();
1507
case 2:
1508
return getSpeedLimit();
1509
case 3:
1510
return getBruttoOccupancy();
1511
case 4:
1512
return getNettoOccupancy();
1513
case 5:
1514
return firstWaitingTime();
1515
case 6:
1516
return getEdgeLaneNumber();
1517
case 7:
1518
return getEmissions<PollutantsInterface::CO2>() / myLength;
1519
case 8:
1520
return getEmissions<PollutantsInterface::CO>() / myLength;
1521
case 9:
1522
return getEmissions<PollutantsInterface::PM_X>() / myLength;
1523
case 10:
1524
return getEmissions<PollutantsInterface::NO_X>() / myLength;
1525
case 11:
1526
return getEmissions<PollutantsInterface::HC>() / myLength;
1527
case 12:
1528
return getEmissions<PollutantsInterface::FUEL>() / myLength;
1529
case 13:
1530
return getHarmonoise_NoiseEmissions();
1531
case 14: {
1532
return getStoredEdgeTravelTime();
1533
}
1534
case 15: {
1535
MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
1536
if (!ews.knowsTravelTime(myEdge)) {
1537
return -1;
1538
} else {
1539
double value(0);
1540
ews.retrieveExistingTravelTime(myEdge, 0, value);
1541
return 100 * myLength / value / getSpeedLimit();
1542
}
1543
}
1544
case 16: {
1545
return 1 / getLengthGeometryFactor(s2);
1546
}
1547
case 17: {
1548
return getLoadedEdgeWeight();
1549
}
1550
case 18: {
1551
return myEdge->getPriority();
1552
}
1553
case 19: {
1554
// scale by average speed
1555
return getMeanSpeed();
1556
}
1557
case 20: {
1558
// scale by average relative speed
1559
return getMeanSpeed() / myMaxSpeed;
1560
}
1561
case 21:
1562
return getEmissions<PollutantsInterface::ELEC>() / myLength;
1563
case 22:
1564
return MSNet::getInstance()->getInsertionControl().getPendingEmits(this);
1565
case 23:
1566
// by edge data value
1567
return GUINet::getGUIInstance()->getEdgeData(myEdge, s.edgeDataScaling);
1568
}
1569
return 0;
1570
}
1571
1572
1573
bool
1574
GUILane::drawAsRailway(const GUIVisualizationSettings& s) const {
1575
return isRailway(myPermissions) && ((myPermissions & SVC_BUS) == 0) && s.showRails;
1576
}
1577
1578
1579
bool
1580
GUILane::drawAsWaterway(const GUIVisualizationSettings& s) const {
1581
return isWaterway(myPermissions) && s.showRails; // reusing the showRails setting
1582
}
1583
1584
1585
#ifdef HAVE_OSG
1586
void
1587
GUILane::updateColor(const GUIVisualizationSettings& s) {
1588
if (myGeom == 0) {
1589
// not drawn
1590
return;
1591
}
1592
const RGBColor col = setColor(s);
1593
osg::Vec4ubArray* colors = dynamic_cast<osg::Vec4ubArray*>(myGeom->getColorArray());
1594
(*colors)[0].set(col.red(), col.green(), col.blue(), col.alpha());
1595
myGeom->setColorArray(colors);
1596
}
1597
#endif
1598
1599
1600
void
1601
GUILane::closeTraffic(bool rebuildAllowed) {
1602
MSGlobals::gCheckRoutes = false;
1603
if (myAmClosed) {
1604
myPermissionChanges.clear(); // reset rerouters
1605
resetPermissions(CHANGE_PERMISSIONS_GUI);
1606
} else {
1607
setPermissions(SVC_AUTHORITY, CHANGE_PERMISSIONS_GUI);
1608
}
1609
myAmClosed = !myAmClosed;
1610
if (rebuildAllowed) {
1611
getEdge().rebuildAllowedLanes();
1612
}
1613
}
1614
1615
1616
PositionVector
1617
GUILane::splitAtSegments(const PositionVector& shape) {
1618
assert(MSGlobals::gUseMesoSim);
1619
const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdge().getEdgeType());
1620
int no = MELoop::numSegmentsFor(myLength, edgeType.edgeLength);
1621
const double slength = myLength / no;
1622
PositionVector result = shape;
1623
double offset = 0;
1624
for (int i = 0; i < no; ++i) {
1625
offset += slength;
1626
Position pos = shape.positionAtOffset(offset);
1627
int index = result.indexOfClosest(pos);
1628
if (pos.distanceTo(result[index]) > POSITION_EPS) {
1629
index = result.insertAtClosest(pos, false);
1630
}
1631
if (i != no - 1) {
1632
mySegmentStartIndex.push_back(index);
1633
}
1634
while ((int)myShapeSegments.size() < index) {
1635
myShapeSegments.push_back(i);
1636
}
1637
//std::cout << "splitAtSegments " << getID() << " no=" << no << " i=" << i << " offset=" << offset << " index=" << index << " segs=" << toString(myShapeSegments) << " resultSize=" << result.size() << " result=" << toString(result) << "\n";
1638
}
1639
while (myShapeSegments.size() < result.size()) {
1640
myShapeSegments.push_back(no - 1);
1641
}
1642
return result;
1643
}
1644
1645
bool
1646
GUILane::isSelected() const {
1647
return gSelected.isSelected(GLO_LANE, getGlID());
1648
}
1649
1650
bool
1651
GUILane::isLaneOrEdgeSelected() const {
1652
return isSelected() || gSelected.isSelected(GLO_EDGE, dynamic_cast<GUIEdge*>(myEdge)->getGlID());
1653
}
1654
1655
double
1656
GUILane::getPendingEmits() const {
1657
return MSNet::getInstance()->getInsertionControl().getPendingEmits(this);
1658
}
1659
1660
double
1661
GUILane::getClickPriority() const {
1662
if (MSGlobals::gUseMesoSim) {
1663
// do not select lanes in meso mode
1664
return INVALID_PRIORITY;
1665
}
1666
if (myEdge->isCrossing()) {
1667
return GLO_CROSSING;
1668
}
1669
return GLO_LANE;
1670
}
1671
1672
1673
/****************************************************************************/
1674
1675