LCOV - code coverage report
Current view: top level - src/netimport - NIImporter_DlrNavteq.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 373 438 85.2 %
Date: 2024-05-02 15:31:40 Functions: 29 36 80.6 %

          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        2224 : NIImporter_DlrNavteq::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
      65             :     // check whether the option is set (properly)
      66        4448 :     if (!oc.isSet("dlr-navteq-prefix")) {
      67        2174 :         return;
      68             :     }
      69             :     time_t csTime;
      70          50 :     time(&csTime);
      71          50 :     keepLength = oc.getBool("dlr-navteq.keep-length");
      72             :     // parse file(s)
      73          50 :     LineReader lr;
      74             :     // load nodes
      75             :     std::map<std::string, PositionVector> myGeoms;
      76         100 :     PROGRESS_BEGIN_MESSAGE(TL("Loading nodes"));
      77         150 :     std::string file = oc.getString("dlr-navteq-prefix") + "_nodes_unsplitted.txt";
      78          50 :     NodesHandler handler1(nb.getNodeCont(), file, myGeoms);
      79          50 :     if (!lr.setFile(file)) {
      80           0 :         throw ProcessError(TLF("The file '%' could not be opened.", file));
      81             :     }
      82          50 :     lr.readAll(handler1);
      83          50 :     PROGRESS_DONE_MESSAGE();
      84             : 
      85             :     // load street names if given and wished
      86             :     std::map<std::string, std::string> streetNames; // nameID : name
      87         100 :     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         100 :     PROGRESS_BEGIN_MESSAGE(TL("Loading edges"));
     101         150 :     file = oc.getString("dlr-navteq-prefix") + "_links_unsplitted.txt";
     102             :     // parse the file
     103          50 :     EdgesHandler handler2(nb.getNodeCont(), nb.getEdgeCont(), nb.getTypeCont(), file, myGeoms, streetNames);
     104          50 :     if (!lr.setFile(file)) {
     105           0 :         throw ProcessError(TLF("The file '%' could not be opened.", file));
     106             :     }
     107          50 :     lr.readAll(handler2);
     108          50 :     nb.getEdgeCont().recheckLaneSpread();
     109          50 :     PROGRESS_DONE_MESSAGE();
     110             : 
     111             :     // load traffic lights if given
     112         100 :     file = oc.getString("dlr-navteq-prefix") + "_traffic_signals.txt";
     113          50 :     if (lr.setFile(file)) {
     114          10 :         PROGRESS_BEGIN_MESSAGE(TL("Loading traffic lights"));
     115           5 :         TrafficlightsHandler handler3(nb.getNodeCont(), nb.getTLLogicCont(), nb.getEdgeCont(), file);
     116           5 :         lr.readAll(handler3);
     117           5 :         PROGRESS_DONE_MESSAGE();
     118           5 :     }
     119             : 
     120             :     // load prohibited manoeuvres if given
     121         100 :     file = oc.getString("dlr-navteq-prefix") + "_prohibited_manoeuvres.txt";
     122          50 :     if (lr.setFile(file)) {
     123           8 :         PROGRESS_BEGIN_MESSAGE(TL("Loading prohibited manoeuvres"));
     124           4 :         ProhibitionHandler handler6(nb.getEdgeCont(), file, csTime);
     125           4 :         lr.readAll(handler6);
     126           4 :         PROGRESS_DONE_MESSAGE();
     127           4 :     }
     128             : 
     129             :     // load connected lanes if given
     130         100 :     file = oc.getString("dlr-navteq-prefix") + "_connected_lanes.txt";
     131          50 :     if (lr.setFile(file)) {
     132          12 :         PROGRESS_BEGIN_MESSAGE(TL("Loading connected lanes"));
     133           6 :         ConnectedLanesHandler handler7(nb.getEdgeCont());
     134           6 :         lr.readAll(handler7);
     135           6 :         PROGRESS_DONE_MESSAGE();
     136           6 :     }
     137             : 
     138             :     // load time restrictions if given
     139         100 :     file = oc.getString("dlr-navteq-prefix") + "_links_timerestrictions.txt";
     140          50 :     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         150 : }
     152             : 
     153             : double
     154          62 : NIImporter_DlrNavteq::readVersion(const std::string& line, const std::string& file) {
     155             :     assert(line[0] == '#');
     156          62 :     const std::string marker = "extraction version: v";
     157          62 :     const std::string lowerCase = StringUtils::to_lower_case(line);
     158          62 :     if (lowerCase.find(marker) == std::string::npos) {
     159             :         return -1;
     160             :     }
     161          54 :     const int vStart = (int)(lowerCase.find(marker) + marker.size());
     162          54 :     const int vEnd = (int)line.find(" ", vStart);
     163             :     try {
     164          54 :         const double version = StringUtils::toDouble(line.substr(vStart, vEnd - vStart));
     165          54 :         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          50 : NIImporter_DlrNavteq::NodesHandler::NodesHandler(NBNodeCont& nc,
     179             :         const std::string& file,
     180          50 :         std::map<std::string, PositionVector>& geoms)
     181          50 :     : myNodeCont(nc), myGeoms(geoms) {
     182             :     UNUSED_PARAMETER(file);
     183          50 : }
     184             : 
     185             : 
     186          50 : NIImporter_DlrNavteq::NodesHandler::~NodesHandler() {}
     187             : 
     188             : 
     189             : bool
     190        1176 : NIImporter_DlrNavteq::NodesHandler::report(const std::string& result) {
     191        1176 :     if (result[0] == '#') {
     192             :         return true;
     193             :     }
     194             :     std::string id;
     195             :     double x, y;
     196             :     int no_geoms, intermediate;
     197             :     // parse
     198         712 :     std::istringstream stream(result);
     199             :     // id
     200         712 :     stream >> id;
     201         712 :     if (stream.fail()) {
     202           0 :         throw ProcessError("Something is wrong with the following data line\n" + result);
     203             :     }
     204             :     // intermediate?
     205         712 :     stream >> intermediate;
     206         712 :     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         712 :     stream >> no_geoms;
     214         712 :     if (stream.fail()) {
     215           0 :         throw ProcessError(TLF("Non-numerical value for number of geometries in node %.", id));
     216             :     }
     217             :     // geometrical information
     218         712 :     PositionVector geoms;
     219        1759 :     for (int i = 0; i < no_geoms; i++) {
     220             :         stream >> x;
     221        1047 :         if (stream.fail()) {
     222           0 :             throw ProcessError(TLF("Non-numerical value for x-position in node %.", id));
     223             :         }
     224             :         stream >> y;
     225        1047 :         if (stream.fail()) {
     226           0 :             throw ProcessError(TLF("Non-numerical value for y-position in node %.", id));
     227             :         }
     228        1047 :         Position pos(x, y);
     229        1047 :         if (!NBNetBuilder::transformCoordinate(pos, true)) {
     230           0 :             throw ProcessError(TLF("Unable to project coordinates for node %.", id));
     231             :         }
     232        1047 :         geoms.push_back(pos);
     233             :     }
     234             : 
     235         712 :     if (intermediate == 0) {
     236         502 :         NBNode* n = new NBNode(id, geoms[0]);
     237         502 :         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         210 :         myGeoms[id] = geoms;
     247             :     }
     248             :     return true;
     249         712 : }
     250             : 
     251             : 
     252             : // ---------------------------------------------------------------------------
     253             : // definitions of NIImporter_DlrNavteq::EdgesHandler-methods
     254             : // ---------------------------------------------------------------------------
     255          50 : NIImporter_DlrNavteq::EdgesHandler::EdgesHandler(NBNodeCont& nc, NBEdgeCont& ec,
     256             :         NBTypeCont& tc, const std::string& file,
     257             :         std::map<std::string, PositionVector>& geoms,
     258          50 :         std::map<std::string, std::string>& streetNames):
     259          50 :     myNodeCont(nc),
     260          50 :     myEdgeCont(ec),
     261          50 :     myTypeCont(tc),
     262          50 :     myGeoms(geoms),
     263          50 :     myStreetNames(streetNames),
     264          50 :     myVersion(0),
     265          50 :     myFile(file) {
     266          50 : }
     267             : 
     268             : 
     269          50 : NIImporter_DlrNavteq::EdgesHandler::~EdgesHandler() {}
     270             : 
     271             : 
     272             : bool
     273        1214 : NIImporter_DlrNavteq::EdgesHandler::report(const std::string& result) {
     274             :     // parse version number from first comment line and initialize column definitions
     275        1214 :     if (result[0] == '#') {
     276         360 :         if (!myColumns.empty()) {
     277             :             return true;
     278             :         }
     279          56 :         const double version = readVersion(result, myFile);
     280          56 :         if (version > 0) {
     281          50 :             myVersion = version;
     282             :             // init columns
     283             :             const int NUM_COLUMNS = 25; // @note arrays must match this size!
     284             :             const int MC = MISSING_COLUMN;
     285          50 :             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          74 :                 myColumns = std::vector<int>(columns, columns + NUM_COLUMNS);
     288          13 :             } 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           6 :                 myColumns = std::vector<int>(columns, columns + NUM_COLUMNS);
     291             :             } else {
     292          10 :                 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          20 :                 myColumns = std::vector<int>(columns, columns + NUM_COLUMNS);
     294             :             }
     295             :         }
     296          56 :         return true;
     297             :     }
     298         854 :     if (myColumns.empty()) {
     299           0 :         throw ProcessError(TLF("Missing version string in file '%'.", myFile));
     300             :     }
     301             :     // interpret link attributes
     302         854 :     StringTokenizer st(result, StringTokenizer::WHITECHARS);
     303         854 :     const std::string id = getColumn(st, LINK_ID);
     304             :     // form of way (for priority and permissions)
     305             :     int form_of_way;
     306             :     try {
     307        1708 :         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        1708 :         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         854 :         priority = -StringUtils::toInt(getColumn(st, FUNCTIONAL_ROAD_CLASS));
     322             :         // lower priority using form_of_way
     323         854 :         if (form_of_way == 11) {
     324             :             priority -= 1; // frontage road, very often with lowered curb
     325         852 :         } 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        1708 :                                  getColumn(st, NAME_ID1_REGIONAL),
     334        2562 :                                  getColumn(st, NAME_ID2_LOCAL));
     335             :     // try to get the nodes
     336         854 :     const std::string fromID = getColumn(st, NODE_ID_FROM);
     337         854 :     const std::string toID = getColumn(st, NODE_ID_TO);
     338         854 :     NBNode* from = myNodeCont.retrieve(fromID);
     339         854 :     NBNode* to = myNodeCont.retrieve(toID);
     340         854 :     if (from == nullptr) {
     341           0 :         throw ProcessError("The from-node '" + fromID + "' of link '" + id + "' could not be found");
     342             :     }
     343         854 :     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         854 :         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         854 :     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        1708 :         numLanes = StringUtils::toInt(getColumn(st, EXTENDED_NUMBER_OF_LANES, "-1"));
     362         854 :         if (numLanes == -1) {
     363        1708 :             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        1708 :     const std::string navTeqTypeId = getColumn(st, VEHICLE_TYPE) + "_" + getColumn(st, FORM_OF_WAY);
     370             :     // build the edge
     371             :     NBEdge* e = nullptr;
     372        1708 :     const std::string interID = getColumn(st, BETWEEN_NODE_ID);
     373         854 :     if (interID == "-1") {
     374        1282 :         e = new NBEdge(id, from, to, myTypeCont.knows(navTeqTypeId) ? navTeqTypeId : "", speed, NBEdge::UNSPECIFIED_FRICTION, numLanes, priority,
     375         641 :                        NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, LaneSpreadFunction::RIGHT, streetName);
     376             :     } else {
     377         213 :         PositionVector geoms = myGeoms[interID];
     378         426 :         if (getColumn(st, CONNECTION, "0") == "1") {
     379          70 :             geoms = geoms.reverse();
     380             :         }
     381         213 :         geoms.insert(geoms.begin(), from->getPosition());
     382         213 :         geoms.push_back(to->getPosition());
     383         213 :         const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? id : "";
     384         426 :         e = new NBEdge(id, from, to, myTypeCont.knows(navTeqTypeId) ? navTeqTypeId : "", speed, NBEdge::UNSPECIFIED_FRICTION, numLanes, priority,
     385         213 :                        NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, geoms, LaneSpreadFunction::CENTER, streetName, origID);
     386         213 :     }
     387             : 
     388             :     //Import length or edges from input file
     389         854 :     if (keepLength) {
     390          16 :         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         854 :     if (myTypeCont.knows(navTeqTypeId)) {
     396           8 :         e->setPermissions(myTypeCont.getEdgeTypePermissions(navTeqTypeId));
     397             :     } else {
     398             :         // add vehicle type information to the edge
     399         846 :         const SVCPermissions allPermissions = myTypeCont.getEdgeTypePermissions("");
     400         846 :         const SVCPermissions defaultPermissions = OptionsCont::getOptions().getBool("dlr-navteq.tolerant-permissions") ? allPermissions : 0;
     401         846 :         if (myVersion < 6.0) {
     402         656 :             NINavTeqHelper::addVehicleClasses(*e, getColumn(st, VEHICLE_TYPE), allPermissions, defaultPermissions);
     403             :         } else {
     404        1036 :             NINavTeqHelper::addVehicleClassesV6(*e, getColumn(st, VEHICLE_TYPE), allPermissions, defaultPermissions);
     405             :         }
     406             :         // permission modifications based on form_of_way
     407         846 :         if (form_of_way == 14) { // pedestrian area (fussgaengerzone)
     408             :             // unfortunately, the veh_type string is misleading in this case
     409          60 :             e->disallowVehicleClass(-1, SVC_PASSENGER);
     410             :         }
     411             :         // permission modifications based on brunnel_type
     412         846 :         if (brunnel_type == 10) { // ferry
     413           0 :             e->setPermissions(SVC_SHIP, -1);
     414             :         }
     415             :     }
     416             : 
     417             :     // insert the edge to the network
     418         854 :     if (!myEdgeCont.insert(e)) {
     419           0 :         delete e;
     420           0 :         throw ProcessError(TLF("Could not add edge '%'.", id));
     421             :     }
     422             :     return true;
     423         854 : }
     424             : 
     425             : 
     426             : std::string
     427       13366 : NIImporter_DlrNavteq::EdgesHandler::getColumn(const StringTokenizer& st, ColumnName name, const std::string fallback) {
     428             :     assert(!myColumns.empty());
     429       13366 :     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       12742 :     } else if (myColumns[name] >= 0) {
     436       12724 :         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         854 : NIImporter_DlrNavteq::EdgesHandler::getStreetNameFromIDs(
     455             :     const std::string& regionalID, const std::string& localID) const {
     456         854 :     std::string result = "";
     457             :     bool hadRegional = false;
     458         854 :     if (myStreetNames.count(regionalID) > 0) {
     459             :         hadRegional = true;
     460          24 :         result += myStreetNames[regionalID];
     461             :     }
     462         854 :     if (myStreetNames.count(localID) > 0) {
     463          18 :         if (hadRegional) {
     464             :             result += " / ";
     465             :         }
     466          18 :         result += myStreetNames[localID];
     467             :     }
     468         854 :     return result;
     469             : }
     470             : 
     471             : // ---------------------------------------------------------------------------
     472             : // definitions of NIImporter_DlrNavteq::TrafficlightsHandler-methods
     473             : // ---------------------------------------------------------------------------
     474           5 : NIImporter_DlrNavteq::TrafficlightsHandler::TrafficlightsHandler(NBNodeCont& nc,
     475             :         NBTrafficLightLogicCont& tlc,
     476             :         NBEdgeCont& ne,
     477           5 :         const std::string& file) :
     478           5 :     myNodeCont(nc),
     479           5 :     myTLLogicCont(tlc),
     480           5 :     myEdgeCont(ne) {
     481             :     UNUSED_PARAMETER(file);
     482           5 : }
     483             : 
     484             : 
     485           5 : NIImporter_DlrNavteq::TrafficlightsHandler::~TrafficlightsHandler() {}
     486             : 
     487             : 
     488             : bool
     489         117 : NIImporter_DlrNavteq::TrafficlightsHandler::report(const std::string& result) {
     490             : // #ID     POICOL-TYPE     DESCRIPTION     LONGITUDE       LATITUDE        NAVTEQ_LINK_ID  NODEID
     491             : 
     492         117 :     if (result[0] == '#') {
     493             :         return true;
     494             :     }
     495          18 :     StringTokenizer st(result, StringTokenizer::WHITECHARS);
     496          18 :     const std::string edgeID = st.get(5);
     497          18 :     NBEdge* edge = myEdgeCont.retrieve(edgeID);
     498          18 :     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          18 :         if (node->getType() != SumoXMLNodeType::TRAFFIC_LIGHT) {
     503          10 :             node->reinit(node->getPosition(), SumoXMLNodeType::TRAFFIC_LIGHT);
     504             :             // @note. There may be additional information somewhere in the GDF files about traffic light type ...
     505          30 :             TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type"));
     506             :             // @note actually we could use the navteq node ID here
     507          10 :             NBTrafficLightDefinition* tlDef = new NBOwnTLDef(node->getID(), node, 0, type);
     508          10 :             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          18 : }
     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           6 :     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           4 : NIImporter_DlrNavteq::ProhibitionHandler::ProhibitionHandler(
     712           4 :     NBEdgeCont& ec, const std::string& file, time_t constructionTime) :
     713           4 :     myEdgeCont(ec),
     714           4 :     myFile(file),
     715           4 :     myVersion(0),
     716           4 :     myConstructionTime(constructionTime) {
     717           4 : }
     718             : 
     719             : 
     720           4 : NIImporter_DlrNavteq::ProhibitionHandler::~ProhibitionHandler() {}
     721             : 
     722             : 
     723             : bool
     724         148 : NIImporter_DlrNavteq::ProhibitionHandler::report(const std::string& result) {
     725             : // # NAME_ID    Name
     726         148 :     if (result[0] == '#') {
     727         134 :         if (myVersion == 0) {
     728           6 :             const double version = readVersion(result, myFile);
     729           6 :             if (version > 0) {
     730           4 :                 myVersion = version;
     731             :             }
     732             :         }
     733         134 :         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           6 : NIImporter_DlrNavteq::ConnectedLanesHandler::ConnectedLanesHandler(
     773           6 :     NBEdgeCont& ec) :
     774           6 :     myEdgeCont(ec) {
     775           6 : }
     776             : 
     777             : 
     778           6 : NIImporter_DlrNavteq::ConnectedLanesHandler::~ConnectedLanesHandler() {}
     779             : 
     780             : 
     781             : bool
     782        1438 : NIImporter_DlrNavteq::ConnectedLanesHandler::report(const std::string& result) {
     783        1438 :     if (result[0] == '#') {
     784             :         return true;
     785             :     }
     786        1227 :     StringTokenizer st(result, StringTokenizer::TAB);
     787        1227 :     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        1227 :     const std::string nodeID = st.next();
     792        1227 :     const std::string vehicleType = st.next();
     793        1227 :     const std::string fromLaneS = st.next();
     794        1227 :     const std::string toLaneS = st.next();
     795        1227 :     const std::string throughTraffic = st.next();
     796        1227 :     const std::string startEdge = st.next();
     797        1227 :     const std::string endEdge = st.get(st.size() - 1);
     798             : 
     799        1227 :     NBEdge* from = myEdgeCont.retrieve(startEdge);
     800        1227 :     if (from == nullptr) {
     801           0 :         WRITE_WARNINGF(TL("Ignoring prohibition from unknown start edge '%'."), startEdge);
     802           0 :         return true;
     803             :     }
     804        1227 :     NBEdge* to = myEdgeCont.retrieve(endEdge);
     805        1227 :     if (to == nullptr) {
     806           0 :         WRITE_WARNINGF(TL("Ignoring prohibition from unknown end edge '%'."), endEdge);
     807           0 :         return true;
     808             :     }
     809        1227 :     int fromLane = StringUtils::toInt(fromLaneS) - 1; // one based
     810        1227 :     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        1227 :     int toLane = StringUtils::toInt(toLaneS) - 1; // one based
     815        1227 :     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        2454 :     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        1227 :     from->getLaneStruct(fromLane).connectionsDone = true;
     833        1227 :     return true;
     834        1227 : }
     835             : 
     836             : 
     837             : /****************************************************************************/

Generated by: LCOV version 1.14