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