void NWWriter_SUMO::writeEdge(OutputDevice& into, const NBEdge& e, bool noNames, bool origNames) { // write the edge's begin into.openTag(SUMO_TAG_EDGE).writeAttr(SUMO_ATTR_ID, e.getID()); into.writeAttr(SUMO_ATTR_FROM, e.getFromNode()->getID()); into.writeAttr(SUMO_ATTR_TO, e.getToNode()->getID()); if (!noNames && e.getStreetName() != "") { into.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(e.getStreetName())); } into.writeAttr(SUMO_ATTR_PRIORITY, e.getPriority()); if (e.getTypeID() != "") { into.writeAttr(SUMO_ATTR_TYPE, e.getTypeID()); } if (e.isMacroscopicConnector()) { into.writeAttr(SUMO_ATTR_FUNCTION, EDGEFUNC_CONNECTOR); } // write the spread type if not default ("right") if (e.getLaneSpreadFunction() != LANESPREAD_RIGHT) { into.writeAttr(SUMO_ATTR_SPREADTYPE, e.getLaneSpreadFunction()); } if (e.hasLoadedLength()) { into.writeAttr(SUMO_ATTR_LENGTH, e.getLoadedLength()); } if (!e.hasDefaultGeometry()) { into.writeAttr(SUMO_ATTR_SHAPE, e.getGeometry()); } // write the lanes const std::vector<NBEdge::Lane>& lanes = e.getLanes(); SUMOReal length = e.getLoadedLength(); if (OptionsCont::getOptions().getBool("no-internal-links") && !e.hasLoadedLength()) { // use length to junction center even if a modified geometry was given PositionVector geom = e.cutAtIntersection(e.getGeometry()); geom.push_back_noDoublePos(e.getToNode()->getCenter()); geom.push_front_noDoublePos(e.getFromNode()->getCenter()); length = geom.length(); } if (length <= 0) { length = POSITION_EPS; } for (unsigned int i = 0; i < (unsigned int) lanes.size(); i++) { const NBEdge::Lane& l = lanes[i]; writeLane(into, e.getID(), e.getLaneID(i), l.speed, l.permissions, l.preferred, l.endOffset, l.width, l.shape, l.origID, length, i, origNames); } // close the edge into.closeTag(); }
void NWWriter_SUMO::writeEdge(OutputDevice& into, const NBEdge& e, bool noNames, bool origNames) { // write the edge's begin into.openTag(SUMO_TAG_EDGE).writeAttr(SUMO_ATTR_ID, e.getID()); into.writeAttr(SUMO_ATTR_FROM, e.getFromNode()->getID()); into.writeAttr(SUMO_ATTR_TO, e.getToNode()->getID()); if (!noNames && e.getStreetName() != "") { into.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(e.getStreetName())); } into.writeAttr(SUMO_ATTR_PRIORITY, e.getPriority()); if (e.getTypeName() != "") { into.writeAttr(SUMO_ATTR_TYPE, e.getTypeName()); } if (e.isMacroscopicConnector()) { into.writeAttr(SUMO_ATTR_FUNCTION, EDGEFUNC_CONNECTOR); } // write the spread type if not default ("right") if (e.getLaneSpreadFunction() != LANESPREAD_RIGHT) { into.writeAttr(SUMO_ATTR_SPREADTYPE, e.getLaneSpreadFunction()); } if (e.hasLoadedLength()) { into.writeAttr(SUMO_ATTR_LENGTH, e.getLoadedLength()); } if (!e.hasDefaultGeometry()) { into.writeAttr(SUMO_ATTR_SHAPE, e.getGeometry()); } // write the lanes const std::vector<NBEdge::Lane>& lanes = e.getLanes(); SUMOReal length = e.getLoadedLength(); if (length <= 0) { length = (SUMOReal) .1; } for (unsigned int i = 0; i < (unsigned int) lanes.size(); i++) { writeLane(into, e.getID(), e.getLaneID(i), lanes[i], length, i, origNames); } // close the edge into.closeTag(); }
// ----------- (Helper) methods for joining nodes void NBNodeCont::generateNodeClusters(SUMOReal maxDist, NodeClusters& into) const { std::set<NBNode*> visited; for (NodeCont::const_iterator i = myNodes.begin(); i != myNodes.end(); i++) { std::vector<NBNode*> toProc; if (visited.find((*i).second) != visited.end()) { continue; } toProc.push_back((*i).second); std::set<NBNode*> c; while (!toProc.empty()) { NBNode* n = toProc.back(); toProc.pop_back(); if (visited.find(n) != visited.end()) { continue; } c.insert(n); visited.insert(n); const EdgeVector& edges = n->getEdges(); for (EdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) { NBEdge* e = *j; NBNode* s = 0; if (n->hasIncoming(e)) { s = e->getFromNode(); } else { s = e->getToNode(); } if (visited.find(s) != visited.end()) { continue; } if (e->getLoadedLength() < maxDist) { toProc.push_back(s); } } } if (c.size() < 2) { continue; } into.push_back(c); } }
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(); }
void NWWriter_XML::writeEdgesAndConnections(const OptionsCont& oc, NBNodeCont& nc, NBEdgeCont& ec) { const GeoConvHelper& gch = GeoConvHelper::getFinal(); bool useGeo = oc.exists("proj.plain-geo") && oc.getBool("proj.plain-geo"); const bool geoAccuracy = useGeo || gch.usingInverseGeoProjection(); OutputDevice& edevice = OutputDevice::getDevice(oc.getString("plain-output-prefix") + ".edg.xml"); edevice.writeXMLHeader("edges", NWFrame::MAJOR_VERSION + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://sumo-sim.org/xsd/edges_file.xsd\""); OutputDevice& cdevice = OutputDevice::getDevice(oc.getString("plain-output-prefix") + ".con.xml"); cdevice.writeXMLHeader("connections", NWFrame::MAJOR_VERSION + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://sumo-sim.org/xsd/connections_file.xsd\""); bool noNames = !oc.getBool("output.street-names"); for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) { // write the edge itself to the edges-files NBEdge* e = (*i).second; edevice.openTag(SUMO_TAG_EDGE); edevice.writeAttr(SUMO_ATTR_ID, e->getID()); edevice.writeAttr(SUMO_ATTR_FROM, e->getFromNode()->getID()); edevice.writeAttr(SUMO_ATTR_TO, e->getToNode()->getID()); if (!noNames && e->getStreetName() != "") { edevice.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(e->getStreetName())); } edevice.writeAttr(SUMO_ATTR_PRIORITY, e->getPriority()); // write the type if given if (e->getTypeID() != "") { edevice.writeAttr(SUMO_ATTR_TYPE, e->getTypeID()); } edevice.writeAttr(SUMO_ATTR_NUMLANES, e->getNumLanes()); if (!e->hasLaneSpecificSpeed()) { edevice.writeAttr(SUMO_ATTR_SPEED, e->getSpeed()); } // write non-default geometry if (!e->hasDefaultGeometry()) { PositionVector geom = e->getGeometry(); if (useGeo) { for (int i = 0; i < (int) geom.size(); i++) { gch.cartesian2geo(geom[i]); } } if (geoAccuracy) { edevice.setPrecision(GEO_OUTPUT_ACCURACY); } edevice.writeAttr(SUMO_ATTR_SHAPE, geom); if (geoAccuracy) { edevice.setPrecision(); } } // write the spread type if not default ("right") if (e->getLaneSpreadFunction() != LANESPREAD_RIGHT) { edevice.writeAttr(SUMO_ATTR_SPREADTYPE, toString(e->getLaneSpreadFunction())); } // write the length if it was specified if (e->hasLoadedLength()) { edevice.writeAttr(SUMO_ATTR_LENGTH, e->getLoadedLength()); } // some attributes can be set by edge default or per lane. Write as default if possible (efficiency) if (e->getLaneWidth() != NBEdge::UNSPECIFIED_WIDTH && !e->hasLaneSpecificWidth()) { edevice.writeAttr(SUMO_ATTR_WIDTH, e->getLaneWidth()); } if (e->getOffset() != NBEdge::UNSPECIFIED_OFFSET && !e->hasLaneSpecificOffset()) { edevice.writeAttr(SUMO_ATTR_OFFSET, e->getOffset()); } if (!e->needsLaneSpecificOutput()) { edevice.closeTag(); } else { for (unsigned int i = 0; i < e->getLanes().size(); ++i) { const NBEdge::Lane& lane = e->getLanes()[i]; edevice.openTag(SUMO_TAG_LANE); edevice.writeAttr(SUMO_ATTR_INDEX, i); // write allowed lanes NWWriter_SUMO::writePermissions(edevice, lane.permissions); NWWriter_SUMO::writePreferences(edevice, lane.preferred); // write other attributes if (lane.width != NBEdge::UNSPECIFIED_WIDTH && e->hasLaneSpecificWidth()) { edevice.writeAttr(SUMO_ATTR_WIDTH, lane.width); } if (lane.offset != NBEdge::UNSPECIFIED_OFFSET && e->hasLaneSpecificOffset()) { edevice.writeAttr(SUMO_ATTR_OFFSET, lane.offset); } if (e->hasLaneSpecificSpeed()) { edevice.writeAttr(SUMO_ATTR_SPEED, lane.speed); } edevice.closeTag(); } edevice.closeTag(); } // write this edge's connections to the connections-files e->sortOutgoingConnectionsByIndex(); const std::vector<NBEdge::Connection> connections = e->getConnections(); for (std::vector<NBEdge::Connection>::const_iterator c = connections.begin(); c != connections.end(); ++c) { NWWriter_SUMO::writeConnection(cdevice, *e, *c, false, NWWriter_SUMO::PLAIN); } if (connections.size() > 0) { cdevice << "\n"; } } // write loaded prohibitions to the connections-file for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NWWriter_SUMO::writeProhibitions(cdevice, i->second->getProhibitions()); } edevice.close(); cdevice.close(); }