Line data Source code
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 MSBaseVehicle.cpp
15 : /// @author Michael Behrisch
16 : /// @author Daniel Krajzewicz
17 : /// @author Jakob Erdmann
18 : /// @author Mirko Barthauer
19 : /// @date Mon, 8 Nov 2010
20 : ///
21 : // A base class for vehicle implementations
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <iostream>
26 : #include <cassert>
27 : #include <algorithm>
28 : #include <functional>
29 : #include <utils/common/StdDefs.h>
30 : #include <utils/common/MsgHandler.h>
31 : #include <utils/options/OptionsCont.h>
32 : #include <utils/iodevices/OutputDevice.h>
33 : #include <utils/emissions/PollutantsInterface.h>
34 : #include <utils/emissions/HelpersHarmonoise.h>
35 : #include <libsumo/TraCIConstants.h>
36 : #include <mesosim/MELoop.h>
37 : #include <mesosim/MEVehicle.h>
38 : #include <microsim/devices/MSRoutingEngine.h>
39 : #include <microsim/devices/MSDevice_Transportable.h>
40 : #include <microsim/devices/MSDevice_Emissions.h>
41 : #include <microsim/devices/MSDevice_Battery.h>
42 : #include <microsim/devices/MSDevice_ElecHybrid.h>
43 : #include <microsim/devices/MSDevice_Taxi.h>
44 : #include <microsim/devices/MSDevice_Routing.h>
45 : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
46 : #include <microsim/transportables/MSPerson.h>
47 : #include <microsim/transportables/MSStageDriving.h>
48 : #include <microsim/trigger/MSChargingStation.h>
49 : #include <microsim/trigger/MSStoppingPlaceRerouter.h>
50 : #include <microsim/trigger/MSTriggeredRerouter.h>
51 : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
52 : #include <microsim/traffic_lights/MSRailSignalControl.h>
53 : #include "MSEventControl.h"
54 : #include "MSGlobals.h"
55 : #include "MSVehicleControl.h"
56 : #include "MSVehicleType.h"
57 : #include "MSEdge.h"
58 : #include "MSLane.h"
59 : #include "MSMoveReminder.h"
60 : #include "MSEdgeWeightsStorage.h"
61 : #include "MSNet.h"
62 : #include "MSStop.h"
63 : #include "MSParkingArea.h"
64 : #include "MSInsertionControl.h"
65 : #include "MSStopOptimizer.h"
66 : #include "MSBaseVehicle.h"
67 :
68 : //#define DEBUG_REROUTE
69 : //#define DEBUG_ADD_STOP
70 : //#define DEBUG_COND (getID() == "")
71 : //#define DEBUG_COND (true)
72 : //#define DEBUG_REPLACE_ROUTE
73 : #define DEBUG_COND (isSelected())
74 :
75 : // ===========================================================================
76 : // static members
77 : // ===========================================================================
78 : const SUMOTime MSBaseVehicle::NOT_YET_DEPARTED = SUMOTime_MAX;
79 : std::vector<MSTransportable*> MSBaseVehicle::myEmptyTransportableVector;
80 : #ifdef _DEBUG
81 : std::set<std::string> MSBaseVehicle::myShallTraceMoveReminders;
82 : #endif
83 : SUMOTrafficObject::NumericalID MSBaseVehicle::myCurrentNumericalIndex = 0;
84 :
85 : // ===========================================================================
86 : // Influencer method definitions
87 : // ===========================================================================
88 :
89 3564 : MSBaseVehicle::BaseInfluencer::BaseInfluencer()
90 3564 : {}
91 :
92 : // ===========================================================================
93 : // method definitions
94 : // ===========================================================================
95 :
96 : double
97 0 : MSBaseVehicle::getPreviousSpeed() const {
98 0 : throw ProcessError("getPreviousSpeed() is not available for non-MSVehicles.");
99 : }
100 :
101 :
102 5382016 : MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
103 5382016 : MSVehicleType* type, const double speedFactor) :
104 : SUMOVehicle(pars->id),
105 5382016 : myParameter(pars),
106 : myRoute(route),
107 5382016 : myType(type),
108 5382016 : myCurrEdge(route->begin()),
109 5393845 : myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
110 5382016 : myMoveReminders(0),
111 5382016 : myPersonDevice(nullptr),
112 5382016 : myContainerDevice(nullptr),
113 5382016 : myEnergyParams(nullptr),
114 5382016 : myDeparture(NOT_YET_DEPARTED),
115 5382016 : myDepartPos(-1),
116 5382016 : myArrivalPos(-1),
117 5382016 : myArrivalLane(-1),
118 5382016 : myNumberReroutes(0),
119 5382016 : myStopUntilOffset(0),
120 5382016 : myOdometer(0.),
121 5382016 : myRouteValidity(ROUTE_UNCHECKED),
122 5382016 : myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
123 5382016 : myNumericalID(myCurrentNumericalIndex++),
124 10764032 : myRandomSeed(RandHelper::murmur3_32(pars->id, RandHelper::getSeed())),
125 10764032 : myEdgeWeights(nullptr)
126 : #ifdef _DEBUG
127 : , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
128 : #endif
129 : {
130 5382016 : if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
131 583746 : pars->parametersSet |= VEHPARS_FORCE_REROUTE;
132 : }
133 5382016 : if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
134 3828879 : setDepartAndArrivalEdge();
135 : }
136 5382016 : calculateArrivalParams(true);
137 5382016 : initTransientModelParams();
138 5382016 : }
139 :
140 :
141 5381915 : MSBaseVehicle::~MSBaseVehicle() {
142 5381915 : delete myEdgeWeights;
143 5381915 : if (myParameter->repetitionNumber == -1) {
144 : // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
145 459359 : MSRoute::checkDist(myParameter->routeid);
146 : }
147 9362242 : for (MSVehicleDevice* dev : myDevices) {
148 3980327 : delete dev;
149 : }
150 5381915 : delete myEnergyParams;
151 5381915 : delete myParkingMemory;
152 5381915 : delete myChargingMemory;
153 5381915 : checkRouteRemoval();
154 5381915 : delete myParameter;
155 5381915 : }
156 :
157 :
158 : void
159 14859036 : MSBaseVehicle::checkRouteRemoval() {
160 : // the check for an instance is needed for the unit tests which do not construct a network
161 : // TODO Optimize for speed and there should be a better way to check whether a vehicle is part of a flow
162 14859034 : if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
163 1370035 : myRoute->checkRemoval();
164 : }
165 7429518 : }
166 :
167 :
168 : std::string
169 7429516 : MSBaseVehicle::getFlowID() const {
170 7429516 : return getID().substr(0, getID().rfind('.'));
171 : }
172 :
173 :
174 : void
175 5382016 : MSBaseVehicle::initDevices() {
176 5382016 : MSDevice::buildVehicleDevices(*this, myDevices);
177 9357440 : for (MSVehicleDevice* dev : myDevices) {
178 3975441 : myMoveReminders.push_back(std::make_pair(dev, 0.));
179 : }
180 5381999 : if (MSGlobals::gHaveEmissions) {
181 : // ensure we have the emission parameters even if we don't have the device
182 914155 : getEmissionParameters();
183 : }
184 5381999 : }
185 :
186 :
187 : void
188 0 : MSBaseVehicle::setID(const std::string& /*newID*/) {
189 0 : throw ProcessError(TL("Changing a vehicle ID is not permitted"));
190 : }
191 :
192 : const SUMOVehicleParameter&
193 15454785098 : MSBaseVehicle::getParameter() const {
194 15454785098 : return *myParameter;
195 : }
196 :
197 :
198 : void
199 606 : MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
200 606 : delete myParameter;
201 606 : myParameter = newParameter;
202 606 : }
203 :
204 :
205 : bool
206 655817492 : MSBaseVehicle::ignoreTransientPermissions() const {
207 655817492 : return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
208 : }
209 :
210 : double
211 5753120958 : MSBaseVehicle::getMaxSpeed() const {
212 5753120958 : return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
213 : }
214 :
215 :
216 : const MSEdge*
217 2055669293 : MSBaseVehicle::succEdge(int nSuccs) const {
218 2055669293 : if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
219 1452243496 : return *(myCurrEdge + nSuccs);
220 : } else {
221 603425797 : return nullptr;
222 : }
223 : }
224 :
225 :
226 : const MSEdge*
227 3140703163 : MSBaseVehicle::getEdge() const {
228 3140703163 : return *myCurrEdge;
229 : }
230 :
231 :
232 : const std::set<SUMOTrafficObject::NumericalID>
233 65882 : MSBaseVehicle::getUpcomingEdgeIDs() const {
234 : std::set<SUMOTrafficObject::NumericalID> result;
235 297043 : for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
236 231161 : result.insert((*e)->getNumericalID());
237 : }
238 65882 : return result;
239 : }
240 :
241 :
242 : bool
243 4391631 : MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
244 4391631 : if (stop == nullptr) {
245 : return false;
246 : }
247 8744994 : for (const MSStop& s : myStops) {
248 8743331 : if (s.busstop == stop
249 8704605 : || s.containerstop == stop
250 4353379 : || s.parkingarea == stop
251 4353373 : || s.chargingStation == stop) {
252 : return true;
253 : }
254 : }
255 : return false;
256 : }
257 :
258 : bool
259 188562 : MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
260 397515 : for (const MSStop& s : myStops) {
261 367471 : if (&s.lane->getEdge() == edge) {
262 : return true;
263 : }
264 : }
265 30044 : return myRoute->getLastEdge() == edge;
266 : }
267 :
268 :
269 : bool
270 2793781 : MSBaseVehicle::reroute(SUMOTime t, const std::string& info, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, const bool onInit, const bool withTaz, const bool silent, const MSEdge* sink) {
271 : // check whether to reroute
272 2793781 : const MSEdge* source = withTaz && onInit ? MSEdge::dictionary(myParameter->fromTaz + "-source") : *getRerouteOrigin();
273 2793781 : if (source == nullptr) {
274 5 : source = *getRerouteOrigin();
275 : }
276 2793781 : if (sink == nullptr) {
277 2767937 : sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
278 2767937 : if (sink == nullptr) {
279 5 : sink = myRoute->getLastEdge();
280 : }
281 : }
282 2802196 : ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
283 : ConstMSEdgeVector edges;
284 2793781 : if (source != sink || !sink->prohibits(this)) {
285 2793775 : edges.push_back(source);
286 : }
287 : std::vector<StopEdgeInfo> stops;
288 : std::set<int> jumps;
289 :
290 :
291 2793781 : double sourcePos = getPositionOnLane();
292 : #ifdef DEBUG_REROUTE
293 : if (DEBUG_COND) {
294 : std::cout << " sourcePos=" << sourcePos << " lane=" << Named::getIDSecure(getLane()) << " departPos=" << myParameter->departPos << "\n";
295 : }
296 : #endif
297 2793781 : if (onInit && myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
298 55342 : sourcePos = myParameter->departPos;
299 2738439 : } else if (getLane() != nullptr && source != &getLane()->getEdge()) {
300 : // routing starts on the next edge
301 : sourcePos = 0;
302 : }
303 2793781 : if (myParameter->via.size() == 0) {
304 2785270 : double firstPos = INVALID_DOUBLE;
305 2785270 : double lastPos = INVALID_DOUBLE;
306 2785270 : stops = getStopEdges(firstPos, lastPos, jumps);
307 2785270 : if (stops.size() > 0) {
308 39677 : if (MSGlobals::gUseMesoSim && isStopped()) {
309 271 : sourcePos = getNextStop().pars.endPos;
310 : }
311 39677 : if (/*!MSGlobals::gUseMesoSim &&*/ !isStopped() && myStops.front().pars.speed == 0) {
312 36960 : sourcePos += getBrakeGap();
313 : }
314 : // avoid superfluous waypoints for first and last edge
315 39677 : const bool skipFirst = stops.front().edge == source && (source != getEdge() || sourcePos <= firstPos + NUMERICAL_EPS);
316 : #ifdef DEBUG_REROUTE
317 : if (DEBUG_COND) {
318 : std::cout << SIMTIME << " reroute " << info << " veh=" << getID() << " lane=" << Named::getIDSecure(getLane())
319 : << " source=" << source->getID() << " sourcePos=" << sourcePos << " firstPos=" << firstPos << " arrivalPos=" << myArrivalPos << " lastPos=" << lastPos
320 : << " route=" << toString(myRoute->getEdges()) << " skipFirst=" << skipFirst << "\n";
321 : }
322 : #endif
323 39677 : if (stops.size() == 1 && skipFirst) {
324 : stops.clear();
325 32077 : } else if (skipFirst) {
326 8179 : sourcePos = stops.front().pos;
327 : stops.erase(stops.begin());
328 : }
329 : }
330 : } else {
331 : std::set<const MSEdge*> jumpEdges;
332 : std::map<const MSEdge*, StopEdgeInfo> stopsOnVia;
333 23452 : for (const MSStop& stop : myStops) {
334 14941 : if (stop.pars.jump >= 0) {
335 : jumpEdges.insert(*stop.edge);
336 : }
337 : auto itsov = stopsOnVia.find(*stop.edge);
338 14941 : if (itsov == stopsOnVia.end()) {
339 28280 : stopsOnVia.insert({*stop.edge, StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stop.getEndPos(*this))});
340 : } else {
341 801 : itsov->second.priority = addStopPriority(itsov->second.priority, stop.pars.priority);
342 : }
343 : }
344 : // via takes precedence over stop edges
345 : // there is a consistency check in MSRouteHandler::addStop that warns when a stop edge is not part of the via edges
346 28629 : for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
347 20126 : MSEdge* viaEdge = MSEdge::dictionary(*it);
348 20126 : if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
349 : continue;
350 : }
351 : assert(viaEdge != 0);
352 17043 : if (!viaEdge->isTazConnector() && viaEdge->allowedLanes(getVClass()) == nullptr) {
353 24 : throw ProcessError(TLF("Vehicle '%' is not allowed on any lane of via edge '%'.", getID(), viaEdge->getID()));
354 : }
355 : auto itsov = stopsOnVia.find(viaEdge);
356 17035 : const double priority = (itsov == stopsOnVia.end() ? -1 : itsov->second.priority);
357 17035 : const SUMOTime arrival = (itsov == stopsOnVia.end() ? -1 : itsov->second.arrival);
358 17035 : const double pos = (itsov == stopsOnVia.end() ? 0 : itsov->second.pos);
359 17035 : stops.push_back(StopEdgeInfo(viaEdge, priority, arrival, pos));
360 : // @todo determine wether the viaEdge is also used by a stop and then use the stop priority here
361 : if (jumpEdges.count(viaEdge) != 0) {
362 15 : jumps.insert((int)stops.size());
363 : }
364 : }
365 : }
366 2756167 : if ((stops.size() == 0 && (source != sink || sourcePos > myArrivalPos))
367 2852698 : || ((stops.size() != 0) && (stops.back().edge != sink || myArrivalPos < stops.back().pos))) {
368 5428836 : stops.push_back(StopEdgeInfo(sink, -1, -1, myArrivalPos, true));
369 : }
370 : #ifdef DEBUG_REROUTE
371 : if (DEBUG_COND) {
372 : std::cout << SIMTIME << " stops: veh=" << getID() << " source=" << source->getID() << " sink=" << sink->getID() << " sourcePos=" << sourcePos << " arrivalPos=" << myArrivalPos << "\n";
373 : for (auto item : stops) {
374 : std::cout << " e=" << item.edge->getID() << " pos=" << item.pos << "\n";
375 : }
376 : }
377 : #endif
378 : int stopIndex = -1;
379 : auto stopIt = myStops.begin();
380 : SUMOTime startTime = t;
381 : bool hasSkipped = false;
382 : const double origSourcePos = sourcePos;
383 : const MSEdge* origSource = source;
384 13968865 : const SUMOTime maxDelay = TIME2STEPS(getFloatParam(toString(SUMO_TAG_CLOSING_REROUTE) + ".maxDelay", false, MSTriggeredRerouter::DEFAULT_MAXDELAY, false));
385 5593832 : for (auto& stopEdgeInfo : stops) {
386 2800064 : const MSEdge* const stopEdge = stopEdgeInfo.edge;
387 2800064 : const double priority = stopEdgeInfo.priority;
388 2800064 : stopIndex++;
389 : ConstMSEdgeVector into;
390 1185 : if (jumps.count(stopIndex) != 0) {
391 1185 : edges.push_back(stopEdge);
392 1185 : source = stopEdge;
393 1185 : continue;
394 : }
395 : // !!! need to adapt t here
396 2800608 : router.compute(source, sourcePos, stopEdge, stopEdgeInfo.pos, this, t, into, silent || priority >= 0);
397 : #ifdef DEBUG_REROUTE
398 : if (DEBUG_COND) {
399 : std::cout << SIMTIME << " reroute veh=" << getID() << " source=" << source->getID() << " sourcePos=" << sourcePos << " target=" << stopEdgeInfo.edge->getID() << " targetPos=" << stopEdgeInfo.pos << " edges=" << toString(into) << "\n";
400 : }
401 : #endif
402 2798879 : if (into.size() > 0) {
403 2883187 : while (stopIt != myStops.end() && stopIt->pars.edge != stopEdge->getID()) {
404 : stopIt++;
405 : }
406 :
407 2797913 : startTime += TIME2STEPS(router.recomputeCostsPos(into, this, sourcePos, stopEdgeInfo.pos, startTime));
408 2797913 : if (stopIt != myStops.end()) {
409 78283 : if (stopIt->pars.priority >= 0 && info != "device.rerouting") {
410 : // consider skipping this stop if it cannot be reached in a timely manner
411 : if (stopIt != myStops.end()) {
412 140 : SUMOTime arrival = stopEdgeInfo.arrival;
413 140 : if (arrival > 0) {
414 42 : SUMOTime delay = startTime - arrival;
415 : //std::cout << " t=" << time2string(t) << " veh=" << getID() << " info=" << info << " stopIndex=" << stopIndex
416 : // << " into=" << toString(into) << " sourcePos=" << sourcePos << " stopPos=" << stopPos
417 : // << " startTime=" << time2string(startTime) << " arrival=" << time2string(arrival) << " delay=" << time2string(delay) << "\n";
418 42 : if (delay > 0) {
419 24 : if (delay > maxDelay) {
420 9 : stopEdgeInfo.skipped = true;
421 9 : stopEdgeInfo.delay = delay;
422 : hasSkipped = true;
423 9 : continue;
424 : }
425 : }
426 : }
427 : }
428 : }
429 78274 : sourcePos = stopEdgeInfo.pos;
430 78274 : startTime += stopIt->getMinDuration(startTime);
431 : }
432 : edges.pop_back();
433 2797904 : edges.insert(edges.end(), into.begin(), into.end());
434 2797904 : if (edges.back()->isTazConnector()) {
435 : edges.pop_back();
436 : }
437 2797904 : source = edges.back();
438 2797904 : stopEdgeInfo.routeIndex = (int)edges.size() - 1;
439 : } else {
440 966 : if (priority >= 0) {
441 43 : stopEdgeInfo.skipped = true;
442 : hasSkipped = true;
443 43 : continue;
444 923 : } else if (stopEdgeInfo.isSink) {
445 : //error = TLF("Vehicle '%' has no valid route from edge '%' to destination edge '%'.", getID(), source->getID(), stopEdge->getID());
446 : edges.clear();
447 23 : } else if (source == stopEdge && stopEdgeInfo.stopPar != nullptr && stopEdgeInfo.stopPar->endPos >= sourcePos) {
448 : // special case: no failure on dynamically computed stop position
449 : edges.clear();
450 : } else {
451 14 : std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
452 7 : if (MSGlobals::gCheckRoutes || silent) {
453 5 : throw ProcessError(error);
454 : } else {
455 9 : WRITE_WARNING(error);
456 2 : edges.push_back(source);
457 2 : source = stopEdge;
458 : }
459 : }
460 : }
461 2800064 : }
462 2793768 : if (hasSkipped) {
463 : MSStopOptimizer opti(this, router, t, maxDelay);
464 192 : edges = opti.optimizeSkipped(origSource, origSourcePos, stops, edges);
465 240 : for (auto stop : stops) {
466 195 : if (stop.skipped || stop.origEdge != nullptr) {
467 52 : const MSEdge* origEdge = stop.origEdge == nullptr ? stop.edge : stop.origEdge;
468 52 : if (stop.delay > 0) {
469 27 : WRITE_WARNING(TLF("Vehicle '%' skips stop on edge '%' with delay % at time %.", getID(), origEdge->getID(), time2string(stop.delay), time2string(SIMSTEP)));
470 43 : } else if (stop.backtracked) {
471 9 : WRITE_WARNING(TLF("Vehicle '%' skips stop on edge '%' with priority % at time %.", getID(), origEdge->getID(), stop.priority, time2string(SIMSTEP)));
472 : } else {
473 120 : WRITE_WARNING(TLF("Vehicle '%' skips unreachable stop on edge '%' with priority % at time %.", getID(), origEdge->getID(), stop.priority, time2string(SIMSTEP)));
474 : }
475 : }
476 : }
477 : }
478 :
479 : // router.setHint(myCurrEdge, myRoute->end(), this, t);
480 2793768 : if (edges.empty() && silent) {
481 : return false;
482 : }
483 2793644 : if (!edges.empty() && edges.front()->isTazConnector()) {
484 : edges.erase(edges.begin());
485 : }
486 2793644 : if (!edges.empty() && edges.back()->isTazConnector()) {
487 : edges.pop_back();
488 : }
489 2793644 : const double routeCost = router.recomputeCosts(edges, this, t);
490 2793644 : const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
491 2793644 : const double savings = previousCost - routeCost;
492 2793644 : bool savingsOk = onInit || info != "device.rerouting" || gWeightsRandomFactor != 1;
493 : if (!savingsOk) {
494 593330 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
495 : assert(routingDevice != 0);
496 593330 : savingsOk = routingDevice->sufficientSaving(previousCost, routeCost);
497 593330 : if (!savingsOk) {
498 : std::string dummyMsg;
499 569921 : if (!hasValidRoute(dummyMsg, oldEdgesRemaining.begin(), oldEdgesRemaining.end(), true)) {
500 : // the old route is prohibted (i.e. due to temporary permission changes)
501 : savingsOk = true;
502 : }
503 : }
504 : }
505 : //if (getID() == "43") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
506 : // << " onInit=" << onInit
507 : // << " prevEdges=" << toString(oldEdgesRemaining)
508 : // << " newEdges=" << toString(edges)
509 : // << "\n";
510 569921 : if (savingsOk) {
511 2223890 : replaceRouteEdges(edges, routeCost, savings, info, onInit);
512 : }
513 : // this must be called even if the route could not be replaced
514 2793643 : if (onInit) {
515 2171849 : if (edges.empty()) {
516 210 : if (MSGlobals::gCheckRoutes) {
517 399 : throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
518 77 : } else if (source->isTazConnector()) {
519 228 : WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
520 27 : MSNet::getInstance()->getInsertionControl().descheduleDeparture(this);
521 : return false;
522 : }
523 : }
524 2171689 : setDepartAndArrivalEdge();
525 2171689 : calculateArrivalParams(onInit);
526 : }
527 2793483 : return !edges.empty();
528 2794075 : }
529 :
530 :
531 : bool
532 2263059 : MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
533 2263059 : if (edges.empty()) {
534 2394 : WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
535 798 : if (msgReturn != nullptr) {
536 : *msgReturn = "No route found";
537 : }
538 798 : return false;
539 : }
540 : // build a new id, first
541 : std::string id = getID();
542 2262261 : if (id[0] != '!') {
543 4524523 : id = "!" + id;
544 : }
545 2262261 : const std::string idSuffix = id + "!var#";
546 2262261 : int varIndex = 1;
547 2262261 : id = idSuffix + toString(varIndex);
548 4141917 : while (MSRoute::hasRoute(id)) {
549 3759312 : id = idSuffix + toString(++varIndex);
550 : }
551 2262261 : int oldSize = (int)edges.size();
552 2262261 : if (!onInit) {
553 88951 : const MSEdge* const origin = *getRerouteOrigin();
554 88951 : if (origin != *myCurrEdge && edges.front() == origin) {
555 998 : edges.insert(edges.begin(), *myCurrEdge);
556 998 : oldSize = (int)edges.size();
557 : }
558 177902 : edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
559 : }
560 2262261 : if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
561 : // re-assign stop iterators when rerouting to a new parkingArea / insertStop
562 : return true;
563 : }
564 1523144 : const RGBColor& c = myRoute->getColor();
565 1523144 : MSRoute* newRoute = new MSRoute(id, edges, false, &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), StopParVector());
566 : newRoute->setCosts(cost);
567 : newRoute->setSavings(savings);
568 1523145 : ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
569 3046288 : if (!MSRoute::dictionary(id, constRoute)) {
570 0 : delete newRoute;
571 0 : if (msgReturn != nullptr) {
572 1 : *msgReturn = "duplicate routeID '" + id + "'";
573 : }
574 0 : return false;
575 : }
576 :
577 : std::string msg;
578 1523177 : if (check && !hasValidRoute(msg, constRoute)) {
579 3 : WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), getID(), msg);
580 1 : if (MSGlobals::gCheckRoutes) {
581 1 : if (msgReturn != nullptr) {
582 : *msgReturn = msg;
583 : }
584 1 : return false;
585 : }
586 : }
587 3046286 : if (!replaceRoute(constRoute, info, onInit, (int)edges.size() - oldSize, false, removeStops, msgReturn)) {
588 : return false;
589 : }
590 : return true;
591 : }
592 :
593 :
594 : bool
595 2047621 : MSBaseVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
596 : const ConstMSEdgeVector& edges = newRoute->getEdges();
597 : // rebuild in-vehicle route information
598 2047621 : if (onInit) {
599 1454959 : myCurrEdge = newRoute->begin();
600 : } else {
601 592662 : MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
602 592662 : if (newCurrEdge == edges.end()) {
603 2 : if (msgReturn != nullptr) {
604 6 : *msgReturn = TLF("current edge '%' not found in new route", (*myCurrEdge)->getID());
605 : }
606 : #ifdef DEBUG_REPLACE_ROUTE
607 : if (DEBUG_COND) {
608 : std::cout << " newCurrEdge not found\n";
609 : }
610 : #endif
611 2 : return false;
612 : }
613 592660 : if (getLane() != nullptr) {
614 454560 : if (getLane()->getEdge().isInternal() && (
615 454569 : (newCurrEdge + 1) == edges.end() || (*(newCurrEdge + 1)) != &(getLane()->getOutgoingViaLanes().front().first->getEdge()))) {
616 9 : if (msgReturn != nullptr) {
617 1 : *msgReturn = TL("Vehicle is on junction-internal edge leading elsewhere");
618 : }
619 : #ifdef DEBUG_REPLACE_ROUTE
620 : if (DEBUG_COND) {
621 : std::cout << " Vehicle is on junction-internal edge leading elsewhere\n";
622 : }
623 : #endif
624 9 : return false;
625 454551 : } else if (getPositionOnLane() > getLane()->getLength()
626 454556 : && (myCurrEdge + 1) != myRoute->end()
627 12 : && (newCurrEdge + 1) != edges.end()
628 454563 : && *(myCurrEdge + 1) != *(newCurrEdge + 1)) {
629 7 : if (msgReturn != nullptr) {
630 0 : *msgReturn = TL("Vehicle is moving past junction and committed to move to another successor edge");
631 : }
632 : #ifdef DEBUG_REPLACE_ROUTE
633 : if (DEBUG_COND) {
634 : std::cout << " Vehicle is moving past junction and committed to move to another successor edge\n";
635 : }
636 : #endif
637 7 : return false;
638 : }
639 : }
640 592644 : myCurrEdge = newCurrEdge;
641 : }
642 2047603 : const bool stopsFromScratch = onInit && myRoute->getStops().empty();
643 : // assign new route
644 2047603 : checkRouteRemoval();
645 : myRoute = newRoute;
646 : // update arrival definition
647 2047603 : calculateArrivalParams(onInit);
648 : // save information that the vehicle was rerouted
649 2047603 : myNumberReroutes++;
650 2047603 : myStopUntilOffset += myRoute->getPeriod();
651 2047603 : MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::NEWROUTE, info);
652 2047603 : if (!onInit && isRail() && MSRailSignalControl::hasInstance()) {
653 : // we need to update driveways (add/remove reminders) before the next call to MSRailSignalControl::updateSignals
654 : //
655 : // rerouting may be triggered through
656 : // - MoveReminders (executeMove->activateReminders)
657 : // - rerouters
658 : // - devices (MSDevice_Stationfinder)
659 : // - TraCI (changeTarget, replaceStop, ...
660 : // - events (MSDevice_Routing::myRerouteCommand, MSDevice_Taxi::triggerDispatch)
661 : //
662 : // Since activateReminders actively modifies reminders, adding/deleting reminders would create a mess
663 : // hence, we use an event to be safe for all case
664 :
665 1498 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(new WrappingCommand<MSBaseVehicle>(this,
666 749 : &MSBaseVehicle::activateRemindersOnReroute), SIMSTEP);
667 : }
668 : #ifdef DEBUG_REPLACE_ROUTE
669 : if (DEBUG_COND) {
670 : std::cout << SIMTIME << " veh=" << getID() << " replaceRoute info=" << info << " on " << (*myCurrEdge)->getID()
671 : << " lane=" << Named::getIDSecure(getLane())
672 : << " stopsFromScratch=" << stopsFromScratch
673 : << " newSize=" << newRoute->getEdges().size()
674 : << " newIndex=" << (myCurrEdge - newRoute->begin())
675 : << " edges=" << toString(newRoute->getEdges())
676 : << "\n";
677 : }
678 : #endif
679 : // remove past stops which are not on the route anymore
680 2123213 : for (StopParVector::iterator it = myPastStops.begin(); it != myPastStops.end();) {
681 122631 : const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
682 75610 : if (std::find(myRoute->begin(), myRoute->end(), stopEdge) == myRoute->end()) {
683 5 : it = myPastStops.erase(it);
684 : } else {
685 : ++it;
686 : }
687 : }
688 : // if we did not drive yet it may be best to simply reassign the stops from scratch
689 2047603 : if (stopsFromScratch) {
690 : myStops.clear();
691 1454895 : addStops(!MSGlobals::gCheckRoutes);
692 : } else {
693 : // recheck old stops
694 592708 : MSRouteIterator searchStart = myCurrEdge;
695 592708 : double lastPos = getPositionOnLane() + getBrakeGap();
696 1047252 : if (getLane() != nullptr && getLane()->isInternal()
697 593592 : && myStops.size() > 0 && !myStops.front().lane->isInternal()) {
698 : // searchStart is still incoming to the intersection so lastPos
699 : // relative to that edge must be adapted
700 149 : lastPos += (*myCurrEdge)->getLength();
701 : }
702 : int stopIndex = 0;
703 630007 : for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
704 37299 : double endPos = iter->getEndPos(*this);
705 : #ifdef DEBUG_REPLACE_ROUTE
706 : if (DEBUG_COND) {
707 : std::cout << " stopEdge=" << iter->lane->getEdge().getID() << " start=" << (searchStart - myCurrEdge) << " endPos=" << endPos << " lastPos=" << lastPos << "\n";
708 : }
709 : #endif
710 37299 : if (*searchStart != &iter->lane->getEdge()
711 37299 : || endPos + NUMERICAL_EPS < lastPos) {
712 30412 : if (searchStart != edges.end() && !iter->reached) {
713 : searchStart++;
714 : }
715 : }
716 : lastPos = endPos;
717 :
718 37299 : iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
719 : #ifdef DEBUG_REPLACE_ROUTE
720 : if (DEBUG_COND) {
721 : std::cout << " foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
722 : }
723 : #endif
724 37299 : if (iter->edge == edges.end() && iter->pars.priority >= 0) {
725 : const std::string oldEdge = iter->pars.edge;
726 104 : const std::string oldName = iter->getStoppingPlaceName().first;
727 52 : if (replaceWithAlternative(iter, searchStart, edges.end())) {
728 136 : WRITE_WARNINGF(TL("Vehicle '%' replaced stop on edge '%' (named '%') and now stops at '%' instead; after rerouting (%) at time=%."),
729 : getID(), oldEdge, oldName, iter->getDescription(true), info, time2string(SIMSTEP));
730 : }
731 : }
732 37299 : if (iter->edge == edges.end()) {
733 190 : if (!removeStops) {
734 24 : WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
735 : }
736 190 : iter = myStops.erase(iter);
737 190 : continue;
738 : } else {
739 37109 : setSkips(*iter, stopIndex);
740 37109 : searchStart = iter->edge;
741 : }
742 : ++iter;
743 37109 : stopIndex++;
744 : }
745 : // add new stops
746 592708 : if (addRouteStops) {
747 524745 : for (StopParVector::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
748 : std::string error;
749 307 : addStop(*i, error, myParameter->depart + myStopUntilOffset);
750 307 : if (error != "") {
751 0 : WRITE_WARNING(error);
752 : }
753 : }
754 : }
755 : }
756 : return true;
757 : }
758 :
759 :
760 : bool
761 52 : MSBaseVehicle::replaceWithAlternative(std::list<MSStop>::iterator iter, const MSRouteIterator searchStart, const MSRouteIterator end) {
762 52 : std::pair<std::string, SumoXMLTag> nameTag = iter->getStoppingPlaceName();
763 52 : if (!nameTag.first.empty()) {
764 34 : const std::vector<MSStoppingPlace*>& alternatives = MSNet::getInstance()->getStoppingPlaceAlternatives(nameTag.first, nameTag.second);
765 96 : for (MSStoppingPlace* alt : alternatives) {
766 : //std::cout << SIMTIME << " veh=" << getID() << " name=" << nameTag.first << " alt=" << alt->getID() << "\n";
767 96 : if (&alt->getLane().getEdge() == &iter->lane->getEdge()
768 96 : || !alt->getLane().allowsVehicleClass(getVClass())) {
769 55 : continue;
770 : }
771 41 : iter->edge = std::find(searchStart, end, &alt->getLane().getEdge());
772 41 : if (iter->edge != end) {
773 34 : iter->replaceStoppingPlace(alt);
774 : return true;
775 : }
776 : }
777 : }
778 : return false;
779 : }
780 :
781 :
782 : double
783 164061 : MSBaseVehicle::getAcceleration() const {
784 164061 : return 0;
785 : }
786 :
787 :
788 : void
789 3745270 : MSBaseVehicle::onDepart() {
790 3745270 : myDeparture = MSNet::getInstance()->getCurrentTimeStep();
791 3745270 : myDepartPos = getPositionOnLane();
792 3745270 : MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
793 3745270 : }
794 :
795 :
796 : SUMOTime
797 3023961 : MSBaseVehicle:: getDepartDelay() const {
798 3023961 : const SUMOTime dep = getParameter().depart;
799 3023961 : if (dep < 0) {
800 : return 0;
801 : }
802 3023854 : return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
803 : }
804 :
805 :
806 : bool
807 0 : MSBaseVehicle::hasArrived() const {
808 0 : return succEdge(1) == nullptr;
809 : }
810 :
811 :
812 : int
813 31219657 : MSBaseVehicle::getRoutePosition() const {
814 31219657 : return (int) std::distance(myRoute->begin(), myCurrEdge);
815 : }
816 :
817 :
818 : int
819 338600 : MSBaseVehicle::getNumRemainingEdges() const {
820 338600 : if (myParameter->arrivalEdge >= 0) {
821 0 : return myParameter->arrivalEdge - getRoutePosition() + 1;
822 : } else {
823 338600 : return myRoute->size() - getRoutePosition();
824 : }
825 : }
826 :
827 :
828 : void
829 104058 : MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
830 104058 : myCurrEdge = myRoute->begin() + index;
831 104058 : const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
832 : // !!! hack
833 104058 : myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
834 104058 : }
835 :
836 : double
837 26505 : MSBaseVehicle::getOdometer() const {
838 26505 : return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
839 : }
840 :
841 : bool
842 4592843 : MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
843 4592843 : if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
844 : return false;
845 4488912 : } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
846 : return false;
847 : }
848 8860913 : if (isStopped() && myStops.begin()->pars.permitted.size() > 0
849 4430512 : && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
850 6094 : return false;
851 : }
852 4424418 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
853 : if (taxiDevice != nullptr) {
854 27070 : return taxiDevice->allowsBoarding(t);
855 : }
856 : return true;
857 : }
858 :
859 :
860 : void
861 4288608 : MSBaseVehicle::addTransportable(MSTransportable* transportable) {
862 4288608 : if (transportable->isPerson()) {
863 12826 : if (myPersonDevice == nullptr) {
864 4484 : myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
865 4484 : myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
866 4484 : if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
867 1947 : const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
868 : }
869 : }
870 12826 : myPersonDevice->addTransportable(transportable);
871 : } else {
872 4275782 : if (myContainerDevice == nullptr) {
873 4275348 : myContainerDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, true);
874 424 : myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myContainerDevice, 0.));
875 424 : if (myParameter->departProcedure == DepartDefinition::CONTAINER_TRIGGERED && myParameter->depart == -1) {
876 79 : const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
877 : }
878 : }
879 858 : myContainerDevice->addTransportable(transportable);
880 : }
881 13684 : if (myEnergyParams != nullptr) {
882 8850 : myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() + transportable->getVehicleType().getMass());
883 : }
884 13684 : }
885 :
886 :
887 : bool
888 2936 : MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
889 3421 : for (const MSStop& stop : myStops) {
890 1199 : if (stop.edge == it && stop.pars.jump >= 0) {
891 : return true;
892 1079 : } else if (stop.edge > it) {
893 : return false;
894 : }
895 : }
896 : return false;
897 : }
898 :
899 :
900 : bool
901 4482728 : MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
902 4482728 : MSRouteIterator start = myCurrEdge;
903 4482728 : if (route == nullptr) {
904 : route = myRoute;
905 : } else {
906 3785522 : start = route->begin();
907 : }
908 : const bool checkJumps = route == myRoute; // the edge iterators in the stops are invalid otherwise
909 4482728 : return hasValidRoute(msg, start, route->end(), checkJumps);
910 : }
911 :
912 :
913 : bool
914 5052649 : MSBaseVehicle::hasValidRoute(std::string& msg, MSRouteIterator start, MSRouteIterator last, bool checkJumps) const {
915 : MSRouteIterator lastValid = last - 1;
916 : // check connectivity, first
917 22785526 : for (MSRouteIterator e = start; e != lastValid; ++e) {
918 17782187 : const MSEdge& next = **(e + 1);
919 17782187 : if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
920 50067 : if (!checkJumps || !hasJump(e)) {
921 49947 : if ((myRoutingMode & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) == 0
922 49947 : || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
923 147930 : msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
924 49310 : return false;
925 : }
926 : }
927 : }
928 : }
929 : // check usable lanes, then
930 27738643 : for (MSRouteIterator e = start; e != last; ++e) {
931 22735304 : if ((*e)->prohibits(this)) {
932 0 : msg = TLF("Edge '%' prohibits.", (*e)->getID());
933 : return false;
934 : }
935 : }
936 : return true;
937 : }
938 :
939 :
940 : bool
941 503698419 : MSBaseVehicle::hasValidRouteStart(std::string& msg) {
942 503698419 : if (!(*myCurrEdge)->isTazConnector()) {
943 503561357 : if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
944 12 : msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
945 6 : myRouteValidity |= ROUTE_START_INVALID_LANE;
946 6 : return false;
947 : }
948 : }
949 503698413 : if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
950 503698355 : myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
951 503698355 : return true;
952 : } else {
953 174 : msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
954 58 : myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
955 58 : return false;
956 : }
957 : }
958 :
959 :
960 : int
961 5045290040 : MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
962 5045290040 : if (!update) {
963 2136205936 : return myRouteValidity;
964 : }
965 : // insertion check must be done in any case
966 : std::string msg;
967 2909084104 : if (!hasValidRouteStart(msg)) {
968 186 : if (MSGlobals::gCheckRoutes) {
969 114 : throw ProcessError(msg);
970 72 : } else if (!silent) {
971 : // vehicle will be discarded
972 138 : WRITE_WARNING(msg);
973 26 : } else if (msgReturn != nullptr) {
974 : *msgReturn = msg;
975 : }
976 : }
977 20903 : if ((MSGlobals::gCheckRoutes || myRoute->getFirstEdge()->isInternal())
978 2909063093 : && (myRouteValidity & ROUTE_UNCHECKED) != 0
979 : // we could check after the first rerouting
980 2914327283 : && (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
981 7472674 : if (!hasValidRoute(msg, myRoute)) {
982 78 : myRouteValidity |= ROUTE_INVALID;
983 234 : throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
984 : }
985 : }
986 2909083912 : myRouteValidity &= ~ROUTE_UNCHECKED;
987 : return myRouteValidity;
988 : }
989 :
990 :
991 : bool
992 112 : MSBaseVehicle::hasReminder(MSMoveReminder* rem) const {
993 415 : for (auto item : myMoveReminders) {
994 338 : if (item.first == rem) {
995 : return true;
996 : }
997 : }
998 77 : return false;
999 : }
1000 :
1001 :
1002 : void
1003 24925353 : MSBaseVehicle::addReminder(MSMoveReminder* rem, double pos) {
1004 : #ifdef _DEBUG
1005 : if (myTraceMoveReminders) {
1006 : traceMoveReminder("add", rem, pos, true);
1007 : }
1008 : #endif
1009 24925353 : myMoveReminders.push_back(std::make_pair(rem, pos));
1010 24925353 : }
1011 :
1012 :
1013 : void
1014 0 : MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
1015 0 : for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
1016 0 : if (r->first == rem) {
1017 : #ifdef _DEBUG
1018 : if (myTraceMoveReminders) {
1019 : traceMoveReminder("remove", rem, 0, false);
1020 : }
1021 : #endif
1022 : myMoveReminders.erase(r);
1023 : return;
1024 : }
1025 : }
1026 : }
1027 :
1028 :
1029 : void
1030 46042050 : MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
1031 : // notifyEnter may cause new reminders to be added so we cannot use an iterator
1032 129469124 : for (int i = 0; i < (int)myMoveReminders.size();) {
1033 83427077 : MSMoveReminder* rem = myMoveReminders[i].first;
1034 83427077 : const double remPos = myMoveReminders[i].second;
1035 : // skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
1036 83427077 : if (rem->getLane() != nullptr && remPos > 0.) {
1037 : #ifdef _DEBUG
1038 : if (myTraceMoveReminders) {
1039 : traceMoveReminder("notifyEnter_skipped", rem, remPos, true);
1040 : }
1041 : #endif
1042 16688765 : ++i;
1043 : } else {
1044 66738312 : if (rem->notifyEnter(*this, reason, enteredLane)) {
1045 : #ifdef _DEBUG
1046 : if (myTraceMoveReminders) {
1047 : traceMoveReminder("notifyEnter", rem, remPos, true);
1048 : }
1049 : #endif
1050 64949425 : ++i;
1051 : } else {
1052 : #ifdef _DEBUG
1053 : if (myTraceMoveReminders) {
1054 : traceMoveReminder("notifyEnter", rem, remPos, false);
1055 : }
1056 : #endif
1057 : myMoveReminders.erase(myMoveReminders.begin() + i);
1058 : }
1059 : }
1060 : }
1061 46042047 : }
1062 :
1063 :
1064 : bool
1065 2740252485 : MSBaseVehicle::isRail() const {
1066 2740252485 : return isRailway(getVClass()) || isRailway(getCurrentEdge()->getPermissions());
1067 : }
1068 :
1069 : void
1070 9603089 : MSBaseVehicle::calculateArrivalParams(bool onInit) {
1071 9603089 : if (myRoute->getLastEdge()->isTazConnector()) {
1072 : return;
1073 : }
1074 9019357 : const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
1075 9019357 : if (arrivalEdgeIndex != myParameter->arrivalEdge) {
1076 21 : if (!(onInit && myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
1077 42 : WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
1078 : getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
1079 : }
1080 : }
1081 9019357 : const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
1082 9019357 : if (!onInit) {
1083 592644 : arrivalEdge = myRoute->getLastEdge();
1084 : // ignore arrivalEdge parameter after rerouting
1085 592644 : const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
1086 : }
1087 : const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
1088 9019357 : const double lastLaneLength = lanes[0]->getLength();
1089 9019357 : switch (myParameter->arrivalPosProcedure) {
1090 218143 : case ArrivalPosDefinition::GIVEN:
1091 218143 : if (fabs(myParameter->arrivalPos) > lastLaneLength) {
1092 3351 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
1093 : }
1094 : // Maybe we should warn the user about invalid inputs!
1095 218143 : myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
1096 218143 : if (myArrivalPos < 0) {
1097 22499 : myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
1098 : }
1099 : break;
1100 : case ArrivalPosDefinition::RANDOM:
1101 87579 : myArrivalPos = RandHelper::rand(lastLaneLength);
1102 87579 : break;
1103 0 : case ArrivalPosDefinition::CENTER:
1104 0 : myArrivalPos = lastLaneLength / 2.;
1105 0 : break;
1106 8713635 : default:
1107 8713635 : myArrivalPos = lastLaneLength;
1108 8713635 : break;
1109 : }
1110 9019357 : if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
1111 135096 : if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
1112 320190 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
1113 : }
1114 135096 : myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
1115 8884261 : } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
1116 7 : myArrivalLane = -1;
1117 7 : for (MSLane* lane : lanes) {
1118 7 : if (lane->allowsVehicleClass(myType->getVehicleClass())) {
1119 7 : myArrivalLane = lane->getIndex();
1120 7 : break;
1121 : }
1122 : }
1123 7 : if (myArrivalLane == -1) {
1124 0 : WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
1125 0 : myArrivalLane = 0;
1126 : }
1127 8884254 : } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
1128 : // pick random lane among all usable lanes
1129 : std::vector<MSLane*> usable;
1130 372148 : for (MSLane* lane : lanes) {
1131 284745 : if (lane->allowsVehicleClass(myType->getVehicleClass())) {
1132 265026 : usable.push_back(lane);
1133 : }
1134 : }
1135 87403 : if (usable.empty()) {
1136 0 : WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
1137 0 : myArrivalLane = 0;
1138 : } else {
1139 87403 : myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
1140 : }
1141 87403 : }
1142 9019357 : if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
1143 235788 : for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
1144 182469 : if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
1145 : return;
1146 : }
1147 : }
1148 159957 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
1149 : }
1150 : }
1151 :
1152 : void
1153 6000568 : MSBaseVehicle::setDepartAndArrivalEdge() {
1154 6000568 : SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
1155 6000568 : if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
1156 7982 : const int routeEdges = (int)myRoute->getEdges().size();
1157 7982 : if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
1158 : // write specific edge in vehroute output for reproducibility
1159 4185 : pars->departEdge = RandHelper::rand(0, routeEdges);
1160 4185 : pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
1161 : }
1162 : assert(pars->departEdge >= 0);
1163 7982 : if (pars->departEdge >= routeEdges) {
1164 0 : WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
1165 : } else {
1166 : myCurrEdge += pars->departEdge;
1167 : }
1168 : }
1169 6000568 : if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
1170 147 : const int routeEdges = (int)myRoute->getEdges().size();
1171 147 : const int begin = (int)(myCurrEdge - myRoute->begin());
1172 : // write specific edge in vehroute output for reproducibility
1173 147 : pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
1174 147 : pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
1175 : assert(pars->arrivalEdge >= begin);
1176 : assert(pars->arrivalEdge < routeEdges);
1177 : }
1178 6000568 : }
1179 :
1180 : int
1181 3746 : MSBaseVehicle::getDepartEdge() const {
1182 3746 : return myParameter->departEdge <= myRoute->size() ? myParameter->departEdge : 0;
1183 : }
1184 :
1185 : int
1186 28191259 : MSBaseVehicle::getInsertionChecks() const {
1187 28191259 : if (getParameter().wasSet(VEHPARS_INSERTION_CHECKS_SET)) {
1188 251076 : return getParameter().insertionChecks;
1189 : } else {
1190 27940183 : return MSGlobals::gInsertionChecks;
1191 : }
1192 : }
1193 :
1194 : double
1195 610364120 : MSBaseVehicle::getImpatience() const {
1196 1220728240 : return MAX2(0., MIN2(1., getVehicleType().getImpatience()
1197 610364120 : + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
1198 610364120 : + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
1199 : }
1200 :
1201 :
1202 : MSDevice*
1203 939555373 : MSBaseVehicle::getDevice(const std::type_info& type) const {
1204 1635003767 : for (MSVehicleDevice* const dev : myDevices) {
1205 760395524 : if (typeid(*dev) == type) {
1206 64947130 : return dev;
1207 : }
1208 : }
1209 : return nullptr;
1210 : }
1211 :
1212 :
1213 : void
1214 4261 : MSBaseVehicle::saveState(OutputDevice& out) {
1215 : // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
1216 4261 : const std::string& typeID = myParameter->vtypeid != getVehicleType().getID() ? getVehicleType().getID() : "";
1217 4261 : myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
1218 : // params and stops must be written in child classes since they may wish to add additional attributes first
1219 4261 : out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
1220 4261 : std::ostringstream os;
1221 8522 : os << myOdometer << " " << myNumberReroutes;
1222 4261 : out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
1223 4261 : if (myParameter->arrivalPosProcedure == ArrivalPosDefinition::RANDOM) {
1224 13 : out.writeAttr(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, myArrivalPos);
1225 : }
1226 4261 : if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
1227 : const int precision = out.getPrecision();
1228 4261 : out.setPrecision(MAX2(gPrecisionRandom, precision));
1229 4261 : out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
1230 4261 : out.setPrecision(precision);
1231 : }
1232 4261 : if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
1233 2876 : out.writeAttr(SUMO_ATTR_REROUTE, true);
1234 : }
1235 4261 : if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
1236 : // could be set from stop
1237 2 : out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
1238 : }
1239 : // here starts the vehicle internal part (see loading)
1240 : // @note: remember to close the vehicle tag when calling this in a subclass!
1241 8522 : }
1242 :
1243 :
1244 : bool
1245 0 : MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
1246 : UNUSED_PARAMETER(stop);
1247 : UNUSED_PARAMETER(distToStop);
1248 0 : return true;
1249 : }
1250 :
1251 :
1252 : bool
1253 9241507956 : MSBaseVehicle::isStopped() const {
1254 9241507956 : return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
1255 : }
1256 :
1257 :
1258 : bool
1259 2577670109 : MSBaseVehicle::isParking() const {
1260 2634029461 : return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
1261 4908816 : && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
1262 2582432931 : && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
1263 : }
1264 :
1265 :
1266 : bool
1267 657800324 : MSBaseVehicle::isJumping() const {
1268 657800324 : return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
1269 : }
1270 :
1271 :
1272 : bool
1273 7074432 : MSBaseVehicle::isStoppedTriggered() const {
1274 7074432 : return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
1275 : }
1276 :
1277 :
1278 : bool
1279 27867 : MSBaseVehicle::isStoppedParking() const {
1280 27867 : return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
1281 : }
1282 :
1283 :
1284 : bool
1285 4293062 : MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
1286 4293062 : if (isStopped() || (checkFuture && hasStops())) {
1287 : const MSStop& stop = myStops.front();
1288 4294249 : return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
1289 : }
1290 : return false;
1291 : }
1292 :
1293 : bool
1294 18280 : MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
1295 : // Check if there is a parking area to be replaced
1296 18280 : if (parkingArea == 0) {
1297 : errorMsg = "new parkingArea is NULL";
1298 0 : return false;
1299 : }
1300 18280 : if (myStops.size() == 0) {
1301 : errorMsg = "vehicle has no stops";
1302 0 : return false;
1303 : }
1304 18280 : if (myStops.front().parkingarea == 0) {
1305 : errorMsg = "first stop is not at parkingArea";
1306 0 : return false;
1307 : }
1308 : MSStop& first = myStops.front();
1309 : SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
1310 18280 : std::string oldStopEdgeID = first.lane->getEdge().getID();
1311 : // merge subsequent duplicate stops equals to parking area
1312 18299 : for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
1313 292 : if (iter->parkingarea == parkingArea) {
1314 19 : stopPar.duration += iter->duration;
1315 19 : myStops.erase(iter++);
1316 : } else {
1317 : break;
1318 : }
1319 : }
1320 18280 : stopPar.lane = parkingArea->getLane().getID();
1321 18280 : stopPar.parkingarea = parkingArea->getID();
1322 18280 : stopPar.startPos = parkingArea->getBeginLanePosition();
1323 18280 : stopPar.endPos = parkingArea->getEndLanePosition();
1324 18280 : first.edge = myRoute->end(); // will be patched in replaceRoute
1325 18280 : first.lane = &parkingArea->getLane();
1326 18280 : first.parkingarea = parkingArea;
1327 :
1328 : // patch via edges
1329 18280 : std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
1330 18280 : if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
1331 210 : myParameter->via.erase(myParameter->via.begin());
1332 210 : myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
1333 : }
1334 : return true;
1335 : }
1336 :
1337 :
1338 : MSParkingArea*
1339 91656 : MSBaseVehicle::getNextParkingArea() {
1340 : MSParkingArea* nextParkingArea = nullptr;
1341 91656 : if (!myStops.empty()) {
1342 90373 : SUMOVehicleParameter::Stop stopPar;
1343 90373 : MSStop stop = myStops.front();
1344 90373 : if (!stop.reached && stop.parkingarea != nullptr) {
1345 : nextParkingArea = stop.parkingarea;
1346 : }
1347 90373 : }
1348 91656 : return nextParkingArea;
1349 : }
1350 :
1351 :
1352 : MSParkingArea*
1353 117488 : MSBaseVehicle::getCurrentParkingArea() {
1354 : MSParkingArea* currentParkingArea = nullptr;
1355 117488 : if (isParking()) {
1356 117419 : currentParkingArea = myStops.begin()->parkingarea;
1357 : }
1358 117488 : return currentParkingArea;
1359 : }
1360 :
1361 :
1362 : const std::vector<std::string>&
1363 1656 : MSBaseVehicle::getParkingBadges() const {
1364 1656 : if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
1365 7 : return myParameter->parkingBadges;
1366 : } else {
1367 1649 : return getVehicleType().getParkingBadges();
1368 : }
1369 : }
1370 :
1371 :
1372 : double
1373 9895019 : MSBaseVehicle::basePos(const MSEdge* edge) const {
1374 9895019 : double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
1375 9895019 : if (hasStops()
1376 9918774 : && myStops.front().edge == myRoute->begin()
1377 9918774 : && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
1378 23711 : result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
1379 : }
1380 9895019 : return result;
1381 : }
1382 :
1383 :
1384 : MSLane*
1385 298 : MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
1386 298 : const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
1387 298 : const MSEdge* edge = MSEdge::dictionary(edgeID);
1388 298 : if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
1389 8 : return nullptr;
1390 : }
1391 580 : const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
1392 290 : if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
1393 290 : const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
1394 290 : stop.edge = edgeID;
1395 290 : return edge->getOppositeEdge()->getLanes()[oppositeIndex];
1396 : }
1397 : return nullptr;
1398 : }
1399 :
1400 :
1401 : bool
1402 137770 : MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
1403 : MSRouteIterator* searchStart) {
1404 137770 : MSStop stop(stopPar);
1405 137770 : if (stopPar.lane == "") {
1406 2900 : MSEdge* e = MSEdge::dictionary(stopPar.edge);
1407 2900 : stop.lane = e->getFirstAllowed(getVClass(), getRoutingMode());
1408 2900 : if (stop.lane == nullptr) {
1409 0 : errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
1410 0 : return false;
1411 : }
1412 : } else {
1413 134870 : stop.lane = MSLane::dictionary(stopPar.lane);
1414 134870 : if (stop.lane == nullptr) {
1415 : // must be an opposite stop
1416 145 : SUMOVehicleParameter::Stop tmp = stopPar;
1417 145 : stop.lane = interpretOppositeStop(tmp);
1418 : assert(stop.lane != nullptr);
1419 145 : }
1420 134870 : if (!stop.lane->allowsVehicleClass(myType->getVehicleClass(), getRoutingMode())) {
1421 24 : errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
1422 12 : return false;
1423 : }
1424 : }
1425 137758 : if (MSGlobals::gUseMesoSim) {
1426 28452 : stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
1427 28452 : if (stop.lane->isInternal()) {
1428 2 : errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
1429 1 : return false;
1430 : }
1431 : }
1432 137757 : stop.initPars(stopPar);
1433 137757 : if (stopPar.until != -1) {
1434 : // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
1435 52953 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
1436 : }
1437 137757 : if (stopPar.arrival != -1) {
1438 620 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
1439 : }
1440 137757 : std::string stopType = "stop";
1441 137757 : std::string stopID = "";
1442 137757 : double parkingLength = stop.pars.endPos - stop.pars.startPos;
1443 137757 : if (stop.busstop != nullptr) {
1444 : stopType = "busStop";
1445 37396 : stopID = stop.busstop->getID();
1446 37396 : parkingLength = stop.busstop->getParkingLength();
1447 100361 : } else if (stop.containerstop != nullptr) {
1448 : stopType = "containerStop";
1449 1046 : stopID = stop.containerstop->getID();
1450 1046 : parkingLength = stop.containerstop->getParkingLength();
1451 99315 : } else if (stop.chargingStation != nullptr) {
1452 : stopType = "chargingStation";
1453 8182 : stopID = stop.chargingStation->getID();
1454 8182 : parkingLength = stop.chargingStation->getParkingLength();
1455 91133 : } else if (stop.overheadWireSegment != nullptr) {
1456 : stopType = "overheadWireSegment";
1457 0 : stopID = stop.overheadWireSegment->getID();
1458 0 : parkingLength = stop.overheadWireSegment->getParkingLength();
1459 91133 : } else if (stop.parkingarea != nullptr) {
1460 : stopType = "parkingArea";
1461 28931 : stopID = stop.parkingarea->getID();
1462 : }
1463 275514 : const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
1464 :
1465 137757 : if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
1466 0 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
1467 0 : return false;
1468 : }
1469 75555 : if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > parkingLength
1470 : // do not warn for stops that fill the whole lane
1471 307 : && parkingLength < stop.lane->getLength()
1472 : // do not warn twice for the same stop
1473 214149 : && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
1474 837 : errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
1475 : }
1476 137757 : if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
1477 : // forbid access in case the parking requests other badges
1478 14 : errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
1479 7 : return false;
1480 : }
1481 137750 : const MSEdge* stopLaneEdge = &stop.lane->getEdge();
1482 : const MSEdge* stopEdge;
1483 137750 : if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
1484 : // stop lane is on the opposite side
1485 145 : stopEdge = stopLaneEdge->getOppositeEdge();
1486 145 : stop.isOpposite = true;
1487 : } else {
1488 : // if stop is on an internal edge the normal edge before the intersection is used
1489 137605 : stopEdge = stopLaneEdge->getNormalBefore();
1490 : }
1491 137750 : MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
1492 137750 : if (searchStart == nullptr) {
1493 130920 : searchStart = &myCurrEdge;
1494 130920 : if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
1495 : // already on the intersection but myCurrEdge is before it
1496 : searchStart = ≻
1497 : }
1498 : }
1499 : #ifdef DEBUG_ADD_STOP
1500 : if (DEBUG_COND) {
1501 : std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
1502 : << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
1503 : << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
1504 : << "\n";
1505 : }
1506 : #endif
1507 137750 : stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
1508 137750 : MSRouteIterator prevStopEdge = myCurrEdge;
1509 137750 : const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
1510 137750 : double prevStopPos = getPositionOnLane();
1511 : // where to insert the stop
1512 : std::list<MSStop>::iterator iter = myStops.begin();
1513 137750 : if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
1514 : iter = myStops.end();
1515 114990 : if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
1516 : prevStopEdge = myStops.back().edge;
1517 48901 : prevEdge = &myStops.back().lane->getEdge();
1518 48901 : prevStopPos = myStops.back().pars.endPos;
1519 48901 : stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1520 : if (prevStopEdge == stop.edge // laneEdge check is insufficient for looped routes
1521 8019 : && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
1522 56908 : && (prevStopPos > stop.pars.endPos ||
1523 2233 : (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
1524 434 : stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
1525 : }
1526 : #ifdef DEBUG_ADD_STOP
1527 : if (DEBUG_COND) {
1528 : std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
1529 : << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
1530 : }
1531 : #endif
1532 : }
1533 : // skip a number of occurences of stopEdge in looped route
1534 114990 : int skipLooped = stopPar.index - static_cast<int>(myStops.size());
1535 115091 : for (int j = 0; j < skipLooped; j++) {
1536 247 : auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
1537 247 : if (nextIt == myRoute->end()) {
1538 146 : if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
1539 : // only warn if the route loops over the stop edge at least once
1540 28 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
1541 : }
1542 146 : break;
1543 : } else {
1544 101 : stop.edge = nextIt;
1545 : }
1546 : }
1547 : } else {
1548 22760 : if (stopPar.index == STOP_INDEX_FIT) {
1549 34452 : while (iter != myStops.end() && (iter->edge < stop.edge ||
1550 1408 : (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
1551 1408 : (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
1552 : prevStopEdge = iter->edge;
1553 11791 : prevStopPos = iter->pars.endPos;
1554 : ++iter;
1555 : }
1556 : } else {
1557 : int index = stopPar.index;
1558 99 : while (index > 0) {
1559 0 : prevStopEdge = iter->edge;
1560 0 : prevStopPos = iter->pars.endPos;
1561 : ++iter;
1562 0 : --index;
1563 : }
1564 : #ifdef DEBUG_ADD_STOP
1565 : if (DEBUG_COND) {
1566 : std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
1567 : }
1568 : #endif
1569 99 : stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1570 : }
1571 : }
1572 138064 : const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
1573 137750 : if (stop.edge == myRoute->end()) {
1574 78 : if (!wasTooClose) {
1575 210 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
1576 : }
1577 78 : return false;
1578 : }
1579 :
1580 137672 : const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
1581 35273 : prevStopPos + (iter == myStops.begin() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
1582 :
1583 137672 : if (prevStopEdge > stop.edge ||
1584 : // a collision-stop happens after vehicle movement and may move the
1585 : // vehicle backwards on its lane (prevStopPos is the vehicle position)
1586 1960 : (tooClose && !stop.pars.collision)
1587 275316 : || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
1588 : // check if the edge occurs again later in the route
1589 : //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges()) << "\n";
1590 28 : if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
1591 84 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
1592 : }
1593 28 : MSRouteIterator next = stop.edge + 1;
1594 28 : return addStop(stopPar, errorMsg, untilOffset, &next);
1595 : }
1596 137644 : if (wasTooClose) {
1597 : errorMsg = "";
1598 : }
1599 : // David.C:
1600 : //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
1601 137644 : const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
1602 137644 : const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
1603 137644 : if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
1604 : return false;
1605 : }
1606 137644 : if (!hasDeparted() && myCurrEdge == stop.edge) {
1607 : double pos = -1;
1608 26087 : if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
1609 4658 : pos = myParameter->departPos;
1610 4658 : if (pos < 0.) {
1611 219 : pos += (*myCurrEdge)->getLength();
1612 : }
1613 : }
1614 26087 : if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
1615 18199 : pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
1616 : }
1617 26087 : if (pos > stop.pars.endPos + endPosOffset) {
1618 20 : if (stop.edge != myRoute->end()) {
1619 : // check if the edge occurs again later in the route
1620 20 : MSRouteIterator next = stop.edge + 1;
1621 20 : return addStop(stopPar, errorMsg, untilOffset, &next);
1622 : }
1623 0 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
1624 0 : return false;
1625 : }
1626 : }
1627 137624 : if (iter != myStops.begin()) {
1628 : std::list<MSStop>::iterator iter2 = iter;
1629 : iter2--;
1630 95869 : if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
1631 60673 : && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
1632 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1633 18 : + "' set to end at " + time2string(stop.getUntil())
1634 24 : + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
1635 : }
1636 60656 : if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1637 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1638 18 : + "' set to start at " + time2string(stop.pars.arrival)
1639 24 : + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
1640 : }
1641 60656 : if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1642 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1643 18 : + "' set to start at " + time2string(stop.pars.arrival)
1644 24 : + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
1645 : }
1646 : } else {
1647 94704 : if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
1648 76980 : && (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
1649 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1650 18 : + "' set to end at " + time2string(stop.getUntil())
1651 24 : + " earlier than departure at " + time2string(getParameter().depart) + ".";
1652 : }
1653 : }
1654 137624 : if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
1655 18 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1656 54 : + "' set to end at " + time2string(stop.getUntil())
1657 72 : + " earlier than arrival at " + time2string(stop.getArrival()) + ".";
1658 : }
1659 137624 : setSkips(stop, (int)myStops.size());
1660 137624 : myStops.insert(iter, stop);
1661 137624 : if (stopPar.tripId != "") {
1662 2664 : MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
1663 : }
1664 : //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
1665 : // << " routeIndex=" << (stop.edge - myRoute->begin())
1666 : // << " stopIndex=" << std::distance(myStops.begin(), iter)
1667 : // << " route=" << toString(myRoute->getEdges()) << "\n";
1668 : return true;
1669 : }
1670 :
1671 :
1672 : void
1673 174733 : MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
1674 174733 : if (hasDeparted() && stop.edge > myRoute->begin()) {
1675 : // if the route is looped we must patch the index to ensure that state
1676 : // loading (and vehroute-output) encode the correct number of skips
1677 : int foundSkips = 0;
1678 : MSRouteIterator itPrev;
1679 : double prevEndPos;
1680 70564 : if (prevActiveStops > 0) {
1681 : assert((int)myStops.size() >= prevActiveStops);
1682 : auto prevStopIt = myStops.begin();
1683 34387 : std::advance(prevStopIt, prevActiveStops - 1);
1684 : const MSStop& prev = *prevStopIt;
1685 34387 : itPrev = prev.edge;
1686 34387 : prevEndPos = prev.pars.endPos;
1687 36177 : } else if (myPastStops.size() > 0) {
1688 11014 : itPrev = myRoute->begin() + myPastStops.back().routeIndex;
1689 11014 : prevEndPos = myPastStops.back().endPos;
1690 : } else {
1691 25163 : itPrev = myRoute->begin() + myParameter->departEdge;
1692 25163 : prevEndPos = myDepartPos;
1693 : }
1694 : //auto itPrevOrig = itPrev;
1695 70564 : if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
1696 : itPrev++;
1697 : }
1698 : //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
1699 687231 : while (itPrev < stop.edge) {
1700 616667 : if (*itPrev == *stop.edge) {
1701 37328 : foundSkips++;
1702 : }
1703 : itPrev++;
1704 : }
1705 : int newIndex = STOP_INDEX_END;
1706 70564 : if (foundSkips > 0) {
1707 : //if (getID() == "77_0_0") {
1708 : // std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
1709 : // << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
1710 : // << " prevEdge=" << (*itPrevOrig)->getID()
1711 : // << " prevIndex=" << (itPrevOrig - myRoute->begin())
1712 : // << " skips=" << foundSkips << "\n";
1713 : //}
1714 12599 : newIndex = (int)myPastStops.size() + prevActiveStops + foundSkips;
1715 : }
1716 70564 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
1717 : }
1718 174733 : }
1719 :
1720 :
1721 : SUMOTime
1722 744 : MSBaseVehicle::activateRemindersOnReroute(SUMOTime /*currentTime*/) {
1723 3377 : for (int i = 0; i < (int)myMoveReminders.size();) {
1724 2633 : auto rem = &myMoveReminders[i];
1725 2633 : if (rem->first->notifyReroute(*this)) {
1726 : #ifdef _DEBUG
1727 : if (myTraceMoveReminders) {
1728 : traceMoveReminder("notifyReroute", rem->first, rem->second, true);
1729 : }
1730 : #endif
1731 2579 : ++i;
1732 : } else {
1733 : #ifdef _DEBUG
1734 : if (myTraceMoveReminders) {
1735 : traceMoveReminder("notifyReroute", rem->first, rem->second, false);
1736 : }
1737 : #endif
1738 : myMoveReminders.erase(myMoveReminders.begin() + i);
1739 : }
1740 : }
1741 744 : resetApproachOnReroute();
1742 : // event only called once
1743 744 : return 0;
1744 : }
1745 :
1746 :
1747 : void
1748 6836877 : MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
1749 6836877 : if (addRouteStops) {
1750 6841160 : for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
1751 : std::string errorMsg;
1752 9831 : if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
1753 6 : throw ProcessError(errorMsg);
1754 : }
1755 9825 : if (errorMsg != "") {
1756 687 : WRITE_WARNING(errorMsg);
1757 : }
1758 : }
1759 : }
1760 6836871 : const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
1761 6934659 : for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
1762 : std::string errorMsg;
1763 97817 : if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
1764 29 : throw ProcessError(errorMsg);
1765 : }
1766 97788 : if (errorMsg != "") {
1767 464 : WRITE_WARNING(errorMsg);
1768 : }
1769 : }
1770 6836842 : }
1771 :
1772 :
1773 : bool
1774 746054 : MSBaseVehicle::haveValidStopEdges(bool silent) const {
1775 746054 : MSRouteIterator start = myCurrEdge;
1776 : int i = 0;
1777 : bool ok = true;
1778 769996 : for (const MSStop& stop : myStops) {
1779 : MSRouteIterator it;
1780 23942 : if (stop.lane->isInternal()) {
1781 : // find the normal predecessor and ensure that the next route edge
1782 : // matches the successor of the internal edge successor
1783 0 : it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
1784 0 : if (it != myRoute->end() && (
1785 0 : it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
1786 0 : it = myRoute->end(); // signal failure
1787 : }
1788 : } else {
1789 23942 : it = std::find(start, myRoute->end(), &stop.lane->getEdge());
1790 : }
1791 23942 : if (it == myRoute->end()) {
1792 0 : if (!silent) {
1793 0 : WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
1794 : i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1795 : }
1796 : ok = false;
1797 : } else {
1798 : MSRouteIterator it2;
1799 1112078 : for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
1800 1105141 : if (it2 == stop.edge) {
1801 : break;
1802 : }
1803 : }
1804 23942 : if (it2 == myRoute->end()) {
1805 6937 : if (!silent) {
1806 0 : WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
1807 : i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
1808 : }
1809 : ok = false;
1810 17005 : } else if (it2 < start) {
1811 0 : if (!silent) {
1812 0 : WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
1813 : i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1814 : }
1815 : ok = false;
1816 : } else {
1817 17005 : start = stop.edge;
1818 : }
1819 : }
1820 23942 : i++;
1821 : }
1822 746054 : return ok;
1823 : }
1824 :
1825 :
1826 : std::vector<MSBaseVehicle::StopEdgeInfo>
1827 2785270 : MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
1828 : assert(haveValidStopEdges());
1829 : std::vector<StopEdgeInfo> result;
1830 : const MSStop* prev = nullptr;
1831 : const MSEdge* internalSuccessor = nullptr;
1832 2880333 : for (const MSStop& stop : myStops) {
1833 95063 : if (stop.reached) {
1834 9417 : if (stop.pars.jump >= 0) {
1835 0 : jumps.insert((int)result.size());
1836 : }
1837 9417 : continue;
1838 : }
1839 85646 : double stopPos = stop.getEndPos(*this);
1840 : if ((prev == nullptr
1841 45969 : || prev->edge != stop.edge
1842 1260 : || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
1843 130355 : && *stop.edge != internalSuccessor) {
1844 84386 : if (stop.lane->isInternal()) {
1845 9 : stopPos = (*stop.edge)->getLength();
1846 : }
1847 84386 : result.push_back(StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stopPos));
1848 84386 : result.back().nameTag = stop.getStoppingPlaceName();
1849 84386 : result.back().stopPar = &stop.pars;
1850 84386 : if (stop.lane->isInternal()) {
1851 9 : internalSuccessor = stop.lane->getNextNormal();
1852 18 : result.push_back(StopEdgeInfo(internalSuccessor, stop.pars.priority, stop.getArrivalFallback(), 0));
1853 : } else {
1854 : internalSuccessor = nullptr;
1855 : }
1856 1260 : } else if (prev != nullptr && prev->edge == stop.edge) {
1857 1260 : result.back().priority = addStopPriority(result.back().priority, stop.pars.priority);
1858 : }
1859 : prev = &stop;
1860 85646 : if (firstPos == INVALID_DOUBLE) {
1861 39677 : if (stop.parkingarea != nullptr) {
1862 5062 : firstPos = MAX2(0., stopPos);
1863 : } else {
1864 34615 : firstPos = stopPos;
1865 : }
1866 : }
1867 85646 : lastPos = stopPos;
1868 85646 : if (stop.pars.jump >= 0) {
1869 1208 : jumps.insert((int)result.size() - 1);
1870 : }
1871 : }
1872 : //std::cout << SIMTIME << " getStopEdges veh=" << getID() << "\n";
1873 : //for (auto item : result) {
1874 : // std::cout << " e=" << item.edge->getID() << " pos=" << item.pos << "\n";
1875 : //}
1876 2785270 : return result;
1877 0 : }
1878 :
1879 :
1880 : double
1881 2061 : MSBaseVehicle::addStopPriority(double p1, double p2) {
1882 2061 : if (p1 < 0 || p2 < 0) {
1883 : return p1;
1884 : }
1885 0 : return p1 + p2;
1886 : }
1887 :
1888 : std::vector<std::pair<int, double> >
1889 30536 : MSBaseVehicle::getStopIndices() const {
1890 : std::vector<std::pair<int, double> > result;
1891 62275 : for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
1892 63478 : result.push_back(std::make_pair(
1893 31739 : (int)(iter->edge - myRoute->begin()),
1894 31739 : iter->getEndPos(*this)));
1895 : }
1896 30536 : return result;
1897 0 : }
1898 :
1899 :
1900 : const MSStop&
1901 17368607 : MSBaseVehicle::getNextStop() const {
1902 : assert(myStops.size() > 0);
1903 17368607 : return myStops.front();
1904 : }
1905 :
1906 : MSStop&
1907 87089 : MSBaseVehicle::getNextStopMutable() {
1908 : assert(myStops.size() > 0);
1909 87089 : return myStops.front();
1910 : }
1911 :
1912 : SUMOTime
1913 3934341 : MSBaseVehicle::getStopDuration() const {
1914 3934341 : if (isStopped()) {
1915 1516668 : return myStops.front().duration;
1916 : } else {
1917 : return 0;
1918 : }
1919 : }
1920 :
1921 :
1922 : MSStop&
1923 15217 : MSBaseVehicle::getStop(int nextStopIndex) {
1924 15217 : if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
1925 0 : throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
1926 : }
1927 : auto stopIt = myStops.begin();
1928 : std::advance(stopIt, nextStopIndex);
1929 15217 : return *stopIt;
1930 : }
1931 :
1932 :
1933 : const SUMOVehicleParameter::Stop*
1934 251028 : MSBaseVehicle::getNextStopParameter() const {
1935 251028 : if (hasStops()) {
1936 115095 : return &myStops.front().pars;
1937 : }
1938 : return nullptr;
1939 : }
1940 :
1941 :
1942 : bool
1943 45208 : MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
1944 : //if the stop exists update the duration
1945 70220 : for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
1946 47316 : if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
1947 : // update existing stop
1948 22304 : if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
1949 20810 : myStops.erase(iter);
1950 : } else {
1951 1494 : iter->duration = stop.duration;
1952 1494 : iter->triggered = stop.triggered;
1953 1494 : iter->containerTriggered = stop.containerTriggered;
1954 1494 : const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
1955 1494 : const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
1956 : }
1957 : return true;
1958 : }
1959 : }
1960 22904 : const bool result = addStop(stop, errorMsg);
1961 22904 : if (result) {
1962 : /// XXX handle stops added out of order
1963 22891 : myParameter->stops.push_back(stop);
1964 : }
1965 : return result;
1966 : }
1967 :
1968 :
1969 : void
1970 625 : MSBaseVehicle::unregisterWaiting() {
1971 625 : if (myAmRegisteredAsWaiting) {
1972 432 : MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
1973 432 : myAmRegisteredAsWaiting = false;
1974 : }
1975 625 : }
1976 :
1977 :
1978 : bool
1979 932 : MSBaseVehicle::abortNextStop(int nextStopIndex) {
1980 932 : if (hasStops() && nextStopIndex < (int)myStops.size()) {
1981 932 : if (nextStopIndex == 0 && isStopped()) {
1982 34 : resumeFromStopping();
1983 : } else {
1984 : auto stopIt = myStops.begin();
1985 : std::advance(stopIt, nextStopIndex);
1986 898 : myStops.erase(stopIt);
1987 : }
1988 932 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1989 : // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
1990 : auto stopIt2 = myParameter->stops.begin();
1991 : std::advance(stopIt2, nextStopIndex);
1992 7 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
1993 : }
1994 932 : return true;
1995 : } else {
1996 : return false;
1997 : }
1998 : }
1999 :
2000 :
2001 : bool
2002 148 : MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
2003 148 : const int n = (int)myStops.size();
2004 148 : if (nextStopIndex < 0 || nextStopIndex >= n) {
2005 5 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
2006 5 : return false;
2007 : }
2008 143 : if (nextStopIndex == 0 && isStopped()) {
2009 7 : errorMsg = TL("cannot replace reached stop");
2010 7 : return false;
2011 : }
2012 136 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
2013 136 : MSLane* stopLane = MSLane::dictionary(stop.lane);
2014 136 : MSEdge* stopEdge = &stopLane->getEdge();
2015 :
2016 : auto itStop = myStops.begin();
2017 : std::advance(itStop, nextStopIndex);
2018 : MSStop& replacedStop = *itStop;
2019 :
2020 : // check parking access rights
2021 136 : if (stop.parkingarea != "") {
2022 0 : MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
2023 0 : if (pa != nullptr && !pa->accepts(this)) {
2024 0 : errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
2025 0 : return false;
2026 : }
2027 : }
2028 :
2029 136 : if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
2030 : // only replace stop attributes
2031 9 : const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
2032 9 : replacedStop.initPars(stop);
2033 9 : return true;
2034 : }
2035 :
2036 127 : if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
2037 0 : errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
2038 0 : return false;
2039 : }
2040 :
2041 127 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
2042 127 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
2043 127 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
2044 127 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
2045 127 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
2046 127 : MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
2047 127 : auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
2048 127 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2049 :
2050 127 : bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
2051 :
2052 : ConstMSEdgeVector toNewStop;
2053 127 : if (!teleport) {
2054 98 : router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
2055 98 : if (toNewStop.size() == 0) {
2056 15 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
2057 5 : return false;
2058 : }
2059 : }
2060 :
2061 : ConstMSEdgeVector fromNewStop;
2062 122 : if (!newDestination) {
2063 117 : router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
2064 117 : if (fromNewStop.size() == 0) {
2065 0 : errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
2066 0 : return false;
2067 : }
2068 : }
2069 :
2070 122 : const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
2071 122 : replacedStop.initPars(stop);
2072 122 : replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
2073 122 : replacedStop.lane = stopLane;
2074 122 : if (MSGlobals::gUseMesoSim) {
2075 22 : replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
2076 22 : if (replacedStop.lane->isInternal()) {
2077 0 : errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
2078 0 : return false;
2079 : }
2080 : }
2081 :
2082 122 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2083 : ConstMSEdgeVector newEdges; // only remaining
2084 122 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2085 122 : if (!teleport) {
2086 93 : newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
2087 : } else {
2088 29 : newEdges.push_back(*itStart);
2089 : }
2090 122 : if (!newDestination) {
2091 117 : newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
2092 117 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2093 : } else {
2094 5 : newEdges.push_back(stopEdge);
2095 : }
2096 : //std::cout << SIMTIME << " replaceStop veh=" << getID()
2097 : // << " teleport=" << teleport
2098 : // << " busStop=" << stop.busstop
2099 : // << " oldEdges=" << oldRemainingEdges.size()
2100 : // << " newEdges=" << newEdges.size()
2101 : // << " toNewStop=" << toNewStop.size()
2102 : // << " fromNewStop=" << fromNewStop.size()
2103 : // << "\n";
2104 :
2105 122 : const double routeCost = router.recomputeCosts(newEdges, this, t);
2106 122 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2107 122 : const double savings = previousCost - routeCost;
2108 122 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
2109 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
2110 5 : const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
2111 : }
2112 122 : if (teleport) {
2113 : // let the vehicle jump rather than teleport
2114 : // we add a jump-stop at the end of the edge (unless the vehicle is
2115 : // already configure to jump before the replaced stop)
2116 29 : if (!insertJump(nextStopIndex, itStart, errorMsg)) {
2117 : return false;
2118 : };
2119 : }
2120 122 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2121 127 : }
2122 :
2123 :
2124 : bool
2125 52 : MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
2126 52 : const int n = (int)myStops.size();
2127 52 : if (nextStopIndex < 0 || nextStopIndex > n) {
2128 0 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
2129 0 : return false;
2130 : }
2131 52 : if (nextStopIndex == 0 && isStopped()) {
2132 0 : errorMsg = TL("cannot reroute towards reached stop");
2133 0 : return false;
2134 : }
2135 52 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
2136 :
2137 52 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
2138 52 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
2139 52 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
2140 52 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
2141 52 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
2142 52 : MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
2143 52 : auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
2144 52 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2145 :
2146 : ConstMSEdgeVector newBetween;
2147 52 : if (!teleport) {
2148 15 : router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
2149 15 : if (newBetween.size() == 0) {
2150 0 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
2151 0 : return false;
2152 : }
2153 : }
2154 :
2155 52 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2156 : ConstMSEdgeVector newEdges; // only remaining
2157 52 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2158 52 : if (!teleport) {
2159 15 : newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
2160 : } else {
2161 37 : newEdges.push_back(*itStart);
2162 : }
2163 52 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2164 : //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
2165 : // << " oldEdges=" << oldRemainingEdges.size()
2166 : // << " newEdges=" << newEdges.size()
2167 : // << " toNewStop=" << toNewStop.size()
2168 : // << " fromNewStop=" << fromNewStop.size()
2169 : // << "\n";
2170 :
2171 52 : const double routeCost = router.recomputeCosts(newEdges, this, t);
2172 52 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2173 52 : const double savings = previousCost - routeCost;
2174 :
2175 52 : if (teleport) {
2176 : // let the vehicle jump rather than teleport
2177 : // we add a jump-stop at the end of the edge (unless the vehicle is
2178 : // already configure to jump before the replaced stop)
2179 37 : if (!insertJump(nextStopIndex, itStart, errorMsg)) {
2180 : return false;
2181 : };
2182 : }
2183 52 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2184 52 : }
2185 :
2186 :
2187 : bool
2188 66 : MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
2189 : bool needJump = true;
2190 66 : if (nextStopIndex > 0) {
2191 : auto itPriorStop = myStops.begin();
2192 48 : std::advance(itPriorStop, nextStopIndex - 1);
2193 : const MSStop& priorStop = *itPriorStop;
2194 48 : if (priorStop.pars.jump >= 0) {
2195 : needJump = false;
2196 : }
2197 : }
2198 : if (needJump) {
2199 47 : SUMOVehicleParameter::Stop jumpStopPars;
2200 47 : jumpStopPars.endPos = (*itStart)->getLength();
2201 47 : jumpStopPars.speed = 1000;
2202 47 : jumpStopPars.jump = 0;
2203 : jumpStopPars.edge = (*itStart)->getID();
2204 47 : jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
2205 : MSLane* jumpStopLane = nullptr;
2206 47 : for (MSLane* cand : (*itStart)->getLanes()) {
2207 47 : if (cand->allowsVehicleClass(getVClass())) {
2208 : jumpStopLane = cand;
2209 : break;
2210 : }
2211 : }
2212 47 : if (jumpStopLane == nullptr) {
2213 0 : errorMsg = TL("unable to replace stop with teleporting");
2214 : return false;
2215 : }
2216 : auto itStop = myStops.begin();
2217 : std::advance(itStop, nextStopIndex);
2218 47 : MSStop jumpStop(jumpStopPars);
2219 47 : jumpStop.initPars(jumpStopPars);
2220 47 : jumpStop.lane = jumpStopLane;
2221 47 : jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
2222 47 : myStops.insert(itStop, jumpStop);
2223 47 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
2224 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
2225 : auto it = myParameter->stops.begin() + nextStopIndex;
2226 0 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
2227 : }
2228 47 : }
2229 : return true;
2230 : }
2231 :
2232 :
2233 : bool
2234 390 : MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
2235 390 : const int n = (int)myStops.size();
2236 390 : if (nextStopIndex < 0 || nextStopIndex > n) {
2237 5 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
2238 5 : return false;
2239 : }
2240 385 : if (nextStopIndex == 0 && isStopped()) {
2241 7 : errorMsg = TL("cannot insert stop before the currently reached stop");
2242 7 : return false;
2243 : }
2244 378 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
2245 378 : MSLane* stopLane = MSLane::dictionary(stop.lane);
2246 378 : MSEdge* stopEdge = &stopLane->getEdge();
2247 :
2248 378 : if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
2249 0 : errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
2250 0 : return false;
2251 : }
2252 :
2253 : // check parking access rights
2254 378 : if (stop.parkingarea != "") {
2255 160 : MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
2256 160 : if (pa != nullptr && !pa->accepts(this)) {
2257 0 : errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
2258 0 : return false;
2259 : }
2260 : }
2261 :
2262 378 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
2263 378 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
2264 378 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
2265 378 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
2266 378 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
2267 378 : MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
2268 378 : auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
2269 378 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2270 :
2271 378 : bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
2272 :
2273 : ConstMSEdgeVector toNewStop;
2274 378 : if (!teleport) {
2275 350 : router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
2276 350 : if (toNewStop.size() == 0) {
2277 15 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
2278 5 : return false;
2279 : }
2280 : }
2281 :
2282 : ConstMSEdgeVector fromNewStop;
2283 373 : if (!newDestination) {
2284 336 : router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
2285 336 : if (fromNewStop.size() == 0) {
2286 0 : errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
2287 0 : return false;
2288 : }
2289 : }
2290 :
2291 : auto itStop = myStops.begin();
2292 : std::advance(itStop, nextStopIndex);
2293 373 : MSStop newStop(stop);
2294 373 : newStop.initPars(stop);
2295 373 : newStop.edge = myRoute->end(); // will be patched in replaceRoute
2296 373 : newStop.lane = stopLane;
2297 373 : if (MSGlobals::gUseMesoSim) {
2298 73 : newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
2299 73 : if (newStop.lane->isInternal()) {
2300 0 : errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
2301 0 : return false;
2302 : }
2303 : }
2304 373 : myStops.insert(itStop, newStop);
2305 :
2306 373 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2307 : ConstMSEdgeVector newEdges; // only remaining
2308 373 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2309 373 : if (!teleport) {
2310 345 : newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
2311 : } else {
2312 28 : newEdges.push_back(*itStart);
2313 : }
2314 373 : if (!newDestination) {
2315 336 : newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
2316 336 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2317 : } else {
2318 37 : newEdges.push_back(stopEdge);
2319 : }
2320 : //std::cout << SIMTIME << " insertStop veh=" << getID()
2321 : // << " teleport=" << teleport
2322 : // << " busStop=" << stop.busstop
2323 : // << " oldEdges=" << oldRemainingEdges.size()
2324 : // << " newEdges=" << newEdges.size()
2325 : // << " toNewStop=" << toNewStop.size()
2326 : // << " fromNewStop=" << fromNewStop.size()
2327 : // << "\n";
2328 :
2329 373 : const double routeCost = router.recomputeCosts(newEdges, this, t);
2330 373 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2331 373 : const double savings = previousCost - routeCost;
2332 :
2333 373 : if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
2334 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
2335 : auto it = myParameter->stops.begin() + nextStopIndex;
2336 15 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
2337 : }
2338 373 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2339 751 : }
2340 :
2341 :
2342 : double
2343 0 : MSBaseVehicle::getStateOfCharge() const {
2344 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2345 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2346 0 : return batteryOfVehicle->getActualBatteryCapacity();
2347 : } else {
2348 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2349 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2350 0 : return batteryOfVehicle->getActualBatteryCapacity();
2351 : }
2352 : }
2353 : return -1;
2354 : }
2355 :
2356 :
2357 : double
2358 0 : MSBaseVehicle::getRelativeStateOfCharge() const {
2359 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2360 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2361 0 : return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2362 : } else {
2363 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2364 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2365 0 : return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2366 : }
2367 : }
2368 : return -1;
2369 : }
2370 :
2371 :
2372 : double
2373 0 : MSBaseVehicle::getChargedEnergy() const {
2374 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2375 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2376 0 : return batteryOfVehicle->getEnergyCharged();
2377 : } else {
2378 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2379 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2380 0 : return batteryOfVehicle->getEnergyCharged();
2381 : }
2382 : }
2383 : return -1;
2384 : }
2385 :
2386 :
2387 : double
2388 0 : MSBaseVehicle::getMaxChargeRate() const {
2389 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2390 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2391 0 : return batteryOfVehicle->getMaximumChargeRate();
2392 : }
2393 : return -1;
2394 : }
2395 :
2396 :
2397 : double
2398 0 : MSBaseVehicle::getElecHybridCurrent() const {
2399 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2400 0 : MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2401 0 : return elecHybridDevice->getCurrentFromOverheadWire();
2402 : }
2403 :
2404 : return NAN;
2405 : }
2406 :
2407 : double
2408 766 : MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
2409 766 : if (isOnRoad() || isIdling()) {
2410 766 : return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
2411 : } else {
2412 : return 0.;
2413 : }
2414 : }
2415 :
2416 :
2417 : const MSEdgeWeightsStorage&
2418 6333406 : MSBaseVehicle::getWeightsStorage() const {
2419 6333406 : return _getWeightsStorage();
2420 : }
2421 :
2422 :
2423 : MSEdgeWeightsStorage&
2424 666 : MSBaseVehicle::getWeightsStorage() {
2425 666 : return _getWeightsStorage();
2426 : }
2427 :
2428 :
2429 : MSEdgeWeightsStorage&
2430 6334072 : MSBaseVehicle::_getWeightsStorage() const {
2431 6334072 : if (myEdgeWeights == nullptr) {
2432 13803 : myEdgeWeights = new MSEdgeWeightsStorage();
2433 : }
2434 6334072 : return *myEdgeWeights;
2435 : }
2436 :
2437 :
2438 :
2439 :
2440 : int
2441 7934480 : MSBaseVehicle::getPersonNumber() const {
2442 7934480 : int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
2443 7934480 : return boarded + myParameter->personNumber;
2444 : }
2445 :
2446 : int
2447 0 : MSBaseVehicle::getLeavingPersonNumber() const {
2448 : int leavingPersonNumber = 0;
2449 0 : const std::vector<MSTransportable*>& persons = getPersons();
2450 0 : for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2451 0 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
2452 : const MSStop* stop = &myStops.front();
2453 0 : const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
2454 0 : if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
2455 0 : leavingPersonNumber++;
2456 : }
2457 : }
2458 0 : return leavingPersonNumber;
2459 : }
2460 :
2461 : std::vector<std::string>
2462 194 : MSBaseVehicle::getPersonIDList() const {
2463 : std::vector<std::string> ret;
2464 194 : const std::vector<MSTransportable*>& persons = getPersons();
2465 669 : for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2466 475 : ret.push_back((*it_p)->getID());
2467 : }
2468 194 : return ret;
2469 0 : }
2470 :
2471 : int
2472 8879504 : MSBaseVehicle::getContainerNumber() const {
2473 8879504 : int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
2474 8879504 : return loaded + myParameter->containerNumber;
2475 : }
2476 :
2477 :
2478 : void
2479 162 : MSBaseVehicle::removeTransportable(MSTransportable* t) {
2480 : // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
2481 162 : if (myPersonDevice != nullptr) {
2482 142 : myPersonDevice->removeTransportable(t);
2483 : }
2484 162 : if (myContainerDevice != nullptr) {
2485 20 : myContainerDevice->removeTransportable(t);
2486 : }
2487 162 : if (myEnergyParams != nullptr) {
2488 84 : myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
2489 : }
2490 162 : }
2491 :
2492 :
2493 : void
2494 9265 : MSBaseVehicle::removeTransportableMass(MSTransportable* t) {
2495 9265 : if (myEnergyParams != nullptr) {
2496 6022 : myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
2497 : }
2498 9265 : }
2499 :
2500 :
2501 : const std::vector<MSTransportable*>&
2502 11255025 : MSBaseVehicle::getPersons() const {
2503 11255025 : if (myPersonDevice == nullptr) {
2504 : return myEmptyTransportableVector;
2505 : } else {
2506 13589 : return myPersonDevice->getTransportables();
2507 : }
2508 : }
2509 :
2510 :
2511 : const std::vector<MSTransportable*>&
2512 10012251 : MSBaseVehicle::getContainers() const {
2513 10012251 : if (myContainerDevice == nullptr) {
2514 : return myEmptyTransportableVector;
2515 : } else {
2516 3290 : return myContainerDevice->getTransportables();
2517 : }
2518 : }
2519 :
2520 :
2521 : bool
2522 203 : MSBaseVehicle::isLineStop(double position) const {
2523 203 : if (myParameter->line == "") {
2524 : // not a public transport line
2525 : return false;
2526 : }
2527 349 : for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
2528 209 : if (stop.startPos <= position && position <= stop.endPos) {
2529 : return true;
2530 : }
2531 : }
2532 166 : for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
2533 36 : if (stop.startPos <= position && position <= stop.endPos) {
2534 : return true;
2535 : }
2536 : }
2537 : return false;
2538 : }
2539 :
2540 :
2541 : bool
2542 45 : MSBaseVehicle::hasDevice(const std::string& deviceName) const {
2543 144 : for (MSDevice* const dev : myDevices) {
2544 126 : if (dev->deviceName() == deviceName) {
2545 : return true;
2546 : }
2547 : }
2548 : return false;
2549 : }
2550 :
2551 :
2552 : void
2553 9 : MSBaseVehicle::createDevice(const std::string& deviceName) {
2554 9 : if (!hasDevice(deviceName)) {
2555 9 : if (deviceName == "rerouting") {
2556 27 : ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
2557 9 : MSDevice_Routing::buildVehicleDevices(*this, myDevices);
2558 9 : if (hasDeparted()) {
2559 : // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
2560 0 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
2561 : assert(routingDevice != 0);
2562 0 : routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
2563 : }
2564 : } else {
2565 0 : throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
2566 : }
2567 : }
2568 9 : }
2569 :
2570 :
2571 : std::string
2572 50142 : MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
2573 59702 : for (MSVehicleDevice* const dev : myDevices) {
2574 59693 : if (dev->deviceName() == deviceName) {
2575 50133 : return dev->getParameter(key);
2576 : }
2577 : }
2578 27 : throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2579 : }
2580 :
2581 :
2582 : void
2583 208 : MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
2584 355 : for (MSVehicleDevice* const dev : myDevices) {
2585 355 : if (dev->deviceName() == deviceName) {
2586 208 : dev->setParameter(key, value);
2587 208 : return;
2588 : }
2589 : }
2590 0 : throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2591 : }
2592 :
2593 :
2594 : void
2595 842 : MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
2596 1669 : if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
2597 837 : getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
2598 837 : const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2599 : // checked in MSLink::ignoreFoe
2600 : } else {
2601 15 : throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
2602 : }
2603 837 : }
2604 :
2605 :
2606 : void
2607 38 : MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
2608 : // handle some generic params first and then delegate to the carFollowModel itself
2609 67 : if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
2610 17 : getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
2611 17 : const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2612 : // checked in MSVehicle::planMove
2613 : } else {
2614 21 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
2615 21 : if (microVeh) {
2616 : // remove 'carFollowModel.' prefix
2617 21 : const std::string attrName = key.substr(15);
2618 21 : microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
2619 : }
2620 : }
2621 33 : }
2622 :
2623 :
2624 : void
2625 5382016 : MSBaseVehicle::initTransientModelParams() {
2626 : /* Design idea for additional junction model parameters:
2627 : We can distinguish between 3 levels of parameters
2628 : 1. typically shared by multiple vehicles -> vType parameter
2629 : 2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
2630 : 3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
2631 : */
2632 5655955 : for (auto item : getParameter().getParametersMap()) {
2633 547878 : if (StringUtils::startsWith(item.first, "junctionModel.")) {
2634 832 : setJunctionModelParameter(item.first, item.second);
2635 546214 : } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
2636 17 : setCarFollowModelParameter(item.first, item.second);
2637 : }
2638 : }
2639 10764032 : const std::string routingModeStr = getStringParam("device.rerouting.mode");
2640 : try {
2641 5382016 : int routingMode = StringUtils::toInt(routingModeStr);
2642 5382016 : if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
2643 : setRoutingMode(routingMode);
2644 : }
2645 0 : } catch (NumberFormatException&) {
2646 : // @todo interpret symbolic constants
2647 0 : throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
2648 0 : }
2649 5382016 : }
2650 :
2651 :
2652 : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
2653 22725 : MSBaseVehicle::getRouterTT() const {
2654 22725 : if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
2655 204 : return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
2656 : } else {
2657 45246 : return MSNet::getInstance()->getRouterTT(getRNGIndex());
2658 : }
2659 : }
2660 :
2661 :
2662 : void
2663 30681 : MSBaseVehicle::replaceVehicleType(const MSVehicleType* type) {
2664 : assert(type != nullptr);
2665 : // save old parameters before possible type deletion
2666 30681 : const double oldMu = myType->getSpeedFactor().getParameter(0);
2667 : const double oldDev = myType->getSpeedFactor().getParameter(1);
2668 30681 : if (myType->isVehicleSpecific() && type != myType) {
2669 938 : MSNet::getInstance()->getVehicleControl().removeVType(myType);
2670 : }
2671 : // adapt myChosenSpeedFactor to the new type
2672 30681 : if (oldDev == 0.) {
2673 : // old type had speedDev 0, reroll
2674 22805 : myChosenSpeedFactor = type->computeChosenSpeedDeviation(getRNG());
2675 : } else {
2676 : // map old speedFactor onto new distribution
2677 7876 : const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
2678 : const double newMu = type->getSpeedFactor().getParameter(0);
2679 : const double newDev = type->getSpeedFactor().getParameter(1);
2680 7876 : myChosenSpeedFactor = newMu + distPoint * newDev;
2681 : // respect distribution limits
2682 7876 : myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
2683 7881 : myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
2684 : }
2685 30681 : myType = type;
2686 30681 : if (myEnergyParams != nullptr) {
2687 : myEnergyParams->setSecondary(type->getEmissionParameters());
2688 : }
2689 30681 : }
2690 :
2691 :
2692 : MSVehicleType&
2693 144732 : MSBaseVehicle::getSingularType() {
2694 144732 : if (myType->isVehicleSpecific()) {
2695 : return *const_cast<MSVehicleType*>(myType);
2696 : }
2697 2528 : MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
2698 1264 : replaceVehicleType(type);
2699 1264 : return *type;
2700 : }
2701 :
2702 :
2703 : int
2704 546465 : MSBaseVehicle::getRNGIndex() const {
2705 546465 : const MSLane* const lane = getLane();
2706 546465 : if (lane == nullptr) {
2707 17637 : return getEdge()->getLanes()[0]->getRNGIndex();
2708 : } else {
2709 528828 : return lane->getRNGIndex();
2710 : }
2711 : }
2712 :
2713 :
2714 : SumoRNG*
2715 724069264 : MSBaseVehicle::getRNG() const {
2716 724069264 : const MSLane* lane = getLane();
2717 724069264 : if (lane == nullptr) {
2718 6815 : return getEdge()->getLanes()[0]->getRNG();
2719 : } else {
2720 724062449 : return lane->getRNG();
2721 : }
2722 : }
2723 :
2724 : std::string
2725 69089 : MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
2726 69089 : const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
2727 138178 : if (StringUtils::startsWith(key, "device.")) {
2728 150426 : StringTokenizer tok(key, ".");
2729 50142 : if (tok.size() < 3) {
2730 0 : error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
2731 0 : return "";
2732 : }
2733 : try {
2734 150426 : return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
2735 18 : } catch (InvalidArgument& e) {
2736 54 : error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
2737 18 : return "";
2738 18 : }
2739 88036 : } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
2740 324 : if (microVeh == nullptr) {
2741 36 : error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
2742 18 : return "";
2743 : }
2744 306 : const std::string attrName = key.substr(16);
2745 : try {
2746 306 : return microVeh->getLaneChangeModel().getParameter(attrName);
2747 44 : } catch (InvalidArgument& e) {
2748 132 : error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
2749 44 : return "";
2750 44 : }
2751 37246 : } else if (StringUtils::startsWith(key, "carFollowModel.")) {
2752 16 : if (microVeh == nullptr) {
2753 0 : error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
2754 0 : return "";
2755 : }
2756 16 : const std::string attrName = key.substr(15);
2757 : try {
2758 16 : return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
2759 0 : } catch (InvalidArgument& e) {
2760 0 : error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
2761 0 : return "";
2762 0 : }
2763 18643 : } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
2764 108 : StringTokenizer tok(key, ".");
2765 36 : if (tok.size() != 3) {
2766 0 : error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
2767 0 : return "";
2768 : }
2769 81 : return hasDevice(tok.get(1)) ? "true" : "false";
2770 : // parking related parameters start here
2771 18607 : } else if (key == "parking.rerouteCount") {
2772 15 : return toString(getNumberParkingReroutes());
2773 37112 : } else if (StringUtils::startsWith(key, "parking.memory.")) {
2774 : std::vector<std::string> values;
2775 65 : if (getParkingMemory()) {
2776 25 : if (key == "parking.memory.IDList") {
2777 30 : for (const auto& item : *getParkingMemory()) {
2778 25 : values.push_back(item.first->getID());
2779 : }
2780 20 : } else if (key == "parking.memory.score") {
2781 30 : for (const auto& item : *getParkingMemory()) {
2782 25 : values.push_back(item.second.score);
2783 : }
2784 15 : } else if (key == "parking.memory.blockedAtTime") {
2785 30 : for (const auto& item : *getParkingMemory()) {
2786 50 : values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
2787 : }
2788 10 : } else if (key == "parking.memory.blockedAtTimeLocal") {
2789 30 : for (const auto& item : *getParkingMemory()) {
2790 50 : values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
2791 : }
2792 : } else {
2793 10 : error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
2794 : }
2795 : }
2796 65 : return toString(values);
2797 65 : } else {
2798 : // default: custom user parameter
2799 36982 : return getParameter().getParameter(key, "");
2800 : }
2801 : }
2802 :
2803 :
2804 : void
2805 54344 : MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
2806 54344 : if (myParkingMemory == nullptr) {
2807 0 : myParkingMemory = new StoppingPlaceMemory();
2808 : }
2809 54344 : myParkingMemory->rememberBlockedStoppingPlace(pa, local);
2810 54344 : }
2811 :
2812 :
2813 : void
2814 19077 : MSBaseVehicle::resetParkingAreaScores() {
2815 19077 : if (myParkingMemory != nullptr) {
2816 17358 : myParkingMemory->resetStoppingPlaceScores();
2817 : }
2818 19077 : }
2819 :
2820 :
2821 : void
2822 360 : MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
2823 360 : if (myChargingMemory == nullptr) {
2824 80 : myChargingMemory = new StoppingPlaceMemory();
2825 : }
2826 360 : myChargingMemory->rememberStoppingPlaceScore(cs, score);
2827 360 : }
2828 :
2829 :
2830 : void
2831 127 : MSBaseVehicle::resetChargingStationScores() {
2832 127 : if (myChargingMemory != nullptr) {
2833 11 : myChargingMemory->resetStoppingPlaceScores();
2834 : }
2835 127 : }
2836 :
2837 :
2838 : void
2839 86339 : MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
2840 86339 : if (myParkingMemory == nullptr) {
2841 2226 : myParkingMemory = new StoppingPlaceMemory();
2842 : }
2843 86339 : myParkingMemory->rememberStoppingPlaceScore(pa, score);
2844 86339 : }
2845 :
2846 :
2847 : SUMOTime
2848 51792 : MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
2849 51792 : if (myParkingMemory == nullptr) {
2850 : return -1;
2851 : }
2852 51792 : return myParkingMemory->sawBlockedStoppingPlace(pa, local);
2853 : }
2854 :
2855 :
2856 0 : void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
2857 0 : if (myChargingMemory == nullptr) {
2858 0 : myChargingMemory = new StoppingPlaceMemory();
2859 : }
2860 0 : myChargingMemory->rememberBlockedStoppingPlace(cs, local);
2861 0 : }
2862 :
2863 :
2864 : SUMOTime
2865 548 : MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
2866 548 : if (myChargingMemory == nullptr) {
2867 : return -1;
2868 : }
2869 72 : return myChargingMemory->sawBlockedStoppingPlace(cs, local);
2870 : }
2871 :
2872 :
2873 : #ifdef _DEBUG
2874 : void
2875 : MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
2876 : if (oc.isSet("movereminder-output.vehicles")) {
2877 : const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
2878 : myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
2879 : }
2880 : }
2881 :
2882 :
2883 : void
2884 : MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
2885 : OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
2886 : od.openTag("movereminder");
2887 : od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
2888 : od.writeAttr("veh", getID());
2889 : od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
2890 : od.writeAttr("type", type);
2891 : od.writeAttr("pos", toString(pos));
2892 : od.writeAttr("keep", toString(keep));
2893 : od.closeTag();
2894 : }
2895 : #endif
2896 :
2897 :
2898 : /****************************************************************************/
|