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