LCOV - code coverage report
Current view: top level - src/libsumo - GUI.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 28.9 % 204 59
Test Date: 2024-11-20 15:55:46 Functions: 29.3 % 41 12

            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           96 : GUI::getIDList() {
      63              :     try {
      64           96 :         return GUIMainWindow::getInstance()->getViewIDs();
      65           48 :     } catch (const ProcessError&) {
      66           96 :         throw TraCIException("GUI is not running, command not implemented in command line sumo");
      67           48 :     }
      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            0 : GUI::getZoom(const std::string& viewID) {
      83            0 :     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            0 : GUI::getOffset(const std::string& viewID) {
      95            0 :     GUISUMOAbstractView* v = getView(viewID);
      96            0 :     libsumo::TraCIPosition pos;
      97            0 :     pos.x = v->getChanger().getXPos();
      98            0 :     pos.y = v->getChanger().getYPos();
      99            0 :     return pos;
     100              : }
     101              : 
     102              : 
     103              : std::string
     104            0 : GUI::getSchema(const std::string& viewID) {
     105            0 :     return getView(viewID)->getVisualisationSettings().name;
     106              : }
     107              : 
     108              : 
     109              : libsumo::TraCIPositionVector
     110            0 : GUI::getBoundary(const std::string& viewID) {
     111            0 :     const Boundary& b = getView(viewID)->getVisibleBoundary();
     112              :     TraCIPositionVector tb;
     113            0 :     TraCIPosition minV;
     114            0 :     TraCIPosition maxV;
     115            0 :     minV.x = b.xmin();
     116            0 :     maxV.x = b.xmax();
     117            0 :     minV.y = b.ymin();
     118            0 :     maxV.y = b.ymax();
     119            0 :     minV.z = b.zmin();
     120            0 :     maxV.z = b.zmax();
     121            0 :     tb.value.push_back(minV);
     122            0 :     tb.value.push_back(maxV);
     123            0 :     return tb;
     124            0 : }
     125              : 
     126              : 
     127              : void
     128            0 : GUI::setZoom(const std::string& viewID, double zoom) {
     129            0 :     GUISUMOAbstractView* const v = getView(viewID);
     130            0 :     const Position off(v->getChanger().getXPos(), v->getChanger().getYPos(), v->getChanger().zoom2ZPos(zoom));
     131              :     const Position p(off.x(), off.y(), 0);
     132            0 :     v->setViewportFromToRot(off, p, v->getChanger().getRotation());
     133            0 : }
     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            0 : GUI::setOffset(const std::string& viewID, double x, double y) {
     147            0 :     GUISUMOAbstractView* const v = getView(viewID);
     148            0 :     const Position off(x, y, v->getChanger().getZPos());
     149              :     const Position p(x, y, 0);
     150            0 :     v->setViewportFromToRot(off, p, v->getChanger().getRotation());
     151            0 : }
     152              : 
     153              : 
     154              : void
     155            0 : GUI::setSchema(const std::string& viewID, const std::string& schemeName) {
     156            0 :     getView(viewID)->setColorScheme(schemeName);
     157            0 : }
     158              : 
     159              : 
     160              : void
     161            0 : 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            0 :         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            0 : }  // NOSONAR
     170              : 
     171              : 
     172              : void
     173            0 : GUI::removeView(const std::string& viewID) {
     174              :     try {
     175              :         // calling removeViewByID directly doesn't work from the traci/simulation thread
     176            0 :         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            0 : }  // NOSONAR
     182              : 
     183              : 
     184              : void
     185            0 : GUI::setBoundary(const std::string& viewID, double xmin, double ymin, double xmax, double ymax) {
     186            0 :     getView(viewID)->centerTo(Boundary(xmin, ymin, xmax, ymax));
     187            0 : }
     188              : 
     189              : 
     190              : void
     191          300 : GUI::screenshot(const std::string& viewID, const std::string& filename, const int width, const int height) {
     192          300 :     getView(viewID)->addSnapshot(SIMSTEP, filename, width, height);
     193          300 : }
     194              : 
     195              : 
     196              : void
     197            0 : GUI::trackVehicle(const std::string& viewID, const std::string& vehID) {
     198            0 :     GUISUMOAbstractView* const v = getView(viewID);
     199            0 :     if (vehID == "") {
     200            0 :         v->stopTrack();
     201              :     } else {
     202              :         GUIGlID glID = 0;
     203            0 :         SUMOVehicle* veh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
     204            0 :         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            0 :         if (v->getTrackedID() != glID) {
     220            0 :             v->startTrack(glID);
     221              :         }
     222              :     }
     223            0 : }
     224              : 
     225              : 
     226              : bool
     227            0 : GUI::hasView(const std::string& viewID) {
     228              :     try {
     229            0 :         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            0 : GUI::getTrackedVehicle(const std::string& viewID) {
     238            0 :     GUISUMOAbstractView* const v = getView(viewID);
     239              :     GUIGlObject* tracked = nullptr;
     240            0 :     const GUIGlID gid = v->getTrackedID();
     241            0 :     if (gid != GUIGlObject::INVALID_ID) {
     242            0 :         tracked = GUIGlObjectStorage::gIDStorage.getObjectBlocking(gid);
     243              :     }
     244            0 :     const std::string result = tracked == nullptr ? "" : tracked->getMicrosimID();
     245            0 :     if (gid != GUIGlObject::INVALID_ID) {
     246            0 :         GUIGlObjectStorage::gIDStorage.unblockObject(gid);
     247              :     }
     248            0 :     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            0 : GUI::isSelected(const std::string& objID, const std::string& objType) {
     260            0 :     const std::string fullName = objType + ":" + objID;
     261            0 :     GUIGlObject* obj = GUIGlObjectStorage::gIDStorage.getObjectBlocking(fullName);
     262            0 :     if (obj == nullptr) {
     263            0 :         GUIGlObjectStorage::gIDStorage.unblockObject(obj->getGlID());
     264            0 :         throw TraCIException("The " + objType + " " + objID + " is not known.");
     265              :     }
     266            0 :     const bool result = gSelected.isSelected(obj);
     267            0 :     GUIGlObjectStorage::gIDStorage.unblockObject(obj->getGlID());
     268            0 :     return result;
     269              : }
     270              : 
     271              : 
     272              : void
     273            0 : GUI::toggleSelection(const std::string& objID, const std::string& objType) {
     274            0 :     const std::string fullName = objType + ":" + objID;
     275            0 :     GUIGlObject* obj = GUIGlObjectStorage::gIDStorage.getObjectBlocking(fullName);
     276            0 :     if (obj == nullptr) {
     277            0 :         GUIGlObjectStorage::gIDStorage.unblockObject(obj->getGlID());
     278            0 :         throw TraCIException("The " + objType + " " + objID + " is not known.");
     279              :     }
     280            0 :     gSelected.toggleSelection(obj->getGlID());
     281            0 :     GUIGlObjectStorage::gIDStorage.unblockObject(obj->getGlID());
     282            0 : }
     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          126 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(GUI, GUI)
     298              : 
     299              : 
     300              : bool
     301         1043 : GUI::start(const std::vector<std::string>& cmd) {
     302         1043 :     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          482 :         if (!GUI::close("Libsumo started new instance.")) {
     311              : //            SystemFrame::close();
     312              :         }
     313          482 :         int argc = 1;
     314          482 :         char array[1][10] = {{0}};
     315              :         strcpy(array[0], "dummy");
     316              :         char* argv[1];
     317          482 :         argv[0] = array[0];
     318              :         // make the output aware of threading
     319              :         MsgHandler::setFactory(&MsgHandlerSynchronized::create);
     320          482 :         gSimulation = true;
     321          482 :         XMLSubSys::init();
     322          482 :         MSFrame::fillOptions();
     323          482 :         std::vector<std::string> args(cmd.begin() + 1, cmd.end());
     324          482 :         OptionsIO::setArgs(args);
     325          482 :         OptionsIO::getOptions(true);
     326          482 :         OptionsCont::getOptions().processMetaOptions(false);
     327              :         // Open display
     328          482 :         myApp = new FXApp("SUMO GUI", "sumo-gui");
     329          482 :         myApp->init(argc, argv);
     330              :         int minor, major;
     331          482 :         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          482 :         myWindow = new GUIApplicationWindow(myApp, "*.sumo.cfg,*.sumocfg");
     337          482 :         gSchemeStorage.init(myApp);
     338          482 :         myWindow->dependentBuild(true);
     339          482 :         myApp->create();
     340          482 :         myWindow->getRunner()->enableLibsumo();
     341              :         // Load configuration given on command line
     342          482 :         myWindow->loadOnStartup(true);
     343          482 :     } catch (const ProcessError& e) {
     344            0 :         throw TraCIException(e.what());
     345            0 :     }
     346          482 :     return true;
     347              : #endif
     348              : }
     349              : 
     350              : 
     351              : bool
     352          568 : GUI::load(const std::vector<std::string>& /* cmd */) {
     353          568 :     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       158766 : GUI::step(SUMOTime t) {
     369       158766 :     if (myWindow != nullptr) {
     370        77025 :         if (t == 0) {
     371        76861 :             t = SIMSTEP + DELTA_T;
     372              :         }
     373       156315 :         while (SIMSTEP < t) {
     374        79290 :             myWindow->getRunner()->tryStep();
     375              :         }
     376              :         return true;
     377              :     }
     378              :     return false;
     379              : }
     380              : 
     381              : 
     382              : bool
     383         2082 : GUI::close(const std::string& /*reason*/) {
     384         2082 :     if (myWindow != nullptr) {
     385          473 :         myApp->stop();
     386          473 :         delete myWindow;
     387          472 :         myWindow = nullptr;
     388          472 :         SystemFrame::close();
     389          472 :         delete myApp;
     390          472 :         return true;
     391              :     }
     392              :     return false;
     393              : }
     394              : 
     395              : 
     396              : GUISUMOAbstractView*
     397          300 : GUI::getView(const std::string& id) {
     398              :     // we cannot use myWindow here, this is not set for the traci server
     399              :     try {
     400          300 :         GUIGlChildWindow* const c = GUIMainWindow::getInstance()->getViewByID(id);
     401          300 :         if (c == nullptr) {
     402            0 :             throw TraCIException("View '" + id + "' is not known");
     403              :         }
     404          300 :         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          265 : GUI::makeWrapper() {
     413          265 :     return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
     414              : }
     415              : 
     416              : 
     417              : bool
     418            0 : GUI::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* /* paramData */) {
     419            0 :     switch (variable) {
     420            0 :         case TRACI_ID_LIST:
     421            0 :             return wrapper->wrapStringList(objID, variable, getIDList());
     422            0 :         case ID_COUNT:
     423            0 :             return wrapper->wrapInt(objID, variable, getIDCount());
     424            0 :         case VAR_VIEW_ZOOM:
     425            0 :             return wrapper->wrapDouble(objID, variable, getZoom(objID));
     426            0 :         case VAR_VIEW_OFFSET:
     427            0 :             return wrapper->wrapPosition(objID, variable, getOffset(objID));
     428            0 :         case VAR_VIEW_SCHEMA:
     429            0 :             return wrapper->wrapString(objID, variable, getSchema(objID));
     430            0 :         case VAR_ANGLE:
     431            0 :             return wrapper->wrapDouble(objID, variable, getAngle(objID));
     432            0 :         case VAR_VIEW_BOUNDARY:
     433            0 :             return wrapper->wrapPositionVector(objID, variable, getBoundary(objID));
     434            0 :         case VAR_HAS_VIEW:
     435            0 :             return wrapper->wrapInt(objID, variable, hasView(objID) ? 1 : 0);
     436            0 :         case VAR_TRACK_VEHICLE:
     437            0 :             return wrapper->wrapString(objID, variable, getTrackedVehicle(objID));
     438              :         default:
     439              :             return false;
     440              :     }
     441              : }
     442              : 
     443              : }
     444              : 
     445              : 
     446              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1