Eclipse SUMO - Simulation of Urban MObility
MSRouteHandler.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2020 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 /****************************************************************************/
21 // Parser and container for routes during their loading
22 /****************************************************************************/
23 #include <config.h>
24 
25 #include "MSRouteHandler.h"
29 #include <microsim/MSEdge.h>
37 
38 #define JUNCTION_TAZ_MISSING_HELP "\nSet option '--junction-taz' or load a TAZ-file"
39 
40 
41 // ===========================================================================
42 // static members
43 // ===========================================================================
44 std::mt19937 MSRouteHandler::myParsingRNG;
45 
46 
47 // ===========================================================================
48 // method definitions
49 // ===========================================================================
50 MSRouteHandler::MSRouteHandler(const std::string& file, bool addVehiclesDirectly) :
51  SUMORouteHandler(file, addVehiclesDirectly ? "" : "routes", true),
52  myActiveRouteRepeat(0),
53  myActiveRoutePeriod(0),
54  myActivePlan(nullptr),
55  myActiveContainerPlan(nullptr),
56  myAddVehiclesDirectly(addVehiclesDirectly),
57  myCurrentVTypeDistribution(nullptr),
58  myCurrentRouteDistribution(nullptr),
59  myAmLoadingState(false) {
60  myActiveRoute.reserve(100);
61 }
62 
63 
65 
66 
67 void
69  MSTransportable::MSTransportablePlan::iterator i;
70  if (myActivePlan != nullptr) {
71  for (i = myActivePlan->begin(); i != myActivePlan->end(); i++) {
72  delete *i;
73  }
74  delete myActivePlan;
75  myActivePlan = nullptr;
76  }
77  if (myActiveContainerPlan != nullptr) {
78  for (i = myActiveContainerPlan->begin(); i != myActiveContainerPlan->end(); i++) {
79  delete *i;
80  }
81  delete myActiveContainerPlan;
82  myActivePlan = nullptr;
83  }
84 }
85 
86 
87 void
89  const std::string element = toString(tag);
90  myActiveRoute.clear();
91  bool useTaz = OptionsCont::getOptions().getBool("with-taz");
93  WRITE_WARNING("Taz usage was requested but no taz present in " + element + " '" + myVehicleParameter->id + "'!");
94  useTaz = false;
95  }
96  bool ok = true;
97  // from-attributes
98  if ((useTaz || !attrs.hasAttribute(SUMO_ATTR_FROM)) &&
100  const bool useJunction = attrs.hasAttribute(SUMO_ATTR_FROMJUNCTION);
101  const std::string tazType = useJunction ? "junction" : "taz";
102  const std::string tazID = attrs.get<std::string>(useJunction ? SUMO_ATTR_FROMJUNCTION : SUMO_ATTR_FROM_TAZ, myVehicleParameter->id.c_str(), ok, true);
103  const MSEdge* fromTaz = MSEdge::dictionary(tazID + "-source");
104  if (fromTaz == nullptr) {
105  throw ProcessError("Source " + tazType + " '" + tazID + "' not known for " + element + " '" + myVehicleParameter->id + "'!"
106  + (useJunction ? JUNCTION_TAZ_MISSING_HELP : ""));
107  } else if (fromTaz->getNumSuccessors() == 0 && tag != SUMO_TAG_PERSON) {
108  throw ProcessError("Source " + tazType + " '" + tazID + "' has no outgoing edges for " + element + " '" + myVehicleParameter->id + "'!");
109  } else {
110  myActiveRoute.push_back(fromTaz);
111  }
112  } else {
113  MSEdge::parseEdgesList(attrs.getOpt<std::string>(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok, "", true),
114  myActiveRoute, "for " + element + " '" + myVehicleParameter->id + "'");
115  }
116 
117  // via-attributes
118  if (!attrs.hasAttribute(SUMO_ATTR_VIA) && !attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
119  myInsertStopEdgesAt = (int)myActiveRoute.size();
120  }
121  ConstMSEdgeVector viaEdges;
123  for (std::string junctionID : attrs.getStringVector(SUMO_ATTR_VIAJUNCTIONS)) {
124  const MSEdge* viaSink = MSEdge::dictionary(junctionID + "-sink");
125  if (viaSink == nullptr) {
126  throw ProcessError("Junction-taz '" + junctionID + "' not found." + JUNCTION_TAZ_MISSING_HELP);
127  } else {
128  viaEdges.push_back(viaSink);
129  }
130  }
131  } else {
132  MSEdge::parseEdgesList(attrs.getOpt<std::string>(SUMO_ATTR_VIA, myVehicleParameter->id.c_str(), ok, "", true),
133  viaEdges, "for " + element + " '" + myVehicleParameter->id + "'");
134  }
135  for (const MSEdge* e : viaEdges) {
136  myActiveRoute.push_back(e);
137  myVehicleParameter->via.push_back(e->getID());
138  }
139 
140  // to-attributes
141  if ((useTaz || !attrs.hasAttribute(SUMO_ATTR_TO)) &&
143  const bool useJunction = attrs.hasAttribute(SUMO_ATTR_TOJUNCTION);
144  const std::string tazType = useJunction ? "junction" : "taz";
145  const std::string tazID = attrs.get<std::string>(useJunction ? SUMO_ATTR_TOJUNCTION : SUMO_ATTR_TO_TAZ, myVehicleParameter->id.c_str(), ok, true);
146  const MSEdge* toTaz = MSEdge::dictionary(tazID + "-sink");
147  if (toTaz == nullptr) {
148  throw ProcessError("Sink " + tazType + " '" + tazID + "' not known for " + element + " '" + myVehicleParameter->id + "'!"
149  + (useJunction ? JUNCTION_TAZ_MISSING_HELP : ""));
150  } else if (toTaz->getNumPredecessors() == 0 && tag != SUMO_TAG_PERSON) {
151  throw ProcessError("Sink " + tazType + " '" + tazID + "' has no incoming edges for " + element + " '" + myVehicleParameter->id + "'!");
152  } else {
153  myActiveRoute.push_back(toTaz);
154  }
155  } else {
156  MSEdge::parseEdgesList(attrs.getOpt<std::string>(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok, "", true),
157  myActiveRoute, "for " + element + " '" + myVehicleParameter->id + "'");
158  }
160  if (myVehicleParameter->routeid == "") {
162  }
163 }
164 
165 
166 void
168  const SUMOSAXAttributes& attrs) {
170  && (element == SUMO_TAG_WALK || element == SUMO_TAG_PERSONTRIP || element == SUMO_TAG_STOP)) {
171  throw ProcessError("Triggered departure for person '" + myVehicleParameter->id + "' requires starting with a ride.");
172  }
173  SUMORouteHandler::myStartElement(element, attrs);
174  try {
175  switch (element) {
176  case SUMO_TAG_PERSON:
177  case SUMO_TAG_PERSONFLOW:
178  if (!MSNet::getInstance()->getVehicleControl().hasVType(myVehicleParameter->vtypeid)) {
179  const std::string error = "The type '" + myVehicleParameter->vtypeid + "' for person '" + myVehicleParameter->id + "' is not known.";
180  delete myVehicleParameter;
181  myVehicleParameter = nullptr;
182  throw ProcessError(error);
183  }
185  break;
186  case SUMO_TAG_CONTAINER:
188  break;
189  case SUMO_TAG_TRANSHIP: {
190  myActiveRoute.clear();
191  bool ok = true;
192  double departPos = attrs.getOpt<double>(SUMO_ATTR_DEPARTPOS, myVehicleParameter->id.c_str(), ok, 0);
193  double arrivalPos = attrs.getOpt<double>(SUMO_ATTR_ARRIVALPOS, myVehicleParameter->id.c_str(), ok, -NUMERICAL_EPS);
194  double speed = DEFAULT_CONTAINER_TRANSHIP_SPEED;
196  // need to check for explicitly set speed since we might have // DEFAULT_VEHTYPE
197  if (vtype != nullptr && vtype->wasSet(VTYPEPARS_MAXSPEED_SET)) {
198  speed = vtype->getMaxSpeed();
199  }
200  speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, speed);
201  if (speed <= 0) {
202  throw ProcessError("Non-positive tranship speed for container '" + myVehicleParameter->id + "'.");
203  }
204  std::string csID = attrs.getOpt<std::string>(SUMO_ATTR_CONTAINER_STOP, nullptr, ok, "");
205  MSStoppingPlace* cs = nullptr;
206  if (csID != "") {
208  if (cs == nullptr) {
209  throw ProcessError("Unknown container stop '" + csID + "' for container '" + myVehicleParameter->id + "'.");
210  }
211  arrivalPos = cs->getEndLanePosition();
212  }
213  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
215  } else {
216  if (attrs.hasAttribute(SUMO_ATTR_FROM) && attrs.hasAttribute(SUMO_ATTR_TO)) {
217  const std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok);
218  MSEdge* from = MSEdge::dictionary(fromID);
219  if (from == nullptr) {
220  throw ProcessError("The from edge '" + fromID + "' within a tranship of container '" + myVehicleParameter->id + "' is not known.");
221  }
222  const std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok);
223  MSEdge* to = MSEdge::dictionary(toID);
224  if (to == nullptr) {
225  throw ProcessError("The to edge '" + toID + "' within a tranship of container '" + myVehicleParameter->id + "' is not known.");
226  }
227  //the route of the container's tranship stage consists only of the 'from' and the 'to' edge
228  myActiveRoute.push_back(from);
229  myActiveRoute.push_back(to);
230  if (myActiveRoute.empty()) {
231  const std::string error = "No connection found between '" + from->getID() + "' and '" + to->getID() + "' for container '" + myVehicleParameter->id + "'.";
233  myActiveRoute.push_back(from);
234  } else {
236  }
237  }
238  }
239  }
240  if (myActiveRoute.empty()) {
241  throw ProcessError("No edges to tranship container '" + myVehicleParameter->id + "'.");
242  }
243  if (!myActiveContainerPlan->empty() && myActiveContainerPlan->back()->getDestination() != myActiveRoute.front()) {
244  throw ProcessError("Disconnected plan for container '" + myVehicleParameter->id + "' (" + myActiveRoute.front()->getID() + "!=" + myActiveContainerPlan->back()->getDestination()->getID() + ").");
245  }
246  if (myActiveContainerPlan->empty()) {
247  myActiveContainerPlan->push_back(new MSStageWaiting(
248  myActiveRoute.front(), nullptr, -1, myVehicleParameter->depart, departPos, "start", true));
249  }
250  myActiveContainerPlan->push_back(new MSStageTranship(myActiveRoute, cs, speed, departPos, arrivalPos));
251  myActiveRoute.clear();
252  break;
253  }
254  case SUMO_TAG_FLOW:
255  parseFromViaTo((SumoXMLTag)element, attrs);
256  break;
257  case SUMO_TAG_TRIP:
258  parseFromViaTo((SumoXMLTag)element, attrs);
259  break;
260  default:
261  break;
262  }
263  } catch (ProcessError&) {
264  delete myVehicleParameter;
265  myVehicleParameter = nullptr;
266  throw;
267  }
268 }
269 
270 
271 void
273  bool ok = true;
274  myCurrentVTypeDistributionID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
275  if (ok) {
277  if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
278  const std::string vTypes = attrs.get<std::string>(SUMO_ATTR_VTYPES, myCurrentVTypeDistributionID.c_str(), ok);
279  StringTokenizer st(vTypes);
280  while (st.hasNext()) {
281  std::string vtypeID = st.next();
283  if (type == nullptr) {
284  throw ProcessError("Unknown vtype '" + vtypeID + "' in distribution '" + myCurrentVTypeDistributionID + "'.");
285  }
287  }
288  }
289  }
290 }
291 
292 
293 void
295  if (myCurrentVTypeDistribution != nullptr) {
296  if (MSGlobals::gStateLoaded && MSNet::getInstance()->getVehicleControl().hasVTypeDistribution(myCurrentVTypeDistributionID)) {
298  return;
299  }
302  throw ProcessError("Vehicle type distribution '" + myCurrentVTypeDistributionID + "' is empty.");
303  }
304  if (!MSNet::getInstance()->getVehicleControl().addVTypeDistribution(myCurrentVTypeDistributionID, myCurrentVTypeDistribution)) {
306  throw ProcessError("Another vehicle type (or distribution) with the id '" + myCurrentVTypeDistributionID + "' exists.");
307  }
308  myCurrentVTypeDistribution = nullptr;
309  }
310 }
311 
312 
313 void
315  myActiveRoute.clear();
316  myInsertStopEdgesAt = -1;
317  // check whether the id is really necessary
318  std::string rid;
319  if (myCurrentRouteDistribution != nullptr) {
321  rid = "distribution '" + myCurrentRouteDistributionID + "'";
322  } else if (myVehicleParameter != nullptr) {
323  // ok, a vehicle is wrapping the route,
324  // we may use this vehicle's id as default
325  myActiveRouteID = "!" + myVehicleParameter->id; // !!! document this
326  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
327  WRITE_WARNING("Ids of internal routes are ignored (vehicle '" + myVehicleParameter->id + "').");
328  }
329  } else {
330  bool ok = true;
331  myActiveRouteID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok, false);
332  if (!ok) {
333  return;
334  }
335  rid = "'" + myActiveRouteID + "'";
336  }
337  if (myVehicleParameter != nullptr) { // have to do this here for nested route distributions
338  rid = "for vehicle '" + myVehicleParameter->id + "'";
339  }
340  bool ok = true;
341  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
342  MSEdge::parseEdgesList(attrs.get<std::string>(SUMO_ATTR_EDGES, myActiveRouteID.c_str(), ok), myActiveRoute, rid);
343  }
344  myActiveRouteRefID = attrs.getOpt<std::string>(SUMO_ATTR_REFID, myActiveRouteID.c_str(), ok, "");
346  WRITE_ERROR("Invalid reference to route '" + myActiveRouteRefID + "' in route " + rid + ".");
347  }
350  myActiveRouteRepeat = attrs.getOpt<int>(SUMO_ATTR_REPEAT, myActiveRouteID.c_str(), ok, 0);
352  // handle obsolete attribute name
354  if (attrs.hasAttribute(SUMO_ATTR_PERIOD)) {
355  WRITE_WARNING("Attribute 'period' is deprecated for route. Use 'cycleTime' instead.");
356  }
357  if (myActiveRouteRepeat > 0) {
360  if (myVehicleParameter != nullptr) {
363  if (vtype != nullptr) {
364  vClass = vtype->getVehicleClass();
365  }
366  }
367  if (myActiveRoute.size() > 0 && !myActiveRoute.back()->isConnectedTo(*myActiveRoute.front(), vClass)) {
368  WRITE_ERROR("Disconnected route " + rid + " when repeating.");
369  }
370  }
371  }
372  myCurrentCosts = attrs.getOpt<double>(SUMO_ATTR_COST, myActiveRouteID.c_str(), ok, -1);
373  if (ok && myCurrentCosts != -1 && myCurrentCosts < 0) {
374  WRITE_ERROR("Invalid cost for route '" + myActiveRouteID + "'.");
375  }
376 }
377 
378 
379 void
381  // Currently unused
382 }
383 
384 
385 void
387  // Currently unused
388 }
389 
390 
391 void
393  // Currently unsued
394 }
395 
396 
397 void
398 MSRouteHandler::closeRoute(const bool mayBeDisconnected) {
399  std::string type = "vehicle";
400  if (mayBeDisconnected) {
402  type = "flow";
403  } else {
404  type = "trip";
405  }
406  }
407 
408  try {
409  const bool mustReroute = myActiveRoute.size() == 0 && myActiveRouteStops.size() != 0;
410  if (mustReroute) {
411  // implicit route from stops
412  for (const SUMOVehicleParameter::Stop& stop : myActiveRouteStops) {
413  myActiveRoute.push_back(MSEdge::dictionary(stop.edge));
414  }
415  }
416  if (myActiveRoute.size() == 0) {
417  delete myActiveRouteColor;
418  myActiveRouteColor = nullptr;
419  if (myActiveRouteRefID != "" && myCurrentRouteDistribution != nullptr) {
421  if (route != nullptr) {
423  route->addReference();
424  }
425  }
426  myActiveRouteID = "";
427  myActiveRouteRefID = "";
428  return;
429  }
430  if (myVehicleParameter != nullptr) {
431  throw ProcessError("The route for " + type + " '" + myVehicleParameter->id + "' has no edges.");
432  } else {
433  throw ProcessError("Route '" + myActiveRouteID + "' has no edges.");
434  }
435  }
436  if (myActiveRoute.size() == 1 && myActiveRoute.front()->isTazConnector()) {
437  throw ProcessError("The routing information for " + type + " '" + myVehicleParameter->id + "' is insufficient.");
438  }
439  if (myActiveRouteRepeat > 0) {
440  // duplicate route
441  ConstMSEdgeVector tmpEdges = myActiveRoute;
442  auto tmpStops = myActiveRouteStops;
443  for (int i = 0; i < myActiveRouteRepeat; i++) {
444  myActiveRoute.insert(myActiveRoute.begin(), tmpEdges.begin(), tmpEdges.end());
445  for (SUMOVehicleParameter::Stop stop : tmpStops) {
446  if (stop.until > 0) {
447  if (myActiveRoutePeriod <= 0) {
448  const std::string description = myVehicleParameter != nullptr
449  ? "for " + type + " '" + myVehicleParameter->id + "'"
450  : "'" + myActiveRouteID + "'";
451  throw ProcessError("Cannot repeat stops with 'until' in route " + description + " because no cycleTime is defined.");
452  }
453  stop.until += myActiveRoutePeriod * (i + 1);
454  }
455  if (stop.arrival > 0) {
456  if (myActiveRoutePeriod <= 0) {
457  const std::string description = myVehicleParameter != nullptr
458  ? "for " + type + " '" + myVehicleParameter->id + "'"
459  : "'" + myActiveRouteID + "'";
460  throw ProcessError("Cannot repeat stops with 'arrival' in route " + description + " because no cycleTime is defined.");
461  }
462  stop.arrival += myActiveRoutePeriod * (i + 1);
463  }
464  myActiveRouteStops.push_back(stop);
465  }
466  }
467  }
472  route->setCosts(myCurrentCosts);
473  route->setReroute(mustReroute);
474  myActiveRoute.clear();
475  if (!MSRoute::dictionary(myActiveRouteID, route)) {
476  delete route;
478  if (myVehicleParameter != nullptr) {
479  if (MSNet::getInstance()->getVehicleControl().getVehicle(myVehicleParameter->id) == nullptr) {
480  throw ProcessError("Another route for " + type + " '" + myVehicleParameter->id + "' exists.");
481  } else {
482  throw ProcessError("A vehicle with id '" + myVehicleParameter->id + "' already exists.");
483  }
484  } else {
485  throw ProcessError("Another route (or distribution) with the id '" + myActiveRouteID + "' exists.");
486  }
487  }
488  } else {
489  if (myCurrentRouteDistribution != nullptr) {
491  route->addReference();
492  }
493  }
494  }
495  myActiveRouteID = "";
496  myActiveRouteColor = nullptr;
497  myActiveRouteStops.clear();
498  } catch (ProcessError&) {
499  delete myVehicleParameter;
500  throw;
501  }
502 }
503 
504 
505 void
507  // check whether the id is really necessary
508  if (myVehicleParameter != nullptr) {
509  // ok, a vehicle is wrapping the route,
510  // we may use this vehicle's id as default
511  myCurrentRouteDistributionID = "!" + myVehicleParameter->id; // !!! document this
512  } else {
513  bool ok = true;
514  myCurrentRouteDistributionID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
515  if (!ok) {
516  return;
517  }
518  }
520  std::vector<double> probs;
521  if (attrs.hasAttribute(SUMO_ATTR_PROBS)) {
522  bool ok = true;
523  StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_PROBS, myCurrentRouteDistributionID.c_str(), ok));
524  while (st.hasNext()) {
525  probs.push_back(StringUtils::toDoubleSecure(st.next(), 1.0));
526  }
527  }
528  if (attrs.hasAttribute(SUMO_ATTR_ROUTES)) {
529  bool ok = true;
530  StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_ROUTES, myCurrentRouteDistributionID.c_str(), ok));
531  int probIndex = 0;
532  while (st.hasNext()) {
533  std::string routeID = st.next();
534  const MSRoute* route = MSRoute::dictionary(routeID, &myParsingRNG);
535  if (route == nullptr) {
536  throw ProcessError("Unknown route '" + routeID + "' in distribution '" + myCurrentRouteDistributionID + "'.");
537  }
538  const double prob = ((int)probs.size() > probIndex ? probs[probIndex] : 1.0);
539  if (myCurrentRouteDistribution->add(route, prob, false)) {
540  route->addReference();
541  }
542  probIndex++;
543  }
544  if (probs.size() > 0 && probIndex != (int)probs.size()) {
545  WRITE_WARNING("Got " + toString(probs.size()) + " probabilities for " + toString(probIndex) +
546  " routes in routeDistribution '" + myCurrentRouteDistributionID + "'");
547  }
548  }
549 }
550 
551 
552 void
554  if (myCurrentRouteDistribution != nullptr) {
555  const bool haveSameID = MSRoute::dictionary(myCurrentRouteDistributionID, &myParsingRNG) != nullptr;
556  if (MSGlobals::gStateLoaded && haveSameID) {
558  myCurrentRouteDistribution = nullptr;
559  return;
560  }
561  if (haveSameID) {
563  throw ProcessError("Another route (or distribution) with the id '" + myCurrentRouteDistributionID + "' exists.");
564  }
567  throw ProcessError("Route distribution '" + myCurrentRouteDistributionID + "' is empty.");
568  }
570  myCurrentRouteDistribution = nullptr;
571  }
572 }
573 
574 
575 void
577  // get nested route
581  // let's check whether this vehicle had to depart before the simulation starts
583  if (route != nullptr) {
584  route->addReference();
585  route->release();
586  }
587  return;
588  }
589  }
590 
591  // get the vehicle's type
592  MSVehicleType* vtype = nullptr;
593 
594  try {
595  if (myVehicleParameter->vtypeid != "") {
596  vtype = vehControl.getVType(myVehicleParameter->vtypeid, &myParsingRNG);
597  if (vtype == nullptr) {
598  throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
599  }
600  if (vtype->getVehicleClass() == SVC_PEDESTRIAN) {
601  WRITE_WARNING("Vehicle type '" + vtype->getID() + "' with vClass=pedestrian should only be used for persons and not for vehicle '" + myVehicleParameter->id + "'.");
602  }
603  } else {
604  // there should be one (at least the default one)
605  vtype = vehControl.getVType(DEFAULT_VTYPE_ID, &myParsingRNG);
606  }
608  // if the route id was given, prefer that one
609  if (route != nullptr && !myAmLoadingState) {
610  WRITE_WARNING("Ignoring child element 'route' for vehicle '" + myVehicleParameter->id + "' because attribute 'route' is set.");
611  }
613  }
614  if (route == nullptr) {
615  // nothing found? -> error
616  if (myVehicleParameter->routeid != "") {
617  throw ProcessError("The route '" + myVehicleParameter->routeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
618  } else {
619  throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has no route.");
620  }
621  }
622  myActiveRouteID = "";
623 
624  } catch (ProcessError&) {
625  delete myVehicleParameter;
626  throw;
627  }
628  if (route->mustReroute()) {
630  if (myVehicleParameter->stops.size() > 0) {
631  route = addVehicleStopsToImplicitRoute(route, false);
632  }
633  }
636  WRITE_WARNING("Ignoring attribute '" + toString(SUMO_ATTR_DEPARTEDGE) + "' for vehicle '" + myVehicleParameter->id + "' because the route is computed dynamically.");
638  myVehicleParameter->departEdge >= (int)route->getEdges().size()) {
639  throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has invalid departEdge index "
640  + toString(myVehicleParameter->departEdge) + " for route with " + toString(route->getEdges().size()) + " edges.");
641  }
642  }
643 
644  // try to build the vehicle
645  SUMOVehicle* vehicle = nullptr;
646  if (vehControl.getVehicle(myVehicleParameter->id) == nullptr) {
647  try {
648  vehicle = vehControl.buildVehicle(myVehicleParameter, route, vtype, !MSGlobals::gCheckRoutes);
649  } catch (const ProcessError& e) {
651  WRITE_WARNING(e.what());
652  vehControl.fixVehicleCounts();
653  myVehicleParameter = nullptr;
654  vehicle = nullptr;
655  return;
656  } else {
657  throw e;
658  }
659  }
660  const SUMOTime origDepart = myVehicleParameter->depart;
661  // maybe we do not want this vehicle to be inserted due to scaling
662  int quota = myAmLoadingState ? 1 : vehControl.getQuota();
663  if (quota > 0) {
666  vehControl.addVehicle(myVehicleParameter->id, vehicle);
667  for (int i = 1; i < quota; i++) {
668  if (vehicle->getParameter().departProcedure == DEPART_GIVEN) {
670  }
672  newPars->id = myVehicleParameter->id + "." + toString(i);
674  vehicle = vehControl.buildVehicle(newPars, route, vtype, !MSGlobals::gCheckRoutes);
675  vehControl.addVehicle(newPars->id, vehicle);
676  }
677  myVehicleParameter = nullptr;
678  } else {
679  vehControl.deleteVehicle(vehicle, true);
680  myVehicleParameter = nullptr;
681  vehicle = nullptr;
682  }
683  } else {
684  // strange: another vehicle with the same id already exists
686  // and was not loaded while loading a simulation state
687  // -> error
688  std::string veh_id = myVehicleParameter->id;
689  delete myVehicleParameter;
690  myVehicleParameter = nullptr;
691  throw ProcessError("Another vehicle with the id '" + veh_id + "' exists.");
692  } else {
693  // ok, it seems to be loaded previously while loading a simulation state
694  vehicle = nullptr;
695  }
696  }
697  // check whether the vehicle shall be added directly to the network or
698  // shall stay in the internal buffer
699  if (vehicle != nullptr) {
700  if (vehicle->getParameter().departProcedure == DEPART_GIVEN) {
702  }
703  }
704 }
705 
706 
707 MSRoute*
709  // the route was defined without edges and its current edges were
710  // derived from route-stops.
711  // We may need to add additional edges for the vehicle-stops
713  assert(route->getStops().size() > 0);
714  ConstMSEdgeVector edges = route->getEdges();
716  MSEdge* stopEdge = MSEdge::dictionary(stop.edge);
717  if (stop.index == 0) {
718  if (edges.front() != stopEdge ||
719  route->getStops().front().endPos < stop.endPos) {
720  edges.insert(edges.begin(), stopEdge);
721  }
722  } else if (stop.index == STOP_INDEX_END) {
723  if (edges.back() != stopEdge ||
724  route->getStops().back().endPos > stop.endPos) {
725  edges.push_back(stopEdge);
726  }
727  } else {
728  WRITE_WARNING("Could not merge vehicle stops for vehicle '" + myVehicleParameter->id + "' into implicitly defined route '" + route->getID() + "'");
729  }
730  }
731  MSRoute* newRoute = new MSRoute("!" + myVehicleParameter->id, edges,
732  isPermanent, new RGBColor(route->getColor()), route->getStops());
733  if (!MSRoute::dictionary(newRoute->getID(), newRoute)) {
734  delete newRoute;
735  throw ProcessError("Could not adapt implicit route for " + std::string(isPermanent ? "flow" : "vehicle") + " '" + myVehicleParameter->id + "'");
736  }
737  return newRoute;
738 }
739 
740 
741 void
743  if (myActivePlan->size() == 0) {
744  const std::string error = "Person '" + myVehicleParameter->id + "' has no plan.";
745  delete myVehicleParameter;
746  myVehicleParameter = nullptr;
748  throw ProcessError(error);
749  }
750  // let's check whether this person had to depart before the simulation starts
753  delete myVehicleParameter;
754  myVehicleParameter = nullptr;
756  return;
757  }
758  // type existence has been checked on opening
762  myVehicleParameter = nullptr;
763  myActivePlan = nullptr;
764 }
765 
766 
767 void
769  if (myActivePlan->size() == 0) {
770  const std::string error = "personFlow '" + myVehicleParameter->id + "' has no plan.";
771  delete myVehicleParameter;
772  myVehicleParameter = nullptr;
774  throw ProcessError(error);
775  }
776  // let's check whether this person had to depart before the simulation starts
779  delete myVehicleParameter;
780  myVehicleParameter = nullptr;
782  return;
783  }
784  // type existence has been checked on opening
786  // instantiate all persons of this flow
787  int i = 0;
789  std::string baseID = myVehicleParameter->id;
792  throw ProcessError("probabilistic personFlow '" + myVehicleParameter->id + "' must specify end time");
793  } else {
794  for (SUMOTime t = myVehicleParameter->depart; t < myVehicleParameter->repetitionEnd; t += TIME2STEPS(1)) {
796  addFlowPerson(t, type, baseID, i++);
797  }
798  }
799  }
800  } else {
802  for (; i < myVehicleParameter->repetitionNumber; i++) {
803  addFlowPerson(depart, type, baseID, i);
805  }
806  }
807 
808  myVehicleParameter = nullptr;
809  myActivePlan = nullptr;
810 }
811 
812 
813 void
814 MSRouteHandler::addFlowPerson(SUMOTime depart, MSVehicleType* type, const std::string& baseID, int i) {
815  MSNet* const net = MSNet::getInstance();
817  const int quota = MSNet::getInstance()->getVehicleControl().getQuota(-1, pc.getLoadedNumber());
818  if (quota == 0) {
819  pc.addDiscarded();
820  }
821  for (int j = 0; j < quota; j++) {
822  if (i > 0 || j > 0) {
823  // copy parameter and plan because the person takes over responsibility
824  SUMOVehicleParameter* copyParam = new SUMOVehicleParameter();
825  *copyParam = *myVehicleParameter;
826  myVehicleParameter = copyParam;
828  for (MSStage* s : *myActivePlan) {
829  copyPlan->push_back(s->clone());
830  }
831  myActivePlan = copyPlan;
833  const double initialDepartPos = RandHelper::rand(myActivePlan->front()->getDestination()->getLength(), &myParsingRNG);
834  myActivePlan->front()->setArrivalPos(initialDepartPos);
835  }
836  }
837  myVehicleParameter->id = (baseID
838  + (i >= 0 ? "." + toString(i) : "")
839  + (j > 0 ? "." + toString(j) : ""));
842  if (!pc.add(person)) {
843  ProcessError error("Another person with the id '" + myVehicleParameter->id + "' exists.");
844  delete person;
846  throw error;
847  }
848  } else if (net->hasContainers() && net->getContainerControl().get(myVehicleParameter->id) != nullptr) {
849  WRITE_WARNINGF("A person has the same id as container '%'. Starting with SUMO 1.9.0 this will be an error.", myVehicleParameter->id);
850  }
851  }
852 }
853 
854 
855 void
858  if (!MSNet::getInstance()->getVehicleControl().addVType(vehType)) {
859  const std::string id = vehType->getID();
860  delete vehType;
862  throw ProcessError("Another vehicle type (or distribution) with the id '" + id + "' exists.");
863  }
864  } else {
865  if (myCurrentVTypeDistribution != nullptr) {
867  }
868  }
869 }
870 
871 
872 void
874  if (myActiveContainerPlan->size() == 0) {
875  throw ProcessError("Container '" + myVehicleParameter->id + "' has no plan.");
876  }
877  MSNet* const net = MSNet::getInstance();
879  if (type == nullptr) {
880  throw ProcessError("The type '" + myVehicleParameter->vtypeid + "' for container '" + myVehicleParameter->id + "' is not known.");
881  }
883  // @todo: consider myScale?
885  if (net->getContainerControl().add(container)) {
886  if (net->hasPersons() && net->getPersonControl().get(myVehicleParameter->id) != nullptr) {
887  WRITE_WARNINGF("A container has the same id as person '%'. Starting with SUMO 1.9.0 this will be an error.", myVehicleParameter->id);
888  }
890  } else {
891  ProcessError error("Another container with the id '" + myVehicleParameter->id + "' exists.");
892  delete container;
893  throw error;
894  }
895  } else {
896  // warning already given
897  delete container;
898  }
899  myVehicleParameter = nullptr;
900  myActiveContainerPlan = nullptr;
901 }
902 
903 
904 void
906  myInsertStopEdgesAt = -1;
908  delete myVehicleParameter;
909  myVehicleParameter = nullptr;
910  return;
911  }
912  // let's check whether vehicles had to depart before the simulation starts
915  const SUMOTime offsetToBegin = string2time(OptionsCont::getOptions().getString("begin")) - myVehicleParameter->depart;
919  delete myVehicleParameter;
920  myVehicleParameter = nullptr;
921  return;
922  }
923  }
924  }
925  if (MSNet::getInstance()->getVehicleControl().getVType(myVehicleParameter->vtypeid, &myParsingRNG) == nullptr) {
926  throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for flow '" + myVehicleParameter->id + "' is not known.");
927  }
930  closeRoute(true);
931  }
933  if (route == nullptr) {
934  throw ProcessError("The route '" + myVehicleParameter->routeid + "' for flow '" + myVehicleParameter->id + "' is not known.");
935  }
936  if (route->mustReroute()) {
938  if (myVehicleParameter->stops.size() > 0) {
939  route = addVehicleStopsToImplicitRoute(route, true);
940  myVehicleParameter->routeid = route->getID();
941  }
942  }
943  myActiveRouteID = "";
944 
945  // check whether the vehicle shall be added directly to the network or
946  // shall stay in the internal buffer
948  if (MSNet::getInstance()->getInsertionControl().addFlow(myVehicleParameter)) {
950  } else {
951  throw ProcessError("Another flow with the id '" + myVehicleParameter->id + "' exists.");
952  }
953  }
954  myVehicleParameter = nullptr;
955 }
956 
957 
958 void
961  closeRoute(true);
962  closeVehicle();
963 }
964 
965 void
967  if (myActivePlan == nullptr) {
968  throw ProcessError("Found ride outside person element");
969  }
970  const std::string pid = myVehicleParameter->id;
971  bool ok = true;
972  MSEdge* from = nullptr;
973  const std::string desc = attrs.get<std::string>(SUMO_ATTR_LINES, pid.c_str(), ok);
974  StringTokenizer st(desc);
975  std::string bsID = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
976  MSStoppingPlace* bs = nullptr;
977  MSEdge* to = nullptr;
978  if (bsID != "") {
980  if (bs == nullptr) {
981  throw ProcessError("Unknown bus stop '" + bsID + "' for person '" + myVehicleParameter->id + "'.");
982  }
983  to = &bs->getLane().getEdge();
984  }
985  double arrivalPos = attrs.getOpt<double>(SUMO_ATTR_ARRIVALPOS, myVehicleParameter->id.c_str(), ok,
986  bs == nullptr ? std::numeric_limits<double>::infinity() : bs->getEndLanePosition());
987 
988  SUMOVehicle* startVeh = nullptr;
990  if (st.size() != 1) {
991  throw ProcessError("Triggered departure for person '" + pid + "' requires a unique lines value.");
992  }
993  // person starts
995  const std::string vehID = st.front();
996  startVeh = vehControl.getVehicle(vehID);
997  if (startVeh == nullptr) {
998  throw ProcessError("Unknown vehicle '" + vehID + "' in triggered departure for person '" + pid + "'.");
999  }
1000  if (startVeh->getParameter().departProcedure == DEPART_TRIGGERED) {
1001  throw ProcessError("Cannot use triggered vehicle '" + vehID + "' in triggered departure for person '" + pid + "'.");
1002  }
1003  myVehicleParameter->depart = startVeh->getParameter().depart;
1004  }
1005 
1006  if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
1007  const std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, pid.c_str(), ok);
1008  from = MSEdge::dictionary(fromID);
1009  if (from == nullptr) {
1010  throw ProcessError("The from edge '" + fromID + "' within a ride of person '" + pid + "' is not known.");
1011  }
1012  if (!myActivePlan->empty() && myActivePlan->back()->getDestination() != from) {
1013  const bool stopWithAccess = (myActivePlan->back()->getDestinationStop() != nullptr
1014  && &myActivePlan->back()->getDestinationStop()->getLane().getEdge() == from);
1015  const bool transferAtJunction = (from->getFromJunction() == myActivePlan->back()->getDestination()->getFromJunction()
1016  || from->getFromJunction() == myActivePlan->back()->getDestination()->getToJunction());
1017  if (!(stopWithAccess || transferAtJunction)) {
1018  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id +
1019  "' (edge '" + fromID + "' != edge '" + myActivePlan->back()->getDestination()->getID() + "').");
1020  }
1021  }
1022  if (startVeh != nullptr && startVeh->getRoute().getEdges().front() != from) {
1023  throw ProcessError("Disconnected plan for triggered person '" + pid +
1024  "' (edge '" + fromID + "' != edge '" + startVeh->getRoute().getEdges().front()->getID() + "').");
1025  }
1026  if (myActivePlan->empty()) {
1027  myActivePlan->push_back(new MSStageWaiting(
1028  from, nullptr, -1, myVehicleParameter->depart, myVehicleParameter->departPos, "start", true));
1029  }
1030  } else if (myActivePlan->empty()) {
1031  throw ProcessError("The start edge for person '" + pid + "' is not known.");
1032  }
1033  if (to == nullptr) {
1034  const std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, pid.c_str(), ok);
1035  to = MSEdge::dictionary(toID);
1036  if (to == nullptr) {
1037  throw ProcessError("The to edge '" + toID + "' within a ride of person '" + pid + "' is not known.");
1038  }
1039  }
1040  const std::string group = attrs.getOpt<std::string>(SUMO_ATTR_GROUP, pid.c_str(), ok, getDefaultGroup(pid));
1041  const std::string intendedVeh = attrs.getOpt<std::string>(SUMO_ATTR_INTENDED, nullptr, ok, "");
1042  const SUMOTime intendedDepart = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DEPART, nullptr, ok, -1);
1043  arrivalPos = SUMOVehicleParameter::interpretEdgePos(arrivalPos, to->getLength(), SUMO_ATTR_ARRIVALPOS, "person '" + pid + "' riding to edge '" + to->getID() + "'");
1044  myActivePlan->push_back(new MSStageDriving(from, to, bs, arrivalPos, st.getVector(), group, intendedVeh, intendedDepart));
1045 }
1046 
1047 void
1049  if (myActiveContainerPlan == nullptr) {
1050  throw ProcessError("Found transport outside container element");
1051  }
1052  try {
1053  const std::string containerId = myVehicleParameter->id;
1054  bool ok = true;
1055  MSEdge* from = nullptr;
1056  const std::string desc = attrs.get<std::string>(SUMO_ATTR_LINES, containerId.c_str(), ok);
1057  StringTokenizer st(desc);
1058  std::string csID = attrs.getOpt<std::string>(SUMO_ATTR_CONTAINER_STOP, nullptr, ok, "");
1059  MSStoppingPlace* cs = nullptr;
1060  if (csID != "") {
1062  if (cs == nullptr) {
1063  throw ProcessError("Unknown container stop '" + csID + "' for container '" + myVehicleParameter->id + "'.");
1064  }
1065  }
1066  double arrivalPos = attrs.getOpt<double>(SUMO_ATTR_ARRIVALPOS, myVehicleParameter->id.c_str(), ok,
1067  cs == nullptr ? std::numeric_limits<double>::infinity() : cs->getEndLanePosition());
1068  if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
1069  const std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, containerId.c_str(), ok);
1070  from = MSEdge::dictionary(fromID);
1071  if (from == nullptr) {
1072  throw ProcessError("The from edge '" + fromID + "' within a transport of container '" + containerId + "' is not known.");
1073  }
1074  if (!myActiveContainerPlan->empty() && myActiveContainerPlan->back()->getDestination() != from) {
1075  throw ProcessError("Disconnected plan for container '" + myVehicleParameter->id + "' (" + fromID + "!=" + myActiveContainerPlan->back()->getDestination()->getID() + ").");
1076  }
1077 
1078  if (!myActiveContainerPlan->empty() && myActiveContainerPlan->back()->getDestination() != from) {
1079  const bool stopWithAccess = (myActiveContainerPlan->back()->getDestinationStop() != nullptr
1080  && &myActiveContainerPlan->back()->getDestinationStop()->getLane().getEdge() == from);
1081  const bool transferAtJunction = (from->getFromJunction() == myActiveContainerPlan->back()->getDestination()->getFromJunction()
1082  || from->getFromJunction() == myActiveContainerPlan->back()->getDestination()->getToJunction());
1083  if (!(stopWithAccess || transferAtJunction)) {
1084  throw ProcessError("Disconnected plan for container '" + myVehicleParameter->id +
1085  "' (edge '" + fromID + "' != edge '" + myActiveContainerPlan->back()->getDestination()->getID() + "').");
1086  }
1087  }
1088 
1089  if (myActiveContainerPlan->empty()) {
1090  myActiveContainerPlan->push_back(new MSStageWaiting(
1091  from, nullptr, -1, myVehicleParameter->depart, myVehicleParameter->departPos, "start", true));
1092  }
1093  } else if (myActiveContainerPlan->empty()) {
1094  throw ProcessError("The start edge within a transport of container '" + containerId + "' is not known.");
1095  }
1096  const std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, containerId.c_str(), ok);
1097  MSEdge* to = MSEdge::dictionary(toID);
1098  if (to == nullptr) {
1099  throw ProcessError("The to edge '" + toID + "' within a transport of container '" + containerId + "' is not known.");
1100  }
1101  arrivalPos = SUMOVehicleParameter::interpretEdgePos(arrivalPos, to->getLength(), SUMO_ATTR_ARRIVALPOS, "transport of container '" + containerId + "' to edge '" + to->getID() + "'");
1102  myActiveContainerPlan->push_back(new MSStageDriving(from, to, cs, arrivalPos, st.getVector()));
1103  } catch (ProcessError&) {
1105  throw;
1106  }
1107 }
1108 
1109 
1110 
1111 void
1113  std::string errorSuffix;
1114  if (myActivePlan != nullptr) {
1115  errorSuffix = " in person '" + myVehicleParameter->id + "'.";
1116  } else if (myActiveContainerPlan != nullptr) {
1117  errorSuffix = " in container '" + myVehicleParameter->id + "'.";
1118  } else if (myVehicleParameter != nullptr) {
1119  errorSuffix = " in vehicle '" + myVehicleParameter->id + "'.";
1120  } else {
1121  errorSuffix = " in route '" + myActiveRouteID + "'.";
1122  }
1124  bool ok = parseStop(stop, attrs, errorSuffix, MsgHandler::getErrorInstance());
1125  if (!ok) {
1126  return;
1127  }
1128  const MSEdge* edge = nullptr;
1129  MSStoppingPlace* toStop = nullptr;
1130  // try to parse the assigned bus stop
1131  if (stop.busstop != "") {
1132  // ok, we have a bus stop
1134  if (bs == nullptr) {
1135  WRITE_ERROR("The busStop '" + stop.busstop + "' is not known" + errorSuffix);
1136  return;
1137  }
1138  toStop = bs;
1139  const MSLane& l = bs->getLane();
1140  stop.lane = l.getID();
1141  stop.endPos = bs->getEndLanePosition();
1142  stop.startPos = bs->getBeginLanePosition();
1143  edge = &l.getEdge();
1144  } //try to parse the assigned container stop
1145  else if (stop.containerstop != "") {
1146  // ok, we have obviously a container stop
1148  if (cs == nullptr) {
1149  WRITE_ERROR("The containerStop '" + stop.containerstop + "' is not known" + errorSuffix);
1150  return;
1151  }
1152  toStop = cs;
1153  const MSLane& l = cs->getLane();
1154  stop.lane = l.getID();
1155  stop.endPos = cs->getEndLanePosition();
1156  stop.startPos = cs->getBeginLanePosition();
1157  edge = &l.getEdge();
1158  } //try to parse the assigned parking area
1159  else if (stop.parkingarea != "") {
1160  // ok, we have obviously a parking area
1162  if (pa == nullptr) {
1163  WRITE_ERROR("The parkingArea '" + stop.parkingarea + "' is not known" + errorSuffix);
1164  return;
1165  }
1166  toStop = pa;
1167  const MSLane& l = pa->getLane();
1168  stop.lane = l.getID();
1169  stop.endPos = pa->getEndLanePosition();
1170  stop.startPos = pa->getBeginLanePosition();
1171  edge = &l.getEdge();
1172  } else if (stop.chargingStation != "") {
1173  // ok, we have a charging station
1175  if (cs == nullptr) {
1176  WRITE_ERROR("The chargingStation '" + stop.chargingStation + "' is not known" + errorSuffix);
1177  return;
1178  }
1179  toStop = cs;
1180  const MSLane& l = cs->getLane();
1181  stop.lane = l.getID();
1182  stop.endPos = cs->getEndLanePosition();
1183  stop.startPos = cs->getBeginLanePosition();
1184  edge = &l.getEdge();
1185  } else if (stop.overheadWireSegment != "") {
1186  // ok, we have an overhead wire segment
1188  if (ows == nullptr) {
1189  WRITE_ERROR("The overhead wire segment '" + stop.overheadWireSegment + "' is not known" + errorSuffix);
1190  return;
1191  }
1192  toStop = ows;
1193  const MSLane& l = ows->getLane();
1194  stop.lane = l.getID();
1195  stop.endPos = ows->getEndLanePosition();
1196  stop.startPos = ows->getBeginLanePosition();
1197  edge = &l.getEdge();
1198  } else {
1199  // no, the lane and the position should be given
1200  // get the lane
1201  stop.lane = attrs.getOpt<std::string>(SUMO_ATTR_LANE, nullptr, ok, "");
1202  stop.edge = attrs.getOpt<std::string>(SUMO_ATTR_EDGE, nullptr, ok, "");
1203  if (ok && stop.edge != "") {
1204  edge = MSEdge::dictionary(stop.edge);
1205  if (edge == nullptr || (edge->isInternal() && !MSGlobals::gUsingInternalLanes)) {
1206  WRITE_ERROR("The edge '" + stop.edge + "' for a stop is not known" + errorSuffix);
1207  return;
1208  }
1209  } else if (ok && stop.lane != "") {
1210  MSLane* stopLane = MSLane::dictionary(stop.lane);
1211  if (stopLane == nullptr || (stopLane->isInternal() && !MSGlobals::gUsingInternalLanes)) {
1212  WRITE_ERROR("The lane '" + stop.lane + "' for a stop is not known" + errorSuffix);
1213  return;
1214  }
1215  edge = &stopLane->getEdge();
1216  } else {
1217  if (myActivePlan && !myActivePlan->empty()) {
1218  const MSStoppingPlace* bs = myActivePlan->back()->getDestinationStop();
1219  if (bs != nullptr) {
1220  edge = &bs->getLane().getEdge();
1221  stop.lane = bs->getLane().getID();
1222  stop.endPos = bs->getEndLanePosition();
1223  stop.startPos = bs->getBeginLanePosition();
1224  } else {
1225  edge = myActivePlan->back()->getDestination();
1226  stop.lane = edge->getLanes()[0]->getID();
1227  stop.endPos = myActivePlan->back()->getArrivalPos();
1228  stop.startPos = MAX2(0., stop.endPos - MIN_STOP_LENGTH);
1229  }
1230  } else {
1231  WRITE_ERROR("A stop must be placed on a busStop, a chargingStation, an overheadWireSegment, a containerStop, a parkingArea, an edge or a lane" + errorSuffix);
1232  return;
1233  }
1234  }
1235  stop.endPos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, nullptr, ok, edge->getLength());
1236  if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
1237  WRITE_WARNING("Deprecated attribute 'pos' in description of stop" + errorSuffix);
1238  stop.endPos = attrs.getOpt<double>(SUMO_ATTR_POSITION, nullptr, ok, stop.endPos);
1239  }
1240  stop.startPos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, nullptr, ok, MAX2(0., stop.endPos - MIN_STOP_LENGTH));
1241  if (!myAmLoadingState) {
1242  const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, nullptr, ok, false);
1243  if (!ok || (checkStopPos(stop.startPos, stop.endPos, edge->getLength(), POSITION_EPS, friendlyPos) != StopPos::STOPPOS_VALID)) {
1244  WRITE_ERROR("Invalid start or end position for stop on "
1245  + (stop.lane != ""
1246  ? ("lane '" + stop.lane)
1247  : ("edge '" + stop.edge)) + "'" + errorSuffix);
1248  return;
1249  }
1250  }
1251  }
1252  stop.edge = edge->getID();
1253  if (myActivePlan) {
1254  if (myActivePlan->empty()) {
1255  double departPos = toStop == nullptr || myVehicleParameter->wasSet(VEHPARS_DEPARTPOS_SET)
1257  : (toStop->getBeginLanePosition() + toStop->getEndLanePosition()) / 2;
1258  myActivePlan->push_back(new MSStageWaiting(
1259  edge, toStop, -1, myVehicleParameter->depart, departPos, "start", true));
1260  } else if (myActivePlan->back()->getDestination() != edge) {
1261  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + edge->getID() + "!=" + myActivePlan->back()->getDestination()->getID() + ").");
1262  } else if (myActivePlan->back()->getStageType() == MSStageType::WAITING
1264  const double start = SUMOVehicleParameter::interpretEdgePos(stop.startPos, edge->getLength(), SUMO_ATTR_STARTPOS, "stopping at " + edge->getID());
1265  const double end = SUMOVehicleParameter::interpretEdgePos(stop.endPos, edge->getLength(), SUMO_ATTR_ENDPOS, "stopping at " + edge->getID());
1266  const double prevAr = myActivePlan->back()->getArrivalPos();
1267  if (start > prevAr + NUMERICAL_EPS || end < prevAr - NUMERICAL_EPS) {
1268  WRITE_WARNING("Disconnected plan for person '" + myVehicleParameter->id
1269  + "' (stop range " + toString(start) + "-" + toString(end) + " does not cover previous arrival position " + toString(prevAr) + + ").");
1270  }
1271  }
1272  std::string actType = attrs.getOpt<std::string>(SUMO_ATTR_ACTTYPE, nullptr, ok, "waiting");
1273  double pos = (stop.startPos + stop.endPos) / 2.;
1274  if (!myActivePlan->empty()) {
1275  pos = myActivePlan->back()->getArrivalPos();
1276  }
1277  myActivePlan->push_back(new MSStageWaiting(edge, toStop, stop.duration, stop.until, pos, actType, false));
1278 
1279  } else if (myActiveContainerPlan) {
1280  if (myActiveContainerPlan->empty()) {
1281  double departPos = toStop == nullptr || myVehicleParameter->wasSet(VEHPARS_DEPARTPOS_SET)
1283  : (toStop->getBeginLanePosition() + toStop->getEndLanePosition()) / 2;
1284  myActiveContainerPlan->push_back(new MSStageWaiting(edge, toStop, -1, myVehicleParameter->depart, departPos, "start", true));
1285  } else if (myActiveContainerPlan->back()->getDestination() != edge) {
1286  throw ProcessError("Disconnected plan for container '" + myVehicleParameter->id + "' (" + edge->getID() + "!=" + myActiveContainerPlan->back()->getDestination()->getID() + ").");
1287  }
1288  std::string actType = attrs.getOpt<std::string>(SUMO_ATTR_ACTTYPE, nullptr, ok, "waiting");
1289  myActiveContainerPlan->push_back(new MSStageWaiting(edge, toStop, stop.duration, stop.until, stop.startPos, actType, false));
1290  } else if (myVehicleParameter != nullptr) {
1291  myVehicleParameter->stops.push_back(stop);
1292  } else {
1293  myActiveRouteStops.push_back(stop);
1294  }
1295  if (myInsertStopEdgesAt >= 0) {
1296  //std::cout << " myInsertStopEdgesAt=" << myInsertStopEdgesAt << " edge=" << edge->getID() << " myRoute=" << toString(myActiveRoute) << "\n";
1297  if (edge->isInternal()) {
1298  if (myInsertStopEdgesAt > 0 && *(myActiveRoute.begin() + (myInsertStopEdgesAt - 1)) != edge->getNormalBefore()) {
1301  }
1304  } else {
1305  myActiveRoute.insert(myActiveRoute.begin() + myInsertStopEdgesAt, edge);
1307  }
1308  }
1309 }
1310 
1311 
1312 void
1313 MSRouteHandler::parseWalkPositions(const SUMOSAXAttributes& attrs, const std::string& personID,
1314  const MSEdge* fromEdge, const MSEdge*& toEdge,
1315  double& departPos, double& arrivalPos, MSStoppingPlace*& bs,
1316  const MSStage* const lastStage, bool& ok) {
1317  const std::string description = "person '" + personID + "' walking from " + fromEdge->getID();
1318 
1319  if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
1320  WRITE_WARNING("The attribute departPos is no longer supported for walks, please use the person attribute, the arrivalPos of the previous step or explicit stops.");
1321  }
1322  departPos = 0.;
1323  if (lastStage != nullptr) {
1324  if (lastStage->getDestinationStop() != nullptr) {
1325  departPos = lastStage->getDestinationStop()->getAccessPos(fromEdge);
1326  } else if (lastStage->getDestination() == fromEdge) {
1327  departPos = lastStage->getArrivalPos();
1328  } else if (lastStage->getDestination()->getToJunction() == fromEdge->getToJunction()) {
1329  departPos = fromEdge->getLength();
1330  }
1331  }
1332 
1333  std::string bsID = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
1334  if (bsID != "") {
1336  if (bs == nullptr) {
1337  throw ProcessError("Unknown bus stop '" + bsID + "' for " + description + ".");
1338  }
1339  arrivalPos = bs->getAccessPos(toEdge != nullptr ? toEdge : &bs->getLane().getEdge());
1340  if (arrivalPos < 0) {
1341  throw ProcessError("Bus stop '" + bsID + "' is not connected to arrival edge '" + toEdge->getID() + "' for " + description + ".");
1342  }
1343  if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
1344  const double length = toEdge != nullptr ? toEdge->getLength() : bs->getLane().getLength();
1345  const double arrPos = SUMOVehicleParserHelper::parseWalkPos(SUMO_ATTR_ARRIVALPOS, myHardFail, description, length,
1346  attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS, description.c_str(), ok), &myParsingRNG);
1347  if (arrPos >= bs->getBeginLanePosition() && arrPos < bs->getEndLanePosition()) {
1348  arrivalPos = arrPos;
1349  } else {
1350  WRITE_WARNING("Ignoring arrivalPos for " + description + " because it is outside the given stop '" + toString(SUMO_ATTR_BUS_STOP) + "'.");
1351  arrivalPos = bs->getAccessPos(&bs->getLane().getEdge());
1352  }
1353  }
1354  } else {
1355  if (toEdge == nullptr) {
1356  throw ProcessError("No destination edge for " + description + ".");
1357  }
1358  if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
1360  attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS, description.c_str(), ok), &myParsingRNG);
1361  } else {
1362  arrivalPos = toEdge->getLength() / 2.;
1363  }
1364  }
1365 }
1366 
1367 
1368 void
1370  myActiveRoute.clear();
1371  bool ok = true;
1372  const char* const id = myVehicleParameter->id.c_str();
1373  const MSEdge* from = nullptr;
1374  const MSEdge* to = nullptr;
1376  myInsertStopEdgesAt = -1;
1378  from = myActiveRoute.front();
1379  } else if (myActivePlan->empty()) {
1380  throw ProcessError("Start edge not defined for person '" + myVehicleParameter->id + "'.");
1381  } else {
1382  from = myActivePlan->back()->getDestination();
1383  }
1385  to = myActiveRoute.back();
1386  } // else, to may also be derived from stopping place
1387 
1388  const SUMOTime duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, id, ok, -1);
1389  if (attrs.hasAttribute(SUMO_ATTR_DURATION) && duration <= 0) {
1390  throw ProcessError("Non-positive walking duration for '" + myVehicleParameter->id + "'.");
1391  }
1392 
1393  double departPos = 0;
1394  double arrivalPos = 0;
1395  MSStoppingPlace* stoppingPlace = nullptr;
1396  parseWalkPositions(attrs, myVehicleParameter->id, from, to, departPos, arrivalPos, stoppingPlace, nullptr, ok);
1397 
1398  const std::string modes = attrs.getOpt<std::string>(SUMO_ATTR_MODES, id, ok, "");
1399  const std::string group = attrs.getOpt<std::string>(SUMO_ATTR_GROUP, id, ok, getDefaultGroup(id));
1400  SVCPermissions modeSet = 0;
1401  std::string errorMsg;
1402  // try to parse person modes
1403  if (!SUMOVehicleParameter::parsePersonModes(modes, "person", id, modeSet, errorMsg)) {
1404  throw InvalidArgument(errorMsg);
1405  }
1407  const std::string types = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id, ok, "");
1408  for (StringTokenizer st(types); st.hasNext();) {
1409  const std::string vtypeid = st.next();
1410  if (vehControl.getVType(vtypeid) == nullptr) {
1411  throw InvalidArgument("The vehicle type '" + vtypeid + "' in a trip for person '" + myVehicleParameter->id + "' is not known.");
1412  }
1413  modeSet |= SVC_PASSENGER;
1414  }
1415  const double speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, id, ok, -1.);
1416  if (attrs.hasAttribute(SUMO_ATTR_SPEED) && speed <= 0) {
1417  throw ProcessError("Non-positive walking speed for '" + myVehicleParameter->id + "'.");
1418  }
1419  const double walkFactor = attrs.getOpt<double>(SUMO_ATTR_WALKFACTOR, id, ok, OptionsCont::getOptions().getFloat("persontrip.walkfactor"));
1420  const double departPosLat = attrs.getOpt<double>(SUMO_ATTR_DEPARTPOS_LAT, nullptr, ok, 0);
1421  if (ok) {
1422  if (myActivePlan->empty()) {
1423  double initialDepartPos = myVehicleParameter->departPos;
1425  initialDepartPos = RandHelper::rand(from->getLength(), &myParsingRNG);
1426  }
1427  myActivePlan->push_back(new MSStageWaiting(from, nullptr, -1, myVehicleParameter->depart, initialDepartPos, "start", true));
1428  }
1430  MSStoppingPlace* fromStop = myActivePlan->empty() ? nullptr : myActivePlan->back()->getDestinationStop();
1431  myActivePlan->push_back(new MSStageTrip(from, fromStop, to == nullptr ? &stoppingPlace->getLane().getEdge() : to,
1432  stoppingPlace, duration, modeSet, types, speed, walkFactor, group,
1433  departPosLat, attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS), arrivalPos));
1434  }
1435  myActiveRoute.clear();
1436 }
1437 
1438 
1439 void
1441  // parse walks from->to as person trips
1443  try {
1444  myActiveRoute.clear();
1445  bool ok = true;
1446  const SUMOTime duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, nullptr, ok, -1);
1447  if (attrs.hasAttribute(SUMO_ATTR_DURATION) && duration <= 0) {
1448  throw ProcessError("Non-positive walking duration for '" + myVehicleParameter->id + "'.");
1449  }
1450  double speed = -1; // default to vType speed
1451  if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
1452  speed = attrs.get<double>(SUMO_ATTR_SPEED, nullptr, ok);
1453  if (speed <= 0) {
1454  throw ProcessError("Non-positive walking speed for '" + myVehicleParameter->id + "'.");
1455  }
1456  }
1457  double departPos = 0;
1458  double arrivalPos = 0;
1459  MSStoppingPlace* bs = nullptr;
1460  if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
1461  const std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, myVehicleParameter->id.c_str(), ok);
1462  const MSRoute* route = MSRoute::dictionary(routeID, &myParsingRNG);
1463  if (route == nullptr) {
1464  throw ProcessError("The route '" + routeID + "' for walk of person '" + myVehicleParameter->id + "' is not known.");
1465  }
1466  myActiveRoute = route->getEdges();
1467  } else {
1469  }
1470  if (myActivePlan->empty()) {
1471  double initialDepartPos = myVehicleParameter->departPos;
1473  initialDepartPos = RandHelper::rand(myActiveRoute.front()->getLength(), &myParsingRNG);
1474  }
1475  myActivePlan->push_back(new MSStageWaiting(myActiveRoute.front(), nullptr, -1, myVehicleParameter->depart, initialDepartPos, "start", true));
1476  }
1477  parseWalkPositions(attrs, myVehicleParameter->id, myActiveRoute.front(), myActiveRoute.back(), departPos, arrivalPos, bs, myActivePlan->back(), ok);
1478  if (myActiveRoute.empty()) {
1479  throw ProcessError("No edges to walk for person '" + myVehicleParameter->id + "'.");
1480  }
1481  if (myActivePlan->back()->getDestination() != myActiveRoute.front() &&
1482  myActivePlan->back()->getDestination()->getToJunction() != myActiveRoute.front()->getFromJunction() &&
1483  myActivePlan->back()->getDestination()->getToJunction() != myActiveRoute.front()->getToJunction()) {
1484  if (myActivePlan->back()->getDestinationStop() == nullptr || myActivePlan->back()->getDestinationStop()->getAccessPos(myActiveRoute.front()) < 0.) {
1485  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + myActiveRoute.front()->getID() + " not connected to " + myActivePlan->back()->getDestination()->getID() + ").");
1486  }
1487  }
1488  const double departPosLat = attrs.getOpt<double>(SUMO_ATTR_DEPARTPOS_LAT, nullptr, ok, 0);
1489  myActivePlan->push_back(new MSPerson::MSPersonStage_Walking(myVehicleParameter->id, myActiveRoute, bs, duration, speed, departPos, arrivalPos, departPosLat));
1490  myActiveRoute.clear();
1491  } catch (ProcessError&) {
1493  throw;
1494  }
1495  } else {
1496  addPersonTrip(attrs);
1497  }
1498 }
1499 
1500 
1501 void
1503 }
1504 
1505 
1506 void
1508 }
1509 
1510 
1511 void
1513 }
1514 
1515 std::string
1516 MSRouteHandler::getDefaultGroup(const std::string& personID) {
1517  const std::string defaultGroup = OptionsCont::getOptions().getString("persontrip.default.group");
1518  return defaultGroup == "" ? personID : defaultGroup;
1519 }
1520 
1521 /****************************************************************************/
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
#define JUNCTION_TAZ_MISSING_HELP
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:277
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:284
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:45
#define SUMOTime_MAX
Definition: SUMOTime.h:32
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:31
const int VTYPEPARS_MAXSPEED_SET
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_IGNORING
vehicles ignoring classes
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_PEDESTRIAN
pedestrian
const double DEFAULT_VEH_PROB
const std::string DEFAULT_VTYPE_ID
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
const double DEFAULT_CONTAINER_TRANSHIP_SPEED
const int STOP_INDEX_END
const int VEHPARS_ROUTE_SET
const int VEHPARS_TO_TAZ_SET
@ RANDOM
The position is chosen randomly.
const int VEHPARS_DEPARTPOS_SET
@ GIVEN
The edge index is given.
@ DEFAULT
No information given; use default.
const int VEHPARS_FROM_TAZ_SET
const int VEHPARS_FORCE_REROUTE
const double MIN_STOP_LENGTH
@ DEPART_GIVEN
The time is given.
@ DEPART_TRIGGERED
The departure is person triggered.
SumoXMLTag
Numbers representing SUMO-XML - element names.
@ SUMO_TAG_CHARGING_STATION
A Charging Station.
@ SUMO_TAG_WALK
@ SUMO_TAG_TRANSHIP
@ SUMO_TAG_CONTAINER_STOP
A container stop.
@ SUMO_TAG_BUS_STOP
A bus stop.
@ SUMO_TAG_STOP
stop for vehicles
@ SUMO_TAG_FLOW
a flow definitio nusing a from-to edges instead of a route (used by router)
@ SUMO_TAG_PARKING_AREA
A parking area.
@ SUMO_TAG_CONTAINER
@ SUMO_TAG_OVERHEAD_WIRE_SEGMENT
An overhead wire segment.
@ SUMO_TAG_PERSON
@ SUMO_TAG_PERSONTRIP
@ SUMO_TAG_PERSONFLOW
@ SUMO_TAG_TRIP
a single trip definition (used by router)
@ SUMO_ATTR_STARTPOS
@ SUMO_ATTR_LINES
@ SUMO_ATTR_LANE
@ SUMO_ATTR_DEPART
@ SUMO_ATTR_DEPARTEDGE
@ SUMO_ATTR_REFID
@ SUMO_ATTR_SPEED
@ SUMO_ATTR_VIA
@ SUMO_ATTR_CONTAINER_STOP
@ SUMO_ATTR_EDGE
@ SUMO_ATTR_FROMJUNCTION
@ SUMO_ATTR_DEPARTPOS_LAT
@ SUMO_ATTR_BUS_STOP
@ SUMO_ATTR_ENDPOS
@ SUMO_ATTR_ARRIVALPOS
@ SUMO_ATTR_ACTTYPE
@ SUMO_ATTR_PROBS
@ SUMO_ATTR_EDGES
the edges of a route
@ SUMO_ATTR_ROUTES
@ SUMO_ATTR_MODES
@ SUMO_ATTR_VTYPES
@ SUMO_ATTR_DEPARTPOS
@ SUMO_ATTR_GROUP
@ SUMO_ATTR_COST
@ SUMO_ATTR_PERIOD
@ SUMO_ATTR_TO_TAZ
@ SUMO_ATTR_TO
@ SUMO_ATTR_FROM
@ SUMO_ATTR_FROM_TAZ
@ SUMO_ATTR_VIAJUNCTIONS
@ SUMO_ATTR_PROB
@ SUMO_ATTR_FRIENDLY_POS
@ SUMO_ATTR_WALKFACTOR
@ SUMO_ATTR_ROUTE
@ SUMO_ATTR_COLOR
A color information.
@ SUMO_ATTR_ID
@ SUMO_ATTR_DURATION
@ SUMO_ATTR_REPEAT
@ SUMO_ATTR_INTENDED
@ SUMO_ATTR_POSITION
@ SUMO_ATTR_CYCLETIME
@ SUMO_ATTR_TOJUNCTION
T MAX2(T a, T b)
Definition: StdDefs.h:79
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
void error(const XERCES_CPP_NAMESPACE::SAXParseException &exception)
Handler for XML-errors.
A road/street connecting two junctions.
Definition: MSEdge.h:77
static void parseEdgesList(const std::string &desc, ConstMSEdgeVector &into, const std::string &rid)
Parses the given string assuming it contains a list of edge ids divided by spaces.
Definition: MSEdge.cpp:871
const MSEdge * getNormalSuccessor() const
if this edge is an internal edge, return its first normal successor, otherwise the edge itself
Definition: MSEdge.cpp:733
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:166
double getLength() const
return the length of the edge
Definition: MSEdge.h:630
bool isInternal() const
return whether this edge is an internal edge
Definition: MSEdge.h:256
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:814
const MSEdge * getNormalBefore() const
if this edge is an internal edge, return its first normal predecessor, otherwise the edge itself
Definition: MSEdge.cpp:723
const MSJunction * getToJunction() const
Definition: MSEdge.h:392
static bool gCheckRoutes
Definition: MSGlobals.h:76
static bool gStateLoaded
Information whether a state has been loaded.
Definition: MSGlobals.h:85
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition: MSGlobals.h:66
void add(SUMOVehicle *veh)
Adds a single vehicle for departure.
SUMOTime computeRandomDepartOffset() const
compute (optional) random offset to the departure time
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
double getLength() const
Returns the lane's length.
Definition: MSLane.h:539
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition: MSLane.cpp:1908
bool isInternal() const
Definition: MSLane.cpp:2036
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:673
The simulated network and simulation perfomer.
Definition: MSNet.h:89
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:171
virtual MSTransportableControl & getContainerControl()
Returns the container control.
Definition: MSNet.cpp:995
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:371
MSStoppingPlace * getStoppingPlace(const std::string &id, const SumoXMLTag category) const
Returns the named stopping place of the given category.
Definition: MSNet.cpp:1098
bool hasContainers() const
Returns whether containers are simulated.
Definition: MSNet.h:404
MSInsertionControl & getInsertionControl()
Returns the insertion control.
Definition: MSNet.h:424
bool hasPersons() const
Returns whether persons are simulated.
Definition: MSNet.h:388
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition: MSNet.cpp:986
static std::mt19937 myParsingRNG
A random number generator used to choose from vtype/route distributions and computing the speed facto...
virtual void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
void addStop(const SUMOSAXAttributes &attrs)
Processing of a stop.
bool myAmLoadingState
whether a state file is being loaded
SUMOTime myActiveRoutePeriod
void closeVType()
Ends the processing of a vehicle type.
void openTrip(const SUMOSAXAttributes &attrs)
opens a trip for reading
void closeVehicleTypeDistribution()
closes (ends) the building of a distribution
std::string myCurrentVTypeDistributionID
The id of the currently parsed vehicle type distribution.
RandomDistributor< const MSRoute * > * myCurrentRouteDistribution
The currently parsed distribution of routes (probability->route)
void closeRouteDistribution()
closes (ends) the building of a distribution
void parseFromViaTo(SumoXMLTag tag, const SUMOSAXAttributes &attrs)
Called for parsing from and to and the corresponding taz attributes.
void closeFlow()
Ends the processing of a flow.
void closeContainer()
Ends the processing of a container.
MSTransportable::MSTransportablePlan * myActiveContainerPlan
The plan of the current container.
std::string myCurrentRouteDistributionID
The id of the currently parsed route distribution.
void closePersonFlow()
Ends the processing of a personFlow.
void openRouteFlow(const SUMOSAXAttributes &attrs)
opens a route flow for reading
RandomDistributor< MSVehicleType * > * myCurrentVTypeDistribution
The currently parsed distribution of vehicle types (probability->vehicle type)
void deleteActivePlans()
delete already created MSTransportablePlans if error occurs before handing over responsibility to a M...
void closePerson()
Ends the processing of a person.
void closeTrip()
Ends the processing of a trip.
void openRouteDistribution(const SUMOSAXAttributes &attrs)
opens a route distribution for reading
ConstMSEdgeVector myActiveRoute
The current route.
int myActiveRouteRepeat
number of repetitions of the active route
MSTransportable::MSTransportablePlan * myActivePlan
The plan of the current person.
void addPersonTrip(const SUMOSAXAttributes &attrs)
add a routing request for a walking or intermodal person
void addTranship(const SUMOSAXAttributes &attrs)
Processing of a tranship.
virtual void closeVehicle()
Ends the processing of a vehicle (note: is virtual because is reimplemented in MSStateHandler)
MSRoute * addVehicleStopsToImplicitRoute(const MSRoute *route, bool isPermanent)
adapt implicit route (edges derived from stops) to additional vehicle-stops
void openVehicleTypeDistribution(const SUMOSAXAttributes &attrs)
opens a type distribution for reading
void openFlow(const SUMOSAXAttributes &attrs)
opens a flow for reading
MSRouteHandler(const std::string &file, bool addVehiclesDirectly)
standard constructor
virtual ~MSRouteHandler()
standard destructor
bool myAddVehiclesDirectly
Information whether vehicles shall be directly added to the network or kept within the buffer.
void addWalk(const SUMOSAXAttributes &attrs)
add a fully specified walk
void openRoute(const SUMOSAXAttributes &attrs)
opens a route for reading
void addTransport(const SUMOSAXAttributes &attrs)
Processing of a transport.
void parseWalkPositions(const SUMOSAXAttributes &attrs, const std::string &personID, const MSEdge *fromEdge, const MSEdge *&toEdge, double &departPos, double &arrivalPos, MSStoppingPlace *&bs, const MSStage *const lastStage, bool &ok)
@ brief parse depart- and arrival positions of a walk
void addRide(const SUMOSAXAttributes &attrs)
Processing of a ride.
static std::string getDefaultGroup(const std::string &personID)
determine the default group for rides and trips
void addFlowPerson(SUMOTime depart, MSVehicleType *type, const std::string &baseID, int i)
delete already created MSTransportablePlans if error occurs before handing over responsibility to a M...
void addPerson(const SUMOSAXAttributes &attrs)
Processing of a person.
void closeRoute(const bool mayBeDisconnected=false)
closes (ends) the building of a route.
void addContainer(const SUMOSAXAttributes &attrs)
Processing of a container.
void addReference() const
increments the reference counter for the route
Definition: MSRoute.cpp:94
void setReroute(bool reroute=true)
Definition: MSRoute.h:200
const std::vector< SUMOVehicleParameter::Stop > & getStops() const
Returns the stops.
Definition: MSRoute.cpp:397
static bool dictionary(const std::string &id, const MSRoute *route)
Adds a route to the dictionary.
Definition: MSRoute.cpp:113
void setCosts(double costs)
Sets the costs of the route.
Definition: MSRoute.h:185
void release() const
deletes the route if there are no further references to it
Definition: MSRoute.cpp:100
const RGBColor & getColor() const
Returns the color.
Definition: MSRoute.cpp:388
void setPeriod(SUMOTime period)
sets the period
Definition: MSRoute.h:177
bool mustReroute() const
Definition: MSRoute.h:196
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:120
const MSEdge * getDestination() const
returns the destination edge
Definition: MSStage.cpp:70
virtual double getArrivalPos() const
Definition: MSStage.h:89
MSStoppingPlace * getDestinationStop() const
returns the destination stop (if any)
Definition: MSStage.h:80
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.
double getAccessPos(const MSEdge *edge) const
the position on the given edge which is connected to this stop, -1 on failure
virtual MSTransportable * buildPerson(const SUMOVehicleParameter *pars, MSVehicleType *vtype, MSTransportable::MSTransportablePlan *plan, std::mt19937 *rng) const
Builds a new person.
int getLoadedNumber() const
Returns the number of build transportables.
virtual MSTransportable * buildContainer(const SUMOVehicleParameter *pars, MSVehicleType *vtype, MSTransportable::MSTransportablePlan *plan) const
Builds a new container.
bool add(MSTransportable *transportable)
Adds a single transportable, returns false if an id clash occurred.
MSTransportable * get(const std::string &id) const
Returns the named transportable, if existing.
std::vector< MSStage * > MSTransportablePlan
the structure holding the plan of a transportable
The class responsible for building and deletion of vehicles.
virtual void deleteVehicle(SUMOVehicle *v, bool discard=false)
Deletes the vehicle.
virtual bool addVehicle(const std::string &id, SUMOVehicle *v)
Tries to insert the vehicle into the internal vehicle container.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
int getQuota(double frac=-1, int loaded=-1) const
Returns the number of instances of the current vehicle that shall be emitted considering that "frac" ...
MSVehicleType * getVType(const std::string &id=DEFAULT_VTYPE_ID, std::mt19937 *rng=nullptr)
Returns the named vehicle type or a sample from the named distribution.
virtual SUMOVehicle * buildVehicle(SUMOVehicleParameter *defs, const MSRoute *route, MSVehicleType *type, const bool ignoreStopErrors, const bool fromRouteFile=true)
Builds a vehicle, increases the number of built vehicles.
The car-following model and parameter.
Definition: MSVehicleType.h:62
double getDefaultProbability() const
Get the default probability of this vehicle type.
SUMOVehicleClass getVehicleClass() const
Get this vehicle type's vehicle class.
static MSVehicleType * build(SUMOVTypeParameter &from)
Builds the microsim vehicle type described by the given parameter.
double getMaxSpeed() const
Get vehicle's maximum speed [m/s].
const std::string & getID() const
Returns the name of the vehicle type.
Definition: MSVehicleType.h:90
bool wasSet(int what) const
Returns whether the given parameter was set.
Definition: MSVehicleType.h:79
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:80
const std::string & getID() const
Returns the id.
Definition: Named.h:73
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
static double rand(std::mt19937 *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.h:51
double getOverallProb() const
Return the sum of the probabilites assigned to the members.
const std::vector< double > & getProbs() const
Returns the probabilities assigned to the members of the distribution.
bool add(T val, double prob, bool checkDuplicates=true)
Adds a value with an assigned probability to the distribution.
Parser for routes during their loading.
bool parseStop(SUMOVehicleParameter::Stop &stop, const SUMOSAXAttributes &attrs, std::string errorSuffix, MsgHandler *const errorOutput)
parses attributes common to all stops
std::vector< SUMOVehicleParameter::Stop > myActiveRouteStops
List of the stops on the parsed route.
void registerLastDepart()
save last depart (only to be used if vehicle is not discarded)
double myCurrentCosts
The currently parsed route costs.
std::string myActiveRouteID
The id of the current route.
SUMOVehicleParameter * myVehicleParameter
Parameter of the current vehicle, trip, person, container or flow.
const bool myHardFail
flag to enable or disable hard fails
SUMOVTypeParameter * myCurrentVType
The currently parsed vehicle type.
static StopPos checkStopPos(double &startPos, double &endPos, const double laneLength, const double minLength, const bool friendlyPos)
check start and end position of a stop
virtual void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
double myActiveRouteProbability
The probability of the current route.
int myInsertStopEdgesAt
where stop edges can be inserted into the current route (-1 means no insertion)
std::string myActiveRouteRefID
The id of the route the current route references to.
const RGBColor * myActiveRouteColor
The currently parsed route's color.
bool checkLastDepart()
Checks whether the route file is sorted by departure time if needed.
Encapsulated SAX-Attributes.
T getOpt(int attr, const char *objectid, bool &ok, T defaultValue, bool report=true) const
Tries to read given attribute assuming it is an int.
const std::vector< std::string > getStringVector(int attr) const
Tries to read given attribute assuming it is a string vector.
SUMOTime getOptSUMOTimeReporting(int attr, const char *objectid, bool &ok, SUMOTime defaultValue, bool report=true) const
Tries to read given attribute assuming it is a SUMOTime.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
Representation of a vehicle.
Definition: SUMOVehicle.h:58
Definition of vehicle stop (position and duration)
std::string edge
The edge to stop at (used only in NETEDIT)
std::string lane
The lane to stop at.
std::string parkingarea
(Optional) parking area if one is assigned to the stop
double startPos
The stopping position start.
std::string chargingStation
(Optional) charging station if one is assigned to the stop
std::string overheadWireSegment
(Optional) overhead line segment if one is assigned to the stop
int index
at which position in the stops list
SUMOTime until
The time at which the vehicle may continue its journey.
double endPos
The stopping position end.
std::string busstop
(Optional) bus stop if one is assigned to the stop
std::string containerstop
(Optional) container stop if one is assigned to the stop
SUMOTime duration
The stopping duration.
Structure representing possible vehicle parameter.
double repetitionProbability
The probability for emitting a vehicle per second.
int parametersSet
Information for the router which parameter were set, TraCI may modify this (when changing color)
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.
SUMOTime repetitionEnd
The time at which the flow ends (only needed when using repetitionProbability)
double departPos
(optional) The position the vehicle shall depart from
std::string routeid
The vehicle's route id.
std::string id
The vehicle's id.
std::vector< Stop > stops
List of the stops the vehicle will make, TraCI may add entries here.
int departEdge
(optional) The initial edge within the route of the vehicle
static bool parsePersonModes(const std::string &modes, const std::string &element, const std::string &id, SVCPermissions &modeSet, std::string &error)
Validates a given person modes value.
bool wasSet(int what) const
Returns whether the given parameter was set.
DepartEdgeDefinition departEdgeProcedure
Information how the vehicle's initial edge shall be chosen.
static double interpretEdgePos(double pos, double maximumValue, SumoXMLAttr attr, const std::string &id, bool silent=false)
Interprets negative edge positions and fits them onto a given edge.
DepartDefinition departProcedure
Information how the vehicle shall choose the depart time.
DepartPosDefinition departPosProcedure
Information how the vehicle shall choose the departure position.
static double parseWalkPos(SumoXMLAttr attr, const bool hardFail, const std::string &id, double maxPos, const std::string &val, std::mt19937 *rng=0)
parse departPos or arrivalPos for a walk
bool hasNext()
returns the information whether further substrings exist
std::string next()
returns the next substring when it exists. Otherwise the behaviour is undefined
static double toDoubleSecure(const std::string &sData, const double def)
converts a string into the integer value described by it