LCOV - code coverage report
Current view: top level - src/netwrite - NWWriter_XML.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.1 % 324 318
Test Date: 2025-11-13 15:38:19 Functions: 100.0 % 13 13

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    NWWriter_XML.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Leonhard Luecken
      19              : /// @date    Tue, 11.05.2011
      20              : ///
      21              : // Exporter writing networks using XML (native input) format
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : #include <algorithm>
      25              : #include <utils/common/MsgHandler.h>
      26              : #include <utils/common/ToString.h>
      27              : #include <utils/common/StringUtils.h>
      28              : #include <utils/options/OptionsCont.h>
      29              : #include <utils/iodevices/OutputDevice.h>
      30              : #include <utils/geom/GeoConvHelper.h>
      31              : #include <netbuild/NBEdge.h>
      32              : #include <netbuild/NBEdgeCont.h>
      33              : #include <netbuild/NBNode.h>
      34              : #include <netbuild/NBNodeCont.h>
      35              : #include <netbuild/NBNetBuilder.h>
      36              : #include <netbuild/NBPTLineCont.h>
      37              : #include <netbuild/NBPTStop.h>
      38              : #include <netbuild/NBParking.h>
      39              : #include "NWFrame.h"
      40              : #include "NWWriter_SUMO.h"
      41              : #include "NWWriter_XML.h"
      42              : 
      43              : 
      44              : // ===========================================================================
      45              : // method definitions
      46              : // ===========================================================================
      47              : // ---------------------------------------------------------------------------
      48              : // static methods
      49              : // ---------------------------------------------------------------------------
      50              : void
      51         1807 : NWWriter_XML::writeNetwork(const OptionsCont& oc, const std::string& prefix, NBNetBuilder& nb) {
      52              :     // check whether plain-output files shall be generated
      53         1807 :     if (prefix != "") {
      54          175 :         const bool haveTypes = nb.getTypeCont().size() > 0;
      55          175 :         writeNodes(oc, prefix, nb.getNodeCont());
      56          173 :         if (haveTypes) {
      57           16 :             writeTypes(prefix, nb.getEdgeCont(), nb.getTypeCont());
      58              :         }
      59          173 :         writeEdgesAndConnections(oc, prefix, nb.getNodeCont(), nb.getEdgeCont());
      60          173 :         writeTrafficLights(prefix, nb.getTLLogicCont(), nb.getEdgeCont());
      61          173 :         writeConfig(oc, prefix, haveTypes);
      62              :     }
      63         3610 :     if (oc.isSet("junctions.join-output")) {
      64           10 :         writeJoinedJunctions(oc.getString("junctions.join-output"), nb.getNodeCont());
      65              :     }
      66         3610 :     if (oc.isSet("street-sign-output")) {
      67            1 :         writeStreetSigns(oc, nb.getEdgeCont());
      68              :     }
      69         3525 :     if (oc.exists("ptstop-output") && oc.isSet("ptstop-output")) {
      70           72 :         writePTStops(oc, nb.getPTStopCont());
      71              :     }
      72         3525 :     if (oc.exists("ptline-output") && oc.isSet("ptline-output")) {
      73           46 :         writePTLines(oc, nb.getPTLineCont());
      74              :     }
      75              : 
      76         3525 :     if (oc.exists("parking-output") && oc.isSet("parking-output")) {
      77            3 :         writeParkingAreas(oc, nb.getParkingCont(), nb.getEdgeCont());
      78              :     }
      79         3525 :     if (oc.exists("taz-output") && oc.isSet("taz-output")) {
      80            1 :         writeDistricts(oc, nb.getDistrictCont());
      81              :     }
      82         1805 : }
      83              : 
      84              : 
      85              : void
      86          173 : NWWriter_XML::writeConfig(const OptionsCont& oc, const std::string& prefix, bool haveTypes) {
      87          346 :     if (!oc.exists("node-files")) {
      88              :         // do not write configuration for netgen
      89            1 :         return;
      90              :     }
      91          172 :     OptionsCont* tmp = oc.clone();
      92          344 :     tmp->set("node-files", prefix + ".nod.xml");
      93          344 :     tmp->set("edge-files", prefix + ".edg.xml");
      94          344 :     tmp->set("connection-files", prefix + ".con.xml");
      95          344 :     tmp->set("tllogic-files", prefix + ".tll.xml");
      96          172 :     if (haveTypes) {
      97           32 :         tmp->set("type-files", prefix + ".typ.xml");
      98              :     }
      99          344 :     tmp->setDefault("sumo-net-file", "");
     100          344 :     tmp->setDefault("plain-output-prefix", "");
     101              : 
     102          172 :     const std::string configPath = prefix + ".netccfg";
     103          172 :     std::ofstream out(configPath.c_str());
     104          172 :     if (!out.good()) {
     105            0 :         delete tmp;
     106            0 :         throw ProcessError(TLF("Could not save configuration to '%'", configPath));
     107              :     } else {
     108          344 :         tmp->writeConfiguration(out, true, false, false);
     109              :     }
     110          172 :     delete tmp;
     111          172 : }
     112              : 
     113              : 
     114              : void
     115          175 : NWWriter_XML::writeNodes(const OptionsCont& oc, const std::string& prefix, NBNodeCont& nc) {
     116              :     const GeoConvHelper& gch = GeoConvHelper::getFinal();
     117          348 :     bool useGeo = oc.exists("proj.plain-geo") && oc.getBool("proj.plain-geo");
     118          175 :     if (useGeo && !gch.usingGeoProjection()) {
     119            0 :         WRITE_WARNING(TL("Ignoring option \"proj.plain-geo\" because no geo-conversion has been defined"));
     120              :         useGeo = false;
     121              :     }
     122          175 :     const bool geoAccuracy = useGeo || gch.usingInverseGeoProjection();
     123              : 
     124          348 :     OutputDevice& device = OutputDevice::getDevice(prefix + ".nod.xml");
     125              :     std::map<SumoXMLAttr, std::string> attrs;
     126          173 :     attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
     127          346 :     device.writeXMLHeader("nodes", "nodes_file.xsd", attrs);
     128              : 
     129              :     // write network offsets and projection to allow reconstruction of original coordinates
     130          173 :     if (!useGeo) {
     131          169 :         GeoConvHelper::writeLocation(device);
     132              :     }
     133              : 
     134              :     // write nodes
     135          346 :     TrafficLightType tlsDefaultType = SUMOXMLDefinitions::TrafficLightTypes.get(oc.getString("tls.default-type"));
     136         1399 :     for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
     137         1226 :         NBNode* n = (*i).second;
     138         1226 :         device.openTag(SUMO_TAG_NODE);
     139         1226 :         device.writeAttr(SUMO_ATTR_ID, n->getID());
     140              :         // write position
     141         1226 :         Position pos = n->getPosition();
     142         1226 :         if (useGeo) {
     143           99 :             gch.cartesian2geo(pos);
     144              :         }
     145         1226 :         if (geoAccuracy) {
     146           99 :             device.setPrecision(gPrecisionGeo);
     147              :         }
     148         1226 :         NWFrame::writePositionLong(pos, device);
     149         1226 :         if (geoAccuracy) {
     150           99 :             device.setPrecision();
     151              :         }
     152              : 
     153         2452 :         device.writeAttr(SUMO_ATTR_TYPE, toString(n->getType()));
     154         1226 :         if (n->isTLControlled()) {
     155              :             // set may contain multiple programs for the same id.
     156              :             // make sure ids are unique and sorted
     157              :             std::set<std::string> tlsIDs;
     158              :             std::set<std::string> controlledInnerEdges;
     159          101 :             std::string tlType = "";
     160          203 :             for (NBTrafficLightDefinition* tl : n->getControllingTLS()) {
     161              :                 tlsIDs.insert(tl->getID());
     162          102 :                 std::vector<std::string> cie = tl->getControlledInnerEdges();
     163              :                 controlledInnerEdges.insert(cie.begin(), cie.end());
     164          102 :                 if (tl->getType() != tlsDefaultType) {
     165            8 :                     tlType = toString(tl->getType());
     166              :                 }
     167          102 :             }
     168          101 :             std::vector<std::string> sortedIDs(tlsIDs.begin(), tlsIDs.end());
     169          101 :             sort(sortedIDs.begin(), sortedIDs.end());
     170          101 :             device.writeAttr(SUMO_ATTR_TLID, sortedIDs);
     171          101 :             if (tlType != "") {
     172            4 :                 device.writeAttr(SUMO_ATTR_TLTYPE, tlType);
     173              :             }
     174          101 :             if (controlledInnerEdges.size() > 0) {
     175            8 :                 std::vector<std::string> sortedCIEs(controlledInnerEdges.begin(), controlledInnerEdges.end());
     176            8 :                 sort(sortedCIEs.begin(), sortedCIEs.end());
     177            8 :                 device.writeAttr(SUMO_ATTR_CONTROLLED_INNER, joinToString(sortedCIEs, " "));
     178            8 :             }
     179          101 :         }
     180         1226 :         if (n->hasCustomShape()) {
     181           28 :             writeShape(device, gch, n->getShape(), SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
     182              :         }
     183         1226 :         if (n->getRadius() != NBNode::UNSPECIFIED_RADIUS) {
     184            8 :             device.writeAttr(SUMO_ATTR_RADIUS, n->getRadius());
     185              :         }
     186         1226 :         if (!n->getKeepClear()) {
     187            0 :             device.writeAttr<bool>(SUMO_ATTR_KEEP_CLEAR, n->getKeepClear());
     188              :         }
     189         1226 :         if (n->getRightOfWay() != RightOfWay::DEFAULT) {
     190            0 :             device.writeAttr<std::string>(SUMO_ATTR_RIGHT_OF_WAY, toString(n->getRightOfWay()));
     191              :         }
     192         1226 :         if (n->getFringeType() != FringeType::DEFAULT) {
     193            8 :             device.writeAttr<std::string>(SUMO_ATTR_FRINGE, toString(n->getFringeType()));
     194              :         }
     195         1226 :         if (n->getRoundaboutType() != RoundaboutType::DEFAULT) {
     196            2 :             device.writeAttr<std::string>(SUMO_ATTR_ROUNDABOUT, toString(n->getRoundaboutType()));
     197              :         }
     198         1226 :         if (n->getName() != "") {
     199            8 :             device.writeAttr<std::string>(SUMO_ATTR_NAME, StringUtils::escapeXML(n->getName()));
     200              :         }
     201         1226 :         n->writeParams(device);
     202         2452 :         device.closeTag();
     203              :     }
     204          173 :     device.close();
     205          173 : }
     206              : 
     207              : 
     208              : void
     209           16 : NWWriter_XML::writeTypes(const std::string& prefix, NBEdgeCont& ec, NBTypeCont& tc) {
     210           32 :     OutputDevice& device = OutputDevice::getDevice(prefix + ".typ.xml");
     211              :     std::map<SumoXMLAttr, std::string> attrs;
     212           16 :     attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
     213           32 :     device.writeXMLHeader(toString(SUMO_TAG_TYPES), "types_file.xsd", attrs);
     214           16 :     std::set<std::string> usedTypes = ec.getUsedTypes();
     215           16 :     tc.writeEdgeTypes(device, usedTypes);
     216           16 :     device.close();
     217           16 : }
     218              : 
     219              : 
     220              : void
     221          173 : NWWriter_XML::writeEdgesAndConnections(const OptionsCont& oc, const std::string& prefix, NBNodeCont& nc, NBEdgeCont& ec) {
     222              :     const GeoConvHelper& gch = GeoConvHelper::getFinal();
     223          345 :     bool useGeo = oc.exists("proj.plain-geo") && oc.getBool("proj.plain-geo");
     224          173 :     const bool geoAccuracy = useGeo || gch.usingInverseGeoProjection();
     225              : 
     226              :     std::map<SumoXMLAttr, std::string> attrs;
     227          173 :     attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
     228          346 :     OutputDevice& edevice = OutputDevice::getDevice(prefix + ".edg.xml");
     229          346 :     edevice.writeXMLHeader("edges", "edges_file.xsd", attrs);
     230          346 :     OutputDevice& cdevice = OutputDevice::getDevice(prefix + ".con.xml");
     231          346 :     cdevice.writeXMLHeader("connections", "connections_file.xsd", attrs);
     232          173 :     const bool writeNames = oc.getBool("output.street-names");
     233          173 :     const bool writeLanes = oc.getBool("plain-output.lanes");
     234              : 
     235              :     // write network offsets and projection to allow reconstruction of original coordinates at least for geo-referenced networks
     236          173 :     if (!useGeo && gch.usingGeoProjection()) {
     237           22 :         GeoConvHelper::writeLocation(edevice);
     238              :     }
     239          346 :     LaneSpreadFunction defaultSpread = SUMOXMLDefinitions::LaneSpreadFunctions.get(oc.getString("default.spreadtype"));
     240         2059 :     for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
     241              :         // write the edge itself to the edges-files
     242         1886 :         NBEdge* e = (*i).second;
     243         1886 :         edevice.openTag(SUMO_TAG_EDGE);
     244         1886 :         edevice.writeAttr(SUMO_ATTR_ID, e->getID());
     245         1886 :         edevice.writeAttr(SUMO_ATTR_FROM, e->getFromNode()->getID());
     246         1886 :         edevice.writeAttr(SUMO_ATTR_TO, e->getToNode()->getID());
     247         1886 :         if (writeNames && e->getStreetName() != "") {
     248          592 :             edevice.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(e->getStreetName()));
     249              :         }
     250         1886 :         edevice.writeAttr(SUMO_ATTR_PRIORITY, e->getPriority());
     251              :         // write the type if given
     252         1886 :         if (e->getTypeID() != "") {
     253          779 :             edevice.writeAttr(SUMO_ATTR_TYPE, e->getTypeID());
     254              :         }
     255         1886 :         if (e->getRoutingType() != "") {
     256            2 :             edevice.writeAttr(SUMO_ATTR_ROUTINGTYPE, e->getRoutingType());
     257              :         }
     258         1886 :         edevice.writeAttr(SUMO_ATTR_NUMLANES, e->getNumLanes());
     259         1886 :         if (!e->hasLaneSpecificSpeed()) {
     260         1883 :             edevice.writeAttr(SUMO_ATTR_SPEED, e->getSpeed());
     261              :         }
     262         1886 :         if (!e->hasLaneSpecificFriction()) {
     263         1882 :             if (e->getFriction() != NBEdge::UNSPECIFIED_FRICTION) {
     264            3 :                 edevice.writeAttr(SUMO_ATTR_FRICTION, e->getFriction());
     265              :             }
     266              :         }
     267              :         // write non-default geometry
     268         1886 :         if (!e->hasDefaultGeometry()) {
     269          591 :             writeShape(edevice, gch, e->getGeometry(), SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
     270              :         }
     271              :         // write the spread type if not default ("right")
     272         1886 :         if (e->getLaneSpreadFunction() != defaultSpread) {
     273          836 :             edevice.writeAttr(SUMO_ATTR_SPREADTYPE, toString(e->getLaneSpreadFunction()));
     274              :         }
     275              :         // write the length if it was specified
     276         1886 :         if (e->hasLoadedLength()) {
     277            3 :             edevice.writeAttr(SUMO_ATTR_LENGTH, e->getLoadedLength());
     278              :         }
     279              :         // some attributes can be set by edge default or per lane. Write as default if possible (efficiency)
     280         1886 :         if (e->getLaneWidth() != NBEdge::UNSPECIFIED_WIDTH && !e->hasLaneSpecificWidth()) {
     281          227 :             edevice.writeAttr(SUMO_ATTR_WIDTH, e->getLaneWidth());
     282              :         }
     283         1886 :         if (e->getEndOffset() != NBEdge::UNSPECIFIED_OFFSET && !e->hasLaneSpecificEndOffset()) {
     284            7 :             edevice.writeAttr(SUMO_ATTR_ENDOFFSET, e->getEndOffset());
     285              :         }
     286         1886 :         if (!e->hasLaneSpecificPermissions()) {
     287         1613 :             writePermissions(edevice, e->getPermissions(0));
     288              :         }
     289         1886 :         if (!e->hasLaneSpecificStopOffsets() && e->getEdgeStopOffset().isDefined()) {
     290            0 :             NWWriter_SUMO::writeStopOffsets(edevice, e->getEdgeStopOffset());
     291              :         }
     292         1886 :         if (e->getDistance() != 0) {
     293            2 :             edevice.writeAttr(SUMO_ATTR_DISTANCE, e->getDistance());
     294              :         }
     295         1886 :         if (e->getBidiEdge() != 0) {
     296           30 :             edevice.writeAttr(SUMO_ATTR_BIDI, e->getBidiEdge()->getID());
     297              :         }
     298         1886 :         if (e->needsLaneSpecificOutput() || writeLanes) {
     299              :             int idx = 0;
     300         1530 :             for (const NBEdge::Lane& lane : e->getLanes()) {
     301         1172 :                 edevice.openTag(SUMO_TAG_LANE);
     302         1172 :                 edevice.writeAttr(SUMO_ATTR_INDEX, idx++);
     303              :                 // write allowed lanes
     304         1172 :                 if (e->hasLaneSpecificPermissions() || writeLanes) {
     305         1005 :                     writePermissions(edevice, lane.permissions);
     306              :                 }
     307         1172 :                 writePreferences(edevice, lane.preferred);
     308              :                 // write other attributes
     309         1172 :                 if (lane.width != NBEdge::UNSPECIFIED_WIDTH && (e->hasLaneSpecificWidth() || writeLanes)) {
     310          468 :                     edevice.writeAttr(SUMO_ATTR_WIDTH, lane.width);
     311              :                 }
     312         1172 :                 if (lane.endOffset != NBEdge::UNSPECIFIED_OFFSET && (e->hasLaneSpecificEndOffset() || writeLanes)) {
     313            8 :                     edevice.writeAttr(SUMO_ATTR_ENDOFFSET, lane.endOffset);
     314              :                 }
     315         1172 :                 if (e->hasLaneSpecificSpeed() || writeLanes) {
     316           25 :                     edevice.writeAttr(SUMO_ATTR_SPEED, lane.speed);
     317              :                 }
     318         1172 :                 if (lane.accelRamp) {
     319            1 :                     edevice.writeAttr(SUMO_ATTR_ACCELERATION, lane.accelRamp);
     320              :                 }
     321         1172 :                 if (lane.customShape.size() > 0 || writeLanes) {
     322           42 :                     writeShape(edevice, gch, lane.customShape.size() > 0 ? lane.customShape : lane.shape, SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
     323              :                 }
     324         1172 :                 if (lane.type != "") {
     325            3 :                     edevice.writeAttr(SUMO_ATTR_TYPE, lane.type);
     326              :                 }
     327         1172 :                 if (lane.changeLeft != SVCAll && lane.changeLeft != SVC_UNSPECIFIED && lane.changeLeft != SVC_IGNORING) {
     328            6 :                     edevice.writeAttr(SUMO_ATTR_CHANGE_LEFT, getVehicleClassNames(lane.changeLeft));
     329              :                 }
     330         1172 :                 if (lane.changeRight != SVCAll && lane.changeRight != SVC_UNSPECIFIED && lane.changeRight != SVC_IGNORING) {
     331            7 :                     edevice.writeAttr(SUMO_ATTR_CHANGE_RIGHT, getVehicleClassNames(lane.changeRight));
     332              :                 }
     333         1172 :                 if (lane.oppositeID != "") {
     334           47 :                     edevice.openTag(SUMO_TAG_NEIGH);
     335           47 :                     edevice.writeAttr(SUMO_ATTR_LANE, lane.oppositeID);
     336           94 :                     edevice.closeTag();
     337              :                 }
     338         1172 :                 lane.writeParams(edevice);
     339         1172 :                 NWWriter_SUMO::writeStopOffsets(edevice, lane.laneStopOffset);
     340         2344 :                 edevice.closeTag();
     341              :             }
     342              :         }
     343         1886 :         e->writeParams(edevice);
     344         3772 :         edevice.closeTag();
     345              :         // write this edge's connections to the connections-files
     346         1886 :         const std::vector<NBEdge::Connection> connections = e->getConnections();
     347         1886 :         if (connections.empty()) {
     348              :             // if there are no connections and this appears to be customized, preserve the information
     349          355 :             const int numOutgoing = (int)e->getToNode()->getOutgoingEdges().size();
     350          355 :             if (numOutgoing > 0) {
     351          227 :                 const SVCPermissions inPerm = e->getPermissions();
     352              :                 SVCPermissions outPerm = 0;
     353          557 :                 for (auto out : e->getToNode()->getOutgoingEdges()) {
     354          330 :                     outPerm |= out->getPermissions();
     355              :                 }
     356          227 :                 if ((inPerm & outPerm) != 0 && (inPerm & outPerm) != SVC_PEDESTRIAN) {
     357          122 :                     cdevice.openTag(SUMO_TAG_CONNECTION);
     358          122 :                     cdevice.writeAttr(SUMO_ATTR_FROM, e->getID());
     359          122 :                     cdevice.closeTag();
     360          122 :                     cdevice << "\n";
     361              :                 }
     362              :             }
     363              :         } else {
     364         5297 :             for (NBEdge::Connection c : connections) {
     365         3766 :                 if (useGeo) {
     366          404 :                     for (Position& p : c.customShape) {
     367            3 :                         gch.cartesian2geo(p);
     368              :                     }
     369              :                 }
     370         3766 :                 NWWriter_SUMO::writeConnection(cdevice, *e, c, false, NWWriter_SUMO::PLAIN, geoAccuracy);
     371         3766 :             }
     372         1531 :             cdevice << "\n";
     373              :         }
     374         1886 :     }
     375              :     // write roundabout information to the edges-files
     376          346 :     if (ec.getRoundabouts().size() > 0) {
     377            6 :         edevice.lf();
     378           12 :         NWWriter_SUMO::writeRoundabouts(edevice, ec.getRoundabouts(), ec);
     379              :     }
     380              : 
     381              :     // write loaded prohibitions to the connections-file
     382         1399 :     for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
     383         1226 :         NWWriter_SUMO::writeProhibitions(cdevice, i->second->getProhibitions());
     384              :     }
     385              :     // write pedestrian crossings to the connections-file
     386         1399 :     for (std::map<std::string, NBNode*>::const_iterator it_node = nc.begin(); it_node != nc.end(); ++it_node) {
     387         1226 :         const std::vector<NBNode::Crossing*>& crossings = (*it_node).second->getCrossings();
     388         1311 :         for (auto c : crossings) {
     389           85 :             cdevice.openTag(SUMO_TAG_CROSSING);
     390           85 :             cdevice.writeAttr(SUMO_ATTR_NODE, (*it_node).second->getID());
     391           85 :             cdevice.writeAttr(SUMO_ATTR_EDGES, c->edges);
     392           85 :             cdevice.writeAttr(SUMO_ATTR_PRIORITY, c->priority);
     393           85 :             if (c->customWidth != NBEdge::UNSPECIFIED_WIDTH) {
     394           39 :                 cdevice.writeAttr(SUMO_ATTR_WIDTH, c->customWidth);
     395              :             }
     396           85 :             if (c->customTLIndex != -1) {
     397           24 :                 cdevice.writeAttr(SUMO_ATTR_TLLINKINDEX, c->customTLIndex);
     398              :             }
     399           85 :             if (c->customTLIndex2 != -1) {
     400            4 :                 cdevice.writeAttr(SUMO_ATTR_TLLINKINDEX2, c->customTLIndex2);
     401              :             }
     402           85 :             if (c->customShape.size() != 0) {
     403            4 :                 writeShape(cdevice, gch, c->customShape, SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
     404              :             }
     405           85 :             if (c->outlineShape.size() != 0) {
     406           85 :                 writeShape(cdevice, gch, c->outlineShape, SUMO_ATTR_OUTLINESHAPE, useGeo, geoAccuracy);
     407              :             }
     408           85 :             c->writeParams(cdevice);
     409          170 :             cdevice.closeTag();
     410              :         }
     411         1226 :     }
     412              :     // write custom walkingarea shapes to the connections file
     413         1399 :     for (std::map<std::string, NBNode*>::const_iterator it_node = nc.begin(); it_node != nc.end(); ++it_node) {
     414         1233 :         for (const auto& wacs : it_node->second->getWalkingAreaCustomShapes()) {
     415            7 :             cdevice.openTag(SUMO_TAG_WALKINGAREA);
     416            7 :             cdevice.writeAttr(SUMO_ATTR_NODE, it_node->first);
     417           14 :             cdevice.writeAttr(SUMO_ATTR_EDGES, joinNamedToString(wacs.edges, " "));
     418            7 :             if (wacs.shape.size() != 0) {
     419            6 :                 writeShape(cdevice, gch, wacs.shape, SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
     420              :             }
     421            7 :             if (wacs.width != NBEdge::UNSPECIFIED_WIDTH) {
     422            1 :                 cdevice.writeAttr(SUMO_ATTR_WIDTH, wacs.width);
     423              :             }
     424           14 :             cdevice.closeTag();
     425              :         }
     426              :     }
     427              : 
     428          173 :     edevice.close();
     429          173 :     cdevice.close();
     430          173 : }
     431              : 
     432              : 
     433              : void
     434          173 : NWWriter_XML::writeTrafficLights(const std::string& prefix, NBTrafficLightLogicCont& tc, NBEdgeCont& ec) {
     435              :     std::map<SumoXMLAttr, std::string> attrs;
     436          173 :     attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
     437          346 :     OutputDevice& device = OutputDevice::getDevice(prefix + ".tll.xml");
     438          346 :     device.writeXMLHeader("tlLogics", "tllogic_file.xsd", attrs);
     439          173 :     NWWriter_SUMO::writeTrafficLights(device, tc);
     440              :     // we also need to remember the associations between tlLogics and connections
     441              :     // since the information in con.xml is insufficient
     442         2059 :     for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
     443         1886 :         NBEdge* e = (*i).second;
     444              :         // write this edge's tl-controlled connections
     445         1886 :         const std::vector<NBEdge::Connection> connections = e->getConnections();
     446         5652 :         for (std::vector<NBEdge::Connection>::const_iterator c = connections.begin(); c != connections.end(); ++c) {
     447         3766 :             if (c->tlID != "") {
     448         1065 :                 NWWriter_SUMO::writeConnection(device, *e, *c, false, NWWriter_SUMO::TLL);
     449              :             }
     450              :         }
     451         1886 :     }
     452          173 :     device.close();
     453          173 : }
     454              : 
     455              : 
     456              : void
     457            5 : NWWriter_XML::writeJoinedJunctions(const std::string& filename, NBNodeCont& nc) {
     458              :     std::map<SumoXMLAttr, std::string> attrs;
     459            5 :     attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
     460            5 :     OutputDevice& device = OutputDevice::getDevice(filename);
     461           10 :     device.writeXMLHeader("nodes", "nodes_file.xsd", attrs);
     462              :     const std::vector<std::set<std::string> >& clusters = nc.getJoinedClusters();
     463           10 :     for (std::vector<std::set<std::string> >::const_iterator it = clusters.begin(); it != clusters.end(); it++) {
     464              :         assert((*it).size() > 0);
     465            5 :         device.openTag(SUMO_TAG_JOIN);
     466              :         // prepare string
     467            5 :         std::ostringstream oss;
     468           29 :         for (std::set<std::string>::const_iterator it_id = it->begin(); it_id != it->end(); it_id++) {
     469           24 :             oss << *it_id << " ";
     470              :         }
     471              :         // remove final space
     472              :         std::string ids = oss.str();
     473            5 :         device.writeAttr(SUMO_ATTR_NODES, ids.substr(0, ids.size() - 1));
     474           10 :         device.closeTag();
     475            5 :     }
     476            5 :     device.close();
     477            5 : }
     478              : 
     479              : 
     480              : void
     481            1 : NWWriter_XML::writeStreetSigns(const OptionsCont& oc, NBEdgeCont& ec) {
     482            2 :     OutputDevice& device = OutputDevice::getDevice(oc.getString("street-sign-output"));
     483            2 :     device.writeXMLHeader("additional", "additional_file.xsd");
     484           23 :     for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
     485           22 :         NBEdge* e = (*i).second;
     486              :         const std::vector<NBSign>& signs =  e->getSigns();
     487           30 :         for (std::vector<NBSign>::const_iterator it = signs.begin(); it != signs.end(); ++it) {
     488            8 :             it->writeAsPOI(device, e);
     489              :         }
     490              :     }
     491            1 :     device.close();
     492            1 : }
     493              : 
     494              : 
     495              : void
     496           72 : NWWriter_XML::writePTStops(const OptionsCont& oc, NBPTStopCont& sc) {
     497          144 :     OutputDevice& device = OutputDevice::getDevice(oc.getString("ptstop-output"));
     498          144 :     device.writeXMLHeader("additional", "additional_file.xsd");
     499          816 :     for (const auto& stopIt : sc.getStops()) {
     500          744 :         stopIt.second->write(device);
     501              :     }
     502           72 :     device.close();
     503           72 : }
     504              : 
     505              : 
     506           46 : void NWWriter_XML::writePTLines(const OptionsCont& oc, NBPTLineCont& lc) {
     507           92 :     OutputDevice& device = OutputDevice::getDevice(oc.getString("ptline-output"));
     508           92 :     device.writeXMLHeader("ptLines", "ptlines_file.xsd");
     509          427 :     for (const auto& item : lc.getLines()) {
     510          381 :         item.second->write(device);
     511              :     }
     512           46 :     device.close();
     513           46 : }
     514              : 
     515              : 
     516            3 : void NWWriter_XML::writeParkingAreas(const OptionsCont& oc, NBParkingCont& pc, NBEdgeCont& ec) {
     517            6 :     OutputDevice& device = OutputDevice::getDevice(oc.getString("parking-output"));
     518            6 :     device.writeXMLHeader("additional", "additional_file.xsd");
     519          297 :     for (NBParking& p : pc) {
     520          294 :         p.write(device, ec);
     521              :     }
     522            3 :     device.close();
     523            3 : }
     524              : 
     525              : 
     526              : void
     527            1 : NWWriter_XML::writeDistricts(const OptionsCont& oc, NBDistrictCont& dc) {
     528            2 :     OutputDevice& device = OutputDevice::getDevice(oc.getString("taz-output"));
     529            2 :     device.writeXMLHeader("additional", "additional_file.xsd");
     530           30 :     for (std::map<std::string, NBDistrict*>::const_iterator i = dc.begin(); i != dc.end(); i++) {
     531           29 :         NWWriter_SUMO::writeDistrict(device, *(*i).second);
     532              :     }
     533            1 : }
     534              : 
     535              : 
     536              : void
     537          721 : NWWriter_XML::writeShape(OutputDevice& out, const GeoConvHelper& gch, PositionVector shape, SumoXMLAttr attr, bool useGeo, bool geoAccuracy) {
     538          721 :     if (useGeo) {
     539          322 :         for (int i = 0; i < (int) shape.size(); i++) {
     540          259 :             gch.cartesian2geo(shape[i]);
     541              :         }
     542              :     }
     543          721 :     if (geoAccuracy) {
     544           63 :         out.setPrecision(gPrecisionGeo);
     545              :     }
     546          721 :     out.writeAttr(attr, shape);
     547          721 :     if (geoAccuracy) {
     548           63 :         out.setPrecision();
     549              :     }
     550          721 : }
     551              : 
     552              : 
     553              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1