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