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 GUISUMOAbstractView.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Laura Bieker
19 : /// @author Andreas Gaubatz
20 : /// @date Sept 2002
21 : ///
22 : // The base class for a view
23 : /****************************************************************************/
24 : #include <config.h>
25 :
26 : #include <iostream>
27 : #include <utility>
28 : #include <cmath>
29 : #include <cassert>
30 : #include <limits>
31 : #include <fxkeys.h>
32 : #ifdef HAVE_GL2PS
33 : #include <gl2ps.h>
34 : #endif
35 : #include <utils/foxtools/MFXSingleEventThread.h>
36 : #include <utils/foxtools/MFXCheckableButton.h>
37 : #include <utils/foxtools/MFXImageHelper.h>
38 : #include <utils/common/RGBColor.h>
39 : #include <utils/common/ToString.h>
40 : #include <utils/common/StringUtils.h>
41 : #include <utils/common/MsgHandler.h>
42 : #include <utils/common/SysUtils.h>
43 : #include <utils/gui/windows/GUIAppEnum.h>
44 : #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
45 : #include <utils/gui/globjects/GUICursorDialog.h>
46 : #include <utils/gui/images/GUITexturesHelper.h>
47 : #include <utils/gui/div/GUIGlobalSelection.h>
48 : #include <utils/gui/div/GLHelper.h>
49 : #include <utils/gui/globjects/GUIGlObjectStorage.h>
50 : #include <utils/gui/globjects/GUIGlObject.h>
51 : #include <utils/shapes/PointOfInterest.h>
52 : #include <utils/gui/globjects/GUIPointOfInterest.h>
53 : #include <utils/gui/globjects/GUIPolygon.h>
54 : #include <utils/gui/windows/GUIDialog_ViewSettings.h>
55 : #include <utils/geom/GeoConvHelper.h>
56 : #include <utils/geom/GeomHelper.h>
57 : #include <utils/gui/settings/GUICompleteSchemeStorage.h>
58 : #include <utils/gui/globjects/GLIncludes.h>
59 : #include <utils/gui/settings/GUIVisualizationSettings.h>
60 : #include <foreign/fontstash/fontstash.h>
61 : #include <utils/gui/cursors/GUICursorSubSys.h>
62 : #include <utils/options/OptionsCont.h>
63 :
64 : #include <unordered_set>
65 :
66 : #include "GUISUMOAbstractView.h"
67 : #include "GUIMainWindow.h"
68 : #include "GUIGlChildWindow.h"
69 : #include "GUIDanielPerspectiveChanger.h"
70 : #include "GUIDialog_EditViewport.h"
71 :
72 : #ifdef HAVE_GDAL
73 : #ifdef _MSC_VER
74 : #pragma warning(push)
75 : #pragma warning(disable: 4435 5219 5220)
76 : #endif
77 : #if __GNUC__ > 3
78 : #pragma GCC diagnostic push
79 : #pragma GCC diagnostic ignored "-Wpedantic"
80 : #endif
81 : #include <gdal_priv.h>
82 : #if __GNUC__ > 3
83 : #pragma GCC diagnostic pop
84 : #endif
85 : #ifdef _MSC_VER
86 : #pragma warning(pop)
87 : #endif
88 : #endif
89 :
90 :
91 : // ===========================================================================
92 : // debug constants
93 : // ===========================================================================
94 : //#define DEBUG_SNAPSHOT
95 :
96 : // ===========================================================================
97 : // static members
98 : // ===========================================================================
99 :
100 : const double GUISUMOAbstractView::SENSITIVITY = 0.1; // meters
101 :
102 :
103 : // ===========================================================================
104 : // member method definitions
105 : // ===========================================================================
106 : /* -------------------------------------------------------------------------
107 : * GUISUMOAbstractView - FOX callback mapping
108 : * ----------------------------------------------------------------------- */
109 : FXDEFMAP(GUISUMOAbstractView) GUISUMOAbstractViewMap[] = {
110 : FXMAPFUNC(SEL_CONFIGURE, 0, GUISUMOAbstractView::onConfigure),
111 : FXMAPFUNC(SEL_PAINT, 0, GUISUMOAbstractView::onPaint),
112 : FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, GUISUMOAbstractView::onLeftBtnPress),
113 : FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, GUISUMOAbstractView::onLeftBtnRelease),
114 : FXMAPFUNC(SEL_MIDDLEBUTTONPRESS, 0, GUISUMOAbstractView::onMiddleBtnPress),
115 : FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE, 0, GUISUMOAbstractView::onMiddleBtnRelease),
116 : FXMAPFUNC(SEL_RIGHTBUTTONPRESS, 0, GUISUMOAbstractView::onRightBtnPress),
117 : FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, 0, GUISUMOAbstractView::onRightBtnRelease),
118 : FXMAPFUNC(SEL_DOUBLECLICKED, 0, GUISUMOAbstractView::onDoubleClicked),
119 : FXMAPFUNC(SEL_MOUSEWHEEL, 0, GUISUMOAbstractView::onMouseWheel),
120 : FXMAPFUNC(SEL_MOTION, 0, GUISUMOAbstractView::onMouseMove),
121 : FXMAPFUNC(SEL_LEAVE, 0, GUISUMOAbstractView::onMouseLeft),
122 : FXMAPFUNC(SEL_KEYPRESS, 0, GUISUMOAbstractView::onKeyPress),
123 : FXMAPFUNC(SEL_KEYRELEASE, 0, GUISUMOAbstractView::onKeyRelease),
124 : FXMAPFUNC(SEL_COMMAND, MID_CLOSE_LANE, GUISUMOAbstractView::onCmdCloseLane),
125 : FXMAPFUNC(SEL_COMMAND, MID_CLOSE_EDGE, GUISUMOAbstractView::onCmdCloseEdge),
126 : FXMAPFUNC(SEL_COMMAND, MID_ADD_REROUTER, GUISUMOAbstractView::onCmdAddRerouter),
127 : FXMAPFUNC(SEL_COMMAND, MID_REACHABILITY, GUISUMOAbstractView::onCmdShowReachability),
128 : FXMAPFUNC(SEL_COMMAND, MID_REACHABILITY, GUISUMOAbstractView::onCmdShowReachability),
129 : FXMAPFUNC(SEL_CHANGED, MID_SIMPLE_VIEW_COLORCHANGE, GUISUMOAbstractView::onVisualizationChange),
130 : };
131 :
132 :
133 1783307 : FXIMPLEMENT_ABSTRACT(GUISUMOAbstractView, FXGLCanvas, GUISUMOAbstractViewMap, ARRAYNUMBER(GUISUMOAbstractViewMap))
134 :
135 :
136 : /* -------------------------------------------------------------------------
137 : * GUISUMOAbstractView - methods
138 : * ----------------------------------------------------------------------- */
139 6836 : GUISUMOAbstractView::GUISUMOAbstractView(FXComposite* p, GUIMainWindow& app, GUIGlChildWindow* parent, const SUMORTree& grid, FXGLVisual* glVis, FXGLCanvas* share) :
140 : FXGLCanvas(p, glVis, share, p, MID_GLCANVAS, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0),
141 6836 : myApp(&app),
142 6836 : myGlChildWindowParent(parent),
143 6836 : myGrid(&grid),
144 6836 : myMouseHotspotX(app.getDefaultCursor()->getHotX()),
145 6836 : myMouseHotspotY(app.getDefaultCursor()->getHotY()),
146 6836 : myWindowCursorPositionX(getWidth() / 2),
147 6836 : myWindowCursorPositionY(getHeight() / 2) {
148 6836 : setTarget(this);
149 6836 : enable();
150 6836 : flags |= FLAG_ENABLED;
151 6836 : myChanger = new GUIDanielPerspectiveChanger(*this, *myGrid);
152 6836 : myVisualizationSettings = &gSchemeStorage.getDefault();
153 6836 : myVisualizationSettings->gaming = myApp->isGaming();
154 6836 : gSchemeStorage.setViewport(this);
155 6836 : myDecals = gSchemeStorage.getDecals();
156 6836 : }
157 :
158 :
159 6820 : GUISUMOAbstractView::~GUISUMOAbstractView() {
160 6820 : gSchemeStorage.setDefault(myVisualizationSettings->name);
161 6820 : gSchemeStorage.saveViewport(myChanger->getXPos(), myChanger->getYPos(), myChanger->getZPos(), myChanger->getRotation());
162 6820 : gSchemeStorage.saveDecals(myDecals);
163 6820 : delete myPopup;
164 6820 : delete myChanger;
165 6820 : delete myGUIDialogEditViewport;
166 6820 : delete myGUIDialogViewSettings;
167 : // cleanup decals
168 6827 : for (auto& decal : myDecals) {
169 7 : delete decal.image;
170 : }
171 : // remove all elements
172 6820 : for (auto& additional : myAdditionallyDrawn) {
173 0 : additional.first->removeActiveAddVisualisation(this, ~0);
174 : }
175 20460 : }
176 :
177 :
178 : bool
179 0 : GUISUMOAbstractView::isInEditMode() {
180 0 : return myInEditMode;
181 : }
182 :
183 :
184 : GUIPerspectiveChanger&
185 42 : GUISUMOAbstractView::getChanger() const {
186 42 : return *myChanger;
187 : }
188 :
189 :
190 : void
191 0 : GUISUMOAbstractView::updateToolTip() {
192 0 : if (myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->isStaticToolTipEnabled()) {
193 0 : update();
194 : }
195 0 : }
196 :
197 :
198 : Position
199 580 : GUISUMOAbstractView::getPositionInformation() const {
200 580 : return screenPos2NetPos(myWindowCursorPositionX, myWindowCursorPositionY);
201 : }
202 :
203 :
204 : Position
205 0 : GUISUMOAbstractView::snapToActiveGrid(const Position& pos, bool snapXY) const {
206 0 : Position result = pos;
207 0 : if (myVisualizationSettings->showGrid) {
208 0 : if (snapXY) {
209 0 : const double xRest = std::fmod(pos.x(), myVisualizationSettings->gridXSize) + (pos.x() < 0 ? myVisualizationSettings->gridXSize : 0);
210 0 : const double yRest = std::fmod(pos.y(), myVisualizationSettings->gridYSize) + (pos.y() < 0 ? myVisualizationSettings->gridYSize : 0);
211 0 : result.setx(pos.x() - xRest + (xRest < myVisualizationSettings->gridXSize * 0.5 ? 0 : myVisualizationSettings->gridXSize));
212 0 : result.sety(pos.y() - yRest + (yRest < myVisualizationSettings->gridYSize * 0.5 ? 0 : myVisualizationSettings->gridYSize));
213 : } else {
214 : // snapZToActiveGrid uses grid Y Size
215 0 : const double zRest = std::fmod(pos.z(), myVisualizationSettings->gridYSize) + (pos.z() < 0 ? myVisualizationSettings->gridYSize : 0);
216 0 : result.setz(pos.z() - zRest + (zRest < myVisualizationSettings->gridYSize * 0.5 ? 0 : myVisualizationSettings->gridYSize));
217 : }
218 : }
219 0 : return result;
220 : }
221 :
222 :
223 : Position
224 580 : GUISUMOAbstractView::screenPos2NetPos(int x, int y) const {
225 580 : Boundary bound = myChanger->getViewport();
226 580 : double xNet = bound.xmin() + bound.getWidth() * x / getWidth();
227 : // cursor origin is in the top-left corner
228 580 : double yNet = bound.ymin() + bound.getHeight() * (getHeight() - y) / getHeight();
229 : // rotate around the viewport center
230 580 : if (myChanger->getRotation() != 0) {
231 0 : return Position(xNet, yNet).rotateAround2D(-DEG2RAD(myChanger->getRotation()), bound.getCenter());
232 : } else {
233 : return Position(xNet, yNet);
234 : }
235 580 : }
236 :
237 :
238 : void
239 37 : GUISUMOAbstractView::addDecals(const std::vector<Decal>& decals) {
240 37 : myDecals.insert(myDecals.end(), decals.begin(), decals.end());
241 37 : }
242 :
243 :
244 : void
245 580 : GUISUMOAbstractView::updatePositionInformationLabel() const {
246 580 : Position pos = getPositionInformation();
247 : // set cartesian position
248 1160 : myApp->getCartesianLabel()->setText(("x:" + toString(pos.x()) + ", y:" + toString(pos.y())).c_str());
249 : // set geo position
250 580 : GeoConvHelper::getFinal().cartesian2geo(pos);
251 580 : if (GeoConvHelper::getFinal().usingGeoProjection()) {
252 0 : myApp->getGeoLabel()->setText(("lat:" + toString(pos.y(), gPrecisionGeo) + ", lon:" + toString(pos.x(), gPrecisionGeo)).c_str());
253 : } else {
254 580 : myApp->getGeoLabel()->setText(TL("(No projection defined)"));
255 : }
256 : // if enabled, set test position
257 580 : if (myApp->getTestFrame()) {
258 0 : if (OptionsCont::getOptions().getBool("gui-testing")) {
259 0 : myApp->getTestFrame()->show();
260 : // adjust cursor position (24,25) to show exactly the same position as in function netedit.leftClick(match, X, Y)
261 0 : myApp->getTestLabel()->setText(("Test: x:" + toString(getWindowCursorPosition().x() - 24.0) + " y:" + toString(getWindowCursorPosition().y() - 25.0)).c_str());
262 : } else {
263 0 : myApp->getTestFrame()->hide();
264 : }
265 : }
266 580 : }
267 :
268 :
269 : int
270 0 : GUISUMOAbstractView::doPaintGL(int /*mode*/, const Boundary& /*boundary*/) {
271 0 : return 0;
272 : }
273 :
274 :
275 : void
276 6374 : GUISUMOAbstractView::doInit() {
277 6374 : }
278 :
279 :
280 : Boundary
281 4 : GUISUMOAbstractView::getVisibleBoundary() const {
282 4 : return myChanger->getViewport();
283 : }
284 :
285 :
286 : bool
287 18 : GUISUMOAbstractView::is3DView() const {
288 18 : return false;
289 : }
290 :
291 :
292 0 : void GUISUMOAbstractView::zoom2Pos(Position& /* camera */, Position& /* lookAt */, double /* zoom */) {
293 0 : }
294 :
295 :
296 : void
297 476287 : GUISUMOAbstractView::paintGL() {
298 : // reset debug counters
299 476287 : GLHelper::resetMatrixCounter();
300 476287 : GLHelper::resetVertexCounter();
301 476287 : if (getWidth() == 0 || getHeight() == 0) {
302 0 : return;
303 : }
304 476287 : const long start = SysUtils::getCurrentMillis();
305 :
306 476287 : if (getTrackedID() != GUIGlObject::INVALID_ID) {
307 580 : centerTo(getTrackedID(), false);
308 : }
309 : // draw
310 1905148 : glClearColor(
311 476287 : myVisualizationSettings->backgroundColor.red() / 255.f,
312 476287 : myVisualizationSettings->backgroundColor.green() / 255.f,
313 476287 : myVisualizationSettings->backgroundColor.blue() / 255.f,
314 476287 : myVisualizationSettings->backgroundColor.alpha() / 255.f);
315 476287 : glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
316 476287 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
317 :
318 476287 : if (myVisualizationSettings->dither) {
319 0 : glEnable(GL_DITHER);
320 : } else {
321 476287 : glDisable(GL_DITHER);
322 : }
323 476287 : glEnable(GL_BLEND);
324 476287 : glDisable(GL_LINE_SMOOTH);
325 :
326 476287 : Boundary bound = applyGLTransform();
327 476287 : doPaintGL(GL_RENDER, bound);
328 476287 : GLHelper::checkCounterMatrix();
329 476287 : GLHelper::checkCounterName();
330 476287 : displayLegends();
331 476286 : const long end = SysUtils::getCurrentMillis();
332 476286 : myFrameDrawTime = end - start;
333 476286 : if (myVisualizationSettings->fps) {
334 0 : drawFPS();
335 : }
336 : // check if show tooltip
337 476286 : if (myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->isStaticToolTipEnabled()) {
338 0 : showToolTipFor(getToolTipID());
339 : } else {
340 476286 : myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->hideStaticToolTip();
341 : }
342 476286 : swapBuffers();
343 476286 : }
344 :
345 :
346 : long
347 0 : GUISUMOAbstractView::onCmdCloseLane(FXObject*, FXSelector, void*) {
348 0 : return 1;
349 : }
350 :
351 :
352 : long
353 0 : GUISUMOAbstractView::onCmdCloseEdge(FXObject*, FXSelector, void*) {
354 0 : return 1;
355 : }
356 :
357 :
358 : long
359 0 : GUISUMOAbstractView::onCmdAddRerouter(FXObject*, FXSelector, void*) {
360 0 : return 1;
361 : }
362 :
363 :
364 : long
365 0 : GUISUMOAbstractView::onCmdShowReachability(FXObject*, FXSelector, void*) {
366 0 : return 1;
367 : }
368 :
369 :
370 : long
371 0 : GUISUMOAbstractView::onVisualizationChange(FXObject*, FXSelector, void*) {
372 0 : return 1;
373 : }
374 :
375 :
376 : GUILane*
377 0 : GUISUMOAbstractView::getLaneUnderCursor() {
378 0 : return nullptr;
379 : }
380 :
381 :
382 : GUIGlID
383 0 : GUISUMOAbstractView::getToolTipID() {
384 0 : return getObjectUnderCursor();
385 : }
386 :
387 :
388 : GUIGlID
389 0 : GUISUMOAbstractView::getObjectUnderCursor() {
390 0 : return getObjectAtPosition(getPositionInformation());
391 : }
392 :
393 :
394 : std::vector<GUIGlID>
395 0 : GUISUMOAbstractView::getObjectsUnderCursor() {
396 0 : return getObjectsAtPosition(getPositionInformation(), SENSITIVITY);
397 : }
398 :
399 :
400 :
401 : std::vector<GUIGlObject*>
402 0 : GUISUMOAbstractView::getGUIGlObjectsUnderCursor() {
403 0 : return getGUIGlObjectsAtPosition(getPositionInformation(), SENSITIVITY);
404 : }
405 :
406 :
407 : std::vector<GUIGlObject*>
408 0 : GUISUMOAbstractView::getGUIGlObjectsUnderSnappedCursor() {
409 0 : return getGUIGlObjectsAtPosition(snapToActiveGrid(getPositionInformation()), SENSITIVITY);
410 : }
411 :
412 :
413 : GUIGlID
414 0 : GUISUMOAbstractView::getObjectAtPosition(Position pos) {
415 : // calculate a boundary for the given position
416 0 : Boundary positionBoundary;
417 0 : positionBoundary.add(pos);
418 0 : positionBoundary.grow(SENSITIVITY);
419 0 : const std::vector<GUIGlID> ids = getObjectsInBoundary(positionBoundary);
420 : // Interpret results
421 : int idMax = 0;
422 : double maxLayer = -std::numeric_limits<double>::max();
423 : // iterate over obtained GUIGlIDs
424 0 : for (const auto& i : ids) {
425 : // obtain GUIGlObject
426 0 : GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(i);
427 : // check that GUIGlObject exist
428 0 : if (o == nullptr) {
429 0 : continue;
430 : }
431 : // check that GUIGlObject isn't the network
432 0 : if (o->getGlID() == 0) {
433 0 : continue;
434 : }
435 : //std::cout << "point selection hit " << o->getMicrosimID() << "\n";
436 0 : double layer = o->getClickPriority();
437 : // check whether the current object is above a previous one
438 0 : if (layer > maxLayer) {
439 0 : idMax = i;
440 : maxLayer = layer;
441 : }
442 : // unblock object
443 0 : GUIGlObjectStorage::gIDStorage.unblockObject(i);
444 : }
445 0 : return idMax;
446 0 : }
447 :
448 :
449 : std::vector<GUIGlID>
450 0 : GUISUMOAbstractView::getObjectsAtPosition(Position pos, double radius) {
451 : // declare result vector
452 : std::vector<GUIGlID> result;
453 : // calculate boundary
454 0 : Boundary selection;
455 0 : selection.add(pos);
456 0 : selection.grow(radius);
457 : // obtain GUIGlID of objects in boundary
458 0 : const std::vector<GUIGlID> ids = getObjectsInBoundary(selection);
459 : // iterate over obtained GUIGlIDs
460 0 : for (const auto& i : ids) {
461 : // obtain GUIGlObject
462 0 : GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(i);
463 : // check that GUIGlObject exist
464 0 : if (o == nullptr) {
465 0 : continue;
466 : }
467 : // check that GUIGlObject isn't the network
468 0 : if (o->getGlID() == 0) {
469 0 : continue;
470 : }
471 : //std::cout << "point selection hit " << o->getMicrosimID() << "\n";
472 : GUIGlObjectType type = o->getType();
473 : // avoid network
474 0 : if (type != GLO_NETWORK) {
475 0 : result.push_back(i);
476 : }
477 : // unblock object
478 0 : GUIGlObjectStorage::gIDStorage.unblockObject(i);
479 : }
480 0 : return result;
481 0 : }
482 :
483 :
484 : std::vector<GUIGlObject*>
485 0 : GUISUMOAbstractView::getGUIGlObjectsAtPosition(Position pos, double radius) {
486 : // declare result vector
487 : std::vector<GUIGlObject*> result;
488 : // calculate boundary
489 0 : Boundary selection;
490 0 : selection.add(pos);
491 0 : selection.grow(radius);
492 : // obtain GUIGlID of objects in boundary
493 0 : const std::vector<GUIGlID> ids = getObjectsInBoundary(selection);
494 : // iterate over obtained GUIGlIDs
495 0 : for (const auto& i : ids) {
496 : // obtain GUIGlObject
497 0 : GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(i);
498 : // check that GUIGlObject exist
499 0 : if (o == nullptr) {
500 0 : continue;
501 : }
502 : // check that GUIGlObject isn't the network
503 0 : if (o->getGlID() == 0) {
504 0 : continue;
505 : }
506 0 : result.push_back(o);
507 : // unblock object
508 0 : GUIGlObjectStorage::gIDStorage.unblockObject(i);
509 : }
510 0 : return result;
511 0 : }
512 :
513 :
514 : std::vector<GUIGlID>
515 0 : GUISUMOAbstractView::getObjectsInBoundary(Boundary bound) {
516 : const int NB_HITS_MAX = 1024 * 1024;
517 : // Prepare the selection mode
518 : static GUIGlID hits[NB_HITS_MAX];
519 : static GLint nb_hits = 0;
520 0 : glSelectBuffer(NB_HITS_MAX, hits);
521 0 : glInitNames();
522 :
523 0 : myVisualizationSettings->scale = m2p(SUMO_const_laneWidth);
524 0 : Boundary oldViewPort = myChanger->getViewport(false); // backup the actual viewPort
525 0 : myChanger->setViewport(bound);
526 0 : bound = applyGLTransform(false);
527 : // enable draw for selecting (to draw objects with less details)
528 0 : myVisualizationSettings->drawForRectangleSelection = true;
529 0 : int hits2 = doPaintGL(GL_SELECT, bound);
530 : // reset flags
531 0 : myVisualizationSettings->drawForRectangleSelection = false;
532 : // Get the results
533 0 : nb_hits = glRenderMode(GL_RENDER);
534 0 : if (nb_hits == -1) {
535 0 : myApp->setStatusBarText("Selection in boundary failed. Try to select fewer than " + toString(hits2) + " items");
536 : }
537 : std::vector<GUIGlID> result;
538 : GLuint numNames;
539 : GLuint* ptr = hits;
540 0 : for (int i = 0; i < nb_hits; ++i) {
541 0 : numNames = *ptr;
542 0 : ptr += 3;
543 0 : for (int j = 0; j < (int)numNames; j++) {
544 0 : result.push_back(*ptr);
545 0 : ptr++;
546 : }
547 : }
548 : // switch viewport back to normal
549 0 : myChanger->setViewport(oldViewPort);
550 0 : return result;
551 0 : }
552 :
553 :
554 : std::vector<GUIGlObject*>
555 0 : GUISUMOAbstractView::filterInternalLanes(const std::vector<GUIGlObject*>& objects) const {
556 : // count number of internal lanes
557 : size_t internalLanes = 0;
558 0 : for (const auto& object : objects) {
559 0 : if ((object->getType() == GLO_LANE) && (object->getMicrosimID().find(':') != std::string::npos)) {
560 0 : internalLanes++;
561 : }
562 : }
563 : // if all objects are internal lanes, return it all
564 0 : if (objects.size() == internalLanes || !myVisualizationSettings->drawJunctionShape) {
565 0 : return objects;
566 : }
567 : // in other case filter internal lanes
568 : std::vector<GUIGlObject*> filteredObjects;
569 0 : for (const auto& object : objects) {
570 0 : if ((object->getType() == GLO_LANE) && (object->getMicrosimID().find(':') != std::string::npos)) {
571 0 : continue;
572 : }
573 0 : filteredObjects.push_back(object);
574 : }
575 : return filteredObjects;
576 : }
577 :
578 :
579 : bool
580 0 : GUISUMOAbstractView::showToolTipFor(const GUIGlID idToolTip) {
581 0 : if (idToolTip != GUIGlObject::INVALID_ID) {
582 0 : const GUIGlObject* object = GUIGlObjectStorage::gIDStorage.getObjectBlocking(idToolTip);
583 0 : if (object != nullptr) {
584 0 : myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->showStaticToolTip(object->getFullName().c_str());
585 0 : return true;
586 : }
587 : }
588 : // nothing to show
589 0 : myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->hideStaticToolTip();
590 0 : return false;
591 : }
592 :
593 :
594 : void
595 0 : GUISUMOAbstractView::paintGLGrid() const {
596 : // obtain minimum grid
597 0 : const double minimumSizeGrid = (myVisualizationSettings->gridXSize < myVisualizationSettings->gridYSize) ? myVisualizationSettings->gridXSize : myVisualizationSettings->gridYSize;
598 : // Check if the distance is enough to draw grid
599 0 : if (myVisualizationSettings->scale * myVisualizationSettings->addSize.getExaggeration(*myVisualizationSettings, nullptr) >= (25 / minimumSizeGrid)) {
600 0 : glEnable(GL_DEPTH_TEST);
601 0 : glLineWidth(1);
602 : // get multiplication values (2 is the margin)
603 0 : const int multXmin = (int)(myChanger->getViewport().xmin() / myVisualizationSettings->gridXSize) - 2;
604 0 : const int multYmin = (int)(myChanger->getViewport().ymin() / myVisualizationSettings->gridYSize) - 2;
605 0 : const int multXmax = (int)(myChanger->getViewport().xmax() / myVisualizationSettings->gridXSize) + 2;
606 0 : const int multYmax = (int)(myChanger->getViewport().ymax() / myVisualizationSettings->gridYSize) + 2;
607 : // obtain references
608 0 : const double xmin = myVisualizationSettings->gridXSize * multXmin;
609 0 : const double ymin = myVisualizationSettings->gridYSize * multYmin;
610 0 : const double xmax = myVisualizationSettings->gridXSize * multXmax;
611 0 : const double ymax = myVisualizationSettings->gridYSize * multYmax;
612 : double xp = xmin;
613 : double yp = ymin;
614 : // move drawing matrix
615 0 : glTranslated(0, 0, .55);
616 0 : glColor3d(0.5, 0.5, 0.5);
617 : // draw horizontal lines
618 0 : glBegin(GL_LINES);
619 0 : while (yp <= ymax) {
620 0 : glVertex2d(xmin, yp);
621 0 : glVertex2d(xmax, yp);
622 0 : yp += myVisualizationSettings->gridYSize;
623 : }
624 : // draw vertical lines
625 0 : while (xp <= xmax) {
626 0 : glVertex2d(xp, ymin);
627 0 : glVertex2d(xp, ymax);
628 0 : xp += myVisualizationSettings->gridXSize;
629 : }
630 0 : glEnd();
631 0 : glTranslated(0, 0, -.55);
632 : }
633 0 : }
634 :
635 :
636 : void
637 476697 : GUISUMOAbstractView::displayLegend() {
638 : // compute the scale bar length
639 : int length = 1;
640 476697 : const std::string text("10000000000");
641 : int noDigits = 1;
642 476697 : int pixelSize = (int) m2p((double) length);
643 1599148 : while (pixelSize <= 20) {
644 1122451 : length *= 10;
645 1122451 : noDigits++;
646 1122451 : if (noDigits > (int)text.length()) {
647 : return;
648 : }
649 1122451 : pixelSize = (int) m2p((double) length);
650 : }
651 476697 : glLineWidth(1.0);
652 :
653 476697 : glMatrixMode(GL_PROJECTION);
654 476697 : GLHelper::pushMatrix();
655 476697 : glLoadIdentity();
656 476697 : glMatrixMode(GL_MODELVIEW);
657 476697 : GLHelper::pushMatrix();
658 476697 : glLoadIdentity();
659 :
660 : // draw the scale bar
661 : const double z = -1;
662 476697 : glDisable(GL_TEXTURE_2D);
663 476697 : glDisable(GL_ALPHA_TEST);
664 476697 : glDisable(GL_BLEND);
665 476697 : glEnable(GL_DEPTH_TEST);
666 476697 : GLHelper::pushMatrix();
667 476697 : glTranslated(0, 0, z);
668 :
669 476697 : double len = (double) pixelSize / (double)(getWidth() - 1) * (double) 2.0;
670 476697 : glColor3d(0, 0, 0);
671 476697 : double o = double(15) / double(getHeight());
672 476697 : double o2 = o + o;
673 476697 : double oo = double(5) / double(getHeight());
674 476697 : glBegin(GL_LINES);
675 : // vertical
676 476697 : glVertex2d(-.98, -1. + o);
677 476697 : glVertex2d(-.98 + len, -1. + o);
678 : // tick at begin
679 476697 : glVertex2d(-.98, -1. + o);
680 476697 : glVertex2d(-.98, -1. + o2);
681 : // tick at end
682 476697 : glVertex2d(-.98 + len, -1. + o);
683 476697 : glVertex2d(-.98 + len, -1. + o2);
684 476697 : glEnd();
685 476697 : GLHelper::popMatrix();
686 :
687 476697 : const double fontHeight = 0.1 * 300. / getHeight();
688 476697 : const double fontWidth = 0.1 * 300. / getWidth();
689 : // draw 0
690 953393 : GLHelper::drawText("0", Position(-.99, -0.99 + o2 + oo), z, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT, fontWidth);
691 :
692 : // draw current scale
693 953392 : GLHelper::drawText((text.substr(0, noDigits) + "m").c_str(), Position(-.99 + len, -0.99 + o2 + oo), z, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT, fontWidth);
694 :
695 : // restore matrices
696 476696 : glMatrixMode(GL_PROJECTION);
697 476696 : GLHelper::popMatrix();
698 476696 : glMatrixMode(GL_MODELVIEW);
699 476696 : GLHelper::popMatrix();
700 : }
701 :
702 : void
703 476697 : GUISUMOAbstractView::displayLegends() {
704 476697 : if (myVisualizationSettings->showSizeLegend) {
705 476697 : displayLegend();
706 : }
707 476696 : if (myVisualizationSettings->showColorLegend) {
708 0 : displayColorLegend(myVisualizationSettings->getLaneEdgeScheme(), false);
709 : }
710 476696 : if (myVisualizationSettings->showVehicleColorLegend) {
711 0 : displayColorLegend(myVisualizationSettings->vehicleColorer.getScheme(), true);
712 : }
713 476696 : }
714 :
715 : void
716 0 : GUISUMOAbstractView::displayColorLegend(const GUIColorScheme& scheme, bool leftSide) {
717 : // compute the scale bar length
718 0 : glLineWidth(1.0);
719 0 : glMatrixMode(GL_PROJECTION);
720 0 : GLHelper::pushMatrix();
721 0 : glLoadIdentity();
722 0 : glMatrixMode(GL_MODELVIEW);
723 0 : GLHelper::pushMatrix();
724 0 : glLoadIdentity();
725 :
726 : const double z = -1;
727 0 : glEnable(GL_DEPTH_TEST);
728 0 : glEnable(GL_BLEND);
729 0 : GLHelper::pushMatrix();
730 0 : glTranslated(0, 0, z);
731 :
732 : const bool fixed = scheme.isFixed();
733 0 : const int numColors = (int)scheme.getColors().size();
734 :
735 : // vertical
736 : double right = 0.98;
737 : double left = 0.95;
738 : double textX = left - 0.01;
739 : double textDir = 1;
740 : FONSalign textAlign = FONS_ALIGN_RIGHT;
741 : const double top = -0.7;
742 : const double bot = 0.9;
743 0 : const double dy = (top - bot) / numColors;
744 0 : const double bot2 = fixed ? bot : bot + dy / 2;
745 : // legend placement
746 0 : if (leftSide) {
747 : right = -right;
748 : left = -left;
749 : std::swap(right, left);
750 : textX = right + 0.01;
751 : textDir *= -1;
752 : textAlign = FONS_ALIGN_LEFT;
753 : }
754 : // draw black boundary around legend colors
755 0 : glColor3d(0, 0, 0);
756 0 : glBegin(GL_LINES);
757 0 : glVertex2d(right, top);
758 0 : glVertex2d(right, bot2);
759 0 : glVertex2d(left, bot2);
760 0 : glVertex2d(left, top);
761 0 : glVertex2d(right, top);
762 0 : glVertex2d(left, top);
763 0 : glVertex2d(right, bot2);
764 0 : glVertex2d(left, bot2);
765 0 : glEnd();
766 :
767 0 : const double fontHeight = 0.20 * 300. / getHeight();
768 0 : const double fontWidth = 0.20 * 300. / getWidth();
769 :
770 0 : const int fadeSteps = fixed ? 1 : 10;
771 0 : double colorStep = dy / fadeSteps;
772 0 : for (int i = 0; i < numColors; i++) {
773 0 : RGBColor col = scheme.getColors()[i];
774 0 : const double topi = top - i * dy;
775 : //const double boti = top - (i + 1) * dy;
776 : //std::cout << " col=" << scheme.getColors()[i] << " i=" << i << " topi=" << topi << " boti=" << boti << "\n";
777 0 : if (i + 1 < numColors) {
778 : // fade
779 0 : RGBColor col2 = scheme.getColors()[i + 1];
780 0 : double thresh2 = scheme.getThresholds()[i + 1];
781 0 : if (!fixed && thresh2 == GUIVisualizationSettings::MISSING_DATA) {
782 : // draw scale end before missing data
783 0 : GLHelper::setColor(col);
784 0 : glBegin(GL_QUADS);
785 0 : glVertex2d(left, topi);
786 0 : glVertex2d(right, topi);
787 0 : glVertex2d(right, topi - 5 * colorStep);
788 0 : glVertex2d(left, topi - 5 * colorStep);
789 0 : glEnd();
790 0 : glColor3d(0, 0, 0);
791 0 : glBegin(GL_LINES);
792 0 : glVertex2d(right, topi - 10 * colorStep);
793 0 : glVertex2d(left, topi - 10 * colorStep);
794 0 : glEnd();
795 0 : glBegin(GL_LINES);
796 0 : glVertex2d(right, topi - 5 * colorStep);
797 0 : glVertex2d(left, topi - 5 * colorStep);
798 0 : glEnd();
799 : } else {
800 : // fade colors
801 0 : for (double j = 0.0; j < fadeSteps; j++) {
802 0 : GLHelper::setColor(RGBColor::interpolate(col, col2, j / fadeSteps));
803 0 : glBegin(GL_QUADS);
804 0 : glVertex2d(left, topi - j * colorStep);
805 0 : glVertex2d(right, topi - j * colorStep);
806 0 : glVertex2d(right, topi - (j + 1) * colorStep);
807 0 : glVertex2d(left, topi - (j + 1) * colorStep);
808 0 : glEnd();
809 : }
810 : }
811 : } else {
812 0 : GLHelper::setColor(col);
813 0 : glBegin(GL_QUADS);
814 0 : glVertex2d(left, topi);
815 0 : glVertex2d(right, topi);
816 0 : glVertex2d(right, bot2);
817 0 : glVertex2d(left, bot2);
818 0 : glEnd();
819 : }
820 :
821 0 : const double threshold = scheme.getThresholds()[i];
822 : std::string name = scheme.getNames()[i];
823 0 : std::string text = fixed || threshold == GUIVisualizationSettings::MISSING_DATA ? name : toString(threshold);
824 :
825 : const double bgShift = 0.0;
826 : const double textShift = 0.01;
827 : const double textXShift = -0.005;
828 :
829 0 : GLHelper::setColor(RGBColor::WHITE);
830 0 : glTranslated(0, 0, 0.1);
831 0 : glBegin(GL_QUADS);
832 0 : glVertex2d(textX, topi + fontHeight * bgShift);
833 0 : glVertex2d(textX - textDir * fontWidth * (double)text.size() / 2.1, topi + fontHeight * bgShift);
834 0 : glVertex2d(textX - textDir * fontWidth * (double)text.size() / 2.1, topi + fontHeight * (0.8 + bgShift));
835 0 : glVertex2d(textX, topi + fontHeight * (0.8 + bgShift));
836 0 : glEnd();
837 0 : glTranslated(0, 0, -0.1);
838 0 : GLHelper::drawText(text, Position(textX + textDir * textXShift, topi + textShift), 0, fontHeight, RGBColor::BLACK, 0, textAlign, fontWidth);
839 : }
840 : // draw scheme name
841 : std::string name = scheme.getName();
842 0 : if (StringUtils::startsWith(name, "by ")) {
843 0 : name = name.substr(3);
844 : }
845 : const double topN = -0.8;
846 : const double bgShift = 0.0;
847 0 : GLHelper::setColor(RGBColor::WHITE);
848 0 : glTranslated(0, 0, 0.1);
849 0 : glBegin(GL_QUADS);
850 0 : glVertex2d(textX + textDir * 0.04, topN + fontHeight * bgShift - 0.01);
851 0 : glVertex2d(textX + textDir * 0.04 - textDir * fontWidth * (double)name.size() / 2.3, topN + fontHeight * bgShift - 0.01);
852 0 : glVertex2d(textX + textDir * 0.04 - textDir * fontWidth * (double)name.size() / 2.3, topN + fontHeight * (0.8 + bgShift));
853 0 : glVertex2d(textX + textDir * 0.04, topN + fontHeight * (0.8 + bgShift));
854 0 : glEnd();
855 0 : glTranslated(0, 0, -0.1);
856 0 : GLHelper::drawText(name, Position(textX + textDir * 0.04, topN), 0, fontHeight, RGBColor::BLACK, 0, textAlign, fontWidth);
857 :
858 0 : GLHelper::popMatrix();
859 : // restore matrices
860 0 : glMatrixMode(GL_PROJECTION);
861 0 : GLHelper::popMatrix();
862 0 : glMatrixMode(GL_MODELVIEW);
863 0 : GLHelper::popMatrix();
864 0 : }
865 :
866 :
867 : double
868 0 : GUISUMOAbstractView::getFPS() const {
869 0 : return 1000.0 / MAX2((long)1, myFrameDrawTime);
870 : }
871 :
872 :
873 : GUIGlChildWindow*
874 0 : GUISUMOAbstractView::getGUIGlChildWindow() {
875 0 : return myGlChildWindowParent;
876 : }
877 :
878 :
879 : void
880 0 : GUISUMOAbstractView::drawFPS() {
881 0 : glMatrixMode(GL_PROJECTION);
882 0 : GLHelper::pushMatrix();
883 0 : glLoadIdentity();
884 0 : glMatrixMode(GL_MODELVIEW);
885 0 : GLHelper::pushMatrix();
886 0 : glLoadIdentity();
887 0 : const double fontHeight = 0.2 * 300. / getHeight();
888 0 : const double fontWidth = 0.2 * 300. / getWidth();
889 0 : GLHelper::drawText(toString((int)getFPS()) + " FPS", Position(0.82, 0.88), -1, fontHeight, RGBColor::RED, 0, FONS_ALIGN_LEFT, fontWidth);
890 : #ifdef CHECK_ELEMENTCOUNTER
891 : GLHelper::drawText(toString(GLHelper::getMatrixCounter()) + " matrix", Position(0.82, 0.79), -1, fontHeight, RGBColor::RED, 0, FONS_ALIGN_LEFT, fontWidth);
892 : GLHelper::drawText(toString(GLHelper::getVertexCounter()) + " vertex", Position(0.82, 0.71), -1, fontHeight, RGBColor::RED, 0, FONS_ALIGN_LEFT, fontWidth);
893 : #endif
894 : // restore matrices
895 0 : glMatrixMode(GL_PROJECTION);
896 0 : GLHelper::popMatrix();
897 0 : glMatrixMode(GL_MODELVIEW);
898 0 : GLHelper::popMatrix();
899 0 : }
900 :
901 :
902 : double
903 2075845 : GUISUMOAbstractView::m2p(double meter) const {
904 2075845 : return meter * getWidth() / myChanger->getViewport().getWidth();
905 : }
906 :
907 :
908 : double
909 0 : GUISUMOAbstractView::p2m(double pixel) const {
910 0 : return pixel * myChanger->getViewport().getWidth() / getWidth();
911 : }
912 :
913 :
914 : void
915 6836 : GUISUMOAbstractView::recenterView() {
916 6836 : myChanger->setViewport(*myGrid);
917 6836 : }
918 :
919 :
920 : void
921 580 : GUISUMOAbstractView::centerTo(GUIGlID id, bool applyZoom, double zoomDist) {
922 580 : GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
923 580 : if (o != nullptr && dynamic_cast<GUIGlObject*>(o) != nullptr) {
924 580 : const Boundary& b = o->getCenteringBoundary();
925 1160 : if (b.getCenter() != Position::INVALID) {
926 580 : if (applyZoom && zoomDist < 0) {
927 0 : myChanger->setViewport(b);
928 0 : update(); // only update when centering onto an object once
929 : } else {
930 : // called during tracking. update is triggered somewhere else
931 580 : myChanger->centerTo(b.getCenter(), zoomDist, applyZoom);
932 580 : updatePositionInformationLabel();
933 : }
934 : }
935 580 : }
936 580 : GUIGlObjectStorage::gIDStorage.unblockObject(id);
937 580 : }
938 :
939 :
940 : void
941 0 : GUISUMOAbstractView::centerTo(const Position& pos, bool applyZoom, double zoomDist) {
942 : // called during tracking. update is triggered somewhere else
943 0 : myChanger->centerTo(pos, zoomDist, applyZoom);
944 0 : updatePositionInformationLabel();
945 0 : }
946 :
947 :
948 : void
949 4 : GUISUMOAbstractView::centerTo(const Boundary& bound) {
950 4 : myChanger->setViewport(bound);
951 4 : update();
952 4 : }
953 :
954 :
955 : GUIMainWindow*
956 0 : GUISUMOAbstractView::getMainWindow() const {
957 0 : return myApp;
958 : }
959 :
960 :
961 : Position
962 0 : GUISUMOAbstractView::getWindowCursorPosition() const {
963 0 : return Position(myWindowCursorPositionX, myWindowCursorPositionY);
964 : }
965 :
966 :
967 : void
968 0 : GUISUMOAbstractView::setWindowCursorPosition(FXint x, FXint y) {
969 0 : myWindowCursorPositionX = x + myMouseHotspotX;
970 0 : myWindowCursorPositionY = y + myMouseHotspotY;
971 0 : }
972 :
973 :
974 : FXbool
975 523117 : GUISUMOAbstractView::makeCurrent() {
976 523117 : FXbool ret = FXGLCanvas::makeCurrent();
977 523117 : return ret;
978 : }
979 :
980 :
981 : long
982 6374 : GUISUMOAbstractView::onConfigure(FXObject*, FXSelector, void*) {
983 6374 : if (makeCurrent()) {
984 6374 : glViewport(0, 0, getWidth() - 1, getHeight() - 1);
985 25496 : glClearColor(
986 6374 : myVisualizationSettings->backgroundColor.red() / 255.f,
987 6374 : myVisualizationSettings->backgroundColor.green() / 255.f,
988 6374 : myVisualizationSettings->backgroundColor.blue() / 255.f,
989 6374 : myVisualizationSettings->backgroundColor.alpha() / 255.f);
990 6374 : doInit();
991 6374 : myAmInitialised = true;
992 6374 : makeNonCurrent();
993 6374 : checkSnapshots();
994 : }
995 6374 : return 1;
996 : }
997 :
998 :
999 : long
1000 482740 : GUISUMOAbstractView::onPaint(FXObject*, FXSelector, void*) {
1001 482740 : if (!isEnabled() || !myAmInitialised) {
1002 : return 1;
1003 : }
1004 476287 : if (makeCurrent()) {
1005 476287 : paintGL();
1006 476286 : makeNonCurrent();
1007 : }
1008 : return 1;
1009 : }
1010 :
1011 :
1012 : const Position&
1013 0 : GUISUMOAbstractView::getPopupPosition() const {
1014 0 : return myPopupPosition;
1015 : }
1016 :
1017 :
1018 : void
1019 0 : GUISUMOAbstractView::destroyPopup() {
1020 0 : if (myPopup != nullptr) {
1021 0 : myPopup->removePopupFromObject();
1022 0 : delete myPopup;
1023 : myPopupPosition.set(0, 0);
1024 0 : myPopup = nullptr;
1025 : myCurrentObjectsDialog.clear();
1026 : }
1027 0 : }
1028 :
1029 :
1030 : void
1031 0 : GUISUMOAbstractView::replacePopup(GUIGLObjectPopupMenu* popUp) {
1032 : // use the same position of old popUp
1033 0 : popUp->move(myPopup->getX(), myPopup->getY());
1034 : // delete and replace popup
1035 0 : myPopup->removePopupFromObject();
1036 0 : delete myPopup;
1037 0 : myPopup = popUp;
1038 : // create and show popUp
1039 0 : myPopup->create();
1040 0 : myPopup->show();
1041 0 : myChanger->onRightBtnRelease(nullptr);
1042 0 : setFocus();
1043 0 : }
1044 :
1045 :
1046 : long
1047 0 : GUISUMOAbstractView::onLeftBtnPress(FXObject*, FXSelector, void* ptr) {
1048 0 : destroyPopup();
1049 0 : setFocus();
1050 : FXEvent* e = (FXEvent*) ptr;
1051 : // check whether the selection-mode is activated
1052 0 : if ((e->state & CONTROLMASK) != 0) {
1053 : // toggle selection of object under cursor
1054 0 : if (makeCurrent()) {
1055 0 : int id = getObjectUnderCursor();
1056 0 : if (id != 0) {
1057 0 : gSelected.toggleSelection(id);
1058 : }
1059 0 : makeNonCurrent();
1060 0 : if (id != 0) {
1061 : // possibly, the selection-coloring is used,
1062 : // so we should update the screen again...
1063 0 : update();
1064 : }
1065 : }
1066 : }
1067 0 : if ((e->state & SHIFTMASK) != 0) {
1068 : // track vehicle or person under cursor
1069 0 : if (makeCurrent()) {
1070 0 : int id = getObjectUnderCursor();
1071 0 : if (id != 0) {
1072 0 : GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
1073 0 : if (o != nullptr) {
1074 0 : if (o->getType() == GLO_VEHICLE || o->getType() == GLO_PERSON) {
1075 0 : startTrack(id);
1076 0 : } else if (o->getType() == GLO_REROUTER_EDGE) {
1077 0 : o->onLeftBtnPress(ptr);
1078 0 : update();
1079 : }
1080 : }
1081 : }
1082 0 : makeNonCurrent();
1083 : }
1084 : }
1085 0 : myChanger->onLeftBtnPress(ptr);
1086 0 : grab();
1087 : // Check there are double click
1088 0 : if (e->click_count == 2) {
1089 0 : handle(this, FXSEL(SEL_DOUBLECLICKED, 0), ptr);
1090 : }
1091 0 : return 1;
1092 : }
1093 :
1094 :
1095 : long
1096 0 : GUISUMOAbstractView::onLeftBtnRelease(FXObject*, FXSelector, void* ptr) {
1097 0 : destroyPopup();
1098 0 : myChanger->onLeftBtnRelease(ptr);
1099 0 : if (myApp->isGaming()) {
1100 0 : onGamingClick(getPositionInformation());
1101 : }
1102 0 : ungrab();
1103 0 : return 1;
1104 : }
1105 :
1106 :
1107 : long
1108 0 : GUISUMOAbstractView::onMiddleBtnPress(FXObject*, FXSelector, void* ptr) {
1109 0 : destroyPopup();
1110 0 : setFocus();
1111 0 : if (!myApp->isGaming()) {
1112 0 : myChanger->onMiddleBtnPress(ptr);
1113 : }
1114 0 : grab();
1115 : // enable panning
1116 0 : myPanning = true;
1117 : // set cursors
1118 0 : setDefaultCursor(GUICursorSubSys::getCursor(GUICursor::MOVEVIEW));
1119 0 : setDragCursor(GUICursorSubSys::getCursor(GUICursor::MOVEVIEW));
1120 0 : return 1;
1121 : }
1122 :
1123 :
1124 : long
1125 0 : GUISUMOAbstractView::onMiddleBtnRelease(FXObject*, FXSelector, void* ptr) {
1126 0 : destroyPopup();
1127 0 : if (!myApp->isGaming()) {
1128 0 : myChanger->onMiddleBtnRelease(ptr);
1129 : }
1130 0 : ungrab();
1131 : // disable panning
1132 0 : myPanning = false;
1133 : // restore cursors
1134 0 : setDefaultCursor(GUICursorSubSys::getCursor(GUICursor::DEFAULT));
1135 0 : setDragCursor(GUICursorSubSys::getCursor(GUICursor::DEFAULT));
1136 0 : return 1;
1137 : }
1138 :
1139 :
1140 : long
1141 0 : GUISUMOAbstractView::onRightBtnPress(FXObject*, FXSelector, void* ptr) {
1142 0 : destroyPopup();
1143 0 : if (!myApp->isGaming()) {
1144 0 : myChanger->onRightBtnPress(ptr);
1145 : }
1146 0 : grab();
1147 0 : return 1;
1148 : }
1149 :
1150 :
1151 : long
1152 0 : GUISUMOAbstractView::onRightBtnRelease(FXObject* o, FXSelector sel, void* ptr) {
1153 0 : destroyPopup();
1154 0 : onMouseMove(o, sel, ptr);
1155 0 : if (!myChanger->onRightBtnRelease(ptr) && !myApp->isGaming()) {
1156 0 : openObjectDialogAtCursor((FXEvent*)ptr);
1157 : }
1158 0 : if (myApp->isGaming()) {
1159 0 : onGamingRightClick(getPositionInformation());
1160 : }
1161 0 : ungrab();
1162 0 : return 1;
1163 : }
1164 :
1165 :
1166 : long
1167 0 : GUISUMOAbstractView::onDoubleClicked(FXObject*, FXSelector, void*) {
1168 0 : return 1;
1169 : }
1170 :
1171 :
1172 : long
1173 0 : GUISUMOAbstractView::onMouseWheel(FXObject*, FXSelector, void* ptr) {
1174 0 : if (!myApp->isGaming()) {
1175 0 : myChanger->onMouseWheel(ptr);
1176 : // upddate viewport
1177 0 : if (myGUIDialogEditViewport != nullptr) {
1178 0 : myGUIDialogEditViewport->setValues(myChanger->getZoom(),
1179 0 : myChanger->getXPos(), myChanger->getYPos(),
1180 0 : myChanger->getRotation());
1181 : }
1182 0 : updatePositionInformationLabel();
1183 : }
1184 0 : return 1;
1185 : }
1186 :
1187 :
1188 : long
1189 0 : GUISUMOAbstractView::onMouseMove(FXObject*, FXSelector, void* ptr) {
1190 : // check if popup exist
1191 0 : if (myPopup) {
1192 : // check if handle front element
1193 0 : if (myPopupPosition == getPositionInformation()) {
1194 0 : myPopupPosition = Position::INVALID;
1195 0 : myPopup->handle(this, FXSEL(SEL_COMMAND, MID_CURSORDIALOG_FRONT), nullptr);
1196 0 : destroyPopup();
1197 0 : } else if (!myPopup->shown()) {
1198 0 : destroyPopup();
1199 : }
1200 : }
1201 0 : if (myPopup == nullptr) {
1202 0 : if (myGUIDialogEditViewport == nullptr || !myGUIDialogEditViewport->haveGrabbed()) {
1203 0 : myChanger->onMouseMove(ptr);
1204 : }
1205 0 : if (myGUIDialogEditViewport != nullptr) {
1206 0 : myGUIDialogEditViewport->setValues(myChanger->getZoom(),
1207 0 : myChanger->getXPos(), myChanger->getYPos(),
1208 0 : myChanger->getRotation());
1209 : }
1210 0 : updatePositionInformationLabel();
1211 : }
1212 0 : return 1;
1213 : }
1214 :
1215 :
1216 : long
1217 0 : GUISUMOAbstractView::onMouseLeft(FXObject*, FXSelector, void* /*data*/) {
1218 0 : return 1;
1219 : }
1220 :
1221 : std::vector<GUIGlObject*>
1222 0 : GUISUMOAbstractView::filterContextObjects(const std::vector<GUIGlObject*>& objects) {
1223 : // assume input is sorted with ComparatorClickPriority
1224 : std::vector<GUIGlObject*> result;
1225 0 : for (GUIGlObject* o : objects) {
1226 0 : if (o->getClickPriority() != GUIGlObject::INVALID_PRIORITY && (result.empty() || result.back() != o)) {
1227 0 : result.push_back(o);
1228 : }
1229 : }
1230 0 : return result;
1231 : }
1232 :
1233 :
1234 : void
1235 0 : GUISUMOAbstractView::openObjectDialogAtCursor(const FXEvent* ev) {
1236 : // release the mouse grab
1237 0 : ungrab();
1238 : // check if alt key is pressed
1239 0 : const bool altKeyPressed = ((ev->state & ALTMASK) != 0);
1240 : // check if SUMO is enabled, initialised and Make OpenGL context current
1241 0 : if (isEnabled() && myAmInitialised && makeCurrent()) {
1242 0 : auto objectsUnderCursor = getGUIGlObjectsUnderCursor();
1243 0 : if (objectsUnderCursor.empty()) {
1244 0 : myPopup = GUIGlObjectStorage::gIDStorage.getNetObject()->getPopUpMenu(*myApp, *this);
1245 : } else {
1246 0 : std::sort(objectsUnderCursor.begin(), objectsUnderCursor.end(), ComparatorClickPriority());
1247 0 : std::vector<GUIGlObject*> filtered = filterContextObjects(objectsUnderCursor);
1248 0 : if (filtered.size() > 1 && (altKeyPressed
1249 0 : || filtered[0]->getClickPriority() == filtered[1]->getClickPriority())) {
1250 : // open dialog for picking among objects (without duplicates)
1251 0 : myPopup = new GUICursorDialog(GUIGLObjectPopupMenu::PopupType::PROPERTIES, this, filtered);
1252 : } else {
1253 0 : myPopup = objectsUnderCursor.front()->getPopUpMenu(*myApp, *this);
1254 : }
1255 : }
1256 0 : openPopupDialog();
1257 0 : makeNonCurrent();
1258 : }
1259 0 : }
1260 :
1261 :
1262 : void
1263 0 : GUISUMOAbstractView::openObjectDialog(const std::vector<GUIGlObject*>& objects, const bool filter) {
1264 0 : if (objects.size() > 0) {
1265 : // create cursor popup dialog
1266 0 : if (objects.size() == 1) {
1267 0 : myCurrentObjectsDialog = objects;
1268 0 : } else if (filter) {
1269 : // declare filtered objects
1270 : std::vector<GUIGlObject*> filteredGLObjects;
1271 : // fill filtered objects
1272 0 : for (const auto& glObject : objects) {
1273 : // compare type with first element type
1274 0 : if (glObject->getType() == objects.front()->getType()) {
1275 0 : filteredGLObjects.push_back(glObject);
1276 : }
1277 : }
1278 0 : myCurrentObjectsDialog = filteredGLObjects;
1279 : } else {
1280 0 : myCurrentObjectsDialog = objects;
1281 : }
1282 0 : if (myCurrentObjectsDialog.size() > 1) {
1283 0 : myPopup = new GUICursorDialog(GUIGLObjectPopupMenu::PopupType::PROPERTIES, this, myCurrentObjectsDialog);
1284 : } else {
1285 0 : myPopup = myCurrentObjectsDialog.front()->getPopUpMenu(*myApp, *this);
1286 : }
1287 : // open popup dialog
1288 0 : openPopupDialog();
1289 : }
1290 0 : }
1291 :
1292 :
1293 : long
1294 0 : GUISUMOAbstractView::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {
1295 : const FXEvent* e = (FXEvent*) ptr;
1296 0 : if (e->state & ALTMASK) {
1297 0 : myVisualizationSettings->altKeyPressed = true;
1298 : // update view (for polygon layers)
1299 0 : update();
1300 : } else {
1301 0 : myVisualizationSettings->altKeyPressed = false;
1302 : }
1303 : // check if process canvas or popup
1304 0 : if (myPopup != nullptr) {
1305 0 : return myPopup->onKeyPress(o, sel, ptr);
1306 : } else {
1307 0 : if (e->state & CONTROLMASK) {
1308 0 : if (e->code == FX::KEY_Page_Up) {
1309 0 : myVisualizationSettings->gridXSize *= 2;
1310 0 : myVisualizationSettings->gridYSize *= 2;
1311 0 : update();
1312 0 : return 1;
1313 0 : } else if (e->code == FX::KEY_Page_Down) {
1314 0 : myVisualizationSettings->gridXSize /= 2;
1315 0 : myVisualizationSettings->gridYSize /= 2;
1316 0 : update();
1317 0 : return 1;
1318 : }
1319 : }
1320 0 : FXGLCanvas::onKeyPress(o, sel, ptr);
1321 0 : return myChanger->onKeyPress(ptr);
1322 : }
1323 : }
1324 :
1325 :
1326 : long
1327 0 : GUISUMOAbstractView::onKeyRelease(FXObject* o, FXSelector sel, void* ptr) {
1328 : const FXEvent* e = (FXEvent*) ptr;
1329 0 : if ((e->state & ALTMASK) == 0) {
1330 0 : myVisualizationSettings->altKeyPressed = false;
1331 : // update view (for polygon layers)
1332 0 : update();
1333 : }
1334 : // check if process canvas or popup
1335 0 : if (myPopup != nullptr) {
1336 0 : return myPopup->onKeyRelease(o, sel, ptr);
1337 : } else {
1338 0 : FXGLCanvas::onKeyRelease(o, sel, ptr);
1339 0 : return myChanger->onKeyRelease(ptr);
1340 : }
1341 : }
1342 :
1343 : // ------------ Dealing with snapshots
1344 :
1345 : void
1346 410 : GUISUMOAbstractView::addSnapshot(SUMOTime time, const std::string& file, const int w, const int h) {
1347 : #ifdef DEBUG_SNAPSHOT
1348 : std::cout << "add snapshot time=" << time << " file=" << file << "\n";
1349 : #endif
1350 410 : FXMutexLock lock(mySnapshotsMutex);
1351 820 : mySnapshots[time].push_back(std::make_tuple(file, w, h));
1352 410 : }
1353 :
1354 :
1355 : std::string
1356 410 : GUISUMOAbstractView::makeSnapshot(const std::string& destFile, const int w, const int h) {
1357 410 : if (w >= 0) {
1358 4 : resize(w, h);
1359 4 : repaint();
1360 : }
1361 : std::string errorMessage;
1362 410 : FXString ext = FXPath::extension(destFile.c_str());
1363 410 : const bool useGL2PS = ext == "ps" || ext == "eps" || ext == "pdf" || ext == "svg" || ext == "tex" || ext == "pgf";
1364 : #ifdef HAVE_FFMPEG
1365 410 : const bool useVideo = destFile == "" || ext == "h264" || ext == "hevc" || ext == "mp4";
1366 : #endif
1367 410 : for (int i = 0; i < 10 && !makeCurrent(); ++i) {
1368 0 : MFXSingleEventThread::sleep(100);
1369 : }
1370 : // draw
1371 1640 : glClearColor(
1372 410 : myVisualizationSettings->backgroundColor.red() / 255.f,
1373 410 : myVisualizationSettings->backgroundColor.green() / 255.f,
1374 410 : myVisualizationSettings->backgroundColor.blue() / 255.f,
1375 410 : myVisualizationSettings->backgroundColor.alpha() / 255.f);
1376 410 : glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
1377 410 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1378 :
1379 410 : if (myVisualizationSettings->dither) {
1380 0 : glEnable(GL_DITHER);
1381 : } else {
1382 410 : glDisable(GL_DITHER);
1383 : }
1384 410 : glEnable(GL_BLEND);
1385 410 : glDisable(GL_LINE_SMOOTH);
1386 :
1387 410 : applyGLTransform();
1388 :
1389 410 : if (useGL2PS) {
1390 : #ifdef HAVE_GL2PS
1391 : GLint format = GL2PS_PS;
1392 0 : if (ext == "ps") {
1393 : format = GL2PS_PS;
1394 0 : } else if (ext == "eps") {
1395 : format = GL2PS_EPS;
1396 0 : } else if (ext == "pdf") {
1397 : format = GL2PS_PDF;
1398 0 : } else if (ext == "tex") {
1399 : format = GL2PS_TEX;
1400 0 : } else if (ext == "svg") {
1401 : format = GL2PS_SVG;
1402 0 : } else if (ext == "pgf") {
1403 : format = GL2PS_PGF;
1404 : } else {
1405 0 : return "Could not save '" + destFile + "'.\n Unrecognized format '" + std::string(ext.text()) + "'.";
1406 : }
1407 0 : FILE* fp = fopen(destFile.c_str(), "wb");
1408 0 : if (fp == 0) {
1409 0 : return "Could not save '" + destFile + "'.\n Could not open file for writing";
1410 : }
1411 0 : GLHelper::setGL2PS();
1412 : GLint buffsize = 0, state = GL2PS_OVERFLOW;
1413 : GLint viewport[4];
1414 0 : glGetIntegerv(GL_VIEWPORT, viewport);
1415 0 : while (state == GL2PS_OVERFLOW) {
1416 0 : buffsize += 1024 * 1024;
1417 0 : gl2psBeginPage(destFile.c_str(), "sumo-gui; https://sumo.dlr.de", viewport, format, GL2PS_SIMPLE_SORT,
1418 : GL2PS_DRAW_BACKGROUND | GL2PS_USE_CURRENT_VIEWPORT,
1419 : GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, "out.eps");
1420 0 : glMatrixMode(GL_MODELVIEW);
1421 0 : GLHelper::pushMatrix();
1422 0 : glDisable(GL_TEXTURE_2D);
1423 0 : glDisable(GL_ALPHA_TEST);
1424 0 : glDisable(GL_BLEND);
1425 0 : glEnable(GL_DEPTH_TEST);
1426 : // draw decals (if not in grabbing mode)
1427 :
1428 0 : drawDecals();
1429 0 : if (myVisualizationSettings->showGrid) {
1430 0 : paintGLGrid();
1431 : }
1432 :
1433 0 : glLineWidth(1);
1434 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1435 0 : Boundary viewPort = myChanger->getViewport();
1436 0 : const float minB[2] = { (float)viewPort.xmin(), (float)viewPort.ymin() };
1437 0 : const float maxB[2] = { (float)viewPort.xmax(), (float)viewPort.ymax() };
1438 0 : myVisualizationSettings->scale = m2p(SUMO_const_laneWidth);
1439 0 : glEnable(GL_POLYGON_OFFSET_FILL);
1440 0 : glEnable(GL_POLYGON_OFFSET_LINE);
1441 0 : myGrid->Search(minB, maxB, *myVisualizationSettings);
1442 :
1443 0 : displayLegends();
1444 0 : state = gl2psEndPage();
1445 0 : glFinish();
1446 0 : }
1447 0 : GLHelper::setGL2PS(false);
1448 0 : fclose(fp);
1449 : #else
1450 : return "Could not save '" + destFile + "', gl2ps was not enabled at compile time.";
1451 : #endif
1452 : } else {
1453 410 : doPaintGL(GL_RENDER, myChanger->getViewport());
1454 410 : displayLegends();
1455 410 : swapBuffers();
1456 410 : glFinish();
1457 : FXColor* buf;
1458 410 : FXMALLOC(&buf, FXColor, getWidth()*getHeight());
1459 : // read from the back buffer
1460 410 : glReadBuffer(GL_BACK);
1461 : // Read the pixels
1462 410 : glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)buf);
1463 410 : makeNonCurrent();
1464 410 : update();
1465 : // mirror
1466 : int mwidth = getWidth();
1467 : int mheight = getHeight();
1468 410 : FXColor* paa = buf;
1469 410 : FXColor* pbb = buf + mwidth * (mheight - 1);
1470 : do {
1471 : FXColor* pa = paa;
1472 53202 : paa += mwidth;
1473 : FXColor* pb = pbb;
1474 53202 : pbb -= mwidth;
1475 : do {
1476 26088002 : FXColor t = *pa;
1477 26088002 : *pa++ = *pb;
1478 26088002 : *pb++ = t;
1479 26088002 : } while (pa < paa);
1480 53202 : } while (paa < pbb);
1481 : try {
1482 : #ifdef HAVE_FFMPEG
1483 410 : if (useVideo) {
1484 : try {
1485 0 : saveFrame(destFile, buf);
1486 : errorMessage = "video";
1487 0 : } catch (std::runtime_error& err) {
1488 0 : errorMessage = err.what();
1489 0 : }
1490 : } else
1491 : #endif
1492 410 : if (!MFXImageHelper::saveImage(destFile, getWidth(), getHeight(), buf)) {
1493 0 : errorMessage = "Could not save '" + destFile + "'.";
1494 : }
1495 4 : } catch (InvalidArgument& e) {
1496 8 : errorMessage = "Could not save '" + destFile + "'.\n" + e.what();
1497 4 : }
1498 410 : FXFREE(&buf);
1499 : }
1500 : return errorMessage;
1501 410 : }
1502 :
1503 :
1504 : void
1505 0 : GUISUMOAbstractView::saveFrame(const std::string& destFile, FXColor* buf) {
1506 : UNUSED_PARAMETER(destFile);
1507 : UNUSED_PARAMETER(buf);
1508 0 : }
1509 :
1510 :
1511 : void
1512 5333790 : GUISUMOAbstractView::checkSnapshots() {
1513 5333790 : const SUMOTime time = getCurrentTimeStep() - DELTA_T;
1514 : #ifdef DEBUG_SNAPSHOT
1515 : std::cout << "check snapshots time=" << time << " registeredTimes=" << mySnapshots.size() << "\n";
1516 : #endif
1517 5333790 : FXMutexLock lock(mySnapshotsMutex);
1518 : const auto snapIt = mySnapshots.find(time);
1519 5333790 : if (snapIt == mySnapshots.end()) {
1520 : return;
1521 : }
1522 45 : std::vector<std::tuple<std::string, int, int> > files = snapIt->second;
1523 : lock.unlock();
1524 : // decouple map access and painting to avoid deadlock
1525 455 : for (const auto& entry : files) {
1526 : #ifdef DEBUG_SNAPSHOT
1527 : std::cout << "make snapshot time=" << time << " file=" << file << "\n";
1528 : #endif
1529 410 : const std::string& error = makeSnapshot(std::get<0>(entry), std::get<1>(entry), std::get<2>(entry));
1530 414 : if (error != "" && error != "video") {
1531 12 : WRITE_WARNING(error);
1532 : }
1533 : }
1534 : // synchronization with a waiting run thread
1535 : lock.lock();
1536 : mySnapshots.erase(time);
1537 45 : mySnapshotCondition.signal();
1538 : #ifdef DEBUG_SNAPSHOT
1539 : std::cout << " files=" << toString(files) << " myApplicationSnapshots=" << joinToString(*myApplicationSnapshots, ",") << "\n";
1540 : #endif
1541 45 : }
1542 :
1543 :
1544 : void
1545 5334360 : GUISUMOAbstractView::waitForSnapshots(const SUMOTime snapshotTime) {
1546 5334360 : FXMutexLock lock(mySnapshotsMutex);
1547 : if (mySnapshots.count(snapshotTime) > 0) {
1548 45 : mySnapshotCondition.wait(mySnapshotsMutex);
1549 : }
1550 5334360 : }
1551 :
1552 :
1553 : SUMOTime
1554 0 : GUISUMOAbstractView::getCurrentTimeStep() const {
1555 0 : return 0;
1556 : }
1557 :
1558 :
1559 : void
1560 0 : GUISUMOAbstractView::showViewschemeEditor() {
1561 0 : if (myGUIDialogViewSettings == nullptr) {
1562 0 : myGUIDialogViewSettings = new GUIDialog_ViewSettings(this, myVisualizationSettings);
1563 0 : myGUIDialogViewSettings->create();
1564 : } else {
1565 0 : myGUIDialogViewSettings->setCurrent(myVisualizationSettings);
1566 : }
1567 0 : setFocus();
1568 0 : myGUIDialogViewSettings->show();
1569 0 : }
1570 :
1571 :
1572 : GUIDialog_EditViewport*
1573 0 : GUISUMOAbstractView::getViewportEditor() {
1574 0 : if (myGUIDialogEditViewport == nullptr) {
1575 0 : myGUIDialogEditViewport = new GUIDialog_EditViewport(this, TLC("Labels", "Edit Viewport"));
1576 0 : myGUIDialogEditViewport->create();
1577 : }
1578 0 : updateViewportValues();
1579 0 : return myGUIDialogEditViewport;
1580 : }
1581 :
1582 :
1583 0 : void GUISUMOAbstractView::updateViewportValues() {
1584 0 : myGUIDialogEditViewport->setValues(myChanger->getZoom(),
1585 0 : myChanger->getXPos(), myChanger->getYPos(),
1586 0 : myChanger->getRotation());
1587 0 : }
1588 :
1589 :
1590 : void
1591 0 : GUISUMOAbstractView::showViewportEditor() {
1592 0 : getViewportEditor(); // make sure it exists;
1593 0 : Position p(myChanger->getXPos(), myChanger->getYPos(), myChanger->getZPos());
1594 0 : myGUIDialogEditViewport->setOldValues(p, Position::INVALID, myChanger->getRotation());
1595 0 : myGUIDialogEditViewport->show();
1596 0 : }
1597 :
1598 :
1599 : void
1600 19 : GUISUMOAbstractView::setViewportFromToRot(const Position& lookFrom, const Position& /* lookAt */, double rotation) {
1601 19 : myChanger->setViewportFrom(lookFrom.x(), lookFrom.y(), lookFrom.z());
1602 19 : myChanger->setRotation(rotation);
1603 19 : update();
1604 19 : }
1605 :
1606 :
1607 : void
1608 5 : GUISUMOAbstractView::copyViewportTo(GUISUMOAbstractView* view) {
1609 : // look straight down
1610 5 : view->setViewportFromToRot(Position(myChanger->getXPos(), myChanger->getYPos(), myChanger->getZPos()),
1611 5 : Position(myChanger->getXPos(), myChanger->getYPos(), 0),
1612 5 : myChanger->getRotation());
1613 5 : }
1614 :
1615 :
1616 : bool
1617 0 : GUISUMOAbstractView::setColorScheme(const std::string&) {
1618 0 : return true;
1619 : }
1620 :
1621 :
1622 : const GUIVisualizationSettings&
1623 4 : GUISUMOAbstractView::getVisualisationSettings() const {
1624 4 : return *myVisualizationSettings;
1625 : }
1626 :
1627 :
1628 : GUIVisualizationSettings*
1629 0 : GUISUMOAbstractView::editVisualisationSettings() const {
1630 0 : return myVisualizationSettings;
1631 : }
1632 :
1633 :
1634 : void
1635 0 : GUISUMOAbstractView::remove(GUIDialog_EditViewport*) {
1636 0 : myGUIDialogEditViewport = nullptr;
1637 0 : }
1638 :
1639 :
1640 : void
1641 0 : GUISUMOAbstractView::remove(GUIDialog_ViewSettings*) {
1642 0 : myGUIDialogViewSettings = nullptr;
1643 0 : }
1644 :
1645 :
1646 : double
1647 0 : GUISUMOAbstractView::getGridWidth() const {
1648 0 : return myGrid->getWidth();
1649 : }
1650 :
1651 :
1652 : double
1653 0 : GUISUMOAbstractView::getGridHeight() const {
1654 0 : return myGrid->getHeight();
1655 : }
1656 :
1657 :
1658 : void
1659 0 : GUISUMOAbstractView::startTrack(int /*id*/) {
1660 0 : }
1661 :
1662 :
1663 : void
1664 0 : GUISUMOAbstractView::stopTrack() {
1665 0 : }
1666 :
1667 :
1668 : GUIGlID
1669 0 : GUISUMOAbstractView::getTrackedID() const {
1670 0 : return GUIGlObject::INVALID_ID;
1671 : }
1672 :
1673 :
1674 : void
1675 0 : GUISUMOAbstractView::onGamingClick(Position /*pos*/) {
1676 0 : }
1677 :
1678 : void
1679 0 : GUISUMOAbstractView::onGamingRightClick(Position /*pos*/) {
1680 0 : }
1681 :
1682 :
1683 : std::vector<GUISUMOAbstractView::Decal>&
1684 0 : GUISUMOAbstractView::getDecals() {
1685 0 : return myDecals;
1686 : }
1687 :
1688 :
1689 : FXMutex&
1690 0 : GUISUMOAbstractView::getDecalsLockMutex() {
1691 0 : return myDecalsLockMutex;
1692 : }
1693 :
1694 :
1695 : MFXComboBoxIcon*
1696 41 : GUISUMOAbstractView::getColoringSchemesCombo() {
1697 41 : return myGlChildWindowParent->getColoringSchemesCombo();
1698 : }
1699 :
1700 :
1701 : FXImage*
1702 7 : GUISUMOAbstractView::checkGDALImage(Decal& d) {
1703 : #ifdef HAVE_GDAL
1704 7 : GDALAllRegister();
1705 7 : GDALDataset* poDataset = (GDALDataset*)GDALOpen(d.filename.c_str(), GA_ReadOnly);
1706 7 : if (poDataset == 0) {
1707 : return 0;
1708 : }
1709 7 : const int xSize = poDataset->GetRasterXSize();
1710 7 : const int ySize = poDataset->GetRasterYSize();
1711 : // checking for geodata in the picture and try to adapt position and scale
1712 7 : if (d.width <= 0.) {
1713 : double adfGeoTransform[6];
1714 0 : if (poDataset->GetGeoTransform(adfGeoTransform) == CE_None) {
1715 0 : Position topLeft(adfGeoTransform[0], adfGeoTransform[3]);
1716 0 : const double horizontalSize = xSize * adfGeoTransform[1];
1717 0 : const double verticalSize = ySize * adfGeoTransform[5];
1718 0 : Position bottomRight(topLeft.x() + horizontalSize, topLeft.y() + verticalSize);
1719 0 : if (GeoConvHelper::getProcessing().x2cartesian(topLeft) && GeoConvHelper::getProcessing().x2cartesian(bottomRight)) {
1720 0 : d.width = bottomRight.x() - topLeft.x();
1721 0 : d.height = topLeft.y() - bottomRight.y();
1722 0 : d.centerX = (topLeft.x() + bottomRight.x()) / 2;
1723 0 : d.centerY = (topLeft.y() + bottomRight.y()) / 2;
1724 : //WRITE_MESSAGE("proj: " + toString(poDataset->GetProjectionRef()) + " dim: " + toString(d.width) + "," + toString(d.height) + " center: " + toString(d.centerX) + "," + toString(d.centerY));
1725 : } else {
1726 0 : WRITE_WARNINGF(TL("Could not convert coordinates in %."), d.filename);
1727 : }
1728 : }
1729 : }
1730 : #endif
1731 7 : if (d.width <= 0.) {
1732 0 : d.width = getGridWidth();
1733 0 : d.height = getGridHeight();
1734 : }
1735 :
1736 : // trying to read the picture
1737 : #ifdef HAVE_GDAL
1738 7 : const int picSize = xSize * ySize;
1739 : FXColor* result;
1740 7 : if (!FXMALLOC(&result, FXColor, picSize)) {
1741 0 : WRITE_WARNINGF("Could not allocate memory for %.", d.filename);
1742 0 : return 0;
1743 : }
1744 544775 : for (int j = 0; j < picSize; j++) {
1745 544768 : result[j] = FXRGB(0, 0, 0);
1746 : }
1747 : bool valid = true;
1748 7 : for (int i = 1; i <= poDataset->GetRasterCount(); i++) {
1749 7 : GDALRasterBand* poBand = poDataset->GetRasterBand(i);
1750 : int shift = -1;
1751 7 : if (poBand->GetColorInterpretation() == GCI_RedBand) {
1752 : shift = 0;
1753 7 : } else if (poBand->GetColorInterpretation() == GCI_GreenBand) {
1754 : shift = 1;
1755 7 : } else if (poBand->GetColorInterpretation() == GCI_BlueBand) {
1756 : shift = 2;
1757 7 : } else if (poBand->GetColorInterpretation() == GCI_AlphaBand) {
1758 : shift = 3;
1759 : } else {
1760 : valid = false;
1761 : break;
1762 : }
1763 : assert(xSize == poBand->GetXSize() && ySize == poBand->GetYSize());
1764 0 : if (poBand->RasterIO(GF_Read, 0, 0, xSize, ySize, ((unsigned char*)result) + shift, xSize, ySize, GDT_Byte, 4, 4 * xSize) == CE_Failure) {
1765 : valid = false;
1766 : break;
1767 : }
1768 : }
1769 7 : GDALClose(poDataset);
1770 7 : if (valid) {
1771 0 : return new FXImage(getApp(), result, IMAGE_OWNED | IMAGE_KEEP | IMAGE_SHMI | IMAGE_SHMP, xSize, ySize);
1772 : }
1773 7 : FXFREE(&result);
1774 : #endif
1775 : return nullptr;
1776 : }
1777 :
1778 :
1779 : void
1780 476697 : GUISUMOAbstractView::drawDecals() {
1781 476697 : GLHelper::pushName(0);
1782 476697 : myDecalsLockMutex.lock();
1783 478932 : for (auto& decal : myDecals) {
1784 2235 : if (decal.skip2D || decal.filename.empty()) {
1785 0 : continue;
1786 : }
1787 2235 : if (!decal.initialised) {
1788 : try {
1789 7 : FXImage* img = checkGDALImage(decal);
1790 7 : if (img == nullptr) {
1791 7 : img = MFXImageHelper::loadImage(getApp(), decal.filename);
1792 : }
1793 7 : MFXImageHelper::scalePower2(img, GUITexturesHelper::getMaxTextureSize());
1794 7 : decal.glID = GUITexturesHelper::add(img);
1795 7 : decal.initialised = true;
1796 7 : decal.image = img;
1797 0 : } catch (InvalidArgument& e) {
1798 0 : WRITE_ERROR("Could not load '" + decal.filename + "'.\n" + e.what());
1799 0 : decal.skip2D = true;
1800 0 : }
1801 : }
1802 2235 : GLHelper::pushMatrix();
1803 2235 : if (decal.screenRelative) {
1804 0 : Position center = screenPos2NetPos((int)decal.centerX, (int)decal.centerY);
1805 0 : glTranslated(center.x(), center.y(), decal.layer);
1806 : } else {
1807 2235 : glTranslated(decal.centerX, decal.centerY, decal.layer);
1808 : }
1809 2235 : glRotated(decal.rot, 0, 0, 1);
1810 2235 : glColor3d(1, 1, 1);
1811 2235 : double halfWidth = decal.width / 2.;
1812 2235 : double halfHeight = decal.height / 2.;
1813 2235 : if (decal.screenRelative) {
1814 0 : halfWidth = p2m(halfWidth);
1815 0 : halfHeight = p2m(halfHeight);
1816 : }
1817 2235 : GUITexturesHelper::drawTexturedBox(decal.glID, -halfWidth, -halfHeight, halfWidth, halfHeight);
1818 2235 : GLHelper::popMatrix();
1819 : }
1820 476697 : myDecalsLockMutex.unlock();
1821 476697 : GLHelper::popName();
1822 476697 : }
1823 :
1824 :
1825 : void
1826 0 : GUISUMOAbstractView::openPopupDialog() {
1827 : int x, y;
1828 : FXuint b;
1829 0 : myApp->getCursorPosition(x, y, b);
1830 0 : int appX = myApp->getX();
1831 0 : int popX = x + appX;
1832 0 : int popY = y + myApp->getY();
1833 0 : myPopup->setX(popX);
1834 0 : myPopup->setY(popY);
1835 0 : myPopup->create();
1836 0 : myPopup->show();
1837 : // TODO: try to stay on screen even on a right secondary screen in multi-monitor setup
1838 : const int rootWidth = getApp()->getRootWindow()->getWidth();
1839 : const int rootHeight = getApp()->getRootWindow()->getHeight();
1840 0 : if (popX <= rootWidth) {
1841 0 : const int maxX = (appX < 0) ? 0 : rootWidth;
1842 0 : popX = MIN2(popX, maxX - myPopup->getWidth() - 10);
1843 : }
1844 0 : popY = MIN2(popY, rootHeight - myPopup->getHeight() - 50);
1845 0 : myPopup->move(popX, popY);
1846 0 : myPopupPosition = getPositionInformation();
1847 0 : myChanger->onRightBtnRelease(nullptr);
1848 0 : setFocus();
1849 0 : }
1850 :
1851 : // ------------ Additional visualisations
1852 :
1853 : bool
1854 8 : GUISUMOAbstractView::addAdditionalGLVisualisation(GUIGlObject* const which) {
1855 8 : if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1856 8 : myAdditionallyDrawn[which] = 1;
1857 : } else {
1858 0 : myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1;
1859 : }
1860 8 : update();
1861 8 : return true;
1862 : }
1863 :
1864 :
1865 : bool
1866 28 : GUISUMOAbstractView::removeAdditionalGLVisualisation(GUIGlObject* const which) {
1867 28 : if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1868 : return false;
1869 : }
1870 8 : int cnt = myAdditionallyDrawn[which];
1871 8 : if (cnt == 1) {
1872 : myAdditionallyDrawn.erase(which);
1873 : } else {
1874 0 : myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1;
1875 : }
1876 8 : update();
1877 8 : return true;
1878 : }
1879 :
1880 :
1881 : bool
1882 0 : GUISUMOAbstractView::isAdditionalGLVisualisationEnabled(GUIGlObject* const which) const {
1883 0 : if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1884 : return false;
1885 : } else {
1886 0 : return true;
1887 : }
1888 : }
1889 :
1890 :
1891 : Boundary
1892 476697 : GUISUMOAbstractView::applyGLTransform(bool fixRatio) {
1893 476697 : Boundary bound = myChanger->getViewport(fixRatio);
1894 476697 : glMatrixMode(GL_PROJECTION);
1895 476697 : glLoadIdentity();
1896 : // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType
1897 : // thus, objects with a higher value will be closer (drawn on top)
1898 : // // @todo last param should be 0 after modifying all glDraw methods
1899 476697 : glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX - 1, GLO_MAX + 1);
1900 476697 : glMatrixMode(GL_MODELVIEW);
1901 476697 : glLoadIdentity();
1902 476697 : double scaleX = (double)getWidth() / bound.getWidth();
1903 476697 : double scaleY = (double)getHeight() / bound.getHeight();
1904 476697 : glScaled(scaleX, scaleY, 1);
1905 476697 : glTranslated(-bound.xmin(), -bound.ymin(), 0);
1906 : // rotate around the center of the screen
1907 : //double angle = -90;
1908 476697 : if (myChanger->getRotation() != 0) {
1909 0 : glTranslated(bound.getCenter().x(), bound.getCenter().y(), 0);
1910 0 : glRotated(myChanger->getRotation(), 0, 0, 1);
1911 0 : glTranslated(-bound.getCenter().x(), -bound.getCenter().y(), 0);
1912 0 : Boundary rotBound;
1913 0 : double rad = -DEG2RAD(myChanger->getRotation());
1914 0 : rotBound.add(Position(bound.xmin(), bound.ymin()).rotateAround2D(rad, bound.getCenter()));
1915 0 : rotBound.add(Position(bound.xmin(), bound.ymax()).rotateAround2D(rad, bound.getCenter()));
1916 0 : rotBound.add(Position(bound.xmax(), bound.ymin()).rotateAround2D(rad, bound.getCenter()));
1917 0 : rotBound.add(Position(bound.xmax(), bound.ymax()).rotateAround2D(rad, bound.getCenter()));
1918 : bound = rotBound;
1919 0 : }
1920 476697 : myVisualizationSettings->angle = myChanger->getRotation();
1921 476697 : return bound;
1922 0 : }
1923 :
1924 :
1925 : double
1926 0 : GUISUMOAbstractView::getDelay() const {
1927 0 : return myApp->getDelay();
1928 : }
1929 :
1930 :
1931 : void
1932 0 : GUISUMOAbstractView::setDelay(double delay) {
1933 0 : myApp->setDelay(delay);
1934 0 : }
1935 :
1936 :
1937 : void
1938 0 : GUISUMOAbstractView::setBreakpoints(const std::vector<SUMOTime>& breakpoints) {
1939 0 : myApp->setBreakpoints(breakpoints);
1940 0 : }
1941 :
1942 :
1943 0 : GUISUMOAbstractView::LayerObject::LayerObject(double layer, GUIGlObject* object) :
1944 0 : myGLObject(object) {
1945 0 : first = layer;
1946 0 : second.first = object->getType();
1947 0 : second.second = object->getMicrosimID();
1948 0 : }
1949 :
1950 :
1951 0 : GUISUMOAbstractView::LayerObject::LayerObject(GUIGlObject* object) :
1952 0 : myGLObject(object) {
1953 0 : first = object->getType();
1954 0 : second.first = object->getType();
1955 0 : second.second = object->getMicrosimID();
1956 0 : }
1957 :
1958 :
1959 : GUIGlObject*
1960 0 : GUISUMOAbstractView::LayerObject::getGLObject() const {
1961 0 : return myGLObject;
1962 : }
1963 :
1964 : /****************************************************************************/
|