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-sim.org/
13 // Copyright (C) 2001-2014 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/MSJunction.h>
40 #include <microsim/MSVehicleType.h>
41 #include <microsim/MSVehicle.h>
44 #include <microsim/MSLane.h>
45 #include "MSRouteHandler.h"
46 #include "MSPersonControl.h"
54 #include "MSNet.h"
55 
57 #include <microsim/MSGlobals.h>
59 
60 #ifdef CHECK_MEMORY_LEAKS
61 #include <foreign/nvwa/debug_new.h>
62 #endif // CHECK_MEMORY_LEAKS
63 
64 
65 // ===========================================================================
66 // method definitions
67 // ===========================================================================
68 MSRouteHandler::MSRouteHandler(const std::string& file,
69  bool addVehiclesDirectly) :
70  SUMORouteHandler(file),
71  myActivePlan(0),
72  myAddVehiclesDirectly(addVehiclesDirectly),
73  myCurrentVTypeDistribution(0),
74  myCurrentRouteDistribution(0) {
75  myActiveRoute.reserve(100);
76 }
77 
78 
80 }
81 
82 
83 void
85  const SUMOSAXAttributes& attrs) {
86  SUMORouteHandler::myStartElement(element, attrs);
87  switch (element) {
88  case SUMO_TAG_PERSON:
90  break;
91  case SUMO_TAG_RIDE: {
92  const std::string pid = myVehicleParameter->id;
93  bool ok = true;
94  MSEdge* from = 0;
95  const std::string desc = attrs.get<std::string>(SUMO_ATTR_LINES, pid.c_str(), ok);
96  StringTokenizer st(desc);
97  std::string bsID = attrs.getOpt<std::string>(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  }
105  if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
106  const std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, pid.c_str(), ok);
107  from = MSEdge::dictionary(fromID);
108  if (from == 0) {
109  throw ProcessError("The from edge '" + fromID + "' within a ride of person '" + pid + "' is not known.");
110  }
111  if (!myActivePlan->empty() && &myActivePlan->back()->getDestination() != from) {
112  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + fromID + "!=" + myActivePlan->back()->getDestination().getID() + ").");
113  }
114  if (myActivePlan->empty()) {
116  *from, -1, myVehicleParameter->depart, myVehicleParameter->departPos, "start"));
117  }
118  } else if (myActivePlan->empty()) {
119  throw ProcessError("The start edge within for person '" + pid + "' is not known.");
120  }
121  const std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, pid.c_str(), ok);
122  MSEdge* to = MSEdge::dictionary(toID);
123  if (to == 0) {
124  throw ProcessError("The to edge '" + toID + "' within a ride of person '" + pid + "' is not known.");
125  }
126  myActivePlan->push_back(new MSPerson::MSPersonStage_Driving(*to, bs, st.getVector()));
127  break;
128  }
129  case SUMO_TAG_WALK: {
130  myActiveRoute.clear();
131  bool ok = true;
132  SUMOReal departPos = attrs.getOpt<SUMOReal>(SUMO_ATTR_DEPARTPOS, myVehicleParameter->id.c_str(), ok, 0);
133  SUMOReal arrivalPos = attrs.getOpt<SUMOReal>(SUMO_ATTR_ARRIVALPOS, myVehicleParameter->id.c_str(), ok, -NUMERICAL_EPS);
134  const SUMOTime duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, 0, ok, -1);
135  if (attrs.hasAttribute(SUMO_ATTR_DURATION) && duration <= 0) {
136  throw ProcessError("Non-positive walking duration for '" + myVehicleParameter->id + "'.");
137  }
140  // need to check for explicitly set speed since we might have // DEFAULT_VEHTYPE
141  if (vtype != 0 && vtype->wasSet(VTYPEPARS_MAXSPEED_SET)) {
142  speed = vtype->getMaxSpeed();
143  }
144  speed = attrs.getOpt<SUMOReal>(SUMO_ATTR_SPEED, 0, ok, speed);
145  if (speed <= 0) {
146  throw ProcessError("Non-positive walking speed for '" + myVehicleParameter->id + "'.");
147  }
148  std::string bsID = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, 0, ok, "");
149  MSBusStop* bs = 0;
150  if (bsID != "") {
151  bs = MSNet::getInstance()->getBusStop(bsID);
152  if (bs == 0) {
153  throw ProcessError("Unknown bus stop '" + bsID + "' for person '" + myVehicleParameter->id + "'.");
154  }
155  arrivalPos = bs->getEndLanePosition();
156  }
157  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
159  } else {
160  if (attrs.hasAttribute(SUMO_ATTR_FROM) && attrs.hasAttribute(SUMO_ATTR_TO)) {
161  const std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok);
162  MSEdge* from = MSEdge::dictionary(fromID);
163  if (from == 0) {
164  throw ProcessError("The from edge '" + fromID + "' within a walk of person '" + myVehicleParameter->id + "' is not known.");
165  }
166  const std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok);
167  MSEdge* to = MSEdge::dictionary(toID);
168  if (to == 0) {
169  throw ProcessError("The to edge '" + toID + "' within a walk of person '" + myVehicleParameter->id + "' is not known.");
170  }
172  SUMOVehicleParameter::interpretEdgePos(departPos, from->getLength(), SUMO_ATTR_DEPARTPOS, "person walking from " + from->getID()),
173  SUMOVehicleParameter::interpretEdgePos(arrivalPos, to->getLength(), SUMO_ATTR_ARRIVALPOS, "person walking to " + to->getID()),
174  speed, 0, 0, myActiveRoute);
175  if (myActiveRoute.empty()) {
176  const std::string error = "No connection found between '" + from->getID() + "' and '" + to->getID() + "' for person '" + myVehicleParameter->id + "'.";
177  if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
178  myActiveRoute.push_back(from);
179  // XXX
180  //myActiveRoute.push_back(to);
181  //WRITE_WARNING(error);
182  } else {
183  WRITE_ERROR(error);
184  }
185  }
186  //std::cout << myVehicleParameter->id << " edges=" << toString(myActiveRoute) << "\n";
187  }
188  }
189  if (myActiveRoute.empty()) {
190  throw ProcessError("No edges to walk for person '" + myVehicleParameter->id + "'.");
191  }
192  if (!myActivePlan->empty() && &myActivePlan->back()->getDestination() != myActiveRoute.front()) {
193  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + myActiveRoute.front()->getID() + "!=" + myActivePlan->back()->getDestination().getID() + ").");
194  }
195  if (myActivePlan->empty()) {
197  *myActiveRoute.front(), -1, myVehicleParameter->depart, departPos, "start"));
198  }
199  myActivePlan->push_back(new MSPerson::MSPersonStage_Walking(myActiveRoute, bs, duration, speed, departPos, arrivalPos));
200  myActiveRoute.clear();
201  break;
202  }
203  case SUMO_TAG_FLOW:
204  if (attrs.hasAttribute(SUMO_ATTR_FROM) && attrs.hasAttribute(SUMO_ATTR_TO)) {
206  bool ok = true;
207  MSEdge::parseEdgesList(attrs.get<std::string>(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok),
208  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
209  MSEdge::parseEdgesList(attrs.get<std::string>(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok),
210  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
211  closeRoute(true);
212  }
213  break;
214  case SUMO_TAG_TRIP: {
215  bool ok = true;
217  MSEdge::parseEdgesList(attrs.get<std::string>(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok),
218  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
219  MSEdge::parseEdgesList(attrs.get<std::string>(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok),
220  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
221  } else {
222  const MSEdge* fromTaz = MSEdge::dictionary(myVehicleParameter->fromTaz + "-source");
223  if (fromTaz == 0) {
224  WRITE_ERROR("Source district '" + myVehicleParameter->fromTaz + "' not known for '" + myVehicleParameter->id + "'!");
225  } else if (fromTaz->getNoFollowing() == 0) {
226  WRITE_ERROR("Source district '" + myVehicleParameter->fromTaz + "' has no outgoing edges for '" + myVehicleParameter->id + "'!");
227  } else {
228  myActiveRoute.push_back(fromTaz->getFollower(0));
229  }
230  }
231  closeRoute(true);
232  closeVehicle();
233  }
234  break;
235  default:
236  break;
237  }
238  // parse embedded vtype information
239  if (myCurrentVType != 0 && element != SUMO_TAG_VTYPE && element != SUMO_TAG_PARAM) {
241  return;
242  }
243 }
244 
245 
246 void
248  bool ok = true;
249  myCurrentVTypeDistributionID = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
250  if (ok) {
252  if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
253  const std::string vTypes = attrs.get<std::string>(SUMO_ATTR_VTYPES, myCurrentVTypeDistributionID.c_str(), ok);
254  StringTokenizer st(vTypes);
255  while (st.hasNext()) {
256  std::string vtypeID = st.next();
258  if (type == 0) {
259  throw ProcessError("Unknown vtype '" + vtypeID + "' in distribution '" + myCurrentVTypeDistributionID + "'.");
260  }
262  }
263  }
264  }
265 }
266 
267 
268 void
270  if (myCurrentVTypeDistribution != 0) {
271  if (MSGlobals::gStateLoaded && MSNet::getInstance()->getVehicleControl().hasVTypeDistribution(myCurrentVTypeDistributionID)) {
273  return;
274  }
277  throw ProcessError("Vehicle type distribution '" + myCurrentVTypeDistributionID + "' is empty.");
278  }
279  if (!MSNet::getInstance()->getVehicleControl().addVTypeDistribution(myCurrentVTypeDistributionID, myCurrentVTypeDistribution)) {
281  throw ProcessError("Another vehicle type (or distribution) with the id '" + myCurrentVTypeDistributionID + "' exists.");
282  }
284  }
285 }
286 
287 
288 void
290  // check whether the id is really necessary
291  std::string rid;
292  if (myCurrentRouteDistribution != 0) {
294  rid = "distribution '" + myCurrentRouteDistributionID + "'";
295  } else if (myVehicleParameter != 0) {
296  // ok, a vehicle is wrapping the route,
297  // we may use this vehicle's id as default
298  myActiveRouteID = "!" + myVehicleParameter->id; // !!! document this
299  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
300  WRITE_WARNING("Ids of internal routes are ignored (vehicle '" + myVehicleParameter->id + "').");
301  }
302  } else {
303  bool ok = true;
304  myActiveRouteID = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok, false);
305  if (!ok) {
306  return;
307  }
308  rid = "'" + myActiveRouteID + "'";
309  }
310  if (myVehicleParameter != 0) { // have to do this here for nested route distributions
311  rid = "for vehicle '" + myVehicleParameter->id + "'";
312  }
313  bool ok = true;
314  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
315  MSEdge::parseEdgesList(attrs.get<std::string>(SUMO_ATTR_EDGES, myActiveRouteID.c_str(), ok), myActiveRoute, rid);
316  }
317  myActiveRouteRefID = attrs.getOpt<std::string>(SUMO_ATTR_REFID, myActiveRouteID.c_str(), ok, "");
319  WRITE_ERROR("Invalid reference to route '" + myActiveRouteRefID + "' in route " + rid + ".");
320  }
323 }
324 
325 
326 void
329  switch (element) {
330  case SUMO_TAG_VTYPE: {
332  delete myCurrentVType;
333  myCurrentVType = 0;
334  if (!MSNet::getInstance()->getVehicleControl().addVType(vehType)) {
335  const std::string id = vehType->getID();
336  delete vehType;
338  throw ProcessError("Another vehicle type (or distribution) with the id '" + id + "' exists.");
339  }
340  } else {
341  if (myCurrentVTypeDistribution != 0) {
343  }
344  }
345  }
346  break;
347  default:
348  break;
349  }
350 }
351 
352 
353 void
354 MSRouteHandler::closeRoute(const bool /* mayBeDisconnected */) {
355  if (myActiveRoute.size() == 0) {
356  delete myActiveRouteColor;
357  myActiveRouteColor = 0;
360  if (route != 0) {
362  route->addReference();
363  }
364  }
365  myActiveRouteID = "";
366  myActiveRouteRefID = "";
367  return;
368  }
369  if (myVehicleParameter != 0) {
370  throw ProcessError("Vehicle's '" + myVehicleParameter->id + "' route has no edges.");
371  } else {
372  throw ProcessError("Route '" + myActiveRouteID + "' has no edges.");
373  }
374  }
378  myActiveRoute.clear();
379  if (!MSRoute::dictionary(myActiveRouteID, route)) {
380  delete route;
382  if (myVehicleParameter != 0) {
383  if (MSNet::getInstance()->getVehicleControl().getVehicle(myVehicleParameter->id) == 0) {
384  throw ProcessError("Another route for vehicle '" + myVehicleParameter->id + "' exists.");
385  } else {
386  throw ProcessError("A vehicle with id '" + myVehicleParameter->id + "' already exists.");
387  }
388  } else {
389  throw ProcessError("Another route (or distribution) with the id '" + myActiveRouteID + "' exists.");
390  }
391  }
392  } else {
393  if (myCurrentRouteDistribution != 0) {
395  route->addReference();
396  }
397  }
398  }
399  myActiveRouteID = "";
400  myActiveRouteColor = 0;
401  myActiveRouteStops.clear();
402 }
403 
404 
405 void
407  // check whether the id is really necessary
408  bool ok = true;
409  if (myVehicleParameter != 0) {
410  // ok, a vehicle is wrapping the route,
411  // we may use this vehicle's id as default
412  myCurrentRouteDistributionID = "!" + myVehicleParameter->id; // !!! document this
413  } else {
414  myCurrentRouteDistributionID = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
415  if (!ok) {
416  return;
417  }
418  }
420  std::vector<SUMOReal> probs;
421  if (attrs.hasAttribute(SUMO_ATTR_PROBS)) {
422  bool ok = true;
423  StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_PROBS, myCurrentRouteDistributionID.c_str(), ok));
424  while (st.hasNext()) {
425  probs.push_back(TplConvert::_2SUMORealSec(st.next().c_str(), 1.0));
426  }
427  }
428  if (attrs.hasAttribute(SUMO_ATTR_ROUTES)) {
429  bool ok = true;
430  StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_ROUTES, myCurrentRouteDistributionID.c_str(), ok));
431  size_t probIndex = 0;
432  while (st.hasNext()) {
433  std::string routeID = st.next();
434  const MSRoute* route = MSRoute::dictionary(routeID);
435  if (route == 0) {
436  throw ProcessError("Unknown route '" + routeID + "' in distribution '" + myCurrentRouteDistributionID + "'.");
437  }
438  const SUMOReal prob = (probs.size() > probIndex ? probs[probIndex] : 1.0);
439  if (myCurrentRouteDistribution->add(prob, route, false)) {
440  route->addReference();
441  }
442  probIndex++;
443  }
444  if (probs.size() > 0 && probIndex != probs.size()) {
445  WRITE_WARNING("Got " + toString(probs.size()) + " probabilities for " + toString(probIndex) +
446  " routes in routeDistribution '" + myCurrentRouteDistributionID + "'");
447  }
448  }
449 }
450 
451 
452 void
454  if (myCurrentRouteDistribution != 0) {
455  const bool haveSameID = MSRoute::dictionary(myCurrentRouteDistributionID) != 0;
456  if (MSGlobals::gStateLoaded && haveSameID) {
458  return;
459  }
460  if (haveSameID) {
462  throw ProcessError("Another route (or distribution) with the id '" + myCurrentRouteDistributionID + "' exists.");
463  }
466  throw ProcessError("Route distribution '" + myCurrentRouteDistributionID + "' is empty.");
467  }
470  }
471 }
472 
473 
474 void
476  // get nested route
477  const MSRoute* route = MSRoute::dictionary("!" + myVehicleParameter->id);
480  // let's check whether this vehicle had to depart before the simulation starts
482  if (route != 0) {
483  route->addReference();
484  route->release();
485  }
486  return;
487  }
488  }
489  // get the vehicle's type
490  MSVehicleType* vtype = 0;
491  if (myVehicleParameter->vtypeid != "") {
492  vtype = vehControl.getVType(myVehicleParameter->vtypeid);
493  if (vtype == 0) {
494  throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
495  }
496  } else {
497  // there should be one (at least the default one)
498  vtype = vehControl.getVType();
499  }
500  if (route == 0) {
501  // if there is no nested route, try via the (hopefully) given route-id
503  }
504  if (route == 0) {
505  // nothing found? -> error
506  if (myVehicleParameter->routeid != "") {
507  throw ProcessError("The route '" + myVehicleParameter->routeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
508  } else {
509  throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has no route.");
510  }
511  }
512  myActiveRouteID = "";
513 
514  // try to build the vehicle
515  SUMOVehicle* vehicle = 0;
516  if (vehControl.getVehicle(myVehicleParameter->id) == 0) {
517  vehicle = vehControl.buildVehicle(myVehicleParameter, route, vtype);
518  // maybe we do not want this vehicle to be inserted due to scaling
519  unsigned int quota = vehControl.getQuota();
520  if (quota > 0) {
521  vehControl.addVehicle(myVehicleParameter->id, vehicle);
523  vehControl.addWaiting(*route->begin(), vehicle);
524  vehControl.registerOneWaitingForPerson();
525  } else {
526  // !!! no scaling for triggered vehicles yet
527  for (unsigned int i = 1; i < quota; i++) {
530  newPars->id = myVehicleParameter->id + "." + toString(i);
531  vehicle = vehControl.buildVehicle(newPars, route, vtype);
532  vehControl.addVehicle(newPars->id, vehicle);
533  }
534  }
536  myVehicleParameter = 0;
537  } else {
538  vehControl.deleteVehicle(vehicle, true);
539  myVehicleParameter = 0;
540  vehicle = 0;
541  }
542  } else {
543  // strange: another vehicle with the same id already exists
545  // and was not loaded while loading a simulation state
546  // -> error
547  throw ProcessError("Another vehicle with the id '" + myVehicleParameter->id + "' exists.");
548  } else {
549  // ok, it seems to be loaded previously while loading a simulation state
550  vehicle = 0;
551  }
552  }
553  // check whether the vehicle shall be added directly to the network or
554  // shall stay in the internal buffer
555  if (vehicle != 0) {
556  if (vehicle->getParameter().departProcedure == DEPART_GIVEN) {
558  }
559  }
560 }
561 
562 
563 void
565  if (myActivePlan->size() == 0) {
566  throw ProcessError("Person '" + myVehicleParameter->id + "' has no plan.");
567  }
569  if (type == 0) {
570  throw ProcessError("The type '" + myVehicleParameter->vtypeid + "' for person '" + myVehicleParameter->id + "' is not known.");
571  }
573  // @todo: consider myScale?
575  if (MSNet::getInstance()->getPersonControl().add(myVehicleParameter->id, person)) {
578  } else {
579  delete person;
580  throw ProcessError("Another person with the id '" + myVehicleParameter->id + "' exists.");
581  }
582  } else {
583  // warning already given
584  delete person;
585  }
586  myVehicleParameter = 0;
587  myActivePlan = 0;
588 }
589 
590 
591 void
594  return;
595  }
596  // let's check whether vehicles had to depart before the simulation starts
598  const SUMOTime offsetToBegin = string2time(OptionsCont::getOptions().getString("begin")) - myVehicleParameter->depart;
602  return;
603  }
604  }
605  if (MSNet::getInstance()->getVehicleControl().getVType(myVehicleParameter->vtypeid) == 0) {
606  throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
607  }
608  if (MSRoute::dictionary("!" + myVehicleParameter->id) == 0) {
609  // if not, try via the (hopefully) given route-id
611  if (myVehicleParameter->routeid != "") {
612  throw ProcessError("The route '" + myVehicleParameter->routeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
613  } else {
614  throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has no route.");
615  }
616  }
617  } else {
619  }
620  myActiveRouteID = "";
621 
622  // check whether the vehicle shall be added directly to the network or
623  // shall stay in the internal buffer
627  }
628  myVehicleParameter = 0;
629 }
630 
631 
632 void
634  std::string errorSuffix;
635  if (myActiveRouteID != "") {
636  errorSuffix = " in route '" + myActiveRouteID + "'.";
637  } else if (myActivePlan) {
638  errorSuffix = " in person '" + myVehicleParameter->id + "'.";
639  } else {
640  errorSuffix = " in vehicle '" + myVehicleParameter->id + "'.";
641  }
643  bool ok = parseStop(stop, attrs, errorSuffix, MsgHandler::getErrorInstance());
644  if (!ok) {
645  return;
646  }
647  // try to parse the assigned bus stop
648  if (stop.busstop != "") {
649  // ok, we have obviously a bus stop
651  if (bs != 0) {
652  const MSLane& l = bs->getLane();
653  stop.lane = l.getID();
654  stop.endPos = bs->getEndLanePosition();
655  stop.startPos = bs->getBeginLanePosition();
656  } else {
657  WRITE_ERROR("The bus stop '" + stop.busstop + "' is not known" + errorSuffix);
658  return;
659  }
660  } else {
661  // no, the lane and the position should be given
662  // get the lane
663  stop.lane = attrs.getOpt<std::string>(SUMO_ATTR_LANE, 0, ok, "");
664  if (ok && stop.lane != "") {
665  if (MSLane::dictionary(stop.lane) == 0) {
666  WRITE_ERROR("The lane '" + stop.lane + "' for a stop is not known" + errorSuffix);
667  return;
668  }
669  } else {
670  WRITE_ERROR("A stop must be placed on a bus stop or a lane" + errorSuffix);
671  return;
672  }
673  if (myActivePlan &&
674  !myActivePlan->empty() &&
675  &myActivePlan->back()->getDestination() != &MSLane::dictionary(stop.lane)->getEdge()) {
676  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + MSLane::dictionary(stop.lane)->getEdge().getID() + "!=" + myActivePlan->back()->getDestination().getID() + ").");
677  }
678  if (myActivePlan && myActivePlan->empty()) {
680  MSLane::dictionary(stop.lane)->getEdge(), -1, myVehicleParameter->depart, myVehicleParameter->departPos, "start"));
681  }
682  stop.endPos = attrs.getOpt<SUMOReal>(SUMO_ATTR_ENDPOS, 0, ok, MSLane::dictionary(stop.lane)->getLength());
683  if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
684  WRITE_WARNING("Deprecated attribute 'pos' in description of stop" + errorSuffix);
685  stop.endPos = attrs.getOpt<SUMOReal>(SUMO_ATTR_POSITION, 0, ok, stop.endPos);
686  }
687  stop.startPos = attrs.getOpt<SUMOReal>(SUMO_ATTR_STARTPOS, 0, ok, MAX2((SUMOReal)0., stop.endPos - 2 * POSITION_EPS));
688  const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, 0, ok, false);
689  if (!ok || !checkStopPos(stop.startPos, stop.endPos, MSLane::dictionary(stop.lane)->getLength(), POSITION_EPS, friendlyPos)) {
690  WRITE_ERROR("Invalid start or end position for stop on lane '" + stop.lane + "'" + errorSuffix);
691  return;
692  }
693  }
694  if (myActiveRouteID != "") {
695  myActiveRouteStops.push_back(stop);
696  } else if (myActivePlan) {
697  std::string actType = attrs.getOpt<std::string>(SUMO_ATTR_ACTTYPE, 0, ok, "waiting");
699  MSLane::dictionary(stop.lane)->getEdge(), stop.duration, stop.until, stop.startPos, actType));
700  } else {
701  myVehicleParameter->stops.push_back(stop);
702  }
703 }
704 
705 
706 /****************************************************************************/