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