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-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
20 // A base class for vehicle implementations
21 /****************************************************************************/
22 #include <config.h>
23 
24 #include <iostream>
25 #include <cassert>
26 #include <utils/common/StdDefs.h>
32 #include <libsumo/TraCIConstants.h>
33 #include <mesosim/MELoop.h>
34 #include <mesosim/MEVehicle.h>
47 #include "MSGlobals.h"
48 #include "MSVehicleControl.h"
49 #include "MSVehicleType.h"
50 #include "MSEdge.h"
51 #include "MSLane.h"
52 #include "MSMoveReminder.h"
53 #include "MSEdgeWeightsStorage.h"
54 #include "MSNet.h"
55 #include "MSStop.h"
56 #include "MSParkingArea.h"
57 #include "MSInsertionControl.h"
58 #include "MSBaseVehicle.h"
59 
60 //#define DEBUG_REROUTE
61 //#define DEBUG_ADD_STOP
62 //#define DEBUG_COND (getID() == "")
63 //#define DEBUG_COND (true)
64 //#define DEBUG_REPLACE_ROUTE
65 #define DEBUG_COND (isSelected())
66 
67 // ===========================================================================
68 // static members
69 // ===========================================================================
71 std::vector<MSTransportable*> MSBaseVehicle::myEmptyTransportableVector;
72 #ifdef _DEBUG
73 std::set<std::string> MSBaseVehicle::myShallTraceMoveReminders;
74 #endif
76 
77 // ===========================================================================
78 // Influencer method definitions
79 // ===========================================================================
80 
82 {}
83 
84 // ===========================================================================
85 // method definitions
86 // ===========================================================================
87 
88 double
90  throw ProcessError("getPreviousSpeed() is not available for non-MSVehicles.");
91 }
92 
93 
95  MSVehicleType* type, const double speedFactor) :
96  SUMOVehicle(pars->id),
97  myParameter(pars),
98  myRoute(route),
99  myType(type),
100  myCurrEdge(route->begin()),
101  myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
102  myMoveReminders(0),
103  myPersonDevice(nullptr),
104  myContainerDevice(nullptr),
105  myEnergyParams(nullptr),
107  myDepartPos(-1),
108  myArrivalPos(-1),
109  myArrivalLane(-1),
110  myNumberReroutes(0),
112  myOdometer(0.),
116  myEdgeWeights(nullptr)
117 #ifdef _DEBUG
118  , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
119 #endif
120 {
121  if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
123  }
124  if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
126  }
127  if (!pars->wasSet(VEHPARS_FORCE_REROUTE)) {
129  }
131 }
132 
133 
135  delete myEdgeWeights;
136  if (myParameter->repetitionNumber == -1) {
137  // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
139  }
140  for (MSVehicleDevice* dev : myDevices) {
141  delete dev;
142  }
143  delete myEnergyParams;
144  delete myParkingMemory;
145  delete myChargingMemory;
147  delete myParameter;
148 }
149 
150 
151 void
153  // the check for an instance is needed for the unit tests which do not construct a network
154  // TODO Optimize for speed and there should be a better way to check whether a vehicle is part of a flow
155  if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
156  myRoute->checkRemoval();
157  }
158 }
159 
160 
161 std::string
163  return getID().substr(0, getID().rfind('.'));
164 }
165 
166 
167 void
170  for (MSVehicleDevice* dev : myDevices) {
171  myMoveReminders.push_back(std::make_pair(dev, 0.));
172  }
174  // ensure we have the emission parameters even if we don't have the device
176  }
177 }
178 
179 
180 void
181 MSBaseVehicle::setID(const std::string& /*newID*/) {
182  throw ProcessError(TL("Changing a vehicle ID is not permitted"));
183 }
184 
187  return *myParameter;
188 }
189 
190 
191 void
193  delete myParameter;
194  myParameter = newParameter;
195 }
196 
197 
198 bool
201 }
202 
203 double
206 }
207 
208 
209 const MSEdge*
210 MSBaseVehicle::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 
219 const MSEdge*
221  return *myCurrEdge;
222 }
223 
224 
225 const std::set<SUMOTrafficObject::NumericalID>
227  std::set<SUMOTrafficObject::NumericalID> result;
228  for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
229  result.insert((*e)->getNumericalID());
230  }
231  return result;
232 }
233 
234 
235 bool
237  if (stop == nullptr) {
238  return false;
239  }
240  for (const MSStop& s : myStops) {
241  if (s.busstop == stop
242  || s.containerstop == stop
243  || s.parkingarea == stop
244  || s.chargingStation == stop) {
245  return true;
246  }
247  }
248  return false;
249 }
250 
251 bool
252 MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
253  for (const MSStop& s : myStops) {
254  if (&s.lane->getEdge() == edge) {
255  return true;
256  }
257  }
258  return myRoute->getLastEdge() == edge;
259 }
260 
261 
262 bool
263 MSBaseVehicle::reroute(SUMOTime t, const std::string& info, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, const bool onInit, const bool withTaz, const bool silent, const MSEdge* sink) {
264  // check whether to reroute
265  const MSEdge* source = withTaz && onInit ? MSEdge::dictionary(myParameter->fromTaz + "-source") : *getRerouteOrigin();
266  if (source == nullptr) {
267  source = *getRerouteOrigin();
268  }
269  if (sink == nullptr) {
270  sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
271  if (sink == nullptr) {
272  sink = myRoute->getLastEdge();
273  }
274  }
275  ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
276  ConstMSEdgeVector edges;
277  ConstMSEdgeVector stops;
278  std::set<int> jumps;
279  if (myParameter->via.size() == 0) {
280  double firstPos = -1;
281  double lastPos = -1;
282  stops = getStopEdges(firstPos, lastPos, jumps);
283  if (stops.size() > 0) {
284  double sourcePos = onInit ? 0 : getPositionOnLane();
286  sourcePos = getNextStop().pars.endPos;
287  }
288  // avoid superfluous waypoints for first and last edge
289  const bool skipFirst = stops.front() == source && (source != getEdge() || sourcePos + getBrakeGap() <= firstPos + NUMERICAL_EPS);
290  const bool skipLast = (stops.back() == sink
291  && myArrivalPos >= lastPos
292  && (stops.size() < 2 || stops.back() != stops[stops.size() - 2])
293  && (stops.size() > 1 || skipFirst));
294 
295 #ifdef DEBUG_REROUTE
296  if (DEBUG_COND) {
297  std::cout << SIMTIME << " reroute " << info << " veh=" << getID() << " lane=" << Named::getIDSecure(getLane())
298  << " source=" << source->getID() << " sourcePos=" << sourcePos << " firstPos=" << firstPos << " arrivalPos=" << myArrivalPos << " lastPos=" << lastPos
299  << " route=" << toString(myRoute->getEdges()) << " stopEdges=" << toString(stops) << " skipFirst=" << skipFirst << " skipLast=" << skipLast << "\n";
300  }
301 #endif
302  if (stops.size() == 1 && (skipFirst || skipLast)) {
303  stops.clear();
304  } else {
305  if (skipFirst) {
306  stops.erase(stops.begin());
307  }
308  if (skipLast) {
309  stops.erase(stops.end() - 1);
310  }
311  }
312  }
313  } else {
314  std::set<const MSEdge*> jumpEdges;
315  for (const MSStop& stop : myStops) {
316  if (stop.pars.jump >= 0) {
317  jumpEdges.insert(*stop.edge);
318  }
319  }
320  // via takes precedence over stop edges
321  // there is a consistency check in MSRouteHandler::addStop that warns when a stop edge is not part of the via edges
322  for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
323  MSEdge* viaEdge = MSEdge::dictionary(*it);
324  if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
325  continue;
326  }
327  assert(viaEdge != 0);
328  if (!viaEdge->isTazConnector() && viaEdge->allowedLanes(getVClass()) == nullptr) {
329  throw ProcessError(TLF("Vehicle '%' is not allowed on any lane of via edge '%'.", getID(), viaEdge->getID()));
330  }
331  stops.push_back(viaEdge);
332  if (jumpEdges.count(viaEdge) != 0) {
333  jumps.insert((int)stops.size());
334  }
335  }
336  }
337 
338  int stopIndex = -1;
339  for (const MSEdge* const stopEdge : stops) {
340  stopIndex++;
341  // !!! need to adapt t here
342  ConstMSEdgeVector into;
343  if (jumps.count(stopIndex) != 0) {
344  edges.push_back(source);
345  source = stopEdge;
346  continue;
347  }
348  router.computeLooped(source, stopEdge, this, t, into, silent);
349  //std::cout << SIMTIME << " reroute veh=" << getID() << " source=" << source->getID() << " target=" << (*s)->getID() << " edges=" << toString(into) << "\n";
350  if (into.size() > 0) {
351  into.pop_back();
352  edges.insert(edges.end(), into.begin(), into.end());
353  if (stopEdge->isTazConnector()) {
354  source = into.back();
355  edges.pop_back();
356  } else {
357  source = stopEdge;
358  }
359  } else {
360  std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
361  if (MSGlobals::gCheckRoutes || silent) {
362  throw ProcessError(error);
363  } else {
364  WRITE_WARNING(error);
365  edges.push_back(source);
366  }
367  source = stopEdge;
368  }
369  }
370  if (stops.empty() && source == sink && onInit
374  router.computeLooped(source, sink, this, t, edges, silent);
375  } else {
376  if (!router.compute(source, sink, this, t, edges, silent)) {
377  edges.clear();
378  }
379  }
380 
381  // router.setHint(myCurrEdge, myRoute->end(), this, t);
382  if (edges.empty() && silent) {
383  return false;
384  }
385  if (!edges.empty() && edges.front()->isTazConnector()) {
386  edges.erase(edges.begin());
387  }
388  if (!edges.empty() && edges.back()->isTazConnector()) {
389  edges.pop_back();
390  }
391  const double routeCost = router.recomputeCosts(edges, this, t);
392  const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
393  const double savings = previousCost - routeCost;
394  //if (getID() == "43") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
395  // << " onInit=" << onInit
396  // << " prevEdges=" << toString(oldEdgesRemaining)
397  // << " newEdges=" << toString(edges)
398  // << "\n";
399  replaceRouteEdges(edges, routeCost, savings, info, onInit);
400  // this must be called even if the route could not be replaced
401  if (onInit) {
402  if (edges.empty()) {
404  throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
405  } else if (source->isTazConnector()) {
406  WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
408  return false;
409  }
410  }
412  calculateArrivalParams(onInit);
413  }
414  return !edges.empty();
415 }
416 
417 
418 bool
419 MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
420  if (edges.empty()) {
421  WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
422  if (msgReturn != nullptr) {
423  *msgReturn = "No route found";
424  }
425  return false;
426  }
427  // build a new id, first
428  std::string id = getID();
429  if (id[0] != '!') {
430  id = "!" + id;
431  }
432  const std::string idSuffix = id + "!var#";
433  int varIndex = 1;
434  id = idSuffix + toString(varIndex);
435  while (MSRoute::hasRoute(id)) {
436  id = idSuffix + toString(++varIndex);
437  }
438  int oldSize = (int)edges.size();
439  if (!onInit) {
440  const MSEdge* const origin = *getRerouteOrigin();
441  if (origin != *myCurrEdge && edges.front() == origin) {
442  edges.insert(edges.begin(), *myCurrEdge);
443  oldSize = (int)edges.size();
444  }
445  edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
446  }
447  if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
448  // re-assign stop iterators when rerouting to a new parkingArea / insertStop
449  return true;
450  }
451  const RGBColor& c = myRoute->getColor();
452  MSRoute* newRoute = new MSRoute(id, edges, false, &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), std::vector<SUMOVehicleParameter::Stop>());
453  newRoute->setCosts(cost);
454  newRoute->setSavings(savings);
455  ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
456  if (!MSRoute::dictionary(id, constRoute)) {
457  delete newRoute;
458  if (msgReturn != nullptr) {
459  *msgReturn = "duplicate routeID '" + id + "'";
460  }
461  return false;
462  }
463 
464  std::string msg;
465  if (check && !hasValidRoute(msg, constRoute)) {
466  WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), getID(), msg);
468  if (msgReturn != nullptr) {
469  *msgReturn = msg;
470  }
471  return false;
472  }
473  }
474  if (!replaceRoute(constRoute, info, onInit, (int)edges.size() - oldSize, false, removeStops, msgReturn)) {
475  return false;
476  }
477  return true;
478 }
479 
480 
481 bool
482 MSBaseVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
483  const ConstMSEdgeVector& edges = newRoute->getEdges();
484  // rebuild in-vehicle route information
485  if (onInit) {
486  myCurrEdge = newRoute->begin();
487  } else {
488  MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
489  if (newCurrEdge == edges.end()) {
490  if (msgReturn != nullptr) {
491  *msgReturn = TLF("current edge '%' not found in new route", (*myCurrEdge)->getID());
492  }
493 #ifdef DEBUG_REPLACE_ROUTE
494  if (DEBUG_COND) {
495  std::cout << " newCurrEdge not found\n";
496  }
497 #endif
498  return false;
499  }
500  if (getLane() != nullptr) {
501  if (getLane()->getEdge().isInternal() && (
502  (newCurrEdge + 1) == edges.end() || (*(newCurrEdge + 1)) != &(getLane()->getOutgoingViaLanes().front().first->getEdge()))) {
503  if (msgReturn != nullptr) {
504  *msgReturn = TL("Vehicle is on junction-internal edge leading elsewhere");
505  }
506 #ifdef DEBUG_REPLACE_ROUTE
507  if (DEBUG_COND) {
508  std::cout << " Vehicle is on junction-internal edge leading elsewhere\n";
509  }
510 #endif
511  return false;
512  } else if (getPositionOnLane() > getLane()->getLength()
513  && (myCurrEdge + 1) != myRoute->end()
514  && (newCurrEdge + 1) != edges.end()
515  && *(myCurrEdge + 1) != *(newCurrEdge + 1)) {
516  if (msgReturn != nullptr) {
517  *msgReturn = TL("Vehicle is moving past junction and committed to move to another successor edge");
518  }
519 #ifdef DEBUG_REPLACE_ROUTE
520  if (DEBUG_COND) {
521  std::cout << " Vehicle is moving past junction and committed to move to another successor edge\n";
522  }
523 #endif
524  return false;
525  }
526  }
527  myCurrEdge = newCurrEdge;
528  }
529  const bool stopsFromScratch = onInit && myRoute->getStops().empty();
530  // assign new route
532  myRoute = newRoute;
533  // update arrival definition
534  calculateArrivalParams(onInit);
535  // save information that the vehicle was rerouted
537  myStopUntilOffset += myRoute->getPeriod();
539 #ifdef DEBUG_REPLACE_ROUTE
540  if (DEBUG_COND) {
541  std::cout << SIMTIME << " veh=" << getID() << " replaceRoute info=" << info << " on " << (*myCurrEdge)->getID()
542  << " lane=" << Named::getIDSecure(getLane())
543  << " stopsFromScratch=" << stopsFromScratch
544  << " newSize=" << newRoute->getEdges().size()
545  << " newIndex=" << (myCurrEdge - newRoute->begin())
546  << " edges=" << toString(newRoute->getEdges())
547  << "\n";
548  }
549 #endif
550  // remove past stops which are not on the route anymore
551  for (std::vector<SUMOVehicleParameter::Stop>::iterator it = myPastStops.begin(); it != myPastStops.end();) {
552  const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
553  if (std::find(myRoute->begin(), myRoute->end(), stopEdge) == myRoute->end()) {
554  it = myPastStops.erase(it);
555  } else {
556  ++it;
557  }
558  }
559  // if we did not drive yet it may be best to simply reassign the stops from scratch
560  if (stopsFromScratch) {
561  myStops.clear();
563  } else {
564  // recheck old stops
565  MSRouteIterator searchStart = myCurrEdge;
566  double lastPos = getPositionOnLane() + getBrakeGap();
567  if (getLane() != nullptr && getLane()->isInternal()
568  && myStops.size() > 0 && !myStops.front().lane->isInternal()) {
569  // searchStart is still incoming to the intersection so lastPos
570  // relative to that edge must be adapted
571  lastPos += (*myCurrEdge)->getLength();
572  }
573  int stopIndex = 0;
574  for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
575  double endPos = iter->getEndPos(*this);
576 #ifdef DEBUG_REPLACE_ROUTE
577  if (DEBUG_COND) {
578  std::cout << " stopEdge=" << iter->lane->getEdge().getID() << " start=" << (searchStart - myCurrEdge) << " endPos=" << endPos << " lastPos=" << lastPos << "\n";
579  }
580 #endif
581  if (*searchStart != &iter->lane->getEdge()
582  || endPos + NUMERICAL_EPS < lastPos) {
583  if (searchStart != edges.end() && !iter->reached) {
584  searchStart++;
585  }
586  }
587  lastPos = endPos;
588 
589  iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
590 #ifdef DEBUG_REPLACE_ROUTE
591  if (DEBUG_COND) {
592  std::cout << " foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
593  }
594 #endif
595  if (iter->edge == edges.end()) {
596  if (!removeStops) {
597  WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
598  }
599  iter = myStops.erase(iter);
600  continue;
601  } else {
602  setSkips(*iter, stopIndex);
603  searchStart = iter->edge;
604  }
605  ++iter;
606  stopIndex++;
607  }
608  // add new stops
609  if (addRouteStops) {
610  for (std::vector<SUMOVehicleParameter::Stop>::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
611  std::string error;
613  if (error != "") {
614  WRITE_WARNING(error);
615  }
616  }
617  }
618  }
619  return true;
620 }
621 
622 
623 double
625  return 0;
626 }
627 
628 
629 void
634 }
635 
636 
637 SUMOTime
639  const SUMOTime dep = getParameter().depart;
640  if (dep < 0) {
641  return 0;
642  }
643  return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
644 }
645 
646 
647 bool
649  return succEdge(1) == nullptr;
650 }
651 
652 
653 int
655  return (int) std::distance(myRoute->begin(), myCurrEdge);
656 }
657 
658 
659 void
661  myCurrEdge = myRoute->begin() + index;
662  const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
663  // !!! hack
664  myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
665 }
666 
667 double
670 }
671 
672 bool
674  if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
675  return false;
676  } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
677  return false;
678  }
679  if (isStopped() && myStops.begin()->pars.permitted.size() > 0
680  && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
681  return false;
682  }
683  MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
684  if (taxiDevice != nullptr) {
685  return taxiDevice->allowsBoarding(t);
686  }
687  return true;
688 }
689 
690 
691 void
693  if (transportable->isPerson()) {
694  if (myPersonDevice == nullptr) {
696  myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
699  }
700  }
701  myPersonDevice->addTransportable(transportable);
702  } else {
703  if (myContainerDevice == nullptr) {
705  myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myContainerDevice, 0.));
708  }
709  }
710  myContainerDevice->addTransportable(transportable);
711  }
712 }
713 
714 
715 bool
717  for (const MSStop& stop : myStops) {
718  if (stop.edge == it) {
719  return stop.pars.jump >= 0;
720  }
721  }
722  return false;
723 }
724 
725 
726 bool
727 MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
728  MSRouteIterator start = myCurrEdge;
729  if (route == nullptr) {
730  route = myRoute;
731  } else {
732  start = route->begin();
733  }
734  const bool checkJumps = route == myRoute; // the edge iterators in the stops are invalid otherwise
735  MSRouteIterator last = route->end() - 1;
736  // check connectivity, first
737  for (MSRouteIterator e = start; e != last; ++e) {
738  const MSEdge& next = **(e + 1);
739  if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
740  if (!checkJumps || !hasJump(e)) {
742  || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
743  msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
744  return false;
745  }
746  }
747  }
748  }
749  last = route->end();
750  // check usable lanes, then
751  for (MSRouteIterator e = start; e != last; ++e) {
752  if ((*e)->prohibits(this)) {
753  msg = TLF("Edge '%' prohibits.", (*e)->getID());
754  return false;
755  }
756  }
757  return true;
758 }
759 
760 
761 bool
763  if (!(*myCurrEdge)->isTazConnector()) {
765  msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
767  return false;
768  }
769  }
770  if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
772  return true;
773  } else {
774  msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
776  return false;
777  }
778 }
779 
780 
781 int
782 MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
783  if (!update) {
784  return myRouteValidity;
785  }
786  // insertion check must be done in any case
787  std::string msg;
788  if (!hasValidRouteStart(msg)) {
790  throw ProcessError(msg);
791  } else if (!silent) {
792  // vehicle will be discarded
793  WRITE_WARNING(msg);
794  } else if (msgReturn != nullptr) {
795  *msgReturn = msg;
796  }
797  }
799  && (myRouteValidity & ROUTE_UNCHECKED) != 0
800  // we could check after the first rerouting
802  if (!hasValidRoute(msg, myRoute)) {
804  throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
805  }
806  }
808  return myRouteValidity;
809 }
810 
811 void
813 #ifdef _DEBUG
814  if (myTraceMoveReminders) {
815  traceMoveReminder("add", rem, 0, true);
816  }
817 #endif
818  myMoveReminders.push_back(std::make_pair(rem, 0.));
819 }
820 
821 
822 void
824  for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
825  if (r->first == rem) {
826 #ifdef _DEBUG
827  if (myTraceMoveReminders) {
828  traceMoveReminder("remove", rem, 0, false);
829  }
830 #endif
831  myMoveReminders.erase(r);
832  return;
833  }
834  }
835 }
836 
837 
838 void
840  for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
841  if (rem->first->notifyEnter(*this, reason, enteredLane)) {
842 #ifdef _DEBUG
843  if (myTraceMoveReminders) {
844  traceMoveReminder("notifyEnter", rem->first, rem->second, true);
845  }
846 #endif
847  ++rem;
848  } else {
849 #ifdef _DEBUG
850  if (myTraceMoveReminders) {
851  traceMoveReminder("notifyEnter", rem->first, rem->second, false);
852  }
853 #endif
854  rem = myMoveReminders.erase(rem);
855  }
856  }
857 }
858 
859 
860 void
862  if (myRoute->getLastEdge()->isTazConnector()) {
863  return;
864  }
865  const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
866  if (arrivalEdgeIndex != myParameter->arrivalEdge) {
867  WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
868  getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
869  }
870  const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
871  if (!onInit) {
872  arrivalEdge = myRoute->getLastEdge();
873  // ignore arrivalEdge parameter after rerouting
874  const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
875  }
876  const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
877  const double lastLaneLength = lanes[0]->getLength();
878  switch (myParameter->arrivalPosProcedure) {
880  if (fabs(myParameter->arrivalPos) > lastLaneLength) {
881  WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
882  }
883  // Maybe we should warn the user about invalid inputs!
884  myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
885  if (myArrivalPos < 0) {
886  myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
887  }
888  break;
890  myArrivalPos = RandHelper::rand(lastLaneLength);
891  break;
893  myArrivalPos = lastLaneLength / 2.;
894  break;
895  default:
896  myArrivalPos = lastLaneLength;
897  break;
898  }
900  if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
901  WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
902  }
903  myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
905  myArrivalLane = -1;
906  for (MSLane* lane : lanes) {
907  if (lane->allowsVehicleClass(myType->getVehicleClass())) {
908  myArrivalLane = lane->getIndex();
909  break;
910  }
911  }
912  if (myArrivalLane == -1) {
913  WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
914  myArrivalLane = 0;
915  }
917  // pick random lane among all usable lanes
918  std::vector<MSLane*> usable;
919  for (MSLane* lane : lanes) {
920  if (lane->allowsVehicleClass(myType->getVehicleClass())) {
921  usable.push_back(lane);
922  }
923  }
924  if (usable.empty()) {
925  WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
926  myArrivalLane = 0;
927  } else {
928  myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
929  }
930  }
932  for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
933  if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
934  return;
935  }
936  }
937  WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
938  }
939 }
940 
941 void
945  const int routeEdges = (int)myRoute->getEdges().size();
947  // write specific edge in vehroute output for reproducibility
948  pars->departEdge = RandHelper::rand(0, routeEdges);
950  }
951  assert(pars->departEdge >= 0);
952  if (pars->departEdge >= routeEdges) {
953  WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
954  } else {
955  myCurrEdge += pars->departEdge;
956  }
957  }
959  const int routeEdges = (int)myRoute->getEdges().size();
960  const int begin = (int)(myCurrEdge - myRoute->begin());
961  // write specific edge in vehroute output for reproducibility
962  pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
964  assert(pars->arrivalEdge >= begin);
965  assert(pars->arrivalEdge < routeEdges);
966  }
967 }
968 
969 
970 double
972  return MAX2(0., MIN2(1., getVehicleType().getImpatience()
973  + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
974  + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
975 }
976 
977 
978 MSDevice*
979 MSBaseVehicle::getDevice(const std::type_info& type) const {
980  for (MSVehicleDevice* const dev : myDevices) {
981  if (typeid(*dev) == type) {
982  return dev;
983  }
984  }
985  return nullptr;
986 }
987 
988 
989 void
991  // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
994  // params and stops must be written in child classes since they may wish to add additional attributes first
995  out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
996  std::ostringstream os;
997  os << myOdometer << " " << myNumberReroutes;
998  out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
1000  const int precision = out.precision();
1001  out.setPrecision(MAX2(gPrecisionRandom, precision));
1003  out.setPrecision(precision);
1004  }
1006  out.writeAttr(SUMO_ATTR_REROUTE, true);
1007  }
1008  if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
1009  // could be set from stop
1011  }
1012  // here starts the vehicle internal part (see loading)
1013  // @note: remember to close the vehicle tag when calling this in a subclass!
1014 }
1015 
1016 
1017 bool
1018 MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
1019  UNUSED_PARAMETER(stop);
1020  UNUSED_PARAMETER(distToStop);
1021  return true;
1022 }
1023 
1024 
1025 bool
1027  return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
1028 }
1029 
1030 
1031 bool
1033  return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
1034  && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
1035  && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
1036 }
1037 
1038 
1039 bool
1041  return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
1042 }
1043 
1044 
1045 bool
1047  return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
1048 }
1049 
1050 
1051 bool
1053  return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
1054 }
1055 
1056 
1057 bool
1058 MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
1059  if (isStopped() || (checkFuture && hasStops())) {
1060  const MSStop& stop = myStops.front();
1061  return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
1062  }
1063  return false;
1064 }
1065 
1066 bool
1067 MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
1068  // Check if there is a parking area to be replaced
1069  if (parkingArea == 0) {
1070  errorMsg = "new parkingArea is NULL";
1071  return false;
1072  }
1073  if (myStops.size() == 0) {
1074  errorMsg = "vehicle has no stops";
1075  return false;
1076  }
1077  if (myStops.front().parkingarea == 0) {
1078  errorMsg = "first stop is not at parkingArea";
1079  return false;
1080  }
1081  MSStop& first = myStops.front();
1082  SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
1083  // merge subsequent duplicate stops equals to parking area
1084  for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
1085  if (iter->parkingarea == parkingArea) {
1086  stopPar.duration += iter->duration;
1087  myStops.erase(iter++);
1088  } else {
1089  break;
1090  }
1091  }
1092  stopPar.lane = parkingArea->getLane().getID();
1093  stopPar.parkingarea = parkingArea->getID();
1094  stopPar.startPos = parkingArea->getBeginLanePosition();
1095  stopPar.endPos = parkingArea->getEndLanePosition();
1096  first.edge = myRoute->end(); // will be patched in replaceRoute
1097  first.lane = &parkingArea->getLane();
1098  first.parkingarea = parkingArea;
1099  return true;
1100 }
1101 
1102 
1105  MSParkingArea* nextParkingArea = nullptr;
1106  if (!myStops.empty()) {
1108  MSStop stop = myStops.front();
1109  if (!stop.reached && stop.parkingarea != nullptr) {
1110  nextParkingArea = stop.parkingarea;
1111  }
1112  }
1113  return nextParkingArea;
1114 }
1115 
1116 
1119  MSParkingArea* currentParkingArea = nullptr;
1120  if (isParking()) {
1121  currentParkingArea = myStops.begin()->parkingarea;
1122  }
1123  return currentParkingArea;
1124 }
1125 
1126 
1127 const std::vector<std::string>&
1130  return myParameter->parkingBadges;
1131  } else {
1132  return getVehicleType().getParkingBadges();
1133  }
1134 }
1135 
1136 
1137 double
1138 MSBaseVehicle::basePos(const MSEdge* edge) const {
1139  double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
1140  if (hasStops()
1141  && myStops.front().edge == myRoute->begin()
1142  && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
1143  result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
1144  }
1145  return result;
1146 }
1147 
1148 
1149 MSLane*
1151  const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
1152  const MSEdge* edge = MSEdge::dictionary(edgeID);
1153  if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
1154  return nullptr;
1155  }
1156  const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
1157  if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
1158  const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
1159  stop.edge = edgeID;
1160  return edge->getOppositeEdge()->getLanes()[oppositeIndex];
1161  }
1162  return nullptr;
1163 }
1164 
1165 
1166 bool
1167 MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
1168  MSRouteIterator* searchStart) {
1169  MSStop stop(stopPar);
1170  if (stopPar.lane == "") {
1171  MSEdge* e = MSEdge::dictionary(stopPar.edge);
1172  stop.lane = e->getFirstAllowed(getVClass());
1173  if (stop.lane == nullptr) {
1174  errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
1175  return false;
1176  }
1177  } else {
1178  stop.lane = MSLane::dictionary(stopPar.lane);
1179  if (stop.lane == nullptr) {
1180  // must be an opposite stop
1181  SUMOVehicleParameter::Stop tmp = stopPar;
1182  stop.lane = interpretOppositeStop(tmp);
1183  assert(stop.lane != nullptr);
1184  }
1185  if (!stop.lane->allowsVehicleClass(myType->getVehicleClass())) {
1186  errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
1187  return false;
1188  }
1189  }
1190  if (MSGlobals::gUseMesoSim) {
1191  stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
1192  if (stop.lane->isInternal()) {
1193  errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
1194  return false;
1195  }
1196  }
1197  stop.initPars(stopPar);
1198  if (stopPar.until != -1) {
1199  // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
1200  const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
1201  }
1202  if (stopPar.arrival != -1) {
1203  const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
1204  }
1205  std::string stopType = "stop";
1206  std::string stopID = "";
1207  if (stop.busstop != nullptr) {
1208  stopType = "busStop";
1209  stopID = stop.busstop->getID();
1210  } else if (stop.containerstop != nullptr) {
1211  stopType = "containerStop";
1212  stopID = stop.containerstop->getID();
1213  } else if (stop.chargingStation != nullptr) {
1214  stopType = "chargingStation";
1215  stopID = stop.chargingStation->getID();
1216  } else if (stop.overheadWireSegment != nullptr) {
1217  stopType = "overheadWireSegment";
1218  stopID = stop.overheadWireSegment->getID();
1219  } else if (stop.parkingarea != nullptr) {
1220  stopType = "parkingArea";
1221  stopID = stop.parkingarea->getID();
1222  }
1223  const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
1224 
1225  if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
1226  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
1227  return false;
1228  }
1229  if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > stop.pars.endPos - stop.pars.startPos
1230  && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
1231  errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
1232  }
1233  if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
1234  // forbid access in case the parking requests other badges
1235  errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
1236  return false;
1237  }
1238  const MSEdge* stopLaneEdge = &stop.lane->getEdge();
1239  const MSEdge* stopEdge;
1240  if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
1241  // stop lane is on the opposite side
1242  stopEdge = stopLaneEdge->getOppositeEdge();
1243  stop.isOpposite = true;
1244  } else {
1245  // if stop is on an internal edge the normal edge before the intersection is used
1246  stopEdge = stopLaneEdge->getNormalBefore();
1247  }
1248  MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
1249  if (searchStart == nullptr) {
1250  searchStart = &myCurrEdge;
1251  if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
1252  // already on the intersection but myCurrEdge is before it
1253  searchStart = &succ;
1254  }
1255  }
1256 #ifdef DEBUG_ADD_STOP
1257  if (DEBUG_COND) {
1258  std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
1259  << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
1260  << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
1261  << "\n";
1262  }
1263 #endif
1264  stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
1265  MSRouteIterator prevStopEdge = myCurrEdge;
1266  const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
1267  double prevStopPos = getPositionOnLane();
1268  // where to insert the stop
1269  std::list<MSStop>::iterator iter = myStops.begin();
1270  if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
1271  iter = myStops.end();
1272  if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
1273  prevStopEdge = myStops.back().edge;
1274  prevEdge = &myStops.back().lane->getEdge();
1275  prevStopPos = myStops.back().pars.endPos;
1276  stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1277  if (prevStopEdge == stop.edge // laneEdge check is insufficient for looped routes
1278  && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
1279  && (prevStopPos > stop.pars.endPos ||
1280  (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
1281  stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
1282  }
1283 #ifdef DEBUG_ADD_STOP
1284  if (DEBUG_COND) {
1285  std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
1286  << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
1287  }
1288 #endif
1289  }
1290  // skip a number of occurences of stopEdge in looped route
1291  int skipLooped = stopPar.index - static_cast<int>(myStops.size());
1292  for (int j = 0; j < skipLooped; j++) {
1293  auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
1294  if (nextIt == myRoute->end()) {
1295  if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
1296  // only warn if the route loops over the stop edge at least once
1297  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
1298  }
1299  break;
1300  } else {
1301  stop.edge = nextIt;
1302  }
1303  }
1304  } else {
1305  if (stopPar.index == STOP_INDEX_FIT) {
1306  while (iter != myStops.end() && (iter->edge < stop.edge ||
1307  (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
1308  (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
1309  prevStopEdge = iter->edge;
1310  prevStopPos = iter->pars.endPos;
1311  ++iter;
1312  }
1313  } else {
1314  int index = stopPar.index;
1315  while (index > 0) {
1316  prevStopEdge = iter->edge;
1317  prevStopPos = iter->pars.endPos;
1318  ++iter;
1319  --index;
1320  }
1321 #ifdef DEBUG_ADD_STOP
1322  if (DEBUG_COND) {
1323  std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
1324  }
1325 #endif
1326  stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1327  }
1328  }
1329  const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
1330  if (stop.edge == myRoute->end()) {
1331  if (!wasTooClose) {
1332  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
1333  }
1334  return false;
1335  }
1336 
1337  const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
1338  prevStopPos + (iter == myStops.begin() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
1339 
1340  if (prevStopEdge > stop.edge ||
1341  // a collision-stop happens after vehicle movement and may move the
1342  // vehicle backwards on its lane (prevStopPos is the vehicle position)
1343  (tooClose && !stop.pars.collision)
1344  || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
1345  // check if the edge occurs again later in the route
1346  //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges()) << "\n";
1347  if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
1348  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
1349  }
1350  MSRouteIterator next = stop.edge + 1;
1351  return addStop(stopPar, errorMsg, untilOffset, &next);
1352  }
1353  if (wasTooClose) {
1354  errorMsg = "";
1355  }
1356  // David.C:
1357  //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
1358  const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
1359  const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
1360  if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
1361  return false;
1362  }
1363  if (!hasDeparted() && myCurrEdge == stop.edge) {
1364  double pos = -1;
1366  pos = myParameter->departPos;
1367  if (pos < 0.) {
1368  pos += (*myCurrEdge)->getLength();
1369  }
1370  }
1372  pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
1373  }
1374  if (pos > stop.pars.endPos + endPosOffset) {
1375  if (stop.edge != myRoute->end()) {
1376  // check if the edge occurs again later in the route
1377  MSRouteIterator next = stop.edge + 1;
1378  return addStop(stopPar, errorMsg, untilOffset, &next);
1379  }
1380  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
1381  return false;
1382  }
1383  }
1384  if (iter != myStops.begin()) {
1385  std::list<MSStop>::iterator iter2 = iter;
1386  iter2--;
1387  if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
1388  && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
1389  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1390  + "' set to end at " + time2string(stop.getUntil())
1391  + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
1392  }
1393  if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1394  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1395  + "' set to start at " + time2string(stop.pars.arrival)
1396  + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
1397  }
1398  if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1399  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1400  + "' set to start at " + time2string(stop.pars.arrival)
1401  + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
1402  }
1403  } else {
1404  if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()) {
1405  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1406  + "' set to end at " + time2string(stop.getUntil())
1407  + " earlier than departure at " + time2string(getParameter().depart) + ".";
1408  }
1409  }
1410  if (stop.getUntil() >= 0 && stop.pars.arrival > stop.getUntil() && errorMsg == "") {
1411  errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1412  + "' set to end at " + time2string(stop.getUntil())
1413  + " earlier than arrival at " + time2string(stop.pars.arrival) + ".";
1414  }
1415  setSkips(stop, (int)myStops.size());
1416  myStops.insert(iter, stop);
1417  //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
1418  // << " routeIndex=" << (stop.edge - myRoute->begin())
1419  // << " stopIndex=" << std::distance(myStops.begin(), iter)
1420  // << " route=" << toString(myRoute->getEdges()) << "\n";
1421  return true;
1422 }
1423 
1424 
1425 void
1426 MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
1427  if (hasDeparted() && stop.pars.index <= 0 && stop.edge > myRoute->begin()) {
1428  // if the route is looped we must patch the index to ensure that state
1429  // loading (and vehroute-output) encode the correct number of skips
1430  int foundSkips = 0;
1431  MSRouteIterator itPrev;
1432  double prevEndPos;
1433  if (prevActiveStops > 0) {
1434  assert((int)myStops.size() >= prevActiveStops);
1435  auto prevStopIt = myStops.begin();
1436  std::advance(prevStopIt, prevActiveStops - 1);
1437  const MSStop& prev = *prevStopIt;
1438  itPrev = prev.edge;
1439  prevEndPos = prev.pars.endPos;
1440  } else if (myPastStops.size() > 0) {
1441  itPrev = myRoute->begin() + myPastStops.back().routeIndex;
1442  prevEndPos = myPastStops.back().endPos;
1443  } else {
1444  itPrev = myRoute->begin() + myParameter->departEdge;
1445  prevEndPos = myDepartPos;
1446  }
1447  if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
1448  itPrev++;
1449  }
1450  //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
1451  while (itPrev < stop.edge) {
1452  if (*itPrev == *stop.edge) {
1453  foundSkips++;
1454  }
1455  itPrev++;
1456  }
1457  if (foundSkips > 0) {
1458  //std::cout << " foundSkips=" << foundSkips << "\n";
1459  const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = (int)myPastStops.size() + prevActiveStops + foundSkips;
1460  }
1461  }
1462 }
1463 
1464 
1465 void
1466 MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
1467  if (addRouteStops) {
1468  for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
1469  std::string errorMsg;
1470  if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
1471  throw ProcessError(errorMsg);
1472  }
1473  if (errorMsg != "") {
1474  WRITE_WARNING(errorMsg);
1475  }
1476  }
1477  }
1479  for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
1480  std::string errorMsg;
1481  if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
1482  throw ProcessError(errorMsg);
1483  }
1484  if (errorMsg != "") {
1485  WRITE_WARNING(errorMsg);
1486  }
1487  }
1488 }
1489 
1490 
1491 bool
1493  MSRouteIterator start = myCurrEdge;
1494  int i = 0;
1495  bool ok = true;
1496  for (const MSStop& stop : myStops) {
1497  MSRouteIterator it;
1498  if (stop.lane->isInternal()) {
1499  // find the normal predecessor and ensure that the next route edge
1500  // matches the successor of the internal edge successor
1501  it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
1502  if (it != myRoute->end() && (
1503  it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
1504  it = myRoute->end(); // signal failure
1505  }
1506  } else {
1507  it = std::find(start, myRoute->end(), &stop.lane->getEdge());
1508  }
1509  if (it == myRoute->end()) {
1510  if (!silent) {
1511  WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
1512  i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1513  }
1514  ok = false;
1515  } else {
1516  MSRouteIterator it2;
1517  for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
1518  if (it2 == stop.edge) {
1519  break;
1520  }
1521  }
1522  if (it2 == myRoute->end()) {
1523  if (!silent) {
1524  WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
1525  i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
1526  }
1527  ok = false;
1528  } else if (it2 < start) {
1529  if (!silent) {
1530  WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
1531  i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1532  }
1533  ok = false;
1534  } else {
1535  start = stop.edge;
1536  }
1537  }
1538  i++;
1539  }
1540  return ok;
1541 }
1542 
1543 
1544 const ConstMSEdgeVector
1545 MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
1546  assert(haveValidStopEdges());
1547  ConstMSEdgeVector result;
1548  const MSStop* prev = nullptr;
1549  const MSEdge* internalSuccessor = nullptr;
1550  for (const MSStop& stop : myStops) {
1551  if (stop.reached) {
1552  if (stop.pars.jump >= 0) {
1553  jumps.insert((int)result.size());
1554  }
1555  continue;
1556  }
1557  const double stopPos = stop.getEndPos(*this);
1558  if ((prev == nullptr
1559  || prev->edge != stop.edge
1560  || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
1561  && *stop.edge != internalSuccessor) {
1562  result.push_back(*stop.edge);
1563  if (stop.lane->isInternal()) {
1564  internalSuccessor = stop.lane->getNextNormal();
1565  result.push_back(internalSuccessor);
1566  } else {
1567  internalSuccessor = nullptr;
1568  }
1569  }
1570  prev = &stop;
1571  if (firstPos < 0) {
1572  firstPos = stopPos;
1573  }
1574  lastPos = stopPos;
1575  if (stop.pars.jump >= 0) {
1576  jumps.insert((int)result.size() - 1);
1577  }
1578  }
1579  //std::cout << "getStopEdges veh=" << getID() << " result=" << toString(result) << "\n";
1580  return result;
1581 }
1582 
1583 
1584 std::vector<std::pair<int, double> >
1586  std::vector<std::pair<int, double> > result;
1587  for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
1588  result.push_back(std::make_pair(
1589  (int)(iter->edge - myRoute->begin()),
1590  iter->getEndPos(*this)));
1591  }
1592  return result;
1593 }
1594 
1595 
1596 MSStop&
1598  assert(myStops.size() > 0);
1599  return myStops.front();
1600 }
1601 
1602 SUMOTime
1604  if (isStopped()) {
1605  return myStops.front().duration;
1606  } else {
1607  return 0;
1608  }
1609 }
1610 
1611 
1612 MSStop&
1613 MSBaseVehicle::getStop(int nextStopIndex) {
1614  if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
1615  throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
1616  }
1617  auto stopIt = myStops.begin();
1618  std::advance(stopIt, nextStopIndex);
1619  return *stopIt;
1620 }
1621 
1622 
1625  if (hasStops()) {
1626  return &myStops.front().pars;
1627  }
1628  return nullptr;
1629 }
1630 
1631 
1632 bool
1634  //if the stop exists update the duration
1635  for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
1636  if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
1637  // update existing stop
1638  if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
1639  myStops.erase(iter);
1640  } else {
1641  iter->duration = stop.duration;
1642  iter->triggered = stop.triggered;
1643  iter->containerTriggered = stop.containerTriggered;
1644  const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
1645  const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
1646  }
1647  return true;
1648  }
1649  }
1650  const bool result = addStop(stop, errorMsg);
1651  if (result) {
1653  myParameter->stops.push_back(stop);
1654  }
1655  return result;
1656 }
1657 
1658 
1659 void
1663  myAmRegisteredAsWaiting = false;
1664  }
1665 }
1666 
1667 
1668 bool
1669 MSBaseVehicle::abortNextStop(int nextStopIndex) {
1670  if (hasStops() && nextStopIndex < (int)myStops.size()) {
1671  if (nextStopIndex == 0 && isStopped()) {
1673  } else {
1674  auto stopIt = myStops.begin();
1675  std::advance(stopIt, nextStopIndex);
1676  myStops.erase(stopIt);
1677  }
1678  if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1679  // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
1680  auto stopIt2 = myParameter->stops.begin();
1681  std::advance(stopIt2, nextStopIndex);
1682  const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
1683  }
1684  return true;
1685  } else {
1686  return false;
1687  }
1688 }
1689 
1690 
1691 bool
1692 MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
1693  const int n = (int)myStops.size();
1694  if (nextStopIndex < 0 || nextStopIndex >= n) {
1695  errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
1696  return false;
1697  }
1698  if (nextStopIndex == 0 && isStopped()) {
1699  errorMsg = TL("cannot replace reached stop");
1700  return false;
1701  }
1703  MSLane* stopLane = MSLane::dictionary(stop.lane);
1704  MSEdge* stopEdge = &stopLane->getEdge();
1705 
1706  auto itStop = myStops.begin();
1707  std::advance(itStop, nextStopIndex);
1708  MSStop& replacedStop = *itStop;
1709 
1710  // check parking access rights
1711  if (stop.parkingarea != "") {
1713  if (pa != nullptr && !pa->accepts(this)) {
1714  errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
1715  return false;
1716  }
1717  }
1718 
1719  if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
1720  // only replace stop attributes
1721  const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
1722  replacedStop.initPars(stop);
1723  return true;
1724  }
1725 
1726  if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
1727  errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
1728  return false;
1729  }
1730 
1731  const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1732  std::vector<MSStop> stops(myStops.begin(), myStops.end());
1733  const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1734  MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1735  double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1736  MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
1737  auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
1739 
1740  bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
1741 
1742  ConstMSEdgeVector toNewStop;
1743  if (!teleport) {
1744  router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
1745  if (toNewStop.size() == 0) {
1746  errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
1747  return false;
1748  }
1749  }
1750 
1751  ConstMSEdgeVector fromNewStop;
1752  if (!newDestination) {
1753  router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
1754  if (fromNewStop.size() == 0) {
1755  errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
1756  return false;
1757  }
1758  }
1759 
1760  const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
1761  replacedStop.initPars(stop);
1762  replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
1763  replacedStop.lane = stopLane;
1764  if (MSGlobals::gUseMesoSim) {
1765  replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
1766  if (replacedStop.lane->isInternal()) {
1767  errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
1768  return false;
1769  }
1770  }
1771 
1772  ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1773  ConstMSEdgeVector newEdges; // only remaining
1774  newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1775  if (!teleport) {
1776  newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
1777  } else {
1778  newEdges.push_back(*itStart);
1779  }
1780  if (!newDestination) {
1781  newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
1782  newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
1783  } else {
1784  newEdges.push_back(stopEdge);
1785  }
1786  //std::cout << SIMTIME << " replaceStop veh=" << getID()
1787  // << " teleport=" << teleport
1788  // << " busStop=" << stop.busstop
1789  // << " oldEdges=" << oldRemainingEdges.size()
1790  // << " newEdges=" << newEdges.size()
1791  // << " toNewStop=" << toNewStop.size()
1792  // << " fromNewStop=" << fromNewStop.size()
1793  // << "\n";
1794 
1795  const double routeCost = router.recomputeCosts(newEdges, this, t);
1796  const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
1797  const double savings = previousCost - routeCost;
1798  if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1799  // stops will be rebuilt from scratch so we must patch the stops in myParameter
1800  const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
1801  }
1802  if (teleport) {
1803  // let the vehicle jump rather than teleport
1804  // we add a jump-stop at the end of the edge (unless the vehicle is
1805  // already configure to jump before the replaced stop)
1806  if (!insertJump(nextStopIndex, itStart, errorMsg)) {
1807  return false;
1808  };
1809  }
1810  return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
1811 }
1812 
1813 
1814 bool
1815 MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
1816  const int n = (int)myStops.size();
1817  if (nextStopIndex < 0 || nextStopIndex > n) {
1818  errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
1819  return false;
1820  }
1821  if (nextStopIndex == 0 && isStopped()) {
1822  errorMsg = TL("cannot reroute towards reached stop");
1823  return false;
1824  }
1826 
1827  const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1828  std::vector<MSStop> stops(myStops.begin(), myStops.end());
1829  const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1830  MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1831  double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1832  MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
1833  auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
1835 
1836  ConstMSEdgeVector newBetween;
1837  if (!teleport) {
1838  router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
1839  if (newBetween.size() == 0) {
1840  errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
1841  return false;
1842  }
1843  }
1844 
1845  ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1846  ConstMSEdgeVector newEdges; // only remaining
1847  newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1848  if (!teleport) {
1849  newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
1850  } else {
1851  newEdges.push_back(*itStart);
1852  }
1853  newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
1854  //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
1855  // << " oldEdges=" << oldRemainingEdges.size()
1856  // << " newEdges=" << newEdges.size()
1857  // << " toNewStop=" << toNewStop.size()
1858  // << " fromNewStop=" << fromNewStop.size()
1859  // << "\n";
1860 
1861  const double routeCost = router.recomputeCosts(newEdges, this, t);
1862  const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
1863  const double savings = previousCost - routeCost;
1864 
1865  if (teleport) {
1866  // let the vehicle jump rather than teleport
1867  // we add a jump-stop at the end of the edge (unless the vehicle is
1868  // already configure to jump before the replaced stop)
1869  if (!insertJump(nextStopIndex, itStart, errorMsg)) {
1870  return false;
1871  };
1872  }
1873  return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
1874 }
1875 
1876 
1877 bool
1878 MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
1879  bool needJump = true;
1880  if (nextStopIndex > 0) {
1881  auto itPriorStop = myStops.begin();
1882  std::advance(itPriorStop, nextStopIndex - 1);
1883  const MSStop& priorStop = *itPriorStop;
1884  if (priorStop.pars.jump >= 0) {
1885  needJump = false;
1886  }
1887  }
1888  if (needJump) {
1889  SUMOVehicleParameter::Stop jumpStopPars;
1890  jumpStopPars.endPos = (*itStart)->getLength();
1891  jumpStopPars.speed = 1000;
1892  jumpStopPars.jump = 0;
1893  jumpStopPars.edge = (*itStart)->getID();
1894  jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
1895  MSLane* jumpStopLane = nullptr;
1896  for (MSLane* cand : (*itStart)->getLanes()) {
1897  if (cand->allowsVehicleClass(getVClass())) {
1898  jumpStopLane = cand;
1899  break;
1900  }
1901  }
1902  if (jumpStopLane == nullptr) {
1903  errorMsg = TL("unable to replace stop with teleporting");
1904  return false;
1905  }
1906  auto itStop = myStops.begin();
1907  std::advance(itStop, nextStopIndex);
1908  MSStop jumpStop(jumpStopPars);
1909  jumpStop.initPars(jumpStopPars);
1910  jumpStop.lane = jumpStopLane;
1911  jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
1912  myStops.insert(itStop, jumpStop);
1913  if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1914  // stops will be rebuilt from scratch so we must patch the stops in myParameter
1915  auto it = myParameter->stops.begin() + nextStopIndex;
1916  const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
1917  }
1918  }
1919  return true;
1920 }
1921 
1922 
1923 bool
1924 MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
1925  const int n = (int)myStops.size();
1926  if (nextStopIndex < 0 || nextStopIndex > n) {
1927  errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
1928  return false;
1929  }
1930  if (nextStopIndex == 0 && isStopped()) {
1931  errorMsg = TL("cannot insert stop before the currently reached stop");
1932  return false;
1933  }
1935  MSLane* stopLane = MSLane::dictionary(stop.lane);
1936  MSEdge* stopEdge = &stopLane->getEdge();
1937 
1938  if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
1939  errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
1940  return false;
1941  }
1942 
1943  // check parking access rights
1944  if (stop.parkingarea != "") {
1946  if (pa != nullptr && !pa->accepts(this)) {
1947  errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
1948  return false;
1949  }
1950  }
1951 
1952  const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
1953  std::vector<MSStop> stops(myStops.begin(), myStops.end());
1954  const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
1955  MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
1956  double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
1957  MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
1958  auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
1960 
1961  bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
1962 
1963  ConstMSEdgeVector toNewStop;
1964  if (!teleport) {
1965  router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
1966  if (toNewStop.size() == 0) {
1967  errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
1968  return false;
1969  }
1970  }
1971 
1972  ConstMSEdgeVector fromNewStop;
1973  if (!newDestination) {
1974  router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
1975  if (fromNewStop.size() == 0) {
1976  errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
1977  return false;
1978  }
1979  }
1980 
1981  auto itStop = myStops.begin();
1982  std::advance(itStop, nextStopIndex);
1983  MSStop newStop(stop);
1984  newStop.initPars(stop);
1985  newStop.edge = myRoute->end(); // will be patched in replaceRoute
1986  newStop.lane = stopLane;
1987  if (MSGlobals::gUseMesoSim) {
1988  newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
1989  if (newStop.lane->isInternal()) {
1990  errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
1991  return false;
1992  }
1993  }
1994  myStops.insert(itStop, newStop);
1995 
1996  ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
1997  ConstMSEdgeVector newEdges; // only remaining
1998  newEdges.insert(newEdges.end(), myCurrEdge, itStart);
1999  if (!teleport) {
2000  newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
2001  } else {
2002  newEdges.push_back(*itStart);
2003  }
2004  if (!newDestination) {
2005  newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
2006  newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2007  } else {
2008  newEdges.push_back(stopEdge);
2009  }
2010  //std::cout << SIMTIME << " insertStop veh=" << getID()
2011  // << " teleport=" << teleport
2012  // << " busStop=" << stop.busstop
2013  // << " oldEdges=" << oldRemainingEdges.size()
2014  // << " newEdges=" << newEdges.size()
2015  // << " toNewStop=" << toNewStop.size()
2016  // << " fromNewStop=" << fromNewStop.size()
2017  // << "\n";
2018 
2019  const double routeCost = router.recomputeCosts(newEdges, this, t);
2020  const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2021  const double savings = previousCost - routeCost;
2022 
2023  if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
2024  // stops will be rebuilt from scratch so we must patch the stops in myParameter
2025  auto it = myParameter->stops.begin() + nextStopIndex;
2026  const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
2027  }
2028  return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2029 }
2030 
2031 
2032 double
2034  if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2035  MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2036  return batteryOfVehicle->getActualBatteryCapacity();
2037  } else {
2038  if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2039  MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2040  return batteryOfVehicle->getActualBatteryCapacity();
2041  }
2042  }
2043  return -1;
2044 }
2045 
2046 
2047 double
2049  if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2050  MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2051  return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2052  } else {
2053  if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2054  MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2055  return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2056  }
2057  }
2058  return -1;
2059 }
2060 
2061 
2062 double
2064  if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2065  MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2066  return batteryOfVehicle->getEnergyCharged();
2067  } else {
2068  if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2069  MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2070  return batteryOfVehicle->getEnergyCharged();
2071  }
2072  }
2073  return -1;
2074 }
2075 
2076 
2077 double
2079  if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2080  MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2081  return batteryOfVehicle->getMaximumChargeRate();
2082  }
2083  return -1;
2084 }
2085 
2086 
2087 double
2089  if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2090  MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2091  return elecHybridDevice->getCurrentFromOverheadWire();
2092  }
2093 
2094  return NAN;
2095 }
2096 
2097 double
2099  if (isOnRoad() || isIdling()) {
2101  } else {
2102  return 0.;
2103  }
2104 }
2105 
2106 
2107 const MSEdgeWeightsStorage&
2109  return _getWeightsStorage();
2110 }
2111 
2112 
2115  return _getWeightsStorage();
2116 }
2117 
2118 
2121  if (myEdgeWeights == nullptr) {
2123  }
2124  return *myEdgeWeights;
2125 }
2126 
2127 
2128 
2129 
2130 int
2132  int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
2133  return boarded + myParameter->personNumber;
2134 }
2135 
2136 int
2138  int leavingPersonNumber = 0;
2139  const std::vector<MSTransportable*>& persons = getPersons();
2140  for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2141  MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
2142  const MSStop* stop = &myStops.front();
2143  const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
2144  if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
2145  leavingPersonNumber++;
2146  }
2147  }
2148  return leavingPersonNumber;
2149 }
2150 
2151 std::vector<std::string>
2153  std::vector<std::string> ret;
2154  const std::vector<MSTransportable*>& persons = getPersons();
2155  for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2156  ret.push_back((*it_p)->getID());
2157  }
2158  return ret;
2159 }
2160 
2161 int
2163  int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
2164  return loaded + myParameter->containerNumber;
2165 }
2166 
2167 
2168 void
2170  // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
2171  if (myPersonDevice != nullptr) {
2173  }
2174  if (myContainerDevice != nullptr) {
2176  }
2177 }
2178 
2179 
2180 const std::vector<MSTransportable*>&
2182  if (myPersonDevice == nullptr) {
2184  } else {
2186  }
2187 }
2188 
2189 
2190 const std::vector<MSTransportable*>&
2192  if (myContainerDevice == nullptr) {
2194  } else {
2196  }
2197 }
2198 
2199 
2200 bool
2201 MSBaseVehicle::isLineStop(double position) const {
2202  if (myParameter->line == "") {
2203  // not a public transport line
2204  return false;
2205  }
2206  for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
2207  if (stop.startPos <= position && position <= stop.endPos) {
2208  return true;
2209  }
2210  }
2211  for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
2212  if (stop.startPos <= position && position <= stop.endPos) {
2213  return true;
2214  }
2215  }
2216  return false;
2217 }
2218 
2219 
2220 bool
2221 MSBaseVehicle::hasDevice(const std::string& deviceName) const {
2222  for (MSDevice* const dev : myDevices) {
2223  if (dev->deviceName() == deviceName) {
2224  return true;
2225  }
2226  }
2227  return false;
2228 }
2229 
2230 
2231 void
2232 MSBaseVehicle::createDevice(const std::string& deviceName) {
2233  if (!hasDevice(deviceName)) {
2234  if (deviceName == "rerouting") {
2235  ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
2237  if (hasDeparted()) {
2238  // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
2239  MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
2240  assert(routingDevice != 0);
2241  routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
2242  }
2243  } else {
2244  throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
2245  }
2246  }
2247 }
2248 
2249 
2250 std::string
2251 MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
2252  for (MSVehicleDevice* const dev : myDevices) {
2253  if (dev->deviceName() == deviceName) {
2254  return dev->getParameter(key);
2255  }
2256  }
2257  throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2258 }
2259 
2260 
2261 void
2262 MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
2263  for (MSVehicleDevice* const dev : myDevices) {
2264  if (dev->deviceName() == deviceName) {
2265  dev->setParameter(key, value);
2266  return;
2267  }
2268  }
2269  throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2270 }
2271 
2272 
2273 void
2274 MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
2277  const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2278  // checked in MSLink::ignoreFoe
2279  } else {
2280  throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
2281  }
2282 }
2283 
2284 
2285 void
2286 MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
2287  // handle some generic params first and then delegate to the carFollowModel itself
2290  const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2291  // checked in MSVehicle::planMove
2292  } else {
2293  MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
2294  if (microVeh) {
2295  // remove 'carFollowModel.' prefix
2296  const std::string attrName = key.substr(15);
2297  microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
2298  }
2299  }
2300 }
2301 
2302 
2303 void
2305  /* Design idea for additional junction model parameters:
2306  We can distinguish between 3 levels of parameters
2307  1. typically shared by multiple vehicles -> vType parameter
2308  2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
2309  3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
2310  */
2311  for (auto item : getParameter().getParametersMap()) {
2312  if (StringUtils::startsWith(item.first, "junctionModel.")) {
2313  setJunctionModelParameter(item.first, item.second);
2314  } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
2315  setCarFollowModelParameter(item.first, item.second);
2316  }
2317  }
2318  const std::string routingModeStr = getStringParam("device.rerouting.mode");
2319  try {
2320  int routingMode = StringUtils::toInt(routingModeStr);
2321  if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
2322  setRoutingMode(routingMode);
2323  }
2324  } catch (NumberFormatException&) {
2325  // @todo interpret symbolic constants
2326  throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
2327  }
2328 }
2329 
2330 
2335  } else {
2337  }
2338 }
2339 
2340 
2341 void
2343  assert(type != nullptr);
2344  // save old parameters before possible type deletion
2345  const double oldMu = myType->getSpeedFactor().getParameter()[0];
2346  const double oldDev = myType->getSpeedFactor().getParameter()[1];
2347  if (myType->isVehicleSpecific() && type != myType) {
2349  }
2350  // adapt myChosenSpeedFactor to the new type
2351  if (oldDev == 0.) {
2352  // old type had speedDev 0, reroll
2354  } else {
2355  // map old speedFactor onto new distribution
2356  const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
2357  const double newMu = type->getSpeedFactor().getParameter()[0];
2358  const double newDev = type->getSpeedFactor().getParameter()[1];
2359  myChosenSpeedFactor = newMu + distPoint * newDev;
2360  // respect distribution limits
2363  }
2364  myType = type;
2365  if (myEnergyParams != nullptr) {
2367  }
2368 }
2369 
2370 
2373  if (myType->isVehicleSpecific()) {
2374  return *myType;
2375  }
2376  MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
2377  replaceVehicleType(type);
2378  return *type;
2379 }
2380 
2381 
2382 int
2384  const MSLane* const lane = getLane();
2385  if (lane == nullptr) {
2386  return getEdge()->getLanes()[0]->getRNGIndex();
2387  } else {
2388  return lane->getRNGIndex();
2389  }
2390 }
2391 
2392 
2393 SumoRNG*
2395  const MSLane* lane = getLane();
2396  if (lane == nullptr) {
2397  return getEdge()->getLanes()[0]->getRNG();
2398  } else {
2399  return lane->getRNG();
2400  }
2401 }
2402 
2403 std::string
2404 MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
2405  const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
2406  if (StringUtils::startsWith(key, "device.")) {
2407  StringTokenizer tok(key, ".");
2408  if (tok.size() < 3) {
2409  error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
2410  return "";
2411  }
2412  try {
2413  return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
2414  } catch (InvalidArgument& e) {
2415  error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
2416  return "";
2417  }
2418  } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
2419  if (microVeh == nullptr) {
2420  error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
2421  return "";
2422  }
2423  const std::string attrName = key.substr(16);
2424  try {
2425  return microVeh->getLaneChangeModel().getParameter(attrName);
2426  } catch (InvalidArgument& e) {
2427  error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
2428  return "";
2429  }
2430  } else if (StringUtils::startsWith(key, "carFollowModel.")) {
2431  if (microVeh == nullptr) {
2432  error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
2433  return "";
2434  }
2435  const std::string attrName = key.substr(15);
2436  try {
2437  return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
2438  } catch (InvalidArgument& e) {
2439  error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
2440  return "";
2441  }
2442  } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
2443  StringTokenizer tok(key, ".");
2444  if (tok.size() != 3) {
2445  error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
2446  return "";
2447  }
2448  return hasDevice(tok.get(1)) ? "true" : "false";
2449  // parking related parameters start here
2450  } else if (key == "parking.rerouteCount") {
2452  } else if (StringUtils::startsWith(key, "parking.memory.")) {
2453  std::vector<std::string> values;
2454  if (getParkingMemory()) {
2455  if (key == "parking.memory.IDList") {
2456  for (const auto& item : *getParkingMemory()) {
2457  values.push_back(item.first->getID());
2458  }
2459  } else if (key == "parking.memory.score") {
2460  for (const auto& item : *getParkingMemory()) {
2461  values.push_back(item.second.score);
2462  }
2463  } else if (key == "parking.memory.blockedAtTime") {
2464  for (const auto& item : *getParkingMemory()) {
2465  values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
2466  }
2467  } else if (key == "parking.memory.blockedAtTimeLocal") {
2468  for (const auto& item : *getParkingMemory()) {
2469  values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
2470  }
2471  } else {
2472  error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
2473  }
2474  }
2475  return toString(values);
2476  } else {
2477  // default: custom user parameter
2478  return getParameter().getParameter(key, "");
2479  }
2480 }
2481 
2482 
2483 void
2485  if (myParkingMemory == nullptr) {
2487  }
2489 }
2490 
2491 
2492 void
2494  if (myParkingMemory != nullptr) {
2496  }
2497 }
2498 
2499 
2500 void
2501 MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
2502  if (myChargingMemory == nullptr) {
2504  }
2506 }
2507 
2508 
2509 void
2511  if (myChargingMemory != nullptr) {
2513  }
2514 }
2515 
2516 
2517 void
2518 MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
2519  if (myParkingMemory == nullptr) {
2521  }
2523 }
2524 
2525 
2526 SUMOTime
2528  if (myParkingMemory == nullptr) {
2529  return -1;
2530  }
2531  return myParkingMemory->sawBlockedStoppingPlace(pa, local);
2532 }
2533 
2534 
2536  if (myChargingMemory == nullptr) {
2538  }
2540 }
2541 
2542 
2543 SUMOTime
2545  if (myChargingMemory == nullptr) {
2546  return -1;
2547  }
2548  return myChargingMemory->sawBlockedStoppingPlace(cs, local);
2549 }
2550 
2551 
2552 #ifdef _DEBUG
2553 void
2554 MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
2555  if (oc.isSet("movereminder-output.vehicles")) {
2556  const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
2557  myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
2558  }
2559 }
2560 
2561 
2562 void
2563 MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
2564  OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
2565  od.openTag("movereminder");
2566  od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
2567  od.writeAttr("veh", getID());
2569  od.writeAttr("type", type);
2570  od.writeAttr("pos", toString(pos));
2571  od.writeAttr("keep", toString(keep));
2572  od.closeTag();
2573 }
2574 #endif
2575 
2576 
2577 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
#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:296
#define WRITE_ERRORF(...)
Definition: MsgHandler.h:305
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
std::shared_ptr< const MSRoute > ConstMSRoutePtr
Definition: Route.h:31
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
const int VEHPARS_CFMODEL_PARAMS_SET
const int VEHPARS_PARKING_BADGES_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 STOP_SPEED_SET
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.
@ GIVEN
The speed is given.
const int STOP_INDEX_REPEAT
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 STOP_JUMP_SET
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_TAG_PARKING_AREA
A parking area.
@ 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
double getMax() const
Returns the maximum value of this distribution.
double getMin() const
Returns the minimum value of this distribution.
std::vector< double > & getParameter()
Returns the parameters of this distribution.
void setSecondary(const EnergyParams *secondaryParams)
Set secondary params.
Definition: EnergyParams.h:60
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:333
virtual std::string getParameter(const std::string &key) const
try to retrieve the given parameter from this laneChangeModel. Throw exception for unsupported key
double getMaxSpeed() const
Returns the maximum speed (the minimum of desired and technical maximum speed)
bool haveValidStopEdges(bool silent=false) const
check whether all stop.edge MSRouteIterators are valid and in order
int myRoutingMode
routing mode (see TraCIConstants.h)
bool hasJump(const MSRouteIterator &it) const
check wether the vehicle has jump at the given part of its route
const StoppingPlaceMemory * getParkingMemory() const
std::list< MSStop > myStops
The vehicle's list of stops.
StoppingPlaceMemory * myParkingMemory
memory for parking search
double getImpatience() const
Returns this vehicles impatience.
void setSkips(MSStop &stop, int prevActiveStops)
patch stop.pars.index to record the number of skipped candidate edges before stop....
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()
void rememberParkingAreaScore(const MSStoppingPlace *pa, const std::string &score)
score only needed when running with gui
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
virtual BaseInfluencer & getBaseInfluencer()=0
Returns the velocity/lane influencer.
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...
StoppingPlaceMemory * myChargingMemory
bool replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string &info, bool teleport, std::string &errorMsg)
int getLeavingPersonNumber() const
Returns the number of leaving persons.
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 setRoutingMode(int value)
Sets routing behavior.
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.
void rememberChargingStationScore(const MSStoppingPlace *cs, const std::string &score)
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.
double getMaxChargeRate() const
Returns the maximum charge rate allowed by the battery in the current time step (W)
void replaceParameter(const SUMOVehicleParameter *newParameter)
replace the vehicle parameter (deleting the old one)
void rememberBlockedParkingArea(const MSStoppingPlace *pa, bool local)
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.
const SUMOVehicleParameter::Stop * getNextStopParameter() const
return parameters for the next stop (SUMOVehicle Interface)
void rememberBlockedChargingStation(const MSStoppingPlace *cs, bool local)
virtual bool replaceRoute(ConstMSRoutePtr route, const std::string &info, bool onInit=false, int offset=0, bool addRouteStops=true, bool removeStops=true, std::string *msgReturn=nullptr)
Replaces the current route by the given one.
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.
virtual void replaceVehicleType(MSVehicleType *type)
Replaces the current vehicle type by the one given.
bool isStoppedParking() const
Returns whether the vehicle is on a parking stop.
void unregisterWaiting()
mark vehicle as active
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.
double getRelativeStateOfCharge() const
Returns actual relative state of charge of battery (-)
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
const std::vector< std::string > & getParkingBadges() const
get the valid parking access rights (vehicle settings override vehicle type settings)
bool hasDeparted() const
Returns whether this vehicle has already departed.
MSStop & getNextStop()
bool ignoreTransientPermissions() const
Returns whether this object is ignoring transient permission changes (during routing)
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.
void resetChargingStationScores()
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
SUMOTime sawBlockedChargingStation(const MSStoppingPlace *cs, bool local) const
double basePos(const MSEdge *edge) const
departure position where the vehicle fits fully onto the edge (if possible)
const MSRouteIterator & getCurrentRouteEdge() const
Returns an iterator pointing to the current edge in this vehicles route.
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.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
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:76
@ ROUTE_START_INVALID_LANE
Definition: MSBaseVehicle.h:80
@ ROUTE_START_INVALID_PERMISSIONS
Definition: MSBaseVehicle.h:78
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
SUMOTime sawBlockedParkingArea(const MSStoppingPlace *pa, bool local) const
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)
const std::set< SUMOTrafficObject::NumericalID > getUpcomingEdgeIDs() const
returns the numerical ids of edges to travel
bool stopsAtEdge(const MSEdge *edge) const
Returns whether the vehicle stops at the given edge.
bool addStop(const SUMOVehicleParameter::Stop &stopPar, std::string &errorMsg, SUMOTime untilOffset=0, MSRouteIterator *searchStart=nullptr)
Adds a stop.
double getChargedEnergy() const
Returns the energy charged to the battery in the current time step (Wh)
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)
int getRoutingMode() const
return routing mode (configures router choice but also handling of transient permission changes)
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...
bool myAmRegisteredAsWaiting
Whether this vehicle is registered as waiting for a person or container (for deadlock-recognition)
SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT() const
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 isOnRoad() const
Returns the information whether the vehicle is on a road (is simulated)
const std::vector< MSTransportable * > & getContainers() const
retrieve riding containers
const MSRoute & getRoute() const
Returns the current route.
bool reroute(SUMOTime t, const std::string &info, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router, const bool onInit=false, const bool withTaz=false, const bool silent=false, const MSEdge *sink=nullptr)
Performs a rerouting using the given router.
bool stopsAt(MSStoppingPlace *stop) const
Returns whether the vehicle stops at the given stopping place.
int getRNGIndex() const
MSEdgeWeightsStorage * myEdgeWeights
void createDevice(const std::string &deviceName)
create device of the given type
bool isStopped() const
Returns whether the vehicle is at a stop.
MSDevice * getDevice(const std::type_info &type) const
Returns a device of the given type if it exists, nullptr otherwise.
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.
bool insertJump(int nextStopIndex, MSRouteIterator itStart, std::string &errorMsg)
helper function
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:646
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:659
Battery device for electric vehicles.
double getActualBatteryCapacity() const
Get the actual vehicle's Battery Capacity in Wh.
double getMaximumChargeRate() const
Get current charge rate in W depending on the state of charge.
double getMaximumBatteryCapacity() const
Get the total vehicle's Battery Capacity in Wh.
double getEnergyCharged() const
Get charged energy.
A device which collects info on the vehicle trip (mainly on departure and arrival)
double getMaximumBatteryCapacity() const
Get the total vehicle's Battery Capacity in kWh.
double getCurrentFromOverheadWire() const
Get actual current in the overhead wire segment.
double getEnergyCharged() const
Get charged energy.
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 bool willTransferAtJoin(const MSTransportable *t, const MSBaseVehicle *joinVeh)
check if boardingDuration should be applied
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:62
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSVehicleDevice * > &into)
Build devices for the given vehicle, if needed.
Definition: MSDevice.cpp:112
A road/street connecting two junctions.
Definition: MSEdge.h:77
bool hasTransientPermissions() const
Definition: MSEdge.cpp:1619
const MSEdge * getOppositeEdge() const
Returns the opposite direction edge if on exists else a nullptr.
Definition: MSEdge.cpp:1288
const std::vector< MSLane * > * allowedLanes(const MSEdge &destination, SUMOVehicleClass vclass=SVC_IGNORING, bool ignoreTransientPermissions=false) const
Get the allowed lanes to reach the destination-edge.
Definition: MSEdge.cpp:479
bool isNormal() const
return whether this edge is an internal edge
Definition: MSEdge.h:263
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
double getLength() const
return the length of the edge
Definition: MSEdge.h:670
bool isTazConnector() const
Definition: MSEdge.h:291
int getNumLanes() const
Definition: MSEdge.h:172
bool isInternal() const
return whether this edge is an internal edge
Definition: MSEdge.h:268
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:995
const MSEdge * getNormalBefore() const
if this edge is an internal edge, return its first normal predecessor, otherwise the edge itself
Definition: MSEdge.cpp:885
MSLane * getFirstAllowed(SUMOVehicleClass vClass, bool defaultFirst=false) const
Definition: MSEdge.cpp:674
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:180
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
SumoRNG * getRNG() const
return the associated RNG
Definition: MSLane.h:246
int getRNGIndex() const
returns the associated RNG index
Definition: MSLane.h:241
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition: MSLane.cpp:2371
double getLength() const
Returns the lane's length.
Definition: MSLane.h:598
bool allowsVehicleClass(SUMOVehicleClass vclass) const
Definition: MSLane.h:917
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition: MSLane.cpp:2395
bool isInternal() const
Definition: MSLane.cpp:2526
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:756
Something on a lane to be noticed about vehicle movement.
Notification
Definition of a vehicle state.
@ NOTIFICATION_DEPARTED
The vehicle has departed (was inserted into the network)
const std::string & getDescription() const
bool warnOnce(const std::string &typeAndID)
return whether a warning regarding the given object shall be issued
Definition: MSNet.cpp:1615
@ NEWROUTE
The vehicle got a new route.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:184
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:378
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:320
static bool hasInstance()
Returns whether the network was already constructed.
Definition: MSNet.h:152
MSStoppingPlace * getStoppingPlace(const std::string &id, const SumoXMLTag category) const
Returns the named stopping place of the given category.
Definition: MSNet.cpp:1373
MSInsertionControl & getInsertionControl()
Returns the insertion control.
Definition: MSNet.h:431
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:1267
MSVehicleRouter & getRouterTT(const int rngIndex, const MSEdgeVector &prohibited=MSEdgeVector()) const
Definition: MSNet.cpp:1487
A lane area vehicles can halt at.
Definition: MSParkingArea.h:60
bool accepts(MSBaseVehicle *veh) const
Return the parking accepts the vehicle (due to its given badges)
void setCosts(double costs)
Sets the costs of the route.
Definition: MSRoute.h:205
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
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:124
void setSavings(double savings)
Sets the savings of the route.
Definition: MSRoute.h:212
static MSVehicleRouter & getRouterTT(const int rngIndex, SUMOVehicleClass svc, const MSEdgeVector &prohibited=MSEdgeVector())
return the vehicle router instance
bool canLeaveVehicle(const MSTransportable *t, const SUMOVehicle &veh, const MSStop &stop)
checks whether the person may exit at the current vehicle position
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.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
void removeVType(const MSVehicleType *vehType)
void unregisterOneWaiting()
decreases the count of vehicles waiting for a transport to allow recognition of person / container re...
Abstract in-vehicle device.
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:5774
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition: MSVehicle.h:977
The car-following model and parameter.
Definition: MSVehicleType.h:63
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 EnergyParams * getEmissionParameters() const
retrieve parameters for the energy consumption model
bool isVehicleSpecific() const
Returns whether this type belongs to a single vehicle only (was modified)
const Distribution_Parameterized & getSpeedFactor() const
Returns this type's speed factor.
SUMOEmissionClass getEmissionClass() const
Get this vehicle type's emission class.
const std::string & getID() const
Returns the name of the vehicle type.
Definition: MSVehicleType.h:91
double getLength() const
Get vehicle's length [m].
double computeChosenSpeedDeviation(SumoRNG *rng, const double minDev=-1.) const
Computes and returns the speed deviation.
const std::vector< std::string > & getParkingBadges() const
Returns the parking access rights of this type.
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 & openTag(const std::string &xmlElement)
Opens an XML tag.
int precision()
return precision set on the device
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:254
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
std::string getStringParam(const std::string &paramName, const bool required=false, const std::string &deflt="") const
Retrieve a string parameter for the traffic object.
long long int NumericalID
virtual double getSpeed() const =0
Returns the object's current speed.
virtual SUMOTime getWaitingTime(const bool accumulated=false) const =0
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
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.
ParkingType parking
whether the vehicle is removed from the net while stopping
std::string lane
The lane to stop at.
double speed
the speed at which this stop counts as reached (waypoint mode)
std::string parkingarea
(Optional) parking area if one is assigned to the stop
double startPos
The stopping position start.
int parametersSet
Information for the output which parameter were set.
int index
at which position in the stops list
SUMOTime jump
transfer time if there shall be a jump from this stop to the next route edge
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.
double departSpeed
(optional) The initial speed of the vehicle
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
DepartSpeedDefinition departSpeedProcedure
Information how the vehicle's initial speed shall be chosen.
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< std::string > parkingBadges
The parking access rights.
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
SUMOTime sawBlockedStoppingPlace(const MSStoppingPlace *stoppingPlace, bool local) const
Get the time the StoppingPlace was confirmed to be blocked.
void rememberStoppingPlaceScore(const MSStoppingPlace *stoppingPlace, const std::string &score)
score only needed when running with gui
void rememberBlockedStoppingPlace(const MSStoppingPlace *stoppingPlace, bool local)
Store the time the StoppingPlace was confirmed to be blocked.
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.
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
TRACI_CONST int ROUTING_MODE_AGGREGATED
TRACI_CONST int ROUTING_MODE_DEFAULT
TRACI_CONST int ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS