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