LCOV - code coverage report
Current view: top level - src/guisim - GUIVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 25.1 % 642 161
Test Date: 2026-09-20 15:45:03 Functions: 33.3 % 36 12

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 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    GUIVehicle.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    Sept 2002
      19              : ///
      20              : // A MSVehicle extended by some values for usage within the gui
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <cmath>
      25              : #include <vector>
      26              : #include <string>
      27              : #include <bitset>
      28              : #include <utils/common/MsgHandler.h>
      29              : #include <utils/common/StringUtils.h>
      30              : #include <utils/vehicle/SUMOVehicleParameter.h>
      31              : #include <utils/emissions/PollutantsInterface.h>
      32              : #include <utils/geom/GeomHelper.h>
      33              : #include <utils/gui/globjects/GLIncludes.h>
      34              : #include <utils/gui/windows/GUISUMOAbstractView.h>
      35              : #include <utils/gui/windows/GUIAppEnum.h>
      36              : #include <utils/gui/images/GUITexturesHelper.h>
      37              : #include <utils/gui/div/GUIParameterTableWindow.h>
      38              : #include <utils/gui/div/GUIGlobalSelection.h>
      39              : #include <utils/gui/div/GLHelper.h>
      40              : #include <utils/gui/div/GLObjectValuePassConnector.h>
      41              : #include <utils/gui/div/GUIGlobalSelection.h>
      42              : #include <utils/gui/div/GUIBaseVehicleHelper.h>
      43              : #include <microsim/MSGlobals.h>
      44              : #include <microsim/MSVehicle.h>
      45              : #include <microsim/MSJunction.h>
      46              : #include <microsim/MSLane.h>
      47              : #include <microsim/MSLink.h>
      48              : #include <microsim/MSStop.h>
      49              : #include <microsim/MSParkingArea.h>
      50              : #include <microsim/MSTrainHelper.h>
      51              : #include <microsim/logging/CastingFunctionBinding.h>
      52              : #include <microsim/logging/FunctionBinding.h>
      53              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      54              : #include <microsim/devices/MSDevice_Vehroutes.h>
      55              : #include <microsim/devices/MSDevice_Routing.h>
      56              : #include <microsim/devices/MSRoutingEngine.h>
      57              : #include <microsim/devices/MSDevice_Transportable.h>
      58              : #include <microsim/devices/MSDevice_BTreceiver.h>
      59              : #include <microsim/devices/MSDevice_ElecHybrid.h>
      60              : #include <microsim/devices/MSDevice_Battery.h>
      61              : #include <microsim/traffic_lights/MSDriveWay.h>
      62              : #include <gui/GUIApplicationWindow.h>
      63              : #include <gui/GUIGlobals.h>
      64              : #include "GUIVehicle.h"
      65              : #include "GUIPerson.h"
      66              : #include "GUIContainer.h"
      67              : #include "GUINet.h"
      68              : #include "GUIEdge.h"
      69              : #include "GUILane.h"
      70              : 
      71              : #define SPEEDMODE_DEFAULT 31
      72              : #define LANECHANGEMODE_DEFAULT 1621
      73              : //#define DEBUG_FOES
      74              : 
      75              : 
      76              : // ===========================================================================
      77              : // member method definitions
      78              : // ===========================================================================
      79              : /* -------------------------------------------------------------------------
      80              :  * GUIVehicle - methods
      81              :  * ----------------------------------------------------------------------- */
      82              : #ifdef _MSC_VER
      83              : #pragma warning(push)
      84              : #pragma warning(disable: 4355) // mask warning about "this" in initializers
      85              : #endif
      86       658934 : GUIVehicle::GUIVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
      87       658934 :                        MSVehicleType* type, const double speedFactor) :
      88              :     MSVehicle(pars, route, type, speedFactor),
      89      1317868 :     GUIBaseVehicle((MSBaseVehicle&) * this) {
      90       658934 : }
      91              : #ifdef _MSC_VER
      92              : #pragma warning(pop)
      93              : #endif
      94              : 
      95              : 
      96      1317764 : GUIVehicle::~GUIVehicle() {
      97       658882 :     gSelected.deselect(GLO_VEHICLE, getGlID());
      98              :     // cleanupFurtherLanes will be called again in MSVehicle. However, we must
      99              :     // first call it here to avoid stale pointers to a partially destructed
     100              :     // GUIVehicle in MSLane::myPartialVehicles
     101       658882 :     cleanupFurtherLanes();
     102       658882 :     cleanupOnDestruction();
     103      1317764 : }
     104              : 
     105              : 
     106              : GUIParameterTableWindow*
     107            0 : GUIVehicle::getParameterWindow(GUIMainWindow& app,
     108              :                                GUISUMOAbstractView&) {
     109            0 :     const bool isElecHybrid = getDevice(typeid(MSDevice_ElecHybrid)) != nullptr ? true : false;
     110            0 :     const bool hasBattery = getDevice(typeid(MSDevice_Battery)) != nullptr;
     111            0 :     GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
     112              :     // add items
     113            0 :     ret->mkItem(TL("lane [id]"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getLaneID));
     114            0 :     if (MSGlobals::gSublane) {
     115            0 :         ret->mkItem(TL("shadow lane [id]"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getShadowLaneID));
     116              :     }
     117            0 :     if (MSGlobals::gLateralResolution > 0) {
     118            0 :         ret->mkItem(TL("target lane [id]"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getTargetLaneID));
     119              :     }
     120            0 :     if (isSelected()) {
     121            0 :         ret->mkItem(TL("back lanes [id,..]"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getBackLaneIDs));
     122              :     }
     123            0 :     ret->mkItem(TL("position [m]"), true,
     124            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getPositionOnLane));
     125            0 :     ret->mkItem(TL("lateral offset [m]"), true,
     126            0 :                 new FunctionBinding<GUIVehicle, double>(this, &GUIVehicle::getLateralPositionOnLane));
     127            0 :     ret->mkItem(TL("speed [m/s]"), true,
     128            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getSpeed));
     129            0 :     ret->mkItem(TL("lateral speed [m/s]"), true,
     130            0 :                 new FunctionBinding<MSAbstractLaneChangeModel, double>(&getLaneChangeModel(), &MSAbstractLaneChangeModel::getSpeedLat));
     131            0 :     ret->mkItem(TL("acceleration [m/s^2]"), true,
     132            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getAcceleration));
     133            0 :     ret->mkItem(TL("angle [degree]"), true,
     134            0 :                 new FunctionBinding<GUIVehicle, double>(this, &GUIBaseVehicle::getNaviDegree));
     135            0 :     ret->mkItem(TL("slope [degree]"), true,
     136            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getSlope));
     137            0 :     ret->mkItem(TL("speed factor"), true,
     138            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getChosenSpeedFactor));
     139            0 :     ret->mkItem(TL("time gap on lane [s]"), true,
     140            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getTimeGapOnLane));
     141            0 :     ret->mkItem(TL("waiting time [s]"), true,
     142            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getWaitingSeconds));
     143            0 :     ret->mkItem(TLF("waiting time (accumulated, % s) [s]", time2string(MSGlobals::gWaitingTimeMemory)).c_str(), true,
     144            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getAccumulatedWaitingSeconds));
     145            0 :     ret->mkItem(TL("time since startup [s]"), true,
     146            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getTimeSinceStartupSeconds));
     147            0 :     ret->mkItem(TL("time loss [s]"), true,
     148            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getTimeLossSeconds));
     149            0 :     ret->mkItem(TL("impatience"), true,
     150            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getImpatience));
     151            0 :     ret->mkItem(TL("last lane change [s]"), true,
     152            0 :                 new FunctionBinding<GUIVehicle, double>(this, &GUIVehicle::getLastLaneChangeOffset));
     153            0 :     ret->mkItem(TL("desired depart [s]"), false, time2string(getParameter().depart));
     154            0 :     ret->mkItem(TL("depart delay [s]"), false, time2string(getDepartDelay()));
     155            0 :     ret->mkItem(TL("odometer [m]"), true,
     156            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSBaseVehicle::getOdometer));
     157            0 :     if (getParameter().repetitionNumber < std::numeric_limits<long long int>::max()) {
     158            0 :         ret->mkItem(TL("remaining [#]"), false, (long long int) getParameter().repetitionNumber - getParameter().repetitionsDone);
     159              :     }
     160            0 :     if (getParameter().repetitionOffset > 0) {
     161            0 :         ret->mkItem(TL("insertion period [s]"), false, time2string(getParameter().repetitionOffset));
     162              :     }
     163            0 :     if (getParameter().repetitionProbability > 0) {
     164            0 :         ret->mkItem(TL("insertion probability"), false, getParameter().repetitionProbability);
     165              :     }
     166            0 :     if (getParameter().poissonRate > 0) {
     167            0 :         ret->mkItem(TL("poisson rate"), false, getParameter().poissonRate);
     168              :     }
     169            0 :     ret->mkItem(TL("stop info"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getStopInfo));
     170            0 :     ret->mkItem(TL("line"), false, myParameter->line);
     171            0 :     ret->mkItem(TL("CO2 [mg/s]"), true,
     172            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getEmissions<PollutantsInterface::CO2>));
     173            0 :     ret->mkItem(TL("CO [mg/s]"), true,
     174            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getEmissions<PollutantsInterface::CO>));
     175            0 :     ret->mkItem(TL("HC [mg/s]"), true,
     176            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getEmissions<PollutantsInterface::HC>));
     177            0 :     ret->mkItem(TL("NOx [mg/s]"), true,
     178            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getEmissions<PollutantsInterface::NO_X>));
     179            0 :     ret->mkItem(TL("PMx [mg/s]"), true,
     180            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getEmissions<PollutantsInterface::PM_X>));
     181            0 :     ret->mkItem(TL("fuel [mg/s]"), true,
     182            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getEmissions<PollutantsInterface::FUEL>));
     183            0 :     ret->mkItem(TL("electricity [Wh/s]"), true,
     184            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getEmissions<PollutantsInterface::ELEC>));
     185            0 :     ret->mkItem(TL("noise (Harmonoise) [dB]"), true,
     186            0 :                 new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getHarmonoise_NoiseEmissions));
     187            0 :     ret->mkItem(TL("devices"), false, getDeviceDescription());
     188            0 :     ret->mkItem(TL("persons"), true,
     189            0 :                 new FunctionBinding<GUIVehicle, int>(this, &MSVehicle::getPersonNumber));
     190            0 :     ret->mkItem(TL("containers"), true,
     191            0 :                 new FunctionBinding<GUIVehicle, int>(this, &MSVehicle::getContainerNumber));
     192            0 :     ret->mkItem(TL("lcState right"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getLCStateRight));
     193            0 :     ret->mkItem(TL("lcState left"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getLCStateLeft));
     194            0 :     ret->mkItem(TL("parking badges"), false, joinToString(getParkingBadges(), " "));
     195              :     // close building
     196            0 :     if (MSGlobals::gLateralResolution > 0) {
     197            0 :         ret->mkItem(TL("lcState center"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getLCStateCenter));
     198            0 :         ret->mkItem(TL("right side on edge [m]"), true, new FunctionBinding<GUIVehicle, double>(this, &GUIVehicle::getRightSideOnEdge2));
     199            0 :         ret->mkItem(TL("left side on edge [m]"), true, new FunctionBinding<GUIVehicle, double>(this, &GUIVehicle::getLeftSideOnEdge));
     200            0 :         ret->mkItem(TL("rightmost edge sublane [#]"), true, new FunctionBinding<GUIVehicle, int>(this, &GUIVehicle::getRightSublaneOnEdge));
     201            0 :         ret->mkItem(TL("leftmost edge sublane [#]"), true, new FunctionBinding<GUIVehicle, int>(this, &GUIVehicle::getLeftSublaneOnEdge));
     202            0 :         ret->mkItem(TL("lane change maneuver distance [m]"), true, new FunctionBinding<GUIVehicle, double>(this, &GUIVehicle::getManeuverDist));
     203              :     }
     204            0 :     if (isRailway(getVClass())) {
     205            0 :         ret->mkItem(TL("driveways"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getDriveWays));
     206              :     }
     207            0 :     if (hasBattery || isElecHybrid) {
     208            0 :         ret->mkItem(TL("present state of charge [Wh]"), true,
     209            0 :                     new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getStateOfCharge));
     210              :     }
     211            0 :     if (hasBattery) {
     212            0 :         ret->mkItem(TL("relative state of charge (SoC) [-]"), true,
     213            0 :                     new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getRelativeStateOfCharge));
     214            0 :         ret->mkItem(TL("current timestep charge [Wh]"), true,
     215            0 :                     new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getChargedEnergy));
     216            0 :         ret->mkItem(TL("maximum charge rate [W]"), true,
     217            0 :                     new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getMaxChargeRate));
     218              :     }
     219            0 :     if (isElecHybrid) {
     220            0 :         ret->mkItem(TL("present electric current [A]"), true,
     221            0 :                     new FunctionBinding<GUIVehicle, double>(this, &MSVehicle::getElecHybridCurrent));
     222              :     }
     223            0 :     if (hasInfluencer()) {
     224            0 :         if (getInfluencer().getSpeedMode() != SPEEDMODE_DEFAULT) {
     225            0 :             ret->mkItem(TL("speed mode"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getSpeedMode));
     226              :         }
     227            0 :         if (getInfluencer().getLaneChangeMode() != LANECHANGEMODE_DEFAULT) {
     228            0 :             ret->mkItem(TL("lane change mode"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getLaneChangeMode));
     229              :         }
     230              :     }
     231            0 :     ret->closeBuilding(&getParameter());
     232            0 :     return ret;
     233              : }
     234              : 
     235              : 
     236              : GUIParameterTableWindow*
     237            0 : GUIVehicle::getTypeParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {
     238            0 :     GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this, "vType:" + myType->getID());
     239            0 :     ret->mkItem(TL("type"), false, myType->getID());
     240            0 :     ret->mkItem(TL("length [m]"), false, myType->getLength());
     241            0 :     ret->mkItem(TL("width [m]"), false, myType->getWidth());
     242            0 :     ret->mkItem(TL("height [m]"), false, myType->getHeight());
     243            0 :     ret->mkItem(TL("minGap [m]"), false, myType->getMinGap());
     244            0 :     ret->mkItem(TL("vehicle class"), false, SumoVehicleClassStrings.getString(myType->getVehicleClass()));
     245            0 :     ret->mkItem(TL("emission class"), false, PollutantsInterface::getName(myType->getEmissionClass()));
     246            0 :     ret->mkItem(TL("mass [kg]"), false, myType->getMass());
     247            0 :     ret->mkItem(TL("car-following model"), false, SUMOXMLDefinitions::CarFollowModels.getString((SumoXMLTag)getCarFollowModel().getModelID()));
     248            0 :     ret->mkItem(TL("lane-change model"), false, SUMOXMLDefinitions::LaneChangeModels.getString(getLaneChangeModel().getModelID()));
     249            0 :     ret->mkItem(TL("guiShape"), false, getVehicleShapeName(myType->getGuiShape()));
     250            0 :     ret->mkItem(TL("maximum speed [m/s]"), false, getVehicleType().getMaxSpeed());
     251            0 :     ret->mkItem(TL("desired maximum speed [m/s]"), false, getVehicleType().getDesiredMaxSpeed());
     252            0 :     ret->mkItem(TL("maximum acceleration [m/s^2]"), false, getCarFollowModel().getMaxAccel());
     253            0 :     ret->mkItem(TL("maximum deceleration [m/s^2]"), false, getCarFollowModel().getMaxDecel());
     254            0 :     ret->mkItem(TL("emergency deceleration [m/s^2]"), false, getCarFollowModel().getEmergencyDecel());
     255            0 :     ret->mkItem(TL("apparent deceleration [m/s^2]"), false, getCarFollowModel().getApparentDecel());
     256            0 :     ret->mkItem(TL("imperfection (sigma)"), false, getCarFollowModel().getImperfection());
     257            0 :     ret->mkItem(TL("desired headway (tau) [s]"), false, getCarFollowModel().getHeadwayTime());
     258            0 :     ret->mkItem(TL("speedfactor"), false, myType->getParameter().speedFactor.toStr(gPrecision));
     259            0 :     ret->mkItem(TL("startupDelay [s]"), false, STEPS2TIME(getCarFollowModel().getStartupDelay()));
     260            0 :     if (myType->getParameter().wasSet(VTYPEPARS_ACTIONSTEPLENGTH_SET)) {
     261            0 :         ret->mkItem(TL("action step length [s]"), false, myType->getActionStepLengthSecs());
     262              :     }
     263            0 :     ret->mkItem(TL("person capacity"), false, myType->getPersonCapacity());
     264            0 :     ret->mkItem(TL("boarding time [s]"), false, STEPS2TIME(myType->getLoadingDuration(true)));
     265            0 :     ret->mkItem(TL("container capacity"), false, myType->getContainerCapacity());
     266            0 :     ret->mkItem(TL("loading time [s]"), false, STEPS2TIME(myType->getLoadingDuration(false)));
     267            0 :     if (MSGlobals::gLateralResolution > 0) {
     268            0 :         ret->mkItem(TL("minGapLat [m]"), false, myType->getMinGapLat());
     269            0 :         ret->mkItem(TL("maxSpeedLat [m/s]"), false, myType->getMaxSpeedLat());
     270            0 :         ret->mkItem(TL("latAlignment"), true, new FunctionBindingString<GUIVehicle>(this, &GUIVehicle::getDynamicAlignment));
     271            0 :     } else if (MSGlobals::gLaneChangeDuration > 0) {
     272            0 :         ret->mkItem(TL("maxSpeedLat [m/s]"), false, myType->getMaxSpeedLat());
     273              :     }
     274            0 :     for (auto item : myType->getParameter().lcParameter) {
     275            0 :         ret->mkItem(toString(item.first).c_str(), false, toString(item.second));
     276              :     }
     277            0 :     for (auto item : myType->getParameter().jmParameter) {
     278            0 :         ret->mkItem(toString(item.first).c_str(), false, toString(item.second));
     279              :     }
     280            0 :     if (MSGlobals::gModelParkingManoeuver) {
     281            0 :         ret->mkItem(TL("manoeuver Angle vs Times"), false, myType->getParameter().getManoeuverAngleTimesS());
     282              :     }
     283            0 :     ret->closeBuilding(&(myType->getParameter()));
     284            0 :     return ret;
     285              : }
     286              : 
     287              : 
     288              : std::string
     289            0 : GUIVehicle::getDynamicAlignment() const {
     290            0 :     std::string align = myType->getPreferredLateralAlignment() == LatAlignmentDefinition::GIVEN
     291            0 :                         ? toString(myType->getPreferredLateralAlignmentOffset())
     292            0 :                         : toString(myType->getPreferredLateralAlignment());
     293            0 :     std::string align2 = toString(getLaneChangeModel().getDesiredAlignment());
     294            0 :     if (align2 != align) {
     295            0 :         align = align2 + " (default: " + align + ")";
     296              :     }
     297            0 :     return align;
     298              : }
     299              : 
     300              : void
     301            0 : GUIVehicle::drawAction_drawLinkItems(const GUIVisualizationSettings& s) const {
     302            0 :     glTranslated(0, 0, getType() + .2); // draw on top of cars
     303            0 :     for (DriveItemVector::const_iterator i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
     304            0 :         if ((*i).myLink == nullptr) {
     305            0 :             continue;
     306              :         }
     307              :         MSLink* link = (*i).myLink;
     308              :         MSLane* via = link->getViaLaneOrLane();
     309            0 :         if (via != nullptr) {
     310            0 :             Position p = via->getShape()[0];
     311            0 :             if ((*i).mySetRequest) {
     312            0 :                 glColor3d(0, .8, 0);
     313              :             } else {
     314            0 :                 glColor3d(.8, 0, 0);
     315              :             }
     316            0 :             const SUMOTime leaveTime = (*i).myLink->getLeaveTime(
     317            0 :                                            (*i).myArrivalTime, (*i).myArrivalSpeed, (*i).getLeaveSpeed(), getVehicleType().getLength());
     318            0 :             drawLinkItem(p, (*i).myArrivalTime, leaveTime, s.vehicleName.size / s.scale);
     319              :             // the time slot that ego vehicle uses when checking opened may
     320              :             // differ from the one it requests in setApproaching
     321            0 :             MSLink::ApproachingVehicleInformation avi = (*i).myLink->getApproaching(this);
     322              :             assert(avi.arrivalTime == (*i).myArrivalTime && avi.leavingTime == leaveTime);
     323              :             UNUSED_PARAMETER(avi); // only used for assertion
     324              :         }
     325              :     }
     326            0 :     glTranslated(0, 0, getType() - .2); // draw on top of cars
     327            0 : }
     328              : 
     329              : 
     330              : void
     331         4397 : GUIVehicle::drawAction_drawCarriageClass(const GUIVisualizationSettings& s, double scaledLength, bool asImage) const {
     332         4397 :     RGBColor current = GLHelper::getColor();
     333         4397 :     RGBColor darker = current.changedBrightness(-20);
     334         4397 :     const double exaggeration = (s.vehicleSize.getExaggeration(s, this)
     335         4397 :                                  * s.vehicleScaler.getScheme().getColor(getScaleValue(s, s.vehicleScaler.getActive())));
     336         4397 :     if (exaggeration == 0) {
     337            0 :         return;
     338              :     }
     339         4397 :     MSTrainHelper trainHelper(this, scaledLength, isReversed() && s.drawReversed, s.secondaryShape, exaggeration, s.vehicleQuality);
     340              :     const int numCarriages = trainHelper.getNumCarriages();
     341              :     const int firstPassengerCarriage = trainHelper.getFirstPassengerCarriage();
     342         4397 :     const int noPersonsBackCarriages = (getVehicleType().getGuiShape() == SUMOVehicleShape::TRUCK_SEMITRAILER || getVehicleType().getGuiShape() == SUMOVehicleShape::TRUCK_1TRAILER) && numCarriages > 1 ? 1 : 0;
     343         4869 :     const int firstContainerCarriage = numCarriages == 1 || getVehicleType().getGuiShape() == SUMOVehicleShape::TRUCK_1TRAILER ? 0 : 1;
     344         4397 :     const int seatsPerCarriage = (int)ceil(getVType().getPersonCapacity() / (numCarriages - firstPassengerCarriage - noPersonsBackCarriages));
     345         4397 :     const int containersPerCarriage = (int)ceil(getVType().getContainerCapacity() / (numCarriages - firstContainerCarriage));
     346              :     // Handle seats.
     347         4397 :     int requiredSeats = getNumPassengers();
     348         4397 :     int requiredPositions = getNumContainers();
     349         4397 :     if (requiredSeats > 0) {
     350              :         mySeatPositions.clear();
     351              :     }
     352         4397 :     if (requiredPositions > 0) {
     353              :         myContainerPositions.clear();
     354              :     }
     355         4397 :     GLHelper::popMatrix(); // undo initial translation and rotation
     356         4397 :     const double xCornerCut = 0.3 * exaggeration;
     357         4397 :     const double yCornerCut = MIN2(0.4 * trainHelper.getUpscaleLength(),  trainHelper.getUpscaleLength() * scaledLength / 4);
     358              :     Position front, back;
     359              :     double angle = 0.0;
     360              :     double curCLength = trainHelper.getFirstCarriageLength();
     361              :     const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
     362        18231 :     for (int i = 0; i < numCarriages; ++i) {
     363        13834 :         front = carriages[i]->front;
     364        13834 :         back = carriages[i]->back;
     365            0 :         if (front == back) {
     366              :             // No place for drawing available.
     367            0 :             continue;
     368              :         }
     369              :         const double drawnCarriageLength = front.distanceTo2D(back);
     370        13834 :         angle = atan2((front.x() - back.x()), (back.y() - front.y())) * (double) 180.0 / (double) M_PI;
     371              :         // if we are in reverse 'first' carriages are drawn last so the >= test doesn't work
     372              :         const bool reversed = trainHelper.isReversed();
     373        13834 :         if (reversed) {
     374         3080 :             if (i <= numCarriages - firstPassengerCarriage) {
     375         3080 :                 computeSeats(back, front, SUMO_const_waitingPersonWidth, seatsPerCarriage, exaggeration, requiredSeats, mySeatPositions);
     376              :             }
     377         3080 :             if (i <= numCarriages - firstContainerCarriage) {
     378         3080 :                 computeSeats(front, back, SUMO_const_waitingContainerWidth, containersPerCarriage, exaggeration, requiredPositions, myContainerPositions);
     379              :             }
     380              :         } else {
     381        10754 :             if (i >= firstPassengerCarriage) {
     382         8743 :                 computeSeats(front, back, SUMO_const_waitingPersonWidth, seatsPerCarriage, exaggeration, requiredSeats, mySeatPositions);
     383              :             }
     384        10754 :             if (i >= firstContainerCarriage) {
     385         7822 :                 computeSeats(front, back, SUMO_const_waitingContainerWidth, containersPerCarriage, exaggeration, requiredPositions, myContainerPositions);
     386              :             }
     387              :         }
     388        13834 :         curCLength = (i == trainHelper.getFirstCarriageNo() ? trainHelper.getFirstCarriageLength() : trainHelper.getCarriageLength());
     389        13834 :         GLHelper::pushMatrix();
     390        13834 :         if (s.trueZ) {
     391           70 :             glTranslated(front.x(), front.y(), front.z() + 1);
     392              :         } else {
     393        13764 :             glTranslated(front.x(), front.y(), getType());
     394              :         }
     395        13834 :         glRotated(angle, 0, 0, 1);
     396              :         double halfWidth = trainHelper.getHalfWidth();
     397              :         std::string imgFile = getVType().getImgFile();
     398        13834 :         if (asImage && i != trainHelper.getFirstCarriageNo()) {
     399              :             const size_t nImages = getVType().getParameter().carriageImages.size();
     400            0 :             if (nImages > 0) {
     401            0 :                 const int carIndex = trainHelper.isReversed() ? numCarriages - i : i;
     402            0 :                 imgFile = getVType().getParameter().carriageImages[MIN2((int)nImages - 1, carIndex - 1)];
     403              :             }
     404              :         }
     405        13834 :         if (!asImage || !GUIBaseVehicleHelper::drawAction_drawVehicleAsImage(s, imgFile, this, getVType().getWidth() * exaggeration, curCLength)) {
     406        13834 :             switch (getVType().getGuiShape()) {
     407              :                 case SUMOVehicleShape::TRUCK_SEMITRAILER:
     408              :                 case SUMOVehicleShape::TRUCK_1TRAILER:
     409         1800 :                     if (i == trainHelper.getFirstCarriageNo()) {  // at the moment amReversed is only ever set for rail - so has no impact in this call
     410          900 :                         GLHelper::pushMatrix();
     411          900 :                         if (getVType().getGuiShape() == SUMOVehicleShape::TRUCK_SEMITRAILER) {
     412              :                             // default drawing uses a fixed cab length but we want to scale here
     413          428 :                             glScaled(1, curCLength / 2.5, 1);
     414              :                         }
     415          900 :                         GUIBaseVehicleHelper::drawAction_drawVehicleAsPoly(s, getVType().getGuiShape(), getVType().getWidth() * exaggeration, curCLength, 0, false, reversed);
     416          900 :                         GLHelper::popMatrix();
     417              :                     } else {
     418          900 :                         GLHelper::setColor(current);
     419          900 :                         GLHelper::drawBoxLine(Position(0, 0), 180, curCLength, halfWidth);
     420              :                     }
     421              :                     break;
     422              :                 default: {
     423        12034 :                     if (i == trainHelper.getFirstCarriageNo()) {
     424         3497 :                         GLHelper::setColor(darker);
     425              :                     } else {
     426         8537 :                         GLHelper::setColor(current);
     427              :                     }
     428              :                     // generic rail carriage
     429        12034 :                     glBegin(GL_TRIANGLE_FAN);
     430        12034 :                     glVertex2d(-halfWidth + xCornerCut, 0);
     431        12034 :                     glVertex2d(-halfWidth, yCornerCut);
     432        12034 :                     glVertex2d(-halfWidth, drawnCarriageLength - yCornerCut);
     433        12034 :                     glVertex2d(-halfWidth + xCornerCut, drawnCarriageLength);
     434        12034 :                     glVertex2d(halfWidth - xCornerCut, drawnCarriageLength);
     435        12034 :                     glVertex2d(halfWidth, drawnCarriageLength - yCornerCut);
     436        12034 :                     glVertex2d(halfWidth, yCornerCut);
     437        12034 :                     glVertex2d(halfWidth - xCornerCut, 0);
     438        12034 :                     glEnd();
     439              :                     // indicate front of the head of the train
     440        12034 :                     if (i == trainHelper.getFirstCarriageNo()) {
     441         3497 :                         glTranslated(0, 0, 0.1);
     442         3497 :                         glColor3d(0, 0, 0);
     443         3497 :                         glBegin(GL_TRIANGLE_FAN);
     444         3497 :                         if (reversed) {  // not quite correct as its drawing at the wrong end of the locomotive - however useful as visual indicator of reverse?
     445          923 :                             glVertex2d(-halfWidth + xCornerCut, yCornerCut);
     446          923 :                             glVertex2d(-halfWidth + 2 * xCornerCut, 3 * yCornerCut);
     447          923 :                             glVertex2d(halfWidth - 2 * xCornerCut, 3 * yCornerCut);
     448          923 :                             glVertex2d(halfWidth - xCornerCut, yCornerCut);
     449              :                         } else {
     450         2574 :                             glVertex2d(-halfWidth + 2 * xCornerCut, yCornerCut);
     451         2574 :                             glVertex2d(-halfWidth + xCornerCut, 3 * yCornerCut);
     452         2574 :                             glVertex2d(halfWidth - xCornerCut, 3 * yCornerCut);
     453         2574 :                             glVertex2d(halfWidth - 2 * xCornerCut, yCornerCut);
     454              :                         }
     455         3497 :                         glEnd();
     456         3497 :                         glTranslated(0, 0, -0.1);
     457              :                     }
     458              :                 }
     459              :             }
     460              :         }
     461        13834 :         GLHelper::popMatrix();
     462              :     }
     463         4397 :     if (getVType().getGuiShape() == SUMOVehicleShape::RAIL_CAR) {
     464           70 :         GLHelper::pushMatrix();
     465           70 :         if (s.trueZ) {
     466           70 :             glTranslated(front.x(), front.y(), front.z() + 1);
     467              :         } else {
     468            0 :             glTranslated(front.x(), front.y(), getType());
     469              :         }
     470           70 :         glRotated(angle, 0, 0, 1);
     471           70 :         drawAction_drawVehicleBlinker(curCLength);
     472           70 :         drawAction_drawVehicleBrakeLight(curCLength);
     473           70 :         GLHelper::popMatrix();
     474              :     }
     475              :     // restore matrix
     476         4397 :     GLHelper::pushMatrix();
     477         4397 :     front = getPosition();
     478         4397 :     glTranslated(front.x(), front.y(), getType());
     479         4397 :     const double degAngle = RAD2DEG(getAngle() + M_PI / 2.);
     480         4397 :     glRotated(degAngle, 0, 0, 1);
     481         4397 :     glScaled(exaggeration, trainHelper.getUpscaleLength(), 1);
     482         4397 :     if (mySeatPositions.size() == 0) {
     483            0 :         mySeatPositions.push_back(Seat(back, DEG2RAD(angle)));
     484              :     }
     485         4397 :     if (myContainerPositions.size() == 0) {
     486            0 :         myContainerPositions.push_back(Seat(back, DEG2RAD(angle)));
     487              :     }
     488         4397 : }
     489              : 
     490              : #define BLINKER_POS_FRONT .5
     491              : #define BLINKER_POS_BACK .5
     492              : 
     493              : inline void
     494      3684289 : drawAction_drawBlinker(double dir, double length) {
     495      3684289 :     glColor3d(1.f, .8f, 0);
     496      3684289 :     GLHelper::pushMatrix();
     497      3684289 :     glTranslated(dir, BLINKER_POS_FRONT, -0.1);
     498      3684289 :     GLHelper::drawFilledCircle(.5, 6);
     499      3684289 :     GLHelper::popMatrix();
     500      3684289 :     GLHelper::pushMatrix();
     501      3684289 :     glTranslated(dir, length - BLINKER_POS_BACK, -0.1);
     502      3684289 :     GLHelper::drawFilledCircle(.5, 6);
     503      3684289 :     GLHelper::popMatrix();
     504      3684289 : }
     505              : 
     506              : 
     507              : void
     508     14005110 : GUIVehicle::drawAction_drawVehicleBlinker(double length) const {
     509     14005110 :     if (!signalSet(MSVehicle::VEH_SIGNAL_BLINKER_RIGHT | MSVehicle::VEH_SIGNAL_BLINKER_LEFT | MSVehicle::VEH_SIGNAL_BLINKER_EMERGENCY)) {
     510              :         return;
     511              :     }
     512      3678976 :     const double offset = MAX2(.5 * getVehicleType().getWidth(), .4);
     513      3678976 :     if (signalSet(MSVehicle::VEH_SIGNAL_BLINKER_RIGHT)) {
     514      2112436 :         drawAction_drawBlinker(-offset, length);
     515              :     }
     516      3678976 :     if (signalSet(MSVehicle::VEH_SIGNAL_BLINKER_LEFT)) {
     517      1571853 :         drawAction_drawBlinker(offset, length);
     518              :     }
     519      3678976 :     if (signalSet(MSVehicle::VEH_SIGNAL_BLINKER_EMERGENCY)) {
     520            0 :         drawAction_drawBlinker(-offset, length);
     521            0 :         drawAction_drawBlinker(offset, length);
     522              :     }
     523              : }
     524              : 
     525              : 
     526              : inline void
     527     14005110 : GUIVehicle::drawAction_drawVehicleBrakeLight(double length, bool onlyOne) const {
     528     14005110 :     if (!signalSet(MSVehicle::VEH_SIGNAL_BRAKELIGHT)) {
     529              :         return;
     530              :     }
     531      6159007 :     glColor3f(1.f, .2f, 0);
     532      6159007 :     GLHelper::pushMatrix();
     533      6159007 :     if (onlyOne) {
     534       392342 :         glTranslated(0, length, -0.1);
     535       392342 :         GLHelper::drawFilledCircle(.5, 6);
     536              :     } else {
     537      5766665 :         glTranslated(-getVehicleType().getWidth() * 0.5, length, -0.1);
     538      5766665 :         GLHelper::drawFilledCircle(.5, 6);
     539      5766665 :         GLHelper::popMatrix();
     540      5766665 :         GLHelper::pushMatrix();
     541      5766665 :         glTranslated(getVehicleType().getWidth() * 0.5, length, -0.1);
     542      5766665 :         GLHelper::drawFilledCircle(.5, 6);
     543              :     }
     544      6159007 :     GLHelper::popMatrix();
     545              : }
     546              : 
     547              : inline void
     548            0 : GUIVehicle::drawAction_drawVehicleBlueLight() const {
     549            0 :     if (signalSet(MSVehicle::VEH_SIGNAL_EMERGENCY_BLUE)) {
     550            0 :         GLHelper::pushMatrix();
     551            0 :         glTranslated(0, 2.5, .5);
     552            0 :         glColor3f(0, 0, 1);
     553            0 :         GLHelper::drawFilledCircle(.5, 6);
     554            0 :         GLHelper::popMatrix();
     555              :     }
     556            0 : }
     557              : 
     558              : 
     559              : double
     560     13671800 : GUIVehicle::getColorValue(const GUIVisualizationSettings& s, int activeScheme) const {
     561     13671800 :     switch (activeScheme) {
     562       197814 :         case 8:
     563       197814 :             if (isStopped() && getNextStop().getSpeed() <= 0) {
     564         1102 :                 return isParking() ? -2 : -1;
     565              :             }
     566       196712 :             return getSpeed();
     567            0 :         case 9:
     568              :             // color by action step
     569            0 :             if (isActionStep(SIMSTEP)) {
     570              :                 // Upcoming simstep is actionstep (t was already increased before drawing)
     571              :                 return 1.;
     572            0 :             } else if (isActive()) {
     573              :                 // Completed simstep was actionstep
     574              :                 return 2.;
     575              :             } else {
     576              :                 // not active
     577            0 :                 return 0.;
     578              :             }
     579            0 :         case 10:
     580            0 :             return getWaitingSeconds();
     581            0 :         case 11:
     582            0 :             return getAccumulatedWaitingSeconds();
     583            0 :         case 12:
     584            0 :             return getLastLaneChangeOffset();
     585            0 :         case 13:
     586            0 :             return getLane()->getVehicleMaxSpeed(this);
     587            0 :         case 14:
     588            0 :             return getEmissions<PollutantsInterface::CO2>();
     589            0 :         case 15:
     590            0 :             return getEmissions<PollutantsInterface::CO>();
     591            0 :         case 16:
     592            0 :             return getEmissions<PollutantsInterface::PM_X>();
     593            0 :         case 17:
     594            0 :             return getEmissions<PollutantsInterface::NO_X>();
     595            0 :         case 18:
     596            0 :             return getEmissions<PollutantsInterface::HC>();
     597            0 :         case 19:
     598            0 :             return getEmissions<PollutantsInterface::FUEL>();
     599            0 :         case 20:
     600            0 :             return getHarmonoise_NoiseEmissions();
     601            0 :         case 21:
     602            0 :             return getNumberReroutes();
     603            0 :         case 22:
     604            0 :             return gSelected.isSelected(GLO_VEHICLE, getGlID());
     605            0 :         case 23:
     606            0 :             return getLaneChangeModel().isOpposite() ? -100 : getBestLaneOffset();
     607            0 :         case 24:
     608            0 :             return getAcceleration();
     609            0 :         case 25:
     610            0 :             return getTimeGapOnLane();
     611            0 :         case 26:
     612            0 :             return STEPS2TIME(getDepartDelay());
     613            0 :         case 27:
     614            0 :             return getEmissions<PollutantsInterface::ELEC>();
     615            0 :         case 28:
     616            0 :             return getRelativeStateOfCharge();
     617            0 :         case 29:
     618            0 :             return getChargedEnergy();
     619            0 :         case 30:
     620            0 :             return getTimeLossSeconds();
     621            0 :         case 31:
     622            0 :             return getStopDelay();
     623            0 :         case 32:
     624            0 :             return getStopArrivalDelay();
     625            0 :         case 33:
     626            0 :             return getLaneChangeModel().getSpeedLat();
     627              :         case 34: // by numerical param value
     628              :             std::string error;
     629            0 :             std::string val = getPrefixedParameter(s.vehicleParam, error);
     630              :             try {
     631            0 :                 if (val == "") {
     632            0 :                     return GUIVisualizationSettings::MISSING_DATA;
     633              :                 } else {
     634            0 :                     return StringUtils::toDouble(val);
     635              :                 }
     636            0 :             } catch (NumberFormatException&) {
     637              :                 try {
     638            0 :                     return StringUtils::toBool(val);
     639            0 :                 } catch (BoolFormatException&) {
     640            0 :                     WRITE_WARNINGF(TL("Vehicle parameter '%' key '%' is not a number for vehicle '%'."),
     641              :                                    myParameter->getParameter(s.vehicleParam, "0"), s.vehicleParam, getID());
     642            0 :                     return GUIVisualizationSettings::MISSING_DATA;
     643            0 :                 }
     644            0 :             }
     645              :     }
     646              :     return 0;
     647              : }
     648              : 
     649              : 
     650              : void
     651            0 : GUIVehicle::drawBestLanes() const {
     652            0 :     myLock.lock();
     653            0 :     std::vector<std::vector<MSVehicle::LaneQ> > bestLanes = myBestLanes;
     654            0 :     myLock.unlock();
     655            0 :     for (std::vector<std::vector<MSVehicle::LaneQ> >::iterator j = bestLanes.begin(); j != bestLanes.end(); ++j) {
     656              :         std::vector<MSVehicle::LaneQ>& lanes = *j;
     657              :         double gmax = -1;
     658              :         double rmax = -1;
     659            0 :         for (std::vector<MSVehicle::LaneQ>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
     660            0 :             gmax = MAX2((*i).length, gmax);
     661            0 :             rmax = MAX2((*i).occupation, rmax);
     662              :         }
     663            0 :         for (std::vector<MSVehicle::LaneQ>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
     664            0 :             const PositionVector& shape = (*i).lane->getShape();
     665            0 :             double g = (*i).length / gmax;
     666            0 :             double r = (*i).occupation / rmax;
     667            0 :             glColor3d(r, g, 0);
     668            0 :             double width = 0.5 / (1 + abs((*i).bestLaneOffset));
     669            0 :             GLHelper::drawBoxLines(shape, width);
     670              : 
     671              :             PositionVector s1 = shape;
     672            0 :             s1.move2side((double) .1);
     673            0 :             glColor3d(r, 0, 0);
     674            0 :             GLHelper::drawLine(s1);
     675            0 :             s1.move2side((double) - .2);
     676            0 :             glColor3d(0, g, 0);
     677            0 :             GLHelper::drawLine(s1);
     678              : 
     679            0 :             glColor3d(r, g, 0);
     680            0 :         }
     681              :     }
     682            0 : }
     683              : 
     684              : 
     685              : void
     686            0 : GUIVehicle::drawRouteHelper(const GUIVisualizationSettings& s, ConstMSRoutePtr r, bool future, bool noLoop, const RGBColor& col) const {
     687            0 :     const double exaggeration = s.vehicleSize.getExaggeration(s, this) * (s.gaming ? 0.5 : 1);
     688            0 :     MSRouteIterator start = future ? myCurrEdge : r->begin();
     689              :     MSRouteIterator i = start;
     690            0 :     const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation();
     691              :     // draw continuation lanes when drawing the current route where available
     692            0 :     int bestLaneIndex = (r == myRoute ? 0 : (int)bestLaneConts.size());
     693              :     std::map<const MSLane*, int> repeatLane; // count repeated occurrences of the same edge
     694            0 :     const double textSize = s.vehicleName.size / s.scale;
     695              :     const GUILane* prevLane = nullptr;
     696              :     int reversalIndex = 0;
     697            0 :     const int indexDigits = (int)toString(r->size()).size();
     698            0 :     if (!isOnRoad() && !isParking()) {
     699              :         // simulation time has already advanced so isRemoteControlled is always false
     700            0 :         const std::string offRoadLabel = hasInfluencer() && getInfluencer()->isRemoteAffected(SIMSTEP) ? "offRoad" : "teleporting";
     701            0 :         GLHelper::drawTextSettings(s.vehicleValue, offRoadLabel, getPosition(), s.scale, s.angle, 1.0);
     702            0 :     } else if (myLane->isInternal()) {
     703            0 :         bestLaneIndex++;
     704              :     }
     705            0 :     const bool s2 = s.secondaryShape;
     706            0 :     for (; i != r->end(); ++i) {
     707              :         const GUILane* lane;
     708            0 :         if (bestLaneIndex < (int)bestLaneConts.size() && bestLaneConts[bestLaneIndex] != 0 && (*i) == &(bestLaneConts[bestLaneIndex]->getEdge())) {
     709              :             lane = static_cast<GUILane*>(bestLaneConts[bestLaneIndex]);
     710            0 :             ++bestLaneIndex;
     711              :         } else {
     712            0 :             const std::vector<MSLane*>* allowed = (*i)->allowedLanes(getVClass());
     713            0 :             if (allowed != nullptr && allowed->size() != 0) {
     714            0 :                 lane = static_cast<GUILane*>((*allowed)[0]);
     715              :             } else {
     716            0 :                 lane = static_cast<GUILane*>((*i)->getLanes()[0]);
     717              :             }
     718              :         }
     719            0 :         GLHelper::setColor(col);
     720            0 :         GLHelper::drawBoxLines(lane->getShape(s2), lane->getShapeRotations(s2), lane->getShapeLengths(s2), exaggeration);
     721            0 :         if (prevLane != nullptr && lane->getBidiLane() == prevLane) {
     722              :             // indicate train reversal
     723            0 :             std::string label = "reverse:" + toString(reversalIndex++);
     724            0 :             if (s.showRouteIndex) {
     725            0 :                 label += "@r" + toString((int)(i - myCurrEdge));
     726              :             }
     727            0 :             Position pos = lane->geometryPositionAtOffset(lane->getLength() / 2) - Position(0, textSize * repeatLane[lane]);
     728            0 :             GLHelper::drawTextSettings(s.vehicleValue, label, pos, s.scale, s.angle, 1.0);
     729              :         }
     730            0 :         if (s.showRouteIndex) {
     731            0 :             std::string label = toString((int)(i - myCurrEdge));
     732            0 :             const double laneAngle = lane->getShape(s2).angleAt2D(0);
     733            0 :             Position pos = lane->getShape(s2).front() - Position(0, textSize * repeatLane[lane]) + Position(
     734            0 :                                (laneAngle >= -0.25 * M_PI && laneAngle < 0.75 * M_PI ? 1 : -1) * 0.4 * indexDigits * textSize, 0);
     735              :             //GLHelper::drawText(label, pos, 1.0, textSize, s.vehicleName.color);
     736            0 :             GLHelper::drawTextSettings(s.vehicleName, label, pos, s.scale, s.angle, 1.0);
     737              :         }
     738            0 :         repeatLane[lane]++;
     739              :         prevLane = lane;
     740            0 :         if (noLoop && i != start && (*i) == (*start)) {
     741              :             break;
     742              :         }
     743              :     }
     744            0 :     drawStopLabels(s, noLoop, col);
     745            0 :     drawParkingInfo(s);
     746            0 :     drawChargingInfo(s);
     747            0 : }
     748              : 
     749              : 
     750              : double
     751            0 : GUIVehicle::getLastLaneChangeOffset() const {
     752            0 :     return STEPS2TIME(getLaneChangeModel().getLastLaneChangeOffset());
     753              : }
     754              : 
     755              : 
     756              : std::string
     757            0 : GUIVehicle::getStopInfo() const {
     758            0 :     std::string result = "";
     759            0 :     if (isParking()) {
     760              :         result += "parking";
     761            0 :     } else if (isStopped()) {
     762              :         result += "stopped";
     763            0 :     } else if (hasStops()) {
     764            0 :         return "next: " + myStops.front().getDescription();
     765              :     } else {
     766            0 :         return "";
     767              :     }
     768            0 :     if (myStops.front().pars.triggered) {
     769              :         result += ", triggered";
     770              :     }
     771            0 :     if (myStops.front().pars.containerTriggered) {
     772              :         result += ", containerTriggered";
     773              :     }
     774            0 :     if (myStops.front().pars.collision) {
     775              :         result += ", collision";
     776              :     }
     777            0 :     if (myStops.front().pars.arrival != -1) {
     778            0 :         result += ", arrival=" + time2string(myStops.front().pars.arrival);
     779              :     }
     780            0 :     if (myStops.front().pars.started != -1) {
     781            0 :         result += ", started=" + time2string(myStops.front().pars.started);
     782              :     }
     783            0 :     if (myStops.front().pars.until != -1) {
     784            0 :         result += ", until=" + time2string(myStops.front().pars.until);
     785              :     }
     786            0 :     if (myStops.front().pars.extension != -1) {
     787            0 :         result += ", extension=" + time2string(myStops.front().pars.extension);
     788              :     }
     789            0 :     if (!myStops.front().pars.permitted.empty()) {
     790            0 :         result += ", permitted=" + toString(myStops.front().pars.permitted);
     791              :     }
     792            0 :     if (myStops.front().pars.actType != "") {
     793            0 :         result += ", actType=" + myStops.front().pars.actType;
     794              :     }
     795            0 :     result += ", duration=" + time2string(myStops.front().duration);
     796            0 :     return StringUtils::wrapText(result, 60);
     797              : }
     798              : 
     799              : 
     800              : void
     801            0 : GUIVehicle::selectBlockingFoes() const {
     802            0 :     double dist = myLane->getLength() - getPositionOnLane();
     803              : #ifdef DEBUG_FOES
     804              :     gDebugFlag1 = true;
     805              :     std::cout << SIMTIME << " selectBlockingFoes veh=" << getID() << " dist=" << dist << " numLinks=" << myLFLinkLanes.size() << "\n";
     806              : #endif
     807            0 :     for (DriveItemVector::const_iterator i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
     808              :         const DriveProcessItem& dpi = *i;
     809            0 :         if (dpi.myLink == nullptr) {
     810              :             /// XXX if the vehicle intends to stop on an intersection, there could be a relevant exitLink (see #4299)
     811            0 :             continue;
     812              :         }
     813              :         MSLink::BlockingFoes blockingFoes;
     814              :         std::vector<const MSPerson*> blockingPersons;
     815              : #ifdef DEBUG_FOES
     816              :         std::cout << "   foeLink=" << dpi.myLink->getViaLaneOrLane()->getID() << "\n";
     817              :         const bool isOpen =
     818              : #endif
     819            0 :             dpi.myLink->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(), getVehicleType().getLength(),
     820            0 :                                getImpatience(), getCarFollowModel().getMaxDecel(), getWaitingTime(), getLateralPositionOnLane(), &blockingFoes, false, this, dpi.myDistance);
     821              : #ifdef DEBUG_FOES
     822              :         if (!isOpen) {
     823              :             std::cout << "     closed due to:\n";
     824              :             for (const auto& item : blockingFoes) {
     825              :                 std::cout << "   " << item->getID() << "\n";
     826              :             }
     827              :         }
     828              : #endif
     829            0 :         if (getLaneChangeModel().getShadowLane() != nullptr) {
     830            0 :             MSLink* parallelLink = dpi.myLink->getParallelLink(getLaneChangeModel().getShadowDirection());
     831            0 :             if (parallelLink != nullptr) {
     832            0 :                 const double shadowLatPos = getLateralPositionOnLane() - getLaneChangeModel().getShadowDirection() * 0.5 * (
     833            0 :                                                 myLane->getWidth() + getLaneChangeModel().getShadowLane()->getWidth());
     834              : #ifdef DEBUG_FOES
     835              :                 const bool isShadowOpen =
     836              : #endif
     837            0 :                     parallelLink->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
     838            0 :                                          getVehicleType().getLength(), getImpatience(),
     839              :                                          getCarFollowModel().getMaxDecel(),
     840            0 :                                          getWaitingTime(), shadowLatPos, &blockingFoes, false, this, dpi.myDistance);
     841              : #ifdef DEBUG_FOES
     842              :                 if (!isShadowOpen) {
     843              :                     std::cout <<  "    foes at shadow link=" << parallelLink->getViaLaneOrLane()->getID() << ":\n";
     844              :                     for (const auto& item : blockingFoes) {
     845              :                         std::cout << "   " << item->getID() << "\n";
     846              :                     }
     847              :                 }
     848              : #endif
     849              :             }
     850              :         }
     851            0 :         for (const auto& item : blockingFoes) {
     852            0 :             if (item->isVehicle()) {
     853            0 :                 gSelected.select(static_cast<const GUIVehicle*>(item)->getGlID());
     854              :             } else {
     855            0 :                 gSelected.select(static_cast<const GUIPerson*>(item)->getGlID());
     856              :             }
     857              :         }
     858            0 :         const MSLink::LinkLeaders linkLeaders = (dpi.myLink)->getLeaderInfo(this, dist, &blockingPersons);
     859              : #ifdef DEBUG_FOES
     860              :         gDebugFlag1 = false;
     861              : #endif
     862            0 :         for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
     863              :             // the vehicle to enter the junction first has priority
     864            0 :             const GUIVehicle* leader = dynamic_cast<const GUIVehicle*>(it->vehAndGap.first);
     865            0 :             if (leader != nullptr) {
     866            0 :                 if (isLeader(dpi.myLink, leader, it->vehAndGap.second) || it->inTheWay()) {
     867            0 :                     gSelected.select(leader->getGlID());
     868              : #ifdef DEBUG_FOES
     869              :                     std::cout << "      linkLeader=" << leader->getID() << "\n";
     870              : #endif
     871              :                 }
     872              :             } else {
     873            0 :                 for (std::vector<const MSPerson*>::iterator it_p = blockingPersons.begin(); it_p != blockingPersons.end(); ++it_p) {
     874            0 :                     const GUIPerson* foe = dynamic_cast<const GUIPerson*>(*it_p);
     875            0 :                     if (foe != nullptr) {
     876            0 :                         gSelected.select(foe->getGlID());
     877              :                         //std::cout << SIMTIME << " veh=" << getID() << " is blocked on link " << dpi.myLink->getRespondIndex() << " to " << dpi.myLink->getViaLaneOrLane()->getID() << " by pedestrian. dist=" << it->second << "\n";
     878              :                     }
     879              :                 }
     880              :             }
     881              :         }
     882            0 :         dist += dpi.myLink->getViaLaneOrLane()->getLength();
     883            0 :     }
     884            0 : }
     885              : 
     886              : 
     887              : void
     888           43 : GUIVehicle::drawOutsideNetwork(bool add) {
     889           43 :     GUIMainWindow* mw = GUIMainWindow::getInstance();
     890           43 :     GUISUMOAbstractView* view = mw->getActiveView();
     891           43 :     if (view != nullptr) {
     892           43 :         if (add) {
     893           32 :             if ((myAdditionalVisualizations[view] & VO_DRAW_OUTSIDE_NETWORK) == 0) {
     894            5 :                 myAdditionalVisualizations[view] |= VO_DRAW_OUTSIDE_NETWORK;
     895            5 :                 view->addAdditionalGLVisualisation(this);
     896              :             }
     897              :         } else {
     898           11 :             view->removeAdditionalGLVisualisation(this);
     899           11 :             myAdditionalVisualizations[view] &= ~VO_DRAW_OUTSIDE_NETWORK;
     900              :         }
     901              :     }
     902           43 : }
     903              : 
     904              : bool
     905     22741375 : GUIVehicle::isSelected() const {
     906     22741375 :     return gSelected.isSelected(GLO_VEHICLE, getGlID());
     907              : }
     908              : 
     909              : int
     910            0 : GUIVehicle::getRightSublaneOnEdge() const {
     911            0 :     const double rightSide = getRightSideOnEdge();
     912            0 :     const std::vector<double>& sublaneSides = myLane->getEdge().getSubLaneSides();
     913            0 :     for (int i = 0; i < (int)sublaneSides.size(); ++i) {
     914            0 :         if (sublaneSides[i] > rightSide) {
     915            0 :             return MAX2(i - 1, 0);
     916              :         }
     917              :     }
     918            0 :     return (int)sublaneSides.size() - 1;
     919            0 : }
     920              : 
     921              : int
     922            0 : GUIVehicle::getLeftSublaneOnEdge() const {
     923              :     const double leftSide = getLeftSideOnEdge();
     924            0 :     const std::vector<double>& sublaneSides = myLane->getEdge().getSubLaneSides();
     925            0 :     for (int i = (int)sublaneSides.size() - 1; i >= 0; --i) {
     926            0 :         if (sublaneSides[i] < leftSide) {
     927            0 :             return i;
     928              :         }
     929              :     }
     930              :     return -1;
     931            0 : }
     932              : 
     933              : 
     934              : std::string
     935            0 : GUIVehicle::getLCStateRight() const {
     936            0 :     return toString((LaneChangeAction)getLaneChangeModel().getSavedState(-1).second);
     937              : }
     938              : 
     939              : std::string
     940            0 : GUIVehicle::getLCStateLeft() const {
     941            0 :     return toString((LaneChangeAction)getLaneChangeModel().getSavedState(1).second);
     942              : }
     943              : 
     944              : std::string
     945            0 : GUIVehicle::getLCStateCenter() const {
     946            0 :     return toString((LaneChangeAction)getLaneChangeModel().getSavedState(0).second);
     947              : }
     948              : 
     949              : std::string
     950            0 : GUIVehicle::getLaneID() const {
     951            0 :     return Named::getIDSecure(myLane, "n/a");
     952              : }
     953              : 
     954              : std::string
     955            0 : GUIVehicle::getBackLaneIDs() const {
     956            0 :     return toString(myFurtherLanes);
     957              : }
     958              : 
     959              : std::string
     960            0 : GUIVehicle::getShadowLaneID() const {
     961            0 :     return Named::getIDSecure(getLaneChangeModel().getShadowLane(), "");
     962              : }
     963              : 
     964              : std::string
     965            0 : GUIVehicle::getTargetLaneID() const {
     966            0 :     return Named::getIDSecure(getLaneChangeModel().getTargetLane(), "");
     967              : }
     968              : 
     969              : 
     970              : std::string
     971            0 : GUIVehicle::getDriveWays() const {
     972              :     std::vector<std::string> result;
     973            0 :     for (auto item : myMoveReminders) {
     974            0 :         const MSDriveWay* dw = dynamic_cast<const MSDriveWay*>(item.first);
     975            0 :         if (dw) {
     976            0 :             result.push_back(dw->getID());
     977              :         }
     978              :     }
     979            0 :     return StringUtils::wrapText(joinToStringSorting(result, " "), 60);
     980            0 : }
     981              : 
     982              : double
     983            0 : GUIVehicle::getManeuverDist() const {
     984            0 :     return getLaneChangeModel().getManeuverDist();
     985              : }
     986              : 
     987              : std::string
     988            0 : GUIVehicle::getSpeedMode() const {
     989            0 :     return std::bitset<7>(getInfluencer()->getSpeedMode()).to_string();
     990              : }
     991              : 
     992              : std::string
     993            0 : GUIVehicle::getLaneChangeMode() const {
     994            0 :     return std::bitset<12>(getInfluencer()->getLaneChangeMode()).to_string();
     995              : }
     996              : 
     997              : void
     998            0 : GUIVehicle::rerouteDRTStop(MSStoppingPlace* busStop) {
     999              :     SUMOTime intermediateDuration = TIME2STEPS(20);
    1000              :     SUMOTime finalDuration = SUMOTime_MAX;
    1001            0 :     if (myParameter->stops.size() >= 2) {
    1002              :         // copy durations from the original stops
    1003            0 :         intermediateDuration = myParameter->stops.front().duration;
    1004            0 :         finalDuration = myParameter->stops.back().duration;
    1005              :     }
    1006              :     // if the stop is already in the list of stops, cancel all stops that come
    1007              :     // after it and set the stop duration
    1008            0 :     std::string line = "";
    1009              :     int destinations = 0;
    1010              :     bool add = true;
    1011            0 :     for (auto it = myStops.begin(); it != myStops.end(); it++) {
    1012            0 :         if (!it->reached && destinations < 2 && it->busstop != nullptr) {
    1013              :             line += it->busstop->getID();
    1014            0 :             destinations++;
    1015              :         }
    1016            0 :         if (it->busstop == busStop) {
    1017            0 :             it->duration = finalDuration;
    1018            0 :             myStops.erase(++it, myStops.end());
    1019              :             add = false;
    1020              :             break;
    1021              :         } else {
    1022            0 :             it->duration = MIN2(it->duration, intermediateDuration);
    1023              :         }
    1024              :     }
    1025            0 :     if (destinations < 2) {
    1026              :         line += busStop->getID();
    1027              :     }
    1028            0 :     if (add) {
    1029              :         // create new stop
    1030            0 :         SUMOVehicleParameter::Stop stopPar;
    1031              :         stopPar.busstop = busStop->getID();
    1032            0 :         stopPar.lane = busStop->getLane().getID();
    1033            0 :         stopPar.startPos = busStop->getBeginLanePosition();
    1034            0 :         stopPar.endPos = busStop->getEndLanePosition();
    1035            0 :         stopPar.duration = finalDuration;
    1036            0 :         stopPar.until = -1;
    1037            0 :         stopPar.triggered = false;
    1038            0 :         stopPar.containerTriggered = false;
    1039            0 :         stopPar.parking = ParkingType::ONROAD;
    1040            0 :         stopPar.index = STOP_INDEX_FIT;
    1041            0 :         stopPar.parametersSet = STOP_START_SET | STOP_END_SET;
    1042              :         // clean up prior route to improve visualisation, ensure that the stop can be added immediately
    1043            0 :         ConstMSEdgeVector edges = myRoute->getEdges();
    1044            0 :         edges.erase(edges.begin(), edges.begin() + getRoutePosition());
    1045            0 :         edges.push_back(&busStop->getLane().getEdge());
    1046            0 :         replaceRouteEdges(edges, -1, 0, "DRT.tmp", false, false, false);
    1047              :         std::string errorMsg;
    1048              :         // add stop
    1049            0 :         addStop(stopPar, errorMsg);
    1050            0 :     }
    1051            0 :     const bool hasReroutingDevice = getDevice(typeid(MSDevice_Routing)) != nullptr;
    1052              :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
    1053            0 :             ? MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass())
    1054            0 :             : MSNet::getInstance()->getRouterTT(getRNGIndex());
    1055              :     // reroute to ensure the new stop is reached
    1056            0 :     reroute(MSNet::getInstance()->getCurrentTimeStep(), "DRT", router);
    1057            0 :     myParameter->line = line;
    1058              :     assert(haveValidStopEdges());
    1059            0 : }
    1060              : 
    1061              : Position
    1062     14584861 : GUIVehicle::getVisualPosition(bool s2, const double offset) const {
    1063     14584861 :     if (s2) {
    1064              :         // see MSVehicle::getPosition
    1065            0 :         if (myLane == nullptr) {
    1066            0 :             return Position::INVALID;
    1067              :         }
    1068            0 :         if (isParking()) {
    1069            0 :             if (myStops.begin()->parkingarea != nullptr) {
    1070            0 :                 return myStops.begin()->parkingarea->getVehiclePosition(*this);
    1071              :             } else {
    1072              :                 // position beside the road
    1073            0 :                 PositionVector shp = myLane->getEdge().getLanes()[0]->getShape(s2);
    1074            0 :                 shp.move2side(SUMO_const_laneWidth * (MSGlobals::gLefthand ? -1 : 1));
    1075            0 :                 return shp.positionAtOffset((getPositionOnLane() + offset) * myLane->getLengthGeometryFactor(s2));
    1076            0 :             }
    1077              :         }
    1078            0 :         const PositionVector& shape = myLane->getShape(s2);
    1079            0 :         const double posLat = (MSGlobals::gLefthand ? 1 : -1) * getLateralPositionOnLane();
    1080            0 :         return shape.positionAtOffset((getPositionOnLane() + offset) * myLane->getLengthGeometryFactor(s2), posLat);
    1081              :     } else {
    1082     14584861 :         return getPosition(offset);
    1083              :     }
    1084              : }
    1085              : 
    1086              : 
    1087              : double
    1088     14584331 : GUIVehicle::getVisualAngle(bool s2) const {
    1089     14584331 :     if (s2) {
    1090              :         // see MSVehicle::computeAngle
    1091            0 :         const PositionVector& shape = myLane->getShape(s2);
    1092            0 :         if (isParking()) {
    1093            0 :             if (myStops.begin()->parkingarea != nullptr) {
    1094            0 :                 return myStops.begin()->parkingarea->getVehicleAngle(*this);
    1095              :             } else {
    1096            0 :                 return shape.rotationAtOffset(getPositionOnLane() * myLane->getLengthGeometryFactor(s2));
    1097              :             }
    1098              :         }
    1099              :         // if (myLaneChangeModel->isChangingLanes()) {
    1100            0 :         const double lefthandSign = (MSGlobals::gLefthand ? -1 : 1);
    1101            0 :         Position p1 = getVisualPosition(s2);
    1102            0 :         Position p2 = getVisualPosition(s2, MAX2(0.0, -myType->getLength()));
    1103              :         double result = (p1 != p2 ? p2.angleTo2D(p1) :
    1104            0 :                          shape.rotationAtOffset(getPositionOnLane() * myLane->getLengthGeometryFactor(s2)));
    1105            0 :         if (myLaneChangeModel->isChangingLanes()) {
    1106            0 :             result += lefthandSign * DEG2RAD(myLaneChangeModel->getAngleOffset());
    1107              :         }
    1108            0 :         return result;
    1109              :     } else {
    1110     14584331 :         return getAngle();
    1111              :     }
    1112              : }
    1113              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1