LCOV - code coverage report
Current view: top level - src/guisim - GUIBaseVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 28.9 % 609 176
Test Date: 2024-11-22 15:46:21 Functions: 33.3 % 54 18

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-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    GUIBaseVehicle.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Laura Bieker-Walz
      19              : /// @date    Sept 2002
      20              : ///
      21              : // A MSVehicle extended by some values for usage within the gui
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <cmath>
      26              : #include <vector>
      27              : #include <string>
      28              : #include <functional>
      29              : #include <utils/common/MsgHandler.h>
      30              : #include <utils/common/StringUtils.h>
      31              : #include <utils/common/StringTokenizer.h>
      32              : #include <utils/geom/GeomHelper.h>
      33              : #include <utils/vehicle/SUMOVehicleParameter.h>
      34              : #include <utils/emissions/PollutantsInterface.h>
      35              : #include <utils/gui/globjects/GLIncludes.h>
      36              : #include <utils/gui/windows/GUISUMOAbstractView.h>
      37              : #include <utils/gui/windows/GUIAppEnum.h>
      38              : #include <utils/gui/images/GUITexturesHelper.h>
      39              : #include <utils/gui/div/GUIGlobalSelection.h>
      40              : #include <utils/gui/div/GLHelper.h>
      41              : #include <utils/gui/div/GUIGlobalSelection.h>
      42              : #include <utils/gui/div/GUIBaseVehicleHelper.h>
      43              : #include <mesosim/MEVehicle.h>
      44              : #include <mesosim/MELoop.h>
      45              : #include <microsim/MSVehicle.h>
      46              : #include <microsim/MSLane.h>
      47              : #include <microsim/logging/CastingFunctionBinding.h>
      48              : #include <microsim/logging/FunctionBinding.h>
      49              : #include <microsim/MSVehicleControl.h>
      50              : #include <microsim/MSStop.h>
      51              : #include <microsim/MSTrainHelper.h>
      52              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      53              : #include <microsim/devices/MSDevice_Vehroutes.h>
      54              : #include <microsim/devices/MSDevice_Transportable.h>
      55              : #include <microsim/devices/MSDevice_BTreceiver.h>
      56              : #include <microsim/trigger/MSStoppingPlaceRerouter.h>
      57              : #include <gui/GUIApplicationWindow.h>
      58              : #include <gui/GUIGlobals.h>
      59              : #include <utils/gui/div/GUIDesigns.h>
      60              : 
      61              : #include "GUIBaseVehicle.h"
      62              : #include "GUIChargingStation.h"
      63              : #include "GUIPerson.h"
      64              : #include "GUIContainer.h"
      65              : #include "GUINet.h"
      66              : #include "GUIEdge.h"
      67              : #include "GUILane.h"
      68              : #include "GUIParkingArea.h"
      69              : 
      70              : //#define DRAW_BOUNDING_BOX
      71              : 
      72              : // ===========================================================================
      73              : // FOX callback mapping
      74              : // ===========================================================================
      75              : FXDEFMAP(GUIBaseVehicle::GUIBaseVehiclePopupMenu) GUIBaseVehiclePopupMenuMap[] = {
      76              :     FXMAPFUNC(SEL_COMMAND, MID_SHOW_ALLROUTES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowAllRoutes),
      77              :     FXMAPFUNC(SEL_COMMAND, MID_HIDE_ALLROUTES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideAllRoutes),
      78              :     FXMAPFUNC(SEL_COMMAND, MID_SHOW_CURRENTROUTE, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowCurrentRoute),
      79              :     FXMAPFUNC(SEL_COMMAND, MID_HIDE_CURRENTROUTE, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideCurrentRoute),
      80              :     FXMAPFUNC(SEL_COMMAND, MID_SHOW_FUTUREROUTE, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowFutureRoute),
      81              :     FXMAPFUNC(SEL_COMMAND, MID_HIDE_FUTUREROUTE, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideFutureRoute),
      82              :     FXMAPFUNC(SEL_COMMAND, MID_SHOW_ROUTE_NOLOOPS, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowRouteNoLoops),
      83              :     FXMAPFUNC(SEL_COMMAND, MID_HIDE_ROUTE_NOLOOPS, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideRouteNoLoops),
      84              :     FXMAPFUNC(SEL_COMMAND, MID_SHOW_BEST_LANES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowBestLanes),
      85              :     FXMAPFUNC(SEL_COMMAND, MID_HIDE_BEST_LANES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideBestLanes),
      86              :     FXMAPFUNC(SEL_COMMAND, MID_START_TRACK, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdStartTrack),
      87              :     FXMAPFUNC(SEL_COMMAND, MID_STOP_TRACK, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdStopTrack),
      88              :     FXMAPFUNC(SEL_COMMAND, MID_SHOW_LFLINKITEMS, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowLFLinkItems),
      89              :     FXMAPFUNC(SEL_COMMAND, MID_HIDE_LFLINKITEMS, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideLFLinkItems),
      90              :     FXMAPFUNC(SEL_COMMAND, MID_SHOW_FOES, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowFoes),
      91              :     FXMAPFUNC(SEL_COMMAND, MID_SELECT_TRANSPORTED, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdSelectTransported),
      92              :     FXMAPFUNC(SEL_COMMAND, MID_REMOVE_OBJECT, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdRemoveObject),
      93              :     FXMAPFUNC(SEL_COMMAND, MID_TOGGLE_STOP, GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdToggleStop),
      94              : };
      95              : 
      96              : // Object implementation
      97            0 : FXIMPLEMENT(GUIBaseVehicle::GUIBaseVehiclePopupMenu, GUIGLObjectPopupMenu, GUIBaseVehiclePopupMenuMap, ARRAYNUMBER(GUIBaseVehiclePopupMenuMap))
      98              : 
      99              : // ===========================================================================
     100              : // method definitions
     101              : // ===========================================================================
     102              : /* -------------------------------------------------------------------------
     103              :  * GUIBaseVehicle::GUIBaseVehiclePopupMenu - methods
     104              :  * ----------------------------------------------------------------------- */
     105            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::GUIBaseVehiclePopupMenu(
     106            0 :     GUIMainWindow& app, GUISUMOAbstractView& parent, GUIGlObject& o)
     107            0 :     : GUIGLObjectPopupMenu(app, parent, o) {
     108            0 : }
     109              : 
     110              : 
     111            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::~GUIBaseVehiclePopupMenu() {}
     112              : 
     113              : 
     114              : long
     115            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowAllRoutes(FXObject*, FXSelector, void*) {
     116              :     assert(myObject->getType() == GLO_VEHICLE);
     117            0 :     if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_ALL_ROUTES)) {
     118            0 :         static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_ALL_ROUTES);
     119              :     }
     120            0 :     return 1;
     121              : }
     122              : 
     123              : long
     124            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideAllRoutes(FXObject*, FXSelector, void*) {
     125              :     assert(myObject->getType() == GLO_VEHICLE);
     126            0 :     static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_ALL_ROUTES);
     127            0 :     return 1;
     128              : }
     129              : 
     130              : 
     131              : long
     132            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowCurrentRoute(FXObject*, FXSelector, void*) {
     133              :     assert(myObject->getType() == GLO_VEHICLE);
     134            0 :     if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_ROUTE)) {
     135            0 :         static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_ROUTE);
     136              :     }
     137            0 :     return 1;
     138              : }
     139              : 
     140              : long
     141            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideCurrentRoute(FXObject*, FXSelector, void*) {
     142              :     assert(myObject->getType() == GLO_VEHICLE);
     143            0 :     static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_ROUTE);
     144            0 :     return 1;
     145              : }
     146              : 
     147              : 
     148              : long
     149            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowFutureRoute(FXObject*, FXSelector, void*) {
     150              :     assert(myObject->getType() == GLO_VEHICLE);
     151            0 :     if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_FUTURE_ROUTE)) {
     152            0 :         static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_FUTURE_ROUTE);
     153              :     }
     154            0 :     return 1;
     155              : }
     156              : 
     157              : long
     158            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideFutureRoute(FXObject*, FXSelector, void*) {
     159              :     assert(myObject->getType() == GLO_VEHICLE);
     160            0 :     static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_FUTURE_ROUTE);
     161            0 :     return 1;
     162              : }
     163              : 
     164              : 
     165              : long
     166            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowRouteNoLoops(FXObject*, FXSelector, void*) {
     167              :     assert(myObject->getType() == GLO_VEHICLE);
     168            0 :     if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_ROUTE_NOLOOP)) {
     169            0 :         static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_ROUTE_NOLOOP);
     170              :     }
     171            0 :     return 1;
     172              : }
     173              : 
     174              : long
     175            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideRouteNoLoops(FXObject*, FXSelector, void*) {
     176              :     assert(myObject->getType() == GLO_VEHICLE);
     177            0 :     static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_ROUTE_NOLOOP);
     178            0 :     return 1;
     179              : }
     180              : 
     181              : 
     182              : long
     183            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowBestLanes(FXObject*, FXSelector, void*) {
     184              :     assert(myObject->getType() == GLO_VEHICLE);
     185            0 :     if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_BEST_LANES)) {
     186            0 :         static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_BEST_LANES);
     187              :     }
     188            0 :     return 1;
     189              : }
     190              : 
     191              : long
     192            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideBestLanes(FXObject*, FXSelector, void*) {
     193              :     assert(myObject->getType() == GLO_VEHICLE);
     194            0 :     static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_BEST_LANES);
     195            0 :     return 1;
     196              : }
     197              : 
     198              : 
     199              : long
     200            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdStartTrack(FXObject*, FXSelector, void*) {
     201              :     assert(myObject->getType() == GLO_VEHICLE);
     202            0 :     if (myParent->getTrackedID() != static_cast<GUIBaseVehicle*>(myObject)->getGlID()) {
     203            0 :         myParent->startTrack(static_cast<GUIBaseVehicle*>(myObject)->getGlID());
     204              :     }
     205            0 :     return 1;
     206              : }
     207              : 
     208              : long
     209            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdStopTrack(FXObject*, FXSelector, void*) {
     210              :     assert(myObject->getType() == GLO_VEHICLE);
     211            0 :     myParent->stopTrack();
     212            0 :     return 1;
     213              : }
     214              : 
     215              : 
     216              : long
     217            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowLFLinkItems(FXObject*, FXSelector, void*) {
     218              :     assert(myObject->getType() == GLO_VEHICLE);
     219            0 :     if (!static_cast<GUIBaseVehicle*>(myObject)->hasActiveAddVisualisation(myParent, VO_SHOW_LFLINKITEMS)) {
     220            0 :         static_cast<GUIBaseVehicle*>(myObject)->addActiveAddVisualisation(myParent, VO_SHOW_LFLINKITEMS);
     221              :     }
     222            0 :     return 1;
     223              : }
     224              : 
     225              : long
     226            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdHideLFLinkItems(FXObject*, FXSelector, void*) {
     227              :     assert(myObject->getType() == GLO_VEHICLE);
     228            0 :     static_cast<GUIBaseVehicle*>(myObject)->removeActiveAddVisualisation(myParent, VO_SHOW_LFLINKITEMS);
     229            0 :     return 1;
     230              : }
     231              : 
     232              : long
     233            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdShowFoes(FXObject*, FXSelector, void*) {
     234              :     assert(myObject->getType() == GLO_VEHICLE);
     235            0 :     static_cast<GUIBaseVehicle*>(myObject)->selectBlockingFoes();
     236            0 :     myParent->update();
     237            0 :     return 1;
     238              : }
     239              : 
     240              : 
     241              : long
     242            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdSelectTransported(FXObject*, FXSelector, void*) {
     243              :     assert(myObject->getType() == GLO_VEHICLE);
     244            0 :     const MSBaseVehicle& veh = static_cast<GUIBaseVehicle*>(myObject)->getVehicle();
     245            0 :     for (const MSTransportable* t : veh.getPersons()) {
     246            0 :         gSelected.select((static_cast<const GUIPerson*>(t))->getGlID());
     247              :     }
     248            0 :     for (MSTransportable* t : veh.getContainers()) {
     249            0 :         gSelected.select((static_cast<const GUIContainer*>(t))->getGlID());
     250              :     }
     251            0 :     myParent->update();
     252            0 :     return 1;
     253              : }
     254              : 
     255              : long
     256            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdRemoveObject(FXObject*, FXSelector, void*) {
     257            0 :     GUIBaseVehicle* baseVeh = static_cast<GUIBaseVehicle*>(myObject);
     258            0 :     MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&baseVeh->myVehicle);
     259            0 :     if (microVeh != nullptr) {
     260              :         MSLane* lane = microVeh->getMutableLane();
     261            0 :         if (lane != nullptr) {
     262            0 :             lane->getVehiclesSecure();
     263            0 :             lane->removeVehicle(microVeh, MSMoveReminder::NOTIFICATION_VAPORIZED_GUI);
     264              :         }
     265            0 :         microVeh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_VAPORIZED_GUI);
     266            0 :         if (lane != nullptr) {
     267            0 :             lane->releaseVehicles();
     268              :         }
     269              :     } else {
     270            0 :         MEVehicle* mesoVeh = dynamic_cast<MEVehicle*>(&baseVeh->myVehicle);
     271            0 :         MSGlobals::gMesoNet->vaporizeCar(mesoVeh, MSMoveReminder::NOTIFICATION_VAPORIZED_GUI);
     272              :     }
     273            0 :     MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(&baseVeh->myVehicle);
     274            0 :     myParent->destroyPopup();
     275            0 :     myParent->update();
     276            0 :     return 1;
     277              : }
     278              : 
     279              : 
     280              : long
     281            0 : GUIBaseVehicle::GUIBaseVehiclePopupMenu::onCmdToggleStop(FXObject*, FXSelector, void*) {
     282            0 :     GUIBaseVehicle* baseVeh = static_cast<GUIBaseVehicle*>(myObject);
     283            0 :     MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&baseVeh->myVehicle);
     284            0 :     if (microVeh != nullptr) {
     285            0 :         if (microVeh->isStopped()) {
     286            0 :             microVeh->resumeFromStopping();
     287              :         } else {
     288              :             std::string errorOut;
     289            0 :             const double brakeGap = microVeh->getCarFollowModel().brakeGap(microVeh->getSpeed());
     290            0 :             std::pair<const MSLane*, double> stopPos = microVeh->getLanePosAfterDist(brakeGap);
     291            0 :             if (stopPos.first != nullptr) {
     292            0 :                 SUMOVehicleParameter::Stop stop;
     293              :                 stop.lane = stopPos.first->getID();
     294            0 :                 stop.startPos = stopPos.second;
     295            0 :                 stop.endPos = stopPos.second + POSITION_EPS;
     296            0 :                 stop.duration = TIME2STEPS(3600);
     297            0 :                 microVeh->addTraciStop(stop, errorOut);
     298            0 :                 if (errorOut != "") {
     299            0 :                     WRITE_WARNING(errorOut);
     300              :                 }
     301            0 :             }
     302              :         }
     303              :     } else {
     304            0 :         WRITE_WARNING(TL("GUI-triggered stop not implemented for meso"));
     305              :     }
     306            0 :     myParent->update();
     307            0 :     return 1;
     308              : }
     309              : 
     310              : 
     311              : /* -------------------------------------------------------------------------
     312              :  * GUIBaseVehicle - methods
     313              :  * ----------------------------------------------------------------------- */
     314              : 
     315       765017 : GUIBaseVehicle::GUIBaseVehicle(MSBaseVehicle& vehicle) :
     316              :     GUIGlObject(GLO_VEHICLE, vehicle.getID(), GUIIconSubSys::getIcon(GUIIcon::VEHICLE)),
     317       765017 :     myVehicle(vehicle),
     318       765017 :     myPopup(nullptr) {
     319              :     // as it is possible to show all vehicle routes, we have to store them... (bug [ 2519761 ])
     320       765017 :     myRoutes = MSDevice_Vehroutes::buildVehicleDevices(myVehicle, myVehicle.myDevices, 5);
     321       765017 :     myVehicle.myMoveReminders.push_back(std::make_pair(myRoutes, 0.));
     322       765017 :     mySeatPositions.push_back(Seat()); // ensure length 1
     323       765017 :     myContainerPositions.push_back(Seat()); // ensure length 1
     324       765017 : }
     325              : 
     326              : 
     327       764972 : GUIBaseVehicle::~GUIBaseVehicle() {
     328       764972 :     myLock.lock();
     329       764981 :     for (std::map<GUISUMOAbstractView*, int>::iterator i = myAdditionalVisualizations.begin(); i != myAdditionalVisualizations.end(); ++i) {
     330            9 :         if (i->first->getTrackedID() == getGlID()) {
     331            0 :             i->first->stopTrack();
     332              :         }
     333           13 :         while (i->first->removeAdditionalGLVisualisation(this));
     334              :     }
     335       764972 :     myLock.unlock();
     336       764972 :     delete myRoutes;
     337       764972 :     if (myPopup != nullptr) {
     338            0 :         myPopup->getParentView()->destroyPopup();
     339              :     }
     340      1529944 : }
     341              : 
     342              : 
     343              : GUIGLObjectPopupMenu*
     344            0 : GUIBaseVehicle::getPopUpMenu(GUIMainWindow& app,
     345              :                              GUISUMOAbstractView& parent) {
     346            0 :     GUIGLObjectPopupMenu* ret = new GUIBaseVehiclePopupMenu(app, parent, *this);
     347            0 :     buildPopupHeader(ret, app);
     348            0 :     buildCenterPopupEntry(ret);
     349            0 :     buildNameCopyPopupEntry(ret);
     350            0 :     buildSelectionPopupEntry(ret);
     351              :     //
     352            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_ROUTE)) {
     353            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide Current Route"), nullptr, ret, MID_HIDE_CURRENTROUTE);
     354              :     } else {
     355            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show Current Route"), nullptr, ret, MID_SHOW_CURRENTROUTE);
     356              :     }
     357            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_FUTURE_ROUTE)) {
     358            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide Future Route"), nullptr, ret, MID_HIDE_FUTUREROUTE);
     359              :     } else {
     360            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show Future Route"), nullptr, ret, MID_SHOW_FUTUREROUTE);
     361              :     }
     362            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_ALL_ROUTES)) {
     363            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide All Routes"), nullptr, ret, MID_HIDE_ALLROUTES);
     364              :     } else {
     365            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show All Routes"), nullptr, ret, MID_SHOW_ALLROUTES);
     366              :     }
     367            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_ROUTE_NOLOOP)) {
     368            0 :         FXMenuCheck* showLoops = new FXMenuCheck(ret, TL("Draw looped routes"), ret, MID_HIDE_ROUTE_NOLOOPS);
     369            0 :         showLoops->setCheck(false);
     370              :     } else {
     371            0 :         FXMenuCheck* showLoops = new FXMenuCheck(ret, TL("Draw looped routes"), ret, MID_SHOW_ROUTE_NOLOOPS);
     372            0 :         showLoops->setCheck(true);
     373              :     }
     374            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_BEST_LANES)) {
     375            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide Best Lanes"), nullptr, ret, MID_HIDE_BEST_LANES);
     376              :     } else {
     377            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show Best Lanes"), nullptr, ret, MID_SHOW_BEST_LANES);
     378              :     }
     379            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_LFLINKITEMS)) {
     380            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide Link Items"), nullptr, ret, MID_HIDE_LFLINKITEMS);
     381              :     } else {
     382            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show Link Items"), nullptr, ret, MID_SHOW_LFLINKITEMS);
     383              :     }
     384            0 :     new FXMenuSeparator(ret);
     385            0 :     if (parent.getTrackedID() != getGlID()) {
     386            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Start Tracking"), nullptr, ret, MID_START_TRACK);
     387              :     } else {
     388            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Stop Tracking"), nullptr, ret, MID_STOP_TRACK);
     389              :     }
     390            0 :     GUIDesigns::buildFXMenuCommand(ret, TL("Select Foes"), nullptr, ret, MID_SHOW_FOES);
     391            0 :     if (myVehicle.getPersons().size() + myVehicle.getContainers().size() > 0) {
     392            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Select transported"), nullptr, ret, MID_SELECT_TRANSPORTED);
     393              :     }
     394            0 :     GUIDesigns::buildFXMenuCommand(ret, myVehicle.isStopped() ? TL("Abort stop") : TL("Stop"), nullptr, ret, MID_TOGGLE_STOP);
     395            0 :     GUIDesigns::buildFXMenuCommand(ret, TL("Remove"), nullptr, ret, MID_REMOVE_OBJECT);
     396              : 
     397            0 :     new FXMenuSeparator(ret);
     398              :     //
     399            0 :     buildShowParamsPopupEntry(ret, false);
     400            0 :     buildShowTypeParamsPopupEntry(ret);
     401            0 :     buildPositionCopyEntry(ret, app);
     402            0 :     myPopup = ret;
     403            0 :     return ret;
     404              : }
     405              : 
     406              : 
     407              : void
     408            0 : GUIBaseVehicle::removedPopupMenu() {
     409            0 :     myPopup = nullptr;
     410            0 : }
     411              : 
     412              : 
     413              : double
     414      8161492 : GUIBaseVehicle::getExaggeration(const GUIVisualizationSettings& s) const {
     415      8161492 :     return (s.vehicleSize.getExaggeration(s, this) *
     416      8161492 :             s.vehicleScaler.getScheme().getColor(getScaleValue(s, s.vehicleScaler.getActive())));
     417              : }
     418              : 
     419              : 
     420              : Boundary
     421            0 : GUIBaseVehicle::getCenteringBoundary() const {
     422            0 :     Boundary b;
     423            0 :     b.add(getVisualPosition(GUIGlobals::gSecondaryShape));
     424            0 :     b.grow(myVehicle.getVehicleType().getLength());
     425            0 :     return b;
     426            0 : }
     427              : 
     428              : 
     429              : const std::string
     430            0 : GUIBaseVehicle::getOptionalName() const {
     431            0 :     return myVehicle.getParameter().getParameter("name", "");
     432              : }
     433              : 
     434              : 
     435              : void
     436      8949371 : GUIBaseVehicle::drawOnPos(const GUIVisualizationSettings& s, const Position& pos, const double angle) const {
     437      8949371 :     GLHelper::pushName(getGlID());
     438      8949371 :     GLHelper::pushMatrix();
     439      8949371 :     Position p1 = pos;
     440      8949371 :     const double degAngle = RAD2DEG(angle + M_PI / 2.);
     441              :     const double length = getVType().getLength();
     442      8949371 :     if (s.trueZ) {
     443          284 :         glTranslated(p1.x(), p1.y(), p1.z() + 1);
     444              :     } else {
     445      8949087 :         glTranslated(p1.x(), p1.y(), getType());
     446              :     }
     447      8949371 :     glRotated(degAngle, 0, 0, 1);
     448      8949371 :     RGBColor col = setColor(s);
     449              :     // scale
     450      8949371 :     const double upscale = getExaggeration(s);
     451      8949371 :     const bool s2 = s.secondaryShape;
     452              : 
     453      8949371 :     if (upscale > 1 && s.laneWidthExaggeration > 1 && myVehicle.isOnRoad()) {
     454              :         // optionally shift according to edge exaggeration
     455            0 :         double offsetFromLeftBorder = myVehicle.getCurrentEdge()->getWidth() - myVehicle.getRightSideOnEdge() - myVehicle.getVehicleType().getWidth() / 2;
     456            0 :         glTranslated((s.laneWidthExaggeration - 1) * -offsetFromLeftBorder / 2, 0, 0);
     457              :     }
     458              : 
     459      8949371 :     double upscaleLength = MSTrainHelper::getUpscaleLength(upscale, length, getVType().getWidth(), s.vehicleQuality);
     460      8949371 :     glScaled(upscale, upscaleLength, 1);
     461              :     /*
     462              :         MSLaneChangeModel::DK2004 &m2 = static_cast<MSLaneChangeModel::DK2004&>(veh->getLaneChangeModel());
     463              :         if((m2.getState()&LCA_URGENT)!=0) {
     464              :             glColor3d(1, .4, .4);
     465              :         } else if((m2.getState()&LCA_SPEEDGAIN)!=0) {
     466              :             glColor3d(.4, .4, 1);
     467              :         } else {
     468              :             glColor3d(.4, 1, .4);
     469              :         }
     470              :         */
     471              :     // draw the vehicle
     472              :     bool drawCarriages = false;
     473      8949371 :     const double geometryFactor = (s.scaleLength ?
     474      8949371 :                                    ((myVehicle.getLane() != nullptr
     475      8949371 :                                      ? myVehicle.getLane()->getLengthGeometryFactor(s2)
     476       787879 :                                      : (myVehicle.getEdge()->getLanes().size() > 0 ? myVehicle.getEdge()->getLanes()[0]->getLengthGeometryFactor(s2) : 1)))
     477              :                                    : 1);
     478      8949371 :     double scaledLength = length * geometryFactor;
     479      8949371 :     if (col.alpha() != 0) {
     480      8949371 :         switch (s.vehicleQuality) {
     481      8729189 :             case 0:
     482      8729189 :                 GUIBaseVehicleHelper::drawAction_drawVehicleAsTrianglePlus(getVType().getWidth(), scaledLength, drawReversed(s));
     483              :                 break;
     484            0 :             case 1:
     485            0 :                 GUIBaseVehicleHelper::drawAction_drawVehicleAsBoxPlus(getVType().getWidth(), scaledLength, drawReversed(s));
     486              :                 break;
     487       212007 :             case 2:
     488       212007 :                 drawCarriages = drawAction_drawVehicleAsPolyWithCarriagges(s, scaledLength);
     489              :                 // draw flashing blue light for emergency vehicles
     490       212007 :                 if (getVType().getGuiShape() == SUMOVehicleShape::EMERGENCY) {
     491            0 :                     glTranslated(0, 0, .1);
     492            0 :                     drawAction_drawVehicleBlueLight();
     493              :                 }
     494              :                 break;
     495         8175 :             case 3:
     496         8175 :                 drawCarriages = drawAction_drawVehicleAsPolyWithCarriagges(s, scaledLength, true);
     497              :                 break;
     498              :             case 4: {
     499              :                 // do not scale circle radius by lengthGeometryFactor nor length and reduce the effect of width
     500            0 :                 const double w = 1.8 * sqrt(getVType().getWidth() / 1.8);
     501            0 :                 GUIBaseVehicleHelper::drawAction_drawVehicleAsCircle(w, s.scale * upscale);
     502              :                 // display text at circle center
     503              :                 scaledLength = 0;
     504              :                 break;
     505              :             }
     506              :             default:
     507              :                 break;
     508              :         }
     509      8949371 :         if (s.drawMinGap) {
     510            0 :             const double minGap = -getVType().getMinGap();
     511            0 :             glColor3d(0., 1., 0.);
     512            0 :             glBegin(GL_LINES);
     513            0 :             glVertex2d(0., 0);
     514            0 :             glVertex2d(0., minGap);
     515            0 :             glVertex2d(-.5, minGap);
     516            0 :             glVertex2d(.5, minGap);
     517            0 :             glEnd();
     518              :         }
     519            0 :         if (s.drawBrakeGap && !MSGlobals::gUseMesoSim
     520      8949371 :                 && (!s.vehicleSize.constantSizeSelected || myVehicle.isSelected())) {
     521            0 :             const double brakeGap = -static_cast<MSVehicle&>(myVehicle).getCarFollowModel().brakeGap(myVehicle.getSpeed());
     522            0 :             glColor3d(1., 0., 0.);
     523            0 :             glBegin(GL_LINES);
     524            0 :             glVertex2d(0., 0);
     525            0 :             glVertex2d(0., brakeGap);
     526            0 :             glVertex2d(-.5, brakeGap);
     527            0 :             glVertex2d(.5, brakeGap);
     528            0 :             glEnd();
     529              :         }
     530      8949371 :         if (s.showBTRange) {
     531            0 :             MSVehicleDevice_BTreceiver* dev = static_cast<MSVehicleDevice_BTreceiver*>(myVehicle.getDevice(typeid(MSVehicleDevice_BTreceiver)));
     532              :             if (dev != nullptr) {
     533            0 :                 glColor3d(1., 0., 0.);
     534            0 :                 GLHelper::drawOutlineCircle(dev->getRange(), dev->getRange() - .2, 32);
     535              :             }
     536              :         }
     537              :         // draw the blinker and brakelights if wished
     538      8949371 :         if (s.showBlinker) {
     539      8949371 :             glTranslated(0, 0, .1);
     540      8949371 :             switch (getVType().getGuiShape()) {
     541              :                 case SUMOVehicleShape::PEDESTRIAN:
     542              :                 case SUMOVehicleShape::BICYCLE:
     543              :                 case SUMOVehicleShape::SCOOTER:
     544              :                 case SUMOVehicleShape::ANT:
     545              :                 case SUMOVehicleShape::SHIP:
     546              :                 case SUMOVehicleShape::RAIL:
     547              :                 case SUMOVehicleShape::RAIL_CARGO:
     548              :                 case SUMOVehicleShape::RAIL_CAR:
     549              :                 case SUMOVehicleShape::AIRCRAFT:
     550              :                     break;
     551       514995 :                 case SUMOVehicleShape::MOTORCYCLE:
     552              :                 case SUMOVehicleShape::MOPED:
     553       514995 :                     drawAction_drawVehicleBlinker(scaledLength);
     554       514995 :                     drawAction_drawVehicleBrakeLight(scaledLength, true);
     555              :                     break;
     556      7943605 :                 default:
     557              :                     // only SUMOVehicleShape::RAIL_CAR has blinkers and brake lights but they are drawn along with the carriages
     558      7943605 :                     if (!drawCarriages) {
     559      7942212 :                         drawAction_drawVehicleBlinker(scaledLength);
     560      7942212 :                         drawAction_drawVehicleBrakeLight(scaledLength);
     561              :                     }
     562              :                     break;
     563              :             }
     564              :         }
     565              :         // draw the wish to change the lane
     566              :         if (s.drawLaneChangePreference) {
     567              :             /*
     568              :                if(gSelected.isSelected(GLO_VEHICLE, veh->getGlID())) {
     569              :                MSLaneChangeModel::DK2004 &m = static_cast<MSLaneChangeModel::DK2004&>(veh->getLaneChangeModel());
     570              :                glColor3d(.5, .5, 1);
     571              :                glBegin(GL_LINES);
     572              :                glVertex2f(0, 0);
     573              :                glVertex2f(m.getChangeProbability(), .5);
     574              :                glEnd();
     575              : 
     576              :                glColor3d(1, 0, 0);
     577              :                glBegin(GL_LINES);
     578              :                glVertex2f(0.1, 0);
     579              :                glVertex2f(0.1, m.myMaxJam1);
     580              :                glEnd();
     581              : 
     582              :                glColor3d(0, 1, 0);
     583              :                glBegin(GL_LINES);
     584              :                glVertex2f(-0.1, 0);
     585              :                glVertex2f(-0.1, m.myTDist);
     586              :                glEnd();
     587              :                }
     588              :                */
     589              :         }
     590              :     }
     591      9012503 :     glTranslated(0, MIN2(scaledLength / 2, double(5)), -getType()); // drawing name at GLO_MAX fails unless translating z
     592      8949371 :     glScaled(1 / upscale, 1 / upscaleLength, 1);
     593      8949371 :     glRotated(-degAngle, 0, 0, 1);
     594      8949371 :     drawName(Position(0, 0), s.scale, s.vehicleName, s.angle);
     595      8949371 :     if (s.vehicleName.show(this) && myVehicle.getParameter().line != "") {
     596            0 :         glRotated(-s.angle, 0, 0, 1);
     597            0 :         glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
     598            0 :         glRotated(s.angle, 0, 0, 1);
     599            0 :         GLHelper::drawTextSettings(s.vehicleName, "line:" + myVehicle.getParameter().line, Position(0, 0), s.scale, s.angle);
     600              :     }
     601      8949371 :     if (s.vehicleValue.show(this)) {
     602            0 :         glRotated(-s.angle, 0, 0, 1);
     603            0 :         glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
     604            0 :         glRotated(s.angle, 0, 0, 1);
     605            0 :         const double value = getColorValue(s, s.vehicleColorer.getActive());
     606            0 :         GLHelper::drawTextSettings(s.vehicleValue, toString(value), Position(0, 0), s.scale, s.angle);
     607              :     }
     608      8949371 :     if (s.vehicleScaleValue.show(this)) {
     609            0 :         glRotated(-s.angle, 0, 0, 1);
     610            0 :         glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
     611            0 :         glRotated(s.angle, 0, 0, 1);
     612            0 :         const double value = getScaleValue(s, s.vehicleScaler.getActive());
     613            0 :         GLHelper::drawTextSettings(s.vehicleScaleValue, toString(value), Position(0, 0), s.scale, s.angle);
     614              :     }
     615      8949371 :     if (s.vehicleText.show(this)) {
     616              :         std::string error;
     617            0 :         std::string value = myVehicle.getPrefixedParameter(s.vehicleTextParam, error);
     618            0 :         if (value != "") {
     619            0 :             auto lines = StringTokenizer(value, StringTokenizer::NEWLINE).getVector();
     620            0 :             glRotated(-s.angle, 0, 0, 1);
     621            0 :             glTranslated(0, 0.7 * s.vehicleText.scaledSize(s.scale) * (double)lines.size(), 0);
     622            0 :             glRotated(s.angle, 0, 0, 1);
     623            0 :             for (std::string& line : lines) {
     624            0 :                 GLHelper::drawTextSettings(s.vehicleText, line, Position(0, 0), s.scale, s.angle);
     625            0 :                 glRotated(-s.angle, 0, 0, 1);
     626            0 :                 glTranslated(0, -0.7 * s.vehicleText.scaledSize(s.scale), 0);
     627            0 :                 glRotated(s.angle, 0, 0, 1);
     628              :             }
     629            0 :         }
     630              :     }
     631      8949371 :     if (s.showParkingInfo && myAdditionalVisualizations.size() != 0 && hasActiveAddVisualisation(
     632            0 :                 myAdditionalVisualizations.begin()->first, VO_SHOW_ROUTE | VO_SHOW_FUTURE_ROUTE | VO_SHOW_ALL_ROUTES)) {
     633            0 :         glRotated(-s.angle, 0, 0, 1);
     634            0 :         glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
     635            0 :         glRotated(s.angle, 0, 0, 1);
     636            0 :         const double value = myVehicle.getNumberParkingReroutes();
     637            0 :         GLHelper::drawTextSettings(s.vehicleName, toString(value), Position(0, 0), s.scale, s.angle);
     638              :     }
     639              : 
     640      8949371 :     if (!drawCarriages) {
     641              :         mySeatPositions.clear();
     642              :         myContainerPositions.clear();
     643      8945013 :         int requiredSeats = getNumPassengers();
     644      8945013 :         int requiredContainerPositions = getNumContainers();
     645      8945013 :         const Position back = (p1 + Position(-scaledLength * upscaleLength, 0)).rotateAround2D(angle, p1);
     646      8945013 :         double extraOffset = scaledLength * 0.15;
     647      8945013 :         computeSeats(p1, back, SUMO_const_waitingPersonWidth, getVType().getPersonCapacity(), upscale, requiredSeats, mySeatPositions, extraOffset);
     648      8945013 :         computeSeats(p1, back, SUMO_const_waitingContainerWidth, getVType().getContainerCapacity(), upscale, requiredContainerPositions, myContainerPositions, extraOffset);
     649              :     }
     650              : 
     651      8949371 :     GLHelper::popMatrix();
     652      8949371 :     GLHelper::popName();
     653      8949371 :     drawAction_drawPersonsAndContainers(s);
     654      8949371 : }
     655              : 
     656              : 
     657              : void
     658      8161721 : GUIBaseVehicle::drawGL(const GUIVisualizationSettings& s) const {
     659      8161721 :     drawOnPos(s, getVisualPosition(s.secondaryShape), getVisualAngle(s.secondaryShape));
     660      8161721 : }
     661              : 
     662              : 
     663              : void
     664            3 : GUIBaseVehicle::drawGLAdditional(GUISUMOAbstractView* const parent, const GUIVisualizationSettings& s) const {
     665            3 :     if (!myVehicle.isOnRoad()) {
     666            3 :         drawGL(s);
     667              :     }
     668            3 :     GLHelper::pushName(getGlID());
     669            3 :     GLHelper::pushMatrix();
     670            3 :     glTranslated(0, 0, getType() - .1); // don't draw on top of other cars
     671            3 :     if (hasActiveAddVisualisation(parent, VO_SHOW_BEST_LANES)) {
     672            0 :         drawBestLanes();
     673              :     }
     674            3 :     bool noLoop = hasActiveAddVisualisation(parent, VO_SHOW_ROUTE_NOLOOP);
     675            3 :     if (hasActiveAddVisualisation(parent, VO_SHOW_ROUTE)) {
     676            0 :         drawRoute(s, 0, 0.25, false, noLoop);
     677              :     }
     678            3 :     if (hasActiveAddVisualisation(parent, VO_SHOW_FUTURE_ROUTE)) {
     679            0 :         drawRoute(s, 0, 0.25, true, noLoop);
     680              :     }
     681            3 :     if (hasActiveAddVisualisation(parent, VO_SHOW_ALL_ROUTES)) {
     682            0 :         if (myVehicle.getNumberReroutes() > 0) {
     683            0 :             const int noReroutePlus1 = myVehicle.getNumberReroutes() + 1;
     684            0 :             for (int i = noReroutePlus1 - 1; i >= 0; i--) {
     685            0 :                 double darken = double(0.4) / double(noReroutePlus1) * double(i);
     686            0 :                 drawRoute(s, i, darken);
     687              :             }
     688              :         } else {
     689            0 :             drawRoute(s, 0, 0.25, false, noLoop);
     690              :         }
     691              :     }
     692            3 :     if (hasActiveAddVisualisation(parent, VO_SHOW_LFLINKITEMS)) {
     693            0 :         drawAction_drawLinkItems(s);
     694              :     }
     695            3 :     GLHelper::popMatrix();
     696            3 :     GLHelper::popName();
     697            3 : }
     698              : 
     699              : 
     700              : void
     701            0 : GUIBaseVehicle::drawLinkItem(const Position& pos, SUMOTime arrivalTime, SUMOTime leaveTime, double exagerate) {
     702            0 :     glTranslated(pos.x(), pos.y(), -.1);
     703            0 :     GLHelper::drawFilledCircle(1);
     704            0 :     std::string times = toString(STEPS2TIME(arrivalTime)) + "/" + toString(STEPS2TIME(leaveTime));
     705            0 :     GLHelper::drawText(times.c_str(), Position(), .1, 1.6 * exagerate, RGBColor::GREEN, 0);
     706            0 :     glTranslated(-pos.x(), -pos.y(), .1);
     707            0 : }
     708              : 
     709              : 
     710              : RGBColor
     711      8949371 : GUIBaseVehicle::setColor(const GUIVisualizationSettings& s) const {
     712      8949371 :     RGBColor col;
     713              :     const GUIColorer& c = s.vehicleColorer;
     714      8949371 :     if (!setFunctionalColor(c.getActive(), &myVehicle, col)) {
     715      5974706 :         col = c.getScheme().getColor(getColorValue(s, c.getActive()));
     716              :     }
     717      8949371 :     GLHelper::setColor(col);
     718      8949371 :     return col;
     719              : }
     720              : 
     721              : 
     722              : bool
     723     11214981 : GUIBaseVehicle::setFunctionalColor(int activeScheme, const MSBaseVehicle* veh, RGBColor& col) {
     724     11214981 :     switch (activeScheme) {
     725     11034026 :         case 0: {
     726              :             //test for emergency vehicle
     727     11034026 :             if (veh->getVehicleType().getGuiShape() == SUMOVehicleShape::EMERGENCY) {
     728           67 :                 col = RGBColor::WHITE;
     729           67 :                 return true;
     730              :             }
     731              :             //test for firebrigade
     732     11033959 :             if (veh->getVehicleType().getGuiShape() == SUMOVehicleShape::FIREBRIGADE) {
     733            0 :                 col = RGBColor::RED;
     734            0 :                 return true;
     735              :             }
     736              :             //test for police car
     737     11033959 :             if (veh->getVehicleType().getGuiShape() == SUMOVehicleShape::POLICE) {
     738            0 :                 col = RGBColor::BLUE;
     739            0 :                 return true;
     740              :             }
     741     11033959 :             if (veh->getParameter().wasSet(VEHPARS_COLOR_SET)) {
     742      2509115 :                 col = veh->getParameter().color;
     743      2509115 :                 return true;
     744              :             }
     745      8524844 :             if (veh->getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
     746       272592 :                 col = veh->getVehicleType().getColor();
     747       272592 :                 return true;
     748              :             }
     749      8252252 :             if (&(veh->getRoute().getColor()) != &RGBColor::DEFAULT_COLOR) {
     750       195423 :                 col = veh->getRoute().getColor();
     751       195423 :                 return true;
     752              :             }
     753              :             return false;
     754              :         }
     755            0 :         case 2: {
     756            0 :             if (veh->getParameter().wasSet(VEHPARS_COLOR_SET)) {
     757            0 :                 col = veh->getParameter().color;
     758            0 :                 return true;
     759              :             }
     760              :             return false;
     761              :         }
     762            0 :         case 3: {
     763            0 :             if (veh->getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
     764            0 :                 col = veh->getVehicleType().getColor();
     765            0 :                 return true;
     766              :             }
     767              :             return false;
     768              :         }
     769            0 :         case 4: {
     770            0 :             if (&(veh->getRoute().getColor()) != &RGBColor::DEFAULT_COLOR) {
     771            0 :                 col = veh->getRoute().getColor();
     772            0 :                 return true;
     773              :             }
     774              :             return false;
     775              :         }
     776            0 :         case 5: {
     777            0 :             Position p = veh->getRoute().getEdges()[0]->getLanes()[0]->getShape()[0];
     778            0 :             const Boundary& b = ((GUINet*) MSNet::getInstance())->getBoundary();
     779            0 :             Position center = b.getCenter();
     780            0 :             double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;
     781            0 :             double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));
     782            0 :             col = RGBColor::fromHSV(hue, sat, 1.);
     783              :             return true;
     784              :         }
     785            0 :         case 6: {
     786            0 :             Position p = veh->getRoute().getEdges().back()->getLanes()[0]->getShape()[-1];
     787            0 :             const Boundary& b = ((GUINet*) MSNet::getInstance())->getBoundary();
     788            0 :             Position center = b.getCenter();
     789            0 :             double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;
     790            0 :             double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));
     791            0 :             col = RGBColor::fromHSV(hue, sat, 1.);
     792              :             return true;
     793              :         }
     794            0 :         case 7: {
     795            0 :             Position pb = veh->getRoute().getEdges()[0]->getLanes()[0]->getShape()[0];
     796            0 :             Position pe = veh->getRoute().getEdges().back()->getLanes()[0]->getShape()[-1];
     797            0 :             const Boundary& b = ((GUINet*) MSNet::getInstance())->getBoundary();
     798            0 :             double hue = 180. + atan2(pb.x() - pe.x(), pb.y() - pe.y()) * 180. / M_PI;
     799            0 :             Position minp(b.xmin(), b.ymin());
     800            0 :             Position maxp(b.xmax(), b.ymax());
     801            0 :             double sat = pb.distanceTo(pe) / minp.distanceTo(maxp);
     802            0 :             col = RGBColor::fromHSV(hue, sat, 1.);
     803              :             return true;
     804              :         }
     805              :         case 35: { // color randomly (by pointer hash)
     806              :             std::hash<const MSBaseVehicle*> ptr_hash;
     807            0 :             const double hue = (double)(ptr_hash(veh) % 360); // [0-360]
     808            0 :             const double sat = (double)((ptr_hash(veh) / 360) % 67) / 100.0 + 0.33; // [0.33-1]
     809            0 :             col = RGBColor::fromHSV(hue, sat, 1.);
     810              :             return true;
     811              :         }
     812            0 :         case 36: { // color by angle
     813            0 :             double hue = GeomHelper::naviDegree(veh->getAngle());
     814            0 :             col = RGBColor::fromHSV(hue, 1., 1.);
     815            0 :             return true;
     816              :         }
     817              :     }
     818              :     return false;
     819              : }
     820              : 
     821              : 
     822              : double
     823      8165850 : GUIBaseVehicle::getScaleValue(const GUIVisualizationSettings& s, int activeScheme) const {
     824      8165850 :     switch (activeScheme) {
     825              :         case 0: // uniform
     826              :             return 0;
     827            0 :         case 1: // selection
     828            0 :             return myVehicle.isSelected();
     829            0 :         case 2: // by speed
     830            0 :             if (myVehicle.isStopped()) {
     831            0 :                 return myVehicle.isParking() ? -2 : -1;
     832              :             }
     833            0 :             return myVehicle.getSpeed();
     834            0 :         case 3:
     835            0 :             return myVehicle.getWaitingSeconds();
     836            0 :         case 4: {
     837            0 :             MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
     838            0 :             return (microVeh != nullptr ? microVeh->getAccumulatedWaitingSeconds() : 0);
     839              :         }
     840            0 :         case 5: {
     841            0 :             MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
     842            0 :             return (microVeh != nullptr ? microVeh->getLane()->getVehicleMaxSpeed(microVeh) : myVehicle.getEdge()->getVehicleMaxSpeed(&myVehicle));
     843              :         }
     844            0 :         case 6:
     845            0 :             return myVehicle.getNumberReroutes();
     846            0 :         case 7: {
     847            0 :             MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
     848              :             return (microVeh != nullptr
     849            0 :                     ? (microVeh->getLaneChangeModel().isOpposite() ? -100 : microVeh->getBestLaneOffset())
     850            0 :                     : 0);
     851              :         }
     852            0 :         case 8:
     853            0 :             return myVehicle.getAcceleration();
     854            0 :         case 9: {
     855            0 :             MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
     856            0 :             return (microVeh != nullptr ? microVeh->getTimeGapOnLane() : 0);
     857              :         }
     858            0 :         case 10:
     859            0 :             return STEPS2TIME(myVehicle.getDepartDelay());
     860            0 :         case 11:
     861            0 :             return myVehicle.getTimeLossSeconds();
     862            0 :         case 12:
     863            0 :             return myVehicle.getStopDelay();
     864            0 :         case 13:
     865            0 :             return myVehicle.getStopArrivalDelay();
     866              :         case 14: // by numerical param value
     867              :             std::string error;
     868            0 :             std::string val = myVehicle.getPrefixedParameter(s.vehicleScaleParam, error);
     869              :             try {
     870            0 :                 if (val == "") {
     871              :                     return 0;
     872              :                 } else {
     873            0 :                     return StringUtils::toDouble(val);
     874              :                 }
     875            0 :             } catch (NumberFormatException&) {
     876              :                 try {
     877            0 :                     return StringUtils::toBool(val);
     878            0 :                 } catch (BoolFormatException&) {
     879            0 :                     WRITE_WARNINGF(TL("Vehicle parameter '%' key '%' is not a number for vehicle '%'."),
     880              :                                    myVehicle.getParameter().getParameter(s.vehicleScaleParam, "0"), s.vehicleScaleParam, myVehicle.getID());
     881              :                     return -1;
     882            0 :                 }
     883            0 :             }
     884              :     }
     885              :     return 0;
     886              : }
     887              : 
     888              : 
     889              : // ------------ Additional visualisations
     890              : bool
     891           18 : GUIBaseVehicle::hasActiveAddVisualisation(GUISUMOAbstractView* const parent, int which) const {
     892           36 :     return myAdditionalVisualizations.find(parent) != myAdditionalVisualizations.end() && (myAdditionalVisualizations.find(parent)->second & which) != 0;
     893              : }
     894              : 
     895              : 
     896              : void
     897            0 : GUIBaseVehicle::addActiveAddVisualisation(GUISUMOAbstractView* const parent, int which) {
     898            0 :     if (myAdditionalVisualizations.find(parent) == myAdditionalVisualizations.end()) {
     899            0 :         myAdditionalVisualizations[parent] = 0;
     900              :     }
     901            0 :     myAdditionalVisualizations[parent] |= which;
     902            0 :     if (which != VO_TRACK) {
     903            0 :         parent->addAdditionalGLVisualisation(this);
     904              :     }
     905            0 : }
     906              : 
     907              : 
     908              : void
     909            0 : GUIBaseVehicle::removeActiveAddVisualisation(GUISUMOAbstractView* const parent, int which) {
     910            0 :     myAdditionalVisualizations[parent] &= ~which;
     911            0 :     if (myAdditionalVisualizations[parent] == 0) {
     912              :         myAdditionalVisualizations.erase(parent);
     913              :     }
     914            0 :     parent->removeAdditionalGLVisualisation(this);
     915            0 : }
     916              : 
     917              : 
     918              : void
     919            0 : GUIBaseVehicle::drawRoute(const GUIVisualizationSettings& s, int routeNo, double darken, bool future, bool noLoop) const {
     920            0 :     RGBColor vehColor = setColor(s);
     921            0 :     RGBColor darker = vehColor.changedBrightness((int)(darken * -255));
     922            0 :     if (darker == RGBColor::BLACK) {
     923            0 :         darker = vehColor.multiply(1 - darken);
     924              :     }
     925            0 :     GLHelper::setColor(darker);
     926            0 :     if (routeNo == 0) {
     927            0 :         drawRouteHelper(s, myVehicle.getRoutePtr(), future, noLoop, darker);
     928            0 :         return;
     929              :     }
     930            0 :     ConstMSRoutePtr route = myRoutes->getRoute(routeNo - 1); // only prior routes are stored
     931            0 :     if (route != nullptr) {
     932            0 :         drawRouteHelper(s, route, future, noLoop, darker);
     933              :     }
     934              : }
     935              : 
     936              : 
     937              : void
     938            0 : GUIBaseVehicle::drawStopLabels(const GUIVisualizationSettings& s, bool noLoop, const RGBColor& col) const {
     939              :     // (vertical shift for repeated stops at the same position
     940              :     std::map<const MSLane*, int> repeat; // count repeated occurrences of the same position
     941            0 :     int stopIndex = 0;
     942            0 :     for (const MSStop& stop : myVehicle.getStops()) {
     943              :         double stopLanePos;
     944            0 :         if (stop.getSpeed() > 0) {
     945            0 :             stopLanePos = stop.reached ? stop.pars.endPos : stop.pars.startPos;
     946              :         } else {
     947            0 :             stopLanePos = stop.reached ? myVehicle.getPositionOnLane() : MAX2(0.0, stop.getEndPos(myVehicle));
     948              :         }
     949            0 :         if (stop.isOpposite && !stop.reached) {
     950            0 :             stopLanePos = stop.lane->getLength() - stopLanePos;
     951              :         }
     952            0 :         Position pos = stop.lane->geometryPositionAtOffset(stopLanePos);
     953            0 :         GLHelper::setColor(col);
     954            0 :         GLHelper::drawBoxLines(stop.lane->getShape().getOrthogonal(pos, 10, true, stop.lane->getWidth()), 0.1);
     955            0 :         std::string label = (stop.getSpeed() > 0
     956            0 :                              ? (stop.reached ? "passing waypoint" : "waypoint ")
     957            0 :                              : (stop.reached ? "stopped" : "stop "));
     958            0 :         if (!stop.reached) {
     959            0 :             label += toString(stopIndex);
     960              :         }
     961              : 
     962            0 :         if (stop.isOpposite) {
     963              :             label += " (opposite)";
     964              :         }
     965              : #ifdef _DEBUG
     966              :         label += " (" + toString(stop.edge - myVehicle.getCurrentRouteEdge()) + "e)";
     967              : #endif
     968            0 :         if (myVehicle.isStoppedTriggered()) {
     969              :             label += " triggered:";
     970            0 :             if (stop.triggered) {
     971              :                 label += "person";
     972            0 :                 if (stop.numExpectedPerson > 0) {
     973            0 :                     label += "(" + toString(stop.numExpectedPerson) + ")";
     974              :                 }
     975              :             }
     976            0 :             if (stop.containerTriggered) {
     977              :                 label += "container";
     978            0 :                 if (stop.numExpectedContainer > 0) {
     979            0 :                     label += "(" + toString(stop.numExpectedContainer) + ")";
     980              :                 }
     981              :             }
     982            0 :             if (stop.joinTriggered) {
     983              :                 label += "join";
     984            0 :                 if (stop.pars.join != "") {
     985            0 :                     label += "(" + stop.pars.join + ")";
     986              :                 }
     987              :             }
     988              :         }
     989            0 :         if (stop.pars.ended >= 0 && MSGlobals::gUseStopEnded) {
     990            0 :             label += " ended:" + time2string(stop.pars.ended);
     991            0 :         } else if (stop.pars.until >= 0) {
     992            0 :             label += " until:" + time2string(stop.pars.until);
     993              :         }
     994            0 :         if (stop.duration >= 0 || stop.pars.duration > 0) {
     995            0 :             if (STEPS2TIME(stop.duration) > 3600 * 24) {
     996              :                 label += " duration:1day+";
     997              :             } else {
     998            0 :                 label += " duration:" + time2string(stop.duration);
     999              :             }
    1000              :         }
    1001            0 :         if (stop.getSpeed() > 0) {
    1002            0 :             if (stop.skipOnDemand) {
    1003              :                 label += " onDemand (skipped)";
    1004              :             } else {
    1005            0 :                 label += " speed:" + toString(stop.getSpeed());
    1006              :             }
    1007              :         }
    1008            0 :         if (stop.pars.actType != "") {
    1009            0 :             label += " actType:" + stop.pars.actType;
    1010              :         }
    1011            0 :         const double nameSize = s.vehicleName.size / s.scale;
    1012            0 :         Position pos2 = pos - Position(0, nameSize * repeat[stop.lane]);
    1013            0 :         if (noLoop && repeat[stop.lane] > 0) {
    1014              :             break;
    1015              :         }
    1016            0 :         GLHelper::drawTextSettings(s.vehicleText, label, pos2, s.scale, s.angle, 1.0);
    1017            0 :         repeat[stop.lane]++;
    1018            0 :         stopIndex++;
    1019              :     }
    1020              :     // indicate arrivalPos if set
    1021            0 :     if (myVehicle.getParameter().wasSet(VEHPARS_ARRIVALPOS_SET) || myVehicle.getArrivalLane() >= 0) {
    1022            0 :         const int arrivalEdge = myVehicle.getParameter().arrivalEdge >= 0
    1023            0 :                                 ? myVehicle.getParameter().arrivalEdge
    1024            0 :                                 : (int)myVehicle.getRoute().getEdges().size() - 1;
    1025            0 :         const MSLane* arrivalLane = myVehicle.getRoute().getEdges()[arrivalEdge]->getLanes()[MAX2(0, myVehicle.getArrivalLane())];
    1026            0 :         Position pos = arrivalLane->geometryPositionAtOffset(myVehicle.getArrivalPos());
    1027            0 :         GLHelper::setColor(col);
    1028            0 :         GLHelper::drawBoxLines(arrivalLane->getShape().getOrthogonal(pos, 10, true, arrivalLane->getWidth() * 0.5,  90), 0.1);
    1029            0 :         GLHelper::drawBoxLines(arrivalLane->getShape().getOrthogonal(pos, 10, true, arrivalLane->getWidth() * 0.5, 270), 0.1);
    1030            0 :         GLHelper::drawTextSettings(s.vehicleText, "arrival", pos, s.scale, s.angle, 1.0);
    1031              : 
    1032              :     }
    1033            0 : }
    1034              : 
    1035              : void
    1036            0 : GUIBaseVehicle::drawParkingInfo(const GUIVisualizationSettings& s) const {
    1037            0 :     if (s.showParkingInfo) {
    1038            0 :         const StoppingPlaceMemory* pm = myVehicle.getParkingMemory();
    1039            0 :         if (pm != nullptr) {
    1040            0 :             for (auto item : *pm) {
    1041            0 :                 const GUIParkingArea* pa = dynamic_cast<const GUIParkingArea*>(item.first);
    1042            0 :                 if (item.second.blockedAtTime >= 0) {
    1043            0 :                     std::string seenAgo = time2string(SIMSTEP - item.second.blockedAtTime);
    1044              :                     //if (item.second.blockedAtTime >= 0) {
    1045              :                     //    seenAgo += ", " + time2string(SIMSTEP - item.second.blockedAtTimeLocal);
    1046              :                     //}
    1047            0 :                     GLHelper::drawTextSettings(s.vehicleValue, seenAgo, pa->getSignPos(), s.scale, s.angle, 1.0);
    1048              :                 }
    1049            0 :                 if (item.second.score != "") {
    1050            0 :                     const double dist = 0.4 * (s.vehicleText.scaledSize(s.scale) + s.vehicleValue.scaledSize(s.scale));
    1051              :                     Position shift(0, -dist);
    1052            0 :                     GLHelper::drawTextSettings(s.vehicleText, item.second.score, pa->getSignPos() + shift, s.scale, s.angle, 1.0);
    1053              :                 }
    1054              :             }
    1055              :         }
    1056              :     }
    1057            0 : }
    1058              : 
    1059              : void
    1060            0 : GUIBaseVehicle::drawChargingInfo(const GUIVisualizationSettings& s) const {
    1061            0 :     if (s.showChargingInfo) {
    1062            0 :         const StoppingPlaceMemory* pm = myVehicle.getChargingMemory();
    1063            0 :         if (pm != nullptr) {
    1064            0 :             for (auto item : *pm) {
    1065            0 :                 const GUIChargingStation* cs = dynamic_cast<const GUIChargingStation*>(item.first);
    1066            0 :                 if (item.second.blockedAtTime >= 0) {
    1067            0 :                     std::string seenAgo = time2string(SIMSTEP - item.second.blockedAtTime);
    1068            0 :                     GLHelper::drawTextSettings(s.vehicleValue, seenAgo, cs->getSignPos(), s.scale, s.angle, 1.0);
    1069              :                 }
    1070            0 :                 if (item.second.score != "") {
    1071            0 :                     const double dist = 0.4 * (s.vehicleText.scaledSize(s.scale) + s.vehicleValue.scaledSize(s.scale));
    1072              :                     Position shift(0, -dist);
    1073            0 :                     GLHelper::drawTextSettings(s.vehicleText, item.second.score, cs->getSignPos() + shift, s.scale, s.angle, 1.0);
    1074              :                 }
    1075              :             }
    1076              :         }
    1077              :     }
    1078            0 : }
    1079              : 
    1080              : const GUIBaseVehicle::Seat&
    1081       214021 : GUIBaseVehicle::getSeatPosition(int personIndex) const {
    1082              :     /// if there are not enough seats in the vehicle people have to squeeze onto the last seat
    1083       214021 :     return mySeatPositions[MIN2(personIndex, (int)mySeatPositions.size() - 1)];
    1084              : }
    1085              : 
    1086              : const GUIBaseVehicle::Seat&
    1087         5850 : GUIBaseVehicle::getContainerPosition(int containerIndex) const {
    1088              :     /// if there are not enough positions in the vehicle containers have to squeeze onto the last position
    1089         5850 :     return myContainerPositions[MIN2(containerIndex, (int)myContainerPositions.size() - 1)];
    1090              : }
    1091              : 
    1092              : 
    1093              : void
    1094      8949371 : GUIBaseVehicle::drawAction_drawPersonsAndContainers(const GUIVisualizationSettings& s) const {
    1095      8949371 :     if (myVehicle.myPersonDevice != nullptr) {
    1096              :         const std::vector<MSTransportable*>& ps = myVehicle.myPersonDevice->getTransportables();
    1097              :         int personIndex = 0;
    1098       222392 :         for (std::vector<MSTransportable*>::const_iterator i = ps.begin(); i != ps.end(); ++i) {
    1099       214021 :             GUIPerson* person = dynamic_cast<GUIPerson*>(*i);
    1100              :             assert(person != 0);
    1101       214021 :             person->setPositionInVehicle(getSeatPosition(personIndex++));
    1102       214021 :             person->drawGL(s);
    1103              :         }
    1104              :     }
    1105      8949371 :     if (myVehicle.myContainerDevice != nullptr) {
    1106              :         const std::vector<MSTransportable*>& cs = myVehicle.myContainerDevice->getTransportables();
    1107              :         int containerIndex = 0;
    1108        10996 :         for (std::vector<MSTransportable*>::const_iterator i = cs.begin(); i != cs.end(); ++i) {
    1109         5850 :             GUIContainer* container = dynamic_cast<GUIContainer*>(*i);
    1110              :             assert(container != 0);
    1111         5850 :             container->setPositionInVehicle(getContainerPosition(containerIndex++));
    1112         5850 :             container->drawGL(s);
    1113              :         }
    1114              :     }
    1115              : #ifdef DRAW_BOUNDING_BOX
    1116              :     if (!MSGlobals::gUseMesoSim) {
    1117              :         MSVehicle& microVeh = dynamic_cast<MSVehicle&>(myVehicle);
    1118              :         GLHelper::pushName(getGlID());
    1119              :         GLHelper::pushMatrix();
    1120              :         glTranslated(0, 0, getType());
    1121              :         PositionVector smallBB = microVeh.getBoundingPoly();
    1122              :         glColor3d(0.5, .8, 0);
    1123              :         GLHelper::drawBoxLines(smallBB, 0.3);
    1124              :         glTranslated(0, 0, 0.1);
    1125              :         PositionVector boundingBox = microVeh.getBoundingBox();
    1126              :         boundingBox.push_back(boundingBox.front());
    1127              :         glColor3d(1, 0, 0);
    1128              :         GLHelper::drawBoxLines(boundingBox, 0.15);
    1129              :         GLHelper::popMatrix();
    1130              :         GLHelper::popName();
    1131              :     }
    1132              : #endif
    1133      8949371 : }
    1134              : 
    1135              : bool
    1136      8936838 : GUIBaseVehicle::drawReversed(const GUIVisualizationSettings& s) const {
    1137      8936838 :     return myVehicle.isReversed() && s.drawReversed;
    1138              : }
    1139              : 
    1140              : bool
    1141       220182 : GUIBaseVehicle::drawAction_drawVehicleAsPolyWithCarriagges(const GUIVisualizationSettings& s, double scaledLength, bool asImage) const {
    1142       224540 :     if (getVType().getParameter().carriageLength > 0 &&
    1143         4358 :             (!myVehicle.isParking() || myVehicle.getNextStop().parkingarea == nullptr || myVehicle.getNextStop().parkingarea->parkOnRoad())) {
    1144         4358 :         drawAction_drawCarriageClass(s, asImage);
    1145         4358 :         return true;
    1146              :     } else {
    1147       232174 :         if (asImage && GUIBaseVehicleHelper::drawAction_drawVehicleAsImage(
    1148       215824 :                     s, getVType().getImgFile(), this, getVType().getWidth(), scaledLength)) {
    1149              :             return false;
    1150              :         }
    1151       415298 :         GUIBaseVehicleHelper::drawAction_drawVehicleAsPoly(s, getVType().getGuiShape(), getVType().getWidth(), scaledLength, -1, myVehicle.isStopped(), drawReversed(s));
    1152       207649 :         return false;
    1153              :     }
    1154              : }
    1155              : 
    1156              : 
    1157              : int
    1158      8949371 : GUIBaseVehicle::getNumPassengers() const {
    1159      8949371 :     if (myVehicle.getPersonDevice() != nullptr) {
    1160         8371 :         return (int)myVehicle.getPersonDevice()->size();
    1161              :     }
    1162              :     return 0;
    1163              : }
    1164              : 
    1165              : 
    1166              : int
    1167      8949371 : GUIBaseVehicle::getNumContainers() const {
    1168      8949371 :     if (myVehicle.getContainerDevice() != nullptr) {
    1169         5146 :         return (int)myVehicle.getContainerDevice()->size();
    1170              :     }
    1171              :     return 0;
    1172              : }
    1173              : 
    1174              : std::string
    1175            0 : GUIBaseVehicle::getDeviceDescription() {
    1176              :     std::vector<std::string> devs;
    1177            0 :     for (MSDevice* d : myVehicle.getDevices()) {
    1178            0 :         devs.push_back(d->deviceName());
    1179              :     }
    1180            0 :     return joinToString(devs, " ");
    1181            0 : }
    1182              : 
    1183              : 
    1184              : void
    1185     17912323 : GUIBaseVehicle::computeSeats(const Position& front, const Position& back, double seatOffset, int maxSeats, double exaggeration, int& requiredSeats, Seats& into, double extraOffset) const {
    1186     17912323 :     if (requiredSeats <= 0) {
    1187              :         return;
    1188              :     }
    1189              :     maxSeats = MAX2(maxSeats, 1); // compute at least one seat
    1190        13353 :     seatOffset *= exaggeration;
    1191        13353 :     const double vehWidth = getVType().getSeatingWidth() * exaggeration;
    1192              :     const double length = front.distanceTo2D(back);
    1193        13353 :     const int rowSize = MAX2(1, (int)floor(vehWidth / seatOffset));
    1194        13353 :     const double frontSeatPos = getVType().getFrontSeatPos() + extraOffset;
    1195        13353 :     const double rowOffset = MAX2(1.0, (length - frontSeatPos - 1)) / ceil((double)maxSeats / rowSize);
    1196        13353 :     const double sideOffset = (rowSize - 1) / 2.0 * seatOffset;
    1197        13353 :     double rowPos = frontSeatPos - rowOffset;
    1198              :     double angle = back.angleTo2D(front);
    1199        13353 :     const int fillDirection = MSGlobals::gLefthand ? -1 : 1;
    1200              :     //if (myVehicle.getID() == "v0") std::cout << SIMTIME << " seatOffset=" << seatOffset << " max=" << maxSeats << " ex=" << exaggeration << " req=" << requiredSeats << " rowSize=" << rowSize << " sideOffset=" << sideOffset << " front=" << front << " back=" << back << " a=" << angle << " da=" << RAD2DEG(angle) << "\n";
    1201       231788 :     for (int i = 0; requiredSeats > 0 && i < maxSeats; i++) {
    1202       218435 :         int seat = (i % rowSize);
    1203       218435 :         if (seat == 0) {
    1204        81067 :             rowPos += rowOffset;
    1205              :         }
    1206       218435 :         into.push_back(Seat(PositionVector::positionAtOffset2D(front, back, rowPos, (sideOffset - seat * seatOffset) * fillDirection), angle));
    1207       218435 :         requiredSeats--;
    1208              :     }
    1209              : }
    1210              : 
    1211              : 
    1212              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1