Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/gui/GUIViewTraffic.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GUIViewTraffic.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Christian Roessel
18
/// @author Michael Behrisch
19
/// @author Andreas Gaubatz
20
/// @date Sept 2002
21
///
22
// A view on the simulation; this view is a microscopic one
23
/****************************************************************************/
24
#include <config.h>
25
26
#ifdef HAVE_FFMPEG
27
#include <utils/gui/div/GUIVideoEncoder.h>
28
#endif
29
30
#include <iostream>
31
#include <utility>
32
#include <cmath>
33
#include <limits>
34
#include <foreign/rtree/SUMORTree.h>
35
#include <gui/GUIApplicationWindow.h>
36
#include <gui/GUIGlobals.h>
37
#include <guisim/GUIEdge.h>
38
#include <guisim/GUILane.h>
39
#include <guisim/GUINet.h>
40
#include <guisim/GUIVehicle.h>
41
#include <guisim/GUIVehicleControl.h>
42
#include <mesogui/GUIMEVehicle.h>
43
#include <mesogui/GUIMEVehicleControl.h>
44
#include <microsim/MSEdge.h>
45
#include <microsim/MSGlobals.h>
46
#include <microsim/MSJunctionControl.h>
47
#include <microsim/MSLane.h>
48
#include <microsim/MSStoppingPlace.h>
49
#include <microsim/traffic_lights/MSSimpleTrafficLightLogic.h>
50
#include <microsim/traffic_lights/MSTLLogicControl.h>
51
#include <utils/common/RGBColor.h>
52
#include <utils/foxtools/MFXButtonTooltip.h>
53
#include <utils/foxtools/MFXCheckableButton.h>
54
#include <utils/foxtools/MFXImageHelper.h>
55
#include <utils/geom/PositionVector.h>
56
#include <utils/gui/div/GLHelper.h>
57
#include <utils/gui/div/GUIDesigns.h>
58
#include <utils/gui/div/GUIGlobalSelection.h>
59
#include <utils/gui/globjects/GLIncludes.h>
60
#include <utils/gui/globjects/GUIGlObjectStorage.h>
61
#include <utils/gui/globjects/GUIShapeContainer.h>
62
#include <utils/gui/images/GUIIconSubSys.h>
63
#include <utils/gui/settings/GUICompleteSchemeStorage.h>
64
#include <utils/gui/windows/GUIAppEnum.h>
65
#include <utils/gui/windows/GUIDialog_ViewSettings.h>
66
#include <utils/gui/windows/GUIPerspectiveChanger.h>
67
#include <utils/gui/windows/GUISUMOAbstractView.h>
68
#include <utils/shapes/ShapeContainer.h>
69
70
#include "GUISUMOViewParent.h"
71
#include "GUIViewTraffic.h"
72
73
// ===========================================================================
74
// member method definitions
75
// ===========================================================================
76
GUIViewTraffic::GUIViewTraffic(
77
FXComposite* p,
78
GUIMainWindow& app,
79
GUISUMOViewParent* parent,
80
GUINet& net, FXGLVisual* glVis,
81
FXGLCanvas* share) :
82
GUISUMOAbstractView(p, app, parent, net.getVisualisationSpeedUp(), glVis, share),
83
myTrackedID(GUIGlObject::INVALID_ID),
84
myTLSGame(OptionsCont::getOptions().getString("game.mode") == "tls")
85
#ifdef HAVE_FFMPEG
86
, myCurrentVideo(nullptr)
87
#endif
88
{}
89
90
91
GUIViewTraffic::~GUIViewTraffic() {
92
endSnapshot();
93
}
94
95
96
void
97
GUIViewTraffic::buildViewToolBars(GUIGlChildWindow* v) {
98
// build coloring tools
99
{
100
const std::vector<std::string>& names = gSchemeStorage.getNames();
101
for (std::vector<std::string>::const_iterator i = names.begin(); i != names.end(); ++i) {
102
v->getColoringSchemesCombo()->appendIconItem(i->c_str());
103
if ((*i) == myVisualizationSettings->name) {
104
v->getColoringSchemesCombo()->setCurrentItem(v->getColoringSchemesCombo()->getNumItems() - 1);
105
}
106
}
107
}
108
// for junctions
109
new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
110
(std::string("\t") + TL("Locate Junctions") + std::string("\t") + TL("Locate a junction within the network.")).c_str(),
111
GUIIconSubSys::getIcon(GUIIcon::LOCATEJUNCTION), v, MID_HOTKEY_SHIFT_J_LOCATEJUNCTION,
112
GUIDesignButtonPopup);
113
// for edges
114
new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
115
(std::string("\t") + TL("Locate Edges") + std::string("\t") + TL("Locate an edge within the network.")).c_str(),
116
GUIIconSubSys::getIcon(GUIIcon::LOCATEEDGE), v, MID_HOTKEY_SHIFT_E_LOCATEEDGE,
117
GUIDesignButtonPopup);
118
// for vehicles
119
new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
120
(std::string("\t") + TL("Locate Vehicles") + std::string("\t") + TL("Locate a vehicle within the network.")).c_str(),
121
GUIIconSubSys::getIcon(GUIIcon::LOCATEVEHICLE), v, MID_HOTKEY_SHIFT_V_LOCATEVEHICLE,
122
GUIDesignButtonPopup);
123
// for persons
124
new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
125
(std::string("\t") + TL("Locate Persons") + std::string("\t") + TL("Locate a person within the network.")).c_str(),
126
GUIIconSubSys::getIcon(GUIIcon::LOCATEPERSON), v, MID_HOTKEY_SHIFT_P_LOCATEPERSON,
127
GUIDesignButtonPopup);
128
// for containers
129
new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
130
(std::string("\t") + TL("Locate Container") + std::string("\t") + TL("Locate a container within the network.")).c_str(),
131
GUIIconSubSys::getIcon(GUIIcon::LOCATECONTAINER), v, MID_HOTKEY_SHIFT_C_LOCATECONTAINER,
132
GUIDesignButtonPopup);
133
// for tls
134
new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
135
(std::string("\t") + TL("Locate TLS") + std::string("\t") + TL("Locate a tls within the network.")).c_str(),
136
GUIIconSubSys::getIcon(GUIIcon::LOCATETLS), v, MID_HOTKEY_SHIFT_T_LOCATETLS,
137
GUIDesignButtonPopup);
138
// for additional stuff
139
new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
140
(std::string("\t") + TL("Locate Additional") + std::string("\t") + TL("Locate an additional structure within the network.")).c_str(),
141
GUIIconSubSys::getIcon(GUIIcon::LOCATEADD), v, MID_HOTKEY_SHIFT_A_LOCATEADDITIONAL,
142
GUIDesignButtonPopup);
143
// for pois
144
new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
145
(std::string("\t") + TL("Locate PoI") + std::string("\t") + TL("Locate a PoI within the network.")).c_str(),
146
GUIIconSubSys::getIcon(GUIIcon::LOCATEPOI), v, MID_HOTKEY_SHIFT_O_LOCATEPOI,
147
GUIDesignButtonPopup);
148
// for polygons
149
new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
150
(std::string("\t") + TL("Locate Polygon") + std::string("\t") + TL("Locate a Polygon within the network.")).c_str(),
151
GUIIconSubSys::getIcon(GUIIcon::LOCATEPOLY), v, MID_HOTKEY_SHIFT_L_LOCATEPOLY,
152
GUIDesignButtonPopup);
153
}
154
155
156
bool
157
GUIViewTraffic::setColorScheme(const std::string& name) {
158
if (!gSchemeStorage.contains(name)) {
159
return false;
160
}
161
if (myGUIDialogViewSettings != nullptr) {
162
if (myGUIDialogViewSettings->getCurrentScheme() != name) {
163
myGUIDialogViewSettings->setCurrentScheme(name);
164
}
165
}
166
myVisualizationSettings = &gSchemeStorage.get(name.c_str());
167
myVisualizationSettings->gaming = myApp->isGaming();
168
update();
169
return true;
170
}
171
172
173
void
174
GUIViewTraffic::buildColorRainbow(const GUIVisualizationSettings& s, GUIColorScheme& scheme, int active, GUIGlObjectType objectType,
175
const GUIVisualizationRainbowSettings& rs) {
176
assert(!scheme.isFixed());
177
double minValue = std::numeric_limits<double>::infinity();
178
double maxValue = -std::numeric_limits<double>::infinity();
179
// retrieve range
180
bool hasMissingData = false;
181
if (objectType == GLO_LANE) {
182
// XXX (see #3409) multi-colors are not currently handled. this is a quick hack
183
if (active == 22) {
184
active = 21; // segment height, fall back to start height
185
} else if (active == 24) {
186
active = 23; // segment incline, fall back to total incline
187
}
188
const MSEdgeVector& edges = MSEdge::getAllEdges();
189
for (MSEdgeVector::const_iterator it = edges.begin(); it != edges.end(); ++it) {
190
if (MSGlobals::gUseMesoSim) {
191
const double val = static_cast<GUIEdge*>(*it)->getColorValue(s, active);
192
if (val == s.MISSING_DATA) {
193
hasMissingData = true;
194
continue;
195
}
196
minValue = MIN2(minValue, val);
197
maxValue = MAX2(maxValue, val);
198
} else {
199
const std::vector<MSLane*>& lanes = (*it)->getLanes();
200
for (std::vector<MSLane*>::const_iterator it_l = lanes.begin(); it_l != lanes.end(); it_l++) {
201
const double val = static_cast<GUILane*>(*it_l)->getColorValue(s, active);
202
if (val == s.MISSING_DATA) {
203
hasMissingData = true;
204
continue;
205
}
206
minValue = MIN2(minValue, val);
207
maxValue = MAX2(maxValue, val);
208
}
209
}
210
}
211
} else if (objectType == GLO_VEHICLE) {
212
MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
213
for (MSVehicleControl::constVehIt it_v = c.loadedVehBegin(); it_v != c.loadedVehEnd(); ++it_v) {
214
const GUIGlObject* veh;
215
if (MSGlobals::gUseMesoSim) {
216
veh = static_cast<const GUIMEVehicle*>(it_v->second);
217
} else {
218
veh = static_cast<const GUIVehicle*>(it_v->second);
219
}
220
const double val = veh->getColorValue(s, active);
221
if (val == s.MISSING_DATA) {
222
hasMissingData = true;
223
continue;
224
}
225
minValue = MIN2(minValue, val);
226
maxValue = MAX2(maxValue, val);
227
}
228
} else if (objectType == GLO_JUNCTION) {
229
if (active == 3) {
230
std::set<const MSJunction*> junctions;
231
for (MSEdge* edge : MSEdge::getAllEdges()) {
232
junctions.insert(edge->getFromJunction());
233
junctions.insert(edge->getToJunction());
234
}
235
for (const MSJunction* junction : junctions) {
236
minValue = MIN2(minValue, junction->getPosition().z());
237
maxValue = MAX2(maxValue, junction->getPosition().z());
238
}
239
}
240
}
241
if (scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_PERMISSION_CODE) {
242
scheme.clear();
243
// add threshold for every distinct value
244
std::set<SVCPermissions> codes;
245
for (MSEdge* edge : MSEdge::getAllEdges()) {
246
for (MSLane* lane : edge->getLanes()) {
247
codes.insert(lane->getPermissions());
248
}
249
}
250
int step = MAX2(1, 360 / (int)codes.size());
251
int hue = 0;
252
for (SVCPermissions p : codes) {
253
scheme.addColor(RGBColor::fromHSV(hue, 1, 1), (double)p);
254
hue = (hue + step) % 360;
255
}
256
return;
257
}
258
buildMinMaxRainbow(s, scheme, rs, minValue, maxValue, hasMissingData);
259
}
260
261
262
std::vector<std::string>
263
GUIViewTraffic::getEdgeDataAttrs() const {
264
if (GUINet::getGUIInstance() != nullptr) {
265
return GUINet::getGUIInstance()->getEdgeDataAttrs();
266
}
267
return std::vector<std::string>();
268
}
269
270
271
std::vector<std::string>
272
GUIViewTraffic::getMeanDataIDs() const {
273
if (GUINet::getGUIInstance() != nullptr) {
274
return GUINet::getGUIInstance()->getMeanDataIDs();
275
}
276
return std::vector<std::string>();
277
}
278
279
std::vector<std::string>
280
GUIViewTraffic::getMeanDataAttrs(const std::string& meanDataID) const {
281
if (GUINet::getGUIInstance() != nullptr) {
282
return GUINet::getGUIInstance()->getMeanDataAttrs(meanDataID);
283
}
284
return std::vector<std::string>();
285
}
286
287
288
std::vector<std::string>
289
GUIViewTraffic::getEdgeLaneParamKeys(bool edgeKeys) const {
290
std::set<std::string> keys;
291
for (const MSEdge* e : MSEdge::getAllEdges()) {
292
if (edgeKeys) {
293
for (const auto& item : e->getParametersMap()) {
294
keys.insert(item.first);
295
}
296
} else {
297
for (const auto lane : e->getLanes()) {
298
for (const auto& item : lane->getParametersMap()) {
299
keys.insert(item.first);
300
}
301
}
302
}
303
}
304
return std::vector<std::string>(keys.begin(), keys.end());
305
}
306
307
308
std::vector<std::string>
309
GUIViewTraffic::getVehicleParamKeys(bool /*vTypeKeys*/) const {
310
std::set<std::string> keys;
311
MSVehicleControl* vc = nullptr;
312
if (MSGlobals::gUseMesoSim) {
313
vc = GUINet::getGUIInstance()->getGUIMEVehicleControl();
314
} else {
315
vc = GUINet::getGUIInstance()->getGUIVehicleControl();
316
}
317
vc->secureVehicles();
318
for (auto vehIt = vc->loadedVehBegin(); vehIt != vc->loadedVehEnd(); ++vehIt) {
319
for (auto kv : vehIt->second->getParameter().getParametersMap()) {
320
keys.insert(kv.first);
321
}
322
}
323
vc->releaseVehicles();
324
return std::vector<std::string>(keys.begin(), keys.end());
325
}
326
327
std::vector<std::string>
328
GUIViewTraffic::getPOIParamKeys() const {
329
std::set<std::string> keys;
330
const ShapeContainer::POIs& pois = static_cast<ShapeContainer&>(GUINet::getInstance()->getShapeContainer()).getPOIs();
331
for (auto item : pois) {
332
for (auto kv : item.second->getParametersMap()) {
333
keys.insert(kv.first);
334
}
335
}
336
return std::vector<std::string>(keys.begin(), keys.end());
337
}
338
339
340
void
341
GUIViewTraffic::centerTo(GUIGlID id, bool applyZoom, double zoomDist) {
342
GUIGlobals::gSecondaryShape = myVisualizationSettings->secondaryShape;
343
GUISUMOAbstractView::centerTo(id, applyZoom, zoomDist);
344
GUIGlobals::gSecondaryShape = false;
345
}
346
347
int
348
GUIViewTraffic::doPaintGL(int mode, const Boundary& bound) {
349
// init view settings
350
glRenderMode(mode);
351
glMatrixMode(GL_MODELVIEW);
352
GLHelper::pushMatrix();
353
glDisable(GL_TEXTURE_2D);
354
glDisable(GL_ALPHA_TEST);
355
glEnable(GL_BLEND);
356
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
357
glEnable(GL_DEPTH_TEST);
358
359
// draw decals (if not in grabbing mode)
360
drawDecals();
361
myVisualizationSettings->scale = m2p(SUMO_const_laneWidth);
362
if (myVisualizationSettings->showGrid) {
363
paintGLGrid();
364
}
365
glLineWidth(1);
366
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
367
const float minB[2] = { (float)bound.xmin(), (float)bound.ymin() };
368
const float maxB[2] = { (float)bound.xmax(), (float)bound.ymax() };
369
glEnable(GL_POLYGON_OFFSET_FILL);
370
glEnable(GL_POLYGON_OFFSET_LINE);
371
const SUMORTree& grid = GUINet::getGUIInstance()->getVisualisationSpeedUp(myVisualizationSettings->secondaryShape);
372
int hits2 = grid.Search(minB, maxB, *myVisualizationSettings);
373
GUIGlobals::gSecondaryShape = myVisualizationSettings->secondaryShape;
374
// Draw additional objects
375
if (myAdditionallyDrawn.size() > 0) {
376
glTranslated(0, 0, -.01);
377
GUINet::getGUIInstance()->lock();
378
for (auto i : myAdditionallyDrawn) {
379
i.first->drawGLAdditional(this, *myVisualizationSettings);
380
}
381
GUINet::getGUIInstance()->unlock();
382
glTranslated(0, 0, .01);
383
}
384
GLHelper::popMatrix();
385
/*
386
// draw legends
387
glMatrixMode(GL_MODELVIEW);
388
glLoadIdentity();
389
glTranslated(1.-.2, 1.-.5, 0.);
390
glScaled(.2, .5, 1.);
391
GUIColoringSchemesMap<GUILane> &sm = GUIViewTraffic::getLaneSchemesMap(); //!!!
392
sm.getColorer(myVisualizationSettings->laneEdgeMode)->drawLegend();
393
*/
394
return hits2;
395
}
396
397
398
void
399
GUIViewTraffic::startTrack(int id) {
400
myTrackedID = id;
401
GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
402
if (o != nullptr) {
403
GUIBaseVehicle* v = dynamic_cast<GUIBaseVehicle*>(o);
404
if (v != nullptr) {
405
v->addActiveAddVisualisation(this, GUIBaseVehicle::VO_TRACK);
406
}
407
}
408
}
409
410
411
void
412
GUIViewTraffic::stopTrack() {
413
myTrackedID = GUIGlObject::INVALID_ID;
414
}
415
416
417
GUIGlID
418
GUIViewTraffic::getTrackedID() const {
419
return myTrackedID;
420
}
421
422
423
void
424
GUIViewTraffic::onGamingClick(Position pos) {
425
if (myTLSGame) {
426
MSTLLogicControl& tlsControl = MSNet::getInstance()->getTLSControl();
427
MSTrafficLightLogic* minTll = nullptr;
428
GUIGlObject* minRR = nullptr;
429
double minDist = std::numeric_limits<double>::infinity();
430
double minDistRR = std::numeric_limits<double>::infinity();
431
for (MSTrafficLightLogic* const tll : tlsControl.getAllLogics()) {
432
if (tlsControl.isActive(tll) && tll->getProgramID() != "off") {
433
// get the links
434
const MSTrafficLightLogic::LaneVector& lanes = tll->getLanesAt(0);
435
if (lanes.size() > 0) {
436
const Position& endPos = lanes[0]->getShape().back();
437
if (endPos.distanceTo(pos) < minDist) {
438
minDist = endPos.distanceTo(pos);
439
minTll = tll;
440
}
441
}
442
}
443
}
444
if (makeCurrent()) {
445
for (GUIGlObject* o : getGUIGlObjectsAtPosition(getPositionInformation(), MIN2(minDist, 20.0))) {
446
if (o->getType() == GLO_REROUTER_EDGE) {
447
const double dist = o->getCenter().distanceTo2D(pos);
448
if (dist < minDistRR) {
449
minDistRR = dist;
450
minRR = o;
451
}
452
}
453
}
454
makeNonCurrent();
455
}
456
if (minDistRR < minDist && minRR != nullptr) {
457
minRR->onLeftBtnPress(nullptr);
458
update();
459
return;
460
}
461
462
if (minTll != nullptr) {
463
if (minTll->getPhaseNumber() == 0) {
464
// MSRailSignal
465
return;
466
}
467
const int ci = minTll->getCurrentPhaseIndex();
468
const int n = minTll->getPhaseNumber();
469
int greenCount = 0;
470
for (auto& phase : minTll->getPhases()) {
471
if (phase->isGreenPhase()) {
472
greenCount++;
473
}
474
}
475
int nextPhase = (ci + 1) % n;
476
SUMOTime nextDuration = 0;
477
if (minTll->getCurrentPhaseDef().isGreenPhase() || (greenCount == 1 && minTll->getCurrentPhaseDef().isAllRedPhase())) {
478
nextDuration = minTll->getPhase(nextPhase).duration;
479
} else {
480
// we are in transition to a green phase
481
// -> skip forward to the transition into the next green phase
482
// but ensure that the total transition time is maintained
483
// taking into account how much time was already spent
484
SUMOTime spentTransition = minTll->getSpentDuration();
485
// the transition may consist of more than one phase so we
486
// search backwards until the prior green phase
487
for (int i = ci - 1; i != ci; i--) {
488
if (i < 0) {
489
i = n - 1;
490
}
491
if (minTll->getPhase(i).isGreenPhase()) {
492
break;
493
}
494
spentTransition += minTll->getPhase(i).duration;
495
}
496
// now we skip past the next greenphase
497
int numGreen = 0;
498
int i = nextPhase;
499
for (; numGreen < 2; i = (i + 1) % n) {
500
if (minTll->getPhase(i).isGreenPhase()) {
501
numGreen++;
502
continue;
503
}
504
// transition after the next green
505
if (numGreen == 1) {
506
SUMOTime dur = minTll->getPhase(i).duration;
507
if (dur <= spentTransition) {
508
spentTransition -= dur;
509
} else {
510
nextPhase = i;
511
nextDuration = dur - spentTransition;
512
break;
513
}
514
}
515
}
516
}
517
minTll->changeStepAndDuration(tlsControl, MSNet::getInstance()->getCurrentTimeStep(), nextPhase, nextDuration);
518
update();
519
}
520
} else {
521
// DRT game
522
if (MSGlobals::gUseMesoSim) {
523
return;
524
}
525
const auto& sel = gSelected.getSelected(GLO_VEHICLE);
526
if (sel.size() == 0) {
527
// find closest pt vehicle
528
double minDist = std::numeric_limits<double>::infinity();
529
GUIVehicle* closest = nullptr;
530
MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
531
MSVehicleControl::constVehIt it = vc.loadedVehBegin();
532
MSVehicleControl::constVehIt end = vc.loadedVehEnd();
533
for (it = vc.loadedVehBegin(); it != end; ++it) {
534
GUIVehicle* veh = dynamic_cast<GUIVehicle*>(it->second);
535
assert(veh != 0);
536
if (veh->getParameter().line != "") {
537
const double dist = veh->getPosition().distanceTo2D(pos);
538
if (dist < minDist) {
539
minDist = dist;
540
closest = veh;
541
}
542
}
543
}
544
if (closest != nullptr) {
545
gSelected.select(closest->getGlID());
546
closest->addActiveAddVisualisation(this, GUIBaseVehicle::VO_SHOW_FUTURE_ROUTE);
547
}
548
} else {
549
// find closest pt stop
550
double minDist = std::numeric_limits<double>::infinity();
551
MSStoppingPlace* closestStop = nullptr;
552
const NamedObjectCont<MSStoppingPlace*>& stops = MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_BUS_STOP);
553
for (auto it = stops.begin(); it != stops.end(); ++it) {
554
MSStoppingPlace* stop = it->second;
555
const double dist = pos.distanceTo2D(stop->getLane().geometryPositionAtOffset(stop->getEndLanePosition()));
556
if (dist < minDist) {
557
minDist = dist;
558
closestStop = stop;
559
}
560
}
561
if (closestStop != 0) {
562
GUIGlID id = *sel.begin();
563
GUIVehicle* veh = dynamic_cast<GUIVehicle*>(GUIGlObjectStorage::gIDStorage.getObjectBlocking(id));
564
assert(veh != 0);
565
MSLane* lane = veh->getMutableLane();
566
lane->getVehiclesSecure();
567
veh->rerouteDRTStop(closestStop);
568
GUIGlObjectStorage::gIDStorage.unblockObject(id);
569
lane->releaseVehicles();
570
}
571
}
572
}
573
}
574
575
576
void
577
GUIViewTraffic::onGamingRightClick(Position /*pos*/) {
578
const auto& sel = gSelected.getSelected(GLO_VEHICLE);
579
if (sel.size() > 0) {
580
GUIGlID id = *sel.begin();
581
GUIVehicle* veh = dynamic_cast<GUIVehicle*>(GUIGlObjectStorage::gIDStorage.getObjectBlocking(id));
582
if (veh != 0) {
583
veh->removeActiveAddVisualisation(this, GUIBaseVehicle::VO_SHOW_FUTURE_ROUTE);
584
}
585
GUIGlObjectStorage::gIDStorage.unblockObject(id);
586
}
587
gSelected.clear();
588
}
589
590
591
SUMOTime
592
GUIViewTraffic::getCurrentTimeStep() const {
593
return MSNet::getInstance()->getCurrentTimeStep();
594
}
595
596
597
long
598
GUIViewTraffic::onCmdCloseLane(FXObject*, FXSelector, void*) {
599
GUILane* lane = getLaneUnderCursor();
600
if (lane != nullptr) {
601
lane->closeTraffic();
602
GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
603
update();
604
}
605
return 1;
606
}
607
608
609
long
610
GUIViewTraffic::onCmdCloseEdge(FXObject*, FXSelector, void*) {
611
GUILane* lane = getLaneUnderCursor();
612
if (lane != nullptr) {
613
dynamic_cast<GUIEdge*>(&lane->getEdge())->closeTraffic(lane);
614
GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
615
update();
616
}
617
return 1;
618
}
619
620
621
long
622
GUIViewTraffic::onCmdAddRerouter(FXObject*, FXSelector, void*) {
623
GUILane* lane = getLaneUnderCursor();
624
if (lane != nullptr) {
625
dynamic_cast<GUIEdge*>(&lane->getEdge())->addRerouter();
626
GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
627
update();
628
}
629
return 1;
630
}
631
632
633
long
634
GUIViewTraffic::showLaneReachability(GUILane* lane, FXObject* menu, FXSelector) {
635
if (lane != nullptr) {
636
// reset
637
const double UNREACHED = INVALID_DOUBLE;
638
gSelected.clear();
639
for (const MSEdge* const e : MSEdge::getAllEdges()) {
640
for (MSLane* const l : e->getLanes()) {
641
GUILane* gLane = dynamic_cast<GUILane*>(l);
642
gLane->setReachability(UNREACHED);
643
}
644
}
645
// prepare
646
FXMenuCommand* mc = dynamic_cast<FXMenuCommand*>(menu);
647
const SUMOVehicleClass svc = SumoVehicleClassStrings.get(mc->getText().text());
648
const double defaultMaxSpeed = SUMOVTypeParameter::VClassDefaultValues(svc).desiredMaxSpeed;
649
// find reachable
650
std::map<MSEdge*, double> reachableEdges;
651
reachableEdges[&lane->getEdge()] = 0;
652
MSEdgeVector check;
653
check.push_back(&lane->getEdge());
654
while (check.size() > 0) {
655
MSEdge* e = check.front();
656
check.erase(check.begin());
657
double traveltime = reachableEdges[e];
658
for (MSLane* const l : e->getLanes()) {
659
if (l->allowsVehicleClass(svc)) {
660
GUILane* gLane = dynamic_cast<GUILane*>(l);
661
gSelected.select(gLane->getGlID(), false);
662
gLane->setReachability(traveltime);
663
}
664
}
665
const double dt = e->getLength() / MIN2(e->getSpeedLimit(), defaultMaxSpeed);
666
// ensure algorithm termination
667
traveltime += MAX2(dt, NUMERICAL_EPS);
668
for (MSEdge* const nextEdge : e->getSuccessors(svc)) {
669
if (reachableEdges.count(nextEdge) == 0 ||
670
// revisit edge via faster path
671
reachableEdges[nextEdge] > traveltime) {
672
reachableEdges[nextEdge] = traveltime;
673
check.push_back(nextEdge);
674
}
675
}
676
if (svc == SVC_PEDESTRIAN) {
677
// can also walk backwards
678
for (MSEdge* const prevEdge : e->getPredecessors()) {
679
if (prevEdge->allowedLanes(*e, svc) != nullptr &&
680
(reachableEdges.count(prevEdge) == 0 ||
681
// revisit edge via faster path
682
reachableEdges[prevEdge] > traveltime)) {
683
reachableEdges[prevEdge] = traveltime;
684
check.push_back(prevEdge);
685
}
686
}
687
// and connect to arbitrary incoming if there are no walkingareas
688
if (!MSNet::getInstance()->hasPedestrianNetwork()) {
689
for (const MSEdge* const in_const : e->getToJunction()->getIncoming()) {
690
MSEdge* in = const_cast<MSEdge*>(in_const);
691
if ((in->getPermissions() & svc) == svc &&
692
(reachableEdges.count(in) == 0 ||
693
// revisit edge via faster path
694
reachableEdges[in] > traveltime)) {
695
reachableEdges[in] = traveltime;
696
check.push_back(in);
697
}
698
}
699
}
700
}
701
}
702
gSelected.notifyChanged();
703
}
704
return 1;
705
}
706
707
708
long
709
GUIViewTraffic::onCmdShowReachability(FXObject* menu, FXSelector selector, void*) {
710
GUILane* lane = getLaneUnderCursor();
711
if (lane != nullptr) {
712
// reset
713
showLaneReachability(lane, menu, selector);
714
// switch to 'color by selection' unless coloring 'by reachability'
715
if (myVisualizationSettings->laneColorer.getActive() != 36) {
716
myVisualizationSettings->laneColorer.setActive(1);
717
}
718
update();
719
}
720
return 1;
721
}
722
723
724
GUILane*
725
GUIViewTraffic::getLaneUnderCursor() {
726
if (makeCurrent()) {
727
int id = getObjectUnderCursor();
728
if (id != 0) {
729
GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
730
if (o != nullptr) {
731
return dynamic_cast<GUILane*>(o);
732
}
733
}
734
makeNonCurrent();
735
}
736
return nullptr;
737
}
738
739
740
long
741
GUIViewTraffic::onDoubleClicked(FXObject*, FXSelector, void*) {
742
// leave fullscreen mode
743
if (myApp->isFullScreen()) {
744
myApp->onCmdFullScreen(nullptr, 0, nullptr);
745
} else {
746
stopTrack();
747
}
748
return 1;
749
}
750
751
752
753
void
754
GUIViewTraffic::saveFrame(const std::string& destFile, FXColor* buf) {
755
#ifdef HAVE_FFMPEG
756
if (myCurrentVideo == nullptr) {
757
myCurrentVideo = new GUIVideoEncoder(destFile.c_str(), getWidth(), getHeight(), myApp->getDelay());
758
}
759
myCurrentVideo->writeFrame((uint8_t*)buf);
760
#else
761
UNUSED_PARAMETER(destFile);
762
UNUSED_PARAMETER(buf);
763
#endif
764
}
765
766
767
void
768
GUIViewTraffic::endSnapshot() {
769
#ifdef HAVE_FFMPEG
770
if (myCurrentVideo != nullptr) {
771
delete myCurrentVideo;
772
myCurrentVideo = nullptr;
773
}
774
#endif
775
}
776
777
778
void
779
GUIViewTraffic::checkSnapshots() {
780
#ifdef HAVE_FFMPEG
781
if (myCurrentVideo != nullptr) {
782
addSnapshot(getCurrentTimeStep() - DELTA_T, "");
783
}
784
#endif
785
GUISUMOAbstractView::checkSnapshots();
786
}
787
788
789
const std::vector<SUMOTime>
790
GUIViewTraffic::retrieveBreakpoints() const {
791
return myApp->retrieveBreakpoints();
792
}
793
794
795
void
796
GUIViewTraffic::drawPedestrianNetwork(const GUIVisualizationSettings& s) const {
797
GUIShapeContainer& shapeContainer = dynamic_cast<GUIShapeContainer&>(GUINet::getInstance()->getShapeContainer());
798
if (s.showPedestrianNetwork) {
799
shapeContainer.removeInactivePolygonTypes(std::set<std::string> {"jupedsim.pedestrian_network"});
800
} else {
801
shapeContainer.addInactivePolygonTypes(std::set<std::string> {"jupedsim.pedestrian_network"});
802
}
803
update();
804
}
805
806
807
void
808
GUIViewTraffic::changePedestrianNetworkColor(const GUIVisualizationSettings& s) const {
809
GUIShapeContainer& shapeContainer = dynamic_cast<GUIShapeContainer&>(GUINet::getInstance()->getShapeContainer());
810
for (auto polygonwithID : shapeContainer.getPolygons()) {
811
if (polygonwithID.second->getShapeType() == "jupedsim.pedestrian_network") {
812
polygonwithID.second->setShapeColor(s.pedestrianNetworkColor);
813
}
814
}
815
update();
816
}
817
818
/****************************************************************************/
819
820