Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/libsumo/GUI.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2017-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 GUI.cpp
15
/// @author Michael Behrisch
16
/// @date 07.04.2021
17
///
18
// C++ TraCI client API implementation
19
/****************************************************************************/
20
#include <config.h>
21
22
#include <utils/common/MsgHandler.h>
23
#include <utils/common/SystemFrame.h>
24
#include <utils/options/OptionsCont.h>
25
#include <utils/options/OptionsIO.h>
26
#include <utils/foxtools/MsgHandlerSynchronized.h>
27
#include <utils/gui/div/GUIGlobalSelection.h>
28
#include <utils/gui/globjects/GUIGlObjectStorage.h>
29
#include <utils/gui/settings/GUICompleteSchemeStorage.h>
30
#include <utils/gui/windows/GUIPerspectiveChanger.h>
31
#include <utils/gui/events/GUIEvent_AddView.h>
32
#include <utils/gui/events/GUIEvent_CloseView.h>
33
#include <utils/xml/XMLSubSys.h>
34
#include <gui/GUIApplicationWindow.h>
35
#include <gui/GUIRunThread.h>
36
#include <guisim/GUIVehicle.h>
37
#include <guisim/GUIPerson.h>
38
#include <guisim/GUIContainer.h>
39
#include <microsim/MSFrame.h>
40
#include <microsim/MSNet.h>
41
#include <microsim/transportables/MSTransportableControl.h>
42
#include <microsim/MSVehicleControl.h>
43
#include <libsumo/TraCIDefs.h>
44
#include <libsumo/Helper.h>
45
#include <libsumo/GUI.h>
46
47
48
namespace libsumo {
49
// ===========================================================================
50
// static member initializations
51
// ===========================================================================
52
SubscriptionResults GUI::mySubscriptionResults;
53
ContextSubscriptionResults GUI::myContextSubscriptionResults;
54
GUIApplicationWindow* GUI::myWindow = nullptr;
55
FXApp* GUI::myApp = nullptr;
56
57
58
// ===========================================================================
59
// static member definitions
60
// ===========================================================================
61
std::vector<std::string>
62
GUI::getIDList() {
63
try {
64
return GUIMainWindow::getInstance()->getViewIDs();
65
} catch (const ProcessError&) {
66
throw TraCIException("GUI is not running, command not implemented in command line sumo");
67
}
68
}
69
70
71
int
72
GUI::getIDCount() {
73
try {
74
return (int)GUIMainWindow::getInstance()->getViewIDs().size();
75
} catch (const ProcessError&) {
76
throw TraCIException("GUI is not running, command not implemented in command line sumo");
77
}
78
}
79
80
81
double
82
GUI::getZoom(const std::string& viewID) {
83
return getView(viewID)->getChanger().getZoom();
84
}
85
86
87
double
88
GUI::getAngle(const std::string& viewID) {
89
return getView(viewID)->getChanger().getRotation();
90
}
91
92
93
libsumo::TraCIPosition
94
GUI::getOffset(const std::string& viewID) {
95
GUISUMOAbstractView* v = getView(viewID);
96
libsumo::TraCIPosition pos;
97
pos.x = v->getChanger().getXPos();
98
pos.y = v->getChanger().getYPos();
99
return pos;
100
}
101
102
103
std::string
104
GUI::getSchema(const std::string& viewID) {
105
return getView(viewID)->getVisualisationSettings().name;
106
}
107
108
109
libsumo::TraCIPositionVector
110
GUI::getBoundary(const std::string& viewID) {
111
const Boundary& b = getView(viewID)->getVisibleBoundary();
112
TraCIPositionVector tb;
113
TraCIPosition minV;
114
TraCIPosition maxV;
115
minV.x = b.xmin();
116
maxV.x = b.xmax();
117
minV.y = b.ymin();
118
maxV.y = b.ymax();
119
minV.z = b.zmin();
120
maxV.z = b.zmax();
121
tb.value.push_back(minV);
122
tb.value.push_back(maxV);
123
return tb;
124
}
125
126
127
void
128
GUI::setZoom(const std::string& viewID, double zoom) {
129
GUISUMOAbstractView* const v = getView(viewID);
130
const Position off(v->getChanger().getXPos(), v->getChanger().getYPos(), v->getChanger().zoom2ZPos(zoom));
131
const Position p(off.x(), off.y(), 0);
132
v->setViewportFromToRot(off, p, v->getChanger().getRotation());
133
}
134
135
136
void
137
GUI::setAngle(const std::string& viewID, double angle) {
138
GUISUMOAbstractView* const v = getView(viewID);
139
const Position off(v->getChanger().getXPos(), v->getChanger().getYPos(), v->getChanger().getZPos());
140
const Position p(off.x(), off.y(), 0);
141
v->setViewportFromToRot(off, p, angle);
142
}
143
144
145
void
146
GUI::setOffset(const std::string& viewID, double x, double y) {
147
GUISUMOAbstractView* const v = getView(viewID);
148
const Position off(x, y, v->getChanger().getZPos());
149
const Position p(x, y, 0);
150
v->setViewportFromToRot(off, p, v->getChanger().getRotation());
151
}
152
153
154
void
155
GUI::setSchema(const std::string& viewID, const std::string& schemeName) {
156
getView(viewID)->setColorScheme(schemeName);
157
}
158
159
160
void
161
GUI::addView(const std::string& viewID, const std::string& schemeName, bool in3D) {
162
try {
163
// calling openNewView directly doesn't work from the traci/simulation thread
164
GUIMainWindow::getInstance()->sendBlockingEvent(new GUIEvent_AddView(viewID, schemeName, in3D));
165
} catch (const ProcessError&) {
166
throw TraCIException("GUI is not running, command not implemented in command line sumo");
167
}
168
// sonar thinks here is a memory leak but the GUIApplicationWindow does the clean up
169
} // NOSONAR
170
171
172
void
173
GUI::removeView(const std::string& viewID) {
174
try {
175
// calling removeViewByID directly doesn't work from the traci/simulation thread
176
GUIMainWindow::getInstance()->sendBlockingEvent(new GUIEvent_CloseView(viewID));
177
} catch (const ProcessError&) {
178
throw TraCIException("GUI is not running, command not implemented in command line sumo");
179
}
180
// sonar thinks here is a memory leak but the GUIApplicationWindow does the clean up
181
} // NOSONAR
182
183
184
void
185
GUI::setBoundary(const std::string& viewID, double xmin, double ymin, double xmax, double ymax) {
186
getView(viewID)->centerTo(Boundary(xmin, ymin, xmax, ymax));
187
}
188
189
190
void
191
GUI::screenshot(const std::string& viewID, const std::string& filename, const int width, const int height) {
192
getView(viewID)->addSnapshot(SIMSTEP, filename, width, height);
193
}
194
195
196
void
197
GUI::trackVehicle(const std::string& viewID, const std::string& vehID) {
198
GUISUMOAbstractView* const v = getView(viewID);
199
if (vehID == "") {
200
v->stopTrack();
201
} else {
202
GUIGlID glID = 0;
203
SUMOVehicle* veh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
204
if (veh != nullptr) {
205
glID = static_cast<GUIVehicle*>(veh)->getGlID();
206
} else {
207
MSTransportable* person = MSNet::getInstance()->getPersonControl().get(vehID);
208
if (person != nullptr) {
209
glID = static_cast<GUIPerson*>(person)->getGlID();
210
} else {
211
MSTransportable* container = MSNet::getInstance()->getContainerControl().get(vehID);
212
if (container != nullptr) {
213
glID = static_cast<GUIContainer*>(container)->getGlID();
214
} else {
215
throw TraCIException("Could not find vehicle or person '" + vehID + "'.");
216
}
217
}
218
}
219
if (v->getTrackedID() != glID) {
220
v->startTrack(glID);
221
}
222
}
223
}
224
225
226
bool
227
GUI::hasView(const std::string& viewID) {
228
try {
229
return GUIMainWindow::getInstance()->getViewByID(viewID) != nullptr;
230
} catch (const ProcessError&) {
231
throw TraCIException("GUI is not running, command not implemented in command line sumo");
232
}
233
}
234
235
236
std::string
237
GUI::getTrackedVehicle(const std::string& viewID) {
238
GUISUMOAbstractView* const v = getView(viewID);
239
GUIGlObject* tracked = nullptr;
240
const GUIGlID gid = v->getTrackedID();
241
if (gid != GUIGlObject::INVALID_ID) {
242
tracked = GUIGlObjectStorage::gIDStorage.getObjectBlocking(gid);
243
}
244
const std::string result = tracked == nullptr ? "" : tracked->getMicrosimID();
245
if (gid != GUIGlObject::INVALID_ID) {
246
GUIGlObjectStorage::gIDStorage.unblockObject(gid);
247
}
248
return result;
249
}
250
251
252
void
253
GUI::track(const std::string& objID, const std::string& viewID) {
254
trackVehicle(viewID, objID);
255
}
256
257
258
bool
259
GUI::isSelected(const std::string& objID, const std::string& objType) {
260
const std::string fullName = objType + ":" + objID;
261
GUIGlObject* obj = GUIGlObjectStorage::gIDStorage.getObjectBlocking(fullName);
262
if (obj == nullptr) {
263
GUIGlObjectStorage::gIDStorage.unblockObject(obj->getGlID());
264
throw TraCIException("The " + objType + " " + objID + " is not known.");
265
}
266
const bool result = gSelected.isSelected(obj);
267
GUIGlObjectStorage::gIDStorage.unblockObject(obj->getGlID());
268
return result;
269
}
270
271
272
void
273
GUI::toggleSelection(const std::string& objID, const std::string& objType) {
274
const std::string fullName = objType + ":" + objID;
275
GUIGlObject* obj = GUIGlObjectStorage::gIDStorage.getObjectBlocking(fullName);
276
if (obj == nullptr) {
277
GUIGlObjectStorage::gIDStorage.unblockObject(obj->getGlID());
278
throw TraCIException("The " + objType + " " + objID + " is not known.");
279
}
280
gSelected.toggleSelection(obj->getGlID());
281
GUIGlObjectStorage::gIDStorage.unblockObject(obj->getGlID());
282
}
283
284
285
std::string
286
GUI::getParameter(const std::string& /* viewID */, const std::string& /* name */) {
287
return "";
288
}
289
290
291
void
292
GUI::setParameter(const std::string& /* viewID */, const std::string& /* name */, const std::string& /* value */) {
293
}
294
295
296
LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(GUI)
297
LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(GUI, GUI)
298
299
300
bool
301
GUI::start(const std::vector<std::string>& cmd) {
302
if (cmd[0].find("sumo-gui") == std::string::npos && std::getenv("LIBSUMO_GUI") == nullptr) {
303
return false;
304
}
305
#ifdef WIN32
306
WRITE_WARNING("Libsumo on Windows does not work with GUI, falling back to plain libsumo.");
307
return false;
308
#else
309
try {
310
if (!GUI::close("Libsumo started new instance.")) {
311
// SystemFrame::close();
312
}
313
int argc = 1;
314
char array[1][10] = {{0}};
315
strcpy(array[0], "dummy");
316
char* argv[1];
317
argv[0] = array[0];
318
// make the output aware of threading
319
MsgHandler::setFactory(&MsgHandlerSynchronized::create);
320
gSimulation = true;
321
XMLSubSys::init();
322
MSFrame::fillOptions();
323
std::vector<std::string> args(cmd.begin() + 1, cmd.end());
324
OptionsIO::setArgs(args);
325
OptionsIO::getOptions(true);
326
OptionsCont::getOptions().processMetaOptions(false);
327
// Open display
328
myApp = new FXApp("SUMO GUI", "sumo-gui");
329
myApp->init(argc, argv);
330
int minor, major;
331
if (!FXGLVisual::supported(myApp, major, minor)) {
332
throw ProcessError(TL("This system has no OpenGL support. Exiting."));
333
}
334
335
// build the main window
336
myWindow = new GUIApplicationWindow(myApp);
337
gSchemeStorage.init(myApp);
338
myWindow->dependentBuild(true);
339
myApp->create();
340
myWindow->getRunner()->enableLibsumo();
341
// Load configuration given on command line
342
myWindow->loadOnStartup(true);
343
} catch (const ProcessError& e) {
344
throw TraCIException(e.what());
345
}
346
return true;
347
#endif
348
}
349
350
351
bool
352
GUI::load(const std::vector<std::string>& /* cmd */) {
353
if (myWindow != nullptr) {
354
WRITE_ERROR("libsumo.load is not implemented for the GUI.");
355
return true;
356
}
357
return false;
358
}
359
360
361
bool
362
GUI::hasInstance() {
363
return myWindow != nullptr;
364
}
365
366
367
bool
368
GUI::step(SUMOTime t) {
369
if (myWindow != nullptr) {
370
if (t == 0) {
371
t = SIMSTEP + DELTA_T;
372
}
373
while (SIMSTEP < t) {
374
myWindow->getRunner()->tryStep();
375
}
376
return true;
377
}
378
return false;
379
}
380
381
382
bool
383
GUI::close(const std::string& /*reason*/) {
384
if (myWindow != nullptr) {
385
myApp->stop();
386
delete myWindow;
387
myWindow = nullptr;
388
SystemFrame::close();
389
delete myApp;
390
return true;
391
}
392
return false;
393
}
394
395
396
GUISUMOAbstractView*
397
GUI::getView(const std::string& id) {
398
// we cannot use myWindow here, this is not set for the traci server
399
try {
400
GUIGlChildWindow* const c = GUIMainWindow::getInstance()->getViewByID(id);
401
if (c == nullptr) {
402
throw TraCIException("View '" + id + "' is not known");
403
}
404
return c->getView();
405
} catch (const ProcessError&) {
406
throw TraCIException("GUI is not running, command not implemented in command line sumo");
407
}
408
}
409
410
411
std::shared_ptr<VariableWrapper>
412
GUI::makeWrapper() {
413
return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
414
}
415
416
417
bool
418
GUI::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* /* paramData */) {
419
switch (variable) {
420
case TRACI_ID_LIST:
421
return wrapper->wrapStringList(objID, variable, getIDList());
422
case ID_COUNT:
423
return wrapper->wrapInt(objID, variable, getIDCount());
424
case VAR_VIEW_ZOOM:
425
return wrapper->wrapDouble(objID, variable, getZoom(objID));
426
case VAR_VIEW_OFFSET:
427
return wrapper->wrapPosition(objID, variable, getOffset(objID));
428
case VAR_VIEW_SCHEMA:
429
return wrapper->wrapString(objID, variable, getSchema(objID));
430
case VAR_ANGLE:
431
return wrapper->wrapDouble(objID, variable, getAngle(objID));
432
case VAR_VIEW_BOUNDARY:
433
return wrapper->wrapPositionVector(objID, variable, getBoundary(objID));
434
case VAR_HAS_VIEW:
435
return wrapper->wrapInt(objID, variable, hasView(objID) ? 1 : 0);
436
case VAR_TRACK_VEHICLE:
437
return wrapper->wrapString(objID, variable, getTrackedVehicle(objID));
438
default:
439
return false;
440
}
441
}
442
443
}
444
445
446
/****************************************************************************/
447
448