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 6452 : GUIViewTraffic::GUIViewTraffic(
75 : FXComposite* p,
76 : GUIMainWindow& app,
77 : GUISUMOViewParent* parent,
78 : GUINet& net, FXGLVisual* glVis,
79 6452 : FXGLCanvas* share) :
80 : GUISUMOAbstractView(p, app, parent, net.getVisualisationSpeedUp(), glVis, share),
81 6452 : myTrackedID(GUIGlObject::INVALID_ID),
82 12904 : myTLSGame(OptionsCont::getOptions().getString("game.mode") == "tls")
83 : #ifdef HAVE_FFMPEG
84 6452 : , myCurrentVideo(nullptr)
85 : #endif
86 6452 : {}
87 :
88 :
89 12868 : GUIViewTraffic::~GUIViewTraffic() {
90 6434 : endSnapshot();
91 12868 : }
92 :
93 :
94 : void
95 6452 : GUIViewTraffic::buildViewToolBars(GUIGlChildWindow* v) {
96 : // build coloring tools
97 : {
98 6452 : const std::vector<std::string>& names = gSchemeStorage.getNames();
99 38744 : for (std::vector<std::string>::const_iterator i = names.begin(); i != names.end(); ++i) {
100 32292 : v->getColoringSchemesCombo()->appendIconItem(i->c_str());
101 32292 : if ((*i) == myVisualizationSettings->name) {
102 6452 : v->getColoringSchemesCombo()->setCurrentItem(v->getColoringSchemesCombo()->getNumItems() - 1);
103 : }
104 : }
105 : }
106 : // for junctions
107 19356 : new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
108 12904 : (std::string("\t") + TL("Locate Junctions") + std::string("\t") + TL("Locate a junction within the network.")).c_str(),
109 6452 : GUIIconSubSys::getIcon(GUIIcon::LOCATEJUNCTION), v, MID_HOTKEY_SHIFT_J_LOCATEJUNCTION,
110 6452 : GUIDesignButtonPopup);
111 : // for edges
112 19356 : new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
113 12904 : (std::string("\t") + TL("Locate Edges") + std::string("\t") + TL("Locate an edge within the network.")).c_str(),
114 6452 : GUIIconSubSys::getIcon(GUIIcon::LOCATEEDGE), v, MID_HOTKEY_SHIFT_E_LOCATEEDGE,
115 6452 : GUIDesignButtonPopup);
116 : // for vehicles
117 19356 : new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
118 12904 : (std::string("\t") + TL("Locate Vehicles") + std::string("\t") + TL("Locate a vehicle within the network.")).c_str(),
119 6452 : GUIIconSubSys::getIcon(GUIIcon::LOCATEVEHICLE), v, MID_HOTKEY_SHIFT_V_LOCATEVEHICLE,
120 6452 : GUIDesignButtonPopup);
121 : // for persons
122 19356 : new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
123 12904 : (std::string("\t") + TL("Locate Persons") + std::string("\t") + TL("Locate a person within the network.")).c_str(),
124 6452 : GUIIconSubSys::getIcon(GUIIcon::LOCATEPERSON), v, MID_HOTKEY_SHIFT_P_LOCATEPERSON,
125 6452 : GUIDesignButtonPopup);
126 : // for containers
127 19356 : new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
128 12904 : (std::string("\t") + TL("Locate Container") + std::string("\t") + TL("Locate a container within the network.")).c_str(),
129 6452 : GUIIconSubSys::getIcon(GUIIcon::LOCATECONTAINER), v, MID_HOTKEY_SHIFT_C_LOCATECONTAINER,
130 6452 : GUIDesignButtonPopup);
131 : // for tls
132 19356 : new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
133 12904 : (std::string("\t") + TL("Locate TLS") + std::string("\t") + TL("Locate a tls within the network.")).c_str(),
134 6452 : GUIIconSubSys::getIcon(GUIIcon::LOCATETLS), v, MID_HOTKEY_SHIFT_T_LOCATETLS,
135 6452 : GUIDesignButtonPopup);
136 : // for additional stuff
137 19356 : new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
138 12904 : (std::string("\t") + TL("Locate Additional") + std::string("\t") + TL("Locate an additional structure within the network.")).c_str(),
139 6452 : GUIIconSubSys::getIcon(GUIIcon::LOCATEADD), v, MID_HOTKEY_SHIFT_A_LOCATEADDITIONAL,
140 6452 : GUIDesignButtonPopup);
141 : // for pois
142 19356 : new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
143 12904 : (std::string("\t") + TL("Locate PoI") + std::string("\t") + TL("Locate a PoI within the network.")).c_str(),
144 6452 : GUIIconSubSys::getIcon(GUIIcon::LOCATEPOI), v, MID_HOTKEY_SHIFT_O_LOCATEPOI,
145 6452 : GUIDesignButtonPopup);
146 : // for polygons
147 19356 : new MFXButtonTooltip(v->getLocatorPopup(), myApp->getStaticTooltipMenu(),
148 12904 : (std::string("\t") + TL("Locate Polygon") + std::string("\t") + TL("Locate a Polygon within the network.")).c_str(),
149 6452 : GUIIconSubSys::getIcon(GUIIcon::LOCATEPOLY), v, MID_HOTKEY_SHIFT_L_LOCATEPOLY,
150 6452 : GUIDesignButtonPopup);
151 6452 : }
152 :
153 :
154 : bool
155 49 : GUIViewTraffic::setColorScheme(const std::string& name) {
156 49 : if (!gSchemeStorage.contains(name)) {
157 : return false;
158 : }
159 43 : if (myGUIDialogViewSettings != nullptr) {
160 0 : if (myGUIDialogViewSettings->getCurrentScheme() != name) {
161 0 : myGUIDialogViewSettings->setCurrentScheme(name);
162 : }
163 : }
164 43 : myVisualizationSettings = &gSchemeStorage.get(name.c_str());
165 43 : myVisualizationSettings->gaming = myApp->isGaming();
166 43 : update();
167 43 : return true;
168 : }
169 :
170 :
171 : void
172 0 : GUIViewTraffic::buildColorRainbow(const GUIVisualizationSettings& s, GUIColorScheme& scheme, int active, GUIGlObjectType objectType,
173 : bool hide, double hideThreshold, bool hide2, double hideThreshold2) {
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 :
240 0 : if (hide && hide2 && minValue == std::numeric_limits<double>::infinity()) {
241 : minValue = hideThreshold;
242 : maxValue = hideThreshold2;
243 : }
244 0 : if (minValue != std::numeric_limits<double>::infinity()) {
245 0 : scheme.clear();
246 : // add new thresholds
247 0 : if (scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_EDGEDATA_NUMERICAL
248 0 : || scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_EDGE_PARAM_NUMERICAL
249 0 : || scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_LANE_PARAM_NUMERICAL
250 0 : || scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_DATA_ATTRIBUTE_NUMERICAL
251 0 : || scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_PARAM_NUMERICAL
252 0 : || hasMissingData) {
253 0 : scheme.addColor(s.COL_MISSING_DATA, s.MISSING_DATA, "missing data");
254 : }
255 0 : if (hide) {
256 0 : const double rawRange = maxValue - minValue;
257 0 : minValue = MAX2(hideThreshold + MIN2(1.0, rawRange / 100.0), minValue);
258 0 : scheme.addColor(RGBColor(204, 204, 204), hideThreshold);
259 : }
260 0 : if (hide2) {
261 0 : const double rawRange = maxValue - minValue;
262 0 : maxValue = MIN2(hideThreshold2 - MIN2(1.0, rawRange / 100.0), maxValue);
263 0 : scheme.addColor(RGBColor(204, 204, 204), hideThreshold2);
264 : }
265 0 : double range = maxValue - minValue;
266 0 : scheme.addColor(RGBColor::RED, (minValue));
267 0 : scheme.addColor(RGBColor::ORANGE, (minValue + range * 1 / 6.0));
268 0 : scheme.addColor(RGBColor::YELLOW, (minValue + range * 2 / 6.0));
269 0 : scheme.addColor(RGBColor::GREEN, (minValue + range * 3 / 6.0));
270 0 : scheme.addColor(RGBColor::CYAN, (minValue + range * 4 / 6.0));
271 0 : scheme.addColor(RGBColor::BLUE, (minValue + range * 5 / 6.0));
272 0 : scheme.addColor(RGBColor::MAGENTA, (maxValue));
273 : }
274 : }
275 :
276 :
277 : std::vector<std::string>
278 0 : GUIViewTraffic::getEdgeDataAttrs() const {
279 0 : if (GUINet::getGUIInstance() != nullptr) {
280 0 : return GUINet::getGUIInstance()->getEdgeDataAttrs();
281 : }
282 0 : return std::vector<std::string>();
283 : }
284 :
285 :
286 : std::vector<std::string>
287 0 : GUIViewTraffic::getMeanDataIDs() const {
288 0 : if (GUINet::getGUIInstance() != nullptr) {
289 0 : return GUINet::getGUIInstance()->getMeanDataIDs();
290 : }
291 0 : return std::vector<std::string>();
292 : }
293 :
294 : std::vector<std::string>
295 0 : GUIViewTraffic::getMeanDataAttrs(const std::string& meanDataID) const {
296 0 : if (GUINet::getGUIInstance() != nullptr) {
297 0 : return GUINet::getGUIInstance()->getMeanDataAttrs(meanDataID);
298 : }
299 0 : return std::vector<std::string>();
300 : }
301 :
302 :
303 : std::vector<std::string>
304 0 : GUIViewTraffic::getEdgeLaneParamKeys(bool edgeKeys) const {
305 : std::set<std::string> keys;
306 0 : for (const MSEdge* e : MSEdge::getAllEdges()) {
307 0 : if (edgeKeys) {
308 0 : for (const auto& item : e->getParametersMap()) {
309 0 : keys.insert(item.first);
310 : }
311 : } else {
312 0 : for (const auto lane : e->getLanes()) {
313 0 : for (const auto& item : lane->getParametersMap()) {
314 0 : keys.insert(item.first);
315 : }
316 : }
317 : }
318 : }
319 0 : return std::vector<std::string>(keys.begin(), keys.end());
320 : }
321 :
322 :
323 : std::vector<std::string>
324 0 : GUIViewTraffic::getVehicleParamKeys(bool /*vTypeKeys*/) const {
325 : std::set<std::string> keys;
326 0 : GUIVehicleControl* vc = GUINet::getGUIInstance()->getGUIVehicleControl();
327 0 : vc->secureVehicles();
328 0 : for (auto vehIt = vc->loadedVehBegin(); vehIt != vc->loadedVehEnd(); ++vehIt) {
329 0 : for (auto kv : vehIt->second->getParameter().getParametersMap()) {
330 : keys.insert(kv.first);
331 0 : }
332 : }
333 0 : vc->releaseVehicles();
334 0 : return std::vector<std::string>(keys.begin(), keys.end());
335 : }
336 :
337 : std::vector<std::string>
338 0 : GUIViewTraffic::getPOIParamKeys() const {
339 : std::set<std::string> keys;
340 0 : const ShapeContainer::POIs& pois = static_cast<ShapeContainer&>(GUINet::getInstance()->getShapeContainer()).getPOIs();
341 0 : for (auto item : pois) {
342 0 : for (auto kv : item.second->getParametersMap()) {
343 : keys.insert(kv.first);
344 0 : }
345 : }
346 0 : return std::vector<std::string>(keys.begin(), keys.end());
347 : }
348 :
349 : int
350 473247 : GUIViewTraffic::doPaintGL(int mode, const Boundary& bound) {
351 : // init view settings
352 473247 : glRenderMode(mode);
353 473247 : glMatrixMode(GL_MODELVIEW);
354 473247 : GLHelper::pushMatrix();
355 473247 : glDisable(GL_TEXTURE_2D);
356 473247 : glDisable(GL_ALPHA_TEST);
357 473247 : glEnable(GL_BLEND);
358 473247 : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
359 473247 : glEnable(GL_DEPTH_TEST);
360 :
361 : // draw decals (if not in grabbing mode)
362 473247 : drawDecals();
363 473247 : myVisualizationSettings->scale = m2p(SUMO_const_laneWidth);
364 473247 : if (myVisualizationSettings->showGrid) {
365 0 : paintGLGrid();
366 : }
367 473247 : glLineWidth(1);
368 473247 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
369 473247 : const float minB[2] = { (float)bound.xmin(), (float)bound.ymin() };
370 473247 : const float maxB[2] = { (float)bound.xmax(), (float)bound.ymax() };
371 473247 : glEnable(GL_POLYGON_OFFSET_FILL);
372 473247 : glEnable(GL_POLYGON_OFFSET_LINE);
373 473247 : const SUMORTree& grid = GUINet::getGUIInstance()->getVisualisationSpeedUp(myVisualizationSettings->secondaryShape);
374 473247 : int hits2 = grid.Search(minB, maxB, *myVisualizationSettings);
375 473247 : GUIGlobals::gSecondaryShape = myVisualizationSettings->secondaryShape;
376 : // Draw additional objects
377 473247 : if (myAdditionallyDrawn.size() > 0) {
378 2 : glTranslated(0, 0, -.01);
379 2 : GUINet::getGUIInstance()->lock();
380 4 : for (auto i : myAdditionallyDrawn) {
381 2 : i.first->drawGLAdditional(this, *myVisualizationSettings);
382 : }
383 2 : GUINet::getGUIInstance()->unlock();
384 2 : glTranslated(0, 0, .01);
385 : }
386 473247 : GLHelper::popMatrix();
387 : /*
388 : // draw legends
389 : glMatrixMode(GL_MODELVIEW);
390 : glLoadIdentity();
391 : glTranslated(1.-.2, 1.-.5, 0.);
392 : glScaled(.2, .5, 1.);
393 : GUIColoringSchemesMap<GUILane> &sm = GUIViewTraffic::getLaneSchemesMap(); //!!!
394 : sm.getColorer(myVisualizationSettings->laneEdgeMode)->drawLegend();
395 : */
396 473247 : return hits2;
397 : }
398 :
399 :
400 : void
401 4 : GUIViewTraffic::startTrack(int id) {
402 4 : myTrackedID = id;
403 4 : GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
404 4 : if (o != nullptr) {
405 4 : GUIBaseVehicle* v = dynamic_cast<GUIBaseVehicle*>(o);
406 4 : if (v != nullptr) {
407 4 : v->addActiveAddVisualisation(this, GUIBaseVehicle::VO_TRACK);
408 : }
409 : }
410 4 : }
411 :
412 :
413 : void
414 4 : GUIViewTraffic::stopTrack() {
415 4 : myTrackedID = GUIGlObject::INVALID_ID;
416 4 : }
417 :
418 :
419 : GUIGlID
420 1051079 : GUIViewTraffic::getTrackedID() const {
421 1051079 : return myTrackedID;
422 : }
423 :
424 :
425 : void
426 0 : GUIViewTraffic::onGamingClick(Position pos) {
427 0 : if (myTLSGame) {
428 0 : MSTLLogicControl& tlsControl = MSNet::getInstance()->getTLSControl();
429 : MSTrafficLightLogic* minTll = nullptr;
430 : double minDist = 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 : }
444 0 : if (minTll != nullptr) {
445 0 : if (minTll->getPhaseNumber() == 0) {
446 : // MSRailSignal
447 : return;
448 : }
449 0 : const int ci = minTll->getCurrentPhaseIndex();
450 0 : const int n = minTll->getPhaseNumber();
451 : int greenCount = 0;
452 0 : for (auto& phase : minTll->getPhases()) {
453 0 : if (phase->isGreenPhase()) {
454 0 : greenCount++;
455 : }
456 : }
457 0 : int nextPhase = (ci + 1) % n;
458 : SUMOTime nextDuration = 0;
459 0 : if (minTll->getCurrentPhaseDef().isGreenPhase() || (greenCount == 1 && minTll->getCurrentPhaseDef().isAllRedPhase())) {
460 0 : nextDuration = minTll->getPhase(nextPhase).duration;
461 : } else {
462 : // we are in transition to a green phase
463 : // -> skip forward to the transition into the next green phase
464 : // but ensure that the total transition time is maintained
465 : // taking into account how much time was already spent
466 0 : SUMOTime spentTransition = minTll->getSpentDuration();
467 : // the transition may consist of more than one phase so we
468 : // search backwards until the prior green phase
469 0 : for (int i = ci - 1; i != ci; i--) {
470 0 : if (i < 0) {
471 0 : i = n - 1;
472 : }
473 0 : if (minTll->getPhase(i).isGreenPhase()) {
474 : break;
475 : }
476 0 : spentTransition += minTll->getPhase(i).duration;
477 : }
478 : // now we skip past the next greenphase
479 : int numGreen = 0;
480 : int i = nextPhase;
481 0 : for (; numGreen < 2; i = (i + 1) % n) {
482 0 : if (minTll->getPhase(i).isGreenPhase()) {
483 0 : numGreen++;
484 0 : continue;
485 : }
486 : // transition after the next green
487 0 : if (numGreen == 1) {
488 0 : SUMOTime dur = minTll->getPhase(i).duration;
489 0 : if (dur <= spentTransition) {
490 0 : spentTransition -= dur;
491 : } else {
492 : nextPhase = i;
493 0 : nextDuration = dur - spentTransition;
494 0 : break;
495 : }
496 : }
497 : }
498 : }
499 0 : minTll->changeStepAndDuration(tlsControl, MSNet::getInstance()->getCurrentTimeStep(), nextPhase, nextDuration);
500 0 : update();
501 : }
502 : } else {
503 : // DRT game
504 0 : if (MSGlobals::gUseMesoSim) {
505 : return;
506 : }
507 0 : const std::set<GUIGlID>& sel = gSelected.getSelected(GLO_VEHICLE);
508 0 : if (sel.size() == 0) {
509 : // find closest pt vehicle
510 : double minDist = std::numeric_limits<double>::infinity();
511 : GUIVehicle* closest = nullptr;
512 0 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
513 : MSVehicleControl::constVehIt it = vc.loadedVehBegin();
514 : MSVehicleControl::constVehIt end = vc.loadedVehEnd();
515 0 : for (it = vc.loadedVehBegin(); it != end; ++it) {
516 0 : GUIVehicle* veh = dynamic_cast<GUIVehicle*>(it->second);
517 : assert(veh != 0);
518 0 : if (veh->getParameter().line != "") {
519 0 : const double dist = veh->getPosition().distanceTo2D(pos);
520 0 : if (dist < minDist) {
521 : minDist = dist;
522 : closest = veh;
523 : }
524 : }
525 : }
526 0 : if (closest != nullptr) {
527 0 : gSelected.select(closest->getGlID());
528 0 : closest->addActiveAddVisualisation(this, GUIBaseVehicle::VO_SHOW_FUTURE_ROUTE);
529 : }
530 : } else {
531 : // find closest pt stop
532 : double minDist = std::numeric_limits<double>::infinity();
533 : MSStoppingPlace* closestStop = nullptr;
534 0 : const NamedObjectCont<MSStoppingPlace*>& stops = MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_BUS_STOP);
535 0 : for (auto it = stops.begin(); it != stops.end(); ++it) {
536 0 : MSStoppingPlace* stop = it->second;
537 0 : const double dist = pos.distanceTo2D(stop->getLane().geometryPositionAtOffset(stop->getEndLanePosition()));
538 0 : if (dist < minDist) {
539 : minDist = dist;
540 : closestStop = stop;
541 : }
542 : }
543 0 : if (closestStop != 0) {
544 0 : GUIGlID id = *sel.begin();
545 0 : GUIVehicle* veh = dynamic_cast<GUIVehicle*>(GUIGlObjectStorage::gIDStorage.getObjectBlocking(id));
546 : assert(veh != 0);
547 : MSLane* lane = veh->getMutableLane();
548 0 : lane->getVehiclesSecure();
549 0 : veh->rerouteDRTStop(closestStop);
550 0 : GUIGlObjectStorage::gIDStorage.unblockObject(id);
551 0 : lane->releaseVehicles();
552 : }
553 : }
554 : }
555 : }
556 :
557 :
558 : void
559 0 : GUIViewTraffic::onGamingRightClick(Position /*pos*/) {
560 0 : const std::set<GUIGlID>& sel = gSelected.getSelected(GLO_VEHICLE);
561 0 : if (sel.size() > 0) {
562 0 : GUIGlID id = *sel.begin();
563 0 : GUIVehicle* veh = dynamic_cast<GUIVehicle*>(GUIGlObjectStorage::gIDStorage.getObjectBlocking(id));
564 0 : if (veh != 0) {
565 0 : veh->removeActiveAddVisualisation(this, GUIBaseVehicle::VO_SHOW_FUTURE_ROUTE);
566 : }
567 0 : GUIGlObjectStorage::gIDStorage.unblockObject(id);
568 : }
569 0 : gSelected.clear();
570 0 : }
571 :
572 :
573 : SUMOTime
574 5026470 : GUIViewTraffic::getCurrentTimeStep() const {
575 5026470 : return MSNet::getInstance()->getCurrentTimeStep();
576 : }
577 :
578 :
579 : long
580 0 : GUIViewTraffic::onCmdCloseLane(FXObject*, FXSelector, void*) {
581 0 : GUILane* lane = getLaneUnderCursor();
582 0 : if (lane != nullptr) {
583 0 : lane->closeTraffic();
584 0 : GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
585 0 : update();
586 : }
587 0 : return 1;
588 : }
589 :
590 :
591 : long
592 0 : GUIViewTraffic::onCmdCloseEdge(FXObject*, FXSelector, void*) {
593 0 : GUILane* lane = getLaneUnderCursor();
594 0 : if (lane != nullptr) {
595 0 : dynamic_cast<GUIEdge*>(&lane->getEdge())->closeTraffic(lane);
596 0 : GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
597 0 : update();
598 : }
599 0 : return 1;
600 : }
601 :
602 :
603 : long
604 0 : GUIViewTraffic::onCmdAddRerouter(FXObject*, FXSelector, void*) {
605 0 : GUILane* lane = getLaneUnderCursor();
606 0 : if (lane != nullptr) {
607 0 : dynamic_cast<GUIEdge*>(&lane->getEdge())->addRerouter();
608 0 : GUIGlObjectStorage::gIDStorage.unblockObject(lane->getGlID());
609 0 : update();
610 : }
611 0 : return 1;
612 : }
613 :
614 :
615 : long
616 0 : GUIViewTraffic::showLaneReachability(GUILane* lane, FXObject* menu, FXSelector) {
617 0 : if (lane != nullptr) {
618 : // reset
619 : const double UNREACHED = INVALID_DOUBLE;
620 0 : gSelected.clear();
621 0 : for (const MSEdge* const e : MSEdge::getAllEdges()) {
622 0 : for (MSLane* const l : e->getLanes()) {
623 0 : GUILane* gLane = dynamic_cast<GUILane*>(l);
624 : gLane->setReachability(UNREACHED);
625 : }
626 : }
627 : // prepare
628 0 : FXMenuCommand* mc = dynamic_cast<FXMenuCommand*>(menu);
629 0 : const SUMOVehicleClass svc = SumoVehicleClassStrings.get(mc->getText().text());
630 0 : const double defaultMaxSpeed = SUMOVTypeParameter::VClassDefaultValues(svc).maxSpeed;
631 : // find reachable
632 : std::map<MSEdge*, double> reachableEdges;
633 0 : reachableEdges[&lane->getEdge()] = 0;
634 : MSEdgeVector check;
635 0 : check.push_back(&lane->getEdge());
636 0 : while (check.size() > 0) {
637 0 : MSEdge* e = check.front();
638 : check.erase(check.begin());
639 0 : double traveltime = reachableEdges[e];
640 0 : for (MSLane* const l : e->getLanes()) {
641 0 : if (l->allowsVehicleClass(svc)) {
642 0 : GUILane* gLane = dynamic_cast<GUILane*>(l);
643 0 : gSelected.select(gLane->getGlID(), false);
644 : gLane->setReachability(traveltime);
645 : }
646 : }
647 0 : const double dt = e->getLength() / MIN2(e->getSpeedLimit(), defaultMaxSpeed);
648 : // ensure algorithm termination
649 0 : traveltime += MAX2(dt, NUMERICAL_EPS);
650 0 : for (MSEdge* const nextEdge : e->getSuccessors(svc)) {
651 0 : if (reachableEdges.count(nextEdge) == 0 ||
652 : // revisit edge via faster path
653 0 : reachableEdges[nextEdge] > traveltime) {
654 0 : reachableEdges[nextEdge] = traveltime;
655 0 : check.push_back(nextEdge);
656 : }
657 : }
658 0 : if (svc == SVC_PEDESTRIAN) {
659 : // can also walk backwards
660 0 : for (MSEdge* const prevEdge : e->getPredecessors()) {
661 0 : if (prevEdge->allowedLanes(*e, svc) != nullptr &&
662 0 : (reachableEdges.count(prevEdge) == 0 ||
663 : // revisit edge via faster path
664 0 : reachableEdges[prevEdge] > traveltime)) {
665 0 : reachableEdges[prevEdge] = traveltime;
666 0 : check.push_back(prevEdge);
667 : }
668 : }
669 : }
670 : }
671 0 : gSelected.notifyChanged();
672 : }
673 0 : return 1;
674 : }
675 :
676 :
677 : long
678 0 : GUIViewTraffic::onCmdShowReachability(FXObject* menu, FXSelector selector, void*) {
679 0 : GUILane* lane = getLaneUnderCursor();
680 0 : if (lane != nullptr) {
681 : // reset
682 0 : showLaneReachability(lane, menu, selector);
683 : // switch to 'color by selection' unless coloring 'by reachability'
684 0 : if (myVisualizationSettings->laneColorer.getActive() != 36) {
685 : myVisualizationSettings->laneColorer.setActive(1);
686 : }
687 0 : update();
688 : }
689 0 : return 1;
690 : }
691 :
692 :
693 : GUILane*
694 0 : GUIViewTraffic::getLaneUnderCursor() {
695 0 : if (makeCurrent()) {
696 0 : int id = getObjectUnderCursor();
697 0 : if (id != 0) {
698 0 : GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
699 0 : if (o != nullptr) {
700 0 : return dynamic_cast<GUILane*>(o);
701 : }
702 : }
703 0 : makeNonCurrent();
704 : }
705 : return nullptr;
706 : }
707 :
708 :
709 : long
710 0 : GUIViewTraffic::onDoubleClicked(FXObject*, FXSelector, void*) {
711 : // leave fullscreen mode
712 0 : if (myApp->isFullScreen()) {
713 0 : myApp->onCmdFullScreen(nullptr, 0, nullptr);
714 : } else {
715 0 : stopTrack();
716 : }
717 0 : return 1;
718 : }
719 :
720 :
721 :
722 : void
723 0 : GUIViewTraffic::saveFrame(const std::string& destFile, FXColor* buf) {
724 : #ifdef HAVE_FFMPEG
725 0 : if (myCurrentVideo == nullptr) {
726 0 : myCurrentVideo = new GUIVideoEncoder(destFile.c_str(), getWidth(), getHeight(), myApp->getDelay());
727 : }
728 0 : myCurrentVideo->writeFrame((uint8_t*)buf);
729 : #else
730 : UNUSED_PARAMETER(destFile);
731 : UNUSED_PARAMETER(buf);
732 : #endif
733 0 : }
734 :
735 :
736 : void
737 6434 : GUIViewTraffic::endSnapshot() {
738 : #ifdef HAVE_FFMPEG
739 6434 : if (myCurrentVideo != nullptr) {
740 0 : delete myCurrentVideo;
741 0 : myCurrentVideo = nullptr;
742 : }
743 : #endif
744 6434 : }
745 :
746 :
747 : void
748 5026470 : GUIViewTraffic::checkSnapshots() {
749 : #ifdef HAVE_FFMPEG
750 5026470 : if (myCurrentVideo != nullptr) {
751 0 : addSnapshot(getCurrentTimeStep() - DELTA_T, "");
752 : }
753 : #endif
754 5026470 : GUISUMOAbstractView::checkSnapshots();
755 5026470 : }
756 :
757 :
758 : const std::vector<SUMOTime>
759 0 : GUIViewTraffic::retrieveBreakpoints() const {
760 0 : return myApp->retrieveBreakpoints();
761 : }
762 :
763 :
764 : void
765 0 : GUIViewTraffic::drawPedestrianNetwork(const GUIVisualizationSettings& s) const {
766 0 : GUIShapeContainer& shapeContainer = dynamic_cast<GUIShapeContainer&>(GUINet::getInstance()->getShapeContainer());
767 0 : if (s.showPedestrianNetwork) {
768 0 : shapeContainer.removeInactivePolygonTypes(std::set<std::string> {"jupedsim.pedestrian_network"});
769 : } else {
770 0 : shapeContainer.addInactivePolygonTypes(std::set<std::string> {"jupedsim.pedestrian_network"});
771 : }
772 0 : update();
773 0 : }
774 :
775 :
776 : void
777 0 : GUIViewTraffic::changePedestrianNetworkColor(const GUIVisualizationSettings& s) const {
778 0 : GUIShapeContainer& shapeContainer = dynamic_cast<GUIShapeContainer&>(GUINet::getInstance()->getShapeContainer());
779 0 : for (auto polygonwithID : shapeContainer.getPolygons()) {
780 0 : if (polygonwithID.second->getShapeType() == "jupedsim.pedestrian_network") {
781 0 : polygonwithID.second->setShapeColor(s.pedestrianNetworkColor);
782 : }
783 : }
784 0 : update();
785 0 : }
786 :
787 : /****************************************************************************/
|