Eclipse SUMO - Simulation of Urban MObility
RORouteHandler.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-2024 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 <string>
26 #include <map>
27 #include <vector>
28 #include <iostream>
40 #include <utils/xml/XMLSubSys.h>
42 #include "RONet.h"
43 #include "ROEdge.h"
44 #include "ROLane.h"
45 #include "RORouteDef.h"
46 #include "RORouteHandler.h"
47 
48 // ===========================================================================
49 // method definitions
50 // ===========================================================================
51 RORouteHandler::RORouteHandler(RONet& net, const std::string& file,
52  const bool tryRepair,
53  const bool emptyDestinationsAllowed,
54  const bool ignoreErrors,
55  const bool checkSchema) :
56  SUMORouteHandler(file, checkSchema ? "routes" : "", true),
57  MapMatcher(OptionsCont::getOptions().getBool("mapmatch.junctions"),
58  OptionsCont::getOptions().getFloat("mapmatch.distance"),
59  ignoreErrors ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
60  myNet(net),
61  myActiveRouteRepeat(0),
62  myActiveRoutePeriod(0),
63  myActivePlan(nullptr),
64  myActiveContainerPlan(nullptr),
65  myActiveContainerPlanSize(0),
66  myTryRepair(tryRepair),
67  myEmptyDestinationsAllowed(emptyDestinationsAllowed),
68  myErrorOutput(ignoreErrors ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
69  myBegin(string2time(OptionsCont::getOptions().getString("begin"))),
70  myKeepVTypeDist(OptionsCont::getOptions().getBool("keep-vtype-distributions")),
71  myUnsortedInput(OptionsCont::getOptions().exists("unsorted-input") && OptionsCont::getOptions().getBool("unsorted-input")),
72  myCurrentVTypeDistribution(nullptr),
73  myCurrentAlternatives(nullptr) {
74  myActiveRoute.reserve(100);
75 }
76 
77 
79  delete myCurrentAlternatives;
80 }
81 
82 
83 void
85  if (myActivePlan != nullptr) {
86  for (ROPerson::PlanItem* const it : *myActivePlan) {
87  delete it;
88  }
89  delete myActivePlan;
90  myActivePlan = nullptr;
91  }
92  delete myActiveContainerPlan;
93  myActiveContainerPlan = nullptr;
94  delete myVehicleParameter;
95  myVehicleParameter = nullptr;
96 }
97 
98 
99 void
101  const std::string element = toString(tag);
102  myActiveRoute.clear();
103  bool useTaz = OptionsCont::getOptions().getBool("with-taz");
105  WRITE_WARNINGF(TL("Taz usage was requested but no taz present in % '%'!"), element, myVehicleParameter->id);
106  useTaz = false;
107  }
111  if (type != nullptr) {
112  vClass = type->vehicleClass;
113  }
114  }
115  // from-attributes
116  const std::string rid = "for " + element + " '" + myVehicleParameter->id + "'";
117  if ((useTaz || !attrs.hasAttribute(SUMO_ATTR_FROM)) &&
119  const bool useJunction = attrs.hasAttribute(SUMO_ATTR_FROM_JUNCTION);
120  const std::string tazType = useJunction ? "junction" : "taz";
121  const std::string tazID = attrs.get<std::string>(useJunction ? SUMO_ATTR_FROM_JUNCTION : SUMO_ATTR_FROM_TAZ, myVehicleParameter->id.c_str(), ok, true);
122  const ROEdge* fromTaz = myNet.getEdge(tazID + "-source");
123  if (fromTaz == nullptr) {
124  myErrorOutput->inform("Source " + tazType + " '" + tazID + "' not known for " + element + " '" + myVehicleParameter->id + "'!"
125  + (useJunction ? JUNCTION_TAZ_MISSING_HELP : ""));
126  ok = false;
127  } else if (fromTaz->getNumSuccessors() == 0 && tag != SUMO_TAG_PERSON) {
128  myErrorOutput->inform("Source " + tazType + " '" + tazID + "' has no outgoing edges for " + element + " '" + myVehicleParameter->id + "'!");
129  ok = false;
130  } else {
131  myActiveRoute.push_back(fromTaz);
132  }
133  } else if (attrs.hasAttribute(SUMO_ATTR_FROMXY)) {
134  parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_FROMXY, myVehicleParameter->id.c_str(), ok), false, vClass, myActiveRoute, rid, true, ok);
135  } else if (attrs.hasAttribute(SUMO_ATTR_FROMLONLAT)) {
136  parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_FROMLONLAT, myVehicleParameter->id.c_str(), ok), true, vClass, myActiveRoute, rid, true, ok);
137  } else {
138  parseEdges(attrs.getOpt<std::string>(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok), myActiveRoute, rid, ok);
139  }
141  myInsertStopEdgesAt = (int)myActiveRoute.size();
142  }
143 
144  // via-attributes
145  ConstROEdgeVector viaEdges;
146  if (attrs.hasAttribute(SUMO_ATTR_VIAXY)) {
147  parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_VIAXY, myVehicleParameter->id.c_str(), ok), false, vClass, viaEdges, rid, false, ok);
148  } else if (attrs.hasAttribute(SUMO_ATTR_VIALONLAT)) {
149  parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_VIALONLAT, myVehicleParameter->id.c_str(), ok), true, vClass, viaEdges, rid, false, ok);
150  } else if (attrs.hasAttribute(SUMO_ATTR_VIAJUNCTIONS)) {
151  for (std::string junctionID : attrs.get<std::vector<std::string> >(SUMO_ATTR_VIAJUNCTIONS, myVehicleParameter->id.c_str(), ok)) {
152  const ROEdge* viaSink = myNet.getEdge(junctionID + "-sink");
153  if (viaSink == nullptr) {
154  myErrorOutput->inform("Junction-taz '" + junctionID + "' not found." + JUNCTION_TAZ_MISSING_HELP);
155  ok = false;
156  } else {
157  viaEdges.push_back(viaSink);
158  }
159  }
160  } else {
161  parseEdges(attrs.getOpt<std::string>(SUMO_ATTR_VIA, myVehicleParameter->id.c_str(), ok, "", true), viaEdges, rid, ok);
162  }
163  for (const ROEdge* e : viaEdges) {
164  myActiveRoute.push_back(e);
165  myVehicleParameter->via.push_back(e->getID());
166  }
167 
168  // to-attributes
169  if ((useTaz || !attrs.hasAttribute(SUMO_ATTR_TO)) &&
171  const bool useJunction = attrs.hasAttribute(SUMO_ATTR_TO_JUNCTION);
172  const std::string tazType = useJunction ? "junction" : "taz";
173  const std::string tazID = attrs.get<std::string>(useJunction ? SUMO_ATTR_TO_JUNCTION : SUMO_ATTR_TO_TAZ, myVehicleParameter->id.c_str(), ok, true);
174  const ROEdge* toTaz = myNet.getEdge(tazID + "-sink");
175  if (toTaz == nullptr) {
176  myErrorOutput->inform("Sink " + tazType + " '" + tazID + "' not known for " + element + " '" + myVehicleParameter->id + "'!"
177  + (useJunction ? JUNCTION_TAZ_MISSING_HELP : ""));
178  ok = false;
179  } else if (toTaz->getNumPredecessors() == 0 && tag != SUMO_TAG_PERSON) {
180  myErrorOutput->inform("Sink " + tazType + " '" + tazID + "' has no incoming edges for " + element + " '" + myVehicleParameter->id + "'!");
181  ok = false;
182  } else {
183  myActiveRoute.push_back(toTaz);
184  }
185  } else if (attrs.hasAttribute(SUMO_ATTR_TOXY)) {
186  parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_TOXY, myVehicleParameter->id.c_str(), ok, true), false, vClass, myActiveRoute, rid, false, ok);
187  } else if (attrs.hasAttribute(SUMO_ATTR_TOLONLAT)) {
188  parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_TOLONLAT, myVehicleParameter->id.c_str(), ok, true), true, vClass, myActiveRoute, rid, false, ok);
189  } else {
190  parseEdges(attrs.getOpt<std::string>(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok, "", true), myActiveRoute, rid, ok);
191  }
193  if (myVehicleParameter->routeid == "") {
195  }
196 }
197 
198 
199 void
201  const SUMOSAXAttributes& attrs) {
202  try {
203  if (myActivePlan != nullptr && myActivePlan->empty() && myVehicleParameter->departProcedure == DepartDefinition::TRIGGERED && element != SUMO_TAG_RIDE && element != SUMO_TAG_PARAM) {
204  throw ProcessError(TLF("Triggered departure for person '%' requires starting with a ride.", myVehicleParameter->id));
206  throw ProcessError(TLF("Triggered departure for container '%' requires starting with a transport.", myVehicleParameter->id));
207  }
208  SUMORouteHandler::myStartElement(element, attrs);
209  bool ok = true;
210  switch (element) {
211  case SUMO_TAG_PERSON:
212  case SUMO_TAG_PERSONFLOW: {
213  myActivePlan = new std::vector<ROPerson::PlanItem*>();
214  break;
215  }
216  case SUMO_TAG_RIDE:
217  break; // handled in addRide, called from SUMORouteHandler::myStartElement
218  case SUMO_TAG_CONTAINER:
223  (*myActiveContainerPlan) << attrs;
224  break;
225  case SUMO_TAG_TRANSPORT:
226  case SUMO_TAG_TRANSHIP:
227  if (myActiveContainerPlan == nullptr) {
228  throw ProcessError(TLF("Found % outside container element", toString((SumoXMLTag)element)));
229  }
230  // copy container elements
232  (*myActiveContainerPlan) << attrs;
235  break;
236  case SUMO_TAG_FLOW:
238  parseFromViaTo((SumoXMLTag)element, attrs, ok);
239  break;
240  case SUMO_TAG_TRIP:
242  parseFromViaTo((SumoXMLTag)element, attrs, ok);
243  break;
244  default:
245  break;
246  }
247  } catch (ProcessError&) {
249  throw;
250  }
251 }
252 
253 
254 void
256  bool ok = true;
257  myCurrentVTypeDistributionID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
258  if (ok) {
260  if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
261  std::vector<double> probs;
262  if (attrs.hasAttribute(SUMO_ATTR_PROBS)) {
263  StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_PROBS, myCurrentVTypeDistributionID.c_str(), ok));
264  while (st.hasNext()) {
265  probs.push_back(StringUtils::toDoubleSecure(st.next(), 1.0));
266  }
267  }
268  const std::string vTypes = attrs.get<std::string>(SUMO_ATTR_VTYPES, myCurrentVTypeDistributionID.c_str(), ok);
269  StringTokenizer st(vTypes);
270  int probIndex = 0;
271  while (st.hasNext()) {
272  const std::string typeID = st.next();
274  if (dist != nullptr) {
275  const double distProb = ((int)probs.size() > probIndex ? probs[probIndex] : 1.) / dist->getOverallProb();
276  std::vector<double>::const_iterator probIt = dist->getProbs().begin();
277  for (SUMOVTypeParameter* const type : dist->getVals()) {
278  myCurrentVTypeDistribution->add(type, distProb * *probIt);
279  probIt++;
280  }
281  } else {
282  SUMOVTypeParameter* const type = myNet.getVehicleTypeSecure(typeID);
283  if (type == nullptr) {
284  myErrorOutput->inform("Unknown vehicle type '" + typeID + "' in distribution '" + myCurrentVTypeDistributionID + "'.");
285  } else {
286  const double prob = ((int)probs.size() > probIndex ? probs[probIndex] : type->defaultProbability);
287  myCurrentVTypeDistribution->add(type, prob);
288  }
289  }
290  probIndex++;
291  }
292  if (probs.size() > 0 && probIndex != (int)probs.size()) {
293  WRITE_WARNING("Got " + toString(probs.size()) + " probabilities for " + toString(probIndex) +
294  " types in vTypeDistribution '" + myCurrentVTypeDistributionID + "'");
295  }
296  }
297  }
298 }
299 
300 
301 void
303  if (myCurrentVTypeDistribution != nullptr) {
306  myErrorOutput->inform("Vehicle type distribution '" + myCurrentVTypeDistributionID + "' is empty.");
309  myErrorOutput->inform("Another vehicle type (or distribution) with the id '" + myCurrentVTypeDistributionID + "' exists.");
310  }
311  myCurrentVTypeDistribution = nullptr;
312  }
313 }
314 
315 
316 void
318  myActiveRoute.clear();
319  myInsertStopEdgesAt = -1;
320  // check whether the id is really necessary
321  std::string rid;
322  if (myCurrentAlternatives != nullptr) {
324  rid = "distribution '" + myCurrentAlternatives->getID() + "'";
325  } else if (myVehicleParameter != nullptr) {
326  // ok, a vehicle is wrapping the route,
327  // we may use this vehicle's id as default
328  myVehicleParameter->routeid = myActiveRouteID = "!" + myVehicleParameter->id; // !!! document this
329  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
330  WRITE_WARNINGF(TL("Ids of internal routes are ignored (vehicle '%')."), myVehicleParameter->id);
331  }
332  } else {
333  bool ok = true;
334  myActiveRouteID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
335  if (!ok) {
336  return;
337  }
338  rid = "'" + myActiveRouteID + "'";
339  }
340  if (myVehicleParameter != nullptr) { // have to do this here for nested route distributions
341  rid = "for vehicle '" + myVehicleParameter->id + "'";
342  }
343  bool ok = true;
344  if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
345  parseEdges(attrs.get<std::string>(SUMO_ATTR_EDGES, myActiveRouteID.c_str(), ok), myActiveRoute, rid, ok);
346  }
347  myActiveRouteRefID = attrs.getOpt<std::string>(SUMO_ATTR_REFID, myActiveRouteID.c_str(), ok, "");
348  if (myActiveRouteRefID != "" && myNet.getRouteDef(myActiveRouteRefID) == nullptr) {
349  myErrorOutput->inform("Invalid reference to route '" + myActiveRouteRefID + "' in route " + rid + ".");
350  }
351  if (myCurrentAlternatives != nullptr && !attrs.hasAttribute(SUMO_ATTR_PROB)) {
352  WRITE_WARNINGF(TL("No probability for route %, using default."), rid);
353  }
355  if (ok && myActiveRouteProbability < 0) {
356  myErrorOutput->inform("Invalid probability for route '" + myActiveRouteID + "'.");
357  }
359  ok = true;
360  myActiveRouteRepeat = attrs.getOpt<int>(SUMO_ATTR_REPEAT, myActiveRouteID.c_str(), ok, 0);
362  if (myActiveRouteRepeat > 0) {
364  if (myVehicleParameter != nullptr) {
366  if (type != nullptr) {
367  vClass = type->vehicleClass;
368  }
369  }
370  if (myActiveRoute.size() > 0 && !myActiveRoute.back()->isConnectedTo(*myActiveRoute.front(), vClass)) {
371  myErrorOutput->inform("Disconnected route " + rid + " when repeating.");
372  }
373  }
374  myCurrentCosts = attrs.getOpt<double>(SUMO_ATTR_COST, myActiveRouteID.c_str(), ok, -1);
375  if (ok && myCurrentCosts != -1 && myCurrentCosts < 0) {
376  myErrorOutput->inform("Invalid cost for route '" + myActiveRouteID + "'.");
377  }
378 }
379 
380 
381 void
383  // currently unused
384 }
385 
386 
387 void
389  // currently unused
390 }
391 
392 
393 void
395  // currently unused
396 }
397 
398 
399 void
400 RORouteHandler::closeRoute(const bool mayBeDisconnected) {
401  const bool mustReroute = myActiveRoute.size() == 0 && myActiveRouteStops.size() != 0;
402  if (mustReroute) {
403  // implicit route from stops
404  for (const SUMOVehicleParameter::Stop& stop : myActiveRouteStops) {
405  ROEdge* edge = myNet.getEdge(stop.edge);
406  myActiveRoute.push_back(edge);
407  }
408  }
409  if (myActiveRoute.size() == 0) {
410  if (myActiveRouteRefID != "" && myCurrentAlternatives != nullptr) {
412  myActiveRouteID = "";
413  myActiveRouteRefID = "";
414  return;
415  }
416  if (myVehicleParameter != nullptr) {
417  myErrorOutput->inform("The route for vehicle '" + myVehicleParameter->id + "' has no edges.");
418  } else {
419  myErrorOutput->inform("Route '" + myActiveRouteID + "' has no edges.");
420  }
421  myActiveRouteID = "";
422  myActiveRouteStops.clear();
423  return;
424  }
425  if (myActiveRoute.size() == 1 && myActiveRoute.front()->isTazConnector()) {
426  myErrorOutput->inform("The routing information for vehicle '" + myVehicleParameter->id + "' is insufficient.");
427  myActiveRouteID = "";
428  myActiveRouteStops.clear();
429  return;
430  }
431  if (!mayBeDisconnected && OptionsCont::getOptions().exists("no-internal-links") && !OptionsCont::getOptions().getBool("no-internal-links")) {
432  // fix internal edges which did not get parsed
433  const ROEdge* last = nullptr;
434  ConstROEdgeVector fullRoute;
435  for (const ROEdge* roe : myActiveRoute) {
436  if (last != nullptr) {
437  for (const ROEdge* intern : last->getSuccessors()) {
438  if (intern->isInternal() && intern->getSuccessors().size() == 1 && intern->getSuccessors().front() == roe) {
439  fullRoute.push_back(intern);
440  }
441  }
442  }
443  fullRoute.push_back(roe);
444  last = roe;
445  }
446  myActiveRoute = fullRoute;
447  }
448  if (myActiveRouteRepeat > 0) {
449  // duplicate route
450  ConstROEdgeVector tmpEdges = myActiveRoute;
451  auto tmpStops = myActiveRouteStops;
452  for (int i = 0; i < myActiveRouteRepeat; i++) {
453  myActiveRoute.insert(myActiveRoute.begin(), tmpEdges.begin(), tmpEdges.end());
454  for (SUMOVehicleParameter::Stop stop : tmpStops) {
455  if (stop.until > 0) {
456  if (myActiveRoutePeriod <= 0) {
457  const std::string description = myVehicleParameter != nullptr
458  ? "for vehicle '" + myVehicleParameter->id + "'"
459  : "'" + myActiveRouteID + "'";
460  throw ProcessError(TLF("Cannot repeat stops with 'until' in route % because no cycleTime is defined.", description));
461  }
462  stop.until += myActiveRoutePeriod * (i + 1);
463  stop.arrival += myActiveRoutePeriod * (i + 1);
464  }
465  myActiveRouteStops.push_back(stop);
466  }
467  }
468  }
471  myActiveRoute.clear();
472  if (myCurrentAlternatives == nullptr) {
473  if (myNet.getRouteDef(myActiveRouteID) != nullptr) {
474  delete route;
475  if (myVehicleParameter != nullptr) {
476  myErrorOutput->inform("Another route for vehicle '" + myVehicleParameter->id + "' exists.");
477  } else {
478  myErrorOutput->inform("Another route (or distribution) with the id '" + myActiveRouteID + "' exists.");
479  }
480  myActiveRouteID = "";
481  myActiveRouteStops.clear();
482  return;
483  } else {
484  myCurrentAlternatives = new RORouteDef(myActiveRouteID, 0, mayBeDisconnected || myTryRepair, mayBeDisconnected);
487  myCurrentAlternatives = nullptr;
488  }
489  } else {
491  }
492  myActiveRouteID = "";
493  myActiveRouteStops.clear();
494 }
495 
496 
497 void
499  // check whether the id is really necessary
500  bool ok = true;
501  std::string id;
502  if (myVehicleParameter != nullptr) {
503  // ok, a vehicle is wrapping the route,
504  // we may use this vehicle's id as default
505  myVehicleParameter->routeid = id = "!" + myVehicleParameter->id; // !!! document this
506  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
507  WRITE_WARNINGF(TL("Ids of internal route distributions are ignored (vehicle '%')."), myVehicleParameter->id);
508  }
509  } else {
510  id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
511  if (!ok) {
512  return;
513  }
514  }
515  // try to get the index of the last element
516  int index = attrs.getOpt<int>(SUMO_ATTR_LAST, id.c_str(), ok, 0);
517  if (ok && index < 0) {
518  myErrorOutput->inform("Negative index of a route alternative (id='" + id + "').");
519  return;
520  }
521  // build the alternative cont
522  myCurrentAlternatives = new RORouteDef(id, index, myTryRepair, false);
523  if (attrs.hasAttribute(SUMO_ATTR_ROUTES)) {
524  ok = true;
525  StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_ROUTES, id.c_str(), ok));
526  while (st.hasNext()) {
527  const std::string routeID = st.next();
528  const RORouteDef* route = myNet.getRouteDef(routeID);
529  if (route == nullptr) {
530  myErrorOutput->inform("Unknown route '" + routeID + "' in distribution '" + id + "'.");
531  } else {
533  }
534  }
535  }
536 }
537 
538 
539 void
541  if (myCurrentAlternatives != nullptr) {
543  myErrorOutput->inform("Route distribution '" + myCurrentAlternatives->getID() + "' is empty.");
544  delete myCurrentAlternatives;
545  } else if (!myNet.addRouteDef(myCurrentAlternatives)) {
546  myErrorOutput->inform("Another route (or distribution) with the id '" + myCurrentAlternatives->getID() + "' exists.");
547  delete myCurrentAlternatives;
548  }
549  myCurrentAlternatives = nullptr;
550  }
551 }
552 
553 
554 void
556  checkLastDepart();
557  // get the vehicle id
559  return;
560  }
561  // get vehicle type
563  if (type == nullptr) {
564  myErrorOutput->inform("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
566  } else {
567  if (!myKeepVTypeDist) {
568  // fix the type id in case we used a distribution
569  myVehicleParameter->vtypeid = type->id;
570  }
571  }
572  if (type->vehicleClass == SVC_PEDESTRIAN) {
573  WRITE_WARNINGF(TL("Vehicle type '%' with vClass=pedestrian should only be used for persons and not for vehicle '%'."), type->id, myVehicleParameter->id);
574  }
575  // get the route
577  if (route == nullptr) {
578  myErrorOutput->inform("The route of the vehicle '" + myVehicleParameter->id + "' is not known.");
579  return;
580  }
581  if (MsgHandler::getErrorInstance()->wasInformed()) {
582  return;
583  }
584  const bool needCopy = route->getID()[0] != '!';
585  if (needCopy) {
586  route = route->copy("!" + myVehicleParameter->id, myVehicleParameter->depart);
587  }
588  // build the vehicle
589  ROVehicle* veh = new ROVehicle(*myVehicleParameter, route, type, &myNet, myErrorOutput);
590  if (myNet.addVehicle(myVehicleParameter->id, veh)) {
592  } else if (needCopy) {
593  delete route;
594  }
595  delete myVehicleParameter;
596  myVehicleParameter = nullptr;
597 }
598 
599 
600 void
603  if (myCurrentVTypeDistribution != nullptr) {
605  }
606  }
607  if (OptionsCont::getOptions().isSet("restriction-params")) {
608  const std::vector<std::string> paramKeys = OptionsCont::getOptions().getStringVector("restriction-params");
610  }
611  myCurrentVType = nullptr;
612 }
613 
614 
615 void
618  if (type == nullptr) {
619  myErrorOutput->inform("The vehicle type '" + myVehicleParameter->vtypeid + "' for person '" + myVehicleParameter->id + "' is not known.");
621  }
622  if (myActivePlan == nullptr || myActivePlan->empty()) {
623  WRITE_WARNINGF(TL("Discarding person '%' because her plan is empty"), myVehicleParameter->id);
624  } else {
625  ROPerson* person = new ROPerson(*myVehicleParameter, type);
626  for (ROPerson::PlanItem* item : *myActivePlan) {
627  person->getPlan().push_back(item);
628  }
629  if (myNet.addPerson(person)) {
630  checkLastDepart();
632  }
633  }
634  delete myVehicleParameter;
635  myVehicleParameter = nullptr;
636  delete myActivePlan;
637  myActivePlan = nullptr;
638 }
639 
640 
641 void
643  std::string typeID = DEFAULT_PEDTYPE_ID;
645  myErrorOutput->inform("The vehicle type '" + myVehicleParameter->vtypeid + "' for personFlow '" + myVehicleParameter->id + "' is not known.");
646  } else {
647  typeID = myVehicleParameter->vtypeid;
648  }
649  if (myActivePlan == nullptr || myActivePlan->empty()) {
650  WRITE_WARNINGF(TL("Discarding personFlow '%' because their plan is empty"), myVehicleParameter->id);
651  } else {
652  checkLastDepart();
653  // instantiate all persons of this flow
654  int i = 0;
655  std::string baseID = myVehicleParameter->id;
658  throw ProcessError(TLF("probabilistic personFlow '%' must specify end time", myVehicleParameter->id));
659  } else {
660  for (SUMOTime t = myVehicleParameter->depart; t < myVehicleParameter->repetitionEnd; t += TIME2STEPS(1)) {
662  addFlowPerson(typeID, t, baseID, i++);
663  }
664  }
665  }
666  } else {
668  // uniform sampling of departures from range is equivalent to poisson flow (encoded by negative offset)
669  if (OptionsCont::getOptions().getBool("randomize-flows") && myVehicleParameter->repetitionOffset >= 0) {
670  std::vector<SUMOTime> departures;
672  for (int j = 0; j < myVehicleParameter->repetitionNumber; ++j) {
673  departures.push_back(depart + RandHelper::rand(range));
674  }
675  std::sort(departures.begin(), departures.end());
676  std::reverse(departures.begin(), departures.end());
677  for (; i < myVehicleParameter->repetitionNumber; i++) {
678  addFlowPerson(typeID, departures[i], baseID, i);
680  }
681  } else {
684  // poisson: randomize first depart
686  }
688  addFlowPerson(typeID, depart + myVehicleParameter->repetitionTotalOffset, baseID, i);
691  }
692  }
693  }
694  }
695  }
696  delete myVehicleParameter;
697  myVehicleParameter = nullptr;
698  for (ROPerson::PlanItem* const it : *myActivePlan) {
699  delete it;
700  }
701  delete myActivePlan;
702  myActivePlan = nullptr;
703 }
704 
705 
706 void
707 RORouteHandler::addFlowPerson(const std::string& typeID, SUMOTime depart, const std::string& baseID, int i) {
709  pars.id = baseID + "." + toString(i);
710  pars.depart = depart;
711  const SUMOVTypeParameter* const type = myNet.getVehicleTypeSecure(typeID);
712  if (!myKeepVTypeDist) {
713  pars.vtypeid = type->id;
714  }
715  ROPerson* person = new ROPerson(pars, type);
716  for (ROPerson::PlanItem* item : *myActivePlan) {
717  person->getPlan().push_back(item->clone());
718  }
719  if (myNet.addPerson(person)) {
720  if (i == 0) {
722  }
723  }
724 }
725 
726 
727 void
730  if (myActiveContainerPlanSize > 0) {
732  checkLastDepart();
734  } else {
735  WRITE_WARNINGF(TL("Discarding container '%' because its plan is empty"), myVehicleParameter->id);
736  }
737  delete myVehicleParameter;
738  myVehicleParameter = nullptr;
739  delete myActiveContainerPlan;
740  myActiveContainerPlan = nullptr;
742 }
743 
744 
747  if (myActiveContainerPlanSize > 0) {
749  checkLastDepart();
751  } else {
752  WRITE_WARNINGF(TL("Discarding containerFlow '%' because its plan is empty"), myVehicleParameter->id);
753  }
754  delete myVehicleParameter;
755  myVehicleParameter = nullptr;
756  delete myActiveContainerPlan;
757  myActiveContainerPlan = nullptr;
759 }
760 
761 
762 void
764  checkLastDepart();
765  // @todo: consider myScale?
767  delete myVehicleParameter;
768  myVehicleParameter = nullptr;
769  return;
770  }
771  // let's check whether vehicles had to depart before the simulation starts
773  const SUMOTime offsetToBegin = myBegin - myVehicleParameter->depart;
774  while (myVehicleParameter->repetitionTotalOffset < offsetToBegin) {
777  delete myVehicleParameter;
778  myVehicleParameter = nullptr;
779  return;
780  }
781  }
783  myErrorOutput->inform("The vehicle type '" + myVehicleParameter->vtypeid + "' for flow '" + myVehicleParameter->id + "' is not known.");
784  }
785  if (myVehicleParameter->routeid[0] == '!' && myNet.getRouteDef(myVehicleParameter->routeid) == nullptr) {
786  closeRoute(true);
787  }
788  if (myNet.getRouteDef(myVehicleParameter->routeid) == nullptr) {
789  myErrorOutput->inform("The route '" + myVehicleParameter->routeid + "' for flow '" + myVehicleParameter->id + "' is not known.");
790  delete myVehicleParameter;
791  myVehicleParameter = nullptr;
792  return;
793  }
794  myActiveRouteID = "";
795  if (!MsgHandler::getErrorInstance()->wasInformed()) {
796  if (myNet.addFlow(myVehicleParameter, OptionsCont::getOptions().getBool("randomize-flows"))) {
798  } else {
799  myErrorOutput->inform("Another flow with the id '" + myVehicleParameter->id + "' exists.");
800  delete myVehicleParameter;
801  }
802  } else {
803  delete myVehicleParameter;
804  }
805  myVehicleParameter = nullptr;
806  myInsertStopEdgesAt = -1;
807 }
808 
809 
810 void
812  closeRoute(true);
813  closeVehicle();
814 }
815 
816 
818 RORouteHandler::retrieveStoppingPlace(const SUMOSAXAttributes& attrs, const std::string& errorSuffix, std::string& id, const SUMOVehicleParameter::Stop* stopParam) {
819  // dummy stop parameter to hold the attributes
821  if (stopParam != nullptr) {
822  stop = *stopParam;
823  } else {
824  bool ok = true;
825  stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
826  stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_TRAIN_STOP, nullptr, ok, stop.busstop); // alias
827  stop.chargingStation = attrs.getOpt<std::string>(SUMO_ATTR_CHARGING_STATION, nullptr, ok, "");
828  stop.overheadWireSegment = attrs.getOpt<std::string>(SUMO_ATTR_OVERHEAD_WIRE_SEGMENT, nullptr, ok, "");
829  stop.containerstop = attrs.getOpt<std::string>(SUMO_ATTR_CONTAINER_STOP, nullptr, ok, "");
830  stop.parkingarea = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, nullptr, ok, "");
831  }
832  const SUMOVehicleParameter::Stop* toStop = nullptr;
833  if (stop.busstop != "") {
835  id = stop.busstop;
836  if (toStop == nullptr) {
837  WRITE_ERROR("The busStop '" + stop.busstop + "' is not known" + errorSuffix);
838  }
839  } else if (stop.containerstop != "") {
841  id = stop.containerstop;
842  if (toStop == nullptr) {
843  WRITE_ERROR("The containerStop '" + stop.containerstop + "' is not known" + errorSuffix);
844  }
845  } else if (stop.parkingarea != "") {
847  id = stop.parkingarea;
848  if (toStop == nullptr) {
849  WRITE_ERROR("The parkingArea '" + stop.parkingarea + "' is not known" + errorSuffix);
850  }
851  } else if (stop.chargingStation != "") {
852  // ok, we have a charging station
854  id = stop.chargingStation;
855  if (toStop == nullptr) {
856  WRITE_ERROR("The chargingStation '" + stop.chargingStation + "' is not known" + errorSuffix);
857  }
858  } else if (stop.overheadWireSegment != "") {
859  // ok, we have an overhead wire segment
861  id = stop.overheadWireSegment;
862  if (toStop == nullptr) {
863  WRITE_ERROR("The overhead wire segment '" + stop.overheadWireSegment + "' is not known" + errorSuffix);
864  }
865  }
866  return toStop;
867 }
868 
871  Parameterised* result = nullptr;
872  if (myActiveContainerPlan != nullptr) {
874  (*myActiveContainerPlan) << attrs;
877  return result;
878  }
879  std::string errorSuffix;
880  if (myActivePlan != nullptr) {
881  errorSuffix = " in person '" + myVehicleParameter->id + "'.";
882  } else if (myActiveContainerPlan != nullptr) {
883  errorSuffix = " in container '" + myVehicleParameter->id + "'.";
884  } else if (myVehicleParameter != nullptr) {
885  errorSuffix = " in vehicle '" + myVehicleParameter->id + "'.";
886  } else {
887  errorSuffix = " in route '" + myActiveRouteID + "'.";
888  }
890  bool ok = parseStop(stop, attrs, errorSuffix, myErrorOutput);
891  if (!ok) {
892  return result;
893  }
894  // try to parse the assigned bus stop
895  const ROEdge* edge = nullptr;
896  std::string stoppingPlaceID;
897  const SUMOVehicleParameter::Stop* stoppingPlace = retrieveStoppingPlace(attrs, errorSuffix, stoppingPlaceID, &stop);
898  bool hasPos = false;
899  if (stoppingPlace != nullptr) {
900  stop.lane = stoppingPlace->lane;
901  stop.endPos = stoppingPlace->endPos;
902  stop.startPos = stoppingPlace->startPos;
904  } else {
905  // no, the lane and the position should be given
906  stop.lane = attrs.getOpt<std::string>(SUMO_ATTR_LANE, nullptr, ok, "");
907  stop.edge = attrs.getOpt<std::string>(SUMO_ATTR_EDGE, nullptr, ok, "");
908  if (ok && stop.edge != "") {
909  edge = myNet.getEdge(stop.edge);
910  if (edge == nullptr) {
911  myErrorOutput->inform("The edge '" + stop.edge + "' for a stop is not known" + errorSuffix);
912  return result;
913  }
914  } else if (ok && stop.lane != "") {
916  if (edge == nullptr) {
917  myErrorOutput->inform("The lane '" + stop.lane + "' for a stop is not known" + errorSuffix);
918  return result;
919  }
920  } else if (ok && ((attrs.hasAttribute(SUMO_ATTR_X) && attrs.hasAttribute(SUMO_ATTR_Y))
921  || (attrs.hasAttribute(SUMO_ATTR_LON) && attrs.hasAttribute(SUMO_ATTR_LAT)))) {
922  Position pos;
923  bool geo = false;
924  if (attrs.hasAttribute(SUMO_ATTR_X) && attrs.hasAttribute(SUMO_ATTR_Y)) {
925  pos = Position(attrs.get<double>(SUMO_ATTR_X, myVehicleParameter->id.c_str(), ok), attrs.get<double>(SUMO_ATTR_Y, myVehicleParameter->id.c_str(), ok));
926  } else {
927  pos = Position(attrs.get<double>(SUMO_ATTR_LON, myVehicleParameter->id.c_str(), ok), attrs.get<double>(SUMO_ATTR_LAT, myVehicleParameter->id.c_str(), ok));
928  geo = true;
929  }
930  PositionVector positions;
931  positions.push_back(pos);
932  ConstROEdgeVector geoEdges;
936  if (type != nullptr) {
937  vClass = type->vehicleClass;
938  }
939  }
940  parseGeoEdges(positions, geo, vClass, geoEdges, myVehicleParameter->id, true, ok);
941  if (ok) {
942  edge = geoEdges.front();
943  hasPos = true;
944  if (geo) {
946  }
947  stop.parametersSet |= STOP_END_SET;
948  stop.endPos = edge->getLanes()[0]->getShape().nearest_offset_to_point2D(pos, false);
949  } else {
950  return result;
951  }
952  } else if (!ok || (stop.lane == "" && stop.edge == "")) {
953  myErrorOutput->inform("A stop must be placed on a bus stop, a container stop, a parking area, an edge or a lane" + errorSuffix);
954  return result;
955  }
956  if (!hasPos) {
957  stop.endPos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, nullptr, ok, edge->getLength());
958  }
959  stop.startPos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, nullptr, ok, stop.endPos - 2 * POSITION_EPS);
960  const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, nullptr, ok, !attrs.hasAttribute(SUMO_ATTR_STARTPOS) && !attrs.hasAttribute(SUMO_ATTR_ENDPOS));
961  const double endPosOffset = edge->isInternal() ? edge->getNormalBefore()->getLength() : 0;
962  if (!ok || (checkStopPos(stop.startPos, stop.endPos, edge->getLength() + endPosOffset, POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
963  myErrorOutput->inform("Invalid start or end position for stop" + errorSuffix);
964  return result;
965  }
966  }
967  stop.edge = edge->getID();
968  if (myActivePlan != nullptr) {
969  ROPerson::addStop(*myActivePlan, stop, edge);
970  result = myActivePlan->back()->getStopParameters();
971  } else if (myVehicleParameter != nullptr) {
972  myVehicleParameter->stops.push_back(stop);
973  result = &myVehicleParameter->stops.back();
974  } else {
975  myActiveRouteStops.push_back(stop);
976  result = &myActiveRouteStops.back();
977  }
978  if (myInsertStopEdgesAt >= 0) {
979  myActiveRoute.insert(myActiveRoute.begin() + myInsertStopEdgesAt, edge);
981  }
982  return result;
983 }
984 
985 
986 void
988  bool ok = true;
989  std::vector<ROPerson::PlanItem*>& plan = *myActivePlan;
990  const std::string pid = myVehicleParameter->id;
991 
992  const ROEdge* from = nullptr;
993  const ROEdge* to = nullptr;
994  parseFromViaTo(SUMO_TAG_PERSON, attrs, ok);
997  if (ok) {
998  from = myActiveRoute.front();
999  }
1000  } else if (plan.empty()) {
1001  myErrorOutput->inform("The start edge for person '" + pid + "' is not known.");
1002  return;
1003  }
1004  std::string stoppingPlaceID;
1005  const SUMOVehicleParameter::Stop* stop = retrieveStoppingPlace(attrs, " for ride of person '" + myVehicleParameter->id + "'", stoppingPlaceID);
1006  if (stop != nullptr) {
1008  } else {
1011  to = myActiveRoute.back();
1012  } else {
1013  myErrorOutput->inform("The to edge is missing within a ride of '" + myVehicleParameter->id + "'.");
1014  return;
1015  }
1016  }
1017  double arrivalPos = attrs.getOpt<double>(SUMO_ATTR_ARRIVALPOS, myVehicleParameter->id.c_str(), ok,
1018  stop == nullptr ? std::numeric_limits<double>::infinity() : stop->endPos);
1019  const std::string desc = attrs.get<std::string>(SUMO_ATTR_LINES, pid.c_str(), ok);
1020  const std::string group = attrs.getOpt<std::string>(SUMO_ATTR_GROUP, pid.c_str(), ok, "");
1021 
1023  StringTokenizer st(desc);
1024  if (st.size() != 1) {
1025  myErrorOutput->inform("Triggered departure for person '" + pid + "' requires a unique lines value.");
1026  return;
1027  }
1028  const std::string vehID = st.front();
1029  if (!myNet.knowsVehicle(vehID)) {
1030  myErrorOutput->inform("Unknown vehicle '" + vehID + "' in triggered departure for person '" + pid + "'.");
1031  return;
1032  }
1033  SUMOTime vehDepart = myNet.getDeparture(vehID);
1034  if (vehDepart == -1) {
1035  myErrorOutput->inform("Cannot use triggered vehicle '" + vehID + "' in triggered departure for person '" + pid + "'.");
1036  return;
1037  }
1038  myVehicleParameter->depart = vehDepart + 1; // write person after vehicle
1039  }
1040  ROPerson::addRide(plan, from, to, desc, arrivalPos, stoppingPlaceID, group);
1041 }
1042 
1043 
1044 void
1047  bool ok = true;
1048  const std::string pid = myVehicleParameter->id;
1049  const std::string desc = attrs.get<std::string>(SUMO_ATTR_LINES, pid.c_str(), ok);
1050  StringTokenizer st(desc);
1051  if (st.size() != 1) {
1052  throw ProcessError(TLF("Triggered departure for container '%' requires a unique lines value.", pid));
1053  }
1054  const std::string vehID = st.front();
1055  if (!myNet.knowsVehicle(vehID)) {
1056  throw ProcessError("Unknown vehicle '" + vehID + "' in triggered departure for container '" + pid + "'.");
1057  }
1058  SUMOTime vehDepart = myNet.getDeparture(vehID);
1059  if (vehDepart == -1) {
1060  throw ProcessError("Cannot use triggered vehicle '" + vehID + "' in triggered departure for container '" + pid + "'.");
1061  }
1062  myVehicleParameter->depart = vehDepart + 1; // write container after vehicle
1063  }
1064 }
1065 
1066 
1067 void
1069 }
1070 
1071 
1072 void
1073 RORouteHandler::parseEdges(const std::string& desc, ConstROEdgeVector& into,
1074  const std::string& rid, bool& ok) {
1075  for (StringTokenizer st(desc); st.hasNext();) {
1076  const std::string id = st.next();
1077  const ROEdge* edge = myNet.getEdge(id);
1078  if (edge == nullptr) {
1079  myErrorOutput->inform("The edge '" + id + "' within the route " + rid + " is not known.");
1080  ok = false;
1081  } else {
1082  into.push_back(edge);
1083  }
1084  }
1085 }
1086 
1087 
1088 void
1089 RORouteHandler::parseWalkPositions(const SUMOSAXAttributes& attrs, const std::string& personID,
1090  const ROEdge* /*fromEdge*/, const ROEdge*& toEdge,
1091  double& departPos, double& arrivalPos, std::string& busStopID,
1092  const ROPerson::PlanItem* const lastStage, bool& ok) {
1093  const std::string description = "walk or personTrip of '" + personID + "'.";
1094  if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
1095  WRITE_WARNING(TL("The attribute departPos is no longer supported for walks, please use the person attribute, the arrivalPos of the previous step or explicit stops."));
1096  }
1097  departPos = myVehicleParameter->departPos;
1098  if (lastStage != nullptr) {
1099  departPos = lastStage->getDestinationPos();
1100  }
1101 
1102  busStopID = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
1103 
1104  const SUMOVehicleParameter::Stop* bs = retrieveStoppingPlace(attrs, description, busStopID);
1105  if (bs != nullptr) {
1107  arrivalPos = (bs->startPos + bs->endPos) / 2;
1108  }
1109  if (toEdge != nullptr) {
1110  if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
1112  myHardFail, description, toEdge->getLength(),
1113  attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS, description.c_str(), ok));
1114  }
1115  } else {
1116  throw ProcessError(TLF("No destination edge for %.", description));
1117  }
1118 }
1119 
1120 
1121 void
1123  bool ok = true;
1124  const char* const id = myVehicleParameter->id.c_str();
1125  assert(!attrs.hasAttribute(SUMO_ATTR_EDGES));
1126  const ROEdge* from = nullptr;
1127  const ROEdge* to = nullptr;
1128  parseFromViaTo(SUMO_TAG_PERSON, attrs, ok);
1129  myInsertStopEdgesAt = -1;
1132  if (ok) {
1133  from = myActiveRoute.front();
1134  }
1135  } else if (myActivePlan->empty()) {
1136  throw ProcessError(TLF("Start edge not defined for person '%'.", myVehicleParameter->id));
1137  } else {
1138  from = myActivePlan->back()->getDestination();
1139  }
1142  to = myActiveRoute.back();
1143  } // else, to may also be derived from stopping place
1144 
1145  const SUMOTime duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, id, ok, -1);
1146  if (attrs.hasAttribute(SUMO_ATTR_DURATION) && duration <= 0) {
1147  throw ProcessError(TLF("Non-positive walking duration for '%'.", myVehicleParameter->id));
1148  }
1149 
1150  double departPos = 0;
1151  double arrivalPos = std::numeric_limits<double>::infinity();
1152  std::string busStopID;
1153  const ROPerson::PlanItem* const lastStage = myActivePlan->empty() ? nullptr : myActivePlan->back();
1154  parseWalkPositions(attrs, myVehicleParameter->id, from, to, departPos, arrivalPos, busStopID, lastStage, ok);
1155 
1156  const std::string modes = attrs.getOpt<std::string>(SUMO_ATTR_MODES, id, ok, "");
1157  const std::string group = attrs.getOpt<std::string>(SUMO_ATTR_GROUP, id, ok, "");
1158  SVCPermissions modeSet = 0;
1159  for (StringTokenizer st(modes); st.hasNext();) {
1160  const std::string mode = st.next();
1161  if (mode == "car") {
1162  modeSet |= SVC_PASSENGER;
1163  } else if (mode == "taxi") {
1164  modeSet |= SVC_TAXI;
1165  } else if (mode == "bicycle") {
1166  modeSet |= SVC_BICYCLE;
1167  } else if (mode == "public") {
1168  modeSet |= SVC_BUS;
1169  } else {
1170  throw InvalidArgument("Unknown person mode '" + mode + "'.");
1171  }
1172  }
1173  const std::string types = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id, ok, "");
1174  double walkFactor = attrs.getOpt<double>(SUMO_ATTR_WALKFACTOR, id, ok, OptionsCont::getOptions().getFloat("persontrip.walkfactor"));
1175  if (ok) {
1176  const std::string originStopID = myActivePlan->empty() ? "" : myActivePlan->back()->getStopDest();
1177  ROPerson::addTrip(*myActivePlan, myVehicleParameter->id, from, to, modeSet, types,
1178  departPos, originStopID, arrivalPos, busStopID, walkFactor, group);
1179  myParamStack.push_back(myActivePlan->back());
1180  }
1181 }
1182 
1183 
1184 void
1186  // parse walks from->to as person trips
1188  // XXX allow --repair?
1189  bool ok = true;
1190  if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
1191  const std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, myVehicleParameter->id.c_str(), ok);
1192  RORouteDef* routeDef = myNet.getRouteDef(routeID);
1193  const RORoute* route = routeDef != nullptr ? routeDef->getFirstRoute() : nullptr;
1194  if (route == nullptr) {
1195  throw ProcessError("The route '" + routeID + "' for walk of person '" + myVehicleParameter->id + "' is not known.");
1196  }
1197  myActiveRoute = route->getEdgeVector();
1198  } else {
1199  myActiveRoute.clear();
1200  parseEdges(attrs.get<std::string>(SUMO_ATTR_EDGES, myVehicleParameter->id.c_str(), ok), myActiveRoute, " walk for person '" + myVehicleParameter->id + "'", ok);
1201  }
1202  const char* const objId = myVehicleParameter->id.c_str();
1203  const double duration = attrs.getOpt<double>(SUMO_ATTR_DURATION, objId, ok, -1);
1204  if (attrs.hasAttribute(SUMO_ATTR_DURATION) && duration <= 0) {
1205  throw ProcessError(TLF("Non-positive walking duration for '%'.", myVehicleParameter->id));
1206  }
1207  const double speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, objId, ok, -1.);
1208  if (attrs.hasAttribute(SUMO_ATTR_SPEED) && speed <= 0) {
1209  throw ProcessError(TLF("Non-positive walking speed for '%'.", myVehicleParameter->id));
1210  }
1211  double departPos = 0.;
1212  double arrivalPos = std::numeric_limits<double>::infinity();
1213  if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
1214  WRITE_WARNING(TL("The attribute departPos is no longer supported for walks, please use the person attribute, the arrivalPos of the previous step or explicit stops."));
1215  }
1216  if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
1217  arrivalPos = SUMOVehicleParserHelper::parseWalkPos(SUMO_ATTR_ARRIVALPOS, myHardFail, objId, myActiveRoute.back()->getLength(), attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS, objId, ok));
1218  }
1219  std::string stoppingPlaceID;
1220  const std::string errorSuffix = " for walk of person '" + myVehicleParameter->id + "'";
1221  retrieveStoppingPlace(attrs, errorSuffix, stoppingPlaceID);
1222  if (ok) {
1223  ROPerson::addWalk(*myActivePlan, myActiveRoute, duration, speed, departPos, arrivalPos, stoppingPlaceID);
1224  myParamStack.push_back(myActivePlan->back());
1225  }
1226  } else {
1227  addPersonTrip(attrs);
1228  }
1229 }
1230 
1231 
1232 void
1234  for (const auto& edgeItem : myNet.getEdgeMap()) {
1235  for (ROLane* lane : edgeItem.second->getLanes()) {
1236  Boundary b = lane->getShape().getBoxBoundary();
1237  const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
1238  const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
1239  tree->Insert(cmin, cmax, lane);
1240  }
1241  }
1242 }
1243 
1244 
1245 ROEdge*
1246 RORouteHandler::retrieveEdge(const std::string& id) {
1247  return myNet.getEdge(id);
1248 }
1249 
1250 bool
1252  if (!myUnsortedInput) {
1254  }
1255  return true;
1256 }
1257 
1258 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
#define JUNCTION_TAZ_MISSING_HELP
Definition: MapMatcher.h:29
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
std::vector< const ROEdge * > ConstROEdgeVector
Definition: ROEdge.h:54
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:46
#define SUMOTime_MAX
Definition: SUMOTime.h:34
#define TIME2STEPS(x)
Definition: SUMOTime.h:57
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
const double DEFAULT_VEH_PROB
const std::string DEFAULT_PEDTYPE_ID
const std::string DEFAULT_VTYPE_ID
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_BICYCLE
vehicle is a bicycle
@ SVC_TAXI
vehicle is a taxi
@ SVC_BUS
vehicle is a bus
@ SVC_PEDESTRIAN
pedestrian
const int VEHPARS_TO_TAZ_SET
const int VEHPARS_FROM_TAZ_SET
const int STOP_END_SET
@ GIVEN
The time is given.
@ TRIGGERED
The departure is person triggered.
SumoXMLTag
Numbers representing SUMO-XML - element names.
@ SUMO_TAG_CHARGING_STATION
A Charging Station.
@ SUMO_TAG_TRANSHIP
@ SUMO_TAG_CONTAINER_STOP
A container stop.
@ SUMO_TAG_CONTAINERFLOW
@ SUMO_TAG_BUS_STOP
A bus stop.
@ SUMO_TAG_STOP
stop for vehicles
@ SUMO_TAG_FLOW
a flow definition using from and to edges or a route
@ SUMO_TAG_PARKING_AREA
A parking area.
@ SUMO_TAG_TRANSPORT
@ SUMO_TAG_CONTAINER
@ SUMO_TAG_RIDE
@ SUMO_TAG_OVERHEAD_WIRE_SEGMENT
An overhead wire segment.
@ SUMO_TAG_PARAM
parameter associated to a certain key
@ SUMO_TAG_PERSON
@ SUMO_TAG_PERSONFLOW
@ SUMO_TAG_TRIP
a single trip definition (used by router)
@ SUMO_ATTR_STARTPOS
@ SUMO_ATTR_LINES
@ SUMO_ATTR_LAST
@ SUMO_ATTR_LANE
@ SUMO_ATTR_LON
@ SUMO_ATTR_REFID
@ SUMO_ATTR_FROM_JUNCTION
@ SUMO_ATTR_VIALONLAT
@ SUMO_ATTR_SPEED
@ SUMO_ATTR_VIA
@ SUMO_ATTR_CONTAINER_STOP
@ SUMO_ATTR_PARKING_AREA
@ SUMO_ATTR_VIAXY
@ SUMO_ATTR_Y
@ SUMO_ATTR_EDGE
@ SUMO_ATTR_BUS_STOP
@ SUMO_ATTR_TRAIN_STOP
@ SUMO_ATTR_ENDPOS
@ SUMO_ATTR_TO_JUNCTION
@ SUMO_ATTR_X
@ SUMO_ATTR_ARRIVALPOS
@ SUMO_ATTR_PROBS
@ SUMO_ATTR_EDGES
the edges of a route
@ SUMO_ATTR_TOLONLAT
@ SUMO_ATTR_CHARGING_STATION
@ SUMO_ATTR_ROUTES
@ SUMO_ATTR_MODES
@ SUMO_ATTR_VTYPES
@ SUMO_ATTR_OVERHEAD_WIRE_SEGMENT
@ SUMO_ATTR_DEPARTPOS
@ SUMO_ATTR_GROUP
@ SUMO_ATTR_COST
@ SUMO_ATTR_TO_TAZ
@ SUMO_ATTR_TO
@ SUMO_ATTR_FROM
@ SUMO_ATTR_FROM_TAZ
@ SUMO_ATTR_VIAJUNCTIONS
@ SUMO_ATTR_FROMXY
@ SUMO_ATTR_PROB
@ SUMO_ATTR_FRIENDLY_POS
@ SUMO_ATTR_LAT
@ SUMO_ATTR_WALKFACTOR
@ SUMO_ATTR_TOXY
@ SUMO_ATTR_ROUTE
@ SUMO_ATTR_COLOR
A color information.
@ SUMO_ATTR_ID
@ SUMO_ATTR_DURATION
@ SUMO_ATTR_FROMLONLAT
@ SUMO_ATTR_REPEAT
@ SUMO_ATTR_CYCLETIME
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:130
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:118
PositionVector getShape(const bool closeShape) const
get position vector (shape) based on this boundary
Definition: Boundary.cpp:423
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:136
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:124
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
bool x2cartesian_const(Position &from) const
Converts the given coordinate into a cartesian using the previous initialisation.
Provides utility functions for matching locations to edges (during route parsing)
Definition: MapMatcher.h:44
void parseGeoEdges(const PositionVector &positions, bool geo, SUMOVehicleClass vClass, std::vector< const ROEdge * > &into, const std::string &rid, bool isFrom, bool &ok)
Definition: MapMatcher.h:56
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:92
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:154
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A RT-tree for efficient storing of SUMO's Named objects.
Definition: NamedRTree.h:61
void Insert(const float a_min[2], const float a_max[2], Named *const &a_data)
Insert entry.
Definition: NamedRTree.h:79
A storage for options typed value containers)
Definition: OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
An output device that encapsulates an ofstream.
std::string getString() const
Returns the current content as a string.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
An upper class for objects with additional parameters.
Definition: Parameterised.h:41
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
A list of positions.
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
A basic edge for routing applications.
Definition: ROEdge.h:70
const ROEdge * getNormalBefore() const
if this edge is an internal edge, return its first normal predecessor, otherwise the edge itself
Definition: ROEdge.cpp:269
bool isInternal() const
return whether this edge is an internal edge
Definition: ROEdge.h:154
const std::vector< ROLane * > & getLanes() const
Returns this edge's lanes.
Definition: ROEdge.h:524
const ROEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition: ROEdge.cpp:366
double getLength() const
Returns the length of the edge.
Definition: ROEdge.h:219
A single lane the router may use.
Definition: ROLane.h:48
The router's network representation.
Definition: RONet.h:62
SUMOVTypeParameter * getVehicleTypeSecure(const std::string &id)
Retrieves the named vehicle type.
Definition: RONet.cpp:364
const RandomDistributor< SUMOVTypeParameter * > * getVTypeDistribution(const std::string &id)
Retrieves the named vehicle type distribution.
Definition: RONet.h:280
const SUMOVehicleParameter::Stop * getStoppingPlace(const std::string &id, const SumoXMLTag category) const
Retrieves a stopping place from the network.
Definition: RONet.h:216
ROEdge * getEdge(const std::string &name) const
Retrieves an edge from the network.
Definition: RONet.h:157
bool addRouteDef(RORouteDef *def)
Definition: RONet.cpp:286
bool knowsVehicle(const std::string &id) const
returns whether a vehicle with the given id was already loaded
Definition: RONet.cpp:488
virtual bool addVehicle(const std::string &id, ROVehicle *veh)
Definition: RONet.cpp:466
SUMOTime getDeparture(const std::string &vehID) const
returns departure time for the given vehicle id
Definition: RONet.cpp:493
void addContainer(const SUMOTime depart, const std::string desc)
Definition: RONet.cpp:534
bool addPerson(ROPerson *person)
Definition: RONet.cpp:522
virtual bool addVehicleType(SUMOVTypeParameter *type)
Adds a read vehicle type definition to the network.
Definition: RONet.cpp:442
RORouteDef * getRouteDef(const std::string &name) const
Returns the named route definition.
Definition: RONet.h:318
bool addVTypeDistribution(const std::string &id, RandomDistributor< SUMOVTypeParameter * > *vehTypeDistribution)
Adds a vehicle type distribution.
Definition: RONet.cpp:455
bool addFlow(SUMOVehicleParameter *flow, const bool randomize)
Definition: RONet.cpp:504
const NamedObjectCont< ROEdge * > & getEdgeMap() const
Definition: RONet.h:422
Every person has a plan comprising of multiple planItems.
Definition: ROPerson.h:83
virtual double getDestinationPos() const =0
A person as used by router.
Definition: ROPerson.h:50
static void addTrip(std::vector< PlanItem * > &plan, const std::string &id, const ROEdge *const from, const ROEdge *const to, const SVCPermissions modeSet, const std::string &vTypes, const double departPos, const std::string &stopOrigin, const double arrivalPos, const std::string &busStop, double walkFactor, const std::string &group)
Definition: ROPerson.cpp:61
static void addStop(std::vector< PlanItem * > &plan, const SUMOVehicleParameter::Stop &stopPar, const ROEdge *const stopEdge)
Definition: ROPerson.cpp:133
static void addRide(std::vector< PlanItem * > &plan, const ROEdge *const from, const ROEdge *const to, const std::string &lines, double arrivalPos, const std::string &destStop, const std::string &group)
Definition: ROPerson.cpp:116
std::vector< PlanItem * > & getPlan()
Definition: ROPerson.h:440
static void addWalk(std::vector< PlanItem * > &plan, const ConstROEdgeVector &edges, const double duration, const double speed, const double departPos, const double arrivalPos, const std::string &busStop)
Definition: ROPerson.cpp:124
Base class for a vehicle's route definition.
Definition: RORouteDef.h:53
void addLoadedAlternative(RORoute *alternative)
Adds a single alternative loaded from the file An alternative may also be generated during DUA.
Definition: RORouteDef.cpp:69
double getOverallProb() const
Returns the sum of the probablities of the contained routes.
Definition: RORouteDef.cpp:431
void addAlternativeDef(const RORouteDef *alternative)
Adds an alternative loaded from the file.
Definition: RORouteDef.cpp:75
RORouteDef * copy(const std::string &id, const SUMOTime stopOffset) const
Returns a deep copy of the route definition.
Definition: RORouteDef.cpp:418
void openVehicleTypeDistribution(const SUMOSAXAttributes &attrs) override
opens a type distribution for reading
const SUMOVehicleParameter::Stop * retrieveStoppingPlace(const SUMOSAXAttributes &attrs, const std::string &errorSuffix, std::string &id, const SUMOVehicleParameter::Stop *stopParam=nullptr)
retrieve stopping place element
void addTransport(const SUMOSAXAttributes &attrs) override
Processing of a transport.
void deleteActivePlanAndVehicleParameter()
void openRoute(const SUMOSAXAttributes &attrs) override
opens a route for reading
std::string myCurrentVTypeDistributionID
The id of the currently parsed vehicle type distribution.
void addFlowPerson(const std::string &typeID, SUMOTime depart, const std::string &baseID, int i)
Processing of a person from a personFlow.
void closeContainerFlow() override
Ends the processing of a containerFlow.
RORouteHandler(RONet &net, const std::string &file, const bool tryRepair, const bool emptyDestinationsAllowed, const bool ignoreErrors, const bool checkSchema)
standard constructor
void parseEdges(const std::string &desc, ConstROEdgeVector &into, const std::string &rid, bool &ok)
Parse edges from strings.
RONet & myNet
The current route.
void addRide(const SUMOSAXAttributes &attrs) override
Processing of a ride.
ConstROEdgeVector myActiveRoute
The current route.
void closeRouteDistribution() override
closes (ends) the building of a distribution
void addTranship(const SUMOSAXAttributes &attrs) override
Processing of a tranship.
void closeContainer() override
Ends the processing of a container.
std::vector< ROPerson::PlanItem * > * myActivePlan
The plan of the current person.
const bool myTryRepair
Information whether routes shall be repaired.
bool checkLastDepart() override
Checks whether the route file is sorted by departure time if needed.
OutputDevice_String * myActiveContainerPlan
The plan of the current container.
void closeVehicle() override
Ends the processing of a vehicle.
SUMOTime myActiveRoutePeriod
const SUMOTime myBegin
The begin time.
void closeRoute(const bool mayBeDisconnected=false) override
closes (ends) the building of a route.
Parameterised * addStop(const SUMOSAXAttributes &attrs) override
Processing of a stop.
RandomDistributor< SUMOVTypeParameter * > * myCurrentVTypeDistribution
The currently parsed distribution of vehicle types (probability->vehicle type)
void closePersonFlow() override
Ends the processing of a personFlow.
void openRouteDistribution(const SUMOSAXAttributes &attrs) override
opens a route distribution for reading
int myActiveContainerPlanSize
The number of stages in myActiveContainerPlan.
const bool myKeepVTypeDist
whether to keep the the vtype distribution in output
void openTrip(const SUMOSAXAttributes &attrs) override
opens a trip for reading
const bool myUnsortedInput
whether input is read all at once (no sorting check is necessary)
void parseWalkPositions(const SUMOSAXAttributes &attrs, const std::string &personID, const ROEdge *fromEdge, const ROEdge *&toEdge, double &departPos, double &arrivalPos, std::string &busStopID, const ROPerson::PlanItem *const lastStage, bool &ok)
@ brief parse depart- and arrival positions of a walk
MsgHandler *const myErrorOutput
Depending on the "ignore-errors" option different outputs are used.
int myActiveRouteRepeat
number of repetitions of the active route
void closeFlow() override
Ends the processing of a flow.
ROEdge * retrieveEdge(const std::string &id) override
void addPersonTrip(const SUMOSAXAttributes &attrs) override
add a routing request for a walking or intermodal person
void closePerson() override
Ends the processing of a person.
~RORouteHandler() override
standard destructor
RORouteDef * myCurrentAlternatives
The currently parsed route alternatives.
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
void addWalk(const SUMOSAXAttributes &attrs) override
add a fully specified walk
void initLaneTree(NamedRTree *tree) override
void openRouteFlow(const SUMOSAXAttributes &attrs) override
opens a route flow for reading
void closeTrip() override
Ends the processing of a trip.
void openFlow(const SUMOSAXAttributes &attrs) override
opens a flow for reading
void closeVType() override
Ends the processing of a vehicle type.
void closeVehicleTypeDistribution() override
closes (ends) the building of a distribution
void parseFromViaTo(SumoXMLTag tag, const SUMOSAXAttributes &attrs, bool &ok)
Called for parsing from and to and the corresponding taz attributes.
A complete router's route.
Definition: RORoute.h:52
const ConstROEdgeVector & getEdgeVector() const
Returns the list of edges this route consists of.
Definition: RORoute.h:152
A vehicle as used by router.
Definition: ROVehicle.h:50
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.cpp:94
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.
const std::vector< T > & getVals() const
Returns 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.
std::vector< Parameterised * > myParamStack
The stack of currently parsed parameterised objects.
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.
virtual 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=T(), bool report=true) const
Tries to read given attribute assuming it is an int.
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.
Structure representing possible vehicle parameter.
double defaultProbability
The probability when being added to a distribution without an explicit probability.
void cacheParamRestrictions(const std::vector< std::string > &restrictionKeys)
SUMOVehicleClass vehicleClass
The vehicle's class.
std::string id
The vehicle type's id.
Definition of vehicle stop (position and duration)
std::string edge
The edge to stop at.
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 parametersSet
Information for the output which parameter were set.
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
Structure representing possible vehicle parameter.
double repetitionProbability
The probability for emitting a vehicle per second.
void incrementFlow(double scale, SumoRNG *rng=nullptr)
increment flow
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 repetitionTotalOffset
The offset between depart and the time for the next vehicle insertions.
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.
bool wasSet(int what) const
Returns whether the given parameter was set.
DepartDefinition departProcedure
Information how the vehicle shall choose the depart time.
static double parseWalkPos(SumoXMLAttr attr, const bool hardFail, const std::string &id, double maxPos, const std::string &val, SumoRNG *rng=0)
parse departPos or arrivalPos for a walk
static std::string getEdgeIDFromLane(const std::string laneID)
return edge id when given the lane ID
std::string front()
returns the first substring without moving the iterator
int size() const
returns the number of existing substrings
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