19 #ifndef IntermodalNetwork_h 20 #define IntermodalNetwork_h 51 template <
class E,
class L>
53 if (edge ==
nullptr) {
57 const std::vector<L*>& lanes = edge->getLanes();
58 for (
const L*
const lane : lanes) {
63 for (
const L*
const lane : lanes) {
76 template<
class E,
class L,
class N,
class V>
83 typedef std::pair<_IntermodalEdge*, _IntermodalEdge*>
EdgePair;
101 IntermodalNetwork(
const std::vector<E*>& edges,
const bool pedestrianOnly,
const int carWalkTransfer = 0)
103 #ifdef IntermodalRouter_DEBUG_NETWORK 104 std::cout <<
"initIntermodalNetwork\n";
107 bool haveSeenWalkingArea =
false;
108 for (
const E*
const edge : edges) {
109 if (edge->isTazConnector()) {
112 const L* lane = getSidewalk<E, L>(edge);
114 if (edge->isWalkingArea()) {
120 haveSeenWalkingArea =
true;
128 if (!edge->isWalkingArea()) {
137 for (
const E*
const edge : edges) {
138 if (edge->isTazConnector() || edge->isInternal()) {
141 if (haveSeenWalkingArea) {
143 if (!pedestrianOnly && getSidewalk<E, L>(edge) ==
nullptr) {
144 const N*
const node = edge->getToJunction();
151 for (
const N*
const node : {
152 edge->getFromJunction(), edge->getToJunction()
162 for (
const E*
const edge : edges) {
163 const L*
const sidewalk = getSidewalk<E, L>(edge);
164 if (sidewalk ==
nullptr) {
170 #ifdef IntermodalRouter_DEBUG_NETWORK 171 std::cout <<
" building connections from " << sidewalk->getID() <<
"\n";
173 if (haveSeenWalkingArea) {
174 const std::vector<std::pair<const L*, const E*> > outgoing = sidewalk->getOutgoingViaLanes();
178 bool hasWalkingArea =
false;
179 for (
const auto& target : outgoing) {
180 if (target.first->getEdge().isWalkingArea()) {
181 hasWalkingArea =
true;
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";
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";
208 if (toNodeConn !=
nullptr) {
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;
219 EdgePair interVia = std::make_pair(
nullptr,
nullptr);
220 if (minVia !=
nullptr) {
223 interVia = it->second;
226 if (!haveSeenWalkingArea) {
228 pair.first->addSuccessor(toNodeConn, interVia.first);
233 if (fromNodeConn !=
nullptr) {
234 if (!haveSeenWalkingArea) {
235 pair.second->addSuccessor(fromNodeConn);
239 if (!edge->isWalkingArea()) {
246 pair.first->addSuccessor(endConnector);
247 pair.second->addSuccessor(endConnector);
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";
259 for (
typename std::vector<_IntermodalEdge*>::iterator it =
myEdges.begin(); it !=
myEdges.end(); ++it) {
271 void addConnectors(_IntermodalEdge*
const depConn, _IntermodalEdge*
const arrConn,
const int index) {
284 typename std::map<const E*, EdgePair>::const_iterator it =
myBidiLookup.find(e);
287 throw ProcessError(
"Edge '" + e->getID() +
"' not found in intermodal network.'");
294 typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it =
myDepartLookup.find(e);
296 throw ProcessError(
"Depart edge '" + e->getID() +
"' not found in intermodal network.");
300 double totalLength = 0.;
301 double bestDist = std::numeric_limits<double>::max();
302 const _IntermodalEdge* best =
nullptr;
303 for (
const _IntermodalEdge*
split : it->second) {
305 double dist = fabs(totalLength - pos);
306 if (dist < bestDist) {
308 if (bestDist != std::numeric_limits<double>::max() && split == it->second.back()) {
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) {
334 typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it =
myDepartLookup.find(e);
336 throw ProcessError(
"Depart edge '" + e->getID() +
"' not found in intermodal network.");
338 if (splitIndex >= (
int)it->second.size()) {
339 throw ProcessError(
"Split index " +
toString(splitIndex) +
" invalid for depart edge '" + e->getID() +
"' .");
341 return it->second[splitIndex];
346 typename std::map<const E*, std::vector<_IntermodalEdge*> >::const_iterator it =
myArrivalLookup.find(e);
348 throw ProcessError(
"Arrival edge '" + e->getID() +
"' not found in intermodal network.");
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();
367 typename std::map<const N*, _IntermodalEdge*>::const_iterator it =
myWalkingConnectorLookup.find(e->getToJunction());
369 const L*
const sidewalk = getSidewalk<E, L>(e);
370 if (e->isInternal() || sidewalk == 0) {
373 for (
const auto& target : sidewalk->getOutgoingViaLanes()) {
374 if (target.first->getEdge().isWalkingArea()) {
384 for (
const E*
const edge : edges) {
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) {
405 for (
const E*
const out : edgePair.first->getToJunction()->getOutgoing()) {
406 if (!out->isInternal() && !out->isTazConnector() && getSidewalk<E, L>(out) != 0) {
410 for (
const E*
const in : edgePair.first->getToJunction()->getIncoming()) {
411 if (!in->isInternal() && !in->isTazConnector() && getSidewalk<E, L>(in) != 0) {
424 typename std::map<const E*, _IntermodalEdge*>::const_iterator it =
myCarLookup.find(e);
453 void addAccess(
const std::string& stopId,
const E* stopEdge,
const double pos,
const double length,
const SumoXMLTag category) {
454 assert(stopEdge !=
nullptr);
461 const L* lane = getSidewalk<E, L>(stopEdge);
462 if (lane !=
nullptr) {
463 const std::pair<_IntermodalEdge*, _IntermodalEdge*>& pair =
getBothDirections(stopEdge);
466 const int splitIndex =
findSplitIndex(pair.first, pos, relPos, needSplit);
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;
476 splitEdge(
myCarLookup[stopEdge], splitIndex, carSplit, relPos, length, needSplit, stopConn,
true,
false);
482 for (_IntermodalEdge* conn : {
485 _AccessEdge* access =
new _AccessEdge(myNumericalID++, beforeSplit, conn, length);
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");
503 if (carSplit !=
nullptr) {
509 _IntermodalEdge*
const fwdBeforeSplit =
myAccessSplits[pair.first][splitIndex];
510 _IntermodalEdge*
const arrConn =
new _IntermodalEdge(stopEdge->getID() +
"_arrival_connector" +
toString(pos), myNumericalID++, stopEdge,
"!connector");
517 if (carSplit !=
nullptr) {
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();
538 const double newLength = pos - (totalLength - last->
getLength());
540 splitList.insert(splitIt - 1, stopConn);
548 std::vector<SUMOVehicleParameter::Stop> validStops;
549 if (addStops !=
nullptr) {
555 if (newUntil >= lastUntil) {
556 validStops.push_back(stop);
557 validStops.back().until = newUntil;
558 lastUntil = newUntil;
560 WRITE_WARNING(
"Ignoring unordered stop at '" + stop.busstop +
"' until " +
time2string(stop.until) +
" for vehicle '" + pars.
id +
"'.");
568 validStops.push_back(stop);
569 lastUntil = stop.
until;
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.");
579 typename std::vector<_PTEdge*>& lineEdges =
myPTLines[pars.
line];
580 if (lineEdges.empty()) {
581 _IntermodalEdge* lastStop =
nullptr;
586 Position stopPos = E::getStopPosition(s);
587 if (lastStop !=
nullptr) {
593 lineEdges.push_back(newEdge);
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.");
604 if (lineEdges.front()->getEntryStop() !=
myStopConnections[validStops.front().busstop]) {
605 WRITE_WARNING(
"Different stop for '" + pars.
line +
"' compared to earlier definitions, ignoring schedule.");
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) {
612 WRITE_WARNING(
"Different stop for '" + pars.
line +
"' compared to earlier definitions, ignoring schedule.");
616 SUMOTime lastTime = validStops.front().until;
617 if (lineEdges.front()->hasSchedule(lastTime)) {
620 for (lineEdge = lineEdges.begin(), s = validStops.begin() + 1; lineEdge != lineEdges.end(); ++lineEdge, ++s) {
640 int findSplitIndex(_IntermodalEdge*
const toSplit,
const double pos,
double& relPos,
bool& needSplit) {
644 std::vector<_IntermodalEdge*>& splitList =
myAccessSplits[toSplit];
645 if (!splitList.empty()) {
646 for (
const _IntermodalEdge*
const split : splitList) {
650 relPos -=
split->getLength();
653 assert(splitIndex < (
int)splitList.size());
654 if (splitIndex + 1 < (
int)splitList.size() && fabs(relPos - splitList[splitIndex]->getLength()) <
POSITION_EPS) {
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);
681 splitIndex = (int)splitList.size() - 1 - splitIndex;
686 _IntermodalEdge* beforeSplit = splitList[splitIndex];
698 const std::string newID = beforeSplit->
getID();
700 afterSplit->
setID(newID);
702 splitList.insert(splitList.begin() + splitIndex + 1, afterSplit);
705 afterSplit = splitList[splitIndex + 1];
742 std::map<std::string, std::vector<_PTEdge*> >
myPTLines;
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
void splitEdge(_IntermodalEdge *const toSplit, int splitIndex, _IntermodalEdge *afterSplit, const double relPos, const double length, const bool needSplit, _IntermodalEdge *const stopConn, const bool forward=true, const bool addExit=true)
Splits an edge (if necessary) and connects it to a stopping edge.
ModeChangeOptions
where mode changes are possible
_IntermodalEdge * getDepartConnector(const E *e, const int splitIndex=0) const
Returns the departing intermodal connector at the given split offset.
const std::vector< _IntermodalEdge * > & getAllEdges()
IntermodalNetwork(const std::vector< E *> &edges, const bool pedestrianOnly, const int carWalkTransfer=0)
std::map< const E *, EdgePair > myBidiLookup
retrieve the forward and backward edge for the given input edge E
void addEdge(_IntermodalEdge *edge)
const int myCarWalkTransfer
_IntermodalEdge * getStopEdge(const std::string &stopId) const
Returns the associated stop edge.
std::string time2string(SUMOTime t)
int getNumericalID() const
AccessEdge< E, L, N, V > _AccessEdge
the car edge type that is given to the internal router (SUMOAbstractRouter)
std::string busstop
(Optional) bus stop if one is assigned to the stop
IntermodalNetwork & operator=(const IntermodalNetwork &s)
Invalidated assignment operator.
IntermodalEdge< E, L, N, V > _IntermodalEdge
const std::string & getID() const
Returns the id.
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
#define WRITE_WARNING(msg)
SUMOTime repetitionOffset
The time offset between vehicle reinsertions.
void removeSuccessor(const IntermodalEdge *const edge)
std::vector< Stop > stops
List of the stops the vehicle will make, TraCI may add entries here.
const E * getEdge() const
_IntermodalEdge * getWalkingConnector(const E *e) const
Returns the outgoing pedestrian edge, which is either a walking area or a walking connector...
void transferSuccessors(IntermodalEdge *to)
PublicTransportEdge< E, L, N, V > _PTEdge
std::vector< _IntermodalEdge * > myEdges
the edge dictionary
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
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.
SUMOTime until
The time at which the vehicle may continue its journey.
int findSplitIndex(_IntermodalEdge *const toSplit, const double pos, double &relPos, bool &needSplit)
Returns where to insert or use the split edge.
_IntermodalEdge * getArrivalConnector(const E *e, const int splitIndex=0) const
Returns the arriving intermodal connector at the given split offset.
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
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's line (mainly for public transport)
the base edge type that is given to the internal router (SUMOAbstractRouter)
junctions with edges allowing the additional mode
Definition of vehicle stop (position and duration)
std::map< const N *, _IntermodalEdge * > myWalkingConnectorLookup
the walking connector edge (fake walking area)
std::map< _IntermodalEdge *, std::vector< _IntermodalEdge * > > myAccessSplits
retrieve the splitted edges for the given "original"
void setID(const std::string &newID)
resets the id
Structure representing possible vehicle parameter.
void addSchedule(const SUMOVehicleParameter &pars, const std::vector< SUMOVehicleParameter::Stop > *addStops=nullptr)
std::map< const E *, std::vector< _IntermodalEdge * > > myDepartLookup
retrieve the depart edges for the given input edge E
std::map< std::string, std::vector< _PTEdge * > > myPTLines
retrieve the public transport edges for the given line
void addCarEdges(const std::vector< E *> &edges)
the public transport edge type connecting the stop edges
std::map< std::string, _IntermodalEdge * > myStopConnections
retrieve the representing edge for the given stopping place
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
_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
void addSuccessor(IntermodalEdge *const s, IntermodalEdge *const via=nullptr)
vehicles ignoring classes
void addAccess(const std::string &stopId, const E *stopEdge, const double pos, const double length, const SumoXMLTag category)
Adds access edges for stopping places to the intermodal network.
const _IntermodalEdge * getDepartEdge(const E *e, const double pos) const
Returns the departing intermodal edge.
the access edge connecting different modes that is given to the internal router (SUMOAbstractRouter) ...
std::string id
The vehicle's id.
void setLength(const double length)