unsigned int NBNodeCont::joinJunctions(SUMOReal maxdist, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) { NodeClusters cands; NodeClusters clusters; generateNodeClusters(maxdist, cands); for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) { std::set<NBNode*> cluster = (*i); // remove join exclusions for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) { std::set<NBNode*>::iterator check = j; ++j; if (myJoinExclusions.count((*check)->getID()) > 0) { cluster.erase(check); } } // iteratively remove the fringe bool pruneFringe = true; while (pruneFringe) { pruneFringe = false; for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) { std::set<NBNode*>::iterator check = j; NBNode* n = *check; ++j; // remove nodes with degree <= 2 at fringe of the cluster (at least one edge leads to a non-cluster node) if ( (n->getIncomingEdges().size() <= 1 && n->getOutgoingEdges().size() <= 1) && ((n->getIncomingEdges().size() == 0 || (n->getIncomingEdges().size() == 1 && cluster.count(n->getIncomingEdges()[0]->getFromNode()) == 0)) || (n->getOutgoingEdges().size() == 0 || (n->getOutgoingEdges().size() == 1 && cluster.count(n->getOutgoingEdges()[0]->getToNode()) == 0))) ) { cluster.erase(check); pruneFringe = true; // other nodes could belong to the fringe now } } } if (cluster.size() > 1) { // check for clusters which are to complex and probably won't work very well // we count the incoming edges of the final junction std::set<NBEdge*> finalIncoming; std::vector<std::string> nodeIDs; for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) { nodeIDs.push_back((*j)->getID()); const EdgeVector& edges = (*j)->getIncomingEdges(); for (EdgeVector::const_iterator it_edge = edges.begin(); it_edge != edges.end(); ++it_edge) { NBEdge* edge = *it_edge; if (cluster.count(edge->getFromNode()) == 0) { // incoming edge, does not originate in the cluster finalIncoming.insert(edge); } } } if (finalIncoming.size() > 4) { WRITE_WARNING("Not joining junctions " + joinToString(nodeIDs, ',') + " because the cluster is too complex"); } else { clusters.push_back(cluster); } } } joinNodeClusters(clusters, dc, ec, tlc); return (int)clusters.size(); }
void NBNodeCont::joinNodeClusters(NodeClusters clusters, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) { for (NodeClusters::iterator i = clusters.begin(); i != clusters.end(); ++i) { std::set<NBNode*> cluster = *i; assert(cluster.size() > 1); Position pos; bool setTL; std::string id; TrafficLightType type; analyzeCluster(cluster, id, pos, setTL, type); if (!insert(id, pos)) { // should not fail WRITE_WARNING("Could not join junctions " + id); continue; } NBNode* newNode = retrieve(id); if (setTL) { NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, newNode, 0, type); if (!tlc.insert(tlDef)) { // actually, nothing should fail here delete tlDef; throw ProcessError("Could not allocate tls '" + id + "'."); } } // collect edges std::set<NBEdge*> allEdges; for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) { const EdgeVector& edges = (*j)->getEdges(); allEdges.insert(edges.begin(), edges.end()); } // remap and remove edges which are completely within the new intersection for (std::set<NBEdge*>::iterator j = allEdges.begin(); j != allEdges.end();) { NBEdge* e = (*j); NBNode* from = e->getFromNode(); NBNode* to = e->getToNode(); if (cluster.count(from) > 0 && cluster.count(to) > 0) { for (std::set<NBEdge*>::iterator l = allEdges.begin(); l != allEdges.end(); ++l) { if (e != *l) { (*l)->replaceInConnections(e, e->getConnections()); } } ec.erase(dc, e); allEdges.erase(j++); // erase does not invalidate the other iterators } else { ++j; } } // remap edges which are incoming / outgoing for (std::set<NBEdge*>::iterator j = allEdges.begin(); j != allEdges.end(); ++j) { NBEdge* e = (*j); std::vector<NBEdge::Connection> conns = e->getConnections(); const bool outgoing = cluster.count(e->getFromNode()) > 0; NBNode* from = outgoing ? newNode : e->getFromNode(); NBNode* to = outgoing ? e->getToNode() : newNode; e->reinitNodes(from, to); // re-add connections which previously existed and may still valid. // connections to removed edges will be ignored for (std::vector<NBEdge::Connection>::iterator k = conns.begin(); k != conns.end(); ++k) { e->addLane2LaneConnection((*k).fromLane, (*k).toEdge, (*k).toLane, NBEdge::L2L_USER, false, (*k).mayDefinitelyPass); } } // remove original nodes registerJoinedCluster(cluster); for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) { erase(*j); } } }
unsigned int NBNodeCont::joinJunctions(SUMOReal maxDist, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) { NodeClusters cands; NodeClusters clusters; generateNodeClusters(maxDist, cands); for (NodeClusters::iterator i = cands.begin(); i != cands.end(); ++i) { std::set<NBNode*> cluster = (*i); // remove join exclusions for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) { std::set<NBNode*>::iterator check = j; ++j; if (myJoinExclusions.count((*check)->getID()) > 0) { cluster.erase(check); } } // iteratively remove the fringe bool pruneFringe = true; while (pruneFringe) { pruneFringe = false; for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end();) { std::set<NBNode*>::iterator check = j; NBNode* n = *check; ++j; // remove geometry-like nodes at fringe of the cluster // (they have 1 neighbor in the cluster and at most 1 neighbor outside the cluster) std::set<NBNode*> neighbors; std::set<NBNode*> clusterNeigbors; for (EdgeVector::const_iterator it_edge = n->getOutgoingEdges().begin(); it_edge != n->getOutgoingEdges().end(); ++it_edge) { NBNode* neighbor = (*it_edge)->getToNode(); if (cluster.count(neighbor) == 0) { neighbors.insert(neighbor); } else { clusterNeigbors.insert(neighbor); } } for (EdgeVector::const_iterator it_edge = n->getIncomingEdges().begin(); it_edge != n->getIncomingEdges().end(); ++it_edge) { NBNode* neighbor = (*it_edge)->getFromNode(); if (cluster.count(neighbor) == 0) { neighbors.insert(neighbor); } else { clusterNeigbors.insert(neighbor); } } if (neighbors.size() <= 1 && clusterNeigbors.size() == 1) { cluster.erase(check); pruneFringe = true; // other nodes could belong to the fringe now } } } // exclude the fromNode of a long edge if the toNode is in the cluster (and they were both added via an alternative path). std::set<NBNode*> toRemove; for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end(); ++j) { NBNode* n = *j; const EdgeVector& edges = n->getOutgoingEdges(); for (EdgeVector::const_iterator it_edge = edges.begin(); it_edge != edges.end(); ++it_edge) { NBEdge* edge = *it_edge; if (cluster.count(edge->getToNode()) != 0 && edge->getLoadedLength() > maxDist) { //std::cout << "long edge " << edge->getID() << " (" << edge->getLoadedLength() << ", max=" << maxDist << ")\n"; toRemove.insert(n); toRemove.insert(edge->getToNode()); } } } for (std::set<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) { cluster.erase(*j); } if (cluster.size() > 1) { // check for clusters which are to complex and probably won't work very well // we count the incoming edges of the final junction std::set<NBEdge*> finalIncoming; std::set<NBEdge*> finalOutgoing; std::vector<std::string> nodeIDs; for (std::set<NBNode*>::const_iterator j = cluster.begin(); j != cluster.end(); ++j) { nodeIDs.push_back((*j)->getID()); for (EdgeVector::const_iterator it_edge = (*j)->getIncomingEdges().begin(); it_edge != (*j)->getIncomingEdges().end(); ++it_edge) { NBEdge* edge = *it_edge; if (cluster.count(edge->getFromNode()) == 0) { // incoming edge, does not originate in the cluster finalIncoming.insert(edge); } } for (EdgeVector::const_iterator it_edge = (*j)->getOutgoingEdges().begin(); it_edge != (*j)->getOutgoingEdges().end(); ++it_edge) { NBEdge* edge = *it_edge; if (cluster.count(edge->getToNode()) == 0) { // outgoing edge, does not end in the cluster finalOutgoing.insert(edge); } } } if (finalIncoming.size() > 4) { std::sort(nodeIDs.begin(), nodeIDs.end()); WRITE_WARNING("Not joining junctions " + joinToStringSorting(nodeIDs, ',') + " because the cluster is too complex (" + toString(finalIncoming.size()) + " incoming edges)"); } else { // check for incoming parallel edges const SUMOReal PARALLEL_INCOMING_THRESHOLD = 10.0; bool foundParallel = false; for (std::set<NBEdge*>::const_iterator j = finalIncoming.begin(); j != finalIncoming.end() && !foundParallel; ++j) { for (std::set<NBEdge*>::const_iterator k = finalIncoming.begin(); k != finalIncoming.end() && !foundParallel; ++k) { if ((*j) != (*k) && fabs((*j)->getAngleAtNode((*j)->getToNode()) - (*k)->getAngleAtNode((*k)->getToNode())) < PARALLEL_INCOMING_THRESHOLD) { std::vector<std::string> parallelEdgeIDs; parallelEdgeIDs.push_back((*j)->getID()); parallelEdgeIDs.push_back((*k)->getID()); std::sort(parallelEdgeIDs.begin(), parallelEdgeIDs.end()); WRITE_WARNING("Not joining junctions " + joinToStringSorting(nodeIDs, ',') + " because the cluster is too complex (parallel incoming " + joinToString(parallelEdgeIDs, ',') + ")"); foundParallel = true; } } } // check for outgoing parallel edges for (std::set<NBEdge*>::const_iterator j = finalOutgoing.begin(); j != finalOutgoing.end() && !foundParallel; ++j) { for (std::set<NBEdge*>::const_iterator k = finalOutgoing.begin(); k != finalOutgoing.end() && !foundParallel; ++k) { if ((*j) != (*k) && fabs((*j)->getAngleAtNode((*j)->getFromNode()) - (*k)->getAngleAtNode((*k)->getFromNode())) < PARALLEL_INCOMING_THRESHOLD) { std::vector<std::string> parallelEdgeIDs; parallelEdgeIDs.push_back((*j)->getID()); parallelEdgeIDs.push_back((*k)->getID()); std::sort(parallelEdgeIDs.begin(), parallelEdgeIDs.end()); WRITE_WARNING("Not joining junctions " + joinToStringSorting(nodeIDs, ',') + " because the cluster is too complex (parallel outgoing " + joinToStringSorting(parallelEdgeIDs, ',') + ")"); foundParallel = true; } } } if (!foundParallel && cluster.size() > 1) { // compute all connected components of this cluster // (may be more than 1 if intermediate nodes were removed) NodeClusters components; for (std::set<NBNode*>::iterator j = cluster.begin(); j != cluster.end(); ++j) { // merge all connected components into newComp std::set<NBNode*> newComp; NBNode* current = *j; //std::cout << "checking connectivity for " << current->getID() << "\n"; newComp.insert(current); for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end();) { NodeClusters::iterator check = it_comp; //std::cout << " connected with " << toString(*check) << "?\n"; bool connected = false; for (std::set<NBNode*>::iterator k = (*check).begin(); k != (*check).end(); ++k) { if (current->getConnectionTo(*k) != 0 || (*k)->getConnectionTo(current) != 0) { //std::cout << "joining with connected component " << toString(*check) << "\n"; newComp.insert((*check).begin(), (*check).end()); it_comp = components.erase(check); connected = true; break; } } if (!connected) { it_comp++; } } //std::cout << "adding new component " << toString(newComp) << "\n"; components.push_back(newComp); } for (NodeClusters::iterator it_comp = components.begin(); it_comp != components.end(); ++it_comp) { if ((*it_comp).size() > 1) { //std::cout << "adding cluster " << toString(*it_comp) << "\n"; clusters.push_back(*it_comp); } } } } } } joinNodeClusters(clusters, dc, ec, tlc); return (int)clusters.size(); }