SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RORouteHandler.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 <iostream>
47 #include <utils/xml/XMLSubSys.h>
49 #include "RONet.h"
50 #include "ROLane.h"
51 #include "RORouteHandler.h"
52 
53 #ifdef CHECK_MEMORY_LEAKS
54 #include <foreign/nvwa/debug_new.h>
55 #endif // CHECK_MEMORY_LEAKS
56 
57 
58 // ===========================================================================
59 // method definitions
60 // ===========================================================================
61 RORouteHandler::RORouteHandler(RONet& net, const std::string& file,
62  const bool tryRepair,
63  const bool emptyDestinationsAllowed,
64  const bool ignoreErrors) :
65  SUMORouteHandler(file),
66  myPedestrianRouter(0),
67  myNet(net),
68  myActivePlan(0),
69  myActivePlanSize(0),
70  myTryRepair(tryRepair),
71  myEmptyDestinationsAllowed(emptyDestinationsAllowed),
72  myErrorOutput(ignoreErrors ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
73  myCurrentVTypeDistribution(0),
74  myCurrentAlternatives(0) {
75  myActiveRoute.reserve(100);
76 }
77 
78 
80  delete myPedestrianRouter;
81 }
82 
83 
84 void
85 RORouteHandler::parseFromViaTo(std::string element,
86  const SUMOSAXAttributes& attrs) {
87  bool useTaz = OptionsCont::getOptions().getBool("with-taz");
88  if (useTaz && !myVehicleParameter->wasSet(VEHPARS_TAZ_SET)) {
89  WRITE_WARNING("Taz usage was requested but no taz present in " + element + " '" + myVehicleParameter->id + "'!");
90  useTaz = false;
91  } else if (!useTaz && !attrs.hasAttribute(SUMO_ATTR_FROM) && myVehicleParameter->wasSet(VEHPARS_TAZ_SET)) {
92  WRITE_WARNING("'from' attribute missing using taz for " + element + " '" + myVehicleParameter->id + "'!");
93  useTaz = true;
94  }
95  if (useTaz) {
96  const ROEdge* fromTaz = myNet.getEdge(myVehicleParameter->fromTaz + "-source");
97  if (fromTaz == 0) {
98  myErrorOutput->inform("Source taz '" + myVehicleParameter->fromTaz + "' not known for " + element + " '" + myVehicleParameter->id + "'!");
99  } else if (fromTaz->getNoFollowing() == 0) {
100  myErrorOutput->inform("Source taz '" + myVehicleParameter->fromTaz + "' has no outgoing edges for " + element + " '" + myVehicleParameter->id + "'!");
101  } else {
102  myActiveRoute.push_back(fromTaz);
103  }
104  const ROEdge* toTaz = myNet.getEdge(myVehicleParameter->toTaz + "-sink");
105  if (toTaz == 0) {
106  myErrorOutput->inform("Sink taz '" + myVehicleParameter->toTaz + "' not known for " + element + " '" + myVehicleParameter->id + "'!");
107  } else {
108  myActiveRoute.push_back(toTaz);
109  }
110  } else {
111  bool ok = true;
112  parseEdges(attrs.get<std::string>(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok),
113  myActiveRoute, "for " + element + " '" + myVehicleParameter->id + "'");
114  parseEdges(attrs.getOpt<std::string>(SUMO_ATTR_VIA, myVehicleParameter->id.c_str(), ok, "", true),
115  myActiveRoute, "for " + element + " '" + myVehicleParameter->id + "'");
116  parseEdges(attrs.get<std::string>(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok, !myEmptyDestinationsAllowed),
117  myActiveRoute, "for " + element + " '" + myVehicleParameter->id + "'");
118  }
120  if (myVehicleParameter->routeid == "") {
122  }
123  closeRoute(true);
124 }
125 
126 
127 
128 void
130  const SUMOSAXAttributes& attrs) {
131  SUMORouteHandler::myStartElement(element, attrs);
132  switch (element) {
133  case SUMO_TAG_PERSON:
134  myActivePlan = new OutputDevice_String(false, 1);
135  myActivePlanSize = 0;
137  (*myActivePlan) << attrs;
138  break;
139  case SUMO_TAG_RIDE: {
141  (*myActivePlan) << attrs;
144  break;
145  }
146  case SUMO_TAG_WALK: {
147  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
148  // copy walk as it is
149  // XXX allow --repair?
151  (*myActivePlan) << attrs;
154  } else {
155  routePedestrian(attrs, *myActivePlan);
156  }
157  break;
158  }
159  case SUMO_TAG_FLOW:
161  parseFromViaTo("flow", attrs);
162  break;
163  case SUMO_TAG_TRIP: {
165  parseFromViaTo("trip", attrs);
166  closeVehicle();
167  }
168  break;
169  default:
170  break;
171  }
172  // parse embedded vtype information
173  if (myCurrentVType != 0 && element != SUMO_TAG_VTYPE) {
175  return;
176  }
177 }
178 
179 
180 void
182  bool ok = true;
183  myCurrentVTypeDistributionID = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
184  if (ok) {
186  if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
187  const std::string vTypes = attrs.get<std::string>(SUMO_ATTR_VTYPES, myCurrentVTypeDistributionID.c_str(), ok);
188  StringTokenizer st(vTypes);
189  while (st.hasNext()) {
190  SUMOVTypeParameter* type = myNet.getVehicleTypeSecure(st.next());
191  myCurrentVTypeDistribution->add(1., type);
192  }
193  }
194  }
195 }
196 
197 
198 void
200  if (myCurrentVTypeDistribution != 0) {
203  myErrorOutput->inform("Vehicle type distribution '" + myCurrentVTypeDistributionID + "' is empty.");
206  myErrorOutput->inform("Another vehicle type (or distribution) with the id '" + myCurrentVTypeDistributionID + "' exists.");
207  }
209  }
210 }
211 
212 
213 void
215  // check whether the id is really necessary
216  std::string rid;
217  if (myCurrentAlternatives != 0) {
219  rid = "distribution '" + myCurrentAlternatives->getID() + "'";
220  } else if (myVehicleParameter != 0) {
221  // ok, a vehicle is wrapping the route,
222  // we may use this vehicle's id as default
223  myVehicleParameter->routeid = myActiveRouteID = "!" + myVehicleParameter->id; // !!! document this
224  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
225  WRITE_WARNING("Ids of internal routes are ignored (vehicle '" + myVehicleParameter->id + "').");
226  }
227  } else {
228  bool ok = true;
229  myActiveRouteID = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
230  if (!ok) {
231  return;
232  }
233  rid = "'" + myActiveRouteID + "'";
234  }
235  if (myVehicleParameter != 0) { // have to do this here for nested route distributions
236  rid = "for vehicle '" + myVehicleParameter->id + "'";
237  }
238  bool ok = true;
239  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
240  parseEdges(attrs.get<std::string>(SUMO_ATTR_EDGES, myActiveRouteID.c_str(), ok), myActiveRoute, rid);
241  }
242  myActiveRouteRefID = attrs.getOpt<std::string>(SUMO_ATTR_REFID, myActiveRouteID.c_str(), ok, "");
244  myErrorOutput->inform("Invalid reference to route '" + myActiveRouteRefID + "' in route " + rid + ".");
245  }
246  if (myCurrentAlternatives != 0 && !attrs.hasAttribute(SUMO_ATTR_PROB)) {
247  WRITE_WARNING("No probability for a route in '" + rid + "', using default.");
248  }
250  if (ok && myActiveRouteProbability < 0) {
251  myErrorOutput->inform("Invalid probability for route '" + myActiveRouteID + "'.");
252  }
254  ok = true;
255  myCurrentCosts = attrs.getOpt<SUMOReal>(SUMO_ATTR_COST, myActiveRouteID.c_str(), ok, -1);
256  if (ok && myCurrentCosts != -1 && myCurrentCosts < 0) {
257  myErrorOutput->inform("Invalid cost for route '" + myActiveRouteID + "'.");
258  }
259 }
260 
261 
262 void
265  switch (element) {
266  case SUMO_TAG_VTYPE: {
268  if (myCurrentVTypeDistribution != 0) {
270  }
271  }
272  myCurrentVType = 0;
273  }
274  break;
275  default:
276  break;
277  }
278 }
279 
280 
281 void
282 RORouteHandler::closeRoute(const bool mayBeDisconnected) {
283  if (myActiveRoute.size() == 0) {
284  if (myActiveRouteRefID != "" && myCurrentAlternatives != 0) {
286  myActiveRouteID = "";
287  myActiveRouteRefID = "";
288  return;
289  }
290  if (myVehicleParameter != 0) {
291  myErrorOutput->inform("Vehicle's '" + myVehicleParameter->id + "' route has no edges.");
292  } else {
293  myErrorOutput->inform("Route '" + myActiveRouteID + "' has no edges.");
294  }
295  myActiveRouteID = "";
296  myActiveRouteStops.clear();
297  return;
298  }
301  myActiveRoute.clear();
302  if (myCurrentAlternatives == 0) {
303  if (myNet.getRouteDef(myActiveRouteID) != 0) {
304  delete route;
305  if (myVehicleParameter != 0) {
306  myErrorOutput->inform("Another route for vehicle '" + myVehicleParameter->id + "' exists.");
307  } else {
308  myErrorOutput->inform("Another route (or distribution) with the id '" + myActiveRouteID + "' exists.");
309  }
310  myActiveRouteID = "";
311  myActiveRouteStops.clear();
312  return;
313  } else {
314  myCurrentAlternatives = new RORouteDef(myActiveRouteID, 0, mayBeDisconnected || myTryRepair);
318  }
319  } else {
321  }
322  myActiveRouteID = "";
323  myActiveRouteStops.clear();
324 }
325 
326 
327 void
329  // check whether the id is really necessary
330  bool ok = true;
331  std::string id;
332  if (myVehicleParameter != 0) {
333  // ok, a vehicle is wrapping the route,
334  // we may use this vehicle's id as default
335  myVehicleParameter->routeid = id = "!" + myVehicleParameter->id; // !!! document this
336  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
337  WRITE_WARNING("Ids of internal route distributions are ignored (vehicle '" + myVehicleParameter->id + "').");
338  }
339  } else {
340  id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
341  if (!ok) {
342  return;
343  }
344  }
345  // try to get the index of the last element
346  int index = attrs.get<int>(SUMO_ATTR_LAST, id.c_str(), ok);
347  if (ok && index < 0) {
348  myErrorOutput->inform("Negative index of a route alternative (id='" + id + "').");
349  return;
350  }
351  // build the alternative cont
352  myCurrentAlternatives = new RORouteDef(id, index, myTryRepair);
353  if (attrs.hasAttribute(SUMO_ATTR_ROUTES)) {
354  ok = true;
355  StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_ROUTES, id.c_str(), ok));
356  while (st.hasNext()) {
357  const std::string routeID = st.next();
358  const RORouteDef* route = myNet.getRouteDef(routeID);
359  if (route == 0) {
360  myErrorOutput->inform("Unknown route '" + routeID + "' in distribution '" + id + "'.");
361  } else {
363  }
364  }
365  }
366 }
367 
368 
369 void
371  if (myCurrentAlternatives != 0) {
373  myErrorOutput->inform("Route distribution '" + myCurrentAlternatives->getID() + "' is empty.");
374  delete myCurrentAlternatives;
375  } else if (!myNet.addRouteDef(myCurrentAlternatives)) {
376  myErrorOutput->inform("Another route (or distribution) with the id '" + myCurrentAlternatives->getID() + "' exists.");
377  delete myCurrentAlternatives;
378  }
380  }
381 }
382 
383 
384 void
386  // get the vehicle id
388  return;
389  }
390  // get vehicle type
392  // get the route
394  if (route == 0) {
395  myErrorOutput->inform("The route of the vehicle '" + myVehicleParameter->id + "' is not known.");
396  return;
397  }
398  if (route->getID()[0] != '!') {
399  route = route->copy("!" + myVehicleParameter->id);
400  }
401  // build the vehicle
402  if (!MsgHandler::getErrorInstance()->wasInformed()) {
403  ROVehicle* veh = new ROVehicle(*myVehicleParameter, route, type, &myNet);
406  }
407 }
408 
409 
410 void
413  if (myActivePlanSize > 0) {
416  } else {
417  WRITE_WARNING("Discarding person '" + myVehicleParameter->id + "' because it's plan is empty");
418  }
419  delete myVehicleParameter;
420  myVehicleParameter = 0;
421  delete myActivePlan;
422  myActivePlan = 0;
423  myActivePlanSize = 0;
424 }
425 
426 
427 void
429  // @todo: consider myScale?
431  delete myVehicleParameter;
432  myVehicleParameter = 0;
433  return;
434  }
435  // let's check whether vehicles had to depart before the simulation starts
437  const SUMOTime offsetToBegin = string2time(OptionsCont::getOptions().getString("begin")) - myVehicleParameter->depart;
441  delete myVehicleParameter;
442  myVehicleParameter = 0;
443  return;
444  }
445  }
448  if (type == 0) {
449  myErrorOutput->inform("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
450  delete myVehicleParameter;
451  myVehicleParameter = 0;
452  return;
453  }
454  if (route == 0) {
455  myErrorOutput->inform("Vehicle '" + myVehicleParameter->id + "' has no route.");
456  delete myVehicleParameter;
457  myVehicleParameter = 0;
458  return;
459  }
460  myActiveRouteID = "";
461  myNet.addFlow(myVehicleParameter, OptionsCont::getOptions().getBool("randomize-flows"));
463  myVehicleParameter = 0;
464 }
465 
466 
467 void
469  if (myActivePlan) {
471  (*myActivePlan) << attrs;
474  return;
475  }
476  std::string errorSuffix;
477  if (myActiveRouteID != "") {
478  errorSuffix = " in route '" + myActiveRouteID + "'.";
479  } else {
480  errorSuffix = " in vehicle '" + myVehicleParameter->id + "'.";
481  }
483  bool ok = parseStop(stop, attrs, errorSuffix, myErrorOutput);
484  if (!ok) {
485  return;
486  }
487  // try to parse the assigned bus stop
488  if (stop.busstop != "") {
489  const SUMOVehicleParameter::Stop* busstop = myNet.getBusStop(stop.busstop);
490  if (busstop == 0) {
491  myErrorOutput->inform("Unknown bus stop '" + stop.busstop + "'" + errorSuffix);
492  } else {
493  stop.lane = busstop->lane;
494  stop.endPos = busstop->endPos;
495  stop.startPos = busstop->startPos;
496  }
497  } else {
498  // no, the lane and the position should be given
499  stop.lane = attrs.getOpt<std::string>(SUMO_ATTR_LANE, 0, ok, "");
500  if (!ok || stop.lane == "") {
501  myErrorOutput->inform("A stop must be placed on a bus stop or a lane" + errorSuffix);
502  return;
503  }
504  ROEdge* edge = myNet.getEdge(stop.lane.substr(0, stop.lane.rfind('_')));
505  if (edge == 0) {
506  myErrorOutput->inform("The lane '" + stop.lane + "' for a stop is not known" + errorSuffix);
507  return;
508  }
509  stop.endPos = attrs.getOpt<SUMOReal>(SUMO_ATTR_ENDPOS, 0, ok, edge->getLength());
510  stop.startPos = attrs.getOpt<SUMOReal>(SUMO_ATTR_STARTPOS, 0, ok, stop.endPos - 2 * POSITION_EPS);
511  const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, 0, ok, false);
512  if (!ok || !checkStopPos(stop.startPos, stop.endPos, edge->getLength(), POSITION_EPS, friendlyPos)) {
513  myErrorOutput->inform("Invalid start or end position for stop" + errorSuffix);
514  return;
515  }
516  }
517  if (myVehicleParameter != 0) {
518  myVehicleParameter->stops.push_back(stop);
519  } else {
520  myActiveRouteStops.push_back(stop);
521  }
522 }
523 
524 
525 void
526 RORouteHandler::parseEdges(const std::string& desc, std::vector<const ROEdge*>& into,
527  const std::string& rid) {
528  if (desc[0] == BinaryFormatter::BF_ROUTE) {
529  std::istringstream in(desc, std::ios::binary);
530  char c;
531  in >> c;
532  FileHelpers::readEdgeVector(in, into, rid);
533  } else {
534  for (StringTokenizer st(desc); st.hasNext();) {
535  const std::string id = st.next();
536  const ROEdge* edge = myNet.getEdge(id);
537  if (edge == 0) {
538  myErrorOutput->inform("The edge '" + id + "' within the route " + rid + " is not known.");
539  } else {
540  into.push_back(edge);
541  }
542  }
543  }
544 }
545 
546 
547 bool
549  bool ok = true;
550  const char* id = myVehicleParameter->id.c_str();
551  SUMOReal departPos = attrs.getOpt<SUMOReal>(SUMO_ATTR_DEPARTPOS, id, ok, 0);
552  SUMOReal arrivalPos = attrs.getOpt<SUMOReal>(SUMO_ATTR_ARRIVALPOS, id, ok, -NUMERICAL_EPS);
553  assert(!attrs.hasAttribute(SUMO_ATTR_EDGES));
554  assert(myActiveRoute.size() == 0);
555  const std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, id, ok);
556  const std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, id, ok);
557  const ROEdge* from = myNet.getEdge(fromID);
558  if (from == 0) {
559  myErrorOutput->inform("The edge '" + fromID + "' within a walk of " + myVehicleParameter->id + " is not known."
560  + "\n The route can not be build.");
561  ok = false;
562  }
563  const ROEdge* to = myNet.getEdge(toID);
564  if (to == 0) {
565  myErrorOutput->inform("The edge '" + toID + "' within a walk of " + myVehicleParameter->id + " is not known."
566  + "\n The route can not be build.");
567  ok = false;
568  }
569  if (ok) {
570  if (myPedestrianRouter == 0) {
572  }
573  myPedestrianRouter->compute(from, to,
574  SUMOVehicleParameter::interpretEdgePos(departPos, from->getLength(), SUMO_ATTR_DEPARTPOS, "person walking from " + fromID),
575  SUMOVehicleParameter::interpretEdgePos(arrivalPos, to->getLength(), SUMO_ATTR_ARRIVALPOS, "person walking to " + toID),
577  if (myActiveRoute.empty()) {
578  myErrorOutput->inform("No connection found between '" + fromID + "' and '" + toID + "' for person '" + myVehicleParameter->id + "'.");
579  return false;
580  }
582  if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
583  plan.writeAttr(SUMO_ATTR_DEPARTPOS, attrs.get<SUMOReal>(SUMO_ATTR_DEPARTPOS, id, ok));
584  }
585  if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
586  plan.writeAttr(SUMO_ATTR_ARRIVALPOS, attrs.get<SUMOReal>(SUMO_ATTR_ARRIVALPOS, id, ok));
587  }
588  if (attrs.hasAttribute(SUMO_ATTR_DURATION)) {
590  }
591  if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
592  plan.writeAttr(SUMO_ATTR_SPEED, attrs.get<SUMOReal>(SUMO_ATTR_SPEED, id, ok));
593  }
594  if (attrs.hasAttribute(SUMO_ATTR_BUS_STOP)) {
595  plan.writeAttr(SUMO_ATTR_BUS_STOP, attrs.get<std::string>(SUMO_ATTR_BUS_STOP, id, ok));
596  }
600  }
601  myActiveRoute.clear();
602  return ok;
603 }
604 
605 
606 
607 /****************************************************************************/