LCOV - code coverage report
Current view: top level - src/libsumo - GUI.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 154 204 75.5 %
Date: 2024-04-28 15:39:05 Functions: 28 41 68.3 %

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

Generated by: LCOV version 1.14