SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MSRouteHandler.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // Parser and container for routes during their loading
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
13 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 
34 #include <string>
35 #include <map>
36 #include <vector>
37 #include <microsim/MSRoute.h>
38 #include <microsim/MSEdge.h>
39 #include <microsim/MSVehicleType.h>
40 #include <microsim/MSVehicle.h>
43 #include <microsim/MSLane.h>
44 #include "MSRouteHandler.h"
45 #include "MSPersonControl.h"
53 #include "MSNet.h"
54 
56 #include <microsim/MSGlobals.h>
58 
59 #ifdef CHECK_MEMORY_LEAKS
60 #include <foreign/nvwa/debug_new.h>
61 #endif // CHECK_MEMORY_LEAKS
62 
63 
64 // ===========================================================================
65 // method definitions
66 // ===========================================================================
67 MSRouteHandler::MSRouteHandler(const std::string& file,
68  bool addVehiclesDirectly) :
69  SUMORouteHandler(file),
70  myActivePlan(0),
71  myAddVehiclesDirectly(addVehiclesDirectly),
72  myCurrentVTypeDistribution(0),
73  myCurrentRouteDistribution(0) {
74  myActiveRoute.reserve(100);
75 }
76 
77 
79 }
80 
81 
82 void
84  const SUMOSAXAttributes& attrs) {
85  SUMORouteHandler::myStartElement(element, attrs);
86  switch (element) {
87  case SUMO_TAG_PERSON:
89  break;
90  case SUMO_TAG_RIDE: {
91  const std::string pid = myVehicleParameter->id;
92  bool ok = true;
93  MSEdge* from = 0;
94  SUMOReal departPos = 0;
95  const std::string desc = attrs.getStringReporting(SUMO_ATTR_LINES, pid.c_str(), ok);
96  StringTokenizer st(desc);
97  std::string bsID = attrs.getOptStringReporting(SUMO_ATTR_BUS_STOP, 0, ok, "");
98  MSBusStop* bs = 0;
99  if (bsID != "") {
100  bs = MSNet::getInstance()->getBusStop(bsID);
101  if (bs == 0) {
102  throw ProcessError("Unknown bus stop '" + bsID + "' for person '" + myVehicleParameter->id + "'.");
103  }
104  departPos = bs->getBeginLanePosition();
105  }
106  if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
107  const std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, pid.c_str(), ok);
108  from = MSEdge::dictionary(fromID);
109  if (from == 0) {
110  throw ProcessError("The from edge '" + fromID + "' within a ride of person '" + pid + "' is not known.");
111  }
112  if (!myActivePlan->empty() && &myActivePlan->back()->getDestination() != from) {
113  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + fromID + "!=" + myActivePlan->back()->getDestination().getID() + ").");
114  }
115  if (myActivePlan->empty()) {
117  *from, -1, myVehicleParameter->depart, myVehicleParameter->departPos, "start"));
118  }
119  } else if (myActivePlan->empty()) {
120  throw ProcessError("The start edge within for person '" + pid + "' is not known.");
121  }
122  const std::string toID = attrs.getStringReporting(SUMO_ATTR_TO, pid.c_str(), ok);
123  MSEdge* to = MSEdge::dictionary(toID);
124  if (to == 0) {
125  throw ProcessError("The to edge '" + toID + "' within a ride of person '" + pid + "' is not known.");
126  }
127  myActivePlan->push_back(new MSPerson::MSPersonStage_Driving(*to, bs, st.getVector()));
128  break;
129  }
130  case SUMO_TAG_WALK: {
131  myActiveRoute.clear();
132  bool ok = true;
133  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
135  } else {
136  if (attrs.hasAttribute(SUMO_ATTR_FROM) && attrs.hasAttribute(SUMO_ATTR_TO)) {
137  const std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok);
138  MSEdge* from = MSEdge::dictionary(fromID);
139  if (from == 0) {
140  throw ProcessError("The from edge '" + fromID + "' within a walk of person '" + myVehicleParameter->id + "' is not known.");
141  }
142  const std::string toID = attrs.getStringReporting(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok);
143  MSEdge* to = MSEdge::dictionary(toID);
144  if (to == 0) {
145  throw ProcessError("The to edge '" + toID + "' within a walk of person '" + myVehicleParameter->id + "' is not known.");
146  }
147  MSNet::getInstance()->getRouterTT().compute(from, to, 0, 0, myActiveRoute); // @todo: only footways, current time?
148  }
149  }
150  if (myActiveRoute.empty()) {
151  throw ProcessError("No edges to walk for person '" + myVehicleParameter->id + "'.");
152  }
153  if (!myActivePlan->empty() && &myActivePlan->back()->getDestination() != myActiveRoute.front()) {
154  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + myActiveRoute.front()->getID() + "!=" + myActivePlan->back()->getDestination().getID() + ").");
155  }
156  SUMOReal departPos = attrs.getOptSUMORealReporting(SUMO_ATTR_DEPARTPOS, myVehicleParameter->id.c_str(), ok, 0);
157  SUMOReal arrivalPos = attrs.getOptSUMORealReporting(SUMO_ATTR_ARRIVALPOS, myVehicleParameter->id.c_str(), ok, -1);
158  const SUMOTime duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, 0, ok, -1);
160  if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
161  speed = attrs.getOptSUMORealReporting(SUMO_ATTR_SPEED, 0, ok, speed);
162  if (speed < 0) {
163  throw ProcessError("Negative walking speed for '" + myVehicleParameter->id + "'.");
164  }
165  }
166  std::string bsID = attrs.getOptStringReporting(SUMO_ATTR_BUS_STOP, 0, ok, "");
167  MSBusStop* bs = 0;
168  if (bsID != "") {
169  bs = MSNet::getInstance()->getBusStop(bsID);
170  if (bs == 0) {
171  throw ProcessError("Unknown bus stop '" + bsID + "' for person '" + myVehicleParameter->id + "'.");
172  }
173  }
174  if (myActivePlan->empty()) {
176  *myActiveRoute.front(), -1, myVehicleParameter->depart, departPos, "start"));
177  }
178  myActivePlan->push_back(new MSPerson::MSPersonStage_Walking(myActiveRoute, bs, duration, speed, departPos, arrivalPos));
179  myActiveRoute.clear();
180  break;
181  }
182  case SUMO_TAG_FLOW:
183  if (attrs.hasAttribute(SUMO_ATTR_FROM) && attrs.hasAttribute(SUMO_ATTR_TO)) {
185  bool ok = true;
187  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
189  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
190  closeRoute();
191  }
192  break;
193  case SUMO_TAG_TRIP: {
194  bool ok = true;
197  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
199  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
200  } else {
201  const MSEdge* fromTaz = MSEdge::dictionary(myVehicleParameter->fromTaz + "-source");
202  if (fromTaz == 0) {
203  WRITE_ERROR("Source district '" + myVehicleParameter->fromTaz + "' not known for '" + myVehicleParameter->id + "'!");
204  } else if (fromTaz->getNoFollowing() == 0) {
205  WRITE_ERROR("Source district '" + myVehicleParameter->fromTaz + "' has no outgoing edges for '" + myVehicleParameter->id + "'!");
206  } else {
207  myActiveRoute.push_back(fromTaz->getFollower(0));
208  }
209  }
210  closeRoute();
211  closeVehicle();
212  }
213  break;
214  default:
215  break;
216  }
217  // parse embedded vtype information
218  if (myCurrentVType != 0 && element != SUMO_TAG_VTYPE) {
220  return;
221  }
222 }
223 
224 
225 void
227  bool ok = true;
229  if (ok) {
231  if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
232  const std::string vTypes = attrs.getStringReporting(SUMO_ATTR_VTYPES, myCurrentVTypeDistributionID.c_str(), ok);
233  StringTokenizer st(vTypes);
234  while (st.hasNext()) {
235  std::string vtypeID = st.next();
237  if (type == 0) {
238  throw ProcessError("Unknown vtype '" + vtypeID + "' in distribution '" + myCurrentVTypeDistributionID + "'.");
239  }
241  }
242  }
243  }
244 }
245 
246 
247 void
249  if (myCurrentVTypeDistribution != 0) {
252  WRITE_ERROR("Vehicle type distribution '" + myCurrentVTypeDistributionID + "' is empty.");
253  } else if (!MSNet::getInstance()->getVehicleControl().addVTypeDistribution(myCurrentVTypeDistributionID, myCurrentVTypeDistribution)) {
255  WRITE_ERROR("Another vehicle type (or distribution) with the id '" + myCurrentVTypeDistributionID + "' exists.");
256  }
258  }
259 }
260 
261 
262 void
264  // check whether the id is really necessary
265  std::string rid;
266  if (myCurrentRouteDistribution != 0) {
268  rid = "distribution '" + myCurrentRouteDistributionID + "'";
269  } else if (myVehicleParameter != 0) {
270  // ok, a vehicle is wrapping the route,
271  // we may use this vehicle's id as default
272  myActiveRouteID = "!" + myVehicleParameter->id; // !!! document this
273  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
274  WRITE_WARNING("Ids of internal routes are ignored (vehicle '" + myVehicleParameter->id + "').");
275  }
276  } else {
277  bool ok = true;
278  myActiveRouteID = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok, false);
279  if (!ok) {
280  return;
281  }
282  rid = "'" + myActiveRouteID + "'";
283  }
284  if (myVehicleParameter != 0) { // have to do this here for nested route distributions
285  rid = "for vehicle '" + myVehicleParameter->id + "'";
286  }
287  bool ok = true;
288  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
290  }
293  WRITE_ERROR("Invalid reference to route '" + myActiveRouteRefID + "' in route " + rid + ".");
294  }
297 }
298 
299 
300 void
303  switch (element) {
304  case SUMO_TAG_VTYPE: {
306  delete myCurrentVType;
307  myCurrentVType = 0;
308  if (!MSNet::getInstance()->getVehicleControl().addVType(vehType)) {
309  const std::string id = vehType->getID();
310  delete vehType;
311 #ifdef HAVE_INTERNAL
312  if (!MSGlobals::gStateLoaded) {
313 #endif
314  throw ProcessError("Another vehicle type (or distribution) with the id '" + id + "' exists.");
315 #ifdef HAVE_INTERNAL
316  }
317 #endif
318  } else {
319  if (myCurrentVTypeDistribution != 0) {
321  }
322  }
323  }
324  break;
325  default:
326  break;
327  }
328 }
329 
330 
331 void
333  if (myActiveRoute.size() == 0) {
334  delete myActiveRouteColor;
335  myActiveRouteColor = 0;
338  myActiveRouteID = "";
339  myActiveRouteRefID = "";
340  return;
341  }
342  if (myVehicleParameter != 0) {
343  throw ProcessError("Vehicle's '" + myVehicleParameter->id + "' route has no edges.");
344  } else {
345  throw ProcessError("Route '" + myActiveRouteID + "' has no edges.");
346  }
347  }
351  myActiveRoute.clear();
352  if (!MSRoute::dictionary(myActiveRouteID, route)) {
353  delete route;
354 #ifdef HAVE_INTERNAL
355  if (!MSGlobals::gStateLoaded) {
356 #endif
357  if (myVehicleParameter != 0) {
358  if (MSNet::getInstance()->getVehicleControl().getVehicle(myVehicleParameter->id) == 0) {
359  throw ProcessError("Another route for vehicle '" + myVehicleParameter->id + "' exists.");
360  } else {
361  throw ProcessError("A vehicle with id '" + myVehicleParameter->id + "' already exists.");
362  }
363  } else {
364  throw ProcessError("Another route (or distribution) with the id '" + myActiveRouteID + "' exists.");
365  }
366 #ifdef HAVE_INTERNAL
367  }
368 #endif
369  } else {
370  if (myCurrentRouteDistribution != 0) {
372  }
373  }
374  myActiveRouteID = "";
375  myActiveRouteColor = 0;
376  myActiveRouteStops.clear();
377 }
378 
379 
380 void
382  // check whether the id is really necessary
383  bool ok = true;
384  if (myVehicleParameter != 0) {
385  // ok, a vehicle is wrapping the route,
386  // we may use this vehicle's id as default
387  myCurrentRouteDistributionID = "!" + myVehicleParameter->id; // !!! document this
388  } else {
390  if (!ok) {
391  return;
392  }
393  }
395  std::vector<SUMOReal> probs;
396  if (attrs.hasAttribute(SUMO_ATTR_PROBS)) {
397  bool ok = true;
399  while (st.hasNext()) {
400  probs.push_back(TplConvert::_2SUMORealSec(st.next().c_str(), 1.0));
401  }
402  }
403  if (attrs.hasAttribute(SUMO_ATTR_ROUTES)) {
404  bool ok = true;
406  size_t probIndex = 0;
407  while (st.hasNext()) {
408  std::string routeID = st.next();
409  const MSRoute* route = MSRoute::dictionary(routeID);
410  if (route == 0) {
411  throw ProcessError("Unknown route '" + routeID + "' in distribution '" + myCurrentRouteDistributionID + "'.");
412  }
413  const SUMOReal prob = (probs.size() > probIndex ? probs[probIndex] : 1.0);
414  myCurrentRouteDistribution->add(prob, route, false);
415  probIndex++;
416  }
417  if (probs.size() > 0 && probIndex != probs.size()) {
418  WRITE_WARNING("Got " + toString(probs.size()) + " probabilities for " + toString(probIndex) +
419  " routes in routeDistribution '" + myCurrentRouteDistributionID + "'");
420  }
421  }
422 }
423 
424 
425 void
427  if (myCurrentRouteDistribution != 0) {
430  WRITE_ERROR("Route distribution '" + myCurrentRouteDistributionID + "' is empty.");
433  WRITE_ERROR("Another route (or distribution) with the id '" + myCurrentRouteDistributionID + "' exists.");
434  }
436  }
437 }
438 
439 
440 void
442  // get nested route
443  const MSRoute* route = MSRoute::dictionary("!" + myVehicleParameter->id);
446  // let's check whether this vehicle had to depart before the simulation starts
448  if (route != 0) {
449  route->addReference();
450  route->release();
451  }
452  return;
453  }
454  }
455  // get the vehicle's type
456  MSVehicleType* vtype = 0;
457  if (myVehicleParameter->vtypeid != "") {
458  vtype = vehControl.getVType(myVehicleParameter->vtypeid);
459  if (vtype == 0) {
460  throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
461  }
462  } else {
463  // there should be one (at least the default one)
464  vtype = vehControl.getVType();
465  }
466  if (route == 0) {
467  // if there is no nested route, try via the (hopefully) given route-id
469  }
470  if (route == 0) {
471  // nothing found? -> error
472  if (myVehicleParameter->routeid != "") {
473  throw ProcessError("The route '" + myVehicleParameter->routeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
474  } else {
475  throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has no route.");
476  }
477  }
478  myActiveRouteID = "";
479 
480  // try to build the vehicle
481  SUMOVehicle* vehicle = 0;
482  if (vehControl.getVehicle(myVehicleParameter->id) == 0) {
483  vehicle = vehControl.buildVehicle(myVehicleParameter, route, vtype);
484  // maybe we do not want this vehicle to be inserted due to scaling
485  if (vehControl.isInQuota()) {
486  // add the vehicle to the vehicle control
487  vehControl.addVehicle(myVehicleParameter->id, vehicle);
489  vehControl.addWaiting(*route->begin(), vehicle);
490  vehControl.registerOneWaitingForPerson();
491  }
493  myVehicleParameter = 0;
494  } else {
495  vehControl.deleteVehicle(vehicle, true);
496  myVehicleParameter = 0;
497  vehicle = 0;
498  }
499  } else {
500  // strange: another vehicle with the same id already exists
501 #ifdef HAVE_INTERNAL
502  if (!MSGlobals::gStateLoaded) {
503 #endif
504  // and was not loaded while loading a simulation state
505  // -> error
506  throw ProcessError("Another vehicle with the id '" + myVehicleParameter->id + "' exists.");
507 #ifdef HAVE_INTERNAL
508  } else {
509  // ok, it seems to be loaded previously while loading a simulation state
510  vehicle = 0;
511  }
512 #endif
513  }
514  // check whether the vehicle shall be added directly to the network or
515  // shall stay in the internal buffer
516  if (vehicle != 0) {
517  if (vehicle->getParameter().departProcedure == DEPART_GIVEN) {
519  }
520  }
521 }
522 
523 
524 void
526  if (myActivePlan->size() == 0) {
527  throw ProcessError("Person '" + myVehicleParameter->id + "' has no plan.");
528  }
530  if (type == 0) {
531  throw ProcessError("The type '" + myVehicleParameter->vtypeid + "' for person '" + myVehicleParameter->id + "' is not known.");
532  }
534  // @todo: consider myScale?
535  if ((myAddVehiclesDirectly || checkLastDepart()) && MSNet::getInstance()->getPersonControl().add(myVehicleParameter->id, person)) {
538  } else {
539  delete person;
540  }
541  myVehicleParameter = 0;
542  myActivePlan = 0;
543 }
544 
545 
546 void
548  // let's check whether vehicles had to depart before the simulation starts
550  SUMOTime offsetToBegin = string2time(OptionsCont::getOptions().getString("begin")) - myVehicleParameter->depart;
554  return;
555  }
556  }
557  if (MSNet::getInstance()->getVehicleControl().getVType(myVehicleParameter->vtypeid) == 0) {
558  throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
559  }
560  if (MSRoute::dictionary("!" + myVehicleParameter->id) == 0) {
561  // if not, try via the (hopefully) given route-id
563  if (myVehicleParameter->routeid != "") {
564  throw ProcessError("The route '" + myVehicleParameter->routeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
565  } else {
566  throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has no route.");
567  }
568  }
569  } else {
571  }
572  myActiveRouteID = "";
573 
574  // check whether the vehicle shall be added directly to the network or
575  // shall stay in the internal buffer
579  }
580  myVehicleParameter = 0;
581 }
582 
583 
584 void
586  bool ok = true;
587  std::string errorSuffix;
588  if (myActiveRouteID != "") {
589  errorSuffix = " in route '" + myActiveRouteID + "'.";
590  } else if (myActivePlan) {
591  errorSuffix = " in person '" + myVehicleParameter->id + "'.";
592  } else {
593  errorSuffix = " in vehicle '" + myVehicleParameter->id + "'.";
594  }
596  // try to parse the assigned bus stop
597  stop.busstop = attrs.getOptStringReporting(SUMO_ATTR_BUS_STOP, 0, ok, "");
598  if (stop.busstop != "") {
599  // ok, we have obviously a bus stop
601  if (bs != 0) {
602  const MSLane& l = bs->getLane();
603  stop.lane = l.getID();
604  stop.endPos = bs->getEndLanePosition();
605  stop.startPos = bs->getBeginLanePosition();
606  } else {
607  WRITE_ERROR("The bus stop '" + stop.busstop + "' is not known" + errorSuffix);
608  return;
609  }
610  } else {
611  // no, the lane and the position should be given
612  // get the lane
613  stop.lane = attrs.getOptStringReporting(SUMO_ATTR_LANE, 0, ok, "");
614  if (ok && stop.lane != "") {
615  if (MSLane::dictionary(stop.lane) == 0) {
616  WRITE_ERROR("The lane '" + stop.lane + "' for a stop is not known" + errorSuffix);
617  return;
618  }
619  } else {
620  WRITE_ERROR("A stop must be placed on a bus stop or a lane" + errorSuffix);
621  return;
622  }
623  if (myActivePlan &&
624  !myActivePlan->empty() &&
625  &myActivePlan->back()->getDestination() != &MSLane::dictionary(stop.lane)->getEdge()) {
626  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + MSLane::dictionary(stop.lane)->getEdge().getID() + "!=" + myActivePlan->back()->getDestination().getID() + ").");
627  }
628  if (myActivePlan && myActivePlan->empty()) {
630  MSLane::dictionary(stop.lane)->getEdge(), -1, myVehicleParameter->depart, myVehicleParameter->departPos, "start"));
631  }
632  stop.endPos = attrs.getOptSUMORealReporting(SUMO_ATTR_ENDPOS, 0, ok, MSLane::dictionary(stop.lane)->getLength());
633  if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
634  WRITE_WARNING("Deprecated attribute 'pos' in description of stop" + errorSuffix);
635  stop.endPos = attrs.getOptSUMORealReporting(SUMO_ATTR_POSITION, 0, ok, stop.endPos);
636  }
637  stop.startPos = attrs.getOptSUMORealReporting(SUMO_ATTR_STARTPOS, 0, ok, MAX2(0., stop.endPos - 2 * POSITION_EPS));
638  const bool friendlyPos = attrs.getOptBoolReporting(SUMO_ATTR_FRIENDLY_POS, 0, ok, false);
639  if (!ok || !checkStopPos(stop.startPos, stop.endPos, MSLane::dictionary(stop.lane)->getLength(), POSITION_EPS, friendlyPos)) {
640  WRITE_ERROR("Invalid start or end position for stop on lane '" + stop.lane + "'" + errorSuffix);
641  return;
642  }
643  }
644 
645  // get the standing duration
647  stop.triggered = attrs.getOptBoolReporting(SUMO_ATTR_TRIGGERED, 0, ok, true);
648  stop.duration = -1;
649  stop.until = -1;
650  } else {
651  stop.duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, 0, ok, -1);
652  stop.until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, 0, ok, -1);
653  if (!ok || (stop.duration < 0 && stop.until < 0)) {
654  WRITE_ERROR("Invalid duration or end time is given for a stop on lane '" + stop.lane + "'" + errorSuffix);
655  return;
656  }
657  stop.triggered = attrs.getOptBoolReporting(SUMO_ATTR_TRIGGERED, 0, ok, false);
658  }
659  stop.parking = attrs.getOptBoolReporting(SUMO_ATTR_PARKING, 0, ok, stop.triggered);
660  if (!ok) {
661  WRITE_ERROR("Invalid bool for 'triggered' or 'parking' for stop on lane '" + stop.lane + "'" + errorSuffix);
662  return;
663  }
664  const std::string idx = attrs.getOptStringReporting(SUMO_ATTR_INDEX, 0, ok, "end");
665  if (idx == "end") {
666  stop.index = STOP_INDEX_END;
667  } else if (idx == "fit") {
668  stop.index = STOP_INDEX_FIT;
669  } else {
670  stop.index = attrs.getIntReporting(SUMO_ATTR_INDEX, 0, ok);
671  if (!ok || stop.index < 0) {
672  WRITE_ERROR("Invalid 'index' for stop on lane '" + stop.lane + "'" + errorSuffix);
673  return;
674  }
675  }
676  if (myActiveRouteID != "") {
677  myActiveRouteStops.push_back(stop);
678  } else if (myActivePlan) {
679  std::string actType = attrs.getOptStringReporting(SUMO_ATTR_ACTTYPE, 0, ok, "waiting");
681  MSLane::dictionary(stop.lane)->getEdge(), stop.duration, stop.until, stop.startPos, actType));
682  } else {
683  myVehicleParameter->stops.push_back(stop);
684  }
685 }
686 
687 
688 /****************************************************************************/