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