Eclipse SUMO - Simulation of Urban MObility
MSDevice_Taxi.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2013-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 /****************************************************************************/
18 // A device which controls a taxi
19 /****************************************************************************/
20 #include <config.h>
21 
31 #include <microsim/MSGlobals.h>
32 #include <microsim/MSVehicle.h>
33 #include <microsim/MSEdge.h>
34 #include <microsim/MSLane.h>
35 #include <microsim/MSStop.h>
38 
39 #include "MSDispatch.h"
40 #include "MSDispatch_Greedy.h"
43 #include "MSDispatch_TraCI.h"
44 
45 #include "MSIdling.h"
46 
47 #include "MSRoutingEngine.h"
48 #include "MSDevice_Routing.h"
49 #include "MSDevice_Taxi.h"
50 
51 //#define DEBUG_DISPATCH
52 
53 //#define DEBUG_COND (myHolder.isSelected())
54 #define DEBUG_COND (true)
55 
56 // ===========================================================================
57 // static member variables
58 // ===========================================================================
64 // @brief the list of available taxis
65 std::vector<MSDevice_Taxi*> MSDevice_Taxi::myFleet;
68 
69 #define TAXI_SERVICE "taxi"
70 #define TAXI_SERVICE_PREFIX "taxi:"
71 
72 // ===========================================================================
73 // method definitions
74 // ===========================================================================
75 // ---------------------------------------------------------------------------
76 // static initialisation methods
77 // ---------------------------------------------------------------------------
78 void
80  oc.addOptionSubTopic("Taxi Device");
81  insertDefaultAssignmentOptions("taxi", "Taxi Device", oc);
82 
83  oc.doRegister("device.taxi.dispatch-algorithm", new Option_String("greedy"));
84  oc.addDescription("device.taxi.dispatch-algorithm", "Taxi Device", TL("The dispatch algorithm [greedy|greedyClosest|greedyShared|routeExtension|traci]"));
85 
86  oc.doRegister("device.taxi.dispatch-algorithm.output", new Option_FileName());
87  oc.addDescription("device.taxi.dispatch-algorithm.output", "Taxi Device", TL("Write information from the dispatch algorithm to FILE"));
88 
89  oc.doRegister("device.taxi.dispatch-algorithm.params", new Option_String(""));
90  oc.addDescription("device.taxi.dispatch-algorithm.params", "Taxi Device", TL("Load dispatch algorithm parameters in format KEY1:VALUE1[,KEY2:VALUE]"));
91 
92  oc.doRegister("device.taxi.dispatch-period", new Option_String("60", "TIME"));
93  oc.addDescription("device.taxi.dispatch-period", "Taxi Device", TL("The period between successive calls to the dispatcher"));
94 
95  oc.doRegister("device.taxi.idle-algorithm", new Option_String("stop"));
96  oc.addDescription("device.taxi.idle-algorithm", "Taxi Device", TL("The behavior of idle taxis [stop|randomCircling]"));
97 
98  oc.doRegister("device.taxi.idle-algorithm.output", new Option_FileName());
99  oc.addDescription("device.taxi.idle-algorithm.output", "Taxi Device", TL("Write information from the idling algorithm to FILE"));
100 }
101 
102 
103 void
104 MSDevice_Taxi::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
106  if (equippedByDefaultAssignmentOptions(oc, "taxi", v, false)) {
107  // build the device
108  MSDevice_Taxi* device = new MSDevice_Taxi(v, "taxi_" + v.getID());
109  into.push_back(device);
110  myFleet.push_back(device);
111  if (v.getParameter().line == "") {
112  // automatically set the line so that persons are willing to enter
113  // (see MSStageDriving::isWaitingFor)
114  const_cast<SUMOVehicleParameter&>(v.getParameter()).line = TAXI_SERVICE;
115  }
116  if (v.getVClass() != SVC_TAXI) {
117  WRITE_WARNINGF(TL("Vehicle '%' with device.taxi should have vClass taxi instead of '%'."), v.getID(), toString(v.getVClass()));
118  }
119  const int personCapacity = v.getVehicleType().getPersonCapacity();
120  const int containerCapacity = v.getVehicleType().getContainerCapacity();
121  myMaxCapacity = MAX2(myMaxCapacity, personCapacity);
122  myMaxContainerCapacity = MAX2(myMaxContainerCapacity, containerCapacity);
123  if (personCapacity < 1 && containerCapacity < 1) {
124  WRITE_WARNINGF(TL("Vehicle '%' with personCapacity % and containerCapacity % is not usable as taxi."), v.getID(), toString(personCapacity), toString(containerCapacity));
125  }
126  }
127 }
128 
129 
130 void
133  myDispatchPeriod = string2time(oc.getString("device.taxi.dispatch-period"));
134  // init dispatch algorithm
135  std::string algo = oc.getString("device.taxi.dispatch-algorithm");
136  Parameterised params;
137  params.setParametersStr(OptionsCont::getOptions().getString("device.taxi.dispatch-algorithm.params"), ":", ",");
138  if (algo == "greedy") {
140  } else if (algo == "greedyClosest") {
142  } else if (algo == "greedyShared") {
144  } else if (algo == "routeExtension") {
146  } else if (algo == "traci") {
148  } else {
149  throw ProcessError(TLF("Dispatch algorithm '%' is not known", algo));
150  }
152  // round to next multiple of myDispatchPeriod
154  const SUMOTime begin = string2time(oc.getString("begin"));
155  const SUMOTime delay = (myDispatchPeriod - ((now - begin) % myDispatchPeriod)) % myDispatchPeriod;
157 }
158 
159 bool
160 MSDevice_Taxi::isReservation(const std::set<std::string>& lines) {
161  return lines.size() == 1 && (
162  *lines.begin() == TAXI_SERVICE
163  || StringUtils::startsWith(*lines.begin(), TAXI_SERVICE_PREFIX));
164 }
165 
166 void
168  const std::set<std::string>& lines,
169  SUMOTime reservationTime,
170  SUMOTime pickupTime,
171  SUMOTime earliestPickupTime,
172  const MSEdge* from, double fromPos,
173  const MSStoppingPlace* fromStop,
174  const MSEdge* to, double toPos,
175  const MSStoppingPlace* toStop,
176  const std::string& group) {
177  if (!isReservation(lines)) {
178  return;
179  }
180  if ((to->getPermissions() & SVC_TAXI) == 0) {
181  throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
182  + " '" + person->getID() + "' because destination edge '" + to->getID() + "'"
183  + " does not permit taxi access");
184  }
185  if ((from->getPermissions() & SVC_TAXI) == 0) {
186  throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
187  + " '" + person->getID() + "' because origin edge '" + from->getID() + "'"
188  + " does not permit taxi access");
189  }
190  if (myDispatchCommand == nullptr) {
191  initDispatch();
192  }
193  if (fromStop != nullptr && &fromStop->getLane().getEdge() == from) {
194  // pickup position should be at the stop-endPos
195  fromPos = fromStop->getEndLanePosition();
196  }
197  myDispatcher->addReservation(person, reservationTime, pickupTime, earliestPickupTime, from, fromPos, fromStop, to, toPos, toStop, group, *lines.begin(), myMaxCapacity, myMaxContainerCapacity);
198 }
199 
200 void
202  const std::set<std::string>& lines,
203  const MSEdge* from, double fromPos,
204  const MSEdge* to, double toPos,
205  const std::string& group) {
206  if (myDispatcher != nullptr && lines.size() == 1 && *lines.begin() == TAXI_SERVICE) {
207  myDispatcher->removeReservation(person, from, fromPos, to, toPos, group);
208  }
209 }
210 
211 void
213  const std::set<std::string>& lines,
214  const MSEdge* from, double fromPos,
215  const MSEdge* to, double toPos,
216  const std::string& group, double newFromPos) {
217  if (myDispatcher != nullptr && lines.size() == 1 && *lines.begin() == TAXI_SERVICE) {
218  myDispatcher->updateReservationFromPos(person, from, fromPos, to, toPos, group, newFromPos);
219  }
220 }
221 
222 
223 SUMOTime
225  std::vector<MSDevice_Taxi*> active;
226  for (MSDevice_Taxi* taxi : myFleet) {
227  if (taxi->getHolder().hasDeparted()) {
228  active.push_back(taxi);
229  }
230  }
231  myDispatcher->computeDispatch(currentTime, active);
232  return myDispatchPeriod;
233 }
234 
235 bool
237  return myDispatcher != nullptr && myDispatcher->hasServableReservations();
238 }
239 
240 void
242  if (myDispatcher != nullptr) {
243  delete myDispatcher;
244  myDispatcher = nullptr;
245  }
246  myDispatchCommand = nullptr;
247 }
248 
249 // ---------------------------------------------------------------------------
250 // MSDevice_Taxi-methods
251 // ---------------------------------------------------------------------------
252 MSDevice_Taxi::MSDevice_Taxi(SUMOVehicle& holder, const std::string& id) :
253  MSVehicleDevice(holder, id) {
254  std::string defaultServiceEnd = toString(1e15);
255  const std::string algo = getStringParam(holder, OptionsCont::getOptions(), "taxi.idle-algorithm", "", false);
256  if (algo == "stop") {
258  } else if (algo == "randomCircling") {
260  // make sure simulation terminates
261  defaultServiceEnd = toString(STEPS2TIME(
264  : MSNet::getInstance()->getCurrentTimeStep()) + (3600 * 8));
265  } else if (algo == "taxistand") {
266  const std::string rerouterID = getStringParam(holder, OptionsCont::getOptions(), "taxi.stands-rerouter", "", false);
267  if (rerouterID.empty()) {
268  throw ProcessError("Idle algorithm '" + algo + "' requires a rerouter id to be defined using device param 'stands-rerouter' for vehicle '" + myHolder.getID() + "'");
269  }
270  if (MSTriggeredRerouter::getInstances().count(rerouterID) == 0) {
271  throw ProcessError("Unknown rerouter '" + rerouterID + "' when loading taxi stands for vehicle '" + myHolder.getID() + "'");
272  }
273  MSTriggeredRerouter* rerouter = MSTriggeredRerouter::getInstances().find(rerouterID)->second;
274  myIdleAlgorithm = new MSIdling_TaxiStand(rerouter);
275  } else {
276  throw ProcessError("Idle algorithm '" + algo + "' is not known for vehicle '" + myHolder.getID() + "'");
277  }
278  myServiceEnd = string2time(getStringParam(holder, OptionsCont::getOptions(), "taxi.end", defaultServiceEnd, false));
280 }
281 
282 
284  myFleet.erase(std::find(myFleet.begin(), myFleet.end(), this));
285  // recompute myMaxCapacity
286  myMaxCapacity = 0;
288  for (MSDevice_Taxi* taxi : myFleet) {
289  myMaxCapacity = MAX2(myMaxCapacity, taxi->getHolder().getVehicleType().getPersonCapacity());
290  myMaxContainerCapacity = MAX2(myMaxContainerCapacity, taxi->getHolder().getVehicleType().getContainerCapacity());
291  }
292  delete myIdleAlgorithm;
293 }
294 
295 
298  if (myFleet.size() > 0) {
299  return &myFleet[0]->getHolder();
300  } else {
301  return nullptr;
302  }
303 }
304 
305 
306 void
308  dispatchShared({&res, &res});
309 }
310 
311 
312 void
313 MSDevice_Taxi::dispatchShared(std::vector<const Reservation*> reservations) {
314 #ifdef DEBUG_DISPATCH
315  if (DEBUG_COND) {
316  std::cout << SIMTIME << " taxi=" << myHolder.getID() << " dispatch:\n";
317  for (const Reservation* res : reservations) {
318  std::cout << " persons=" << toString(res->persons) << "\n";
319  }
320  }
321 #endif
322  myLastDispatch = reservations;
323  ConstMSEdgeVector tmpEdges;
324  std::vector<SUMOVehicleParameter::Stop> stops;
325  double lastPos = myHolder.getPositionOnLane();
326  const MSEdge* rerouteOrigin = *myHolder.getRerouteOrigin();
327  if (isEmpty()) {
328  // start fresh from the current edge
329  while (myHolder.hasStops()) {
330  // in meso there might be more than 1 stop at this point
332  }
333  assert(!myHolder.hasStops());
334  tmpEdges.push_back(myHolder.getEdge());
335  if (myHolder.getEdge() != rerouteOrigin) {
336  tmpEdges.push_back(rerouteOrigin);
337  }
338  } else {
339  assert(myHolder.hasStops());
340  // check how often existing customers appear in the new reservations
341  std::map<const MSTransportable*, int> nOccur;
342  for (const Reservation* res : reservations) {
343  for (const MSTransportable* person : res->persons) {
344  if (myCustomers.count(person) != 0) {
345  nOccur[person] += 1;
346  if (myCurrentReservations.count(res) == 0) {
347  throw ProcessError(TLF("Invalid Re-dispatch for existing customer '%' with a new reservation", person->getID()));
348  }
349  }
350  }
351  }
352 #ifdef DEBUG_DISPATCH
353  if (DEBUG_COND) {
354  for (auto item : nOccur) {
355  std::cout << " previousCustomer=" << item.first->getID() << " occurs=" << item.second << "\n";
356  }
357  }
358 #endif
359  if (nOccur.size() == 0) {
360  // no overlap with existing customers - extend route
361  tmpEdges = myHolder.getRoute().getEdges();
362  lastPos = myHolder.getStops().back().pars.endPos;
363 #ifdef DEBUG_DISPATCH
364  if (DEBUG_COND) {
365  std::cout << " re-dispatch with route-extension\n";
366  }
367 #endif
368  } else if (nOccur.size() == myCustomers.size()) {
369  // redefine route (verify correct number of mentions)
370  std::set<const MSTransportable*> onBoard;
371  const std::vector<MSTransportable*>& onBoardP = myHolder.getPersons();
372  const std::vector<MSTransportable*>& onBoardC = myHolder.getContainers();
373  onBoard.insert(onBoardP.begin(), onBoardP.end());
374  onBoard.insert(onBoardC.begin(), onBoardC.end());
375  std::set<const MSTransportable*> redundantPickup;
376  for (auto item : nOccur) {
377  if (item.second == 1) {
378  // customers must already be on board
379  if (onBoard.count(item.first) == 0) {
380  throw ProcessError(TLF("Re-dispatch did not mention pickup for existing customer '%'", item.first->getID()));
381  }
382  } else if (item.second == 2) {
383  if (onBoard.count(item.first) == 0) {
384  // treat like a new customer
385  // TODO: need to be checked
386  myCustomers.erase(item.first);
387  } else {
388  redundantPickup.insert(item.first);
389  }
390  } else {
391  throw ProcessError("Re-dispatch mentions existing customer '" + item.first->getID() + "' " + toString(item.second) + " times");
392  }
393  }
394  // remove redundancy
395  if (!redundantPickup.empty()) {
396  for (auto it = reservations.begin(); it != reservations.end();) {
397  bool isRedundant = false;
398  for (const MSTransportable* person : (*it)->persons) {
399  if (redundantPickup.count(person) != 0) {
400  isRedundant = true;
401  break;
402  }
403  }
404  if (isRedundant) {
405  for (const MSTransportable* person : (*it)->persons) {
406  redundantPickup.erase(person);
407  }
408  it = reservations.erase(it);
409  } else {
410  it++;
411  }
412  }
413  }
414  while (myHolder.hasStops()) {
416  }
417  tmpEdges.push_back(myHolder.getEdge());
418  if (myHolder.getEdge() != rerouteOrigin) {
419  tmpEdges.push_back(rerouteOrigin);
420  }
421 #ifdef DEBUG_DISPATCH
422  if (DEBUG_COND) {
423  std::cout << " re-dispatch from scratch\n";
424  }
425 #endif
426  } else {
427  // inconsistent re-dispatch
428  std::vector<std::string> missing;
429  for (const MSTransportable* c : myCustomers) {
430  if (nOccur.count(c) == 0) {
431  missing.push_back(c->getID());
432  }
433  }
434  throw ProcessError("Re-dispatch did mention some customers but failed to mention " + joinToStringSorting(missing, " "));
435  }
436  }
437 
439  bool hasPickup = false;
440  for (const Reservation* res : reservations) {
441  myCurrentReservations.insert(res);
442  bool isPickup = false;
443  for (const MSTransportable* person : res->persons) {
444  if (myCustomers.count(person) == 0) {
445  myCustomers.insert(person);
446  isPickup = true;
447  hasPickup = true;
448  }
449  }
450  if (isPickup) {
451  prepareStop(tmpEdges, stops, lastPos, res->from, res->fromPos, res->fromStop, "pickup " + toString(res->persons) + " (" + res->id + ")", res, isPickup);
452  for (const MSTransportable* const transportable : res->persons) {
453  if (transportable->isPerson()) {
454  stops.back().triggered = true;
455  } else {
456  stops.back().containerTriggered = true;
457  }
458  stops.back().permitted.insert(transportable->getID());
459  }
460  // proof this lines: Is needed for pre-booking?
461  std::set<const MSTransportable*> persons = res->persons;
462  for (auto itr = persons.begin(); itr != persons.end(); itr++) {
463  stops.back().awaitedPersons.insert((*itr)->getID());
464  }
465 
466  stops.back().parametersSet |= STOP_PERMITTED_SET;
467  if (stops.back().duration == -1) {
468  // keep dropOffDuration if the stop is dropOff and pickUp
469  stops.back().duration = TIME2STEPS(getFloatParam(myHolder, OptionsCont::getOptions(), "taxi.pickUpDuration", 0, false));
470  }
471  } else {
472  prepareStop(tmpEdges, stops, lastPos, res->to, res->toPos, res->toStop, "dropOff " + toString(res->persons) + " (" + res->id + ")", res, isPickup);
473  stops.back().duration = TIME2STEPS(getFloatParam(myHolder, OptionsCont::getOptions(), "taxi.dropOffDuration", 60, false)); // pay and collect bags
474  }
475  }
476 #ifdef DEBUG_DISPATCH
477  if (DEBUG_COND) {
478  std::cout << " tmpEdges=" << toString(tmpEdges) << "\n";
479  }
480 #endif
481  if (!myHolder.replaceRouteEdges(tmpEdges, -1, 0, "taxi:prepare_dispatch", false, false, false)) {
482  throw ProcessError("Route replacement for taxi dispatch failed for vehicle '" + myHolder.getID()
483  + "' at time=" + time2string(t) + ".");
484  }
485 #ifdef DEBUG_DISPATCH
486  if (DEBUG_COND) std::cout << " replacedRoute=" << toString(tmpEdges)
487  << "\n actualRoute=" << toString(myHolder.getRoute().getEdges()) << "\n";
488 #endif
489  for (SUMOVehicleParameter::Stop& stop : stops) {
490  std::string error;
491  myHolder.addStop(stop, error);
492  if (error != "") {
493  WRITE_WARNINGF(TL("Could not add taxi stop for vehicle '%' to %. time=% error=%."), myHolder.getID(), stop.actType, time2string(t), error)
494  }
495  }
497  // SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = myHolder.getInfluencer().getRouterTT(veh->getRNGIndex())
498  myHolder.reroute(t, "taxi:dispatch", router, false);
499 #ifdef DEBUG_DISPATCH
500  if (DEBUG_COND) {
501  std::cout << "\n finalRoute=" << toString(myHolder.getRoute().getEdges()) << " routeIndex=" << myHolder.getRoutePosition() << "\n";
502  }
503 #endif
504  if (hasPickup) {
505  myState |= PICKUP;
506  }
507 }
508 
509 
510 void
512  // check if taxi has stopped
513  if (myHolder.getNextStopParameter() == nullptr) {
514  return;
515  }
516  // find customers of the current stop
517  std::set<const MSTransportable*> customersToBeRemoved;
518  for (std::string tID : myHolder.getNextStopParameter()->permitted) {
519  //for (const MSTransportable* t : myCustomers) {
520  for (auto t : myCustomers) {
521  //bool removed = false;
522  //if (t->getID() == tID) {
523  if (t->getID() == tID) {
524  //cancelCustomer(t);
525  customersToBeRemoved.insert(t);
526  //removed = cancelCustomer((*tIt));
527 
528  }
529  //if (!removed) {
530  // tIt++;
531  //}
532  }
533  }
534  for (auto t : customersToBeRemoved) {
535  cancelCustomer(t);
536  }
537 }
538 
539 
540 bool
542  // is the given transportable a customer of the reservations?
543  if (myCustomers.count(t) == 0) {
544  return false;
545  }
546  myCustomers.erase(t);
547  // check whether a single reservation has been fulfilled or another customer is part of the reservation
548  for (auto resIt = myCurrentReservations.begin(); resIt != myCurrentReservations.end();) {
549  bool fulfilled = false;
550  if ((*resIt)->persons.size() == 1 && (*resIt)->persons.count(t) != 0) {
551  // the reservation contains only the customer
552  fulfilled = true;
553  }
554  if (fulfilled) {
555  // delete the reservation
557  // remove reservation from the current dispatch
558  for (auto it = myLastDispatch.begin(); it != myLastDispatch.end();) {
559  if (*it == *resIt) {
560  it = myLastDispatch.erase(it);
561  } else {
562  ++it;
563  }
564  }
565  // remove reservation from the served reservations
566  resIt = myCurrentReservations.erase(resIt);
567  } else {
568  ++resIt;
569  }
570  }
571  myState &= ~PICKUP; // remove state PICKUP
572  for (const Reservation* res : myCurrentReservations) {
573  // if there is another pickup in the dispatch left, add the state PICKUP
574  if (std::count(myLastDispatch.begin(), myLastDispatch.end(), res) == 2) {
575  myState |= PICKUP; // add state PICKUP
576  }
577  }
578  // if there are reservations left, go on with the dispatch
579  // in meso, wait for the next dispatch cycle to avoid updating stops in this stage
580  if (!MSGlobals::gUseMesoSim) {
582  }
583  return true;
584 }
585 
586 
587 void
589  std::vector<SUMOVehicleParameter::Stop>& stops,
590  double& lastPos, const MSEdge* stopEdge, double stopPos,
591  const MSStoppingPlace* stopPlace,
592  const std::string& action, const Reservation* res, const bool isPickup) {
593  assert(!edges.empty());
594  if (stopPlace != nullptr && &stopPlace->getLane().getEdge() == stopEdge) {
595  stopPos = stopPlace->getEndLanePosition();
596  }
597  if (stopPos < lastPos && stopPos + NUMERICAL_EPS >= lastPos) {
598  stopPos = lastPos;
599  }
600 
601  if (stops.empty()) {
602  // check brakeGap
603  double distToStop = stopPos - lastPos;
604  const double brakeGap = myHolder.getBrakeGap();
605  if (myHolder.getLane() != nullptr && myHolder.getLane()->isInternal()) {
606  distToStop += myHolder.getLane()->getLength();
607  }
608  if (stopEdge != edges.back()) {
609  distToStop += edges.back()->getLength();
610  if (distToStop < brakeGap) {
611  // the distance between current edge and stop edge may be small
613  ConstMSEdgeVector toFirstStop;
614  router.compute(edges.back(), stopEdge, &myHolder, SIMSTEP, toFirstStop, true);
615  for (int i = 1; i < (int)toFirstStop.size() - 1; i++) {
616  distToStop += toFirstStop[i]->getLength();
617  }
618  }
619  }
620  if (distToStop < brakeGap) {
621  // circle back to stopEdge
622  //std::cout << SIMTIME << " taxi=" << getID() << " brakeGap=" << brakeGap << " distToStop=" << distToStop << "\n";
623  edges.push_back(stopEdge);
624  }
625  }
626 
627  if (stopEdge == edges.back() && !stops.empty()) {
628  if (stopPos >= lastPos && stopPos <= stops.back().endPos) {
629  // no new stop and no adaption needed
630  stops.back().actType += "," + action;
631  return;
632  }
633  if (stopPos >= lastPos && stopPos <= lastPos + myHolder.getVehicleType().getLength()) {
634  // stop length adaption needed
635  stops.back().endPos = MIN2(lastPos + myHolder.getVehicleType().getLength(), stopEdge->getLength());
636  stops.back().actType += "," + action;
637  return;
638  }
639  }
640  if (stopEdge != edges.back() || stopPos < lastPos) {
641  edges.push_back(stopEdge);
642  }
643  lastPos = stopPos;
645  stop.lane = getStopLane(stopEdge, action)->getID();
646  if (stopPlace != nullptr && &stopPlace->getLane().getEdge() == stopEdge) {
647  stop.startPos = stopPlace->getBeginLanePosition();
648  stop.endPos = stopPlace->getEndLanePosition();
649  } else {
650  stop.startPos = stopPos;
651  stop.endPos = MAX2(stopPos, MIN2(myHolder.getVehicleType().getLength(), stopEdge->getLength()));
652  }
654  stop.actType = action;
655  stop.index = STOP_INDEX_END;
656  // In case of prebooking if person is not there/ comes to late for pickup set maximum waiting time:
657  SUMOTime earliestPickupTime = res->earliestPickupTime;
658  if (isPickup && earliestPickupTime >= 0) {
659  stop.waitUntil = earliestPickupTime;
660  // TODO: replace hard coded extension with parameter
661  stop.extension = static_cast<SUMOTime>(3 * 60 * 1000); // 3mins
662  }
663  stops.push_back(stop);
664 }
665 
666 
667 MSLane*
668 MSDevice_Taxi::getStopLane(const MSEdge* edge, const std::string& action) {
669  const std::vector<MSLane*>* allowedLanes = edge->allowedLanes(myHolder.getVClass());
670  if (allowedLanes == nullptr) {
671  throw ProcessError("Taxi vehicle '" + myHolder.getID() + "' cannot stop on edge '" + edge->getID() + "' (" + action + ")");
672  }
673  return allowedLanes->front();
674 }
675 
676 bool
678  return myState == EMPTY;
679 }
680 
681 
682 bool
684  return myCustomers.count(t) != 0;
685 }
686 
687 
688 void
689 MSDevice_Taxi::updateMove(const SUMOTime traveltime, const double travelledDist) {
691  myOccupiedDistance += travelledDist;
692  myOccupiedTime += traveltime;
693  }
694  if (isEmpty()) {
695  if (MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
696  myIdleAlgorithm->idle(this);
697  if (myRoutingDevice != nullptr) {
698  // prevent rerouting during idling (#11079)
699  myRoutingDevice->setActive(false);
700  }
701  } else if (!myReachedServiceEnd) {
702  WRITE_WARNINGF(TL("Taxi '%' reaches scheduled end of service at time=%."), myHolder.getID(), time2string(SIMSTEP));
703  myReachedServiceEnd = true;
704  }
705  } else if (myRoutingDevice != nullptr) {
706  myRoutingDevice->setActive(true);
707  }
709  // limit duration of stop (but only for idling-related stops)
711  }
712 #ifdef DEBUG_DISPATCH
714  std::cout << SIMTIME << " updateMove veh=" << myHolder.getID() << " myIsStopped=" << myIsStopped << " myHolderStopped=" << myHolder.isStopped() << " myState=" << myState << "\n";
715  }
716 #endif
718 }
719 
720 
721 bool
722 MSDevice_Taxi::notifyMove(SUMOTrafficObject& /*tObject*/, double oldPos,
723  double newPos, double /*newSpeed*/) {
724  updateMove(DELTA_T, newPos - oldPos);
725  return true; // keep the device
726 }
727 
728 
729 void
731  const double /* frontOnLane */,
732  const double timeOnLane,
733  const double /* meanSpeedFrontOnLane */,
734  const double /* meanSpeedVehicleOnLane */,
735  const double travelledDistanceFrontOnLane,
736  const double /* travelledDistanceVehicleOnLane */,
737  const double /* meanLengthOnLane */) {
738  updateMove(TIME2STEPS(timeOnLane), travelledDistanceFrontOnLane);
739 }
740 
741 
742 bool
743 MSDevice_Taxi::notifyEnter(SUMOTrafficObject& /*veh*/, MSMoveReminder::Notification /*reason*/, const MSLane* /* enteredLane */) {
744  if (isEmpty() && MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
745  myIdleAlgorithm->idle(this);
746  }
747  return true; // keep the device
748 }
749 
750 
751 void
753  myState |= OCCUPIED;
754  if (!hasFuturePickup()) {
755  myState &= ~PICKUP;
756  }
757  for (const Reservation* res : myCurrentReservations) {
758  for (const MSTransportable* cand : res->persons) {
759  if (cand == t) {
760  const_cast<Reservation*>(res)->state = Reservation::ONBOARD;
761  break;
762  }
763  }
764  }
765 }
766 
767 
768 void
771  myCustomers.erase(person);
772  if (myHolder.getPersonNumber() == 0 && myHolder.getContainerNumber() == 0) {
773  myState &= ~OCCUPIED;
774  if (myHolder.getStops().size() > 1 && (myState & PICKUP) == 0) {
775  WRITE_WARNINGF(TL("All customers left vehicle '%' at time=% but there are % remaining stops"),
776  myHolder.getID(), time2string(SIMSTEP), myHolder.getStops().size() - 1);
777  while (myHolder.getStops().size() > 1) {
779  }
780  }
781  }
782  if (isEmpty()) {
783  // cleanup
784  for (const Reservation* res : myCurrentReservations) {
786  }
787  myCurrentReservations.clear();
788  if (MSGlobals::gUseMesoSim && MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
789  myIdleAlgorithm->idle(this);
790  }
791  } else {
792  // check whether a single reservation has been fulfilled
793  for (auto resIt = myCurrentReservations.begin(); resIt != myCurrentReservations.end();) {
794  bool fulfilled = true;
795  for (const MSTransportable* t : (*resIt)->persons) {
796  if (myCustomers.count(t) != 0) {
797  fulfilled = false;
798  break;
799  }
800  }
801  if (fulfilled) {
803  resIt = myCurrentReservations.erase(resIt);
804  } else {
805  ++resIt;
806  }
807  }
808  }
809 }
810 
811 
812 bool
814  for (const auto& stop : myHolder.getStops()) {
815  if (stop.reached) {
816  continue;
817  }
818  if (stop.pars.permitted.size() > 0) {
819  return true;
820  }
821  }
822  return false;
823 }
824 
825 void
827  if (tripinfoOut != nullptr) {
828  tripinfoOut->openTag("taxi");
829  tripinfoOut->writeAttr("customers", toString(myCustomersServed));
830  tripinfoOut->writeAttr("occupiedDistance", toString(myOccupiedDistance));
831  tripinfoOut->writeAttr("occupiedTime", time2string(myOccupiedTime));
832  tripinfoOut->closeTag();
833  }
834 }
835 
836 std::string
837 MSDevice_Taxi::getParameter(const std::string& key) const {
838  if (key == "customers") {
839  return toString(myCustomersServed);
840  } else if (key == "occupiedDistance") {
842  } else if (key == "occupiedTime") {
844  } else if (key == "state") {
845  return toString(myState);
846  } else if (key == "currentCustomers") {
848  } else if (key == "pickUpDuration") {
849  return getStringParam(myHolder, OptionsCont::getOptions(), "taxi.pickUpDuration", "0", false);
850  } else if (key == "dropOffDuration") {
851  return getStringParam(myHolder, OptionsCont::getOptions(), "taxi.dropOffDuration", "60", false);
852  }
853  throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
854 }
855 
856 
857 void
858 MSDevice_Taxi::setParameter(const std::string& key, const std::string& value) {
859  double doubleValue;
860  try {
861  doubleValue = StringUtils::toDouble(value);
862  } catch (NumberFormatException&) {
863  throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
864  }
865  if (key == "pickUpDuration" || key == "dropOffDuration") {
866  // store as generic vehicle parameters
867  ((SUMOVehicleParameter&)myHolder.getParameter()).setParameter("device.taxi." + key, value);
868  } else {
869  UNUSED_PARAMETER(doubleValue);
870  throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
871  }
872 }
873 
874 bool
875 MSDevice_Taxi::compatibleLine(const std::string& taxiLine, const std::string& rideLine) {
876  return ((taxiLine == rideLine && StringUtils::startsWith(rideLine, "taxi") && StringUtils::startsWith(taxiLine, "taxi"))
877  || (taxiLine == TAXI_SERVICE && StringUtils::startsWith(rideLine, "taxi:"))
878  || (rideLine == TAXI_SERVICE && StringUtils::startsWith(taxiLine, "taxi:")));
879 }
880 
881 bool
883  return compatibleLine(myHolder.getParameter().line, res->line);
884 }
885 
886 
887 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
#define TAXI_SERVICE
#define DEBUG_COND
#define TAXI_SERVICE_PREFIX
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
SUMOTime DELTA_T
Definition: SUMOTime.cpp:38
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:46
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 SIMTIME
Definition: SUMOTime.h:62
#define TIME2STEPS(x)
Definition: SUMOTime.h:57
@ SVC_TAXI
vehicle is a taxi
const int STOP_INDEX_END
const int STOP_PERMITTED_SET
@ GIVEN
The time is given.
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
T MIN2(T a, T b)
Definition: StdDefs.h:76
T MAX2(T a, T b)
Definition: StdDefs.h:82
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:299
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
std::string joinNamedToStringSorting(const std::set< T * > &ns, const T_BETWEEN &between)
Definition: ToString.h:307
Base (microsim) event class.
Definition: Command.h:50
A device that performs vehicle rerouting based on current edge speeds.
void setActive(bool active)
A device which collects info on the vehicle trip (mainly on departure and arrival)
Definition: MSDevice_Taxi.h:49
static void initDispatch()
initialize the dispatch algorithm
static Command * myDispatchCommand
The repeated call to the dispatcher.
void customerArrived(const MSTransportable *person)
called by MSDevice_Transportable upon unloading a person
static SUMOTime triggerDispatch(SUMOTime currentTime)
period command to trigger the dispatch algorithm
void dispatch(const Reservation &res)
service the given reservation
std::set< const MSTransportable * > myCustomers
the customer of the current reservation
SUMOTime myServiceEnd
the time at which the taxi service ends (end the vehicle may leave the simulation)
static void updateReservationFromPos(MSTransportable *person, const std::set< std::string > &lines, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, const std::string &group, double newFromPos)
update reservation's fromPos due to pre-booking
bool cancelCustomer(const MSTransportable *t)
remove person from reservations
void generateOutput(OutputDevice *tripinfoOut) const
Called on writing tripinfo output.
static int myMaxCapacity
void dispatchShared(std::vector< const Reservation * > reservations)
service the given reservations
static void addReservation(MSTransportable *person, const std::set< std::string > &lines, SUMOTime reservationTime, SUMOTime pickupTime, SUMOTime earliestPickupTime, const MSEdge *from, double fromPos, const MSStoppingPlace *fromStop, const MSEdge *to, double toPos, const MSStoppingPlace *toStop, const std::string &group)
add new reservation
MSIdling * myIdleAlgorithm
algorithm for controlling idle behavior
std::set< const Reservation * > myCurrentReservations
reservations currently being served
bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
Checks for waiting steps when the vehicle moves.
bool hasFuturePickup()
whether the taxi has another pickup scheduled
void cancelCurrentCustomers()
remove the persons the taxi is currently waiting for from reservations
std::vector< const Reservation * > myLastDispatch
the last dispatch order
static MSDispatch * myDispatcher
the dispatch algorithm
int myCustomersServed
number of customers that were served
void updateMove(const SUMOTime traveltime, const double travelledDist)
void notifyMoveInternal(const SUMOTrafficObject &veh, const double frontOnLane, const double timeOnLane, const double meanSpeedFrontOnLane, const double meanSpeedVehicleOnLane, const double travelledDistanceFrontOnLane, const double travelledDistanceVehicleOnLane, const double meanLengthOnLane)
Internal notification about the vehicle moves, see MSMoveReminder::notifyMoveInternal()
static int myMaxContainerCapacity
MSDevice_Routing * myRoutingDevice
routing device (if the vehicle has one)
bool isEmpty()
whether the taxi is empty
const std::string deviceName() const
return the name for this type of device
static std::vector< MSDevice_Taxi * > myFleet
static void removeReservation(MSTransportable *person, const std::set< std::string > &lines, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, const std::string &group)
retract reservation
static SUMOTime myDispatchPeriod
the time between successive calls to the dispatcher
bool notifyEnter(SUMOTrafficObject &veh, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Saves departure info on insertion.
static void cleanup()
resets counters
static bool isReservation(const std::set< std::string > &lines)
whether the given lines description is a taxi call
double myOccupiedDistance
distance driven with customers
MSDevice_Taxi(SUMOVehicle &holder, const std::string &id)
Constructor.
bool allowsBoarding(const MSTransportable *t) const
whether the given person is allowed to board this taxi
static bool hasServableReservations()
check whether there are still (servable) reservations in the system
static SUMOVehicle * getTaxi()
returns a taxi if any exist or nullptr
void customerEntered(const MSTransportable *t)
called by MSDevice_Transportable upon loading a person
bool compatibleLine(const Reservation *res)
whether the given reservation is compatible with the taxi line
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSVehicleDevice * > &into)
Build devices for the given vehicle, if needed.
static void insertOptions(OptionsCont &oc)
Inserts MSDevice_Taxi-options.
bool myIsStopped
whether the vehicle is currently stopped
void setParameter(const std::string &key, const std::string &value)
try to set the given parameter for this device. Throw exception for unsupported key
SUMOTime myOccupiedTime
time spent driving with customers
bool myReachedServiceEnd
whether the taxi has reached its schedule service end
~MSDevice_Taxi()
Destructor.
void prepareStop(ConstMSEdgeVector &edges, std::vector< SUMOVehicleParameter::Stop > &stops, double &lastPos, const MSEdge *stopEdge, double stopPos, const MSStoppingPlace *stopPlace, const std::string &action, const Reservation *res, const bool isPickup)
prepare stop for the given action
MSLane * getStopLane(const MSEdge *edge, const std::string &action)
determine stopping lane for taxi
std::string getParameter(const std::string &key) const
try to retrieve the given parameter from this device. Throw exception for unsupported key
static double getFloatParam(const SUMOVehicle &v, const OptionsCont &oc, const std::string &paramName, const double deflt, bool required=false)
Definition: MSDevice.cpp:206
static std::string getStringParam(const SUMOVehicle &v, const OptionsCont &oc, const std::string &paramName, const std::string &deflt, bool required=false)
Definition: MSDevice.cpp:182
static void insertDefaultAssignmentOptions(const std::string &deviceName, const std::string &optionsTopic, OptionsCont &oc, const bool isPerson=false)
Adds common command options that allow to assign devices to vehicles.
Definition: MSDevice.cpp:155
static bool equippedByDefaultAssignmentOptions(const OptionsCont &oc, const std::string &deviceName, DEVICEHOLDER &v, bool outputOptionSet, const bool isPerson=false)
Determines whether a vehicle should get a certain device.
Definition: MSDevice.h:203
A dispatch algorithm that services the reservations with the shortest traveltime-to-pickup first.
A dispatch algorithm that services customers in reservation order and always sends the closest availa...
A dispatch algorithm that services customers in reservation order and always sends the closest availa...
An algorithm that performs distpach for a taxi fleet.
Definition: MSDispatch.h:112
virtual std::string removeReservation(MSTransportable *person, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, std::string group)
remove person from reservation. If the whole reservation is removed, return its id
Definition: MSDispatch.cpp:137
virtual Reservation * updateReservationFromPos(MSTransportable *person, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, std::string group, double newFromPos)
update fromPos of the person's reservation. TODO: if there is already a reservation with the newFromP...
Definition: MSDispatch.cpp:181
virtual Reservation * addReservation(MSTransportable *person, SUMOTime reservationTime, SUMOTime pickupTime, SUMOTime earliestPickupTime, const MSEdge *from, double fromPos, const MSStoppingPlace *fromStop, const MSEdge *to, double toPos, const MSStoppingPlace *tostop, std::string group, const std::string &line, int maxCapacity, int maxContainerCapacity)
add a new reservation
Definition: MSDispatch.cpp:70
bool hasServableReservations()
check whether there are still (servable) reservations in the system
Definition: MSDispatch.h:174
virtual void fulfilledReservation(const Reservation *res)
erase reservation from storage
Definition: MSDispatch.cpp:264
virtual void computeDispatch(SUMOTime now, const std::vector< MSDevice_Taxi * > &fleet)=0
computes dispatch and updates reservations
A road/street connecting two junctions.
Definition: MSEdge.h:77
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition: MSEdge.h:626
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:474
double getLength() const
return the length of the edge
Definition: MSEdge.h:662
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUseMesoSim
Definition: MSGlobals.h:103
virtual void idle(MSDevice_Taxi *taxi)=0
computes Idling and updates reservations
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
double getLength() const
Returns the lane's length.
Definition: MSLane.h:598
bool isInternal() const
Definition: MSLane.cpp:2506
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:756
Notification
Definition of a vehicle state.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:182
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:320
MSEventControl * getEndOfTimestepEvents()
Returns the event control for events executed at the end of a time step.
Definition: MSNet.h:481
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:124
static MSVehicleRouter & getRouterTT(const int rngIndex, SUMOVehicleClass svc, const MSEdgeVector &prohibited=MSEdgeVector())
return the vehicle router instance
SUMOTime endBoarding
the maximum time at which persons may board this vehicle
Definition: MSStop.h:85
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.
Reroutes traffic objects passing an edge.
static const std::map< std::string, MSTriggeredRerouter * > & getInstances()
return all rerouter instances
Abstract in-vehicle device.
SUMOVehicle & myHolder
The vehicle that stores the device.
int getPersonCapacity() const
Get this vehicle type's person capacity.
double getLength() const
Get vehicle's length [m].
int getContainerCapacity() const
Get this vehicle type's container capacity.
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A storage for options typed value containers)
Definition: OptionsCont.h:89
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
void doRegister(const std::string &name, Option *o)
Adds an option under the given name.
Definition: OptionsCont.cpp:76
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
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.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:254
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
An upper class for objects with additional parameters.
Definition: Parameterised.h:41
void setParametersStr(const std::string &paramsString, const std::string kvsep="=", const std::string sep="|")
set the inner key/value map in string format "key1=value1|key2=value2|...|keyN=valueN"
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
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...
Representation of a vehicle, person, or container.
virtual MSDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or nullptr if not.
virtual int getRNGIndex() const =0
virtual bool isStopped() const =0
Returns whether the object is at a stop.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual SUMOVehicleClass getVClass() const =0
Returns the object's access class.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual int getRoutePosition() const =0
return index of edge within route
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
virtual const MSEdge * getEdge() const =0
Returns the edge 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:60
virtual ConstMSEdgeVector::const_iterator getRerouteOrigin() const =0
Returns the starting point for reroutes (usually the current edge)
virtual 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)=0
Performs a rerouting using the given router.
virtual 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)=0
Replaces the current route by the given edges.
virtual const MSRoute & getRoute() const =0
Returns the current route.
virtual const std::list< MSStop > & getStops() const =0
virtual const std::vector< MSTransportable * > & getContainers() const =0
retrieve riding containers
virtual bool hasStops() const =0
Returns whether the vehicle has to stop somewhere.
virtual bool addStop(const SUMOVehicleParameter::Stop &stopPar, std::string &errorMsg, SUMOTime untilOffset=0, ConstMSEdgeVector::const_iterator *searchStart=0)=0
Adds a stop.
virtual MSStop & getNextStop()=0
virtual int getPersonNumber() const =0
Returns the number of persons.
virtual const std::vector< MSTransportable * > & getPersons() const =0
retrieve riding persons
virtual int getContainerNumber() const =0
Returns the number of containers.
virtual double getBrakeGap(bool delayed=false) const =0
get distance for coming to a stop (used for rerouting checks)
virtual const SUMOVehicleParameter::Stop * getNextStopParameter() const =0
Returns parameters of the next stop or nullptr.
virtual bool abortNextStop(int nextStopIndex=0)=0
deletes the next stop at the given index if it exists
Definition of vehicle stop (position and duration)
ParkingType parking
whether the vehicle is removed from the net while stopping
std::string lane
The lane to stop at.
SUMOTime extension
The maximum time extension for boarding / loading.
double startPos
The stopping position start.
std::set< std::string > permitted
IDs of persons or containers that may board/load at this stop.
int index
at which position in the stops list
std::string actType
act Type (only used by Persons) (used by netedit)
double endPos
The stopping position end.
SUMOTime waitUntil
The earliest pickup time for a taxi stop.
Structure representing possible vehicle parameter.
DepartDefinition departProcedure
Information how the vehicle shall choose the depart time.
std::string line
The vehicle's line (mainly for public transport)
static ParkingType parseParkingType(const std::string &value)
parses parking type value
A wrapper for a Command function.
Definition: StaticCommand.h:38
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
std::string line
Definition: MSDispatch.h:88
SUMOTime earliestPickupTime
Definition: MSDispatch.h:80