LCOV - code coverage report
Current view: top level - src/netwrite - NWWriter_DlrNavteq.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 303 313 96.8 %
Date: 2024-04-30 15:40:33 Functions: 16 16 100.0 %

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

Generated by: LCOV version 1.14