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 3421 : MSBaseVehicle::BaseInfluencer::BaseInfluencer()
84 3421 : {}
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 4613644 : MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
97 4613644 : MSVehicleType* type, const double speedFactor) :
98 : SUMOVehicle(pars->id),
99 4613644 : myParameter(pars),
100 : myRoute(route),
101 4613644 : myType(type),
102 4613644 : myCurrEdge(route->begin()),
103 4624323 : myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
104 4613644 : myMoveReminders(0),
105 4613644 : myPersonDevice(nullptr),
106 4613644 : myContainerDevice(nullptr),
107 4613644 : myEnergyParams(nullptr),
108 4613644 : myDeparture(NOT_YET_DEPARTED),
109 4613644 : myDepartPos(-1),
110 4613644 : myArrivalPos(-1),
111 4613644 : myArrivalLane(-1),
112 4613644 : myNumberReroutes(0),
113 4613644 : myStopUntilOffset(0),
114 4613644 : myOdometer(0.),
115 4613644 : myRouteValidity(ROUTE_UNCHECKED),
116 4613644 : myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
117 4613644 : myNumericalID(myCurrentNumericalIndex++),
118 9227288 : myEdgeWeights(nullptr)
119 : #ifdef _DEBUG
120 : , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
121 : #endif
122 : {
123 4613644 : if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
124 566510 : pars->parametersSet |= VEHPARS_FORCE_REROUTE;
125 : }
126 4613644 : if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
127 3121311 : setDepartAndArrivalEdge();
128 : }
129 4613644 : if (!pars->wasSet(VEHPARS_FORCE_REROUTE)) {
130 3121311 : calculateArrivalParams(true);
131 : }
132 4613644 : initTransientModelParams();
133 4613644 : }
134 :
135 :
136 4613553 : MSBaseVehicle::~MSBaseVehicle() {
137 4613553 : delete myEdgeWeights;
138 4613553 : if (myParameter->repetitionNumber == -1) {
139 : // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
140 439911 : MSRoute::checkDist(myParameter->routeid);
141 : }
142 8401837 : for (MSVehicleDevice* dev : myDevices) {
143 3788284 : delete dev;
144 : }
145 4613553 : delete myEnergyParams;
146 4613553 : delete myParkingMemory;
147 4613553 : delete myChargingMemory;
148 4613553 : checkRouteRemoval();
149 4613553 : delete myParameter;
150 4613553 : }
151 :
152 :
153 : void
154 6557957 : 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 13115912 : if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
158 1289833 : myRoute->checkRemoval();
159 : }
160 6557957 : }
161 :
162 :
163 : std::string
164 6557955 : MSBaseVehicle::getFlowID() const {
165 6557955 : return getID().substr(0, getID().rfind('.'));
166 : }
167 :
168 :
169 : void
170 4613644 : MSBaseVehicle::initDevices() {
171 4613644 : MSDevice::buildVehicleDevices(*this, myDevices);
172 8397368 : for (MSVehicleDevice* dev : myDevices) {
173 3783740 : myMoveReminders.push_back(std::make_pair(dev, 0.));
174 : }
175 4613628 : if (MSGlobals::gHaveEmissions) {
176 : // ensure we have the emission parameters even if we don't have the device
177 852248 : getEmissionParameters();
178 : }
179 4613628 : }
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 12511246547 : MSBaseVehicle::getParameter() const {
189 12511246547 : return *myParameter;
190 : }
191 :
192 :
193 : void
194 496 : MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
195 496 : delete myParameter;
196 496 : myParameter = newParameter;
197 496 : }
198 :
199 :
200 : bool
201 632448494 : MSBaseVehicle::ignoreTransientPermissions() const {
202 632448494 : return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
203 : }
204 :
205 : double
206 5906272812 : MSBaseVehicle::getMaxSpeed() const {
207 5906272812 : return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
208 : }
209 :
210 :
211 : const MSEdge*
212 1709838122 : MSBaseVehicle::succEdge(int nSuccs) const {
213 1709838122 : if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
214 1346600541 : return *(myCurrEdge + nSuccs);
215 : } else {
216 363237581 : return nullptr;
217 : }
218 : }
219 :
220 :
221 : const MSEdge*
222 2947188232 : MSBaseVehicle::getEdge() const {
223 2947188232 : return *myCurrEdge;
224 : }
225 :
226 :
227 : const std::set<SUMOTrafficObject::NumericalID>
228 67589 : MSBaseVehicle::getUpcomingEdgeIDs() const {
229 : std::set<SUMOTrafficObject::NumericalID> result;
230 305517 : for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
231 237928 : result.insert((*e)->getNumericalID());
232 : }
233 67589 : return result;
234 : }
235 :
236 :
237 : bool
238 112743 : MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
239 112743 : if (stop == nullptr) {
240 : return false;
241 : }
242 261024 : for (const MSStop& s : myStops) {
243 186512 : if (s.busstop == stop
244 148300 : || s.containerstop == stop
245 148294 : || s.parkingarea == stop
246 148289 : || s.chargingStation == stop) {
247 : return true;
248 : }
249 : }
250 : return false;
251 : }
252 :
253 : bool
254 184830 : MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
255 391999 : for (const MSStop& s : myStops) {
256 366033 : if (&s.lane->getEdge() == edge) {
257 : return true;
258 : }
259 : }
260 25966 : return myRoute->getLastEdge() == edge;
261 : }
262 :
263 :
264 : bool
265 2663458 : 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 2663458 : const MSEdge* source = withTaz && onInit ? MSEdge::dictionary(myParameter->fromTaz + "-source") : *getRerouteOrigin();
268 2663458 : if (source == nullptr) {
269 289 : source = *getRerouteOrigin();
270 : }
271 2663458 : if (sink == nullptr) {
272 2636187 : sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
273 2636187 : if (sink == nullptr) {
274 289 : sink = myRoute->getLastEdge();
275 : }
276 : }
277 2674345 : 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 2663458 : if (myParameter->via.size() == 0) {
283 2654945 : double firstPos = INVALID_DOUBLE;
284 2654945 : double lastPos = INVALID_DOUBLE;
285 2654945 : stops = getStopEdges(firstPos, lastPos, jumps);
286 2654945 : if (stops.size() > 0) {
287 39307 : double sourcePos = onInit ? 0 : getPositionOnLane();
288 39307 : if (MSGlobals::gUseMesoSim && isStopped()) {
289 231 : sourcePos = getNextStop().pars.endPos;
290 : }
291 : // avoid superfluous waypoints for first and last edge
292 39307 : const bool skipFirst = stops.front() == source && (source != getEdge() || sourcePos + getBrakeGap() <= firstPos + NUMERICAL_EPS);
293 39307 : const bool skipLast = (stops.back() == sink
294 21639 : && myArrivalPos >= lastPos
295 13230 : && (stops.size() < 2 || stops.back() != stops[stops.size() - 2])
296 52522 : && (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 39307 : if (stops.size() == 1 && (skipFirst || skipLast)) {
305 : stops.clear();
306 : } else {
307 31210 : if (skipFirst) {
308 : stops.erase(stops.begin());
309 : }
310 31210 : if (skipLast) {
311 : stops.erase(stops.end() - 1);
312 : }
313 : }
314 39307 : stopAtSink = stops.size() > 0 && stops.back() == sink && jumps.size() == 0;
315 : }
316 : } else {
317 : std::set<const MSEdge*> jumpEdges;
318 20741 : 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 26550 : for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
326 18045 : MSEdge* viaEdge = MSEdge::dictionary(*it);
327 18045 : if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
328 3098 : continue;
329 : }
330 : assert(viaEdge != 0);
331 14947 : 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 14939 : 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 2721184 : for (const MSEdge* const stopEdge : stops) {
343 57916 : 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 57158 : 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 57158 : if (into.size() > 0) {
354 : into.pop_back();
355 56960 : edges.insert(edges.end(), into.begin(), into.end());
356 56960 : if (stopEdge->isTazConnector()) {
357 49 : source = into.back();
358 : edges.pop_back();
359 : } else {
360 56911 : source = stopEdge;
361 : }
362 : } else {
363 198 : if ((source != sink || !stopAtSink)) {
364 364 : std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
365 182 : if (MSGlobals::gCheckRoutes || silent) {
366 364 : throw ProcessError(error);
367 : } else {
368 182 : WRITE_WARNING(error);
369 0 : edges.push_back(source);
370 : }
371 : }
372 16 : source = stopEdge;
373 : }
374 57916 : }
375 2630869 : if (stops.empty() && source == sink && onInit
376 18615 : && myParameter->departPosProcedure == DepartPosDefinition::GIVEN
377 91 : && myParameter->arrivalPosProcedure == ArrivalPosDefinition::GIVEN
378 2663289 : && myParameter->departPos > myParameter->arrivalPos) {
379 14 : router.computeLooped(source, sink, this, t, edges, silent);
380 : } else {
381 2663254 : if (!router.compute(source, sink, this, t, edges, silent)) {
382 : edges.clear();
383 : }
384 : }
385 :
386 : // router.setHint(myCurrEdge, myRoute->end(), this, t);
387 2663268 : if (edges.empty() && silent) {
388 : return false;
389 : }
390 2662515 : if (!edges.empty() && edges.front()->isTazConnector()) {
391 : edges.erase(edges.begin());
392 : }
393 2662515 : if (!edges.empty() && edges.back()->isTazConnector()) {
394 : edges.pop_back();
395 : }
396 2662515 : const double routeCost = router.recomputeCosts(edges, this, t);
397 2662515 : const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
398 2662515 : 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 2662515 : replaceRouteEdges(edges, routeCost, savings, info, onInit);
405 : // this must be called even if the route could not be replaced
406 2662515 : if (onInit) {
407 2087790 : if (edges.empty()) {
408 191 : if (MSGlobals::gCheckRoutes) {
409 342 : throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
410 77 : } else if (source->isTazConnector()) {
411 385 : WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
412 27 : MSNet::getInstance()->getInsertionControl().descheduleDeparture(this);
413 : return false;
414 : }
415 : }
416 2087649 : setDepartAndArrivalEdge();
417 2087649 : calculateArrivalParams(onInit);
418 : }
419 2662374 : return !edges.empty();
420 2664066 : }
421 :
422 :
423 : bool
424 2684213 : MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
425 2684213 : if (edges.empty()) {
426 1686 : WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
427 562 : if (msgReturn != nullptr) {
428 : *msgReturn = "No route found";
429 : }
430 562 : return false;
431 : }
432 : // build a new id, first
433 : std::string id = getID();
434 2683651 : if (id[0] != '!') {
435 5367302 : id = "!" + id;
436 : }
437 2683651 : const std::string idSuffix = id + "!var#";
438 2683651 : int varIndex = 1;
439 2683651 : id = idSuffix + toString(varIndex);
440 4886799 : while (MSRoute::hasRoute(id)) {
441 4406296 : id = idSuffix + toString(++varIndex);
442 : }
443 2683651 : int oldSize = (int)edges.size();
444 2683651 : if (!onInit) {
445 594428 : const MSEdge* const origin = *getRerouteOrigin();
446 594428 : if (origin != *myCurrEdge && edges.front() == origin) {
447 10664 : edges.insert(edges.begin(), *myCurrEdge);
448 10664 : oldSize = (int)edges.size();
449 : }
450 1188856 : edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
451 : }
452 2683651 : if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
453 : // re-assign stop iterators when rerouting to a new parkingArea / insertStop
454 : return true;
455 : }
456 1447638 : const RGBColor& c = myRoute->getColor();
457 1447638 : 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 1447638 : ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
461 2895276 : 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 1447670 : 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 2895274 : 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 1944412 : 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 1944412 : if (onInit) {
491 1398893 : myCurrEdge = newRoute->begin();
492 : } else {
493 545519 : MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
494 545519 : 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 545517 : if (getLane() != nullptr) {
506 412728 : if (getLane()->getEdge().isInternal() && (
507 412729 : (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 412727 : } else if (getPositionOnLane() > getLane()->getLength()
518 412732 : && (myCurrEdge + 1) != myRoute->end()
519 10 : && (newCurrEdge + 1) != edges.end()
520 412737 : && *(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 545511 : myCurrEdge = newCurrEdge;
533 : }
534 1944404 : const bool stopsFromScratch = onInit && myRoute->getStops().empty();
535 : // assign new route
536 1944404 : checkRouteRemoval();
537 : myRoute = newRoute;
538 : // update arrival definition
539 1944404 : calculateArrivalParams(onInit);
540 : // save information that the vehicle was rerouted
541 1944404 : myNumberReroutes++;
542 1944404 : myStopUntilOffset += myRoute->getPeriod();
543 1944404 : 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 2003568 : for (std::vector<SUMOVehicleParameter::Stop>::iterator it = myPastStops.begin(); it != myPastStops.end();) {
557 85485 : const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
558 59164 : if (std::find(myRoute->begin(), myRoute->end(), stopEdge) == myRoute->end()) {
559 3 : 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 1944404 : if (stopsFromScratch) {
566 : myStops.clear();
567 1398829 : addStops(!MSGlobals::gCheckRoutes);
568 : } else {
569 : // recheck old stops
570 545575 : MSRouteIterator searchStart = myCurrEdge;
571 545575 : double lastPos = getPositionOnLane() + getBrakeGap();
572 958297 : if (getLane() != nullptr && getLane()->isInternal()
573 546426 : && 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 576397 : for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
580 30822 : 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 30822 : if (*searchStart != &iter->lane->getEdge()
587 30822 : || endPos + NUMERICAL_EPS < lastPos) {
588 27895 : if (searchStart != edges.end() && !iter->reached) {
589 : searchStart++;
590 : }
591 : }
592 : lastPos = endPos;
593 :
594 30822 : 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 30822 : 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 30635 : setSkips(*iter, stopIndex);
608 30635 : searchStart = iter->edge;
609 : }
610 : ++iter;
611 30635 : stopIndex++;
612 : }
613 : // add new stops
614 545575 : if (addRouteStops) {
615 497030 : 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 160540 : MSBaseVehicle::getAcceleration() const {
630 160540 : return 0;
631 : }
632 :
633 :
634 : void
635 3312499 : MSBaseVehicle::onDepart() {
636 3312499 : myDeparture = MSNet::getInstance()->getCurrentTimeStep();
637 3312499 : myDepartPos = getPositionOnLane();
638 3312499 : MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
639 3312499 : }
640 :
641 :
642 : SUMOTime
643 2629428 : MSBaseVehicle:: getDepartDelay() const {
644 2629428 : const SUMOTime dep = getParameter().depart;
645 2629428 : if (dep < 0) {
646 : return 0;
647 : }
648 2629321 : 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 23489453 : MSBaseVehicle::getRoutePosition() const {
660 23489453 : return (int) std::distance(myRoute->begin(), myCurrEdge);
661 : }
662 :
663 :
664 : void
665 100994 : MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
666 100994 : myCurrEdge = myRoute->begin() + index;
667 100994 : const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
668 : // !!! hack
669 100994 : myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
670 100994 : }
671 :
672 : double
673 975632 : MSBaseVehicle::getOdometer() const {
674 975632 : return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
675 : }
676 :
677 : bool
678 310428 : MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
679 310428 : if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
680 : return false;
681 206699 : } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
682 : return false;
683 : }
684 296487 : if (isStopped() && myStops.begin()->pars.permitted.size() > 0
685 148299 : && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
686 5844 : return false;
687 : }
688 142455 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
689 : if (taxiDevice != nullptr) {
690 23255 : return taxiDevice->allowsBoarding(t);
691 : }
692 : return true;
693 : }
694 :
695 :
696 : void
697 12879 : MSBaseVehicle::addTransportable(MSTransportable* transportable) {
698 12879 : if (transportable->isPerson()) {
699 12149 : if (myPersonDevice == nullptr) {
700 4158 : myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
701 4158 : myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
702 4158 : if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
703 1901 : const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
704 : }
705 : }
706 12149 : 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 12879 : }
718 :
719 :
720 : bool
721 2050 : MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
722 2827 : for (const MSStop& stop : myStops) {
723 1033 : if (stop.edge == it) {
724 256 : return stop.pars.jump >= 0;
725 : }
726 : }
727 : return false;
728 : }
729 :
730 :
731 : bool
732 3743070 : MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
733 3743070 : MSRouteIterator start = myCurrEdge;
734 3743070 : if (route == nullptr) {
735 : route = myRoute;
736 : } else {
737 3067749 : start = route->begin();
738 : }
739 : const bool checkJumps = route == myRoute; // the edge iterators in the stops are invalid otherwise
740 3743070 : MSRouteIterator last = route->end() - 1;
741 : // check connectivity, first
742 19429211 : for (MSRouteIterator e = start; e != last; ++e) {
743 15720231 : const MSEdge& next = **(e + 1);
744 15720231 : if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
745 34237 : if (!checkJumps || !hasJump(e)) {
746 34144 : if ((myRoutingMode & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) == 0
747 34144 : || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
748 102270 : msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
749 34090 : return false;
750 : }
751 : }
752 : }
753 : }
754 3708980 : last = route->end();
755 : // check usable lanes, then
756 23103246 : for (MSRouteIterator e = start; e != last; ++e) {
757 19394266 : if ((*e)->prohibits(this)) {
758 0 : msg = TLF("Edge '%' prohibits.", (*e)->getID());
759 : return false;
760 : }
761 : }
762 : return true;
763 : }
764 :
765 :
766 : bool
767 506537583 : MSBaseVehicle::hasValidRouteStart(std::string& msg) {
768 506537583 : if (!(*myCurrEdge)->isTazConnector()) {
769 506400537 : if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
770 12 : msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
771 6 : myRouteValidity |= ROUTE_START_INVALID_LANE;
772 6 : return false;
773 : }
774 : }
775 506537577 : if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
776 506537519 : myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
777 506537519 : return true;
778 : } else {
779 174 : msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
780 58 : myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
781 58 : return false;
782 : }
783 : }
784 :
785 :
786 : int
787 4820402668 : MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
788 4820402668 : if (!update) {
789 2049355747 : return myRouteValidity;
790 : }
791 : // insertion check must be done in any case
792 : std::string msg;
793 2771046921 : if (!hasValidRouteStart(msg)) {
794 182 : if (MSGlobals::gCheckRoutes) {
795 220 : throw ProcessError(msg);
796 72 : } else if (!silent) {
797 : // vehicle will be discarded
798 138 : WRITE_WARNING(msg);
799 26 : } else if (msgReturn != nullptr) {
800 : *msgReturn = msg;
801 : }
802 : }
803 : if (MSGlobals::gCheckRoutes
804 2771032208 : && (myRouteValidity & ROUTE_UNCHECKED) != 0
805 : // we could check after the first rerouting
806 2775533935 : && (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
807 6066468 : if (!hasValidRoute(msg, myRoute)) {
808 72 : myRouteValidity |= ROUTE_INVALID;
809 216 : throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
810 : }
811 : }
812 2771046739 : myRouteValidity &= ~ROUTE_UNCHECKED;
813 : return myRouteValidity;
814 : }
815 :
816 : void
817 19433491 : MSBaseVehicle::addReminder(MSMoveReminder* rem) {
818 : #ifdef _DEBUG
819 : if (myTraceMoveReminders) {
820 : traceMoveReminder("add", rem, 0, true);
821 : }
822 : #endif
823 19433491 : myMoveReminders.push_back(std::make_pair(rem, 0.));
824 19433491 : }
825 :
826 :
827 : void
828 0 : MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
829 0 : for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
830 0 : if (r->first == rem) {
831 : #ifdef _DEBUG
832 : if (myTraceMoveReminders) {
833 : traceMoveReminder("remove", rem, 0, false);
834 : }
835 : #endif
836 : myMoveReminders.erase(r);
837 : return;
838 : }
839 : }
840 : }
841 :
842 :
843 : void
844 23773517 : MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
845 54045788 : for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
846 30272271 : if (rem->first->notifyEnter(*this, reason, enteredLane)) {
847 : #ifdef _DEBUG
848 : if (myTraceMoveReminders) {
849 : traceMoveReminder("notifyEnter", rem->first, rem->second, true);
850 : }
851 : #endif
852 : ++rem;
853 : } else {
854 : #ifdef _DEBUG
855 : if (myTraceMoveReminders) {
856 : traceMoveReminder("notifyEnter", rem->first, rem->second, false);
857 : }
858 : #endif
859 : rem = myMoveReminders.erase(rem);
860 : }
861 : }
862 23773517 : }
863 :
864 :
865 : void
866 7154728 : MSBaseVehicle::calculateArrivalParams(bool onInit) {
867 7154728 : if (myRoute->getLastEdge()->isTazConnector()) {
868 : return;
869 : }
870 7154728 : const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
871 7154728 : if (arrivalEdgeIndex != myParameter->arrivalEdge) {
872 42 : WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
873 : getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
874 : }
875 7154728 : const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
876 7154728 : if (!onInit) {
877 545511 : arrivalEdge = myRoute->getLastEdge();
878 : // ignore arrivalEdge parameter after rerouting
879 545511 : const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
880 : }
881 : const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
882 7154728 : const double lastLaneLength = lanes[0]->getLength();
883 7154728 : switch (myParameter->arrivalPosProcedure) {
884 201239 : case ArrivalPosDefinition::GIVEN:
885 201239 : if (fabs(myParameter->arrivalPos) > lastLaneLength) {
886 3048 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
887 : }
888 : // Maybe we should warn the user about invalid inputs!
889 201239 : myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
890 201239 : if (myArrivalPos < 0) {
891 20597 : myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
892 : }
893 : break;
894 : case ArrivalPosDefinition::RANDOM:
895 74093 : myArrivalPos = RandHelper::rand(lastLaneLength);
896 74093 : break;
897 0 : case ArrivalPosDefinition::CENTER:
898 0 : myArrivalPos = lastLaneLength / 2.;
899 0 : break;
900 6879396 : default:
901 6879396 : myArrivalPos = lastLaneLength;
902 6879396 : break;
903 : }
904 7154728 : if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
905 115107 : if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
906 283707 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
907 : }
908 115107 : myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
909 7039621 : } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
910 7 : myArrivalLane = -1;
911 7 : for (MSLane* lane : lanes) {
912 7 : if (lane->allowsVehicleClass(myType->getVehicleClass())) {
913 7 : myArrivalLane = lane->getIndex();
914 7 : break;
915 : }
916 : }
917 7 : if (myArrivalLane == -1) {
918 0 : WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
919 0 : myArrivalLane = 0;
920 : }
921 7039614 : } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
922 : // pick random lane among all usable lanes
923 : std::vector<MSLane*> usable;
924 364240 : for (MSLane* lane : lanes) {
925 279473 : if (lane->allowsVehicleClass(myType->getVehicleClass())) {
926 261555 : usable.push_back(lane);
927 : }
928 : }
929 84767 : if (usable.empty()) {
930 0 : WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
931 0 : myArrivalLane = 0;
932 : } else {
933 84767 : myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
934 : }
935 84767 : }
936 7154728 : if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
937 180561 : for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
938 142241 : if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
939 : return;
940 : }
941 : }
942 114960 : WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
943 : }
944 : }
945 :
946 : void
947 5208960 : MSBaseVehicle::setDepartAndArrivalEdge() {
948 5208960 : SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
949 5208960 : if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
950 7871 : const int routeEdges = (int)myRoute->getEdges().size();
951 7871 : if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
952 : // write specific edge in vehroute output for reproducibility
953 4185 : pars->departEdge = RandHelper::rand(0, routeEdges);
954 4185 : pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
955 : }
956 : assert(pars->departEdge >= 0);
957 7871 : if (pars->departEdge >= routeEdges) {
958 0 : WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
959 : } else {
960 : myCurrEdge += pars->departEdge;
961 : }
962 : }
963 5208960 : if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
964 147 : const int routeEdges = (int)myRoute->getEdges().size();
965 147 : const int begin = (int)(myCurrEdge - myRoute->begin());
966 : // write specific edge in vehroute output for reproducibility
967 147 : pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
968 147 : pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
969 : assert(pars->arrivalEdge >= begin);
970 : assert(pars->arrivalEdge < routeEdges);
971 : }
972 5208960 : }
973 :
974 :
975 : double
976 569177424 : MSBaseVehicle::getImpatience() const {
977 1138354848 : return MAX2(0., MIN2(1., getVehicleType().getImpatience()
978 569177424 : + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
979 569177424 : + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
980 : }
981 :
982 :
983 : MSDevice*
984 780480000 : MSBaseVehicle::getDevice(const std::type_info& type) const {
985 1409702870 : for (MSVehicleDevice* const dev : myDevices) {
986 684317369 : if (typeid(*dev) == type) {
987 55094499 : return dev;
988 : }
989 : }
990 : return nullptr;
991 : }
992 :
993 :
994 : void
995 2817 : MSBaseVehicle::saveState(OutputDevice& out) {
996 : // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
997 2817 : const std::string& typeID = MSNet::getInstance()->getVehicleControl().hasVTypeDistribution(myParameter->vtypeid) || getVehicleType().isVehicleSpecific() ? getVehicleType().getID() : "";
998 2817 : myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
999 : // params and stops must be written in child classes since they may wish to add additional attributes first
1000 : out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
1001 2817 : std::ostringstream os;
1002 5634 : os << myOdometer << " " << myNumberReroutes;
1003 2817 : out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
1004 2817 : if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
1005 2817 : const int precision = out.precision();
1006 2817 : out.setPrecision(MAX2(gPrecisionRandom, precision));
1007 2817 : out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
1008 2817 : out.setPrecision(precision);
1009 : }
1010 2817 : if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
1011 3872 : out.writeAttr(SUMO_ATTR_REROUTE, true);
1012 : }
1013 2817 : if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
1014 : // could be set from stop
1015 : out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
1016 : }
1017 : // here starts the vehicle internal part (see loading)
1018 : // @note: remember to close the vehicle tag when calling this in a subclass!
1019 5634 : }
1020 :
1021 :
1022 : bool
1023 0 : MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
1024 : UNUSED_PARAMETER(stop);
1025 : UNUSED_PARAMETER(distToStop);
1026 0 : return true;
1027 : }
1028 :
1029 :
1030 : bool
1031 7067913346 : MSBaseVehicle::isStopped() const {
1032 7067913346 : return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
1033 : }
1034 :
1035 :
1036 : bool
1037 2015600985 : MSBaseVehicle::isParking() const {
1038 2063104700 : return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
1039 328977 : && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
1040 2015809182 : && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
1041 : }
1042 :
1043 :
1044 : bool
1045 523621942 : MSBaseVehicle::isJumping() const {
1046 523621942 : return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
1047 : }
1048 :
1049 :
1050 : bool
1051 6250870 : MSBaseVehicle::isStoppedTriggered() const {
1052 6250870 : return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
1053 : }
1054 :
1055 :
1056 : bool
1057 23795 : MSBaseVehicle::isStoppedParking() const {
1058 23795 : return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
1059 : }
1060 :
1061 :
1062 : bool
1063 17230 : MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
1064 17230 : if (isStopped() || (checkFuture && hasStops())) {
1065 : const MSStop& stop = myStops.front();
1066 18147 : return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
1067 : }
1068 : return false;
1069 : }
1070 :
1071 : bool
1072 11470 : MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
1073 : // Check if there is a parking area to be replaced
1074 11470 : if (parkingArea == 0) {
1075 : errorMsg = "new parkingArea is NULL";
1076 0 : return false;
1077 : }
1078 11470 : if (myStops.size() == 0) {
1079 : errorMsg = "vehicle has no stops";
1080 0 : return false;
1081 : }
1082 11470 : if (myStops.front().parkingarea == 0) {
1083 : errorMsg = "first stop is not at parkingArea";
1084 0 : return false;
1085 : }
1086 : MSStop& first = myStops.front();
1087 : SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
1088 11470 : std::string oldStopEdgeID = first.lane->getEdge().getID();
1089 : // merge subsequent duplicate stops equals to parking area
1090 11490 : for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
1091 331 : if (iter->parkingarea == parkingArea) {
1092 20 : stopPar.duration += iter->duration;
1093 20 : myStops.erase(iter++);
1094 : } else {
1095 : break;
1096 : }
1097 : }
1098 11470 : stopPar.lane = parkingArea->getLane().getID();
1099 11470 : stopPar.parkingarea = parkingArea->getID();
1100 11470 : stopPar.startPos = parkingArea->getBeginLanePosition();
1101 11470 : stopPar.endPos = parkingArea->getEndLanePosition();
1102 11470 : first.edge = myRoute->end(); // will be patched in replaceRoute
1103 11470 : first.lane = &parkingArea->getLane();
1104 11470 : first.parkingarea = parkingArea;
1105 :
1106 : // patch via edges
1107 11470 : std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
1108 11470 : if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
1109 198 : myParameter->via.erase(myParameter->via.begin());
1110 198 : myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
1111 : }
1112 : return true;
1113 : }
1114 :
1115 :
1116 : MSParkingArea*
1117 58597 : MSBaseVehicle::getNextParkingArea() {
1118 : MSParkingArea* nextParkingArea = nullptr;
1119 58597 : if (!myStops.empty()) {
1120 57646 : SUMOVehicleParameter::Stop stopPar;
1121 57646 : MSStop stop = myStops.front();
1122 57646 : if (!stop.reached && stop.parkingarea != nullptr) {
1123 : nextParkingArea = stop.parkingarea;
1124 : }
1125 57646 : }
1126 58597 : return nextParkingArea;
1127 : }
1128 :
1129 :
1130 : MSParkingArea*
1131 84783 : MSBaseVehicle::getCurrentParkingArea() {
1132 : MSParkingArea* currentParkingArea = nullptr;
1133 84783 : if (isParking()) {
1134 84766 : currentParkingArea = myStops.begin()->parkingarea;
1135 : }
1136 84783 : return currentParkingArea;
1137 : }
1138 :
1139 :
1140 : const std::vector<std::string>&
1141 21 : MSBaseVehicle::getParkingBadges() const {
1142 21 : if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
1143 7 : return myParameter->parkingBadges;
1144 : } else {
1145 14 : return getVehicleType().getParkingBadges();
1146 : }
1147 : }
1148 :
1149 :
1150 : double
1151 7571939 : MSBaseVehicle::basePos(const MSEdge* edge) const {
1152 7571939 : double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
1153 7571939 : if (hasStops()
1154 7596515 : && myStops.front().edge == myRoute->begin()
1155 7596515 : && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
1156 24548 : result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
1157 : }
1158 7571939 : return result;
1159 : }
1160 :
1161 :
1162 : MSLane*
1163 298 : MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
1164 298 : const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
1165 298 : const MSEdge* edge = MSEdge::dictionary(edgeID);
1166 298 : if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
1167 8 : return nullptr;
1168 : }
1169 580 : const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
1170 290 : if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
1171 290 : const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
1172 290 : stop.edge = edgeID;
1173 290 : return edge->getOppositeEdge()->getLanes()[oppositeIndex];
1174 : }
1175 : return nullptr;
1176 : }
1177 :
1178 :
1179 : bool
1180 127803 : MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
1181 : MSRouteIterator* searchStart) {
1182 127803 : MSStop stop(stopPar);
1183 127803 : if (stopPar.lane == "") {
1184 2465 : MSEdge* e = MSEdge::dictionary(stopPar.edge);
1185 2465 : stop.lane = e->getFirstAllowed(getVClass());
1186 2465 : if (stop.lane == nullptr) {
1187 0 : errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
1188 0 : return false;
1189 : }
1190 : } else {
1191 125338 : stop.lane = MSLane::dictionary(stopPar.lane);
1192 125338 : if (stop.lane == nullptr) {
1193 : // must be an opposite stop
1194 145 : SUMOVehicleParameter::Stop tmp = stopPar;
1195 145 : stop.lane = interpretOppositeStop(tmp);
1196 : assert(stop.lane != nullptr);
1197 145 : }
1198 125338 : if (!stop.lane->allowsVehicleClass(myType->getVehicleClass())) {
1199 32 : errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
1200 16 : return false;
1201 : }
1202 : }
1203 127787 : if (MSGlobals::gUseMesoSim) {
1204 16278 : stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
1205 16278 : if (stop.lane->isInternal()) {
1206 2 : errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
1207 1 : return false;
1208 : }
1209 : }
1210 127786 : stop.initPars(stopPar);
1211 127786 : if (stopPar.until != -1) {
1212 : // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
1213 41021 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
1214 : }
1215 127786 : if (stopPar.arrival != -1) {
1216 589 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
1217 : }
1218 127786 : std::string stopType = "stop";
1219 127786 : std::string stopID = "";
1220 127786 : if (stop.busstop != nullptr) {
1221 : stopType = "busStop";
1222 33469 : stopID = stop.busstop->getID();
1223 94317 : } else if (stop.containerstop != nullptr) {
1224 : stopType = "containerStop";
1225 727 : stopID = stop.containerstop->getID();
1226 93590 : } else if (stop.chargingStation != nullptr) {
1227 : stopType = "chargingStation";
1228 8067 : stopID = stop.chargingStation->getID();
1229 85523 : } else if (stop.overheadWireSegment != nullptr) {
1230 : stopType = "overheadWireSegment";
1231 0 : stopID = stop.overheadWireSegment->getID();
1232 85523 : } else if (stop.parkingarea != nullptr) {
1233 : stopType = "parkingArea";
1234 16242 : stopID = stop.parkingarea->getID();
1235 : }
1236 255572 : const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
1237 :
1238 127786 : if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
1239 0 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
1240 0 : return false;
1241 : }
1242 58505 : if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > stop.pars.endPos - stop.pars.startPos
1243 187164 : && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
1244 834 : errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
1245 : }
1246 127786 : if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
1247 : // forbid access in case the parking requests other badges
1248 14 : errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
1249 7 : return false;
1250 : }
1251 127779 : const MSEdge* stopLaneEdge = &stop.lane->getEdge();
1252 : const MSEdge* stopEdge;
1253 127779 : if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
1254 : // stop lane is on the opposite side
1255 145 : stopEdge = stopLaneEdge->getOppositeEdge();
1256 145 : stop.isOpposite = true;
1257 : } else {
1258 : // if stop is on an internal edge the normal edge before the intersection is used
1259 127634 : stopEdge = stopLaneEdge->getNormalBefore();
1260 : }
1261 127779 : MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
1262 127779 : if (searchStart == nullptr) {
1263 124325 : searchStart = &myCurrEdge;
1264 124325 : if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
1265 : // already on the intersection but myCurrEdge is before it
1266 : searchStart = ≻
1267 : }
1268 : }
1269 : #ifdef DEBUG_ADD_STOP
1270 : if (DEBUG_COND) {
1271 : std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
1272 : << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
1273 : << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
1274 : << "\n";
1275 : }
1276 : #endif
1277 127779 : stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
1278 127779 : MSRouteIterator prevStopEdge = myCurrEdge;
1279 127779 : const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
1280 127779 : double prevStopPos = getPositionOnLane();
1281 : // where to insert the stop
1282 : std::list<MSStop>::iterator iter = myStops.begin();
1283 127779 : if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
1284 : iter = myStops.end();
1285 103439 : if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
1286 : prevStopEdge = myStops.back().edge;
1287 38877 : prevEdge = &myStops.back().lane->getEdge();
1288 38877 : prevStopPos = myStops.back().pars.endPos;
1289 38877 : stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1290 : if (prevStopEdge == stop.edge // laneEdge check is insufficient for looped routes
1291 5979 : && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
1292 44844 : && (prevStopPos > stop.pars.endPos ||
1293 2481 : (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
1294 424 : stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
1295 : }
1296 : #ifdef DEBUG_ADD_STOP
1297 : if (DEBUG_COND) {
1298 : std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
1299 : << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
1300 : }
1301 : #endif
1302 : }
1303 : // skip a number of occurences of stopEdge in looped route
1304 103439 : int skipLooped = stopPar.index - static_cast<int>(myStops.size());
1305 103524 : for (int j = 0; j < skipLooped; j++) {
1306 231 : auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
1307 231 : if (nextIt == myRoute->end()) {
1308 146 : if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
1309 : // only warn if the route loops over the stop edge at least once
1310 28 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
1311 : }
1312 146 : break;
1313 : } else {
1314 85 : stop.edge = nextIt;
1315 : }
1316 : }
1317 : } else {
1318 24340 : if (stopPar.index == STOP_INDEX_FIT) {
1319 36241 : while (iter != myStops.end() && (iter->edge < stop.edge ||
1320 1991 : (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
1321 1991 : (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
1322 : prevStopEdge = iter->edge;
1323 12000 : prevStopPos = iter->pars.endPos;
1324 : ++iter;
1325 : }
1326 : } else {
1327 : int index = stopPar.index;
1328 99 : while (index > 0) {
1329 0 : prevStopEdge = iter->edge;
1330 0 : prevStopPos = iter->pars.endPos;
1331 : ++iter;
1332 0 : --index;
1333 : }
1334 : #ifdef DEBUG_ADD_STOP
1335 : if (DEBUG_COND) {
1336 : std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
1337 : }
1338 : #endif
1339 99 : stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1340 : }
1341 : }
1342 128080 : const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
1343 127779 : if (stop.edge == myRoute->end()) {
1344 72 : if (!wasTooClose) {
1345 192 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
1346 : }
1347 72 : return false;
1348 : }
1349 :
1350 127707 : const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
1351 32676 : prevStopPos + (iter == myStops.begin() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
1352 :
1353 127707 : if (prevStopEdge > stop.edge ||
1354 : // a collision-stop happens after vehicle movement and may move the
1355 : // vehicle backwards on its lane (prevStopPos is the vehicle position)
1356 1575 : (tooClose && !stop.pars.collision)
1357 255398 : || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
1358 : // check if the edge occurs again later in the route
1359 : //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges()) << "\n";
1360 16 : if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
1361 48 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
1362 : }
1363 16 : MSRouteIterator next = stop.edge + 1;
1364 16 : return addStop(stopPar, errorMsg, untilOffset, &next);
1365 : }
1366 127691 : if (wasTooClose) {
1367 : errorMsg = "";
1368 : }
1369 : // David.C:
1370 : //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
1371 127691 : const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
1372 127691 : const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
1373 127691 : if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
1374 : return false;
1375 : }
1376 127691 : if (!hasDeparted() && myCurrEdge == stop.edge) {
1377 : double pos = -1;
1378 26180 : if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
1379 4597 : pos = myParameter->departPos;
1380 4597 : if (pos < 0.) {
1381 194 : pos += (*myCurrEdge)->getLength();
1382 : }
1383 : }
1384 26180 : if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
1385 19190 : pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
1386 : }
1387 26180 : if (pos > stop.pars.endPos + endPosOffset) {
1388 20 : if (stop.edge != myRoute->end()) {
1389 : // check if the edge occurs again later in the route
1390 20 : MSRouteIterator next = stop.edge + 1;
1391 20 : return addStop(stopPar, errorMsg, untilOffset, &next);
1392 : }
1393 0 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
1394 0 : return false;
1395 : }
1396 : }
1397 127671 : if (iter != myStops.begin()) {
1398 : std::list<MSStop>::iterator iter2 = iter;
1399 : iter2--;
1400 75539 : if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
1401 50836 : && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
1402 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1403 18 : + "' set to end at " + time2string(stop.getUntil())
1404 24 : + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
1405 : }
1406 50819 : if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1407 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1408 18 : + "' set to start at " + time2string(stop.pars.arrival)
1409 24 : + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
1410 : }
1411 50819 : if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1412 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1413 18 : + "' set to start at " + time2string(stop.pars.arrival)
1414 24 : + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
1415 : }
1416 : } else {
1417 93149 : if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
1418 76864 : && (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
1419 6 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1420 18 : + "' set to end at " + time2string(stop.getUntil())
1421 24 : + " earlier than departure at " + time2string(getParameter().depart) + ".";
1422 : }
1423 : }
1424 127671 : if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
1425 18 : errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1426 54 : + "' set to end at " + time2string(stop.getUntil())
1427 72 : + " earlier than arrival at " + time2string(stop.getArrival()) + ".";
1428 : }
1429 127671 : setSkips(stop, (int)myStops.size());
1430 127671 : myStops.insert(iter, stop);
1431 127671 : if (stopPar.tripId != "") {
1432 2500 : MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
1433 : }
1434 : //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
1435 : // << " routeIndex=" << (stop.edge - myRoute->begin())
1436 : // << " stopIndex=" << std::distance(myStops.begin(), iter)
1437 : // << " route=" << toString(myRoute->getEdges()) << "\n";
1438 : return true;
1439 : }
1440 :
1441 :
1442 : void
1443 158306 : MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
1444 158306 : if (hasDeparted() && stop.edge > myRoute->begin()) {
1445 : // if the route is looped we must patch the index to ensure that state
1446 : // loading (and vehroute-output) encode the correct number of skips
1447 : int foundSkips = 0;
1448 : MSRouteIterator itPrev;
1449 : double prevEndPos;
1450 61880 : if (prevActiveStops > 0) {
1451 : assert((int)myStops.size() >= prevActiveStops);
1452 : auto prevStopIt = myStops.begin();
1453 32231 : std::advance(prevStopIt, prevActiveStops - 1);
1454 : const MSStop& prev = *prevStopIt;
1455 32231 : itPrev = prev.edge;
1456 32231 : prevEndPos = prev.pars.endPos;
1457 29649 : } else if (myPastStops.size() > 0) {
1458 11800 : itPrev = myRoute->begin() + myPastStops.back().routeIndex;
1459 11800 : prevEndPos = myPastStops.back().endPos;
1460 : } else {
1461 17849 : itPrev = myRoute->begin() + myParameter->departEdge;
1462 17849 : prevEndPos = myDepartPos;
1463 : }
1464 : //auto itPrevOrig = itPrev;
1465 61880 : if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
1466 : itPrev++;
1467 : }
1468 : //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
1469 584204 : while (itPrev < stop.edge) {
1470 522324 : if (*itPrev == *stop.edge) {
1471 19570 : foundSkips++;
1472 : }
1473 : itPrev++;
1474 : }
1475 : int newIndex = STOP_INDEX_END;
1476 61880 : if (foundSkips > 0) {
1477 : //if (getID() == "77_0_0") {
1478 : // std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
1479 : // << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
1480 : // << " prevEdge=" << (*itPrevOrig)->getID()
1481 : // << " prevIndex=" << (itPrevOrig - myRoute->begin())
1482 : // << " skips=" << foundSkips << "\n";
1483 : //}
1484 7021 : newIndex = (int)myPastStops.size() + prevActiveStops + foundSkips;
1485 : }
1486 61880 : const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
1487 : }
1488 158306 : }
1489 :
1490 :
1491 : void
1492 6012440 : MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
1493 6012440 : if (addRouteStops) {
1494 6016536 : for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
1495 : std::string errorMsg;
1496 8541 : if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
1497 20 : throw ProcessError(errorMsg);
1498 : }
1499 8531 : if (errorMsg != "") {
1500 694 : WRITE_WARNING(errorMsg);
1501 : }
1502 : }
1503 : }
1504 6012430 : const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
1505 6101091 : for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
1506 : std::string errorMsg;
1507 88684 : if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
1508 46 : throw ProcessError(errorMsg);
1509 : }
1510 88661 : if (errorMsg != "") {
1511 452 : WRITE_WARNING(errorMsg);
1512 : }
1513 : }
1514 6012407 : }
1515 :
1516 :
1517 : bool
1518 1239933 : MSBaseVehicle::haveValidStopEdges(bool silent) const {
1519 1239933 : MSRouteIterator start = myCurrEdge;
1520 : int i = 0;
1521 : bool ok = true;
1522 1292173 : for (const MSStop& stop : myStops) {
1523 : MSRouteIterator it;
1524 52240 : if (stop.lane->isInternal()) {
1525 : // find the normal predecessor and ensure that the next route edge
1526 : // matches the successor of the internal edge successor
1527 0 : it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
1528 0 : if (it != myRoute->end() && (
1529 0 : it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
1530 0 : it = myRoute->end(); // signal failure
1531 : }
1532 : } else {
1533 52240 : it = std::find(start, myRoute->end(), &stop.lane->getEdge());
1534 : }
1535 52240 : if (it == myRoute->end()) {
1536 0 : if (!silent) {
1537 0 : WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
1538 : i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1539 : }
1540 : ok = false;
1541 : } else {
1542 : MSRouteIterator it2;
1543 2199752 : for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
1544 2195832 : if (it2 == stop.edge) {
1545 : break;
1546 : }
1547 : }
1548 52240 : if (it2 == myRoute->end()) {
1549 3920 : if (!silent) {
1550 0 : WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
1551 : i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
1552 : }
1553 : ok = false;
1554 48320 : } else if (it2 < start) {
1555 0 : if (!silent) {
1556 0 : WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
1557 : i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1558 : }
1559 : ok = false;
1560 : } else {
1561 48320 : start = stop.edge;
1562 : }
1563 : }
1564 52240 : i++;
1565 : }
1566 1239933 : return ok;
1567 : }
1568 :
1569 :
1570 : const ConstMSEdgeVector
1571 2654945 : MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
1572 : assert(haveValidStopEdges());
1573 : ConstMSEdgeVector result;
1574 : const MSStop* prev = nullptr;
1575 2654945 : const MSEdge* internalSuccessor = nullptr;
1576 2731237 : for (const MSStop& stop : myStops) {
1577 76292 : if (stop.reached) {
1578 9404 : if (stop.pars.jump >= 0) {
1579 0 : jumps.insert((int)result.size());
1580 : }
1581 9404 : continue;
1582 : }
1583 66888 : const double stopPos = stop.getEndPos(*this);
1584 : if ((prev == nullptr
1585 27581 : || prev->edge != stop.edge
1586 1325 : || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
1587 93144 : && *stop.edge != internalSuccessor) {
1588 65563 : result.push_back(*stop.edge);
1589 65563 : if (stop.lane->isInternal()) {
1590 5 : internalSuccessor = stop.lane->getNextNormal();
1591 5 : result.push_back(internalSuccessor);
1592 : } else {
1593 65558 : internalSuccessor = nullptr;
1594 : }
1595 : }
1596 : prev = &stop;
1597 66888 : if (firstPos == INVALID_DOUBLE) {
1598 39307 : if (stop.parkingarea != nullptr) {
1599 3281 : firstPos = MAX2(0., stopPos);
1600 : } else {
1601 36026 : firstPos = stopPos;
1602 : }
1603 : }
1604 66888 : lastPos = stopPos;
1605 66888 : if (stop.pars.jump >= 0) {
1606 780 : jumps.insert((int)result.size() - 1);
1607 : }
1608 : }
1609 : //std::cout << "getStopEdges veh=" << getID() << " result=" << toString(result) << "\n";
1610 2654945 : return result;
1611 0 : }
1612 :
1613 :
1614 : std::vector<std::pair<int, double> >
1615 21954 : MSBaseVehicle::getStopIndices() const {
1616 : std::vector<std::pair<int, double> > result;
1617 45316 : for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
1618 46724 : result.push_back(std::make_pair(
1619 23362 : (int)(iter->edge - myRoute->begin()),
1620 23362 : iter->getEndPos(*this)));
1621 : }
1622 21954 : return result;
1623 0 : }
1624 :
1625 :
1626 : MSStop&
1627 5916807 : MSBaseVehicle::getNextStop() {
1628 : assert(myStops.size() > 0);
1629 5916807 : return myStops.front();
1630 : }
1631 :
1632 : SUMOTime
1633 3952512 : MSBaseVehicle::getStopDuration() const {
1634 3952512 : if (isStopped()) {
1635 1511098 : return myStops.front().duration;
1636 : } else {
1637 : return 0;
1638 : }
1639 : }
1640 :
1641 :
1642 : MSStop&
1643 14584 : MSBaseVehicle::getStop(int nextStopIndex) {
1644 14584 : if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
1645 0 : throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
1646 : }
1647 : auto stopIt = myStops.begin();
1648 : std::advance(stopIt, nextStopIndex);
1649 14584 : return *stopIt;
1650 : }
1651 :
1652 :
1653 : const SUMOVehicleParameter::Stop*
1654 186133 : MSBaseVehicle::getNextStopParameter() const {
1655 186133 : if (hasStops()) {
1656 105674 : return &myStops.front().pars;
1657 : }
1658 : return nullptr;
1659 : }
1660 :
1661 :
1662 : bool
1663 48273 : MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
1664 : //if the stop exists update the duration
1665 73721 : for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
1666 49343 : if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
1667 : // update existing stop
1668 23895 : if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
1669 22318 : myStops.erase(iter);
1670 : } else {
1671 1577 : iter->duration = stop.duration;
1672 1577 : iter->triggered = stop.triggered;
1673 1577 : iter->containerTriggered = stop.containerTriggered;
1674 1577 : const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
1675 1577 : const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
1676 : }
1677 : return true;
1678 : }
1679 : }
1680 24378 : const bool result = addStop(stop, errorMsg);
1681 24378 : if (result) {
1682 : /// XXX handle stops added out of order
1683 24365 : myParameter->stops.push_back(stop);
1684 : }
1685 : return result;
1686 : }
1687 :
1688 :
1689 : void
1690 561 : MSBaseVehicle::unregisterWaiting() {
1691 561 : if (myAmRegisteredAsWaiting) {
1692 403 : MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
1693 403 : myAmRegisteredAsWaiting = false;
1694 : }
1695 561 : }
1696 :
1697 :
1698 : bool
1699 834 : MSBaseVehicle::abortNextStop(int nextStopIndex) {
1700 834 : if (hasStops() && nextStopIndex < (int)myStops.size()) {
1701 834 : if (nextStopIndex == 0 && isStopped()) {
1702 34 : resumeFromStopping();
1703 : } else {
1704 : auto stopIt = myStops.begin();
1705 : std::advance(stopIt, nextStopIndex);
1706 800 : myStops.erase(stopIt);
1707 : }
1708 834 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1709 : // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
1710 : auto stopIt2 = myParameter->stops.begin();
1711 : std::advance(stopIt2, nextStopIndex);
1712 8 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
1713 : }
1714 834 : return true;
1715 : } else {
1716 : return false;
1717 : }
1718 : }
1719 :
1720 :
1721 : bool
1722 133 : MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
1723 133 : const int n = (int)myStops.size();
1724 133 : if (nextStopIndex < 0 || nextStopIndex >= n) {
1725 5 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
1726 5 : return false;
1727 : }
1728 128 : if (nextStopIndex == 0 && isStopped()) {
1729 7 : errorMsg = TL("cannot replace reached stop");
1730 7 : return false;
1731 : }
1732 121 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
1733 121 : MSLane* stopLane = MSLane::dictionary(stop.lane);
1734 121 : MSEdge* stopEdge = &stopLane->getEdge();
1735 :
1736 : auto itStop = myStops.begin();
1737 : std::advance(itStop, nextStopIndex);
1738 : MSStop& replacedStop = *itStop;
1739 :
1740 : // check parking access rights
1741 121 : if (stop.parkingarea != "") {
1742 0 : MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
1743 0 : if (pa != nullptr && !pa->accepts(this)) {
1744 0 : errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
1745 0 : return false;
1746 : }
1747 : }
1748 :
1749 121 : if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
1750 : // only replace stop attributes
1751 10 : const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
1752 10 : replacedStop.initPars(stop);
1753 10 : return true;
1754 : }
1755 :
1756 111 : if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
1757 0 : errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
1758 0 : return false;
1759 : }
1760 :
1761 111 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1762 111 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
1763 111 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1764 111 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1765 111 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1766 111 : MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
1767 111 : auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
1768 111 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
1769 :
1770 111 : bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
1771 :
1772 : ConstMSEdgeVector toNewStop;
1773 111 : if (!teleport) {
1774 82 : router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
1775 82 : if (toNewStop.size() == 0) {
1776 15 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
1777 5 : return false;
1778 : }
1779 : }
1780 :
1781 : ConstMSEdgeVector fromNewStop;
1782 106 : if (!newDestination) {
1783 101 : router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
1784 101 : if (fromNewStop.size() == 0) {
1785 0 : errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
1786 0 : return false;
1787 : }
1788 : }
1789 :
1790 106 : const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
1791 106 : replacedStop.initPars(stop);
1792 106 : replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
1793 106 : replacedStop.lane = stopLane;
1794 106 : if (MSGlobals::gUseMesoSim) {
1795 18 : replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
1796 18 : if (replacedStop.lane->isInternal()) {
1797 0 : errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
1798 0 : return false;
1799 : }
1800 : }
1801 :
1802 106 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1803 : ConstMSEdgeVector newEdges; // only remaining
1804 106 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1805 106 : if (!teleport) {
1806 77 : newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
1807 : } else {
1808 29 : newEdges.push_back(*itStart);
1809 : }
1810 106 : if (!newDestination) {
1811 101 : newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
1812 101 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
1813 : } else {
1814 5 : newEdges.push_back(stopEdge);
1815 : }
1816 : //std::cout << SIMTIME << " replaceStop veh=" << getID()
1817 : // << " teleport=" << teleport
1818 : // << " busStop=" << stop.busstop
1819 : // << " oldEdges=" << oldRemainingEdges.size()
1820 : // << " newEdges=" << newEdges.size()
1821 : // << " toNewStop=" << toNewStop.size()
1822 : // << " fromNewStop=" << fromNewStop.size()
1823 : // << "\n";
1824 :
1825 106 : const double routeCost = router.recomputeCosts(newEdges, this, t);
1826 106 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
1827 106 : const double savings = previousCost - routeCost;
1828 106 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1829 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
1830 5 : const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
1831 : }
1832 106 : if (teleport) {
1833 : // let the vehicle jump rather than teleport
1834 : // we add a jump-stop at the end of the edge (unless the vehicle is
1835 : // already configure to jump before the replaced stop)
1836 29 : if (!insertJump(nextStopIndex, itStart, errorMsg)) {
1837 : return false;
1838 : };
1839 : }
1840 106 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
1841 111 : }
1842 :
1843 :
1844 : bool
1845 52 : MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
1846 52 : const int n = (int)myStops.size();
1847 52 : if (nextStopIndex < 0 || nextStopIndex > n) {
1848 0 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
1849 0 : return false;
1850 : }
1851 52 : if (nextStopIndex == 0 && isStopped()) {
1852 0 : errorMsg = TL("cannot reroute towards reached stop");
1853 0 : return false;
1854 : }
1855 52 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
1856 :
1857 52 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1858 52 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
1859 52 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1860 52 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1861 52 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1862 52 : MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
1863 52 : auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
1864 52 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
1865 :
1866 : ConstMSEdgeVector newBetween;
1867 52 : if (!teleport) {
1868 15 : router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
1869 15 : if (newBetween.size() == 0) {
1870 0 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
1871 0 : return false;
1872 : }
1873 : }
1874 :
1875 52 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1876 : ConstMSEdgeVector newEdges; // only remaining
1877 52 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1878 52 : if (!teleport) {
1879 15 : newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
1880 : } else {
1881 37 : newEdges.push_back(*itStart);
1882 : }
1883 52 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
1884 : //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
1885 : // << " oldEdges=" << oldRemainingEdges.size()
1886 : // << " newEdges=" << newEdges.size()
1887 : // << " toNewStop=" << toNewStop.size()
1888 : // << " fromNewStop=" << fromNewStop.size()
1889 : // << "\n";
1890 :
1891 52 : const double routeCost = router.recomputeCosts(newEdges, this, t);
1892 52 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
1893 52 : const double savings = previousCost - routeCost;
1894 :
1895 52 : if (teleport) {
1896 : // let the vehicle jump rather than teleport
1897 : // we add a jump-stop at the end of the edge (unless the vehicle is
1898 : // already configure to jump before the replaced stop)
1899 37 : if (!insertJump(nextStopIndex, itStart, errorMsg)) {
1900 : return false;
1901 : };
1902 : }
1903 52 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
1904 52 : }
1905 :
1906 :
1907 : bool
1908 66 : MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
1909 : bool needJump = true;
1910 66 : if (nextStopIndex > 0) {
1911 : auto itPriorStop = myStops.begin();
1912 48 : std::advance(itPriorStop, nextStopIndex - 1);
1913 : const MSStop& priorStop = *itPriorStop;
1914 48 : if (priorStop.pars.jump >= 0) {
1915 : needJump = false;
1916 : }
1917 : }
1918 : if (needJump) {
1919 47 : SUMOVehicleParameter::Stop jumpStopPars;
1920 47 : jumpStopPars.endPos = (*itStart)->getLength();
1921 47 : jumpStopPars.speed = 1000;
1922 47 : jumpStopPars.jump = 0;
1923 : jumpStopPars.edge = (*itStart)->getID();
1924 47 : jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
1925 : MSLane* jumpStopLane = nullptr;
1926 47 : for (MSLane* cand : (*itStart)->getLanes()) {
1927 47 : if (cand->allowsVehicleClass(getVClass())) {
1928 : jumpStopLane = cand;
1929 : break;
1930 : }
1931 : }
1932 47 : if (jumpStopLane == nullptr) {
1933 0 : errorMsg = TL("unable to replace stop with teleporting");
1934 : return false;
1935 : }
1936 : auto itStop = myStops.begin();
1937 : std::advance(itStop, nextStopIndex);
1938 47 : MSStop jumpStop(jumpStopPars);
1939 47 : jumpStop.initPars(jumpStopPars);
1940 47 : jumpStop.lane = jumpStopLane;
1941 47 : jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
1942 47 : myStops.insert(itStop, jumpStop);
1943 47 : if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1944 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
1945 : auto it = myParameter->stops.begin() + nextStopIndex;
1946 0 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
1947 : }
1948 47 : }
1949 : return true;
1950 : }
1951 :
1952 :
1953 : bool
1954 326 : MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
1955 326 : const int n = (int)myStops.size();
1956 326 : if (nextStopIndex < 0 || nextStopIndex > n) {
1957 5 : errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
1958 5 : return false;
1959 : }
1960 321 : if (nextStopIndex == 0 && isStopped()) {
1961 7 : errorMsg = TL("cannot insert stop before the currently reached stop");
1962 7 : return false;
1963 : }
1964 314 : const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
1965 314 : MSLane* stopLane = MSLane::dictionary(stop.lane);
1966 314 : MSEdge* stopEdge = &stopLane->getEdge();
1967 :
1968 314 : if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
1969 0 : errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
1970 0 : return false;
1971 : }
1972 :
1973 : // check parking access rights
1974 314 : if (stop.parkingarea != "") {
1975 137 : MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
1976 137 : if (pa != nullptr && !pa->accepts(this)) {
1977 0 : errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
1978 0 : return false;
1979 : }
1980 : }
1981 :
1982 314 : const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1983 314 : std::vector<MSStop> stops(myStops.begin(), myStops.end());
1984 314 : const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1985 314 : MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1986 314 : double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1987 314 : MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
1988 314 : auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
1989 314 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
1990 :
1991 314 : bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
1992 :
1993 : ConstMSEdgeVector toNewStop;
1994 314 : if (!teleport) {
1995 286 : router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
1996 286 : if (toNewStop.size() == 0) {
1997 15 : errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
1998 5 : return false;
1999 : }
2000 : }
2001 :
2002 : ConstMSEdgeVector fromNewStop;
2003 309 : if (!newDestination) {
2004 280 : router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
2005 280 : if (fromNewStop.size() == 0) {
2006 0 : errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
2007 0 : return false;
2008 : }
2009 : }
2010 :
2011 : auto itStop = myStops.begin();
2012 : std::advance(itStop, nextStopIndex);
2013 309 : MSStop newStop(stop);
2014 309 : newStop.initPars(stop);
2015 309 : newStop.edge = myRoute->end(); // will be patched in replaceRoute
2016 309 : newStop.lane = stopLane;
2017 309 : if (MSGlobals::gUseMesoSim) {
2018 66 : newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
2019 66 : if (newStop.lane->isInternal()) {
2020 0 : errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
2021 0 : return false;
2022 : }
2023 : }
2024 309 : myStops.insert(itStop, newStop);
2025 :
2026 309 : ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2027 : ConstMSEdgeVector newEdges; // only remaining
2028 309 : newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2029 309 : if (!teleport) {
2030 281 : newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
2031 : } else {
2032 28 : newEdges.push_back(*itStart);
2033 : }
2034 309 : if (!newDestination) {
2035 280 : newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
2036 280 : newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2037 : } else {
2038 29 : newEdges.push_back(stopEdge);
2039 : }
2040 : //std::cout << SIMTIME << " insertStop veh=" << getID()
2041 : // << " teleport=" << teleport
2042 : // << " busStop=" << stop.busstop
2043 : // << " oldEdges=" << oldRemainingEdges.size()
2044 : // << " newEdges=" << newEdges.size()
2045 : // << " toNewStop=" << toNewStop.size()
2046 : // << " fromNewStop=" << fromNewStop.size()
2047 : // << "\n";
2048 :
2049 309 : const double routeCost = router.recomputeCosts(newEdges, this, t);
2050 309 : const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2051 309 : const double savings = previousCost - routeCost;
2052 :
2053 309 : if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
2054 : // stops will be rebuilt from scratch so we must patch the stops in myParameter
2055 : auto it = myParameter->stops.begin() + nextStopIndex;
2056 15 : const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
2057 : }
2058 309 : return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2059 623 : }
2060 :
2061 :
2062 : double
2063 0 : MSBaseVehicle::getStateOfCharge() const {
2064 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2065 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2066 0 : return batteryOfVehicle->getActualBatteryCapacity();
2067 : } else {
2068 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2069 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2070 0 : return batteryOfVehicle->getActualBatteryCapacity();
2071 : }
2072 : }
2073 : return -1;
2074 : }
2075 :
2076 :
2077 : double
2078 0 : MSBaseVehicle::getRelativeStateOfCharge() const {
2079 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2080 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2081 0 : return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2082 : } else {
2083 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2084 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2085 0 : return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2086 : }
2087 : }
2088 : return -1;
2089 : }
2090 :
2091 :
2092 : double
2093 0 : MSBaseVehicle::getChargedEnergy() const {
2094 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2095 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2096 0 : return batteryOfVehicle->getEnergyCharged();
2097 : } else {
2098 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2099 0 : MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2100 0 : return batteryOfVehicle->getEnergyCharged();
2101 : }
2102 : }
2103 : return -1;
2104 : }
2105 :
2106 :
2107 : double
2108 0 : MSBaseVehicle::getMaxChargeRate() const {
2109 0 : if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2110 0 : MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2111 0 : return batteryOfVehicle->getMaximumChargeRate();
2112 : }
2113 : return -1;
2114 : }
2115 :
2116 :
2117 : double
2118 0 : MSBaseVehicle::getElecHybridCurrent() const {
2119 0 : if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2120 0 : MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2121 0 : return elecHybridDevice->getCurrentFromOverheadWire();
2122 : }
2123 :
2124 : return NAN;
2125 : }
2126 :
2127 : double
2128 630 : MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
2129 630 : if (isOnRoad() || isIdling()) {
2130 630 : return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
2131 : } else {
2132 : return 0.;
2133 : }
2134 : }
2135 :
2136 :
2137 : const MSEdgeWeightsStorage&
2138 5123548 : MSBaseVehicle::getWeightsStorage() const {
2139 5123548 : return _getWeightsStorage();
2140 : }
2141 :
2142 :
2143 : MSEdgeWeightsStorage&
2144 650 : MSBaseVehicle::getWeightsStorage() {
2145 650 : return _getWeightsStorage();
2146 : }
2147 :
2148 :
2149 : MSEdgeWeightsStorage&
2150 5124198 : MSBaseVehicle::_getWeightsStorage() const {
2151 5124198 : if (myEdgeWeights == nullptr) {
2152 13307 : myEdgeWeights = new MSEdgeWeightsStorage();
2153 : }
2154 5124198 : return *myEdgeWeights;
2155 : }
2156 :
2157 :
2158 :
2159 :
2160 : int
2161 7250376 : MSBaseVehicle::getPersonNumber() const {
2162 7250376 : int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
2163 7250376 : return boarded + myParameter->personNumber;
2164 : }
2165 :
2166 : int
2167 0 : MSBaseVehicle::getLeavingPersonNumber() const {
2168 : int leavingPersonNumber = 0;
2169 0 : const std::vector<MSTransportable*>& persons = getPersons();
2170 0 : for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2171 0 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
2172 : const MSStop* stop = &myStops.front();
2173 0 : const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
2174 0 : if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
2175 0 : leavingPersonNumber++;
2176 : }
2177 : }
2178 0 : return leavingPersonNumber;
2179 : }
2180 :
2181 : std::vector<std::string>
2182 165 : MSBaseVehicle::getPersonIDList() const {
2183 : std::vector<std::string> ret;
2184 165 : const std::vector<MSTransportable*>& persons = getPersons();
2185 525 : for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2186 360 : ret.push_back((*it_p)->getID());
2187 : }
2188 165 : return ret;
2189 0 : }
2190 :
2191 : int
2192 4394764 : MSBaseVehicle::getContainerNumber() const {
2193 4394764 : int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
2194 4394764 : return loaded + myParameter->containerNumber;
2195 : }
2196 :
2197 :
2198 : void
2199 138 : MSBaseVehicle::removeTransportable(MSTransportable* t) {
2200 : // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
2201 138 : if (myPersonDevice != nullptr) {
2202 118 : myPersonDevice->removeTransportable(t);
2203 : }
2204 138 : if (myContainerDevice != nullptr) {
2205 20 : myContainerDevice->removeTransportable(t);
2206 : }
2207 138 : }
2208 :
2209 :
2210 : const std::vector<MSTransportable*>&
2211 6862092 : MSBaseVehicle::getPersons() const {
2212 6862092 : if (myPersonDevice == nullptr) {
2213 : return myEmptyTransportableVector;
2214 : } else {
2215 13299 : return myPersonDevice->getTransportables();
2216 : }
2217 : }
2218 :
2219 :
2220 : const std::vector<MSTransportable*>&
2221 5626394 : MSBaseVehicle::getContainers() const {
2222 5626394 : if (myContainerDevice == nullptr) {
2223 : return myEmptyTransportableVector;
2224 : } else {
2225 2906 : return myContainerDevice->getTransportables();
2226 : }
2227 : }
2228 :
2229 :
2230 : bool
2231 202 : MSBaseVehicle::isLineStop(double position) const {
2232 202 : if (myParameter->line == "") {
2233 : // not a public transport line
2234 : return false;
2235 : }
2236 348 : for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
2237 209 : if (stop.startPos <= position && position <= stop.endPos) {
2238 : return true;
2239 : }
2240 : }
2241 164 : for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
2242 34 : if (stop.startPos <= position && position <= stop.endPos) {
2243 : return true;
2244 : }
2245 : }
2246 : return false;
2247 : }
2248 :
2249 :
2250 : bool
2251 45 : MSBaseVehicle::hasDevice(const std::string& deviceName) const {
2252 144 : for (MSDevice* const dev : myDevices) {
2253 126 : if (dev->deviceName() == deviceName) {
2254 : return true;
2255 : }
2256 : }
2257 : return false;
2258 : }
2259 :
2260 :
2261 : void
2262 9 : MSBaseVehicle::createDevice(const std::string& deviceName) {
2263 9 : if (!hasDevice(deviceName)) {
2264 9 : if (deviceName == "rerouting") {
2265 27 : ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
2266 9 : MSDevice_Routing::buildVehicleDevices(*this, myDevices);
2267 9 : if (hasDeparted()) {
2268 : // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
2269 0 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
2270 : assert(routingDevice != 0);
2271 0 : routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
2272 : }
2273 : } else {
2274 0 : throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
2275 : }
2276 : }
2277 9 : }
2278 :
2279 :
2280 : std::string
2281 49494 : MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
2282 57650 : for (MSVehicleDevice* const dev : myDevices) {
2283 57641 : if (dev->deviceName() == deviceName) {
2284 49485 : return dev->getParameter(key);
2285 : }
2286 : }
2287 27 : throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2288 : }
2289 :
2290 :
2291 : void
2292 207 : MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
2293 342 : for (MSVehicleDevice* const dev : myDevices) {
2294 342 : if (dev->deviceName() == deviceName) {
2295 207 : dev->setParameter(key, value);
2296 207 : return;
2297 : }
2298 : }
2299 0 : throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2300 : }
2301 :
2302 :
2303 : void
2304 842 : MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
2305 1669 : if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
2306 837 : getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
2307 837 : const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2308 : // checked in MSLink::ignoreFoe
2309 : } else {
2310 15 : throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
2311 : }
2312 837 : }
2313 :
2314 :
2315 : void
2316 38 : MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
2317 : // handle some generic params first and then delegate to the carFollowModel itself
2318 67 : if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
2319 17 : getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
2320 17 : const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2321 : // checked in MSVehicle::planMove
2322 : } else {
2323 21 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
2324 21 : if (microVeh) {
2325 : // remove 'carFollowModel.' prefix
2326 21 : const std::string attrName = key.substr(15);
2327 21 : microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
2328 : }
2329 : }
2330 33 : }
2331 :
2332 :
2333 : void
2334 4613644 : MSBaseVehicle::initTransientModelParams() {
2335 : /* Design idea for additional junction model parameters:
2336 : We can distinguish between 3 levels of parameters
2337 : 1. typically shared by multiple vehicles -> vType parameter
2338 : 2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
2339 : 3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
2340 : */
2341 4881400 : for (auto item : getParameter().getParametersMap()) {
2342 535512 : if (StringUtils::startsWith(item.first, "junctionModel.")) {
2343 832 : setJunctionModelParameter(item.first, item.second);
2344 533848 : } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
2345 17 : setCarFollowModelParameter(item.first, item.second);
2346 : }
2347 : }
2348 9227288 : const std::string routingModeStr = getStringParam("device.rerouting.mode");
2349 : try {
2350 4613644 : int routingMode = StringUtils::toInt(routingModeStr);
2351 4613644 : if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
2352 : setRoutingMode(routingMode);
2353 : }
2354 0 : } catch (NumberFormatException&) {
2355 : // @todo interpret symbolic constants
2356 0 : throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
2357 0 : }
2358 4613644 : }
2359 :
2360 :
2361 : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
2362 24221 : MSBaseVehicle::getRouterTT() const {
2363 24221 : if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
2364 102 : return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
2365 : } else {
2366 24119 : return MSNet::getInstance()->getRouterTT(getRNGIndex());
2367 : }
2368 : }
2369 :
2370 :
2371 : void
2372 30448 : MSBaseVehicle::replaceVehicleType(MSVehicleType* type) {
2373 : assert(type != nullptr);
2374 : // save old parameters before possible type deletion
2375 30448 : const double oldMu = myType->getSpeedFactor().getParameter()[0];
2376 30448 : const double oldDev = myType->getSpeedFactor().getParameter()[1];
2377 30448 : if (myType->isVehicleSpecific() && type != myType) {
2378 848 : MSNet::getInstance()->getVehicleControl().removeVType(myType);
2379 : }
2380 : // adapt myChosenSpeedFactor to the new type
2381 30448 : if (oldDev == 0.) {
2382 : // old type had speedDev 0, reroll
2383 22584 : myChosenSpeedFactor = type->computeChosenSpeedDeviation(getRNG());
2384 : } else {
2385 : // map old speedFactor onto new distribution
2386 7864 : const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
2387 7864 : const double newMu = type->getSpeedFactor().getParameter()[0];
2388 7864 : const double newDev = type->getSpeedFactor().getParameter()[1];
2389 7864 : myChosenSpeedFactor = newMu + distPoint * newDev;
2390 : // respect distribution limits
2391 7864 : myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
2392 7869 : myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
2393 : }
2394 30448 : myType = type;
2395 30448 : if (myEnergyParams != nullptr) {
2396 : myEnergyParams->setSecondary(type->getEmissionParameters());
2397 : }
2398 30448 : }
2399 :
2400 :
2401 : MSVehicleType&
2402 96634 : MSBaseVehicle::getSingularType() {
2403 96634 : if (myType->isVehicleSpecific()) {
2404 : return *myType;
2405 : }
2406 2296 : MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
2407 1148 : replaceVehicleType(type);
2408 1148 : return *type;
2409 : }
2410 :
2411 :
2412 : int
2413 510178 : MSBaseVehicle::getRNGIndex() const {
2414 510178 : const MSLane* const lane = getLane();
2415 510178 : if (lane == nullptr) {
2416 14595 : return getEdge()->getLanes()[0]->getRNGIndex();
2417 : } else {
2418 495583 : return lane->getRNGIndex();
2419 : }
2420 : }
2421 :
2422 :
2423 : SumoRNG*
2424 589223843 : MSBaseVehicle::getRNG() const {
2425 589223843 : const MSLane* lane = getLane();
2426 589223843 : if (lane == nullptr) {
2427 2745 : return getEdge()->getLanes()[0]->getRNG();
2428 : } else {
2429 589221098 : return lane->getRNG();
2430 : }
2431 : }
2432 :
2433 : std::string
2434 60393 : MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
2435 60393 : const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
2436 120786 : if (StringUtils::startsWith(key, "device.")) {
2437 148482 : StringTokenizer tok(key, ".");
2438 49494 : if (tok.size() < 3) {
2439 0 : error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
2440 0 : return "";
2441 : }
2442 : try {
2443 148482 : return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
2444 18 : } catch (InvalidArgument& e) {
2445 54 : error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
2446 18 : return "";
2447 18 : }
2448 71292 : } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
2449 316 : if (microVeh == nullptr) {
2450 36 : error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
2451 18 : return "";
2452 : }
2453 298 : const std::string attrName = key.substr(16);
2454 : try {
2455 298 : return microVeh->getLaneChangeModel().getParameter(attrName);
2456 36 : } catch (InvalidArgument& e) {
2457 108 : error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
2458 36 : return "";
2459 36 : }
2460 21166 : } else if (StringUtils::startsWith(key, "carFollowModel.")) {
2461 16 : if (microVeh == nullptr) {
2462 0 : error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
2463 0 : return "";
2464 : }
2465 16 : const std::string attrName = key.substr(15);
2466 : try {
2467 16 : return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
2468 0 : } catch (InvalidArgument& e) {
2469 0 : error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
2470 0 : return "";
2471 0 : }
2472 10603 : } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
2473 108 : StringTokenizer tok(key, ".");
2474 36 : if (tok.size() != 3) {
2475 0 : error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
2476 0 : return "";
2477 : }
2478 81 : return hasDevice(tok.get(1)) ? "true" : "false";
2479 : // parking related parameters start here
2480 10567 : } else if (key == "parking.rerouteCount") {
2481 15 : return toString(getNumberParkingReroutes());
2482 21032 : } else if (StringUtils::startsWith(key, "parking.memory.")) {
2483 : std::vector<std::string> values;
2484 65 : if (getParkingMemory()) {
2485 25 : if (key == "parking.memory.IDList") {
2486 30 : for (const auto& item : *getParkingMemory()) {
2487 25 : values.push_back(item.first->getID());
2488 : }
2489 20 : } else if (key == "parking.memory.score") {
2490 30 : for (const auto& item : *getParkingMemory()) {
2491 25 : values.push_back(item.second.score);
2492 : }
2493 15 : } else if (key == "parking.memory.blockedAtTime") {
2494 30 : for (const auto& item : *getParkingMemory()) {
2495 50 : values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
2496 : }
2497 10 : } else if (key == "parking.memory.blockedAtTimeLocal") {
2498 30 : for (const auto& item : *getParkingMemory()) {
2499 50 : values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
2500 : }
2501 : } else {
2502 10 : error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
2503 : }
2504 : }
2505 65 : return toString(values);
2506 65 : } else {
2507 : // default: custom user parameter
2508 20902 : return getParameter().getParameter(key, "");
2509 : }
2510 : }
2511 :
2512 :
2513 : void
2514 30884 : MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
2515 30884 : if (myParkingMemory == nullptr) {
2516 0 : myParkingMemory = new StoppingPlaceMemory();
2517 : }
2518 30884 : myParkingMemory->rememberBlockedStoppingPlace(pa, local);
2519 30884 : }
2520 :
2521 :
2522 : void
2523 12163 : MSBaseVehicle::resetParkingAreaScores() {
2524 12163 : if (myParkingMemory != nullptr) {
2525 10639 : myParkingMemory->resetStoppingPlaceScores();
2526 : }
2527 12163 : }
2528 :
2529 :
2530 : void
2531 212 : MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
2532 212 : if (myChargingMemory == nullptr) {
2533 44 : myChargingMemory = new StoppingPlaceMemory();
2534 : }
2535 212 : myChargingMemory->rememberStoppingPlaceScore(cs, score);
2536 212 : }
2537 :
2538 :
2539 : void
2540 60 : MSBaseVehicle::resetChargingStationScores() {
2541 60 : if (myChargingMemory != nullptr) {
2542 4 : myChargingMemory->resetStoppingPlaceScores();
2543 : }
2544 60 : }
2545 :
2546 :
2547 : void
2548 54455 : MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
2549 54455 : if (myParkingMemory == nullptr) {
2550 2025 : myParkingMemory = new StoppingPlaceMemory();
2551 : }
2552 54455 : myParkingMemory->rememberStoppingPlaceScore(pa, score);
2553 54455 : }
2554 :
2555 :
2556 : SUMOTime
2557 37852 : MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
2558 37852 : if (myParkingMemory == nullptr) {
2559 : return -1;
2560 : }
2561 37852 : return myParkingMemory->sawBlockedStoppingPlace(pa, local);
2562 : }
2563 :
2564 :
2565 0 : void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
2566 0 : if (myChargingMemory == nullptr) {
2567 0 : myChargingMemory = new StoppingPlaceMemory();
2568 : }
2569 0 : myChargingMemory->rememberBlockedStoppingPlace(cs, local);
2570 0 : }
2571 :
2572 :
2573 : SUMOTime
2574 276 : MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
2575 276 : if (myChargingMemory == nullptr) {
2576 : return -1;
2577 : }
2578 16 : return myChargingMemory->sawBlockedStoppingPlace(cs, local);
2579 : }
2580 :
2581 :
2582 : #ifdef _DEBUG
2583 : void
2584 : MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
2585 : if (oc.isSet("movereminder-output.vehicles")) {
2586 : const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
2587 : myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
2588 : }
2589 : }
2590 :
2591 :
2592 : void
2593 : MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
2594 : OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
2595 : od.openTag("movereminder");
2596 : od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
2597 : od.writeAttr("veh", getID());
2598 : od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
2599 : od.writeAttr("type", type);
2600 : od.writeAttr("pos", toString(pos));
2601 : od.writeAttr("keep", toString(keep));
2602 : od.closeTag();
2603 : }
2604 : #endif
2605 :
2606 :
2607 : /****************************************************************************/
|