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