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