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>
41 #include <microsim/MSEdge.h>
44 #include <microsim/MSLane.h>
45 #include "MSRouteHandler.h"
46 #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  myScale(-1.) {
76  if (oc.isSet("incremental-dua-step")) {
77  myScale = oc.getInt("incremental-dua-step") / static_cast<SUMOReal>(oc.getInt("incremental-dua-base"));
78  }
79  if (oc.isSet("scale")) {
80  myScale = oc.getFloat("scale");
81  }
82  myActiveRoute.reserve(100);
83 }
84 
85 
87 }
88 
89 
90 void
92  const SUMOSAXAttributes& attrs) {
93  SUMORouteHandler::myStartElement(element, attrs);
94  switch (element) {
95  case SUMO_TAG_PERSON:
97  break;
98  case SUMO_TAG_RIDE: {
99  const std::string pid = myVehicleParameter->id;
100  bool ok = true;
101  MSEdge* from = 0;
102  if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
103  const std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, pid.c_str(), ok);
104  from = MSEdge::dictionary(fromID);
105  if (from == 0) {
106  throw ProcessError("The from edge '" + fromID + "' within a ride of person '" + pid + "' is not known.");
107  }
108  if (!myActivePlan->empty() && &myActivePlan->back()->getDestination() != from) {
109  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + fromID + "!=" + myActivePlan->back()->getDestination().getID() + ").");
110  }
111  if (myActivePlan->empty()) {
113  }
114  }
115  const std::string toID = attrs.getStringReporting(SUMO_ATTR_TO, pid.c_str(), ok);
116  MSEdge* to = MSEdge::dictionary(toID);
117  if (to == 0) {
118  throw ProcessError("The to edge '" + toID + "' within a ride of person '" + pid + "' is not known.");
119  }
120  const std::string desc = attrs.getStringReporting(SUMO_ATTR_LINES, pid.c_str(), ok);
121  StringTokenizer st(desc);
122  myActivePlan->push_back(new MSPerson::MSPersonStage_Driving(*to, st.getVector()));
123  break;
124  }
125  case SUMO_TAG_WALK: {
126  myActiveRoute.clear();
127  bool ok = true;
129  if (myActiveRoute.empty()) {
130  throw ProcessError("No edges to walk for person '" + myVehicleParameter->id + "'.");
131  }
132  if (!myActivePlan->empty() && &myActivePlan->back()->getDestination() != myActiveRoute.front()) {
133  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + myActiveRoute.front()->getID() + "!=" + myActivePlan->back()->getDestination().getID() + ").");
134  }
135  if (myActivePlan->empty()) {
137  }
138  const SUMOTime duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, 0, ok, -1);
139  const SUMOReal speed = attrs.getOptSUMORealReporting(SUMO_ATTR_SPEED, 0, ok, -1);
140  myActivePlan->push_back(new MSPerson::MSPersonStage_Walking(myActiveRoute, duration, speed));
141  myActiveRoute.clear();
142  break;
143  }
144  case SUMO_TAG_FLOW:
145  if (attrs.hasAttribute(SUMO_ATTR_FROM) && attrs.hasAttribute(SUMO_ATTR_TO)) {
147  bool ok = true;
149  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
151  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
152  closeRoute();
153  }
154  break;
156  case SUMO_TAG_TRIP: {
157  bool ok = true;
160  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
162  myActiveRoute, "for vehicle '" + myVehicleParameter->id + "'");
163  } else {
164  const MSEdge* fromTaz = MSEdge::dictionary(myVehicleParameter->fromTaz + "-source");
165  if (fromTaz == 0) {
166  WRITE_ERROR("Source district '" + myVehicleParameter->fromTaz + "' not known for '" + myVehicleParameter->id + "'!");
167  } else if (fromTaz->getNoFollowing() == 0) {
168  WRITE_ERROR("Source district '" + myVehicleParameter->fromTaz + "' has no outgoing edges for '" + myVehicleParameter->id + "'!");
169  } else {
170  myActiveRoute.push_back(fromTaz->getFollower(0));
171  }
172  }
173  closeRoute();
174  closeVehicle();
175  }
176  break;
177  default:
178  break;
179  }
180  // parse embedded vtype information
181  if (myCurrentVType != 0 && element != SUMO_TAG_VTYPE && element != SUMO_TAG_VTYPE__DEPRECATED) {
183  return;
184  }
185 }
186 
187 
188 void
190  bool ok = true;
192  if (ok) {
195  const std::string vTypes = attrs.getStringReporting(SUMO_ATTR_VTYPES, myCurrentVTypeDistributionID.c_str(), ok);
196  StringTokenizer st(vTypes);
197  while (st.hasNext()) {
198  std::string vtypeID = st.next();
200  if (type == 0) {
201  throw ProcessError("Unknown vtype '" + vtypeID + "' in distribution '" + myCurrentVTypeDistributionID + "'.");
202  }
204  }
205  }
206  }
207 }
208 
209 
210 void
212  if (myCurrentVTypeDistribution != 0) {
215  WRITE_ERROR("Vehicle type distribution '" + myCurrentVTypeDistributionID + "' is empty.");
216  } else if (!MSNet::getInstance()->getVehicleControl().addVTypeDistribution(myCurrentVTypeDistributionID, myCurrentVTypeDistribution)) {
218  WRITE_ERROR("Another vehicle type (or distribution) with the id '" + myCurrentVTypeDistributionID + "' exists.");
219  }
221  }
222 }
223 
224 
225 void
227  // check whether the id is really necessary
228  std::string rid;
229  if (myCurrentRouteDistribution != 0) {
231  rid = "distribution '" + myCurrentRouteDistributionID + "'";
232  } else if (myVehicleParameter != 0) {
233  // ok, a vehicle is wrapping the route,
234  // we may use this vehicle's id as default
235  myActiveRouteID = "!" + myVehicleParameter->id; // !!! document this
236  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
237  WRITE_WARNING("Ids of internal routes are ignored (vehicle '" + myVehicleParameter->id + "').");
238  }
239  } else {
240  bool ok = true;
241  myActiveRouteID = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok, false);
242  if (!ok) {
243  return;
244  }
245  rid = "'" + myActiveRouteID + "'";
246  }
247  if (myVehicleParameter != 0) { // have to do this here for nested route distributions
248  rid = "for vehicle '" + myVehicleParameter->id + "'";
249  }
250  bool ok = true;
251  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
253  }
256  WRITE_ERROR("Invalid reference to route '" + myActiveRouteRefID + "' in route " + rid + ".");
257  }
260 }
261 
262 
263 void
266  switch (element) {
267  case SUMO_TAG_VTYPE: {
269  delete myCurrentVType;
270  myCurrentVType = 0;
271  if (!MSNet::getInstance()->getVehicleControl().addVType(vehType)) {
272  const std::string id = vehType->getID();
273  delete vehType;
274 #ifdef HAVE_MESOSIM
275  if (!MSGlobals::gStateLoaded) {
276 #endif
277  throw ProcessError("Another vehicle type (or distribution) with the id '" + id + "' exists.");
278 #ifdef HAVE_MESOSIM
279  }
280 #endif
281  } else {
282  if (myCurrentVTypeDistribution != 0) {
284  }
285  }
286  }
287  break;
288  default:
289  break;
290  }
291 }
292 
293 
294 void
296  if (myActiveRoute.size() == 0) {
299  myActiveRouteID = "";
300  myActiveRouteRefID = "";
301  return;
302  }
303  if (myVehicleParameter != 0) {
304  throw ProcessError("Vehicle's '" + myVehicleParameter->id + "' route has no edges.");
305  } else {
306  throw ProcessError("Route '" + myActiveRouteID + "' has no edges.");
307  }
308  }
312  myActiveRoute.clear();
313  if (!MSRoute::dictionary(myActiveRouteID, route)) {
314  delete route;
315 #ifdef HAVE_MESOSIM
316  if (!MSGlobals::gStateLoaded) {
317 #endif
318  if (myVehicleParameter != 0) {
319  if (MSNet::getInstance()->getVehicleControl().getVehicle(myVehicleParameter->id) == 0) {
320  throw ProcessError("Another route for vehicle '" + myVehicleParameter->id + "' exists.");
321  } else {
322  throw ProcessError("A vehicle with id '" + myVehicleParameter->id + "' already exists.");
323  }
324  } else {
325  throw ProcessError("Another route (or distribution) with the id '" + myActiveRouteID + "' exists.");
326  }
327 #ifdef HAVE_MESOSIM
328  }
329 #endif
330  } else {
331  if (myCurrentRouteDistribution != 0) {
333  }
334  }
335  myActiveRouteID = "";
336  myActiveRouteStops.clear();
337 }
338 
339 
340 void
342  // check whether the id is really necessary
343  bool ok = true;
344  if (myVehicleParameter != 0) {
345  // ok, a vehicle is wrapping the route,
346  // we may use this vehicle's id as default
347  myCurrentRouteDistributionID = "!" + myVehicleParameter->id; // !!! document this
348  } else {
350  if (!ok) {
351  return;
352  }
353  }
355  if (attrs.hasAttribute(SUMO_ATTR_ROUTES)) {
356  bool ok = true;
358  while (st.hasNext()) {
359  std::string routeID = st.next();
360  const MSRoute* route = MSRoute::dictionary(routeID);
361  if (route == 0) {
362  throw ProcessError("Unknown route '" + routeID + "' in distribution '" + myCurrentRouteDistributionID + "'.");
363  }
364  myCurrentRouteDistribution->add(1., route, false);
365  }
366  }
367 }
368 
369 
370 void
372  if (myCurrentRouteDistribution != 0) {
375  WRITE_ERROR("Route distribution '" + myCurrentRouteDistributionID + "' is empty.");
378  WRITE_ERROR("Another route (or distribution) with the id '" + myCurrentRouteDistributionID + "' exists.");
379  }
381  }
382 }
383 
384 
385 void
387  // get nested route
388  const MSRoute* route = MSRoute::dictionary("!" + myVehicleParameter->id);
391  // let's check whether this vehicle had to depart before the simulation starts
393  if (route != 0) {
394  route->addReference();
395  route->release();
396  }
397  return;
398  }
399  }
400  // get the vehicle's type
401  MSVehicleType* vtype = 0;
402  if (myVehicleParameter->vtypeid != "") {
403  vtype = vehControl.getVType(myVehicleParameter->vtypeid);
404  if (vtype == 0) {
405  throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
406  }
407  } else {
408  // there should be one (at least the default one)
409  vtype = vehControl.getVType();
410  }
411  if (route == 0) {
412  // if there is no nested route, try via the (hopefully) given route-id
414  }
415  if (route == 0) {
416  // nothing found? -> error
417  if (myVehicleParameter->routeid != "") {
418  throw ProcessError("The route '" + myVehicleParameter->routeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
419  } else {
420  throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has no route.");
421  }
422  }
423  myActiveRouteID = "";
424 
425  // try to build the vehicle
426  SUMOVehicle* vehicle = 0;
427  if (vehControl.getVehicle(myVehicleParameter->id) == 0) {
428  vehicle = vehControl.buildVehicle(myVehicleParameter, route, vtype);
429  // maybe we do not want this vehicle to be inserted due to scaling
430  if (myScale < 0 || vehControl.isInQuota(myScale)) {
431  // add the vehicle to the vehicle control
432  vehControl.addVehicle(myVehicleParameter->id, vehicle);
434  vehControl.addWaiting(*route->begin(), vehicle);
435  vehControl.registerOneWaitingForPerson();
436  }
438  myVehicleParameter = 0;
439  } else {
440  vehControl.deleteVehicle(vehicle, true);
441  myVehicleParameter = 0;
442  vehicle = 0;
443  }
444  } else {
445  // strange: another vehicle with the same id already exists
446 #ifdef HAVE_MESOSIM
447  if (!MSGlobals::gStateLoaded) {
448 #endif
449  // and was not loaded while loading a simulation state
450  // -> error
451  throw ProcessError("Another vehicle with the id '" + myVehicleParameter->id + "' exists.");
452 #ifdef HAVE_MESOSIM
453  } else {
454  // ok, it seems to be loaded previously while loading a simulation state
455  vehicle = 0;
456  }
457 #endif
458  }
459  // check whether the vehicle shall be added directly to the network or
460  // shall stay in the internal buffer
461  if (vehicle != 0) {
462  if (vehicle->getParameter().departProcedure == DEPART_GIVEN) {
464  }
465  }
466 }
467 
468 
469 void
471  if (myActivePlan->size() == 0) {
472  throw ProcessError("Person '" + myVehicleParameter->id + "' has no plan.");
473  }
475  // @todo: consider myScale?
476  if ((myAddVehiclesDirectly || checkLastDepart()) && MSNet::getInstance()->getPersonControl().add(myVehicleParameter->id, person)) {
479  } else {
480  delete person;
481  }
482  myVehicleParameter = 0;
483  myActivePlan = 0;
484 }
485 
486 
487 void
489  // @todo: consider myScale?
490  // let's check whether vehicles had to depart before the simulation starts
492  SUMOTime offsetToBegin = string2time(OptionsCont::getOptions().getString("begin")) - myVehicleParameter->depart;
496  return;
497  }
498  }
499  if (MSNet::getInstance()->getVehicleControl().getVType(myVehicleParameter->vtypeid) == 0) {
500  throw ProcessError("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
501  }
502  if (MSRoute::dictionary("!" + myVehicleParameter->id) == 0) {
503  // if not, try via the (hopefully) given route-id
505  if (myVehicleParameter->routeid != "") {
506  throw ProcessError("The route '" + myVehicleParameter->routeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
507  } else {
508  throw ProcessError("Vehicle '" + myVehicleParameter->id + "' has no route.");
509  }
510  }
511  } else {
513  }
514  myActiveRouteID = "";
515 
516  // check whether the vehicle shall be added directly to the network or
517  // shall stay in the internal buffer
521  }
522  myVehicleParameter = 0;
523 }
524 
525 
526 void
528  bool ok = true;
529  std::string errorSuffix;
530  if (myActiveRouteID != "") {
531  errorSuffix = " in route '" + myActiveRouteID + "'.";
532  } else if (myActivePlan) {
533  errorSuffix = " in person '" + myVehicleParameter->id + "'.";
534  } else {
535  errorSuffix = " in vehicle '" + myVehicleParameter->id + "'.";
536  }
538  // try to parse the assigned bus stop
539  stop.busstop = attrs.getOptStringReporting(SUMO_ATTR_BUS_STOP, 0, ok, "");
540  if (stop.busstop != "") {
541  // ok, we have obviously a bus stop
543  if (bs != 0) {
544  const MSLane& l = bs->getLane();
545  stop.lane = l.getID();
546  stop.endPos = bs->getEndLanePosition();
547  stop.startPos = bs->getBeginLanePosition();
548  } else {
549  WRITE_ERROR("The bus stop '" + stop.busstop + "' is not known" + errorSuffix);
550  return;
551  }
552  } else {
553  // no, the lane and the position should be given
554  // get the lane
555  stop.lane = attrs.getOptStringReporting(SUMO_ATTR_LANE, 0, ok, "");
556  if (ok && stop.lane != "") {
557  if (MSLane::dictionary(stop.lane) == 0) {
558  WRITE_ERROR("The lane '" + stop.lane + "' for a stop is not known" + errorSuffix);
559  return;
560  }
561  } else {
562  WRITE_ERROR("A stop must be placed on a bus stop or a lane" + errorSuffix);
563  return;
564  }
565  if (myActivePlan &&
566  !myActivePlan->empty() &&
567  &myActivePlan->back()->getDestination() != &MSLane::dictionary(stop.lane)->getEdge()) {
568  throw ProcessError("Disconnected plan for person '" + myVehicleParameter->id + "' (" + MSLane::dictionary(stop.lane)->getEdge().getID() + "!=" + myActivePlan->back()->getDestination().getID() + ").");
569  }
570  stop.endPos = attrs.getOptSUMORealReporting(SUMO_ATTR_ENDPOS, 0, ok, MSLane::dictionary(stop.lane)->getLength());
571  if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
572  WRITE_WARNING("Deprecated attribute 'pos' in description of stop" + errorSuffix);
573  stop.endPos = attrs.getOptSUMORealReporting(SUMO_ATTR_POSITION, 0, ok, stop.endPos);
574  }
575  stop.startPos = attrs.getOptSUMORealReporting(SUMO_ATTR_STARTPOS, 0, ok, stop.endPos - 2 * POSITION_EPS);
576  const bool friendlyPos = attrs.getOptBoolReporting(SUMO_ATTR_FRIENDLY_POS, 0, ok, false);
577  if (!ok || !checkStopPos(stop.startPos, stop.endPos, MSLane::dictionary(stop.lane)->getLength(), POSITION_EPS, friendlyPos)) {
578  WRITE_ERROR("Invalid start or end position for stop" + errorSuffix);
579  return;
580  }
581  }
582 
583  // get the standing duration
585  stop.triggered = attrs.getOptBoolReporting(SUMO_ATTR_TRIGGERED, 0, ok, true);
586  stop.duration = -1;
587  stop.until = -1;
588  } else {
589  stop.duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, 0, ok, -1);
590  stop.until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, 0, ok, -1);
591  if (!ok || (stop.duration < 0 && stop.until < 0)) {
592  WRITE_ERROR("Invalid duration or end time is given for a stop" + errorSuffix);
593  return;
594  }
595  stop.triggered = attrs.getOptBoolReporting(SUMO_ATTR_TRIGGERED, 0, ok, false);
596  }
597  stop.parking = attrs.getOptBoolReporting(SUMO_ATTR_PARKING, 0, ok, stop.triggered);
598  if (!ok) {
599  WRITE_ERROR("Invalid bool for 'triggered' or 'parking' for stop" + errorSuffix);
600  return;
601  }
602  const std::string idx = attrs.getOptStringReporting(SUMO_ATTR_INDEX, 0, ok, "end");
603  if (idx == "end") {
604  stop.index = STOP_INDEX_END;
605  } else if (idx == "fit") {
606  stop.index = STOP_INDEX_FIT;
607  } else {
608  stop.index = attrs.getIntReporting(SUMO_ATTR_INDEX, 0, ok);
609  if (!ok || stop.index < 0) {
610  WRITE_ERROR("Invalid 'index' for stop" + errorSuffix);
611  return;
612  }
613  }
614  if (myActiveRouteID != "") {
615  myActiveRouteStops.push_back(stop);
616  } else if (myActivePlan) {
617  myActivePlan->push_back(new MSPerson::MSPersonStage_Waiting(MSLane::dictionary(stop.lane)->getEdge(), stop.duration, stop.until));
618  } else {
619  myVehicleParameter->stops.push_back(stop);
620  }
621 }
622 
623 
624 /****************************************************************************/