61#define MAX_SLIPLANE_LENGTH 1000
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++) {
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 (
int)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;
516 auto itTL = tlsLookup.find(continuation);
517 if (itTL != tlsLookup.end()) {
519 tls->replaceRemoved(continuation, -1,
begin, -1,
true);
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
1005 || cluster.size() == 2))
1006 || touchingCluster) {
1007 outsideNeighbors.insert(neighbor);
1010 clusterNeighbors.insert(neighbor);
1013#ifdef DEBUG_JOINJUNCTIONS
1015 <<
" clusterDist=" << clusterDist
1016 <<
" cd<th=" << (clusterDist <= pedestrianFringeThreshold)
1017 <<
" touching=" << touchingCluster
1023 if (clusterNeighbors.size() == 0
1024 || (outsideNeighbors.size() <= 1
1025 && clusterNeighbors.size() == 1
1027 cluster.erase(check);
1029#ifdef DEBUG_JOINJUNCTIONS
1031 std::cout <<
" pruned n=" << n->
getID() <<
"\n";
1036 if (!pruneFringe && !pruneNoisyFringe) {
1039 pruneNoisyFringe =
true;
1048 for (
const NBNode* n1 : cluster) {
1049 for (
const NBNode* n2 : cluster) {
1050 result =
MAX2(result, n1->getPosition().distanceTo2D(n2->getPosition()));
1058 std::set<NBNode*> toRemove;
1059 int maxPassengerLanes = 0;
1060 for (
NBNode* n : cluster) {
1061 for (
NBEdge* edge : n->getEdges()) {
1062 maxPassengerLanes =
MAX2(maxPassengerLanes, edge->getNumLanesThatAllow(
SVC_PASSENGER));
1065 for (
NBNode* n : cluster) {
1066 for (
NBEdge* edge : n->getOutgoingEdges()) {
1070 std::vector<NBNode*> passed;
1073 NBNode* to = edge->getToNode();
1074 while (cluster.count(to) != 0) {
1076 bool goStraight = (std::find(passed.begin(), passed.end(), to) == passed.end()
1081 passed.push_back(to);
1084 if (cur !=
nullptr) {
1095#ifdef DEBUG_JOINJUNCTIONS
1097 std::cout <<
"check edge length " << edge->getID() <<
" (" << length <<
", passed=" << passed.size() <<
", max=" << longThreshold <<
")\n";
1100 if (length > longThreshold) {
1104 const bool keepStart =
getClusterNeighbors(passed.back(), longThreshold, cluster).size() == 1;
1105 const bool keepEnd = !keepStart &&
getClusterNeighbors(n, longThreshold, cluster).size() == 1;
1106#ifdef DEBUG_JOINJUNCTIONS
1108 std::cout <<
"node=" << n->getID() <<
" long edge " << edge->getID() <<
" (" << length <<
", passed=" <<
toString(passed) <<
", max=" << longThreshold <<
") keepStart=" << keepStart <<
" keepEnd=" << keepEnd <<
"\n";
1114 toRemove.insert(passed.begin(), passed.end() - 1);
1116 toRemove.insert(passed.back());
1123 for (std::set<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
1127 return (
int)toRemove.size();
1135 if (e->getLength() > longThreshold) {
1138 NBNode* neighbor = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
1139 if (cluster.count(neighbor) != 0) {
1140 result.insert(neighbor);
1149#ifdef DEBUG_JOINJUNCTIONS
1151 std::cout <<
"pruning slip-lanes at cluster=" <<
joinNamedToString(cluster,
' ') <<
"\n";
1155 if (cluster.size() <= 2) {
1159 for (
NBNode* n : cluster) {
1165#ifdef DEBUG_JOINJUNCTIONS
1167 std::cout <<
" candidate slip-lane start=" << n->
getID() <<
" outgoing=" <<
toString(outgoing) <<
"\n";
1170 for (
NBEdge* contEdge : outgoing) {
1174 double slipLength = contEdge->getLength();
1175 NBNode* cont = contEdge->getToNode();
1179 if (cands.count(cont) != 0) {
1183#ifdef DEBUG_JOINJUNCTIONS
1185 std::cout <<
" candidate slip-lane cont=" << cont->
getID() <<
"\n";
1192#ifdef DEBUG_JOINJUNCTIONS
1194 std::cout <<
" candidate slip-lane end=" << cont->
getID() <<
" slipLength=" << slipLength <<
"\n";
1201 const NBEdge*
const otherEdge = (contEdge == outgoing.front() ? outgoing.back() : outgoing.front());
1204 std::vector<NodeAndDist> toProc;
1207 while (!toProc.empty()) {
1209 NBNode* cont2 = nodeAndDist.first;
1210 double dist = nodeAndDist.second;
1211#ifdef DEBUG_JOINJUNCTIONS
1213 std::cout <<
" search alternative cont2=" << cont2->
getID() <<
" dist=" << dist <<
"\n";
1217 if (visited.find(cont2) != visited.end()) {
1220 visited.insert(cont2);
1221 if (cont2 == cont) {
1226 const double dist2 = dist + e->getLength();
1227 if (dist2 < slipLength * 2 && (e->getPermissions() &
SVC_PASSENGER) != 0) {
1228 toProc.push_back(std::make_pair(e->getToNode(), dist2));
1235 toRemove.insert(cands.begin(), cands.end());
1236#ifdef DEBUG_JOINJUNCTIONS
1238 std::cout <<
" found slip-lane with nodes=" <<
joinNamedToString(cands,
' ') <<
"\n";
1251#ifdef DEBUG_JOINJUNCTIONS
1253 std::cout <<
" candidate slip-lane end=" << n->getID() <<
" incoming=" <<
toString(incoming) <<
"\n";
1256 for (
NBEdge* contEdge : incoming) {
1260 double slipLength = contEdge->getLength();
1261 NBNode* cont = contEdge->getFromNode();
1265 if (cands.count(cont) != 0) {
1269#ifdef DEBUG_JOINJUNCTIONS
1271 std::cout <<
" candidate slip-lane cont=" << cont->
getID() <<
"\n";
1278#ifdef DEBUG_JOINJUNCTIONS
1280 std::cout <<
" candidate slip-lane start=" << cont->
getID() <<
" slipLength=" << slipLength <<
"\n";
1287 const NBEdge*
const otherEdge = (contEdge == incoming.front() ? incoming.back() : incoming.front());
1290 std::vector<NodeAndDist> toProc;
1293 while (!toProc.empty()) {
1295 NBNode* cont2 = nodeAndDist.first;
1296 double dist = nodeAndDist.second;
1297#ifdef DEBUG_JOINJUNCTIONS
1299 std::cout <<
" search alternative cont2=" << cont2->
getID() <<
" dist=" << dist <<
"\n";
1303 if (visited.find(cont2) != visited.end()) {
1306 visited.insert(cont2);
1307 if (cont2 == cont) {
1312 const double dist2 = dist + e->getLength();
1313 if (dist2 < slipLength * 2 && (e->getPermissions() &
SVC_PASSENGER) != 0) {
1314 toProc.push_back(std::make_pair(e->getFromNode(), dist2));
1321 toRemove.insert(cands.begin(), cands.end());
1322#ifdef DEBUG_JOINJUNCTIONS
1324 std::cout <<
" found slip-lane start with nodes=" <<
joinNamedToString(cands,
' ') <<
"\n";
1336 for (
NBNode* n : toRemove) {
1337 numRemoved += (int)cluster.erase(n);
1339 if (numRemoved > 0) {
1340#ifdef DEBUG_JOINJUNCTIONS
1342 std::cout <<
" removed " << numRemoved <<
" nodes from cluster: " <<
joinNamedToString(toRemove,
' ') <<
"\n";
1360 if (inPE.size() == 1 && outPE.size() == 2) {
1361 outgoing.insert(outgoing.begin(), outPE.begin(), outPE.end());
1362 inAngle = inPE.front()->getAngleAtNode(n);
1364 }
else if (inPE.size() >= 2 && outPE.size() == 3) {
1367 const double inRelAngle = fabs(
NBHelpers::relAngle(inPE.front()->getAngleAtNode(n), inPE.back()->getAngleAtNode(n)));
1369 if (inRelAngle < 135) {
1372 for (
NBEdge* in : inPE) {
1375 for (
NBEdge* out : outPE) {
1376 const double outRelAngle = fabs(
NBHelpers::relAngle(in->getAngleAtNode(n), out->getAngleAtNode(n)));
1377 if (outRelAngle <= 45) {
1378 straight.push_back(out);
1379 }
else if (outRelAngle >= 135) {
1383 if (straight.size() == 2 && numReverse == 1) {
1384 outgoing.insert(outgoing.begin(), straight.begin(), straight.end());
1385 inAngle = in->getAngleAtNode(n);
1398 if (inPE.size() == 2 && outPE.size() == 1) {
1399 incoming.insert(incoming.begin(), inPE.begin(), inPE.end());
1400 outAngle = outPE.front()->getAngleAtNode(n);
1402 }
else if (inPE.size() == 3 && outPE.size() >= 2) {
1405 const double outRelAngle = fabs(
NBHelpers::relAngle(outPE.front()->getAngleAtNode(n), outPE.back()->getAngleAtNode(n)));
1407 if (outRelAngle < 135) {
1410 for (
NBEdge* out : outPE) {
1413 for (
NBEdge* in : inPE) {
1414 const double inRelAngle = fabs(
NBHelpers::relAngle(in->getAngleAtNode(n), out->getAngleAtNode(n)));
1415 if (inRelAngle <= 45) {
1416 straight.push_back(in);
1417 }
else if (inRelAngle >= 135) {
1421 if (straight.size() == 2 && numReverse == 1) {
1422 incoming.insert(incoming.begin(), straight.begin(), straight.end());
1423 outAngle = out->getAngleAtNode(n);
1433 double maxDist, std::string& reason)
const {
1436 std::map<NBEdge*, double, ComparatorIdLess> finalIncomingAngles;
1437 std::map<NBEdge*, double, ComparatorIdLess> finalOutgoingAngles;
1438 for (
NBNode* n : cluster) {
1439 for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) {
1446 for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) {
1455#ifdef DEBUG_JOINJUNCTIONS
1456 for (
NBNode* n : cluster) {
1465 if (finalIncomingAngles.size() > 5) {
1466 reason =
toString(finalIncomingAngles.size()) +
" incoming edges";
1470 const double PARALLEL_THRESHOLD_SAME_NODE = 10;
1471 const double PARALLEL_THRESHOLD_DIFF_NODE = 30;
1472 bool foundParallel =
false;
1473 for (
auto j = finalIncomingAngles.begin(); j != finalIncomingAngles.end() && !foundParallel; ++j) {
1475 for (++k; k != finalIncomingAngles.end() && !foundParallel; ++k) {
1476 const double angleDiff = fabs(j->second - k->second);
1477 if (angleDiff < PARALLEL_THRESHOLD_DIFF_NODE) {
1479 const double edgeDist = j->first->getLaneShape(0).back().distanceTo2D(k->first->getLaneShape(0).back());
1480#ifdef DEBUG_JOINJUNCTIONS
1482 std::cout <<
" angleDiff=" << angleDiff <<
" shapeDist=" << edgeDist <<
"\n";
1485 if (angleDiff >= PARALLEL_THRESHOLD_SAME_NODE && (
1486 (j->first->getToNode() == k->first->getToNode()
1487 || (edgeDist < maxDist)))) {
1490 reason =
"parallel incoming " + j->first->getID() +
"," + k->first->getID();
1496 for (
auto j = finalOutgoingAngles.begin(); j != finalOutgoingAngles.end() && !foundParallel; ++j) {
1498 for (++k; k != finalOutgoingAngles.end() && !foundParallel; ++k) {
1499 const double angleDiff = fabs(j->second - k->second);
1500 if (angleDiff < PARALLEL_THRESHOLD_DIFF_NODE) {
1502 const double edgeDist = j->first->getLaneShape(0).front().distanceTo2D(k->first->getLaneShape(0).front());
1503#ifdef DEBUG_JOINJUNCTIONS
1504 if (
DEBUGCOND(j->first->getFromNode())) {
1505 std::cout <<
" angleDiff=" << angleDiff <<
" shapeDist=" << edgeDist <<
"\n";
1508 if (angleDiff >= PARALLEL_THRESHOLD_SAME_NODE && (
1509 (j->first->getFromNode() == k->first->getFromNode()
1510 || (edgeDist < maxDist)))) {
1513 reason =
"parallel outgoing " + j->first->getID() +
"," + k->first->getID();
1519 bool hasTLS =
false;
1520 for (
NBNode* n : cluster) {
1521 if (n->isTLControlled()) {
1524 const auto& stopEnds = ptStopEnds.find(n);
1525 if (stopEnds != ptStopEnds.end()) {
1526 for (
NBNode*
const to : stopEnds->second) {
1527 if (cluster.count(to) != 0) {
1528 reason =
"it contains a pt stop edge";
1535 if (cluster.size() > 2) {
1537 double maxLength = -1;
1538 NBEdge* maxEdge =
nullptr;
1539 for (
NBNode* n1 : cluster) {
1540 for (
NBNode* n2 : cluster) {
1541 NBEdge* e1 = n1->getConnectionTo(n2);
1542 NBEdge* e2 = n2->getConnectionTo(n1);
1553#ifdef DEBUG_JOINJUNCTIONS
1554 for (
NBNode* n : cluster) {
1556 std::cout <<
"feasible hasTLS=" << hasTLS <<
" maxLength=" << maxLength <<
" maxEdge=" << maxEdge->
getID() <<
"\n";
1560 if (!hasTLS && maxLength > 5) {
1562 std::vector<NBNode*> toCheck;
1563 std::set<NBNode*> visited;
1564 toCheck.push_back(maxEdge->
getToNode());
1565 bool foundCircle =
false;
1566 while (!toCheck.empty()) {
1567 NBNode* n = toCheck.back();
1576 NBNode* cand = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
1577 if (visited.count(cand) == 0 && cluster.count(cand) != 0) {
1578 toCheck.push_back(cand);
1584 reason =
"not compact (maxEdge=" + maxEdge->
getID() +
" length=" +
toString(maxLength) +
")";
1590 if (!hasTLS && cluster.size() >= 2) {
1593 int outsideIncoming = 0;
1594 int outsideOutgoing = 0;
1595 int edgesWithin = 0;
1596 for (
NBNode* n : cluster) {
1597 bool foundOutsideIncoming =
false;
1598 for (
NBEdge* e : n->getIncomingEdges()) {
1599 if (cluster.count(e->getFromNode()) == 0) {
1602 foundOutsideIncoming =
true;
1607 if (foundOutsideIncoming) {
1610 bool foundOutsideOutgoing =
false;
1611 for (
NBEdge* e : n->getOutgoingEdges()) {
1612 if (cluster.count(e->getToNode()) == 0) {
1615 foundOutsideOutgoing =
true;
1618 if (foundOutsideOutgoing) {
1622 if (entryNodes < 2) {
1623 reason =
"only 1 entry node";
1626 if (exitNodes < 2) {
1627 reason =
"only 1 exit node";
1630 if (cluster.size() == 2) {
1631 if (edgesWithin == 1 && outsideIncoming < 3 && outsideOutgoing < 3) {
1632 reason =
"only 1 edge within and no cross-traffic";
1644 assert(circleSize >= 2);
1645 if ((
int)cands.size() == circleSize) {
1646 if (cands.back()->getConnectionTo(cands.front()) !=
nullptr) {
1649 candCluster.insert(cands.begin(), cands.end());
1651 const bool feasible = (int)candCluster.size() == circleSize;
1654 cluster.insert(cands.begin(), cands.end());
1661 if ((
int)cluster.size() <= circleSize || startNodes.size() == 0) {
1666 if (cands.size() == 0) {
1672 if (
reduceToCircle(cluster, circleSize, startNodes, maxDist, cands)) {
1681 singleStart.insert(cands.back());
1684 std::vector<NBNode*> cands2(cands);
1686 if (
reduceToCircle(cluster, circleSize, startNodes, maxDist, cands2)) {
1698 double minDist = std::numeric_limits<double>::max();
1699 NBEdge* result =
nullptr;
1700 for (
NBNode* n : startNodes) {
1701 for (
NBEdge* e : n->getOutgoingEdges()) {
1702 NBNode* neigh = e->getToNode();
1703 if (cluster.count(neigh) != 0 && std::find(exclude.begin(), exclude.end(), neigh) == exclude.end()) {
1706 if (dist < minDist) {
1720 for (
NodeSet cluster : clusters) {
1729 assert(cluster.size() > 1);
1730 std::string
id =
"cluster_";
1736 std::set<NBEdge*, ComparatorIdLess> allEdges;
1737 for (
NBNode* n : cluster) {
1739 allEdges.insert(edges.begin(), edges.end());
1742 std::set<NBEdge*, ComparatorIdLess> clusterIncoming;
1743 std::set<NBEdge*, ComparatorIdLess> inside;
1744 for (
NBEdge* e : allEdges) {
1745 if (cluster.count(e->getToNode()) > 0) {
1746 if (cluster.count(e->getFromNode()) > 0) {
1753 clusterIncoming.insert(e);
1757#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1759 <<
" resetConnections=" << resetConnections <<
"\n"
1764 NBNode* newNode =
nullptr;
1765 if (predefined !=
nullptr) {
1766 newNode = predefined;
1775 std::string tlID = id;
1776 if (predefined !=
nullptr) {
1778 nodeType = predefined->
getType();
1791 newNode->
reinit(pos, nodeType);
1797 if (!tlc.
insert(tlDef)) {
1805 std::map<NBEdge*, EdgeSet> reachable;
1806 std::map<std::pair<NBEdge*, NBEdge*>,
SVCPermissions> conPermissions;
1808 for (
NBEdge*
const e : clusterIncoming) {
1812 while (open.size() > 0) {
1813 NBEdge*
const cur = open.back();
1815#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1816 std::cout <<
"e=" << e->getID() <<
" cur=" << cur->
getID() <<
" open=" <<
toString(open) <<
"\n";
1817 std::cout <<
"e=" << e->getID() <<
" cur=" << cur->
getID() <<
" open=" <<
toString(open) <<
"\n";
1821 if (cluster.count(cur->
getToNode()) == 0) {
1829 if (allEdges.count(out) != 0) {
1831 if (seen.count(out) == 0 || (~conPermissions[ {e, out}] & p) != 0) {
1833 open.push_back(out);
1834 conPermissions[ {e, out}] |= p;
1835#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1844 for (
const auto& con : cons) {
1845 if (con.toEdge !=
nullptr && allEdges.count(con.toEdge) != 0) {
1848 p &= con.permissions;
1850 if (seen.count(con.toEdge) == 0 || (~conPermissions[ {e, con.toEdge}] & p) != 0) {
1851 open.push_back(con.toEdge);
1852 conPermissions[ {e, con.toEdge}] |= p;
1860 for (
NBEdge* reached : seen) {
1862 if (inside.count(reached) == 0) {
1867 reachable[e].insert(reached);
1868 const SVCPermissions pDefault = e->getPermissions() & reached->getPermissions();
1869 if (conPermissions[ {e, reached}] != pDefault) {
1870 specialPermissions.insert(e);
1871#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1872 std::cout <<
"e=" << e->getID() <<
" out=" << reached->getID() <<
" special=" <<
getVehicleClassNames(conPermissions[ {e, reached}]) <<
"\n";
1877#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1878 std::cout <<
" reachable e=" << e->getID() <<
" seen=" <<
toString(seen) <<
" reachable=" <<
toString(reachable[e]) <<
"\n";
1886 for (
NBEdge* e : inside) {
1887 for (
NBEdge* e2 : allEdges) {
1889 e2->replaceInConnections(e, e->getConnections());
1897 for (
NBEdge* e : allEdges) {
1898 const bool outgoing = cluster.count(e->getFromNode()) > 0;
1899 NBNode* from = outgoing ? newNode : e->getFromNode();
1900 NBNode* to = outgoing ? e->getToNode() : newNode;
1903 e->
setParameter(
"origFrom", e->getFromNode()->getID());
1905 e->setParameter(
"origTo", e->getToNode()->getID());
1908 if (e->getTurnSignTarget() !=
"") {
1909 for (
NBNode* n : cluster) {
1910 if (e->getTurnSignTarget() == n->getID()) {
1911 e->setTurnSignTarget(to->
getID());
1916 e->reinitNodes(from, to);
1919 std::vector<NBEdge::Connection> conns = e->getConnections();
1920 for (std::vector<NBEdge::Connection>::iterator k = conns.begin(); k != conns.end(); ++k) {
1921 if ((*k).toEdge ==
nullptr) {
1926 if ((*k).fromLane >= 0 && (*k).fromLane < e->getNumLanes() && e->getLaneStruct((*k).fromLane).connectionsDone) {
1929#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1930 std::cout <<
" e=" << e->getID() <<
" declareConnectionsAsLoaded\n";
1935 if (!resetConnections) {
1940 if (reachable[in].count(out) == 0) {
1943 in->removeFromConnections(out, -1, -1,
true,
false,
true);
1947 }
else if (specialPermissions.count(in) != 0) {
1948 SVCPermissions pDefault = in->getPermissions() & out->getPermissions();
1949 SVCPermissions p = conPermissions[ {in, out}] == 0 ? pDefault : conPermissions[ {in, out}];
1950 in->addEdge2EdgeConnection(out,
true, p == pDefault ?
SVC_UNSPECIFIED : p);
1957 in->invalidateConnections(
true);
1963 for (
NBNode* n : cluster) {
1971 std::set<std::string> ids;
1972 for (
NBNode* n : cluster) {
1973 ids.insert(n->getID());
1996 bool ambiguousType =
false;
1997 for (
NBNode* j : cluster) {
1998 pos.
add(j->getPosition());
2000 if (j->isTLControlled()) {
2003 type = (*j->getControllingTLS().begin())->getType();
2004 }
else if (type != (*j->getControllingTLS().begin())->getType()) {
2005 ambiguousType =
true;
2011 nodeType = otherType;
2012 }
else if (nodeType != otherType) {
2024 pos.
mul(1. / (
double)cluster.size());
2025 if (ambiguousType) {
2035 bool tooFast =
false;
2036 double laneSpeedSum = 0;
2037 std::set<NBEdge*> seen;
2039 for (
const NBEdge* e : j->getEdges()) {
2040 if (c.find(e->getFromNode()) != c.end() && c.find(e->getToNode()) != c.end()) {
2044 if (j->hasIncoming(e)) {
2045 if (recheck && !j->hasConflict(e)) {
2050 laneSpeedSum += (double)e->getNumLanes() * e->getLaneSpeed(0);
2052 if (e->getLaneSpeed(0) * 3.6 > 79) {
2058 return !tooFast && laneSpeedSum >= laneSpeedThreshold && c.size() != 0;
2068 for (
NBEdge* e : node->getIncomingEdges()) {
2070 nonPedIncoming.push_back(e);
2073 for (
NBEdge* e : node->getOutgoingEdges()) {
2075 nonPedOutgoing.push_back(e);
2078 if (!node->geometryLike(nonPedIncoming, nonPedOutgoing)) {
2094 if (node->isTLControlled()) {
2100 const std::string tlID = tl->
getID();
2101 if (tlID != node->getID()
2117 const double laneSpeedThreshold = oc.
getFloat(
"tls.guess.threshold");
2118 if (oc.
isSet(
"tls.unset")) {
2119 std::vector<std::string> notTLControlledNodes = oc.
getStringVector(
"tls.unset");
2120 for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) {
2123 throw ProcessError(
TLF(
" The junction '%' to set as not-controlled is not known.", *i));
2126 for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) {
2127 (*j)->removeNode(n);
2137 if (oc.
exists(
"tls.taz-nodes") && oc.
getBool(
"tls.taz-nodes")) {
2138 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2139 NBNode* cur = (*i).second;
2148 if (oc.
exists(
"tls.guess-signals") && oc.
getBool(
"tls.guess-signals")) {
2150 const double signalDist = oc.
getFloat(
"tls.guess-signals.dist");
2151 for (
const auto& item :
myNodes) {
2152 const NBNode* node = item.second;
2154#ifdef DEBUG_GUESSSIGNALS
2156 std::cout <<
" propagate TLS from " << node->
getID() <<
" downstream\n";
2162 edge->setSignalPosition(node->
getPosition(), node);
2167 std::set<NBEdge*> seen;
2168 std::set<NBEdge*> check;
2169 for (
const auto& item :
myNodes) {
2170 for (
NBEdge* edge : item.second->getOutgoingEdges()) {
2174#ifdef DEBUG_GUESSSIGNALS
2175 if (
DEBUGCOND(edge->getSignalNode()) ||
true) {
2176 std::cout <<
" primary signalPosition edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2183 while (check.size() > 0) {
2184 NBEdge*
const edge = *check.begin();
2185 check.erase(check.begin());
2190 if (seen.count(outEdge) == 0) {
2192#ifdef DEBUG_GUESSSIGNALS
2194 std::cout <<
" setSignalPosition edge=" << outEdge->
getID() <<
" pos=" << edge->
getSignalPosition() <<
"\n";
2197 check.insert(outEdge);
2204 const int slack = oc.
getInt(
"tls.guess-signals.slack");
2205 for (std::map<std::string, NBNode*>::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2206 NBNode* node = i->second;
2215 std::vector<const NBNode*> signals;
2216 int foundSignals = 0;
2217 int missingSignals = 0;
2219 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2220 const NBEdge* inEdge = *it_i;
2223#ifdef DEBUG_GUESSSIGNALS
2225 std::cout <<
" noTLS, edge=" << inEdge->
getID() <<
"\n";
2229 if (missingSignals > slack) {
2238 int foundSignalsAtDist = 0;
2239 if (foundSignals > 1 && missingSignals <= slack && missingSignals < foundSignals) {
2243 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2244 const NBEdge* inEdge = *it_i;
2247#ifdef DEBUG_GUESSSIGNALS
2253 if (missingSignals > slack) {
2258 foundSignalsAtDist++;
2261 if (signal !=
nullptr) {
2262 signals.push_back(signal);
2267 for (
const NBEdge* outEdge : outgoing) {
2268 NBNode* cand = outEdge->getToNode();
2270#ifdef DEBUG_GUESSSIGNALS
2272 std::cout <<
" node=" << node->
getID() <<
" outEdge=" << outEdge->getID() <<
" signalNode=" << cand->
getID() <<
" len=" << outEdge->getLength() <<
"\n";
2275 signals.push_back(cand);
2279 if (foundSignalsAtDist > 1 && missingSignals <= slack && missingSignals < foundSignalsAtDist) {
2280 for (
const NBNode* s : signals) {
2281 std::set<NBTrafficLightDefinition*> tls = s->getControllingTLS();
2283 for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
2290 if (!tlc.
insert(tlDef)) {
2302 if (oc.
getBool(
"tls.guess.joining")) {
2307 for (NodeClusters::iterator i = cands.begin(); i != cands.end();) {
2311 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2312 if ((*j)->isTLControlled() ||
myUnsetTLS.count(*j) != 0) {
2327 for (
auto nodeSet : cands) {
2328 std::vector<NBNode*> nodes;
2329 for (
NBNode* node : nodeSet) {
2330 nodes.push_back(node);
2335 if (!tlc.
insert(tlDef)) {
2345 if (oc.
getBool(
"tls.guess")) {
2346 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2347 NBNode* cur = (*i).second;
2370 std::set<NBTrafficLightDefinition*> recompute;
2373 const std::set<NBTrafficLightDefinition*>& tlDefs = node->getControllingTLS();
2374 recompute.insert(tlDefs.begin(), tlDefs.end());
2375 node->removeTrafficLights(
true);
2376 for (
NBEdge* edge : node->getIncomingEdges()) {
2377 edge->clearControllingTLInformation();
2382 if (def->getNodes().size() == 0) {
2385 def->setParticipantsInformation();
2386 def->setTLControllingInformation();
2411 for (
const auto& item :
myNodes) {
2412 item.second->computeKeepClear();
2420 for (
const std::string& tlsID : excludeList) {
2421 if (!tlc.
exist(tlsID,
false)) {
2422 WRITE_WARNINGF(
"Unknown tls ID '%' in option tls.join-exclude", tlsID);
2425 std::set<std::string> exclude(excludeList.begin(), excludeList.end());
2429 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2430 if (!(*j)->isTLControlled() || exclude.count((*(*j)->getControllingTLS().begin())->getID()) != 0) {
2441 bool dummySetTL =
false;
2442 std::string
id =
"joinedS_";
2447 std::set<NBTrafficLightDefinition*> tls = j->getControllingTLS();
2448 j->removeTrafficLights();
2453 std::vector<NBNode*> nodes;
2458 if (!tlc.
insert(tlDef)) {
2475 if (!tlc.
insert(tlDef)) {
2477 WRITE_WARNINGF(
TL(
"Building a tl-logic for junction '%' twice is not possible."),
id);
2487 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2488 (*i).second->computeLanes2Lanes();
2496 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2497 (*i).second->computeLogic(ec);
2504 std::set<NBNode*> roundaboutNodes;
2505 const bool checkLaneFoesAll = oc.
getBool(
"check-lane-foes.all");
2506 const bool checkLaneFoesRoundabout = !checkLaneFoesAll && oc.
getBool(
"check-lane-foes.roundabout");
2507 if (checkLaneFoesRoundabout) {
2509 for (std::set<EdgeSet>::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
2510 for (EdgeSet::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
2511 roundaboutNodes.insert((*j)->getToNode());
2515 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2516 const bool checkLaneFoes = checkLaneFoesAll || (checkLaneFoesRoundabout && roundaboutNodes.count((*i).second) > 0);
2517 (*i).second->computeLogic2(checkLaneFoes);
2524 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2525 delete ((*i).second);
2538 std::string freeID =
"SUMOGenerated" + toString<int>(counter);
2540 while (
retrieve(freeID) !=
nullptr) {
2543 freeID =
"SUMOGenerated" + toString<int>(counter);
2551 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2552 (*i).second->computeNodeShape(mismatchThreshold);
2559 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2562 int numUnregulatedJunctions = 0;
2563 int numDeadEndJunctions = 0;
2564 int numTrafficLightJunctions = 0;
2565 int numPriorityJunctions = 0;
2566 int numRightBeforeLeftJunctions = 0;
2567 int numLeftBeforeRightJunctions = 0;
2568 int numAllWayStopJunctions = 0;
2569 int numZipperJunctions = 0;
2570 int numDistrictJunctions = 0;
2571 int numRailCrossing = 0;
2572 int numRailSignals = 0;
2573 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2574 switch ((*i).second->getType()) {
2576 ++numUnregulatedJunctions;
2579 ++numDeadEndJunctions;
2584 ++numTrafficLightJunctions;
2588 ++numPriorityJunctions;
2591 ++numRightBeforeLeftJunctions;
2594 ++numLeftBeforeRightJunctions;
2597 ++numAllWayStopJunctions;
2600 ++numZipperJunctions;
2603 ++numDistrictJunctions;
2620 if (numDeadEndJunctions > 0) {
2625 if (numLeftBeforeRightJunctions > 0) {
2628 if (numTrafficLightJunctions > 0) {
2631 if (numAllWayStopJunctions > 0) {
2634 if (numZipperJunctions > 0) {
2637 if (numRailCrossing > 0) {
2640 if (numRailSignals > 0) {
2643 if (numDistrictJunctions > 0) {
2651 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2655std::vector<std::string>
2657 std::vector<std::string> ret;
2658 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2659 ret.push_back((*i).first);
2668 const auto nodeContainerCopy =
myNodes;
2670 for (
const auto& node : nodeContainerCopy) {
2671 node.second->setID(prefix + node.second->getID());
2672 myNodes[node.second->getID()] = node.second;
2679 if (
myNodes.count(newID) != 0) {
2680 throw ProcessError(
TLF(
"Attempt to rename node using existing id '%'", newID));
2690 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2691 NBNode* node = i->second;
2695 if (geometryLike && (*tldefs.begin())->getNodes().size() > 1) {
2706 edge->setSignalPosition(node->
getPosition(),
nullptr);
2707#ifdef DEBUG_GUESSSIGNALS
2708 std::cout <<
" discard-simple " << node->
getID() <<
" edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2712 for (std::set<NBTrafficLightDefinition*>::const_iterator it = tldefs.begin(); it != tldefs.end(); ++it) {
2727 NBNode* node = item.second;
2738 if (!numericaIDs && !reservedIDs && prefix ==
"" && !startGiven) {
2741 std::vector<std::string> avoid;
2747 std::set<std::string> reserve;
2751 avoid.insert(avoid.end(), reserve.begin(), reserve.end());
2755 for (NodeCont::iterator it =
myNodes.begin(); it !=
myNodes.end(); it++) {
2757 toChange.insert(it->second);
2764 toChange.insert(it->second);
2767 if (reservedIDs && reserve.count(it->first) > 0) {
2768 toChange.insert(it->second);
2772 for (
NBNode* node : toChange) {
2775 for (
NBNode* node : toChange) {
2779 node->setID(idSupplier.
getNext());
2781 tlc.
rename(tlDef, node->getID());
2783 myNodes[node->getID()] = node;
2785 if (prefix.empty()) {
2786 return (
int)toChange.size();
2791 for (
auto item : oldNodes) {
2793 rename(item.second, prefix + item.first);
2796 tlc.
rename(tlDef, prefix + tlDef->getID());
2814 for (
const auto& item :
myNodes) {
2817 paretoCheck(item.second, bottomRightFront, 1, -1);
2818 paretoCheck(item.second, bottomLeftFront, -1, -1);
2821 front.insert(topRightFront.begin(), topRightFront.end());
2822 front.insert(topLeftFront.begin(), topLeftFront.end());
2823 front.insert(bottomRightFront.begin(), bottomRightFront.end());
2824 front.insert(bottomLeftFront.begin(), bottomLeftFront.end());
2826 for (
NBNode* n : front) {
2827 const int in = (int)n->getIncomingEdges().size();
2828 const int out = (int)n->getOutgoingEdges().size();
2829 if ((in <= 1 && out <= 1) &&
2830 (in == 0 || out == 0
2831 || n->getIncomingEdges().front()->isTurningDirectionAt(n->getOutgoingEdges().front()))) {
2838 for (
const auto& item :
myNodes) {
2840 if (front.count(n) != 0) {
2843 if (n->
getEdges().size() == 1 && n->
getEdges().front()->getSpeed() > speedThreshold) {
2856 std::vector<NBNode*> dominated;
2858 const double x2 =
fn->getPosition().x() * xSign;
2859 const double y2 =
fn->getPosition().y() * ySign;
2860 if (x2 >= x && y2 >= y) {
2862 }
else if (x2 <= x && y2 <= y) {
2863 dominated.push_back(
fn);
2866 frontier.insert(node);
2867 for (
NBNode* r : dominated) {
2875 for (
const auto& item :
myNodes) {
2878 bool hasNEMA =
false;
2896 bool hadShapes =
false;
2897 for (
const auto& item :
myNodes) {
2898 if (item.second->getShape().size() > 0 && !item.second->hasCustomShape()) {
2900 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 isForVulnerableModes(SVCPermissions permissions)
Returns whether an edge with the given permissions allows only vulnerable road users.
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permissions is a railway edge.
const SVCPermissions SVC_UNSPECIFIED
permissions not specified
bool isWaterway(SVCPermissions permissions)
Returns whether an edge with the given permissions 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
const Boundary & getOrigBoundary() const
Returns the original boundary.
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
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.
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 begin() const
Returns the pointer to the begin 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.
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
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
const std::vector< Connection > & getConnections() const
Returns the connections.
const Position & getSignalPosition() const
Returns the position of a traffic signal on this edge.
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
NBNode * getToNode() const
Returns the destination node of the edge.
static EdgeVector filterByPermissions(const EdgeVector &edges, SVCPermissions permissions)
return only those edges that permit at least one of the give permissions
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...
bool isNearEnough2BeJoined2(NBEdge *e, double threshold) const
Check if edge is near enought to be joined to another edge.
@ INIT
The edge has been loaded, nothing is computed yet.
double getSpeed() const
Returns the speed allowed on this edge.
const std::string & getID() const
static const double UNSPECIFIED_SIGNAL_OFFSET
unspecified signal offset
const NBNode * getSignalNode() const
Returns the node that (possibly) represents a traffic signal controlling at the end of this edge.
@ USER
The connection was given by the user.
NBNode * getFromNode() const
Returns the origin node of the edge.
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.
void append(NBEdge *continuation)
append another edge
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
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
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
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.
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 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
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
std::vector< std::pair< NBEdge *, NBEdge * > > getEdgesToJoin() const
get edges to join
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
void removeTrafficLights(bool setAsPriority=false)
Removes all references to traffic lights that control this tls.
int removeSelfLoops(NBDistrictCont &dc, NBEdgeCont &ec, NBTrafficLightLogicCont &tc)
Removes edges which are both incoming and outgoing into this node.
std::vector< Crossing * > getCrossings() const
return this junctions pedestrian crossings
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 Position & getPosition() const
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
void updateSurroundingGeometry()
update geometry of node and surrounding edges
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.
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.