void GNEJunction::setLogicValid(bool valid, GNEUndoList* undoList, const std::string& status) { myHasValidLogic = valid; if (!valid) { assert(undoList != 0); assert(undoList->hasCommandGroup()); undoList->add(new GNEChange_Attribute(this, GNE_ATTR_MODIFICATION_STATUS, status)); // allow edges to recompute their connections NBTurningDirectionsComputer::computeTurnDirectionsForNode(&myNBNode, false); EdgeVector incoming = EdgeVector(myNBNode.getIncomingEdges()); for (EdgeVector::iterator it = incoming.begin(); it != incoming.end(); it++) { NBEdge* srcNBE = *it; NBEdge* turnEdge = srcNBE->getTurnDestination(); GNEEdge* srcEdge = myNet->retrieveEdge(srcNBE->getID()); std::vector<NBEdge::Connection> connections = srcNBE->getConnections(); // make a copy! // delete in reverse so that undoing will add connections in the original order for (std::vector<NBEdge::Connection>::reverse_iterator con_it = connections.rbegin(); con_it != connections.rend(); con_it++) { bool hasTurn = con_it->toEdge == turnEdge; undoList->add(new GNEChange_Connection( srcEdge, con_it->fromLane, con_it->toEdge->getID(), con_it->toLane, con_it->mayDefinitelyPass, false), true); // needs to come after GNEChange_Connection // XXX bug: this code path will not be used on a redo! if (hasTurn) { myNet->addExplicitTurnaround(srcNBE->getID()); } } undoList->add(new GNEChange_Attribute(srcEdge, GNE_ATTR_MODIFICATION_STATUS, status), true); } invalidateTLS(undoList); } else { rebuildCrossings(false); } }
void NBNodeCont::joinSimilarEdges(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) { // magic values SUMOReal distanceThreshold = 7; // don't merge edges further apart SUMOReal lengthThreshold = 0.05; // don't merge edges with higher relative length-difference for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { // count the edges to other nodes outgoing from the current node std::map<NBNode*, EdgeVector> connectionCount; const EdgeVector& outgoing = (*i).second->getOutgoingEdges(); for (EdgeVector::const_iterator j = outgoing.begin(); j != outgoing.end(); j++) { NBEdge* e = (*j); NBNode* connected = e->getToNode(); if (connectionCount.find(connected) == connectionCount.end()) { connectionCount[connected] = EdgeVector(); } connectionCount[connected].push_back(e); } // check whether more than a single edge connect another node and join them std::map<NBNode*, EdgeVector>::iterator k; for (k = connectionCount.begin(); k != connectionCount.end(); k++) { // possibly we do not have anything to join... if ((*k).second.size() < 2) { continue; } // for the edges that seem to be a single street, // check whether the geometry is similar const EdgeVector& ev = (*k).second; const NBEdge* const first = ev.front(); EdgeVector::const_iterator jci; // join candidate iterator for (jci = ev.begin() + 1; jci != ev.end(); ++jci) { const SUMOReal relativeLengthDifference = fabs(first->getLoadedLength() - (*jci)->getLoadedLength()) / first->getLoadedLength(); if ((!first->isNearEnough2BeJoined2(*jci, distanceThreshold)) || (relativeLengthDifference > lengthThreshold) || (first->getSpeed() != (*jci)->getSpeed()) // @todo check vclass ) { break; } } // @bug If there are 3 edges of which 2 can be joined, no joining will // take place with the current implementation if (jci == ev.end()) { ec.joinSameNodeConnectingEdges(dc, tlc, ev); } } } }
void NBEdgeCont::guessRoundabouts(std::vector<EdgeVector>& marked) { // step 1: keep only those edges which have no turnarounds std::set<NBEdge*> candidates; for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) { NBEdge* e = (*i).second; NBNode* const to = e->getToNode(); if (e->getTurnDestination() == 0 && to->getConnectionTo(e->getFromNode()) == 0) { candidates.insert(e); } } // step 2: std::set<NBEdge*> visited; for (std::set<NBEdge*>::const_iterator i = candidates.begin(); i != candidates.end(); ++i) { EdgeVector loopEdges; // start with a random edge (this doesn't have to be a roundabout edge) // loop over connected edges (using always the leftmost one) // and keep the list in loopEdges // continue until we loop back onto a loopEdges and extract the loop NBEdge* e = (*i); if (visited.count(e) > 0) { // already seen continue; } loopEdges.push_back(e); bool doLoop = true; do { visited.insert(e); const EdgeVector& edges = e->getToNode()->getEdges(); if (edges.size() < 2) { doLoop = false; break; } if (e->getTurnDestination() != 0 || e->getToNode()->getConnectionTo(e->getFromNode()) != 0) { // do not follow turn-arounds while in a (tentative) loop doLoop = false; break; } EdgeVector::const_iterator me = find(edges.begin(), edges.end(), e); NBContHelper::nextCW(edges, me); NBEdge* left = *me; SUMOReal angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), left->getAngleAtNode(e->getToNode()))); if (angle >= 90) { // roundabouts do not have sharp turns (or they wouldn't be called 'round') doLoop = false; break; } EdgeVector::const_iterator loopClosed = find(loopEdges.begin(), loopEdges.end(), left); const size_t loopSize = loopEdges.end() - loopClosed; if (loopSize > 0) { // loop found if (loopSize < 3) { doLoop = false; // need at least 3 edges for a roundabout } else if (loopSize < loopEdges.size()) { // remove initial edges not belonging to the loop EdgeVector(loopEdges.begin() + (loopEdges.size() - loopSize), loopEdges.end()).swap(loopEdges); } // count attachments to the outside. need at least 3 or a roundabout doesn't make much sense int attachments = 0; for (EdgeVector::const_iterator j = loopEdges.begin(); j != loopEdges.end(); ++j) { if ((*j)->getToNode()->getEdges().size() > 2) { attachments++; } } if (attachments < 3) { doLoop = false; } break; } if (visited.count(left) > 0) { doLoop = false; } else { // keep going loopEdges.push_back(left); e = left; } } while (doLoop); // mark collected edges in the case a loop (roundabout) was found if (doLoop) { std::set<NBEdge*> loopEdgesSet(loopEdges.begin(), loopEdges.end()); for (std::set<NBEdge*>::const_iterator j = loopEdgesSet.begin(); j != loopEdgesSet.end(); ++j) { // disable turnarounds on incoming edges NBNode* node = (*j)->getToNode(); const EdgeVector& incoming = node->getIncomingEdges(); for (EdgeVector::const_iterator k = incoming.begin(); k != incoming.end(); ++k) { NBEdge* inEdge = *k; if (loopEdgesSet.count(inEdge) > 0) { continue; } if ((inEdge)->getStep() >= NBEdge::LANES2LANES_USER) { continue; } inEdge->removeFromConnections(inEdge->getTurnDestination(), -1); } // let the connections to succeeding roundabout edge have a higher priority (*j)->setJunctionPriority(node, 1000); } marked.push_back(loopEdges); } } }