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