Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 1689 : NWWriter_XML::writeNetwork(const OptionsCont& oc, const std::string& prefix, NBNetBuilder& nb) {
52 : // check whether plain-output files shall be generated
53 1689 : if (prefix != "") {
54 164 : writeNodes(oc, prefix, nb.getNodeCont());
55 162 : if (nb.getTypeCont().size() > 0) {
56 14 : writeTypes(prefix, nb.getEdgeCont(), nb.getTypeCont());
57 : }
58 162 : writeEdgesAndConnections(oc, prefix, nb.getNodeCont(), nb.getEdgeCont());
59 162 : writeTrafficLights(prefix, nb.getTLLogicCont(), nb.getEdgeCont());
60 : }
61 3374 : if (oc.isSet("junctions.join-output")) {
62 10 : writeJoinedJunctions(oc.getString("junctions.join-output"), nb.getNodeCont());
63 : }
64 3374 : if (oc.isSet("street-sign-output")) {
65 1 : writeStreetSigns(oc, nb.getEdgeCont());
66 : }
67 3290 : if (oc.exists("ptstop-output") && oc.isSet("ptstop-output")) {
68 64 : writePTStops(oc, nb.getPTStopCont());
69 : }
70 3290 : if (oc.exists("ptline-output") && oc.isSet("ptline-output")) {
71 45 : writePTLines(oc, nb.getPTLineCont());
72 : }
73 :
74 3290 : if (oc.exists("parking-output") && oc.isSet("parking-output")) {
75 2 : writeParkingAreas(oc, nb.getParkingCont(), nb.getEdgeCont());
76 : }
77 3290 : if (oc.exists("taz-output") && oc.isSet("taz-output")) {
78 1 : writeDistricts(oc, nb.getDistrictCont());
79 : }
80 1687 : }
81 :
82 :
83 : void
84 164 : NWWriter_XML::writeNodes(const OptionsCont& oc, const std::string& prefix, NBNodeCont& nc) {
85 : const GeoConvHelper& gch = GeoConvHelper::getFinal();
86 327 : bool useGeo = oc.exists("proj.plain-geo") && oc.getBool("proj.plain-geo");
87 164 : if (useGeo && !gch.usingGeoProjection()) {
88 0 : WRITE_WARNING(TL("Ignoring option \"proj.plain-geo\" because no geo-conversion has been defined"));
89 : useGeo = false;
90 : }
91 164 : const bool geoAccuracy = useGeo || gch.usingInverseGeoProjection();
92 :
93 326 : OutputDevice& device = OutputDevice::getDevice(prefix + ".nod.xml");
94 : std::map<SumoXMLAttr, std::string> attrs;
95 162 : attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
96 324 : device.writeXMLHeader("nodes", "nodes_file.xsd", attrs);
97 :
98 : // write network offsets and projection to allow reconstruction of original coordinates
99 162 : if (!useGeo) {
100 158 : GeoConvHelper::writeLocation(device);
101 : }
102 :
103 : // write nodes
104 324 : TrafficLightType tlsDefaultType = SUMOXMLDefinitions::TrafficLightTypes.get(oc.getString("tls.default-type"));
105 1332 : for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
106 1170 : NBNode* n = (*i).second;
107 1170 : device.openTag(SUMO_TAG_NODE);
108 : device.writeAttr(SUMO_ATTR_ID, n->getID());
109 : // write position
110 1170 : Position pos = n->getPosition();
111 1170 : if (useGeo) {
112 99 : gch.cartesian2geo(pos);
113 : }
114 1170 : if (geoAccuracy) {
115 99 : device.setPrecision(gPrecisionGeo);
116 : }
117 1170 : NWFrame::writePositionLong(pos, device);
118 1170 : if (geoAccuracy) {
119 99 : device.setPrecision();
120 : }
121 :
122 2340 : device.writeAttr(SUMO_ATTR_TYPE, toString(n->getType()));
123 1170 : if (n->isTLControlled()) {
124 : // set may contain multiple programs for the same id.
125 : // make sure ids are unique and sorted
126 : std::set<std::string> tlsIDs;
127 : std::set<std::string> controlledInnerEdges;
128 101 : std::string tlType = "";
129 203 : for (NBTrafficLightDefinition* tl : n->getControllingTLS()) {
130 : tlsIDs.insert(tl->getID());
131 102 : std::vector<std::string> cie = tl->getControlledInnerEdges();
132 : controlledInnerEdges.insert(cie.begin(), cie.end());
133 102 : if (tl->getType() != tlsDefaultType) {
134 8 : tlType = toString(tl->getType());
135 : }
136 102 : }
137 101 : std::vector<std::string> sortedIDs(tlsIDs.begin(), tlsIDs.end());
138 101 : sort(sortedIDs.begin(), sortedIDs.end());
139 : device.writeAttr(SUMO_ATTR_TLID, sortedIDs);
140 101 : if (tlType != "") {
141 : device.writeAttr(SUMO_ATTR_TLTYPE, tlType);
142 : }
143 101 : if (controlledInnerEdges.size() > 0) {
144 8 : std::vector<std::string> sortedCIEs(controlledInnerEdges.begin(), controlledInnerEdges.end());
145 8 : sort(sortedCIEs.begin(), sortedCIEs.end());
146 8 : device.writeAttr(SUMO_ATTR_CONTROLLED_INNER, joinToString(sortedCIEs, " "));
147 8 : }
148 101 : }
149 1170 : if (n->hasCustomShape()) {
150 28 : writeShape(device, gch, n->getShape(), SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
151 : }
152 1170 : if (n->getRadius() != NBNode::UNSPECIFIED_RADIUS) {
153 16 : device.writeAttr(SUMO_ATTR_RADIUS, n->getRadius());
154 : }
155 1170 : if (!n->getKeepClear()) {
156 0 : device.writeAttr<bool>(SUMO_ATTR_KEEP_CLEAR, n->getKeepClear());
157 : }
158 1170 : if (n->getRightOfWay() != RightOfWay::DEFAULT) {
159 0 : device.writeAttr<std::string>(SUMO_ATTR_RIGHT_OF_WAY, toString(n->getRightOfWay()));
160 : }
161 1170 : if (n->getFringeType() != FringeType::DEFAULT) {
162 0 : device.writeAttr<std::string>(SUMO_ATTR_FRINGE, toString(n->getFringeType()));
163 : }
164 1170 : if (n->getName() != "") {
165 8 : device.writeAttr<std::string>(SUMO_ATTR_NAME, StringUtils::escapeXML(n->getName()));
166 : }
167 1170 : n->writeParams(device);
168 2340 : device.closeTag();
169 : }
170 162 : device.close();
171 162 : }
172 :
173 :
174 : void
175 14 : NWWriter_XML::writeTypes(const std::string& prefix, NBEdgeCont& ec, NBTypeCont& tc) {
176 28 : OutputDevice& device = OutputDevice::getDevice(prefix + ".typ.xml");
177 : std::map<SumoXMLAttr, std::string> attrs;
178 14 : attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
179 28 : device.writeXMLHeader("types", "types_file.xsd", attrs);
180 14 : std::set<std::string> usedTypes = ec.getUsedTypes();
181 14 : tc.writeEdgeTypes(device, usedTypes);
182 14 : device.close();
183 14 : }
184 :
185 :
186 : void
187 162 : NWWriter_XML::writeEdgesAndConnections(const OptionsCont& oc, const std::string& prefix, NBNodeCont& nc, NBEdgeCont& ec) {
188 : const GeoConvHelper& gch = GeoConvHelper::getFinal();
189 324 : bool useGeo = oc.exists("proj.plain-geo") && oc.getBool("proj.plain-geo");
190 162 : const bool geoAccuracy = useGeo || gch.usingInverseGeoProjection();
191 :
192 : std::map<SumoXMLAttr, std::string> attrs;
193 162 : attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
194 324 : OutputDevice& edevice = OutputDevice::getDevice(prefix + ".edg.xml");
195 324 : edevice.writeXMLHeader("edges", "edges_file.xsd", attrs);
196 324 : OutputDevice& cdevice = OutputDevice::getDevice(prefix + ".con.xml");
197 324 : cdevice.writeXMLHeader("connections", "connections_file.xsd", attrs);
198 162 : const bool writeNames = oc.getBool("output.street-names");
199 162 : const bool writeLanes = oc.getBool("plain-output.lanes");
200 :
201 : // write network offsets and projection to allow reconstruction of original coordinates at least for geo-referenced networks
202 162 : if (!useGeo && gch.usingGeoProjection()) {
203 20 : GeoConvHelper::writeLocation(edevice);
204 : }
205 324 : LaneSpreadFunction defaultSpread = SUMOXMLDefinitions::LaneSpreadFunctions.get(oc.getString("default.spreadtype"));
206 1975 : for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
207 : // write the edge itself to the edges-files
208 1813 : NBEdge* e = (*i).second;
209 1813 : edevice.openTag(SUMO_TAG_EDGE);
210 1813 : edevice.writeAttr(SUMO_ATTR_ID, e->getID());
211 : edevice.writeAttr(SUMO_ATTR_FROM, e->getFromNode()->getID());
212 : edevice.writeAttr(SUMO_ATTR_TO, e->getToNode()->getID());
213 1813 : if (writeNames && e->getStreetName() != "") {
214 592 : edevice.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(e->getStreetName()));
215 : }
216 3626 : edevice.writeAttr(SUMO_ATTR_PRIORITY, e->getPriority());
217 : // write the type if given
218 1813 : if (e->getTypeID() != "") {
219 : edevice.writeAttr(SUMO_ATTR_TYPE, e->getTypeID());
220 : }
221 1813 : edevice.writeAttr(SUMO_ATTR_NUMLANES, e->getNumLanes());
222 1813 : if (!e->hasLaneSpecificSpeed()) {
223 3620 : edevice.writeAttr(SUMO_ATTR_SPEED, e->getSpeed());
224 : }
225 1813 : if (!e->hasLaneSpecificFriction()) {
226 1809 : if (e->getFriction() != NBEdge::UNSPECIFIED_FRICTION) {
227 6 : edevice.writeAttr(SUMO_ATTR_FRICTION, e->getFriction());
228 : }
229 : }
230 : // write non-default geometry
231 1813 : if (!e->hasDefaultGeometry()) {
232 574 : writeShape(edevice, gch, e->getGeometry(), SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
233 : }
234 : // write the spread type if not default ("right")
235 1813 : if (e->getLaneSpreadFunction() != defaultSpread) {
236 818 : edevice.writeAttr(SUMO_ATTR_SPREADTYPE, toString(e->getLaneSpreadFunction()));
237 : }
238 : // write the length if it was specified
239 1813 : if (e->hasLoadedLength()) {
240 6 : edevice.writeAttr(SUMO_ATTR_LENGTH, e->getLoadedLength());
241 : }
242 : // some attributes can be set by edge default or per lane. Write as default if possible (efficiency)
243 1813 : if (e->getLaneWidth() != NBEdge::UNSPECIFIED_WIDTH && !e->hasLaneSpecificWidth()) {
244 454 : edevice.writeAttr(SUMO_ATTR_WIDTH, e->getLaneWidth());
245 : }
246 1813 : if (e->getEndOffset() != NBEdge::UNSPECIFIED_OFFSET && !e->hasLaneSpecificEndOffset()) {
247 14 : edevice.writeAttr(SUMO_ATTR_ENDOFFSET, e->getEndOffset());
248 : }
249 1813 : if (!e->hasLaneSpecificPermissions()) {
250 1568 : writePermissions(edevice, e->getPermissions(0));
251 : }
252 1813 : if (!e->hasLaneSpecificStopOffsets() && e->getEdgeStopOffset().isDefined()) {
253 0 : NWWriter_SUMO::writeStopOffsets(edevice, e->getEdgeStopOffset());
254 : }
255 1813 : if (e->getDistance() != 0) {
256 4 : edevice.writeAttr(SUMO_ATTR_DISTANCE, e->getDistance());
257 : }
258 1813 : if (e->getBidiEdge() != 0) {
259 30 : edevice.writeAttr(SUMO_ATTR_BIDI, e->getBidiEdge()->getID());
260 : }
261 1813 : if (e->needsLaneSpecificOutput() || writeLanes) {
262 : int idx = 0;
263 1398 : for (const NBEdge::Lane& lane : e->getLanes()) {
264 1068 : edevice.openTag(SUMO_TAG_LANE);
265 1068 : edevice.writeAttr(SUMO_ATTR_INDEX, idx++);
266 : // write allowed lanes
267 1068 : if (e->hasLaneSpecificPermissions() || writeLanes) {
268 901 : writePermissions(edevice, lane.permissions);
269 : }
270 1068 : writePreferences(edevice, lane.preferred);
271 : // write other attributes
272 1068 : if (lane.width != NBEdge::UNSPECIFIED_WIDTH && (e->hasLaneSpecificWidth() || writeLanes)) {
273 416 : edevice.writeAttr(SUMO_ATTR_WIDTH, lane.width);
274 : }
275 1068 : if (lane.endOffset != NBEdge::UNSPECIFIED_OFFSET && (e->hasLaneSpecificEndOffset() || writeLanes)) {
276 8 : edevice.writeAttr(SUMO_ATTR_ENDOFFSET, lane.endOffset);
277 : }
278 1068 : if (e->hasLaneSpecificSpeed() || writeLanes) {
279 25 : edevice.writeAttr(SUMO_ATTR_SPEED, lane.speed);
280 : }
281 1068 : if (lane.accelRamp) {
282 1 : edevice.writeAttr(SUMO_ATTR_ACCELERATION, lane.accelRamp);
283 : }
284 1068 : if (lane.customShape.size() > 0 || writeLanes) {
285 42 : writeShape(edevice, gch, lane.customShape.size() > 0 ? lane.customShape : lane.shape, SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
286 : }
287 1068 : if (lane.type != "") {
288 : edevice.writeAttr(SUMO_ATTR_TYPE, lane.type);
289 : }
290 1068 : if (lane.changeLeft != SVCAll && lane.changeLeft != SVC_UNSPECIFIED && lane.changeLeft != SVC_IGNORING) {
291 6 : edevice.writeAttr(SUMO_ATTR_CHANGE_LEFT, getVehicleClassNames(lane.changeLeft));
292 : }
293 1068 : if (lane.changeRight != SVCAll && lane.changeRight != SVC_UNSPECIFIED && lane.changeRight != SVC_IGNORING) {
294 7 : edevice.writeAttr(SUMO_ATTR_CHANGE_RIGHT, getVehicleClassNames(lane.changeRight));
295 : }
296 1068 : if (lane.oppositeID != "") {
297 47 : edevice.openTag(SUMO_TAG_NEIGH);
298 : edevice.writeAttr(SUMO_ATTR_LANE, lane.oppositeID);
299 94 : edevice.closeTag();
300 : }
301 1068 : lane.writeParams(edevice);
302 1068 : NWWriter_SUMO::writeStopOffsets(edevice, lane.laneStopOffset);
303 2136 : edevice.closeTag();
304 : }
305 : }
306 1813 : e->writeParams(edevice);
307 3626 : edevice.closeTag();
308 : // write this edge's connections to the connections-files
309 1813 : const std::vector<NBEdge::Connection> connections = e->getConnections();
310 1813 : if (connections.empty()) {
311 : // if there are no connections and this appears to be customized, preserve the information
312 341 : const int numOutgoing = (int)e->getToNode()->getOutgoingEdges().size();
313 341 : if (numOutgoing > 0) {
314 217 : const SVCPermissions inPerm = e->getPermissions();
315 : SVCPermissions outPerm = 0;
316 537 : for (auto out : e->getToNode()->getOutgoingEdges()) {
317 320 : outPerm |= out->getPermissions();
318 : }
319 217 : if ((inPerm & outPerm) != 0 && (inPerm & outPerm) != SVC_PEDESTRIAN) {
320 112 : cdevice.openTag(SUMO_TAG_CONNECTION);
321 112 : cdevice.writeAttr(SUMO_ATTR_FROM, e->getID());
322 112 : cdevice.closeTag();
323 112 : cdevice << "\n";
324 : }
325 : }
326 : } else {
327 5125 : for (NBEdge::Connection c : connections) {
328 3653 : if (useGeo) {
329 404 : for (Position& p : c.customShape) {
330 3 : gch.cartesian2geo(p);
331 : }
332 : }
333 3653 : NWWriter_SUMO::writeConnection(cdevice, *e, c, false, NWWriter_SUMO::PLAIN, geoAccuracy);
334 3653 : }
335 1472 : cdevice << "\n";
336 : }
337 1813 : }
338 : // write roundabout information to the edges-files
339 324 : if (ec.getRoundabouts().size() > 0) {
340 4 : edevice.lf();
341 8 : NWWriter_SUMO::writeRoundabouts(edevice, ec.getRoundabouts(), ec);
342 : }
343 :
344 : // write loaded prohibitions to the connections-file
345 1332 : for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
346 1170 : NWWriter_SUMO::writeProhibitions(cdevice, i->second->getProhibitions());
347 : }
348 : // write pedestrian crossings to the connections-file
349 1332 : for (std::map<std::string, NBNode*>::const_iterator it_node = nc.begin(); it_node != nc.end(); ++it_node) {
350 1170 : const std::vector<NBNode::Crossing*>& crossings = (*it_node).second->getCrossings();
351 1247 : for (auto c : crossings) {
352 77 : cdevice.openTag(SUMO_TAG_CROSSING);
353 77 : cdevice.writeAttr(SUMO_ATTR_NODE, (*it_node).second->getID());
354 77 : cdevice.writeAttr(SUMO_ATTR_EDGES, c->edges);
355 77 : cdevice.writeAttr(SUMO_ATTR_PRIORITY, c->priority);
356 77 : if (c->customWidth != NBEdge::UNSPECIFIED_WIDTH) {
357 39 : cdevice.writeAttr(SUMO_ATTR_WIDTH, c->customWidth);
358 : }
359 77 : if (c->customTLIndex != -1) {
360 24 : cdevice.writeAttr(SUMO_ATTR_TLLINKINDEX, c->customTLIndex);
361 : }
362 77 : if (c->customTLIndex2 != -1) {
363 4 : cdevice.writeAttr(SUMO_ATTR_TLLINKINDEX2, c->customTLIndex2);
364 : }
365 77 : if (c->customShape.size() != 0) {
366 4 : writeShape(cdevice, gch, c->customShape, SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
367 : }
368 77 : if (c->outlineShape.size() != 0) {
369 77 : writeShape(cdevice, gch, c->outlineShape, SUMO_ATTR_OUTLINESHAPE, useGeo, geoAccuracy);
370 : }
371 77 : c->writeParams(cdevice);
372 154 : cdevice.closeTag();
373 : }
374 1170 : }
375 : // write custom walkingarea shapes to the connections file
376 1332 : for (std::map<std::string, NBNode*>::const_iterator it_node = nc.begin(); it_node != nc.end(); ++it_node) {
377 1177 : for (const auto& wacs : it_node->second->getWalkingAreaCustomShapes()) {
378 7 : cdevice.openTag(SUMO_TAG_WALKINGAREA);
379 7 : cdevice.writeAttr(SUMO_ATTR_NODE, it_node->first);
380 14 : cdevice.writeAttr(SUMO_ATTR_EDGES, joinNamedToString(wacs.edges, " "));
381 7 : if (wacs.shape.size() != 0) {
382 6 : writeShape(cdevice, gch, wacs.shape, SUMO_ATTR_SHAPE, useGeo, geoAccuracy);
383 : }
384 7 : if (wacs.width != NBEdge::UNSPECIFIED_WIDTH) {
385 1 : cdevice.writeAttr(SUMO_ATTR_WIDTH, wacs.width);
386 : }
387 14 : cdevice.closeTag();
388 : }
389 : }
390 :
391 162 : edevice.close();
392 162 : cdevice.close();
393 162 : }
394 :
395 :
396 : void
397 162 : NWWriter_XML::writeTrafficLights(const std::string& prefix, NBTrafficLightLogicCont& tc, NBEdgeCont& ec) {
398 : std::map<SumoXMLAttr, std::string> attrs;
399 162 : attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
400 324 : OutputDevice& device = OutputDevice::getDevice(prefix + ".tll.xml");
401 324 : device.writeXMLHeader("tlLogics", "tllogic_file.xsd", attrs);
402 162 : NWWriter_SUMO::writeTrafficLights(device, tc);
403 : // we also need to remember the associations between tlLogics and connections
404 : // since the information in con.xml is insufficient
405 1975 : for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
406 1813 : NBEdge* e = (*i).second;
407 : // write this edge's tl-controlled connections
408 1813 : const std::vector<NBEdge::Connection> connections = e->getConnections();
409 5466 : for (std::vector<NBEdge::Connection>::const_iterator c = connections.begin(); c != connections.end(); ++c) {
410 3653 : if (c->tlID != "") {
411 1065 : NWWriter_SUMO::writeConnection(device, *e, *c, false, NWWriter_SUMO::TLL);
412 : }
413 : }
414 1813 : }
415 162 : device.close();
416 162 : }
417 :
418 :
419 : void
420 5 : NWWriter_XML::writeJoinedJunctions(const std::string& filename, NBNodeCont& nc) {
421 : std::map<SumoXMLAttr, std::string> attrs;
422 5 : attrs[SUMO_ATTR_VERSION] = toString(NETWORK_VERSION);
423 5 : OutputDevice& device = OutputDevice::getDevice(filename);
424 10 : device.writeXMLHeader("nodes", "nodes_file.xsd", attrs);
425 : const std::vector<std::set<std::string> >& clusters = nc.getJoinedClusters();
426 10 : for (std::vector<std::set<std::string> >::const_iterator it = clusters.begin(); it != clusters.end(); it++) {
427 : assert((*it).size() > 0);
428 5 : device.openTag(SUMO_TAG_JOIN);
429 : // prepare string
430 5 : std::ostringstream oss;
431 29 : for (std::set<std::string>::const_iterator it_id = it->begin(); it_id != it->end(); it_id++) {
432 24 : oss << *it_id << " ";
433 : }
434 : // remove final space
435 : std::string ids = oss.str();
436 5 : device.writeAttr(SUMO_ATTR_NODES, ids.substr(0, ids.size() - 1));
437 10 : device.closeTag();
438 5 : }
439 5 : device.close();
440 5 : }
441 :
442 :
443 : void
444 1 : NWWriter_XML::writeStreetSigns(const OptionsCont& oc, NBEdgeCont& ec) {
445 2 : OutputDevice& device = OutputDevice::getDevice(oc.getString("street-sign-output"));
446 2 : device.writeXMLHeader("additional", "additional_file.xsd");
447 23 : for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
448 22 : NBEdge* e = (*i).second;
449 : const std::vector<NBSign>& signs = e->getSigns();
450 30 : for (std::vector<NBSign>::const_iterator it = signs.begin(); it != signs.end(); ++it) {
451 8 : it->writeAsPOI(device, e);
452 : }
453 : }
454 1 : device.close();
455 1 : }
456 :
457 :
458 : void
459 64 : NWWriter_XML::writePTStops(const OptionsCont& oc, NBPTStopCont& sc) {
460 128 : OutputDevice& device = OutputDevice::getDevice(oc.getString("ptstop-output"));
461 128 : device.writeXMLHeader("additional", "additional_file.xsd");
462 829 : for (const auto& stopIt : sc.getStops()) {
463 765 : stopIt.second->write(device);
464 : }
465 64 : device.close();
466 64 : }
467 :
468 :
469 45 : void NWWriter_XML::writePTLines(const OptionsCont& oc, NBPTLineCont& lc) {
470 90 : OutputDevice& device = OutputDevice::getDevice(oc.getString("ptline-output"));
471 90 : device.writeXMLHeader("ptLines", "ptlines_file.xsd");
472 404 : for (const auto& item : lc.getLines()) {
473 359 : item.second->write(device);
474 : }
475 45 : device.close();
476 45 : }
477 :
478 :
479 2 : void NWWriter_XML::writeParkingAreas(const OptionsCont& oc, NBParkingCont& pc, NBEdgeCont& ec) {
480 4 : OutputDevice& device = OutputDevice::getDevice(oc.getString("parking-output"));
481 4 : device.writeXMLHeader("additional", "additional_file.xsd");
482 276 : for (NBParking& p : pc) {
483 274 : p.write(device, ec);
484 : }
485 2 : device.close();
486 2 : }
487 :
488 :
489 : void
490 1 : NWWriter_XML::writeDistricts(const OptionsCont& oc, NBDistrictCont& dc) {
491 2 : OutputDevice& device = OutputDevice::getDevice(oc.getString("taz-output"));
492 2 : device.writeXMLHeader("additional", "additional_file.xsd");
493 30 : for (std::map<std::string, NBDistrict*>::const_iterator i = dc.begin(); i != dc.end(); i++) {
494 29 : NWWriter_SUMO::writeDistrict(device, *(*i).second);
495 : }
496 1 : }
497 :
498 :
499 : void
500 696 : NWWriter_XML::writeShape(OutputDevice& out, const GeoConvHelper& gch, PositionVector shape, SumoXMLAttr attr, bool useGeo, bool geoAccuracy) {
501 696 : if (useGeo) {
502 322 : for (int i = 0; i < (int) shape.size(); i++) {
503 259 : gch.cartesian2geo(shape[i]);
504 : }
505 : }
506 696 : if (geoAccuracy) {
507 63 : out.setPrecision(gPrecisionGeo);
508 : }
509 : out.writeAttr(attr, shape);
510 696 : if (geoAccuracy) {
511 63 : out.setPrecision();
512 : }
513 696 : }
514 :
515 :
516 : /****************************************************************************/
|