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