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