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 
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 /****************************************************************************/
StopEdge.h
EDGEFUNC_INTERNAL
Definition: SUMOXMLDefinitions.h:1080
PublicTransportEdge::addSchedule
void addSchedule(const std::string id, const SUMOTime begin, const int repetitionNumber, const SUMOTime period, const SUMOTime travelTime)
Definition: PublicTransportEdge.h:73
SVC_PEDESTRIAN
pedestrian
Definition: SUMOVehicleClass.h:157
ToString.h
IntermodalEdge.h
IntermodalNetwork::getStopEdge
_IntermodalEdge * getStopEdge(const std::string &stopId) const
Returns the associated stop edge.
Definition: IntermodalNetwork.h:432
WRITE_WARNING
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:239
SUMOTime.h
IntermodalNetwork::getDepartEdge
const _IntermodalEdge * getDepartEdge(const E *e, const double pos) const
Returns the departing intermodal edge.
Definition: IntermodalNetwork.h:293
IntermodalNetwork::myArrivalLookup
std::map< const E *, std::vector< _IntermodalEdge * > > myArrivalLookup
retrieve the arrival edges for the given input edge E
Definition: IntermodalNetwork.h:733
IntermodalNetwork::EdgePair
std::pair< _IntermodalEdge *, _IntermodalEdge * > EdgePair
Definition: IntermodalNetwork.h:83
IntermodalNetwork::ALL_JUNCTIONS
junctions with edges allowing the additional mode
Definition: IntermodalNetwork.h:94
IntermodalEdge::removeSuccessor
void removeSuccessor(const IntermodalEdge *const edge)
Definition: IntermodalEdge.h:80
PedestrianEdge.h
IntermodalNetwork::getCarEdge
_IntermodalEdge * getCarEdge(const E *e) const
Returns the associated car edge.
Definition: IntermodalNetwork.h:423
MsgHandler.h
SUMOVehicleParameter::repetitionOffset
SUMOTime repetitionOffset
The time offset between vehicle reinsertions.
Definition: SUMOVehicleParameter.h:544
SUMOVehicleParameter::Stop::busstop
std::string busstop
(Optional) bus stop if one is assigned to the stop
Definition: SUMOVehicleParameter.h:583
PublicTransportEdge.h
SUMOTime
long long int SUMOTime
Definition: SUMOTime.h:35
IntermodalEdge::getLength
double getLength() const
Definition: IntermodalEdge.h:132
PublicTransportEdge
the public transport edge type connecting the stop edges
Definition: PublicTransportEdge.h:34
IntermodalNetwork::PARKING_AREAS
parking areas
Definition: IntermodalNetwork.h:90
IntermodalNetwork::addSchedule
void addSchedule(const SUMOVehicleParameter &pars, const std::vector< SUMOVehicleParameter::Stop > *addStops=nullptr)
Definition: IntermodalNetwork.h:546
FareToken::L
SUMOVehicleParameter
Structure representing possible vehicle parameter.
Definition: SUMOVehicleParameter.h:291
IntermodalNetwork::addEdge
void addEdge(_IntermodalEdge *edge)
Definition: IntermodalNetwork.h:264
IntermodalEdge::setLength
void setLength(const double length)
Definition: IntermodalEdge.h:136
IntermodalEdge
the base edge type that is given to the internal router (SUMOAbstractRouter)
Definition: IntermodalEdge.h:40
IntermodalNetwork::_PTEdge
PublicTransportEdge< E, L, N, V > _PTEdge
Definition: IntermodalNetwork.h:82
IntermodalNetwork::myStopConnections
std::map< std::string, _IntermodalEdge * > myStopConnections
retrieve the representing edge for the given stopping place
Definition: IntermodalNetwork.h:745
SumoXMLTag
SumoXMLTag
Numbers representing SUMO-XML - element names.
Definition: SUMOXMLDefinitions.h:42
SUMOVehicleParameter::depart
SUMOTime depart
Definition: SUMOVehicleParameter.h:476
IntermodalNetwork::myEdges
std::vector< _IntermodalEdge * > myEdges
the edge dictionary
Definition: IntermodalNetwork.h:724
IntermodalNetwork::~IntermodalNetwork
~IntermodalNetwork()
Definition: IntermodalNetwork.h:258
PedestrianEdge
the pedestrian edge type that is given to the internal router (SUMOAbstractRouter)
Definition: PedestrianEdge.h:38
IntermodalNetwork::_PedestrianEdge
PedestrianEdge< E, L, N, V > _PedestrianEdge
Definition: IntermodalNetwork.h:81
SUMOVehicleParameter.h
IntermodalNetwork::addCarEdges
void addCarEdges(const std::vector< E * > &edges)
Definition: IntermodalNetwork.h:383
IntermodalNetwork::myNumericalID
int myNumericalID
Definition: IntermodalNetwork.h:750
SUMOVehicleParameter::line
std::string line
The vehicle's line (mainly for public transport)
Definition: SUMOVehicleParameter.h:555
IntermodalNetwork::myWalkingConnectorLookup
std::map< const N *, _IntermodalEdge * > myWalkingConnectorLookup
the walking connector edge (fake walking area)
Definition: IntermodalNetwork.h:736
CarEdge
the car edge type that is given to the internal router (SUMOAbstractRouter)
Definition: CarEdge.h:37
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:640
AccessEdge
the access edge connecting different modes that is given to the internal router (SUMOAbstractRouter)
Definition: AccessEdge.h:34
IntermodalNetwork::myBidiLookup
std::map< const E *, EdgePair > myBidiLookup
retrieve the forward and backward edge for the given input edge E
Definition: IntermodalNetwork.h:727
IntermodalEdge::getNumericalID
int getNumericalID() const
Definition: IntermodalEdge.h:64
Position::distanceTo
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:234
Named.h
SUMOVehicleParameter::Stop::until
SUMOTime until
The time at which the vehicle may continue its journey.
Definition: SUMOVehicleParameter.h:604
SUMOVehicleParameter::id
std::string id
The vehicle's id.
Definition: SUMOVehicleParameter.h:462
SUMO_TAG_PARKING_AREA
A parking area.
Definition: SUMOXMLDefinitions.h:108
IntermodalNetwork::PT_STOPS
public transport stops and access
Definition: IntermodalNetwork.h:92
IntermodalNetwork::IntermodalNetwork
IntermodalNetwork(const std::vector< E * > &edges, const bool pedestrianOnly, const int carWalkTransfer=0)
Definition: IntermodalNetwork.h:101
ProcessError
Definition: UtilExceptions.h:40
isRailway
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
Definition: SUMOVehicleClass.cpp:364
Position
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
IntermodalNetwork::_AccessEdge
AccessEdge< E, L, N, V > _AccessEdge
Definition: IntermodalNetwork.h:80
time2string
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:65
IntermodalNetwork::getArrivalEdge
_IntermodalEdge * getArrivalEdge(const E *e, const double pos) const
Returns the arriving intermodal edge.
Definition: IntermodalNetwork.h:345
IntermodalNetwork::addConnectors
void addConnectors(_IntermodalEdge *const depConn, _IntermodalEdge *const arrConn, const int index)
Definition: IntermodalNetwork.h:271
IntermodalNetwork::myAccessSplits
std::map< _IntermodalEdge *, std::vector< _IntermodalEdge * > > myAccessSplits
retrieve the splitted edges for the given "original"
Definition: IntermodalNetwork.h:748
EDGEFUNC_NORMAL
Definition: SUMOXMLDefinitions.h:1076
IntermodalNetwork::_IntermodalEdge
IntermodalEdge< E, L, N, V > _IntermodalEdge
Definition: IntermodalNetwork.h:79
IntermodalEdge::addSuccessor
void addSuccessor(IntermodalEdge *const s, IntermodalEdge *const via=nullptr)
Definition: IntermodalEdge.h:68
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:333
IntermodalNetwork::getAllEdges
const std::vector< _IntermodalEdge * > & getAllEdges()
Definition: IntermodalNetwork.h:278
IntermodalEdge::getEdge
const E * getEdge() const
Definition: IntermodalEdge.h:60
split
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
Definition: MSSOTLE2Sensors.cpp:489
IntermodalNetwork::myDepartLookup
std::map< const E *, std::vector< _IntermodalEdge * > > myDepartLookup
retrieve the depart edges for the given input edge E
Definition: IntermodalNetwork.h:730
Position.h
toString
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:48
SUMO_TAG_BUS_STOP
A bus stop.
Definition: SUMOXMLDefinitions.h:98
IntermodalNetwork
the intermodal network storing edges, connections and the mappings to the "real" edges
Definition: IntermodalNetwork.h:77
IntermodalNetwork::getBothDirections
const EdgePair & getBothDirections(const E *e) const
Returns the pair of forward and backward edge.
Definition: IntermodalNetwork.h:283
StopEdge
the stop edge type representing bus and train stops
Definition: StopEdge.h:34
IntermodalNetwork::operator=
IntermodalNetwork & operator=(const IntermodalNetwork &s)
Invalidated assignment operator.
getSidewalk
const L * getSidewalk(const E *edge)
Definition: IntermodalNetwork.h:52
IntermodalEdge::transferSuccessors
void transferSuccessors(IntermodalEdge *to)
Definition: IntermodalEdge.h:73
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)
Splits an edge (if necessary) and connects it to a stopping edge.
Definition: IntermodalNetwork.h:673
IntermodalNetwork::ModeChangeOptions
ModeChangeOptions
where mode changes are possible
Definition: IntermodalNetwork.h:88
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:361
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:453
IntermodalNetwork::myCarWalkTransfer
const int myCarWalkTransfer
Definition: IntermodalNetwork.h:751
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:366
IntermodalNetwork::myPTLines
std::map< std::string, std::vector< _PTEdge * > > myPTLines
retrieve the public transport edges for the given line
Definition: IntermodalNetwork.h:742
SUMOVehicleParameter::repetitionNumber
int repetitionNumber
Definition: SUMOVehicleParameter.h:538
SVC_IGNORING
vehicles ignoring classes
Definition: SUMOVehicleClass.h:136
SUMOVehicleParameter::stops
std::vector< Stop > stops
List of the stops the vehicle will make, TraCI may add entries here.
Definition: SUMOVehicleParameter.h:638
Named::getID
const std::string & getID() const
Returns the id.
Definition: Named.h:77
POSITION_EPS
#define POSITION_EPS
Definition: config.h:169
IntermodalNetwork::myCarLookup
std::map< const E *, _IntermodalEdge * > myCarLookup
retrieve the car edge for the given input edge E
Definition: IntermodalNetwork.h:739
CarEdge.h
SUMOVehicleParameter::Stop
Definition of vehicle stop (position and duration)
Definition: SUMOVehicleParameter.h:566
Named::setID
void setID(const std::string &newID)
resets the id
Definition: Named.h:85