61 #define MAX_SLIPLANE_LENGTH 1000
70 #define DEBUGNODEID ""
71 #define DEBUGNODEID2 ""
73 #define DEBUGCOND(obj) ((obj) != 0 && ((obj)->getID() == DEBUGNODEID || (obj)->getID() == DEBUGNODEID2))
89 NodeCont::iterator i =
myNodes.find(
id);
95 const float pos[2] = {(float)position.
x(), (float)position.
y()};
103 std::string
id = node->
getID();
104 NodeCont::iterator i =
myNodes.find(
id);
117 NodeCont::const_iterator i =
myNodes.find(
id);
127 const double extOffset = offset + POSITION_EPS;
128 const float cmin[2] = {(float)(position.
x() - extOffset), (
float)(position.
y() - extOffset)};
129 const float cmax[2] = {(float)(position.
x() + extOffset), (
float)(position.
y() + extOffset)};
130 std::set<const Named*> into;
133 for (
const Named* namedNode : into) {
177 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
178 no += (*i).second->removeSelfLoops(dc, ec, tc);
190 const double distanceThreshold = 7.;
191 const double lengthThreshold = 0.10;
193 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
195 std::map<NBNode*, EdgeVector> connectionCount;
196 const EdgeVector& outgoing = (*i).second->getOutgoingEdges();
197 for (EdgeVector::const_iterator j = outgoing.begin(); j != outgoing.end(); j++) {
198 connectionCount[(*j)->getToNode()].push_back(*j);
201 std::map<NBNode*, EdgeVector>::iterator k;
202 for (k = connectionCount.begin(); k != connectionCount.end(); k++) {
204 if ((*k).second.size() < 2) {
210 const NBEdge*
const first = ev.front();
211 EdgeVector::const_iterator jci;
212 for (jci = ev.begin() + 1; jci != ev.end(); ++jci) {
215 (relativeLengthDifference > lengthThreshold) ||
216 (fabs(first->
getSpeed() - (*jci)->getSpeed()) >= 0.01) ||
224 if (jci == ev.end()) {
225 if (removeDuplicates) {
226 for (
int ei = 1; ei < (int)ev.size(); ei++) {
240 int numRemovedEdges = 0;
242 const std::vector<std::string>& edgeNames = ec.
getAllNames();
243 for (std::vector<std::string>::const_iterator it = edgeNames.begin(); it != edgeNames.end(); ++it) {
252 if (outgoingEdges.size() != 1) {
257 if (incomingEdges.size() > 1) {
260 }
else if (incomingEdges.size() == 1) {
261 NBNode* fromNodeOfIncomingEdge = incomingEdges[0]->getFromNode();
262 NBNode* toNodeOfOutgoingEdge = outgoingEdges[0]->getToNode();
263 if (fromNodeOfIncomingEdge != toNodeOfOutgoingEdge) {
271 bool hasJunction =
false;
283 adjacentNodes.clear();
284 for (EdgeVector::const_iterator itOfOutgoings = outgoingEdgesOfToNode.begin(); itOfOutgoings != outgoingEdgesOfToNode.end(); ++itOfOutgoings) {
285 if ((*itOfOutgoings)->getToNode() != from
286 && (*itOfOutgoings)->getToNode() != to
290 adjacentNodes.insert((*itOfOutgoings)->getToNode());
292 for (EdgeVector::const_iterator itOfIncomings = incomingEdgesOfToNode.begin(); itOfIncomings != incomingEdgesOfToNode.end(); ++itOfIncomings) {
293 adjacentNodes.insert((*itOfIncomings)->getFromNode());
295 adjacentNodes.erase(to);
296 if (adjacentNodes.size() > 2) {
299 }
while (!hasJunction && eOld != e);
301 std::string warningString;
302 for (EdgeVector::iterator roadIt = road.begin(); roadIt != road.end(); ++roadIt) {
303 if (roadIt == road.begin()) {
304 warningString += (*roadIt)->
getID();
306 warningString +=
"," + (*roadIt)->getID();
309 NBNode* fromNode = (*roadIt)->getFromNode();
310 NBNode* toNode = (*roadIt)->getToNode();
311 ec.
erase(dc, *roadIt);
325 return numRemovedEdges;
332 std::vector<std::set<NBEdge*> > components;
334 std::set<std::string> edgesLeft;
335 for (std::map<std::string, NBEdge*>::const_iterator edgeIt = ec.
begin(); edgeIt != ec.
end(); ++edgeIt) {
336 edgesLeft.insert(edgeIt->first);
339 std::set<NBEdge*> toRemove;
340 int foundComponents = 0;
342 while (!edgesLeft.empty()) {
343 queue.push_back(ec.
getByID(*edgesLeft.begin()));
344 std::set<NBEdge*> component;
345 while (!queue.empty()) {
346 NBEdge*
const e = queue.back();
349 std::vector<EdgeVector> edgeLists;
354 for (std::vector<EdgeVector>::const_iterator listIt = edgeLists.begin(); listIt != edgeLists.end(); ++listIt) {
355 for (EdgeVector::const_iterator edgeIt = listIt->begin(); edgeIt != listIt->end(); ++edgeIt) {
356 std::set<std::string>::iterator leftIt = edgesLeft.find((*edgeIt)->getID());
357 if (leftIt != edgesLeft.end()) {
358 queue.push_back(*edgeIt);
359 edgesLeft.erase(leftIt);
365 std::vector<std::set<NBEdge*> >::iterator cIt;
366 for (cIt = components.begin(); cIt != components.end(); ++cIt) {
367 if (cIt->size() < component.size()) {
371 components.insert(cIt, component);
372 if ((
int)components.size() > numKeep) {
373 bool recheck =
false;
375 for (
NBEdge* e : components.back()) {
385 toRemove.insert(components.back().begin(), components.back().end());
388 std::vector<std::string> edgeIDs;
389 for (
NBEdge* e : components.back()) {
390 edgeIDs.push_back(e->getID());
394 components.pop_back();
398 for (
NBEdge* e : toRemove) {
399 NBNode*
const fromNode = e->getFromNode();
400 NBNode*
const toNode = e->getToNode();
409 if (foundComponents > 1) {
412 return toRemove.size();
418 std::set<std::string> stopEdges;
419 for (
const auto& item : sc.
getStops()) {
420 stopEdges.insert(item.second->getEdgeId());
423 int numRemovedEdges = 0;
426 for (std::string edgeID : component) {
427 if (stopEdges.count(edgeID) != 0) {
434 numRemovedEdges += (int)component.size();
435 for (std::string edgeID : component) {
451 if (numRemoved > 0) {
463 bool removeGeometryNodes) {
465 std::set<std::string> edges2keep;
466 if (removeGeometryNodes) {
468 if (oc.
isSet(
"geometry.remove.keep-edges.input-file")) {
471 if (oc.
isSet(
"geometry.remove.keep-edges.explicit")) {
472 const std::vector<std::string> edges = oc.
getStringVector(
"geometry.remove.keep-edges.explicit");
473 edges2keep.insert(edges.begin(), edges.end());
478 if (oc.
exists(
"geometry.remove.keep-ptstops") && oc.
getBool(
"geometry.remove.keep-ptstops")) {
483 std::map<NBEdge*, std::set<NBTrafficLightDefinition*> > tlsLookup;
484 for (
auto it = ec.
begin(); it != ec.
end(); it++) {
492 std::vector<NBNode*> toRemove;
493 for (
const auto& i :
myNodes) {
494 NBNode*
const current = i.second;
501 if (edges2keep.find(it_edge->getID()) != edges2keep.end()) {
511 for (
const std::pair<NBEdge*, NBEdge*>& j : current->
getEdgesToJoin()) {
513 NBEdge*
const continuation = j.second;
514 begin->append(continuation);
516 auto itTL = tlsLookup.find(continuation);
517 if (itTL != tlsLookup.end()) {
521 tlsLookup[
begin] = itTL->second;
525 ec.
extract(dc, continuation,
true);
527 toRemove.push_back(current);
530 for (
NBNode* n : toRemove) {
533 return (
int)toRemove.size();
539 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
540 (*i).second->avoidOverlap();
548 std::set<NBNode*> visited;
549 for (
const auto& i :
myNodes) {
550 if (visited.count(i.second) > 0) {
553 std::vector<NodeAndDist> toProc;
554 toProc.emplace_back(i.second, 0.);
556 while (!toProc.empty()) {
557 NBNode*
const n = toProc.back().first;
558 const double dist = toProc.back().second;
560 if (visited.count(n) > 0) {
564 bool pureRail =
true;
565 bool railAndPeds =
true;
583 const double length = e->getLoadedLength();
584 #ifdef DEBUG_JOINJUNCTIONS
586 std::cout <<
"generateNodeClusters: consider s=" << s->
getID()
587 <<
" clusterNode=" << n->
getID() <<
" edge=" << e->getID() <<
" dist=" << dist <<
" length=" << length <<
" with cluster " <<
joinNamedToString(c,
' ') <<
"\n";
591 bool railAndPeds2 =
true;
594 railAndPeds2 =
false;
605 const bool joinPedCrossings = bothCrossing && e->getPermissions() ==
SVC_PEDESTRIAN;
607 !joinPedCrossings && (
610 || (length > 3 * POSITION_EPS
613 #ifdef DEBUG_JOINJUNCTIONS
624 bool foundRail =
false;
627 if ((e2->getPermissions() & railNoTram) != 0) {
640 if (visited.find(s) != visited.end()) {
643 if (length + dist < maxDist) {
648 const double fullLength = e->getGeometry().length2D();
649 const double length2 = bothCrossing || hasTLS || trueGeomLike ? length : fullLength;
650 toProc.emplace_back(s, dist + length2);
652 toProc.emplace_back(s, 0.);
660 #ifdef DEBUG_JOINJUNCTIONS
673 if ((e->getPermissions() & ~ignored) != 0) {
674 allowedIn.push_back(e);
678 if ((e->getPermissions() & ~ignored) != 0) {
679 allowedOut.push_back(e);
682 if (allowedIn.size() > 0 && allowedOut.size() > 0) {
692 for (
const std::string& nodeID : ids) {
696 WRITE_WARNINGF(
TL(
"Ignoring join exclusion for junction '%' since it already occurred in a list of nodes to be joined."), nodeID);
708 maxIds = (int)cluster.size();
710 if ((
int)cluster.size() > maxIds) {
711 auto clusterIt = cluster.begin();
712 std::string result = prefix + *clusterIt;
713 for (
int i = 1; i < maxIds; i++) {
715 result +=
"_" + *clusterIt;
717 return result +
"_#" +
toString((
int)cluster.size() - maxIds) +
"more";
726 std::set<std::string> validCluster;
727 for (std::string nodeID : cluster) {
729 WRITE_WARNINGF(
TL(
"Ignoring join-cluster because junction '%' was already excluded from joining."), nodeID);
731 }
else if (
myJoined.count(nodeID) > 0) {
732 WRITE_WARNINGF(
TL(
"Ignoring join-cluster because junction '%' already occurred in another join-cluster."), nodeID);
736 validCluster.insert(nodeID);
738 WRITE_ERRORF(
TL(
"Unknown junction '%' in join-cluster."), nodeID);
742 if (validCluster.size() > 1) {
743 myJoined.insert(validCluster.begin(), validCluster.end());
746 WRITE_WARNINGF(
TL(
"Ignoring join-cluster '%' because it has size '%'."), node->
getID(), validCluster.size());
757 for (std::string nodeID : item.first) {
759 if (node ==
nullptr) {
762 cluster.insert(node);
765 if (cluster.size() > 1) {
778 #ifdef DEBUG_JOINJUNCTIONS
779 std::cout <<
"joinJunctions...\n";
783 std::map<const NBNode*, std::vector<NBNode*> > ptStopEnds;
785 for (
const auto& stopIt : sc.
getStops()) {
787 if (edge !=
nullptr) {
792 for (
NodeSet& cluster : cands) {
793 #ifdef DEBUG_JOINJUNCTIONS
795 for (
NBNode* n : cluster) {
802 for (NodeSet::iterator j = cluster.begin(); j != cluster.end();) {
803 NodeSet::iterator check = j;
806 cluster.erase(check);
812 if (cluster.size() < 2) {
817 if (cluster.size() < 2) {
818 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"slip lane");
822 std::string origReason;
824 bool feasible =
feasibleCluster(cluster, ptStopEnds, maxDist, origReason);
825 if (feasible && ((
int)cluster.size() -
pruneLongEdges(cluster, maxDist,
true) < 2)) {
826 origReason =
"long edge";
830 #ifdef DEBUG_JOINJUNCTIONS
832 std::cout <<
" try to reduce to 4-circle nodes=" <<
joinNamedToString(cluster,
',') <<
"\n";
838 WRITE_WARNINGF(
TL(
"Reducing junction cluster % (%)."), origCluster, origReason);
843 #ifdef DEBUG_JOINJUNCTIONS
845 std::cout <<
" try to reduce to 2-circle nodes=" <<
joinNamedToString(cluster,
',') <<
"\n";
852 WRITE_WARNINGF(
TL(
"Reducing junction cluster % (%)."), origCluster, origReason);
858 if (cluster.size() < 2) {
859 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"long edge");
865 if (cluster.size() < 2) {
866 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"long edge");
870 if (cluster.size() < 2) {
871 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"slip lane");
878 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster, origReason);
884 for (
NBNode* current : cluster) {
888 newComp.insert(current);
889 for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end();) {
890 NodeClusters::iterator check = it_comp;
892 bool connected =
false;
893 for (
NBNode* k : *check) {
894 if (current->getConnectionTo(k) !=
nullptr || k->getConnectionTo(current) !=
nullptr) {
896 newComp.insert((*check).begin(), (*check).end());
897 it_comp = components.erase(check);
907 components.push_back(newComp);
909 for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end(); ++it_comp) {
910 if ((*it_comp).size() > 1) {
912 clusters.push_back(*it_comp);
915 #ifdef DEBUG_JOINJUNCTIONS
920 return (
int)clusters.size();
926 #ifdef DEBUG_JOINJUNCTIONS
927 std::cout <<
"joinSameJunctions...\n";
929 std::map<std::string, NodeSet> positions;
931 Position pos = item.second->getPosition();
935 positions[rounded].insert(item.second);
938 for (
auto& item : positions) {
939 if (item.second.size() > 1) {
940 for (
NBNode* n : item.second) {
942 item.second.erase(n);
945 if (item.second.size() > 1) {
946 clusters.push_back(item.second);
951 return (
int)clusters.size();
956 #ifdef DEBUG_JOINJUNCTIONS
962 bool pruneFringe =
true;
963 bool pruneNoisyFringe =
false;
966 while (pruneFringe) {
968 for (NodeSet::iterator j = cluster.begin(); j != cluster.end();) {
969 NodeSet::iterator check = j;
974 double clusterDist = std::numeric_limits<double>::max();
975 bool touchingCluster =
false;
977 NBNode* neighbor = (*it_edge)->getToNode();
978 if (cluster.count(neighbor) != 0) {
979 clusterDist =
MIN2(clusterDist, (*it_edge)->getLoadedLength());
984 NBNode* neighbor = (*it_edge)->getFromNode();
985 if (cluster.count(neighbor) != 0) {
986 clusterDist =
MIN2(clusterDist, (*it_edge)->getLoadedLength());
992 std::set<NBNode*> outsideNeighbors;
993 std::set<NBNode*> clusterNeighbors;
994 const double pedestrianFringeThreshold = 0.3;
996 NBNode* neighbor = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
997 if (cluster.count(neighbor) == 0) {
1000 || (clusterDist <= pedestrianFringeThreshold
1001 && (!pruneNoisyFringe
1002 || ((e->getPermissions() &
SVC_WEAK) != 0 &&
1003 (e->getPermissions() & ~
SVC_WEAK) == 0)
1006 || cluster.size() == 2))
1007 || touchingCluster) {
1008 outsideNeighbors.insert(neighbor);
1011 clusterNeighbors.insert(neighbor);
1014 #ifdef DEBUG_JOINJUNCTIONS
1016 <<
" clusterDist=" << clusterDist
1017 <<
" cd<th=" << (clusterDist <= pedestrianFringeThreshold)
1018 <<
" touching=" << touchingCluster
1024 if (clusterNeighbors.size() == 0
1025 || (outsideNeighbors.size() <= 1
1026 && clusterNeighbors.size() == 1
1028 cluster.erase(check);
1030 #ifdef DEBUG_JOINJUNCTIONS
1032 std::cout <<
" pruned n=" << n->
getID() <<
"\n";
1037 if (!pruneFringe && !pruneNoisyFringe) {
1040 pruneNoisyFringe =
true;
1049 for (
const NBNode* n1 : cluster) {
1050 for (
const NBNode* n2 : cluster) {
1051 result =
MAX2(result, n1->getPosition().distanceTo2D(n2->getPosition()));
1059 std::set<NBNode*> toRemove;
1060 int maxPassengerLanes = 0;
1061 for (
NBNode* n : cluster) {
1062 for (
NBEdge* edge : n->getEdges()) {
1063 maxPassengerLanes =
MAX2(maxPassengerLanes, edge->getNumLanesThatAllow(
SVC_PASSENGER));
1066 for (
NBNode* n : cluster) {
1067 for (
NBEdge* edge : n->getOutgoingEdges()) {
1071 std::vector<NBNode*> passed;
1074 NBNode* to = edge->getToNode();
1075 while (cluster.count(to) != 0) {
1077 bool goStraight = (std::find(passed.begin(), passed.end(), to) == passed.end()
1082 passed.push_back(to);
1085 if (cur !=
nullptr) {
1096 #ifdef DEBUG_JOINJUNCTIONS
1098 std::cout <<
"check edge length " << edge->getID() <<
" (" << length <<
", passed=" << passed.size() <<
", max=" << longThreshold <<
")\n";
1101 if (length > longThreshold) {
1105 const bool keepStart =
getClusterNeighbors(passed.back(), longThreshold, cluster).size() == 1;
1106 const bool keepEnd = !keepStart &&
getClusterNeighbors(n, longThreshold, cluster).size() == 1;
1107 #ifdef DEBUG_JOINJUNCTIONS
1109 std::cout <<
"node=" << n->getID() <<
" long edge " << edge->getID() <<
" (" << length <<
", passed=" <<
toString(passed) <<
", max=" << longThreshold <<
") keepStart=" << keepStart <<
" keepEnd=" << keepEnd <<
"\n";
1115 toRemove.insert(passed.begin(), passed.end() - 1);
1117 toRemove.insert(passed.back());
1124 for (std::set<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
1128 return (
int)toRemove.size();
1136 if (e->getLength() > longThreshold) {
1139 NBNode* neighbor = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
1140 if (cluster.count(neighbor) != 0) {
1141 result.insert(neighbor);
1150 #ifdef DEBUG_JOINJUNCTIONS
1152 std::cout <<
"pruning slip-lanes at cluster=" <<
joinNamedToString(cluster,
' ') <<
"\n";
1156 if (cluster.size() <= 2) {
1160 for (
NBNode* n : cluster) {
1166 #ifdef DEBUG_JOINJUNCTIONS
1168 std::cout <<
" candidate slip-lane start=" << n->getID() <<
" outgoing=" <<
toString(outgoing) <<
"\n";
1171 for (
NBEdge* contEdge : outgoing) {
1175 double slipLength = contEdge->getLength();
1176 NBNode* cont = contEdge->getToNode();
1180 if (cands.count(cont) != 0) {
1184 #ifdef DEBUG_JOINJUNCTIONS
1186 std::cout <<
" candidate slip-lane cont=" << cont->
getID() <<
"\n";
1193 #ifdef DEBUG_JOINJUNCTIONS
1195 std::cout <<
" candidate slip-lane end=" << cont->
getID() <<
" slipLength=" << slipLength <<
"\n";
1202 const NBEdge*
const otherEdge = (contEdge == outgoing.front() ? outgoing.back() : outgoing.front());
1205 std::vector<NodeAndDist> toProc;
1208 while (!toProc.empty()) {
1210 NBNode* cont2 = nodeAndDist.first;
1211 double dist = nodeAndDist.second;
1212 #ifdef DEBUG_JOINJUNCTIONS
1214 std::cout <<
" search alternative cont2=" << cont2->
getID() <<
" dist=" << dist <<
"\n";
1218 if (visited.find(cont2) != visited.end()) {
1221 visited.insert(cont2);
1222 if (cont2 == cont) {
1227 const double dist2 = dist + e->getLength();
1228 if (dist2 < slipLength * 2 && (e->getPermissions() &
SVC_PASSENGER) != 0) {
1229 toProc.push_back(std::make_pair(e->getToNode(), dist2));
1236 toRemove.insert(cands.begin(), cands.end());
1237 #ifdef DEBUG_JOINJUNCTIONS
1239 std::cout <<
" found slip-lane with nodes=" <<
joinNamedToString(cands,
' ') <<
"\n";
1252 #ifdef DEBUG_JOINJUNCTIONS
1254 std::cout <<
" candidate slip-lane end=" << n->getID() <<
" incoming=" <<
toString(incoming) <<
"\n";
1257 for (
NBEdge* contEdge : incoming) {
1261 double slipLength = contEdge->getLength();
1262 NBNode* cont = contEdge->getFromNode();
1266 if (cands.count(cont) != 0) {
1270 #ifdef DEBUG_JOINJUNCTIONS
1272 std::cout <<
" candidate slip-lane cont=" << cont->
getID() <<
"\n";
1279 #ifdef DEBUG_JOINJUNCTIONS
1281 std::cout <<
" candidate slip-lane start=" << cont->
getID() <<
" slipLength=" << slipLength <<
"\n";
1288 const NBEdge*
const otherEdge = (contEdge == incoming.front() ? incoming.back() : incoming.front());
1291 std::vector<NodeAndDist> toProc;
1294 while (!toProc.empty()) {
1296 NBNode* cont2 = nodeAndDist.first;
1297 double dist = nodeAndDist.second;
1298 #ifdef DEBUG_JOINJUNCTIONS
1300 std::cout <<
" search alternative cont2=" << cont2->
getID() <<
" dist=" << dist <<
"\n";
1304 if (visited.find(cont2) != visited.end()) {
1307 visited.insert(cont2);
1308 if (cont2 == cont) {
1313 const double dist2 = dist + e->getLength();
1314 if (dist2 < slipLength * 2 && (e->getPermissions() &
SVC_PASSENGER) != 0) {
1315 toProc.push_back(std::make_pair(e->getFromNode(), dist2));
1322 toRemove.insert(cands.begin(), cands.end());
1323 #ifdef DEBUG_JOINJUNCTIONS
1325 std::cout <<
" found slip-lane start with nodes=" <<
joinNamedToString(cands,
' ') <<
"\n";
1337 for (
NBNode* n : toRemove) {
1338 numRemoved += (int)cluster.erase(n);
1340 if (numRemoved > 0) {
1341 #ifdef DEBUG_JOINJUNCTIONS
1343 std::cout <<
" removed " << numRemoved <<
" nodes from cluster: " <<
joinNamedToString(toRemove,
' ') <<
"\n";
1361 if (inPE.size() == 1 && outPE.size() == 2) {
1362 outgoing.insert(outgoing.begin(), outPE.begin(), outPE.end());
1363 inAngle = inPE.front()->getAngleAtNode(n);
1365 }
else if (inPE.size() >= 2 && outPE.size() == 3) {
1368 const double inRelAngle = fabs(
NBHelpers::relAngle(inPE.front()->getAngleAtNode(n), inPE.back()->getAngleAtNode(n)));
1370 if (inRelAngle < 135) {
1373 for (
NBEdge* in : inPE) {
1376 for (
NBEdge* out : outPE) {
1377 const double outRelAngle = fabs(
NBHelpers::relAngle(in->getAngleAtNode(n), out->getAngleAtNode(n)));
1378 if (outRelAngle <= 45) {
1379 straight.push_back(out);
1380 }
else if (outRelAngle >= 135) {
1384 if (straight.size() == 2 && numReverse == 1) {
1385 outgoing.insert(outgoing.begin(), straight.begin(), straight.end());
1386 inAngle = in->getAngleAtNode(n);
1399 if (inPE.size() == 2 && outPE.size() == 1) {
1400 incoming.insert(incoming.begin(), inPE.begin(), inPE.end());
1401 outAngle = outPE.front()->getAngleAtNode(n);
1403 }
else if (inPE.size() == 3 && outPE.size() >= 2) {
1406 const double outRelAngle = fabs(
NBHelpers::relAngle(outPE.front()->getAngleAtNode(n), outPE.back()->getAngleAtNode(n)));
1408 if (outRelAngle < 135) {
1411 for (
NBEdge* out : outPE) {
1414 for (
NBEdge* in : inPE) {
1415 const double inRelAngle = fabs(
NBHelpers::relAngle(in->getAngleAtNode(n), out->getAngleAtNode(n)));
1416 if (inRelAngle <= 45) {
1417 straight.push_back(in);
1418 }
else if (inRelAngle >= 135) {
1422 if (straight.size() == 2 && numReverse == 1) {
1423 incoming.insert(incoming.begin(), straight.begin(), straight.end());
1424 outAngle = out->getAngleAtNode(n);
1434 double maxDist, std::string& reason)
const {
1437 std::map<NBEdge*, double, ComparatorIdLess> finalIncomingAngles;
1438 std::map<NBEdge*, double, ComparatorIdLess> finalOutgoingAngles;
1439 for (
NBNode* n : cluster) {
1440 for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) {
1447 for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) {
1456 #ifdef DEBUG_JOINJUNCTIONS
1457 for (
NBNode* n : cluster) {
1466 if (finalIncomingAngles.size() > 5) {
1467 reason =
toString(finalIncomingAngles.size()) +
" incoming edges";
1471 const double PARALLEL_THRESHOLD_SAME_NODE = 10;
1472 const double PARALLEL_THRESHOLD_DIFF_NODE = 30;
1473 bool foundParallel =
false;
1474 for (
auto j = finalIncomingAngles.begin(); j != finalIncomingAngles.end() && !foundParallel; ++j) {
1476 for (++k; k != finalIncomingAngles.end() && !foundParallel; ++k) {
1477 const double angleDiff = fabs(j->second - k->second);
1478 if (angleDiff < PARALLEL_THRESHOLD_DIFF_NODE) {
1480 const double edgeDist = j->first->getLaneShape(0).back().distanceTo2D(k->first->getLaneShape(0).back());
1481 #ifdef DEBUG_JOINJUNCTIONS
1483 std::cout <<
" angleDiff=" << angleDiff <<
" shapeDist=" << edgeDist <<
"\n";
1486 if (angleDiff >= PARALLEL_THRESHOLD_SAME_NODE && (
1487 (j->first->getToNode() == k->first->getToNode()
1488 || (edgeDist < maxDist)))) {
1491 reason =
"parallel incoming " + j->first->getID() +
"," + k->first->getID();
1497 for (
auto j = finalOutgoingAngles.begin(); j != finalOutgoingAngles.end() && !foundParallel; ++j) {
1499 for (++k; k != finalOutgoingAngles.end() && !foundParallel; ++k) {
1500 const double angleDiff = fabs(j->second - k->second);
1501 if (angleDiff < PARALLEL_THRESHOLD_DIFF_NODE) {
1503 const double edgeDist = j->first->getLaneShape(0).front().distanceTo2D(k->first->getLaneShape(0).front());
1504 #ifdef DEBUG_JOINJUNCTIONS
1505 if (
DEBUGCOND(j->first->getFromNode())) {
1506 std::cout <<
" angleDiff=" << angleDiff <<
" shapeDist=" << edgeDist <<
"\n";
1509 if (angleDiff >= PARALLEL_THRESHOLD_SAME_NODE && (
1510 (j->first->getFromNode() == k->first->getFromNode()
1511 || (edgeDist < maxDist)))) {
1514 reason =
"parallel outgoing " + j->first->getID() +
"," + k->first->getID();
1520 bool hasTLS =
false;
1521 for (
NBNode* n : cluster) {
1522 if (n->isTLControlled()) {
1525 const auto& stopEnds = ptStopEnds.find(n);
1526 if (stopEnds != ptStopEnds.end()) {
1527 for (
NBNode*
const to : stopEnds->second) {
1528 if (cluster.count(to) != 0) {
1529 reason =
"it contains a pt stop edge";
1536 if (cluster.size() > 2) {
1538 double maxLength = -1;
1539 NBEdge* maxEdge =
nullptr;
1540 for (
NBNode* n1 : cluster) {
1541 for (
NBNode* n2 : cluster) {
1542 NBEdge* e1 = n1->getConnectionTo(n2);
1543 NBEdge* e2 = n2->getConnectionTo(n1);
1554 #ifdef DEBUG_JOINJUNCTIONS
1555 for (
NBNode* n : cluster) {
1557 std::cout <<
"feasible hasTLS=" << hasTLS <<
" maxLength=" << maxLength <<
" maxEdge=" << maxEdge->
getID() <<
"\n";
1561 if (!hasTLS && maxLength > 5) {
1563 std::vector<NBNode*> toCheck;
1564 std::set<NBNode*> visited;
1565 toCheck.push_back(maxEdge->
getToNode());
1566 bool foundCircle =
false;
1567 while (!toCheck.empty()) {
1568 NBNode* n = toCheck.back();
1577 NBNode* cand = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
1578 if (visited.count(cand) == 0 && cluster.count(cand) != 0) {
1579 toCheck.push_back(cand);
1585 reason =
"not compact (maxEdge=" + maxEdge->
getID() +
" length=" +
toString(maxLength) +
")";
1591 if (!hasTLS && cluster.size() >= 2) {
1594 int outsideIncoming = 0;
1595 int outsideOutgoing = 0;
1596 int edgesWithin = 0;
1597 for (
NBNode* n : cluster) {
1598 bool foundOutsideIncoming =
false;
1600 if (cluster.count(e->getFromNode()) == 0) {
1603 foundOutsideIncoming =
true;
1608 if (foundOutsideIncoming) {
1611 bool foundOutsideOutgoing =
false;
1612 for (
NBEdge* e : n->getOutgoingEdges()) {
1613 if (cluster.count(e->getToNode()) == 0) {
1616 foundOutsideOutgoing =
true;
1619 if (foundOutsideOutgoing) {
1623 if (entryNodes < 2) {
1624 reason =
"only 1 entry node";
1627 if (exitNodes < 2) {
1628 reason =
"only 1 exit node";
1631 if (cluster.size() == 2) {
1632 if (edgesWithin == 1 && outsideIncoming < 3 && outsideOutgoing < 3) {
1633 reason =
"only 1 edge within and no cross-traffic";
1645 assert(circleSize >= 2);
1646 if ((
int)cands.size() == circleSize) {
1647 if (cands.back()->getConnectionTo(cands.front()) !=
nullptr) {
1650 candCluster.insert(cands.begin(), cands.end());
1652 const bool feasible = (int)candCluster.size() == circleSize;
1655 cluster.insert(cands.begin(), cands.end());
1662 if ((
int)cluster.size() <= circleSize || startNodes.size() == 0) {
1667 if (cands.size() == 0) {
1673 if (
reduceToCircle(cluster, circleSize, startNodes, maxDist, cands)) {
1682 singleStart.insert(cands.back());
1685 std::vector<NBNode*> cands2(cands);
1687 if (
reduceToCircle(cluster, circleSize, startNodes, maxDist, cands2)) {
1699 double minDist = std::numeric_limits<double>::max();
1700 NBEdge* result =
nullptr;
1701 for (
NBNode* n : startNodes) {
1702 for (
NBEdge* e : n->getOutgoingEdges()) {
1703 NBNode* neigh = e->getToNode();
1704 if (cluster.count(neigh) != 0 && std::find(exclude.begin(), exclude.end(), neigh) == exclude.end()) {
1707 if (dist < minDist) {
1721 for (
NodeSet cluster : clusters) {
1730 assert(cluster.size() > 1);
1731 std::string
id =
"cluster_";
1737 std::set<NBEdge*, ComparatorIdLess> allEdges;
1738 for (
NBNode* n : cluster) {
1740 allEdges.insert(edges.begin(), edges.end());
1743 std::set<NBEdge*, ComparatorIdLess> clusterIncoming;
1744 std::set<NBEdge*, ComparatorIdLess> inside;
1745 for (
NBEdge* e : allEdges) {
1746 if (cluster.count(e->getToNode()) > 0) {
1747 if (cluster.count(e->getFromNode()) > 0) {
1754 clusterIncoming.insert(e);
1758 #ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1760 <<
" resetConnections=" << resetConnections <<
"\n"
1765 NBNode* newNode =
nullptr;
1766 if (predefined !=
nullptr) {
1767 newNode = predefined;
1776 std::string tlID = id;
1777 if (predefined !=
nullptr) {
1779 nodeType = predefined->
getType();
1792 newNode->
reinit(pos, nodeType);
1798 if (!tlc.
insert(tlDef)) {
1806 std::map<NBEdge*, EdgeSet> reachable;
1807 std::map<std::pair<NBEdge*, NBEdge*>,
SVCPermissions> conPermissions;
1809 for (
NBEdge*
const e : clusterIncoming) {
1813 while (open.size() > 0) {
1814 NBEdge*
const cur = open.back();
1816 #ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1817 std::cout <<
"e=" << e->getID() <<
" cur=" << cur->
getID() <<
" open=" <<
toString(open) <<
"\n";
1818 std::cout <<
"e=" << e->getID() <<
" cur=" << cur->
getID() <<
" open=" <<
toString(open) <<
"\n";
1822 if (cluster.count(cur->
getToNode()) == 0) {
1830 if (allEdges.count(out) != 0) {
1832 if (seen.count(out) == 0 || (~conPermissions[ {e, out}] & p) != 0) {
1834 open.push_back(out);
1835 conPermissions[ {e, out}] |= p;
1836 #ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1845 for (
const auto& con : cons) {
1846 if (con.toEdge !=
nullptr && allEdges.count(con.toEdge) != 0) {
1849 p &= con.permissions;
1851 if (seen.count(con.toEdge) == 0 || (~conPermissions[ {e, con.toEdge}] & p) != 0) {
1852 open.push_back(con.toEdge);
1853 conPermissions[ {e, con.toEdge}] |= p;
1861 for (
NBEdge* reached : seen) {
1863 if (inside.count(reached) == 0) {
1868 reachable[e].insert(reached);
1869 const SVCPermissions pDefault = e->getPermissions() & reached->getPermissions();
1870 if (conPermissions[ {e, reached}] != pDefault) {
1871 specialPermissions.insert(e);
1872 #ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1873 std::cout <<
"e=" << e->getID() <<
" out=" << reached->getID() <<
" special=" <<
getVehicleClassNames(conPermissions[ {e, reached}]) <<
"\n";
1878 #ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1879 std::cout <<
" reachable e=" << e->getID() <<
" seen=" <<
toString(seen) <<
" reachable=" <<
toString(reachable[e]) <<
"\n";
1887 for (
NBEdge* e : inside) {
1888 for (
NBEdge* e2 : allEdges) {
1890 e2->replaceInConnections(e, e->getConnections());
1898 for (
NBEdge* e : allEdges) {
1899 const bool outgoing = cluster.count(e->getFromNode()) > 0;
1900 NBNode* from = outgoing ? newNode : e->getFromNode();
1901 NBNode* to = outgoing ? e->getToNode() : newNode;
1904 e->
setParameter(
"origFrom", e->getFromNode()->getID());
1906 e->setParameter(
"origTo", e->getToNode()->getID());
1909 if (e->getTurnSignTarget() !=
"") {
1910 for (
NBNode* n : cluster) {
1911 if (e->getTurnSignTarget() == n->getID()) {
1912 e->setTurnSignTarget(to->
getID());
1917 e->reinitNodes(from, to);
1920 std::vector<NBEdge::Connection> conns = e->getConnections();
1921 for (std::vector<NBEdge::Connection>::iterator k = conns.begin(); k != conns.end(); ++k) {
1922 if ((*k).toEdge ==
nullptr) {
1927 if ((*k).fromLane >= 0 && (*k).fromLane < e->getNumLanes() && e->getLaneStruct((*k).fromLane).connectionsDone) {
1930 #ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1931 std::cout <<
" e=" << e->getID() <<
" declareConnectionsAsLoaded\n";
1936 if (!resetConnections) {
1941 if (reachable[in].count(out) == 0) {
1944 in->removeFromConnections(out, -1, -1,
true,
false,
true);
1948 }
else if (specialPermissions.count(in) != 0) {
1949 SVCPermissions pDefault = in->getPermissions() & out->getPermissions();
1950 SVCPermissions p = conPermissions[ {in, out}] == 0 ? pDefault : conPermissions[ {in, out}];
1951 in->addEdge2EdgeConnection(out,
true, p == pDefault ?
SVC_UNSPECIFIED : p);
1958 in->invalidateConnections(
true);
1964 for (
NBNode* n : cluster) {
1972 std::set<std::string> ids;
1973 for (
NBNode* n : cluster) {
1974 ids.insert(n->getID());
1997 bool ambiguousType =
false;
1998 for (
NBNode* j : cluster) {
1999 pos.
add(j->getPosition());
2001 if (j->isTLControlled()) {
2004 type = (*j->getControllingTLS().begin())->getType();
2005 }
else if (type != (*j->getControllingTLS().begin())->getType()) {
2006 ambiguousType =
true;
2012 nodeType = otherType;
2013 }
else if (nodeType != otherType) {
2025 pos.
mul(1. / (
double)cluster.size());
2026 if (ambiguousType) {
2036 bool tooFast =
false;
2037 double laneSpeedSum = 0;
2038 std::set<NBEdge*> seen;
2040 for (
const NBEdge* e : j->getEdges()) {
2041 if (c.find(e->getFromNode()) != c.end() && c.find(e->getToNode()) != c.end()) {
2045 if (j->hasIncoming(e)) {
2046 if (recheck && !j->hasConflict(e)) {
2051 laneSpeedSum += (double)e->getNumLanes() * e->getLaneSpeed(0);
2053 if (e->getLaneSpeed(0) * 3.6 > 79) {
2059 return !tooFast && laneSpeedSum >= laneSpeedThreshold && c.size() != 0;
2071 nonPedIncoming.push_back(e);
2074 for (
NBEdge* e : node->getOutgoingEdges()) {
2076 nonPedOutgoing.push_back(e);
2079 if (!node->geometryLike(nonPedIncoming, nonPedOutgoing)) {
2095 if (node->isTLControlled()) {
2101 const std::string tlID = tl->
getID();
2102 if (tlID != node->getID()
2118 const double laneSpeedThreshold = oc.
getFloat(
"tls.guess.threshold");
2119 if (oc.
isSet(
"tls.unset")) {
2120 std::vector<std::string> notTLControlledNodes = oc.
getStringVector(
"tls.unset");
2121 for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) {
2124 throw ProcessError(
TLF(
" The junction '%' to set as not-controlled is not known.", *i));
2127 for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) {
2128 (*j)->removeNode(n);
2138 if (oc.
exists(
"tls.taz-nodes") && oc.
getBool(
"tls.taz-nodes")) {
2139 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2140 NBNode* cur = (*i).second;
2149 if (oc.
exists(
"tls.guess-signals") && oc.
getBool(
"tls.guess-signals")) {
2151 const double signalDist = oc.
getFloat(
"tls.guess-signals.dist");
2152 for (
const auto& item :
myNodes) {
2153 const NBNode* node = item.second;
2155 #ifdef DEBUG_GUESSSIGNALS
2157 std::cout <<
" propagate TLS from " << node->
getID() <<
" downstream\n";
2163 edge->setSignalPosition(node->
getPosition(), node);
2168 std::set<NBEdge*> seen;
2169 std::set<NBEdge*> check;
2170 for (
const auto& item :
myNodes) {
2171 for (
NBEdge* edge : item.second->getOutgoingEdges()) {
2175 #ifdef DEBUG_GUESSSIGNALS
2176 if (
DEBUGCOND(edge->getSignalNode()) ||
true) {
2177 std::cout <<
" primary signalPosition edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2184 while (check.size() > 0) {
2185 NBEdge*
const edge = *check.begin();
2186 check.erase(check.begin());
2191 if (seen.count(outEdge) == 0) {
2193 #ifdef DEBUG_GUESSSIGNALS
2195 std::cout <<
" setSignalPosition edge=" << outEdge->
getID() <<
" pos=" << edge->
getSignalPosition() <<
"\n";
2198 check.insert(outEdge);
2205 const int slack = oc.
getInt(
"tls.guess-signals.slack");
2206 for (std::map<std::string, NBNode*>::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2207 NBNode* node = i->second;
2216 std::vector<const NBNode*> signals;
2217 int foundSignals = 0;
2218 int missingSignals = 0;
2220 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2221 const NBEdge* inEdge = *it_i;
2224 #ifdef DEBUG_GUESSSIGNALS
2226 std::cout <<
" noTLS, edge=" << inEdge->
getID() <<
"\n";
2230 if (missingSignals > slack) {
2239 int foundSignalsAtDist = 0;
2240 if (foundSignals > 1 && missingSignals <= slack && missingSignals < foundSignals) {
2244 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2245 const NBEdge* inEdge = *it_i;
2248 #ifdef DEBUG_GUESSSIGNALS
2254 if (missingSignals > slack) {
2259 foundSignalsAtDist++;
2262 if (signal !=
nullptr) {
2263 signals.push_back(signal);
2268 for (
const NBEdge* outEdge : outgoing) {
2269 NBNode* cand = outEdge->getToNode();
2271 #ifdef DEBUG_GUESSSIGNALS
2273 std::cout <<
" node=" << node->
getID() <<
" outEdge=" << outEdge->getID() <<
" signalNode=" << cand->
getID() <<
" len=" << outEdge->getLength() <<
"\n";
2276 signals.push_back(cand);
2280 if (foundSignalsAtDist > 1 && missingSignals <= slack && missingSignals < foundSignalsAtDist) {
2281 for (
const NBNode* s : signals) {
2282 std::set<NBTrafficLightDefinition*> tls = s->getControllingTLS();
2284 for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
2291 if (!tlc.
insert(tlDef)) {
2303 if (oc.
getBool(
"tls.guess.joining")) {
2308 for (NodeClusters::iterator i = cands.begin(); i != cands.end();) {
2312 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2313 if ((*j)->isTLControlled() ||
myUnsetTLS.count(*j) != 0) {
2328 for (
auto nodeSet : cands) {
2329 std::vector<NBNode*> nodes;
2330 for (
NBNode* node : nodeSet) {
2331 nodes.push_back(node);
2336 if (!tlc.
insert(tlDef)) {
2346 if (oc.
getBool(
"tls.guess")) {
2347 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2348 NBNode* cur = (*i).second;
2371 std::set<NBTrafficLightDefinition*> recompute;
2374 const std::set<NBTrafficLightDefinition*>& tlDefs = node->getControllingTLS();
2375 recompute.insert(tlDefs.begin(), tlDefs.end());
2376 node->removeTrafficLights(
true);
2378 edge->clearControllingTLInformation();
2383 if (def->getNodes().size() == 0) {
2386 def->setParticipantsInformation();
2387 def->setTLControllingInformation();
2412 for (
const auto& item :
myNodes) {
2413 item.second->computeKeepClear();
2421 for (
const std::string& tlsID : excludeList) {
2422 if (!tlc.
exist(tlsID,
false)) {
2423 WRITE_WARNINGF(
"Unknown tls ID '%' in option tls.join-exclude", tlsID);
2426 std::set<std::string> exclude(excludeList.begin(), excludeList.end());
2430 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2431 if (!(*j)->isTLControlled() || exclude.count((*(*j)->getControllingTLS().begin())->getID()) != 0) {
2442 bool dummySetTL =
false;
2443 std::string
id =
"joinedS_";
2448 std::set<NBTrafficLightDefinition*> tls = j->getControllingTLS();
2449 j->removeTrafficLights();
2454 std::vector<NBNode*> nodes;
2459 if (!tlc.
insert(tlDef)) {
2476 if (!tlc.
insert(tlDef)) {
2478 WRITE_WARNINGF(
TL(
"Building a tl-logic for junction '%' twice is not possible."),
id);
2488 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2489 (*i).second->computeLanes2Lanes();
2497 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2498 (*i).second->computeLogic(ec);
2505 std::set<NBNode*> roundaboutNodes;
2506 const bool checkLaneFoesAll = oc.
getBool(
"check-lane-foes.all");
2507 const bool checkLaneFoesRoundabout = !checkLaneFoesAll && oc.
getBool(
"check-lane-foes.roundabout");
2508 if (checkLaneFoesRoundabout) {
2510 for (std::set<EdgeSet>::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
2511 for (EdgeSet::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
2512 roundaboutNodes.insert((*j)->getToNode());
2516 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2517 const bool checkLaneFoes = checkLaneFoesAll || (checkLaneFoesRoundabout && roundaboutNodes.count((*i).second) > 0);
2518 (*i).second->computeLogic2(checkLaneFoes);
2525 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2526 delete ((*i).second);
2539 std::string freeID =
"SUMOGenerated" + toString<int>(counter);
2541 while (
retrieve(freeID) !=
nullptr) {
2544 freeID =
"SUMOGenerated" + toString<int>(counter);
2552 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2553 (*i).second->computeNodeShape(mismatchThreshold);
2560 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2563 int numUnregulatedJunctions = 0;
2564 int numDeadEndJunctions = 0;
2565 int numTrafficLightJunctions = 0;
2566 int numPriorityJunctions = 0;
2567 int numRightBeforeLeftJunctions = 0;
2568 int numLeftBeforeRightJunctions = 0;
2569 int numAllWayStopJunctions = 0;
2570 int numZipperJunctions = 0;
2571 int numDistrictJunctions = 0;
2572 int numRailCrossing = 0;
2573 int numRailSignals = 0;
2574 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2575 switch ((*i).second->getType()) {
2577 ++numUnregulatedJunctions;
2580 ++numDeadEndJunctions;
2585 ++numTrafficLightJunctions;
2589 ++numPriorityJunctions;
2592 ++numRightBeforeLeftJunctions;
2595 ++numLeftBeforeRightJunctions;
2598 ++numAllWayStopJunctions;
2601 ++numZipperJunctions;
2604 ++numDistrictJunctions;
2621 if (numDeadEndJunctions > 0) {
2626 if (numLeftBeforeRightJunctions > 0) {
2629 if (numTrafficLightJunctions > 0) {
2632 if (numAllWayStopJunctions > 0) {
2635 if (numZipperJunctions > 0) {
2638 if (numRailCrossing > 0) {
2641 if (numRailSignals > 0) {
2644 if (numDistrictJunctions > 0) {
2652 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2656 std::vector<std::string>
2658 std::vector<std::string> ret;
2659 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2660 ret.push_back((*i).first);
2669 const auto nodeContainerCopy =
myNodes;
2671 for (
const auto& node : nodeContainerCopy) {
2672 node.second->setID(prefix + node.second->getID());
2673 myNodes[node.second->getID()] = node.second;
2680 if (
myNodes.count(newID) != 0) {
2681 throw ProcessError(
TLF(
"Attempt to rename node using existing id '%'", newID));
2691 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2692 NBNode* node = i->second;
2696 if (geometryLike && (*tldefs.begin())->getNodes().size() > 1) {
2703 edge->setSignalPosition(node->
getPosition(),
nullptr);
2704 #ifdef DEBUG_GUESSSIGNALS
2705 std::cout <<
" discard-simple " << node->
getID() <<
" edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2709 for (std::set<NBTrafficLightDefinition*>::const_iterator it = tldefs.begin(); it != tldefs.end(); ++it) {
2724 NBNode* node = item.second;
2735 if (!numericaIDs && !reservedIDs && prefix ==
"" && !startGiven) {
2738 std::vector<std::string> avoid;
2744 std::set<std::string> reserve;
2748 avoid.insert(avoid.end(), reserve.begin(), reserve.end());
2752 for (NodeCont::iterator it =
myNodes.begin(); it !=
myNodes.end(); it++) {
2754 toChange.insert(it->second);
2761 toChange.insert(it->second);
2764 if (reservedIDs && reserve.count(it->first) > 0) {
2765 toChange.insert(it->second);
2769 for (
NBNode* node : toChange) {
2772 for (
NBNode* node : toChange) {
2776 node->setID(idSupplier.
getNext());
2778 tlc.
rename(tlDef, node->getID());
2780 myNodes[node->getID()] = node;
2782 if (prefix.empty()) {
2783 return (
int)toChange.size();
2788 for (
auto item : oldNodes) {
2790 rename(item.second, prefix + item.first);
2793 tlc.
rename(tlDef, prefix + tlDef->getID());
2811 for (
const auto& item :
myNodes) {
2814 paretoCheck(item.second, bottomRightFront, 1, -1);
2815 paretoCheck(item.second, bottomLeftFront, -1, -1);
2818 front.insert(topRightFront.begin(), topRightFront.end());
2819 front.insert(topLeftFront.begin(), topLeftFront.end());
2820 front.insert(bottomRightFront.begin(), bottomRightFront.end());
2821 front.insert(bottomLeftFront.begin(), bottomLeftFront.end());
2823 for (
NBNode* n : front) {
2824 const int in = (int)n->getIncomingEdges().size();
2825 const int out = (int)n->getOutgoingEdges().size();
2826 if ((in <= 1 && out <= 1) &&
2827 (in == 0 || out == 0
2828 || n->getIncomingEdges().front()->isTurningDirectionAt(n->getOutgoingEdges().front()))) {
2835 for (
const auto& item :
myNodes) {
2837 if (front.count(n) != 0) {
2840 if (n->
getEdges().size() == 1 && n->
getEdges().front()->getSpeed() > speedThreshold) {
2853 std::vector<NBNode*> dominated;
2855 const double x2 =
fn->getPosition().x() * xSign;
2856 const double y2 =
fn->getPosition().y() * ySign;
2857 if (x2 >= x && y2 >= y) {
2859 }
else if (x2 <= x && y2 <= y) {
2860 dominated.push_back(
fn);
2863 frontier.insert(node);
2864 for (
NBNode* r : dominated) {
2872 for (
const auto& item :
myNodes) {
2875 bool hasNEMA =
false;
2893 bool hadShapes =
false;
2894 for (
const auto& item :
myNodes) {
2895 if (item.second->getShape().size() > 0 && !item.second->hasCustomShape()) {
2897 item.second->resetShape();
#define WRITE_WARNINGF(...)
#define WRITE_MESSAGEF(...)
#define WRITE_ERRORF(...)
#define WRITE_MESSAGE(msg)
#define WRITE_WARNING(msg)
std::set< NBNode *, ComparatorIdLess > NodeSet
std::set< NBEdge * > EdgeSet
container for unique edges
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
#define MAX_SLIPLANE_LENGTH
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
const SVCPermissions SVC_UNSPECIFIED
permissions not specified
bool isWaterway(SVCPermissions permissions)
Returns whether an edge with the given permission is a waterway edge.
const std::string & getVehicleClassNames(SVCPermissions permissions, bool expand)
Returns the ids of the given classes, divided using a ' '.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_DELIVERY
vehicle is a small delivery vehicle
@ SVC_TRAM
vehicle is a light rail
@ SVC_PEDESTRIAN
pedestrian
const std::string SUMO_PARAM_ORIGID
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
@ TRAFFIC_LIGHT_RIGHT_ON_RED
@ TRAFFIC_LIGHT_NOJUNCTION
int gPrecision
the precision for floating point outputs
bool gDebugFlag1
global utility flags for debugging
const double SUMO_const_laneWidth
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
static methods for processing the coordinates conversion for the current net
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
const Boundary & getOrigBoundary() const
Returns the original boundary.
const Position getOffsetBase() const
Returns the network base.
const Boundary & getConvBoundary() const
Returns the converted boundary.
std::string getNext()
Returns the next id.
A container for districts.
A class representing a single district.
Storage for edges, including some functionality operating on multiple edges.
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
NBEdge * getByID(const std::string &edgeID) const
Returns the edge with id if it exists.
const std::set< EdgeSet > getRoundabouts() const
Returns the determined roundabouts.
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
void extract(NBDistrictCont &dc, NBEdge *edge, bool remember=false)
Removes the given edge from the container like erase but does not delete it.
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
bool hasPostProcessConnection(const std::string &from, const std::string &to="")
add post process connections
void removeRoundaboutEdges(const EdgeSet &toRemove)
remove edges from all stored roundabouts
void joinSameNodeConnectingEdges(NBDistrictCont &dc, NBTrafficLightLogicCont &tlc, EdgeVector edges)
Joins the given edges because they connect the same nodes.
std::vector< std::string > getAllNames() const
Returns all ids of known edges.
The representation of a single edge during network building.
double getLength() const
Returns the computed length of the edge.
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
static EdgeVector filterByPermissions(const EdgeVector &edges, SVCPermissions permissions)
return only those edges that permit at least one of the give permissions
const Position & getSignalPosition() const
Returns the position of a traffic signal on this edge.
EdgeBuildingStep getStep() const
The building step of this edge.
NBEdge * getStraightContinuation(SVCPermissions permissions) const
return the straightest follower edge for the given permissions or nullptr (never returns turn-arounds...
const NBNode * getSignalNode() const
Returns the node that (possibly) represents a traffic signal controlling at the end of this edge.
const std::string & getID() const
bool isNearEnough2BeJoined2(NBEdge *e, double threshold) const
Check if edge is near enought to be joined to another edge.
NBNode * getToNode() const
Returns the destination node of the edge.
@ INIT
The edge has been loaded, nothing is computed yet.
double getSpeed() const
Returns the speed allowed on this edge.
static const double UNSPECIFIED_SIGNAL_OFFSET
unspecified signal offset
@ USER
The connection was given by the user.
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
double getSignalOffset() const
Returns the offset of a traffic signal from the end of this edge.
const std::vector< Connection > & getConnections() const
Returns the connections.
NBNode * getFromNode() const
Returns the origin node of the edge.
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
static void loadPrefixedIDsFomFile(const std::string &file, const std::string prefix, std::set< std::string > &into)
Add prefixed ids defined in file.
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
static void loadEdgesFromFile(const std::string &file, std::set< std::string > &into)
Add edge ids defined in file (either ID or edge:ID per line) into the given set.
void clear()
deletes all nodes
std::set< std::string > myJoinExclusions
set of node ids which should not be joined
std::vector< std::vector< std::string > > myRailComponents
network components that must be removed if not connected to the road network via stop access
void pruneClusterFringe(NodeSet &cluster, double maxDist) const
remove geometry-like fringe nodes from cluster
static double getDiameter(const NodeSet &cluster)
compute the maximum distance between any two cluster nodes
NamedRTree myRTree
node positions for faster lookup
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
void avoidOverlap()
fix overlap
int removeRailComponents(NBDistrictCont &dc, NBEdgeCont &ec, NBPTStopCont &sc)
bool onlyCrossings(const NodeSet &c) const
check wheter the set of nodes only contains pedestrian crossings
std::vector< std::pair< std::set< std::string >, NBNode * > > myClusters2Join
loaded sets of node ids to join (cleared after use)
std::string createClusterId(const NodeSet &cluster, const std::string &prefix="cluster_")
generate id from cluster node ids
void recheckGuessedTLS(NBTrafficLightLogicCont &tlc)
recheck myGuessedTLS after node logics are computed
std::vector< NodeSet > NodeClusters
Definition of a node cluster container.
void computeKeepClear()
compute keepClear status for all connections
NodeCont myNodes
The map of names to nodes.
bool reduceToCircle(NodeSet &cluster, int circleSize, NodeSet startNodes, double maxDist, std::vector< NBNode * > cands=std::vector< NBNode * >()) const
try to find a joinable subset (recursively)
bool feasibleCluster(const NodeSet &cluster, const std::map< const NBNode *, std::vector< NBNode * > > &ptStopEnds, double maxDist, std::string &reason) const
determine wether the cluster is not too complex for joining
void registerJoinedCluster(const NodeSet &cluster)
gets all joined clusters (see doc for myClusters2Join)
std::string getFreeID()
generates a new node ID
int removeSelfLoops(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tc)
Removes self-loop edges (edges where the source and the destination node are the same)
bool recheckTLSThreshold(NBNode *node)
check whether a specific guessed tls should keep its type
void paretoCheck(NBNode *node, NodeSet &frontier, int xSign, int ySign)
update pareto frontier with the given node
bool maybeSlipLaneStart(const NBNode *n, EdgeVector &outgoing, double &inAngle) const
check whether the given node maybe the start of a slip lane
void addJoinExclusion(const std::vector< std::string > &ids)
bool erase(NBNode *node)
Removes the given node, deleting it.
int joinLoadedClusters(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
Joins loaded junction clusters (see NIXMLNodesHandler)
static bool geometryLikeForClass(const NBNode *n, SVCPermissions permissions)
check whether the node is geometryLike when only considering edges that support the given permissions
void applyConditionalDefaults()
apply default values after loading
void pruneSlipLaneNodes(NodeSet &cluster, double maxDist) const
remove nodes that form a slip lane from cluster
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
std::set< const NBNode * > myUnsetTLS
nodes that are excluded from tls-guessing
int remapIDs(bool numericaIDs, bool reservedIDs, const std::string &prefix, NBTrafficLightLogicCont &tlc)
remap node IDs according to options –numerical-ids and –reserved-ids
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
NodeCont myExtractedNodes
The extracted nodes which are kept for reference.
void joinTLS(NBTrafficLightLogicCont &tlc, double maxdist)
Builds clusters of tls-controlled junctions and joins the control if possible.
int removeUnwishedNodes(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, NBPTStopCont &sc, NBPTLineCont &lc, NBParkingCont &pc, bool removeGeometryNodes)
Removes "unwished" nodes.
bool extract(NBNode *node, bool remember=false)
Removes the given node but does not delete it.
int removeComponents(NBDistrictCont &dc, NBEdgeCont &ec, const int numKeep, bool hasPTStops)
Checks the network for weak connectivity and removes all but the largest components....
std::vector< std::string > getAllNames() const
get all node names
void computeLogics2(const NBEdgeCont &ec, OptionsCont &oc)
compute right-of-way logic for all lane-to-lane connections
bool shouldBeTLSControlled(const NodeSet &c, double laneSpeedThreshold, bool recheck=false) const
Returns whethe the given node cluster should be controlled by a tls.
void rename(NBNode *node, const std::string &newID)
Renames the node. Throws exception if newID already exists.
void joinSimilarEdges(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, bool removeDuplicates)
Joins edges connecting the same nodes.
int removeIsolatedRoads(NBDistrictCont &dc, NBEdgeCont &ec)
Removes sequences of edges that are not connected with a junction. Simple roads without junctions som...
void joinNodeClusters(NodeClusters clusters, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, bool resetConnections=false)
joins the given node clusters
void discardRailSignals()
discards rail signals
void addPrefix(const std::string &prefix)
add prefix to all nodes
void printBuiltNodesStatistics() const
Prints statistics about built nodes.
void setAsTLControlled(NBNode *node, NBTrafficLightLogicCont &tlc, TrafficLightType type, std::string id="")
Sets the given node as being controlled by a tls.
std::set< const NBNode * > mySplit
nodes that were created when splitting an edge
static NodeSet getClusterNeighbors(const NBNode *n, double longThreshold, NodeSet &cluster)
return all cluster neighbors for the given node
void computeLogics(const NBEdgeCont &ec)
build the list of outgoing edges and lanes
void joinNodeCluster(NodeSet clusters, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, NBNode *predefined=nullptr, bool resetConnections=false)
void unregisterJoinedCluster(const std::set< std::string > &cluster)
remove cluster from list (on netedit-undo)
void generateNodeClusters(double maxDist, NodeClusters &into) const
Builds node clusters.
static bool isSlipLaneContinuation(const NBNode *cont)
whether the given node may continue a slip lane
void computeNodeShapes(double mismatchThreshold=-1)
Compute the junction shape for this node.
std::vector< std::set< std::string > > myJoinedClusters
sets of node ids which were joined
NBEdge * shortestEdge(const NodeSet &cluster, const NodeSet &startNodes, const std::vector< NBNode * > &exclude) const
find closest neighbor for building circle
std::pair< NBNode *, double > NodeAndDist
void guessTLs(OptionsCont &oc, NBTrafficLightLogicCont &tlc)
Guesses which junctions or junction clusters shall be controlled by tls.
int guessFringe()
guess and mark fringe nodes
int joinJunctions(double maxDist, NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc, NBPTStopCont &sc)
Joins junctions that are very close together.
void computeLanes2Lanes()
divides the incoming lanes on outgoing lanes
void discardTrafficLights(NBTrafficLightLogicCont &tlc, bool geometryLike, bool guessSignals)
std::set< NBNode *, ComparatorIdLess > myGuessedTLS
nodes that received a traffic light due to guessing (–tls.guess)
std::set< std::string > myJoined
ids found in loaded join clusters used for error checking
int joinSameJunctions(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tlc)
Joins junctions with the same coordinates regardless of topology.
void analyzeCluster(NodeSet cluster, std::string &id, Position &pos, bool &hasTLS, TrafficLightType &type, SumoXMLNodeType &nodeType)
void addCluster2Join(const std::set< std::string > &cluster, NBNode *node)
add ids of nodes which shall be joined into a single node
bool customTLID(const NodeSet &c) const
check wheter the set of nodes contains traffic lights with custom id
bool resetNodeShapes()
reset all node shapes
static int pruneLongEdges(NodeSet &cluster, double maxDist, const bool dryRun=false)
avoid removal of long edges when joining junction clusters
bool maybeSlipLaneEnd(const NBNode *n, EdgeVector &incoming, double &outAngle) const
check whether the given node maybe the end of a slip lane
Represents a single node (junction) during network building.
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
RightOfWay getRightOfWay() const
Returns hint on how to compute right of way.
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
SumoXMLNodeType getType() const
Returns the type of this node.
void setRightOfWay(RightOfWay rightOfWay)
set method for computing right-of-way
static bool isTrafficLight(SumoXMLNodeType type)
return whether the given type is a traffic light
std::vector< std::pair< NBEdge *, NBEdge * > > getEdgesToJoin() const
get edges to join
void removeTrafficLights(bool setAsPriority=false)
Removes all references to traffic lights that control this tls.
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
void replaceIncoming(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurrences of the first edge within the list of incoming by the second Connections are rema...
EdgeVector getPassengerEdges(bool incoming) const
return edges that permit passengers (either incoming or outgoing)
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node (The set of tls that control this node)
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
void updateSurroundingGeometry()
update geometry of node and surrounding edges
const Position & getPosition() const
bool checkIsRemovable() const
check if node is removable
void setFringeType(FringeType fringeType)
set method for computing right-of-way
bool geometryLike() const
whether this is structurally similar to a geometry node
bool isNearDistrict() const
@chech if node is near district
bool isTLControlled() const
Returns whether this node is controlled by any tls.
static bool isRailwayNode(const NBNode *n)
whether the given node only has rail edges
A traffic light logics which must be computed (only nodes/edges are given)
void replaceEdge(const std::string &edgeID, const EdgeVector &replacement)
replace the edge with the given edge list in all lines
Container for public transport stops during the net building process.
void replaceEdge(const std::string &edgeID, const std::vector< NBEdge * > &replacement)
replace the edge with the closes edge on the given edge list in all stops
const std::map< std::string, std::shared_ptr< NBPTStop > > & getStops() const
Returns an unmodifiable reference to the stored pt stops.
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
The base class for traffic light logic definitions.
const std::vector< NBNode * > & getNodes() const
Returns the list of controlled nodes.
virtual void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)=0
Replaces a removed edge/lane.
A container for traffic light definitions and built programs.
bool exist(const std::string &newID, bool requireComputed=true) const
check if exists a definition with the given ID
void rename(NBTrafficLightDefinition *tlDef, const std::string &newID)
rename traffic light
bool computeSingleLogic(OptionsCont &oc, NBTrafficLightDefinition *def)
Computes a specific traffic light logic (using by netedit)
bool removeFully(const std::string id)
Removes a logic definition (and all programs) from the dictionary.
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
void extract(NBTrafficLightDefinition *definition)
Extracts a traffic light definition from myDefinitions but keeps it in myExtracted for eventual * del...
Allows to store the object; used as context while traveling the rtree in TraCI.
Base class for objects which have an id.
virtual void setID(const std::string &newID)
resets the id
const std::string & getID() const
Returns the id.
void Remove(const float a_min[2], const float a_max[2], Named *const &a_data)
Remove entry.
void Insert(const float a_min[2], const float a_max[2], Named *const &a_data)
Insert entry.
int Search(const float a_min[2], const float a_max[2], const Named::StoringVisitor &c) const
Find all within search rectangle.
A storage for options typed value containers)
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
bool exists(const std::string &name) const
Returns the information whether the named option is known.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
static std::string realString(const double v, const int precision=gPrecision)
Helper method for string formatting.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
A point in 2D or 3D with translation and scaling methods.
void setx(double x)
set position x
static const Position INVALID
used to indicate that a position is valid
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
double x() const
Returns the x-position.
void add(const Position &pos)
Adds the given position to this one.
void setz(double z)
set position z
void mul(double val)
Multiplies position with the given value.
double z() const
Returns the z-position.
void sety(double y)
set position y
double y() const
Returns the y-position.
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
T get(const std::string &str) const
static long long int toLong(const std::string &sData)
converts a string into the long value described by it by calling the char-type converter,...
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.