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 <utils/geom/Position.h>
37 #include "AccessEdge.h"
38 #include "CarEdge.h"
39 #include "IntermodalEdge.h"
40 #include "PedestrianEdge.h"
41 #include "PublicTransportEdge.h"
42 #include "StopEdge.h"
43 #include "SUMOVehicleParameter.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  _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  const std::vector<_IntermodalEdge*>& splitList = it->second;
299  typename std::vector<_IntermodalEdge*>::const_iterator splitIt = splitList.begin();
300  double totalLength = 0.;
301  while (splitIt != splitList.end() && totalLength + (*splitIt)->getLength() < pos) {
302  totalLength += (*splitIt)->getLength();
303  ++splitIt;
304  }
305  return *splitIt;
306  }
307 
309  _IntermodalEdge* getDepartConnector(const E* e, const int splitIndex = 0) const {
310  typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it = myDepartLookup.find(e);
311  if (it == myDepartLookup.end()) {
312  throw ProcessError("Depart edge '" + e->getID() + "' not found in intermodal network.");
313  }
314  if (splitIndex >= (int)it->second.size()) {
315  throw ProcessError("Split index " + toString(splitIndex) + " invalid for depart edge '" + e->getID() + "' .");
316  }
317  return it->second[splitIndex];
318  }
319 
321  _IntermodalEdge* getArrivalEdge(const E* e, const double pos) const {
322  typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it = myArrivalLookup.find(e);
323  if (it == myArrivalLookup.end()) {
324  throw ProcessError("Arrival edge '" + e->getID() + "' not found in intermodal network.");
325  }
326  const std::vector<_IntermodalEdge*>& splitList = it->second;
327  typename std::vector<_IntermodalEdge*>::const_iterator splitIt = splitList.begin();
328  double totalLength = 0.;
329  while (splitIt != splitList.end() && totalLength + (*splitIt)->getLength() < pos) {
330  totalLength += (*splitIt)->getLength();
331  ++splitIt;
332  }
333  return *splitIt;
334  }
335 
337  _IntermodalEdge* getArrivalConnector(const E* e, const int splitIndex = 0) const {
338  return myArrivalLookup.find(e)->second[splitIndex];
339  }
340 
342  _IntermodalEdge* getWalkingConnector(const E* e) const {
343  typename std::map<const N*, _IntermodalEdge*>::const_iterator it = myWalkingConnectorLookup.find(e->getToJunction());
344  if (it == myWalkingConnectorLookup.end()) {
345  const L* const sidewalk = getSidewalk<E, L>(e);
346  if (e->isInternal() || sidewalk == 0) {
347  return 0;
348  }
349  for (const auto& target : sidewalk->getOutgoingViaLanes()) {
350  if (target.first->getEdge().isWalkingArea()) {
351  return getBothDirections(&target.first->getEdge()).first;
352  }
353  }
354  return 0;
355  }
356  return it->second;
357  }
358 
359  void addCarEdges(const std::vector<E*>& edges) {
360  for (const E* const edge : edges) {
361  if (edge->getFunction() == EDGEFUNC_NORMAL || edge->getFunction() == EDGEFUNC_INTERNAL) {
362  myCarLookup[edge] = new CarEdge<E, L, N, V>(myNumericalID++, edge);
363  addEdge(myCarLookup[edge]);
364  }
365  }
366  for (const auto& edgePair : myCarLookup) {
367  _IntermodalEdge* const carEdge = edgePair.second;
368  for (const auto& suc : edgePair.first->getViaSuccessors()) {
369  _IntermodalEdge* const sucCarEdge = getCarEdge(suc.first);
370  _IntermodalEdge* const sucViaEdge = getCarEdge(suc.second);
371  if (sucCarEdge != nullptr) {
372  carEdge->addSuccessor(sucCarEdge, sucViaEdge);
373  }
374  }
375  if ((myCarWalkTransfer & ALL_JUNCTIONS) != 0) {
376  _IntermodalEdge* const walkCon = getWalkingConnector(edgePair.first);
377  if (walkCon != 0) {
378  carEdge->addSuccessor(walkCon);
379  } else {
380  // we are on an edge where pedestrians are forbidden and want to continue on an arbitrary pedestrian edge
381  for (const E* const out : edgePair.first->getToJunction()->getOutgoing()) {
382  if (!out->isInternal() && !out->isTazConnector() && getSidewalk<E, L>(out) != 0) {
383  carEdge->addSuccessor(getBothDirections(out).first);
384  }
385  }
386  for (const E* const in : edgePair.first->getToJunction()->getIncoming()) {
387  if (!in->isInternal() && !in->isTazConnector() && getSidewalk<E, L>(in) != 0) {
388  carEdge->addSuccessor(getBothDirections(in).second);
389  }
390  }
391  }
392  }
393  getDepartConnector(edgePair.first)->addSuccessor(carEdge);
394  carEdge->addSuccessor(getArrivalConnector(edgePair.first));
395  }
396  }
397 
399  _IntermodalEdge* getCarEdge(const E* e) const {
400  typename std::map<const E*, _IntermodalEdge*>::const_iterator it = myCarLookup.find(e);
401  if (it == myCarLookup.end()) {
402  return nullptr;
403  }
404  return it->second;
405  }
406 
408  _IntermodalEdge* getStopEdge(const std::string& stopId) const {
409  auto it = myStopConnections.find(stopId);
410  if (it == myStopConnections.end()) {
411  return 0;
412  }
413  return it->second;
414  }
415 
429  void addAccess(const std::string& stopId, const E* stopEdge, const double pos, const double length, const SumoXMLTag category) {
430  assert(stopEdge != 0);
431  if (myStopConnections.count(stopId) == 0) {
432  myStopConnections[stopId] = new StopEdge<E, L, N, V>(stopId, myNumericalID++, stopEdge);
433  addEdge(myStopConnections[stopId]);
434  }
435  _IntermodalEdge* const stopConn = myStopConnections[stopId];
436  const L* lane = getSidewalk<E, L>(stopEdge);
437  if (lane != 0) {
438  const std::pair<_IntermodalEdge*, _IntermodalEdge*>& pair = getBothDirections(stopEdge);
439  double relPos;
440  bool needSplit;
441  const int splitIndex = findSplitIndex(pair.first, pos, relPos, needSplit);
442  _IntermodalEdge* const fwdSplit = needSplit ? new PedestrianEdge<E, L, N, V>(myNumericalID++, stopEdge, lane, true, pos) : nullptr;
443  splitEdge(pair.first, splitIndex, fwdSplit, relPos, length, needSplit, stopConn);
444  _IntermodalEdge* const backSplit = needSplit ? new PedestrianEdge<E, L, N, V>(myNumericalID++, stopEdge, lane, false, pos) : nullptr;
445  splitEdge(pair.second, splitIndex, backSplit, relPos, length, needSplit, stopConn, false);
446  _IntermodalEdge* carSplit = nullptr;
447  if (myCarLookup.count(stopEdge) > 0) {
448  if (needSplit) {
449  carSplit = new CarEdge<E, L, N, V>(myNumericalID++, stopEdge, pos);
450  }
451  splitEdge(myCarLookup[stopEdge], splitIndex, carSplit, relPos, length, needSplit, stopConn, true, false);
452  }
453  if (needSplit) {
454  if (carSplit != nullptr && ((category == SUMO_TAG_PARKING_AREA && (myCarWalkTransfer & PARKING_AREAS) != 0) || (category == SUMO_TAG_BUS_STOP && (myCarWalkTransfer & PT_STOPS) != 0))) {
455  // adding access from car to walk
456  _IntermodalEdge* const beforeSplit = myAccessSplits[myCarLookup[stopEdge]][splitIndex];
457  for (_IntermodalEdge* conn : {
458  fwdSplit, backSplit
459  }) {
460  _AccessEdge* access = new _AccessEdge(myNumericalID++, beforeSplit, conn, length);
461  addEdge(access);
462  beforeSplit->addSuccessor(access);
463  access->addSuccessor(conn);
464  }
465  }
466 
467  // fixing depart connections for the forward pedestrian, the backward pedestrian and the car edge
468  _IntermodalEdge* const prevDep = getDepartConnector(stopEdge, splitIndex);
469  const std::vector<_IntermodalEdge*>& backSplitList = myAccessSplits[pair.second];
470  _IntermodalEdge* const backBeforeSplit = backSplitList[backSplitList.size() - 2 - splitIndex];
471  _IntermodalEdge* const depConn = new _IntermodalEdge(stopEdge->getID() + "_depart_connector" + toString(pos), myNumericalID++, stopEdge, "!connector");
472  depConn->addSuccessor(fwdSplit);
473  depConn->addSuccessor(backBeforeSplit);
474  depConn->setLength(fwdSplit->getLength());
475  prevDep->removeSuccessor(backBeforeSplit);
476  prevDep->addSuccessor(backSplit);
477  prevDep->setLength(backSplit->getLength());
478  if (carSplit != nullptr) {
479  depConn->addSuccessor(carSplit);
480  }
481 
482  // fixing arrival connections for the forward pedestrian, the backward pedestrian and the car edge
483  _IntermodalEdge* const prevArr = getArrivalConnector(stopEdge, splitIndex);
484  _IntermodalEdge* const fwdBeforeSplit = myAccessSplits[pair.first][splitIndex];
485  _IntermodalEdge* const arrConn = new _IntermodalEdge(stopEdge->getID() + "_arrival_connector" + toString(pos), myNumericalID++, stopEdge, "!connector");
486  fwdSplit->addSuccessor(arrConn);
487  backBeforeSplit->addSuccessor(arrConn);
488  arrConn->setLength(fwdSplit->getLength());
489  fwdSplit->removeSuccessor(prevArr);
490  fwdBeforeSplit->addSuccessor(prevArr);
491  prevArr->setLength(backSplit->getLength());
492  if (carSplit != nullptr) {
493  carSplit->addSuccessor(arrConn);
494  carSplit->removeSuccessor(prevArr);
495  myAccessSplits[myCarLookup[stopEdge]][splitIndex]->addSuccessor(prevArr);
496  }
497  addConnectors(depConn, arrConn, splitIndex + 1);
498  }
499  }
500  }
501 
502  void addSchedule(const SUMOVehicleParameter& pars, const std::vector<SUMOVehicleParameter::Stop>* addStops = nullptr) {
503  SUMOTime lastUntil = 0;
504  std::vector<SUMOVehicleParameter::Stop> validStops;
505  if (addStops != nullptr) {
506  // stops are part of a stand-alone route. until times are offsets from vehicle departure
507  for (const SUMOVehicleParameter::Stop& stop : *addStops) {
508  if (myStopConnections.count(stop.busstop) > 0) {
509  // compute stop times for the first vehicle
510  const SUMOTime newUntil = stop.until + pars.depart;
511  if (newUntil >= lastUntil) {
512  validStops.push_back(stop);
513  validStops.back().until = newUntil;
514  lastUntil = newUntil;
515  } else {
516  WRITE_WARNING("Ignoring unordered stop at '" + stop.busstop + "' until " + time2string(stop.until) + " for vehicle '" + pars.id + "'.");
517  }
518  }
519  }
520  }
521  for (const SUMOVehicleParameter::Stop& stop : pars.stops) {
522  // stops are part of the vehicle until times are absolute times for the first vehicle
523  if (myStopConnections.count(stop.busstop) > 0 && stop.until >= lastUntil) {
524  validStops.push_back(stop);
525  lastUntil = stop.until;
526  } else {
527  WRITE_WARNING("Ignoring stop at '" + stop.busstop + "' until " + time2string(stop.until) + " for vehicle '" + pars.id + "'.");
528  }
529  }
530  if (validStops.size() < 2) {
531  WRITE_WARNING("Not using public transport line '" + pars.line + "' for routing persons. It has less than two usable stops.");
532  return;
533  }
534 
535  typename std::vector<_PTEdge*>& lineEdges = myPTLines[pars.line];
536  if (lineEdges.empty()) {
537  _IntermodalEdge* lastStop = nullptr;
538  Position lastPos;
539  SUMOTime lastTime = 0;
540  for (const SUMOVehicleParameter::Stop& s : validStops) {
541  _IntermodalEdge* currStop = myStopConnections[s.busstop];
542  Position stopPos = E::getStopPosition(s);
543  if (lastStop != nullptr) {
544  _PTEdge* const newEdge = new _PTEdge(s.busstop, myNumericalID++, lastStop, currStop->getEdge(), pars.line, lastPos.distanceTo(stopPos));
545  addEdge(newEdge);
546  newEdge->addSchedule(pars.id, lastTime, pars.repetitionNumber, pars.repetitionOffset, s.until - lastTime);
547  lastStop->addSuccessor(newEdge);
548  newEdge->addSuccessor(currStop);
549  lineEdges.push_back(newEdge);
550  }
551  lastTime = s.until;
552  lastStop = currStop;
553  lastPos = stopPos;
554  }
555  } else {
556  if (validStops.size() != lineEdges.size() + 1) {
557  WRITE_WARNING("Number of stops for public transport line '" + pars.line + "' does not match earlier definitions, ignoring schedule.");
558  return;
559  }
560  if (lineEdges.front()->getEntryStop() != myStopConnections[validStops.front().busstop]) {
561  WRITE_WARNING("Different stop for '" + pars.line + "' compared to earlier definitions, ignoring schedule.");
562  return;
563  }
564  typename std::vector<_PTEdge*>::const_iterator lineEdge = lineEdges.begin();
565  typename std::vector<SUMOVehicleParameter::Stop>::const_iterator s = validStops.begin() + 1;
566  for (; s != validStops.end(); ++s, ++lineEdge) {
567  if ((*lineEdge)->getSuccessors(SVC_IGNORING)[0] != myStopConnections[s->busstop]) {
568  WRITE_WARNING("Different stop for '" + pars.line + "' compared to earlier definitions, ignoring schedule.");
569  return;
570  }
571  }
572  SUMOTime lastTime = validStops.front().until;
573  if (lineEdges.front()->hasSchedule(lastTime)) {
574  WRITE_WARNING("Duplicate schedule for '" + pars.line + "' at time " + time2string(lastTime) + ".");
575  }
576  for (lineEdge = lineEdges.begin(), s = validStops.begin() + 1; lineEdge != lineEdges.end(); ++lineEdge, ++s) {
577  (*lineEdge)->addSchedule(pars.id, lastTime, pars.repetitionNumber, pars.repetitionOffset, s->until - lastTime);
578  lastTime = s->until;
579  }
580  }
581  }
582 
583 
584 private:
596  int findSplitIndex(_IntermodalEdge* const toSplit, const double pos, double& relPos, bool& needSplit) {
597  relPos = pos;
598  needSplit = true;
599  int splitIndex = 0;
600  std::vector<_IntermodalEdge*>& splitList = myAccessSplits[toSplit];
601  if (!splitList.empty()) {
602  for (const _IntermodalEdge* const split : splitList) {
603  if (relPos < split->getLength() + POSITION_EPS) {
604  break;
605  }
606  relPos -= split->getLength();
607  splitIndex++;
608  }
609  assert(splitIndex < (int)splitList.size());
610  if (splitIndex + 1 < (int)splitList.size() && fabs(relPos - splitList[splitIndex]->getLength()) < POSITION_EPS) {
611  needSplit = false;
612  }
613  }
614  return splitIndex;
615  }
616 
629  void splitEdge(_IntermodalEdge* const toSplit, int splitIndex,
630  _IntermodalEdge* afterSplit, const double relPos, const double length, const bool needSplit,
631  _IntermodalEdge* const stopConn, const bool forward = true, const bool addExit = true) {
632  std::vector<_IntermodalEdge*>& splitList = myAccessSplits[toSplit];
633  if (splitList.empty()) {
634  splitList.push_back(toSplit);
635  }
636  if (!forward) {
637  splitIndex = (int)splitList.size() - 1 - splitIndex;
638  if (!needSplit) {
639  splitIndex--;
640  }
641  }
642  _IntermodalEdge* beforeSplit = splitList[splitIndex];
643  if (needSplit) {
644  addEdge(afterSplit);
645  beforeSplit->transferSuccessors(afterSplit);
646  beforeSplit->addSuccessor(afterSplit);
647  if (forward) {
648  afterSplit->setLength(beforeSplit->getLength() - relPos);
649  beforeSplit->setLength(relPos);
650  } else {
651  afterSplit->setLength(relPos);
652  beforeSplit->setLength(beforeSplit->getLength() - relPos);
653  // rename backward edges for easier referencing
654  const std::string newID = beforeSplit->getID();
655  beforeSplit->setID(afterSplit->getID());
656  afterSplit->setID(newID);
657  }
658  splitList.insert(splitList.begin() + splitIndex + 1, afterSplit);
659  } else {
660  // don't split, use the present split edges
661  afterSplit = splitList[splitIndex + 1];
662  }
663  // add access to / from edge
664  _AccessEdge* access = new _AccessEdge(myNumericalID++, beforeSplit, stopConn, length);
665  addEdge(access);
666  beforeSplit->addSuccessor(access);
667  access->addSuccessor(stopConn);
668  if (addExit) {
669  // pedestrian case only, exit from public to pedestrian
670  _AccessEdge* exit = new _AccessEdge(myNumericalID++, stopConn, afterSplit, length);
671  addEdge(exit);
672  stopConn->addSuccessor(exit);
673  exit->addSuccessor(afterSplit);
674  }
675  }
676 
677 
678 private:
680  std::vector<_IntermodalEdge*> myEdges;
681 
683  std::map<const E*, EdgePair> myBidiLookup;
684 
686  std::map<const E*, std::vector<_IntermodalEdge*> > myDepartLookup;
687 
689  std::map<const E*, std::vector<_IntermodalEdge*> > myArrivalLookup;
690 
692  std::map<const N*, _IntermodalEdge*> myWalkingConnectorLookup;
693 
695  std::map<const E*, _IntermodalEdge*> myCarLookup;
696 
698  std::map<std::string, std::vector<_PTEdge*> > myPTLines;
699 
701  std::map<std::string, _IntermodalEdge*> myStopConnections;
702 
704  std::map<_IntermodalEdge*, std::vector<_IntermodalEdge*> > myAccessSplits;
705 
707  const int myCarWalkTransfer;
708 
709 private:
712 
713 };
714 
715 
716 #endif
717 
718 /****************************************************************************/
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: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
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:78
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:241
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)
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
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:86
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
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
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.
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)