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 3485 : MSBaseVehicle::BaseInfluencer::BaseInfluencer()
90 3485 : {}
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 5557086 : MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
103 5557086 : MSVehicleType* type, const double speedFactor) :
104 : SUMOVehicle(pars->id),
105 5557086 : myParameter(pars),
106 : myRoute(route),
107 5557086 : myType(type),
108 5557086 : myCurrEdge(route->begin()),
109 5568317 : myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
110 5557086 : myMoveReminders(0),
111 5557086 : myPersonDevice(nullptr),
112 5557086 : myContainerDevice(nullptr),
113 5557086 : myEnergyParams(nullptr),
114 5557086 : myDeparture(NOT_YET_DEPARTED),
115 5557086 : myDepartPos(-1),
116 5557086 : myArrivalPos(-1),
117 5557086 : myArrivalLane(-1),
118 5557086 : myNumberReroutes(0),
119 5557086 : myStopUntilOffset(0),
120 5557086 : myOdometer(0.),
121 5557086 : myRouteValidity(ROUTE_UNCHECKED),
122 5557086 : myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
123 5557086 : myNumericalID(myCurrentNumericalIndex++),
124 11114172 : myRandomSeed(RandHelper::murmur3_32(pars->id, RandHelper::getSeed())),
125 11114172 : myEdgeWeights(nullptr)
126 : #ifdef _DEBUG
127 : , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
128 : #endif
129 : {
130 5557086 : if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
131 577706 : pars->parametersSet |= VEHPARS_FORCE_REROUTE;
132 : }
133 5557086 : if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
134 4005898 : setDepartAndArrivalEdge();
135 : }
136 5557086 : calculateArrivalParams(true);
137 5557086 : initTransientModelParams();
138 5557086 : }
139 :
140 :
141 5556991 : MSBaseVehicle::~MSBaseVehicle() {
142 5556991 : delete myEdgeWeights;
143 5556991 : if (myParameter->repetitionNumber == -1) {
144 : // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
145 460327 : MSRoute::checkDist(myParameter->routeid);
146 : }
147 9707573 : for (MSVehicleDevice* dev : myDevices) {
148 4150582 : delete dev;
149 : }
150 5556991 : delete myEnergyParams;
151 5556991 : delete myParkingMemory;
152 5556991 : delete myChargingMemory;
153 5556991 : checkRouteRemoval();
154 5556991 : delete myParameter;
155 5556991 : }
156 :
157 :
158 : void
159 15234594 : 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 15234592 : if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
163 837226 : myRoute->checkRemoval();
164 : }
165 7617297 : }
166 :
167 :
168 : std::string
169 7617295 : MSBaseVehicle::getFlowID() const {
170 7617295 : return getID().substr(0, getID().rfind('.'));
171 : }
172 :
173 :
174 : void
175 5557086 : MSBaseVehicle::initDevices() {
176 5557086 : MSDevice::buildVehicleDevices(*this, myDevices);
177 9702634 : for (MSVehicleDevice* dev : myDevices) {
178 4145565 : myMoveReminders.push_back(std::make_pair(dev, 0.));
179 : }
180 5557069 : if (MSGlobals::gHaveEmissions) {
181 : // ensure we have the emission parameters even if we don't have the device
182 1061872 : getEmissionParameters();
183 : }
184 5557069 : }
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 39030123137 : MSBaseVehicle::getParameter() const {
194 39030123137 : return *myParameter;
195 : }
196 :
197 :
198 : void
199 54 : MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
200 54 : delete myParameter;
201 54 : myParameter = newParameter;
202 54 : }
203 :
204 :
205 : bool
206 7658751995 : MSBaseVehicle::ignoreTransientPermissions() const {
207 7658751995 : return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
208 : }
209 :
210 : double
211 6189967803 : MSBaseVehicle::getMaxSpeed() const {
212 6189967803 : return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
213 : }
214 :
215 :
216 : const MSEdge*
217 2163736854 : MSBaseVehicle::succEdge(int nSuccs) const {
218 2163736854 : if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
219 1539055438 : return *(myCurrEdge + nSuccs);
220 : } else {
221 624681416 : return nullptr;
222 : }
223 : }
224 :
225 :
226 : const MSEdge*
227 7787015347 : MSBaseVehicle::getEdge() const {
228 7787015347 : return *myCurrEdge;
229 : }
230 :
231 :
232 : const std::set<SUMOTrafficObject::NumericalID>
233 65475 : MSBaseVehicle::getUpcomingEdgeIDs() const {
234 : std::set<SUMOTrafficObject::NumericalID> result;
235 294663 : for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
236 229188 : result.insert((*e)->getNumericalID());
237 : }
238 65475 : return result;
239 : }
240 :
241 :
242 : bool
243 1226039 : MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
244 1226039 : if (stop == nullptr) {
245 : return false;
246 : }
247 2413094 : for (const MSStop& s : myStops) {
248 2411555 : if (s.busstop == stop
249 2372702 : || s.containerstop == stop
250 1187071 : || s.parkingarea == stop
251 1187065 : || s.chargingStation == stop) {
252 : return true;
253 : }
254 : }
255 : return false;
256 : }
257 :
258 : bool
259 189016 : MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
260 398430 : for (const MSStop& s : myStops) {
261 368167 : if (&s.lane->getEdge() == edge) {
262 : return true;
263 : }
264 : }
265 30263 : return myRoute->getLastEdge() == edge;
266 : }
267 :
268 :
269 : bool
270 3129639 : 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 3129639 : const MSEdge* source = nullptr;
273 3129639 : if (onInit) {
274 2946867 : 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 2946338 : source = myRoute->getEdges().front();
281 : }
282 : } else {
283 182772 : source = *getRerouteOrigin();
284 : }
285 3129639 : if (sink == nullptr) {
286 3103140 : sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
287 3103140 : if (sink == nullptr) {
288 5 : sink = myRoute->getLastEdge();
289 : }
290 : }
291 3137982 : ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
292 : ConstMSEdgeVector edges;
293 3129639 : if (source != sink || !sink->prohibits(this)) {
294 3129633 : edges.push_back(source);
295 : }
296 : std::vector<StopEdgeInfo> stops;
297 : std::set<int> jumps;
298 :
299 :
300 3129639 : 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 2946867 : if (onInit && myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
307 86779 : sourcePos = myParameter->departPos;
308 3042860 : } else if (getLane() != nullptr && source != &getLane()->getEdge()) {
309 : // routing starts on the next edge
310 : sourcePos = 0;
311 : }
312 3129639 : if (myParameter->via.size() == 0) {
313 3119083 : double firstPos = INVALID_DOUBLE;
314 3119083 : double lastPos = INVALID_DOUBLE;
315 3119083 : stops = getStopEdges(firstPos, lastPos, jumps);
316 3119083 : if (stops.size() > 0) {
317 40706 : if (MSGlobals::gUseMesoSim && isStopped()) {
318 300 : sourcePos = getNextStop().pars.endPos;
319 : }
320 40706 : if (/*!MSGlobals::gUseMesoSim &&*/ !isStopped() && myStops.front().pars.speed == 0) {
321 37550 : sourcePos += getBrakeGap();
322 : }
323 : // avoid superfluous waypoints for first and last edge
324 40706 : 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 40706 : if (stops.size() == 1 && skipFirst) {
333 : stops.clear();
334 33434 : } else if (skipFirst) {
335 8234 : 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 27364 : for (const MSStop& stop : myStops) {
343 16808 : if (stop.pars.jump >= 0) {
344 : jumpEdges.insert(*stop.edge);
345 : }
346 : auto itsov = stopsOnVia.find(*stop.edge);
347 16808 : if (itsov == stopsOnVia.end()) {
348 31842 : stopsOnVia.insert({*stop.edge, StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stop.getEndPos(*this))});
349 : } else {
350 887 : 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 34169 : for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
356 23621 : MSEdge* viaEdge = MSEdge::dictionary(*it);
357 23621 : if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
358 : continue;
359 : }
360 : assert(viaEdge != 0);
361 19540 : 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 19532 : const double priority = (itsov == stopsOnVia.end() ? -1 : itsov->second.priority);
366 19532 : const SUMOTime arrival = (itsov == stopsOnVia.end() ? -1 : itsov->second.arrival);
367 19532 : const double pos = (itsov == stopsOnVia.end() ? 0 : itsov->second.pos);
368 19532 : 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 3089623 : if ((stops.size() == 0 && (source != sink || sourcePos > myArrivalPos))
376 3191460 : || ((stops.size() != 0) && (stops.back().edge != sink || myArrivalPos < stops.back().pos))) {
377 6093926 : 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 3129631 : const MSEdge* origSource = source;
393 15648155 : const SUMOTime maxDelay = TIME2STEPS(getFloatParam(toString(SUMO_TAG_CLOSING_REROUTE) + ".maxDelay", false, MSTriggeredRerouter::DEFAULT_MAXDELAY, false));
394 6265947 : for (auto& stopEdgeInfo : stops) {
395 3136321 : const MSEdge* const stopEdge = stopEdgeInfo.edge;
396 3136321 : const double priority = stopEdgeInfo.priority;
397 3136321 : 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 3137295 : 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 3135136 : if (into.size() > 0) {
412 3222292 : while (stopIt != myStops.end() && stopIt->pars.edge != stopEdge->getID()) {
413 : stopIt++;
414 : }
415 :
416 3134329 : startTime += TIME2STEPS(router.recomputeCostsPos(into, this, sourcePos, stopEdgeInfo.pos, startTime));
417 3134329 : if (stopIt != myStops.end()) {
418 80961 : 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 80952 : sourcePos = stopEdgeInfo.pos;
439 80952 : startTime += stopIt->getMinDuration(startTime);
440 : }
441 : edges.pop_back();
442 3134320 : edges.insert(edges.end(), into.begin(), into.end());
443 3134320 : if (edges.back()->isTazConnector()) {
444 : edges.pop_back();
445 : }
446 3134320 : source = edges.back();
447 3134320 : stopEdgeInfo.routeIndex = (int)edges.size() - 1;
448 : } else {
449 807 : if (priority >= 0) {
450 53 : stopEdgeInfo.skipped = true;
451 : hasSkipped = true;
452 53 : continue;
453 754 : } 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 731 : 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 3136321 : }
475 3129626 : 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 3129626 : if (edges.empty() && silent) {
494 : return false;
495 : }
496 3129502 : if (!edges.empty() && edges.front()->isTazConnector()) {
497 : edges.erase(edges.begin());
498 : }
499 3129502 : if (!edges.empty() && edges.back()->isTazConnector()) {
500 : edges.pop_back();
501 : }
502 3129502 : const double routeCost = router.recomputeCosts(edges, this, t);
503 3129502 : const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
504 3129502 : const double savings = previousCost - routeCost;
505 3129502 : bool savingsOk = onInit || info != "device.rerouting" || gWeightsRandomFactor != 1;
506 : if (!savingsOk) {
507 153367 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
508 : assert(routingDevice != 0);
509 153367 : savingsOk = routingDevice->sufficientSaving(previousCost, routeCost);
510 153367 : if (!savingsOk) {
511 : std::string dummyMsg;
512 141422 : 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 141422 : if (savingsOk) {
524 2988087 : replaceRouteEdges(edges, routeCost, savings, info, onInit);
525 : }
526 : // this must be called even if the route could not be replaced
527 3129502 : if (onInit) {
528 2946859 : 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 2946720 : setDepartAndArrivalEdge();
538 2946720 : calculateArrivalParams(onInit);
539 : }
540 3129363 : return !edges.empty();
541 3129889 : }
542 :
543 :
544 : bool
545 3039363 : MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
546 3039363 : if (edges.empty()) {
547 1731 : WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
548 577 : if (msgReturn != nullptr) {
549 : *msgReturn = "No route found";
550 : }
551 577 : return false;
552 : }
553 : // build a new id, first
554 : std::string id = getID();
555 3038786 : if (id[0] != '!') {
556 6077572 : id = "!" + id;
557 : }
558 3038786 : const std::string idSuffix = id + "!var#";
559 3038786 : int varIndex = 1;
560 3038786 : id = idSuffix + toString(varIndex);
561 7184948 : while (MSRoute::hasRoute(id)) {
562 8292324 : id = idSuffix + toString(++varIndex);
563 : }
564 3038786 : int oldSize = (int)edges.size();
565 3038786 : if (!onInit) {
566 90412 : const MSEdge* const origin = *getRerouteOrigin();
567 90412 : if (origin != *myCurrEdge && edges.front() == origin) {
568 1016 : edges.insert(edges.begin(), *myCurrEdge);
569 1016 : oldSize = (int)edges.size();
570 : }
571 180824 : edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
572 : }
573 3038786 : if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
574 : // re-assign stop iterators when rerouting to a new parkingArea / insertStop
575 : return true;
576 : }
577 1535671 : const RGBColor& c = myRoute->getColor();
578 1535671 : 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 1535671 : ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
582 3071342 : 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 1535703 : 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 3071340 : 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 2060324 : 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 2060324 : if (onInit) {
612 1466247 : myCurrEdge = newRoute->begin();
613 : } else {
614 594077 : MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
615 594077 : 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 594075 : if (getLane() != nullptr) {
627 456599 : if (getLane()->getEdge().isInternal() && (
628 456608 : (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 456590 : } else if (getPositionOnLane() > getLane()->getLength()
639 456595 : && (myCurrEdge + 1) != myRoute->end()
640 12 : && (newCurrEdge + 1) != edges.end()
641 456602 : && *(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 594059 : myCurrEdge = newCurrEdge;
654 : }
655 2060306 : const bool stopsFromScratch = onInit && myRoute->getStops().empty();
656 : // assign new route
657 2060306 : checkRouteRemoval();
658 : myRoute = newRoute;
659 : // update arrival definition
660 2060306 : calculateArrivalParams(onInit);
661 : // save information that the vehicle was rerouted
662 2060306 : myNumberReroutes++;
663 2060306 : myStopUntilOffset += myRoute->getPeriod();
664 2060306 : MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::NEWROUTE, info);
665 2060306 : 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 2146181 : for (StopParVector::iterator it = myPastStops.begin(); it != myPastStops.end();) {
694 140971 : const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
695 85875 : 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 2060306 : if (stopsFromScratch) {
703 : myStops.clear();
704 1466184 : addStops(!MSGlobals::gCheckRoutes);
705 : } else {
706 : // recheck old stops
707 594122 : MSRouteIterator searchStart = myCurrEdge;
708 594122 : double lastPos = getPositionOnLane() + getBrakeGap();
709 1050705 : if (getLane() != nullptr && getLane()->isInternal()
710 595039 : && 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 169 : lastPos += (*myCurrEdge)->getLength();
714 : }
715 : int stopIndex = 0;
716 644442 : for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
717 50320 : 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 50320 : if (*searchStart != &iter->lane->getEdge()
724 : // loop required to reach upstream position
725 20389 : || endPos + NUMERICAL_EPS < lastPos
726 : // loop requested at duplicate pos
727 13744 : || (endPos == lastPos && iter->pars.index == STOP_INDEX_REPEAT)
728 : // index encodes a skip
729 64029 : || iter->pars.index > (int)myPastStops.size() + stopIndex) {
730 36617 : if (searchStart != edges.end() && !iter->reached) {
731 : searchStart++;
732 : }
733 : }
734 : lastPos = endPos;
735 :
736 50320 : iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
737 : #ifdef DEBUG_REPLACE_ROUTE
738 : if (DEBUG_COND) {
739 : std::cout << " foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
740 : }
741 : #endif
742 50320 : if (iter->edge == edges.end() && iter->pars.priority >= 0) {
743 : const std::string oldEdge = iter->pars.edge;
744 124 : const std::string oldName = iter->getStoppingPlaceName().first;
745 62 : if (replaceWithAlternative(iter, searchStart, edges.end())) {
746 164 : WRITE_WARNINGF(TL("Vehicle '%' replaced stop on edge '%' (named '%') and now stops at '%' instead; after rerouting (%) at time=%."),
747 : getID(), oldEdge, oldName, iter->getDescription(true), info, time2string(SIMSTEP));
748 : }
749 : }
750 50320 : if (iter->edge == edges.end()) {
751 174 : if (!removeStops) {
752 0 : WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
753 : }
754 174 : iter = myStops.erase(iter);
755 174 : continue;
756 : } else {
757 50146 : setSkips(*iter, stopIndex);
758 50146 : searchStart = iter->edge;
759 : }
760 : ++iter;
761 50146 : stopIndex++;
762 : }
763 : // add new stops
764 594122 : if (addRouteStops) {
765 524920 : for (StopParVector::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
766 : std::string error;
767 307 : addStop(*i, error, myParameter->depart + myStopUntilOffset);
768 307 : if (error != "") {
769 0 : WRITE_WARNING(error);
770 : }
771 : }
772 : }
773 : }
774 : return true;
775 : }
776 :
777 :
778 : bool
779 62 : MSBaseVehicle::replaceWithAlternative(std::list<MSStop>::iterator iter, const MSRouteIterator searchStart, const MSRouteIterator end) {
780 62 : std::pair<std::string, SumoXMLTag> nameTag = iter->getStoppingPlaceName();
781 62 : if (!nameTag.first.empty()) {
782 41 : const std::vector<MSStoppingPlace*>& alternatives = MSNet::getInstance()->getStoppingPlaceAlternatives(nameTag.first, nameTag.second);
783 110 : for (MSStoppingPlace* alt : alternatives) {
784 : //std::cout << SIMTIME << " veh=" << getID() << " name=" << nameTag.first << " alt=" << alt->getID() << "\n";
785 110 : if (&alt->getLane().getEdge() == &iter->lane->getEdge()
786 110 : || !alt->getLane().allowsVehicleClass(getVClass())) {
787 62 : continue;
788 : }
789 48 : iter->edge = std::find(searchStart, end, &alt->getLane().getEdge());
790 48 : if (iter->edge != end) {
791 41 : iter->replaceStoppingPlace(alt);
792 : return true;
793 : }
794 : }
795 : }
796 : return false;
797 : }
798 :
799 :
800 : double
801 173005 : MSBaseVehicle::getAcceleration() const {
802 173005 : return 0;
803 : }
804 :
805 :
806 : void
807 4441702 : MSBaseVehicle::onDepart() {
808 4441702 : myDeparture = MSNet::getInstance()->getCurrentTimeStep();
809 4441702 : myDepartPos = getPositionOnLane();
810 4441702 : MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
811 4441702 : }
812 :
813 :
814 : SUMOTime
815 3481688 : MSBaseVehicle:: getDepartDelay() const {
816 3481688 : const SUMOTime dep = getParameter().depart;
817 3481688 : if (dep < 0) {
818 : return 0;
819 : }
820 3481581 : return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
821 : }
822 :
823 :
824 : bool
825 0 : MSBaseVehicle::hasArrived() const {
826 0 : return succEdge(1) == nullptr;
827 : }
828 :
829 :
830 : int
831 33938009 : MSBaseVehicle::getRoutePosition() const {
832 33938009 : return (int) std::distance(myRoute->begin(), myCurrEdge);
833 : }
834 :
835 :
836 : int
837 384153 : MSBaseVehicle::getNumRemainingEdges() const {
838 384153 : if (myParameter->arrivalEdge >= 0) {
839 0 : return myParameter->arrivalEdge - getRoutePosition() + 1;
840 : } else {
841 384153 : return myRoute->size() - getRoutePosition();
842 : }
843 : }
844 :
845 :
846 : void
847 104044 : MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
848 104044 : myCurrEdge = myRoute->begin() + index;
849 104044 : const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
850 : // !!! hack
851 104044 : myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
852 104044 : }
853 :
854 : double
855 26932 : MSBaseVehicle::getOdometer() const {
856 26932 : return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
857 : }
858 :
859 : bool
860 1427832 : MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
861 1427832 : if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
862 : return false;
863 1323901 : } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
864 : return false;
865 : }
866 2530891 : if (isStopped() && myStops.begin()->pars.permitted.size() > 0
867 1265501 : && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
868 6193 : return false;
869 : }
870 1259308 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
871 : if (taxiDevice != nullptr) {
872 27569 : return taxiDevice->allowsBoarding(t);
873 : }
874 : return true;
875 : }
876 :
877 :
878 : void
879 1123254 : MSBaseVehicle::addTransportable(MSTransportable* transportable) {
880 1123254 : if (transportable->isPerson()) {
881 13067 : if (myPersonDevice == nullptr) {
882 4610 : myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
883 4610 : myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
884 4610 : if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
885 1970 : const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
886 : }
887 : }
888 13067 : myPersonDevice->addTransportable(transportable);
889 : } else {
890 1110187 : if (myContainerDevice == nullptr) {
891 1109753 : myContainerDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, true);
892 424 : myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myContainerDevice, 0.));
893 424 : if (myParameter->departProcedure == DepartDefinition::CONTAINER_TRIGGERED && myParameter->depart == -1) {
894 79 : const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
895 : }
896 : }
897 858 : myContainerDevice->addTransportable(transportable);
898 : }
899 13925 : if (myEnergyParams != nullptr) {
900 9020 : myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() + transportable->getVehicleType().getMass());
901 : }
902 13925 : }
903 :
904 :
905 : bool
906 2874 : MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
907 3326 : for (const MSStop& stop : myStops) {
908 1049 : if (stop.edge == it && stop.pars.jump >= 0) {
909 : return true;
910 929 : } else if (stop.edge > it) {
911 : return false;
912 : }
913 : }
914 : return false;
915 : }
916 :
917 :
918 : bool
919 4679821 : MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
920 4679821 : MSRouteIterator start = myCurrEdge;
921 4679821 : if (route == nullptr) {
922 : route = myRoute;
923 : } else {
924 3962809 : start = route->begin();
925 : }
926 : const bool checkJumps = route == myRoute; // the edge iterators in the stops are invalid otherwise
927 4679821 : return hasValidRoute(msg, start, route->end(), checkJumps);
928 : }
929 :
930 :
931 : bool
932 4821243 : MSBaseVehicle::hasValidRoute(std::string& msg, MSRouteIterator start, MSRouteIterator last, bool checkJumps) const {
933 : MSRouteIterator lastValid = last - 1;
934 : // check connectivity, first
935 22150905 : for (MSRouteIterator e = start; e != lastValid; ++e) {
936 17378972 : const MSEdge& next = **(e + 1);
937 17378972 : if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
938 50100 : if (!checkJumps || !hasJump(e)) {
939 49980 : if (!ignoreTransientPermissions()
940 49980 : || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
941 147930 : msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
942 49310 : return false;
943 : }
944 : }
945 : }
946 : }
947 : // check usable lanes, then
948 26872553 : for (MSRouteIterator e = start; e != last; ++e) {
949 22100620 : if ((*e)->prohibits(this)) {
950 0 : msg = TLF("Edge '%' prohibits.", (*e)->getID());
951 : return false;
952 : }
953 : }
954 : return true;
955 : }
956 :
957 :
958 : bool
959 504198945 : MSBaseVehicle::hasValidRouteStart(std::string& msg) {
960 504198945 : if (!(*myCurrEdge)->isTazConnector()) {
961 504061470 : if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
962 12 : msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
963 6 : myRouteValidity |= ROUTE_START_INVALID_LANE;
964 6 : return false;
965 : }
966 : }
967 504198939 : if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
968 504198878 : myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
969 504198878 : return true;
970 : } else {
971 183 : msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
972 61 : myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
973 61 : return false;
974 : }
975 : }
976 :
977 :
978 : int
979 12749057381 : MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
980 12749057381 : if (!update) {
981 5193749588 : return myRouteValidity;
982 : }
983 : // insertion check must be done in any case
984 : std::string msg;
985 7555307793 : if (!hasValidRouteStart(msg)) {
986 183 : if (MSGlobals::gCheckRoutes) {
987 111 : throw ProcessError(msg);
988 72 : } else if (!silent) {
989 : // vehicle will be discarded
990 138 : WRITE_WARNING(msg);
991 26 : } else if (msgReturn != nullptr) {
992 : *msgReturn = msg;
993 : }
994 : }
995 29838 : if ((MSGlobals::gCheckRoutes || myRoute->getFirstEdge()->isInternal())
996 7555277850 : && (myRouteValidity & ROUTE_UNCHECKED) != 0
997 : // we could check after the first rerouting
998 7560733763 : && (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
999 7826789 : if (!hasValidRoute(msg, myRoute)) {
1000 78 : myRouteValidity |= ROUTE_INVALID;
1001 234 : throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
1002 : }
1003 : }
1004 7555307604 : myRouteValidity &= ~ROUTE_UNCHECKED;
1005 : return myRouteValidity;
1006 : }
1007 :
1008 :
1009 : bool
1010 715 : MSBaseVehicle::hasReminder(MSMoveReminder* rem) const {
1011 3172 : for (auto item : myMoveReminders) {
1012 2485 : if (item.first == rem) {
1013 : return true;
1014 : }
1015 : }
1016 687 : return false;
1017 : }
1018 :
1019 :
1020 : void
1021 28805997 : MSBaseVehicle::addReminder(MSMoveReminder* rem, double pos) {
1022 : #ifdef _DEBUG
1023 : if (myTraceMoveReminders) {
1024 : traceMoveReminder("add", rem, pos, true);
1025 : }
1026 : #endif
1027 28805997 : myMoveReminders.push_back(std::make_pair(rem, pos));
1028 28805997 : }
1029 :
1030 :
1031 : void
1032 0 : MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
1033 0 : for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
1034 0 : if (r->first == rem) {
1035 : #ifdef _DEBUG
1036 : if (myTraceMoveReminders) {
1037 : traceMoveReminder("remove", rem, 0, false);
1038 : }
1039 : #endif
1040 : myMoveReminders.erase(r);
1041 : return;
1042 : }
1043 : }
1044 : }
1045 :
1046 :
1047 : void
1048 49596402 : MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
1049 : // notifyEnter may cause new reminders to be added so we cannot use an iterator
1050 141785747 : for (int i = 0; i < (int)myMoveReminders.size();) {
1051 92189348 : MSMoveReminder* rem = myMoveReminders[i].first;
1052 92189348 : const double remPos = myMoveReminders[i].second;
1053 : // skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
1054 92189348 : if (rem->getLane() != nullptr && remPos > 0.) {
1055 : #ifdef _DEBUG
1056 : if (myTraceMoveReminders) {
1057 : traceMoveReminder("notifyEnter_skipped", rem, remPos, true);
1058 : }
1059 : #endif
1060 20000145 : ++i;
1061 : } else {
1062 72189203 : if (rem->notifyEnter(*this, reason, enteredLane)) {
1063 : #ifdef _DEBUG
1064 : if (myTraceMoveReminders) {
1065 : traceMoveReminder("notifyEnter", rem, remPos, true);
1066 : }
1067 : #endif
1068 70082044 : ++i;
1069 : } else {
1070 : #ifdef _DEBUG
1071 : if (myTraceMoveReminders) {
1072 : traceMoveReminder("notifyEnter", rem, remPos, false);
1073 : }
1074 : #endif
1075 : myMoveReminders.erase(myMoveReminders.begin() + i);
1076 : }
1077 : }
1078 : }
1079 49596399 : }
1080 :
1081 :
1082 : bool
1083 2877197992 : MSBaseVehicle::isRail() const {
1084 2877197992 : return isRailway(getVClass()) || isRailway(getCurrentEdge()->getPermissions());
1085 : }
1086 :
1087 : void
1088 10565666 : MSBaseVehicle::calculateArrivalParams(bool onInit) {
1089 10565666 : if (myRoute->getLastEdge()->isTazConnector()) {
1090 : return;
1091 : }
1092 9987974 : const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
1093 9987974 : if (arrivalEdgeIndex != myParameter->arrivalEdge) {
1094 21 : if (!(onInit && myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
1095 42 : WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
1096 : getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
1097 : }
1098 : }
1099 9987974 : const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
1100 9987974 : if (!onInit) {
1101 594059 : arrivalEdge = myRoute->getLastEdge();
1102 : // ignore arrivalEdge parameter after rerouting
1103 594059 : const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
1104 : }
1105 : const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
1106 9987974 : const double lastLaneLength = lanes[0]->getLength();
1107 9987974 : switch (myParameter->arrivalPosProcedure) {
1108 249288 : case ArrivalPosDefinition::GIVEN:
1109 249288 : if (fabs(myParameter->arrivalPos) > lastLaneLength) {
1110 4212 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
1111 : }
1112 : // Maybe we should warn the user about invalid inputs!
1113 249288 : myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
1114 249288 : if (myArrivalPos < 0) {
1115 28201 : myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
1116 : }
1117 : break;
1118 : case ArrivalPosDefinition::RANDOM:
1119 100265 : myArrivalPos = RandHelper::rand(lastLaneLength);
1120 100265 : break;
1121 0 : case ArrivalPosDefinition::CENTER:
1122 0 : myArrivalPos = lastLaneLength / 2.;
1123 0 : break;
1124 9638421 : default:
1125 9638421 : myArrivalPos = lastLaneLength;
1126 9638421 : break;
1127 : }
1128 9987974 : if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
1129 161386 : if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
1130 384711 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
1131 : }
1132 161386 : myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
1133 9826588 : } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
1134 7 : myArrivalLane = -1;
1135 7 : for (MSLane* lane : lanes) {
1136 7 : if (lane->allowsVehicleClass(myType->getVehicleClass())) {
1137 7 : myArrivalLane = lane->getIndex();
1138 7 : break;
1139 : }
1140 : }
1141 7 : if (myArrivalLane == -1) {
1142 0 : WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
1143 0 : myArrivalLane = 0;
1144 : }
1145 9826581 : } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
1146 : // pick random lane among all usable lanes
1147 : std::vector<MSLane*> usable;
1148 388393 : for (MSLane* lane : lanes) {
1149 295575 : if (lane->allowsVehicleClass(myType->getVehicleClass())) {
1150 270441 : usable.push_back(lane);
1151 : }
1152 : }
1153 92818 : if (usable.empty()) {
1154 0 : WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
1155 0 : myArrivalLane = 0;
1156 : } else {
1157 92818 : myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
1158 : }
1159 92818 : }
1160 9987974 : if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
1161 292073 : for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
1162 224491 : if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
1163 : return;
1164 : }
1165 : }
1166 202746 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
1167 : }
1168 : }
1169 :
1170 : void
1171 6952618 : MSBaseVehicle::setDepartAndArrivalEdge() {
1172 6952618 : SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
1173 6952618 : if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
1174 8142 : const int routeEdges = (int)myRoute->getEdges().size();
1175 8142 : if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
1176 : // write specific edge in vehroute output for reproducibility
1177 4185 : pars->departEdge = RandHelper::rand(0, routeEdges);
1178 4185 : pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
1179 : }
1180 : assert(pars->departEdge >= 0);
1181 8142 : if (pars->departEdge >= routeEdges) {
1182 0 : WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
1183 : } else {
1184 8142 : myCurrEdge = myRoute->begin() + pars->departEdge;
1185 : }
1186 : }
1187 6952618 : if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
1188 147 : const int routeEdges = (int)myRoute->getEdges().size();
1189 147 : const int begin = (int)(myCurrEdge - myRoute->begin());
1190 : // write specific edge in vehroute output for reproducibility
1191 147 : pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
1192 147 : pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
1193 : assert(pars->arrivalEdge >= begin);
1194 : assert(pars->arrivalEdge < routeEdges);
1195 : }
1196 6952618 : }
1197 :
1198 : int
1199 3905 : MSBaseVehicle::getDepartEdge() const {
1200 3905 : return myParameter->departEdge < myRoute->size() ? myParameter->departEdge : 0;
1201 : }
1202 :
1203 : int
1204 33044230 : MSBaseVehicle::getInsertionChecks() const {
1205 33044230 : if (getParameter().wasSet(VEHPARS_INSERTION_CHECKS_SET)) {
1206 432582 : return getParameter().insertionChecks;
1207 : } else {
1208 32611648 : return MSGlobals::gInsertionChecks;
1209 : }
1210 : }
1211 :
1212 : double
1213 647908618 : MSBaseVehicle::getImpatience() const {
1214 1295817236 : return MAX2(0., MIN2(1., getVehicleType().getImpatience()
1215 647908618 : + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
1216 647908618 : + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
1217 : }
1218 :
1219 :
1220 : MSDevice*
1221 991398689 : MSBaseVehicle::getDevice(const std::type_info& type) const {
1222 1700682309 : for (MSVehicleDevice* const dev : myDevices) {
1223 790302557 : if (typeid(*dev) == type) {
1224 81018937 : return dev;
1225 : }
1226 : }
1227 : return nullptr;
1228 : }
1229 :
1230 :
1231 : void
1232 4261 : MSBaseVehicle::saveState(OutputDevice& out) {
1233 : // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
1234 4261 : const std::string& typeID = myParameter->vtypeid != getVehicleType().getID() ? getVehicleType().getID() : "";
1235 4261 : myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
1236 : // params and stops must be written in child classes since they may wish to add additional attributes first
1237 4261 : out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
1238 4261 : std::ostringstream os;
1239 8522 : os << myOdometer << " " << myNumberReroutes;
1240 4261 : out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
1241 4261 : if (myParameter->arrivalPosProcedure == ArrivalPosDefinition::RANDOM) {
1242 13 : out.writeAttr(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, myArrivalPos);
1243 : }
1244 4261 : if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
1245 : const int precision = out.getPrecision();
1246 4261 : out.setPrecision(MAX2(gPrecisionRandom, precision));
1247 4261 : out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
1248 4261 : out.setPrecision(precision);
1249 : }
1250 4261 : if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
1251 2876 : out.writeAttr(SUMO_ATTR_REROUTE, true);
1252 : }
1253 4261 : if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
1254 : // could be set from stop
1255 2 : out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
1256 : }
1257 : // here starts the vehicle internal part (see loading)
1258 : // @note: remember to close the vehicle tag when calling this in a subclass!
1259 8522 : }
1260 :
1261 :
1262 : bool
1263 0 : MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
1264 : UNUSED_PARAMETER(stop);
1265 : UNUSED_PARAMETER(distToStop);
1266 0 : return true;
1267 : }
1268 :
1269 :
1270 : bool
1271 9603565190 : MSBaseVehicle::isStopped() const {
1272 9603565190 : return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
1273 : }
1274 :
1275 :
1276 : bool
1277 2676545922 : MSBaseVehicle::isParking() const {
1278 2731117897 : return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
1279 2583426 : && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
1280 2678070644 : && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
1281 : }
1282 :
1283 :
1284 : bool
1285 682781830 : MSBaseVehicle::isJumping() const {
1286 682781830 : return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
1287 : }
1288 :
1289 :
1290 : bool
1291 7377424 : MSBaseVehicle::isStoppedTriggered() const {
1292 7377424 : return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
1293 : }
1294 :
1295 :
1296 : bool
1297 28210 : MSBaseVehicle::isStoppedParking() const {
1298 28210 : return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
1299 : }
1300 :
1301 :
1302 : bool
1303 1127696 : MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
1304 1127696 : if (isStopped() || (checkFuture && hasStops())) {
1305 : const MSStop& stop = myStops.front();
1306 1128850 : return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
1307 : }
1308 : return false;
1309 : }
1310 :
1311 : bool
1312 28912 : MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
1313 : // Check if there is a parking area to be replaced
1314 28912 : if (parkingArea == 0) {
1315 : errorMsg = "new parkingArea is NULL";
1316 0 : return false;
1317 : }
1318 28912 : if (myStops.size() == 0) {
1319 : errorMsg = "vehicle has no stops";
1320 0 : return false;
1321 : }
1322 28912 : if (myStops.front().parkingarea == 0) {
1323 : errorMsg = "first stop is not at parkingArea";
1324 0 : return false;
1325 : }
1326 : MSStop& first = myStops.front();
1327 : SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
1328 28912 : std::string oldStopEdgeID = first.lane->getEdge().getID();
1329 : // merge subsequent duplicate stops equals to parking area
1330 28929 : for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
1331 301 : if (iter->parkingarea == parkingArea) {
1332 17 : stopPar.duration += iter->duration;
1333 17 : myStops.erase(iter++);
1334 : } else {
1335 : break;
1336 : }
1337 : }
1338 28912 : stopPar.lane = parkingArea->getLane().getID();
1339 28912 : stopPar.parkingarea = parkingArea->getID();
1340 28912 : stopPar.startPos = parkingArea->getBeginLanePosition();
1341 28912 : stopPar.endPos = parkingArea->getEndLanePosition();
1342 28912 : stopPar.index = STOP_INDEX_FIT;
1343 28912 : first.edge = myRoute->end(); // will be patched in replaceRoute
1344 28912 : first.lane = &parkingArea->getLane();
1345 28912 : first.parkingarea = parkingArea;
1346 :
1347 : // patch via edges
1348 28912 : std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
1349 28912 : if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
1350 172 : myParameter->via.erase(myParameter->via.begin());
1351 172 : myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
1352 : }
1353 : return true;
1354 : }
1355 :
1356 :
1357 : MSParkingArea*
1358 208500 : MSBaseVehicle::getNextParkingArea() {
1359 : MSParkingArea* nextParkingArea = nullptr;
1360 208500 : if (!myStops.empty()) {
1361 205668 : SUMOVehicleParameter::Stop stopPar;
1362 205668 : MSStop stop = myStops.front();
1363 205668 : if (!stop.reached && stop.parkingarea != nullptr) {
1364 : nextParkingArea = stop.parkingarea;
1365 : }
1366 205668 : }
1367 208500 : return nextParkingArea;
1368 : }
1369 :
1370 :
1371 : MSParkingArea*
1372 132253 : MSBaseVehicle::getCurrentParkingArea() {
1373 : MSParkingArea* currentParkingArea = nullptr;
1374 132253 : if (isParking()) {
1375 132184 : currentParkingArea = myStops.begin()->parkingarea;
1376 : }
1377 132253 : return currentParkingArea;
1378 : }
1379 :
1380 :
1381 : const std::vector<std::string>&
1382 1656 : MSBaseVehicle::getParkingBadges() const {
1383 1656 : if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
1384 7 : return myParameter->parkingBadges;
1385 : } else {
1386 1649 : return getVehicleType().getParkingBadges();
1387 : }
1388 : }
1389 :
1390 :
1391 : double
1392 12299832 : MSBaseVehicle::basePos(const MSEdge* edge) const {
1393 12299832 : double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
1394 12299832 : if (hasStops()
1395 12324921 : && myStops.front().edge == myRoute->begin()
1396 12324921 : && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
1397 25045 : result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
1398 : }
1399 12299832 : return result;
1400 : }
1401 :
1402 :
1403 : MSLane*
1404 298 : MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
1405 298 : const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
1406 298 : const MSEdge* edge = MSEdge::dictionary(edgeID);
1407 298 : if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
1408 8 : return nullptr;
1409 : }
1410 580 : const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
1411 290 : if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
1412 290 : const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
1413 290 : stop.edge = edgeID;
1414 290 : return edge->getOppositeEdge()->getLanes()[oppositeIndex];
1415 : }
1416 : return nullptr;
1417 : }
1418 :
1419 :
1420 : bool
1421 140608 : MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
1422 : MSRouteIterator* searchStart) {
1423 140608 : MSStop stop(stopPar);
1424 140608 : if (stopPar.lane == "") {
1425 2990 : MSEdge* e = MSEdge::dictionary(stopPar.edge);
1426 2990 : stop.lane = e->getFirstAllowed(getVClass(), getRoutingMode());
1427 2990 : if (stop.lane == nullptr) {
1428 0 : errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
1429 0 : return false;
1430 : }
1431 : } else {
1432 137618 : stop.lane = MSLane::dictionary(stopPar.lane);
1433 137618 : if (stop.lane == nullptr) {
1434 : // must be an opposite stop
1435 145 : SUMOVehicleParameter::Stop tmp = stopPar;
1436 145 : stop.lane = interpretOppositeStop(tmp);
1437 : assert(stop.lane != nullptr);
1438 145 : }
1439 137618 : if (!stop.lane->allowsVehicleClass(myType->getVehicleClass(), getRoutingMode())) {
1440 24 : errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
1441 12 : return false;
1442 : }
1443 : }
1444 140596 : if (MSGlobals::gUseMesoSim) {
1445 29102 : stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
1446 29102 : if (stop.lane->isInternal()) {
1447 2 : errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
1448 1 : return false;
1449 : }
1450 : }
1451 140595 : stop.initPars(stopPar);
1452 140595 : if (stopPar.until != -1) {
1453 : // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
1454 53146 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
1455 : }
1456 140595 : if (stopPar.arrival != -1) {
1457 626 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
1458 : }
1459 140595 : std::string stopType = "stop";
1460 140595 : std::string stopID = "";
1461 140595 : double parkingLength = stop.pars.endPos - stop.pars.startPos;
1462 140595 : if (stop.busstop != nullptr) {
1463 : stopType = "busStop";
1464 37753 : stopID = stop.busstop->getID();
1465 37753 : parkingLength = stop.busstop->getParkingLength();
1466 102842 : } else if (stop.containerstop != nullptr) {
1467 : stopType = "containerStop";
1468 1050 : stopID = stop.containerstop->getID();
1469 1050 : parkingLength = stop.containerstop->getParkingLength();
1470 101792 : } else if (stop.chargingStation != nullptr) {
1471 : stopType = "chargingStation";
1472 8310 : stopID = stop.chargingStation->getID();
1473 8310 : parkingLength = stop.chargingStation->getParkingLength();
1474 93482 : } else if (stop.overheadWireSegment != nullptr) {
1475 : stopType = "overheadWireSegment";
1476 0 : stopID = stop.overheadWireSegment->getID();
1477 0 : parkingLength = stop.overheadWireSegment->getParkingLength();
1478 93482 : } else if (stop.parkingarea != nullptr) {
1479 : stopType = "parkingArea";
1480 29804 : stopID = stop.parkingarea->getID();
1481 : }
1482 281190 : const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
1483 :
1484 140595 : if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
1485 0 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
1486 0 : return false;
1487 : }
1488 76917 : if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > parkingLength
1489 : // do not warn for stops that fill the whole lane
1490 307 : && parkingLength < stop.lane->getLength()
1491 : // do not warn twice for the same stop
1492 218349 : && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
1493 837 : errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
1494 : }
1495 140595 : if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
1496 : // forbid access in case the parking requests other badges
1497 14 : errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
1498 7 : return false;
1499 : }
1500 140588 : const MSEdge* stopLaneEdge = &stop.lane->getEdge();
1501 : const MSEdge* stopEdge;
1502 140588 : if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
1503 : // stop lane is on the opposite side
1504 145 : stopEdge = stopLaneEdge->getOppositeEdge();
1505 145 : stop.isOpposite = true;
1506 : } else {
1507 : // if stop is on an internal edge the normal edge before the intersection is used
1508 140443 : stopEdge = stopLaneEdge->getNormalBefore();
1509 : }
1510 140588 : MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
1511 140588 : if (searchStart == nullptr) {
1512 133407 : searchStart = &myCurrEdge;
1513 133407 : if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
1514 : // already on the intersection but myCurrEdge is before it
1515 : searchStart = ≻
1516 : }
1517 : }
1518 : #ifdef DEBUG_ADD_STOP
1519 : if (DEBUG_COND) {
1520 : std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
1521 : << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
1522 : << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
1523 : << " stopParIndex=" << stopPar.index
1524 : << "\n";
1525 : }
1526 : #endif
1527 140588 : stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
1528 140588 : MSRouteIterator prevStopEdge = myCurrEdge;
1529 140588 : const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
1530 140588 : double prevStopPos = getPositionOnLane();
1531 : // where to insert the stop
1532 : std::list<MSStop>::iterator iter = myStops.begin();
1533 140588 : if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
1534 : iter = myStops.end();
1535 117389 : if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
1536 : prevStopEdge = myStops.back().edge;
1537 49402 : prevEdge = &myStops.back().lane->getEdge();
1538 49402 : prevStopPos = myStops.back().pars.endPos;
1539 49402 : stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1540 : if (prevStopEdge == stop.edge // laneEdge check is insufficient for looped routes
1541 8038 : && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
1542 57428 : && (prevStopPos > stop.pars.endPos ||
1543 2246 : (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
1544 455 : stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
1545 : }
1546 : #ifdef DEBUG_ADD_STOP
1547 : if (DEBUG_COND) {
1548 : std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
1549 : << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
1550 : }
1551 : #endif
1552 : }
1553 : // skip a number of occurences of stopEdge in looped route
1554 117389 : int skipLooped = stopPar.index - static_cast<int>(myStops.size());
1555 117954 : for (int j = 0; j < skipLooped; j++) {
1556 711 : auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
1557 711 : if (nextIt == myRoute->end()) {
1558 146 : if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
1559 : // only warn if the route loops over the stop edge at least once
1560 28 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
1561 : }
1562 146 : break;
1563 : } else {
1564 565 : stop.edge = nextIt;
1565 : }
1566 : }
1567 : } else {
1568 23199 : if (stopPar.index == STOP_INDEX_FIT) {
1569 34847 : while (iter != myStops.end() && (iter->edge < stop.edge ||
1570 2234 : (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
1571 2234 : (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
1572 : prevStopEdge = iter->edge;
1573 11751 : prevStopPos = iter->pars.endPos;
1574 : ++iter;
1575 : }
1576 : } else {
1577 : int index = stopPar.index;
1578 103 : while (index > 0) {
1579 0 : prevStopEdge = iter->edge;
1580 0 : prevStopPos = iter->pars.endPos;
1581 : ++iter;
1582 0 : --index;
1583 : }
1584 : #ifdef DEBUG_ADD_STOP
1585 : if (DEBUG_COND) {
1586 : std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
1587 : }
1588 : #endif
1589 103 : stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1590 : }
1591 : }
1592 140934 : const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
1593 140588 : if (stop.edge == myRoute->end()) {
1594 89 : if (!wasTooClose) {
1595 207 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
1596 : }
1597 89 : return false;
1598 : }
1599 :
1600 140499 : const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
1601 43353 : prevStopPos + (iter == myStops.begin() && !instantStopping() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
1602 :
1603 140499 : if (prevStopEdge > stop.edge ||
1604 : // a collision-stop happens after vehicle movement and may move the
1605 : // vehicle backwards on its lane (prevStopPos is the vehicle position)
1606 1880 : (tooClose && !stop.pars.collision)
1607 280958 : || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
1608 : // check if the edge occurs again later in the route
1609 : //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges()) << "\n";
1610 40 : if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
1611 120 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
1612 : }
1613 40 : MSRouteIterator next = stop.edge + 1;
1614 40 : return addStop(stopPar, errorMsg, untilOffset, &next);
1615 : }
1616 140459 : if (wasTooClose) {
1617 : errorMsg = "";
1618 : }
1619 : // David.C:
1620 : //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
1621 140459 : const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
1622 140459 : const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
1623 140459 : if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
1624 : return false;
1625 : }
1626 140459 : if (!hasDeparted() && myCurrEdge == stop.edge) {
1627 : double pos = -1;
1628 26550 : if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
1629 5010 : pos = myParameter->departPos;
1630 5010 : if (pos < 0.) {
1631 219 : pos += (*myCurrEdge)->getLength();
1632 : }
1633 : }
1634 26550 : if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
1635 18312 : pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
1636 : }
1637 26550 : if (pos > stop.pars.endPos + endPosOffset) {
1638 20 : if (stop.edge != myRoute->end()) {
1639 : // check if the edge occurs again later in the route
1640 20 : MSRouteIterator next = stop.edge + 1;
1641 20 : return addStop(stopPar, errorMsg, untilOffset, &next);
1642 : }
1643 0 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
1644 0 : return false;
1645 : }
1646 : }
1647 140439 : if (iter != myStops.begin()) {
1648 : std::list<MSStop>::iterator iter2 = iter;
1649 : iter2--;
1650 96395 : if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
1651 61100 : && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
1652 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1653 18 : + "' set to end at " + time2string(stop.getUntil())
1654 24 : + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
1655 : }
1656 61083 : if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1657 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1658 18 : + "' set to start at " + time2string(stop.pars.arrival)
1659 24 : + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
1660 : }
1661 61083 : if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1662 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1663 18 : + "' set to start at " + time2string(stop.pars.arrival)
1664 24 : + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
1665 : }
1666 : } else {
1667 97186 : if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
1668 79368 : && (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
1669 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1670 18 : + "' set to end at " + time2string(stop.getUntil())
1671 24 : + " earlier than departure at " + time2string(getParameter().depart) + ".";
1672 : }
1673 : }
1674 140439 : if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
1675 18 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1676 54 : + "' set to end at " + time2string(stop.getUntil())
1677 72 : + " earlier than arrival at " + time2string(stop.getArrival()) + ".";
1678 : }
1679 140439 : setSkips(stop, (int)myStops.size());
1680 140439 : myStops.insert(iter, stop);
1681 140439 : if (stopPar.tripId != "") {
1682 2664 : MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
1683 : }
1684 : //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
1685 : // << " routeIndex=" << (stop.edge - myRoute->begin())
1686 : // << " stopIndex=" << std::distance(myStops.begin(), iter)
1687 : // << " route=" << toString(myRoute->getEdges()) << "\n";
1688 : return true;
1689 : }
1690 :
1691 :
1692 : void
1693 190585 : MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
1694 190585 : if (hasDeparted() && stop.edge > myRoute->begin()) {
1695 : // if the route is looped we must patch the index to ensure that state
1696 : // loading (and vehroute-output) encode the correct number of skips
1697 : int foundSkips = 0;
1698 : MSRouteIterator itPrev;
1699 : double prevEndPos;
1700 84953 : if (prevActiveStops > 0) {
1701 : assert((int)myStops.size() >= prevActiveStops);
1702 : auto prevStopIt = myStops.begin();
1703 37031 : std::advance(prevStopIt, prevActiveStops - 1);
1704 : const MSStop& prev = *prevStopIt;
1705 37031 : itPrev = prev.edge;
1706 37031 : prevEndPos = prev.pars.endPos;
1707 47922 : } else if (myPastStops.size() > 0) {
1708 12430 : itPrev = myRoute->begin() + myPastStops.back().routeIndex;
1709 12430 : prevEndPos = myPastStops.back().endPos;
1710 : } else {
1711 35492 : itPrev = myRoute->begin() + myParameter->departEdge;
1712 35492 : prevEndPos = myDepartPos;
1713 : }
1714 : //auto itPrevOrig = itPrev;
1715 84953 : if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
1716 : itPrev++;
1717 : }
1718 : //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
1719 760584 : while (itPrev < stop.edge) {
1720 675631 : if (*itPrev == *stop.edge) {
1721 49724 : foundSkips++;
1722 : }
1723 : itPrev++;
1724 : }
1725 : int newIndex = STOP_INDEX_END;
1726 84953 : if (foundSkips > 0) {
1727 : //if (getID() == "77_0_0") {
1728 : // std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
1729 : // << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
1730 : // << " prevEdge=" << (*itPrevOrig)->getID()
1731 : // << " prevIndex=" << (itPrevOrig - myRoute->begin())
1732 : // << " skips=" << foundSkips << "\n";
1733 : //}
1734 21504 : newIndex = (int)myPastStops.size() + prevActiveStops + foundSkips;
1735 : }
1736 84953 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
1737 : }
1738 190585 : }
1739 :
1740 :
1741 : SUMOTime
1742 681 : MSBaseVehicle::activateRemindersOnReroute(SUMOTime /*currentTime*/) {
1743 3640 : for (int i = 0; i < (int)myMoveReminders.size();) {
1744 2959 : auto rem = &myMoveReminders[i];
1745 2959 : if (rem->first->notifyReroute(*this)) {
1746 : #ifdef _DEBUG
1747 : if (myTraceMoveReminders) {
1748 : traceMoveReminder("notifyReroute", rem->first, rem->second, true);
1749 : }
1750 : #endif
1751 2258 : ++i;
1752 : } else {
1753 : #ifdef _DEBUG
1754 : if (myTraceMoveReminders) {
1755 : traceMoveReminder("notifyReroute", rem->first, rem->second, false);
1756 : }
1757 : #endif
1758 : myMoveReminders.erase(myMoveReminders.begin() + i);
1759 : }
1760 : }
1761 681 : resetApproachOnReroute();
1762 : // event only called once
1763 681 : return 0;
1764 : }
1765 :
1766 :
1767 : void
1768 7023231 : MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
1769 7023231 : if (addRouteStops) {
1770 7028181 : for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
1771 : std::string errorMsg;
1772 9890 : if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
1773 6 : throw ProcessError(errorMsg);
1774 : }
1775 9884 : if (errorMsg != "") {
1776 687 : WRITE_WARNING(errorMsg);
1777 : }
1778 : }
1779 : }
1780 7023225 : const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
1781 7122378 : for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
1782 : std::string errorMsg;
1783 99181 : if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
1784 28 : throw ProcessError(errorMsg);
1785 : }
1786 99153 : if (errorMsg != "") {
1787 463 : WRITE_WARNING(errorMsg);
1788 : }
1789 : }
1790 7023197 : }
1791 :
1792 :
1793 : bool
1794 1512568 : MSBaseVehicle::haveValidStopEdges(bool silent) const {
1795 1512568 : MSRouteIterator start = myCurrEdge;
1796 : int i = 0;
1797 : bool ok = true;
1798 1540784 : for (const MSStop& stop : myStops) {
1799 : MSRouteIterator it;
1800 28216 : if (stop.lane->isInternal()) {
1801 : // find the normal predecessor and ensure that the next route edge
1802 : // matches the successor of the internal edge successor
1803 0 : it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
1804 0 : if (it != myRoute->end() && (
1805 0 : it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
1806 0 : it = myRoute->end(); // signal failure
1807 : }
1808 : } else {
1809 28216 : it = std::find(start, myRoute->end(), &stop.lane->getEdge());
1810 : }
1811 28216 : if (it == myRoute->end()) {
1812 0 : if (!silent) {
1813 0 : WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
1814 : i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1815 : }
1816 : ok = false;
1817 : } else {
1818 : MSRouteIterator it2;
1819 1179807 : for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
1820 1170354 : if (it2 == stop.edge) {
1821 : break;
1822 : }
1823 : }
1824 28216 : if (it2 == myRoute->end()) {
1825 9453 : if (!silent) {
1826 0 : WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
1827 : i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
1828 : }
1829 : ok = false;
1830 18763 : } else if (it2 < start) {
1831 0 : if (!silent) {
1832 0 : WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
1833 : i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1834 : }
1835 : ok = false;
1836 : } else {
1837 18763 : start = stop.edge;
1838 : }
1839 : }
1840 28216 : i++;
1841 : }
1842 1512568 : return ok;
1843 : }
1844 :
1845 :
1846 : std::vector<MSBaseVehicle::StopEdgeInfo>
1847 3119083 : MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
1848 : assert(haveValidStopEdges());
1849 : std::vector<StopEdgeInfo> result;
1850 : const MSStop* prev = nullptr;
1851 : const MSEdge* internalSuccessor = nullptr;
1852 3215408 : for (const MSStop& stop : myStops) {
1853 96325 : if (stop.reached) {
1854 9737 : if (stop.pars.jump >= 0) {
1855 0 : jumps.insert((int)result.size());
1856 : }
1857 9737 : continue;
1858 : }
1859 86588 : double stopPos = stop.getEndPos(*this);
1860 : if ((prev == nullptr
1861 45882 : || prev->edge != stop.edge
1862 1260 : || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
1863 131210 : && *stop.edge != internalSuccessor) {
1864 85328 : if (stop.lane->isInternal()) {
1865 9 : stopPos = (*stop.edge)->getLength();
1866 : }
1867 85328 : result.push_back(StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stopPos));
1868 85328 : result.back().nameTag = stop.getStoppingPlaceName();
1869 85328 : result.back().stopPar = &stop.pars;
1870 85328 : if (stop.lane->isInternal()) {
1871 9 : internalSuccessor = stop.lane->getNextNormal();
1872 18 : result.push_back(StopEdgeInfo(internalSuccessor, stop.pars.priority, stop.getArrivalFallback(), 0));
1873 : } else {
1874 : internalSuccessor = nullptr;
1875 : }
1876 1260 : } else if (prev != nullptr && prev->edge == stop.edge) {
1877 1260 : result.back().priority = addStopPriority(result.back().priority, stop.pars.priority);
1878 : }
1879 : prev = &stop;
1880 86588 : if (firstPos == INVALID_DOUBLE) {
1881 40706 : if (stop.parkingarea != nullptr) {
1882 5091 : firstPos = MAX2(0., stopPos);
1883 : } else {
1884 35615 : firstPos = stopPos;
1885 : }
1886 : }
1887 86588 : lastPos = stopPos;
1888 86588 : if (stop.pars.jump >= 0) {
1889 1208 : jumps.insert((int)result.size() - 1);
1890 : }
1891 : }
1892 : //std::cout << SIMTIME << " getStopEdges veh=" << getID() << "\n";
1893 : //for (auto item : result) {
1894 : // std::cout << " e=" << item.edge->getID() << " pos=" << item.pos << "\n";
1895 : //}
1896 3119083 : return result;
1897 0 : }
1898 :
1899 :
1900 : double
1901 2147 : MSBaseVehicle::addStopPriority(double p1, double p2) {
1902 2147 : if (p1 < 0 || p2 < 0) {
1903 : return p1;
1904 : }
1905 0 : return p1 + p2;
1906 : }
1907 :
1908 : std::vector<std::pair<int, double> >
1909 41277 : MSBaseVehicle::getStopIndices() const {
1910 : std::vector<std::pair<int, double> > result;
1911 83567 : for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
1912 84580 : result.push_back(std::make_pair(
1913 42290 : (int)(iter->edge - myRoute->begin()),
1914 42290 : iter->getEndPos(*this)));
1915 : }
1916 41277 : return result;
1917 0 : }
1918 :
1919 :
1920 : const MSStop&
1921 15757233 : MSBaseVehicle::getNextStop() const {
1922 : assert(myStops.size() > 0);
1923 15757233 : return myStops.front();
1924 : }
1925 :
1926 : MSStop&
1927 95422 : MSBaseVehicle::getNextStopMutable() {
1928 : assert(myStops.size() > 0);
1929 95422 : return myStops.front();
1930 : }
1931 :
1932 : SUMOTime
1933 3648889 : MSBaseVehicle::getStopDuration() const {
1934 3648889 : if (isStopped()) {
1935 1181964 : return myStops.front().duration;
1936 : } else {
1937 : return 0;
1938 : }
1939 : }
1940 :
1941 :
1942 : MSStop&
1943 325198 : MSBaseVehicle::getStop(int nextStopIndex) {
1944 325198 : if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
1945 0 : throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
1946 : }
1947 : auto stopIt = myStops.begin();
1948 : std::advance(stopIt, nextStopIndex);
1949 325198 : return *stopIt;
1950 : }
1951 :
1952 :
1953 : const SUMOVehicleParameter::Stop*
1954 257664 : MSBaseVehicle::getNextStopParameter() const {
1955 257664 : if (hasStops()) {
1956 115903 : return &myStops.front().pars;
1957 : }
1958 : return nullptr;
1959 : }
1960 :
1961 :
1962 : bool
1963 45938 : MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
1964 : //if the stop exists update the duration
1965 71186 : for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
1966 47861 : if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
1967 : // update existing stop
1968 22613 : if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
1969 21144 : myStops.erase(iter);
1970 : } else {
1971 1469 : iter->duration = stop.duration;
1972 1469 : iter->triggered = stop.triggered;
1973 1469 : iter->containerTriggered = stop.containerTriggered;
1974 1469 : const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
1975 1469 : const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
1976 : }
1977 : return true;
1978 : }
1979 : }
1980 23325 : const bool result = addStop(stop, errorMsg);
1981 23325 : if (result) {
1982 : /// XXX handle stops added out of order
1983 23302 : myParameter->stops.push_back(stop);
1984 : }
1985 : return result;
1986 : }
1987 :
1988 :
1989 : void
1990 748 : MSBaseVehicle::unregisterWaiting() {
1991 748 : if (myAmRegisteredAsWaiting) {
1992 548 : MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
1993 548 : myAmRegisteredAsWaiting = false;
1994 : }
1995 748 : }
1996 :
1997 :
1998 : bool
1999 1642 : MSBaseVehicle::abortNextStop(int nextStopIndex) {
2000 1642 : if (hasStops() && nextStopIndex < (int)myStops.size()) {
2001 1642 : if (nextStopIndex == 0 && isStopped()) {
2002 700 : resumeFromStopping();
2003 : } else {
2004 : auto stopIt = myStops.begin();
2005 : std::advance(stopIt, nextStopIndex);
2006 942 : if (stopIt->parkingarea != nullptr && stopIt->parkingarea->isReservable()) {
2007 0 : stopIt->parkingarea->removeSpaceReservation(this);
2008 : }
2009 942 : myStops.erase(stopIt);
2010 : }
2011 1642 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
2012 : // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
2013 : auto stopIt2 = myParameter->stops.begin();
2014 : std::advance(stopIt2, nextStopIndex);
2015 8 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
2016 : }
2017 1642 : return true;
2018 : } else {
2019 : return false;
2020 : }
2021 : }
2022 :
2023 :
2024 : bool
2025 147 : MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
2026 147 : const int n = (int)myStops.size();
2027 147 : if (nextStopIndex < 0 || nextStopIndex >= n) {
2028 5 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
2029 5 : return false;
2030 : }
2031 142 : if (nextStopIndex == 0 && isStopped()) {
2032 6 : errorMsg = TL("cannot replace reached stop");
2033 6 : return false;
2034 : }
2035 136 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
2036 136 : MSLane* stopLane = MSLane::dictionary(stop.lane);
2037 136 : MSEdge* stopEdge = &stopLane->getEdge();
2038 :
2039 : auto itStop = myStops.begin();
2040 : std::advance(itStop, nextStopIndex);
2041 : MSStop& replacedStop = *itStop;
2042 :
2043 : // check parking access rights
2044 136 : if (stop.parkingarea != "") {
2045 0 : MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
2046 0 : if (pa != nullptr && !pa->accepts(this)) {
2047 0 : errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
2048 0 : return false;
2049 : }
2050 : }
2051 :
2052 136 : if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
2053 : // only replace stop attributes
2054 10 : const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
2055 10 : replacedStop.initPars(stop);
2056 10 : return true;
2057 : }
2058 :
2059 126 : if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
2060 0 : errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
2061 0 : return false;
2062 : }
2063 :
2064 126 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
2065 126 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
2066 126 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
2067 126 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
2068 126 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
2069 126 : MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
2070 126 : auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
2071 126 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2072 :
2073 126 : bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
2074 :
2075 : ConstMSEdgeVector toNewStop;
2076 126 : if (!teleport) {
2077 98 : router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
2078 98 : if (toNewStop.size() == 0) {
2079 15 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
2080 5 : return false;
2081 : }
2082 : }
2083 :
2084 : ConstMSEdgeVector fromNewStop;
2085 121 : if (!newDestination) {
2086 116 : router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
2087 116 : if (fromNewStop.size() == 0) {
2088 0 : errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
2089 0 : return false;
2090 : }
2091 : }
2092 :
2093 121 : cleanupParkingReservation();
2094 121 : const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
2095 121 : replacedStop.initPars(stop);
2096 121 : replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
2097 121 : replacedStop.lane = stopLane;
2098 121 : if (MSGlobals::gUseMesoSim) {
2099 21 : replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
2100 21 : if (replacedStop.lane->isInternal()) {
2101 0 : errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
2102 0 : return false;
2103 : }
2104 : }
2105 :
2106 121 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2107 : ConstMSEdgeVector newEdges; // only remaining
2108 121 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2109 121 : if (!teleport) {
2110 93 : newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
2111 : } else {
2112 28 : newEdges.push_back(*itStart);
2113 : }
2114 121 : if (!newDestination) {
2115 116 : newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
2116 116 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2117 : } else {
2118 5 : newEdges.push_back(stopEdge);
2119 : }
2120 : //std::cout << SIMTIME << " replaceStop veh=" << getID()
2121 : // << " teleport=" << teleport
2122 : // << " busStop=" << stop.busstop
2123 : // << " oldEdges=" << oldRemainingEdges.size()
2124 : // << " newEdges=" << newEdges.size()
2125 : // << " toNewStop=" << toNewStop.size()
2126 : // << " fromNewStop=" << fromNewStop.size()
2127 : // << "\n";
2128 :
2129 121 : const double routeCost = router.recomputeCosts(newEdges, this, t);
2130 121 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2131 121 : const double savings = previousCost - routeCost;
2132 121 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
2133 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
2134 5 : const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
2135 : }
2136 121 : if (teleport) {
2137 : // let the vehicle jump rather than teleport
2138 : // we add a jump-stop at the end of the edge (unless the vehicle is
2139 : // already configure to jump before the replaced stop)
2140 28 : if (!insertJump(nextStopIndex, itStart, errorMsg)) {
2141 : return false;
2142 : };
2143 : }
2144 121 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2145 126 : }
2146 :
2147 :
2148 : bool
2149 52 : MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
2150 52 : const int n = (int)myStops.size();
2151 52 : if (nextStopIndex < 0 || nextStopIndex > n) {
2152 0 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
2153 0 : return false;
2154 : }
2155 52 : if (nextStopIndex == 0 && isStopped()) {
2156 0 : errorMsg = TL("cannot reroute towards reached stop");
2157 0 : return false;
2158 : }
2159 52 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
2160 :
2161 52 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
2162 52 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
2163 52 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
2164 52 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
2165 52 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
2166 52 : MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
2167 52 : auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
2168 52 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2169 :
2170 : ConstMSEdgeVector newBetween;
2171 52 : if (!teleport) {
2172 15 : router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
2173 15 : if (newBetween.size() == 0) {
2174 0 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
2175 0 : return false;
2176 : }
2177 : }
2178 :
2179 52 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2180 : ConstMSEdgeVector newEdges; // only remaining
2181 52 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2182 52 : if (!teleport) {
2183 15 : newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
2184 : } else {
2185 37 : newEdges.push_back(*itStart);
2186 : }
2187 52 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2188 : //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
2189 : // << " oldEdges=" << oldRemainingEdges.size()
2190 : // << " newEdges=" << newEdges.size()
2191 : // << " toNewStop=" << toNewStop.size()
2192 : // << " fromNewStop=" << fromNewStop.size()
2193 : // << "\n";
2194 :
2195 52 : const double routeCost = router.recomputeCosts(newEdges, this, t);
2196 52 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2197 52 : const double savings = previousCost - routeCost;
2198 :
2199 52 : if (teleport) {
2200 : // let the vehicle jump rather than teleport
2201 : // we add a jump-stop at the end of the edge (unless the vehicle is
2202 : // already configure to jump before the replaced stop)
2203 37 : if (!insertJump(nextStopIndex, itStart, errorMsg)) {
2204 : return false;
2205 : };
2206 : }
2207 52 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2208 52 : }
2209 :
2210 :
2211 : bool
2212 65 : MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
2213 : bool needJump = true;
2214 65 : if (nextStopIndex > 0) {
2215 : auto itPriorStop = myStops.begin();
2216 47 : std::advance(itPriorStop, nextStopIndex - 1);
2217 : const MSStop& priorStop = *itPriorStop;
2218 47 : if (priorStop.pars.jump >= 0) {
2219 : needJump = false;
2220 : }
2221 : }
2222 : if (needJump) {
2223 47 : SUMOVehicleParameter::Stop jumpStopPars;
2224 47 : jumpStopPars.endPos = (*itStart)->getLength();
2225 47 : jumpStopPars.speed = 1000;
2226 47 : jumpStopPars.jump = 0;
2227 : jumpStopPars.edge = (*itStart)->getID();
2228 47 : jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
2229 : MSLane* jumpStopLane = nullptr;
2230 47 : for (MSLane* cand : (*itStart)->getLanes()) {
2231 47 : if (cand->allowsVehicleClass(getVClass())) {
2232 : jumpStopLane = cand;
2233 : break;
2234 : }
2235 : }
2236 47 : if (jumpStopLane == nullptr) {
2237 0 : errorMsg = TL("unable to replace stop with teleporting");
2238 : return false;
2239 : }
2240 : auto itStop = myStops.begin();
2241 : std::advance(itStop, nextStopIndex);
2242 47 : MSStop jumpStop(jumpStopPars);
2243 47 : jumpStop.initPars(jumpStopPars);
2244 47 : jumpStop.lane = jumpStopLane;
2245 47 : jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
2246 47 : myStops.insert(itStop, jumpStop);
2247 47 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
2248 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
2249 : auto it = myParameter->stops.begin() + nextStopIndex;
2250 0 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
2251 : }
2252 47 : }
2253 : return true;
2254 : }
2255 :
2256 :
2257 : bool
2258 894 : MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
2259 894 : const int n = (int)myStops.size();
2260 894 : if (nextStopIndex < 0 || nextStopIndex > n) {
2261 5 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
2262 5 : return false;
2263 : }
2264 889 : if (nextStopIndex == 0 && isStopped()) {
2265 7 : errorMsg = TL("cannot insert stop before the currently reached stop");
2266 7 : return false;
2267 : }
2268 882 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
2269 882 : MSLane* stopLane = MSLane::dictionary(stop.lane);
2270 882 : MSEdge* stopEdge = &stopLane->getEdge();
2271 :
2272 882 : if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
2273 0 : errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
2274 0 : return false;
2275 : }
2276 :
2277 : // check parking access rights
2278 882 : if (stop.parkingarea != "") {
2279 570 : MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
2280 570 : if (pa != nullptr && !pa->accepts(this)) {
2281 0 : errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
2282 0 : return false;
2283 : }
2284 : }
2285 :
2286 882 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
2287 882 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
2288 1549 : const int junctionOffset = ((getLane() != nullptr && getLane()->isInternal())
2289 1545 : || getRerouteOrigin() != getCurrentRouteEdge()) ? 1 : 0;
2290 882 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
2291 882 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
2292 882 : MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
2293 882 : auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
2294 882 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2295 :
2296 882 : const bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
2297 882 : const bool needLoop = nextStopIndex > 0 && *itStart == stopEdge && startPos >= stop.endPos;
2298 103 : if (needLoop && startPos == stop.endPos) {
2299 : // assume that two stops at the same position indicate a looped route
2300 95 : startPos += POSITION_EPS;
2301 95 : stop.index = STOP_INDEX_REPEAT;
2302 787 : } else if (!hasDeparted()) {
2303 50 : stop.index = STOP_INDEX_END;
2304 : }
2305 :
2306 : MSRouteIterator itSentintel = itEnd + 1;
2307 882 : MSRouteIterator onRouteStart = itStart + (needLoop ? 1 : 0);
2308 882 : const bool onRoute = std::find(onRouteStart, itSentintel, stopEdge) != itSentintel;
2309 882 : if (onRoute) {
2310 370 : if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
2311 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
2312 : auto it = myParameter->stops.begin() + nextStopIndex;
2313 20 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
2314 : }
2315 370 : const bool ok = addStop(stop, errorMsg, 0, &onRouteStart);
2316 370 : if (ok) {
2317 368 : updateBestLanes(true, !hasDeparted() ? (*myCurrEdge)->getLanes().front() : 0);
2318 : }
2319 370 : return ok;
2320 : }
2321 :
2322 : ConstMSEdgeVector toNewStop;
2323 512 : if (!teleport) {
2324 484 : router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
2325 484 : if (toNewStop.size() == 0) {
2326 15 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
2327 5 : return false;
2328 : }
2329 : }
2330 :
2331 : ConstMSEdgeVector fromNewStop;
2332 507 : if (!newDestination) {
2333 447 : router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
2334 447 : if (fromNewStop.size() == 0) {
2335 0 : errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
2336 0 : return false;
2337 : }
2338 : }
2339 :
2340 : auto itStop = myStops.begin();
2341 : std::advance(itStop, nextStopIndex);
2342 507 : MSStop newStop(stop);
2343 507 : newStop.initPars(stop);
2344 507 : newStop.edge = myRoute->end(); // will be patched in replaceRoute
2345 507 : newStop.lane = stopLane;
2346 507 : if (MSGlobals::gUseMesoSim) {
2347 124 : newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
2348 124 : if (newStop.lane->isInternal()) {
2349 0 : errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
2350 0 : return false;
2351 : }
2352 : }
2353 507 : myStops.insert(itStop, newStop);
2354 :
2355 507 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2356 : ConstMSEdgeVector newEdges; // only remaining
2357 507 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2358 507 : if (!teleport) {
2359 479 : newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
2360 : } else {
2361 28 : newEdges.push_back(*itStart);
2362 : }
2363 507 : if (!newDestination) {
2364 447 : newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
2365 447 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2366 : } else {
2367 60 : newEdges.push_back(stopEdge);
2368 : }
2369 : //std::cout << SIMTIME << " insertStop veh=" << getID()
2370 : // << " teleport=" << teleport
2371 : // << " busStop=" << stop.busstop
2372 : // << " oldEdges=" << oldRemainingEdges.size()
2373 : // << " newEdges=" << newEdges.size()
2374 : // << " toNewStop=" << toNewStop.size()
2375 : // << " fromNewStop=" << fromNewStop.size()
2376 : // << "\n";
2377 :
2378 507 : const double routeCost = router.recomputeCosts(newEdges, this, t);
2379 507 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2380 507 : const double savings = previousCost - routeCost;
2381 :
2382 507 : if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
2383 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
2384 : auto it = myParameter->stops.begin() + nextStopIndex;
2385 40 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
2386 : }
2387 507 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2388 1389 : }
2389 :
2390 :
2391 : EnergyParams*
2392 106235797 : MSBaseVehicle::getEmissionParameters() const {
2393 106235797 : if (myEnergyParams == nullptr) {
2394 1065715 : myEnergyParams = new EnergyParams(getVehicleType().getEmissionParameters());
2395 : double tMass = 0;
2396 1065715 : if (myPersonDevice != nullptr) {
2397 16 : for (MSTransportable* t : myPersonDevice->getTransportables()) {
2398 16 : tMass += t->getVehicleType().getMass();
2399 : }
2400 : }
2401 1065715 : if (myContainerDevice != nullptr) {
2402 0 : for (MSTransportable* t : myContainerDevice->getTransportables()) {
2403 0 : tMass += t->getVehicleType().getMass();
2404 : }
2405 : }
2406 1065715 : myEnergyParams->setTransportableMass(tMass);
2407 : }
2408 106235797 : return myEnergyParams;
2409 : }
2410 :
2411 :
2412 : double
2413 0 : MSBaseVehicle::getStateOfCharge() const {
2414 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2415 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2416 0 : return batteryOfVehicle->getActualBatteryCapacity();
2417 : } else {
2418 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2419 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2420 0 : return batteryOfVehicle->getActualBatteryCapacity();
2421 : }
2422 : }
2423 : return -1;
2424 : }
2425 :
2426 :
2427 : double
2428 0 : MSBaseVehicle::getRelativeStateOfCharge() const {
2429 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2430 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2431 0 : return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2432 : } else {
2433 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2434 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2435 0 : return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2436 : }
2437 : }
2438 : return -1;
2439 : }
2440 :
2441 :
2442 : double
2443 0 : MSBaseVehicle::getChargedEnergy() const {
2444 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2445 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2446 0 : return batteryOfVehicle->getEnergyCharged();
2447 : } else {
2448 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2449 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2450 0 : return batteryOfVehicle->getEnergyCharged();
2451 : }
2452 : }
2453 : return -1;
2454 : }
2455 :
2456 :
2457 : double
2458 0 : MSBaseVehicle::getMaxChargeRate() const {
2459 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2460 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2461 0 : return batteryOfVehicle->getMaximumChargeRate();
2462 : }
2463 : return -1;
2464 : }
2465 :
2466 :
2467 : double
2468 0 : MSBaseVehicle::getElecHybridCurrent() const {
2469 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2470 0 : MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2471 0 : return elecHybridDevice->getCurrentFromOverheadWire();
2472 : }
2473 :
2474 : return NAN;
2475 : }
2476 :
2477 : double
2478 768 : MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
2479 768 : if (isOnRoad() || isIdling()) {
2480 768 : return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
2481 : } else {
2482 : return 0.;
2483 : }
2484 : }
2485 :
2486 :
2487 : const MSEdgeWeightsStorage&
2488 6749799 : MSBaseVehicle::getWeightsStorage() const {
2489 6749799 : return _getWeightsStorage();
2490 : }
2491 :
2492 :
2493 : MSEdgeWeightsStorage&
2494 670 : MSBaseVehicle::getWeightsStorage() {
2495 670 : return _getWeightsStorage();
2496 : }
2497 :
2498 :
2499 : MSEdgeWeightsStorage&
2500 6750469 : MSBaseVehicle::_getWeightsStorage() const {
2501 6750469 : if (myEdgeWeights == nullptr) {
2502 13829 : myEdgeWeights = new MSEdgeWeightsStorage();
2503 : }
2504 6750469 : return *myEdgeWeights;
2505 : }
2506 :
2507 :
2508 :
2509 :
2510 : int
2511 10582279 : MSBaseVehicle::getPersonNumber() const {
2512 10582279 : int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
2513 10582279 : return boarded + myParameter->personNumber;
2514 : }
2515 :
2516 : int
2517 0 : MSBaseVehicle::getLeavingPersonNumber() const {
2518 : int leavingPersonNumber = 0;
2519 0 : const std::vector<MSTransportable*>& persons = getPersons();
2520 0 : for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2521 0 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
2522 : const MSStop* stop = &myStops.front();
2523 0 : const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
2524 0 : if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
2525 0 : leavingPersonNumber++;
2526 : }
2527 : }
2528 0 : return leavingPersonNumber;
2529 : }
2530 :
2531 : std::vector<std::string>
2532 196 : MSBaseVehicle::getPersonIDList() const {
2533 : std::vector<std::string> ret;
2534 196 : const std::vector<MSTransportable*>& persons = getPersons();
2535 671 : for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2536 475 : ret.push_back((*it_p)->getID());
2537 : }
2538 196 : return ret;
2539 0 : }
2540 :
2541 : int
2542 8198107 : MSBaseVehicle::getContainerNumber() const {
2543 8198107 : int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
2544 8198107 : return loaded + myParameter->containerNumber;
2545 : }
2546 :
2547 :
2548 : void
2549 166 : MSBaseVehicle::removeTransportable(MSTransportable* t) {
2550 : // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
2551 166 : if (myPersonDevice != nullptr) {
2552 146 : myPersonDevice->removeTransportable(t);
2553 : }
2554 166 : if (myContainerDevice != nullptr) {
2555 20 : myContainerDevice->removeTransportable(t);
2556 : }
2557 166 : if (myEnergyParams != nullptr) {
2558 86 : myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
2559 : }
2560 166 : }
2561 :
2562 :
2563 : void
2564 9478 : MSBaseVehicle::removeTransportableMass(MSTransportable* t) {
2565 9478 : if (myEnergyParams != nullptr) {
2566 6166 : myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
2567 : }
2568 9478 : }
2569 :
2570 :
2571 : const std::vector<MSTransportable*>&
2572 8172122 : MSBaseVehicle::getPersons() const {
2573 8172122 : if (myPersonDevice == nullptr) {
2574 : return myEmptyTransportableVector;
2575 : } else {
2576 13875 : return myPersonDevice->getTransportables();
2577 : }
2578 : }
2579 :
2580 :
2581 : const std::vector<MSTransportable*>&
2582 6918914 : MSBaseVehicle::getContainers() const {
2583 6918914 : if (myContainerDevice == nullptr) {
2584 : return myEmptyTransportableVector;
2585 : } else {
2586 3368 : return myContainerDevice->getTransportables();
2587 : }
2588 : }
2589 :
2590 :
2591 : bool
2592 210 : MSBaseVehicle::isLineStop(double position) const {
2593 210 : if (myParameter->line == "") {
2594 : // not a public transport line
2595 : return false;
2596 : }
2597 362 : for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
2598 215 : if (stop.startPos <= position && position <= stop.endPos) {
2599 : return true;
2600 : }
2601 : }
2602 174 : for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
2603 38 : if (stop.startPos <= position && position <= stop.endPos) {
2604 : return true;
2605 : }
2606 : }
2607 : return false;
2608 : }
2609 :
2610 :
2611 : bool
2612 45 : MSBaseVehicle::hasDevice(const std::string& deviceName) const {
2613 144 : for (MSDevice* const dev : myDevices) {
2614 126 : if (dev->deviceName() == deviceName) {
2615 : return true;
2616 : }
2617 : }
2618 : return false;
2619 : }
2620 :
2621 :
2622 : void
2623 9 : MSBaseVehicle::createDevice(const std::string& deviceName) {
2624 9 : if (!hasDevice(deviceName)) {
2625 9 : if (deviceName == "rerouting") {
2626 27 : ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
2627 9 : MSDevice_Routing::buildVehicleDevices(*this, myDevices);
2628 9 : if (hasDeparted()) {
2629 : // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
2630 0 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
2631 : assert(routingDevice != 0);
2632 0 : routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
2633 : }
2634 : } else {
2635 0 : throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
2636 : }
2637 : }
2638 9 : }
2639 :
2640 :
2641 : std::string
2642 50018 : MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
2643 59494 : for (MSVehicleDevice* const dev : myDevices) {
2644 59485 : if (dev->deviceName() == deviceName) {
2645 50009 : return dev->getParameter(key);
2646 : }
2647 : }
2648 27 : throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2649 : }
2650 :
2651 :
2652 : void
2653 208 : MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
2654 355 : for (MSVehicleDevice* const dev : myDevices) {
2655 355 : if (dev->deviceName() == deviceName) {
2656 208 : dev->setParameter(key, value);
2657 208 : return;
2658 : }
2659 : }
2660 0 : throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2661 : }
2662 :
2663 :
2664 : void
2665 842 : MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
2666 1669 : if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
2667 837 : getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
2668 837 : const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2669 : // checked in MSLink::ignoreFoe
2670 : } else {
2671 15 : throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
2672 : }
2673 837 : }
2674 :
2675 :
2676 : void
2677 33 : MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
2678 : // handle some generic params first and then delegate to the carFollowModel itself
2679 57 : if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
2680 17 : getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
2681 17 : const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2682 : // checked in MSVehicle::planMove
2683 : } else {
2684 16 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
2685 16 : if (microVeh) {
2686 : // remove 'carFollowModel.' prefix
2687 16 : const std::string attrName = key.substr(15);
2688 16 : microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
2689 : }
2690 : }
2691 29 : }
2692 :
2693 :
2694 : void
2695 5557086 : MSBaseVehicle::initTransientModelParams() {
2696 : /* Design idea for additional junction model parameters:
2697 : We can distinguish between 3 levels of parameters
2698 : 1. typically shared by multiple vehicles -> vType parameter
2699 : 2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
2700 : 3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
2701 : */
2702 5830475 : for (auto item : getParameter().getParametersMap()) {
2703 546778 : if (StringUtils::startsWith(item.first, "junctionModel.")) {
2704 832 : setJunctionModelParameter(item.first, item.second);
2705 545114 : } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
2706 17 : setCarFollowModelParameter(item.first, item.second);
2707 : }
2708 : }
2709 11114172 : const std::string routingModeStr = getStringParam("device.rerouting.mode");
2710 : try {
2711 5557086 : int routingMode = StringUtils::toInt(routingModeStr);
2712 5557086 : if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
2713 : setRoutingMode(routingMode);
2714 : }
2715 0 : } catch (NumberFormatException&) {
2716 : // @todo interpret symbolic constants
2717 0 : throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
2718 0 : }
2719 5557086 : }
2720 :
2721 :
2722 : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
2723 23575 : MSBaseVehicle::getRouterTT() const {
2724 23575 : if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
2725 204 : return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
2726 : } else {
2727 46946 : return MSNet::getInstance()->getRouterTT(getRNGIndex());
2728 : }
2729 : }
2730 :
2731 :
2732 : void
2733 30684 : MSBaseVehicle::replaceVehicleType(const MSVehicleType* type) {
2734 : assert(type != nullptr);
2735 : // save old parameters before possible type deletion
2736 30684 : const double oldMu = myType->getSpeedFactor().getParameter(0);
2737 : const double oldDev = myType->getSpeedFactor().getParameter(1);
2738 30684 : if (myType->isVehicleSpecific() && type != myType) {
2739 936 : MSNet::getInstance()->getVehicleControl().removeVType(myType);
2740 : }
2741 : // adapt myChosenSpeedFactor to the new type
2742 30684 : if (oldDev == 0.) {
2743 : // old type had speedDev 0, reroll
2744 22805 : myChosenSpeedFactor = type->computeChosenSpeedDeviation(getRNG());
2745 : } else {
2746 : // map old speedFactor onto new distribution
2747 7879 : const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
2748 : const double newMu = type->getSpeedFactor().getParameter(0);
2749 : const double newDev = type->getSpeedFactor().getParameter(1);
2750 7879 : myChosenSpeedFactor = newMu + distPoint * newDev;
2751 : // respect distribution limits
2752 7879 : myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
2753 7884 : myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
2754 : }
2755 30684 : myType = type;
2756 30684 : if (myEnergyParams != nullptr) {
2757 : myEnergyParams->setSecondary(type->getEmissionParameters());
2758 : }
2759 30684 : }
2760 :
2761 :
2762 : MSVehicleType&
2763 145089 : MSBaseVehicle::getSingularType() {
2764 145089 : if (myType->isVehicleSpecific()) {
2765 : return *const_cast<MSVehicleType*>(myType);
2766 : }
2767 2536 : MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
2768 1268 : replaceVehicleType(type);
2769 1268 : return *type;
2770 : }
2771 :
2772 :
2773 : int
2774 892061 : MSBaseVehicle::getRNGIndex() const {
2775 892061 : const MSLane* const lane = getLane();
2776 892061 : if (lane == nullptr) {
2777 18454 : return getEdge()->getLanes()[0]->getRNGIndex();
2778 : } else {
2779 873607 : return lane->getRNGIndex();
2780 : }
2781 : }
2782 :
2783 :
2784 : SumoRNG*
2785 752182058 : MSBaseVehicle::getRNG() const {
2786 752182058 : const MSLane* lane = getLane();
2787 752182058 : if (lane == nullptr) {
2788 7084 : return getEdge()->getLanes()[0]->getRNG();
2789 : } else {
2790 752174974 : return lane->getRNG();
2791 : }
2792 : }
2793 :
2794 : std::string
2795 68863 : MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
2796 68863 : const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
2797 137726 : if (StringUtils::startsWith(key, "device.")) {
2798 150054 : StringTokenizer tok(key, ".");
2799 50018 : if (tok.size() < 3) {
2800 0 : error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
2801 0 : return "";
2802 : }
2803 : try {
2804 150054 : return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
2805 18 : } catch (InvalidArgument& e) {
2806 54 : error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
2807 18 : return "";
2808 18 : }
2809 87708 : } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
2810 324 : if (microVeh == nullptr) {
2811 40 : error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
2812 20 : return "";
2813 : }
2814 304 : const std::string attrName = key.substr(16);
2815 : try {
2816 304 : return microVeh->getLaneChangeModel().getParameter(attrName);
2817 44 : } catch (InvalidArgument& e) {
2818 132 : error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
2819 44 : return "";
2820 44 : }
2821 37042 : } else if (StringUtils::startsWith(key, "carFollowModel.")) {
2822 12 : if (microVeh == nullptr) {
2823 0 : error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
2824 0 : return "";
2825 : }
2826 12 : const std::string attrName = key.substr(15);
2827 : try {
2828 12 : return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
2829 0 : } catch (InvalidArgument& e) {
2830 0 : error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
2831 0 : return "";
2832 0 : }
2833 18545 : } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
2834 108 : StringTokenizer tok(key, ".");
2835 36 : if (tok.size() != 3) {
2836 0 : error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
2837 0 : return "";
2838 : }
2839 81 : return hasDevice(tok.get(1)) ? "true" : "false";
2840 : // parking related parameters start here
2841 18509 : } else if (key == "parking.rerouteCount") {
2842 15 : return toString(getNumberParkingReroutes());
2843 36916 : } else if (StringUtils::startsWith(key, "parking.memory.")) {
2844 : std::vector<std::string> values;
2845 65 : if (getParkingMemory()) {
2846 20 : if (key == "parking.memory.IDList") {
2847 24 : for (const auto& item : *getParkingMemory()) {
2848 20 : values.push_back(item.first->getID());
2849 : }
2850 16 : } else if (key == "parking.memory.score") {
2851 24 : for (const auto& item : *getParkingMemory()) {
2852 20 : values.push_back(item.second.score);
2853 : }
2854 12 : } else if (key == "parking.memory.blockedAtTime") {
2855 24 : for (const auto& item : *getParkingMemory()) {
2856 40 : values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
2857 : }
2858 8 : } else if (key == "parking.memory.blockedAtTimeLocal") {
2859 24 : for (const auto& item : *getParkingMemory()) {
2860 40 : values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
2861 : }
2862 : } else {
2863 8 : error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
2864 : }
2865 : }
2866 65 : return toString(values);
2867 65 : } else {
2868 : // default: custom user parameter
2869 36786 : return getParameter().getParameter(key, "");
2870 : }
2871 : }
2872 :
2873 :
2874 : void
2875 88992 : MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
2876 88992 : if (myParkingMemory == nullptr) {
2877 0 : myParkingMemory = new StoppingPlaceMemory();
2878 : }
2879 88992 : myParkingMemory->rememberBlockedStoppingPlace(pa, local);
2880 88992 : }
2881 :
2882 :
2883 : void
2884 29684 : MSBaseVehicle::resetParkingAreaScores() {
2885 29684 : if (myParkingMemory != nullptr) {
2886 27856 : myParkingMemory->resetStoppingPlaceScores();
2887 : }
2888 29684 : }
2889 :
2890 :
2891 : void
2892 360 : MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
2893 360 : if (myChargingMemory == nullptr) {
2894 80 : myChargingMemory = new StoppingPlaceMemory();
2895 : }
2896 360 : myChargingMemory->rememberStoppingPlaceScore(cs, score);
2897 360 : }
2898 :
2899 :
2900 : void
2901 127 : MSBaseVehicle::resetChargingStationScores() {
2902 127 : if (myChargingMemory != nullptr) {
2903 11 : myChargingMemory->resetStoppingPlaceScores();
2904 : }
2905 127 : }
2906 :
2907 :
2908 : void
2909 131687 : MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
2910 131687 : if (myParkingMemory == nullptr) {
2911 2330 : myParkingMemory = new StoppingPlaceMemory();
2912 : }
2913 131687 : myParkingMemory->rememberStoppingPlaceScore(pa, score);
2914 131687 : }
2915 :
2916 :
2917 : SUMOTime
2918 71984 : MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
2919 71984 : if (myParkingMemory == nullptr) {
2920 : return -1;
2921 : }
2922 71960 : return myParkingMemory->sawBlockedStoppingPlace(pa, local);
2923 : }
2924 :
2925 :
2926 0 : void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
2927 0 : if (myChargingMemory == nullptr) {
2928 0 : myChargingMemory = new StoppingPlaceMemory();
2929 : }
2930 0 : myChargingMemory->rememberBlockedStoppingPlace(cs, local);
2931 0 : }
2932 :
2933 :
2934 : SUMOTime
2935 548 : MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
2936 548 : if (myChargingMemory == nullptr) {
2937 : return -1;
2938 : }
2939 72 : return myChargingMemory->sawBlockedStoppingPlace(cs, local);
2940 : }
2941 :
2942 :
2943 : void
2944 4795278 : MSBaseVehicle::cleanupParkingReservation() {
2945 4795278 : if (hasStops() && myStops.front().parkingarea != nullptr && myStops.front().parkingarea->isReservable()) {
2946 0 : myStops.front().parkingarea->removeSpaceReservation(this);
2947 : }
2948 4795278 : }
2949 :
2950 :
2951 : #ifdef _DEBUG
2952 : void
2953 : MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
2954 : if (oc.isSet("movereminder-output.vehicles")) {
2955 : const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
2956 : myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
2957 : }
2958 : }
2959 :
2960 :
2961 : void
2962 : MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
2963 : OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
2964 : od.openTag("movereminder");
2965 : od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
2966 : od.writeAttr("veh", getID());
2967 : od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
2968 : od.writeAttr("type", type);
2969 : od.writeAttr("pos", toString(pos));
2970 : od.writeAttr("keep", toString(keep));
2971 : od.closeTag();
2972 : }
2973 : #endif
2974 :
2975 :
2976 : /****************************************************************************/
|