Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 <utils/common/StdDefs.h>
28 : #include <utils/common/MsgHandler.h>
29 : #include <utils/options/OptionsCont.h>
30 : #include <utils/iodevices/OutputDevice.h>
31 : #include <utils/emissions/PollutantsInterface.h>
32 : #include <utils/emissions/HelpersHarmonoise.h>
33 : #include <libsumo/TraCIConstants.h>
34 : #include <mesosim/MELoop.h>
35 : #include <mesosim/MEVehicle.h>
36 : #include <microsim/devices/MSRoutingEngine.h>
37 : #include <microsim/devices/MSDevice_Transportable.h>
38 : #include <microsim/devices/MSDevice_Emissions.h>
39 : #include <microsim/devices/MSDevice_Battery.h>
40 : #include <microsim/devices/MSDevice_ElecHybrid.h>
41 : #include <microsim/devices/MSDevice_Taxi.h>
42 : #include <microsim/devices/MSDevice_Routing.h>
43 : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
44 : #include <microsim/transportables/MSPerson.h>
45 : #include <microsim/transportables/MSStageDriving.h>
46 : #include <microsim/trigger/MSChargingStation.h>
47 : #include <microsim/trigger/MSStoppingPlaceRerouter.h>
48 : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
49 : #include "MSGlobals.h"
50 : #include "MSVehicleControl.h"
51 : #include "MSVehicleType.h"
52 : #include "MSEdge.h"
53 : #include "MSLane.h"
54 : #include "MSMoveReminder.h"
55 : #include "MSEdgeWeightsStorage.h"
56 : #include "MSNet.h"
57 : #include "MSStop.h"
58 : #include "MSParkingArea.h"
59 : #include "MSInsertionControl.h"
60 : #include "MSBaseVehicle.h"
61 :
62 : //#define DEBUG_REROUTE
63 : //#define DEBUG_ADD_STOP
64 : //#define DEBUG_COND (getID() == "")
65 : //#define DEBUG_COND (true)
66 : //#define DEBUG_REPLACE_ROUTE
67 : #define DEBUG_COND (isSelected())
68 :
69 : // ===========================================================================
70 : // static members
71 : // ===========================================================================
72 : const SUMOTime MSBaseVehicle::NOT_YET_DEPARTED = SUMOTime_MAX;
73 : std::vector<MSTransportable*> MSBaseVehicle::myEmptyTransportableVector;
74 : #ifdef _DEBUG
75 : std::set<std::string> MSBaseVehicle::myShallTraceMoveReminders;
76 : #endif
77 : SUMOTrafficObject::NumericalID MSBaseVehicle::myCurrentNumericalIndex = 0;
78 :
79 : // ===========================================================================
80 : // Influencer method definitions
81 : // ===========================================================================
82 :
83 3368 : MSBaseVehicle::BaseInfluencer::BaseInfluencer()
84 3368 : {}
85 :
86 : // ===========================================================================
87 : // method definitions
88 : // ===========================================================================
89 :
90 : double
91 0 : MSBaseVehicle::getPreviousSpeed() const {
92 0 : throw ProcessError("getPreviousSpeed() is not available for non-MSVehicles.");
93 : }
94 :
95 :
96 5104379 : MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
97 5104379 : MSVehicleType* type, const double speedFactor) :
98 : SUMOVehicle(pars->id),
99 5104379 : myParameter(pars),
100 : myRoute(route),
101 5104379 : myType(type),
102 5104379 : myCurrEdge(route->begin()),
103 5115040 : myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
104 5104379 : myMoveReminders(0),
105 5104379 : myPersonDevice(nullptr),
106 5104379 : myContainerDevice(nullptr),
107 5104379 : myEnergyParams(nullptr),
108 5104379 : myDeparture(NOT_YET_DEPARTED),
109 5104379 : myDepartPos(-1),
110 5104379 : myArrivalPos(-1),
111 5104379 : myArrivalLane(-1),
112 5104379 : myNumberReroutes(0),
113 5104379 : myStopUntilOffset(0),
114 5104379 : myOdometer(0.),
115 5104379 : myRouteValidity(ROUTE_UNCHECKED),
116 5104379 : myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
117 5104379 : myNumericalID(myCurrentNumericalIndex++),
118 10208758 : myEdgeWeights(nullptr)
119 : #ifdef _DEBUG
120 : , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
121 : #endif
122 : {
123 5104379 : if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
124 566545 : pars->parametersSet |= VEHPARS_FORCE_REROUTE;
125 : }
126 5104379 : if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
127 3611618 : setDepartAndArrivalEdge();
128 : }
129 5104379 : if (!pars->wasSet(VEHPARS_FORCE_REROUTE)) {
130 3611618 : calculateArrivalParams(true);
131 : }
132 5104379 : initTransientModelParams();
133 5104379 : }
134 :
135 :
136 5104287 : MSBaseVehicle::~MSBaseVehicle() {
137 5104287 : delete myEdgeWeights;
138 5104287 : if (myParameter->repetitionNumber == -1) {
139 : // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
140 441197 : MSRoute::checkDist(myParameter->routeid);
141 : }
142 8905856 : for (MSVehicleDevice* dev : myDevices) {
143 3801569 : delete dev;
144 : }
145 5104287 : delete myEnergyParams;
146 5104287 : delete myParkingMemory;
147 5104287 : delete myChargingMemory;
148 5104287 : checkRouteRemoval();
149 5104287 : delete myParameter;
150 5104287 : }
151 :
152 :
153 : void
154 7045874 : MSBaseVehicle::checkRouteRemoval() {
155 : // the check for an instance is needed for the unit tests which do not construct a network
156 : // TODO Optimize for speed and there should be a better way to check whether a vehicle is part of a flow
157 14091746 : if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
158 1295894 : myRoute->checkRemoval();
159 : }
160 7045874 : }
161 :
162 :
163 : std::string
164 7045872 : MSBaseVehicle::getFlowID() const {
165 7045872 : return getID().substr(0, getID().rfind('.'));
166 : }
167 :
168 :
169 : void
170 5104379 : MSBaseVehicle::initDevices() {
171 5104379 : MSDevice::buildVehicleDevices(*this, myDevices);
172 8901375 : for (MSVehicleDevice* dev : myDevices) {
173 3797012 : myMoveReminders.push_back(std::make_pair(dev, 0.));
174 : }
175 5104363 : if (MSGlobals::gHaveEmissions) {
176 : // ensure we have the emission parameters even if we don't have the device
177 857575 : getEmissionParameters();
178 : }
179 5104363 : }
180 :
181 :
182 : void
183 0 : MSBaseVehicle::setID(const std::string& /*newID*/) {
184 0 : throw ProcessError(TL("Changing a vehicle ID is not permitted"));
185 : }
186 :
187 : const SUMOVehicleParameter&
188 12696335435 : MSBaseVehicle::getParameter() const {
189 12696335435 : return *myParameter;
190 : }
191 :
192 :
193 : void
194 477 : MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
195 477 : delete myParameter;
196 477 : myParameter = newParameter;
197 477 : }
198 :
199 :
200 : bool
201 632965772 : MSBaseVehicle::ignoreTransientPermissions() const {
202 632965772 : return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
203 : }
204 :
205 : double
206 6448539095 : MSBaseVehicle::getMaxSpeed() const {
207 6448539095 : return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
208 : }
209 :
210 :
211 : const MSEdge*
212 1901504767 : MSBaseVehicle::succEdge(int nSuccs) const {
213 1901504767 : if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
214 1371098265 : return *(myCurrEdge + nSuccs);
215 : } else {
216 530406502 : return nullptr;
217 : }
218 : }
219 :
220 :
221 : const MSEdge*
222 2976991322 : MSBaseVehicle::getEdge() const {
223 2976991322 : return *myCurrEdge;
224 : }
225 :
226 :
227 : const std::set<SUMOTrafficObject::NumericalID>
228 65301 : MSBaseVehicle::getUpcomingEdgeIDs() const {
229 : std::set<SUMOTrafficObject::NumericalID> result;
230 294161 : for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
231 228860 : result.insert((*e)->getNumericalID());
232 : }
233 65301 : return result;
234 : }
235 :
236 :
237 : bool
238 112690 : MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
239 112690 : if (stop == nullptr) {
240 : return false;
241 : }
242 260897 : for (const MSStop& s : myStops) {
243 186382 : if (s.busstop == stop
244 148229 : || s.containerstop == stop
245 148223 : || s.parkingarea == stop
246 148217 : || s.chargingStation == stop) {
247 : return true;
248 : }
249 : }
250 : return false;
251 : }
252 :
253 : bool
254 184824 : MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
255 391978 : for (const MSStop& s : myStops) {
256 366012 : if (&s.lane->getEdge() == edge) {
257 : return true;
258 : }
259 : }
260 25966 : return myRoute->getLastEdge() == edge;
261 : }
262 :
263 :
264 : bool
265 2661420 : MSBaseVehicle::reroute(SUMOTime t, const std::string& info, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, const bool onInit, const bool withTaz, const bool silent, const MSEdge* sink) {
266 : // check whether to reroute
267 2661420 : const MSEdge* source = withTaz && onInit ? MSEdge::dictionary(myParameter->fromTaz + "-source") : *getRerouteOrigin();
268 2661420 : if (source == nullptr) {
269 289 : source = *getRerouteOrigin();
270 : }
271 2661420 : if (sink == nullptr) {
272 2635315 : sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
273 2635315 : if (sink == nullptr) {
274 289 : sink = myRoute->getLastEdge();
275 : }
276 : }
277 2672104 : ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
278 : ConstMSEdgeVector edges;
279 : ConstMSEdgeVector stops;
280 : std::set<int> jumps;
281 : bool stopAtSink = false;
282 2661420 : if (myParameter->via.size() == 0) {
283 2653024 : double firstPos = INVALID_DOUBLE;
284 2653024 : double lastPos = INVALID_DOUBLE;
285 2653024 : stops = getStopEdges(firstPos, lastPos, jumps);
286 2653024 : if (stops.size() > 0) {
287 39292 : double sourcePos = onInit ? 0 : getPositionOnLane();
288 39292 : if (MSGlobals::gUseMesoSim && isStopped()) {
289 232 : sourcePos = getNextStop().pars.endPos;
290 : }
291 : // avoid superfluous waypoints for first and last edge
292 39292 : const bool skipFirst = stops.front() == source && (source != getEdge() || sourcePos + getBrakeGap() <= firstPos + NUMERICAL_EPS);
293 39292 : const bool skipLast = (stops.back() == sink
294 21586 : && myArrivalPos >= lastPos
295 13175 : && (stops.size() < 2 || stops.back() != stops[stops.size() - 2])
296 52452 : && (stops.size() > 1 || skipFirst));
297 : #ifdef DEBUG_REROUTE
298 : if (DEBUG_COND) {
299 : std::cout << SIMTIME << " reroute " << info << " veh=" << getID() << " lane=" << Named::getIDSecure(getLane())
300 : << " source=" << source->getID() << " sourcePos=" << sourcePos << " firstPos=" << firstPos << " arrivalPos=" << myArrivalPos << " lastPos=" << lastPos
301 : << " route=" << toString(myRoute->getEdges()) << " stopEdges=" << toString(stops) << " skipFirst=" << skipFirst << " skipLast=" << skipLast << "\n";
302 : }
303 : #endif
304 39292 : if (stops.size() == 1 && (skipFirst || skipLast)) {
305 : stops.clear();
306 : } else {
307 31505 : if (skipFirst) {
308 : stops.erase(stops.begin());
309 : }
310 31505 : if (skipLast) {
311 : stops.erase(stops.end() - 1);
312 : }
313 : }
314 39292 : stopAtSink = stops.size() > 0 && stops.back() == sink && jumps.size() == 0;
315 : }
316 : } else {
317 : std::set<const MSEdge*> jumpEdges;
318 20624 : for (const MSStop& stop : myStops) {
319 12228 : if (stop.pars.jump >= 0) {
320 : jumpEdges.insert(*stop.edge);
321 : }
322 : }
323 : // via takes precedence over stop edges
324 : // there is a consistency check in MSRouteHandler::addStop that warns when a stop edge is not part of the via edges
325 26300 : for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
326 17912 : MSEdge* viaEdge = MSEdge::dictionary(*it);
327 17912 : if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
328 3098 : continue;
329 : }
330 : assert(viaEdge != 0);
331 14814 : if (!viaEdge->isTazConnector() && viaEdge->allowedLanes(getVClass()) == nullptr) {
332 24 : throw ProcessError(TLF("Vehicle '%' is not allowed on any lane of via edge '%'.", getID(), viaEdge->getID()));
333 : }
334 14806 : stops.push_back(viaEdge);
335 : if (jumpEdges.count(viaEdge) != 0) {
336 15 : jumps.insert((int)stops.size());
337 : }
338 : }
339 : }
340 :
341 : int stopIndex = -1;
342 2720155 : for (const MSEdge* const stopEdge : stops) {
343 58745 : stopIndex++;
344 : // !!! need to adapt t here
345 : ConstMSEdgeVector into;
346 758 : if (jumps.count(stopIndex) != 0) {
347 758 : edges.push_back(source);
348 758 : source = stopEdge;
349 : continue;
350 : }
351 57987 : router.computeLooped(source, stopEdge, this, t, into, silent);
352 : //std::cout << SIMTIME << " reroute veh=" << getID() << " source=" << source->getID() << " target=" << (*s)->getID() << " edges=" << toString(into) << "\n";
353 57987 : if (into.size() > 0) {
354 : into.pop_back();
355 57969 : edges.insert(edges.end(), into.begin(), into.end());
356 57969 : if (stopEdge->isTazConnector()) {
357 63 : source = into.back();
358 : edges.pop_back();
359 : } else {
360 57906 : source = stopEdge;
361 : }
362 : } else {
363 18 : if ((source != sink || !stopAtSink)) {
364 4 : std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
365 2 : if (MSGlobals::gCheckRoutes || silent) {
366 4 : throw ProcessError(error);
367 : } else {
368 2 : WRITE_WARNING(error);
369 0 : edges.push_back(source);
370 : }
371 : }
372 16 : source = stopEdge;
373 : }
374 58745 : }
375 2628643 : if (stops.empty() && source == sink && onInit
376 18679 : && myParameter->departPosProcedure == DepartPosDefinition::GIVEN
377 90 : && myParameter->arrivalPosProcedure == ArrivalPosDefinition::GIVEN
378 2661430 : && myParameter->departPos > myParameter->arrivalPos) {
379 13 : router.computeLooped(source, sink, this, t, edges, silent);
380 : } else {
381 2661397 : if (!router.compute(source, sink, this, t, edges, silent)) {
382 : edges.clear();
383 : }
384 : }
385 :
386 : // router.setHint(myCurrEdge, myRoute->end(), this, t);
387 2661410 : if (edges.empty() && silent) {
388 : return false;
389 : }
390 2661286 : if (!edges.empty() && edges.front()->isTazConnector()) {
391 : edges.erase(edges.begin());
392 : }
393 2661286 : if (!edges.empty() && edges.back()->isTazConnector()) {
394 : edges.pop_back();
395 : }
396 2661286 : const double routeCost = router.recomputeCosts(edges, this, t);
397 2661286 : const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
398 2661286 : const double savings = previousCost - routeCost;
399 : //if (getID() == "43") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
400 : // << " onInit=" << onInit
401 : // << " prevEdges=" << toString(oldEdgesRemaining)
402 : // << " newEdges=" << toString(edges)
403 : // << "\n";
404 2661286 : replaceRouteEdges(edges, routeCost, savings, info, onInit);
405 : // this must be called even if the route could not be replaced
406 2661286 : if (onInit) {
407 2088236 : if (edges.empty()) {
408 190 : if (MSGlobals::gCheckRoutes) {
409 339 : throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
410 77 : } else if (source->isTazConnector()) {
411 204 : WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
412 27 : MSNet::getInstance()->getInsertionControl().descheduleDeparture(this);
413 : return false;
414 : }
415 : }
416 2088096 : setDepartAndArrivalEdge();
417 2088096 : calculateArrivalParams(onInit);
418 : }
419 2661146 : return !edges.empty();
420 2661666 : }
421 :
422 :
423 : bool
424 2682952 : MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
425 2682952 : if (edges.empty()) {
426 1683 : WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
427 561 : if (msgReturn != nullptr) {
428 : *msgReturn = "No route found";
429 : }
430 561 : return false;
431 : }
432 : // build a new id, first
433 : std::string id = getID();
434 2682391 : if (id[0] != '!') {
435 5364782 : id = "!" + id;
436 : }
437 2682391 : const std::string idSuffix = id + "!var#";
438 2682391 : int varIndex = 1;
439 2682391 : id = idSuffix + toString(varIndex);
440 4743058 : while (MSRoute::hasRoute(id)) {
441 4121334 : id = idSuffix + toString(++varIndex);
442 : }
443 2682391 : int oldSize = (int)edges.size();
444 2682391 : if (!onInit) {
445 592710 : const MSEdge* const origin = *getRerouteOrigin();
446 592710 : if (origin != *myCurrEdge && edges.front() == origin) {
447 10615 : edges.insert(edges.begin(), *myCurrEdge);
448 10615 : oldSize = (int)edges.size();
449 : }
450 1185420 : edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
451 : }
452 2682391 : if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
453 : // re-assign stop iterators when rerouting to a new parkingArea / insertStop
454 : return true;
455 : }
456 1447760 : const RGBColor& c = myRoute->getColor();
457 1447760 : MSRoute* newRoute = new MSRoute(id, edges, false, &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), std::vector<SUMOVehicleParameter::Stop>());
458 : newRoute->setCosts(cost);
459 : newRoute->setSavings(savings);
460 1447760 : ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
461 2895520 : if (!MSRoute::dictionary(id, constRoute)) {
462 0 : delete newRoute;
463 0 : if (msgReturn != nullptr) {
464 0 : *msgReturn = "duplicate routeID '" + id + "'";
465 : }
466 0 : return false;
467 : }
468 :
469 : std::string msg;
470 1447793 : if (check && !hasValidRoute(msg, constRoute)) {
471 3 : WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), getID(), msg);
472 1 : if (MSGlobals::gCheckRoutes) {
473 1 : if (msgReturn != nullptr) {
474 : *msgReturn = msg;
475 : }
476 1 : return false;
477 : }
478 : }
479 2895518 : if (!replaceRoute(constRoute, info, onInit, (int)edges.size() - oldSize, false, removeStops, msgReturn)) {
480 : return false;
481 : }
482 : return true;
483 : }
484 :
485 :
486 : bool
487 1941595 : MSBaseVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
488 : const ConstMSEdgeVector& edges = newRoute->getEdges();
489 : // rebuild in-vehicle route information
490 1941595 : if (onInit) {
491 1399092 : myCurrEdge = newRoute->begin();
492 : } else {
493 542503 : MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
494 542503 : if (newCurrEdge == edges.end()) {
495 2 : if (msgReturn != nullptr) {
496 6 : *msgReturn = TLF("current edge '%' not found in new route", (*myCurrEdge)->getID());
497 : }
498 : #ifdef DEBUG_REPLACE_ROUTE
499 : if (DEBUG_COND) {
500 : std::cout << " newCurrEdge not found\n";
501 : }
502 : #endif
503 2 : return false;
504 : }
505 542501 : if (getLane() != nullptr) {
506 409710 : if (getLane()->getEdge().isInternal() && (
507 409711 : (newCurrEdge + 1) == edges.end() || (*(newCurrEdge + 1)) != &(getLane()->getOutgoingViaLanes().front().first->getEdge()))) {
508 1 : if (msgReturn != nullptr) {
509 1 : *msgReturn = TL("Vehicle is on junction-internal edge leading elsewhere");
510 : }
511 : #ifdef DEBUG_REPLACE_ROUTE
512 : if (DEBUG_COND) {
513 : std::cout << " Vehicle is on junction-internal edge leading elsewhere\n";
514 : }
515 : #endif
516 1 : return false;
517 409709 : } else if (getPositionOnLane() > getLane()->getLength()
518 409714 : && (myCurrEdge + 1) != myRoute->end()
519 10 : && (newCurrEdge + 1) != edges.end()
520 409719 : && *(myCurrEdge + 1) != *(newCurrEdge + 1)) {
521 5 : if (msgReturn != nullptr) {
522 0 : *msgReturn = TL("Vehicle is moving past junction and committed to move to another successor edge");
523 : }
524 : #ifdef DEBUG_REPLACE_ROUTE
525 : if (DEBUG_COND) {
526 : std::cout << " Vehicle is moving past junction and committed to move to another successor edge\n";
527 : }
528 : #endif
529 5 : return false;
530 : }
531 : }
532 542495 : myCurrEdge = newCurrEdge;
533 : }
534 1941587 : const bool stopsFromScratch = onInit && myRoute->getStops().empty();
535 : // assign new route
536 1941587 : checkRouteRemoval();
537 : myRoute = newRoute;
538 : // update arrival definition
539 1941587 : calculateArrivalParams(onInit);
540 : // save information that the vehicle was rerouted
541 1941587 : myNumberReroutes++;
542 1941587 : myStopUntilOffset += myRoute->getPeriod();
543 1941587 : MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::NEWROUTE, info);
544 : #ifdef DEBUG_REPLACE_ROUTE
545 : if (DEBUG_COND) {
546 : std::cout << SIMTIME << " veh=" << getID() << " replaceRoute info=" << info << " on " << (*myCurrEdge)->getID()
547 : << " lane=" << Named::getIDSecure(getLane())
548 : << " stopsFromScratch=" << stopsFromScratch
549 : << " newSize=" << newRoute->getEdges().size()
550 : << " newIndex=" << (myCurrEdge - newRoute->begin())
551 : << " edges=" << toString(newRoute->getEdges())
552 : << "\n";
553 : }
554 : #endif
555 : // remove past stops which are not on the route anymore
556 2001103 : for (std::vector<SUMOVehicleParameter::Stop>::iterator it = myPastStops.begin(); it != myPastStops.end();) {
557 85837 : const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
558 59516 : if (std::find(myRoute->begin(), myRoute->end(), stopEdge) == myRoute->end()) {
559 4 : it = myPastStops.erase(it);
560 : } else {
561 : ++it;
562 : }
563 : }
564 : // if we did not drive yet it may be best to simply reassign the stops from scratch
565 1941587 : if (stopsFromScratch) {
566 : myStops.clear();
567 1399028 : addStops(!MSGlobals::gCheckRoutes);
568 : } else {
569 : // recheck old stops
570 542559 : MSRouteIterator searchStart = myCurrEdge;
571 542559 : double lastPos = getPositionOnLane() + getBrakeGap();
572 952263 : if (getLane() != nullptr && getLane()->isInternal()
573 543392 : && myStops.size() > 0 && !myStops.front().lane->isInternal()) {
574 : // searchStart is still incoming to the intersection so lastPos
575 : // relative to that edge must be adapted
576 193 : lastPos += (*myCurrEdge)->getLength();
577 : }
578 : int stopIndex = 0;
579 573323 : for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
580 30764 : double endPos = iter->getEndPos(*this);
581 : #ifdef DEBUG_REPLACE_ROUTE
582 : if (DEBUG_COND) {
583 : std::cout << " stopEdge=" << iter->lane->getEdge().getID() << " start=" << (searchStart - myCurrEdge) << " endPos=" << endPos << " lastPos=" << lastPos << "\n";
584 : }
585 : #endif
586 30764 : if (*searchStart != &iter->lane->getEdge()
587 30764 : || endPos + NUMERICAL_EPS < lastPos) {
588 27860 : if (searchStart != edges.end() && !iter->reached) {
589 : searchStart++;
590 : }
591 : }
592 : lastPos = endPos;
593 :
594 30764 : iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
595 : #ifdef DEBUG_REPLACE_ROUTE
596 : if (DEBUG_COND) {
597 : std::cout << " foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
598 : }
599 : #endif
600 30764 : if (iter->edge == edges.end()) {
601 187 : if (!removeStops) {
602 8 : WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
603 : }
604 187 : iter = myStops.erase(iter);
605 187 : continue;
606 : } else {
607 30577 : setSkips(*iter, stopIndex);
608 30577 : searchStart = iter->edge;
609 : }
610 : ++iter;
611 30577 : stopIndex++;
612 : }
613 : // add new stops
614 542559 : if (addRouteStops) {
615 494091 : for (std::vector<SUMOVehicleParameter::Stop>::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
616 : std::string error;
617 307 : addStop(*i, error, myParameter->depart + myStopUntilOffset);
618 307 : if (error != "") {
619 0 : WRITE_WARNING(error);
620 : }
621 : }
622 : }
623 : }
624 : return true;
625 : }
626 :
627 :
628 : double
629 160990 : MSBaseVehicle::getAcceleration() const {
630 160990 : return 0;
631 : }
632 :
633 :
634 : void
635 3552417 : MSBaseVehicle::onDepart() {
636 3552417 : myDeparture = MSNet::getInstance()->getCurrentTimeStep();
637 3552417 : myDepartPos = getPositionOnLane();
638 3552417 : MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
639 3552417 : }
640 :
641 :
642 : SUMOTime
643 2820758 : MSBaseVehicle:: getDepartDelay() const {
644 2820758 : const SUMOTime dep = getParameter().depart;
645 2820758 : if (dep < 0) {
646 : return 0;
647 : }
648 2820651 : return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
649 : }
650 :
651 :
652 : bool
653 0 : MSBaseVehicle::hasArrived() const {
654 0 : return succEdge(1) == nullptr;
655 : }
656 :
657 :
658 : int
659 26934738 : MSBaseVehicle::getRoutePosition() const {
660 26934738 : return (int) std::distance(myRoute->begin(), myCurrEdge);
661 : }
662 :
663 :
664 : void
665 102052 : MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
666 102052 : myCurrEdge = myRoute->begin() + index;
667 102052 : const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
668 : // !!! hack
669 102052 : myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
670 102052 : }
671 :
672 : double
673 979686 : MSBaseVehicle::getOdometer() const {
674 979686 : return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
675 : }
676 :
677 : bool
678 310365 : MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
679 310365 : if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
680 : return false;
681 206637 : } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
682 : return false;
683 : }
684 296363 : if (isStopped() && myStops.begin()->pars.permitted.size() > 0
685 148237 : && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
686 5842 : return false;
687 : }
688 142395 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
689 : if (taxiDevice != nullptr) {
690 23252 : return taxiDevice->allowsBoarding(t);
691 : }
692 : return true;
693 : }
694 :
695 :
696 : void
697 12892 : MSBaseVehicle::addTransportable(MSTransportable* transportable) {
698 12892 : if (transportable->isPerson()) {
699 12162 : if (myPersonDevice == nullptr) {
700 4171 : myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
701 4171 : myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
702 4171 : if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
703 1911 : const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
704 : }
705 : }
706 12162 : myPersonDevice->addTransportable(transportable);
707 : } else {
708 730 : if (myContainerDevice == nullptr) {
709 404 : myContainerDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, true);
710 404 : myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myContainerDevice, 0.));
711 404 : if (myParameter->departProcedure == DepartDefinition::CONTAINER_TRIGGERED && myParameter->depart == -1) {
712 79 : const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
713 : }
714 : }
715 730 : myContainerDevice->addTransportable(transportable);
716 : }
717 12892 : }
718 :
719 :
720 : bool
721 2064 : MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
722 2346 : for (const MSStop& stop : myStops) {
723 741 : if (stop.edge == it && stop.pars.jump >= 0) {
724 : return true;
725 639 : } else if (stop.edge > it) {
726 : return false;
727 : }
728 : }
729 : return false;
730 : }
731 :
732 :
733 : bool
734 4236965 : MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
735 4236965 : MSRouteIterator start = myCurrEdge;
736 4236965 : if (route == nullptr) {
737 : route = myRoute;
738 : } else {
739 3558055 : start = route->begin();
740 : }
741 : const bool checkJumps = route == myRoute; // the edge iterators in the stops are invalid otherwise
742 4236965 : MSRouteIterator last = route->end() - 1;
743 : // check connectivity, first
744 19942357 : for (MSRouteIterator e = start; e != last; ++e) {
745 15739531 : const MSEdge& next = **(e + 1);
746 15739531 : if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
747 34295 : if (!checkJumps || !hasJump(e)) {
748 34193 : if ((myRoutingMode & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) == 0
749 34193 : || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
750 102417 : msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
751 34139 : return false;
752 : }
753 : }
754 : }
755 : }
756 4202826 : last = route->end();
757 : // check usable lanes, then
758 24110186 : for (MSRouteIterator e = start; e != last; ++e) {
759 19907360 : if ((*e)->prohibits(this)) {
760 0 : msg = TLF("Edge '%' prohibits.", (*e)->getID());
761 : return false;
762 : }
763 : }
764 : return true;
765 : }
766 :
767 :
768 : bool
769 506541263 : MSBaseVehicle::hasValidRouteStart(std::string& msg) {
770 506541263 : if (!(*myCurrEdge)->isTazConnector()) {
771 506404207 : if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
772 12 : msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
773 6 : myRouteValidity |= ROUTE_START_INVALID_LANE;
774 6 : return false;
775 : }
776 : }
777 506541257 : if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
778 506541199 : myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
779 506541199 : return true;
780 : } else {
781 174 : msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
782 58 : myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
783 58 : return false;
784 : }
785 : }
786 :
787 :
788 : int
789 4837296888 : MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
790 4837296888 : if (!update) {
791 2057576699 : return myRouteValidity;
792 : }
793 : // insertion check must be done in any case
794 : std::string msg;
795 2779720189 : if (!hasValidRouteStart(msg)) {
796 182 : if (MSGlobals::gCheckRoutes) {
797 220 : throw ProcessError(msg);
798 72 : } else if (!silent) {
799 : // vehicle will be discarded
800 138 : WRITE_WARNING(msg);
801 26 : } else if (msgReturn != nullptr) {
802 : *msgReturn = msg;
803 : }
804 : }
805 : if (MSGlobals::gCheckRoutes
806 2779701620 : && (myRouteValidity & ROUTE_UNCHECKED) != 0
807 : // we could check after the first rerouting
808 2784697911 : && (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
809 7046992 : if (!hasValidRoute(msg, myRoute)) {
810 74 : myRouteValidity |= ROUTE_INVALID;
811 222 : throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
812 : }
813 : }
814 2779720005 : myRouteValidity &= ~ROUTE_UNCHECKED;
815 : return myRouteValidity;
816 : }
817 :
818 : void
819 19436547 : MSBaseVehicle::addReminder(MSMoveReminder* rem) {
820 : #ifdef _DEBUG
821 : if (myTraceMoveReminders) {
822 : traceMoveReminder("add", rem, 0, true);
823 : }
824 : #endif
825 19436547 : myMoveReminders.push_back(std::make_pair(rem, 0.));
826 19436547 : }
827 :
828 :
829 : void
830 0 : MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
831 0 : for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
832 0 : if (r->first == rem) {
833 : #ifdef _DEBUG
834 : if (myTraceMoveReminders) {
835 : traceMoveReminder("remove", rem, 0, false);
836 : }
837 : #endif
838 : myMoveReminders.erase(r);
839 : return;
840 : }
841 : }
842 : }
843 :
844 :
845 : void
846 44553161 : MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
847 115980989 : for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
848 : // skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
849 71427828 : if (rem->first->getLane() != nullptr && rem->second > 0.) {
850 : #ifdef _DEBUG
851 : if (myTraceMoveReminders) {
852 : traceMoveReminder("notifyEnter_skipped", rem->first, rem->second, true);
853 : }
854 : #endif
855 : ++rem;
856 : } else {
857 59260124 : if (rem->first->notifyEnter(*this, reason, enteredLane)) {
858 : #ifdef _DEBUG
859 : if (myTraceMoveReminders) {
860 : traceMoveReminder("notifyEnter", rem->first, rem->second, true);
861 : }
862 : #endif
863 : ++rem;
864 : } else {
865 : #ifdef _DEBUG
866 : if (myTraceMoveReminders) {
867 : traceMoveReminder("notifyEnter", rem->first, rem->second, false);
868 : }
869 : #endif
870 : rem = myMoveReminders.erase(rem);
871 : }
872 : }
873 : }
874 44553161 : }
875 :
876 :
877 : void
878 7642656 : MSBaseVehicle::calculateArrivalParams(bool onInit) {
879 7642656 : if (myRoute->getLastEdge()->isTazConnector()) {
880 : return;
881 : }
882 7642656 : const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
883 7642656 : if (arrivalEdgeIndex != myParameter->arrivalEdge) {
884 42 : WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
885 : getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
886 : }
887 7642656 : const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
888 7642656 : if (!onInit) {
889 542495 : arrivalEdge = myRoute->getLastEdge();
890 : // ignore arrivalEdge parameter after rerouting
891 542495 : const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
892 : }
893 : const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
894 7642656 : const double lastLaneLength = lanes[0]->getLength();
895 7642656 : switch (myParameter->arrivalPosProcedure) {
896 201243 : case ArrivalPosDefinition::GIVEN:
897 201243 : if (fabs(myParameter->arrivalPos) > lastLaneLength) {
898 3048 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
899 : }
900 : // Maybe we should warn the user about invalid inputs!
901 201243 : myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
902 201243 : if (myArrivalPos < 0) {
903 20597 : myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
904 : }
905 : break;
906 : case ArrivalPosDefinition::RANDOM:
907 74093 : myArrivalPos = RandHelper::rand(lastLaneLength);
908 74093 : break;
909 0 : case ArrivalPosDefinition::CENTER:
910 0 : myArrivalPos = lastLaneLength / 2.;
911 0 : break;
912 7367320 : default:
913 7367320 : myArrivalPos = lastLaneLength;
914 7367320 : break;
915 : }
916 7642656 : if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
917 115107 : if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
918 283707 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
919 : }
920 115107 : myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
921 7527549 : } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
922 7 : myArrivalLane = -1;
923 7 : for (MSLane* lane : lanes) {
924 7 : if (lane->allowsVehicleClass(myType->getVehicleClass())) {
925 7 : myArrivalLane = lane->getIndex();
926 7 : break;
927 : }
928 : }
929 7 : if (myArrivalLane == -1) {
930 0 : WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
931 0 : myArrivalLane = 0;
932 : }
933 7527542 : } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
934 : // pick random lane among all usable lanes
935 : std::vector<MSLane*> usable;
936 364240 : for (MSLane* lane : lanes) {
937 279473 : if (lane->allowsVehicleClass(myType->getVehicleClass())) {
938 261555 : usable.push_back(lane);
939 : }
940 : }
941 84767 : if (usable.empty()) {
942 0 : WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
943 0 : myArrivalLane = 0;
944 : } else {
945 84767 : myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
946 : }
947 84767 : }
948 7642656 : if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
949 180580 : for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
950 142260 : if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
951 : return;
952 : }
953 : }
954 114960 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
955 : }
956 : }
957 :
958 : void
959 5699714 : MSBaseVehicle::setDepartAndArrivalEdge() {
960 5699714 : SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
961 5699714 : if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
962 7871 : const int routeEdges = (int)myRoute->getEdges().size();
963 7871 : if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
964 : // write specific edge in vehroute output for reproducibility
965 4185 : pars->departEdge = RandHelper::rand(0, routeEdges);
966 4185 : pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
967 : }
968 : assert(pars->departEdge >= 0);
969 7871 : if (pars->departEdge >= routeEdges) {
970 0 : WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
971 : } else {
972 : myCurrEdge += pars->departEdge;
973 : }
974 : }
975 5699714 : if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
976 147 : const int routeEdges = (int)myRoute->getEdges().size();
977 147 : const int begin = (int)(myCurrEdge - myRoute->begin());
978 : // write specific edge in vehroute output for reproducibility
979 147 : pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
980 147 : pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
981 : assert(pars->arrivalEdge >= begin);
982 : assert(pars->arrivalEdge < routeEdges);
983 : }
984 5699714 : }
985 :
986 :
987 : double
988 577667723 : MSBaseVehicle::getImpatience() const {
989 1155335446 : return MAX2(0., MIN2(1., getVehicleType().getImpatience()
990 577667723 : + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
991 577667723 : + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
992 : }
993 :
994 :
995 : MSDevice*
996 865170519 : MSBaseVehicle::getDevice(const std::type_info& type) const {
997 1495088110 : for (MSVehicleDevice* const dev : myDevices) {
998 685075816 : if (typeid(*dev) == type) {
999 55158225 : return dev;
1000 : }
1001 : }
1002 : return nullptr;
1003 : }
1004 :
1005 :
1006 : void
1007 2817 : MSBaseVehicle::saveState(OutputDevice& out) {
1008 : // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
1009 2817 : const std::string& typeID = MSNet::getInstance()->getVehicleControl().hasVTypeDistribution(myParameter->vtypeid) || getVehicleType().isVehicleSpecific() ? getVehicleType().getID() : "";
1010 2817 : myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
1011 : // params and stops must be written in child classes since they may wish to add additional attributes first
1012 : out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
1013 2817 : std::ostringstream os;
1014 5634 : os << myOdometer << " " << myNumberReroutes;
1015 2817 : out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
1016 2817 : if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
1017 2817 : const int precision = out.precision();
1018 2817 : out.setPrecision(MAX2(gPrecisionRandom, precision));
1019 2817 : out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
1020 2817 : out.setPrecision(precision);
1021 : }
1022 2817 : if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
1023 3872 : out.writeAttr(SUMO_ATTR_REROUTE, true);
1024 : }
1025 2817 : if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
1026 : // could be set from stop
1027 : out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
1028 : }
1029 : // here starts the vehicle internal part (see loading)
1030 : // @note: remember to close the vehicle tag when calling this in a subclass!
1031 5634 : }
1032 :
1033 :
1034 : bool
1035 0 : MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
1036 : UNUSED_PARAMETER(stop);
1037 : UNUSED_PARAMETER(distToStop);
1038 0 : return true;
1039 : }
1040 :
1041 :
1042 : bool
1043 8101870465 : MSBaseVehicle::isStopped() const {
1044 8101870465 : return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
1045 : }
1046 :
1047 :
1048 : bool
1049 2263152792 : MSBaseVehicle::isParking() const {
1050 2310897248 : return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
1051 328883 : && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
1052 2263360656 : && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
1053 : }
1054 :
1055 :
1056 : bool
1057 606152047 : MSBaseVehicle::isJumping() const {
1058 606152047 : return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
1059 : }
1060 :
1061 :
1062 : bool
1063 6254456 : MSBaseVehicle::isStoppedTriggered() const {
1064 6254456 : return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
1065 : }
1066 :
1067 :
1068 : bool
1069 23904 : MSBaseVehicle::isStoppedParking() const {
1070 23904 : return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
1071 : }
1072 :
1073 :
1074 : bool
1075 17180 : MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
1076 17180 : if (isStopped() || (checkFuture && hasStops())) {
1077 : const MSStop& stop = myStops.front();
1078 18023 : return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
1079 : }
1080 : return false;
1081 : }
1082 :
1083 : bool
1084 11423 : MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
1085 : // Check if there is a parking area to be replaced
1086 11423 : if (parkingArea == 0) {
1087 : errorMsg = "new parkingArea is NULL";
1088 0 : return false;
1089 : }
1090 11423 : if (myStops.size() == 0) {
1091 : errorMsg = "vehicle has no stops";
1092 0 : return false;
1093 : }
1094 11423 : if (myStops.front().parkingarea == 0) {
1095 : errorMsg = "first stop is not at parkingArea";
1096 0 : return false;
1097 : }
1098 : MSStop& first = myStops.front();
1099 : SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
1100 11423 : std::string oldStopEdgeID = first.lane->getEdge().getID();
1101 : // merge subsequent duplicate stops equals to parking area
1102 11443 : for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
1103 331 : if (iter->parkingarea == parkingArea) {
1104 20 : stopPar.duration += iter->duration;
1105 20 : myStops.erase(iter++);
1106 : } else {
1107 : break;
1108 : }
1109 : }
1110 11423 : stopPar.lane = parkingArea->getLane().getID();
1111 11423 : stopPar.parkingarea = parkingArea->getID();
1112 11423 : stopPar.startPos = parkingArea->getBeginLanePosition();
1113 11423 : stopPar.endPos = parkingArea->getEndLanePosition();
1114 11423 : first.edge = myRoute->end(); // will be patched in replaceRoute
1115 11423 : first.lane = &parkingArea->getLane();
1116 11423 : first.parkingarea = parkingArea;
1117 :
1118 : // patch via edges
1119 11423 : std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
1120 11423 : if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
1121 198 : myParameter->via.erase(myParameter->via.begin());
1122 198 : myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
1123 : }
1124 : return true;
1125 : }
1126 :
1127 :
1128 : MSParkingArea*
1129 58460 : MSBaseVehicle::getNextParkingArea() {
1130 : MSParkingArea* nextParkingArea = nullptr;
1131 58460 : if (!myStops.empty()) {
1132 57501 : SUMOVehicleParameter::Stop stopPar;
1133 57501 : MSStop stop = myStops.front();
1134 57501 : if (!stop.reached && stop.parkingarea != nullptr) {
1135 : nextParkingArea = stop.parkingarea;
1136 : }
1137 57501 : }
1138 58460 : return nextParkingArea;
1139 : }
1140 :
1141 :
1142 : MSParkingArea*
1143 84817 : MSBaseVehicle::getCurrentParkingArea() {
1144 : MSParkingArea* currentParkingArea = nullptr;
1145 84817 : if (isParking()) {
1146 84756 : currentParkingArea = myStops.begin()->parkingarea;
1147 : }
1148 84817 : return currentParkingArea;
1149 : }
1150 :
1151 :
1152 : const std::vector<std::string>&
1153 21 : MSBaseVehicle::getParkingBadges() const {
1154 21 : if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
1155 7 : return myParameter->parkingBadges;
1156 : } else {
1157 14 : return getVehicleType().getParkingBadges();
1158 : }
1159 : }
1160 :
1161 :
1162 : double
1163 9168947 : MSBaseVehicle::basePos(const MSEdge* edge) const {
1164 9168947 : double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
1165 9168947 : if (hasStops()
1166 9194474 : && myStops.front().edge == myRoute->begin()
1167 9194474 : && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
1168 25499 : result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
1169 : }
1170 9168947 : return result;
1171 : }
1172 :
1173 :
1174 : MSLane*
1175 298 : MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
1176 298 : const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
1177 298 : const MSEdge* edge = MSEdge::dictionary(edgeID);
1178 298 : if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
1179 8 : return nullptr;
1180 : }
1181 580 : const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
1182 290 : if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
1183 290 : const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
1184 290 : stop.edge = edgeID;
1185 290 : return edge->getOppositeEdge()->getLanes()[oppositeIndex];
1186 : }
1187 : return nullptr;
1188 : }
1189 :
1190 :
1191 : bool
1192 126847 : MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
1193 : MSRouteIterator* searchStart) {
1194 126847 : MSStop stop(stopPar);
1195 126847 : if (stopPar.lane == "") {
1196 2498 : MSEdge* e = MSEdge::dictionary(stopPar.edge);
1197 2498 : stop.lane = e->getFirstAllowed(getVClass());
1198 2498 : if (stop.lane == nullptr) {
1199 0 : errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
1200 0 : return false;
1201 : }
1202 : } else {
1203 124349 : stop.lane = MSLane::dictionary(stopPar.lane);
1204 124349 : if (stop.lane == nullptr) {
1205 : // must be an opposite stop
1206 145 : SUMOVehicleParameter::Stop tmp = stopPar;
1207 145 : stop.lane = interpretOppositeStop(tmp);
1208 : assert(stop.lane != nullptr);
1209 145 : }
1210 124349 : if (!stop.lane->allowsVehicleClass(myType->getVehicleClass())) {
1211 32 : errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
1212 16 : return false;
1213 : }
1214 : }
1215 126831 : if (MSGlobals::gUseMesoSim) {
1216 16342 : stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
1217 16342 : if (stop.lane->isInternal()) {
1218 2 : errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
1219 1 : return false;
1220 : }
1221 : }
1222 126830 : stop.initPars(stopPar);
1223 126830 : if (stopPar.until != -1) {
1224 : // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
1225 41029 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
1226 : }
1227 126830 : if (stopPar.arrival != -1) {
1228 597 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
1229 : }
1230 126830 : std::string stopType = "stop";
1231 126830 : std::string stopID = "";
1232 126830 : if (stop.busstop != nullptr) {
1233 : stopType = "busStop";
1234 33545 : stopID = stop.busstop->getID();
1235 93285 : } else if (stop.containerstop != nullptr) {
1236 : stopType = "containerStop";
1237 734 : stopID = stop.containerstop->getID();
1238 92551 : } else if (stop.chargingStation != nullptr) {
1239 : stopType = "chargingStation";
1240 8152 : stopID = stop.chargingStation->getID();
1241 84399 : } else if (stop.overheadWireSegment != nullptr) {
1242 : stopType = "overheadWireSegment";
1243 0 : stopID = stop.overheadWireSegment->getID();
1244 84399 : } else if (stop.parkingarea != nullptr) {
1245 : stopType = "parkingArea";
1246 16201 : stopID = stop.parkingarea->getID();
1247 : }
1248 253660 : const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
1249 :
1250 126830 : if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
1251 0 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
1252 0 : return false;
1253 : }
1254 58632 : if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > stop.pars.endPos - stop.pars.startPos
1255 186335 : && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
1256 834 : errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
1257 : }
1258 126830 : if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
1259 : // forbid access in case the parking requests other badges
1260 14 : errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
1261 7 : return false;
1262 : }
1263 126823 : const MSEdge* stopLaneEdge = &stop.lane->getEdge();
1264 : const MSEdge* stopEdge;
1265 126823 : if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
1266 : // stop lane is on the opposite side
1267 145 : stopEdge = stopLaneEdge->getOppositeEdge();
1268 145 : stop.isOpposite = true;
1269 : } else {
1270 : // if stop is on an internal edge the normal edge before the intersection is used
1271 126678 : stopEdge = stopLaneEdge->getNormalBefore();
1272 : }
1273 126823 : MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
1274 126823 : if (searchStart == nullptr) {
1275 123389 : searchStart = &myCurrEdge;
1276 123389 : if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
1277 : // already on the intersection but myCurrEdge is before it
1278 : searchStart = ≻
1279 : }
1280 : }
1281 : #ifdef DEBUG_ADD_STOP
1282 : if (DEBUG_COND) {
1283 : std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
1284 : << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
1285 : << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
1286 : << "\n";
1287 : }
1288 : #endif
1289 126823 : stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
1290 126823 : MSRouteIterator prevStopEdge = myCurrEdge;
1291 126823 : const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
1292 126823 : double prevStopPos = getPositionOnLane();
1293 : // where to insert the stop
1294 : std::list<MSStop>::iterator iter = myStops.begin();
1295 126823 : if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
1296 : iter = myStops.end();
1297 103623 : if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
1298 : prevStopEdge = myStops.back().edge;
1299 38994 : prevEdge = &myStops.back().lane->getEdge();
1300 38994 : prevStopPos = myStops.back().pars.endPos;
1301 38994 : stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1302 : if (prevStopEdge == stop.edge // laneEdge check is insufficient for looped routes
1303 6070 : && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
1304 45052 : && (prevStopPos > stop.pars.endPos ||
1305 2481 : (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
1306 424 : stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
1307 : }
1308 : #ifdef DEBUG_ADD_STOP
1309 : if (DEBUG_COND) {
1310 : std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
1311 : << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
1312 : }
1313 : #endif
1314 : }
1315 : // skip a number of occurences of stopEdge in looped route
1316 103623 : int skipLooped = stopPar.index - static_cast<int>(myStops.size());
1317 103708 : for (int j = 0; j < skipLooped; j++) {
1318 231 : auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
1319 231 : if (nextIt == myRoute->end()) {
1320 146 : if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
1321 : // only warn if the route loops over the stop edge at least once
1322 28 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
1323 : }
1324 146 : break;
1325 : } else {
1326 85 : stop.edge = nextIt;
1327 : }
1328 : }
1329 : } else {
1330 23200 : if (stopPar.index == STOP_INDEX_FIT) {
1331 34976 : while (iter != myStops.end() && (iter->edge < stop.edge ||
1332 2574 : (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
1333 2574 : (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
1334 : prevStopEdge = iter->edge;
1335 11875 : prevStopPos = iter->pars.endPos;
1336 : ++iter;
1337 : }
1338 : } else {
1339 : int index = stopPar.index;
1340 99 : while (index > 0) {
1341 0 : prevStopEdge = iter->edge;
1342 0 : prevStopPos = iter->pars.endPos;
1343 : ++iter;
1344 0 : --index;
1345 : }
1346 : #ifdef DEBUG_ADD_STOP
1347 : if (DEBUG_COND) {
1348 : std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
1349 : }
1350 : #endif
1351 99 : stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1352 : }
1353 : }
1354 127124 : const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
1355 126823 : if (stop.edge == myRoute->end()) {
1356 72 : if (!wasTooClose) {
1357 192 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
1358 : }
1359 72 : return false;
1360 : }
1361 :
1362 126751 : const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
1363 32837 : prevStopPos + (iter == myStops.begin() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
1364 :
1365 126751 : if (prevStopEdge > stop.edge ||
1366 : // a collision-stop happens after vehicle movement and may move the
1367 : // vehicle backwards on its lane (prevStopPos is the vehicle position)
1368 1575 : (tooClose && !stop.pars.collision)
1369 253486 : || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
1370 : // check if the edge occurs again later in the route
1371 : //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges()) << "\n";
1372 16 : if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
1373 48 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
1374 : }
1375 16 : MSRouteIterator next = stop.edge + 1;
1376 16 : return addStop(stopPar, errorMsg, untilOffset, &next);
1377 : }
1378 126735 : if (wasTooClose) {
1379 : errorMsg = "";
1380 : }
1381 : // David.C:
1382 : //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
1383 126735 : const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
1384 126735 : const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
1385 126735 : if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
1386 : return false;
1387 : }
1388 126735 : if (!hasDeparted() && myCurrEdge == stop.edge) {
1389 : double pos = -1;
1390 26318 : if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
1391 4609 : pos = myParameter->departPos;
1392 4609 : if (pos < 0.) {
1393 194 : pos += (*myCurrEdge)->getLength();
1394 : }
1395 : }
1396 26318 : if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
1397 19364 : pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
1398 : }
1399 26318 : if (pos > stop.pars.endPos + endPosOffset) {
1400 20 : if (stop.edge != myRoute->end()) {
1401 : // check if the edge occurs again later in the route
1402 20 : MSRouteIterator next = stop.edge + 1;
1403 20 : return addStop(stopPar, errorMsg, untilOffset, &next);
1404 : }
1405 0 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
1406 0 : return false;
1407 : }
1408 : }
1409 126715 : if (iter != myStops.begin()) {
1410 : std::list<MSStop>::iterator iter2 = iter;
1411 : iter2--;
1412 75559 : if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
1413 50850 : && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
1414 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1415 18 : + "' set to end at " + time2string(stop.getUntil())
1416 24 : + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
1417 : }
1418 50833 : if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1419 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1420 18 : + "' set to start at " + time2string(stop.pars.arrival)
1421 24 : + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
1422 : }
1423 50833 : if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1424 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1425 18 : + "' set to start at " + time2string(stop.pars.arrival)
1426 24 : + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
1427 : }
1428 : } else {
1429 92181 : if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
1430 75894 : && (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
1431 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1432 18 : + "' set to end at " + time2string(stop.getUntil())
1433 24 : + " earlier than departure at " + time2string(getParameter().depart) + ".";
1434 : }
1435 : }
1436 126715 : if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
1437 18 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1438 54 : + "' set to end at " + time2string(stop.getUntil())
1439 72 : + " earlier than arrival at " + time2string(stop.getArrival()) + ".";
1440 : }
1441 126715 : setSkips(stop, (int)myStops.size());
1442 126715 : myStops.insert(iter, stop);
1443 126715 : if (stopPar.tripId != "") {
1444 2500 : MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
1445 : }
1446 : //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
1447 : // << " routeIndex=" << (stop.edge - myRoute->begin())
1448 : // << " stopIndex=" << std::distance(myStops.begin(), iter)
1449 : // << " route=" << toString(myRoute->getEdges()) << "\n";
1450 : return true;
1451 : }
1452 :
1453 :
1454 : void
1455 157292 : MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
1456 157292 : if (hasDeparted() && stop.edge > myRoute->begin()) {
1457 : // if the route is looped we must patch the index to ensure that state
1458 : // loading (and vehroute-output) encode the correct number of skips
1459 : int foundSkips = 0;
1460 : MSRouteIterator itPrev;
1461 : double prevEndPos;
1462 60656 : if (prevActiveStops > 0) {
1463 : assert((int)myStops.size() >= prevActiveStops);
1464 : auto prevStopIt = myStops.begin();
1465 32180 : std::advance(prevStopIt, prevActiveStops - 1);
1466 : const MSStop& prev = *prevStopIt;
1467 32180 : itPrev = prev.edge;
1468 32180 : prevEndPos = prev.pars.endPos;
1469 28476 : } else if (myPastStops.size() > 0) {
1470 10728 : itPrev = myRoute->begin() + myPastStops.back().routeIndex;
1471 10728 : prevEndPos = myPastStops.back().endPos;
1472 : } else {
1473 17748 : itPrev = myRoute->begin() + myParameter->departEdge;
1474 17748 : prevEndPos = myDepartPos;
1475 : }
1476 : //auto itPrevOrig = itPrev;
1477 60656 : if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
1478 : itPrev++;
1479 : }
1480 : //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
1481 564469 : while (itPrev < stop.edge) {
1482 503813 : if (*itPrev == *stop.edge) {
1483 19536 : foundSkips++;
1484 : }
1485 : itPrev++;
1486 : }
1487 : int newIndex = STOP_INDEX_END;
1488 60656 : if (foundSkips > 0) {
1489 : //if (getID() == "77_0_0") {
1490 : // std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
1491 : // << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
1492 : // << " prevEdge=" << (*itPrevOrig)->getID()
1493 : // << " prevIndex=" << (itPrevOrig - myRoute->begin())
1494 : // << " skips=" << foundSkips << "\n";
1495 : //}
1496 7033 : newIndex = (int)myPastStops.size() + prevActiveStops + foundSkips;
1497 : }
1498 60656 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
1499 : }
1500 157292 : }
1501 :
1502 :
1503 : void
1504 6503374 : MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
1505 6503374 : if (addRouteStops) {
1506 6507487 : for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
1507 : std::string errorMsg;
1508 8541 : if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
1509 20 : throw ProcessError(errorMsg);
1510 : }
1511 8531 : if (errorMsg != "") {
1512 694 : WRITE_WARNING(errorMsg);
1513 : }
1514 : }
1515 : }
1516 6503364 : const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
1517 6592212 : for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
1518 : std::string errorMsg;
1519 88871 : if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
1520 46 : throw ProcessError(errorMsg);
1521 : }
1522 88848 : if (errorMsg != "") {
1523 452 : WRITE_WARNING(errorMsg);
1524 : }
1525 : }
1526 6503341 : }
1527 :
1528 :
1529 : bool
1530 1238535 : MSBaseVehicle::haveValidStopEdges(bool silent) const {
1531 1238535 : MSRouteIterator start = myCurrEdge;
1532 : int i = 0;
1533 : bool ok = true;
1534 1291875 : for (const MSStop& stop : myStops) {
1535 : MSRouteIterator it;
1536 53340 : if (stop.lane->isInternal()) {
1537 : // find the normal predecessor and ensure that the next route edge
1538 : // matches the successor of the internal edge successor
1539 0 : it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
1540 0 : if (it != myRoute->end() && (
1541 0 : it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
1542 0 : it = myRoute->end(); // signal failure
1543 : }
1544 : } else {
1545 53340 : it = std::find(start, myRoute->end(), &stop.lane->getEdge());
1546 : }
1547 53340 : if (it == myRoute->end()) {
1548 0 : if (!silent) {
1549 0 : WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
1550 : i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1551 : }
1552 : ok = false;
1553 : } else {
1554 : MSRouteIterator it2;
1555 2273165 : for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
1556 2269261 : if (it2 == stop.edge) {
1557 : break;
1558 : }
1559 : }
1560 53340 : if (it2 == myRoute->end()) {
1561 3904 : if (!silent) {
1562 0 : WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
1563 : i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
1564 : }
1565 : ok = false;
1566 49436 : } else if (it2 < start) {
1567 0 : if (!silent) {
1568 0 : WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
1569 : i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1570 : }
1571 : ok = false;
1572 : } else {
1573 49436 : start = stop.edge;
1574 : }
1575 : }
1576 53340 : i++;
1577 : }
1578 1238535 : return ok;
1579 : }
1580 :
1581 :
1582 : const ConstMSEdgeVector
1583 2653024 : MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
1584 : assert(haveValidStopEdges());
1585 : ConstMSEdgeVector result;
1586 : const MSStop* prev = nullptr;
1587 2653024 : const MSEdge* internalSuccessor = nullptr;
1588 2730066 : for (const MSStop& stop : myStops) {
1589 77042 : if (stop.reached) {
1590 9404 : if (stop.pars.jump >= 0) {
1591 0 : jumps.insert((int)result.size());
1592 : }
1593 9404 : continue;
1594 : }
1595 67638 : const double stopPos = stop.getEndPos(*this);
1596 : if ((prev == nullptr
1597 28346 : || prev->edge != stop.edge
1598 1322 : || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
1599 94662 : && *stop.edge != internalSuccessor) {
1600 66316 : result.push_back(*stop.edge);
1601 66316 : if (stop.lane->isInternal()) {
1602 5 : internalSuccessor = stop.lane->getNextNormal();
1603 5 : result.push_back(internalSuccessor);
1604 : } else {
1605 66311 : internalSuccessor = nullptr;
1606 : }
1607 : }
1608 : prev = &stop;
1609 67638 : if (firstPos == INVALID_DOUBLE) {
1610 39292 : if (stop.parkingarea != nullptr) {
1611 3269 : firstPos = MAX2(0., stopPos);
1612 : } else {
1613 36023 : firstPos = stopPos;
1614 : }
1615 : }
1616 67638 : lastPos = stopPos;
1617 67638 : if (stop.pars.jump >= 0) {
1618 780 : jumps.insert((int)result.size() - 1);
1619 : }
1620 : }
1621 : //std::cout << "getStopEdges veh=" << getID() << " result=" << toString(result) << "\n";
1622 2653024 : return result;
1623 0 : }
1624 :
1625 :
1626 : std::vector<std::pair<int, double> >
1627 21944 : MSBaseVehicle::getStopIndices() const {
1628 : std::vector<std::pair<int, double> > result;
1629 45296 : for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
1630 46704 : result.push_back(std::make_pair(
1631 23352 : (int)(iter->edge - myRoute->begin()),
1632 23352 : iter->getEndPos(*this)));
1633 : }
1634 21944 : return result;
1635 0 : }
1636 :
1637 :
1638 : MSStop&
1639 5923212 : MSBaseVehicle::getNextStop() {
1640 : assert(myStops.size() > 0);
1641 5923212 : return myStops.front();
1642 : }
1643 :
1644 : SUMOTime
1645 3948993 : MSBaseVehicle::getStopDuration() const {
1646 3948993 : if (isStopped()) {
1647 1511098 : return myStops.front().duration;
1648 : } else {
1649 : return 0;
1650 : }
1651 : }
1652 :
1653 :
1654 : MSStop&
1655 14584 : MSBaseVehicle::getStop(int nextStopIndex) {
1656 14584 : if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
1657 0 : throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
1658 : }
1659 : auto stopIt = myStops.begin();
1660 : std::advance(stopIt, nextStopIndex);
1661 14584 : return *stopIt;
1662 : }
1663 :
1664 :
1665 : const SUMOVehicleParameter::Stop*
1666 193225 : MSBaseVehicle::getNextStopParameter() const {
1667 193225 : if (hasStops()) {
1668 107813 : return &myStops.front().pars;
1669 : }
1670 : return nullptr;
1671 : }
1672 :
1673 :
1674 : bool
1675 45969 : MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
1676 : //if the stop exists update the duration
1677 72424 : for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
1678 49186 : if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
1679 : // update existing stop
1680 22731 : if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
1681 21238 : myStops.erase(iter);
1682 : } else {
1683 1493 : iter->duration = stop.duration;
1684 1493 : iter->triggered = stop.triggered;
1685 1493 : iter->containerTriggered = stop.containerTriggered;
1686 1493 : const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
1687 1493 : const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
1688 : }
1689 : return true;
1690 : }
1691 : }
1692 23238 : const bool result = addStop(stop, errorMsg);
1693 23238 : if (result) {
1694 : /// XXX handle stops added out of order
1695 23225 : myParameter->stops.push_back(stop);
1696 : }
1697 : return result;
1698 : }
1699 :
1700 :
1701 : void
1702 550 : MSBaseVehicle::unregisterWaiting() {
1703 550 : if (myAmRegisteredAsWaiting) {
1704 392 : MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
1705 392 : myAmRegisteredAsWaiting = false;
1706 : }
1707 550 : }
1708 :
1709 :
1710 : bool
1711 833 : MSBaseVehicle::abortNextStop(int nextStopIndex) {
1712 833 : if (hasStops() && nextStopIndex < (int)myStops.size()) {
1713 833 : if (nextStopIndex == 0 && isStopped()) {
1714 34 : resumeFromStopping();
1715 : } else {
1716 : auto stopIt = myStops.begin();
1717 : std::advance(stopIt, nextStopIndex);
1718 799 : myStops.erase(stopIt);
1719 : }
1720 833 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1721 : // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
1722 : auto stopIt2 = myParameter->stops.begin();
1723 : std::advance(stopIt2, nextStopIndex);
1724 8 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
1725 : }
1726 833 : return true;
1727 : } else {
1728 : return false;
1729 : }
1730 : }
1731 :
1732 :
1733 : bool
1734 133 : MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
1735 133 : const int n = (int)myStops.size();
1736 133 : if (nextStopIndex < 0 || nextStopIndex >= n) {
1737 5 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
1738 5 : return false;
1739 : }
1740 128 : if (nextStopIndex == 0 && isStopped()) {
1741 7 : errorMsg = TL("cannot replace reached stop");
1742 7 : return false;
1743 : }
1744 121 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
1745 121 : MSLane* stopLane = MSLane::dictionary(stop.lane);
1746 121 : MSEdge* stopEdge = &stopLane->getEdge();
1747 :
1748 : auto itStop = myStops.begin();
1749 : std::advance(itStop, nextStopIndex);
1750 : MSStop& replacedStop = *itStop;
1751 :
1752 : // check parking access rights
1753 121 : if (stop.parkingarea != "") {
1754 0 : MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
1755 0 : if (pa != nullptr && !pa->accepts(this)) {
1756 0 : errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
1757 0 : return false;
1758 : }
1759 : }
1760 :
1761 121 : if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
1762 : // only replace stop attributes
1763 10 : const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
1764 10 : replacedStop.initPars(stop);
1765 10 : return true;
1766 : }
1767 :
1768 111 : if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
1769 0 : errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
1770 0 : return false;
1771 : }
1772 :
1773 111 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1774 111 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
1775 111 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1776 111 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1777 111 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1778 111 : MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
1779 111 : auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
1780 111 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
1781 :
1782 111 : bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
1783 :
1784 : ConstMSEdgeVector toNewStop;
1785 111 : if (!teleport) {
1786 82 : router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
1787 82 : if (toNewStop.size() == 0) {
1788 15 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
1789 5 : return false;
1790 : }
1791 : }
1792 :
1793 : ConstMSEdgeVector fromNewStop;
1794 106 : if (!newDestination) {
1795 101 : router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
1796 101 : if (fromNewStop.size() == 0) {
1797 0 : errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
1798 0 : return false;
1799 : }
1800 : }
1801 :
1802 106 : const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
1803 106 : replacedStop.initPars(stop);
1804 106 : replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
1805 106 : replacedStop.lane = stopLane;
1806 106 : if (MSGlobals::gUseMesoSim) {
1807 18 : replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
1808 18 : if (replacedStop.lane->isInternal()) {
1809 0 : errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
1810 0 : return false;
1811 : }
1812 : }
1813 :
1814 106 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1815 : ConstMSEdgeVector newEdges; // only remaining
1816 106 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1817 106 : if (!teleport) {
1818 77 : newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
1819 : } else {
1820 29 : newEdges.push_back(*itStart);
1821 : }
1822 106 : if (!newDestination) {
1823 101 : newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
1824 101 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
1825 : } else {
1826 5 : newEdges.push_back(stopEdge);
1827 : }
1828 : //std::cout << SIMTIME << " replaceStop veh=" << getID()
1829 : // << " teleport=" << teleport
1830 : // << " busStop=" << stop.busstop
1831 : // << " oldEdges=" << oldRemainingEdges.size()
1832 : // << " newEdges=" << newEdges.size()
1833 : // << " toNewStop=" << toNewStop.size()
1834 : // << " fromNewStop=" << fromNewStop.size()
1835 : // << "\n";
1836 :
1837 106 : const double routeCost = router.recomputeCosts(newEdges, this, t);
1838 106 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
1839 106 : const double savings = previousCost - routeCost;
1840 106 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1841 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
1842 5 : const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
1843 : }
1844 106 : if (teleport) {
1845 : // let the vehicle jump rather than teleport
1846 : // we add a jump-stop at the end of the edge (unless the vehicle is
1847 : // already configure to jump before the replaced stop)
1848 29 : if (!insertJump(nextStopIndex, itStart, errorMsg)) {
1849 : return false;
1850 : };
1851 : }
1852 106 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
1853 111 : }
1854 :
1855 :
1856 : bool
1857 52 : MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
1858 52 : const int n = (int)myStops.size();
1859 52 : if (nextStopIndex < 0 || nextStopIndex > n) {
1860 0 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
1861 0 : return false;
1862 : }
1863 52 : if (nextStopIndex == 0 && isStopped()) {
1864 0 : errorMsg = TL("cannot reroute towards reached stop");
1865 0 : return false;
1866 : }
1867 52 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
1868 :
1869 52 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1870 52 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
1871 52 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1872 52 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1873 52 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1874 52 : MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
1875 52 : auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
1876 52 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
1877 :
1878 : ConstMSEdgeVector newBetween;
1879 52 : if (!teleport) {
1880 15 : router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
1881 15 : if (newBetween.size() == 0) {
1882 0 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
1883 0 : return false;
1884 : }
1885 : }
1886 :
1887 52 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1888 : ConstMSEdgeVector newEdges; // only remaining
1889 52 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1890 52 : if (!teleport) {
1891 15 : newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
1892 : } else {
1893 37 : newEdges.push_back(*itStart);
1894 : }
1895 52 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
1896 : //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
1897 : // << " oldEdges=" << oldRemainingEdges.size()
1898 : // << " newEdges=" << newEdges.size()
1899 : // << " toNewStop=" << toNewStop.size()
1900 : // << " fromNewStop=" << fromNewStop.size()
1901 : // << "\n";
1902 :
1903 52 : const double routeCost = router.recomputeCosts(newEdges, this, t);
1904 52 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
1905 52 : const double savings = previousCost - routeCost;
1906 :
1907 52 : if (teleport) {
1908 : // let the vehicle jump rather than teleport
1909 : // we add a jump-stop at the end of the edge (unless the vehicle is
1910 : // already configure to jump before the replaced stop)
1911 37 : if (!insertJump(nextStopIndex, itStart, errorMsg)) {
1912 : return false;
1913 : };
1914 : }
1915 52 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
1916 52 : }
1917 :
1918 :
1919 : bool
1920 66 : MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
1921 : bool needJump = true;
1922 66 : if (nextStopIndex > 0) {
1923 : auto itPriorStop = myStops.begin();
1924 48 : std::advance(itPriorStop, nextStopIndex - 1);
1925 : const MSStop& priorStop = *itPriorStop;
1926 48 : if (priorStop.pars.jump >= 0) {
1927 : needJump = false;
1928 : }
1929 : }
1930 : if (needJump) {
1931 47 : SUMOVehicleParameter::Stop jumpStopPars;
1932 47 : jumpStopPars.endPos = (*itStart)->getLength();
1933 47 : jumpStopPars.speed = 1000;
1934 47 : jumpStopPars.jump = 0;
1935 : jumpStopPars.edge = (*itStart)->getID();
1936 47 : jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
1937 : MSLane* jumpStopLane = nullptr;
1938 47 : for (MSLane* cand : (*itStart)->getLanes()) {
1939 47 : if (cand->allowsVehicleClass(getVClass())) {
1940 : jumpStopLane = cand;
1941 : break;
1942 : }
1943 : }
1944 47 : if (jumpStopLane == nullptr) {
1945 0 : errorMsg = TL("unable to replace stop with teleporting");
1946 : return false;
1947 : }
1948 : auto itStop = myStops.begin();
1949 : std::advance(itStop, nextStopIndex);
1950 47 : MSStop jumpStop(jumpStopPars);
1951 47 : jumpStop.initPars(jumpStopPars);
1952 47 : jumpStop.lane = jumpStopLane;
1953 47 : jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
1954 47 : myStops.insert(itStop, jumpStop);
1955 47 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1956 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
1957 : auto it = myParameter->stops.begin() + nextStopIndex;
1958 0 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
1959 : }
1960 47 : }
1961 : return true;
1962 : }
1963 :
1964 :
1965 : bool
1966 330 : MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
1967 330 : const int n = (int)myStops.size();
1968 330 : if (nextStopIndex < 0 || nextStopIndex > n) {
1969 5 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
1970 5 : return false;
1971 : }
1972 325 : if (nextStopIndex == 0 && isStopped()) {
1973 7 : errorMsg = TL("cannot insert stop before the currently reached stop");
1974 7 : return false;
1975 : }
1976 318 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
1977 318 : MSLane* stopLane = MSLane::dictionary(stop.lane);
1978 318 : MSEdge* stopEdge = &stopLane->getEdge();
1979 :
1980 318 : if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
1981 0 : errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
1982 0 : return false;
1983 : }
1984 :
1985 : // check parking access rights
1986 318 : if (stop.parkingarea != "") {
1987 137 : MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
1988 137 : if (pa != nullptr && !pa->accepts(this)) {
1989 0 : errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
1990 0 : return false;
1991 : }
1992 : }
1993 :
1994 318 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1995 318 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
1996 318 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1997 318 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1998 318 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1999 318 : MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
2000 318 : auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
2001 318 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2002 :
2003 318 : bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
2004 :
2005 : ConstMSEdgeVector toNewStop;
2006 318 : if (!teleport) {
2007 291 : router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
2008 291 : if (toNewStop.size() == 0) {
2009 15 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
2010 5 : return false;
2011 : }
2012 : }
2013 :
2014 : ConstMSEdgeVector fromNewStop;
2015 313 : if (!newDestination) {
2016 284 : router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
2017 284 : if (fromNewStop.size() == 0) {
2018 0 : errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
2019 0 : return false;
2020 : }
2021 : }
2022 :
2023 : auto itStop = myStops.begin();
2024 : std::advance(itStop, nextStopIndex);
2025 313 : MSStop newStop(stop);
2026 313 : newStop.initPars(stop);
2027 313 : newStop.edge = myRoute->end(); // will be patched in replaceRoute
2028 313 : newStop.lane = stopLane;
2029 313 : if (MSGlobals::gUseMesoSim) {
2030 66 : newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
2031 66 : if (newStop.lane->isInternal()) {
2032 0 : errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
2033 0 : return false;
2034 : }
2035 : }
2036 313 : myStops.insert(itStop, newStop);
2037 :
2038 313 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2039 : ConstMSEdgeVector newEdges; // only remaining
2040 313 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2041 313 : if (!teleport) {
2042 286 : newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
2043 : } else {
2044 27 : newEdges.push_back(*itStart);
2045 : }
2046 313 : if (!newDestination) {
2047 284 : newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
2048 284 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2049 : } else {
2050 29 : newEdges.push_back(stopEdge);
2051 : }
2052 : //std::cout << SIMTIME << " insertStop veh=" << getID()
2053 : // << " teleport=" << teleport
2054 : // << " busStop=" << stop.busstop
2055 : // << " oldEdges=" << oldRemainingEdges.size()
2056 : // << " newEdges=" << newEdges.size()
2057 : // << " toNewStop=" << toNewStop.size()
2058 : // << " fromNewStop=" << fromNewStop.size()
2059 : // << "\n";
2060 :
2061 313 : const double routeCost = router.recomputeCosts(newEdges, this, t);
2062 313 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2063 313 : const double savings = previousCost - routeCost;
2064 :
2065 313 : if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
2066 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
2067 : auto it = myParameter->stops.begin() + nextStopIndex;
2068 15 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
2069 : }
2070 313 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2071 631 : }
2072 :
2073 :
2074 : double
2075 0 : MSBaseVehicle::getStateOfCharge() const {
2076 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2077 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2078 0 : return batteryOfVehicle->getActualBatteryCapacity();
2079 : } else {
2080 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2081 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2082 0 : return batteryOfVehicle->getActualBatteryCapacity();
2083 : }
2084 : }
2085 : return -1;
2086 : }
2087 :
2088 :
2089 : double
2090 0 : MSBaseVehicle::getRelativeStateOfCharge() const {
2091 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2092 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2093 0 : return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2094 : } else {
2095 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2096 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2097 0 : return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2098 : }
2099 : }
2100 : return -1;
2101 : }
2102 :
2103 :
2104 : double
2105 0 : MSBaseVehicle::getChargedEnergy() const {
2106 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2107 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2108 0 : return batteryOfVehicle->getEnergyCharged();
2109 : } else {
2110 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2111 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2112 0 : return batteryOfVehicle->getEnergyCharged();
2113 : }
2114 : }
2115 : return -1;
2116 : }
2117 :
2118 :
2119 : double
2120 0 : MSBaseVehicle::getMaxChargeRate() const {
2121 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2122 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2123 0 : return batteryOfVehicle->getMaximumChargeRate();
2124 : }
2125 : return -1;
2126 : }
2127 :
2128 :
2129 : double
2130 0 : MSBaseVehicle::getElecHybridCurrent() const {
2131 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2132 0 : MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2133 0 : return elecHybridDevice->getCurrentFromOverheadWire();
2134 : }
2135 :
2136 : return NAN;
2137 : }
2138 :
2139 : double
2140 630 : MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
2141 630 : if (isOnRoad() || isIdling()) {
2142 630 : return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
2143 : } else {
2144 : return 0.;
2145 : }
2146 : }
2147 :
2148 :
2149 : const MSEdgeWeightsStorage&
2150 5140878 : MSBaseVehicle::getWeightsStorage() const {
2151 5140878 : return _getWeightsStorage();
2152 : }
2153 :
2154 :
2155 : MSEdgeWeightsStorage&
2156 650 : MSBaseVehicle::getWeightsStorage() {
2157 650 : return _getWeightsStorage();
2158 : }
2159 :
2160 :
2161 : MSEdgeWeightsStorage&
2162 5141528 : MSBaseVehicle::_getWeightsStorage() const {
2163 5141528 : if (myEdgeWeights == nullptr) {
2164 13328 : myEdgeWeights = new MSEdgeWeightsStorage();
2165 : }
2166 5141528 : return *myEdgeWeights;
2167 : }
2168 :
2169 :
2170 :
2171 :
2172 : int
2173 7250987 : MSBaseVehicle::getPersonNumber() const {
2174 7250987 : int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
2175 7250987 : return boarded + myParameter->personNumber;
2176 : }
2177 :
2178 : int
2179 0 : MSBaseVehicle::getLeavingPersonNumber() const {
2180 : int leavingPersonNumber = 0;
2181 0 : const std::vector<MSTransportable*>& persons = getPersons();
2182 0 : for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2183 0 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
2184 : const MSStop* stop = &myStops.front();
2185 0 : const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
2186 0 : if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
2187 0 : leavingPersonNumber++;
2188 : }
2189 : }
2190 0 : return leavingPersonNumber;
2191 : }
2192 :
2193 : std::vector<std::string>
2194 165 : MSBaseVehicle::getPersonIDList() const {
2195 : std::vector<std::string> ret;
2196 165 : const std::vector<MSTransportable*>& persons = getPersons();
2197 525 : for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2198 360 : ret.push_back((*it_p)->getID());
2199 : }
2200 165 : return ret;
2201 0 : }
2202 :
2203 : int
2204 4394800 : MSBaseVehicle::getContainerNumber() const {
2205 4394800 : int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
2206 4394800 : return loaded + myParameter->containerNumber;
2207 : }
2208 :
2209 :
2210 : void
2211 138 : MSBaseVehicle::removeTransportable(MSTransportable* t) {
2212 : // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
2213 138 : if (myPersonDevice != nullptr) {
2214 118 : myPersonDevice->removeTransportable(t);
2215 : }
2216 138 : if (myContainerDevice != nullptr) {
2217 20 : myContainerDevice->removeTransportable(t);
2218 : }
2219 138 : }
2220 :
2221 :
2222 : const std::vector<MSTransportable*>&
2223 6863987 : MSBaseVehicle::getPersons() const {
2224 6863987 : if (myPersonDevice == nullptr) {
2225 : return myEmptyTransportableVector;
2226 : } else {
2227 13267 : return myPersonDevice->getTransportables();
2228 : }
2229 : }
2230 :
2231 :
2232 : const std::vector<MSTransportable*>&
2233 5628337 : MSBaseVehicle::getContainers() const {
2234 5628337 : if (myContainerDevice == nullptr) {
2235 : return myEmptyTransportableVector;
2236 : } else {
2237 2906 : return myContainerDevice->getTransportables();
2238 : }
2239 : }
2240 :
2241 :
2242 : bool
2243 202 : MSBaseVehicle::isLineStop(double position) const {
2244 202 : if (myParameter->line == "") {
2245 : // not a public transport line
2246 : return false;
2247 : }
2248 348 : for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
2249 209 : if (stop.startPos <= position && position <= stop.endPos) {
2250 : return true;
2251 : }
2252 : }
2253 164 : for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
2254 34 : if (stop.startPos <= position && position <= stop.endPos) {
2255 : return true;
2256 : }
2257 : }
2258 : return false;
2259 : }
2260 :
2261 :
2262 : bool
2263 45 : MSBaseVehicle::hasDevice(const std::string& deviceName) const {
2264 144 : for (MSDevice* const dev : myDevices) {
2265 126 : if (dev->deviceName() == deviceName) {
2266 : return true;
2267 : }
2268 : }
2269 : return false;
2270 : }
2271 :
2272 :
2273 : void
2274 9 : MSBaseVehicle::createDevice(const std::string& deviceName) {
2275 9 : if (!hasDevice(deviceName)) {
2276 9 : if (deviceName == "rerouting") {
2277 27 : ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
2278 9 : MSDevice_Routing::buildVehicleDevices(*this, myDevices);
2279 9 : if (hasDeparted()) {
2280 : // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
2281 0 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
2282 : assert(routingDevice != 0);
2283 0 : routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
2284 : }
2285 : } else {
2286 0 : throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
2287 : }
2288 : }
2289 9 : }
2290 :
2291 :
2292 : std::string
2293 49534 : MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
2294 57692 : for (MSVehicleDevice* const dev : myDevices) {
2295 57683 : if (dev->deviceName() == deviceName) {
2296 49525 : return dev->getParameter(key);
2297 : }
2298 : }
2299 27 : throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2300 : }
2301 :
2302 :
2303 : void
2304 207 : MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
2305 342 : for (MSVehicleDevice* const dev : myDevices) {
2306 342 : if (dev->deviceName() == deviceName) {
2307 207 : dev->setParameter(key, value);
2308 207 : return;
2309 : }
2310 : }
2311 0 : throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2312 : }
2313 :
2314 :
2315 : void
2316 842 : MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
2317 1669 : if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
2318 837 : getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
2319 837 : const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2320 : // checked in MSLink::ignoreFoe
2321 : } else {
2322 15 : throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
2323 : }
2324 837 : }
2325 :
2326 :
2327 : void
2328 38 : MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
2329 : // handle some generic params first and then delegate to the carFollowModel itself
2330 67 : if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
2331 17 : getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
2332 17 : const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2333 : // checked in MSVehicle::planMove
2334 : } else {
2335 21 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
2336 21 : if (microVeh) {
2337 : // remove 'carFollowModel.' prefix
2338 21 : const std::string attrName = key.substr(15);
2339 21 : microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
2340 : }
2341 : }
2342 33 : }
2343 :
2344 :
2345 : void
2346 5104379 : MSBaseVehicle::initTransientModelParams() {
2347 : /* Design idea for additional junction model parameters:
2348 : We can distinguish between 3 levels of parameters
2349 : 1. typically shared by multiple vehicles -> vType parameter
2350 : 2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
2351 : 3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
2352 : */
2353 5372156 : for (auto item : getParameter().getParametersMap()) {
2354 535554 : if (StringUtils::startsWith(item.first, "junctionModel.")) {
2355 832 : setJunctionModelParameter(item.first, item.second);
2356 533890 : } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
2357 17 : setCarFollowModelParameter(item.first, item.second);
2358 : }
2359 : }
2360 10208758 : const std::string routingModeStr = getStringParam("device.rerouting.mode");
2361 : try {
2362 5104379 : int routingMode = StringUtils::toInt(routingModeStr);
2363 5104379 : if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
2364 : setRoutingMode(routingMode);
2365 : }
2366 0 : } catch (NumberFormatException&) {
2367 : // @todo interpret symbolic constants
2368 0 : throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
2369 0 : }
2370 5104379 : }
2371 :
2372 :
2373 : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
2374 23113 : MSBaseVehicle::getRouterTT() const {
2375 23113 : if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
2376 102 : return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
2377 : } else {
2378 23011 : return MSNet::getInstance()->getRouterTT(getRNGIndex());
2379 : }
2380 : }
2381 :
2382 :
2383 : void
2384 30338 : MSBaseVehicle::replaceVehicleType(MSVehicleType* type) {
2385 : assert(type != nullptr);
2386 : // save old parameters before possible type deletion
2387 30338 : const double oldMu = myType->getSpeedFactor().getParameter()[0];
2388 30338 : const double oldDev = myType->getSpeedFactor().getParameter()[1];
2389 30338 : if (myType->isVehicleSpecific() && type != myType) {
2390 802 : MSNet::getInstance()->getVehicleControl().removeVType(myType);
2391 : }
2392 : // adapt myChosenSpeedFactor to the new type
2393 30338 : if (oldDev == 0.) {
2394 : // old type had speedDev 0, reroll
2395 22546 : myChosenSpeedFactor = type->computeChosenSpeedDeviation(getRNG());
2396 : } else {
2397 : // map old speedFactor onto new distribution
2398 7792 : const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
2399 7792 : const double newMu = type->getSpeedFactor().getParameter()[0];
2400 7792 : const double newDev = type->getSpeedFactor().getParameter()[1];
2401 7792 : myChosenSpeedFactor = newMu + distPoint * newDev;
2402 : // respect distribution limits
2403 7792 : myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
2404 7797 : myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
2405 : }
2406 30338 : myType = type;
2407 30338 : if (myEnergyParams != nullptr) {
2408 : myEnergyParams->setSecondary(type->getEmissionParameters());
2409 : }
2410 30338 : }
2411 :
2412 :
2413 : MSVehicleType&
2414 93181 : MSBaseVehicle::getSingularType() {
2415 93181 : if (myType->isVehicleSpecific()) {
2416 : return *myType;
2417 : }
2418 2198 : MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
2419 1099 : replaceVehicleType(type);
2420 1099 : return *type;
2421 : }
2422 :
2423 :
2424 : int
2425 508598 : MSBaseVehicle::getRNGIndex() const {
2426 508598 : const MSLane* const lane = getLane();
2427 508598 : if (lane == nullptr) {
2428 14596 : return getEdge()->getLanes()[0]->getRNGIndex();
2429 : } else {
2430 494002 : return lane->getRNGIndex();
2431 : }
2432 : }
2433 :
2434 :
2435 : SumoRNG*
2436 672001405 : MSBaseVehicle::getRNG() const {
2437 672001405 : const MSLane* lane = getLane();
2438 672001405 : if (lane == nullptr) {
2439 2745 : return getEdge()->getLanes()[0]->getRNG();
2440 : } else {
2441 671998660 : return lane->getRNG();
2442 : }
2443 : }
2444 :
2445 : std::string
2446 68325 : MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
2447 68325 : const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
2448 136650 : if (StringUtils::startsWith(key, "device.")) {
2449 148602 : StringTokenizer tok(key, ".");
2450 49534 : if (tok.size() < 3) {
2451 0 : error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
2452 0 : return "";
2453 : }
2454 : try {
2455 148602 : return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
2456 18 : } catch (InvalidArgument& e) {
2457 54 : error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
2458 18 : return "";
2459 18 : }
2460 87116 : } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
2461 316 : if (microVeh == nullptr) {
2462 36 : error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
2463 18 : return "";
2464 : }
2465 298 : const std::string attrName = key.substr(16);
2466 : try {
2467 298 : return microVeh->getLaneChangeModel().getParameter(attrName);
2468 36 : } catch (InvalidArgument& e) {
2469 108 : error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
2470 36 : return "";
2471 36 : }
2472 36950 : } else if (StringUtils::startsWith(key, "carFollowModel.")) {
2473 16 : if (microVeh == nullptr) {
2474 0 : error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
2475 0 : return "";
2476 : }
2477 16 : const std::string attrName = key.substr(15);
2478 : try {
2479 16 : return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
2480 0 : } catch (InvalidArgument& e) {
2481 0 : error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
2482 0 : return "";
2483 0 : }
2484 18495 : } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
2485 108 : StringTokenizer tok(key, ".");
2486 36 : if (tok.size() != 3) {
2487 0 : error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
2488 0 : return "";
2489 : }
2490 81 : return hasDevice(tok.get(1)) ? "true" : "false";
2491 : // parking related parameters start here
2492 18459 : } else if (key == "parking.rerouteCount") {
2493 15 : return toString(getNumberParkingReroutes());
2494 36816 : } else if (StringUtils::startsWith(key, "parking.memory.")) {
2495 : std::vector<std::string> values;
2496 65 : if (getParkingMemory()) {
2497 25 : if (key == "parking.memory.IDList") {
2498 30 : for (const auto& item : *getParkingMemory()) {
2499 25 : values.push_back(item.first->getID());
2500 : }
2501 20 : } else if (key == "parking.memory.score") {
2502 30 : for (const auto& item : *getParkingMemory()) {
2503 25 : values.push_back(item.second.score);
2504 : }
2505 15 : } else if (key == "parking.memory.blockedAtTime") {
2506 30 : for (const auto& item : *getParkingMemory()) {
2507 50 : values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
2508 : }
2509 10 : } else if (key == "parking.memory.blockedAtTimeLocal") {
2510 30 : for (const auto& item : *getParkingMemory()) {
2511 50 : values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
2512 : }
2513 : } else {
2514 10 : error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
2515 : }
2516 : }
2517 65 : return toString(values);
2518 65 : } else {
2519 : // default: custom user parameter
2520 36686 : return getParameter().getParameter(key, "");
2521 : }
2522 : }
2523 :
2524 :
2525 : void
2526 30505 : MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
2527 30505 : if (myParkingMemory == nullptr) {
2528 0 : myParkingMemory = new StoppingPlaceMemory();
2529 : }
2530 30505 : myParkingMemory->rememberBlockedStoppingPlace(pa, local);
2531 30505 : }
2532 :
2533 :
2534 : void
2535 12115 : MSBaseVehicle::resetParkingAreaScores() {
2536 12115 : if (myParkingMemory != nullptr) {
2537 10591 : myParkingMemory->resetStoppingPlaceScores();
2538 : }
2539 12115 : }
2540 :
2541 :
2542 : void
2543 212 : MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
2544 212 : if (myChargingMemory == nullptr) {
2545 44 : myChargingMemory = new StoppingPlaceMemory();
2546 : }
2547 212 : myChargingMemory->rememberStoppingPlaceScore(cs, score);
2548 212 : }
2549 :
2550 :
2551 : void
2552 80 : MSBaseVehicle::resetChargingStationScores() {
2553 80 : if (myChargingMemory != nullptr) {
2554 4 : myChargingMemory->resetStoppingPlaceScores();
2555 : }
2556 80 : }
2557 :
2558 :
2559 : void
2560 54047 : MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
2561 54047 : if (myParkingMemory == nullptr) {
2562 2024 : myParkingMemory = new StoppingPlaceMemory();
2563 : }
2564 54047 : myParkingMemory->rememberStoppingPlaceScore(pa, score);
2565 54047 : }
2566 :
2567 :
2568 : SUMOTime
2569 37537 : MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
2570 37537 : if (myParkingMemory == nullptr) {
2571 : return -1;
2572 : }
2573 37537 : return myParkingMemory->sawBlockedStoppingPlace(pa, local);
2574 : }
2575 :
2576 :
2577 0 : void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
2578 0 : if (myChargingMemory == nullptr) {
2579 0 : myChargingMemory = new StoppingPlaceMemory();
2580 : }
2581 0 : myChargingMemory->rememberBlockedStoppingPlace(cs, local);
2582 0 : }
2583 :
2584 :
2585 : SUMOTime
2586 276 : MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
2587 276 : if (myChargingMemory == nullptr) {
2588 : return -1;
2589 : }
2590 16 : return myChargingMemory->sawBlockedStoppingPlace(cs, local);
2591 : }
2592 :
2593 :
2594 : #ifdef _DEBUG
2595 : void
2596 : MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
2597 : if (oc.isSet("movereminder-output.vehicles")) {
2598 : const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
2599 : myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
2600 : }
2601 : }
2602 :
2603 :
2604 : void
2605 : MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
2606 : OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
2607 : od.openTag("movereminder");
2608 : od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
2609 : od.writeAttr("veh", getID());
2610 : od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
2611 : od.writeAttr("type", type);
2612 : od.writeAttr("pos", toString(pos));
2613 : od.writeAttr("keep", toString(keep));
2614 : od.closeTag();
2615 : }
2616 : #endif
2617 :
2618 :
2619 : /****************************************************************************/
|