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