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 : /****************************************************************************/
|