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