1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2012-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file NWWriter_DlrNavteq.cpp
11 /// @author Jakob Erdmann
12 /// @author Michael Behrisch
13 /// @date 26.10.2012
14 /// @version $Id$
15 ///
16 // Exporter writing networks using DlrNavteq (Elmar) format
17 /****************************************************************************/
18
19
20 // ===========================================================================
21 // included modules
22 // ===========================================================================
23 #include <config.h>
24 #include <algorithm>
25 #include <ctime>
26 #include <cmath>
27 #include <utils/common/MsgHandler.h>
28 #include <netbuild/NBEdge.h>
29 #include <netbuild/NBEdgeCont.h>
30 #include <netbuild/NBNode.h>
31 #include <netbuild/NBNodeCont.h>
32 #include <netbuild/NBNetBuilder.h>
33 #include <utils/common/ToString.h>
34 #include <utils/common/IDSupplier.h>
35 #include <utils/common/StringUtils.h>
36 #include <utils/common/StringTokenizer.h>
37 #include <utils/options/OptionsCont.h>
38 #include <utils/iodevices/OutputDevice.h>
39 #include <utils/geom/GeoConvHelper.h>
40 #include "NWFrame.h"
41 #include "NWWriter_DlrNavteq.h"
42
43
44 // ---------------------------------------------------------------------------
45 // static members
46 // ---------------------------------------------------------------------------
47 const std::string NWWriter_DlrNavteq::UNDEFINED("-1");
48
49 // ---------------------------------------------------------------------------
50 // static methods
51 // ---------------------------------------------------------------------------
52 void
writeNetwork(const OptionsCont & oc,NBNetBuilder & nb)53 NWWriter_DlrNavteq::writeNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
54 // check whether a matsim-file shall be generated
55 if (!oc.isSet("dlr-navteq-output")) {
56 return;
57 }
58 std::map<NBEdge*, std::string> internalNodes;
59 writeNodesUnsplitted(oc, nb.getNodeCont(), nb.getEdgeCont(), internalNodes);
60 writeLinksUnsplitted(oc, nb.getEdgeCont(), internalNodes);
61 writeTrafficSignals(oc, nb.getNodeCont());
62 writeProhibitedManoeuvres(oc, nb.getNodeCont(), nb.getEdgeCont());
63 writeConnectedLanes(oc, nb.getNodeCont());
64 }
65
66
writeHeader(OutputDevice & device,const OptionsCont & oc)67 void NWWriter_DlrNavteq::writeHeader(OutputDevice& device, const OptionsCont& oc) {
68 device << "# Format matches Extraction version: V6.5 \n";
69 std::stringstream tmp;
70 oc.writeConfiguration(tmp, true, false, false);
71 tmp.seekg(std::ios_base::beg);
72 std::string line;
73 while (!tmp.eof()) {
74 std::getline(tmp, line);
75 device << "# " << line << "\n";
76 }
77 device << "#\n";
78 }
79
80 void
writeNodesUnsplitted(const OptionsCont & oc,NBNodeCont & nc,NBEdgeCont & ec,std::map<NBEdge *,std::string> & internalNodes)81 NWWriter_DlrNavteq::writeNodesUnsplitted(const OptionsCont& oc, NBNodeCont& nc, NBEdgeCont& ec, std::map<NBEdge*, std::string>& internalNodes) {
82 // For "real" nodes we simply use the node id.
83 // For internal nodes (geometry vectors describing edge geometry in the parlance of this format)
84 // we use the id of the edge and do not bother with
85 // compression (each direction gets its own internal node).
86 OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_nodes_unsplitted.txt");
87 writeHeader(device, oc);
88 const GeoConvHelper& gch = GeoConvHelper::getFinal();
89 const bool haveGeo = gch.usingGeoProjection();
90 const double geoScale = pow(10.0f, haveGeo ? 5 : 2); // see NIImporter_DlrNavteq::GEO_SCALE
91 device.setPrecision(oc.getInt("dlr-navteq.precision"));
92 if (!haveGeo) {
93 WRITE_WARNING("DlrNavteq node data will be written in (floating point) cartesian coordinates");
94 }
95 // write format specifier
96 device << "# NODE_ID\tIS_BETWEEN_NODE\tamount_of_geocoordinates\tx1\ty1\t[x2 y2 ... xn yn]\n";
97 // write header
98 Boundary boundary = gch.getConvBoundary();
99 Position min(boundary.xmin(), boundary.ymin());
100 Position max(boundary.xmax(), boundary.ymax());
101 gch.cartesian2geo(min);
102 min.mul(geoScale);
103 gch.cartesian2geo(max);
104 max.mul(geoScale);
105 int multinodes = 0;
106 for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
107 if ((*i).second->getGeometry().size() > 2) {
108 multinodes++;
109 }
110 }
111 device << "# [xmin_region] " << min.x() << "\n";
112 device << "# [xmax_region] " << max.x() << "\n";
113 device << "# [ymin_region] " << min.y() << "\n";
114 device << "# [ymax_region] " << max.y() << "\n";
115 device << "# [elements_multinode] " << multinodes << "\n";
116 device << "# [elements_normalnode] " << nc.size() << "\n";
117 device << "# [xmin] " << min.x() << "\n";
118 device << "# [xmax] " << max.x() << "\n";
119 device << "# [ymin] " << min.y() << "\n";
120 device << "# [ymax] " << max.y() << "\n";
121 // write normal nodes
122 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
123 NBNode* n = (*i).second;
124 Position pos = n->getPosition();
125 gch.cartesian2geo(pos);
126 pos.mul(geoScale);
127 device << n->getID() << "\t0\t1\t" << pos.x() << "\t" << pos.y() << "\n";
128 }
129 // write "internal" nodes
130 std::vector<std::string> avoid;
131 std::set<std::string> reservedNodeIDs;
132 const bool numericalIDs = oc.getBool("numerical-ids");
133 if (oc.isSet("reserved-ids")) {
134 NBHelpers::loadPrefixedIDsFomFile(oc.getString("reserved-ids"), "node:", reservedNodeIDs); // backward compatibility
135 NBHelpers::loadPrefixedIDsFomFile(oc.getString("reserved-ids"), "junction:", reservedNodeIDs); // selection format
136 }
137 if (numericalIDs) {
138 avoid = nc.getAllNames();
139 std::vector<std::string> avoid2 = ec.getAllNames();
140 avoid.insert(avoid.end(), avoid2.begin(), avoid2.end());
141 avoid.insert(avoid.end(), reservedNodeIDs.begin(), reservedNodeIDs.end());
142 }
143 IDSupplier idSupplier("", avoid);
144 for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
145 NBEdge* e = (*i).second;
146 PositionVector geom = e->getGeometry();
147 if (geom.size() > 2) {
148 // the import NIImporter_DlrNavteq checks for the presence of a
149 // negated edge id to determine spread type. We may need to do some
150 // shifting to make this consistent
151 const bool hasOppositeID = ec.getOppositeByID(e->getID()) != nullptr;
152 if (e->getLaneSpreadFunction() == LANESPREAD_RIGHT && !hasOppositeID) {
153 // need to write center-line geometry instead
154 try {
155 geom.move2side(e->getTotalWidth() / 2);
156 } catch (InvalidArgument& exception) {
157 WRITE_WARNING("Could not reconstruct shape for edge:'" + e->getID() + "' (" + exception.what() + ").");
158 }
159 } else if (e->getLaneSpreadFunction() == LANESPREAD_CENTER && hasOppositeID) {
160 // need to write left-border geometry instead
161 try {
162 geom.move2side(-e->getTotalWidth() / 2);
163 } catch (InvalidArgument& exception) {
164 WRITE_WARNING("Could not reconstruct shape for edge:'" + e->getID() + "' (" + exception.what() + ").");
165 }
166 }
167
168 std::string internalNodeID = e->getID();
169 if (internalNodeID == UNDEFINED
170 || (nc.retrieve(internalNodeID) != nullptr)
171 || reservedNodeIDs.count(internalNodeID) > 0
172 ) {
173 // need to invent a new name to avoid clashing with the id of a 'real' node or a reserved name
174 if (numericalIDs) {
175 internalNodeID = idSupplier.getNext();
176 } else {
177 internalNodeID += "_geometry";
178 }
179 }
180 internalNodes[e] = internalNodeID;
181 device << internalNodeID << "\t1\t" << geom.size() - 2;
182 for (int ii = 1; ii < (int)geom.size() - 1; ++ii) {
183 Position pos = geom[(int)ii];
184 gch.cartesian2geo(pos);
185 pos.mul(geoScale);
186 device << "\t" << pos.x() << "\t" << pos.y();
187 }
188 device << "\n";
189 }
190 }
191 device.close();
192 }
193
194
195 void
writeLinksUnsplitted(const OptionsCont & oc,NBEdgeCont & ec,std::map<NBEdge *,std::string> & internalNodes)196 NWWriter_DlrNavteq::writeLinksUnsplitted(const OptionsCont& oc, NBEdgeCont& ec, std::map<NBEdge*, std::string>& internalNodes) {
197 std::map<const std::string, std::string> nameIDs;
198 OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_links_unsplitted.txt");
199 writeHeader(device, oc);
200 // write format specifier
201 device << "# LINK_ID\tNODE_ID_FROM\tNODE_ID_TO\tBETWEEN_NODE_ID\tLENGTH\tVEHICLE_TYPE\tFORM_OF_WAY\tBRUNNEL_TYPE\tFUNCTIONAL_ROAD_CLASS\tSPEED_CATEGORY\tNUMBER_OF_LANES\tSPEED_LIMIT\tSPEED_RESTRICTION\tNAME_ID1_REGIONAL\tNAME_ID2_LOCAL\tHOUSENUMBERS_RIGHT\tHOUSENUMBERS_LEFT\tZIP_CODE\tAREA_ID\tSUBAREA_ID\tTHROUGH_TRAFFIC\tSPECIAL_RESTRICTIONS\tEXTENDED_NUMBER_OF_LANES\tISRAMP\tCONNECTION\n";
202 // write edges
203 for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
204 NBEdge* e = (*i).second;
205 const int kph = speedInKph(e->getSpeed());
206 const std::string& betweenNodeID = (e->getGeometry().size() > 2) ? internalNodes[e] : UNDEFINED;
207 std::string nameID = UNDEFINED;
208 if (oc.getBool("output.street-names")) {
209 const std::string& name = i->second->getStreetName();
210 if (name != "") {
211 if (nameIDs.count(name) == 0) {
212 nameIDs[name] = toString(nameIDs.size());
213 }
214 nameID = nameIDs[name];
215 }
216 }
217 device << e->getID() << "\t"
218 << e->getFromNode()->getID() << "\t"
219 << e->getToNode()->getID() << "\t"
220 << betweenNodeID << "\t"
221 << getGraphLength(e) << "\t"
222 << getAllowedTypes(e->getPermissions()) << "\t"
223 << getFormOfWay(e) << "\t"
224 << getBrunnelType(e) << "\t"
225 << getRoadClass(e) << "\t"
226 << getSpeedCategory(kph) << "\t"
227 << getNavteqLaneCode(e->getNumLanes()) << "\t"
228 << getSpeedCategoryUpperBound(kph) << "\t"
229 << kph << "\t"
230 << UNDEFINED << "\t" // NAME_ID1_REGIONAL XXX
231 << nameID << "\t" // NAME_ID2_LOCAL
232 << UNDEFINED << "\t" // housenumbers_right
233 << UNDEFINED << "\t" // housenumbers_left
234 << getSinglePostalCode(e->getParameter("postal_code", UNDEFINED), e->getID()) << "\t" // ZIP_CODE
235 << UNDEFINED << "\t" // AREA_ID
236 << UNDEFINED << "\t" // SUBAREA_ID
237 << "1\t" // through_traffic (allowed)
238 << UNDEFINED << "\t" // special_restrictions
239 << UNDEFINED << "\t" // extended_number_of_lanes
240 << UNDEFINED << "\t" // isRamp
241 << "0\t" // connection (between nodes always in order)
242 << "\n";
243 }
244 if (oc.getBool("output.street-names")) {
245 OutputDevice& namesDevice = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_names.txt");
246 writeHeader(namesDevice, oc);
247 // write format specifier
248 namesDevice << "# NAME_ID\tPERMANENT_ID_INFO\tName\n";
249 namesDevice << "# [elements] " << nameIDs.size() << "\n";
250 for (std::map<const std::string, std::string>::const_iterator i = nameIDs.begin(); i != nameIDs.end(); ++i) {
251 namesDevice
252 << i->second << "\t"
253 << 0 << "\t"
254 << i->first << "\n";
255 }
256 namesDevice.close();
257 }
258 device.close();
259 }
260
261
262 std::string
getAllowedTypes(SVCPermissions permissions)263 NWWriter_DlrNavteq::getAllowedTypes(SVCPermissions permissions) {
264 if (permissions == SVCAll) {
265 return "100000000000";
266 }
267 std::ostringstream oss;
268 oss << "0";
269 oss << ((permissions & SVC_PASSENGER) > 0 ? 1 : 0);
270 oss << ((permissions & SVC_PASSENGER) > 0 ? 1 : 0); // residential
271 oss << ((permissions & SVC_HOV) > 0 ? 1 : 0);
272 oss << ((permissions & SVC_EMERGENCY) > 0 ? 1 : 0);
273 oss << ((permissions & SVC_TAXI) > 0 ? 1 : 0);
274 oss << ((permissions & (SVC_BUS | SVC_COACH)) > 0 ? 1 : 0);
275 oss << ((permissions & SVC_DELIVERY) > 0 ? 1 : 0);
276 oss << ((permissions & (SVC_TRUCK | SVC_TRAILER)) > 0 ? 1 : 0);
277 oss << ((permissions & SVC_MOTORCYCLE) > 0 ? 1 : 0);
278 oss << ((permissions & SVC_BICYCLE) > 0 ? 1 : 0);
279 oss << ((permissions & SVC_PEDESTRIAN) > 0 ? 1 : 0);
280 return oss.str();
281 }
282
283
284 int
getRoadClass(NBEdge * edge)285 NWWriter_DlrNavteq::getRoadClass(NBEdge* edge) {
286 // quoting the navteq manual:
287 // As a general rule, Functional Road Class assignments have no direct
288 // correlation with other road attributes like speed, controlled access, route type, etc.
289 // if the network is based on OSM, we can use the highway types for determining FRC
290 std::string type = edge->getTypeID();
291 if (StringUtils::startsWith(type, "highway.")) {
292 type = type.substr(8);
293 }
294 if (StringUtils::startsWith(type, "motorway")) {
295 return 0;
296 } else if (StringUtils::startsWith(type, "trunk")) {
297 return 1;
298 } else if (StringUtils::startsWith(type, "primary")) {
299 return 1;
300 } else if (StringUtils::startsWith(type, "secondary")) {
301 return 2;
302 } else if (StringUtils::startsWith(type, "tertiary")) {
303 return 3;
304 } else if (type == "unclassified") {
305 return 3;
306 } else if (type == "living_street" || type == "residential" || type == "road" || type == "service" || type == "track" || type == "cycleway" || type == "path" || type == "footway") {
307 return 4;
308 }
309 // as a fallback we do a simple speed / lane-count mapping anyway
310 // the resulting functional road class layers probably won't be connected as required
311 const int kph = speedInKph(edge->getSpeed());
312 if ((kph) > 100) {
313 return 0;
314 }
315 if ((kph) > 70) {
316 return 1;
317 }
318 if ((kph) > 50) {
319 return (edge->getNumLanes() > 1 ? 2 : 3);
320 }
321 if ((kph) > 30) {
322 return 3;
323 }
324 return 4;
325 }
326
327
328 int
getSpeedCategory(int kph)329 NWWriter_DlrNavteq::getSpeedCategory(int kph) {
330 if ((kph) > 130) {
331 return 1;
332 }
333 if ((kph) > 100) {
334 return 2;
335 }
336 if ((kph) > 90) {
337 return 3;
338 }
339 if ((kph) > 70) {
340 return 4;
341 }
342 if ((kph) > 50) {
343 return 5;
344 }
345 if ((kph) > 30) {
346 return 6;
347 }
348 if ((kph) > 10) {
349 return 7;
350 }
351 return 8;
352 }
353
354
355 int
getSpeedCategoryUpperBound(int kph)356 NWWriter_DlrNavteq::getSpeedCategoryUpperBound(int kph) {
357 if ((kph) > 130) {
358 return 131;
359 }
360 if ((kph) > 100) {
361 return 130;
362 }
363 if ((kph) > 90) {
364 return 100;
365 }
366 if ((kph) > 70) {
367 return 90;
368 }
369 if ((kph) > 50) {
370 return 70;
371 }
372 if ((kph) > 30) {
373 return 50;
374 }
375 if ((kph) > 10) {
376 return 30;
377 }
378 return 10;
379 }
380
381
382 int
getNavteqLaneCode(const int numLanes)383 NWWriter_DlrNavteq::getNavteqLaneCode(const int numLanes) {
384 const int code = (numLanes == 1 ? 1 :
385 (numLanes < 4 ? 2 : 3));
386 return numLanes * 10 + code;
387 }
388
389
390 int
getBrunnelType(NBEdge * edge)391 NWWriter_DlrNavteq::getBrunnelType(NBEdge* edge) {
392 if (edge->knowsParameter("bridge")) {
393 return 1;
394 } else if (edge->knowsParameter("tunnel")) {
395 return 4;
396 } else if (edge->getTypeID() == "route.ferry") {
397 return 10;
398 }
399 return -1; // UNDEFINED
400 }
401
402
403 int
getFormOfWay(NBEdge * edge)404 NWWriter_DlrNavteq::getFormOfWay(NBEdge* edge) {
405 if (edge->getPermissions() == SVC_PEDESTRIAN) {
406 return 15;
407 } else if (edge->getJunctionPriority(edge->getToNode()) == NBEdge::ROUNDABOUT) {
408 return 4;
409 } else if (edge->getTypeID() == "highway.service") {
410 return 14;
411 } else if (edge->getTypeID().find("_link") != std::string::npos) {
412 return 10;
413 }
414 return 3; // speed category 1-8;
415 }
416
417
418 double
getGraphLength(NBEdge * edge)419 NWWriter_DlrNavteq::getGraphLength(NBEdge* edge) {
420 PositionVector geom = edge->getGeometry();
421 geom.push_back_noDoublePos(edge->getToNode()->getPosition());
422 geom.push_front_noDoublePos(edge->getFromNode()->getPosition());
423 return geom.length();
424 }
425
426
427 std::string
getSinglePostalCode(const std::string & zipCode,const std::string edgeID)428 NWWriter_DlrNavteq::getSinglePostalCode(const std::string& zipCode, const std::string edgeID) {
429 // might be multiple codes
430 if (zipCode.find_first_of(" ,;") != std::string::npos) {
431 WRITE_WARNING("ambiguous zip code '" + zipCode + "' for edge '" + edgeID + "'. (using first value)");
432 StringTokenizer st(zipCode, " ,;", true);
433 std::vector<std::string> ret = st.getVector();
434 return ret[0];
435 } else if (zipCode.size() > 16) {
436 WRITE_WARNING("long zip code '" + zipCode + "' for edge '" + edgeID + "'");
437 }
438 return zipCode;
439 }
440
441 void
writeTrafficSignals(const OptionsCont & oc,NBNodeCont & nc)442 NWWriter_DlrNavteq::writeTrafficSignals(const OptionsCont& oc, NBNodeCont& nc) {
443 OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_traffic_signals.txt");
444 writeHeader(device, oc);
445 const GeoConvHelper& gch = GeoConvHelper::getFinal();
446 const bool haveGeo = gch.usingGeoProjection();
447 const double geoScale = pow(10.0f, haveGeo ? 5 : 2); // see NIImporter_DlrNavteq::GEO_SCALE
448 device.setPrecision(oc.getInt("dlr-navteq.precision"));
449 // write format specifier
450 device << "#Traffic signal related to LINK_ID and NODE_ID with location relative to driving direction.\n#column format like pointcollection.\n#DESCRIPTION->LOCATION: 1-rechts von LINK; 2-links von LINK; 3-oberhalb LINK -1-keineAngabe\n#RELATREC_ID\tPOICOL_TYPE\tDESCRIPTION\tLONGITUDE\tLATITUDE\tLINK_ID\n";
451 // write record for every edge incoming to a tls controlled node
452 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
453 NBNode* n = (*i).second;
454 if (n->isTLControlled()) {
455 Position pos = n->getPosition();
456 gch.cartesian2geo(pos);
457 pos.mul(geoScale);
458 const EdgeVector& incoming = n->getIncomingEdges();
459 for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
460 NBEdge* e = *it;
461 device << e->getID() << "\t"
462 << "12\t" // POICOL_TYPE
463 << "LSA;NODEIDS#" << n->getID() << "#;LOCATION#-1#;\t"
464 << pos.x() << "\t"
465 << pos.y() << "\t"
466 << e->getID() << "\n";
467 }
468 }
469 }
470 device.close();
471 }
472
473
474 void
writeProhibitedManoeuvres(const OptionsCont & oc,const NBNodeCont & nc,const NBEdgeCont & ec)475 NWWriter_DlrNavteq::writeProhibitedManoeuvres(const OptionsCont& oc, const NBNodeCont& nc, const NBEdgeCont& ec) {
476 OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_prohibited_manoeuvres.txt");
477 writeHeader(device, oc);
478 // need to invent id for relation
479 std::set<std::string> reservedRelIDs;
480 if (oc.isSet("reserved-ids")) {
481 NBHelpers::loadPrefixedIDsFomFile(oc.getString("reserved-ids"), "rel:", reservedRelIDs);
482 }
483 std::vector<std::string> avoid = ec.getAllNames(); // already used for tls RELATREC_ID
484 avoid.insert(avoid.end(), reservedRelIDs.begin(), reservedRelIDs.end());
485 IDSupplier idSupplier("", avoid); // @note: use a global relRecIDsupplier if this is used more often
486 // write format specifier
487 device << "#No driving allowed from ID1 to ID2 or the complete chain from ID1 to IDn\n";
488 device << "#RELATREC_ID\tPERMANENT_ID_INFO\tVALIDITY_PERIOD\tTHROUGH_TRAFFIC\tVEHICLE_TYPE\tNAVTEQ_LINK_ID1\t[NAVTEQ_LINK_ID2 ...]\n";
489 // write record for every pair of incoming/outgoing edge that are not connected despite having common permissions
490 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
491 NBNode* n = (*i).second;
492 const EdgeVector& incoming = n->getIncomingEdges();
493 const EdgeVector& outgoing = n->getOutgoingEdges();
494 for (EdgeVector::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
495 NBEdge* inEdge = *j;
496 const SVCPermissions inPerm = inEdge->getPermissions();
497 for (EdgeVector::const_iterator k = outgoing.begin(); k != outgoing.end(); ++k) {
498 NBEdge* outEdge = *k;
499 const SVCPermissions outPerm = outEdge->getPermissions();
500 const SVCPermissions commonPerm = inPerm & outPerm;
501 if (commonPerm != 0 && commonPerm != SVC_PEDESTRIAN && !inEdge->isConnectedTo(outEdge)) {
502 device
503 << idSupplier.getNext() << "\t"
504 << 1 << "\t" // permanent id
505 << UNDEFINED << "\t"
506 << 1 << "\t"
507 << getAllowedTypes(SVCAll) << "\t"
508 << inEdge->getID() << "\t" << outEdge->getID() << "\n";
509 }
510 }
511 }
512 }
513 device.close();
514 }
515
516
517 void
writeConnectedLanes(const OptionsCont & oc,NBNodeCont & nc)518 NWWriter_DlrNavteq::writeConnectedLanes(const OptionsCont& oc, NBNodeCont& nc) {
519 OutputDevice& device = OutputDevice::getDevice(oc.getString("dlr-navteq-output") + "_connected_lanes.txt");
520 writeHeader(device, oc);
521 // write format specifier
522 device << "#Lane connections related to LINK-IDs and NODE-ID.\n";
523 device << "#column format like pointcollection.\n";
524 device << "#NODE-ID\tVEHICLE-TYPE\tFROM_LANE\tTO_LANE\tTHROUGH_TRAFFIC\tLINK_IDs[2..*]\n";
525 // write record for every connection
526 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
527 NBNode* n = (*i).second;
528 const EdgeVector& incoming = n->getIncomingEdges();
529 for (EdgeVector::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
530 NBEdge* from = *j;
531 const SVCPermissions fromPerm = from->getPermissions();
532 const std::vector<NBEdge::Connection>& connections = from->getConnections();
533 for (std::vector<NBEdge::Connection>::const_iterator it_c = connections.begin(); it_c != connections.end(); it_c++) {
534 const NBEdge::Connection& c = *it_c;
535 device
536 << n->getID() << "\t"
537 << getAllowedTypes(fromPerm & c.toEdge->getPermissions()) << "\t"
538 << c.fromLane + 1 << "\t" // one-based
539 << c.toLane + 1 << "\t" // one-based
540 << 1 << "\t" // no information regarding permissibility of through traffic
541 << from->getID() << "\t"
542 << c.toEdge->getID() << "\t"
543 << "\n";
544 }
545 }
546 }
547 device.close();
548 }
549
550 /****************************************************************************/
551
552