// =========================================================================== // method definitions // =========================================================================== void MSEmissionExport::write(OutputDevice& of, SUMOTime timestep, int precision) { of.openTag("timestep").writeAttr("time", time2string(timestep)); of.setPrecision(precision); MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl(); for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) { const SUMOVehicle* veh = it->second; const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(veh); if (veh->isOnRoad()) { std::string fclass = veh->getVehicleType().getID(); fclass = fclass.substr(0, fclass.find_first_of("@")); PollutantsInterface::Emissions emiss = PollutantsInterface::computeAll(veh->getVehicleType().getEmissionClass(), veh->getSpeed(), veh->getAcceleration(), veh->getSlope()); of.openTag("vehicle").writeAttr("id", veh->getID()).writeAttr("eclass", PollutantsInterface::getName(veh->getVehicleType().getEmissionClass())); of.writeAttr("CO2", emiss.CO2).writeAttr("CO", emiss.CO).writeAttr("HC", emiss.HC).writeAttr("NOx", emiss.NOx); of.writeAttr("PMx", emiss.PMx).writeAttr("fuel", emiss.fuel).writeAttr("electricity", emiss.electricity); of.writeAttr("noise", HelpersHarmonoise::computeNoise(veh->getVehicleType().getEmissionClass(), veh->getSpeed(), veh->getAcceleration())); of.writeAttr("route", veh->getRoute().getID()).writeAttr("type", fclass); if (microVeh != 0) { of.writeAttr("waiting", microVeh->getWaitingSeconds()); of.writeAttr("lane", microVeh->getLane()->getID()); } of.writeAttr("pos", veh->getPositionOnLane()).writeAttr("speed", veh->getSpeed()); of.writeAttr("angle", GeomHelper::naviDegree(veh->getAngle())).writeAttr("x", veh->getPosition().x()).writeAttr("y", veh->getPosition().y()); of.closeTag(); } } of.setPrecision(OUTPUT_ACCURACY); of.closeTag(); }
void ODMatrix::writeFlows(const SUMOTime begin, const SUMOTime end, OutputDevice& dev, bool noVtype, const std::string& prefix, bool asProbability) { if (myContainer.size() == 0) { return; } int flowName = 0; sortByBeginTime(); // recheck begin time for (std::vector<ODCell*>::const_iterator i = myContainer.begin(); i != myContainer.end(); ++i) { const ODCell* const c = *i; if (c->end > begin && c->begin < end) { dev.openTag(SUMO_TAG_FLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++)); dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin)); dev.writeAttr(SUMO_ATTR_END, time2string(c->end)); if (!asProbability) { dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber)); } else { const double probability = float(c->vehicleNumber) / STEPS2TIME(c->end - c->begin); if (probability > 1) { WRITE_WARNING("Flow density of " + toString(probability) + " vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."); dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber)); } else { dev.setPrecision(6); dev.writeAttr(SUMO_ATTR_PROB, probability); dev.setPrecision(); } } writeDefaultAttrs(dev, noVtype, *i); dev.closeTag(); } } }
void GeoConvHelper::writeLocation(OutputDevice& into) { into.openTag(SUMO_TAG_LOCATION); into.writeAttr(SUMO_ATTR_NET_OFFSET, myFinal.getOffsetBase()); into.writeAttr(SUMO_ATTR_CONV_BOUNDARY, myFinal.getConvBoundary()); if (myFinal.usingGeoProjection()) { into.setPrecision(gPrecisionGeo); } into.writeAttr(SUMO_ATTR_ORIG_BOUNDARY, myFinal.getOrigBoundary()); if (myFinal.usingGeoProjection()) { into.setPrecision(); } into.writeAttr(SUMO_ATTR_ORIG_PROJ, myFinal.getProjString()); into.closeTag(); into.lf(); }
// =========================================================================== // static method definitions // =========================================================================== OutputDevice& OutputDevice::getDevice(const std::string& name) { // check whether the device has already been aqcuired if (myOutputDevices.find(name) != myOutputDevices.end()) { return *myOutputDevices[name]; } // build the device OutputDevice* dev = 0; // check whether the device shall print to stdout if (name == "stdout") { dev = OutputDevice_COUT::getDevice(); } else if (name == "stderr") { dev = OutputDevice_CERR::getDevice(); } else if (FileHelpers::isSocket(name)) { try { int port = TplConvert::_2int(name.substr(name.find(":") + 1).c_str()); dev = new OutputDevice_Network(name.substr(0, name.find(":")), port); } catch (NumberFormatException&) { throw IOError("Given port number '" + name.substr(name.find(":") + 1) + "' is not numeric."); } catch (EmptyData&) { throw IOError("No port number given."); } } else { const size_t len = name.length(); dev = new OutputDevice_File(name, len > 4 && name.substr(len - 4) == ".sbx"); } dev->setPrecision(); dev->getOStream() << std::setiosflags(std::ios::fixed); myOutputDevices[name] = dev; return *dev; }
void NWWriter_SUMO::writeLocation(OutputDevice& into) { const GeoConvHelper& geoConvHelper = GeoConvHelper::getFinal(); into.openTag(SUMO_TAG_LOCATION); into.writeAttr(SUMO_ATTR_NET_OFFSET, geoConvHelper.getOffsetBase()); into.writeAttr(SUMO_ATTR_CONV_BOUNDARY, geoConvHelper.getConvBoundary()); if (geoConvHelper.usingGeoProjection()) { into.setPrecision(GEO_OUTPUT_ACCURACY); } into.writeAttr(SUMO_ATTR_ORIG_BOUNDARY, geoConvHelper.getOrigBoundary()); if (geoConvHelper.usingGeoProjection()) { into.setPrecision(); } into.writeAttr(SUMO_ATTR_ORIG_PROJ, geoConvHelper.getProjString()); into.closeTag(); into.lf(); }
void MSFCDExport::writeTransportable(OutputDevice& of, const MSEdge* e, MSTransportable* p, SumoXMLTag tag, bool useGeo, bool elevation) { Position pos = p->getPosition(); if (useGeo) { of.setPrecision(GEO_OUTPUT_ACCURACY); GeoConvHelper::getFinal().cartesian2geo(pos); } of.openTag(tag); of.writeAttr(SUMO_ATTR_ID, p->getID()); of.writeAttr(SUMO_ATTR_X, pos.x()); of.writeAttr(SUMO_ATTR_Y, pos.y()); if (elevation) { of.writeAttr(SUMO_ATTR_Z, pos.z()); } of.writeAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(p->getAngle())); of.writeAttr(SUMO_ATTR_SPEED, p->getSpeed()); of.writeAttr(SUMO_ATTR_POSITION, p->getEdgePos()); of.writeAttr(SUMO_ATTR_EDGE, e->getID()); of.writeAttr(SUMO_ATTR_SLOPE, e->getLanes()[0]->getShape().slopeDegreeAtOffset(p->getEdgePos())); of.closeTag(); }
int NWWriter_OpenDrive::writeInternalEdge(OutputDevice& device, OutputDevice& junctionDevice, const NBEdge* inEdge, int nodeID, int edgeID, int inEdgeID, int outEdgeID, int connectionID, const std::vector<NBEdge::Connection>& parallel, const bool isOuterEdge, const double straightThresh, const std::string& centerMark) { assert(parallel.size() != 0); const NBEdge::Connection& cLeft = parallel.back(); const NBEdge* outEdge = cLeft.toEdge; PositionVector begShape = getLeftLaneBorder(inEdge, cLeft.fromLane); PositionVector endShape = getLeftLaneBorder(outEdge, cLeft.toLane); //std::cout << "computing reference line for internal lane " << cLeft.getInternalLaneID() << " begLane=" << inEdge->getLaneShape(cLeft.fromLane) << " endLane=" << outEdge->getLaneShape(cLeft.toLane) << "\n"; double length; double laneOffset = 0; 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(cLeft.fromLane) + "' to lane '" + outEdge->getLaneID(cLeft.toLane) + "'. Use option 'junctions.scurve-stretch' or increase radius of junction '" + inEdge->getToNode()->getID() + "' to fix this."); } else if (length <= NUMERICAL_EPS) { // left-curving geometry-like edges must use the right // side as reference line and shift begShape = getRightLaneBorder(inEdge, cLeft.fromLane); endShape = getRightLaneBorder(outEdge, cLeft.toLane); init = NBNode::bezierControlPoints(begShape, endShape, turnaround, 25, 25, ok, 0, straightThresh); if (init.size() != 0) { length = bezier(init, 12).length2D(); laneOffset = outEdge->getLaneWidth(cLeft.toLane); //std::cout << " internalLane=" << cLeft.getInternalLaneID() << " length=" << length << "\n"; } } } else { length = bezier(init, 12).length2D(); } junctionDevice << " <connection id=\"" << connectionID << "\" incomingRoad=\"" << inEdgeID << "\" connectingRoad=\"" << edgeID << "\" contactPoint=\"start\">\n"; device.openTag("road"); device.writeAttr("name", cLeft.id); device.setPrecision(8); // length requires higher precision device.writeAttr("length", MAX2(POSITION_EPS, length)); device.setPrecision(gPrecision); device.writeAttr("id", edgeID); device.writeAttr("junction", nodeID); device.openTag("link"); device.openTag("predecessor"); device.writeAttr("elementType", "road"); device.writeAttr("elementId", inEdgeID); device.writeAttr("contactPoint", "end"); device.closeTag(); device.openTag("successor"); device.writeAttr("elementType", "road"); device.writeAttr("elementId", outEdgeID); 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); elevationOSS.setPrecision(8); #ifdef DEBUG_SMOOTH_GEOM if (DEBUGCOND) { std::cout << "write planview for internal edge " << cLeft.id << " init=" << init << " fallback=" << fallBackShape << " begShape=" << begShape << " endShape=" << endShape << "\n"; } #endif if (init.size() == 0) { writeGeomLines(fallBackShape, device, elevationOSS); } else { writeGeomPP3(device, elevationOSS, init, length); } device.setPrecision(gPrecision); device.closeTag(); writeElevationProfile(fallBackShape, device, elevationOSS); device << " <lateralProfile/>\n"; device << " <lanes>\n"; if (laneOffset != 0) { device << " <laneOffset s=\"0\" a=\"" << laneOffset << "\" b=\"0\" c=\"0\" d=\"0\"/>\n"; } device << " <laneSection s=\"0\">\n"; writeEmptyCenterLane(device, centerMark, 0); device << " <right>\n"; for (int j = (int)parallel.size(); --j >= 0;) { const NBEdge::Connection& c = parallel[j]; const int fromIndex = c.fromLane - inEdge->getNumLanes(); const int toIndex = c.toLane - outEdge->getNumLanes(); device << " <lane id=\"-" << parallel.size() - j << "\" type=\"" << getLaneType(outEdge->getPermissions(c.toLane)) << "\" level=\"true\">\n"; device << " <link>\n"; device << " <predecessor id=\"" << fromIndex << "\"/>\n"; device << " <successor id=\"" << toIndex << "\"/>\n"; device << " </link>\n"; device << " <width sOffset=\"0\" a=\"" << outEdge->getLaneWidth(c.toLane) << "\" b=\"0\" c=\"0\" d=\"0\"/>\n"; std::string markType = "broken"; if (inEdge->isTurningDirectionAt(outEdge)) { markType = "none"; } else if (c.fromLane == 0 && c.toLane == 0 && isOuterEdge) { // solid road mark at the outer border markType = "solid"; } else if (isOuterEdge && j > 0 && (outEdge->getPermissions(parallel[j - 1].toLane) & ~(SVC_PEDESTRIAN | SVC_BICYCLE)) == 0) { // solid road mark to the left of sidewalk or bicycle lane markType = "solid"; } else if (!inEdge->getToNode()->geometryLike()) { // draw shorter road marks to indicate turning paths LinkDirection dir = inEdge->getToNode()->getDirection(inEdge, outEdge, OptionsCont::getOptions().getBool("lefthand")); if (dir == LINKDIR_LEFT || dir == LINKDIR_RIGHT || dir == LINKDIR_PARTLEFT || dir == LINKDIR_PARTRIGHT) { // XXX <type><line/><type> is not rendered by odrViewer so cannot be validated // device << " <type name=\"broken\" width=\"0.13\">\n"; // device << " <line length=\"0.5\" space=\"0.5\" tOffset=\"0\" sOffset=\"0\" rule=\"none\"/>\n"; // device << " </type>\n"; markType = "none"; } } device << " <roadMark sOffset=\"0\" type=\"" << markType << "\" weight=\"standard\" color=\"standard\" width=\"0.13\"/>\n"; device << " <speed sOffset=\"0\" max=\"" << c.vmax << "\"/>\n"; device << " </lane>\n"; junctionDevice << " <laneLink from=\"" << fromIndex << "\" to=\"" << toIndex << "\"/>\n"; connectionID++; } device << " </right>\n"; device << " </laneSection>\n"; device << " </lanes>\n"; device << " <objects/>\n"; device << " <signals/>\n"; device.closeTag(); junctionDevice << " </connection>\n"; return connectionID; }
void NWWriter_OpenDrive::writeNormalEdge(OutputDevice& device, const NBEdge* e, int edgeID, int fromNodeID, int toNodeID, const bool origNames, const double straightThresh) { // 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); double length = 0; planViewOSS.openTag("planView"); // 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(gPrecision); device.writeAttr("id", edgeID); device.writeAttr("junction", -1); if (fromNodeID != INVALID_ID || toNodeID != INVALID_ID) { device.openTag("link"); if (fromNodeID != INVALID_ID) { device.openTag("predecessor"); device.writeAttr("elementType", "junction"); device.writeAttr("elementId", fromNodeID); device.closeTag(); } if (toNodeID != INVALID_ID) { device.openTag("successor"); device.writeAttr("elementType", "junction"); device.writeAttr("elementId", toNodeID); 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"; const std::string centerMark = e->getPermissions(e->getNumLanes() - 1) == 0 ? "none" : "solid"; writeEmptyCenterLane(device, centerMark, 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"; } else if (j > 0 && (e->getPermissions(j - 1) & ~(SVC_PEDESTRIAN | SVC_BICYCLE)) == 0) { // solid road mark to the left of sidewalk or bicycle lane markType = "solid"; } else if (e->getPermissions(j) == 0) { // solid road mark to the right of a forbidden lane 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); }
// =========================================================================== // method definitions // =========================================================================== void MSFCDExport::write(OutputDevice& of, SUMOTime timestep, bool elevation) { const bool useGeo = OptionsCont::getOptions().getBool("fcd-output.geo"); const bool signals = OptionsCont::getOptions().getBool("fcd-output.signals"); of.openTag("timestep").writeAttr(SUMO_ATTR_TIME, time2string(timestep)); MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl(); for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) { const SUMOVehicle* veh = it->second; const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(veh); if (veh->isOnRoad() || veh->isParking()) { Position pos = veh->getPosition(); if (useGeo) { of.setPrecision(GEO_OUTPUT_ACCURACY); GeoConvHelper::getFinal().cartesian2geo(pos); } of.openTag(SUMO_TAG_VEHICLE); of.writeAttr(SUMO_ATTR_ID, veh->getID()); of.writeAttr(SUMO_ATTR_X, pos.x()); of.writeAttr(SUMO_ATTR_Y, pos.y()); if (elevation) { of.writeAttr(SUMO_ATTR_Z, pos.z()); } of.writeAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(veh->getAngle())); of.writeAttr(SUMO_ATTR_TYPE, veh->getVehicleType().getID()); of.writeAttr(SUMO_ATTR_SPEED, veh->getSpeed()); of.writeAttr(SUMO_ATTR_POSITION, veh->getPositionOnLane()); if (microVeh != 0) { of.writeAttr(SUMO_ATTR_LANE, microVeh->getLane()->getID()); } of.writeAttr(SUMO_ATTR_SLOPE, veh->getSlope()); if (microVeh != 0 && signals) { of.writeAttr("signals", toString(microVeh->getSignals())); } of.closeTag(); if (microVeh != 0) { // write persons and containers const std::vector<MSTransportable*>& persons = microVeh->getPersons(); for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) { writeTransportable(of, µVeh->getLane()->getEdge(), *it_p, SUMO_TAG_PERSON, useGeo, elevation); } const std::vector<MSTransportable*>& containers = microVeh->getContainers(); for (std::vector<MSTransportable*>::const_iterator it_c = containers.begin(); it_c != containers.end(); ++it_c) { writeTransportable(of, µVeh->getLane()->getEdge(), *it_c, SUMO_TAG_CONTAINER, useGeo, elevation); } } } } if (MSNet::getInstance()->getPersonControl().hasPersons()) { // write persons MSEdgeControl& ec = MSNet::getInstance()->getEdgeControl(); const MSEdgeVector& edges = ec.getEdges(); for (MSEdgeVector::const_iterator e = edges.begin(); e != edges.end(); ++e) { const std::vector<MSTransportable*>& persons = (*e)->getSortedPersons(timestep); for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) { writeTransportable(of, *e, *it_p, SUMO_TAG_PERSON, useGeo, elevation); } } } if (MSNet::getInstance()->getContainerControl().hasContainers()) { // write containers MSEdgeControl& ec = MSNet::getInstance()->getEdgeControl(); const std::vector<MSEdge*>& edges = ec.getEdges(); for (std::vector<MSEdge*>::const_iterator e = edges.begin(); e != edges.end(); ++e) { const std::vector<MSTransportable*>& containers = (*e)->getSortedContainers(timestep); for (std::vector<MSTransportable*>::const_iterator it_c = containers.begin(); it_c != containers.end(); ++it_c) { writeTransportable(of, *e, *it_c, SUMO_TAG_CONTAINER, useGeo, elevation); } } } of.closeTag(); }
void ROVehicle::saveAsXML(OutputDevice& os, OutputDevice* const typeos, bool asAlternatives, OptionsCont& options) const { if (typeos != nullptr && getType() != nullptr && !getType()->saved) { getType()->write(*typeos); getType()->saved = true; } if (getType() != nullptr && !getType()->saved) { getType()->write(os); getType()->saved = asAlternatives; } const bool writeTrip = options.exists("write-trips") && options.getBool("write-trips"); const bool writeGeoTrip = writeTrip && options.getBool("write-trips.geo"); // write the vehicle (new style, with included routes) getParameter().write(os, options, writeTrip ? SUMO_TAG_TRIP : SUMO_TAG_VEHICLE); // save the route if (writeTrip) { const ConstROEdgeVector edges = myRoute->getFirstRoute()->getEdgeVector(); const ROEdge* from = nullptr; const ROEdge* to = nullptr; if (edges.size() > 0) { if (edges.front()->isTazConnector()) { if (edges.size() > 1) { from = edges[1]; } } else { from = edges[0]; } if (edges.back()->isTazConnector()) { if (edges.size() > 1) { to = edges[edges.size() - 2]; } } else { to = edges[edges.size() - 1]; } } if (from != nullptr) { if (writeGeoTrip) { Position fromPos = from->getLanes()[0]->getShape().positionAtOffset2D(0); if (GeoConvHelper::getFinal().usingGeoProjection()) { os.setPrecision(gPrecisionGeo); GeoConvHelper::getFinal().cartesian2geo(fromPos); os.writeAttr(SUMO_ATTR_FROMLONLAT, fromPos); os.setPrecision(gPrecision); } else { os.writeAttr(SUMO_ATTR_FROMXY, fromPos); } } else { os.writeAttr(SUMO_ATTR_FROM, from->getID()); } } if (to != nullptr) { if (writeGeoTrip) { Position toPos = to->getLanes()[0]->getShape().positionAtOffset2D(to->getLanes()[0]->getShape().length2D()); if (GeoConvHelper::getFinal().usingGeoProjection()) { os.setPrecision(gPrecisionGeo); GeoConvHelper::getFinal().cartesian2geo(toPos); os.writeAttr(SUMO_ATTR_TOLONLAT, toPos); os.setPrecision(gPrecision); } else { os.writeAttr(SUMO_ATTR_TOXY, toPos); } } else { os.writeAttr(SUMO_ATTR_TO, to->getID()); } } if (getParameter().via.size() > 0) { if (writeGeoTrip) { PositionVector viaPositions; for (const std::string& viaID : getParameter().via) { const ROEdge* viaEdge = RONet::getInstance()->getEdge(viaID); assert(viaEdge != nullptr); Position viaPos = viaEdge->getLanes()[0]->getShape().positionAtOffset2D(viaEdge->getLanes()[0]->getShape().length2D() / 2); viaPositions.push_back(viaPos); } if (GeoConvHelper::getFinal().usingGeoProjection()) { for (int i = 0; i < (int)viaPositions.size(); i++) { GeoConvHelper::getFinal().cartesian2geo(viaPositions[i]); } os.setPrecision(gPrecisionGeo); os.writeAttr(SUMO_ATTR_VIALONLAT, viaPositions); os.setPrecision(gPrecision); } else { os.writeAttr(SUMO_ATTR_VIAXY, viaPositions); } } else { os.writeAttr(SUMO_ATTR_VIA, getParameter().via); } } } else { myRoute->writeXMLDefinition(os, this, asAlternatives, options.getBool("exit-times")); } for (std::vector<SUMOVehicleParameter::Stop>::const_iterator stop = getParameter().stops.begin(); stop != getParameter().stops.end(); ++stop) { stop->write(os); } getParameter().writeParams(os); os.closeTag(); }