// =========================================================================== // method definitions // =========================================================================== // --------------------------------------------------------------------------- // NBRampsComputer // --------------------------------------------------------------------------- void NBRampsComputer::computeRamps(NBNetBuilder& nb, OptionsCont& oc) { SUMOReal minHighwaySpeed = oc.getFloat("ramps.min-highway-speed"); SUMOReal maxRampSpeed = oc.getFloat("ramps.max-ramp-speed"); SUMOReal rampLength = oc.getFloat("ramps.ramp-length"); bool dontSplit = oc.getBool("ramps.no-split"); std::set<NBEdge*> incremented; // check whether on-off ramps shall be guessed if (oc.getBool("ramps.guess")) { NBNodeCont& nc = nb.getNodeCont(); NBEdgeCont& ec = nb.getEdgeCont(); NBDistrictCont& dc = nb.getDistrictCont(); std::set<NBNode*> potOnRamps; std::set<NBNode*> potOffRamps; for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* cur = (*i).second; if (mayNeedOnRamp(cur, minHighwaySpeed, maxRampSpeed)) { potOnRamps.insert(cur); } if (mayNeedOffRamp(cur, minHighwaySpeed, maxRampSpeed)) { potOffRamps.insert(cur); } } for (std::set<NBNode*>::const_iterator i = potOnRamps.begin(); i != potOnRamps.end(); ++i) { buildOnRamp(*i, nc, ec, dc, rampLength, dontSplit, incremented); } for (std::set<NBNode*>::const_iterator i = potOffRamps.begin(); i != potOffRamps.end(); ++i) { buildOffRamp(*i, nc, ec, dc, rampLength, dontSplit, incremented); } } // check whether on-off ramps shall be guessed if (oc.isSet("ramps.set")) { std::vector<std::string> edges = oc.getStringVector("ramps.set"); NBNodeCont& nc = nb.getNodeCont(); NBEdgeCont& ec = nb.getEdgeCont(); NBDistrictCont& dc = nb.getDistrictCont(); for (std::vector<std::string>::iterator i = edges.begin(); i != edges.end(); ++i) { NBEdge* e = ec.retrieve(*i); if (e == 0) { WRITE_WARNING("Can not build on ramp on edge '" + *i + "' - the edge is not known."); continue; } NBNode* from = e->getFromNode(); if (from->getIncomingEdges().size() == 2 && from->getOutgoingEdges().size() == 1) { buildOnRamp(from, nc, ec, dc, rampLength, dontSplit, incremented); } // load edge again to check offramps e = ec.retrieve(*i); if (e == 0) { WRITE_WARNING("Can not build off ramp on edge '" + *i + "' - the edge is not known."); continue; } NBNode* to = e->getToNode(); if (to->getIncomingEdges().size() == 1 && to->getOutgoingEdges().size() == 2) { buildOffRamp(to, nc, ec, dc, rampLength, dontSplit, incremented); } } } }
unsigned int NBNodeCont::removeUnwishedNodes(NBDistrictCont& dc, NBEdgeCont& ec, NBJoinedEdgesMap& je, NBTrafficLightLogicCont& tlc, bool removeGeometryNodes) { unsigned int no = 0; std::vector<NBNode*> toRemove; for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { NBNode* current = (*i).second; bool remove = false; std::vector<std::pair<NBEdge*, NBEdge*> > toJoin; // check for completely empty nodes if (current->getOutgoingEdges().size() == 0 && current->getIncomingEdges().size() == 0) { // remove if empty remove = true; } // check for nodes which are only geometry nodes if (removeGeometryNodes) { if ((current->getOutgoingEdges().size() == 1 && current->getIncomingEdges().size() == 1) || (current->getOutgoingEdges().size() == 2 && current->getIncomingEdges().size() == 2)) { // ok, one in, one out or two in, two out // -> ask the node whether to join remove = current->checkIsRemovable(); if (remove) { toJoin = current->getEdgesToJoin(); } } } // remove the node and join the geometries when wished if (!remove) { continue; } for (std::vector<std::pair<NBEdge*, NBEdge*> >::iterator j = toJoin.begin(); j != toJoin.end(); j++) { NBEdge* begin = (*j).first; NBEdge* continuation = (*j).second; begin->append(continuation); continuation->getToNode()->replaceIncoming(continuation, begin, 0); tlc.replaceRemoved(continuation, -1, begin, -1); je.appended(begin->getID(), continuation->getID()); ec.erase(dc, continuation); } toRemove.push_back(current); no++; } // erase all for (std::vector<NBNode*>::iterator j = toRemove.begin(); j != toRemove.end(); ++j) { erase(*j); } return no; }
void NWWriter_DlrNavteq::writeConnectedLanes(const OptionsCont& oc, NBNodeCont& nc) { OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_connected_lanes.txt"); writeHeader(device, oc); // write format specifier device << "#Lane connections related to LINK-IDs and NODE-ID.\n"; device << "#column format like pointcollection.\n"; device << "#NODE-ID\tVEHICLE-TYPE\tFROM_LANE\tTO_LANE\tTHROUGH_TRAFFIC\tLINK_IDs[2..*]\n"; // write record for every connection for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; const EdgeVector& incoming = n->getIncomingEdges(); for (EdgeVector::const_iterator j = incoming.begin(); j != incoming.end(); ++j) { NBEdge* from = *j; const SVCPermissions fromPerm = from->getPermissions(); const std::vector<NBEdge::Connection>& connections = from->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator it_c = connections.begin(); it_c != connections.end(); it_c++) { const NBEdge::Connection& c = *it_c; device << n->getID() << "\t" << getAllowedTypes(fromPerm & c.toEdge->getPermissions()) << "\t" << c.fromLane + 1 << "\t" // one-based << c.toLane + 1 << "\t" // one-based << 1 << "\t" // no information regarding permissibility of through traffic << from->getID() << "\t" << c.toEdge->getID() << "\t" << "\n"; } } } device.close(); }
void NWWriter_DlrNavteq::writeTrafficSignals(const OptionsCont& oc, NBNodeCont& nc) { OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_traffic_signals.txt"); writeHeader(device, oc); const GeoConvHelper& gch = GeoConvHelper::getFinal(); const bool haveGeo = gch.usingGeoProjection(); const SUMOReal geoScale = pow(10.0f, haveGeo ? 5 : 2); // see NIImporter_DlrNavteq::GEO_SCALE device.setPrecision(0); // write format specifier device << "#Traffic signal related to LINK_ID and NODE_ID with location relative to driving direction.\n#column format like pointcollection.\n#DESCRIPTION->LOCATION: 1-rechts von LINK; 2-links von LINK; 3-oberhalb LINK -1-keineAngabe\n#RELATREC_ID\tPOICOL_TYPE\tDESCRIPTION\tLONGITUDE\tLATITUDE\tLINK_ID\n"; // write record for every edge incoming to a tls controlled node for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; if (n->isTLControlled()) { Position pos = n->getPosition(); gch.cartesian2geo(pos); pos.mul(geoScale); const EdgeVector& incoming = n->getIncomingEdges(); for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) { NBEdge* e = *it; device << e->getID() << "\t" << "12\t" // POICOL_TYPE << "LSA;NODEIDS#" << n->getID() << "#;LOCATION#-1#;\t" << pos.x() << "\t" << pos.y() << "\t" << e->getID() << "\n"; } } } }
NBEdge* NBEdgeCont::retrievePossiblySplit(const std::string& id, const std::string& hint, bool incoming) const { // try to retrieve using the given name (iterative) NBEdge* edge = retrieve(id); if (edge != 0) { return edge; } // now, we did not find it; we have to look over all possibilities EdgeVector hints; // check whether at least the hint was not splitted NBEdge* hintedge = retrieve(hint); if (hintedge == 0) { hints = getGeneratedFrom(hint); } else { hints.push_back(hintedge); } EdgeVector candidates = getGeneratedFrom(id); for (EdgeVector::iterator i = hints.begin(); i != hints.end(); i++) { NBEdge* hintedge = (*i); for (EdgeVector::iterator j = candidates.begin(); j != candidates.end(); j++) { NBEdge* poss_searched = (*j); NBNode* node = incoming ? poss_searched->myTo : poss_searched->myFrom; const EdgeVector& cont = incoming ? node->getOutgoingEdges() : node->getIncomingEdges(); if (find(cont.begin(), cont.end(), hintedge) != cont.end()) { return poss_searched; } } } return 0; }
bool NWWriter_SUMO::writeInternalNodes(OutputDevice& into, const NBNode& n) { bool ret = false; const std::vector<NBEdge*>& incoming = n.getIncomingEdges(); for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); i++) { const std::vector<NBEdge::Connection>& elv = (*i)->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { if ((*k).toEdge == 0 || !(*k).haveVia) { continue; } Position pos = (*k).shape[-1]; into.openTag(SUMO_TAG_JUNCTION).writeAttr(SUMO_ATTR_ID, (*k).viaID + "_0"); into.writeAttr(SUMO_ATTR_TYPE, NODETYPE_INTERNAL); NWFrame::writePositionLong(pos, into); std::string incLanes = (*k).id + "_0"; if ((*k).foeIncomingLanes.length() != 0) { incLanes += " " + (*k).foeIncomingLanes; } into.writeAttr(SUMO_ATTR_INCLANES, incLanes); into.writeAttr(SUMO_ATTR_INTLANES, (*k).foeInternalLanes); into.closeTag(); ret = true; } } return ret; }
void NGNet::toNB() const { std::vector<NBNode*> nodes; for (NGNodeList::const_iterator i1 = myNodeList.begin(); i1 != myNodeList.end(); i1++) { NBNode* node = (*i1)->buildNBNode(myNetBuilder); nodes.push_back(node); myNetBuilder.getNodeCont().insert(node); } for (NGEdgeList::const_iterator i2 = myEdgeList.begin(); i2 != myEdgeList.end(); i2++) { NBEdge* edge = (*i2)->buildNBEdge(myNetBuilder); myNetBuilder.getEdgeCont().insert(edge); } // now, let's append the reverse directions... SUMOReal bidiProb = OptionsCont::getOptions().getFloat("rand.bidi-probability"); for (std::vector<NBNode*>::const_iterator i = nodes.begin(); i != nodes.end(); ++i) { NBNode* node = *i; EdgeVector incoming = node->getIncomingEdges(); for (EdgeVector::const_iterator j = incoming.begin(); j != incoming.end(); ++j) { if (node->getConnectionTo((*j)->getFromNode()) == 0 && RandHelper::rand() <= bidiProb) { NBEdge* back = new NBEdge("-" + (*j)->getID(), node, (*j)->getFromNode(), "", myNetBuilder.getTypeCont().getSpeed(""), myNetBuilder.getTypeCont().getNumLanes(""), myNetBuilder.getTypeCont().getPriority(""), myNetBuilder.getTypeCont().getWidth(""), NBEdge::UNSPECIFIED_OFFSET); myNetBuilder.getEdgeCont().insert(back); } } } }
void NWWriter_SUMO::writeJunction(OutputDevice& into, const NBNode& n) { // write the attributes into.openTag(SUMO_TAG_JUNCTION).writeAttr(SUMO_ATTR_ID, n.getID()); into.writeAttr(SUMO_ATTR_TYPE, n.getType()); NWFrame::writePositionLong(n.getPosition(), into); // write the incoming lanes std::string incLanes; const std::vector<NBEdge*>& incoming = n.getIncomingEdges(); for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); ++i) { unsigned int noLanes = (*i)->getNumLanes(); for (unsigned int j = 0; j < noLanes; j++) { incLanes += (*i)->getLaneID(j); if (i != incoming.end() - 1 || j < noLanes - 1) { incLanes += ' '; } } } into.writeAttr(SUMO_ATTR_INCLANES, incLanes); // write the internal lanes std::string intLanes; if (!OptionsCont::getOptions().getBool("no-internal-links")) { unsigned int l = 0; for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) { const std::vector<NBEdge::Connection>& elv = (*i)->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { if ((*k).toEdge == 0) { continue; } if (l != 0) { intLanes += ' '; } if (!(*k).haveVia) { intLanes += (*k).id + "_0"; } else { intLanes += (*k).viaID + "_0"; } l++; } } } into.writeAttr(SUMO_ATTR_INTLANES, intLanes); // close writing into.writeAttr(SUMO_ATTR_SHAPE, n.getShape()); if (n.getType() == NODETYPE_DEAD_END) { into.closeTag(); } else { // write right-of-way logics n.writeLogic(into); into.closeTag(); } }
bool NWWriter_SUMO::writeInternalNodes(OutputDevice& into, const NBNode& n) { bool ret = false; const std::vector<NBEdge*>& incoming = n.getIncomingEdges(); // build the list of internal lane ids std::vector<std::string> internalLaneIDs; for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) { const std::vector<NBEdge::Connection>& elv = (*i)->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { if ((*k).toEdge != 0) { internalLaneIDs.push_back((*k).getInternalLaneID()); } } } const std::vector<NBNode::Crossing>& crossings = n.getCrossings(); for (std::vector<NBNode::Crossing>::const_iterator it_c = crossings.begin(); it_c != crossings.end(); ++it_c) { internalLaneIDs.push_back((*it_c).id + "_0"); } // write the internal nodes for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); i++) { const std::vector<NBEdge::Connection>& elv = (*i)->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { if ((*k).toEdge == 0 || !(*k).haveVia) { continue; } Position pos = (*k).shape[-1]; into.openTag(SUMO_TAG_JUNCTION).writeAttr(SUMO_ATTR_ID, (*k).viaID + "_0"); into.writeAttr(SUMO_ATTR_TYPE, NODETYPE_INTERNAL); NWFrame::writePositionLong(pos, into); std::string incLanes = (*k).getInternalLaneID(); if ((*k).foeIncomingLanes.length() != 0) { incLanes += " " + (*k).foeIncomingLanes; } into.writeAttr(SUMO_ATTR_INCLANES, incLanes); const std::vector<unsigned int>& foes = (*k).foeInternalLinks; std::vector<std::string> foeIDs; for (std::vector<unsigned int>::const_iterator it = foes.begin(); it != foes.end(); ++it) { foeIDs.push_back(internalLaneIDs[*it]); } into.writeAttr(SUMO_ATTR_INTLANES, joinToString(foeIDs, " ")); into.closeTag(); ret = true; } } return ret; }
bool NWWriter_SUMO::writeInternalEdges(OutputDevice& into, const NBNode& n, bool origNames) { bool ret = false; const EdgeVector& incoming = n.getIncomingEdges(); for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) { const std::vector<NBEdge::Connection>& elv = (*i)->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { if ((*k).toEdge == 0) { continue; } std::string origID = origNames ? (*k).origID : ""; writeInternalEdge(into, (*k).id, (*k).vmax, (*k).shape, origID); if ((*k).haveVia) { writeInternalEdge(into, (*k).viaID, (*k).viaVmax, (*k).viaShape, origID); } ret = true; } } return ret; }
void NWWriter_DlrNavteq::writeProhibitedManoeuvres(const OptionsCont& oc, const NBNodeCont& nc, const NBEdgeCont& ec) { OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_prohibited_manoeuvres.txt"); writeHeader(device, oc); // need to invent id for relation std::set<std::string> reservedRelIDs; if (oc.isSet("reserved-ids")) { NBHelpers::loadPrefixedIDsFomFile(oc.getString("reserved-ids"), "rel:", reservedRelIDs); } std::vector<std::string> avoid = ec.getAllNames(); // already used for tls RELATREC_ID avoid.insert(avoid.end(), reservedRelIDs.begin(), reservedRelIDs.end()); IDSupplier idSupplier("", avoid); // @note: use a global relRecIDsupplier if this is used more often // write format specifier device << "#No driving allowed from ID1 to ID2 or the complete chain from ID1 to IDn\n"; device << "#RELATREC_ID\tPERMANENT_ID_INFO\tVALIDITY_PERIOD\tTHROUGH_TRAFFIC\tVEHICLE_TYPE\tNAVTEQ_LINK_ID1\t[NAVTEQ_LINK_ID2 ...]\n"; // write record for every pair of incoming/outgoing edge that are not connected despite having common permissions for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; const EdgeVector& incoming = n->getIncomingEdges(); const EdgeVector& outgoing = n->getOutgoingEdges(); for (EdgeVector::const_iterator j = incoming.begin(); j != incoming.end(); ++j) { NBEdge* inEdge = *j; const SVCPermissions inPerm = inEdge->getPermissions(); for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); ++k) { NBEdge* outEdge = *k; const SVCPermissions outPerm = outEdge->getPermissions(); const SVCPermissions commonPerm = inPerm & outPerm; if (commonPerm != 0 && commonPerm != SVC_PEDESTRIAN && !inEdge->isConnectedTo(outEdge)) { device << idSupplier.getNext() << "\t" << 1 << "\t" // permanent id << UNDEFINED << "\t" << 1 << "\t" << getAllowedTypes(SVCAll) << "\t" << inEdge->getID() << "\t" << outEdge->getID() << "\n"; } } } } device.close(); }
bool NWWriter_SUMO::writeInternalConnections(OutputDevice& into, const NBNode& n) { bool ret = false; const std::vector<NBEdge*>& incoming = n.getIncomingEdges(); for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); ++i) { NBEdge* from = *i; const std::vector<NBEdge::Connection>& connections = from->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator j = connections.begin(); j != connections.end(); ++j) { const NBEdge::Connection& c = *j; assert(c.toEdge != 0); if (c.haveVia) { // internal split writeInternalConnection(into, c.id, c.toEdge->getID(), c.internalLaneIndex, c.toLane, c.viaID + "_0"); writeInternalConnection(into, c.viaID, c.toEdge->getID(), 0, c.toLane, ""); } else { // no internal split writeInternalConnection(into, c.id, c.toEdge->getID(), c.internalLaneIndex, c.toLane, ""); } ret = true; } } return ret; }
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); } } }
void NBNodeCont::guessTLs(OptionsCont& oc, NBTrafficLightLogicCont& tlc) { // build list of definitely not tls-controlled junctions std::vector<NBNode*> ncontrolled; if (oc.isSet("tls.unset")) { std::vector<std::string> notTLControlledNodes = oc.getStringVector("tls.unset"); for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) { NBNode* n = NBNodeCont::retrieve(*i); if (n == 0) { throw ProcessError(" The node '" + *i + "' to set as not-controlled is not known."); } std::set<NBTrafficLightDefinition*> tls = n->getControllingTLS(); for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) { (*j)->removeNode(n); } n->removeTrafficLights(); ncontrolled.push_back(n); } } TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type")); // loop#1 checking whether the node shall be tls controlled, // because it is assigned to a district if (oc.exists("tls.taz-nodes") && oc.getBool("tls.taz-nodes")) { for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { NBNode* cur = (*i).second; if (cur->isNearDistrict() && find(ncontrolled.begin(), ncontrolled.end(), cur) == ncontrolled.end()) { setAsTLControlled(cur, tlc, type); } } } // figure out which nodes mark the locations of TLS signals // This assumes nodes are already joined if (oc.exists("tls.guess-signals") && oc.getBool("tls.guess-signals")) { // prepare candidate edges const SUMOReal signalDist = oc.getFloat("tls.guess-signals.dist"); for (std::map<std::string, NBNode*>::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) { NBNode* node = (*i).second; if (node->isTLControlled() && node->geometryLike()) { const EdgeVector& outgoing = node->getOutgoingEdges(); for (EdgeVector::const_iterator it_o = outgoing.begin(); it_o != outgoing.end(); ++it_o) { (*it_o)->setSignalOffset((*it_o)->getLength()); } } } // check which nodes should be controlled for (std::map<std::string, NBNode*>::const_iterator i = myNodes.begin(); i != myNodes.end(); ++i) { NBNode* node = i->second; const EdgeVector& incoming = node->getIncomingEdges(); if (!node->isTLControlled() && incoming.size() > 1 && !node->geometryLike()) { std::vector<NBNode*> signals; bool isTLS = true; for (EdgeVector::const_iterator it_i = incoming.begin(); it_i != incoming.end(); ++it_i) { const NBEdge* inEdge = *it_i; if (inEdge->getSignalOffset() == NBEdge::UNSPECIFIED_SIGNAL_OFFSET || inEdge->getSignalOffset() > signalDist) { isTLS = false; break; } if (inEdge->getSignalOffset() == inEdge->getLength()) { signals.push_back(inEdge->getFromNode()); } } if (isTLS) { for (std::vector<NBNode*>::iterator j = signals.begin(); j != signals.end(); ++j) { std::set<NBTrafficLightDefinition*> tls = (*j)->getControllingTLS(); (*j)->removeTrafficLights(); for (std::set<NBTrafficLightDefinition*>::iterator k = tls.begin(); k != tls.end(); ++k) { tlc.removeFully((*j)->getID()); } } NBTrafficLightDefinition* tlDef = new NBOwnTLDef("GS_" + node->getID(), node, 0, TLTYPE_STATIC); // @todo patch endOffset for all incoming lanes according to the signal positions if (!tlc.insert(tlDef)) { // actually, nothing should fail here WRITE_WARNING("Could not build joined tls '" + node->getID() + "'."); delete tlDef; return; } } } } } // maybe no tls shall be guessed if (!oc.getBool("tls.guess")) { return; } // guess joined tls first, if wished if (oc.getBool("tls.join")) { // get node clusters std::vector<std::set<NBNode*> > cands; generateNodeClusters(oc.getFloat("tls.join-dist"), cands); // check these candidates (clusters) whether they should be controlled by a tls for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end();) { std::set<NBNode*>& c = (*i); // regard only junctions which are not yet controlled and are not // forbidden to be controlled for (std::set<NBNode*>::iterator j = c.begin(); j != c.end();) { if ((*j)->isTLControlled() || find(ncontrolled.begin(), ncontrolled.end(), *j) != ncontrolled.end()) { c.erase(j++); } else { ++j; } } // check whether the cluster should be controlled if (!shouldBeTLSControlled(c)) { i = cands.erase(i); } else { ++i; } } // cands now only contain sets of junctions that shall be joined into being tls-controlled unsigned int index = 0; for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end(); ++i) { std::vector<NBNode*> nodes; for (std::set<NBNode*>::iterator j = (*i).begin(); j != (*i).end(); j++) { nodes.push_back(*j); } std::string id = "joinedG_" + toString(index++); NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes, 0, type); if (!tlc.insert(tlDef)) { // actually, nothing should fail here WRITE_WARNING("Could not build guessed, joined tls"); delete tlDef; return; } } } // guess tls for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { NBNode* cur = (*i).second; // do nothing if already is tl-controlled if (cur->isTLControlled()) { continue; } // do nothing if in the list of explicit non-controlled junctions if (find(ncontrolled.begin(), ncontrolled.end(), cur) != ncontrolled.end()) { continue; } std::set<NBNode*> c; c.insert(cur); if (!shouldBeTLSControlled(c) || cur->getIncomingEdges().size() < 3) { continue; } setAsTLControlled((*i).second, tlc, type); } }
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(); }
// =========================================================================== // method definitions // =========================================================================== // --------------------------------------------------------------------------- // static methods // --------------------------------------------------------------------------- void NWWriter_OpenDrive::writeNetwork(const OptionsCont& oc, NBNetBuilder& nb) { // check whether an opendrive-file shall be generated if (!oc.isSet("opendrive-output")) { return; } const NBNodeCont& nc = nb.getNodeCont(); const NBEdgeCont& ec = nb.getEdgeCont(); const bool origNames = oc.getBool("output.original-names"); const bool lefthand = oc.getBool("lefthand"); const double straightThresh = DEG2RAD(oc.getFloat("opendrive-output.straight-threshold")); // some internal mapping containers int nodeID = 1; int edgeID = nc.size() * 10; // distinct from node ids StringBijection<int> edgeMap; StringBijection<int> nodeMap; // OutputDevice& device = OutputDevice::getDevice(oc.getString("opendrive-output")); device << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; device.openTag("OpenDRIVE"); time_t now = time(0); std::string dstr(ctime(&now)); const Boundary& b = GeoConvHelper::getFinal().getConvBoundary(); // write header device.openTag("header"); device.writeAttr("revMajor", "1"); device.writeAttr("revMinor", "4"); device.writeAttr("name", ""); device.writeAttr("version", "1.00"); device.writeAttr("date", dstr.substr(0, dstr.length() - 1)); device.writeAttr("north", b.ymax()); device.writeAttr("south", b.ymin()); device.writeAttr("east", b.xmax()); device.writeAttr("west", b.xmin()); /* @note obsolete in 1.4 device.writeAttr("maxRoad", ec.size()); device.writeAttr("maxJunc", nc.size()); device.writeAttr("maxPrg", 0); */ device.closeTag(); // write optional geo reference const GeoConvHelper& gch = GeoConvHelper::getFinal(); if (gch.usingGeoProjection()) { if (gch.getOffsetBase() == Position(0,0)) { device.openTag("geoReference"); device.writePreformattedTag(" <![CDATA[\n " + gch.getProjString() + "\n]]>\n"); device.closeTag(); } else { WRITE_WARNING("Could not write OpenDRIVE geoReference. Only unshifted Coordinate systems are supported (offset=" + toString(gch.getOffsetBase()) + ")"); } } // write normal edges (road) for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) { const NBEdge* e = (*i).second; const int fromNodeID = e->getIncomingEdges().size() > 0 ? getID(e->getFromNode()->getID(), nodeMap, nodeID) : INVALID_ID; const int toNodeID = e->getConnections().size() > 0 ? getID(e->getToNode()->getID(), nodeMap, nodeID) : INVALID_ID; writeNormalEdge(device, e, getID(e->getID(), edgeMap, edgeID), fromNodeID, toNodeID, origNames, straightThresh); } device.lf(); // write junction-internal edges (road). In OpenDRIVE these are called 'paths' or 'connecting roads' OutputDevice_String junctionOSS(false, 3); for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; int connectionID = 0; // unique within a junction const int nID = getID(n->getID(), nodeMap, nodeID); if (n->numNormalConnections() > 0) { junctionOSS << " <junction name=\"" << n->getID() << "\" id=\"" << nID << "\">\n"; } std::vector<NBEdge*> incoming = (*i).second->getIncomingEdges(); if (lefthand) { std::reverse(incoming.begin(), incoming.end()); } for (NBEdge* inEdge : incoming) { std::string centerMark = "none"; const int inEdgeID = getID(inEdge->getID(), edgeMap, edgeID); // group parallel edges const NBEdge* outEdge = 0; bool isOuterEdge = true; // determine where a solid outer border should be drawn int lastFromLane = -1; std::vector<NBEdge::Connection> parallel; std::vector<NBEdge::Connection> connections = inEdge->getConnections(); if (lefthand) { std::reverse(connections.begin(), connections.end()); } for (const NBEdge::Connection& c : connections) { assert(c.toEdge != 0); if (outEdge != c.toEdge || c.fromLane == lastFromLane) { if (outEdge != 0) { if (isOuterEdge) { addPedestrianConnection(inEdge, outEdge, parallel); } connectionID = writeInternalEdge(device, junctionOSS, inEdge, nID, getID(parallel.back().getInternalLaneID(), edgeMap, edgeID), inEdgeID, getID(outEdge->getID(), edgeMap, edgeID), connectionID, parallel, isOuterEdge, straightThresh, centerMark); parallel.clear(); isOuterEdge = false; } outEdge = c.toEdge; } lastFromLane = c.fromLane; parallel.push_back(c); } if (isOuterEdge) { addPedestrianConnection(inEdge, outEdge, parallel); } if (!parallel.empty()) { if (!lefthand && (n->geometryLike() || inEdge->isTurningDirectionAt(outEdge))) { centerMark = "solid"; } connectionID = writeInternalEdge(device, junctionOSS, inEdge, nID, getID(parallel.back().getInternalLaneID(), edgeMap, edgeID), inEdgeID, getID(outEdge->getID(), edgeMap, edgeID), connectionID, parallel, isOuterEdge, straightThresh, centerMark); parallel.clear(); } } if (n->numNormalConnections() > 0) { junctionOSS << " </junction>\n"; } } device.lf(); // write junctions (junction) device << junctionOSS.getString(); for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; const std::vector<NBEdge*>& incoming = n->getIncomingEdges(); // check if any connections must be written int numConnections = 0; for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) { numConnections += (int)((*j)->getConnections().size()); } if (numConnections == 0) { continue; } for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) { const NBEdge* inEdge = *j; const std::vector<NBEdge::Connection>& elv = inEdge->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { const NBEdge::Connection& c = *k; const NBEdge* outEdge = c.toEdge; if (outEdge == 0) { continue; } } } } device.closeTag(); device.close(); }
void NBRampsComputer::buildOffRamp(NBNode* cur, NBNodeCont& nc, NBEdgeCont& ec, NBDistrictCont& dc, SUMOReal rampLength, bool dontSplit, std::set<NBEdge*>& incremented) { NBEdge* potHighway, *potRamp, *prev; getOffRampEdges(cur, &potHighway, &potRamp, &prev); // compute the number of lanes to append const unsigned int firstLaneNumber = prev->getNumLanes(); int toAdd = (potRamp->getNumLanes() + potHighway->getNumLanes()) - firstLaneNumber; NBEdge* first = prev; NBEdge* last = prev; NBEdge* curr = prev; if (toAdd > 0 && find(incremented.begin(), incremented.end(), prev) == incremented.end()) { SUMOReal currLength = 0; while (curr != 0 && currLength + curr->getGeometry().length() - POSITION_EPS < rampLength) { if (find(incremented.begin(), incremented.end(), curr) == incremented.end()) { curr->incLaneNo(toAdd); curr->invalidateConnections(true); incremented.insert(curr); moveRampRight(curr, toAdd); currLength += curr->getLength(); // !!! loaded length? last = curr; } NBNode* prevN = curr->getFromNode(); if (prevN->getIncomingEdges().size() == 1) { curr = prevN->getIncomingEdges()[0]; if (curr->getNumLanes() != firstLaneNumber) { // the number of lanes changes along the computation; we'll stop... curr = 0; } else if (last->isTurningDirectionAt(curr)) { // turnarounds certainly should not be included in a ramp curr = 0; } else if (curr == potHighway || curr == potRamp) { // circular connectivity. do not split! curr = 0; } } else { // ambigous; and, in fact, what should it be? ...stop curr = 0; } } // check whether a further split is necessary if (curr != 0 && !dontSplit && currLength - POSITION_EPS < rampLength && curr->getNumLanes() == firstLaneNumber && find(incremented.begin(), incremented.end(), curr) == incremented.end()) { // there is enough place to build a ramp; do it bool wasFirst = first == curr; Position pos = curr->getGeometry().positionAtOffset(curr->getGeometry().length() - (rampLength - currLength)); NBNode* rn = new NBNode(curr->getID() + "-AddedOffRampNode", pos); if (!nc.insert(rn)) { throw ProcessError("Ups - could not build on-ramp for edge '" + curr->getID() + "' (node could not be build)!"); } std::string name = curr->getID(); bool ok = ec.splitAt(dc, curr, rn, curr->getID(), curr->getID() + "-AddedOffRampEdge", curr->getNumLanes(), curr->getNumLanes() + toAdd); if (!ok) { WRITE_ERROR("Ups - could not build on-ramp for edge '" + curr->getID() + "'!"); return; } curr = ec.retrieve(name + "-AddedOffRampEdge"); incremented.insert(curr); last = curr; moveRampRight(curr, toAdd); if (wasFirst) { first = curr; } } if (curr == prev && dontSplit) { WRITE_WARNING("Could not build off-ramp for edge '" + curr->getID() + "' due to option '--ramps.no-split'"); return; } } // set connections from added ramp to ramp/highway if (!first->addLane2LaneConnections(potRamp->getNumLanes(), potHighway, 0, MIN2(first->getNumLanes() - 1, potHighway->getNumLanes()), NBEdge::L2L_VALIDATED, true)) { throw ProcessError("Could not set connection!"); } if (!first->addLane2LaneConnections(0, potRamp, 0, potRamp->getNumLanes(), NBEdge::L2L_VALIDATED, false)) { throw ProcessError("Could not set connection!"); } // patch ramp geometry PositionVector p = potRamp->getGeometry(); p.pop_front(); p.push_front(first->getLaneShape(0)[-1]); potRamp->setGeometry(p); }
void NBNodeCont::guessTLs(OptionsCont& oc, NBTrafficLightLogicCont& tlc) { // build list of definitely not tls-controlled junctions std::vector<NBNode*> ncontrolled; if (oc.isSet("tls.unset")) { std::vector<std::string> notTLControlledNodes = oc.getStringVector("tls.unset"); for (std::vector<std::string>::const_iterator i = notTLControlledNodes.begin(); i != notTLControlledNodes.end(); ++i) { NBNode* n = NBNodeCont::retrieve(*i); if (n == 0) { throw ProcessError(" The node '" + *i + "' to set as not-controlled is not known."); } std::set<NBTrafficLightDefinition*> tls = n->getControllingTLS(); for (std::set<NBTrafficLightDefinition*>::const_iterator j = tls.begin(); j != tls.end(); ++j) { (*j)->removeNode(n); } n->removeTrafficLights(); ncontrolled.push_back(n); } } TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type")); // loop#1 checking whether the node shall be tls controlled, // because it is assigned to a district if (oc.exists("tls.taz-nodes") && oc.getBool("tls.taz-nodes")) { for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { NBNode* cur = (*i).second; if (cur->isNearDistrict() && find(ncontrolled.begin(), ncontrolled.end(), cur) == ncontrolled.end()) { setAsTLControlled(cur, tlc, type); } } } // maybe no tls shall be guessed if (!oc.getBool("tls.guess")) { return; } // guess joined tls first, if wished if (oc.getBool("tls.join")) { // get node clusters std::vector<std::set<NBNode*> > cands; generateNodeClusters(oc.getFloat("tls.join-dist"), cands); // check these candidates (clusters) whether they should be controlled by a tls for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end();) { std::set<NBNode*>& c = (*i); // regard only junctions which are not yet controlled and are not // forbidden to be controlled for (std::set<NBNode*>::iterator j = c.begin(); j != c.end();) { if ((*j)->isTLControlled() || find(ncontrolled.begin(), ncontrolled.end(), *j) != ncontrolled.end()) { c.erase(j++); } else { ++j; } } // check whether the cluster should be controlled if (!shouldBeTLSControlled(c)) { i = cands.erase(i); } else { ++i; } } // cands now only contain sets of junctions that shall be joined into being tls-controlled unsigned int index = 0; for (std::vector<std::set<NBNode*> >::iterator i = cands.begin(); i != cands.end(); ++i) { std::vector<NBNode*> nodes; for (std::set<NBNode*>::iterator j = (*i).begin(); j != (*i).end(); j++) { nodes.push_back(*j); } std::string id = "joinedG_" + toString(index++); NBTrafficLightDefinition* tlDef = new NBOwnTLDef(id, nodes, 0, type); if (!tlc.insert(tlDef)) { // actually, nothing should fail here WRITE_WARNING("Could not build guessed, joined tls"); delete tlDef; return; } } } // guess tls for (NodeCont::iterator i = myNodes.begin(); i != myNodes.end(); i++) { NBNode* cur = (*i).second; // do nothing if already is tl-controlled if (cur->isTLControlled()) { continue; } // do nothing if in the list of explicit non-controlled junctions if (find(ncontrolled.begin(), ncontrolled.end(), cur) != ncontrolled.end()) { continue; } std::set<NBNode*> c; c.insert(cur); if (!shouldBeTLSControlled(c) || cur->getIncomingEdges().size() < 3) { continue; } setAsTLControlled((*i).second, tlc, type); } }
void NIImporter_VISUM::parse_Connectors() { if (OptionsCont::getOptions().getBool("visum.no-connectors")) { // do nothing, if connectors shall not be imported return; } // get the source district std::string bez = NBHelpers::normalIDRepresentation(myLineParser.get("BezNr")); // get the destination node NBNode* dest = getNamedNode("KnotNr"); if (dest == 0) { return; } // get the weight of the connection SUMOReal proz = getWeightedFloat("Proz"); if (proz > 0) { proz /= 100.; } else { proz = 1; } // get the duration to wait (unused) // SUMOReal retard = -1; // if (myLineParser.know("t0-IV")) { // retard = getNamedFloat("t0-IV", -1); // } // get the type; // use a standard type with a large speed when a type is not given std::string type = myLineParser.know("Typ") ? NBHelpers::normalIDRepresentation(myLineParser.get("Typ")) : ""; // add the connectors as an edge std::string id = bez + "-" + dest->getID(); // get the information whether this is a sink or a source std::string dir = myLineParser.get("Richtung"); if (dir.length() == 0) { dir = "QZ"; } // build the source when needed if (dir.find('Q') != std::string::npos) { const EdgeVector& edges = dest->getOutgoingEdges(); bool hasContinuation = false; for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) { if (!(*i)->isMacroscopicConnector()) { hasContinuation = true; } } if (!hasContinuation) { // obviously, there is no continuation on the net WRITE_WARNING("Incoming connector '" + id + "' will not be build - would be not connected to network."); } else { NBNode* src = buildDistrictNode(bez, dest, true); if (src == 0) { WRITE_ERROR("The district '" + bez + "' could not be built."); return; } NBEdge* edge = new NBEdge(id, src, dest, "VisumConnector", OptionsCont::getOptions().getFloat("visum.connector-speeds"), OptionsCont::getOptions().getInt("visum.connectors-lane-number"), -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, "", LANESPREAD_RIGHT); edge->setAsMacroscopicConnector(); if (!myNetBuilder.getEdgeCont().insert(edge)) { WRITE_ERROR("A duplicate edge id occured (ID='" + id + "')."); return; } edge = myNetBuilder.getEdgeCont().retrieve(id); if (edge != 0) { myNetBuilder.getDistrictCont().addSource(bez, edge, proz); } } } // build the sink when needed if (dir.find('Z') != std::string::npos) { const EdgeVector& edges = dest->getIncomingEdges(); bool hasPredeccessor = false; for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) { if (!(*i)->isMacroscopicConnector()) { hasPredeccessor = true; } } if (!hasPredeccessor) { // obviously, the network is not connected to this node WRITE_WARNING("Outgoing connector '" + id + "' will not be build - would be not connected to network."); } else { NBNode* src = buildDistrictNode(bez, dest, false); if (src == 0) { WRITE_ERROR("The district '" + bez + "' could not be built."); return; } id = "-" + id; NBEdge* edge = new NBEdge(id, dest, src, "VisumConnector", OptionsCont::getOptions().getFloat("visum.connector-speeds"), OptionsCont::getOptions().getInt("visum.connectors-lane-number"), -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, "", LANESPREAD_RIGHT); edge->setAsMacroscopicConnector(); if (!myNetBuilder.getEdgeCont().insert(edge)) { WRITE_ERROR("A duplicate edge id occured (ID='" + id + "')."); return; } edge = myNetBuilder.getEdgeCont().retrieve(id); if (edge != 0) { myNetBuilder.getDistrictCont().addSink(bez, edge, proz); } } } }
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(); }
// =========================================================================== // method definitions // =========================================================================== // --------------------------------------------------------------------------- // static methods // --------------------------------------------------------------------------- void NWWriter_OpenDrive::writeNetwork(const OptionsCont& oc, NBNetBuilder& nb) { // check whether an opendrive-file shall be generated if (!oc.isSet("opendrive-output")) { return; } const NBNodeCont& nc = nb.getNodeCont(); const NBEdgeCont& ec = nb.getEdgeCont(); const bool origNames = oc.getBool("output.original-names"); const SUMOReal straightThresh = DEG2RAD(oc.getFloat("opendrive-output.straight-threshold")); // some internal mapping containers int nodeID = 1; int edgeID = nc.size() * 10; // distinct from node ids StringBijection<int> edgeMap; StringBijection<int> nodeMap; // OutputDevice& device = OutputDevice::getDevice(oc.getString("opendrive-output")); device << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; device.openTag("OpenDRIVE"); time_t now = time(0); std::string dstr(ctime(&now)); const Boundary& b = GeoConvHelper::getFinal().getConvBoundary(); // write header device.openTag("header"); device.writeAttr("revMajor", "1"); device.writeAttr("revMinor", "4"); device.writeAttr("name", ""); device.writeAttr("version", "1.00"); device.writeAttr("date", dstr.substr(0, dstr.length() - 1)); device.writeAttr("north", b.ymax()); device.writeAttr("south", b.ymin()); device.writeAttr("east", b.xmax()); device.writeAttr("west", b.xmin()); /* @note obsolete in 1.4 device.writeAttr("maxRoad", ec.size()); device.writeAttr("maxJunc", nc.size()); device.writeAttr("maxPrg", 0); */ device.closeTag(); // write normal edges (road) for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) { const NBEdge* e = (*i).second; // buffer output because some fields are computed out of order OutputDevice_String elevationOSS(false, 3); elevationOSS.setPrecision(8); OutputDevice_String planViewOSS(false, 2); planViewOSS.setPrecision(8); SUMOReal length = 0; planViewOSS.openTag("planView"); planViewOSS.setPrecision(8); // geometry hdg requires higher precision // for the shape we need to use the leftmost border of the leftmost lane const std::vector<NBEdge::Lane>& lanes = e->getLanes(); PositionVector ls = getLeftLaneBorder(e); #ifdef DEBUG_SMOOTH_GEOM if (DEBUGCOND) { std::cout << "write planview for edge " << e->getID() << "\n"; } #endif if (ls.size() == 2 || e->getPermissions() == SVC_PEDESTRIAN) { // foot paths may contain sharp angles length = writeGeomLines(ls, planViewOSS, elevationOSS); } else { bool ok = writeGeomSmooth(ls, e->getSpeed(), planViewOSS, elevationOSS, straightThresh, length); if (!ok) { WRITE_WARNING("Could not compute smooth shape for edge '" + e->getID() + "'."); } } planViewOSS.closeTag(); device.openTag("road"); device.writeAttr("name", StringUtils::escapeXML(e->getStreetName())); device.setPrecision(8); // length requires higher precision device.writeAttr("length", MAX2(POSITION_EPS, length)); device.setPrecision(OUTPUT_ACCURACY); device.writeAttr("id", getID(e->getID(), edgeMap, edgeID)); device.writeAttr("junction", -1); const bool hasSucc = e->getConnections().size() > 0; const bool hasPred = e->getIncomingEdges().size() > 0; if (hasPred || hasSucc) { device.openTag("link"); if (hasPred) { device.openTag("predecessor"); device.writeAttr("elementType", "junction"); device.writeAttr("elementId", getID(e->getFromNode()->getID(), nodeMap, nodeID)); device.closeTag(); } if (hasSucc) { device.openTag("successor"); device.writeAttr("elementType", "junction"); device.writeAttr("elementId", getID(e->getToNode()->getID(), nodeMap, nodeID)); device.closeTag(); } device.closeTag(); } device.openTag("type").writeAttr("s", 0).writeAttr("type", "town").closeTag(); device << planViewOSS.getString(); writeElevationProfile(ls, device, elevationOSS); device << " <lateralProfile/>\n"; device << " <lanes>\n"; device << " <laneSection s=\"0\">\n"; writeEmptyCenterLane(device, "solid", 0.13); device << " <right>\n"; for (int j = e->getNumLanes(); --j >= 0;) { device << " <lane id=\"-" << e->getNumLanes() - j << "\" type=\"" << getLaneType(e->getPermissions(j)) << "\" level=\"true\">\n"; device << " <link/>\n"; // this could be used for geometry-link junctions without u-turn, // predecessor and sucessors would be lane indices, // road predecessor / succesfors would be of type 'road' rather than // 'junction' //device << " <predecessor id=\"-1\"/>\n"; //device << " <successor id=\"-1\"/>\n"; //device << " </link>\n"; device << " <width sOffset=\"0\" a=\"" << e->getLaneWidth(j) << "\" b=\"0\" c=\"0\" d=\"0\"/>\n"; std::string markType = "broken"; if (j == 0) { markType = "solid"; } device << " <roadMark sOffset=\"0\" type=\"" << markType << "\" weight=\"standard\" color=\"standard\" width=\"0.13\"/>\n"; device << " <speed sOffset=\"0\" max=\"" << lanes[j].speed << "\"/>\n"; device << " </lane>\n"; } device << " </right>\n"; device << " </laneSection>\n"; device << " </lanes>\n"; device << " <objects/>\n"; device << " <signals/>\n"; if (origNames) { device << " <userData code=\"sumoId\" value=\"" << e->getID() << "\"/>\n"; } device.closeTag(); checkLaneGeometries(e); } device.lf(); // write junction-internal edges (road). In OpenDRIVE these are called 'paths' or 'connecting roads' for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; const std::vector<NBEdge*>& incoming = (*i).second->getIncomingEdges(); for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) { const NBEdge* inEdge = *j; const std::vector<NBEdge::Connection>& elv = inEdge->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { const NBEdge::Connection& c = *k; const NBEdge* outEdge = c.toEdge; if (outEdge == 0) { continue; } const SUMOReal width = c.toEdge->getLaneWidth(c.toLane); const PositionVector begShape = getLeftLaneBorder(inEdge, c.fromLane); const PositionVector endShape = getLeftLaneBorder(outEdge, c.toLane); //std::cout << "computing reference line for internal lane " << c.getInternalLaneID() << " begLane=" << inEdge->getLaneShape(c.fromLane) << " endLane=" << outEdge->getLaneShape(c.toLane) << "\n"; SUMOReal length; PositionVector fallBackShape; fallBackShape.push_back(begShape.back()); fallBackShape.push_back(endShape.front()); const bool turnaround = inEdge->isTurningDirectionAt(outEdge); bool ok = true; PositionVector init = NBNode::bezierControlPoints(begShape, endShape, turnaround, 25, 25, ok, 0, straightThresh); if (init.size() == 0) { length = fallBackShape.length2D(); // problem with turnarounds is known, method currently returns 'ok' (#2539) if (!ok) { WRITE_WARNING("Could not compute smooth shape from lane '" + inEdge->getLaneID(c.fromLane) + "' to lane '" + outEdge->getLaneID(c.toLane) + "'. Use option 'junctions.scurve-stretch' or increase radius of junction '" + inEdge->getToNode()->getID() + "' to fix this."); } } else { length = bezier(init, 12).length2D(); } device.openTag("road"); device.writeAttr("name", c.getInternalLaneID()); device.setPrecision(8); // length requires higher precision device.writeAttr("length", MAX2(POSITION_EPS, length)); device.setPrecision(OUTPUT_ACCURACY); device.writeAttr("id", getID(c.getInternalLaneID(), edgeMap, edgeID)); device.writeAttr("junction", getID(n->getID(), nodeMap, nodeID)); device.openTag("link"); device.openTag("predecessor"); device.writeAttr("elementType", "road"); device.writeAttr("elementId", getID(inEdge->getID(), edgeMap, edgeID)); device.writeAttr("contactPoint", "end"); device.closeTag(); device.openTag("successor"); device.writeAttr("elementType", "road"); device.writeAttr("elementId", getID(outEdge->getID(), edgeMap, edgeID)); device.writeAttr("contactPoint", "start"); device.closeTag(); device.closeTag(); device.openTag("type").writeAttr("s", 0).writeAttr("type", "town").closeTag(); device.openTag("planView"); device.setPrecision(8); // geometry hdg requires higher precision OutputDevice_String elevationOSS(false, 3); #ifdef DEBUG_SMOOTH_GEOM if (DEBUGCOND) { std::cout << "write planview for internal edge " << c.getInternalLaneID() << " init=" << init << " fallback=" << fallBackShape << "\n"; } #endif if (init.size() == 0) { writeGeomLines(fallBackShape, device, elevationOSS); } else { writeGeomPP3(device, elevationOSS, init, length); } device.setPrecision(OUTPUT_ACCURACY); device.closeTag(); writeElevationProfile(fallBackShape, device, elevationOSS); device << " <lateralProfile/>\n"; device << " <lanes>\n"; device << " <laneSection s=\"0\">\n"; writeEmptyCenterLane(device, "none", 0); device << " <right>\n"; device << " <lane id=\"-1\" type=\"" << getLaneType(outEdge->getPermissions(c.toLane)) << "\" level=\"true\">\n"; device << " <link>\n"; device << " <predecessor id=\"-" << inEdge->getNumLanes() - c.fromLane << "\"/>\n"; device << " <successor id=\"-" << outEdge->getNumLanes() - c.toLane << "\"/>\n"; device << " </link>\n"; device << " <width sOffset=\"0\" a=\"" << width << "\" b=\"0\" c=\"0\" d=\"0\"/>\n"; device << " <roadMark sOffset=\"0\" type=\"none\" weight=\"standard\" color=\"standard\" width=\"0.13\"/>\n"; device << " </lane>\n"; device << " </right>\n"; device << " </laneSection>\n"; device << " </lanes>\n"; device << " <objects/>\n"; device << " <signals/>\n"; device.closeTag(); } } } // write junctions (junction) for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; const std::vector<NBEdge*>& incoming = n->getIncomingEdges(); // check if any connections must be written int numConnections = 0; for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) { numConnections += (int)((*j)->getConnections().size()); } if (numConnections == 0) { continue; } device << " <junction name=\"" << n->getID() << "\" id=\"" << getID(n->getID(), nodeMap, nodeID) << "\">\n"; int index = 0; for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) { const NBEdge* inEdge = *j; const std::vector<NBEdge::Connection>& elv = inEdge->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { const NBEdge::Connection& c = *k; const NBEdge* outEdge = c.toEdge; if (outEdge == 0) { continue; } device << " <connection id=\"" << index << "\" incomingRoad=\"" << getID(inEdge->getID(), edgeMap, edgeID) << "\" connectingRoad=\"" << getID(c.getInternalLaneID(), edgeMap, edgeID) << "\" contactPoint=\"start\">\n"; device << " <laneLink from=\"-" << inEdge->getNumLanes() - c.fromLane << "\" to=\"-1" // every connection has its own edge << "\"/>\n"; device << " </connection>\n"; ++index; } } device << " </junction>\n"; } device.closeTag(); device.close(); }
void NBNodeCont::removeIsolatedRoads(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tc) { UNUSED_PARAMETER(tc); // Warn of isolated edges, i.e. a single edge with no connection to another edge int edgeCounter = 0; const std::vector<std::string>& edgeNames = ec.getAllNames(); for (std::vector<std::string>::const_iterator it = edgeNames.begin(); it != edgeNames.end(); ++it) { // Test whether this node starts at a dead end, i.e. it has only one adjacent node // to which an edge exists and from which an edge may come. NBEdge* e = ec.retrieve(*it); if (e == 0) { continue; } NBNode* from = e->getFromNode(); const EdgeVector& outgoingEdges = from->getOutgoingEdges(); if (outgoingEdges.size() != 1) { // At this node, several edges or no edge start; so, this node is no dead end. continue; } const EdgeVector& incomingEdges = from->getIncomingEdges(); if (incomingEdges.size() > 1) { // At this node, several edges end; so, this node is no dead end. continue; } else if (incomingEdges.size() == 1) { NBNode* fromNodeOfIncomingEdge = incomingEdges[0]->getFromNode(); NBNode* toNodeOfOutgoingEdge = outgoingEdges[0]->getToNode(); if (fromNodeOfIncomingEdge != toNodeOfOutgoingEdge) { // At this node, an edge ends which is not the inverse direction of // the starting node. continue; } } // Now we know that the edge e starts a dead end. // Next we test if the dead end is isolated, i.e. does not lead to a junction bool hasJunction = false; EdgeVector road; NBEdge* eOld = 0; NBNode* to; std::set<NBNode*> adjacentNodes; do { road.push_back(e); eOld = e; from = e->getFromNode(); to = e->getToNode(); const EdgeVector& outgoingEdgesOfToNode = to->getOutgoingEdges(); const EdgeVector& incomingEdgesOfToNode = to->getIncomingEdges(); adjacentNodes.clear(); for (EdgeVector::const_iterator itOfOutgoings = outgoingEdgesOfToNode.begin(); itOfOutgoings != outgoingEdgesOfToNode.end(); ++itOfOutgoings) { if ((*itOfOutgoings)->getToNode() != from // The back path && (*itOfOutgoings)->getToNode() != to // A loop / dummy edge ) { e = *itOfOutgoings; // Probably the next edge } adjacentNodes.insert((*itOfOutgoings)->getToNode()); } for (EdgeVector::const_iterator itOfIncomings = incomingEdgesOfToNode.begin(); itOfIncomings != incomingEdgesOfToNode.end(); ++itOfIncomings) { adjacentNodes.insert((*itOfIncomings)->getFromNode()); } adjacentNodes.erase(to); // Omit loops if (adjacentNodes.size() > 2) { hasJunction = true; } } while (!hasJunction && eOld != e); if (!hasJunction) { edgeCounter += int(road.size()); std::string warningString = "Removed a road without junctions: "; for (EdgeVector::iterator roadIt = road.begin(); roadIt != road.end(); ++roadIt) { if (roadIt == road.begin()) { warningString += (*roadIt)->getID(); } else { warningString += ", " + (*roadIt)->getID(); } NBNode* fromNode = (*roadIt)->getFromNode(); NBNode* toNode = (*roadIt)->getToNode(); ec.erase(dc, *roadIt); if (fromNode->getIncomingEdges().size() == 0 && fromNode->getOutgoingEdges().size() == 0) { // Node is empty; can be removed erase(fromNode); } if (toNode->getIncomingEdges().size() == 0 && toNode->getOutgoingEdges().size() == 0) { // Node is empty; can be removed erase(toNode); } } WRITE_WARNING(warningString); } } if (edgeCounter > 0 && !OptionsCont::getOptions().getBool("remove-edges.isolated")) { WRITE_WARNING("Detected isolated roads. Use the option --remove-edges.isolated to get a list of all affected edges."); } }
bool NWWriter_SUMO::writeInternalEdges(OutputDevice& into, const NBNode& n, bool origNames) { bool ret = false; const EdgeVector& incoming = n.getIncomingEdges(); for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) { const std::vector<NBEdge::Connection>& elv = (*i)->getConnections(); if (elv.size() > 0) { bool haveVia = false; NBEdge* toEdge = 0; std::string internalEdgeID = ""; // first pass: compute average lengths of non-via edges std::map<NBEdge*, SUMOReal> lengthSum; std::map<NBEdge*, int> numLanes; for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { lengthSum[(*k).toEdge] += MAX2((*k).shape.length(), POSITION_EPS); numLanes[(*k).toEdge] += 1; } // second pass: write non-via edges for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { if ((*k).toEdge == 0) { assert(false); // should never happen. tell me when it does continue; } if (toEdge != (*k).toEdge) { internalEdgeID = (*k).id; if (toEdge != 0) { // close the previous edge into.closeTag(); } toEdge = (*k).toEdge; into.openTag(SUMO_TAG_EDGE); into.writeAttr(SUMO_ATTR_ID, internalEdgeID); into.writeAttr(SUMO_ATTR_FUNCTION, EDGEFUNC_INTERNAL); // open a new edge } // to avoid changing to an internal lane which has a successor // with the wrong permissions we need to inherit them from the successor const NBEdge::Lane& successor = (*k).toEdge->getLanes()[(*k).toLane]; const SUMOReal length = lengthSum[toEdge] / numLanes[toEdge]; // @note the actual length should be used once sumo supports lanes of // varying length within the same edge //const SUMOReal length = MAX2((*k).shape.length(), POSITION_EPS); writeLane(into, internalEdgeID, (*k).getInternalLaneID(), (*k).vmax, successor.permissions, successor.preferred, NBEdge::UNSPECIFIED_OFFSET, successor.width, (*k).shape, (*k).origID, length, (*k).internalLaneIndex, origNames, &n); haveVia = haveVia || (*k).haveVia; } ret = true; into.closeTag(); // close the last edge // third pass: write via edges if (haveVia) { for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { if (!(*k).haveVia) { continue; } if ((*k).toEdge == 0) { assert(false); // should never happen. tell me when it does continue; } const NBEdge::Lane& successor = (*k).toEdge->getLanes()[(*k).toLane]; into.openTag(SUMO_TAG_EDGE); into.writeAttr(SUMO_ATTR_ID, (*k).viaID); into.writeAttr(SUMO_ATTR_FUNCTION, EDGEFUNC_INTERNAL); writeLane(into, (*k).viaID, (*k).viaID + "_0", (*k).viaVmax, SVCAll, SVCAll, NBEdge::UNSPECIFIED_OFFSET, successor.width, (*k).viaShape, (*k).origID, MAX2((*k).viaShape.length(), POSITION_EPS), // microsim needs positive length 0, origNames, &n); into.closeTag(); } } } } // write pedestrian crossings const std::vector<NBNode::Crossing>& crossings = n.getCrossings(); for (std::vector<NBNode::Crossing>::const_iterator it = crossings.begin(); it != crossings.end(); it++) { into.openTag(SUMO_TAG_EDGE); into.writeAttr(SUMO_ATTR_ID, (*it).id); into.writeAttr(SUMO_ATTR_FUNCTION, EDGEFUNC_CROSSING); into.writeAttr(SUMO_ATTR_CROSSING_EDGES, (*it).edges); writeLane(into, (*it).id, (*it).id + "_0", 1, SVC_PEDESTRIAN, 0, NBEdge::UNSPECIFIED_OFFSET, (*it).width, (*it).shape, "", (*it).shape.length(), 0, false, &n); into.closeTag(); } // write pedestrian walking areas const std::vector<NBNode::WalkingArea>& WalkingAreas = n.getWalkingAreas(); for (std::vector<NBNode::WalkingArea>::const_iterator it = WalkingAreas.begin(); it != WalkingAreas.end(); it++) { const NBNode::WalkingArea& wa = *it; into.openTag(SUMO_TAG_EDGE); into.writeAttr(SUMO_ATTR_ID, wa.id); into.writeAttr(SUMO_ATTR_FUNCTION, EDGEFUNC_WALKINGAREA); writeLane(into, wa.id, wa.id + "_0", 1, SVC_PEDESTRIAN, 0, NBEdge::UNSPECIFIED_OFFSET, wa.width, wa.shape, "", wa.length, 0, false, &n); into.closeTag(); } return ret; }
void NWWriter_SUMO::writeJunction(OutputDevice& into, const NBNode& n, const bool checkLaneFoes) { // write the attributes into.openTag(SUMO_TAG_JUNCTION).writeAttr(SUMO_ATTR_ID, n.getID()); into.writeAttr(SUMO_ATTR_TYPE, n.getType()); NWFrame::writePositionLong(n.getPosition(), into); // write the incoming lanes std::string incLanes; const std::vector<NBEdge*>& incoming = n.getIncomingEdges(); for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); ++i) { unsigned int noLanes = (*i)->getNumLanes(); for (unsigned int j = 0; j < noLanes; j++) { incLanes += (*i)->getLaneID(j); if (i != incoming.end() - 1 || j < noLanes - 1) { incLanes += ' '; } } } const std::vector<NBNode::Crossing>& crossings = n.getCrossings(); for (std::vector<NBNode::Crossing>::const_iterator it = crossings.begin(); it != crossings.end(); it++) { incLanes += ' ' + (*it).prevWalkingArea + "_0"; } into.writeAttr(SUMO_ATTR_INCLANES, incLanes); // write the internal lanes std::string intLanes; if (!OptionsCont::getOptions().getBool("no-internal-links")) { unsigned int l = 0; for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) { const std::vector<NBEdge::Connection>& elv = (*i)->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) { if ((*k).toEdge == 0) { continue; } if (l != 0) { intLanes += ' '; } if (!(*k).haveVia) { intLanes += (*k).getInternalLaneID(); } else { intLanes += (*k).viaID + "_0"; } l++; } } } if (n.getType() != NODETYPE_DEAD_END && n.getType() != NODETYPE_NOJUNCTION) { for (std::vector<NBNode::Crossing>::const_iterator it = crossings.begin(); it != crossings.end(); it++) { intLanes += ' ' + (*it).id + "_0"; } } into.writeAttr(SUMO_ATTR_INTLANES, intLanes); // close writing into.writeAttr(SUMO_ATTR_SHAPE, n.getShape()); // write optional radius if (n.getRadius() != NBNode::UNSPECIFIED_RADIUS) { into.writeAttr(SUMO_ATTR_RADIUS, n.getRadius()); } // specify whether a custom shape was used if (n.hasCustomShape()) { into.writeAttr(SUMO_ATTR_CUSTOMSHAPE, true); } if (n.getType() == NODETYPE_DEAD_END) { into.closeTag(); } else { // write right-of-way logics n.writeLogic(into, checkLaneFoes); into.closeTag(); } }