Eclipse SUMO - Simulation of Urban MObility
MSBaseVehicle.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2023 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/****************************************************************************/
20// A base class for vehicle implementations
21/****************************************************************************/
22#include <config.h>
23
24#include <iostream>
25#include <cassert>
33#include <mesosim/MELoop.h>
34#include <mesosim/MEVehicle.h>
44#include "MSGlobals.h"
45#include "MSVehicleControl.h"
46#include "MSVehicleType.h"
47#include "MSEdge.h"
48#include "MSLane.h"
49#include "MSMoveReminder.h"
51#include "MSNet.h"
52#include "MSStop.h"
53#include "MSParkingArea.h"
54#include "MSInsertionControl.h"
55#include "MSBaseVehicle.h"
56
57//#define DEBUG_REROUTE
58//#define DEBUG_ADD_STOP
59//#define DEBUG_COND (getID() == "")
60//#define DEBUG_COND (true)
61//#define DEBUG_REPLACE_ROUTE
62#define DEBUG_COND (isSelected())
63
64// ===========================================================================
65// static members
66// ===========================================================================
68std::vector<MSTransportable*> MSBaseVehicle::myEmptyTransportableVector;
69#ifdef _DEBUG
70std::set<std::string> MSBaseVehicle::myShallTraceMoveReminders;
71#endif
73
74// ===========================================================================
75// Influencer method definitions
76// ===========================================================================
77
79 myRoutingMode(libsumo::ROUTING_MODE_DEFAULT)
80{}
81
84 if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
85 return MSRoutingEngine::getRouterTT(rngIndex, svc);
86 } else {
87 return MSNet::getInstance()->getRouterTT(rngIndex);
88 }
89}
90
91
92
93// ===========================================================================
94// method definitions
95// ===========================================================================
96
97double
99 throw ProcessError("getPreviousSpeed() is not available for non-MSVehicles.");
100}
101
102
104 MSVehicleType* type, const double speedFactor) :
105 SUMOVehicle(pars->id),
106 myParameter(pars),
107 myRoute(route),
108 myType(type),
109 myCurrEdge(route->begin()),
110 myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
112 myPersonDevice(nullptr),
113 myContainerDevice(nullptr),
114 myEnergyParams(nullptr),
116 myDepartPos(-1),
117 myArrivalPos(-1),
118 myArrivalLane(-1),
121 myOdometer(0.),
124 myEdgeWeights(nullptr)
125#ifdef _DEBUG
126 , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
127#endif
128{
129 if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
131 }
132 if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
134 }
135 if (!pars->wasSet(VEHPARS_FORCE_REROUTE)) {
137 }
139}
140
141
143 delete myEdgeWeights;
144 if (myParameter->repetitionNumber == -1) {
145 // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
147 }
148 for (MSVehicleDevice* dev : myDevices) {
149 delete dev;
150 }
151 delete myEnergyParams;
152 delete myParkingMemory;
154 delete myParameter;
155}
156
157
158void
162 myRoute->checkRemoval();
163 }
164}
165
166
167std::string
169 return getID().substr(0, getID().rfind('.'));
170}
171
172
173void
176 for (MSVehicleDevice* dev : myDevices) {
177 myMoveReminders.push_back(std::make_pair(dev, 0.));
178 }
180 // ensure we have the emission parameters even if we don't have the device
182 }
183}
184
185
186void
187MSBaseVehicle::setID(const std::string& /*newID*/) {
188 throw ProcessError(TL("Changing a vehicle ID is not permitted"));
189}
190
193 return *myParameter;
194}
195
196
197void
199 delete myParameter;
200 myParameter = newParameter;
201}
202
203double
206}
207
208
209const MSEdge*
210MSBaseVehicle::succEdge(int nSuccs) const {
211 if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
212 return *(myCurrEdge + nSuccs);
213 } else {
214 return nullptr;
215 }
216}
217
218
219const MSEdge*
221 return *myCurrEdge;
222}
223
224
225bool
227 if (stop == nullptr) {
228 return false;
229 }
230 for (const MSStop& s : myStops) {
231 if (s.busstop == stop
232 || s.containerstop == stop
233 || s.parkingarea == stop
234 || s.chargingStation == stop) {
235 return true;
236 }
237 }
238 return false;
239}
240
241bool
243 for (const MSStop& s : myStops) {
244 if (&s.lane->getEdge() == edge) {
245 return true;
246 }
247 }
248 return false;
249}
250
251
252void
253MSBaseVehicle::reroute(SUMOTime t, const std::string& info, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, const bool onInit, const bool withTaz, const bool silent) {
254 // check whether to reroute
255 const MSEdge* source = withTaz && onInit ? MSEdge::dictionary(myParameter->fromTaz + "-source") : *getRerouteOrigin();
256 if (source == nullptr) {
257 source = *getRerouteOrigin();
258 }
259 const MSEdge* sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
260 if (sink == nullptr) {
261 sink = myRoute->getLastEdge();
262 }
263 ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
264 ConstMSEdgeVector edges;
265 ConstMSEdgeVector stops;
266 std::set<int> jumps;
267 if (myParameter->via.size() == 0) {
268 double firstPos = -1;
269 double lastPos = -1;
270 stops = getStopEdges(firstPos, lastPos, jumps);
271 if (stops.size() > 0) {
272 const double sourcePos = onInit ? 0 : getPositionOnLane();
273 // avoid superfluous waypoints for first and last edge
274 const bool skipFirst = stops.front() == source && (source != getEdge() || sourcePos + getBrakeGap() <= firstPos);
275 const bool skipLast = stops.back() == sink && myArrivalPos >= lastPos && (
276 stops.size() < 2 || stops.back() != stops[stops.size() - 2]);
277#ifdef DEBUG_REROUTE
278 if (DEBUG_COND) {
279 std::cout << SIMTIME << " reroute " << info << " veh=" << getID() << " lane=" << Named::getIDSecure(getLane())
280 << " source=" << source->getID() << " sourcePos=" << sourcePos << " firstPos=" << firstPos << " arrivalPos=" << myArrivalPos << " lastPos=" << lastPos
281 << " route=" << toString(myRoute->getEdges()) << " stopEdges=" << toString(stops) << " skipFirst=" << skipFirst << " skipLast=" << skipLast << "\n";
282 }
283#endif
284 if (stops.size() == 1 && (skipFirst || skipLast)) {
285 stops.clear();
286 } else {
287 if (skipFirst) {
288 stops.erase(stops.begin());
289 }
290 if (skipLast) {
291 stops.erase(stops.end() - 1);
292 }
293 }
294 }
295 } else {
296 // via takes precedence over stop edges
297 // there is a consistency check in MSRouteHandler::addStop that warns when a stop edge is not part of the via edges
298 for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
299 MSEdge* viaEdge = MSEdge::dictionary(*it);
300 if (viaEdge == source || viaEdge == sink) {
301 continue;
302 }
303 assert(viaEdge != 0);
304 if (!viaEdge->isTazConnector() && viaEdge->allowedLanes(getVClass()) == nullptr) {
305 throw ProcessError(TLF("Vehicle '%' is not allowed on any lane of via edge '%'.", getID(), viaEdge->getID()));
306 }
307 stops.push_back(viaEdge);
308 }
309 }
310
311 int stopIndex = -1;
312 for (const MSEdge* const stopEdge : stops) {
313 stopIndex++;
314 // !!! need to adapt t here
316 if (jumps.count(stopIndex) != 0) {
317 edges.push_back(source);
318 source = stopEdge;
319 continue;
320 }
321 router.computeLooped(source, stopEdge, this, t, into, silent);
322 //std::cout << SIMTIME << " reroute veh=" << getID() << " source=" << source->getID() << " target=" << (*s)->getID() << " edges=" << toString(into) << "\n";
323 if (into.size() > 0) {
324 into.pop_back();
325 edges.insert(edges.end(), into.begin(), into.end());
326 if (stopEdge->isTazConnector()) {
327 source = into.back();
328 edges.pop_back();
329 } else {
330 source = stopEdge;
331 }
332 } else {
333 std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
334 if (MSGlobals::gCheckRoutes || silent) {
335 throw ProcessError(error);
336 } else {
337 WRITE_WARNING(error);
338 edges.push_back(source);
339 }
340 source = stopEdge;
341 }
342 }
343 if (stops.empty() && source == sink && onInit
347 router.computeLooped(source, sink, this, t, edges, silent);
348 } else {
349 if (!router.compute(source, sink, this, t, edges, silent)) {
350 edges.clear();
351 }
352 }
353
354 // router.setHint(myCurrEdge, myRoute->end(), this, t);
355 if (edges.empty() && silent) {
356 return;
357 }
358 if (!edges.empty() && edges.front()->isTazConnector()) {
359 edges.erase(edges.begin());
360 }
361 if (!edges.empty() && edges.back()->isTazConnector()) {
362 edges.pop_back();
363 }
364 const double routeCost = router.recomputeCosts(edges, this, t);
365 const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
366 const double savings = previousCost - routeCost;
367 //if (getID() == "43") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
368 // << " onInit=" << onInit
369 // << " prevEdges=" << toString(oldEdgesRemaining)
370 // << " newEdges=" << toString(edges)
371 // << "\n";
372 replaceRouteEdges(edges, routeCost, savings, info, onInit);
373 // this must be called even if the route could not be replaced
374 if (onInit) {
375 if (edges.empty()) {
377 throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
378 } else if (source->isTazConnector()) {
379 WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
381 return;
382 }
383 }
386 }
387}
388
389
390bool
391MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
392 if (edges.empty()) {
393 WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
394 if (msgReturn != nullptr) {
395 *msgReturn = "No route found";
396 }
397 return false;
398 }
399 // build a new id, first
400 std::string id = getID();
401 if (id[0] != '!') {
402 id = "!" + id;
403 }
404 const std::string idSuffix = id + "!var#";
405 int varIndex = 1;
406 id = idSuffix + toString(varIndex);
407 while (MSRoute::hasRoute(id)) {
408 id = idSuffix + toString(++varIndex);
409 }
410 int oldSize = (int)edges.size();
411 if (!onInit) {
412 const MSEdge* const origin = *getRerouteOrigin();
413 if (origin != *myCurrEdge && edges.front() == origin) {
414 edges.insert(edges.begin(), *myCurrEdge);
415 oldSize = (int)edges.size();
416 }
417 edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
418 }
419 if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
420 // re-assign stop iterators when rerouting to a new parkingArea / insertStop
421 return true;
422 }
423 const RGBColor& c = myRoute->getColor();
424 MSRoute* newRoute = new MSRoute(id, edges, false, &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), std::vector<SUMOVehicleParameter::Stop>());
425 newRoute->setCosts(cost);
426 newRoute->setSavings(savings);
427 ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
428 if (!MSRoute::dictionary(id, constRoute)) {
429 delete newRoute;
430 if (msgReturn != nullptr) {
431 *msgReturn = "duplicate routeID '" + id + "'";
432 }
433 return false;
434 }
435
436 std::string msg;
437 if (check && !hasValidRoute(msg, constRoute)) {
438 WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), getID(), msg);
440 if (msgReturn != nullptr) {
441 *msgReturn = msg;
442 }
443 return false;
444 }
445 }
446 if (!replaceRoute(constRoute, info, onInit, (int)edges.size() - oldSize, false, removeStops, msgReturn)) {
447 return false;
448 }
449 return true;
450}
451
452
453bool
454MSBaseVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
455 const ConstMSEdgeVector& edges = newRoute->getEdges();
456 // rebuild in-vehicle route information
457 if (onInit) {
458 myCurrEdge = newRoute->begin();
459 } else {
460 MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
461 if (newCurrEdge == edges.end()) {
462 if (msgReturn != nullptr) {
463 *msgReturn = TLF("current edge '%' not found in new route", (*myCurrEdge)->getID());
464 }
465#ifdef DEBUG_REPLACE_ROUTE
466 if (DEBUG_COND) {
467 std::cout << " newCurrEdge not found\n";
468 }
469#endif
470 return false;
471 }
472 if (getLane() != nullptr) {
473 if (getLane()->getEdge().isInternal() && (
474 (newCurrEdge + 1) == edges.end() || (*(newCurrEdge + 1)) != &(getLane()->getOutgoingViaLanes().front().first->getEdge()))) {
475 if (msgReturn != nullptr) {
476 *msgReturn = TL("Vehicle is on junction-internal edge leading elsewhere");
477 }
478#ifdef DEBUG_REPLACE_ROUTE
479 if (DEBUG_COND) {
480 std::cout << " Vehicle is on junction-internal edge leading elsewhere\n";
481 }
482#endif
483 return false;
484 } else if (getPositionOnLane() > getLane()->getLength()
485 && (myCurrEdge + 1) != myRoute->end()
486 && (newCurrEdge + 1) != edges.end()
487 && *(myCurrEdge + 1) != *(newCurrEdge + 1)) {
488 if (msgReturn != nullptr) {
489 *msgReturn = TL("Vehicle is moving past junction and committed to move to another successor edge");
490 }
491#ifdef DEBUG_REPLACE_ROUTE
492 if (DEBUG_COND) {
493 std::cout << " Vehicle is moving past junction and committed to move to another successor edge\n";
494 }
495#endif
496 return false;
497 }
498 }
499 myCurrEdge = newCurrEdge;
500 }
501 const bool stopsFromScratch = onInit && myRoute->getStops().empty();
502 // assign new route
504 myRoute = newRoute;
505 // update arrival definition
507 // save information that the vehicle was rerouted
509 myStopUntilOffset += myRoute->getPeriod();
511#ifdef DEBUG_REPLACE_ROUTE
512 if (DEBUG_COND) {
513 std::cout << SIMTIME << " replaceRoute info=" << info << " on " << (*myCurrEdge)->getID()
514 << " lane=" << Named::getIDSecure(getLane())
515 << " stopsFromScratch=" << stopsFromScratch
516 << " newSize=" << newRoute->getEdges().size()
517 << " newIndex=" << (myCurrEdge - newRoute->begin())
518 << " edges=" << toString(newRoute->getEdges())
519 << "\n";
520 }
521#endif
522 // if we did not drive yet it may be best to simply reassign the stops from scratch
523 if (stopsFromScratch) {
524 myStops.clear();
526 } else {
527 // recheck old stops
528 MSRouteIterator searchStart = myCurrEdge;
529 double lastPos = getPositionOnLane() + getBrakeGap();
530 if (getLane() != nullptr && getLane()->isInternal()
531 && myStops.size() > 0 && !myStops.front().lane->isInternal()) {
532 // searchStart is still incoming to the intersection so lastPos
533 // relative to that edge must be adapted
534 lastPos += (*myCurrEdge)->getLength();
535 }
536 for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
537 double endPos = iter->getEndPos(*this);
538#ifdef DEBUG_REPLACE_ROUTE
539 if (DEBUG_COND) {
540 std::cout << " stopEdge=" << iter->lane->getEdge().getID() << " start=" << (searchStart - myCurrEdge) << " endPos=" << endPos << " lastPos=" << lastPos << "\n";
541 }
542#endif
543 if (*searchStart != &iter->lane->getEdge()
544 || endPos + NUMERICAL_EPS < lastPos) {
545 if (searchStart != edges.end() && !iter->reached) {
546 searchStart++;
547 }
548 }
549 lastPos = endPos;
550
551 iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
552#ifdef DEBUG_REPLACE_ROUTE
553 if (DEBUG_COND) {
554 std::cout << " foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
555 }
556#endif
557 if (iter->edge == edges.end()) {
558 if (!removeStops) {
559 WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
560 }
561 iter = myStops.erase(iter);
562 continue;
563 } else {
564 searchStart = iter->edge;
565 }
566 ++iter;
567 }
568 // add new stops
569 if (addRouteStops) {
570 for (std::vector<SUMOVehicleParameter::Stop>::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
571 std::string error;
573 if (error != "") {
574 WRITE_WARNING(error);
575 }
576 }
577 }
578 }
579 return true;
580}
581
582
583double
585 return 0;
586}
587
588
589void
594}
595
596
599 const SUMOTime dep = getParameter().depart;
600 if (dep < 0) {
601 return 0;
602 }
603 return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
604}
605
606
607bool
609 return succEdge(1) == nullptr;
610}
611
612
613int
615 return (int) std::distance(myRoute->begin(), myCurrEdge);
616}
617
618
619void
621 myCurrEdge = myRoute->begin() + index;
622 const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
623 // !!! hack
624 myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
625}
626
627double
630}
631
632bool
634 if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
635 return false;
636 } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
637 return false;
638 }
639 if (isStopped() && myStops.begin()->pars.permitted.size() > 0
640 && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
641 return false;
642 }
643 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
644 if (taxiDevice != nullptr) {
645 return taxiDevice->allowsBoarding(t);
646 }
647 return true;
648}
649
650
651void
653 if (transportable->isPerson()) {
654 if (myPersonDevice == nullptr) {
656 myMoveReminders.push_back(std::make_pair(myPersonDevice, 0.));
659 }
660 }
661 myPersonDevice->addTransportable(transportable);
662 } else {
663 if (myContainerDevice == nullptr) {
665 myMoveReminders.push_back(std::make_pair(myContainerDevice, 0.));
668 }
669 }
670 myContainerDevice->addTransportable(transportable);
671 }
672}
673
674
675bool
677 for (const MSStop& stop : myStops) {
678 if (stop.edge == it) {
679 return stop.pars.jump >= 0;
680 }
681 }
682 return false;
683}
684
685
686bool
687MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
689 if (route == nullptr) {
690 route = myRoute;
691 } else {
692 start = route->begin();
693 }
694 MSRouteIterator last = route->end() - 1;
695 // check connectivity, first
696 for (MSRouteIterator e = start; e != last; ++e) {
697 if ((*e)->allowedLanes(**(e + 1), myType->getVehicleClass()) == nullptr) {
698 if (!hasJump(e)) {
699 msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
700 return false;
701 }
702 }
703 }
704 last = route->end();
705 // check usable lanes, then
706 for (MSRouteIterator e = start; e != last; ++e) {
707 if ((*e)->prohibits(this)) {
708 msg = TLF("Edge '%' prohibits.", (*e)->getID());
709 return false;
710 }
711 }
712 return true;
713}
714
715
716bool
718 if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
719 myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
720 return true;
721 } else {
722 msg = TLF("Vehicle '%' is not allowed to depart on its first edge.", getID());
724 return false;
725 }
726}
727
728
729int
730MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
731 if (!update) {
732 return myRouteValidity;
733 }
734 // insertion check must be done in any case
735 std::string msg;
736 if (!hasValidRouteStart(msg)) {
738 throw ProcessError(msg);
739 } else if (!silent) {
740 // vehicle will be discarded
741 WRITE_WARNING(msg);
742 } else if (msgReturn != nullptr) {
743 *msgReturn = msg;
744 }
745 }
748 // we could check after the first rerouting
750 if (!hasValidRoute(msg, myRoute)) {
752 throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
753 }
754 }
755 myRouteValidity &= ~ROUTE_UNCHECKED;
756 return myRouteValidity;
757}
758
759void
761#ifdef _DEBUG
762 if (myTraceMoveReminders) {
763 traceMoveReminder("add", rem, 0, true);
764 }
765#endif
766 myMoveReminders.push_back(std::make_pair(rem, 0.));
767}
768
769
770void
772 for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
773 if (r->first == rem) {
774#ifdef _DEBUG
775 if (myTraceMoveReminders) {
776 traceMoveReminder("remove", rem, 0, false);
777 }
778#endif
779 myMoveReminders.erase(r);
780 return;
781 }
782 }
783}
784
785
786void
788 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
789 if (rem->first->notifyEnter(*this, reason, enteredLane)) {
790#ifdef _DEBUG
791 if (myTraceMoveReminders) {
792 traceMoveReminder("notifyEnter", rem->first, rem->second, true);
793 }
794#endif
795 ++rem;
796 } else {
797#ifdef _DEBUG
798 if (myTraceMoveReminders) {
799 traceMoveReminder("notifyEnter", rem->first, rem->second, false);
800 }
801#endif
802 rem = myMoveReminders.erase(rem);
803 }
804 }
805}
806
807
808void
810 if (myRoute->getLastEdge()->isTazConnector()) {
811 return;
812 }
813 const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
814 if (arrivalEdgeIndex != myParameter->arrivalEdge) {
815 WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
816 getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
817 }
818 const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
819 if (!onInit) {
820 arrivalEdge = myRoute->getLastEdge();
821 // ignore arrivalEdge parameter after rerouting
822 const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
823 }
824 const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
825 const double lastLaneLength = lanes[0]->getLength();
828 if (fabs(myParameter->arrivalPos) > lastLaneLength) {
829 WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
830 }
831 // Maybe we should warn the user about invalid inputs!
832 myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
833 if (myArrivalPos < 0) {
834 myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
835 }
836 break;
838 myArrivalPos = RandHelper::rand(lastLaneLength);
839 break;
841 myArrivalPos = lastLaneLength / 2.;
842 break;
843 default:
844 myArrivalPos = lastLaneLength;
845 break;
846 }
848 if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
849 WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
850 }
851 myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
853 myArrivalLane = -1;
854 for (MSLane* lane : lanes) {
855 if (lane->allowsVehicleClass(myType->getVehicleClass())) {
856 myArrivalLane = lane->getIndex();
857 break;
858 }
859 }
860 if (myArrivalLane == -1) {
861 WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
862 myArrivalLane = 0;
863 }
865 // pick random lane among all usable lanes
866 std::vector<MSLane*> usable;
867 for (MSLane* lane : lanes) {
868 if (lane->allowsVehicleClass(myType->getVehicleClass())) {
869 usable.push_back(lane);
870 }
871 }
872 if (usable.empty()) {
873 WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
874 myArrivalLane = 0;
875 } else {
876 myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
877 }
878 }
880 for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
881 if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
882 return;
883 }
884 }
885 WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
886 }
887}
888
889void
893 const int routeEdges = (int)myRoute->getEdges().size();
895 // write specific edge in vehroute output for reproducibility
896 pars->departEdge = RandHelper::rand(0, routeEdges);
898 }
899 assert(pars->departEdge >= 0);
900 if (pars->departEdge >= routeEdges) {
901 WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
902 } else {
903 myCurrEdge += pars->departEdge;
904 }
905 }
907 const int routeEdges = (int)myRoute->getEdges().size();
908 const int begin = (int)(myCurrEdge - myRoute->begin());
909 // write specific edge in vehroute output for reproducibility
910 pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
912 assert(pars->arrivalEdge >= begin);
913 assert(pars->arrivalEdge < routeEdges);
914 }
915}
916
917
918double
920 return MAX2(0., MIN2(1., getVehicleType().getImpatience()
921 + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
923}
924
925
927MSBaseVehicle::getDevice(const std::type_info& type) const {
928 for (MSVehicleDevice* const dev : myDevices) {
929 if (typeid(*dev) == type) {
930 return dev;
931 }
932 }
933 return nullptr;
934}
935
936
937void
939 // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
942 // params and stops must be written in child classes since they may wish to add additional attributes first
943 out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
944 std::ostringstream os;
945 os << myOdometer << " " << myNumberReroutes;
946 out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
948 const int precision = out.precision();
949 out.setPrecision(MAX2(gPrecisionRandom, precision));
951 out.setPrecision(precision);
952 }
954 out.writeAttr(SUMO_ATTR_REROUTE, true);
955 }
957 // could be set from stop
959 }
960 // here starts the vehicle internal part (see loading)
961 // @note: remember to close the vehicle tag when calling this in a subclass!
962}
963
964
965bool
966MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
967 UNUSED_PARAMETER(stop);
968 UNUSED_PARAMETER(distToStop);
969 return true;
970}
971
972
973bool
975 return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
976}
977
978
979bool
981 return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
982 && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
983 && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
984}
985
986
987bool
989 return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge;
990}
991
992
993bool
995 return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
996}
997
998
999bool
1001 return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
1002}
1003
1004
1005bool
1006MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
1007 if (isStopped() || (checkFuture && hasStops())) {
1008 const MSStop& stop = myStops.front();
1009 return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
1010 }
1011 return false;
1012}
1013
1014bool
1015MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
1016 // Check if there is a parking area to be replaced
1017 if (parkingArea == 0) {
1018 errorMsg = "new parkingArea is NULL";
1019 return false;
1020 }
1021 if (myStops.size() == 0) {
1022 errorMsg = "vehicle has no stops";
1023 return false;
1024 }
1025 if (myStops.front().parkingarea == 0) {
1026 errorMsg = "first stop is not at parkingArea";
1027 return false;
1028 }
1029 MSStop& first = myStops.front();
1030 SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
1031 // merge subsequent duplicate stops equals to parking area
1032 for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
1033 if (iter->parkingarea == parkingArea) {
1034 stopPar.duration += iter->duration;
1035 myStops.erase(iter++);
1036 } else {
1037 break;
1038 }
1039 }
1040 stopPar.lane = parkingArea->getLane().getID();
1041 stopPar.parkingarea = parkingArea->getID();
1042 stopPar.startPos = parkingArea->getBeginLanePosition();
1043 stopPar.endPos = parkingArea->getEndLanePosition();
1044 first.edge = myRoute->end(); // will be patched in replaceRoute
1045 first.lane = &parkingArea->getLane();
1046 first.parkingarea = parkingArea;
1047 return true;
1048}
1049
1050
1053 MSParkingArea* nextParkingArea = nullptr;
1054 if (!myStops.empty()) {
1056 MSStop stop = myStops.front();
1057 if (!stop.reached && stop.parkingarea != nullptr) {
1058 nextParkingArea = stop.parkingarea;
1059 }
1060 }
1061 return nextParkingArea;
1062}
1063
1064
1067 MSParkingArea* currentParkingArea = nullptr;
1068 if (isParking()) {
1069 currentParkingArea = myStops.begin()->parkingarea;
1070 }
1071 return currentParkingArea;
1072}
1073
1074
1075
1076double
1077MSBaseVehicle::basePos(const MSEdge* edge) const {
1078 double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
1079 if (hasStops()
1080 && myStops.front().edge == myRoute->begin()
1081 && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
1082 result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
1083 }
1084 return result;
1085}
1086
1087MSLane*
1089 const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
1090 const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
1091 const MSEdge* edge = MSEdge::dictionary(edgeID);
1092 if (edge != nullptr && edge->getOppositeEdge() != nullptr
1093 && laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
1094 const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
1095 stop.edge = edgeID;
1096 return edge->getOppositeEdge()->getLanes()[oppositeIndex];
1097 } else {
1098 return nullptr;
1099 }
1100}
1101
1102bool
1103MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
1104 MSRouteIterator* searchStart) {
1105 MSStop stop(stopPar);
1106 if (stopPar.lane == "") {
1107 // use rightmost allowed lane
1108 MSEdge* e = MSEdge::dictionary(stopPar.edge);
1109 for (MSLane* cand : e->getLanes()) {
1110 if (cand->allowsVehicleClass(getVClass())) {
1111 stop.lane = cand;
1112 break;
1113 }
1114 }
1115 if (stop.lane == nullptr) {
1116 errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
1117 return false;
1118 }
1119 } else {
1120 stop.lane = MSLane::dictionary(stopPar.lane);
1121 if (stop.lane == nullptr) {
1122 // must be an opposite stop
1123 SUMOVehicleParameter::Stop tmp = stopPar;
1124 stop.lane = interpretOppositeStop(tmp);
1125 assert(stop.lane != nullptr);
1126 }
1128 errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
1129 return false;
1130 }
1131 }
1133 stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
1134 if (stop.lane->isInternal()) {
1135 errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
1136 return false;
1137 }
1138 }
1139 stop.initPars(stopPar);
1140 if (stopPar.until != -1) {
1141 // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
1142 const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
1143 }
1144 if (stopPar.arrival != -1) {
1145 const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
1146 }
1147 std::string stopType = "stop";
1148 std::string stopID = "";
1149 if (stop.busstop != nullptr) {
1150 stopType = "busStop";
1151 stopID = stop.busstop->getID();
1152 } else if (stop.containerstop != nullptr) {
1153 stopType = "containerStop";
1154 stopID = stop.containerstop->getID();
1155 } else if (stop.chargingStation != nullptr) {
1156 stopType = "chargingStation";
1157 stopID = stop.chargingStation->getID();
1158 } else if (stop.overheadWireSegment != nullptr) {
1159 stopType = "overheadWireSegment";
1160 stopID = stop.overheadWireSegment->getID();
1161 } else if (stop.parkingarea != nullptr) {
1162 stopType = "parkingArea";
1163 stopID = stop.parkingarea->getID();
1164 }
1165 const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
1166
1167 if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
1168 errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
1169 return false;
1170 }
1171 if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > stop.pars.endPos - stop.pars.startPos
1172 && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
1173 errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
1174 }
1175 const MSEdge* stopLaneEdge = &stop.lane->getEdge();
1176 const MSEdge* stopEdge;
1177 if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
1178 // stop lane is on the opposite side
1179 stopEdge = stopLaneEdge->getOppositeEdge();
1180 stop.isOpposite = true;
1181 } else {
1182 // if stop is on an internal edge the normal edge before the intersection is used
1183 stopEdge = stopLaneEdge->getNormalBefore();
1184 }
1185 MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
1186 if (searchStart == nullptr) {
1187 searchStart = &myCurrEdge;
1188 if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
1189 // already on the intersection but myCurrEdge is before it
1190 searchStart = &succ;
1191 }
1192 }
1193#ifdef DEBUG_ADD_STOP
1194 if (DEBUG_COND) {
1195 std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
1196 << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
1197 << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
1198 << "\n";
1199 }
1200#endif
1201 stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
1202 MSRouteIterator prevStopEdge = myCurrEdge;
1203 const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
1204 double prevStopPos = getPositionOnLane();
1205 // where to insert the stop
1206 std::list<MSStop>::iterator iter = myStops.begin();
1207 if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size())) {
1208 iter = myStops.end();
1209 if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
1210 prevStopEdge = myStops.back().edge;
1211 prevEdge = &myStops.back().lane->getEdge();
1212 prevStopPos = myStops.back().pars.endPos;
1213 stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1214 if (prevStopEdge == stop.edge // laneEdge check is insufficient for looped routes
1215 && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
1216 && prevStopPos > stop.pars.endPos) {
1217 stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
1218 }
1219#ifdef DEBUG_ADD_STOP
1220 if (DEBUG_COND) {
1221 std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin())
1222 << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
1223 }
1224#endif
1225 }
1226 } else {
1227 if (stopPar.index == STOP_INDEX_FIT) {
1228 while (iter != myStops.end() && (iter->edge < stop.edge ||
1229 (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
1230 (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
1231 prevStopEdge = iter->edge;
1232 prevStopPos = iter->pars.endPos;
1233 ++iter;
1234 }
1235 } else {
1236 int index = stopPar.index;
1237 while (index > 0) {
1238 prevStopEdge = iter->edge;
1239 prevStopPos = iter->pars.endPos;
1240 ++iter;
1241 --index;
1242 }
1243#ifdef DEBUG_ADD_STOP
1244 if (DEBUG_COND) {
1245 std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
1246 }
1247#endif
1248 stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1249 }
1250 }
1251 const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
1252 if (stop.edge == myRoute->end()) {
1253 if (!wasTooClose) {
1254 errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
1255 }
1256 return false;
1257 }
1258
1259 const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
1260 prevStopPos + (iter == myStops.begin() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
1261
1262 if (prevStopEdge > stop.edge ||
1263 // a collision-stop happens after vehicle movement and may move the
1264 // vehicle backwards on it's lane (prevStopPos is the vehicle position)
1265 (tooClose && !stop.pars.collision)
1266 || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
1267 // check if the edge occurs again later in the route
1268 //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges()) << "\n";
1269 if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
1270 errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
1271 }
1272 MSRouteIterator next = stop.edge + 1;
1273 return addStop(stopPar, errorMsg, untilOffset, &next);
1274 }
1275 if (wasTooClose) {
1276 errorMsg = "";
1277 }
1278 // David.C:
1279 //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
1280 const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
1281 const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
1282 if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
1283 return false;
1284 }
1285 if (!hasDeparted() && myCurrEdge == stop.edge) {
1286 double pos = -1;
1288 pos = myParameter->departPos;
1289 if (pos < 0.) {
1290 pos += (*myCurrEdge)->getLength();
1291 }
1292 }
1294 pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
1295 }
1296 if (pos > stop.pars.endPos + endPosOffset) {
1297 if (stop.edge != myRoute->end()) {
1298 // check if the edge occurs again later in the route
1299 MSRouteIterator next = stop.edge + 1;
1300 return addStop(stopPar, errorMsg, untilOffset, &next);
1301 }
1302 errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
1303 return false;
1304 }
1305 }
1306 if (iter != myStops.begin()) {
1307 std::list<MSStop>::iterator iter2 = iter;
1308 iter2--;
1309 if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
1310 && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
1311 errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1312 + "' set to end at " + time2string(stop.getUntil())
1313 + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
1314 }
1315 if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1316 errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1317 + "' set to start at " + time2string(stop.pars.arrival)
1318 + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
1319 }
1320 if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1321 errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1322 + "' set to start at " + time2string(stop.pars.arrival)
1323 + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
1324 }
1325 } else {
1326 if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()) {
1327 errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1328 + "' set to end at " + time2string(stop.getUntil())
1329 + " earlier than departure at " + time2string(getParameter().depart) + ".";
1330 }
1331 }
1332 if (stop.getUntil() >= 0 && stop.pars.arrival > stop.getUntil() && errorMsg == "") {
1333 errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1334 + "' set to end at " + time2string(stop.getUntil())
1335 + " earlier than arrival at " + time2string(stop.pars.arrival) + ".";
1336 }
1337 myStops.insert(iter, stop);
1338 //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
1339 // << " routeIndex=" << (stop.edge - myRoute->begin())
1340 // << " stopIndex=" << std::distance(myStops.begin(), iter)
1341 // << " route=" << toString(myRoute->getEdges()) << "\n";
1342 return true;
1343}
1344
1345
1346void
1347MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
1348 if (addRouteStops) {
1349 for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
1350 std::string errorMsg;
1351 if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
1352 throw ProcessError(errorMsg);
1353 }
1354 if (errorMsg != "") {
1355 WRITE_WARNING(errorMsg);
1356 }
1357 }
1358 }
1360 for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
1361 std::string errorMsg;
1362 if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
1363 throw ProcessError(errorMsg);
1364 }
1365 if (errorMsg != "") {
1366 WRITE_WARNING(errorMsg);
1367 }
1368 }
1369}
1370
1371
1372bool
1375 const std::string err = "for vehicle '" + getID() + "' at time=" + time2string(SIMSTEP);
1376 int i = 0;
1377 bool ok = true;
1378 double lastPos = getPositionOnLane();
1379 if (getLane() != nullptr && getLane()->isInternal()
1380 && myStops.size() > 0 && !myStops.front().lane->isInternal()) {
1381 // start edge is still incoming to the intersection so lastPos
1382 // relative to that edge must be adapted
1383 lastPos += (*myCurrEdge)->getLength();
1384 }
1385 for (const MSStop& stop : myStops) {
1386 const double endPos = stop.getEndPos(*this);
1387 MSRouteIterator it;
1388 const std::string prefix = "Stop " + toString(i) + " on edge '" + stop.lane->getEdge().getID() + "' ";
1389 if (stop.lane->isInternal()) {
1390 // find the normal predecessor and ensure that the next route edge
1391 // matches the successor of the internal edge successor
1392 it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
1393 if (it != myRoute->end() && (
1394 it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
1395 it = myRoute->end(); // signal failure
1396 }
1397 } else {
1398 const MSEdge* const stopEdge = &stop.lane->getEdge();
1399 it = std::find(start, myRoute->end(), stopEdge);
1400 }
1401 if (it == myRoute->end()) {
1402 if (!silent) {
1403 WRITE_ERROR(prefix + "is not found after edge '" + (*start)->getID() + "' (" + toString(start - myCurrEdge) + " after current " + err);
1404 }
1405 ok = false;
1406 } else {
1407 MSRouteIterator it2;
1408 for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
1409 if (it2 == stop.edge) {
1410 break;
1411 }
1412 }
1413 if (it2 == myRoute->end()) {
1414 if (!silent) {
1415 WRITE_ERROR(prefix + "used invalid route index " + err);
1416 }
1417 ok = false;
1418 } else if (it2 < start) {
1419 if (!silent) {
1420 WRITE_ERROR(prefix + "used invalid (relative) route index " + toString(it2 - myCurrEdge) + " expected after " + toString(start - myCurrEdge) + " " + err);
1421 }
1422 ok = false;
1423 } else {
1424 if (it != stop.edge) {
1425 double brakeGap = i == 0 ? getBrakeGap() : 0;
1426 if (endPos >= lastPos + brakeGap) {
1427 if (!silent) {
1428 WRITE_WARNING(prefix + "is used in " + toString(stop.edge - myCurrEdge) + " edges but first encounter is in "
1429 + toString(it - myCurrEdge) + " edges " + err);
1430 }
1431 }
1432 }
1433 start = stop.edge;
1434 }
1435 }
1436 lastPos = endPos;
1437 i++;
1438 }
1439 return ok;
1440}
1441
1442
1444MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
1445 assert(haveValidStopEdges());
1446 ConstMSEdgeVector result;
1447 const MSStop* prev = nullptr;
1448 const MSEdge* internalSuccessor = nullptr;
1449 for (const MSStop& stop : myStops) {
1450 if (stop.reached) {
1451 if (stop.pars.jump >= 0) {
1452 jumps.insert((int)result.size());
1453 }
1454 continue;
1455 }
1456 const double stopPos = stop.getEndPos(*this);
1457 if ((prev == nullptr
1458 || prev->edge != stop.edge
1459 || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
1460 && *stop.edge != internalSuccessor) {
1461 result.push_back(*stop.edge);
1462 if (stop.lane->isInternal()) {
1463 internalSuccessor = stop.lane->getNextNormal();
1464 result.push_back(internalSuccessor);
1465 } else {
1466 internalSuccessor = nullptr;
1467 }
1468 }
1469 prev = &stop;
1470 if (firstPos < 0) {
1471 firstPos = stopPos;
1472 }
1473 lastPos = stopPos;
1474 if (stop.pars.jump >= 0) {
1475 jumps.insert((int)result.size() - 1);
1476 }
1477 }
1478 //std::cout << "getStopEdges veh=" << getID() << " result=" << toString(result) << "\n";
1479 return result;
1480}
1481
1482
1483std::vector<std::pair<int, double> >
1485 std::vector<std::pair<int, double> > result;
1486 for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
1487 result.push_back(std::make_pair(
1488 (int)(iter->edge - myRoute->begin()),
1489 iter->getEndPos(*this)));
1490 }
1491 return result;
1492}
1493
1494
1495MSStop&
1497 assert(myStops.size() > 0);
1498 return myStops.front();
1499}
1500
1503 if (isStopped()) {
1504 return myStops.front().duration;
1505 } else {
1506 return 0;
1507 }
1508}
1509
1510
1511MSStop&
1512MSBaseVehicle::getStop(int nextStopIndex) {
1513 if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
1514 throw InvalidArgument("Invalid stop index " + toString(nextStopIndex) + " (has " + toString(myStops.size()) + " stops)");
1515 }
1516 auto stopIt = myStops.begin();
1517 std::advance(stopIt, nextStopIndex);
1518 return *stopIt;
1519}
1520
1521
1524 if (hasStops()) {
1525 return &myStops.front().pars;
1526 }
1527 return nullptr;
1528}
1529
1530
1531bool
1533 //if the stop exists update the duration
1534 for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
1535 if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
1536 // update existing stop
1537 if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
1538 myStops.erase(iter);
1539 } else {
1540 iter->duration = stop.duration;
1541 iter->triggered = stop.triggered;
1542 iter->containerTriggered = stop.containerTriggered;
1543 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
1544 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
1545 }
1546 return true;
1547 }
1548 }
1549 const bool result = addStop(stop, errorMsg);
1550 if (result) {
1552 myParameter->stops.push_back(stop);
1553 }
1554 return result;
1555}
1556
1557
1558bool
1560 if (hasStops() && nextStopIndex < (int)myStops.size()) {
1561 if (nextStopIndex == 0 && isStopped()) {
1563 } else {
1564 auto stopIt = myStops.begin();
1565 std::advance(stopIt, nextStopIndex);
1566 myStops.erase(stopIt);
1567 }
1568 if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1569 // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
1570 auto stopIt2 = myParameter->stops.begin();
1571 std::advance(stopIt2, nextStopIndex);
1572 const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
1573 }
1574 return true;
1575 } else {
1576 return false;
1577 }
1578}
1579
1580
1581bool
1582MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
1583 const int n = (int)myStops.size();
1584 if (nextStopIndex < 0 || nextStopIndex >= n) {
1585 errorMsg = ("Invalid nextStopIndex '" + toString(nextStopIndex) + "' for " + toString(n) + " remaining stops");
1586 return false;
1587 }
1588 if (nextStopIndex == 0 && isStopped()) {
1589 errorMsg = "Cannot replace reached stop";
1590 return false;
1591 }
1593 MSLane* stopLane = MSLane::dictionary(stop.lane);
1594 MSEdge* stopEdge = &stopLane->getEdge();
1595
1596 auto itStop = myStops.begin();
1597 std::advance(itStop, nextStopIndex);
1598 MSStop& replacedStop = *itStop;
1599
1600 if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
1601 // only replace stop attributes
1602 const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
1603 replacedStop.initPars(stop);
1604 return true;
1605 }
1606
1607 if (!stopLane->allowsVehicleClass(getVClass())) {
1608 errorMsg = ("Disallowed stop lane '" + stopLane->getID() + "'");
1609 return false;
1610 }
1611
1612 const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1613 std::vector<MSStop> stops(myStops.begin(), myStops.end());
1614 const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1615 MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1616 double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1617 MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
1618 auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
1620
1621 bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
1622
1623 ConstMSEdgeVector toNewStop;
1624 if (!teleport) {
1625 router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
1626 if (toNewStop.size() == 0) {
1627 errorMsg = "No route found from edge '" + (*itStart)->getID() + "' to stop edge '" + stopEdge->getID() + "'";
1628 return false;
1629 }
1630 }
1631
1632 ConstMSEdgeVector fromNewStop;
1633 if (!newDestination) {
1634 router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
1635 if (fromNewStop.size() == 0) {
1636 errorMsg = "No route found from stop edge '" + stopEdge->getID() + "' to edge '" + (*itEnd)->getID() + "'";
1637 return false;
1638 }
1639 }
1640
1641 const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
1642 replacedStop.initPars(stop);
1643 replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
1644 replacedStop.lane = stopLane;
1646 replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
1647 if (replacedStop.lane->isInternal()) {
1648 errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stop.edge + "' for vehicle '" + getID() + "'.";
1649 return false;
1650 }
1651 }
1652
1653 ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1654 ConstMSEdgeVector newEdges; // only remaining
1655 newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1656 if (!teleport) {
1657 newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
1658 } else {
1659 newEdges.push_back(*itStart);
1660 }
1661 if (!newDestination) {
1662 newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
1663 newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
1664 } else {
1665 newEdges.push_back(stopEdge);
1666 }
1667 //std::cout << SIMTIME << " replaceStop veh=" << getID()
1668 // << " teleport=" << teleport
1669 // << " busStop=" << stop.busstop
1670 // << " oldEdges=" << oldRemainingEdges.size()
1671 // << " newEdges=" << newEdges.size()
1672 // << " toNewStop=" << toNewStop.size()
1673 // << " fromNewStop=" << fromNewStop.size()
1674 // << "\n";
1675
1676 const double routeCost = router.recomputeCosts(newEdges, this, t);
1677 const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
1678 const double savings = previousCost - routeCost;
1679 if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1680 // stops will be rebuilt from scratch so we must patch the stops in myParameter
1681 const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
1682 }
1683 return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
1684}
1685
1686
1687bool
1688MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
1689 const int n = (int)myStops.size();
1690 if (nextStopIndex < 0 || nextStopIndex > n) {
1691 errorMsg = ("Invalid nextStopIndex '" + toString(nextStopIndex) + "' for " + toString(n) + " remaining stops");
1692 return false;
1693 }
1694 if (nextStopIndex == 0 && isStopped()) {
1695 errorMsg = "Cannot reroute towards reached stop";
1696 return false;
1697 }
1699
1700 const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1701 std::vector<MSStop> stops(myStops.begin(), myStops.end());
1702 const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1703 MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1704 double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1705 MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
1706 auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
1708
1709 ConstMSEdgeVector newBetween;
1710 if (!teleport) {
1711 router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
1712 if (newBetween.size() == 0) {
1713 errorMsg = "No route found from edge '" + (*itStart)->getID() + "' to stop edge '" + (*itEnd)->getID() + "'";
1714 return false;
1715 }
1716 }
1717
1718 ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1719 ConstMSEdgeVector newEdges; // only remaining
1720 newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1721 if (!teleport) {
1722 newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
1723 } else {
1724 newEdges.push_back(*itStart);
1725 }
1726 newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
1727 //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
1728 // << " oldEdges=" << oldRemainingEdges.size()
1729 // << " newEdges=" << newEdges.size()
1730 // << " toNewStop=" << toNewStop.size()
1731 // << " fromNewStop=" << fromNewStop.size()
1732 // << "\n";
1733
1734 const double routeCost = router.recomputeCosts(newEdges, this, t);
1735 const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
1736 const double savings = previousCost - routeCost;
1737 return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
1738}
1739
1740
1741bool
1742MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
1743 const int n = (int)myStops.size();
1744 if (nextStopIndex < 0 || nextStopIndex > n) {
1745 errorMsg = ("Invalid nextStopIndex '" + toString(nextStopIndex) + "' for " + toString(n) + " remaining stops");
1746 return false;
1747 }
1748 if (nextStopIndex == 0 && isStopped()) {
1749 errorMsg = "Cannot insert stop before the currently reached stop";
1750 return false;
1751 }
1753 MSLane* stopLane = MSLane::dictionary(stop.lane);
1754 MSEdge* stopEdge = &stopLane->getEdge();
1755
1756 if (!stopLane->allowsVehicleClass(getVClass())) {
1757 errorMsg = ("Disallowed stop lane '" + stopLane->getID() + "'");
1758 return false;
1759 }
1760
1761 const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1762 std::vector<MSStop> stops(myStops.begin(), myStops.end());
1763 const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1764 MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1765 double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1766 MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
1767 auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
1769
1770 bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
1771
1772 ConstMSEdgeVector toNewStop;
1773 if (!teleport) {
1774 router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
1775 if (toNewStop.size() == 0) {
1776 errorMsg = "No route found from edge '" + (*itStart)->getID() + "' to stop edge '" + stopEdge->getID() + "'";
1777 return false;
1778 }
1779 }
1780
1781 ConstMSEdgeVector fromNewStop;
1782 if (!newDestination) {
1783 router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
1784 if (fromNewStop.size() == 0) {
1785 errorMsg = "No route found from stop edge '" + stopEdge->getID() + "' to edge '" + (*itEnd)->getID() + "'";
1786 return false;
1787 }
1788 }
1789
1790 auto itStop = myStops.begin();
1791 std::advance(itStop, nextStopIndex);
1792 MSStop newStop(stop);
1793 newStop.initPars(stop);
1794 newStop.edge = myRoute->end(); // will be patched in replaceRoute
1795 newStop.lane = stopLane;
1797 newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
1798 if (newStop.lane->isInternal()) {
1799 errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stop.edge + "' for vehicle '" + getID() + "'.";
1800 return false;
1801 }
1802 }
1803 myStops.insert(itStop, newStop);
1804
1805 ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1806 ConstMSEdgeVector newEdges; // only remaining
1807 newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1808 if (!teleport) {
1809 newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
1810 } else {
1811 newEdges.push_back(*itStart);
1812 }
1813 if (!newDestination) {
1814 newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
1815 newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
1816 } else {
1817 newEdges.push_back(stopEdge);
1818 }
1819 //std::cout << SIMTIME << " insertStop veh=" << getID()
1820 // << " teleport=" << teleport
1821 // << " busStop=" << stop.busstop
1822 // << " oldEdges=" << oldRemainingEdges.size()
1823 // << " newEdges=" << newEdges.size()
1824 // << " toNewStop=" << toNewStop.size()
1825 // << " fromNewStop=" << fromNewStop.size()
1826 // << "\n";
1827
1828 const double routeCost = router.recomputeCosts(newEdges, this, t);
1829 const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
1830 const double savings = previousCost - routeCost;
1831
1832 if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
1833 // stops will be rebuilt from scratch so we must patch the stops in myParameter
1834 auto it = myParameter->stops.begin() + nextStopIndex;
1835 const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
1836 }
1837 return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
1838}
1839
1840
1841double
1843 if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
1844 MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
1845 return batteryOfVehicle->getActualBatteryCapacity();
1846 } else {
1847 if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
1848 MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
1849 return batteryOfVehicle->getActualBatteryCapacity();
1850 }
1851 }
1852
1853 return -1;
1854}
1855
1856double
1858 if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
1859 MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
1860 return elecHybridDevice->getCurrentFromOverheadWire();
1861 }
1862
1863 return NAN;
1864}
1865
1866double
1868 if (isOnRoad() || isIdling()) {
1870 } else {
1871 return 0.;
1872 }
1873}
1874
1875
1878 return _getWeightsStorage();
1879}
1880
1881
1884 return _getWeightsStorage();
1885}
1886
1887
1890 if (myEdgeWeights == nullptr) {
1892 }
1893 return *myEdgeWeights;
1894}
1895
1896
1897
1898
1899int
1901 int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
1902 return boarded + myParameter->personNumber;
1903}
1904
1905std::vector<std::string>
1907 std::vector<std::string> ret;
1908 const std::vector<MSTransportable*>& persons = getPersons();
1909 for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
1910 ret.push_back((*it_p)->getID());
1911 }
1912 return ret;
1913}
1914
1915int
1917 int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
1918 return loaded + myParameter->containerNumber;
1919}
1920
1921
1922void
1924 // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
1925 if (myPersonDevice != nullptr) {
1927 }
1928 if (myContainerDevice != nullptr) {
1930 }
1931}
1932
1933
1934const std::vector<MSTransportable*>&
1936 if (myPersonDevice == nullptr) {
1938 } else {
1940 }
1941}
1942
1943
1944const std::vector<MSTransportable*>&
1946 if (myContainerDevice == nullptr) {
1948 } else {
1950 }
1951}
1952
1953
1954bool
1955MSBaseVehicle::isLineStop(double position) const {
1956 if (myParameter->line == "") {
1957 // not a public transport line
1958 return false;
1959 }
1960 for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
1961 if (stop.startPos <= position && position <= stop.endPos) {
1962 return true;
1963 }
1964 }
1965 for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
1966 if (stop.startPos <= position && position <= stop.endPos) {
1967 return true;
1968 }
1969 }
1970 return false;
1971}
1972
1973
1974bool
1975MSBaseVehicle::hasDevice(const std::string& deviceName) const {
1976 for (MSDevice* const dev : myDevices) {
1977 if (dev->deviceName() == deviceName) {
1978 return true;
1979 }
1980 }
1981 return false;
1982}
1983
1984
1985void
1986MSBaseVehicle::createDevice(const std::string& deviceName) {
1987 if (!hasDevice(deviceName)) {
1988 if (deviceName == "rerouting") {
1989 ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
1991 if (hasDeparted()) {
1992 // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
1993 MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
1994 assert(routingDevice != 0);
1996 }
1997 } else {
1998 throw InvalidArgument("Creating device of type '" + deviceName + "' is not supported");
1999 }
2000 }
2001}
2002
2003
2004std::string
2005MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
2006 for (MSVehicleDevice* const dev : myDevices) {
2007 if (dev->deviceName() == deviceName) {
2008 return dev->getParameter(key);
2009 }
2010 }
2011 throw InvalidArgument("No device of type '" + deviceName + "' exists");
2012}
2013
2014
2015void
2016MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
2017 for (MSVehicleDevice* const dev : myDevices) {
2018 if (dev->deviceName() == deviceName) {
2019 dev->setParameter(key, value);
2020 return;
2021 }
2022 }
2023 throw InvalidArgument("No device of type '" + deviceName + "' exists");
2024}
2025
2026
2027void
2028MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
2031 const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2032 // checked in MSLink::ignoreFoe
2033 } else {
2034 throw InvalidArgument("Vehicle '" + getID() + "' does not support junctionModel parameter '" + key + "'");
2035 }
2036}
2037
2038
2039void
2040MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
2041 // handle some generic params first and then delegate to the carFollowModel itself
2044 const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2045 // checked in MSVehicle::planMove
2046 } else {
2047 MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
2048 if (microVeh) {
2049 // remove 'carFollowModel.' prefix
2050 const std::string attrName = key.substr(15);
2051 microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
2052 }
2053 }
2054}
2055
2056
2057void
2059 /* Design idea for additional junction model parameters:
2060 We can distinguish between 3 levels of parameters
2061 1. typically shared by multiple vehicles -> vType parameter
2062 2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
2063 3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
2064 */
2065 for (auto item : getParameter().getParametersMap()) {
2066 if (StringUtils::startsWith(item.first, "junctionModel.")) {
2067 setJunctionModelParameter(item.first, item.second);
2068 } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
2069 setCarFollowModelParameter(item.first, item.second);
2070 }
2071 }
2072}
2073
2074
2075void
2077 assert(type != nullptr);
2078 if (myType->isVehicleSpecific() && type != myType) {
2080 }
2081 myType = type;
2082 if (myEnergyParams != nullptr) {
2084 }
2085}
2086
2087
2090 if (myType->isVehicleSpecific()) {
2091 return *myType;
2092 }
2093 MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
2094 replaceVehicleType(type);
2095 return *type;
2096}
2097
2098
2099int
2101 const MSLane* const lane = getLane();
2102 if (lane == nullptr) {
2103 return getEdge()->getLanes()[0]->getRNGIndex();
2104 } else {
2105 return lane->getRNGIndex();
2106 }
2107}
2108
2109
2110SumoRNG*
2112 const MSLane* lane = getLane();
2113 if (lane == nullptr) {
2114 return getEdge()->getLanes()[0]->getRNG();
2115 } else {
2116 return lane->getRNG();
2117 }
2118}
2119
2120std::string
2121MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
2122 const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
2123 if (StringUtils::startsWith(key, "device.")) {
2124 StringTokenizer tok(key, ".");
2125 if (tok.size() < 3) {
2126 error = "Invalid device parameter '" + key + "' for vehicle '" + getID() + "'.";
2127 return "";
2128 }
2129 try {
2130 return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
2131 } catch (InvalidArgument& e) {
2132 error = "Vehicle '" + getID() + "' does not support device parameter '" + key + "' (" + e.what() + ").";
2133 return "";
2134 }
2135 } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
2136 if (microVeh == nullptr) {
2137 error = "Meso Vehicle '" + getID() + "' does not support laneChangeModel parameters.";
2138 return "";
2139 }
2140 const std::string attrName = key.substr(16);
2141 try {
2142 return microVeh->getLaneChangeModel().getParameter(attrName);
2143 } catch (InvalidArgument& e) {
2144 error = "Vehicle '" + getID() + "' does not support laneChangeModel parameter '" + key + "' (" + e.what() + ").";
2145 return "";
2146 }
2147 } else if (StringUtils::startsWith(key, "carFollowModel.")) {
2148 if (microVeh == nullptr) {
2149 error = "Meso Vehicle '" + getID() + "' does not support carFollowModel parameters.";
2150 return "";
2151 }
2152 const std::string attrName = key.substr(15);
2153 try {
2154 return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
2155 } catch (InvalidArgument& e) {
2156 error = "Vehicle '" + getID() + "' does not support carFollowModel parameter '" + key + "' (" + e.what() + ").";
2157 return "";
2158 }
2159 } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
2160 StringTokenizer tok(key, ".");
2161 if (tok.size() != 3) {
2162 error = "Invalid check for device. Expected format is 'has.DEVICENAME.device'.";
2163 return "";
2164 }
2165 return hasDevice(tok.get(1)) ? "true" : "false";
2166 // parking related parameters start here
2167 } else if (key == "parking.rerouteCount") {
2169 } else if (StringUtils::startsWith(key, "parking.memory.")) {
2170 std::vector<std::string> values;
2171 if (getParkingMemory()) {
2172 if (key == "parking.memory.IDList") {
2173 for (const auto& item : *getParkingMemory()) {
2174 values.push_back(item.first->getID());
2175 }
2176 } else if (key == "parking.memory.score") {
2177 for (const auto& item : *getParkingMemory()) {
2178 values.push_back(item.second.score);
2179 }
2180 } else if (key == "parking.memory.blockedAtTime") {
2181 for (const auto& item : *getParkingMemory()) {
2182 values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
2183 }
2184 } else if (key == "parking.memory.blockedAtTimeLocal") {
2185 for (const auto& item : *getParkingMemory()) {
2186 values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
2187 }
2188 } else {
2189 error = "Unsupported parking parameter '" + key + "'.";
2190 }
2191 }
2192 return toString(values);
2193 } else {
2194 // default: custom user parameter
2195 return getParameter().getParameter(key, "");
2196 }
2197}
2198
2199void
2201 if (myParkingMemory == nullptr) {
2203 }
2204 (*myParkingMemory)[pa].blockedAtTime = SIMSTEP;
2205 if (local) {
2206 (*myParkingMemory)[pa].blockedAtTimeLocal = SIMSTEP;
2207 }
2208}
2209
2210void
2212 if (myParkingMemory != nullptr) {
2213 for (auto& item : *myParkingMemory) {
2214 item.second.score = "";
2215 }
2216 }
2217}
2218
2219void
2220MSBaseVehicle::rememberParkingAreaScore(const MSParkingArea* pa, const std::string& score) {
2221 if (myParkingMemory == nullptr) {
2223 }
2224 (*myParkingMemory)[pa].score = score;
2225}
2226
2227
2230 if (myParkingMemory == nullptr) {
2231 return -1;
2232 }
2233 auto it = myParkingMemory->find(pa);
2234 if (it == myParkingMemory->end()) {
2235 return -1;
2236 } else {
2237 return local ? it->second.blockedAtTimeLocal : it->second.blockedAtTime;
2238 }
2239}
2240
2241#ifdef _DEBUG
2242void
2243MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
2244 if (oc.isSet("movereminder-output.vehicles")) {
2245 const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
2246 myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
2247 }
2248}
2249
2250
2251void
2252MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
2253 OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
2254 od.openTag("movereminder");
2255 od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
2256 od.writeAttr("veh", getID());
2258 od.writeAttr("type", type);
2259 od.writeAttr("pos", toString(pos));
2260 od.writeAttr("keep", toString(keep));
2261 od.closeTag();
2262}
2263#endif
2264
2265
2266/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
#define DEBUG_COND
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
ConstMSEdgeVector::const_iterator MSRouteIterator
Definition: MSRoute.h:56
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:271
#define WRITE_ERRORF(...)
Definition: MsgHandler.h:280
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:279
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:270
#define TL(string)
Definition: MsgHandler.h:287
#define TLF(string,...)
Definition: MsgHandler.h:288
std::shared_ptr< const MSRoute > ConstMSRoutePtr
Definition: Route.h:32
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition: SUMOTime.cpp:69
#define STEPS2TIME(x)
Definition: SUMOTime.h:55
#define SIMSTEP
Definition: SUMOTime.h:61
#define SUMOTime_MAX
Definition: SUMOTime.h:34
#define SIMTIME
Definition: SUMOTime.h:62
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
const int VEHPARS_CFMODEL_PARAMS_SET
@ RANDOM
The edge is chosen randomly.
@ GIVEN
The edge index is given.
@ DEFAULT
No information given; use default.
const int STOP_INDEX_END
const int VEHPARS_JUNCTIONMODEL_PARAMS_SET
DepartLaneDefinition
Possible ways to choose a lane on depart.
@ GIVEN
The speed is given.
@ GIVEN
The position is given.
@ DEFAULT
No information given; use default.
@ BASE
Back-at-zero position.
const int VEHPARS_SPEEDFACTOR_SET
@ RANDOM
The lane is chosen randomly.
@ GIVEN
The arrival lane is given.
@ FIRST_ALLOWED
The rightmost lane the vehicle may use.
const int VEHPARS_FORCE_REROUTE
const int STOP_INDEX_FIT
@ RANDOM
The arrival position is chosen randomly.
@ GIVEN
The arrival position is given.
@ CENTER
Half the road length.
const int VEHPARS_LINE_SET
@ CONTAINER_TRIGGERED
The departure is container triggered.
@ TRIGGERED
The departure is person triggered.
@ SUMO_TAG_VEHICLE
description of a vehicle
@ SUMO_ATTR_CF_IGNORE_IDS
@ SUMO_ATTR_JM_IGNORE_IDS
@ SUMO_ATTR_JM_IGNORE_TYPES
@ SUMO_ATTR_LINE
@ SUMO_ATTR_REROUTE
@ SUMO_ATTR_DISTANCE
@ SUMO_ATTR_SPEEDFACTOR
@ SUMO_ATTR_ROUTE
@ SUMO_ATTR_ID
@ SUMO_ATTR_CF_IGNORE_TYPES
@ SUMO_ATTR_TIME
trigger: the time of the step
int gPrecisionRandom
Definition: StdDefs.cpp:28
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
T MIN2(T a, T b)
Definition: StdDefs.h:76
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:58
T MAX2(T a, T b)
Definition: StdDefs.h:82
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
void setSecondary(const EnergyParams *secondaryParams)
Set secondary params.
Definition: EnergyParams.h:55
static double computeNoise(SUMOEmissionClass c, double v, double a)
Returns the noise produced by the a vehicle of the given type at the given speed.
MESegment * getSegmentForEdge(const MSEdge &e, double pos=0)
Get the segment for a given edge at a given position.
Definition: MELoop.cpp:325
virtual std::string getParameter(const std::string &key) const
try to retrieve the given parameter from this laneChangeModel. Throw exception for unsupported key
SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT(const int rngIndex, SUMOVehicleClass svc) const
double getMaxSpeed() const
Returns the maximum speed (the minimum of desired and technical maximum speed)
MSVehicleDevice * getDevice(const std::type_info &type) const
Returns a device of the given type if it exists, nullptr otherwise.
bool haveValidStopEdges(bool silent=false) const
check whether all stop.edge MSRouteIterators are valid and in order
bool hasJump(const MSRouteIterator &it) const
check wether the vehicle has jump at the given part of it's route
ParkingMemory * myParkingMemory
memory for parking search
void rememberBlockedParkingArea(const MSParkingArea *pa, bool local)
std::list< MSStop > myStops
The vehicle's list of stops.
double getImpatience() const
Returns this vehicles impatience.
virtual ConstMSEdgeVector::const_iterator getRerouteOrigin() const
Returns the starting point for reroutes (usually the current edge)
const std::vector< MSTransportable * > & getPersons() const
retrieve riding persons
virtual void initDevices()
const MSEdge * succEdge(int nSuccs) const
Returns the nSuccs'th successor of edge the vehicle is currently at.
void resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure)
reset index of edge within route
std::map< const MSParkingArea *, PaMemory, ComparatorIdLess > ParkingMemory
std::string getDeviceParameter(const std::string &deviceName, const std::string &key) const
try to retrieve the given parameter from any of the vehicles devices, raise InvalidArgument if no dev...
bool replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string &info, bool teleport, std::string &errorMsg)
MSBaseVehicle(SUMOVehicleParameter *pars, ConstMSRoutePtr route, MSVehicleType *type, const double speedFactor)
Constructor.
void calculateArrivalParams(bool onInit)
(Re-)Calculates the arrival position and lane from the vehicle parameters
virtual double getArrivalPos() const
Returns this vehicle's desired arrivalPos for its current route (may change on reroute)
void setCarFollowModelParameter(const std::string &key, const std::string &value)
set individual carFollow model parameters (not type related)
void resetParkingAreaScores()
MSVehicleType * myType
This vehicle's type.
static NumericalID myCurrentNumericalIndex
bool rerouteBetweenStops(int nextStopIndex, const std::string &info, bool teleport, std::string &errorMsg)
MoveReminderCont myMoveReminders
Currently relevant move reminders.
double myDepartPos
The real depart position.
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
void addReminder(MSMoveReminder *rem)
Adds a MoveReminder dynamically.
void replaceParameter(const SUMOVehicleParameter *newParameter)
replace the vehicle parameter (deleting the old one)
int getNumberParkingReroutes() const
std::vector< MSVehicleDevice * > myDevices
The devices this vehicle has.
double getPreviousSpeed() const
Returns the vehicle's previous speed.
virtual void addTransportable(MSTransportable *transportable)
Adds a person or container to this vehicle.
virtual BaseInfluencer & getBaseInfluencer()=0
Returns the velocity/lane influencer.
const SUMOVehicleParameter::Stop * getNextStopParameter() const
return parameters for the next stop (SUMOVehicle Interface)
double getOdometer() const
Returns the distance that was already driven by this vehicle.
virtual bool hasArrived() const
Returns whether this vehicle has already arived (by default this is true if the vehicle has reached i...
const NumericalID myNumericalID
bool isStoppedInRange(const double pos, const double tolerance, bool checkFuture=false) const
return whether the given position is within range of the current stop
bool isJumping() const
Returns whether the vehicle is perform a jump.
void checkRouteRemoval()
remove route at the end of the simulation
MSVehicleType & getSingularType()
Replaces the current vehicle type with a new one used by this vehicle only.
SUMOTime sawBlockedParkingArea(const MSParkingArea *pa, bool local) const
virtual void replaceVehicleType(MSVehicleType *type)
Replaces the current vehicle type by the one given.
const MSRouteIterator & getCurrentRouteEdge() const
Returns an iterator pointing to the current edge in this vehicles route.
bool isStoppedParking() const
Returns whether the vehicle is on a parking stop.
bool hasValidRoute(std::string &msg, ConstMSRoutePtr route=0) const
Validates the current or given route.
double getLength() const
Returns the vehicle's length.
bool isParking() const
Returns whether the vehicle is parking.
MSParkingArea * getCurrentParkingArea()
get the current parking area stop or nullptr
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
double getHarmonoise_NoiseEmissions() const
Returns noise emissions of the current state.
int getPersonNumber() const
Returns the number of persons.
void setJunctionModelParameter(const std::string &key, const std::string &value)
set individual junction model paramete (not type related)
void setDepartAndArrivalEdge()
apply departEdge and arrivalEdge attributes
void setID(const std::string &newID)
set the id (inherited from Named but forbidden for vehicles)
MSRouteIterator myCurrEdge
Iterator to current route-edge.
static MSLane * interpretOppositeStop(SUMOVehicleParameter::Stop &stop)
interpret stop lane on opposite side of the road
static std::vector< MSTransportable * > myEmptyTransportableVector
bool hasDeparted() const
Returns whether this vehicle has already departed.
MSStop & getNextStop()
ConstMSRoutePtr myRoute
This vehicle's route.
const ConstMSEdgeVector getStopEdges(double &firstPos, double &lastPos, std::set< int > &jumps) const
Returns the list of still pending stop edges also returns the first and last stop position.
MSDevice_Transportable * myContainerDevice
The containers this vehicle may have.
bool allowsBoarding(const MSTransportable *t) const
whether the given transportable is allowed to board this vehicle
double getStateOfCharge() const
Returns actual state of charge of battery (Wh) RICE_CHECK: This may be a misnomer,...
MSEdgeWeightsStorage & _getWeightsStorage() const
virtual bool handleCollisionStop(MSStop &stop, const double distToStop)
bool hasDevice(const std::string &deviceName) const
check whether the vehicle is equiped with a device of the given name
SumoRNG * getRNG() const
SUMOTime getDeparture() const
Returns this vehicle's real departure time.
EnergyParams * getEmissionParameters() const
retrieve parameters for the energy consumption model
double basePos(const MSEdge *edge) const
departure position where the vehicle fits fully onto the edge (if possible)
void setDeviceParameter(const std::string &deviceName, const std::string &key, const std::string &value)
try to set the given parameter from any of the vehicles devices, raise InvalidArgument if no device p...
MSDevice_Transportable * myPersonDevice
The passengers this vehicle may have.
bool hasStops() const
Returns whether the vehicle has to stop somewhere.
std::string getFlowID() const
reconstruct flow id from vehicle id
virtual void activateReminders(const MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
"Activates" all current move reminder
bool isLineStop(double position) const
returns whether the vehicle serves a public transport line that serves the given stop
double myChosenSpeedFactor
A precomputed factor by which the driver wants to be faster than the speed limit.
@ ROUTE_INVALID
route was checked and is valid
Definition: MSBaseVehicle.h:74
@ ROUTE_START_INVALID_PERMISSIONS
Definition: MSBaseVehicle.h:76
std::string getPrefixedParameter(const std::string &key, std::string &error) const
retrieve parameters of devices, models and the vehicle itself
void addStops(const bool ignoreStopErrors, MSRouteIterator *searchStart=nullptr, bool addRouteStops=true)
Adds stops to the built vehicle.
void removeTransportable(MSTransportable *t)
removes a person or container
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
MSParkingArea * getNextParkingArea()
get the upcoming parking area stop or nullptr
int myArrivalLane
The destination lane where the vehicle stops.
int getRouteValidity(bool update=true, bool silent=false, std::string *msgReturn=nullptr)
check for route validity at first insertion attempt
MSStop & getStop(int nextStopIndex)
virtual ~MSBaseVehicle()
Destructor.
bool insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string &info, bool teleport, std::string &errorMsg)
SUMOTime myDeparture
The real departure time.
std::vector< std::string > getPersonIDList() const
Returns the list of persons.
const MSEdgeWeightsStorage & getWeightsStorage() const
Returns the vehicle's internal edge travel times/efforts container.
bool isStoppedTriggered() const
Returns whether the vehicle is on a triggered stop.
virtual bool resumeFromStopping()=0
virtual bool hasInfluencer() const =0
whether the vehicle is individually influenced (via TraCI or special parameters)
bool stopsAtEdge(const MSEdge *edge) const
Returns whether the vehicle stops at the given edge.
void rememberParkingAreaScore(const MSParkingArea *pa, const std::string &score)
score only needed when running with gui
bool addStop(const SUMOVehicleParameter::Stop &stopPar, std::string &errorMsg, SUMOTime untilOffset=0, MSRouteIterator *searchStart=nullptr)
Adds a stop.
std::vector< SUMOVehicleParameter::Stop > myPastStops
The list of stops that the vehicle has already reached.
void onDepart()
Called when the vehicle is inserted into the network.
void removeReminder(MSMoveReminder *rem)
Removes a MoveReminder dynamically.
SUMOTime getStopDuration() const
get remaining stop duration or 0 if the vehicle isn't stopped
virtual double getAcceleration() const
Returns the vehicle's acceleration.
virtual bool addTraciStop(SUMOVehicleParameter::Stop stop, std::string &errorMsg)
const MSRoute & getRoute() const
Returns the current route.
int getRoutePosition() const
return index of edge within route
bool replaceParkingArea(MSParkingArea *parkingArea, std::string &errorMsg)
replace the current parking area stop with a new stop with merge duration
static const SUMOTime NOT_YET_DEPARTED
SUMOTime getDepartDelay() const
Returns the depart delay.
double getElecHybridCurrent() const
Returns actual current (A) of ElecHybrid device RICE_CHECK: Is this the current consumed from the ove...
EnergyParams * myEnergyParams
The emission parameters this vehicle may have.
const SUMOVehicleParameter * myParameter
This vehicle's parameter.
virtual bool hasValidRouteStart(std::string &msg)
checks wether the vehicle can depart on the first edge
int myRouteValidity
status of the current vehicle route
std::vector< std::pair< int, double > > getStopIndices() const
return list of route indices for the remaining stops
SUMOTime myStopUntilOffset
The offset when adding route stops with 'until' on route replacement.
virtual bool replaceRoute(ConstMSRoutePtr route, const std::string &info, bool onInit=false, int offset=0, bool addStops=true, bool removeStops=true, std::string *msgReturn=nullptr)
Replaces the current route by the given one.
virtual bool isOnRoad() const
Returns the information whether the vehicle is on a road (is simulated)
void reroute(SUMOTime t, const std::string &info, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router, const bool onInit=false, const bool withTaz=false, const bool silent=false)
Performs a rerouting using the given router.
const std::vector< MSTransportable * > & getContainers() const
retrieve riding containers
bool stopsAt(MSStoppingPlace *stop) const
Returns whether the vehicle stops at the given stopping place.
int getRNGIndex() const
MSEdgeWeightsStorage * myEdgeWeights
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
void createDevice(const std::string &deviceName)
create device of the given type
bool isStopped() const
Returns whether the vehicle is at a stop.
const ParkingMemory * getParkingMemory() const
bool abortNextStop(int nextStopIndex=0)
deletes the next stop at the given index if it exists
int myNumberReroutes
The number of reroutings.
double myArrivalPos
The position on the destination lane where the vehicle stops.
virtual void saveState(OutputDevice &out)
Saves the (common) state of a vehicle.
double myOdometer
A simple odometer to keep track of the length of the route already driven.
void initTransientModelParams()
init model parameters from generic params
int getContainerNumber() const
Returns the number of containers.
bool replaceRouteEdges(ConstMSEdgeVector &edges, double cost, double savings, const std::string &info, bool onInit=false, bool check=false, bool removeStops=true, std::string *msgReturn=nullptr)
Replaces the current route by the given edges.
virtual std::string getParameter(const MSVehicle *veh, const std::string &key) const
try to get the given parameter for this carFollowingModel
Definition: MSCFModel.h:640
virtual void setParameter(MSVehicle *veh, const std::string &key, const std::string &value) const
try to set the given parameter for this carFollowingModel
Definition: MSCFModel.h:653
Battery device for electric vehicles.
double getActualBatteryCapacity() const
Get the actual vehicle's Battery Capacity in Wh.
A device which collects info on the vehicle trip (mainly on departure and arrival)
double getCurrentFromOverheadWire() const
Get actual current in the overhead wire segment.
double getActualBatteryCapacity() const
Get the actual vehicle's Battery Capacity in kWh.
A device that performs vehicle rerouting based on current edge speeds.
bool notifyEnter(SUMOTrafficObject &veh, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Computes a new route on vehicle insertion.
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSVehicleDevice * > &into)
Build devices for the given vehicle, if needed.
A device which collects info on the vehicle trip (mainly on departure and arrival)
Definition: MSDevice_Taxi.h:49
bool allowsBoarding(const MSTransportable *t) const
whether the given person is allowed to board this taxi
const std::vector< MSTransportable * > & getTransportables() const
Returns the list of transportables using this vehicle.
static MSDevice_Transportable * buildVehicleDevices(SUMOVehicle &v, std::vector< MSVehicleDevice * > &into, const bool isContainer)
Build devices for the given vehicle, if needed.
int size() const
Return the number of passengers / containers.
void addTransportable(MSTransportable *transportable)
Add a passenger.
void removeTransportable(MSTransportable *transportable)
Remove a passenger (TraCI)
Abstract in-vehicle / in-person device.
Definition: MSDevice.h:61
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSVehicleDevice * > &into)
Build devices for the given vehicle, if needed.
Definition: MSDevice.cpp:107
A road/street connecting two junctions.
Definition: MSEdge.h:77
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
const MSEdge * getOppositeEdge() const
Returns the opposite direction edge if on exists else a nullptr.
Definition: MSEdge.cpp:1237
bool isNormal() const
return whether this edge is an internal edge
Definition: MSEdge.h:260
const std::vector< MSLane * > * allowedLanes(const MSEdge &destination, SUMOVehicleClass vclass=SVC_IGNORING) const
Get the allowed lanes to reach the destination-edge.
Definition: MSEdge.cpp:439
double getLength() const
return the length of the edge
Definition: MSEdge.h:658
bool isTazConnector() const
Definition: MSEdge.h:288
int getNumLanes() const
Definition: MSEdge.h:172
bool isInternal() const
return whether this edge is an internal edge
Definition: MSEdge.h:265
static bool dictionary(const std::string &id, MSEdge *edge)
Inserts edge into the static dictionary Returns true if the key id isn't already in the dictionary....
Definition: MSEdge.cpp:945
const MSEdge * getNormalBefore() const
if this edge is an internal edge, return its first normal predecessor, otherwise the edge itself
Definition: MSEdge.cpp:835
A storage for edge travel times and efforts.
static bool gUseMesoSim
Definition: MSGlobals.h:103
static bool gCheckRoutes
Definition: MSGlobals.h:88
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition: MSGlobals.h:109
static SUMOTime gTimeToImpatience
Definition: MSGlobals.h:75
static bool gHaveEmissions
Whether emission output of some type is needed (files or GUI)
Definition: MSGlobals.h:178
static bool gUseStopEnded
whether the simulation should replay previous stop times
Definition: MSGlobals.h:130
void descheduleDeparture(const SUMOVehicle *veh)
stops trying to emit the given vehicle (and delete it)
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
int getRNGIndex() const
returns the associated RNG index
Definition: MSLane.h:240
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition: MSLane.cpp:2301
double getLength() const
Returns the lane's length.
Definition: MSLane.h:593
bool allowsVehicleClass(SUMOVehicleClass vclass) const
Definition: MSLane.h:900
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition: MSLane.cpp:2325
bool isInternal() const
Definition: MSLane.cpp:2456
SumoRNG * getRNG() const
return the associated RNG
Definition: MSLane.h:245
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:745
Something on a lane to be noticed about vehicle movement.
const std::string & getDescription() const
Notification
Definition of a vehicle state.
@ NOTIFICATION_DEPARTED
The vehicle has departed (was inserted into the network)
bool warnOnce(const std::string &typeAndID)
return whether a warning regarding the given object shall be issued
Definition: MSNet.cpp:1623
@ NEWROUTE
The vehicle got a new route.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:183
SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT(const int rngIndex, const MSEdgeVector &prohibited=MSEdgeVector()) const
Definition: MSNet.cpp:1465
bool hasFlow(const std::string &id) const
return whether the given flow is known
Definition: MSNet.cpp:388
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:322
void informVehicleStateListener(const SUMOVehicle *const vehicle, VehicleState to, const std::string &info="")
Informs all added listeners about a vehicle's state change.
Definition: MSNet.cpp:1257
MSInsertionControl & getInsertionControl()
Returns the insertion control.
Definition: MSNet.h:433
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:380
A lane area vehicles can halt at.
Definition: MSParkingArea.h:58
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:124
void setCosts(double costs)
Sets the costs of the route.
Definition: MSRoute.h:199
static bool hasRoute(const std::string &id)
returns whether a route with the given id exists
Definition: MSRoute.cpp:152
static bool dictionary(const std::string &id, ConstMSRoutePtr route)
Adds a route to the dictionary.
Definition: MSRoute.cpp:109
static void checkDist(const std::string &id)
Checks the distribution whether it is permanent and deletes it if not.
Definition: MSRoute.cpp:187
void setSavings(double savings)
Sets the savings of the route.
Definition: MSRoute.h:206
static SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT(const int rngIndex, SUMOVehicleClass svc, const MSEdgeVector &prohibited=MSEdgeVector())
return the router instance
Definition: MSStop.h:44
const MSLane * lane
The lane to stop at (microsim only)
Definition: MSStop.h:50
MSStoppingPlace * containerstop
(Optional) container stop if one is assigned to the stop
Definition: MSStop.h:56
bool isOpposite
whether this an opposite-direction stop
Definition: MSStop.h:87
void initPars(const SUMOVehicleParameter::Stop &stopPar)
initialize attributes from the given stop parameters
Definition: MSStop.cpp:112
const MESegment * segment
The segment to stop at (mesosim only)
Definition: MSStop.h:52
bool reached
Information whether the stop has been reached.
Definition: MSStop.h:75
MSRouteIterator edge
The edge in the route to stop at.
Definition: MSStop.h:48
double getEndPos(const SUMOVehicle &veh) const
return halting position for upcoming stop;
Definition: MSStop.cpp:35
MSParkingArea * parkingarea
(Optional) parkingArea if one is assigned to the stop
Definition: MSStop.h:58
MSStoppingPlace * chargingStation
(Optional) charging station if one is assigned to the stop
Definition: MSStop.h:60
std::string getDescription() const
get a short description for showing in the gui
Definition: MSStop.cpp:69
SUMOTime getUntil() const
return until / ended time
Definition: MSStop.cpp:151
const SUMOVehicleParameter::Stop pars
The stop parameter.
Definition: MSStop.h:65
MSStoppingPlace * busstop
(Optional) bus stop if one is assigned to the stop
Definition: MSStop.h:54
MSStoppingPlace * overheadWireSegment
(Optional) overhead wire segment if one is assigned to the stop
Definition: MSStop.h:63
A lane area vehicles can halt at.
double getBeginLanePosition() const
Returns the begin position of this stop.
double getEndLanePosition() const
Returns the end position of this stop.
const MSLane & getLane() const
Returns the lane this stop is located at.
bool isPerson() const
Whether it is a person.
bool hasVTypeDistribution(const std::string &id) const
Asks for a vehicle type distribution.
void vehicleDeparted(const SUMOVehicle &v)
Informs this control about a vehicle's departure.
void removeVType(const MSVehicleType *vehType)
Abstract in-vehicle device.
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:5620
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition: MSVehicle.h:978
The car-following model and parameter.
Definition: MSVehicleType.h:63
const EnergyParams * getEmissionParameters() const
retrieve parameters for the energy consumption model
SUMOVehicleClass getVehicleClass() const
Get this vehicle type's vehicle class.
double getMaxSpeed() const
Get vehicle's (technical) maximum speed [m/s].
double getDesiredMaxSpeed() const
Returns the vehicles's desired maximum speed.
const std::string & getID() const
Returns the name of the vehicle type.
Definition: MSVehicleType.h:91
bool isVehicleSpecific() const
Returns whether this type belongs to a single vehicle only (was modified)
SUMOEmissionClass getEmissionClass() const
Get this vehicle type's emission class.
double getLength() const
Get vehicle's length [m].
MSVehicleType * buildSingularType(const std::string &id) const
Duplicates the microsim vehicle type giving the newly created type the given id, marking it as vehicl...
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:67
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A storage for options typed value containers)
Definition: OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:61
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:254
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
int precision()
return precision set on the device
static OutputDevice & getDeviceByOption(const std::string &name)
Returns the device described by the option.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
void setPrecision(int precision=gPrecision)
Sets the precision or resets it to default.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
static const RGBColor DEFAULT_COLOR
The default color (for vehicle types and vehicles)
Definition: RGBColor.h:199
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.cpp:94
bool computeLooped(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)
Builds the route between the given edges using the minimum effort at the given time if from == to,...
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
virtual double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime, double *lengthp=nullptr) const
virtual SUMOTime getWaitingTime() const =0
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
long long int NumericalID
virtual double getSpeed() const =0
Returns the object's current speed.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
Representation of a vehicle.
Definition: SUMOVehicle.h:62
virtual bool isIdling() const =0
Returns whether the vehicle is idling (waiting to re-enter the net.
virtual double getBrakeGap(bool delayed=false) const =0
get distance for coming to a stop (used for rerouting checks)
Definition of vehicle stop (position and duration)
std::string edge
The edge to stop at (used only in netedit)
ParkingType parking
whether the vehicle is removed from the net while stopping
std::string lane
The lane to stop at.
std::string parkingarea
(Optional) parking area if one is assigned to the stop
double startPos
The stopping position start.
int index
at which position in the stops list
SUMOTime until
The time at which the vehicle may continue its journey.
bool triggered
whether an arriving person lets the vehicle continue
SUMOTime ended
the time at which this stop was ended
double endPos
The stopping position end.
bool containerTriggered
whether an arriving container lets the vehicle continue
bool collision
Whether this stop was triggered by a collision.
SUMOTime arrival
The (expected) time at which the vehicle reaches the stop.
SUMOTime duration
The stopping duration.
Structure representing possible vehicle parameter.
int parametersSet
Information for the router which parameter were set, TraCI may modify this (when changing color)
ArrivalSpeedDefinition arrivalSpeedProcedure
Information how the vehicle's end speed shall be chosen.
std::string vtypeid
The vehicle's type id.
SUMOTime repetitionOffset
The time offset between vehicle reinsertions.
std::vector< std::string > via
List of the via-edges the vehicle must visit.
int repetitionsDone
The number of times the vehicle was already inserted.
ArrivalLaneDefinition arrivalLaneProcedure
Information how the vehicle shall choose the lane to arrive on.
void write(OutputDevice &dev, const OptionsCont &oc, const SumoXMLTag altTag=SUMO_TAG_VEHICLE, const std::string &typeID="") const
Writes the parameters as a beginning element.
int personNumber
The static number of persons in the vehicle when it departs (not including boarding persons)
RouteIndexDefinition arrivalEdgeProcedure
Information how the vehicle's final edge shall be chosen.
double departPos
(optional) The position the vehicle shall depart from
double arrivalPos
(optional) The position the vehicle shall arrive on
std::string routeid
The vehicle's route id.
std::string id
The vehicle's id.
std::vector< Stop > stops
List of the stops the vehicle will make, TraCI may add entries here.
int departEdge
(optional) The initial edge within the route of the vehicle
bool wasSet(int what) const
Returns whether the given parameter was set.
ArrivalPosDefinition arrivalPosProcedure
Information how the vehicle shall choose the arrival position.
std::string toTaz
The vehicle's destination zone (district)
double arrivalSpeed
(optional) The final speed of the vehicle (not used yet)
DepartDefinition departProcedure
Information how the vehicle shall choose the depart time.
int arrivalEdge
(optional) The final edge within the route of the vehicle
std::string fromTaz
The vehicle's origin zone (district)
DepartPosDefinition departPosProcedure
Information how the vehicle shall choose the departure position.
std::string line
The vehicle's line (mainly for public transport)
int containerNumber
The static number of containers in the vehicle when it departs.
RouteIndexDefinition departEdgeProcedure
Information how the vehicle's initial edge shall be chosen.
static std::string getEdgeIDFromLane(const std::string laneID)
return edge id when given the lane ID
static int getIndexFromLane(const std::string laneID)
return lane index when given the lane ID
int size() const
returns the number of existing substrings
std::string get(int pos) const
returns the item at the given position
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static bool endsWith(const std::string &str, const std::string suffix)
Checks whether a given string ends with the suffix.
TRACI_CONST int ROUTING_MODE_AGGREGATED
TRACI_CONST int ROUTING_MODE_DEFAULT