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