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