Eclipse SUMO - Simulation of Urban MObility
libsumo/GUI.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2017-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 /****************************************************************************/
18 // C++ TraCI client API implementation
19 /****************************************************************************/
20 #include <config.h>
21 
33 #include <utils/xml/XMLSubSys.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>
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 {
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 
94 GUI::getOffset(const std::string& viewID) {
95  GUISUMOAbstractView* v = getView(viewID);
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 
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
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;
204  if (veh != nullptr) {
205  glID = static_cast<GUIVehicle*>(veh)->getGlID();
206  } else {
208  if (person != nullptr) {
209  glID = static_cast<GUIPerson*>(person)->getGlID();
210  } else {
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) {
243  }
244  const std::string result = tracked == nullptr ? "" : tracked->getMicrosimID();
245  if (gid != GUIGlObject::INVALID_ID) {
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;
262  if (obj == nullptr) {
264  throw TraCIException("The " + objType + " " + objID + " is not known.");
265  }
266  const bool result = gSelected.isSelected(obj);
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;
276  if (obj == nullptr) {
278  throw TraCIException("The " + objType + " " + objID + " is not known.");
279  }
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 
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
320  gSimulation = true;
321  XMLSubSys::init();
323  std::vector<std::string> args(cmd.begin() + 1, cmd.end());
324  OptionsIO::setArgs(args);
325  OptionsIO::getOptions(true);
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, "*.sumo.cfg,*.sumocfg");
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;
389  delete myApp;
390  return true;
391  }
392  return false;
393 }
394 
395 
397 GUI::getView(const std::string& id) {
398  // we cannot use myWindow here, this is not set for the traci server
399  try {
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 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
GUICompleteSchemeStorage gSchemeStorage
unsigned int GUIGlID
Definition: GUIGlObject.h:43
GUISelectedStorage gSelected
A global holder of selected objects.
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
SUMOTime DELTA_T
Definition: SUMOTime.cpp:38
#define SIMSTEP
Definition: SUMOTime.h:61
bool gSimulation
Definition: StdDefs.cpp:30
#define LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(CLASS, DOM)
Definition: TraCIDefs.h:76
#define LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(CLASS)
Definition: TraCIDefs.h:123
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:130
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:118
double zmin() const
Returns minimum z-coordinate.
Definition: Boundary.cpp:142
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:136
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:124
double zmax() const
Returns maximum z-coordinate.
Definition: Boundary.cpp:148
The main window of the SUMO-gui.
void init(FXApp *app, bool netedit=false)
Initialises the storage with some default settings.
GUISUMOAbstractView * getView() const
return GUISUMOAbstractView
static const GUIGlID INVALID_ID
Definition: GUIGlObject.h:72
const std::string & getMicrosimID() const
Returns the id of the object as known to microsim.
Definition: GUIGlObject.h:143
GUIGlID getGlID() const
Returns the numerical id of the object.
Definition: GUIGlObject.h:104
void unblockObject(GUIGlID id)
Marks an object as unblocked.
GUIGlObject * getObjectBlocking(GUIGlID id) const
Returns the object from the container locking it.
static GUIGlObjectStorage gIDStorage
A single static instance of this class.
C++ TraCI client API implementation.
GUIGlChildWindow * getViewByID(const std::string &id) const
get specific view by ID
std::vector< std::string > getViewIDs() const
get view IDs
static GUIMainWindow * getInstance()
get instance
virtual void sendBlockingEvent(GUIEvent *event)
Sends an event from the application thread to the GUI and waits until it is handled.
virtual double zoom2ZPos(double zoom) const =0
Returns the camera height at which the given zoom level is reached.
virtual double getRotation() const =0
Returns the rotation of the canvas stored in this changer.
virtual double getXPos() const =0
Returns the x-offset of the field to show stored in this changer.
virtual double getYPos() const =0
Returns the y-offset of the field to show stored in this changer.
virtual double getZPos() const =0
Returns the camera height corresponding to the current zoom factor.
GUIPerspectiveChanger & getChanger() const
get changer
virtual void setViewportFromToRot(const Position &lookFrom, const Position &lookAt, double rotation)
applies the given viewport settings
virtual void stopTrack()
stop track
virtual void startTrack(int)
star track
virtual GUIGlID getTrackedID() const
get tracked id
void toggleSelection(GUIGlID id)
Toggles selection of an object.
bool isSelected(GUIGlObjectType type, GUIGlID id)
Returns the information whether the object with the given type and id is selected.
A MSVehicle extended by some values for usage within the gui.
Definition: GUIVehicle.h:51
static void fillOptions()
Inserts options used by the simulation into the OptionsCont-singleton.
Definition: MSFrame.cpp:60
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:182
virtual MSTransportableControl & getContainerControl()
Returns the container control.
Definition: MSNet.cpp:1182
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:378
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition: MSNet.cpp:1173
MSTransportable * get(const std::string &id) const
Returns the named transportable, if existing.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
static void setFactory(Factory func)
Sets the factory function to use for new MsgHandlers.
Definition: MsgHandler.h:64
static MsgHandler * create(MsgType type)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
bool processMetaOptions(bool missingOptions)
Checks for help and configuration output, returns whether we should exit.
static void setArgs(int argc, char **argv)
Stores the command line arguments for later parsing.
Definition: OptionsIO.cpp:58
static void getOptions(const bool commandLineOnly=false)
Parses the command line arguments and loads the configuration.
Definition: OptionsIO.cpp:74
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
Representation of a vehicle.
Definition: SUMOVehicle.h:60
static void close()
Closes all of an applications subsystems.
static void init()
Initialises the xml-subsystem.
Definition: XMLSubSys.cpp:55
TRACI_CONST int TRACI_ID_LIST
TRACI_CONST int VAR_VIEW_BOUNDARY
std::map< std::string, libsumo::SubscriptionResults > ContextSubscriptionResults
Definition: TraCIDefs.h:338
TRACI_CONST int VAR_ANGLE
TRACI_CONST int VAR_VIEW_OFFSET
TRACI_CONST int VAR_VIEW_SCHEMA
TRACI_CONST int VAR_VIEW_ZOOM
TRACI_CONST int VAR_TRACK_VEHICLE
std::map< std::string, libsumo::TraCIResults > SubscriptionResults
{object->{variable->value}}
Definition: TraCIDefs.h:337
TRACI_CONST int VAR_HAS_VIEW
TRACI_CONST int ID_COUNT
@ array
array (ordered collection of values)
A 2D or 3D-position, for 2D positions z == INVALID_DOUBLE_VALUE.
Definition: TraCIDefs.h:178
A list of positions.
Definition: TraCIDefs.h:234