bool NIImporter_DlrNavteq::TrafficlightsHandler::report(const std::string& result) { // #ID POICOL-TYPE DESCRIPTION LONGITUDE LATITUDE NAVTEQ_LINK_ID NODEID if (result[0] == '#') { return true; } StringTokenizer st(result, StringTokenizer::WHITECHARS); const std::string edgeID = st.get(5); NBEdge* edge = myEdgeCont.retrieve(edgeID); if (edge == nullptr) { WRITE_WARNING("The traffic light edge '" + edgeID + "' could not be found"); } else { NBNode* node = edge->getToNode(); if (node->getType() != NODETYPE_TRAFFIC_LIGHT) { node->reinit(node->getPosition(), NODETYPE_TRAFFIC_LIGHT); // @note. There may be additional information somewhere in the GDF files about traffic light type ... TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type")); // @note actually we could use the navteq node ID here NBTrafficLightDefinition* tlDef = new NBOwnTLDef(node->getID(), node, 0, type); if (!myTLLogicCont.insert(tlDef)) { // actually, nothing should fail here delete tlDef; throw ProcessError("Could not allocate tls for '" + node->getID() + "'."); } } } return true; }
void NIImporter_VISUM::parse_Turns() { if (myLineParser.know("VSYSSET") && myLineParser.get("VSYSSET") == "") { // no vehicle allowed; don't add return; } // retrieve the nodes NBNode* from = getNamedNode("VonKnot", "VonKnotNr"); NBNode* via = getNamedNode("UeberKnot", "UeberKnotNr"); NBNode* to = getNamedNode("NachKnot", "NachKnotNr"); if (from == 0 || via == 0 || to == 0) { return; } // all nodes are known std::string type = myLineParser.know("VSysCode") ? myLineParser.get("VSysCode") : myLineParser.get("VSYSSET"); if (myVSysTypes.find(type) != myVSysTypes.end() && myVSysTypes.find(type)->second == "IV") { // try to set the turning definition NBEdge* src = from->getConnectionTo(via); NBEdge* dest = via->getConnectionTo(to); // check both if (src == 0) { // maybe it was removed due to something if (OptionsCont::getOptions().isSet("keep-edges.min-speed") || OptionsCont::getOptions().isSet("keep-edges.explicit")) { WRITE_WARNING("Could not set connection from node '" + from->getID() + "' to node '" + via->getID() + "'."); } else { if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) { WRITE_WARNING("There is no edge from node '" + from->getID() + "' to node '" + via->getID() + "'."); } } return; } if (dest == 0) { if (OptionsCont::getOptions().isSet("keep-edges.min-speed") || OptionsCont::getOptions().isSet("keep-edges.explicit")) { WRITE_WARNING("Could not set connection from node '" + via->getID() + "' to node '" + to->getID() + "'."); } else { if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) { WRITE_WARNING("There is no edge from node '" + via->getID() + "' to node '" + to->getID() + "'."); } } return; } // both edges found // set them into the edge src->addEdge2EdgeConnection(dest); } }
void NIImporter_VISUM::parse_EdgePolys() { // get the from- & to-node and validate them NBNode* from = getNamedNode("VonKnot", "VonKnotNr"); NBNode* to = getNamedNode("NachKnot", "NachKnotNr"); if (!checkNodes(from, to)) { return; } bool failed = false; int index; SUMOReal x, y; try { index = TplConvert::_2int(myLineParser.get("INDEX").c_str()); x = getNamedFloat("XKoord"); y = getNamedFloat("YKoord"); } catch (NumberFormatException&) { WRITE_ERROR("Error in geometry description from node '" + from->getID() + "' to node '" + to->getID() + "'."); return; } Position pos(x, y); if (!NILoader::transformCoordinates(pos)) { WRITE_ERROR("Unable to project coordinates for node '" + from->getID() + "'."); return; } NBEdge* e = from->getConnectionTo(to); if (e != 0) { e->addGeometryPoint(index, pos); } else { failed = true; } e = to->getConnectionTo(from); if (e != 0) { e->addGeometryPoint(-index, pos); failed = false; } // check whether the operation has failed if (failed) { // we should report this to the warning instance only if we have removed // some nodes or edges... if (OptionsCont::getOptions().isSet("keep-edges.min-speed") || OptionsCont::getOptions().isSet("keep-edges.explicit")) { WRITE_WARNING("Could not set geometry between node '" + from->getID() + "' and node '" + to->getID() + "'."); } else { // ... in the other case we report this to the error instance if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) { WRITE_WARNING("There is no edge from node '" + from->getID() + "' to node '" + to->getID() + "'."); } } } }
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"; } } } }
void NBEdgeCont::recheckPostProcessConnections() { for (std::vector<PostProcessConnection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) { NBEdge* from = retrieve((*i).from); NBEdge* to = retrieve((*i).to); if (from != 0 && to != 0) { if (!from->addLane2LaneConnection((*i).fromLane, to, (*i).toLane, NBEdge::L2L_USER, false, (*i).mayDefinitelyPass)) { WRITE_WARNING("Could not insert connection between '" + (*i).from + "' and '" + (*i).to + "' after build."); } } } // during loading we also kept some ambiguous connections in hope they might be valid after processing // we need to make sure that all invalid connections are removed now for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); ++it) { NBEdge* edge = it->second; NBNode* to = edge->getToNode(); // make a copy because we may delete connections std::vector<NBEdge::Connection> connections = edge->getConnections(); for (std::vector<NBEdge::Connection>::iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) { NBEdge::Connection& c = *it_con; if (c.toEdge != 0 && c.toEdge->getFromNode() != to) { WRITE_WARNING("Found and removed invalid connection from " + edge->getID() + " to " + c.toEdge->getID() + " via " + to->getID()); edge->removeFromConnections(c.toEdge); } } } }
void NIVisumTL::build(NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) { for (std::vector<NBNode*>::iterator ni = myNodes.begin(); ni != myNodes.end(); ni++) { NBNode* node = (*ni); TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type")); NBLoadedTLDef* def = new NBLoadedTLDef(ec, node->getID(), node, myOffset, type); tlc.insert(def); def->setCycleDuration((unsigned int) myCycleTime); // signalgroups for (std::map<std::string, SignalGroup*>::iterator gi = mySignalGroups.begin(); gi != mySignalGroups.end(); gi++) { std::string groupName = (*gi).first; NIVisumTL::SignalGroup& SG = *(*gi).second; def->addSignalGroup(groupName); def->addToSignalGroup(groupName, SG.connections()); // phases SUMOTime yellowTime = -1; if (myPhaseDefined) { for (std::map<std::string, Phase*>::iterator pi = SG.phases().begin(); pi != SG.phases().end(); pi++) { NIVisumTL::Phase& PH = *(*pi).second; def->addSignalGroupPhaseBegin(groupName, PH.getStartTime(), NBTrafficLightDefinition::TLCOLOR_GREEN); def->addSignalGroupPhaseBegin(groupName, PH.getEndTime(), NBTrafficLightDefinition::TLCOLOR_RED); yellowTime = MAX2(PH.getYellowTime(), yellowTime); }; } else { def->addSignalGroupPhaseBegin(groupName, SG.getStartTime(), NBTrafficLightDefinition::TLCOLOR_GREEN); def->addSignalGroupPhaseBegin(groupName, SG.getEndTime(), NBTrafficLightDefinition::TLCOLOR_RED); yellowTime = MAX2(SG.getYellowTime(), yellowTime); } // yellowTime can be -1 if not given in the input; it will be "patched" later def->setSignalYellowTimes(groupName, myIntermediateTime, yellowTime); } } }
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_XML::writeNodes(const OptionsCont& oc, NBNodeCont& nc) { const GeoConvHelper& gch = GeoConvHelper::getFinal(); bool useGeo = oc.exists("proj.plain-geo") && oc.getBool("proj.plain-geo"); if (useGeo && !gch.usingGeoProjection()) { WRITE_WARNING("Ignoring option \"proj.plain-geo\" because no geo-conversion has been defined"); useGeo = false; } const bool geoAccuracy = useGeo || gch.usingInverseGeoProjection(); OutputDevice& device = OutputDevice::getDevice(oc.getString("plain-output-prefix") + ".nod.xml"); device.writeXMLHeader("nodes", NWFrame::MAJOR_VERSION + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://sumo-sim.org/xsd/nodes_file.xsd\""); // write network offsets and projection to allow reconstruction of original coordinates if (!useGeo) { NWWriter_SUMO::writeLocation(device); } // write nodes for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; device.openTag(SUMO_TAG_NODE); device.writeAttr(SUMO_ATTR_ID, n->getID()); // write position Position pos = n->getPosition(); if (useGeo) { gch.cartesian2geo(pos); } if (geoAccuracy) { device.setPrecision(GEO_OUTPUT_ACCURACY); } NWFrame::writePositionLong(pos, device); if (geoAccuracy) { device.setPrecision(); } device.writeAttr(SUMO_ATTR_TYPE, toString(n->getType())); if (n->isTLControlled()) { const std::set<NBTrafficLightDefinition*>& tlss = n->getControllingTLS(); // set may contain multiple programs for the same id. // make sure ids are unique and sorted std::set<std::string> tlsIDs; for (std::set<NBTrafficLightDefinition*>::const_iterator it_tl = tlss.begin(); it_tl != tlss.end(); it_tl++) { tlsIDs.insert((*it_tl)->getID()); } std::vector<std::string> sortedIDs(tlsIDs.begin(), tlsIDs.end()); sort(sortedIDs.begin(), sortedIDs.end()); device.writeAttr(SUMO_ATTR_TLID, sortedIDs); } device.closeTag(); } device.close(); }
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(); } }
void NWWriter_DlrNavteq::writeNodesUnsplitted(const OptionsCont& oc, NBNodeCont& nc, NBEdgeCont& ec) { // For "real" nodes we simply use the node id. // For internal nodes (geometry vectors describing edge geometry in the parlance of this format) // we use the id of the edge and do not bother with // compression (each direction gets its own internal node). // XXX add option for generating numerical ids in case the input network has string ids and the target process needs integers OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_nodes_unsplitted.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); if (!haveGeo) { WRITE_WARNING("DlrNavteq node data will be written in (floating point) cartesian coordinates"); } // write format specifier device << "# NODE_ID\tIS_BETWEEN_NODE\tamount_of_geocoordinates\tx1\ty1\t[x2 y2 ... xn yn]\n"; // write normal nodes for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; Position pos = n->getPosition(); gch.cartesian2geo(pos); pos.mul(geoScale); device << n->getID() << "\t0\t1\t" << pos.x() << "\t" << pos.y() << "\n"; } // write "internal" nodes for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) { NBEdge* e = (*i).second; const PositionVector& geom = e->getGeometry(); if (geom.size() > 2) { std::string internalNodeID = e->getID(); if (internalNodeID == UNDEFINED || (nc.retrieve(internalNodeID) != 0)) { // need to invent a new name to avoid clashing with the id of a 'real' node or a reserved name internalNodeID += "_geometry"; } device << internalNodeID << "\t1\t" << geom.size() - 2; for (size_t ii = 1; ii < geom.size() - 1; ++ii) { Position pos = geom[(int)ii]; gch.cartesian2geo(pos); pos.mul(geoScale); device << "\t" << pos.x() << "\t" << pos.y(); } device << "\n"; } } device.close(); }
void GNETLSEditorFrame::updateDescription() const { std::string description; if (myCurrentJunction == 0) { description = "No Junction Selected\n"; } else { NBNode* nbn = myCurrentJunction->getNBNode(); description = "Current junction: " + nbn->getID() + "\n("; if (!nbn->isTLControlled()) { description += "uncontrolled, "; } description += (myHaveModifications ? "modified)" : "unmodified)"); } myDescription->setText(description.c_str()); }
// =========================================================================== // method definitions // =========================================================================== GNEJunction::GNEJunction(NBNode& nbn, GNENet* net, bool loaded) : GUIGlObject(GLO_JUNCTION, nbn.getID()), GNEAttributeCarrier(SUMO_TAG_JUNCTION), myNBNode(nbn), myOrigPos(nbn.getPosition()), myAmCreateEdgeSource(false), myNet(net), myLogicStatus(loaded ? LOADED : GUESSED), myAmResponsible(false), myHasValidLogic(loaded), myAmTLSSelected(false) { const double EXTENT = 2; myBoundary = Boundary( myOrigPos.x() - EXTENT, myOrigPos.y() - EXTENT, myOrigPos.x() + EXTENT, myOrigPos.y() + EXTENT); myMaxSize = 2 * EXTENT; rebuildCrossings(false); }
void NIXMLConnectionsHandler::addWalkingArea(const SUMOSAXAttributes& attrs) { bool ok = true; NBNode* node = 0; EdgeVector edges; const std::string nodeID = attrs.get<std::string>(SUMO_ATTR_NODE, 0, ok); std::vector<std::string> edgeIDs; if (!attrs.hasAttribute(SUMO_ATTR_EDGES)) { WRITE_ERROR("No edges specified for walkingArea at node '" + nodeID + "'."); return; } SUMOSAXAttributes::parseStringVector(attrs.get<std::string>(SUMO_ATTR_EDGES, 0, ok), edgeIDs); if (!ok) { return; } for (std::vector<std::string>::const_iterator it = edgeIDs.begin(); it != edgeIDs.end(); ++it) { NBEdge* edge = myEdgeCont.retrieve(*it); if (edge == 0) { WRITE_ERROR("Edge '" + (*it) + "' for walkingArea at node '" + nodeID + "' is not known."); return; } if (node == 0) { if (edge->getToNode()->getID() == nodeID) { node = edge->getToNode(); } else if (edge->getFromNode()->getID() == nodeID) { node = edge->getFromNode(); } else { WRITE_ERROR("Edge '" + (*it) + "' does not touch node '" + nodeID + "'."); return; } } else { if (edge->getToNode() != node && edge->getFromNode() != node) { WRITE_ERROR("Edge '" + (*it) + "' does not touch node '" + nodeID + "'."); return; } } edges.push_back(edge); } PositionVector customShape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, 0, ok, PositionVector::EMPTY); if (!NBNetBuilder::transformCoordinates(customShape)) { WRITE_ERROR("Unable to project shape for walkingArea at node '" + node->getID() + "'."); } node->addWalkingAreaShape(edges, customShape); }
void NBTrafficLightLogicCont::setTLControllingInformation(const NBEdgeCont& ec, const NBNodeCont& nc) { Definitions definitions = getDefinitions(); // set the information about all participants, first for (Definitions::iterator it = definitions.begin(); it != definitions.end(); it++) { (*it)->setParticipantsInformation(); } // clear previous information because tlDefs may have been removed in NETEDIT ec.clearControllingTLInformation(); // insert the information about the tl-controlling for (Definitions::iterator it = definitions.begin(); it != definitions.end(); it++) { (*it)->setTLControllingInformation(); } // handle rail signals which are not instantiated as normal definitions for (std::map<std::string, NBNode*>::const_iterator it = nc.begin(); it != nc.end(); it ++) { NBNode* n = it->second; if (n->getType() == NODETYPE_RAIL_SIGNAL || n->getType() == NODETYPE_RAIL_CROSSING) { NBOwnTLDef dummy(n->getID(), n, 0, TLTYPE_STATIC); dummy.setParticipantsInformation(); dummy.setTLControllingInformation(); n->removeTrafficLight(&dummy); } } }
void GNETLSEditorFrame::buildIinternalLanes(NBTrafficLightDefinition* tlDef) { // clean up previous objects SUMORTree& rtree = myViewNet->getNet()->getVisualisationSpeedUp(); for (TLIndexMap::iterator it = myInternalLanes.begin(); it != myInternalLanes.end(); it++) { std::vector<GNEInternalLane*> lanes = it->second; for (std::vector<GNEInternalLane*>::iterator it_lane = lanes.begin(); it_lane != lanes.end(); it_lane++) { rtree.removeAdditionalGLObject(*it_lane); delete *it_lane; } } myInternalLanes.clear(); if (tlDef != 0) { const int NUM_POINTS = 10; assert(myCurrentJunction); SUMORTree& rtree = myViewNet->getNet()->getVisualisationSpeedUp(); NBNode* nbn = myCurrentJunction->getNBNode(); std::string innerID = ":" + nbn->getID(); // see NWWriter_SUMO::writeInternalEdges const NBConnectionVector& links = tlDef->getControlledLinks(); for (NBConnectionVector::const_iterator it = links.begin(); it != links.end(); it++) { int tlIndex = it->getTLIndex(); PositionVector shape = nbn->computeInternalLaneShape(it->getFrom(), NBEdge::Connection(it->getFromLane(), it->getTo(), it->getToLane()), NUM_POINTS); GNEInternalLane* ilane = new GNEInternalLane(this, innerID + '_' + toString(tlIndex), shape, tlIndex); rtree.addAdditionalGLObject(ilane); myInternalLanes[tlIndex].push_back(ilane); } const std::vector<NBNode::Crossing>& crossings = nbn->getCrossings(); for (std::vector<NBNode::Crossing>::const_iterator it = crossings.begin(); it != crossings.end(); it++) { const NBNode::Crossing& c = *it; GNEInternalLane* ilane = new GNEInternalLane(this, c.id, c.shape, c.tlLinkNo); rtree.addAdditionalGLObject(ilane); myInternalLanes[c.tlLinkNo].push_back(ilane); } } }
void NWWriter_DlrNavteq::writeNodesUnsplitted(const OptionsCont& oc, NBNodeCont& nc, NBEdgeCont& ec, std::map<NBEdge*, std::string>& internalNodes) { // For "real" nodes we simply use the node id. // For internal nodes (geometry vectors describing edge geometry in the parlance of this format) // we use the id of the edge and do not bother with // compression (each direction gets its own internal node). OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_nodes_unsplitted.txt"); writeHeader(device, oc); const GeoConvHelper& gch = GeoConvHelper::getFinal(); const bool haveGeo = gch.usingGeoProjection(); const double geoScale = pow(10.0f, haveGeo ? 5 : 2); // see NIImporter_DlrNavteq::GEO_SCALE device.setPrecision(oc.getInt("dlr-navteq.precision")); if (!haveGeo) { WRITE_WARNING("DlrNavteq node data will be written in (floating point) cartesian coordinates"); } // write format specifier device << "# NODE_ID\tIS_BETWEEN_NODE\tamount_of_geocoordinates\tx1\ty1\t[x2 y2 ... xn yn]\n"; // write header Boundary boundary = gch.getConvBoundary(); Position min(boundary.xmin(), boundary.ymin()); Position max(boundary.xmax(), boundary.ymax()); gch.cartesian2geo(min); min.mul(geoScale); gch.cartesian2geo(max); max.mul(geoScale); int multinodes = 0; for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) { if ((*i).second->getGeometry().size() > 2) { multinodes++; } } device << "# [xmin_region] " << min.x() << "\n"; device << "# [xmax_region] " << max.x() << "\n"; device << "# [ymin_region] " << min.y() << "\n"; device << "# [ymax_region] " << max.y() << "\n"; device << "# [elements_multinode] " << multinodes << "\n"; device << "# [elements_normalnode] " << nc.size() << "\n"; device << "# [xmin] " << min.x() << "\n"; device << "# [xmax] " << max.x() << "\n"; device << "# [ymin] " << min.y() << "\n"; device << "# [ymax] " << max.y() << "\n"; // write normal nodes for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) { NBNode* n = (*i).second; Position pos = n->getPosition(); gch.cartesian2geo(pos); pos.mul(geoScale); device << n->getID() << "\t0\t1\t" << pos.x() << "\t" << pos.y() << "\n"; } // write "internal" nodes std::vector<std::string> avoid; std::set<std::string> reservedNodeIDs; const bool numericalIDs = oc.getBool("numerical-ids"); if (oc.isSet("reserved-ids")) { NBHelpers::loadPrefixedIDsFomFile(oc.getString("reserved-ids"), "node:", reservedNodeIDs); // backward compatibility NBHelpers::loadPrefixedIDsFomFile(oc.getString("reserved-ids"), "junction:", reservedNodeIDs); // selection format } if (numericalIDs) { avoid = nc.getAllNames(); std::vector<std::string> avoid2 = ec.getAllNames(); avoid.insert(avoid.end(), avoid2.begin(), avoid2.end()); avoid.insert(avoid.end(), reservedNodeIDs.begin(), reservedNodeIDs.end()); } IDSupplier idSupplier("", avoid); for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) { NBEdge* e = (*i).second; PositionVector geom = e->getGeometry(); if (geom.size() > 2) { // the import NIImporter_DlrNavteq checks for the presence of a // negated edge id to determine spread type. We may need to do some // shifting to make this consistent const bool hasOppositeID = ec.getOppositeByID(e->getID()) != nullptr; if (e->getLaneSpreadFunction() == LANESPREAD_RIGHT && !hasOppositeID) { // need to write center-line geometry instead try { geom.move2side(e->getTotalWidth() / 2); } catch (InvalidArgument& exception) { WRITE_WARNING("Could not reconstruct shape for edge:'" + e->getID() + "' (" + exception.what() + ")."); } } else if (e->getLaneSpreadFunction() == LANESPREAD_CENTER && hasOppositeID) { // need to write left-border geometry instead try { geom.move2side(-e->getTotalWidth() / 2); } catch (InvalidArgument& exception) { WRITE_WARNING("Could not reconstruct shape for edge:'" + e->getID() + "' (" + exception.what() + ")."); } } std::string internalNodeID = e->getID(); if (internalNodeID == UNDEFINED || (nc.retrieve(internalNodeID) != nullptr) || reservedNodeIDs.count(internalNodeID) > 0 ) { // need to invent a new name to avoid clashing with the id of a 'real' node or a reserved name if (numericalIDs) { internalNodeID = idSupplier.getNext(); } else { internalNodeID += "_geometry"; } } internalNodes[e] = internalNodeID; device << internalNodeID << "\t1\t" << geom.size() - 2; for (int ii = 1; ii < (int)geom.size() - 1; ++ii) { Position pos = geom[(int)ii]; gch.cartesian2geo(pos); pos.mul(geoScale); device << "\t" << pos.x() << "\t" << pos.y(); } device << "\n"; } } device.close(); }
// =========================================================================== // 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 NIImporter_VISUM::parse_Lanes() { // get the node NBNode* node = getNamedNode("KNOTNR"); // get the edge NBEdge* baseEdge = getNamedEdge("STRNR"); NBEdge* edge = getNamedEdgeContinuating("STRNR", node); // check if (node == 0 || edge == 0) { return; } // get the lane std::string laneS = myLineParser.know("FSNR") ? NBHelpers::normalIDRepresentation(myLineParser.get("FSNR")) : NBHelpers::normalIDRepresentation(myLineParser.get("NR")); int lane = -1; try { lane = TplConvert::_2int(laneS.c_str()); } catch (NumberFormatException&) { WRITE_ERROR("A lane number for edge '" + edge->getID() + "' is not numeric (" + laneS + ")."); return; } lane -= 1; if (lane < 0) { WRITE_ERROR("A lane number for edge '" + edge->getID() + "' is not positive (" + laneS + ")."); return; } // get the direction std::string dirS = NBHelpers::normalIDRepresentation(myLineParser.get("RICHTTYP")); int prevLaneNo = baseEdge->getNumLanes(); if ((dirS == "1" && !(node->hasIncoming(edge))) || (dirS == "0" && !(node->hasOutgoing(edge)))) { // get the last part of the turnaround direction edge = getReversedContinuating(edge, node); } // get the length std::string lengthS = NBHelpers::normalIDRepresentation(myLineParser.get("LAENGE")); SUMOReal length = -1; try { length = TplConvert::_2SUMOReal(lengthS.c_str()); } catch (NumberFormatException&) { WRITE_ERROR("A lane length for edge '" + edge->getID() + "' is not numeric (" + lengthS + ")."); return; } if (length < 0) { WRITE_ERROR("A lane length for edge '" + edge->getID() + "' is not positive (" + lengthS + ")."); return; } // if (dirS == "1") { lane -= prevLaneNo; } // if (length == 0) { if ((int) edge->getNumLanes() > lane) { // ok, we know this already... return; } // increment by one edge->incLaneNo(1); } else { // check whether this edge already has been created if (edge->getID().substr(edge->getID().length() - node->getID().length() - 1) == "_" + node->getID()) { if (edge->getID().substr(edge->getID().find('_')) == "_" + toString(length) + "_" + node->getID()) { if ((int) edge->getNumLanes() > lane) { // ok, we know this already... return; } // increment by one edge->incLaneNo(1); return; } } // nope, we have to split the edge... // maybe it is not the proper edge to split - VISUM seems not to sort the splits... bool mustRecheck = true; SUMOReal seenLength = 0; while (mustRecheck) { if (edge->getID().substr(edge->getID().length() - node->getID().length() - 1) == "_" + node->getID()) { // ok, we have a previously created edge here std::string sub = edge->getID(); sub = sub.substr(sub.rfind('_', sub.rfind('_') - 1)); sub = sub.substr(1, sub.find('_', 1) - 1); SUMOReal dist = TplConvert::_2SUMOReal(sub.c_str()); if (dist < length) { seenLength += edge->getLength(); if (dirS == "1") { // incoming -> move back edge = edge->getFromNode()->getIncomingEdges()[0]; } else { // outgoing -> move forward edge = edge->getToNode()->getOutgoingEdges()[0]; } } else { mustRecheck = false; } } else { // we have the center edge - do not continue... mustRecheck = false; } } // compute position Position p; SUMOReal useLength = length - seenLength; useLength = edge->getLength() - useLength; std::string edgeID = edge->getID(); p = edge->getGeometry().positionAtLengthPosition(useLength); if (edgeID.substr(edgeID.length() - node->getID().length() - 1) == "_" + node->getID()) { edgeID = edgeID.substr(0, edgeID.find('_')); } NBNode* rn = new NBNode(edgeID + "_" + toString((size_t) length) + "_" + node->getID(), p); if (!myNetBuilder.getNodeCont().insert(rn)) { throw ProcessError("Ups - could not insert node!"); } std::string nid = edgeID + "_" + toString((size_t) length) + "_" + node->getID(); myNetBuilder.getEdgeCont().splitAt(myNetBuilder.getDistrictCont(), edge, useLength, rn, edge->getID(), nid, edge->getNumLanes() + 0, edge->getNumLanes() + 1); NBEdge* nedge = myNetBuilder.getEdgeCont().retrieve(nid); nedge = nedge->getToNode()->getOutgoingEdges()[0]; while (nedge->getID().substr(nedge->getID().length() - node->getID().length() - 1) == "_" + node->getID()) { assert(nedge->getToNode()->getOutgoingEdges().size() > 0); nedge->incLaneNo(1); nedge = nedge->getToNode()->getOutgoingEdges()[0]; } } }
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); } } } }
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); } }
void NIXMLConnectionsHandler::addCrossing(const SUMOSAXAttributes& attrs) { bool ok = true; NBNode* node = 0; EdgeVector edges; const std::string nodeID = attrs.get<std::string>(SUMO_ATTR_NODE, 0, ok); const double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, nodeID.c_str(), ok, NBEdge::UNSPECIFIED_WIDTH, true); const bool discard = attrs.getOpt<bool>(SUMO_ATTR_DISCARD, nodeID.c_str(), ok, false, true); int tlIndex = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX, 0, ok, -1); int tlIndex2 = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX2, 0, ok, -1); std::vector<std::string> edgeIDs; if (!attrs.hasAttribute(SUMO_ATTR_EDGES)) { if (discard) { node = myNodeCont.retrieve(nodeID); if (node == 0) { WRITE_ERROR("Node '" + nodeID + "' in crossing is not known."); return; } node->discardAllCrossings(true); return; } else { WRITE_ERROR("No edges specified for crossing at node '" + nodeID + "'."); return; } } SUMOSAXAttributes::parseStringVector(attrs.get<std::string>(SUMO_ATTR_EDGES, 0, ok), edgeIDs); if (!ok) { return; } for (std::vector<std::string>::const_iterator it = edgeIDs.begin(); it != edgeIDs.end(); ++it) { NBEdge* edge = myEdgeCont.retrieve(*it); if (edge == 0) { WRITE_ERROR("Edge '" + (*it) + "' for crossing at node '" + nodeID + "' is not known."); return; } if (node == 0) { if (edge->getToNode()->getID() == nodeID) { node = edge->getToNode(); } else if (edge->getFromNode()->getID() == nodeID) { node = edge->getFromNode(); } else { WRITE_ERROR("Edge '" + (*it) + "' does not touch node '" + nodeID + "'."); return; } } else { if (edge->getToNode() != node && edge->getFromNode() != node) { WRITE_ERROR("Edge '" + (*it) + "' does not touch node '" + nodeID + "'."); return; } } edges.push_back(edge); } bool priority = attrs.getOpt<bool>(SUMO_ATTR_PRIORITY, nodeID.c_str(), ok, node->isTLControlled(), true); if (node->isTLControlled() && !priority) { // traffic_light nodes should always have priority crossings WRITE_WARNING("Crossing at controlled node '" + nodeID + "' must be prioritized"); priority = true; } PositionVector customShape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, 0, ok, PositionVector::EMPTY); if (!NBNetBuilder::transformCoordinates(customShape)) { WRITE_ERROR("Unable to project shape for crossing at node '" + node->getID() + "'."); } if (discard) { node->removeCrossing(edges); } else { if (node->checkCrossingDuplicated(edges)) { WRITE_ERROR("Crossing with edges '" + toString(edges) + "' already exists at node '" + node->getID() + "'."); return; } node->addCrossing(edges, width, priority, tlIndex, tlIndex2, customShape); } }
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(); } }
// =========================================================================== // 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(); }