43 #define DEBUGNODEID "gneJ34" 44 #define DEBUGNODEID2 "28842974" 45 #define DEBUGEDGEID "22820560#0" 46 #define DEBUGCOND(obj) ((obj != 0 && (obj)->getID() == DEBUGNODEID)) 48 #define SHARP_THRESHOLD_SAMEDIR 100 49 #define SHARP_THRESHOLD 80 66 const std::vector<NBRailwayTopologyAnalyzer::Track*>&
72 std::vector<Track*> succ;
74 if ((t->edge->getPermissions() & svc) != 0) {
84 const std::vector<std::pair<const NBRailwayTopologyAnalyzer::Track*, const NBRailwayTopologyAnalyzer::Track*> >&
90 std::vector<std::pair<const Track*, const Track*> >& succ =
svcViaSuccessors[svc];
92 if ((t->edge->getPermissions() & svc) != 0) {
93 succ.push_back(std::make_pair(t,
nullptr));
125 int numRailEdges = 0;
126 int numBidiEdges = 0;
127 int numNotCenterEdges = 0;
128 int numAddedBidiEdges = 0;
148 WRITE_MESSAGE(
"Added " +
toString(numAddedBidiEdges) +
" bidi-edges to ensure that all tracks are usable in both directions.");
149 if (numNotCenterEdges) {
150 WRITE_WARNING(
"Ignore " +
toString(numNotCenterEdges) +
" edges because they have the wrong spreadType");
158 const std::string id2 = (edge->
getID()[0] ==
'-' 159 ? edge->
getID().substr(1)
160 :
"-" + edge->
getID());
182 inEdges.push_back(e);
187 outEdges.push_back(e);
196 std::set<NBNode*> brokenNodes;;
202 std::set<NBNode*> railNodes =
getRailNodes(nb, verbose);
203 std::map<std::pair<int, int>, std::set<NBNode*, ComparatorIdLess> > types;
204 std::set<NBEdge*, ComparatorIdLess> bidiEdges;
205 std::set<NBEdge*, ComparatorIdLess> bufferStops;
206 for (
NBNode* node : railNodes) {
209 types[std::make_pair((
int)inEdges.size(), (int)outEdges.size())].insert(node);
210 for (
NBEdge* e : outEdges) {
211 if (e->isBidiRail() && bidiEdges.count(e->getTurnDestination(
true)) == 0) {
214 if (e->getID()[0] ==
'-') {
215 std::swap(primary, secondary);
216 }
else if (primary->
getID()[0] !=
'-' && secondary->
getID()[0] !=
'-' && secondary->
getID() < primary->
getID()) {
217 std::swap(primary, secondary);
219 if (bidiEdges.count(secondary) == 0) {
221 bidiEdges.insert(primary);
231 int numBufferStops = 0;
232 if (verbose && types.size() > 0) {
233 WRITE_MESSAGE(
"Railway nodes by number of incoming,outgoing edges:")
238 device.
writeAttr(
"meaning",
"edge pair angle supports driving but both are outgoing");
242 device.
writeAttr(
"meaning",
"edge pair angle supports driving but both are incoming");
246 device.
writeAttr(
"meaning",
"an incoming edge has a sharp angle to all outgoing edges");
250 device.
writeAttr(
"meaning",
"an outgoing edge has a sharp angle from all incoming edges");
254 for (
auto it : types) {
255 int numBrokenType = 0;
256 device.
openTag(
"railNodeType");
257 int in = it.first.first;
258 int out = it.first.second;
261 for (
NBNode* n : it.second) {
269 std::string broken =
"";
279 for (
NBEdge* e : inRail) {
290 for (
NBEdge* e : outRail) {
301 if (((in == 1 && out == 1) || (in == 2 && out == 2))
306 if (broken.size() > 0) {
308 brokenNodes.insert(n);
320 +
" count: " +
toString(it.second.size()) +
" broken: " +
toString(numBrokenType));
334 for (
NBEdge* e : bidiEdges) {
337 device.
writeAttr(
"bidi", e->getTurnDestination(
true)->getID());
351 std::set<NBNode*> railNodes;
354 int numRailEdges = 0;
355 for (
auto it = ec.
begin(); it != ec.
end(); it++) {
356 if (
isRailway(it->second->getPermissions())) {
358 railNodes.
insert(it->second->getFromNode());
359 railNodes.insert(it->second->getToNode());
363 std::set<NBNode*> railSignals;
364 for (
NBNode* node : railNodes) {
366 railSignals.insert(node);
402 #ifdef DEBUG_SEQSTOREVERSE 407 for (
NBEdge* e1 : edges) {
408 for (
NBEdge* e2 : edges2) {
428 if (e != candOut &&
isStraight(node, e, candOut)) {
430 std::cout <<
" isStraight e=" << e->getID() <<
" candOut=" << candOut->
getID() <<
"\n";
436 if (e != candOut && !
isStraight(node, e, candOut)) {
438 std::cout <<
" isSharp e=" << e->getID() <<
" candOut=" << candOut->
getID() <<
"\n";
455 if (!e1->isBidiRail(
true)) {
461 return !allBidi || countBidiAsSharp;
468 if (!e->isBidiRail()) {
481 for (
auto it = ec.
begin(); it != ec.
end(); it++) {
499 if (bidiOut ==
nullptr) {
504 tmpBidiOut.push_back(bidiOut);
506 tmpBidiIn.push_back(bidiIn);
510 for (
NBEdge* cand : outRail) {
512 if (!cand->isBidiRail() &&
isStraight(node, bidiIn, cand)
514 &&
allSharp(node, inRail, tmpBidiOut,
true)) {
521 for (
NBEdge* cand : inRail) {
523 if (!cand->isBidiRail() &&
isStraight(node, cand, bidiOut)
525 &&
allSharp(node, outRail, tmpBidiIn,
true)) {
540 std::vector<EdgeVector> seqsToReverse;
541 for (
NBNode* n : brokenNodes) {
544 for (
NBEdge* start : outRail) {
546 tmp.push_back(start);
548 if (!
allBroken(n, start, inRail, outRail)
549 || (inRail.size() == 1 && outRail.size() == 1)) {
550 #ifdef DEBUG_SEQSTOREVERSE 552 std::cout <<
" abort at start n=" << n->getID() <<
" (not all broken)\n";
561 seq.push_back(start);
563 NBNode* n2 = start->getToNode();
566 if (brokenNodes.count(n2) != 0) {
568 tmp2.push_back(start);
569 if (
allBroken(n2, start, outRail2, inRail2)) {
570 seqsToReverse.push_back(seq);
572 #ifdef DEBUG_SEQSTOREVERSE 574 std::cout <<
" abort at n2=" << n2->
getID() <<
" (not all broken)\n";
580 if (outRail2.size() == 0) {
583 #ifdef DEBUG_SEQSTOREVERSE 585 std::cout <<
" abort at n2=" << n2->
getID() <<
" (border)\n";
588 }
else if (outRail2.size() > 1 || inRail2.size() > 1) {
591 #ifdef DEBUG_SEQSTOREVERSE 593 std::cout <<
" abort at n2=" << n2->
getID() <<
" (switch)\n";
597 start = outRail2.front();
604 if (seqsToReverse.size() > 0) {
605 WRITE_MESSAGE(
"Found " +
toString(seqsToReverse.size()) +
" reversible edge sequences between broken rail nodes");
607 std::sort(seqsToReverse.begin(), seqsToReverse.end(),
609 return a.size() < b.size();
612 std::set<NBNode*> affectedEndpoints;
613 std::set<std::string> reversedIDs;
614 std::map<int, int> seqLengths;
616 NBNode* seqStart = seq.front()->getFromNode();
617 NBNode* seqEnd = seq.back()->getToNode();
619 if (affectedEndpoints.count(seqStart) == 0
620 && affectedEndpoints.count(seqEnd) == 0) {
621 affectedEndpoints.insert(seqStart);
622 affectedEndpoints.insert(seqEnd);
625 e->reinitNodes(e->getToNode(), e->getFromNode());
626 e->setGeometry(e->getGeometry().reverse());
627 reversedIDs.insert(e->getID());
629 seqLengths[(int)seq.size()]++;
633 if (numReversed > 0) {
636 if (reversedIDs.count(item.second->getEdgeId())) {
637 item.second->findLaneAndComputeBusStopExtent(nb.
getEdgeCont());
649 int numBufferStops = 0;
650 int numAddedBidiTotal = 0;
651 for (
NBNode* node : railNodes) {
653 if (node->getEdges().size() != 1) {
654 WRITE_WARNING(
"Ignoring buffer stop junction '" + node->getID() +
"' with " +
toString(node->getEdges().size()) +
" edges\n");
657 int numAddedBidi = 0;
664 while (prev ==
nullptr || (inRail.size() + outRail.size()) == 3) {
666 if (prev ==
nullptr) {
667 assert(node->getEdges().size() == 1);
668 e = node->getEdges().front();
673 assert(inRail.size() == 2);
674 e = inRail.front() == prev2 ? inRail.back() : inRail.front();
677 assert(outRail.size() == 2);
678 e = outRail.front() == prev2 ? outRail.back() : outRail.front();
710 if (numAddedBidiTotal > 0) {
711 WRITE_MESSAGE(
"Added " +
toString(numAddedBidiTotal) +
" edges to connect " +
toString(numBufferStops) +
" buffer stops in both directions.");
719 if (inRail.size() == 2 && outRail.size() == 1 &&
isStraight(n, inRail.front(), inRail.back())) {
720 if (
isStraight(n, inRail.front(), outRail.front())) {
721 return inRail.front();
722 }
else if (
isStraight(n, inRail.back(), outRail.front())) {
723 return inRail.back();
726 if (inRail.size() == 1 && outRail.size() == 2 &&
isStraight(n, outRail.front(), outRail.back())) {
727 if (
isStraight(n, outRail.front(), inRail.front())) {
728 return outRail.front();
729 }
else if (
isStraight(n, outRail.back(), inRail.front())) {
730 return outRail.back();
740 std::map<int, int> seqLengths;
743 for (
NBNode* n : brokenNodes) {
745 if (edge !=
nullptr) {
746 std::vector<NBNode*> nodeSeq;
749 nodeSeq.push_back(prev);
750 edgeSeq.push_back(edge);
758 if (allRail.size() == 2 &&
isStraight(next, allRail.front(), allRail.back())) {
760 edge = allRail.front() == edge ? allRail.back() : allRail.front();
761 nodeSeq.push_back(prev);
762 edgeSeq.push_back(edge);
771 for (
NBEdge* e : edgeSeq) {
774 seqLengths[(int)edgeSeq.size()]++;
776 numAdded += (int)edgeSeq.size();
790 if (seqLengths.size() > 0) {
800 std::vector<Track*> tracks;
804 const int numEdges = (int)tracks.
size();
809 std::map<NBEdge*, std::pair<Track*, Track*> > stopTracks;
813 tracks.push_back(start);
815 tracks.push_back(end);
816 stopTracks[
edge] = std::make_pair(start, end);
823 for (
NBEdge* e1 : railEdges) {
824 for (
NBEdge* e2 : railEdges) {
826 int i = e1->getNumericalID();
827 int i2 = e2->getNumericalID();
828 if (e1->getToNode() == node) {
829 if (e2->getFromNode() == node) {
831 tracks[i]->addSuccessor(tracks[i2]);
833 tracks[i2 + numEdges]->addSuccessor(tracks[i + numEdges]);
836 tracks[i]->addSuccessor(tracks[i2 + numEdges]);
837 tracks[i2]->addSuccessor(tracks[i + numEdges]);
840 if (e2->getFromNode() == node) {
842 tracks[i + numEdges]->addSuccessor(tracks[i2]);
843 tracks[i2 + numEdges]->addSuccessor(tracks[i]);
854 for (
auto& item : stopTracks) {
855 const int index = item.first->getNumericalID();
857 item.second.first->addSuccessor(tracks[index]);
858 item.second.first->addSuccessor(tracks[index + numEdges]);
860 tracks[
index]->addSuccessor(item.second.second);
861 tracks[index + numEdges]->addSuccessor(item.second.second);
878 int numDisconnected = 0;
879 std::set<NBEdge*> addBidiStops;
880 std::set<NBEdge*> addBidiEdges;
881 std::set<std::pair<NBPTStop*, NBPTStop*> > visited;
884 std::vector<NBPTStop*> stops = line->
getStops();
885 if (stops.size() < 2) {
888 for (
auto it = stops.begin(); it + 1 != stops.end(); ++it) {
889 std::pair<NBPTStop*, NBPTStop*> trip(*it, *(it + 1));
890 if (visited.count(trip) != 0) {
893 visited.insert(trip);
897 if (fromEdge ==
nullptr || toEdge ==
nullptr) {
900 if (stopTracks.count(fromEdge) == 0
901 || stopTracks.count(toEdge) == 0) {
905 std::vector<const Track*> route;
906 router->
compute(stopTracks[fromEdge].first, stopTracks[toEdge].second, &veh, 0, route);
910 if (route.size() > 0) {
911 assert(route.size() > 2);
912 for (
int i = 1; i < (int)route.size() - 1; ++i) {
915 if (addBidiEdges.count(edge) == 0) {
917 bool isStop = i == 1 || i == (int)route.size() - 2;
919 addBidiEdges.insert(edge);
921 addBidiStops.insert(edge);
925 WRITE_WARNING(
"Stop on edge " + fromEdge->
getID() +
" can only be reached in reverse but edge has the wrong spreadType");
933 WRITE_WARNING(
"No connection found between stops on edge '" + fromEdge->
getID() +
"' and edge '" + toEdge->
getID() +
"'");
950 if (addBidiEdges.size() > 0 || numDisconnected > 0) {
951 WRITE_MESSAGE(
"Added " +
toString(addBidiStops.size()) +
" bidi-edges for public transport stops and a total of " 952 +
toString(added) +
" bidi-edges to ensure connectivity of stops (" 953 +
toString(numDisconnected) +
" stops remain disconnected)");
957 for (
Track* t : tracks) {
969 if (!
isRailway(e.second->getPermissions())) {
972 NBNode*
const from = e.second->getFromNode();
973 NBNode*
const to = e.second->getToNode();
974 if (brokenNodes.count(from) == 0 && brokenNodes.count(to) == 0) {
977 EdgeVector inRailFrom, outRailFrom, inRailTo, outRailTo;
980 bool haveReverse =
false;
981 for (
const NBEdge* cand : outRailTo) {
982 if (cand->getToNode() == from) {
990 bool haveStraightFrom =
false;
991 for (
const NBEdge* fromStraightCand : outRailFrom) {
992 if (fromStraightCand != e.second &&
isStraight(from, fromStraightCand, e.second)) {
993 haveStraightFrom =
true;
997 if (!haveStraightFrom) {
1000 for (
const NBEdge* toStraightCand : inRailTo) {
1001 if (toStraightCand != e.second &&
isStraight(to, toStraightCand, e.second)) {
1004 if (e2 !=
nullptr) {
1014 WRITE_MESSAGE(
"Added " +
toString(added) +
" bidi-edges to ensure connectivity of straight tracks.");
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge's lanes' lateral offset is computed.
bool gDebugFlag1
global utility flags for debugging
void invalidateConnections(bool reallowSetting=false)
invalidate current connections of edge
#define SHARP_THRESHOLD_SAMEDIR
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
NBEdge * getByID(const std::string &edgeID) const
Returns the edge with id if it exists.
void close()
Closes the device and removes it from the dictionary.
static bool allBidi(const EdgeVector &edges)
static bool isStraight(const NBNode *node, const NBEdge *e1, const NBEdge *e2)
static NBEdge * addBidiEdge(NBNetBuilder &nb, NBEdge *edge, bool update=true)
add bidi-edge for the given edge
static std::set< NBNode * > getRailNodes(NBNetBuilder &nb, bool verbose=false)
std::vector< std::pair< const Track *, const Track * > > viaSuccessors
static bool allBroken(const NBNode *node, NBEdge *candOut, const EdgeVector &in, const EdgeVector &out)
std::vector< Track * > successors
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types...
const std::map< std::string, NBPTLine * > & getLines() const
static double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
static void repairTopology(NBNetBuilder &nb)
SVCPermissions minPermissions
static void addBidiEdgesForStraightConnectivity(NBNetBuilder &nb)
add bidi-edges to connect straight tracks
The representation of a single edge during network building.
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
NBEdge * getTurnDestination(bool possibleDestination=false) const
Track(NBEdge *e, int i=-1, const std::string &_id="")
static void updateTurns(NBEdge *edge)
recompute turning directions for both nodes of the given edge
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
PositionVector reverse() const
reverse position vector
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
const std::string & getID() const
Returns the id.
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
const std::vector< std::pair< const Track *, const Track * > > & getViaSuccessors(SUMOVehicleClass svc=SVC_IGNORING) const
static std::set< NBNode * > getBrokenRailNodes(NBNetBuilder &nb, bool verbose=false)
#define WRITE_WARNING(msg)
std::map< SUMOVehicleClass, std::vector< std::pair< const Track *, const Track * > > > svcViaSuccessors
static OptionsCont & getOptions()
Retrieves the options.
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter ...
const std::string & getRef() const
get line reference (not unique)
void invalidateIncomingConnections()
invalidate incoming connections
static void analyzeTopology(NBNetBuilder &nb)
Computes highway on-/off-ramps (if wished)
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
static void reverseEdges(NBNetBuilder &nb)
reverse edges sequences that are to broken nodes on both sides
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Computes the shortest path through a network using the Dijkstra algorithm.
bool writeXMLHeader(const std::string &rootElement, const std::string &schemaFile, std::map< SumoXMLAttr, std::string > attrs=std::map< SumoXMLAttr, std::string >())
Writes an XML header with optional configuration.
static void addBidiEdgesForBufferStops(NBNetBuilder &nb)
add bidi-edges to connect buffers stops in both directions
classes which drive on tracks
int getNumericalID() const
NBEdgeCont & getEdgeCont()
static void getRailEdges(const NBNode *node, EdgeVector &inEdges, EdgeVector &outEdges)
filter out rail edges among all edges of a the given node
const std::string & getID() const
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E *> &into, bool silent=false)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
Storage for edges, including some functionality operating on multiple edges.
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
static void makeAllBidi(NBNetBuilder &nb)
A vehicle as used by router.
static void addBidiEdgesForStops(NBNetBuilder &nb)
add bidi-edges to connect successive public transport stops
static bool allSharp(const NBNode *node, const EdgeVector &in, const EdgeVector &out, bool countBidiAsSharp=false)
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
static NBEdge * isBidiSwitch(const NBNode *n)
static void computeTurnDirectionsForNode(NBNode *node, bool warn)
Computes turnaround destinations for all incoming edges of the given nodes (if any) ...
std::map< SUMOVehicleClass, std::vector< Track * > > svcSuccessors
const PositionVector & getGeometry() const
Returns the geometry of the edge.
const std::map< std::string, NBPTStop * > & getStops() const
EdgeVector getAllEdges() const
return all edges
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Instance responsible for building networks.
static OutputDevice & getDevice(const std::string &name)
Returns the described OutputDevice.
void addSuccessor(Track *track)
static void addBidiEdgesBetweenSwitches(NBNetBuilder &nb)
add bidi-edges to connect switches that are approached in both directions
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
int size() const
Returns the number of edges.
alternative definition for junction
const std::vector< Track * > & getSuccessors(SUMOVehicleClass svc=SVC_IGNORING) const
const std::string getParameter(const std::string &key, const std::string &defaultValue="") const
Returns the value for a given key.
static double getTravelTimeStatic(const NBEdge *const edge, const NBVehicle *const, double)
Represents a single node (junction) during network building.
Static storage of an output device and its base (abstract) implementation.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
static bool hasStraightPair(const NBNode *node, const EdgeVector &edges, const EdgeVector &edges2)
std::vector< NBPTStop * > getStops()
NBNode * getFromNode() const
Returns the origin node of the edge.
static double getTravelTimeStatic(const Track *const track, const NBVehicle *const veh, double time)
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
#define WRITE_MESSAGE(msg)
static int extendBidiEdges(NBNetBuilder &nb)
add further bidi-edges near existing bidi-edges
NBNode * getToNode() const
Returns the destination node of the edge.
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.