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