Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netimport/NIImporter_DlrNavteq.cpp
169666 views
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 NIImporter_DlrNavteq.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @date Mon, 14.04.2008
19
///
20
// Importer for networks stored in Elmar's format
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <string>
25
#include <sstream>
26
#include <limits>
27
#include <utils/importio/LineHandler.h>
28
#include <utils/common/StringTokenizer.h>
29
#include <utils/common/MsgHandler.h>
30
#include <utils/common/UtilExceptions.h>
31
#include <utils/common/StringUtils.h>
32
#include <utils/common/ToString.h>
33
#include <utils/common/StringUtils.h>
34
#include <utils/options/OptionsCont.h>
35
#include <utils/importio/LineReader.h>
36
#include <utils/geom/GeoConvHelper.h>
37
#include <netbuild/NBNetBuilder.h>
38
#include <netbuild/NBNode.h>
39
#include <netbuild/NBNodeCont.h>
40
#include <netbuild/NBEdge.h>
41
#include <netbuild/NBEdgeCont.h>
42
#include <netbuild/NBTypeCont.h>
43
#include <netbuild/NBOwnTLDef.h>
44
#include <netimport/NINavTeqHelper.h>
45
#include "NILoader.h"
46
#include "NIImporter_DlrNavteq.h"
47
48
49
// ---------------------------------------------------------------------------
50
// static members
51
// ---------------------------------------------------------------------------
52
const std::string NIImporter_DlrNavteq::GEO_SCALE("1e-5");
53
const int NIImporter_DlrNavteq::EdgesHandler::MISSING_COLUMN = std::numeric_limits<int>::max();
54
const std::string NIImporter_DlrNavteq::UNDEFINED("-1");
55
bool NIImporter_DlrNavteq::keepLength = false;
56
57
// ===========================================================================
58
// method definitions
59
// ===========================================================================
60
// ---------------------------------------------------------------------------
61
// static methods
62
// ---------------------------------------------------------------------------
63
void
64
NIImporter_DlrNavteq::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
65
// check whether the option is set (properly)
66
if (!oc.isSet("dlr-navteq-prefix")) {
67
return;
68
}
69
time_t csTime;
70
time(&csTime);
71
keepLength = oc.getBool("dlr-navteq.keep-length");
72
// parse file(s)
73
LineReader lr;
74
// load nodes
75
std::map<std::string, PositionVector> myGeoms;
76
PROGRESS_BEGIN_MESSAGE(TL("Loading nodes"));
77
std::string file = oc.getString("dlr-navteq-prefix") + "_nodes_unsplitted.txt";
78
NodesHandler handler1(nb.getNodeCont(), file, myGeoms);
79
if (!lr.setFile(file)) {
80
throw ProcessError(TLF("The file '%' could not be opened.", file));
81
}
82
lr.readAll(handler1);
83
PROGRESS_DONE_MESSAGE();
84
85
// load street names if given and wished
86
std::map<std::string, std::string> streetNames; // nameID : name
87
if (oc.getBool("output.street-names")) {
88
file = oc.getString("dlr-navteq-prefix") + "_names.txt";
89
if (lr.setFile(file)) {
90
PROGRESS_BEGIN_MESSAGE(TL("Loading street names"));
91
NamesHandler handler4(file, streetNames);
92
lr.readAll(handler4);
93
PROGRESS_DONE_MESSAGE();
94
} else {
95
WRITE_WARNINGF(TL("Output will not contain street names because the file '%' was not found"), file);
96
}
97
}
98
99
// load edges
100
PROGRESS_BEGIN_MESSAGE(TL("Loading edges"));
101
file = oc.getString("dlr-navteq-prefix") + "_links_unsplitted.txt";
102
// parse the file
103
EdgesHandler handler2(nb.getNodeCont(), nb.getEdgeCont(), nb.getTypeCont(), file, myGeoms, streetNames);
104
if (!lr.setFile(file)) {
105
throw ProcessError(TLF("The file '%' could not be opened.", file));
106
}
107
lr.readAll(handler2);
108
nb.getEdgeCont().recheckLaneSpread();
109
PROGRESS_DONE_MESSAGE();
110
111
// load traffic lights if given
112
file = oc.getString("dlr-navteq-prefix") + "_traffic_signals.txt";
113
if (lr.setFile(file)) {
114
PROGRESS_BEGIN_MESSAGE(TL("Loading traffic lights"));
115
TrafficlightsHandler handler3(nb.getNodeCont(), nb.getTLLogicCont(), nb.getEdgeCont(), file);
116
lr.readAll(handler3);
117
PROGRESS_DONE_MESSAGE();
118
}
119
120
// load prohibited manoeuvres if given
121
file = oc.getString("dlr-navteq-prefix") + "_prohibited_manoeuvres.txt";
122
if (lr.setFile(file)) {
123
PROGRESS_BEGIN_MESSAGE(TL("Loading prohibited manoeuvres"));
124
ProhibitionHandler handler6(nb.getEdgeCont(), file, csTime);
125
lr.readAll(handler6);
126
PROGRESS_DONE_MESSAGE();
127
}
128
129
// load connected lanes if given
130
file = oc.getString("dlr-navteq-prefix") + "_connected_lanes.txt";
131
if (lr.setFile(file)) {
132
PROGRESS_BEGIN_MESSAGE(TL("Loading connected lanes"));
133
ConnectedLanesHandler handler7(nb.getEdgeCont());
134
lr.readAll(handler7);
135
PROGRESS_DONE_MESSAGE();
136
}
137
138
// load time restrictions if given
139
file = oc.getString("dlr-navteq-prefix") + "_links_timerestrictions.txt";
140
if (lr.setFile(file)) {
141
PROGRESS_BEGIN_MESSAGE(TL("Loading time restrictions"));
142
if (!oc.isDefault("construction-date")) {
143
csTime = readDate(oc.getString("construction-date"));
144
}
145
TimeRestrictionsHandler handler5(nb.getEdgeCont(), nb.getDistrictCont(), csTime);
146
lr.readAll(handler5);
147
handler5.printSummary();
148
PROGRESS_DONE_MESSAGE();
149
}
150
151
}
152
153
double
154
NIImporter_DlrNavteq::readVersion(const std::string& line, const std::string& file) {
155
assert(line[0] == '#');
156
const std::string marker = "extraction version: v";
157
const std::string lowerCase = StringUtils::to_lower_case(line);
158
if (lowerCase.find(marker) == std::string::npos) {
159
return -1;
160
}
161
const int vStart = (int)(lowerCase.find(marker) + marker.size());
162
const int vEnd = (int)line.find(" ", vStart);
163
try {
164
const double version = StringUtils::toDouble(line.substr(vStart, vEnd - vStart));
165
if (version < 0) {
166
throw ProcessError("Invalid version number '" + toString(version) + "' in file '" + file + "'.");
167
}
168
return version;
169
} catch (NumberFormatException&) {
170
throw ProcessError("Non-numerical value '" + line.substr(vStart, vEnd - vStart) + "' for version string in file '" + file + "'.");
171
}
172
}
173
174
175
// ---------------------------------------------------------------------------
176
// definitions of NIImporter_DlrNavteq::NodesHandler-methods
177
// ---------------------------------------------------------------------------
178
NIImporter_DlrNavteq::NodesHandler::NodesHandler(NBNodeCont& nc,
179
const std::string& file,
180
std::map<std::string, PositionVector>& geoms)
181
: myNodeCont(nc), myGeoms(geoms) {
182
UNUSED_PARAMETER(file);
183
}
184
185
186
NIImporter_DlrNavteq::NodesHandler::~NodesHandler() {}
187
188
189
bool
190
NIImporter_DlrNavteq::NodesHandler::report(const std::string& result) {
191
if (result[0] == '#') {
192
return true;
193
}
194
std::string id;
195
double x, y;
196
int no_geoms, intermediate;
197
// parse
198
std::istringstream stream(result);
199
// id
200
stream >> id;
201
if (stream.fail()) {
202
throw ProcessError("Something is wrong with the following data line\n" + result);
203
}
204
// intermediate?
205
stream >> intermediate;
206
if (stream.fail()) {
207
if (myNodeCont.size() == 0) { // be generous with extra data at beginning of file
208
return true;
209
}
210
throw ProcessError(TLF("Non-numerical value for intermediate status in node %.", id));
211
}
212
// number of geometrical information
213
stream >> no_geoms;
214
if (stream.fail()) {
215
throw ProcessError(TLF("Non-numerical value for number of geometries in node %.", id));
216
}
217
// geometrical information
218
PositionVector geoms;
219
for (int i = 0; i < no_geoms; i++) {
220
stream >> x;
221
if (stream.fail()) {
222
throw ProcessError(TLF("Non-numerical value for x-position in node %.", id));
223
}
224
stream >> y;
225
if (stream.fail()) {
226
throw ProcessError(TLF("Non-numerical value for y-position in node %.", id));
227
}
228
Position pos(x, y);
229
if (!NBNetBuilder::transformCoordinate(pos, true)) {
230
throw ProcessError(TLF("Unable to project coordinates for node %.", id));
231
}
232
geoms.push_back(pos);
233
}
234
235
if (intermediate == 0) {
236
NBNode* n = new NBNode(id, geoms[0]);
237
if (!myNodeCont.insert(n)) {
238
delete n;
239
if (OptionsCont::getOptions().getBool("ignore-errors")) {
240
WRITE_WARNINGF(TL("Could not add node '%'."), id);
241
} else {
242
throw ProcessError(TLF("Could not add node '%'.", id));
243
}
244
}
245
} else {
246
myGeoms[id] = geoms;
247
}
248
return true;
249
}
250
251
252
// ---------------------------------------------------------------------------
253
// definitions of NIImporter_DlrNavteq::EdgesHandler-methods
254
// ---------------------------------------------------------------------------
255
NIImporter_DlrNavteq::EdgesHandler::EdgesHandler(NBNodeCont& nc, NBEdgeCont& ec,
256
NBTypeCont& tc, const std::string& file,
257
std::map<std::string, PositionVector>& geoms,
258
std::map<std::string, std::string>& streetNames):
259
myNodeCont(nc),
260
myEdgeCont(ec),
261
myTypeCont(tc),
262
myGeoms(geoms),
263
myStreetNames(streetNames),
264
myVersion(0),
265
myFile(file) {
266
}
267
268
269
NIImporter_DlrNavteq::EdgesHandler::~EdgesHandler() {}
270
271
272
bool
273
NIImporter_DlrNavteq::EdgesHandler::report(const std::string& result) {
274
// parse version number from first comment line and initialize column definitions
275
if (result[0] == '#') {
276
if (!myColumns.empty()) {
277
return true;
278
}
279
const double version = readVersion(result, myFile);
280
if (version > 0) {
281
myVersion = version;
282
// init columns
283
const int NUM_COLUMNS = 25; // @note arrays must match this size!
284
const int MC = MISSING_COLUMN;
285
if (myVersion < 3) {
286
const int columns[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, MC, 12, 13, 14, 15, 16, 17, 18, 19, 20, MC, MC, -21};
287
myColumns = std::vector<int>(columns, columns + NUM_COLUMNS);
288
} else if (myVersion < 6) {
289
const int columns[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, MC, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, -23};
290
myColumns = std::vector<int>(columns, columns + NUM_COLUMNS);
291
} else {
292
const int columns[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
293
myColumns = std::vector<int>(columns, columns + NUM_COLUMNS);
294
}
295
}
296
return true;
297
}
298
if (myColumns.empty()) {
299
throw ProcessError(TLF("Missing version string in file '%'.", myFile));
300
}
301
// interpret link attributes
302
StringTokenizer st(result, StringTokenizer::WHITECHARS);
303
const std::string id = getColumn(st, LINK_ID);
304
// form of way (for priority and permissions)
305
int form_of_way;
306
try {
307
form_of_way = StringUtils::toInt(getColumn(st, FORM_OF_WAY));
308
} catch (NumberFormatException&) {
309
throw ProcessError(TLF("Non-numerical value for form_of_way of link '%'.", id));
310
}
311
// brunnel type (bridge/tunnel/ferry (for permissions)
312
int brunnel_type;
313
try {
314
brunnel_type = StringUtils::toInt(getColumn(st, BRUNNEL_TYPE));
315
} catch (NumberFormatException&) {
316
throw ProcessError(TLF("Non-numerical value for brunnel_type of link '%'.", id));
317
}
318
// priority based on street_type / frc
319
int priority;
320
try {
321
priority = -StringUtils::toInt(getColumn(st, FUNCTIONAL_ROAD_CLASS));
322
// lower priority using form_of_way
323
if (form_of_way == 11) {
324
priority -= 1; // frontage road, very often with lowered curb
325
} else if (form_of_way > 11) {
326
priority -= 2; // parking/service access assume lowered curb
327
}
328
} catch (NumberFormatException&) {
329
throw ProcessError(TLF("Non-numerical value for street_type of link '%'.", id));
330
}
331
// street name
332
std::string streetName = getStreetNameFromIDs(
333
getColumn(st, NAME_ID1_REGIONAL),
334
getColumn(st, NAME_ID2_LOCAL));
335
// try to get the nodes
336
const std::string fromID = getColumn(st, NODE_ID_FROM);
337
const std::string toID = getColumn(st, NODE_ID_TO);
338
NBNode* from = myNodeCont.retrieve(fromID);
339
NBNode* to = myNodeCont.retrieve(toID);
340
if (from == nullptr) {
341
throw ProcessError("The from-node '" + fromID + "' of link '" + id + "' could not be found");
342
}
343
if (to == nullptr) {
344
throw ProcessError("The to-node '" + toID + "' of link '" + id + "' could not be found");
345
}
346
// speed
347
double speed;
348
try {
349
speed = StringUtils::toInt(getColumn(st, SPEED_RESTRICTION, "-1")) / 3.6;
350
} catch (NumberFormatException&) {
351
throw ProcessError(TLF("Non-numerical value for the SPEED_RESTRICTION of link '%'.", id));
352
}
353
if (speed < 0) {
354
// speed category as fallback
355
speed = NINavTeqHelper::getSpeed(id, getColumn(st, SPEED_CATEGORY));
356
}
357
// number of lanes
358
int numLanes;
359
try {
360
// EXTENDED_NUMBER_OF_LANES is prefered but may not be defined
361
numLanes = StringUtils::toInt(getColumn(st, EXTENDED_NUMBER_OF_LANES, "-1"));
362
if (numLanes == -1) {
363
numLanes = NINavTeqHelper::getLaneNumber(id, getColumn(st, NUMBER_OF_LANES), speed);
364
}
365
} catch (NumberFormatException&) {
366
throw ProcessError(TLF("Non-numerical value for the number of lanes of link '%'.", id));
367
}
368
369
const std::string navTeqTypeId = getColumn(st, VEHICLE_TYPE) + "_" + getColumn(st, FORM_OF_WAY);
370
// build the edge
371
NBEdge* e = nullptr;
372
const std::string interID = getColumn(st, BETWEEN_NODE_ID);
373
if (interID == "-1") {
374
e = new NBEdge(id, from, to, myTypeCont.knows(navTeqTypeId) ? navTeqTypeId : "", speed, NBEdge::UNSPECIFIED_FRICTION, numLanes, priority,
375
NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, LaneSpreadFunction::RIGHT, streetName);
376
} else {
377
PositionVector geoms = myGeoms[interID];
378
if (getColumn(st, CONNECTION, "0") == "1") {
379
geoms = geoms.reverse();
380
}
381
geoms.insert(geoms.begin(), from->getPosition());
382
geoms.push_back(to->getPosition());
383
const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? id : "";
384
e = new NBEdge(id, from, to, myTypeCont.knows(navTeqTypeId) ? navTeqTypeId : "", speed, NBEdge::UNSPECIFIED_FRICTION, numLanes, priority,
385
NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, geoms, LaneSpreadFunction::CENTER, streetName, origID);
386
}
387
388
//Import length or edges from input file
389
if (keepLength) {
390
const double length = StringUtils::toDouble(getColumn(st, LENGTH));
391
e->setLoadedLength(length);
392
}
393
394
// NavTeq imports can be done with a typemap (if supplied), if not, the old defaults are used
395
if (myTypeCont.knows(navTeqTypeId)) {
396
e->setPermissions(myTypeCont.getEdgeTypePermissions(navTeqTypeId));
397
} else {
398
// add vehicle type information to the edge
399
const SVCPermissions allPermissions = myTypeCont.getEdgeTypePermissions("");
400
const SVCPermissions defaultPermissions = OptionsCont::getOptions().getBool("dlr-navteq.tolerant-permissions") ? allPermissions : 0;
401
if (myVersion < 6.0) {
402
NINavTeqHelper::addVehicleClasses(*e, getColumn(st, VEHICLE_TYPE), allPermissions, defaultPermissions);
403
} else {
404
NINavTeqHelper::addVehicleClassesV6(*e, getColumn(st, VEHICLE_TYPE), allPermissions, defaultPermissions);
405
}
406
// permission modifications based on form_of_way
407
if (form_of_way == 14) { // pedestrian area (fussgaengerzone)
408
// unfortunately, the veh_type string is misleading in this case
409
e->disallowVehicleClass(-1, SVC_PASSENGER);
410
}
411
// permission modifications based on brunnel_type
412
if (brunnel_type == 10) { // ferry
413
e->setPermissions(SVC_SHIP, -1);
414
}
415
}
416
417
// insert the edge to the network
418
if (!myEdgeCont.insert(e)) {
419
delete e;
420
throw ProcessError(TLF("Could not add edge '%'.", id));
421
}
422
return true;
423
}
424
425
426
std::string
427
NIImporter_DlrNavteq::EdgesHandler::getColumn(const StringTokenizer& st, ColumnName name, const std::string fallback) {
428
assert(!myColumns.empty());
429
if (myColumns[name] == MISSING_COLUMN) {
430
if (fallback == "") {
431
throw ProcessError(TLF("Missing column %.", toString(name)));
432
} else {
433
return fallback;
434
}
435
} else if (myColumns[name] >= 0) {
436
return st.get((int)(myColumns[name]));
437
} else {
438
// negative column number implies an optional column
439
if ((int) st.size() <= -myColumns[name]) {
440
// the column is not present
441
if (fallback == "") {
442
throw ProcessError(TLF("Missing optional column % without default value.", toString(name)));
443
} else {
444
return fallback;
445
}
446
} else {
447
return st.get((int)(-myColumns[name]));
448
}
449
}
450
}
451
452
453
std::string
454
NIImporter_DlrNavteq::EdgesHandler::getStreetNameFromIDs(
455
const std::string& regionalID, const std::string& localID) const {
456
std::string result = "";
457
bool hadRegional = false;
458
if (myStreetNames.count(regionalID) > 0) {
459
hadRegional = true;
460
result += myStreetNames[regionalID];
461
}
462
if (myStreetNames.count(localID) > 0) {
463
if (hadRegional) {
464
result += " / ";
465
}
466
result += myStreetNames[localID];
467
}
468
return result;
469
}
470
471
// ---------------------------------------------------------------------------
472
// definitions of NIImporter_DlrNavteq::TrafficlightsHandler-methods
473
// ---------------------------------------------------------------------------
474
NIImporter_DlrNavteq::TrafficlightsHandler::TrafficlightsHandler(NBNodeCont& nc,
475
NBTrafficLightLogicCont& tlc,
476
NBEdgeCont& ne,
477
const std::string& file) :
478
myNodeCont(nc),
479
myTLLogicCont(tlc),
480
myEdgeCont(ne) {
481
UNUSED_PARAMETER(file);
482
}
483
484
485
NIImporter_DlrNavteq::TrafficlightsHandler::~TrafficlightsHandler() {}
486
487
488
bool
489
NIImporter_DlrNavteq::TrafficlightsHandler::report(const std::string& result) {
490
// #ID POICOL-TYPE DESCRIPTION LONGITUDE LATITUDE NAVTEQ_LINK_ID NODEID
491
492
if (result[0] == '#') {
493
return true;
494
}
495
StringTokenizer st(result, StringTokenizer::WHITECHARS);
496
const std::string edgeID = st.get(5);
497
NBEdge* edge = myEdgeCont.retrieve(edgeID);
498
if (edge == nullptr) {
499
WRITE_WARNINGF(TL("The traffic light edge '%' could not be found."), edgeID);
500
} else {
501
NBNode* node = edge->getToNode();
502
if (node->getType() != SumoXMLNodeType::TRAFFIC_LIGHT) {
503
node->reinit(node->getPosition(), SumoXMLNodeType::TRAFFIC_LIGHT);
504
// @note. There may be additional information somewhere in the GDF files about traffic light type ...
505
TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type"));
506
// @note actually we could use the navteq node ID here
507
NBTrafficLightDefinition* tlDef = new NBOwnTLDef(node->getID(), node, 0, type);
508
if (!myTLLogicCont.insert(tlDef)) {
509
// actually, nothing should fail here
510
delete tlDef;
511
throw ProcessError(TLF("Could not allocate tls for '%'.", node->getID()));
512
}
513
}
514
}
515
return true;
516
}
517
518
519
// ---------------------------------------------------------------------------
520
// definitions of NIImporter_DlrNavteq::NamesHandler-methods
521
// ---------------------------------------------------------------------------
522
NIImporter_DlrNavteq::NamesHandler::NamesHandler(
523
const std::string& file, std::map<std::string, std::string>& streetNames) :
524
myStreetNames(streetNames) {
525
UNUSED_PARAMETER(file);
526
}
527
528
529
NIImporter_DlrNavteq::NamesHandler::~NamesHandler() {}
530
531
532
bool
533
NIImporter_DlrNavteq::NamesHandler::report(const std::string& result) {
534
// # NAME_ID Name
535
if (result[0] == '#') {
536
return true;
537
}
538
StringTokenizer st(result, StringTokenizer::TAB);
539
if (st.size() == 1) {
540
return true; // one line with the number of data containing lines in it (also starts with a comment # since ersion 6.5)
541
}
542
assert(st.size() >= 2);
543
const std::string id = st.next();
544
if (st.size() > 2) {
545
const std::string permanent_id_info = st.next();
546
}
547
myStreetNames[id] = st.next();
548
return true;
549
}
550
551
552
// ---------------------------------------------------------------------------
553
// definitions of NIImporter_DlrNavteq::TimeRestrictionsHandler-methods
554
// ---------------------------------------------------------------------------
555
NIImporter_DlrNavteq::TimeRestrictionsHandler::TimeRestrictionsHandler(NBEdgeCont& ec, NBDistrictCont& dc, time_t constructionTime):
556
myEdgeCont(ec),
557
myDistrictCont(dc),
558
myConstructionTime(constructionTime),
559
myCS_min(std::numeric_limits<time_t>::max()),
560
myCS_max(std::numeric_limits<time_t>::min()),
561
myConstructionEntries(0),
562
myNotStarted(0),
563
myUnderConstruction(0),
564
myFinished(0),
565
myRemovedEdges(0) {
566
}
567
568
569
NIImporter_DlrNavteq::TimeRestrictionsHandler::~TimeRestrictionsHandler() {}
570
571
572
bool
573
NIImporter_DlrNavteq::TimeRestrictionsHandler::report(const std::string& result) {
574
// # NAME_ID Name
575
if (result[0] == '#') {
576
return true;
577
}
578
StringTokenizer st(result, StringTokenizer::WHITECHARS);
579
const std::string id = st.next();
580
const std::string type = st.next();
581
const std::string directionOfFlow = st.next(); // can be ignored since unidirectional edge ids are referenced in the file
582
const std::string throughTraffic = st.next();
583
const std::string vehicleType = st.next();
584
const std::string validityPeriod = st.next();
585
const std::string warning = "Unrecognized TIME_REC '" + validityPeriod + "'";
586
if (type == "CS") {
587
myConstructionEntries++;
588
if (validityPeriod.size() > 1024) {
589
WRITE_WARNING(warning);
590
}
591
// construction
592
char start[1024];
593
char duration[1024];
594
595
int matched;
596
597
matched = sscanf(validityPeriod.c_str(), "[(%[^)]){%[^}]}]", start, duration);
598
if (matched == 2) {
599
time_t tStart = readTimeRec(start, "");
600
time_t tEnd = readTimeRec(start, duration);
601
myCS_min = MIN2(myCS_min, tStart);
602
myCS_max = MAX2(myCS_max, tEnd);
603
//std::cout << " start=" << start << " tStart=" << tStart<< " translation=" << asctime(localtime(&tStart)) << "";
604
//std::cout << " duration=" << duration << " tEnd=" << tEnd << " translation=" << asctime(localtime(&tEnd)) << "\n";
605
if (myConstructionTime < tEnd) {
606
NBEdge* edge = myEdgeCont.retrieve(id);
607
if (edge != nullptr) {
608
myRemovedEdges++;
609
myEdgeCont.extract(myDistrictCont, edge, true);
610
}
611
if (myConstructionTime < tStart) {
612
myNotStarted++;
613
} else {
614
myUnderConstruction++;
615
}
616
} else {
617
myFinished++;
618
}
619
} else {
620
WRITE_WARNING(warning);
621
};
622
}
623
return true;
624
}
625
626
627
void
628
NIImporter_DlrNavteq::TimeRestrictionsHandler::printSummary() {
629
if (myConstructionEntries > 0) {
630
char buff[1024];
631
std::ostringstream msg;
632
strftime(buff, 1024, "%Y-%m-%d", localtime(&myCS_min));
633
msg << "Parsed " << myConstructionEntries << " construction entries between " << buff;
634
strftime(buff, 1024, "%Y-%m-%d", localtime(&myCS_max));
635
msg << " and " << buff << ".\n";
636
strftime(buff, 1024, "%Y-%m-%d", localtime(&myConstructionTime));
637
msg << "Removed " << myRemovedEdges << " edges not yet constructed at " << buff << ".\n";
638
msg << " not yet started: " << myNotStarted << "\n";
639
msg << " under construction: " << myUnderConstruction << "\n";
640
msg << " finished: " << myFinished << "\n";
641
WRITE_MESSAGE(msg.str());
642
}
643
}
644
645
646
int
647
NIImporter_DlrNavteq::readPrefixedInt(const std::string& s, const std::string& prefix, int fallBack) {
648
int result = fallBack;
649
const size_t pos = s.find(prefix);
650
if (pos != std::string::npos) {
651
sscanf(s.substr(pos + prefix.size()).c_str(), "%i", &result);
652
}
653
return result;
654
}
655
656
657
time_t
658
NIImporter_DlrNavteq::readTimeRec(const std::string& start, const std::string& duration) {
659
// http://www.cplusplus.com/reference/ctime/mktime/
660
struct tm timeinfo;
661
timeinfo.tm_hour = 0;
662
timeinfo.tm_min = 0;
663
timeinfo.tm_sec = 0;
664
timeinfo.tm_year = 0;
665
timeinfo.tm_mon = 0;
666
timeinfo.tm_mday = 1;
667
timeinfo.tm_wday = 0;
668
timeinfo.tm_yday = 0;
669
timeinfo.tm_isdst = 0;
670
671
timeinfo.tm_year = readPrefixedInt(start, "y") + readPrefixedInt(duration, "y") - 1900;
672
timeinfo.tm_mon = readPrefixedInt(start, "M") + readPrefixedInt(duration, "M") - 1;
673
timeinfo.tm_mday = 7 * (readPrefixedInt(start, "w") + readPrefixedInt(duration, "w"));
674
timeinfo.tm_mday += readPrefixedInt(start, "d") + readPrefixedInt(duration, "d");
675
676
time_t result = mktime(&timeinfo);
677
return result;
678
}
679
680
681
time_t
682
NIImporter_DlrNavteq::readDate(const std::string& yyyymmdd) {
683
struct tm timeinfo;
684
timeinfo.tm_hour = 0;
685
timeinfo.tm_min = 0;
686
timeinfo.tm_sec = 0;
687
timeinfo.tm_wday = 0;
688
timeinfo.tm_yday = 0;
689
timeinfo.tm_isdst = 0;
690
691
if (yyyymmdd.size() == 10
692
&& yyyymmdd[4] == '-'
693
&& yyyymmdd[7] == '-') {
694
try {
695
timeinfo.tm_year = StringUtils::toInt(yyyymmdd.substr(0, 4)) - 1900;
696
timeinfo.tm_mon = StringUtils::toInt(yyyymmdd.substr(5, 2)) - 1;
697
timeinfo.tm_mday = StringUtils::toInt(yyyymmdd.substr(8, 2));
698
return mktime(&timeinfo);
699
} catch (...) {
700
}
701
}
702
WRITE_ERRORF(TL("Could not parse YYYY-MM-DD date '%'"), yyyymmdd);
703
time_t now;
704
time(&now);
705
return now;
706
}
707
708
// ---------------------------------------------------------------------------
709
// definitions of NIImporter_DlrNavteq::ProhibitionHandler-methods
710
// ---------------------------------------------------------------------------
711
NIImporter_DlrNavteq::ProhibitionHandler::ProhibitionHandler(
712
NBEdgeCont& ec, const std::string& file, time_t constructionTime) :
713
myEdgeCont(ec),
714
myFile(file),
715
myVersion(0),
716
myConstructionTime(constructionTime) {
717
}
718
719
720
NIImporter_DlrNavteq::ProhibitionHandler::~ProhibitionHandler() {}
721
722
723
bool
724
NIImporter_DlrNavteq::ProhibitionHandler::report(const std::string& result) {
725
// # NAME_ID Name
726
if (result[0] == '#') {
727
if (myVersion == 0) {
728
const double version = readVersion(result, myFile);
729
if (version > 0) {
730
myVersion = version;
731
}
732
}
733
return true;
734
}
735
StringTokenizer st(result, StringTokenizer::TAB);
736
if (st.size() == 1) {
737
return true; // one line with the number of data containing lines in it (also starts with a comment # since ersion 6.5)
738
}
739
if (myVersion >= 6) {
740
assert(st.size() >= 7);
741
const std::string id = st.next();
742
const std::string permanent = st.next();
743
const std::string validityPeriod = st.next();
744
const std::string throughTraffic = st.next();
745
const std::string vehicleType = st.next();
746
if (validityPeriod != UNDEFINED) {
747
WRITE_WARNINGF(TL("Ignoring temporary prohibited manoeuvre (%)."), validityPeriod);
748
return true;
749
}
750
}
751
const std::string startEdge = st.next();
752
const std::string endEdge = st.get(st.size() - 1);
753
754
NBEdge* from = myEdgeCont.retrieve(startEdge);
755
if (from == nullptr) {
756
WRITE_WARNINGF(TL("Ignoring prohibition from unknown start edge '%'."), startEdge);
757
return true;
758
}
759
NBEdge* to = myEdgeCont.retrieve(endEdge);
760
if (to == nullptr) {
761
WRITE_WARNINGF(TL("Ignoring prohibition from unknown end edge '%'."), endEdge);
762
return true;
763
}
764
from->removeFromConnections(to, -1, -1, true);
765
return true;
766
}
767
768
769
// ---------------------------------------------------------------------------
770
// definitions of NIImporter_DlrNavteq::ConnectedLanesHandler-methods
771
// ---------------------------------------------------------------------------
772
NIImporter_DlrNavteq::ConnectedLanesHandler::ConnectedLanesHandler(
773
NBEdgeCont& ec) :
774
myEdgeCont(ec) {
775
}
776
777
778
NIImporter_DlrNavteq::ConnectedLanesHandler::~ConnectedLanesHandler() {}
779
780
781
bool
782
NIImporter_DlrNavteq::ConnectedLanesHandler::report(const std::string& result) {
783
if (result[0] == '#') {
784
return true;
785
}
786
StringTokenizer st(result, StringTokenizer::TAB);
787
if (st.size() == 1) {
788
return true; // one line with the number of data containing lines in it (also starts with a comment # since ersion 6.5)
789
}
790
assert(st.size() >= 7);
791
const std::string nodeID = st.next();
792
const std::string vehicleType = st.next();
793
const std::string fromLaneS = st.next();
794
const std::string toLaneS = st.next();
795
const std::string throughTraffic = st.next();
796
const std::string startEdge = st.next();
797
const std::string endEdge = st.get(st.size() - 1);
798
799
NBEdge* from = myEdgeCont.retrieve(startEdge);
800
if (from == nullptr) {
801
WRITE_WARNINGF(TL("Ignoring prohibition from unknown start edge '%'."), startEdge);
802
return true;
803
}
804
NBEdge* to = myEdgeCont.retrieve(endEdge);
805
if (to == nullptr) {
806
WRITE_WARNINGF(TL("Ignoring prohibition from unknown end edge '%'."), endEdge);
807
return true;
808
}
809
int fromLane = StringUtils::toInt(fromLaneS) - 1; // one based
810
if (fromLane < 0 || fromLane >= from->getNumLanes()) {
811
WRITE_WARNINGF(TL("Ignoring invalid lane index '%' in connection from edge '%' with % lanes."), fromLaneS, startEdge, from->getNumLanes());
812
return true;
813
}
814
int toLane = StringUtils::toInt(toLaneS) - 1; // one based
815
if (toLane < 0 || toLane >= to->getNumLanes()) {
816
WRITE_WARNINGF(TL("Ignoring invalid lane index '%' in connection to edge '%' with % lanes"), toLaneS, endEdge, to->getNumLanes());
817
return true;
818
}
819
if (!from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::Lane2LaneInfoType::USER, true)) {
820
if (OptionsCont::getOptions().getBool("show-errors.connections-first-try")) {
821
WRITE_WARNINGF(TL("Could not set loaded connection from '%' to '%'."), from->getLaneID(fromLane), to->getLaneID(toLane));
822
}
823
// set as to be re-applied after network processing
824
// if this connection runs across a node cluster it may not be possible to set this
825
const bool warnOnly = st.size() > 7;
826
myEdgeCont.addPostProcessConnection(from->getID(), fromLane, to->getID(), toLane, false, KEEPCLEAR_UNSPECIFIED,
827
NBEdge::UNSPECIFIED_CONTPOS, NBEdge::UNSPECIFIED_VISIBILITY_DISTANCE,
828
NBEdge::UNSPECIFIED_SPEED, NBEdge::UNSPECIFIED_FRICTION, NBEdge::UNSPECIFIED_LOADED_LENGTH, PositionVector::EMPTY, false, warnOnly);
829
}
830
// ensure that connections for other lanes are guessed if not specified
831
from->declareConnectionsAsLoaded(NBEdge::EdgeBuildingStep::INIT);
832
from->getLaneStruct(fromLane).connectionsDone = true;
833
return true;
834
}
835
836
837
/****************************************************************************/
838
839