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