LCOV - code coverage report
Current view: top level - src/guisim - GUIBaseVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 30.8 % 610 188
Test Date: 2025-12-06 15:35:27 Functions: 37.0 % 54 20

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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       794154 : GUIBaseVehicle::GUIBaseVehicle(MSBaseVehicle& vehicle) :
     316              :     GUIGlObject(GLO_VEHICLE, vehicle.getID(), GUIIconSubSys::getIcon(GUIIcon::VEHICLE)),
     317       794154 :     myVehicle(vehicle),
     318       794154 :     myPopup(nullptr) {
     319              :     // as it is possible to show all vehicle routes, we have to store them... (bug [ 2519761 ])
     320       794154 :     myRoutes = MSDevice_Vehroutes::buildVehicleDevices(myVehicle, myVehicle.myDevices, 5);
     321       794154 :     myVehicle.myMoveReminders.push_back(std::make_pair(myRoutes, 0.));
     322       794154 :     mySeatPositions.push_back(Seat()); // ensure length 1
     323       794154 :     myContainerPositions.push_back(Seat()); // ensure length 1
     324       794154 : }
     325              : 
     326              : 
     327       794098 : GUIBaseVehicle::~GUIBaseVehicle() {
     328       794098 :     myLock.lock();
     329       794113 :     for (std::map<GUISUMOAbstractView*, int>::iterator i = myAdditionalVisualizations.begin(); i != myAdditionalVisualizations.end(); ++i) {
     330           15 :         if (i->first->getTrackedID() == getGlID()) {
     331            3 :             i->first->stopTrack();
     332              :         }
     333           19 :         while (i->first->removeAdditionalGLVisualisation(this));
     334              :     }
     335       794098 :     myLock.unlock();
     336       794098 :     delete myRoutes;
     337       794098 :     if (myPopup != nullptr) {
     338            0 :         myPopup->getParentView()->destroyPopup();
     339              :     }
     340      1588196 : }
     341              : 
     342              : 
     343              : GUIGLObjectPopupMenu*
     344            0 : GUIBaseVehicle::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
     345            0 :     GUIGLObjectPopupMenu* ret = new GUIBaseVehiclePopupMenu(app, parent, this);
     346            0 :     buildPopupHeader(ret, app);
     347            0 :     buildCenterPopupEntry(ret);
     348            0 :     buildNameCopyPopupEntry(ret);
     349            0 :     buildSelectionPopupEntry(ret);
     350              :     //
     351            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_ROUTE)) {
     352            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide Current Route"), nullptr, ret, MID_HIDE_CURRENTROUTE);
     353              :     } else {
     354            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show Current Route"), nullptr, ret, MID_SHOW_CURRENTROUTE);
     355              :     }
     356            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_FUTURE_ROUTE)) {
     357            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide Future Route"), nullptr, ret, MID_HIDE_FUTUREROUTE);
     358              :     } else {
     359            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show Future Route"), nullptr, ret, MID_SHOW_FUTUREROUTE);
     360              :     }
     361            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_ALL_ROUTES)) {
     362            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide All Routes"), nullptr, ret, MID_HIDE_ALLROUTES);
     363              :     } else {
     364            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show All Routes"), nullptr, ret, MID_SHOW_ALLROUTES);
     365              :     }
     366            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_ROUTE_NOLOOP)) {
     367            0 :         FXMenuCheck* showLoops = new FXMenuCheck(ret, TL("Draw looped routes"), ret, MID_HIDE_ROUTE_NOLOOPS);
     368            0 :         showLoops->setCheck(false);
     369              :     } else {
     370            0 :         FXMenuCheck* showLoops = new FXMenuCheck(ret, TL("Draw looped routes"), ret, MID_SHOW_ROUTE_NOLOOPS);
     371            0 :         showLoops->setCheck(true);
     372              :     }
     373            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_BEST_LANES)) {
     374            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide Best Lanes"), nullptr, ret, MID_HIDE_BEST_LANES);
     375              :     } else {
     376            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show Best Lanes"), nullptr, ret, MID_SHOW_BEST_LANES);
     377              :     }
     378            0 :     if (hasActiveAddVisualisation(&parent, VO_SHOW_LFLINKITEMS)) {
     379            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Hide Link Items"), nullptr, ret, MID_HIDE_LFLINKITEMS);
     380              :     } else {
     381            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Show Link Items"), nullptr, ret, MID_SHOW_LFLINKITEMS);
     382              :     }
     383            0 :     new FXMenuSeparator(ret);
     384            0 :     if (parent.getTrackedID() != getGlID()) {
     385            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Start Tracking"), nullptr, ret, MID_START_TRACK);
     386              :     } else {
     387            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Stop Tracking"), nullptr, ret, MID_STOP_TRACK);
     388              :     }
     389            0 :     GUIDesigns::buildFXMenuCommand(ret, TL("Select Foes"), nullptr, ret, MID_SHOW_FOES);
     390            0 :     if (myVehicle.getPersons().size() + myVehicle.getContainers().size() > 0) {
     391            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Select transported"), nullptr, ret, MID_SELECT_TRANSPORTED);
     392              :     }
     393            0 :     GUIDesigns::buildFXMenuCommand(ret, myVehicle.isStopped() ? TL("Abort stop") : TL("Stop"), nullptr, ret, MID_TOGGLE_STOP);
     394            0 :     GUIDesigns::buildFXMenuCommand(ret, TL("Remove"), nullptr, ret, MID_REMOVE_OBJECT);
     395              : 
     396            0 :     new FXMenuSeparator(ret);
     397              :     //
     398            0 :     buildShowParamsPopupEntry(ret, false);
     399            0 :     buildShowTypeParamsPopupEntry(ret);
     400            0 :     buildPositionCopyEntry(ret, app);
     401            0 :     myPopup = ret;
     402            0 :     return ret;
     403              : }
     404              : 
     405              : 
     406              : void
     407            0 : GUIBaseVehicle::removedPopupMenu() {
     408            0 :     myPopup = nullptr;
     409            0 : }
     410              : 
     411              : 
     412              : double
     413     11947537 : GUIBaseVehicle::getExaggeration(const GUIVisualizationSettings& s) const {
     414     11947537 :     return (s.vehicleSize.getExaggeration(s, this) *
     415     11947537 :             s.vehicleScaler.getScheme().getColor(getScaleValue(s, s.vehicleScaler.getActive())));
     416              : }
     417              : 
     418              : 
     419              : Boundary
     420          497 : GUIBaseVehicle::getCenteringBoundary() const {
     421          497 :     Boundary b;
     422          497 :     b.add(getVisualPosition(GUIGlobals::gSecondaryShape));
     423          497 :     b.grow(myVehicle.getVehicleType().getLength());
     424          497 :     return b;
     425              : }
     426              : 
     427              : 
     428              : const std::string
     429            0 : GUIBaseVehicle::getOptionalName() const {
     430            0 :     return myVehicle.getParameter().getParameter("name", "");
     431              : }
     432              : 
     433              : 
     434              : void
     435     13227480 : GUIBaseVehicle::drawOnPos(const GUIVisualizationSettings& s, const Position& pos, const double angle) const {
     436     13227480 :     GLHelper::pushName(getGlID());
     437     13227480 :     GLHelper::pushMatrix();
     438     13227480 :     Position p1 = pos;
     439     13227480 :     const double degAngle = RAD2DEG(angle + M_PI / 2.);
     440              :     const double length = getVType().getLength();
     441     13227480 :     if (s.trueZ) {
     442          296 :         glTranslated(p1.x(), p1.y(), p1.z() + 1);
     443              :     } else {
     444     13227184 :         glTranslated(p1.x(), p1.y(), getType());
     445              :     }
     446     13227480 :     glRotated(degAngle, 0, 0, 1);
     447     13227480 :     RGBColor col = setColor(s);
     448              :     // scale
     449     13227480 :     const double upscale = getExaggeration(s);
     450     13227480 :     const bool s2 = s.secondaryShape;
     451              : 
     452     13227480 :     if (upscale > 1 && s.laneWidthExaggeration > 1 && myVehicle.isOnRoad()) {
     453              :         // optionally shift according to edge exaggeration
     454            0 :         double offsetFromLeftBorder = myVehicle.getCurrentEdge()->getWidth() - myVehicle.getRightSideOnEdge() - myVehicle.getVehicleType().getWidth() / 2;
     455            0 :         glTranslated((s.laneWidthExaggeration - 1) * -offsetFromLeftBorder / 2, 0, 0);
     456              :     }
     457              : 
     458     13227480 :     double upscaleLength = MSTrainHelper::getUpscaleLength(upscale, length, getVType().getWidth(), s.vehicleQuality);
     459     13227480 :     glScaled(upscale, upscaleLength, 1);
     460              :     /*
     461              :         MSLaneChangeModel::DK2004 &m2 = static_cast<MSLaneChangeModel::DK2004&>(veh->getLaneChangeModel());
     462              :         if((m2.getState()&LCA_URGENT)!=0) {
     463              :             glColor3d(1, .4, .4);
     464              :         } else if((m2.getState()&LCA_SPEEDGAIN)!=0) {
     465              :             glColor3d(.4, .4, 1);
     466              :         } else {
     467              :             glColor3d(.4, 1, .4);
     468              :         }
     469              :         */
     470              :     // draw the vehicle
     471              :     bool drawCarriages = false;
     472              :     // do not upscale vehicles on physically impossible geometry factors > 1
     473     13227480 :     const double geometryFactor = (s.scaleLength ?
     474     13227480 :                                    MIN2(1.0, (myVehicle.getLane() != nullptr
     475     11947537 :                                      ? myVehicle.getLane()->getLengthGeometryFactor(s2)
     476      1279943 :                                      : (myVehicle.getEdge()->getLanes().size() > 0 ? myVehicle.getEdge()->getLanes()[0]->getLengthGeometryFactor(s2) : 1)))
     477              :                                    : 1);
     478     13227480 :     double scaledLength = length * geometryFactor;
     479     13227480 :     if (col.alpha() != 0) {
     480     13227480 :         switch (s.vehicleQuality) {
     481     12976983 :             case 0:
     482     12976983 :                 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       241947 :             case 2:
     488       241947 :                 drawCarriages = drawAction_drawVehicleAsPolyWithCarriagges(s, scaledLength);
     489              :                 // draw flashing blue light for emergency vehicles
     490       241947 :                 if (getVType().getGuiShape() == SUMOVehicleShape::EMERGENCY) {
     491            0 :                     glTranslated(0, 0, .1);
     492            0 :                     drawAction_drawVehicleBlueLight();
     493              :                 }
     494              :                 break;
     495         8550 :             case 3:
     496         8550 :                 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     13227480 :         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     13227480 :                 && (!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     13227480 :         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     13227480 :         if (s.showBlinker) {
     539     13227480 :             glTranslated(0, 0, .1);
     540     13227480 :             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       615305 :                 case SUMOVehicleShape::MOTORCYCLE:
     552              :                 case SUMOVehicleShape::MOPED:
     553       615305 :                     drawAction_drawVehicleBlinker(scaledLength);
     554       615305 :                     drawAction_drawVehicleBrakeLight(scaledLength, true);
     555              :                     break;
     556     12031085 :                 default:
     557              :                     // only SUMOVehicleShape::RAIL_CAR has blinkers and brake lights but they are drawn along with the carriages
     558     12031085 :                     if (!drawCarriages) {
     559     12029692 :                         drawAction_drawVehicleBlinker(scaledLength);
     560     12029692 :                         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     13328637 :     glTranslated(0, MIN2(scaledLength / 2, double(5)), -getType()); // drawing name at GLO_MAX fails unless translating z
     592     13227480 :     glScaled(1 / upscale, 1 / upscaleLength, 1);
     593     13227480 :     glRotated(-degAngle, 0, 0, 1);
     594     13227480 :     drawName(Position(0, 0), s.scale, s.vehicleName, s.angle);
     595     13227480 :     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     13227480 :     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 :         if (value != s.MISSING_DATA) {
     607            0 :             GLHelper::drawTextSettings(s.vehicleValue, toString(value), Position(0, 0), s.scale, s.angle);
     608              :         }
     609              :     }
     610     13227480 :     if (s.vehicleScaleValue.show(this)) {
     611            0 :         glRotated(-s.angle, 0, 0, 1);
     612            0 :         glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
     613            0 :         glRotated(s.angle, 0, 0, 1);
     614            0 :         const double value = getScaleValue(s, s.vehicleScaler.getActive());
     615            0 :         if (value != s.MISSING_DATA) {
     616            0 :             GLHelper::drawTextSettings(s.vehicleScaleValue, toString(value), Position(0, 0), s.scale, s.angle);
     617              :         }
     618              :     }
     619     13227480 :     if (s.vehicleText.show(this)) {
     620              :         std::string error;
     621            0 :         std::string value = myVehicle.getPrefixedParameter(s.vehicleTextParam, error);
     622            0 :         if (value != "") {
     623            0 :             auto lines = StringTokenizer(value, StringTokenizer::NEWLINE).getVector();
     624            0 :             glRotated(-s.angle, 0, 0, 1);
     625            0 :             glTranslated(0, 0.7 * s.vehicleText.scaledSize(s.scale) * (double)lines.size(), 0);
     626            0 :             glRotated(s.angle, 0, 0, 1);
     627            0 :             for (std::string& line : lines) {
     628            0 :                 GLHelper::drawTextSettings(s.vehicleText, line, Position(0, 0), s.scale, s.angle);
     629            0 :                 glRotated(-s.angle, 0, 0, 1);
     630            0 :                 glTranslated(0, -0.7 * s.vehicleText.scaledSize(s.scale), 0);
     631            0 :                 glRotated(s.angle, 0, 0, 1);
     632              :             }
     633            0 :         }
     634              :     }
     635     13227480 :     if (s.showParkingInfo && myAdditionalVisualizations.size() != 0 && hasActiveAddVisualisation(
     636            0 :                 myAdditionalVisualizations.begin()->first, VO_SHOW_ROUTE | VO_SHOW_FUTURE_ROUTE | VO_SHOW_ALL_ROUTES)) {
     637            0 :         glRotated(-s.angle, 0, 0, 1);
     638            0 :         glTranslated(0, 0.7 * s.vehicleName.scaledSize(s.scale), 0);
     639            0 :         glRotated(s.angle, 0, 0, 1);
     640            0 :         const double value = myVehicle.getNumberParkingReroutes();
     641            0 :         GLHelper::drawTextSettings(s.vehicleName, toString(value), Position(0, 0), s.scale, s.angle);
     642              :     }
     643              : 
     644     13227480 :     if (!drawCarriages) {
     645              :         mySeatPositions.clear();
     646              :         myContainerPositions.clear();
     647     13223107 :         int requiredSeats = getNumPassengers();
     648     13223107 :         int requiredContainerPositions = getNumContainers();
     649     13223107 :         const Position back = (p1 + Position(-scaledLength * upscaleLength, 0)).rotateAround2D(angle, p1);
     650     13223107 :         double extraOffset = scaledLength * 0.15;
     651     13223107 :         computeSeats(p1, back, SUMO_const_waitingPersonWidth, getVType().getPersonCapacity(), upscale, requiredSeats, mySeatPositions, extraOffset);
     652     13223107 :         computeSeats(p1, back, SUMO_const_waitingContainerWidth, getVType().getContainerCapacity(), upscale, requiredContainerPositions, myContainerPositions, extraOffset);
     653              :     }
     654              : 
     655     13227480 :     GLHelper::popMatrix();
     656     13227480 :     GLHelper::popName();
     657     13227480 :     drawAction_drawPersonsAndContainers(s);
     658     13227480 : }
     659              : 
     660              : 
     661              : void
     662     11948088 : GUIBaseVehicle::drawGL(const GUIVisualizationSettings& s) const {
     663     11948088 :     drawOnPos(s, getVisualPosition(s.secondaryShape), getVisualAngle(s.secondaryShape));
     664     11948088 : }
     665              : 
     666              : 
     667              : void
     668            4 : GUIBaseVehicle::drawGLAdditional(GUISUMOAbstractView* const parent, const GUIVisualizationSettings& s) const {
     669            4 :     if (!myVehicle.isOnRoad()) {
     670            4 :         drawGL(s);
     671              :     }
     672            4 :     GLHelper::pushName(getGlID());
     673            4 :     GLHelper::pushMatrix();
     674            4 :     glTranslated(0, 0, getType() - .1); // don't draw on top of other cars
     675            4 :     if (hasActiveAddVisualisation(parent, VO_SHOW_BEST_LANES)) {
     676            0 :         drawBestLanes();
     677              :     }
     678            4 :     bool noLoop = hasActiveAddVisualisation(parent, VO_SHOW_ROUTE_NOLOOP);
     679            4 :     if (hasActiveAddVisualisation(parent, VO_SHOW_ROUTE)) {
     680            0 :         drawRoute(s, 0, 0.25, false, noLoop);
     681              :     }
     682            4 :     if (hasActiveAddVisualisation(parent, VO_SHOW_FUTURE_ROUTE)) {
     683            0 :         drawRoute(s, 0, 0.25, true, noLoop);
     684              :     }
     685            4 :     if (hasActiveAddVisualisation(parent, VO_SHOW_ALL_ROUTES)) {
     686            0 :         if (myVehicle.getNumberReroutes() > 0) {
     687            0 :             const int noReroutePlus1 = myVehicle.getNumberReroutes() + 1;
     688            0 :             for (int i = noReroutePlus1 - 1; i >= 0; i--) {
     689            0 :                 double darken = double(0.4) / double(noReroutePlus1) * double(i);
     690            0 :                 drawRoute(s, i, darken);
     691              :             }
     692              :         } else {
     693            0 :             drawRoute(s, 0, 0.25, false, noLoop);
     694              :         }
     695              :     }
     696            4 :     if (hasActiveAddVisualisation(parent, VO_SHOW_LFLINKITEMS)) {
     697            0 :         drawAction_drawLinkItems(s);
     698              :     }
     699            4 :     GLHelper::popMatrix();
     700            4 :     GLHelper::popName();
     701            4 : }
     702              : 
     703              : 
     704              : void
     705            0 : GUIBaseVehicle::drawLinkItem(const Position& pos, SUMOTime arrivalTime, SUMOTime leaveTime, double exagerate) {
     706            0 :     glTranslated(pos.x(), pos.y(), -.1);
     707            0 :     GLHelper::drawFilledCircle(1);
     708            0 :     std::string times = toString(STEPS2TIME(arrivalTime)) + "/" + toString(STEPS2TIME(leaveTime));
     709            0 :     GLHelper::drawText(times.c_str(), Position(), .1, 1.6 * exagerate, RGBColor::GREEN, 0);
     710            0 :     glTranslated(-pos.x(), -pos.y(), .1);
     711            0 : }
     712              : 
     713              : 
     714              : RGBColor
     715     13227480 : GUIBaseVehicle::setColor(const GUIVisualizationSettings& s) const {
     716     13227480 :     RGBColor col;
     717              :     const GUIColorer& c = s.vehicleColorer;
     718     13227480 :     if (!setFunctionalColor(c.getActive(), &myVehicle, col)) {
     719      9364750 :         col = c.getScheme().getColor(getColorValue(s, c.getActive()));
     720              :     }
     721     13227480 :     GLHelper::setColor(col);
     722     13227480 :     return col;
     723              : }
     724              : 
     725              : 
     726              : bool
     727     16879349 : GUIBaseVehicle::setFunctionalColor(int activeScheme, const MSBaseVehicle* veh, RGBColor& col) {
     728     16879349 :     switch (activeScheme) {
     729     16680799 :         case 0: {
     730              :             //test for emergency vehicle
     731     16680799 :             if (veh->getVehicleType().getGuiShape() == SUMOVehicleShape::EMERGENCY) {
     732           89 :                 col = RGBColor::WHITE;
     733           89 :                 return true;
     734              :             }
     735              :             //test for firebrigade
     736     16680710 :             if (veh->getVehicleType().getGuiShape() == SUMOVehicleShape::FIREBRIGADE) {
     737            0 :                 col = RGBColor::RED;
     738            0 :                 return true;
     739              :             }
     740              :             //test for police car
     741     16680710 :             if (veh->getVehicleType().getGuiShape() == SUMOVehicleShape::POLICE) {
     742            0 :                 col = RGBColor::BLUE;
     743            0 :                 return true;
     744              :             }
     745     16680710 :             if (veh->getParameter().wasSet(VEHPARS_COLOR_SET)) {
     746      3188834 :                 col = veh->getParameter().color;
     747      3188834 :                 return true;
     748              :             }
     749     13491876 :             if (veh->getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
     750       357995 :                 col = veh->getVehicleType().getColor();
     751       357995 :                 return true;
     752              :             }
     753     13133881 :             if (&(veh->getRoute().getColor()) != &RGBColor::DEFAULT_COLOR) {
     754       322430 :                 col = veh->getRoute().getColor();
     755       322430 :                 return true;
     756              :             }
     757              :             return false;
     758              :         }
     759            0 :         case 2: {
     760            0 :             if (veh->getParameter().wasSet(VEHPARS_COLOR_SET)) {
     761            0 :                 col = veh->getParameter().color;
     762            0 :                 return true;
     763              :             }
     764              :             return false;
     765              :         }
     766            0 :         case 3: {
     767            0 :             if (veh->getVehicleType().wasSet(VTYPEPARS_COLOR_SET)) {
     768            0 :                 col = veh->getVehicleType().getColor();
     769            0 :                 return true;
     770              :             }
     771              :             return false;
     772              :         }
     773            0 :         case 4: {
     774            0 :             if (&(veh->getRoute().getColor()) != &RGBColor::DEFAULT_COLOR) {
     775            0 :                 col = veh->getRoute().getColor();
     776            0 :                 return true;
     777              :             }
     778              :             return false;
     779              :         }
     780            0 :         case 5: {
     781            0 :             Position p = veh->getRoute().getEdges()[0]->getLanes()[0]->getShape()[0];
     782            0 :             const Boundary& b = ((GUINet*) MSNet::getInstance())->getBoundary();
     783            0 :             Position center = b.getCenter();
     784            0 :             double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;
     785            0 :             double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));
     786            0 :             col = RGBColor::fromHSV(hue, sat, 1.);
     787              :             return true;
     788              :         }
     789            0 :         case 6: {
     790            0 :             Position p = veh->getRoute().getEdges().back()->getLanes()[0]->getShape()[-1];
     791            0 :             const Boundary& b = ((GUINet*) MSNet::getInstance())->getBoundary();
     792            0 :             Position center = b.getCenter();
     793            0 :             double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;
     794            0 :             double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));
     795            0 :             col = RGBColor::fromHSV(hue, sat, 1.);
     796              :             return true;
     797              :         }
     798            0 :         case 7: {
     799            0 :             Position pb = veh->getRoute().getEdges()[0]->getLanes()[0]->getShape()[0];
     800            0 :             Position pe = veh->getRoute().getEdges().back()->getLanes()[0]->getShape()[-1];
     801            0 :             const Boundary& b = ((GUINet*) MSNet::getInstance())->getBoundary();
     802            0 :             double hue = 180. + atan2(pb.x() - pe.x(), pb.y() - pe.y()) * 180. / M_PI;
     803            0 :             Position minp(b.xmin(), b.ymin());
     804            0 :             Position maxp(b.xmax(), b.ymax());
     805            0 :             double sat = pb.distanceTo(pe) / minp.distanceTo(maxp);
     806            0 :             col = RGBColor::fromHSV(hue, sat, 1.);
     807              :             return true;
     808              :         }
     809              :         case 35: { // color randomly (by pointer hash)
     810              :             std::hash<const MSBaseVehicle*> ptr_hash;
     811            0 :             const double hue = (double)(ptr_hash(veh) % 360); // [0-360]
     812            0 :             const double sat = (double)((ptr_hash(veh) / 360) % 67) / 100.0 + 0.33; // [0.33-1]
     813            0 :             col = RGBColor::fromHSV(hue, sat, 1.);
     814              :             return true;
     815              :         }
     816            0 :         case 36: { // color by angle
     817            0 :             double hue = GeomHelper::naviDegree(veh->getAngle());
     818            0 :             col = RGBColor::fromHSV(hue, 1., 1.);
     819            0 :             return true;
     820              :         }
     821              :     }
     822              :     return false;
     823              : }
     824              : 
     825              : 
     826              : double
     827     11951910 : GUIBaseVehicle::getScaleValue(const GUIVisualizationSettings& s, int activeScheme) const {
     828     11951910 :     switch (activeScheme) {
     829              :         case 0: // uniform
     830              :             return 0;
     831            0 :         case 1: // selection
     832            0 :             return myVehicle.isSelected();
     833            0 :         case 2: // by speed
     834            0 :             if (myVehicle.isStopped()) {
     835            0 :                 return myVehicle.isParking() ? -2 : -1;
     836              :             }
     837            0 :             return myVehicle.getSpeed();
     838            0 :         case 3:
     839            0 :             return myVehicle.getWaitingSeconds();
     840            0 :         case 4: {
     841            0 :             MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
     842            0 :             return (microVeh != nullptr ? microVeh->getAccumulatedWaitingSeconds() : 0);
     843              :         }
     844            0 :         case 5: {
     845            0 :             MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
     846            0 :             return (microVeh != nullptr ? microVeh->getLane()->getVehicleMaxSpeed(microVeh) : myVehicle.getEdge()->getVehicleMaxSpeed(&myVehicle));
     847              :         }
     848            0 :         case 6:
     849            0 :             return myVehicle.getNumberReroutes();
     850            0 :         case 7: {
     851            0 :             MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
     852              :             return (microVeh != nullptr
     853            0 :                     ? (microVeh->getLaneChangeModel().isOpposite() ? -100 : microVeh->getBestLaneOffset())
     854            0 :                     : 0);
     855              :         }
     856            0 :         case 8:
     857            0 :             return myVehicle.getAcceleration();
     858            0 :         case 9: {
     859            0 :             MSVehicle* microVeh = dynamic_cast<MSVehicle*>(&myVehicle);
     860            0 :             return (microVeh != nullptr ? microVeh->getTimeGapOnLane() : 0);
     861              :         }
     862            0 :         case 10:
     863            0 :             return STEPS2TIME(myVehicle.getDepartDelay());
     864            0 :         case 11:
     865            0 :             return myVehicle.getTimeLossSeconds();
     866            0 :         case 12:
     867            0 :             return myVehicle.getStopDelay();
     868            0 :         case 13:
     869            0 :             return myVehicle.getStopArrivalDelay();
     870              :         case 14: // by numerical param value
     871              :             std::string error;
     872            0 :             std::string val = myVehicle.getPrefixedParameter(s.vehicleScaleParam, error);
     873              :             try {
     874            0 :                 if (val == "") {
     875              :                     return 0;
     876              :                 } else {
     877            0 :                     return StringUtils::toDouble(val);
     878              :                 }
     879            0 :             } catch (NumberFormatException&) {
     880              :                 try {
     881            0 :                     return StringUtils::toBool(val);
     882            0 :                 } catch (BoolFormatException&) {
     883            0 :                     WRITE_WARNINGF(TL("Vehicle parameter '%' key '%' is not a number for vehicle '%'."),
     884              :                                    myVehicle.getParameter().getParameter(s.vehicleScaleParam, "0"), s.vehicleScaleParam, myVehicle.getID());
     885              :                     return -1;
     886            0 :                 }
     887            0 :             }
     888              :     }
     889              :     return 0;
     890              : }
     891              : 
     892              : 
     893              : // ------------ Additional visualisations
     894              : bool
     895           24 : GUIBaseVehicle::hasActiveAddVisualisation(GUISUMOAbstractView* const parent, int which) const {
     896           48 :     return myAdditionalVisualizations.find(parent) != myAdditionalVisualizations.end() && (myAdditionalVisualizations.find(parent)->second & which) != 0;
     897              : }
     898              : 
     899              : 
     900              : void
     901            3 : GUIBaseVehicle::addActiveAddVisualisation(GUISUMOAbstractView* const parent, int which) {
     902            3 :     if (myAdditionalVisualizations.find(parent) == myAdditionalVisualizations.end()) {
     903            3 :         myAdditionalVisualizations[parent] = 0;
     904              :     }
     905            3 :     myAdditionalVisualizations[parent] |= which;
     906            3 :     if (which != VO_TRACK) {
     907            0 :         parent->addAdditionalGLVisualisation(this);
     908              :     }
     909            3 : }
     910              : 
     911              : 
     912              : void
     913            0 : GUIBaseVehicle::removeActiveAddVisualisation(GUISUMOAbstractView* const parent, int which) {
     914            0 :     myAdditionalVisualizations[parent] &= ~which;
     915            0 :     if (myAdditionalVisualizations[parent] == 0) {
     916              :         myAdditionalVisualizations.erase(parent);
     917              :     }
     918            0 :     parent->removeAdditionalGLVisualisation(this);
     919            0 : }
     920              : 
     921              : 
     922              : void
     923            0 : GUIBaseVehicle::drawRoute(const GUIVisualizationSettings& s, int routeNo, double darken, bool future, bool noLoop) const {
     924            0 :     RGBColor vehColor = setColor(s);
     925            0 :     RGBColor darker = vehColor.changedBrightness((int)(darken * -255));
     926            0 :     if (darker == RGBColor::BLACK) {
     927            0 :         darker = vehColor.multiply(1 - darken);
     928              :     }
     929            0 :     GLHelper::setColor(darker);
     930            0 :     if (routeNo == 0) {
     931            0 :         drawRouteHelper(s, myVehicle.getRoutePtr(), future, noLoop, darker);
     932            0 :         return;
     933              :     }
     934            0 :     ConstMSRoutePtr route = myRoutes->getRoute(routeNo - 1); // only prior routes are stored
     935            0 :     if (route != nullptr) {
     936            0 :         drawRouteHelper(s, route, future, noLoop, darker);
     937              :     }
     938              : }
     939              : 
     940              : 
     941              : void
     942            0 : GUIBaseVehicle::drawStopLabels(const GUIVisualizationSettings& s, bool noLoop, const RGBColor& col) const {
     943              :     // (vertical shift for repeated stops at the same position
     944              :     std::map<const MSLane*, int> repeat; // count repeated occurrences of the same position
     945            0 :     int stopIndex = 0;
     946            0 :     for (const MSStop& stop : myVehicle.getStops()) {
     947              :         double stopLanePos;
     948            0 :         if (stop.getSpeed() > 0) {
     949            0 :             stopLanePos = stop.reached ? stop.pars.endPos : stop.pars.startPos;
     950              :         } else {
     951            0 :             stopLanePos = stop.reached ? myVehicle.getPositionOnLane() : MAX2(0.0, stop.getEndPos(myVehicle));
     952              :         }
     953            0 :         if (stop.isOpposite && !stop.reached) {
     954            0 :             stopLanePos = stop.lane->getLength() - stopLanePos;
     955              :         }
     956            0 :         Position pos = stop.lane->geometryPositionAtOffset(stopLanePos);
     957            0 :         GLHelper::setColor(col);
     958            0 :         GLHelper::drawBoxLines(stop.lane->getShape().getOrthogonal(pos, 10, true, stop.lane->getWidth()), 0.1);
     959            0 :         std::string label = (stop.getSpeed() > 0
     960            0 :                              ? (stop.reached ? "passing waypoint" : "waypoint ")
     961            0 :                              : (stop.reached ? "stopped" : "stop "));
     962            0 :         if (!stop.reached) {
     963            0 :             label += toString(stopIndex);
     964              :         }
     965              : 
     966            0 :         if (stop.isOpposite) {
     967              :             label += " (opposite)";
     968              :         }
     969              : #ifdef _DEBUG
     970              :         label += " (" + toString(stop.edge - myVehicle.getCurrentRouteEdge()) + "e)";
     971              : #endif
     972            0 :         if (myVehicle.isStoppedTriggered()) {
     973              :             label += " triggered:";
     974            0 :             if (stop.triggered) {
     975              :                 label += "person";
     976            0 :                 if (stop.numExpectedPerson > 0) {
     977            0 :                     label += "(" + toString(stop.numExpectedPerson) + ")";
     978              :                 }
     979              :             }
     980            0 :             if (stop.containerTriggered) {
     981              :                 label += "container";
     982            0 :                 if (stop.numExpectedContainer > 0) {
     983            0 :                     label += "(" + toString(stop.numExpectedContainer) + ")";
     984              :                 }
     985              :             }
     986            0 :             if (stop.joinTriggered) {
     987              :                 label += "join";
     988            0 :                 if (stop.pars.join != "") {
     989            0 :                     label += "(" + stop.pars.join + ")";
     990              :                 }
     991              :             }
     992              :         }
     993            0 :         if (stop.pars.ended >= 0 && MSGlobals::gUseStopEnded) {
     994            0 :             label += " ended:" + time2string(stop.pars.ended);
     995            0 :         } else if (stop.pars.until >= 0) {
     996            0 :             label += " until:" + time2string(stop.pars.until);
     997              :         }
     998            0 :         if (stop.duration >= 0 || stop.pars.duration > 0) {
     999            0 :             if (STEPS2TIME(stop.duration) > 3600 * 24) {
    1000              :                 label += " duration:1day+";
    1001              :             } else {
    1002            0 :                 label += " duration:" + time2string(stop.duration);
    1003              :             }
    1004              :         }
    1005            0 :         if (stop.getSpeed() > 0) {
    1006            0 :             if (stop.skipOnDemand) {
    1007              :                 label += " onDemand (skipped)";
    1008              :             } else {
    1009            0 :                 label += " speed:" + toString(stop.getSpeed());
    1010              :             }
    1011              :         }
    1012            0 :         if (stop.pars.actType != "") {
    1013            0 :             label += " actType:" + stop.pars.actType;
    1014              :         }
    1015            0 :         const double nameSize = s.vehicleName.size / s.scale;
    1016            0 :         Position pos2 = pos - Position(0, nameSize * repeat[stop.lane]);
    1017            0 :         if (noLoop && repeat[stop.lane] > 0) {
    1018              :             break;
    1019              :         }
    1020            0 :         GLHelper::drawTextSettings(s.vehicleText, label, pos2, s.scale, s.angle, 1.0);
    1021            0 :         repeat[stop.lane]++;
    1022            0 :         stopIndex++;
    1023              :     }
    1024              :     // indicate arrivalPos if set
    1025            0 :     if (myVehicle.getParameter().wasSet(VEHPARS_ARRIVALPOS_SET) || myVehicle.getArrivalLane() >= 0) {
    1026            0 :         const int arrivalEdge = myVehicle.getParameter().arrivalEdge >= 0
    1027            0 :                                 ? myVehicle.getParameter().arrivalEdge
    1028            0 :                                 : (int)myVehicle.getRoute().getEdges().size() - 1;
    1029            0 :         const MSLane* arrivalLane = myVehicle.getRoute().getEdges()[arrivalEdge]->getLanes()[MAX2(0, myVehicle.getArrivalLane())];
    1030            0 :         Position pos = arrivalLane->geometryPositionAtOffset(myVehicle.getArrivalPos());
    1031            0 :         GLHelper::setColor(col);
    1032            0 :         GLHelper::drawBoxLines(arrivalLane->getShape().getOrthogonal(pos, 10, true, arrivalLane->getWidth() * 0.5,  90), 0.1);
    1033            0 :         GLHelper::drawBoxLines(arrivalLane->getShape().getOrthogonal(pos, 10, true, arrivalLane->getWidth() * 0.5, 270), 0.1);
    1034            0 :         GLHelper::drawTextSettings(s.vehicleText, "arrival", pos, s.scale, s.angle, 1.0);
    1035              : 
    1036              :     }
    1037            0 : }
    1038              : 
    1039              : void
    1040            0 : GUIBaseVehicle::drawParkingInfo(const GUIVisualizationSettings& s) const {
    1041            0 :     if (s.showParkingInfo) {
    1042            0 :         const StoppingPlaceMemory* pm = myVehicle.getParkingMemory();
    1043            0 :         if (pm != nullptr) {
    1044            0 :             for (auto item : *pm) {
    1045            0 :                 const GUIParkingArea* pa = dynamic_cast<const GUIParkingArea*>(item.first);
    1046            0 :                 if (item.second.blockedAtTime >= 0) {
    1047            0 :                     std::string seenAgo = time2string(SIMSTEP - item.second.blockedAtTime);
    1048              :                     //if (item.second.blockedAtTime >= 0) {
    1049              :                     //    seenAgo += ", " + time2string(SIMSTEP - item.second.blockedAtTimeLocal);
    1050              :                     //}
    1051            0 :                     GLHelper::drawTextSettings(s.vehicleValue, seenAgo, pa->getSignPos(), s.scale, s.angle, 1.0);
    1052              :                 }
    1053            0 :                 if (item.second.score != "") {
    1054            0 :                     const double dist = 0.4 * (s.vehicleText.scaledSize(s.scale) + s.vehicleValue.scaledSize(s.scale));
    1055              :                     Position shift(0, -dist);
    1056            0 :                     GLHelper::drawTextSettings(s.vehicleText, item.second.score, pa->getSignPos() + shift, s.scale, s.angle, 1.0);
    1057              :                 }
    1058              :             }
    1059              :         }
    1060              :     }
    1061            0 : }
    1062              : 
    1063              : void
    1064            0 : GUIBaseVehicle::drawChargingInfo(const GUIVisualizationSettings& s) const {
    1065            0 :     if (s.showChargingInfo) {
    1066            0 :         const StoppingPlaceMemory* pm = myVehicle.getChargingMemory();
    1067            0 :         if (pm != nullptr) {
    1068            0 :             for (auto item : *pm) {
    1069            0 :                 const GUIChargingStation* cs = dynamic_cast<const GUIChargingStation*>(item.first);
    1070            0 :                 if (item.second.blockedAtTime >= 0) {
    1071            0 :                     std::string seenAgo = time2string(SIMSTEP - item.second.blockedAtTime);
    1072            0 :                     GLHelper::drawTextSettings(s.vehicleValue, seenAgo, cs->getSignPos(), s.scale, s.angle, 1.0);
    1073              :                 }
    1074            0 :                 if (item.second.score != "") {
    1075            0 :                     const double dist = 0.4 * (s.vehicleText.scaledSize(s.scale) + s.vehicleValue.scaledSize(s.scale));
    1076              :                     Position shift(0, -dist);
    1077            0 :                     GLHelper::drawTextSettings(s.vehicleText, item.second.score, cs->getSignPos() + shift, s.scale, s.angle, 1.0);
    1078              :                 }
    1079              :             }
    1080              :         }
    1081              :     }
    1082            0 : }
    1083              : 
    1084              : const GUIBaseVehicle::Seat&
    1085       213347 : GUIBaseVehicle::getSeatPosition(int personIndex) const {
    1086              :     /// if there are not enough seats in the vehicle people have to squeeze onto the last seat
    1087       213347 :     return mySeatPositions[MIN2(personIndex, (int)mySeatPositions.size() - 1)];
    1088              : }
    1089              : 
    1090              : const GUIBaseVehicle::Seat&
    1091         5906 : GUIBaseVehicle::getContainerPosition(int containerIndex) const {
    1092              :     /// if there are not enough positions in the vehicle containers have to squeeze onto the last position
    1093         5906 :     return myContainerPositions[MIN2(containerIndex, (int)myContainerPositions.size() - 1)];
    1094              : }
    1095              : 
    1096              : 
    1097              : void
    1098     13227480 : GUIBaseVehicle::drawAction_drawPersonsAndContainers(const GUIVisualizationSettings& s) const {
    1099     13227480 :     if (myVehicle.myPersonDevice != nullptr) {
    1100              :         const std::vector<MSTransportable*>& ps = myVehicle.myPersonDevice->getTransportables();
    1101              :         int personIndex = 0;
    1102       223216 :         for (std::vector<MSTransportable*>::const_iterator i = ps.begin(); i != ps.end(); ++i) {
    1103       213347 :             GUIPerson* person = dynamic_cast<GUIPerson*>(*i);
    1104              :             assert(person != 0);
    1105       213347 :             person->setPositionInVehicle(getSeatPosition(personIndex++));
    1106       213347 :             person->drawGL(s);
    1107              :         }
    1108              :     }
    1109     13227480 :     if (myVehicle.myContainerDevice != nullptr) {
    1110              :         const std::vector<MSTransportable*>& cs = myVehicle.myContainerDevice->getTransportables();
    1111              :         int containerIndex = 0;
    1112        11107 :         for (std::vector<MSTransportable*>::const_iterator i = cs.begin(); i != cs.end(); ++i) {
    1113         5906 :             GUIContainer* container = dynamic_cast<GUIContainer*>(*i);
    1114              :             assert(container != 0);
    1115         5906 :             container->setPositionInVehicle(getContainerPosition(containerIndex++));
    1116         5906 :             container->drawGL(s);
    1117              :         }
    1118              :     }
    1119              : #ifdef DRAW_BOUNDING_BOX
    1120              :     if (!MSGlobals::gUseMesoSim) {
    1121              :         MSVehicle& microVeh = dynamic_cast<MSVehicle&>(myVehicle);
    1122              :         GLHelper::pushName(getGlID());
    1123              :         GLHelper::pushMatrix();
    1124              :         glTranslated(0, 0, getType());
    1125              :         PositionVector smallBB = microVeh.getBoundingPoly();
    1126              :         glColor3d(0.5, .8, 0);
    1127              :         GLHelper::drawBoxLines(smallBB, 0.3);
    1128              :         glTranslated(0, 0, 0.1);
    1129              :         PositionVector boundingBox = microVeh.getBoundingBox();
    1130              :         boundingBox.push_back(boundingBox.front());
    1131              :         glColor3d(1, 0, 0);
    1132              :         GLHelper::drawBoxLines(boundingBox, 0.15);
    1133              :         GLHelper::popMatrix();
    1134              :         GLHelper::popName();
    1135              :     }
    1136              : #endif
    1137     13227480 : }
    1138              : 
    1139              : bool
    1140     13214557 : GUIBaseVehicle::drawReversed(const GUIVisualizationSettings& s) const {
    1141     13214557 :     return myVehicle.isReversed() && s.drawReversed;
    1142              : }
    1143              : 
    1144              : bool
    1145       250497 : GUIBaseVehicle::drawAction_drawVehicleAsPolyWithCarriagges(const GUIVisualizationSettings& s, double scaledLength, bool asImage) const {
    1146       254870 :     if (getVType().getParameter().carriageLength > 0 &&
    1147         4373 :             (!myVehicle.isParking() || myVehicle.getNextStop().parkingarea == nullptr || myVehicle.getNextStop().parkingarea->parkOnRoad())) {
    1148         4373 :         drawAction_drawCarriageClass(s, scaledLength, asImage);
    1149         4373 :         return true;
    1150              :     } else {
    1151       263224 :         if (asImage && GUIBaseVehicleHelper::drawAction_drawVehicleAsImage(
    1152       246124 :                     s, getVType().getImgFile(), this, getVType().getWidth(), scaledLength)) {
    1153              :             return false;
    1154              :         }
    1155       475148 :         GUIBaseVehicleHelper::drawAction_drawVehicleAsPoly(s, getVType().getGuiShape(), getVType().getWidth(), scaledLength, -1, myVehicle.isStopped(), drawReversed(s));
    1156       237574 :         return false;
    1157              :     }
    1158              : }
    1159              : 
    1160              : 
    1161              : int
    1162     13227480 : GUIBaseVehicle::getNumPassengers() const {
    1163     13227480 :     if (myVehicle.getPersonDevice() != nullptr) {
    1164         9869 :         return (int)myVehicle.getPersonDevice()->size();
    1165              :     }
    1166              :     return 0;
    1167              : }
    1168              : 
    1169              : 
    1170              : int
    1171     13227480 : GUIBaseVehicle::getNumContainers() const {
    1172     13227480 :     if (myVehicle.getContainerDevice() != nullptr) {
    1173         5201 :         return (int)myVehicle.getContainerDevice()->size();
    1174              :     }
    1175              :     return 0;
    1176              : }
    1177              : 
    1178              : std::string
    1179            0 : GUIBaseVehicle::getDeviceDescription() {
    1180              :     std::vector<std::string> devs;
    1181            0 :     for (MSDevice* d : myVehicle.getDevices()) {
    1182            0 :         devs.push_back(d->deviceName());
    1183              :     }
    1184            0 :     return joinToString(devs, " ");
    1185            0 : }
    1186              : 
    1187              : 
    1188              : void
    1189     26468835 : GUIBaseVehicle::computeSeats(const Position& front, const Position& back, double seatOffset, int maxSeats, double exaggeration, int& requiredSeats, Seats& into, double extraOffset) const {
    1190     26468835 :     if (requiredSeats <= 0) {
    1191              :         return;
    1192              :     }
    1193              :     maxSeats = MAX2(maxSeats, 1); // compute at least one seat
    1194        12492 :     seatOffset *= exaggeration;
    1195        12492 :     const double vehWidth = getVType().getSeatingWidth() * exaggeration;
    1196              :     const double length = front.distanceTo2D(back);
    1197        12492 :     const int rowSize = MAX2(1, (int)floor(vehWidth / seatOffset));
    1198        12492 :     const double frontSeatPos = getVType().getFrontSeatPos() + extraOffset;
    1199        12492 :     const double rowOffset = MAX2(1.0, (length - frontSeatPos - 1)) / ceil((double)maxSeats / rowSize);
    1200        12492 :     const double sideOffset = (rowSize - 1) / 2.0 * seatOffset;
    1201        12492 :     double rowPos = frontSeatPos - rowOffset;
    1202              :     double angle = back.angleTo2D(front);
    1203        12492 :     const int fillDirection = MSGlobals::gLefthand ? -1 : 1;
    1204              :     //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";
    1205       230312 :     for (int i = 0; requiredSeats > 0 && i < maxSeats; i++) {
    1206       217820 :         int seat = (i % rowSize);
    1207       217820 :         if (seat == 0) {
    1208        80278 :             rowPos += rowOffset;
    1209              :         }
    1210       217820 :         into.push_back(Seat(PositionVector::positionAtOffset2D(front, back, rowPos, (sideOffset - seat * seatOffset) * fillDirection), angle));
    1211       217820 :         requiredSeats--;
    1212              :     }
    1213              : }
    1214              : 
    1215              : 
    1216              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1