LCOV - code coverage report
Current view: top level - src/guisim - GUIVehicle.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 147 604 24.3 %
Date: 2024-04-27 15:34:54 Functions: 12 35 34.3 %

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

Generated by: LCOV version 1.14