Eclipse SUMO - Simulation of Urban MObility
IntermodalNetwork.h
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
16 // The Edge definition for the Intermodal Router
17 /****************************************************************************/
18 #ifndef IntermodalNetwork_h
19 #define IntermodalNetwork_h
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26 
27 #include <string>
28 #include <vector>
29 #include <algorithm>
30 #include <assert.h>
32 #include <utils/common/Named.h>
33 #include <utils/common/SUMOTime.h>
34 #include <utils/common/ToString.h>
35 #include <utils/geom/Position.h>
37 #include "AccessEdge.h"
38 #include "CarEdge.h"
39 #include "IntermodalEdge.h"
40 #include "PedestrianEdge.h"
41 #include "PublicTransportEdge.h"
42 #include "StopEdge.h"
43 
44 //#define IntermodalRouter_DEBUG_NETWORK
45 
46 
47 // ===========================================================================
48 // function definitions
49 // ===========================================================================
50 template <class E, class L>
51 inline const L* getSidewalk(const E* edge) {
52  if (edge == nullptr) {
53  return nullptr;
54  }
55  // prefer lanes that are exclusive to pedestrians
56  const std::vector<L*>& lanes = edge->getLanes();
57  for (const L* const lane : lanes) {
58  if (lane->getPermissions() == SVC_PEDESTRIAN) {
59  return lane;
60  }
61  }
62  for (const L* const lane : lanes) {
63  if (lane->allowsVehicleClass(SVC_PEDESTRIAN)) {
64  return lane;
65  }
66  }
67  return nullptr;
68 }
69 
70 
71 // ===========================================================================
72 // class definitions
73 // ===========================================================================
75 template<class E, class L, class N, class V>
77 private:
82  typedef std::pair<_IntermodalEdge*, _IntermodalEdge*> EdgePair;
83 
84 public:
91  PT_STOPS = 2,
94  };
95 
96  /* @brief build the pedestrian part of the intermodal network (once)
97  * @param edges The list of MSEdge or ROEdge to build from
98  * @param numericalID the start number for the creation of new edges
99  */
100  IntermodalNetwork(const std::vector<E*>& edges, const bool pedestrianOnly, const int carWalkTransfer = 0)
101  : myNumericalID(0), myCarWalkTransfer(carWalkTransfer) {
102 #ifdef IntermodalRouter_DEBUG_NETWORK
103  std::cout << "initIntermodalNetwork\n";
104 #endif
105  // build the pedestrian edges and the depart / arrival connectors with lookup tables
106  bool haveSeenWalkingArea = false;
107  for (const E* const edge : edges) {
108  if (edge->isTazConnector()) {
109  continue;
110  }
111  const L* lane = getSidewalk<E, L>(edge);
112  if (lane != 0) {
113  if (edge->isWalkingArea()) {
114  // only a single edge
115  addEdge(new _PedestrianEdge(myNumericalID++, edge, lane, true));
116  myBidiLookup[edge] = std::make_pair(myEdges.back(), myEdges.back());
117  myDepartLookup[edge].push_back(myEdges.back());
118  myArrivalLookup[edge].push_back(myEdges.back());
119  haveSeenWalkingArea = true;
120  } else { // regular edge or crossing
121  // forward and backward edges
122  addEdge(new _PedestrianEdge(myNumericalID++, edge, lane, true));
123  addEdge(new _PedestrianEdge(myNumericalID++, edge, lane, false));
124  myBidiLookup[edge] = std::make_pair(myEdges[myNumericalID - 2], myEdges.back());
125  }
126  }
127  if (!edge->isWalkingArea()) {
128  // depart and arrival edges (the router can decide the initial direction to take and the direction to arrive from)
129  _IntermodalEdge* const departConn = new _IntermodalEdge(edge->getID() + "_depart_connector", myNumericalID++, edge, "!connector");
130  _IntermodalEdge* const arrivalConn = new _IntermodalEdge(edge->getID() + "_arrival_connector", myNumericalID++, edge, "!connector");
131  addConnectors(departConn, arrivalConn, 0);
132  }
133  }
134 
135  // build the walking connectors if there are no walking areas
136  for (const E* const edge : edges) {
137  if (edge->isTazConnector() || edge->isInternal()) {
138  continue;
139  }
140  if (haveSeenWalkingArea) {
141  // connectivity needs to be ensured only in the real intermodal case, for simple pedestrian routing we don't have connectors if we have walking areas
142  if (!pedestrianOnly && getSidewalk<E, L>(edge) == nullptr) {
143  const N* const node = edge->getToJunction();
144  if (myWalkingConnectorLookup.count(node) == 0) {
145  addEdge(new _IntermodalEdge(node->getID() + "_walking_connector", myNumericalID++, nullptr, "!connector"));
146  myWalkingConnectorLookup[node] = myEdges.back();
147  }
148  }
149  } else {
150  for (const N* const node : {
151  edge->getFromJunction(), edge->getToJunction()
152  }) {
153  if (myWalkingConnectorLookup.count(node) == 0) {
154  addEdge(new _IntermodalEdge(node->getID() + "_walking_connector", myNumericalID++, nullptr, "!connector"));
155  myWalkingConnectorLookup[node] = myEdges.back();
156  }
157  }
158  }
159  }
160  // build the connections
161  for (const E* const edge : edges) {
162  if (edge->isTazConnector()) {
163  continue;
164  }
165  const L* const sidewalk = getSidewalk<E, L>(edge);
166  if (sidewalk == nullptr) {
167  continue;
168  }
169  // find all incoming and outgoing lanes for the sidewalk and
170  // connect the corresponding IntermodalEdges
171  const EdgePair& pair = getBothDirections(edge);
172 #ifdef IntermodalRouter_DEBUG_NETWORK
173  std::cout << " building connections from " << sidewalk->getID() << "\n";
174 #endif
175  if (haveSeenWalkingArea) {
176  const std::vector<std::pair<const L*, const E*> > outgoing = sidewalk->getOutgoingViaLanes();
177  // if one of the outgoing lanes is a walking area it must be used.
178  // All other connections shall be ignored
179  // if it has no outgoing walking area, it probably is a walking area itself
180  bool hasWalkingArea = false;
181  for (const auto& target : outgoing) {
182  if (target.first->getEdge().isWalkingArea()) {
183  hasWalkingArea = true;
184  break;
185  }
186  }
187  for (const auto& target : outgoing) {
188  const E* const targetEdge = &(target.first->getEdge());
189  const bool used = (target.first == getSidewalk<E, L>(targetEdge)
190  && (!hasWalkingArea || targetEdge->isWalkingArea()));
191 #ifdef IntermodalRouter_DEBUG_NETWORK
192  const L* potTarget = getSidewalk<E, L>(targetEdge);
193  std::cout << " lane=" << (potTarget == 0 ? "NULL" : potTarget->getID()) << (used ? "(used)" : "") << "\n";
194 #endif
195  if (used) {
196  const EdgePair& targetPair = getBothDirections(targetEdge);
197  pair.first->addSuccessor(targetPair.first);
198  targetPair.second->addSuccessor(pair.second);
199 #ifdef IntermodalRouter_DEBUG_NETWORK
200  std::cout << " " << pair.first->getID() << " -> " << targetPair.first->getID() << "\n";
201  std::cout << " " << targetPair.second->getID() << " -> " << pair.second->getID() << "\n";
202 #endif
203  }
204  }
205  }
206  // We may have a network without pedestrian structures or a car-only edge.
207  // In the first case we assume that all sidewalks at a junction are interconnected,
208  // in the second we connect all car-only edges to all sidewalks.
209  _IntermodalEdge* const toNodeConn = myWalkingConnectorLookup[edge->getToJunction()];
210  if (toNodeConn != nullptr) {
211  // Check for the outgoing vias and use the shortest one as an approximation
212  const std::vector<std::pair<const L*, const E*> > outgoing = sidewalk->getOutgoingViaLanes();
213  double minViaLength = std::numeric_limits<double>::max();
214  const E* minVia = nullptr;
215  for (const auto& target : outgoing) {
216  if (target.second != nullptr && target.second->getLength() < minViaLength) {
217  minViaLength = target.second->getLength();
218  minVia = target.second;
219  }
220  }
221  EdgePair interVia = std::make_pair(nullptr, nullptr);
222  if (minVia != nullptr) {
223  const auto it = myBidiLookup.find(minVia);
224  if (it != myBidiLookup.end()) {
225  interVia = it->second;
226  }
227  }
228  if (!haveSeenWalkingArea) {
229  // if we have walking areas we should use them and not the connector
230  pair.first->addSuccessor(toNodeConn, interVia.first);
231  }
232  toNodeConn->addSuccessor(pair.second, interVia.second);
233  }
234  _IntermodalEdge* const fromNodeConn = myWalkingConnectorLookup[edge->getFromJunction()];
235  if (fromNodeConn != nullptr) {
236  if (!haveSeenWalkingArea) {
237  pair.second->addSuccessor(fromNodeConn);
238  }
239  fromNodeConn->addSuccessor(pair.first);
240  }
241  if (!edge->isWalkingArea()) {
242  // build connections from depart connector
243  _IntermodalEdge* startConnector = getDepartConnector(edge);
244  startConnector->addSuccessor(pair.first);
245  startConnector->addSuccessor(pair.second);
246  // build connections to arrival connector
247  _IntermodalEdge* endConnector = getArrivalConnector(edge);
248  pair.first->addSuccessor(endConnector);
249  pair.second->addSuccessor(endConnector);
250  }
251 #ifdef IntermodalRouter_DEBUG_NETWORK
252  std::cout << " " << startConnector->getID() << " -> " << pair.first->getID() << "\n";
253  std::cout << " " << startConnector->getID() << " -> " << pair.second->getID() << "\n";
254  std::cout << " " << pair.first->getID() << " -> " << endConnector->getID() << "\n";
255  std::cout << " " << pair.second->getID() << " -> " << endConnector->getID() << "\n";
256 #endif
257  }
258  }
259 
261  for (typename std::vector<_IntermodalEdge*>::iterator it = myEdges.begin(); it != myEdges.end(); ++it) {
262  delete *it;
263  }
264  }
265 
266  void addEdge(_IntermodalEdge* edge) {
267  while ((int)myEdges.size() <= edge->getNumericalID()) {
268  myEdges.push_back(0);
269  }
270  myEdges[edge->getNumericalID()] = edge;
271  }
272 
273  void addConnectors(_IntermodalEdge* const depConn, _IntermodalEdge* const arrConn, const int index) {
274  addEdge(depConn);
275  addEdge(arrConn);
276  myDepartLookup[depConn->getEdge()].insert(myDepartLookup[depConn->getEdge()].begin() + index, depConn);
277  myArrivalLookup[arrConn->getEdge()].insert(myArrivalLookup[arrConn->getEdge()].begin() + index, arrConn);
278  }
279 
280  const std::vector<_IntermodalEdge*>& getAllEdges() {
281  return myEdges;
282  }
283 
285  const EdgePair& getBothDirections(const E* e) const {
286  typename std::map<const E*, EdgePair>::const_iterator it = myBidiLookup.find(e);
287  if (it == myBidiLookup.end()) {
288  assert(false);
289  throw ProcessError("Edge '" + e->getID() + "' not found in intermodal network.'");
290  }
291  return (*it).second;
292  }
293 
295  const _IntermodalEdge* getDepartEdge(const E* e, const double pos) const {
296  typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it = myDepartLookup.find(e);
297  if (it == myDepartLookup.end()) {
298  throw ProcessError("Depart edge '" + e->getID() + "' not found in intermodal network.");
299  }
300  if (isRailway(e->getPermissions())) {
301  // use closest split (best trainStop)
302  double totalLength = 0.;
303  double bestDist = std::numeric_limits<double>::max();
304  const _IntermodalEdge* best = nullptr;
305  for (const _IntermodalEdge* split : it->second) {
306  totalLength += split->getLength();
307  double dist = fabs(totalLength - pos);
308  if (dist < bestDist) {
309  // make sure to use a stop rather than the final departConnector since walking is not possible
310  if (bestDist != std::numeric_limits<double>::max() && split == it->second.back()) {
311  break;
312  }
313  bestDist = dist;
314  best = split;
315  } else {
316  break;
317  }
318  }
319  assert(best != 0);
320  return best;
321  } else {
322  // use next downstream edge
323  const std::vector<_IntermodalEdge*>& splitList = it->second;
324  typename std::vector<_IntermodalEdge*>::const_iterator splitIt = splitList.begin();
325  double totalLength = 0.;
326  while (splitIt + 1 != splitList.end() && totalLength + (*splitIt)->getLength() < pos) {
327  totalLength += (*splitIt)->getLength();
328  ++splitIt;
329  }
330  return *splitIt;
331  }
332  }
333 
335  _IntermodalEdge* getDepartConnector(const E* e, const int splitIndex = 0) const {
336  typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it = myDepartLookup.find(e);
337  if (it == myDepartLookup.end()) {
338  throw ProcessError("Depart edge '" + e->getID() + "' not found in intermodal network.");
339  }
340  if (splitIndex >= (int)it->second.size()) {
341  throw ProcessError("Split index " + toString(splitIndex) + " invalid for depart edge '" + e->getID() + "' .");
342  }
343  return it->second[splitIndex];
344  }
345 
347  _IntermodalEdge* getArrivalEdge(const E* e, const double pos) const {
348  typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it = myArrivalLookup.find(e);
349  if (it == myArrivalLookup.end()) {
350  throw ProcessError("Arrival edge '" + e->getID() + "' not found in intermodal network.");
351  }
352  const std::vector<_IntermodalEdge*>& splitList = it->second;
353  typename std::vector<_IntermodalEdge*>::const_iterator splitIt = splitList.begin();
354  double totalLength = 0.;
355  while (splitIt != splitList.end() && totalLength + (*splitIt)->getLength() < pos) {
356  totalLength += (*splitIt)->getLength();
357  ++splitIt;
358  }
359  return *splitIt;
360  }
361 
363  _IntermodalEdge* getArrivalConnector(const E* e, const int splitIndex = 0) const {
364  return myArrivalLookup.find(e)->second[splitIndex];
365  }
366 
369  typename std::map<const N*, _IntermodalEdge*>::const_iterator it = myWalkingConnectorLookup.find(e->getToJunction());
370  if (it == myWalkingConnectorLookup.end()) {
371  const L* const sidewalk = getSidewalk<E, L>(e);
372  if (e->isInternal() || sidewalk == 0) {
373  return 0;
374  }
375  for (const auto& target : sidewalk->getOutgoingViaLanes()) {
376  if (target.first->getEdge().isWalkingArea()) {
377  return getBothDirections(&target.first->getEdge()).first;
378  }
379  }
380  return 0;
381  }
382  return it->second;
383  }
384 
385  void addCarEdges(const std::vector<E*>& edges) {
386  for (const E* const edge : edges) {
387  if (edge->getFunction() == EDGEFUNC_NORMAL || edge->getFunction() == EDGEFUNC_INTERNAL) {
388  myCarLookup[edge] = new CarEdge<E, L, N, V>(myNumericalID++, edge);
389  addEdge(myCarLookup[edge]);
390  }
391  }
392  for (const auto& edgePair : myCarLookup) {
393  _IntermodalEdge* const carEdge = edgePair.second;
394  for (const auto& suc : edgePair.first->getViaSuccessors()) {
395  _IntermodalEdge* const sucCarEdge = getCarEdge(suc.first);
396  _IntermodalEdge* const sucViaEdge = getCarEdge(suc.second);
397  if (sucCarEdge != nullptr) {
398  carEdge->addSuccessor(sucCarEdge, sucViaEdge);
399  }
400  }
401  if ((myCarWalkTransfer & ALL_JUNCTIONS) != 0) {
402  _IntermodalEdge* const walkCon = getWalkingConnector(edgePair.first);
403  if (walkCon != 0) {
404  carEdge->addSuccessor(walkCon);
405  } else {
406  // we are on an edge where pedestrians are forbidden and want to continue on an arbitrary pedestrian edge
407  for (const E* const out : edgePair.first->getToJunction()->getOutgoing()) {
408  if (!out->isInternal() && !out->isTazConnector() && getSidewalk<E, L>(out) != 0) {
409  carEdge->addSuccessor(getBothDirections(out).first);
410  }
411  }
412  for (const E* const in : edgePair.first->getToJunction()->getIncoming()) {
413  if (!in->isInternal() && !in->isTazConnector() && getSidewalk<E, L>(in) != 0) {
414  carEdge->addSuccessor(getBothDirections(in).second);
415  }
416  }
417  }
418  }
419  getDepartConnector(edgePair.first)->addSuccessor(carEdge);
420  carEdge->addSuccessor(getArrivalConnector(edgePair.first));
421  }
422  }
423 
425  _IntermodalEdge* getCarEdge(const E* e) const {
426  typename std::map<const E*, _IntermodalEdge*>::const_iterator it = myCarLookup.find(e);
427  if (it == myCarLookup.end()) {
428  return nullptr;
429  }
430  return it->second;
431  }
432 
434  _IntermodalEdge* getStopEdge(const std::string& stopId) const {
435  auto it = myStopConnections.find(stopId);
436  if (it == myStopConnections.end()) {
437  return nullptr;
438  }
439  return it->second;
440  }
441 
455  void addAccess(const std::string& stopId, const E* stopEdge, const double pos, const double length, const SumoXMLTag category) {
456  assert(stopEdge != nullptr);
457  const bool transferCarWalk = ((category == SUMO_TAG_PARKING_AREA && (myCarWalkTransfer & PARKING_AREAS) != 0) ||
458  (category == SUMO_TAG_BUS_STOP && (myCarWalkTransfer & PT_STOPS) != 0));
459  //std::cout << "addAccess stopId=" << stopId << " stopEdge=" << stopEdge->getID() << " pos=" << pos << " length=" << length << " cat=" << category << "\n";
460  if (myStopConnections.count(stopId) == 0) {
461  myStopConnections[stopId] = new StopEdge<E, L, N, V>(stopId, myNumericalID++, stopEdge);
462  addEdge(myStopConnections[stopId]);
463  }
464  _IntermodalEdge* const stopConn = myStopConnections[stopId];
465  const L* lane = getSidewalk<E, L>(stopEdge);
466  if (lane != nullptr) {
467  const std::pair<_IntermodalEdge*, _IntermodalEdge*>& pair = getBothDirections(stopEdge);
468  double relPos;
469  bool needSplit;
470  const int splitIndex = findSplitIndex(pair.first, pos, relPos, needSplit);
471  _IntermodalEdge* const fwdSplit = needSplit ? new PedestrianEdge<E, L, N, V>(myNumericalID++, stopEdge, lane, true, pos) : nullptr;
472  splitEdge(pair.first, splitIndex, fwdSplit, relPos, length, needSplit, stopConn);
473  _IntermodalEdge* const backSplit = needSplit ? new PedestrianEdge<E, L, N, V>(myNumericalID++, stopEdge, lane, false, pos) : nullptr;
474  splitEdge(pair.second, splitIndex, backSplit, relPos, length, needSplit, stopConn, false);
475  _IntermodalEdge* carSplit = nullptr;
476  if (myCarLookup.count(stopEdge) > 0) {
477  if (needSplit) {
478  carSplit = new CarEdge<E, L, N, V>(myNumericalID++, stopEdge, pos);
479  }
480  splitEdge(myCarLookup[stopEdge], splitIndex, carSplit, relPos, length, needSplit, stopConn, true, false, transferCarWalk);
481  }
482  if (needSplit) {
483  if (carSplit != nullptr && transferCarWalk) {
484  // adding access from car to walk
485  _IntermodalEdge* const beforeSplit = myAccessSplits[myCarLookup[stopEdge]][splitIndex];
486  for (_IntermodalEdge* conn : {
487  fwdSplit, backSplit
488  }) {
489  _AccessEdge* access = new _AccessEdge(myNumericalID++, beforeSplit, conn, length);
490  addEdge(access);
491  beforeSplit->addSuccessor(access);
492  access->addSuccessor(conn);
493  }
494  }
495 
496  // fixing depart connections for the forward pedestrian, the backward pedestrian and the car edge
497  _IntermodalEdge* const prevDep = getDepartConnector(stopEdge, splitIndex);
498  const std::vector<_IntermodalEdge*>& backSplitList = myAccessSplits[pair.second];
499  _IntermodalEdge* const backBeforeSplit = backSplitList[backSplitList.size() - 2 - splitIndex];
500  _IntermodalEdge* const depConn = new _IntermodalEdge(stopEdge->getID() + "_depart_connector" + toString(pos), myNumericalID++, stopEdge, "!connector");
501  depConn->addSuccessor(fwdSplit);
502  depConn->addSuccessor(backBeforeSplit);
503  depConn->setLength(fwdSplit->getLength());
504  prevDep->removeSuccessor(backBeforeSplit);
505  prevDep->addSuccessor(backSplit);
506  prevDep->setLength(backSplit->getLength());
507  if (carSplit != nullptr) {
508  depConn->addSuccessor(carSplit);
509  }
510 
511  // fixing arrival connections for the forward pedestrian, the backward pedestrian and the car edge
512  _IntermodalEdge* const prevArr = getArrivalConnector(stopEdge, splitIndex);
513  _IntermodalEdge* const fwdBeforeSplit = myAccessSplits[pair.first][splitIndex];
514  _IntermodalEdge* const arrConn = new _IntermodalEdge(stopEdge->getID() + "_arrival_connector" + toString(pos), myNumericalID++, stopEdge, "!connector");
515  fwdSplit->addSuccessor(arrConn);
516  backBeforeSplit->addSuccessor(arrConn);
517  arrConn->setLength(fwdSplit->getLength());
518  fwdSplit->removeSuccessor(prevArr);
519  fwdBeforeSplit->addSuccessor(prevArr);
520  prevArr->setLength(backSplit->getLength());
521  if (carSplit != nullptr) {
522  carSplit->addSuccessor(arrConn);
523  carSplit->removeSuccessor(prevArr);
524  myAccessSplits[myCarLookup[stopEdge]][splitIndex]->addSuccessor(prevArr);
525  }
526  addConnectors(depConn, arrConn, splitIndex + 1);
527  }
528  } else {
529  // pedestrians cannot walk here:
530  // add depart connectors on the stop edge so that pedestrians may start at the stop
531  std::vector<_IntermodalEdge*>& splitList = myDepartLookup[stopEdge];
532  assert(splitList.size() > 0);
533  typename std::vector<_IntermodalEdge*>::iterator splitIt = splitList.begin();
534  double totalLength = 0.;
535  _IntermodalEdge* last = nullptr;
536  while (splitIt != splitList.end() && totalLength < pos) {
537  totalLength += (*splitIt)->getLength();
538  last = *splitIt;
539  ++splitIt;
540  }
541  // insert before last
542  const double newLength = pos - (totalLength - last->getLength());
543  stopConn->setLength(newLength);
544  splitList.insert(splitIt - 1, stopConn);
545  // correct length of subsequent edge
546  last->setLength(last->getLength() - newLength);
547  }
548  }
549 
550  void addSchedule(const SUMOVehicleParameter& pars, const std::vector<SUMOVehicleParameter::Stop>* addStops = nullptr) {
551  SUMOTime lastUntil = 0;
552  std::vector<SUMOVehicleParameter::Stop> validStops;
553  if (addStops != nullptr) {
554  // stops are part of a stand-alone route. until times are offsets from vehicle departure
555  for (const SUMOVehicleParameter::Stop& stop : *addStops) {
556  if (myStopConnections.count(stop.busstop) > 0) {
557  // compute stop times for the first vehicle
558  const SUMOTime newUntil = stop.until + pars.depart;
559  if (newUntil >= lastUntil) {
560  validStops.push_back(stop);
561  validStops.back().until = newUntil;
562  lastUntil = newUntil;
563  } else {
564  WRITE_WARNING("Ignoring unordered stop at '" + stop.busstop + "' until " + time2string(stop.until) + " for vehicle '" + pars.id + "'.");
565  }
566  }
567  }
568  }
569  for (const SUMOVehicleParameter::Stop& stop : pars.stops) {
570  // stops are part of the vehicle until times are absolute times for the first vehicle
571  if (myStopConnections.count(stop.busstop) > 0 && stop.until >= lastUntil) {
572  validStops.push_back(stop);
573  lastUntil = stop.until;
574  } else {
575  WRITE_WARNING("Ignoring stop at '" + stop.busstop + "' until " + time2string(stop.until) + " for vehicle '" + pars.id + "'.");
576  }
577  }
578  if (validStops.size() < 2) {
579  WRITE_WARNING("Not using public transport line '" + pars.line + "' for routing persons. It has less than two usable stops.");
580  return;
581  }
582 
583  typename std::vector<_PTEdge*>& lineEdges = myPTLines[pars.line];
584  if (lineEdges.empty()) {
585  _IntermodalEdge* lastStop = nullptr;
586  Position lastPos;
587  SUMOTime lastTime = 0;
588  for (const SUMOVehicleParameter::Stop& s : validStops) {
589  _IntermodalEdge* currStop = myStopConnections[s.busstop];
590  Position stopPos = E::getStopPosition(s);
591  if (lastStop != nullptr) {
592  _PTEdge* const newEdge = new _PTEdge(s.busstop, myNumericalID++, lastStop, currStop->getEdge(), pars.line, lastPos.distanceTo(stopPos));
593  addEdge(newEdge);
594  newEdge->addSchedule(pars.id, lastTime, pars.repetitionNumber, pars.repetitionOffset, s.until - lastTime);
595  lastStop->addSuccessor(newEdge);
596  newEdge->addSuccessor(currStop);
597  lineEdges.push_back(newEdge);
598  }
599  lastTime = s.until;
600  lastStop = currStop;
601  lastPos = stopPos;
602  }
603  } else {
604  if (validStops.size() != lineEdges.size() + 1) {
605  WRITE_WARNING("Number of stops for public transport line '" + pars.line + "' does not match earlier definitions, ignoring schedule.");
606  return;
607  }
608  if (lineEdges.front()->getEntryStop() != myStopConnections[validStops.front().busstop]) {
609  WRITE_WARNING("Different stop for '" + pars.line + "' compared to earlier definitions, ignoring schedule.");
610  return;
611  }
612  typename std::vector<_PTEdge*>::const_iterator lineEdge = lineEdges.begin();
613  typename std::vector<SUMOVehicleParameter::Stop>::const_iterator s = validStops.begin() + 1;
614  for (; s != validStops.end(); ++s, ++lineEdge) {
615  if ((*lineEdge)->getSuccessors(SVC_IGNORING)[0] != myStopConnections[s->busstop]) {
616  WRITE_WARNING("Different stop for '" + pars.line + "' compared to earlier definitions, ignoring schedule.");
617  return;
618  }
619  }
620  SUMOTime lastTime = validStops.front().until;
621  if (lineEdges.front()->hasSchedule(lastTime)) {
622  WRITE_WARNING("Duplicate schedule for '" + pars.line + "' at time " + time2string(lastTime) + ".");
623  }
624  for (lineEdge = lineEdges.begin(), s = validStops.begin() + 1; lineEdge != lineEdges.end(); ++lineEdge, ++s) {
625  (*lineEdge)->addSchedule(pars.id, lastTime, pars.repetitionNumber, pars.repetitionOffset, s->until - lastTime);
626  lastTime = s->until;
627  }
628  }
629  }
630 
631 
632 private:
644  int findSplitIndex(_IntermodalEdge* const toSplit, const double pos, double& relPos, bool& needSplit) {
645  relPos = pos;
646  needSplit = true;
647  int splitIndex = 0;
648  std::vector<_IntermodalEdge*>& splitList = myAccessSplits[toSplit];
649  if (!splitList.empty()) {
650  for (const _IntermodalEdge* const split : splitList) {
651  if (relPos < split->getLength() + POSITION_EPS) {
652  break;
653  }
654  relPos -= split->getLength();
655  splitIndex++;
656  }
657  assert(splitIndex < (int)splitList.size());
658  if (splitIndex + 1 < (int)splitList.size() && fabs(relPos - splitList[splitIndex]->getLength()) < POSITION_EPS) {
659  needSplit = false;
660  }
661  }
662  return splitIndex;
663  }
664 
677  void splitEdge(_IntermodalEdge* const toSplit, int splitIndex,
678  _IntermodalEdge* afterSplit, const double relPos, const double length, const bool needSplit,
679  _IntermodalEdge* const stopConn, const bool forward = true, const bool addExit = true, const bool addEntry = true) {
680  std::vector<_IntermodalEdge*>& splitList = myAccessSplits[toSplit];
681  if (splitList.empty()) {
682  splitList.push_back(toSplit);
683  }
684  if (!forward) {
685  splitIndex = (int)splitList.size() - 1 - splitIndex;
686  if (!needSplit) {
687  splitIndex--;
688  }
689  }
690  _IntermodalEdge* beforeSplit = splitList[splitIndex];
691  if (needSplit) {
692  addEdge(afterSplit);
693  beforeSplit->transferSuccessors(afterSplit);
694  beforeSplit->addSuccessor(afterSplit);
695  if (forward) {
696  afterSplit->setLength(beforeSplit->getLength() - relPos);
697  beforeSplit->setLength(relPos);
698  } else {
699  afterSplit->setLength(relPos);
700  beforeSplit->setLength(beforeSplit->getLength() - relPos);
701  // rename backward edges for easier referencing
702  const std::string newID = beforeSplit->getID();
703  beforeSplit->setID(afterSplit->getID());
704  afterSplit->setID(newID);
705  }
706  splitList.insert(splitList.begin() + splitIndex + 1, afterSplit);
707  } else {
708  // don't split, use the present split edges
709  afterSplit = splitList[splitIndex + 1];
710  }
711  // add access to / from edge
712  if (addEntry) {
713  _AccessEdge* access = new _AccessEdge(myNumericalID++, beforeSplit, stopConn, length);
714  addEdge(access);
715  beforeSplit->addSuccessor(access);
716  access->addSuccessor(stopConn);
717  }
718  if (addExit) {
719  // pedestrian case only, exit from public to pedestrian
720  _AccessEdge* exit = new _AccessEdge(myNumericalID++, stopConn, afterSplit, length);
721  addEdge(exit);
722  stopConn->addSuccessor(exit);
723  exit->addSuccessor(afterSplit);
724  }
725  }
726 
727 
728 private:
730  std::vector<_IntermodalEdge*> myEdges;
731 
733  std::map<const E*, EdgePair> myBidiLookup;
734 
736  std::map<const E*, std::vector<_IntermodalEdge*> > myDepartLookup;
737 
739  std::map<const E*, std::vector<_IntermodalEdge*> > myArrivalLookup;
740 
742  std::map<const N*, _IntermodalEdge*> myWalkingConnectorLookup;
743 
745  std::map<const E*, _IntermodalEdge*> myCarLookup;
746 
748  std::map<std::string, std::vector<_PTEdge*> > myPTLines;
749 
751  std::map<std::string, _IntermodalEdge*> myStopConnections;
752 
754  std::map<_IntermodalEdge*, std::vector<_IntermodalEdge*> > myAccessSplits;
755 
757  const int myCarWalkTransfer;
758 
759 private:
762 
763 };
764 
765 
766 #endif
767 
768 /****************************************************************************/
StopEdge.h
EDGEFUNC_INTERNAL
Definition: SUMOXMLDefinitions.h:1085
PublicTransportEdge::addSchedule
void addSchedule(const std::string id, const SUMOTime begin, const int repetitionNumber, const SUMOTime period, const SUMOTime travelTime)
Definition: PublicTransportEdge.h:72
SVC_PEDESTRIAN
pedestrian
Definition: SUMOVehicleClass.h:156
ToString.h
IntermodalEdge.h
IntermodalNetwork::getStopEdge
_IntermodalEdge * getStopEdge(const std::string &stopId) const
Returns the associated stop edge.
Definition: IntermodalNetwork.h:434
WRITE_WARNING
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:275
SUMOTime.h
IntermodalNetwork::getDepartEdge
const _IntermodalEdge * getDepartEdge(const E *e, const double pos) const
Returns the departing intermodal edge.
Definition: IntermodalNetwork.h:295
IntermodalNetwork::myArrivalLookup
std::map< const E *, std::vector< _IntermodalEdge * > > myArrivalLookup
retrieve the arrival edges for the given input edge E
Definition: IntermodalNetwork.h:739
IntermodalNetwork::EdgePair
std::pair< _IntermodalEdge *, _IntermodalEdge * > EdgePair
Definition: IntermodalNetwork.h:82
IntermodalNetwork::ALL_JUNCTIONS
junctions with edges allowing the additional mode
Definition: IntermodalNetwork.h:93
IntermodalEdge::removeSuccessor
void removeSuccessor(const IntermodalEdge *const edge)
Definition: IntermodalEdge.h:79
PedestrianEdge.h
IntermodalNetwork::getCarEdge
_IntermodalEdge * getCarEdge(const E *e) const
Returns the associated car edge.
Definition: IntermodalNetwork.h:425
MsgHandler.h
SUMOVehicleParameter::repetitionOffset
SUMOTime repetitionOffset
The time offset between vehicle reinsertions.
Definition: SUMOVehicleParameter.h:550
SUMOVehicleParameter::Stop::busstop
std::string busstop
(Optional) bus stop if one is assigned to the stop
Definition: SUMOVehicleParameter.h:589
PublicTransportEdge.h
SUMOTime
long long int SUMOTime
Definition: SUMOTime.h:34
IntermodalEdge::getLength
double getLength() const
Definition: IntermodalEdge.h:135
PublicTransportEdge
the public transport edge type connecting the stop edges
Definition: PublicTransportEdge.h:33
IntermodalNetwork::PARKING_AREAS
parking areas
Definition: IntermodalNetwork.h:89
IntermodalNetwork::addSchedule
void addSchedule(const SUMOVehicleParameter &pars, const std::vector< SUMOVehicleParameter::Stop > *addStops=nullptr)
Definition: IntermodalNetwork.h:550
FareToken::L
SUMOVehicleParameter
Structure representing possible vehicle parameter.
Definition: SUMOVehicleParameter.h:297
IntermodalNetwork::addEdge
void addEdge(_IntermodalEdge *edge)
Definition: IntermodalNetwork.h:266
IntermodalEdge::setLength
void setLength(const double length)
Definition: IntermodalEdge.h:139
IntermodalEdge
the base edge type that is given to the internal router (SUMOAbstractRouter)
Definition: IntermodalEdge.h:39
IntermodalNetwork::_PTEdge
PublicTransportEdge< E, L, N, V > _PTEdge
Definition: IntermodalNetwork.h:81
IntermodalNetwork::splitEdge
void splitEdge(_IntermodalEdge *const toSplit, int splitIndex, _IntermodalEdge *afterSplit, const double relPos, const double length, const bool needSplit, _IntermodalEdge *const stopConn, const bool forward=true, const bool addExit=true, const bool addEntry=true)
Splits an edge (if necessary) and connects it to a stopping edge.
Definition: IntermodalNetwork.h:677
IntermodalNetwork::myStopConnections
std::map< std::string, _IntermodalEdge * > myStopConnections
retrieve the representing edge for the given stopping place
Definition: IntermodalNetwork.h:751
SumoXMLTag
SumoXMLTag
Numbers representing SUMO-XML - element names.
Definition: SUMOXMLDefinitions.h:41
SUMOVehicleParameter::depart
SUMOTime depart
Definition: SUMOVehicleParameter.h:482
IntermodalNetwork::myEdges
std::vector< _IntermodalEdge * > myEdges
the edge dictionary
Definition: IntermodalNetwork.h:730
IntermodalNetwork::~IntermodalNetwork
~IntermodalNetwork()
Definition: IntermodalNetwork.h:260
PedestrianEdge
the pedestrian edge type that is given to the internal router (SUMOAbstractRouter)
Definition: PedestrianEdge.h:37
IntermodalNetwork::_PedestrianEdge
PedestrianEdge< E, L, N, V > _PedestrianEdge
Definition: IntermodalNetwork.h:80
SUMOVehicleParameter.h
IntermodalNetwork::addCarEdges
void addCarEdges(const std::vector< E * > &edges)
Definition: IntermodalNetwork.h:385
IntermodalNetwork::myNumericalID
int myNumericalID
Definition: IntermodalNetwork.h:756
SUMOVehicleParameter::line
std::string line
The vehicle's line (mainly for public transport)
Definition: SUMOVehicleParameter.h:561
IntermodalNetwork::myWalkingConnectorLookup
std::map< const N *, _IntermodalEdge * > myWalkingConnectorLookup
the walking connector edge (fake walking area)
Definition: IntermodalNetwork.h:742
CarEdge
the car edge type that is given to the internal router (SUMOAbstractRouter)
Definition: CarEdge.h:36
IntermodalNetwork::findSplitIndex
int findSplitIndex(_IntermodalEdge *const toSplit, const double pos, double &relPos, bool &needSplit)
Returns where to insert or use the split edge.
Definition: IntermodalNetwork.h:644
AccessEdge
the access edge connecting different modes that is given to the internal router (SUMOAbstractRouter)
Definition: AccessEdge.h:33
IntermodalNetwork::myBidiLookup
std::map< const E *, EdgePair > myBidiLookup
retrieve the forward and backward edge for the given input edge E
Definition: IntermodalNetwork.h:733
IntermodalEdge::getNumericalID
int getNumericalID() const
Definition: IntermodalEdge.h:63
Position::distanceTo
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:233
Named.h
SUMOVehicleParameter::Stop::until
SUMOTime until
The time at which the vehicle may continue its journey.
Definition: SUMOVehicleParameter.h:610
SUMOVehicleParameter::id
std::string id
The vehicle's id.
Definition: SUMOVehicleParameter.h:468
SUMO_TAG_PARKING_AREA
A parking area.
Definition: SUMOXMLDefinitions.h:107
IntermodalNetwork::PT_STOPS
public transport stops and access
Definition: IntermodalNetwork.h:91
IntermodalNetwork::IntermodalNetwork
IntermodalNetwork(const std::vector< E * > &edges, const bool pedestrianOnly, const int carWalkTransfer=0)
Definition: IntermodalNetwork.h:100
ProcessError
Definition: UtilExceptions.h:39
isRailway
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
Definition: SUMOVehicleClass.cpp:363
Position
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:38
IntermodalNetwork::_AccessEdge
AccessEdge< E, L, N, V > _AccessEdge
Definition: IntermodalNetwork.h:79
time2string
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:67
IntermodalNetwork::getArrivalEdge
_IntermodalEdge * getArrivalEdge(const E *e, const double pos) const
Returns the arriving intermodal edge.
Definition: IntermodalNetwork.h:347
IntermodalNetwork::addConnectors
void addConnectors(_IntermodalEdge *const depConn, _IntermodalEdge *const arrConn, const int index)
Definition: IntermodalNetwork.h:273
IntermodalNetwork::myAccessSplits
std::map< _IntermodalEdge *, std::vector< _IntermodalEdge * > > myAccessSplits
retrieve the splitted edges for the given "original"
Definition: IntermodalNetwork.h:754
EDGEFUNC_NORMAL
Definition: SUMOXMLDefinitions.h:1081
IntermodalNetwork::_IntermodalEdge
IntermodalEdge< E, L, N, V > _IntermodalEdge
Definition: IntermodalNetwork.h:78
IntermodalEdge::addSuccessor
void addSuccessor(IntermodalEdge *const s, IntermodalEdge *const via=nullptr)
Definition: IntermodalEdge.h:67
IntermodalNetwork::getDepartConnector
_IntermodalEdge * getDepartConnector(const E *e, const int splitIndex=0) const
Returns the departing intermodal connector at the given split offset.
Definition: IntermodalNetwork.h:335
IntermodalNetwork::getAllEdges
const std::vector< _IntermodalEdge * > & getAllEdges()
Definition: IntermodalNetwork.h:280
IntermodalEdge::getEdge
const E * getEdge() const
Definition: IntermodalEdge.h:59
split
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
Definition: MSSOTLE2Sensors.cpp:488
IntermodalNetwork::myDepartLookup
std::map< const E *, std::vector< _IntermodalEdge * > > myDepartLookup
retrieve the depart edges for the given input edge E
Definition: IntermodalNetwork.h:736
Position.h
toString
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:47
SUMO_TAG_BUS_STOP
A bus stop.
Definition: SUMOXMLDefinitions.h:97
IntermodalNetwork
the intermodal network storing edges, connections and the mappings to the "real" edges
Definition: IntermodalNetwork.h:76
IntermodalNetwork::getBothDirections
const EdgePair & getBothDirections(const E *e) const
Returns the pair of forward and backward edge.
Definition: IntermodalNetwork.h:285
StopEdge
the stop edge type representing bus and train stops
Definition: StopEdge.h:33
IntermodalNetwork::operator=
IntermodalNetwork & operator=(const IntermodalNetwork &s)
Invalidated assignment operator.
getSidewalk
const L * getSidewalk(const E *edge)
Definition: IntermodalNetwork.h:51
IntermodalEdge::transferSuccessors
void transferSuccessors(IntermodalEdge *to)
Definition: IntermodalEdge.h:72
IntermodalNetwork::ModeChangeOptions
ModeChangeOptions
where mode changes are possible
Definition: IntermodalNetwork.h:87
AccessEdge.h
config.h
IntermodalNetwork::getArrivalConnector
_IntermodalEdge * getArrivalConnector(const E *e, const int splitIndex=0) const
Returns the arriving intermodal connector at the given split offset.
Definition: IntermodalNetwork.h:363
IntermodalNetwork::addAccess
void addAccess(const std::string &stopId, const E *stopEdge, const double pos, const double length, const SumoXMLTag category)
Adds access edges for stopping places to the intermodal network.
Definition: IntermodalNetwork.h:455
IntermodalNetwork::myCarWalkTransfer
const int myCarWalkTransfer
Definition: IntermodalNetwork.h:757
IntermodalNetwork::getWalkingConnector
_IntermodalEdge * getWalkingConnector(const E *e) const
Returns the outgoing pedestrian edge, which is either a walking area or a walking connector.
Definition: IntermodalNetwork.h:368
IntermodalNetwork::myPTLines
std::map< std::string, std::vector< _PTEdge * > > myPTLines
retrieve the public transport edges for the given line
Definition: IntermodalNetwork.h:748
SUMOVehicleParameter::repetitionNumber
int repetitionNumber
Definition: SUMOVehicleParameter.h:544
SVC_IGNORING
vehicles ignoring classes
Definition: SUMOVehicleClass.h:135
SUMOVehicleParameter::stops
std::vector< Stop > stops
List of the stops the vehicle will make, TraCI may add entries here.
Definition: SUMOVehicleParameter.h:656
Named::getID
const std::string & getID() const
Returns the id.
Definition: Named.h:76
POSITION_EPS
#define POSITION_EPS
Definition: config.h:172
IntermodalNetwork::myCarLookup
std::map< const E *, _IntermodalEdge * > myCarLookup
retrieve the car edge for the given input edge E
Definition: IntermodalNetwork.h:745
CarEdge.h
SUMOVehicleParameter::Stop
Definition of vehicle stop (position and duration)
Definition: SUMOVehicleParameter.h:572
Named::setID
void setID(const std::string &newID)
resets the id
Definition: Named.h:84