61#define MAX_SLIPLANE_LENGTH 1000
72#define DEBUGNODEID2 ""
74#define DEBUGCOND(obj) ((obj) != 0 && ((obj)->getID() == DEBUGNODEID || (obj)->getID() == DEBUGNODEID2))
90 NodeCont::iterator i =
myNodes.find(
id);
96 const float pos[2] = {(float)position.
x(), (float)position.
y()};
104 std::string
id = node->
getID();
105 NodeCont::iterator i =
myNodes.find(
id);
118 NodeCont::const_iterator i =
myNodes.find(
id);
128 const double extOffset = offset + POSITION_EPS;
129 const float cmin[2] = {(float)(position.
x() - extOffset), (
float)(position.
y() - extOffset)};
130 const float cmax[2] = {(float)(position.
x() + extOffset), (
float)(position.
y() + extOffset)};
131 std::set<const Named*> into;
134 for (
const Named* namedNode : into) {
178 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
191 const double distanceThreshold = 7.;
192 const double lengthThreshold = 0.10;
194 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
196 std::map<NBNode*, EdgeVector> connectionCount;
197 const EdgeVector& outgoing = (*i).second->getOutgoingEdges();
198 for (EdgeVector::const_iterator j = outgoing.begin(); j != outgoing.end(); j++) {
199 connectionCount[(*j)->getToNode()].push_back(*j);
202 std::map<NBNode*, EdgeVector>::iterator k;
203 for (k = connectionCount.begin(); k != connectionCount.end(); k++) {
205 if ((*k).second.size() < 2) {
211 const NBEdge*
const first = ev.front();
212 EdgeVector::const_iterator jci;
213 for (jci = ev.begin() + 1; jci != ev.end(); ++jci) {
216 (relativeLengthDifference > lengthThreshold) ||
217 (fabs(first->
getSpeed() - (*jci)->getSpeed()) >= 0.01) ||
225 if (jci == ev.end()) {
226 if (removeDuplicates) {
227 for (
int ei = 1; ei < (int)ev.size(); ei++) {
241 int numRemovedEdges = 0;
243 const std::vector<std::string>& edgeNames = ec.
getAllNames();
244 for (std::vector<std::string>::const_iterator it = edgeNames.begin(); it != edgeNames.end(); ++it) {
253 if (outgoingEdges.size() != 1) {
258 if (incomingEdges.size() > 1) {
261 }
else if (incomingEdges.size() == 1) {
262 NBNode* fromNodeOfIncomingEdge = incomingEdges[0]->getFromNode();
263 NBNode* toNodeOfOutgoingEdge = outgoingEdges[0]->getToNode();
264 if (fromNodeOfIncomingEdge != toNodeOfOutgoingEdge) {
272 bool hasJunction =
false;
284 adjacentNodes.clear();
285 for (EdgeVector::const_iterator itOfOutgoings = outgoingEdgesOfToNode.begin(); itOfOutgoings != outgoingEdgesOfToNode.end(); ++itOfOutgoings) {
286 if ((*itOfOutgoings)->getToNode() != from
287 && (*itOfOutgoings)->getToNode() != to
291 adjacentNodes.insert((*itOfOutgoings)->getToNode());
293 for (EdgeVector::const_iterator itOfIncomings = incomingEdgesOfToNode.begin(); itOfIncomings != incomingEdgesOfToNode.end(); ++itOfIncomings) {
294 adjacentNodes.insert((*itOfIncomings)->getFromNode());
296 adjacentNodes.erase(to);
297 if (adjacentNodes.size() > 2) {
300 }
while (!hasJunction && eOld != e);
302 std::string warningString;
303 for (EdgeVector::iterator roadIt = road.begin(); roadIt != road.end(); ++roadIt) {
304 if (roadIt == road.begin()) {
305 warningString += (*roadIt)->
getID();
307 warningString +=
"," + (*roadIt)->getID();
310 NBNode* fromNode = (*roadIt)->getFromNode();
311 NBNode* toNode = (*roadIt)->getToNode();
312 ec.
erase(dc, *roadIt);
326 return numRemovedEdges;
333 std::vector<std::set<NBEdge*> > components;
335 std::set<std::string> edgesLeft;
336 for (std::map<std::string, NBEdge*>::const_iterator edgeIt = ec.
begin(); edgeIt != ec.
end(); ++edgeIt) {
337 edgesLeft.insert(edgeIt->first);
340 std::set<NBEdge*> toRemove;
341 int foundComponents = 0;
343 while (!edgesLeft.empty()) {
344 queue.push_back(ec.
getByID(*edgesLeft.begin()));
345 std::set<NBEdge*> component;
346 while (!queue.empty()) {
347 NBEdge*
const e = queue.back();
350 std::vector<EdgeVector> edgeLists;
355 for (std::vector<EdgeVector>::const_iterator listIt = edgeLists.begin(); listIt != edgeLists.end(); ++listIt) {
356 for (EdgeVector::const_iterator edgeIt = listIt->begin(); edgeIt != listIt->end(); ++edgeIt) {
357 std::set<std::string>::iterator leftIt = edgesLeft.find((*edgeIt)->getID());
358 if (leftIt != edgesLeft.end()) {
359 queue.push_back(*edgeIt);
360 edgesLeft.erase(leftIt);
366 std::vector<std::set<NBEdge*> >::iterator cIt;
367 for (cIt = components.begin(); cIt != components.end(); ++cIt) {
368 if (cIt->size() < component.size()) {
372 components.insert(cIt, component);
373 if ((
int)components.size() > numKeep) {
374 bool recheck =
false;
376 for (
NBEdge* e : components.back()) {
386 toRemove.insert(components.back().begin(), components.back().end());
389 std::vector<std::string> edgeIDs;
390 for (
NBEdge* e : components.back()) {
391 edgeIDs.push_back(e->getID());
395 components.pop_back();
399 for (
NBEdge* e : toRemove) {
400 NBNode*
const fromNode = e->getFromNode();
401 NBNode*
const toNode = e->getToNode();
410 if (foundComponents > 1) {
413 return (
int)toRemove.size();
419 std::set<std::string> stopEdges;
420 for (
const auto& item : sc.
getStops()) {
421 stopEdges.insert(item.second->getEdgeId());
424 int numRemovedEdges = 0;
427 for (std::string edgeID : component) {
428 if (stopEdges.count(edgeID) != 0) {
435 numRemovedEdges += (int)component.size();
436 for (std::string edgeID : component) {
452 if (numRemoved > 0) {
464 bool removeGeometryNodes) {
466 std::set<std::string> edges2keep;
467 if (removeGeometryNodes) {
469 if (oc.
isSet(
"geometry.remove.keep-edges.input-file")) {
472 if (oc.
isSet(
"geometry.remove.keep-edges.explicit")) {
473 const std::vector<std::string> edges = oc.
getStringVector(
"geometry.remove.keep-edges.explicit");
474 edges2keep.insert(edges.begin(), edges.end());
479 if (oc.
exists(
"geometry.remove.keep-ptstops") && oc.
getBool(
"geometry.remove.keep-ptstops")) {
484 std::map<NBEdge*, std::set<NBTrafficLightDefinition*> > tlsLookup;
485 for (
auto it = ec.
begin(); it != ec.
end(); it++) {
493 std::vector<NBNode*> toRemove;
494 for (
const auto& i :
myNodes) {
495 NBNode*
const current = i.second;
502 if (edges2keep.find(it_edge->getID()) != edges2keep.end()) {
512 for (
const std::pair<NBEdge*, NBEdge*>& j : current->
getEdgesToJoin()) {
514 NBEdge*
const continuation = j.second;
517 auto itTL = tlsLookup.find(continuation);
518 if (itTL != tlsLookup.end()) {
520 tls->replaceRemoved(continuation, -1,
begin, -1,
true);
522 tlsLookup[
begin] = itTL->second;
526 ec.
extract(dc, continuation,
true);
528 toRemove.push_back(current);
531 for (
NBNode* n : toRemove) {
534 return (
int)toRemove.size();
540 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
541 (*i).second->avoidOverlap();
549 std::set<NBNode*> visited;
550 for (
const auto& i :
myNodes) {
551 if (visited.count(i.second) > 0) {
554 std::vector<NodeAndDist> toProc;
555 toProc.emplace_back(i.second, 0.);
557 while (!toProc.empty()) {
558 NBNode*
const n = toProc.back().first;
559 const double dist = toProc.back().second;
561 if (visited.count(n) > 0) {
565 bool pureRail =
true;
566 bool railAndPeds =
true;
584 const double length = e->getLoadedLength();
585#ifdef DEBUG_JOINJUNCTIONS
587 std::cout <<
"generateNodeClusters: consider s=" << s->
getID()
588 <<
" clusterNode=" << n->
getID() <<
" edge=" << e->getID() <<
" dist=" << dist <<
" length=" << length <<
" with cluster " <<
joinNamedToString(c,
' ') <<
"\n";
592 bool railAndPeds2 =
true;
595 railAndPeds2 =
false;
606 const bool joinPedCrossings = bothCrossing && e->getPermissions() ==
SVC_PEDESTRIAN;
608 !joinPedCrossings && (
611 || (length > 3 * POSITION_EPS
614#ifdef DEBUG_JOINJUNCTIONS
625 bool foundRail =
false;
628 if ((e2->getPermissions() & railNoTram) != 0) {
641 if (visited.find(s) != visited.end()) {
644 if (length + dist < maxDist) {
649 const double fullLength = e->getGeometry().length2D();
650 const double length2 = bothCrossing || hasTLS || trueGeomLike ? length : fullLength;
651 toProc.emplace_back(s, dist + length2);
653 toProc.emplace_back(s, 0.);
661#ifdef DEBUG_JOINJUNCTIONS
674 if ((e->getPermissions() & ~ignored) != 0) {
675 allowedIn.push_back(e);
679 if ((e->getPermissions() & ~ignored) != 0) {
680 allowedOut.push_back(e);
683 if (allowedIn.size() > 0 && allowedOut.size() > 0) {
693 for (
const std::string& nodeID : ids) {
697 WRITE_WARNINGF(
TL(
"Ignoring join exclusion for junction '%' since it already occurred in a list of nodes to be joined."), nodeID);
709 maxIds = (int)cluster.size();
711 if ((
int)cluster.size() > maxIds) {
712 auto clusterIt = cluster.begin();
713 std::string result = prefix + *clusterIt;
714 for (
int i = 1; i < maxIds; i++) {
716 result +=
"_" + *clusterIt;
718 return result +
"_#" +
toString((
int)cluster.size() - maxIds) +
"more";
727 std::set<std::string> validCluster;
728 for (std::string nodeID : cluster) {
730 WRITE_WARNINGF(
TL(
"Ignoring join-cluster because junction '%' was already excluded from joining."), nodeID);
732 }
else if (
myJoined.count(nodeID) > 0) {
733 WRITE_WARNINGF(
TL(
"Ignoring join-cluster because junction '%' already occurred in another join-cluster."), nodeID);
737 validCluster.insert(nodeID);
739 WRITE_ERRORF(
TL(
"Unknown junction '%' in join-cluster."), nodeID);
743 if (validCluster.size() > 1) {
744 myJoined.insert(validCluster.begin(), validCluster.end());
747 WRITE_WARNINGF(
TL(
"Ignoring join-cluster '%' because it has size '%'."), node->
getID(), validCluster.size());
758 for (std::string nodeID : item.first) {
760 if (node ==
nullptr) {
763 cluster.insert(node);
766 if (cluster.size() > 1) {
779#ifdef DEBUG_JOINJUNCTIONS
780 std::cout <<
"joinJunctions...\n";
784 std::map<const NBNode*, std::vector<NBNode*> > ptStopEnds;
786 for (
const auto& stopIt : sc.
getStops()) {
788 if (edge !=
nullptr) {
793 for (
NodeSet& cluster : cands) {
794#ifdef DEBUG_JOINJUNCTIONS
796 for (
NBNode* n : cluster) {
803 for (NodeSet::iterator j = cluster.begin(); j != cluster.end();) {
804 NodeSet::iterator check = j;
807 cluster.erase(check);
813 if (cluster.size() < 2) {
818 if (cluster.size() < 2) {
819 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"slip lane");
823 NBNode* tryRemove =
nullptr;
825 std::string origReason;
827 bool feasible =
feasibleCluster(cluster, ptStopEnds, maxDist, origReason, tryRemove);
828 if (feasible && ((
int)cluster.size() -
pruneLongEdges(cluster, maxDist,
true) < 2)) {
829 origReason =
"long edge";
833#ifdef DEBUG_JOINJUNCTIONS
835 std::cout <<
" try to reduce to 4-circle nodes=" <<
joinNamedToString(cluster,
',') <<
"\n";
839 feasible =
feasibleCluster(cluster, ptStopEnds, maxDist, reason, tryRemove);
841 WRITE_WARNINGF(
TL(
"Reducing junction cluster % (%)."), origCluster, origReason);
846#ifdef DEBUG_JOINJUNCTIONS
848 std::cout <<
" try to reduce to 2-circle nodes=" <<
joinNamedToString(cluster,
',') <<
"\n";
852 feasible =
feasibleCluster(cluster, ptStopEnds, maxDist, reason, tryRemove);
854 WRITE_WARNINGF(
TL(
"Reducing junction cluster % (%)."), origCluster, origReason);
858 while (!feasible && tryRemove !=
nullptr) {
859 cluster.erase(tryRemove);
862 feasible =
feasibleCluster(cluster, ptStopEnds, maxDist, reason, tryRemove);
864 WRITE_WARNINGF(
TL(
"Reducing junction cluster % (%)."), origCluster, origReason);
867 if (cluster.size() < 2) {
868 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"after reduction");
873 if (cluster.size() < 2) {
874 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"long edge");
880 if (cluster.size() < 2) {
881 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"long edge");
885 if (cluster.size() < 2) {
886 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster,
"slip lane");
890 feasible =
feasibleCluster(cluster, ptStopEnds, maxDist, origReason, tryRemove);
892 WRITE_WARNINGF(
TL(
"Not joining junctions % (%)."), origCluster, origReason);
898 for (
NBNode* current : cluster) {
902 newComp.insert(current);
903 for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end();) {
904 NodeClusters::iterator check = it_comp;
906 bool connected =
false;
907 for (
NBNode* k : *check) {
908 if (current->getConnectionTo(k) !=
nullptr || k->getConnectionTo(current) !=
nullptr) {
910 newComp.insert((*check).begin(), (*check).end());
911 it_comp = components.erase(check);
921 components.push_back(newComp);
923 for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end(); ++it_comp) {
924 if ((*it_comp).size() > 1) {
926 clusters.push_back(*it_comp);
929#ifdef DEBUG_JOINJUNCTIONS
934 return (
int)clusters.size();
940#ifdef DEBUG_JOINJUNCTIONS
941 std::cout <<
"joinSameJunctions...\n";
943 std::map<std::string, NodeSet> positions;
945 Position pos = item.second->getPosition();
949 positions[rounded].insert(item.second);
952 for (
auto& item : positions) {
953 if (item.second.size() > 1) {
954 for (
NBNode* n : item.second) {
956 item.second.erase(n);
959 if (item.second.size() > 1) {
960 clusters.push_back(item.second);
965 return (
int)clusters.size();
970#ifdef DEBUG_JOINJUNCTIONS
977 bool pruneFringe =
true;
978 bool pruneNoisyFringe =
false;
981 while (pruneFringe) {
983 for (NodeSet::iterator j = cluster.begin(); j != cluster.end();) {
984 NodeSet::iterator check = j;
989 double clusterDist = std::numeric_limits<double>::max();
990 bool touchingCluster =
false;
992 NBNode* neighbor = (*it_edge)->getToNode();
993 if (cluster.count(neighbor) != 0) {
994 clusterDist =
MIN2(clusterDist, (*it_edge)->getLoadedLength());
999 NBNode* neighbor = (*it_edge)->getFromNode();
1000 if (cluster.count(neighbor) != 0) {
1001 clusterDist =
MIN2(clusterDist, (*it_edge)->getLoadedLength());
1007 std::set<NBNode*> outsideNeighbors;
1008 std::set<NBNode*> clusterNeighbors;
1009 const double pedestrianFringeThreshold = 0.3;
1011 NBNode* neighbor = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
1012 if (cluster.count(neighbor) == 0) {
1015 || (clusterDist <= pedestrianFringeThreshold
1016 && (!pruneNoisyFringe
1020 || cluster.size() == 2))
1021 || touchingCluster) {
1022 outsideNeighbors.insert(neighbor);
1025 clusterNeighbors.insert(neighbor);
1028#ifdef DEBUG_JOINJUNCTIONS
1030 <<
" clusterDist=" << clusterDist
1031 <<
" cd<th=" << (clusterDist <= pedestrianFringeThreshold)
1032 <<
" touching=" << touchingCluster
1038 if (clusterNeighbors.size() == 0
1039 || (outsideNeighbors.size() <= 1
1040 && clusterNeighbors.size() == 1
1042 cluster.erase(check);
1044#ifdef DEBUG_JOINJUNCTIONS
1046 std::cout <<
" pruned n=" << n->
getID() <<
"\n";
1049 }
else if (outsideNeighbors.size() <= 1 && clusterNeighbors.size() == 1) {
1050 geometryLikeTLS.insert(n);
1053 if (!pruneFringe && !pruneNoisyFringe) {
1056 pruneNoisyFringe =
true;
1060 if (remove2TLS && geometryLikeTLS.size() == cluster.size()) {
1068 for (
const NBNode* n1 : cluster) {
1069 for (
const NBNode* n2 : cluster) {
1070 result =
MAX2(result, n1->getPosition().distanceTo2D(n2->getPosition()));
1078 std::set<NBNode*> toRemove;
1079 int maxPassengerLanes = 0;
1080 for (
NBNode* n : cluster) {
1081 for (
NBEdge* edge : n->getEdges()) {
1082 maxPassengerLanes =
MAX2(maxPassengerLanes, edge->getNumLanesThatAllow(
SVC_PASSENGER));
1085 for (
NBNode* n : cluster) {
1086 for (
NBEdge* edge : n->getOutgoingEdges()) {
1090 std::vector<NBNode*> passed;
1093 NBNode* to = edge->getToNode();
1094 while (cluster.count(to) != 0) {
1096 bool goStraight = (std::find(passed.begin(), passed.end(), to) == passed.end()
1101 passed.push_back(to);
1104 if (cur !=
nullptr) {
1115#ifdef DEBUG_JOINJUNCTIONS
1117 std::cout <<
"check edge length " << edge->getID() <<
" (" << length <<
", passed=" << passed.size() <<
", max=" << longThreshold <<
")\n";
1120 if (length > longThreshold) {
1124 const bool keepStart =
getClusterNeighbors(passed.back(), longThreshold, cluster).size() == 1;
1125 const bool keepEnd = !keepStart &&
getClusterNeighbors(n, longThreshold, cluster).size() == 1;
1126#ifdef DEBUG_JOINJUNCTIONS
1128 std::cout <<
"node=" << n->getID() <<
" long edge " << edge->getID() <<
" (" << length <<
", passed=" <<
toString(passed) <<
", max=" << longThreshold <<
") keepStart=" << keepStart <<
" keepEnd=" << keepEnd <<
"\n";
1134 toRemove.insert(passed.begin(), passed.end() - 1);
1136 toRemove.insert(passed.back());
1143 for (std::set<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
1147 return (
int)toRemove.size();
1155 if (e->getLength() > longThreshold) {
1158 NBNode* neighbor = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
1159 if (cluster.count(neighbor) != 0) {
1160 result.insert(neighbor);
1169#ifdef DEBUG_JOINJUNCTIONS
1171 std::cout <<
"pruning slip-lanes at cluster=" <<
joinNamedToString(cluster,
' ') <<
"\n";
1175 if (cluster.size() <= 2) {
1179 for (
NBNode* n : cluster) {
1185#ifdef DEBUG_JOINJUNCTIONS
1187 std::cout <<
" candidate slip-lane start=" << n->
getID() <<
" outgoing=" <<
toString(outgoing) <<
"\n";
1190 for (
NBEdge* contEdge : outgoing) {
1194 double slipLength = contEdge->getLength();
1195 NBNode* cont = contEdge->getToNode();
1199 if (cands.count(cont) != 0) {
1203#ifdef DEBUG_JOINJUNCTIONS
1205 std::cout <<
" candidate slip-lane cont=" << cont->
getID() <<
"\n";
1212#ifdef DEBUG_JOINJUNCTIONS
1214 std::cout <<
" candidate slip-lane end=" << cont->
getID() <<
" slipLength=" << slipLength <<
"\n";
1221 const NBEdge*
const otherEdge = (contEdge == outgoing.front() ? outgoing.back() : outgoing.front());
1224 std::vector<NodeAndDist> toProc;
1227 while (!toProc.empty()) {
1229 NBNode* cont2 = nodeAndDist.first;
1230 double dist = nodeAndDist.second;
1231#ifdef DEBUG_JOINJUNCTIONS
1233 std::cout <<
" search alternative cont2=" << cont2->
getID() <<
" dist=" << dist <<
"\n";
1237 if (visited.find(cont2) != visited.end()) {
1240 visited.insert(cont2);
1241 if (cont2 == cont) {
1246 const double dist2 = dist + e->getLength();
1247 if (dist2 < slipLength * 2 && (e->getPermissions() &
SVC_PASSENGER) != 0) {
1248 toProc.push_back(std::make_pair(e->getToNode(), dist2));
1255 toRemove.insert(cands.begin(), cands.end());
1256#ifdef DEBUG_JOINJUNCTIONS
1258 std::cout <<
" found slip-lane with nodes=" <<
joinNamedToString(cands,
' ') <<
"\n";
1271#ifdef DEBUG_JOINJUNCTIONS
1273 std::cout <<
" candidate slip-lane end=" << n->getID() <<
" incoming=" <<
toString(incoming) <<
"\n";
1276 for (
NBEdge* contEdge : incoming) {
1280 double slipLength = contEdge->getLength();
1281 NBNode* cont = contEdge->getFromNode();
1285 if (cands.count(cont) != 0) {
1289#ifdef DEBUG_JOINJUNCTIONS
1291 std::cout <<
" candidate slip-lane cont=" << cont->
getID() <<
"\n";
1298#ifdef DEBUG_JOINJUNCTIONS
1300 std::cout <<
" candidate slip-lane start=" << cont->
getID() <<
" slipLength=" << slipLength <<
"\n";
1307 const NBEdge*
const otherEdge = (contEdge == incoming.front() ? incoming.back() : incoming.front());
1310 std::vector<NodeAndDist> toProc;
1313 while (!toProc.empty()) {
1315 NBNode* cont2 = nodeAndDist.first;
1316 double dist = nodeAndDist.second;
1317#ifdef DEBUG_JOINJUNCTIONS
1319 std::cout <<
" search alternative cont2=" << cont2->
getID() <<
" dist=" << dist <<
"\n";
1323 if (visited.find(cont2) != visited.end()) {
1326 visited.insert(cont2);
1327 if (cont2 == cont) {
1332 const double dist2 = dist + e->getLength();
1333 if (dist2 < slipLength * 2 && (e->getPermissions() &
SVC_PASSENGER) != 0) {
1334 toProc.push_back(std::make_pair(e->getFromNode(), dist2));
1341 toRemove.insert(cands.begin(), cands.end());
1342#ifdef DEBUG_JOINJUNCTIONS
1344 std::cout <<
" found slip-lane start with nodes=" <<
joinNamedToString(cands,
' ') <<
"\n";
1356 for (
NBNode* n : toRemove) {
1357 numRemoved += (int)cluster.erase(n);
1359 if (numRemoved > 0) {
1360#ifdef DEBUG_JOINJUNCTIONS
1362 std::cout <<
" removed " << numRemoved <<
" nodes from cluster: " <<
joinNamedToString(toRemove,
' ') <<
"\n";
1380 if (inPE.size() == 1 && outPE.size() == 2) {
1381 outgoing.insert(outgoing.begin(), outPE.begin(), outPE.end());
1382 inAngle = inPE.front()->getAngleAtNode(n);
1384 }
else if (inPE.size() >= 2 && outPE.size() == 3) {
1387 const double inRelAngle = fabs(
NBHelpers::relAngle(inPE.front()->getAngleAtNode(n), inPE.back()->getAngleAtNode(n)));
1389 if (inRelAngle < 135) {
1392 for (
NBEdge* in : inPE) {
1395 for (
NBEdge* out : outPE) {
1396 const double outRelAngle = fabs(
NBHelpers::relAngle(in->getAngleAtNode(n), out->getAngleAtNode(n)));
1397 if (outRelAngle <= 45) {
1398 straight.push_back(out);
1399 }
else if (outRelAngle >= 135) {
1403 if (straight.size() == 2 && numReverse == 1) {
1404 outgoing.insert(outgoing.begin(), straight.begin(), straight.end());
1405 inAngle = in->getAngleAtNode(n);
1418 if (inPE.size() == 2 && outPE.size() == 1) {
1419 incoming.insert(incoming.begin(), inPE.begin(), inPE.end());
1420 outAngle = outPE.front()->getAngleAtNode(n);
1422 }
else if (inPE.size() == 3 && outPE.size() >= 2) {
1425 const double outRelAngle = fabs(
NBHelpers::relAngle(outPE.front()->getAngleAtNode(n), outPE.back()->getAngleAtNode(n)));
1427 if (outRelAngle < 135) {
1430 for (
NBEdge* out : outPE) {
1433 for (
NBEdge* in : inPE) {
1434 const double inRelAngle = fabs(
NBHelpers::relAngle(in->getAngleAtNode(n), out->getAngleAtNode(n)));
1435 if (inRelAngle <= 45) {
1436 straight.push_back(in);
1437 }
else if (inRelAngle >= 135) {
1441 if (straight.size() == 2 && numReverse == 1) {
1442 incoming.insert(incoming.begin(), straight.begin(), straight.end());
1443 outAngle = out->getAngleAtNode(n);
1453 double maxDist, std::string& reason,
NBNode*& tryRemove)
const {
1456 std::map<NBEdge*, double, ComparatorIdLess> finalIncomingAngles;
1457 std::map<NBEdge*, double, ComparatorIdLess> finalOutgoingAngles;
1458 for (
NBNode* n : cluster) {
1459 for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) {
1466 for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) {
1475#ifdef DEBUG_JOINJUNCTIONS
1476 for (
NBNode* n : cluster) {
1485 if (finalIncomingAngles.size() > 5) {
1486 reason =
toString(finalIncomingAngles.size()) +
" incoming edges";
1491 const double PARALLEL_THRESHOLD_SAME_NODE = PARALLEL_THRESHOLD_DIFF_NODE / 3;
1492 bool foundParallel =
false;
1493 for (
auto j = finalIncomingAngles.begin(); j != finalIncomingAngles.end() && !foundParallel; ++j) {
1495 for (++k; k != finalIncomingAngles.end() && !foundParallel; ++k) {
1496 const double angleDiff = fabs(j->second - k->second);
1497 if (angleDiff < PARALLEL_THRESHOLD_DIFF_NODE) {
1502#ifdef DEBUG_JOINJUNCTIONS
1504 std::cout <<
" angleDiff=" << angleDiff <<
" shapeDist=" << edgeDist <<
"\n";
1507 if (angleDiff >= PARALLEL_THRESHOLD_SAME_NODE && (
1509 || (edgeDist < maxDist)))) {
1512 reason =
"parallel incoming " + e1->
getID() +
"," + e2->
getID();
1527 for (
auto j = finalOutgoingAngles.begin(); j != finalOutgoingAngles.end() && !foundParallel; ++j) {
1529 for (++k; k != finalOutgoingAngles.end() && !foundParallel; ++k) {
1530 const double angleDiff = fabs(j->second - k->second);
1531 if (angleDiff < PARALLEL_THRESHOLD_DIFF_NODE) {
1536#ifdef DEBUG_JOINJUNCTIONS
1538 std::cout <<
" angleDiff=" << angleDiff <<
" shapeDist=" << edgeDist <<
"\n";
1541 if (angleDiff >= PARALLEL_THRESHOLD_SAME_NODE && (
1543 || (edgeDist < maxDist)))) {
1546 reason =
"parallel outgoing " + e1->
getID() +
"," + e2->
getID();
1561 bool hasTLS =
false;
1562 for (
NBNode* n : cluster) {
1563 if (n->isTLControlled() || n->hadSignal()) {
1566 const auto& stopEnds = ptStopEnds.find(n);
1567 if (stopEnds != ptStopEnds.end()) {
1568 for (
NBNode*
const to : stopEnds->second) {
1569 if (cluster.count(to) != 0) {
1570 reason =
"it contains a pt stop edge";
1577 if (cluster.size() > 2) {
1579 double maxLength = -1;
1580 NBEdge* maxEdge =
nullptr;
1581 for (
NBNode* n1 : cluster) {
1582 for (
NBNode* n2 : cluster) {
1583 NBEdge* e1 = n1->getConnectionTo(n2);
1584 NBEdge* e2 = n2->getConnectionTo(n1);
1595#ifdef DEBUG_JOINJUNCTIONS
1596 for (
NBNode* n : cluster) {
1598 std::cout <<
"feasible hasTLS=" << hasTLS <<
" maxLength=" << maxLength <<
" maxEdge=" << maxEdge->
getID() <<
"\n";
1602 if (!hasTLS && maxLength > 5) {
1604 std::vector<NBNode*> toCheck;
1605 std::set<NBNode*> visited;
1606 toCheck.push_back(maxEdge->
getToNode());
1607 bool foundCircle =
false;
1608 while (!toCheck.empty()) {
1609 NBNode* n = toCheck.back();
1618 NBNode* cand = e->getFromNode() == n ? e->getToNode() : e->getFromNode();
1619 if (visited.count(cand) == 0 && cluster.count(cand) != 0) {
1620 toCheck.push_back(cand);
1626 reason =
"not compact (maxEdge=" + maxEdge->
getID() +
" length=" +
toString(maxLength) +
")";
1632 if (cluster.size() >= 2) {
1637 int edgesWithin = 0;
1638 for (
NBNode* n : cluster) {
1639 bool foundOutsideIncoming =
false;
1640 for (
NBEdge* e : n->getIncomingEdges()) {
1641 if (cluster.count(e->getFromNode()) == 0) {
1643 outsideIncoming.push_back(e);
1644 foundOutsideIncoming =
true;
1649 if (foundOutsideIncoming) {
1652 bool foundOutsideOutgoing =
false;
1653 for (
NBEdge* e : n->getOutgoingEdges()) {
1654 if (cluster.count(e->getToNode()) == 0) {
1656 outsideOutgoing.push_back(e);
1657 foundOutsideOutgoing =
true;
1660 if (foundOutsideOutgoing) {
1665 if (entryNodes < 2) {
1666 reason =
"only 1 entry node";
1669 if (exitNodes < 2) {
1670 reason =
"only 1 exit node";
1673 if (cluster.size() == 2) {
1674 if (edgesWithin == 1 && outsideIncoming.size() < 3 && outsideOutgoing.size() < 3) {
1675 reason =
"only 1 edge within and no cross-traffic";
1694 std::cout <<
"reduceToCircle cs=" << circleSize <<
" cands=" <<
toString(cands,
',') <<
" startNodes=" <<
joinNamedToString(startNodes,
',') <<
"\n";
1696 assert(circleSize >= 2);
1697 if ((
int)cands.size() == circleSize) {
1698 if (cands.back()->getConnectionTo(cands.front()) !=
nullptr) {
1701 candCluster.insert(cands.begin(), cands.end());
1703 bool feasible = (int)candCluster.size() == circleSize;
1706 cluster.insert(cands.begin(), cands.end());
1713 if ((
int)cluster.size() <= circleSize || startNodes.size() == 0) {
1716 std::cout <<
" abort\n";
1720 if (cands.size() == 0) {
1726 if (
reduceToCircle(cluster, circleSize, startNodes, maxDist, cands)) {
1735 singleStart.insert(cands.back());
1738 std::vector<NBNode*> cands2(cands);
1740 if (
reduceToCircle(cluster, circleSize, startNodes, maxDist, cands2)) {
1746 std::cout <<
" abort2\n";
1754 double minDist = std::numeric_limits<double>::max();
1755 NBEdge* result =
nullptr;
1756 for (
NBNode* n : startNodes) {
1757 for (
NBEdge* e : n->getOutgoingEdges()) {
1758 NBNode* neigh = e->getToNode();
1759 if (cluster.count(neigh) != 0 && std::find(exclude.begin(), exclude.end(), neigh) == exclude.end()) {
1762 if (dist < minDist) {
1776 for (
NodeSet cluster : clusters) {
1785 assert(cluster.size() > 1);
1786 std::string
id =
"cluster_";
1792 std::set<NBEdge*, ComparatorIdLess> allEdges;
1793 for (
NBNode* n : cluster) {
1795 allEdges.insert(edges.begin(), edges.end());
1798 std::set<NBEdge*, ComparatorIdLess> clusterIncoming;
1799 std::set<NBEdge*, ComparatorIdLess> inside;
1800 for (
NBEdge* e : allEdges) {
1801 if (cluster.count(e->getToNode()) > 0) {
1802 if (cluster.count(e->getFromNode()) > 0) {
1809 clusterIncoming.insert(e);
1813#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1815 <<
" resetConnections=" << resetConnections <<
"\n"
1820 NBNode* newNode =
nullptr;
1821 if (predefined !=
nullptr) {
1822 newNode = predefined;
1831 std::string tlID = id;
1832 if (predefined !=
nullptr) {
1834 nodeType = predefined->
getType();
1847 newNode->
reinit(pos, nodeType);
1853 if (!tlc.
insert(tlDef)) {
1861 std::map<NBEdge*, EdgeSet> reachable;
1862 std::map<std::pair<NBEdge*, NBEdge*>,
SVCPermissions> conPermissions;
1864 for (
NBEdge*
const e : clusterIncoming) {
1868 while (open.size() > 0) {
1869 NBEdge*
const cur = open.back();
1871#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1872 std::cout <<
"e=" << e->getID() <<
" cur=" << cur->
getID() <<
" open=" <<
toString(open) <<
"\n";
1873 std::cout <<
"e=" << e->getID() <<
" cur=" << cur->
getID() <<
" open=" <<
toString(open) <<
"\n";
1877 if (cluster.count(cur->
getToNode()) == 0) {
1885 if (allEdges.count(out) != 0) {
1887 if (seen.count(out) == 0 || (~conPermissions[ {e, out}] & p) != 0) {
1889 open.push_back(out);
1890 conPermissions[ {e, out}] |= p;
1891#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1900 for (
const auto& con : cons) {
1901 if (con.toEdge !=
nullptr && allEdges.count(con.toEdge) != 0) {
1904 p &= con.permissions;
1906 if (seen.count(con.toEdge) == 0 || (~conPermissions[ {e, con.toEdge}] & p) != 0) {
1907 open.push_back(con.toEdge);
1908 conPermissions[ {e, con.toEdge}] |= p;
1916 for (
NBEdge* reached : seen) {
1918 if (inside.count(reached) == 0) {
1923 reachable[e].insert(reached);
1924 const SVCPermissions pDefault = e->getPermissions() & reached->getPermissions();
1925 if (conPermissions[ {e, reached}] != pDefault) {
1926 specialPermissions.insert(e);
1927#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1928 std::cout <<
"e=" << e->getID() <<
" out=" << reached->getID() <<
" special=" <<
getVehicleClassNames(conPermissions[ {e, reached}]) <<
"\n";
1933#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1934 std::cout <<
" reachable e=" << e->getID() <<
" seen=" <<
toString(seen) <<
" reachable=" <<
toString(reachable[e]) <<
"\n";
1942 for (
NBEdge* e : inside) {
1943 for (
NBEdge* e2 : allEdges) {
1945 e2->replaceInConnections(e, e->getConnections());
1953 for (
NBEdge* e : allEdges) {
1954 const bool outgoing = cluster.count(e->getFromNode()) > 0;
1955 NBNode* from = outgoing ? newNode : e->getFromNode();
1956 NBNode* to = outgoing ? e->getToNode() : newNode;
1959 e->
setParameter(
"origFrom", e->getFromNode()->getID());
1961 e->setParameter(
"origTo", e->getToNode()->getID());
1964 if (e->getTurnSignTarget() !=
"") {
1965 for (
NBNode* n : cluster) {
1966 if (e->getTurnSignTarget() == n->getID()) {
1967 e->setTurnSignTarget(to->
getID());
1972 e->reinitNodes(from, to);
1975 std::vector<NBEdge::Connection> conns = e->getConnections();
1976 for (std::vector<NBEdge::Connection>::iterator k = conns.begin(); k != conns.end(); ++k) {
1977 if ((*k).toEdge ==
nullptr) {
1982 if ((*k).fromLane >= 0 && (*k).fromLane < e->getNumLanes() && e->getLaneStruct((*k).fromLane).connectionsDone) {
1985#ifdef DEBUG_JOINJUNCTIONS_CONNECTIONS
1986 std::cout <<
" e=" << e->getID() <<
" declareConnectionsAsLoaded\n";
1991 if (!resetConnections) {
1996 if (reachable[in].count(out) == 0) {
1999 in->removeFromConnections(out, -1, -1,
true,
false,
true);
2003 }
else if (specialPermissions.count(in) != 0) {
2004 SVCPermissions pDefault = in->getPermissions() & out->getPermissions();
2005 SVCPermissions p = conPermissions[ {in, out}] == 0 ? pDefault : conPermissions[ {in, out}];
2006 in->addEdge2EdgeConnection(out,
true, p == pDefault ?
SVC_UNSPECIFIED : p);
2013 in->invalidateConnections(
true);
2019 for (
NBNode* n : cluster) {
2027 std::set<std::string> ids;
2028 for (
NBNode* n : cluster) {
2029 ids.insert(n->getID());
2052 bool ambiguousType =
false;
2053 for (
NBNode* j : cluster) {
2054 pos.
add(j->getPosition());
2056 if (j->isTLControlled()) {
2059 type = (*j->getControllingTLS().begin())->getType();
2060 }
else if (type != (*j->getControllingTLS().begin())->getType()) {
2061 ambiguousType =
true;
2067 nodeType = otherType;
2068 }
else if (nodeType != otherType) {
2080 pos.
mul(1. / (
double)cluster.size());
2081 if (ambiguousType) {
2091 bool tooFast =
false;
2092 double laneSpeedSum = 0;
2093 std::set<NBEdge*> seen;
2095 for (
const NBEdge* e : j->getEdges()) {
2096 if (c.find(e->getFromNode()) != c.end() && c.find(e->getToNode()) != c.end()) {
2100 if (j->hasIncoming(e)) {
2101 if (recheck && !j->hasConflict(e)) {
2106 laneSpeedSum += (double)e->getNumLanes() * e->getLaneSpeed(0);
2108 if (e->getLaneSpeed(0) * 3.6 > 79) {
2114 return !tooFast && laneSpeedSum >= laneSpeedThreshold && c.size() != 0;
2124 for (
NBEdge* e : node->getIncomingEdges()) {
2126 nonPedIncoming.push_back(e);
2129 for (
NBEdge* e : node->getOutgoingEdges()) {
2131 nonPedOutgoing.push_back(e);
2134 if (!node->geometryLike(nonPedIncoming, nonPedOutgoing)) {
2150 if (node->isTLControlled()) {
2156 const std::string tlID = tl->
getID();
2157 if (tlID != node->getID()
2173 const double laneSpeedThreshold = oc.
getFloat(
"tls.guess.threshold");
2174 if (oc.
isSet(
"tls.unset")) {
2175 std::vector<std::string> notTLControlledNodes = oc.
getStringVector(
"tls.unset");
2176 for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) {
2179 throw ProcessError(
TLF(
" The junction '%' to set as not-controlled is not known.", *i));
2182 for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) {
2183 (*j)->removeNode(n);
2193 if (oc.
exists(
"tls.taz-nodes") && oc.
getBool(
"tls.taz-nodes")) {
2194 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2195 NBNode* cur = (*i).second;
2204 if (oc.
exists(
"tls.guess-signals") && oc.
getBool(
"tls.guess-signals")) {
2206 const double signalDist = oc.
getFloat(
"tls.guess-signals.dist");
2207 for (
const auto& item :
myNodes) {
2208 const NBNode* node = item.second;
2210#ifdef DEBUG_GUESSSIGNALS
2212 std::cout <<
" propagate TLS from " << node->
getID() <<
" downstream\n";
2218 edge->setSignalPosition(node->
getPosition(), node);
2223 std::set<NBEdge*> seen;
2224 std::set<NBEdge*> check;
2225 for (
const auto& item :
myNodes) {
2226 for (
NBEdge* edge : item.second->getOutgoingEdges()) {
2230#ifdef DEBUG_GUESSSIGNALS
2231 if (
DEBUGCOND(edge->getSignalNode()) ||
true) {
2232 std::cout <<
" primary signalPosition edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2239 while (check.size() > 0) {
2240 NBEdge*
const edge = *check.begin();
2241 check.erase(check.begin());
2246 if (seen.count(outEdge) == 0) {
2248#ifdef DEBUG_GUESSSIGNALS
2250 std::cout <<
" setSignalPosition edge=" << outEdge->
getID() <<
" pos=" << edge->
getSignalPosition() <<
"\n";
2253 check.insert(outEdge);
2260 const int slack = oc.
getInt(
"tls.guess-signals.slack");
2261 for (std::map<std::string, NBNode*>::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2262 NBNode* node = i->second;
2271 std::vector<const NBNode*> signals;
2272 int foundSignals = 0;
2273 int missingSignals = 0;
2275 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2276 const NBEdge* inEdge = *it_i;
2279#ifdef DEBUG_GUESSSIGNALS
2281 std::cout <<
" noTLS, edge=" << inEdge->
getID() <<
"\n";
2285 if (missingSignals > slack) {
2294 int foundSignalsAtDist = 0;
2295 if (foundSignals > 1 && missingSignals <= slack && missingSignals < foundSignals) {
2299 for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) {
2300 const NBEdge* inEdge = *it_i;
2303#ifdef DEBUG_GUESSSIGNALS
2309 if (missingSignals > slack) {
2314 foundSignalsAtDist++;
2317 if (signal !=
nullptr) {
2318 signals.push_back(signal);
2323 for (
const NBEdge* outEdge : outgoing) {
2324 NBNode* cand = outEdge->getToNode();
2326#ifdef DEBUG_GUESSSIGNALS
2328 std::cout <<
" node=" << node->
getID() <<
" outEdge=" << outEdge->getID() <<
" signalNode=" << cand->
getID() <<
" len=" << outEdge->getLength() <<
"\n";
2331 signals.push_back(cand);
2335 if (foundSignalsAtDist > 1 && missingSignals <= slack && missingSignals < foundSignalsAtDist) {
2336 for (
const NBNode* s : signals) {
2337 std::set<NBTrafficLightDefinition*> tls = s->getControllingTLS();
2339 for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) {
2346 if (!tlc.
insert(tlDef)) {
2358 if (oc.
getBool(
"tls.guess.joining")) {
2363 for (NodeClusters::iterator i = cands.begin(); i != cands.end();) {
2367 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2368 if ((*j)->isTLControlled() ||
myUnsetTLS.count(*j) != 0) {
2383 for (
auto nodeSet : cands) {
2384 std::vector<NBNode*> nodes;
2385 for (
NBNode* node : nodeSet) {
2386 nodes.push_back(node);
2391 if (!tlc.
insert(tlDef)) {
2401 if (oc.
getBool(
"tls.guess")) {
2402 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2403 NBNode* cur = (*i).second;
2426 std::set<NBTrafficLightDefinition*> recompute;
2429 const std::set<NBTrafficLightDefinition*>& tlDefs = node->getControllingTLS();
2430 recompute.insert(tlDefs.begin(), tlDefs.end());
2431 node->removeTrafficLights(
true);
2432 for (
NBEdge* edge : node->getIncomingEdges()) {
2433 edge->clearControllingTLInformation();
2438 if (def->getNodes().size() == 0) {
2441 def->setParticipantsInformation();
2442 def->setTLControllingInformation();
2467 for (
const auto& item :
myNodes) {
2468 item.second->computeKeepClear();
2476 for (
const std::string& tlsID : excludeList) {
2477 if (!tlc.
exist(tlsID,
false)) {
2478 WRITE_WARNINGF(
"Unknown tls ID '%' in option tls.join-exclude", tlsID);
2481 std::set<std::string> exclude(excludeList.begin(), excludeList.end());
2485 for (NodeSet::iterator j = c.begin(); j != c.end();) {
2486 if (!(*j)->isTLControlled() || exclude.count((*(*j)->getControllingTLS().begin())->getID()) != 0) {
2497 bool dummySetTL =
false;
2498 std::string
id =
"joinedS_";
2503 std::set<NBTrafficLightDefinition*> tls = j->getControllingTLS();
2504 j->removeTrafficLights();
2509 std::vector<NBNode*> nodes;
2514 if (!tlc.
insert(tlDef)) {
2531 if (!tlc.
insert(tlDef)) {
2533 WRITE_WARNINGF(
TL(
"Building a tl-logic for junction '%' twice is not possible."),
id);
2543 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2544 (*i).second->computeLanes2Lanes();
2552 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2553 (*i).second->computeLogic(ec);
2560 std::set<NBNode*> roundaboutNodes;
2561 const bool checkLaneFoesAll = oc.
getBool(
"check-lane-foes.all");
2562 const bool checkLaneFoesRoundabout = !checkLaneFoesAll && oc.
getBool(
"check-lane-foes.roundabout");
2563 if (checkLaneFoesRoundabout) {
2565 for (std::set<EdgeSet>::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
2566 for (EdgeSet::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
2567 roundaboutNodes.insert((*j)->getToNode());
2571 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2572 const bool checkLaneFoes = checkLaneFoesAll || (checkLaneFoesRoundabout && roundaboutNodes.count((*i).second) > 0);
2573 (*i).second->computeLogic2(checkLaneFoes);
2580 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2581 delete ((*i).second);
2594 std::string freeID =
"SUMOGenerated" + toString<int>(counter);
2596 while (
retrieve(freeID) !=
nullptr) {
2599 freeID =
"SUMOGenerated" + toString<int>(counter);
2607 for (NodeCont::iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2608 (*i).second->computeNodeShape(mismatchThreshold);
2615 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2618 int numUnregulatedJunctions = 0;
2619 int numDeadEndJunctions = 0;
2620 int numTrafficLightJunctions = 0;
2621 int numPriorityJunctions = 0;
2622 int numRightBeforeLeftJunctions = 0;
2623 int numLeftBeforeRightJunctions = 0;
2624 int numAllWayStopJunctions = 0;
2625 int numZipperJunctions = 0;
2626 int numDistrictJunctions = 0;
2627 int numRailCrossing = 0;
2628 int numRailSignals = 0;
2629 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); i++) {
2630 switch ((*i).second->getType()) {
2632 ++numUnregulatedJunctions;
2635 ++numDeadEndJunctions;
2640 ++numTrafficLightJunctions;
2644 ++numPriorityJunctions;
2647 ++numRightBeforeLeftJunctions;
2650 ++numLeftBeforeRightJunctions;
2653 ++numAllWayStopJunctions;
2656 ++numZipperJunctions;
2659 ++numDistrictJunctions;
2676 if (numDeadEndJunctions > 0) {
2681 if (numLeftBeforeRightJunctions > 0) {
2684 if (numTrafficLightJunctions > 0) {
2687 if (numAllWayStopJunctions > 0) {
2690 if (numZipperJunctions > 0) {
2693 if (numRailCrossing > 0) {
2696 if (numRailSignals > 0) {
2699 if (numDistrictJunctions > 0) {
2707 WRITE_MESSAGE(
TL(
"-----------------------------------------------------"));
2711std::vector<std::string>
2713 std::vector<std::string> ret;
2714 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2715 ret.push_back((*i).first);
2724 const auto nodeContainerCopy =
myNodes;
2726 for (
const auto& node : nodeContainerCopy) {
2727 node.second->setID(prefix + node.second->getID());
2728 myNodes[node.second->getID()] = node.second;
2735 if (
myNodes.count(newID) != 0) {
2736 throw ProcessError(
TLF(
"Attempt to rename node using existing id '%'", newID));
2746 for (NodeCont::const_iterator i =
myNodes.begin(); i !=
myNodes.end(); ++i) {
2747 NBNode* node = i->second;
2751 if (geometryLike && (*tldefs.begin())->getNodes().size() > 1) {
2761 edge->setSignalPosition(node->
getPosition(),
nullptr);
2762#ifdef DEBUG_GUESSSIGNALS
2763 std::cout <<
" discard-simple " << node->
getID() <<
" edge=" << edge->getID() <<
" pos=" << edge->getSignalPosition() <<
"\n";
2766 for (std::set<NBTrafficLightDefinition*>::const_iterator it = tldefs.begin(); it != tldefs.end(); ++it) {
2781 NBNode* node = item.second;
2792 if (!numericaIDs && !reservedIDs && prefix ==
"" && !startGiven) {
2795 std::vector<std::string> avoid;
2801 std::set<std::string> reserve;
2805 avoid.insert(avoid.end(), reserve.begin(), reserve.end());
2809 for (NodeCont::iterator it =
myNodes.begin(); it !=
myNodes.end(); it++) {
2811 toChange.insert(it->second);
2818 toChange.insert(it->second);
2821 if (reservedIDs && reserve.count(it->first) > 0) {
2822 toChange.insert(it->second);
2826 for (
NBNode* node : toChange) {
2829 for (
NBNode* node : toChange) {
2833 node->setID(idSupplier.
getNext());
2835 tlc.
rename(tlDef, node->getID());
2837 myNodes[node->getID()] = node;
2839 if (prefix.empty()) {
2840 return (
int)toChange.size();
2845 for (
auto item : oldNodes) {
2847 rename(item.second, prefix + item.first);
2850 tlc.
rename(tlDef, prefix + tlDef->getID());
2868 for (
const auto& item :
myNodes) {
2871 paretoCheck(item.second, bottomRightFront, 1, -1);
2872 paretoCheck(item.second, bottomLeftFront, -1, -1);
2875 front.insert(topRightFront.begin(), topRightFront.end());
2876 front.insert(topLeftFront.begin(), topLeftFront.end());
2877 front.insert(bottomRightFront.begin(), bottomRightFront.end());
2878 front.insert(bottomLeftFront.begin(), bottomLeftFront.end());
2880 for (
NBNode* n : front) {
2881 const int in = (int)n->getIncomingEdges().size();
2882 const int out = (int)n->getOutgoingEdges().size();
2883 if ((in <= 1 && out <= 1) &&
2884 (in == 0 || out == 0
2885 || n->getIncomingEdges().front()->isTurningDirectionAt(n->getOutgoingEdges().front()))) {
2892 for (
const auto& item :
myNodes) {
2894 if (front.count(n) != 0) {
2897 if (n->
getEdges().size() == 1 && n->
getEdges().front()->getSpeed() > speedThreshold) {
2910 std::vector<NBNode*> dominated;
2912 const double x2 =
fn->getPosition().x() * xSign;
2913 const double y2 =
fn->getPosition().y() * ySign;
2914 if (x2 >= x && y2 >= y) {
2916 }
else if (x2 <= x && y2 <= y) {
2917 dominated.push_back(
fn);
2920 frontier.insert(node);
2921 for (
NBNode* r : dominated) {
2929 for (
const auto& item :
myNodes) {
2932 bool hasNEMA =
false;
2950 bool hadShapes =
false;
2951 for (
const auto& item :
myNodes) {
2952 if (item.second->getShape().size() > 0 && !item.second->hasCustomShape()) {
2954 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 (exclusive) 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.
int getNumLanesThatAllow(SVCPermissions permissions, bool allPermissions=true) const
@ 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.
int getPriority() const
Returns the priority of the edge.
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
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
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)
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.
void pruneClusterFringe(NodeSet &cluster, double maxDist, bool remove2TLS=false) const
remove geometry-like fringe nodes from cluster
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.
bool feasibleCluster(const NodeSet &cluster, const std::map< const NBNode *, std::vector< NBNode * > > &ptStopEnds, double maxDist, std::string &reason, NBNode *&tryRemove) const
determine wether the cluster is not too complex for joining
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)
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
get key
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.