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-2018 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 "AccessEdge.h"
37 #include "CarEdge.h"
38 #include "IntermodalEdge.h"
39 #include "PedestrianEdge.h"
40 #include "PublicTransportEdge.h"
41 #include "StopEdge.h"
42 #include "SUMOVehicleParameter.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()) {
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  const L* const sidewalk = getSidewalk<E, L>(edge);
163  if (sidewalk == nullptr) {
164  continue;
165  }
166  // find all incoming and outgoing lanes for the sidewalk and
167  // connect the corresponding IntermodalEdges
168  const EdgePair& pair = getBothDirections(edge);
169 #ifdef IntermodalRouter_DEBUG_NETWORK
170  std::cout << " building connections from " << sidewalk->getID() << "\n";
171 #endif
172  if (haveSeenWalkingArea) {
173  const std::vector<std::pair<const L*, const E*> > outgoing = sidewalk->getOutgoingViaLanes();
174  // if one of the outgoing lanes is a walking area it must be used.
175  // All other connections shall be ignored
176  // if it has no outgoing walking area, it probably is a walking area itself
177  bool hasWalkingArea = false;
178  for (const auto& target : outgoing) {
179  if (target.first->getEdge().isWalkingArea()) {
180  hasWalkingArea = true;
181  break;
182  }
183  }
184  for (const auto& target : outgoing) {
185  const E* const targetEdge = &(target.first->getEdge());
186  const bool used = (target.first == getSidewalk<E, L>(targetEdge)
187  && (!hasWalkingArea || targetEdge->isWalkingArea()));
188 #ifdef IntermodalRouter_DEBUG_NETWORK
189  const L* potTarget = getSidewalk<E, L>(targetEdge);
190  std::cout << " lane=" << (potTarget == 0 ? "NULL" : potTarget->getID()) << (used ? "(used)" : "") << "\n";
191 #endif
192  if (used) {
193  const EdgePair& targetPair = getBothDirections(targetEdge);
194  pair.first->addSuccessor(targetPair.first);
195  targetPair.second->addSuccessor(pair.second);
196 #ifdef IntermodalRouter_DEBUG_NETWORK
197  std::cout << " " << pair.first->getID() << " -> " << targetPair.first->getID() << "\n";
198  std::cout << " " << targetPair.second->getID() << " -> " << pair.second->getID() << "\n";
199 #endif
200  }
201  }
202  }
203  // We may have a network without pedestrian structures or a car-only edge.
204  // In the first case we assume that all sidewalks at a junction are interconnected,
205  // in the second we connect all car-only edges to all sidewalks.
206  _IntermodalEdge* const toNodeConn = myWalkingConnectorLookup[edge->getToJunction()];
207  if (toNodeConn != nullptr) {
208  if (!haveSeenWalkingArea) {
209  // if we have walking areas we should use them and not the connector
210  pair.first->addSuccessor(toNodeConn);
211  }
212  toNodeConn->addSuccessor(pair.second);
213  }
214  _IntermodalEdge* const fromNodeConn = myWalkingConnectorLookup[edge->getFromJunction()];
215  if (fromNodeConn != nullptr) {
216  if (!haveSeenWalkingArea) {
217  pair.second->addSuccessor(fromNodeConn);
218  }
219  fromNodeConn->addSuccessor(pair.first);
220  }
221  if (!edge->isWalkingArea()) {
222  // build connections from depart connector
223  _IntermodalEdge* startConnector = getDepartConnector(edge);
224  startConnector->addSuccessor(pair.first);
225  startConnector->addSuccessor(pair.second);
226  // build connections to arrival connector
227  _IntermodalEdge* endConnector = getArrivalConnector(edge);
228  pair.first->addSuccessor(endConnector);
229  pair.second->addSuccessor(endConnector);
230  }
231 #ifdef IntermodalRouter_DEBUG_NETWORK
232  std::cout << " " << startConnector->getID() << " -> " << pair.first->getID() << "\n";
233  std::cout << " " << startConnector->getID() << " -> " << pair.second->getID() << "\n";
234  std::cout << " " << pair.first->getID() << " -> " << endConnector->getID() << "\n";
235  std::cout << " " << pair.second->getID() << " -> " << endConnector->getID() << "\n";
236 #endif
237  }
238  }
239 
241  for (typename std::vector<_IntermodalEdge*>::iterator it = myEdges.begin(); it != myEdges.end(); ++it) {
242  delete *it;
243  }
244  }
245 
246  void addEdge(_IntermodalEdge* edge) {
247  while ((int)myEdges.size() <= edge->getNumericalID()) {
248  myEdges.push_back(0);
249  }
250  myEdges[edge->getNumericalID()] = edge;
251  }
252 
253  void addConnectors(_IntermodalEdge* const depConn, _IntermodalEdge* const arrConn, const int index) {
254  addEdge(depConn);
255  addEdge(arrConn);
256  myDepartLookup[depConn->getEdge()].insert(myDepartLookup[depConn->getEdge()].begin() + index, depConn);
257  myArrivalLookup[arrConn->getEdge()].insert(myArrivalLookup[arrConn->getEdge()].begin() + index, arrConn);
258  }
259 
260  const std::vector<_IntermodalEdge*>& getAllEdges() {
261  return myEdges;
262  }
263 
265  const EdgePair& getBothDirections(const E* e) const {
266  typename std::map<const E*, EdgePair>::const_iterator it = myBidiLookup.find(e);
267  if (it == myBidiLookup.end()) {
268  assert(false);
269  throw ProcessError("Edge '" + e->getID() + "' not found in intermodal network '");
270  }
271  return (*it).second;
272  }
273 
275  _IntermodalEdge* getDepartEdge(const E* e, const double pos) const {
276  typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it = myDepartLookup.find(e);
277  if (it == myDepartLookup.end()) {
278  throw ProcessError("Depart edge '" + e->getID() + "' not found in intermodal network.");
279  }
280  const std::vector<_IntermodalEdge*>& splitList = it->second;
281  typename std::vector<_IntermodalEdge*>::const_iterator splitIt = splitList.begin();
282  double totalLength = 0.;
283  while (splitIt != splitList.end() && totalLength + (*splitIt)->getLength() < pos) {
284  totalLength += (*splitIt)->getLength();
285  ++splitIt;
286  }
287  return *splitIt;
288  }
289 
291  _IntermodalEdge* getDepartConnector(const E* e, const int splitIndex = 0) const {
292  typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it = myDepartLookup.find(e);
293  if (it == myDepartLookup.end()) {
294  throw ProcessError("Depart edge '" + e->getID() + "' not found in intermodal network.");
295  }
296  if (splitIndex >= (int)it->second.size()) {
297  throw ProcessError("Split index " + toString(splitIndex) + " invalid for depart edge '" + e->getID() + "' .");
298  }
299  return it->second[splitIndex];
300  }
301 
303  _IntermodalEdge* getArrivalEdge(const E* e, const double pos) const {
304  typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it = myArrivalLookup.find(e);
305  if (it == myArrivalLookup.end()) {
306  throw ProcessError("Arrival edge '" + e->getID() + "' not found in intermodal network.");
307  }
308  const std::vector<_IntermodalEdge*>& splitList = it->second;
309  typename std::vector<_IntermodalEdge*>::const_iterator splitIt = splitList.begin();
310  double totalLength = 0.;
311  while (splitIt != splitList.end() && totalLength + (*splitIt)->getLength() < pos) {
312  totalLength += (*splitIt)->getLength();
313  ++splitIt;
314  }
315  return *splitIt;
316  }
317 
319  _IntermodalEdge* getArrivalConnector(const E* e, const int splitIndex = 0) const {
320  return myArrivalLookup.find(e)->second[splitIndex];
321  }
322 
324  _IntermodalEdge* getWalkingConnector(const E* e) const {
325  typename std::map<const N*, _IntermodalEdge*>::const_iterator it = myWalkingConnectorLookup.find(e->getToJunction());
326  if (it == myWalkingConnectorLookup.end()) {
327  const L* const sidewalk = getSidewalk<E, L>(e);
328  if (e->isInternal() || sidewalk == 0) {
329  return 0;
330  }
331  for (const auto& target : sidewalk->getOutgoingViaLanes()) {
332  if (target.first->getEdge().isWalkingArea()) {
333  return getBothDirections(&target.first->getEdge()).first;
334  }
335  }
336  return 0;
337  }
338  return it->second;
339  }
340 
341  void addCarEdges(const std::vector<E*>& edges) {
342  for (const E* const edge : edges) {
343  if (edge->getFunction() == EDGEFUNC_NORMAL || edge->getFunction() == EDGEFUNC_INTERNAL) {
344  myCarLookup[edge] = new CarEdge<E, L, N, V>(myNumericalID++, edge);
345  addEdge(myCarLookup[edge]);
346  }
347  }
348  for (const auto& edgePair : myCarLookup) {
349  _IntermodalEdge* const carEdge = edgePair.second;
350  for (const auto& suc : edgePair.first->getViaSuccessors()) {
351  _IntermodalEdge* const sucCarEdge = getCarEdge(suc.first);
352  _IntermodalEdge* const sucViaEdge = getCarEdge(suc.second);
353  if (sucCarEdge != nullptr) {
354  carEdge->addSuccessor(sucCarEdge, sucViaEdge);
355  }
356  }
357  if ((myCarWalkTransfer & ALL_JUNCTIONS) != 0) {
358  _IntermodalEdge* const walkCon = getWalkingConnector(edgePair.first);
359  if (walkCon != 0) {
360  carEdge->addSuccessor(walkCon);
361  } else {
362  // we are on an edge where pedestrians are forbidden and want to continue on an arbitrary pedestrian edge
363  for (const E* const out : edgePair.first->getToJunction()->getOutgoing()) {
364  if (!out->isInternal() && !out->isTazConnector() && getSidewalk<E, L>(out) != 0) {
365  carEdge->addSuccessor(getBothDirections(out).first);
366  }
367  }
368  for (const E* const in : edgePair.first->getToJunction()->getIncoming()) {
369  if (!in->isInternal() && !in->isTazConnector() && getSidewalk<E, L>(in) != 0) {
370  carEdge->addSuccessor(getBothDirections(in).second);
371  }
372  }
373  }
374  }
375  getDepartConnector(edgePair.first)->addSuccessor(carEdge);
376  carEdge->addSuccessor(getArrivalConnector(edgePair.first));
377  }
378  }
379 
381  _IntermodalEdge* getCarEdge(const E* e) const {
382  typename std::map<const E*, _IntermodalEdge*>::const_iterator it = myCarLookup.find(e);
383  if (it == myCarLookup.end()) {
384  return nullptr;
385  }
386  return it->second;
387  }
388 
390  _IntermodalEdge* getStopEdge(const std::string& stopId) const {
391  auto it = myStopConnections.find(stopId);
392  if (it == myStopConnections.end()) {
393  return 0;
394  }
395  return it->second;
396  }
397 
411  void addAccess(const std::string& stopId, const E* stopEdge, const double pos, const double length, const SumoXMLTag category) {
412  assert(stopEdge != 0);
413  if (myStopConnections.count(stopId) == 0) {
414  myStopConnections[stopId] = new StopEdge<E, L, N, V>(stopId, myNumericalID++, stopEdge);
415  addEdge(myStopConnections[stopId]);
416  }
417  _IntermodalEdge* const stopConn = myStopConnections[stopId];
418  const L* lane = getSidewalk<E, L>(stopEdge);
419  if (lane != 0) {
420  const std::pair<_IntermodalEdge*, _IntermodalEdge*>& pair = getBothDirections(stopEdge);
421  double relPos;
422  bool needSplit;
423  const int splitIndex = findSplitIndex(pair.first, pos, relPos, needSplit);
424  _IntermodalEdge* const fwdSplit = needSplit ? new PedestrianEdge<E, L, N, V>(myNumericalID++, stopEdge, lane, true, pos) : nullptr;
425  splitEdge(pair.first, splitIndex, fwdSplit, relPos, length, needSplit, stopConn);
426  _IntermodalEdge* const backSplit = needSplit ? new PedestrianEdge<E, L, N, V>(myNumericalID++, stopEdge, lane, false, pos) : nullptr;
427  splitEdge(pair.second, splitIndex, backSplit, relPos, length, needSplit, stopConn, false);
428  _IntermodalEdge* carSplit = nullptr;
429  if (myCarLookup.count(stopEdge) > 0) {
430  if (needSplit) {
431  carSplit = new CarEdge<E, L, N, V>(myNumericalID++, stopEdge, pos);
432  }
433  splitEdge(myCarLookup[stopEdge], splitIndex, carSplit, relPos, length, needSplit, stopConn, true, false);
434  }
435  if (needSplit) {
436  if (carSplit != nullptr && ((category == SUMO_TAG_PARKING_AREA && (myCarWalkTransfer & PARKING_AREAS) != 0) || (category == SUMO_TAG_BUS_STOP && (myCarWalkTransfer & PT_STOPS) != 0))) {
437  // adding access from car to walk
438  _IntermodalEdge* const beforeSplit = myAccessSplits[myCarLookup[stopEdge]][splitIndex];
439  for (_IntermodalEdge* conn : {
440  fwdSplit, backSplit
441  }) {
442  _AccessEdge* access = new _AccessEdge(myNumericalID++, beforeSplit, conn, length);
443  addEdge(access);
444  beforeSplit->addSuccessor(access);
445  access->addSuccessor(conn);
446  }
447  }
448 
449  // fixing depart connections for the forward pedestrian, the backward pedestrian and the car edge
450  _IntermodalEdge* const prevDep = getDepartConnector(stopEdge, splitIndex);
451  const std::vector<_IntermodalEdge*>& backSplitList = myAccessSplits[pair.second];
452  _IntermodalEdge* const backBeforeSplit = backSplitList[backSplitList.size() - 2 - splitIndex];
453  _IntermodalEdge* const depConn = new _IntermodalEdge(stopEdge->getID() + "_depart_connector" + toString(pos), myNumericalID++, stopEdge, "!connector");
454  depConn->addSuccessor(fwdSplit);
455  depConn->addSuccessor(backBeforeSplit);
456  depConn->setLength(fwdSplit->getLength());
457  prevDep->removeSuccessor(backBeforeSplit);
458  prevDep->addSuccessor(backSplit);
459  prevDep->setLength(backSplit->getLength());
460  if (carSplit != nullptr) {
461  depConn->addSuccessor(carSplit);
462  }
463 
464  // fixing arrival connections for the forward pedestrian, the backward pedestrian and the car edge
465  _IntermodalEdge* const prevArr = getArrivalConnector(stopEdge, splitIndex);
466  _IntermodalEdge* const fwdBeforeSplit = myAccessSplits[pair.first][splitIndex];
467  _IntermodalEdge* const arrConn = new _IntermodalEdge(stopEdge->getID() + "_arrival_connector" + toString(pos), myNumericalID++, stopEdge, "!connector");
468  fwdSplit->addSuccessor(arrConn);
469  backBeforeSplit->addSuccessor(arrConn);
470  arrConn->setLength(fwdSplit->getLength());
471  fwdSplit->removeSuccessor(prevArr);
472  fwdBeforeSplit->addSuccessor(prevArr);
473  prevArr->setLength(backSplit->getLength());
474  if (carSplit != nullptr) {
475  carSplit->addSuccessor(arrConn);
476  carSplit->removeSuccessor(prevArr);
477  myAccessSplits[myCarLookup[stopEdge]][splitIndex]->addSuccessor(prevArr);
478  }
479  addConnectors(depConn, arrConn, splitIndex + 1);
480  }
481  }
482  }
483 
484  void addSchedule(const SUMOVehicleParameter& pars, const std::vector<SUMOVehicleParameter::Stop>* addStops = 0) {
485  SUMOTime lastUntil = 0;
486  std::vector<SUMOVehicleParameter::Stop> validStops;
487  if (addStops != 0) {
488  // stops are part of a stand-alone route. until times are offsets from vehicle departure
489  for (std::vector<SUMOVehicleParameter::Stop>::const_iterator s = addStops->begin(); s != addStops->end(); ++s) {
490  if (myStopConnections.count(s->busstop) > 0) {
491  // compute stop times for the first vehicle
492  SUMOVehicleParameter::Stop stop = *s;
493  stop.until += pars.depart;
494  if (stop.until >= lastUntil) {
495  validStops.push_back(stop);
496  lastUntil = stop.until;
497  } else {
498  WRITE_WARNING("Ignoring unordered stop at '" + stop.busstop + "' at " + time2string(stop.until) + " for vehicle '" + pars.id + "'.");
499  }
500  }
501  }
502  }
503  for (std::vector<SUMOVehicleParameter::Stop>::const_iterator s = pars.stops.begin(); s != pars.stops.end(); ++s) {
504  // stops are part of the vehicle until times are absolute times for the first vehicle
505  if (myStopConnections.count(s->busstop) > 0 && s->until >= lastUntil) {
506  validStops.push_back(*s);
507  lastUntil = s->until;
508  }
509  }
510  if (validStops.size() < 2) {
511  WRITE_WARNING("Ignoring public transport line '" + pars.line + "' with less than two usable stops.");
512  return;
513  }
514 
515  typename std::vector<_PTEdge*>& lineEdges = myPTLines[pars.line];
516  if (lineEdges.empty()) {
517  _IntermodalEdge* lastStop = 0;
518  SUMOTime lastTime = 0;
519  for (std::vector<SUMOVehicleParameter::Stop>::const_iterator s = validStops.begin(); s != validStops.end(); ++s) {
520  _IntermodalEdge* currStop = myStopConnections[s->busstop];
521  if (lastStop != 0) {
522  _PTEdge* const newEdge = new _PTEdge(s->busstop, myNumericalID++, lastStop, currStop->getEdge(), pars.line);
523  addEdge(newEdge);
524  newEdge->addSchedule(pars.id, lastTime, pars.repetitionNumber, pars.repetitionOffset, s->until - lastTime);
525  lastStop->addSuccessor(newEdge);
526  newEdge->addSuccessor(currStop);
527  lineEdges.push_back(newEdge);
528  }
529  lastTime = s->until;
530  lastStop = currStop;
531  }
532  } else {
533  if (validStops.size() != lineEdges.size() + 1) {
534  WRITE_WARNING("Number of stops for public transport line '" + pars.line + "' does not match earlier definitions, ignoring schedule.");
535  return;
536  }
537  if (lineEdges.front()->getEntryStop() != myStopConnections[validStops.front().busstop]) {
538  WRITE_WARNING("Different stop for '" + pars.line + "' compared to earlier definitions, ignoring schedule.");
539  return;
540  }
541  typename std::vector<_PTEdge*>::const_iterator lineEdge = lineEdges.begin();
542  typename std::vector<SUMOVehicleParameter::Stop>::const_iterator s = validStops.begin() + 1;
543  for (; s != validStops.end(); ++s, ++lineEdge) {
544  if ((*lineEdge)->getSuccessors(SVC_IGNORING)[0] != myStopConnections[s->busstop]) {
545  WRITE_WARNING("Different stop for '" + pars.line + "' compared to earlier definitions, ignoring schedule.");
546  return;
547  }
548  }
549  SUMOTime lastTime = validStops.front().until;
550  if (lineEdges.front()->hasSchedule(lastTime)) {
551  WRITE_WARNING("Duplicate schedule for '" + pars.line + "' at time " + time2string(lastTime) + ".");
552  }
553  for (lineEdge = lineEdges.begin(), s = validStops.begin() + 1; lineEdge != lineEdges.end(); ++lineEdge, ++s) {
554  (*lineEdge)->addSchedule(pars.id, lastTime, pars.repetitionNumber, pars.repetitionOffset, s->until - lastTime);
555  lastTime = s->until;
556  }
557  }
558  }
559 
560 
561 private:
573  int findSplitIndex(_IntermodalEdge* const toSplit, const double pos, double& relPos, bool& needSplit) {
574  relPos = pos;
575  needSplit = true;
576  int splitIndex = 0;
577  std::vector<_IntermodalEdge*>& splitList = myAccessSplits[toSplit];
578  if (!splitList.empty()) {
579  for (const _IntermodalEdge* const split : splitList) {
580  if (relPos < split->getLength() + POSITION_EPS) {
581  break;
582  }
583  relPos -= split->getLength();
584  splitIndex++;
585  }
586  assert(splitIndex < (int)splitList.size());
587  if (splitIndex + 1 < (int)splitList.size() && fabs(relPos - splitList[splitIndex]->getLength()) < POSITION_EPS) {
588  needSplit = false;
589  }
590  }
591  return splitIndex;
592  }
593 
606  void splitEdge(_IntermodalEdge* const toSplit, int splitIndex,
607  _IntermodalEdge* afterSplit, const double relPos, const double length, const bool needSplit,
608  _IntermodalEdge* const stopConn, const bool forward = true, const bool addExit = true) {
609  std::vector<_IntermodalEdge*>& splitList = myAccessSplits[toSplit];
610  if (splitList.empty()) {
611  splitList.push_back(toSplit);
612  }
613  if (!forward) {
614  splitIndex = (int)splitList.size() - 1 - splitIndex;
615  if (!needSplit) {
616  splitIndex--;
617  }
618  }
619  _IntermodalEdge* beforeSplit = splitList[splitIndex];
620  if (needSplit) {
621  addEdge(afterSplit);
622  beforeSplit->transferSuccessors(afterSplit);
623  beforeSplit->addSuccessor(afterSplit);
624  if (forward) {
625  afterSplit->setLength(beforeSplit->getLength() - relPos);
626  beforeSplit->setLength(relPos);
627  } else {
628  afterSplit->setLength(relPos);
629  beforeSplit->setLength(beforeSplit->getLength() - relPos);
630  // rename backward edges for easier referencing
631  const std::string newID = beforeSplit->getID();
632  beforeSplit->setID(afterSplit->getID());
633  afterSplit->setID(newID);
634  }
635  splitList.insert(splitList.begin() + splitIndex + 1, afterSplit);
636  } else {
637  // don't split, use the present split edges
638  afterSplit = splitList[splitIndex + 1];
639  }
640  // add access to / from edge
641  _AccessEdge* access = new _AccessEdge(myNumericalID++, beforeSplit, stopConn, length);
642  addEdge(access);
643  beforeSplit->addSuccessor(access);
644  access->addSuccessor(stopConn);
645  if (addExit) {
646  // pedestrian case only, exit from public to pedestrian
647  _AccessEdge* exit = new _AccessEdge(myNumericalID++, stopConn, afterSplit, length);
648  addEdge(exit);
649  stopConn->addSuccessor(exit);
650  exit->addSuccessor(afterSplit);
651  }
652  }
653 
654 
655 private:
657  std::vector<_IntermodalEdge*> myEdges;
658 
660  std::map<const E*, EdgePair> myBidiLookup;
661 
663  std::map<const E*, std::vector<_IntermodalEdge*> > myDepartLookup;
664 
666  std::map<const E*, std::vector<_IntermodalEdge*> > myArrivalLookup;
667 
669  std::map<const N*, _IntermodalEdge*> myWalkingConnectorLookup;
670 
672  std::map<const E*, _IntermodalEdge*> myCarLookup;
673 
675  std::map<std::string, std::vector<_PTEdge*> > myPTLines;
676 
678  std::map<std::string, _IntermodalEdge*> myStopConnections;
679 
681  std::map<_IntermodalEdge*, std::vector<_IntermodalEdge*> > myAccessSplits;
682 
684  const int myCarWalkTransfer;
685 
686 private:
689 
690 };
691 
692 
693 #endif
694 
695 /****************************************************************************/
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:36
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.
is a pedestrian
int repetitionNumber
The number of times the vehicle shall be repeatedly inserted.
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:67
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
IntermodalNetwork & operator=(const IntermodalNetwork &s)
Invalidated assignment operator.
SUMOTime until
The time at which the vehicle may continue its journey.
IntermodalEdge< E, L, N, V > _IntermodalEdge
const std::string & getID() const
Returns the id.
Definition: Named.h:69
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:242
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...
std::string busstop
(Optional) bus stop if one is assigned to the stop
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:49
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)
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.
SUMOTime depart
The vehicle&#39;s departure time.
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
#define POSITION_EPS
Definition: config.h:172
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
_IntermodalEdge * getDepartEdge(const E *e, const double pos) const
Returns the departing intermodal edge.
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:77
Structure representing possible vehicle parameter.
std::map< const E *, std::vector< _IntermodalEdge * > > myDepartLookup
retrieve the depart edges for the given input edge E
Definition of vehicle stop (position and duration)
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
_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 addSchedule(const SUMOVehicleParameter &pars, const std::vector< SUMOVehicleParameter::Stop > *addStops=0)
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.
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)