LCOV - code coverage report
Current view: top level - src/netimport - NIImporter_VISUM.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 439 744 59.0 %
Date: 2024-05-02 15:31:40 Functions: 39 51 76.5 %

          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_VISUM.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Sascha Krieg
      18             : /// @author  Michael Behrisch
      19             : /// @date    Fri, 19 Jul 2002
      20             : ///
      21             : // A VISUM network importer
      22             : /****************************************************************************/
      23             : #include <config.h>
      24             : 
      25             : #include <string>
      26             : #include <utils/common/MsgHandler.h>
      27             : #include <utils/common/StringUtils.h>
      28             : #include <utils/common/ToString.h>
      29             : #include <utils/common/StringUtils.h>
      30             : #include <utils/options/OptionsCont.h>
      31             : #include <utils/geom/GeoConvHelper.h>
      32             : #include <netbuild/NBDistrict.h>
      33             : #include <netbuild/NBNetBuilder.h>
      34             : #include <netbuild/NBPTStop.h>
      35             : #include "NILoader.h"
      36             : #include "NIImporter_VISUM.h"
      37             : 
      38             : 
      39             : StringBijection<NIImporter_VISUM::VISUM_KEY>::Entry NIImporter_VISUM::KEYS_DE[] = {
      40             :     { "VSYS", VISUM_SYS },
      41             :     { "STRECKENTYP", VISUM_LINKTYPE },
      42             :     { "KNOTEN", VISUM_NODE },
      43             :     { "BEZIRK", VISUM_DISTRICT },
      44             :     { "PUNKT", VISUM_POINT },
      45             :     { "STRECKE", VISUM_LINK },
      46             :     { "V0IV", VISUM_V0 },
      47             :     { "VSYSSET", VISUM_TYPES },
      48             :     { "RANG", VISUM_RANK },
      49             :     { "KAPIV", VISUM_CAPACITY },
      50             :     { "XKOORD", VISUM_XCOORD },
      51             :     { "YKOORD", VISUM_YCOORD },
      52             :     { "ID", VISUM_ID },
      53             :     { "CODE", VISUM_CODE },
      54             :     { "VONKNOTNR", VISUM_FROMNODE },
      55             :     { "NACHKNOTNR", VISUM_TONODE },
      56             :     { "TYPNR", VISUM_TYPE },
      57             :     { "TYP", VISUM_TYP },
      58             :     { "ANBINDUNG", VISUM_DISTRICT_CONNECTION },
      59             :     { "BEZNR", VISUM_SOURCE_DISTRICT },
      60             :     { "KNOTNR",  VISUM_FROMNODENO },
      61             :     { "RICHTUNG",  VISUM_DIRECTION },
      62             :     { "FLAECHEID",  VISUM_SURFACEID },
      63             :     { "TFLAECHEID",  VISUM_FACEID },
      64             :     { "VONPUNKTID",  VISUM_FROMPOINTID },
      65             :     { "NACHPUNKTID",  VISUM_TOPOINTID },
      66             :     { "KANTE",  VISUM_EDGE },
      67             :     { "ABBIEGER",  VISUM_TURN },
      68             :     { "UEBERKNOTNR",  VISUM_VIANODENO },
      69             :     { "ANZFAHRSTREIFEN",  VISUM_NUMLANES },
      70             :     { "INDEX",  VISUM_INDEX },
      71             :     { "STRECKENPOLY",  VISUM_LINKPOLY },
      72             :     { "FLAECHENELEMENT",  VISUM_SURFACEITEM },
      73             :     { "TEILFLAECHENELEMENT",  VISUM_FACEITEM },
      74             :     { "KANTEID",  VISUM_EDGEID },
      75             :     { "Q",  VISUM_ORIGIN },
      76             :     { "Z",  VISUM_DESTINATION },
      77             :     { "HALTEPUNKT",  VISUM_STOPPOINT },
      78             :     { "NAME",  VISUM_NAME },
      79             :     { "STRNR",  VISUM_LINKNO },
      80             :     { "RELPOS",  VISUM_RELPOS },
      81             :     { "KATNR", VISUM_CATID },
      82             :     { "ZWISCHENPUNKT", VISUM_EDGEITEM },
      83             :     { "POIKATEGORIE", VISUM_POICATEGORY },
      84             :     { "NR", VISUM_NO } // must be the last one
      85             : };
      86             : 
      87             : 
      88             : 
      89             : StringBijection<NIImporter_VISUM::VISUM_KEY> NIImporter_VISUM::KEYS(NIImporter_VISUM::KEYS_DE, VISUM_NO);
      90             : 
      91             : // ===========================================================================
      92             : // method definitions
      93             : // ===========================================================================
      94             : // ---------------------------------------------------------------------------
      95             : // static methods (interface in this case)
      96             : // ---------------------------------------------------------------------------
      97             : void
      98        2224 : NIImporter_VISUM::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
      99             :     // check whether the option is set (properly)
     100        4448 :     if (!oc.isSet("visum-file")) {
     101        2216 :         return;
     102             :     }
     103             :     // build the handler
     104          16 :     NIImporter_VISUM loader(nb, oc.getString("visum-file"),
     105          24 :                             NBCapacity2Lanes(oc.getFloat("lanes-from-capacity.norm")),
     106          16 :                             oc.getBool("visum.use-type-priority"),
     107          32 :                             oc.getString("visum.language-file"));
     108           8 :     loader.load();
     109           8 : }
     110             : 
     111             : 
     112             : 
     113             : // ---------------------------------------------------------------------------
     114             : // loader methods
     115             : // ---------------------------------------------------------------------------
     116           8 : NIImporter_VISUM::NIImporter_VISUM(NBNetBuilder& nb,
     117             :                                    const std::string& file,
     118             :                                    NBCapacity2Lanes capacity2Lanes,
     119             :                                    bool useVisumPrio,
     120           8 :                                    const std::string& languageFile) :
     121           8 :     myNetBuilder(nb), myFileName(file),
     122           8 :     myCapacity2Lanes(capacity2Lanes), myUseVisumPrio(useVisumPrio) {
     123           8 :     if (languageFile != "") {
     124           0 :         loadLanguage(languageFile);
     125             :     }
     126             : 
     127             :     // the order of process is important!
     128             :     // set1
     129           8 :     addParser(KEYS.getString(VISUM_SYS), &NIImporter_VISUM::parse_VSysTypes);
     130           8 :     addParser(KEYS.getString(VISUM_LINKTYPE), &NIImporter_VISUM::parse_Types);
     131           8 :     addParser(KEYS.getString(VISUM_NODE), &NIImporter_VISUM::parse_Nodes);
     132           8 :     addParser(KEYS.getString(VISUM_DISTRICT), &NIImporter_VISUM::parse_Districts);
     133           8 :     addParser(KEYS.getString(VISUM_POINT), &NIImporter_VISUM::parse_Point);
     134             : 
     135             :     // set2
     136             :     // two types of "strecke"
     137           8 :     addParser(KEYS.getString(VISUM_LINK), &NIImporter_VISUM::parse_Edges);
     138           8 :     addParser(KEYS.getString(VISUM_EDGE), &NIImporter_VISUM::parse_Kante);
     139             : 
     140             :     // set3
     141          16 :     if (OptionsCont::getOptions().getBool("visum.no-connectors")) {
     142           8 :         addParser(KEYS.getString(VISUM_DISTRICT_CONNECTION), &NIImporter_VISUM::parse_Connectors);
     143             :     } else {
     144           0 :         addParser(KEYS.getString(VISUM_DISTRICT_CONNECTION), &NIImporter_VISUM::parse_Connectors_legacy);
     145             :     }
     146             :     // two types of "abbieger"
     147           8 :     addParser("ABBIEGEBEZIEHUNG", &NIImporter_VISUM::parse_Turns);
     148           8 :     addParser(KEYS.getString(VISUM_TURN), &NIImporter_VISUM::parse_Turns);
     149             : 
     150           8 :     addParser(KEYS.getString(VISUM_LINKPOLY), &NIImporter_VISUM::parse_EdgePolys);
     151           8 :     addParser("FAHRSTREIFEN", &NIImporter_VISUM::parse_Lanes);
     152           8 :     addParser(KEYS.getString(VISUM_SURFACEITEM), &NIImporter_VISUM::parse_PartOfArea);
     153             : 
     154             : 
     155             :     // set4
     156             :     // two types of lsa
     157           8 :     addParser("LSA", &NIImporter_VISUM::parse_TrafficLights);
     158           8 :     addParser("SIGNALANLAGE", &NIImporter_VISUM::parse_TrafficLights);
     159             :     // two types of knotenzulsa
     160           8 :     addParser("KNOTENZULSA", &NIImporter_VISUM::parse_NodesToTrafficLights);
     161           8 :     addParser("LSAZUKNOTEN", &NIImporter_VISUM::parse_NodesToTrafficLights);
     162           8 :     addParser("SIGNALANLAGEZUKNOTEN", &NIImporter_VISUM::parse_NodesToTrafficLights);
     163             :     // two types of signalgruppe
     164           8 :     addParser("LSASIGNALGRUPPE", &NIImporter_VISUM::parse_SignalGroups);
     165           8 :     addParser("SIGNALGRUPPE", &NIImporter_VISUM::parse_SignalGroups);
     166             :     // three types of ABBZULSASIGNALGRUPPE
     167           8 :     addParser("ABBZULSASIGNALGRUPPE", &NIImporter_VISUM::parse_TurnsToSignalGroups);
     168           8 :     addParser("SIGNALGRUPPEZUABBIEGER", &NIImporter_VISUM::parse_TurnsToSignalGroups);
     169           8 :     addParser("SIGNALGRUPPEZUFSABBIEGER", &NIImporter_VISUM::parse_TurnsToSignalGroups);
     170             : 
     171           8 :     addParser(KEYS.getString(VISUM_FACEITEM), &NIImporter_VISUM::parse_AreaSubPartElement);
     172             : 
     173             :     // two types of LSAPHASE
     174           8 :     addParser("LSAPHASE", &NIImporter_VISUM::parse_Phases);
     175           8 :     addParser("PHASE", &NIImporter_VISUM::parse_Phases);
     176             : 
     177           8 :     addParser("LSASIGNALGRUPPEZULSAPHASE", &NIImporter_VISUM::parse_SignalGroupsToPhases);
     178           8 :     addParser("FAHRSTREIFENABBIEGER", &NIImporter_VISUM::parse_LanesConnections);
     179             : 
     180           8 :     addParser(KEYS.getString(VISUM_STOPPOINT), &NIImporter_VISUM::parse_stopPoints);
     181           8 : }
     182             : 
     183             : 
     184           8 : NIImporter_VISUM::~NIImporter_VISUM() {
     185          25 :     for (NIVisumTL_Map::iterator j = myTLS.begin(); j != myTLS.end(); j++) {
     186          17 :         delete j->second;
     187             :     }
     188          24 : }
     189             : 
     190             : 
     191             : void
     192         232 : NIImporter_VISUM::addParser(const std::string& name, ParsingFunction function) {
     193             :     TypeParser p;
     194             :     p.name = name;
     195         232 :     p.function = function;
     196         232 :     p.position = -1;
     197         232 :     mySingleDataParsers.push_back(p);
     198         232 : }
     199             : 
     200             : 
     201             : void
     202           8 : NIImporter_VISUM::load() {
     203             :     // open the file
     204           8 :     if (!myLineReader.setFile(myFileName)) {
     205           0 :         throw ProcessError(TLF("Can not open visum-file '%'.", myFileName));
     206             :     }
     207             :     // scan the file for data positions
     208       15987 :     while (myLineReader.hasMore()) {
     209       15979 :         std::string line = myLineReader.readLine();
     210       15979 :         if (line.length() > 0 && line[0] == '$') {
     211             :             ParserVector::iterator i;
     212       28710 :             for (i = mySingleDataParsers.begin(); i != mySingleDataParsers.end(); i++) {
     213       55506 :                 std::string dataName = "$" + (*i).name + ":";
     214       37083 :                 if (line.substr(0, dataName.length()) == dataName) {
     215         159 :                     (*i).position = myLineReader.getPosition();
     216         159 :                     (*i).pattern = line.substr(dataName.length());
     217         318 :                     WRITE_MESSAGE("Found: " + dataName + " at line " + toString<int>(myLineReader.getLineNumber()));
     218             :                 }
     219             :             }
     220             :         }
     221             :     }
     222             :     // go through the parsers and process all entries
     223         240 :     for (ParserVector::iterator i = mySingleDataParsers.begin(); i != mySingleDataParsers.end(); i++) {
     224         232 :         if ((*i).position < 0) {
     225             :             // do not process using parsers for which no information was found
     226          73 :             continue;
     227             :         }
     228             :         // ok, the according information is stored in the file
     229         318 :         PROGRESS_BEGIN_MESSAGE("Parsing " + (*i).name);
     230             :         // reset the line reader and let it point to the begin of the according data field
     231         159 :         myLineReader.reinit();
     232         159 :         myLineReader.setPos((*i).position);
     233             :         // prepare the line parser
     234         318 :         myLineParser.reinit((*i).pattern);
     235             :         // read
     236             :         bool singleDataEndFound = false;
     237        3919 :         while (myLineReader.hasMore() && !singleDataEndFound) {
     238        3760 :             std::string line = myLineReader.readLine();
     239        3760 :             if (line.length() == 0 || line[0] == '*' || line[0] == '$') {
     240             :                 singleDataEndFound = true;
     241             :             } else {
     242        3601 :                 myLineParser.parseLine(line);
     243             :                 try {
     244        3601 :                     myCurrentID = "<unknown>";
     245        3601 :                     (this->*(*i).function)();
     246           0 :                 } catch (OutOfBoundsException&) {
     247           0 :                     WRITE_ERRORF(TL("Too short value line in % occurred."), (*i).name);
     248           0 :                 } catch (NumberFormatException&) {
     249           0 :                     WRITE_ERRORF(TL("A value in % should be numeric but is not (id='%')."), (*i).name, myCurrentID);
     250           0 :                 } catch (UnknownElement& e) {
     251           0 :                     WRITE_ERRORF(TL("One of the needed values ('%') is missing in %."), std::string(e.what()), (*i).name);
     252           0 :                 }
     253             :             }
     254             :         }
     255             :         // close single reader processing
     256         159 :         PROGRESS_DONE_MESSAGE();
     257             :     }
     258           8 :     myNetBuilder.getEdgeCont().reduceGeometries(POSITION_EPS);
     259             : 
     260             :     // build traffic lights
     261          25 :     for (NIVisumTL_Map::iterator j = myTLS.begin(); j != myTLS.end(); j++) {
     262          17 :         j->second->build(myNetBuilder.getEdgeCont(), myNetBuilder.getTLLogicCont());
     263             :     }
     264             :     // build district shapes
     265          38 :     for (std::map<NBDistrict*, PositionVector>::const_iterator k = myDistrictShapes.begin(); k != myDistrictShapes.end(); ++k) {
     266          30 :         (*k).first->addShape((*k).second);
     267             :     }
     268           8 : }
     269             : 
     270             : 
     271             : 
     272             : 
     273             : 
     274             : void
     275          44 : NIImporter_VISUM::parse_VSysTypes() {
     276         132 :     std::string name = myLineParser.know("VSysCode") ? myLineParser.get("VSysCode").c_str() : myLineParser.get(KEYS.getString(VISUM_CODE)).c_str();
     277         132 :     std::string type = myLineParser.know("VSysMode") ? myLineParser.get("VSysMode").c_str() : myLineParser.get(KEYS.getString(VISUM_TYP)).c_str();
     278          44 :     myVSysTypes[name] = type;
     279          44 : }
     280             : 
     281             : 
     282             : void
     283         800 : NIImporter_VISUM::parse_Types() {
     284             :     // get the id
     285        1600 :     myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
     286             :     // get the maximum speed
     287         800 :     double speed = getWeightedFloat2("v0-IV", KEYS.getString(VISUM_V0), "km/h");
     288         800 :     if (speed == 0) {
     289             :         // unlimited speed
     290           2 :         speed = 3600;
     291         798 :     } else if (speed < 0) {
     292           0 :         WRITE_ERROR("Type '" + myCurrentID + "' has speed " + toString(speed));
     293             :     }
     294             :     // get the permissions
     295         800 :     SVCPermissions permissions = getPermissions(KEYS.getString(VISUM_TYPES), true);
     296             :     // get the priority
     297         800 :     const int priority = 1000 - StringUtils::toInt(myLineParser.get(KEYS.getString(VISUM_RANK)));
     298             :     // try to retrieve the number of lanes
     299         800 :     const int numLanes = myCapacity2Lanes.get(getNamedFloat("Kap-IV", KEYS.getString(VISUM_CAPACITY)));
     300             :     // insert the type
     301         800 :     myNetBuilder.getTypeCont().insertEdgeType(myCurrentID, numLanes, speed / (double) 3.6, priority, permissions, LaneSpreadFunction::RIGHT,
     302             :             NBEdge::UNSPECIFIED_WIDTH, false, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_WIDTH, 0, 0, 0);
     303         800 :     myNetBuilder.getTypeCont().markEdgeTypeAsSet(myCurrentID, SUMO_ATTR_NUMLANES);
     304         800 :     myNetBuilder.getTypeCont().markEdgeTypeAsSet(myCurrentID, SUMO_ATTR_SPEED);
     305         800 :     myNetBuilder.getTypeCont().markEdgeTypeAsSet(myCurrentID, SUMO_ATTR_PRIORITY);
     306         800 :     myNetBuilder.getTypeCont().markEdgeTypeAsSet(myCurrentID, SUMO_ATTR_ONEWAY);
     307         800 :     myNetBuilder.getTypeCont().markEdgeTypeAsSet(myCurrentID, SUMO_ATTR_ALLOW);
     308         800 :     myNetBuilder.getTypeCont().markEdgeTypeAsSet(myCurrentID, SUMO_ATTR_SPREADTYPE);
     309         800 : }
     310             : 
     311             : 
     312             : void
     313         232 : NIImporter_VISUM::parse_Nodes() {
     314             :     // get the id
     315         464 :     myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
     316             :     // get the position
     317         232 :     double x = getNamedFloat(KEYS.getString(VISUM_XCOORD));
     318         232 :     double y = getNamedFloat(KEYS.getString(VISUM_YCOORD));
     319             :     Position pos(x, y);
     320         232 :     if (!NBNetBuilder::transformCoordinate(pos)) {
     321           0 :         WRITE_ERRORF(TL("Unable to project coordinates for node %."), myCurrentID);
     322             :         return;
     323             :     }
     324             :     // add to the list
     325         232 :     if (!myNetBuilder.getNodeCont().insert(myCurrentID, pos)) {
     326           0 :         WRITE_ERRORF(TL("Duplicate node occurred ('%')."), myCurrentID);
     327             :     }
     328             : }
     329             : 
     330             : 
     331             : void
     332          50 : NIImporter_VISUM::parse_Districts() {
     333             :     // get the id
     334         100 :     myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
     335             :     // get the information whether the source and the destination
     336             :     //  connections are weighted
     337             :     //bool sourcesWeighted = getWeightedBool("Proz_Q");
     338             :     //bool destWeighted = getWeightedBool("Proz_Z");
     339             :     // get the node information
     340          50 :     double x = getNamedFloat(KEYS.getString(VISUM_XCOORD));
     341          50 :     double y = getNamedFloat(KEYS.getString(VISUM_YCOORD));
     342             :     Position pos(x, y);
     343          50 :     if (!NBNetBuilder::transformCoordinate(pos, false)) {
     344           0 :         WRITE_ERRORF(TL("Unable to project coordinates for district %."), myCurrentID);
     345           0 :         return;
     346             :     }
     347             :     // build the district
     348          50 :     NBDistrict* district = new NBDistrict(myCurrentID, pos);
     349          50 :     if (!myNetBuilder.getDistrictCont().insert(district)) {
     350           0 :         WRITE_ERRORF(TL("Duplicate district occurred ('%')."), myCurrentID);
     351           0 :         delete district;
     352           0 :         return;
     353             :     }
     354          50 :     if (myLineParser.know(KEYS.getString(VISUM_SURFACEID))) {
     355          50 :         long long int flaecheID = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_SURFACEID)));
     356          50 :         myShapeDistrictMap[flaecheID] = district;
     357             :     }
     358             : }
     359             : 
     360             : 
     361             : void
     362          25 : NIImporter_VISUM::parse_Point() {
     363          25 :     long long int id = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_ID)));
     364          25 :     double x = StringUtils::toDouble(myLineParser.get(KEYS.getString(VISUM_XCOORD)));
     365          50 :     double y = StringUtils::toDouble(myLineParser.get(KEYS.getString(VISUM_YCOORD)));
     366             :     Position pos(x, y);
     367          25 :     if (!NBNetBuilder::transformCoordinate(pos, false)) {
     368           0 :         WRITE_ERRORF(TL("Unable to project coordinates for point %."), toString(id));
     369             :         return;
     370             :     }
     371          25 :     myPoints[id] = pos;
     372             : }
     373             : 
     374             : 
     375             : void
     376         462 : NIImporter_VISUM::parse_Edges() {
     377        1386 :     if (myLineParser.know(KEYS.getString(VISUM_TYPES)) && myLineParser.get(KEYS.getString(VISUM_TYPES)) == "") {
     378             :         // no vehicle allowed; don't add
     379         462 :         return;
     380             :     }
     381             :     // get the id
     382         924 :     myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
     383             :     // get the from- & to-node and validate them
     384         462 :     NBNode* from = getNamedNode("VonKnot", KEYS.getString(VISUM_FROMNODE));
     385         462 :     NBNode* to = getNamedNode("NachKnot", KEYS.getString(VISUM_TONODE));
     386         462 :     if (!checkNodes(from, to)) {
     387             :         return;
     388             :     }
     389             :     // get the type
     390         462 :     std::string type = myLineParser.know(KEYS.getString(VISUM_TYP)) ? myLineParser.get(KEYS.getString(VISUM_TYP)) : myLineParser.get(KEYS.getString(VISUM_TYPE));
     391             :     // get the speed
     392         462 :     double speed = myNetBuilder.getTypeCont().getEdgeTypeSpeed(type);
     393         924 :     if (!OptionsCont::getOptions().getBool("visum.use-type-speed")) {
     394             :         try {
     395         462 :             std::string speedS = myLineParser.know("v0-IV") ? myLineParser.get("v0-IV") : myLineParser.get(KEYS.getString(VISUM_V0));
     396         462 :             if (speedS.find("km/h") != std::string::npos) {
     397         104 :                 speedS = speedS.substr(0, speedS.find("km/h"));
     398             :             }
     399         462 :             speed = StringUtils::toDouble(speedS) / 3.6;
     400           0 :         } catch (OutOfBoundsException&) {}
     401             :     }
     402         462 :     if (speed <= 0) {
     403           0 :         speed = myNetBuilder.getTypeCont().getEdgeTypeSpeed(type);
     404             :     }
     405             : 
     406             :     // get the information whether the edge is a one-way
     407         462 :     bool oneway = myLineParser.know("Einbahn")
     408         462 :                   ? StringUtils::toBool(myLineParser.get("Einbahn"))
     409             :                   : true;
     410             :     // get the number of lanes
     411         462 :     int nolanes = myNetBuilder.getTypeCont().getEdgeTypeNumLanes(type);
     412         924 :     if (!OptionsCont::getOptions().getBool("visum.recompute-lane-number")) {
     413         924 :         if (!OptionsCont::getOptions().getBool("visum.use-type-laneno")) {
     414         924 :             if (myLineParser.know("Fahrstreifen")) {
     415           0 :                 nolanes = StringUtils::toInt(myLineParser.get("Fahrstreifen"));
     416         462 :             } else if (myLineParser.know(KEYS.getString(VISUM_NUMLANES))) {
     417         924 :                 nolanes = StringUtils::toInt(myLineParser.get(KEYS.getString(VISUM_NUMLANES)));
     418             :             }
     419             :         }
     420             :     } else {
     421           0 :         if (myLineParser.know(KEYS.getString(VISUM_CAPACITY))) {
     422           0 :             nolanes = myCapacity2Lanes.get(StringUtils::toDouble(myLineParser.get(KEYS.getString(VISUM_CAPACITY))));
     423           0 :         } else if (myLineParser.know("KAP-IV")) {
     424           0 :             nolanes = myCapacity2Lanes.get(StringUtils::toDouble(myLineParser.get("KAP-IV")));
     425             :         }
     426             :     }
     427             :     // check whether the id is already used
     428             :     //  (should be the opposite direction)
     429             :     bool oneway_checked = oneway;
     430         462 :     NBEdge* previous = myNetBuilder.getEdgeCont().retrieve(myCurrentID);
     431         462 :     if (previous != nullptr) {
     432         225 :         myCurrentID = '-' + myCurrentID;
     433         225 :         previous->setLaneSpreadFunction(LaneSpreadFunction::RIGHT);
     434             :         oneway_checked = false;
     435             :     }
     436         462 :     if (find(myTouchedEdges.begin(), myTouchedEdges.end(), myCurrentID) != myTouchedEdges.end()) {
     437             :         oneway_checked = false;
     438             :     }
     439         462 :     std::string tmpid = '-' + myCurrentID;
     440         462 :     if (find(myTouchedEdges.begin(), myTouchedEdges.end(), tmpid) != myTouchedEdges.end()) {
     441           0 :         previous = myNetBuilder.getEdgeCont().retrieve(tmpid);
     442           0 :         if (previous != nullptr) {
     443           0 :             previous->setLaneSpreadFunction(LaneSpreadFunction::RIGHT);
     444             :         }
     445             :         oneway_checked = false;
     446             :     }
     447         462 :     std::string name = StringUtils::latin1_to_utf8(myLineParser.get(KEYS.getString(VISUM_NAME)));
     448             :     // add the edge
     449         462 :     const SVCPermissions permissions = getPermissions(KEYS.getString(VISUM_TYPES), false, myNetBuilder.getTypeCont().getEdgeTypePermissions(type));
     450         462 :     int prio = myUseVisumPrio ? myNetBuilder.getTypeCont().getEdgeTypePriority(type) : -1;
     451         462 :     if (nolanes != 0 && speed != 0) {
     452         450 :         LaneSpreadFunction lsf = oneway_checked ? LaneSpreadFunction::CENTER : LaneSpreadFunction::RIGHT;
     453             :         NBEdge* e = new NBEdge(myCurrentID, from, to, type, speed, NBEdge::UNSPECIFIED_FRICTION, nolanes, prio,
     454         450 :                                NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, lsf, name);
     455         450 :         e->setPermissions(permissions);
     456         450 :         if (!myNetBuilder.getEdgeCont().insert(e)) {
     457           0 :             delete e;
     458           0 :             WRITE_ERRORF(TL("Duplicate edge occurred ('%')."), myCurrentID);
     459             :         }
     460             :     }
     461         462 :     myTouchedEdges.push_back(myCurrentID);
     462             :     // nothing more to do, when the edge is a one-way street
     463         462 :     if (oneway) {
     464             :         return;
     465             :     }
     466             :     // add the opposite edge
     467           0 :     myCurrentID = '-' + myCurrentID;
     468           0 :     if (nolanes != 0 && speed != 0) {
     469           0 :         LaneSpreadFunction lsf = oneway_checked ? LaneSpreadFunction::CENTER : LaneSpreadFunction::RIGHT;
     470             :         NBEdge* e = new NBEdge(myCurrentID, from, to, type, speed, NBEdge::UNSPECIFIED_FRICTION, nolanes, prio,
     471           0 :                                NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, lsf, name);
     472           0 :         e->setPermissions(permissions);
     473           0 :         if (!myNetBuilder.getEdgeCont().insert(e)) {
     474           0 :             delete e;
     475           0 :             WRITE_ERRORF(TL("Duplicate edge occurred ('%')."), myCurrentID);
     476             :         }
     477             :     }
     478           0 :     myTouchedEdges.push_back(myCurrentID);
     479             : }
     480             : 
     481             : 
     482             : void
     483          30 : NIImporter_VISUM::parse_Kante() {
     484          30 :     long long int id = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_ID)));
     485          30 :     long long int from = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_FROMPOINTID)));
     486          30 :     long long int to = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_TOPOINTID)));
     487          30 :     myEdges[id] = std::make_pair(from, to);
     488          30 : }
     489             : 
     490             : 
     491             : void
     492          30 : NIImporter_VISUM::parse_PartOfArea() {
     493          30 :     long long int flaecheID = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_SURFACEID)));
     494          30 :     long long int flaechePartID = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_FACEID)));
     495          30 :     if (mySubPartsAreas.find(flaechePartID) == mySubPartsAreas.end()) {
     496          60 :         mySubPartsAreas[flaechePartID] = std::vector<long long int>();
     497             :     }
     498          30 :     mySubPartsAreas[flaechePartID].push_back(flaecheID);
     499          30 : }
     500             : 
     501             : 
     502             : void
     503           0 : NIImporter_VISUM::parse_Connectors() {
     504             :     // get the source district
     505           0 :     std::string bez = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_SOURCE_DISTRICT)));
     506             :     // get the destination node
     507           0 :     NBNode* dest = getNamedNode(KEYS.getString(VISUM_FROMNODENO));
     508           0 :     if (dest == nullptr) {
     509             :         return;
     510             :     }
     511             :     // get the weight of the connection
     512             :     double proz = 1;
     513           0 :     if (myLineParser.know("Proz") || myLineParser.know("Proz(IV)")) {
     514           0 :         proz = getNamedFloat("Proz", "Proz(IV)") / 100;
     515             :     }
     516             :     // get the information whether this is a sink or a source
     517           0 :     std::string dir = myLineParser.get(KEYS.getString(VISUM_DIRECTION));
     518           0 :     if (dir.length() == 0) {
     519           0 :         dir = KEYS.getString(VISUM_ORIGIN) + KEYS.getString(VISUM_DESTINATION);
     520             :     }
     521             :     // build the source when needed
     522           0 :     if (dir.find(KEYS.getString(VISUM_ORIGIN)) != std::string::npos) {
     523           0 :         for (NBEdge* edge : dest->getOutgoingEdges()) {
     524           0 :             myNetBuilder.getDistrictCont().addSource(bez, edge, proz);
     525             :         }
     526             :     }
     527             :     // build the sink when needed
     528           0 :     if (dir.find(KEYS.getString(VISUM_DESTINATION)) != std::string::npos) {
     529           0 :         for (NBEdge* edge : dest->getIncomingEdges()) {
     530           0 :             myNetBuilder.getDistrictCont().addSink(bez, edge, proz);
     531             :         }
     532             :     }
     533             : }
     534             : 
     535             : 
     536             : 
     537             : void
     538           0 : NIImporter_VISUM::parse_Connectors_legacy() {
     539             :     // get the source district
     540           0 :     std::string bez = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_SOURCE_DISTRICT)));
     541             :     // get the destination node
     542           0 :     NBNode* dest = getNamedNode(KEYS.getString(VISUM_FROMNODENO));
     543           0 :     if (dest == nullptr) {
     544             :         return;
     545             :     }
     546             :     // get the weight of the connection
     547             :     double proz = 1;
     548           0 :     if (myLineParser.know("Proz") || myLineParser.know("Proz(IV)")) {
     549           0 :         proz = getNamedFloat("Proz", "Proz(IV)") / 100;
     550             :     }
     551             :     // get the duration to wait (unused)
     552             : //     double retard = -1;
     553             : //     if (myLineParser.know("t0-IV")) {
     554             : //         retard = getNamedFloat("t0-IV", -1);
     555             : //     }
     556             :     // get the type;
     557             :     //  use a standard type with a large speed when a type is not given
     558             : 
     559           0 :     std::string type = myLineParser.know(KEYS.getString(VISUM_TYP))
     560           0 :                        ? NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_TYP)))
     561           0 :                        : "";
     562             :     // add the connectors as an edge
     563           0 :     std::string id = bez + "-" + dest->getID();
     564             :     // get the information whether this is a sink or a source
     565           0 :     std::string dir = myLineParser.get(KEYS.getString(VISUM_DIRECTION));
     566           0 :     if (dir.length() == 0) {
     567           0 :         dir = KEYS.getString(VISUM_ORIGIN) + KEYS.getString(VISUM_DESTINATION);
     568             :     }
     569             :     // build the source when needed
     570           0 :     if (dir.find(KEYS.getString(VISUM_ORIGIN)) != std::string::npos) {
     571             :         const EdgeVector& edges = dest->getOutgoingEdges();
     572             :         bool hasContinuation = false;
     573           0 :         for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
     574           0 :             if (!(*i)->isMacroscopicConnector()) {
     575             :                 hasContinuation = true;
     576             :             }
     577             :         }
     578           0 :         if (!hasContinuation) {
     579             :             // obviously, there is no continuation on the net
     580           0 :             WRITE_WARNINGF(TL("Incoming connector '%' will not be build - would be not connected to network."), id);
     581             :         } else {
     582           0 :             NBNode* src = buildDistrictNode(bez, dest, true);
     583           0 :             if (src == nullptr) {
     584           0 :                 WRITE_ERRORF(TL("The district '%' could not be built."), bez);
     585           0 :                 return;
     586             :             }
     587             :             NBEdge* edge = new NBEdge(id, src, dest, "VisumConnector",
     588           0 :                                       OptionsCont::getOptions().getFloat("visum.connector-speeds"), NBEdge::UNSPECIFIED_FRICTION,
     589           0 :                                       OptionsCont::getOptions().getInt("visum.connectors-lane-number"),
     590             :                                       -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET,
     591           0 :                                       LaneSpreadFunction::RIGHT, "");
     592             :             edge->setAsMacroscopicConnector();
     593           0 :             if (!myNetBuilder.getEdgeCont().insert(edge)) {
     594           0 :                 WRITE_ERRORF(TL("A duplicate edge id occurred (ID='%')."), id);
     595           0 :                 return;
     596             :             }
     597           0 :             edge = myNetBuilder.getEdgeCont().retrieve(id);
     598           0 :             if (edge != nullptr) {
     599           0 :                 myNetBuilder.getDistrictCont().addSource(bez, edge, proz);
     600             :             }
     601             :         }
     602             :     }
     603             :     // build the sink when needed
     604           0 :     if (dir.find(KEYS.getString(VISUM_DESTINATION)) != std::string::npos) {
     605             :         const EdgeVector& edges = dest->getIncomingEdges();
     606             :         bool hasPredeccessor = false;
     607           0 :         for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
     608           0 :             if (!(*i)->isMacroscopicConnector()) {
     609             :                 hasPredeccessor = true;
     610             :             }
     611             :         }
     612           0 :         if (!hasPredeccessor) {
     613             :             // obviously, the network is not connected to this node
     614           0 :             WRITE_WARNINGF(TL("Outgoing connector '%' will not be build - would be not connected to network."), id);
     615             :         } else {
     616           0 :             NBNode* src = buildDistrictNode(bez, dest, false);
     617           0 :             if (src == nullptr) {
     618           0 :                 WRITE_ERRORF(TL("The district '%' could not be built."), bez);
     619           0 :                 return;
     620             :             }
     621           0 :             id = "-" + id;
     622             :             NBEdge* edge = new NBEdge(id, dest, src, "VisumConnector",
     623           0 :                                       OptionsCont::getOptions().getFloat("visum.connector-speeds"), NBEdge::UNSPECIFIED_FRICTION,
     624           0 :                                       OptionsCont::getOptions().getInt("visum.connectors-lane-number"),
     625             :                                       -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET,
     626           0 :                                       LaneSpreadFunction::RIGHT, "");
     627             :             edge->setAsMacroscopicConnector();
     628           0 :             if (!myNetBuilder.getEdgeCont().insert(edge)) {
     629           0 :                 WRITE_ERRORF(TL("A duplicate edge id occurred (ID='%')."), id);
     630           0 :                 return;
     631             :             }
     632           0 :             edge = myNetBuilder.getEdgeCont().retrieve(id);
     633           0 :             if (edge != nullptr) {
     634           0 :                 myNetBuilder.getDistrictCont().addSink(bez, edge, proz);
     635             :             }
     636             :         }
     637             :     }
     638             : }
     639             : 
     640             : 
     641             : void
     642         804 : NIImporter_VISUM::parse_Turns() {
     643        2412 :     if (myLineParser.know(KEYS.getString(VISUM_TYPES)) && myLineParser.get(KEYS.getString(VISUM_TYPES)) == "") {
     644             :         // no vehicle allowed; don't add
     645          96 :         return;
     646             :     }
     647             :     // retrieve the nodes
     648         756 :     NBNode* from = getNamedNode("VonKnot", KEYS.getString(VISUM_FROMNODE));
     649         756 :     NBNode* via = getNamedNode("UeberKnot", KEYS.getString(VISUM_VIANODENO));
     650         756 :     NBNode* to = getNamedNode("NachKnot", KEYS.getString(VISUM_TONODE));
     651         756 :     if (from == nullptr || via == nullptr || to == nullptr) {
     652             :         return;
     653             :     }
     654             :     // all nodes are known
     655        1512 :     std::string type = myLineParser.know("VSysCode")
     656             :                        ? myLineParser.get("VSysCode")
     657         756 :                        : myLineParser.get(KEYS.getString(VISUM_TYPES));
     658         756 :     if (myVSysTypes.find(type) != myVSysTypes.end() && myVSysTypes.find(type)->second == "IV") {
     659             :         // try to set the turning definition
     660         416 :         NBEdge* src = from->getConnectionTo(via);
     661         416 :         NBEdge* dest = via->getConnectionTo(to);
     662             :         // check both
     663         416 :         if (src == nullptr) {
     664          48 :             if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) {
     665           0 :                 WRITE_WARNINGF(TL("There is no edge from node '%' to node '%'."), from->getID(), via->getID());
     666             :             }
     667          24 :             return;
     668             :         }
     669         392 :         if (dest == nullptr) {
     670          48 :             if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) {
     671           0 :                 WRITE_WARNINGF(TL("There is no edge from node '%' to node '%'."), via->getID(), to->getID());
     672             :             }
     673          24 :             return;
     674             :         }
     675             :         // both edges found
     676             :         //  set them into the edge
     677         368 :         src->addEdge2EdgeConnection(dest);
     678             :     }
     679             : }
     680             : 
     681             : 
     682             : void
     683         351 : NIImporter_VISUM::parse_EdgePolys() {
     684             :     // get the from- & to-node and validate them
     685         351 :     NBNode* from = getNamedNode("VonKnot", KEYS.getString(VISUM_FROMNODE));
     686         351 :     NBNode* to = getNamedNode("NachKnot", KEYS.getString(VISUM_TONODE));
     687         351 :     if (!checkNodes(from, to)) {
     688           0 :         return;
     689             :     }
     690             :     bool failed = false;
     691             :     int index;
     692             :     double x, y;
     693             :     try {
     694         351 :         index = StringUtils::toInt(myLineParser.get(KEYS.getString(VISUM_INDEX)));
     695         351 :         x = getNamedFloat(KEYS.getString(VISUM_XCOORD));
     696         351 :         y = getNamedFloat(KEYS.getString(VISUM_YCOORD));
     697           0 :     } catch (NumberFormatException&) {
     698           0 :         WRITE_ERRORF(TL("Error in geometry description from node '%' to node '%'."), from->getID(), to->getID());
     699             :         return;
     700           0 :     }
     701             :     Position pos(x, y);
     702         351 :     if (!NBNetBuilder::transformCoordinate(pos)) {
     703           0 :         WRITE_ERRORF(TL("Unable to project coordinates for node '%'."), from->getID());
     704             :         return;
     705             :     }
     706         351 :     NBEdge* e = from->getConnectionTo(to);
     707         351 :     if (e != nullptr) {
     708         351 :         e->addGeometryPoint(index, pos);
     709             :     } else {
     710             :         failed = true;
     711             :     }
     712         351 :     e = to->getConnectionTo(from);
     713         351 :     if (e != nullptr) {
     714         351 :         e->addGeometryPoint(-index, pos);
     715             :         failed = false;
     716             :     }
     717             :     // check whether the operation has failed
     718           0 :     if (failed) {
     719           0 :         if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) {
     720           0 :             WRITE_WARNINGF(TL("There is no edge from node '%' to node '%'."), from->getID(), to->getID());
     721             :         }
     722             :     }
     723             : }
     724             : 
     725             : 
     726             : void
     727         228 : NIImporter_VISUM::parse_Lanes() {
     728             :     // The base number of lanes for the edge was already defined in STRECKE
     729             :     // this refines lane specific attribute (width) and optionally introduces splits for additional lanes
     730             :     // It is permitted for KNOTNR to be 0
     731             :     //
     732             :     // get the edge
     733         228 :     NBEdge* baseEdge = getNamedEdge(KEYS.getString(VISUM_LINKNO));
     734         228 :     if (baseEdge == nullptr) {
     735         220 :         return;
     736             :     }
     737             :     NBEdge* edge = baseEdge;
     738             :     // get the node
     739         228 :     NBNode* node = getNamedNodeSecure("KNOTNR");
     740         228 :     if (node == nullptr) {
     741             :         node = edge->getToNode();
     742             :     } else {
     743         228 :         edge = getNamedEdgeContinuating(KEYS.getString(VISUM_LINKNO), node);
     744             :     }
     745             :     // check
     746         228 :     if (edge == nullptr) {
     747             :         return;
     748             :     }
     749             :     // get the lane
     750         228 :     std::string laneS = myLineParser.know("FSNR")
     751         294 :                         ? NBHelpers::normalIDRepresentation(myLineParser.get("FSNR"))
     752         651 :                         : NBHelpers::normalIDRepresentation(myLineParser.get("NR"));
     753             :     int lane = -1;
     754             :     try {
     755         228 :         lane = StringUtils::toInt(laneS);
     756           0 :     } catch (NumberFormatException&) {
     757           0 :         WRITE_ERRORF(TL("A lane number for edge '%' is not numeric (%)."), edge->getID(), laneS);
     758             :         return;
     759           0 :     }
     760         228 :     lane -= 1;
     761         228 :     if (lane < 0) {
     762           0 :         WRITE_ERRORF(TL("A lane number for edge '%' is not positive (%)."), edge->getID(), laneS);
     763           0 :         return;
     764             :     }
     765             :     // get the direction
     766         456 :     std::string dirS = NBHelpers::normalIDRepresentation(myLineParser.get("RICHTTYP"));
     767             :     int prevLaneNo = baseEdge->getNumLanes();
     768         335 :     if ((dirS == "1" && !(node->hasIncoming(edge))) || (dirS == "0" && !(node->hasOutgoing(edge)))) {
     769             :         // get the last part of the turnaround direction
     770         134 :         NBEdge* cand = getReversedContinuating(edge, node);
     771         134 :         if (cand) {
     772             :             edge = cand;
     773             :         }
     774             :     }
     775             :     // get the length
     776         456 :     std::string lengthS = NBHelpers::normalIDRepresentation(myLineParser.get("LAENGE"));
     777         228 :     double length = -1;
     778             :     try {
     779         228 :         length = StringUtils::toDouble(lengthS);
     780           0 :     } catch (NumberFormatException&) {
     781           0 :         WRITE_ERRORF(TL("A lane length for edge '%' is not numeric (%)."), edge->getID(), lengthS);
     782             :         return;
     783           0 :     }
     784         228 :     if (length < 0) {
     785           0 :         WRITE_ERRORF(TL("A lane length for edge '%' is not positive (%)."), edge->getID(), lengthS);
     786           0 :         return;
     787             :     }
     788             :     //
     789         228 :     if (dirS == "1") {
     790         136 :         lane -= prevLaneNo;
     791             :     }
     792             :     //
     793         228 :     if (length == 0) {
     794         228 :         if ((int) edge->getNumLanes() > lane) {
     795             :             // ok, we know this already...
     796             :             return;
     797             :         }
     798             :         // increment by one
     799           8 :         edge->incLaneNo(1);
     800             :     } else {
     801             :         // check whether this edge already has been created
     802           0 :         if (isSplitEdge(edge, node)) {
     803           0 :             if (edge->getID().substr(edge->getID().find('_')) == "_" + toString(length) + "_" + node->getID()) {
     804           0 :                 if ((int) edge->getNumLanes() > lane) {
     805             :                     // ok, we know this already...
     806           0 :                     return;
     807             :                 }
     808             :                 // increment by one
     809           0 :                 edge->incLaneNo(1);
     810             :                 return;
     811             :             }
     812             :         }
     813             :         // nope, we have to split the edge...
     814             :         //  maybe it is not the proper edge to split - VISUM seems not to sort the splits...
     815             :         bool mustRecheck = true;
     816             :         double seenLength = 0;
     817           0 :         while (mustRecheck) {
     818           0 :             if (isSplitEdge(edge, node)) {
     819             :                 // ok, we have a previously created edge here
     820           0 :                 std::string sub = edge->getID();
     821           0 :                 sub = sub.substr(sub.rfind('_', sub.rfind('_') - 1));
     822           0 :                 sub = sub.substr(1, sub.find('_', 1) - 1);
     823           0 :                 double dist = StringUtils::toDouble(sub);
     824           0 :                 if (dist < length) {
     825           0 :                     seenLength += edge->getLength();
     826           0 :                     if (dirS == "1") {
     827             :                         // incoming -> move back
     828           0 :                         edge = edge->getFromNode()->getIncomingEdges()[0];
     829             :                     } else {
     830             :                         // outgoing -> move forward
     831           0 :                         edge = edge->getToNode()->getOutgoingEdges()[0];
     832             :                     }
     833             :                 } else {
     834             :                     mustRecheck = false;
     835             :                 }
     836             :             } else {
     837             :                 // we have the center edge - do not continue...
     838             :                 mustRecheck = false;
     839             :             }
     840             :         }
     841             :         // compute position
     842             :         Position p;
     843           0 :         double useLength = length - seenLength;
     844           0 :         useLength = edge->getLength() - useLength;
     845           0 :         if (useLength < 0 || useLength > edge->getLength()) {
     846           0 :             WRITE_WARNINGF(TL("Could not find split position for edge '%'."), edge->getID());
     847             :             return;
     848             :         }
     849           0 :         std::string edgeID = edge->getID();
     850           0 :         p = edge->getGeometry().positionAtOffset(useLength);
     851           0 :         if (isSplitEdge(edge, node)) {
     852           0 :             edgeID = edgeID.substr(0, edgeID.find('_'));
     853             :         }
     854           0 :         NBNode* rn = new NBNode(edgeID + "_" +  toString((int) length) + "_" + node->getID(), p);
     855           0 :         if (!myNetBuilder.getNodeCont().insert(rn)) {
     856           0 :             throw ProcessError(TL("Ups - could not insert node!"));
     857             :         }
     858           0 :         std::string nid = edgeID + "_" +  toString((int) length) + "_" + node->getID();
     859           0 :         myNetBuilder.getEdgeCont().splitAt(myNetBuilder.getDistrictCont(), edge, useLength, rn,
     860           0 :                                            edge->getID(), nid, edge->getNumLanes() + 0, edge->getNumLanes() + 1);
     861             :         // old edge is deleted and a new edge with the same name created
     862           0 :         edge = myNetBuilder.getEdgeCont().retrieve(edgeID);
     863           0 :         NBEdge* nedge = myNetBuilder.getEdgeCont().retrieve(nid);
     864           0 :         nedge = nedge->getToNode()->getOutgoingEdges()[0];
     865           0 :         while (isSplitEdge(edge, node)) {
     866             :             assert(nedge->getToNode()->getOutgoingEdges().size() > 0);
     867           0 :             nedge->incLaneNo(1);
     868           0 :             nedge = nedge->getToNode()->getOutgoingEdges()[0];
     869             :         }
     870             :     }
     871             : }
     872             : 
     873             : 
     874             : void
     875          17 : NIImporter_VISUM::parse_TrafficLights() {
     876          34 :     myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
     877          17 :     const SUMOTime cycleTime = TIME2STEPS(getWeightedFloat2("Umlaufzeit", "UMLZEIT", "s"));
     878          17 :     const SUMOTime intermediateTime = TIME2STEPS(getWeightedFloat2("StdZwischenzeit", "STDZWZEIT", "s"));
     879          17 :     bool phaseBased = myLineParser.know("PhasenBasiert")
     880          17 :                       ? StringUtils::toBool(myLineParser.get("PhasenBasiert"))
     881             :                       : false;
     882          85 :     const SUMOTime offset = myLineParser.know("ZEITVERSATZ") ? TIME2STEPS(getWeightedFloat("ZEITVERSATZ", "s")) : 0;
     883             :     // add to the list
     884          17 :     myTLS[myCurrentID] = new NIVisumTL(myCurrentID, cycleTime, offset, intermediateTime, phaseBased);
     885          17 : }
     886             : 
     887             : 
     888             : void
     889          17 : NIImporter_VISUM::parse_NodesToTrafficLights() {
     890          34 :     std::string node = myLineParser.get("KnotNr").c_str();
     891          17 :     if (node == "0") {
     892             :         // this is a dummy value which cannot be assigned to
     893             :         return;
     894             :     }
     895          34 :     std::string trafficLight = myLineParser.get("LsaNr").c_str();
     896             :     // add to the list
     897          17 :     NBNode* n = myNetBuilder.getNodeCont().retrieve(node);
     898             :     auto tlIt = myTLS.find(trafficLight);
     899          17 :     if (n != nullptr && tlIt != myTLS.end()) {
     900          34 :         tlIt->second->addNode(n);
     901             :     } else {
     902           0 :         WRITE_ERROR("Could not assign" + std::string(n == nullptr ? " missing" : "") + " node '" + node
     903             :                     + "' to" + std::string(tlIt == myTLS.end() ? " missing" : "") + " traffic light '" + trafficLight + "'");
     904             :     }
     905             : }
     906             : 
     907             : 
     908             : void
     909          72 : NIImporter_VISUM::parse_SignalGroups() {
     910         144 :     myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
     911         144 :     std::string LSAid = NBHelpers::normalIDRepresentation(myLineParser.get("LsaNr"));
     912          72 :     const SUMOTime startTime = TIME2STEPS(getNamedFloat("GzStart", "GRUENANF"));
     913          72 :     const SUMOTime endTime = TIME2STEPS(getNamedFloat("GzEnd", "GRUENENDE"));
     914         192 :     const SUMOTime yellowTime = myLineParser.know("GELB") ? TIME2STEPS(getNamedFloat("GELB")) : -1;
     915             :     // add to the list
     916          72 :     if (myTLS.find(LSAid) == myTLS.end()) {
     917           0 :         WRITE_ERRORF(TL("Could not find TLS '%' for setting the signal group."), LSAid);
     918             :         return;
     919             :     }
     920          72 :     myTLS.find(LSAid)->second->addSignalGroup(myCurrentID, startTime, endTime, yellowTime);
     921             : }
     922             : 
     923             : 
     924             : void
     925         184 : NIImporter_VISUM::parse_TurnsToSignalGroups() {
     926             :     // get the id
     927         368 :     std::string SGid = getNamedString("SGNR", "SIGNALGRUPPENNR");
     928         368 :     if (!myLineParser.know("LsaNr")) {
     929             :         /// XXX could be retrieved from context
     930           0 :         WRITE_WARNING(TL("Ignoring SIGNALGRUPPEZUFSABBIEGER because LsaNr is not known"));
     931             :         return;
     932             :     }
     933         184 :     std::string LSAid = getNamedString("LsaNr");
     934             :     // nodes
     935         184 :     NBNode* from = myLineParser.know("VonKnot") ? getNamedNode("VonKnot") : nullptr;
     936         184 :     NBNode* via = myLineParser.know("KNOTNR")
     937         368 :                   ? getNamedNode("KNOTNR")
     938         232 :                   : getNamedNode("UeberKnot", "UeberKnotNr");
     939         184 :     NBNode* to = myLineParser.know("NachKnot") ? getNamedNode("NachKnot") : nullptr;
     940             :     // edges
     941             :     NBEdge* edg1 = nullptr;
     942             :     NBEdge* edg2 = nullptr;
     943         184 :     if (from == nullptr && to == nullptr) {
     944         184 :         edg1 = getNamedEdgeContinuating("VONSTRNR", via);
     945         368 :         edg2 = getNamedEdgeContinuating("NACHSTRNR", via);
     946             :     } else {
     947           0 :         edg1 = getEdge(from, via);
     948           0 :         edg2 = getEdge(via, to);
     949             :     }
     950             :     // add to the list
     951         184 :     NIVisumTL::SignalGroup& SG = myTLS.find(LSAid)->second->getSignalGroup(SGid);
     952         184 :     if (edg1 != nullptr && edg2 != nullptr) {
     953         184 :         if (!via->hasIncoming(edg1)) {
     954             :             std::string sid;
     955         163 :             if (edg1->getID()[0] == '-') {
     956           0 :                 sid = edg1->getID().substr(1);
     957             :             } else {
     958         326 :                 sid = "-" + edg1->getID();
     959             :             }
     960         163 :             if (sid.find('_') != std::string::npos) {
     961           0 :                 sid = sid.substr(0, sid.find('_'));
     962             :             }
     963         163 :             edg1 = getNamedEdgeContinuating(myNetBuilder.getEdgeCont().retrieve(sid),  via);
     964             :         }
     965         184 :         if (!via->hasOutgoing(edg2)) {
     966             :             std::string sid;
     967          21 :             if (edg2->getID()[0] == '-') {
     968           0 :                 sid = edg2->getID().substr(1);
     969             :             } else {
     970          42 :                 sid = "-" + edg2->getID();
     971             :             }
     972          21 :             if (sid.find('_') != std::string::npos) {
     973           0 :                 sid = sid.substr(0, sid.find('_'));
     974             :             }
     975          21 :             edg2 = getNamedEdgeContinuating(myNetBuilder.getEdgeCont().retrieve(sid),  via);
     976             :         }
     977         368 :         SG.connections().push_back(NBConnection(edg1, edg2));
     978             :     }
     979             : }
     980             : 
     981             : 
     982             : void
     983          30 : NIImporter_VISUM::parse_AreaSubPartElement() {
     984          30 :     long long int id = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_FACEID)));
     985          30 :     long long int edgeid = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_EDGEID)));
     986          30 :     if (myEdges.find(edgeid) == myEdges.end()) {
     987           0 :         WRITE_ERROR(TL("Unknown edge in TEILFLAECHENELEMENT"));
     988           0 :         return;
     989             :     }
     990          30 :     std::string dir = myLineParser.get(KEYS.getString(VISUM_DIRECTION));
     991             : // get index (unused)
     992             : //     std::string indexS = NBHelpers::normalIDRepresentation(myLineParser.get("INDEX"));
     993             : //     int index = -1;
     994             : //     try {
     995             : //         index = StringUtils::toInt(indexS) - 1;
     996             : //     } catch (NumberFormatException&) {
     997             : //         WRITE_ERRORF(TL("An index for a TEILFLAECHENELEMENT is not numeric (id='%')."), toString(id));
     998             : //         return;
     999             : //     }
    1000          30 :     PositionVector shape;
    1001          30 :     shape.push_back(myPoints[myEdges[edgeid].first]);
    1002          30 :     shape.push_back(myPoints[myEdges[edgeid].second]);
    1003          30 :     if (dir.length() > 0 && dir[0] == '1') {
    1004           0 :         shape = shape.reverse();
    1005             :     }
    1006          30 :     if (mySubPartsAreas.find(id) == mySubPartsAreas.end()) {
    1007           0 :         WRITE_ERRORF(TL("Unknown are for area part '%'."), myCurrentID);
    1008             :         return;
    1009             :     }
    1010             : 
    1011             :     const std::vector<long long int>& areas = mySubPartsAreas.find(id)->second;
    1012          60 :     for (std::vector<long long int>::const_iterator i = areas.begin(); i != areas.end(); ++i) {
    1013          30 :         NBDistrict* d = myShapeDistrictMap[*i];
    1014          30 :         if (d == nullptr) {
    1015           0 :             continue;
    1016             :         }
    1017          30 :         if (myDistrictShapes.find(d) == myDistrictShapes.end()) {
    1018          60 :             myDistrictShapes[d] = PositionVector();
    1019             :         }
    1020          30 :         if (dir.length() > 0 && dir[0] == '1') {
    1021           0 :             myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].second]);
    1022           0 :             myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].first]);
    1023             :         } else {
    1024          30 :             myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].first]);
    1025          30 :             myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].second]);
    1026             :         }
    1027             :     }
    1028          30 : }
    1029             : 
    1030             : 
    1031             : void
    1032           0 : NIImporter_VISUM::parse_Phases() {
    1033             :     // get the id
    1034           0 :     const std::string phaseid = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
    1035           0 :     const std::string LSAid = NBHelpers::normalIDRepresentation(myLineParser.get("LsaNr"));
    1036           0 :     const SUMOTime startTime = TIME2STEPS(getNamedFloat("GzStart", "GRUENANF"));
    1037           0 :     const SUMOTime endTime = TIME2STEPS(getNamedFloat("GzEnd", "GRUENENDE"));
    1038           0 :     const SUMOTime yellowTime = myLineParser.know("GELB") ? TIME2STEPS(getNamedFloat("GELB")) : -1;
    1039           0 :     myTLS.find(LSAid)->second->addPhase(phaseid, startTime, endTime, yellowTime);
    1040           0 : }
    1041             : 
    1042             : 
    1043           0 : void NIImporter_VISUM::parse_SignalGroupsToPhases() {
    1044             :     // get the id
    1045           0 :     std::string Phaseid = NBHelpers::normalIDRepresentation(myLineParser.get("PsNr"));
    1046           0 :     std::string LSAid = NBHelpers::normalIDRepresentation(myLineParser.get("LsaNr"));
    1047           0 :     std::string SGid = NBHelpers::normalIDRepresentation(myLineParser.get("SGNR"));
    1048             :     // insert
    1049           0 :     NIVisumTL* LSA = myTLS.find(LSAid)->second;
    1050           0 :     NIVisumTL::SignalGroup& SG = LSA->getSignalGroup(SGid);
    1051           0 :     NIVisumTL::Phase* PH = LSA->getPhases().find(Phaseid)->second;
    1052           0 :     SG.phases()[Phaseid] = PH;
    1053           0 : }
    1054             : 
    1055             : 
    1056         178 : void NIImporter_VISUM::parse_LanesConnections() {
    1057             :     NBNode* node = nullptr;
    1058             :     NBEdge* fromEdge = nullptr;
    1059             :     NBEdge* toEdge = nullptr;
    1060             :     // get the node and edges depending on network format
    1061         356 :     const std::string nodeID = getNamedString("KNOTNR", "KNOT");
    1062         178 :     if (nodeID == "0") {
    1063           0 :         fromEdge = getNamedEdge("VONSTRNR", "VONSTR");
    1064           0 :         toEdge = getNamedEdge("NACHSTRNR", "NACHSTR");
    1065           0 :         if (fromEdge == nullptr) {
    1066             :             return;
    1067             :         }
    1068             :         node = fromEdge->getToNode();
    1069           0 :         WRITE_WARNING(TL("Ignoring lane-to-lane connection (not yet implemented for this format version)"));
    1070           0 :         return;
    1071             :     } else {
    1072         356 :         node = getNamedNode("KNOTNR", "KNOT");
    1073         178 :         if (node  == nullptr) {
    1074             :             return;
    1075             :         }
    1076         356 :         fromEdge = getNamedEdgeContinuating("VONSTRNR", "VONSTR", node);
    1077         356 :         toEdge = getNamedEdgeContinuating("NACHSTRNR", "NACHSTR", node);
    1078             :     }
    1079         178 :     if (fromEdge == nullptr || toEdge == nullptr) {
    1080             :         return;
    1081             :     }
    1082             : 
    1083             :     int fromLaneOffset = 0;
    1084         178 :     if (!node->hasIncoming(fromEdge)) {
    1085             :         fromLaneOffset = fromEdge->getNumLanes();
    1086         156 :         fromEdge = getReversedContinuating(fromEdge, node);
    1087             :     } else {
    1088          22 :         fromEdge = getReversedContinuating(fromEdge, node);
    1089          44 :         NBEdge* tmp = myNetBuilder.getEdgeCont().retrieve(fromEdge->getID().substr(0, fromEdge->getID().find('_')));
    1090             :         fromLaneOffset = tmp->getNumLanes();
    1091             :     }
    1092             : 
    1093             :     int toLaneOffset = 0;
    1094         178 :     if (!node->hasOutgoing(toEdge)) {
    1095             :         toLaneOffset = toEdge->getNumLanes();
    1096          22 :         toEdge = getReversedContinuating(toEdge, node);
    1097             :     } else {
    1098         312 :         NBEdge* tmp = myNetBuilder.getEdgeCont().retrieve(toEdge->getID().substr(0, toEdge->getID().find('_')));
    1099             :         toLaneOffset = tmp->getNumLanes();
    1100             :     }
    1101             :     // get the from-lane
    1102         356 :     std::string fromLaneS = NBHelpers::normalIDRepresentation(myLineParser.get("VONFSNR"));
    1103             :     int fromLane = -1;
    1104             :     try {
    1105         178 :         fromLane = StringUtils::toInt(fromLaneS);
    1106           0 :     } catch (NumberFormatException&) {
    1107           0 :         WRITE_ERRORF(TL("A from-lane number for edge '%' is not numeric (%)."), fromEdge->getID(), fromLaneS);
    1108             :         return;
    1109           0 :     }
    1110         178 :     fromLane -= 1;
    1111         178 :     if (fromLane < 0) {
    1112           0 :         WRITE_ERRORF(TL("A from-lane number for edge '%' is not positive (%)."), fromEdge->getID(), fromLaneS);
    1113           0 :         return;
    1114             :     }
    1115             :     // get the from-lane
    1116         356 :     std::string toLaneS = NBHelpers::normalIDRepresentation(myLineParser.get("NACHFSNR"));
    1117             :     int toLane = -1;
    1118             :     try {
    1119         178 :         toLane = StringUtils::toInt(toLaneS);
    1120           0 :     } catch (NumberFormatException&) {
    1121           0 :         WRITE_ERRORF(TL("A to-lane number for edge '%' is not numeric (%)."), toEdge->getID(), toLaneS);
    1122             :         return;
    1123           0 :     }
    1124         178 :     toLane -= 1;
    1125         178 :     if (toLane < 0) {
    1126           0 :         WRITE_ERRORF(TL("A to-lane number for edge '%' is not positive (%)."), toEdge->getID(), toLaneS);
    1127           0 :         return;
    1128             :     }
    1129             :     // !!! the next is probably a hack
    1130         178 :     if (fromLane - fromLaneOffset < 0) {
    1131             :         //fromLaneOffset = 0;
    1132             :     } else {
    1133         178 :         fromLane = (int)fromEdge->getNumLanes() - (fromLane - fromLaneOffset) - 1;
    1134             :     }
    1135         178 :     if (toLane - toLaneOffset < 0) {
    1136             :         //toLaneOffset = 0;
    1137             :     } else {
    1138           0 :         toLane = (int)toEdge->getNumLanes() - (toLane - toLaneOffset) - 1;
    1139             :     }
    1140             :     //
    1141         178 :     if ((int) fromEdge->getNumLanes() <= fromLane) {
    1142           0 :         WRITE_ERRORF(TL("A from-lane number for edge '%' is larger than the edge's lane number (%)."), fromEdge->getID(), fromLaneS);
    1143           0 :         return;
    1144             :     }
    1145         178 :     if ((int) toEdge->getNumLanes() <= toLane) {
    1146           0 :         WRITE_ERRORF(TL("A to-lane number for edge '%' is larger than the edge's lane number (%)."), toEdge->getID(), toLaneS);
    1147           0 :         return;
    1148             :     }
    1149             :     //
    1150         356 :     fromEdge->addLane2LaneConnection(fromLane, toEdge, toLane, NBEdge::Lane2LaneInfoType::VALIDATED);
    1151             : }
    1152             : 
    1153             : 
    1154          47 : void NIImporter_VISUM::parse_stopPoints() {
    1155          47 :     std::string id = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
    1156          47 :     std::string name = StringUtils::latin1_to_utf8(myLineParser.get(KEYS.getString(VISUM_NAME)));
    1157          47 :     SVCPermissions permissions = getPermissions(KEYS.getString(VISUM_TYPES), true);
    1158          47 :     NBNode* from = getNamedNodeSecure(KEYS.getString(VISUM_FROMNODE));
    1159          47 :     NBNode* to = getNamedNodeSecure(KEYS.getString(VISUM_FROMNODENO));
    1160          47 :     const std::string edgeID = myLineParser.get(KEYS.getString(VISUM_LINKNO));
    1161          47 :     if (edgeID == "") {
    1162         141 :         WRITE_WARNINGF(TL("Ignoring stopping place '%' without edge id"), id);
    1163           0 :     } else if (from == nullptr && to == nullptr) {
    1164           0 :         WRITE_WARNINGF(TL("Ignoring stopping place '%' without node information"), id);
    1165             :     } else {
    1166           0 :         NBEdge* edge = getNamedEdge(KEYS.getString(VISUM_LINKNO));
    1167           0 :         if (edge == nullptr) {
    1168           0 :             WRITE_WARNINGF(TL("Ignoring stopping place '%' with invalid edge reference '%'"), id, edgeID);
    1169           0 :             return;
    1170           0 :         } else if (from != nullptr) {
    1171           0 :             if (edge->getToNode() == from) {
    1172           0 :                 NBEdge* edge2 = myNetBuilder.getEdgeCont().retrieve("-" + edge->getID());
    1173           0 :                 if (edge2 == nullptr) {
    1174           0 :                     WRITE_WARNINGF(TL("Could not find edge with from-node '%' and base id '%' for stopping place '%'"), from->getID(), edge->getID(), id);
    1175             :                 } else {
    1176             :                     edge = edge2;
    1177             :                 }
    1178           0 :             } else if (edge->getFromNode() != from) {
    1179           0 :                 WRITE_WARNINGF(TL("Unexpected from-node '%' for edge '%' of stopping place '%'"), from->getID(), edge->getID(), id);
    1180             :             }
    1181             :         } else {
    1182           0 :             if (edge->getFromNode() == to) {
    1183           0 :                 NBEdge* edge2 = myNetBuilder.getEdgeCont().retrieve("-" + edge->getID());
    1184           0 :                 if (edge2 == nullptr) {
    1185           0 :                     WRITE_WARNINGF(TL("Could not find edge with to-node '%' and base id '%' for stopping place '%'"), to->getID(), edge->getID(), id);
    1186             :                 } else {
    1187             :                     edge = edge2;
    1188             :                 }
    1189           0 :             } else if (edge->getToNode() != to) {
    1190           0 :                 WRITE_WARNINGF(TL("Unexpected to-node '%' for edge '%' of stopping place '%'"), to->getID(), edge->getID(), id);
    1191             :             }
    1192             :         }
    1193           0 :         double relPos = StringUtils::toDouble(myLineParser.get(KEYS.getString(VISUM_RELPOS)));
    1194             :         /// @note could also retrieve Xkoord, ykoord from $HALTESTELLE
    1195           0 :         Position pos = edge->getGeometry().positionAtOffset(edge->getLength() * relPos);
    1196             : 
    1197           0 :         const double length = OptionsCont::getOptions().getFloat("osm.stop-output.length");
    1198           0 :         std::shared_ptr<NBPTStop> ptStop = std::make_shared<NBPTStop>(id, pos, edge->getID(), edge->getID(), length, name, permissions);
    1199           0 :         myNetBuilder.getPTStopCont().insert(ptStop);
    1200             :     }
    1201             : }
    1202             : 
    1203             : 
    1204             : double
    1205        1770 : NIImporter_VISUM::getWeightedFloat(const std::string& name, const std::string& suffix) {
    1206             :     try {
    1207        1770 :         std::string val = myLineParser.get(name);
    1208         902 :         if (val.find(suffix) != std::string::npos) {
    1209           0 :             val = val.substr(0, val.find(suffix));
    1210             :         }
    1211         902 :         return StringUtils::toDouble(val);
    1212         868 :     } catch (...) {}
    1213         868 :     return -1;
    1214             : }
    1215             : 
    1216             : 
    1217             : double
    1218         868 : NIImporter_VISUM::getWeightedFloat2(const std::string& name, const std::string& name2, const std::string& suffix) {
    1219         868 :     double result = getWeightedFloat(name, suffix);
    1220         868 :     if (result != -1) {
    1221             :         return result;
    1222             :     } else {
    1223         868 :         return getWeightedFloat(name2, suffix);
    1224             :     }
    1225             : }
    1226             : 
    1227             : bool
    1228           0 : NIImporter_VISUM::getWeightedBool(const std::string& name) {
    1229             :     try {
    1230           0 :         return StringUtils::toBool(myLineParser.get(name));
    1231           0 :     } catch (...) {}
    1232             :     try {
    1233           0 :         return StringUtils::toBool(myLineParser.get((name + "(IV)")));
    1234           0 :     } catch (...) {}
    1235           0 :     return false;
    1236             : }
    1237             : 
    1238             : SVCPermissions
    1239        1309 : NIImporter_VISUM::getPermissions(const std::string& name, bool warn, SVCPermissions unknown) {
    1240             :     SVCPermissions result = 0;
    1241        5233 :     for (std::string v : StringTokenizer(myLineParser.get(name), ",").getVector()) {
    1242             :         // common values in english and german
    1243             :         // || v == "funiculaire-telecabine" ---> no matching
    1244        7718 :         v = StringUtils::to_lower_case(v);
    1245       19295 :         if (v == "bus" || v == "tcsp" || v == "acces tc" || v == "Accès tc" || v == "accès tc") {
    1246           0 :             result |= SVC_BUS;
    1247       17389 :         } else if (v == "walk" || v == "w" || v == "f" || v == "ped" || v == "map") {
    1248         944 :             result |= SVC_PEDESTRIAN;
    1249       21031 :         } else if (v == "l" || v == "lkw" || v == "h" || v == "hgv" || v == "lw" || v == "truck" || v == "tru" || v == "pl") {
    1250         327 :             result |= SVC_TRUCK;
    1251        7362 :         } else if (v == "b" || v == "bike" || v == "velo") {
    1252         201 :             result |= SVC_BICYCLE;
    1253        4774 :         } else if (v == "train" || v == "rail") {
    1254           0 :             result |= SVC_RAIL;
    1255        2387 :         } else if (v == "tram") {
    1256           0 :             result |= SVC_TRAM;
    1257        7883 :         } else if (v == "p" || v == "pkw" || v == "car" || v == "c" || v == "vp" || v == "2rm") {
    1258        1367 :             result |= SVC_PASSENGER;
    1259             :         } else {
    1260        1020 :             if (warn) {
    1261         760 :                 WRITE_WARNINGF("Encountered unknown vehicle category '" + v + "' in type '%'", myLineParser.get(KEYS.getString(VISUM_NO)));
    1262             :             }
    1263        1020 :             result |= unknown;
    1264             :         }
    1265        1309 :     }
    1266        1309 :     return result;
    1267             : }
    1268             : 
    1269             : NBNode*
    1270        4256 : NIImporter_VISUM::getNamedNode(const std::string& fieldName) {
    1271        4256 :     std::string nodeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1272        4256 :     NBNode* node = myNetBuilder.getNodeCont().retrieve(nodeS);
    1273        4256 :     if (node == nullptr) {
    1274           0 :         WRITE_ERRORF(TL("The node '%' is not known."), nodeS);
    1275             :     }
    1276        4256 :     return node;
    1277             : }
    1278             : 
    1279             : NBNode*
    1280         322 : NIImporter_VISUM::getNamedNodeSecure(const std::string& fieldName, NBNode* fallback) {
    1281         322 :     std::string nodeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1282         322 :     NBNode* node = myNetBuilder.getNodeCont().retrieve(nodeS);
    1283         322 :     if (node == nullptr) {
    1284          47 :         return fallback;
    1285             :     }
    1286             :     return node;
    1287             : }
    1288             : 
    1289             : 
    1290             : NBNode*
    1291        4096 : NIImporter_VISUM::getNamedNode(const std::string& fieldName1, const std::string& fieldName2) {
    1292        4096 :     if (myLineParser.know(fieldName1)) {
    1293         178 :         return getNamedNode(fieldName1);
    1294             :     } else {
    1295        3918 :         return getNamedNode(fieldName2);
    1296             :     }
    1297             : }
    1298             : 
    1299             : 
    1300             : NBEdge*
    1301         228 : NIImporter_VISUM::getNamedEdge(const std::string& fieldName) {
    1302         228 :     std::string edgeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1303         228 :     NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeS);
    1304         228 :     if (edge == nullptr) {
    1305           0 :         WRITE_ERRORF(TL("The edge '%' is not known."), edgeS);
    1306             :     }
    1307         228 :     return edge;
    1308             : }
    1309             : 
    1310             : 
    1311             : NBEdge*
    1312           0 : NIImporter_VISUM::getNamedEdge(const std::string& fieldName1, const std::string& fieldName2) {
    1313           0 :     if (myLineParser.know(fieldName1)) {
    1314           0 :         return getNamedEdge(fieldName1);
    1315             :     } else {
    1316           0 :         return getNamedEdge(fieldName2);
    1317             :     }
    1318             : }
    1319             : 
    1320             : 
    1321             : 
    1322             : NBEdge*
    1323         334 : NIImporter_VISUM::getReversedContinuating(NBEdge* edge, NBNode* node) {
    1324             :     std::string sid;
    1325         334 :     if (edge->getID()[0] == '-') {
    1326           0 :         sid = edge->getID().substr(1);
    1327             :     } else {
    1328         668 :         sid = "-" + edge->getID();
    1329             :     }
    1330         334 :     if (sid.find('_') != std::string::npos) {
    1331           0 :         sid = sid.substr(0, sid.find('_'));
    1332             :     }
    1333         668 :     return getNamedEdgeContinuating(myNetBuilder.getEdgeCont().retrieve(sid),  node);
    1334             : }
    1335             : 
    1336             : 
    1337             : NBEdge*
    1338        1470 : NIImporter_VISUM::getNamedEdgeContinuating(NBEdge* begin, NBNode* node) {
    1339        1470 :     if (begin == nullptr) {
    1340             :         return nullptr;
    1341             :     }
    1342             :     NBEdge* ret = begin;
    1343        1470 :     std::string edgeID = ret->getID();
    1344             :     // hangle forward
    1345        1470 :     while (ret != nullptr) {
    1346             :         // ok, this is the edge we are looking for
    1347        1470 :         if (ret->getToNode() == node) {
    1348         554 :             return ret;
    1349             :         }
    1350             :         const EdgeVector& nedges = ret->getToNode()->getOutgoingEdges();
    1351         916 :         if (nedges.size() != 1) {
    1352             :             // too many edges follow
    1353             :             ret = nullptr;
    1354             :             continue;
    1355             :         }
    1356         195 :         NBEdge* next = nedges[0];
    1357         390 :         if (ret->getID().substr(0, edgeID.length()) != next->getID().substr(0, edgeID.length())) {
    1358             :             // ok, another edge is next...
    1359             :             ret = nullptr;
    1360             :             continue;
    1361             :         }
    1362           0 :         if (next->getID().substr(next->getID().length() - node->getID().length()) != node->getID()) {
    1363             :             ret = nullptr;
    1364             :             continue;
    1365             :         }
    1366             :         ret = next;
    1367             :     }
    1368             : 
    1369             :     ret = begin;
    1370             :     // hangle backward
    1371         916 :     while (ret != nullptr) {
    1372             :         // ok, this is the edge we are looking for
    1373         916 :         if (ret->getFromNode() == node) {
    1374         916 :             return ret;
    1375             :         }
    1376             :         const EdgeVector& nedges = ret->getFromNode()->getIncomingEdges();
    1377           0 :         if (nedges.size() != 1) {
    1378             :             // too many edges follow
    1379             :             ret = nullptr;
    1380             :             continue;
    1381             :         }
    1382           0 :         NBEdge* next = nedges[0];
    1383           0 :         if (ret->getID().substr(0, edgeID.length()) != next->getID().substr(0, edgeID.length())) {
    1384             :             // ok, another edge is next...
    1385             :             ret = nullptr;
    1386             :             continue;
    1387             :         }
    1388           0 :         if (next->getID().substr(next->getID().length() - node->getID().length()) != node->getID()) {
    1389             :             ret = nullptr;
    1390             :             continue;
    1391             :         }
    1392             :         ret = next;
    1393             :     }
    1394             :     return nullptr;
    1395             : }
    1396             : 
    1397             : 
    1398             : NBEdge*
    1399         952 : NIImporter_VISUM::getNamedEdgeContinuating(const std::string& fieldName, NBNode* node) {
    1400         952 :     std::string edgeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1401         952 :     NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeS);
    1402         952 :     if (edge == nullptr) {
    1403           0 :         WRITE_ERRORF(TL("The edge '%' is not known."), edgeS);
    1404             :     }
    1405        1904 :     return getNamedEdgeContinuating(edge, node);
    1406             : }
    1407             : 
    1408             : 
    1409             : NBEdge*
    1410         356 : NIImporter_VISUM::getNamedEdgeContinuating(const std::string& fieldName1, const std::string& fieldName2,
    1411             :         NBNode* node) {
    1412         356 :     if (myLineParser.know(fieldName1)) {
    1413         356 :         return getNamedEdgeContinuating(fieldName1, node);
    1414             :     } else {
    1415           0 :         return getNamedEdgeContinuating(fieldName2, node);
    1416             :     }
    1417             : }
    1418             : 
    1419             : 
    1420             : NBEdge*
    1421           0 : NIImporter_VISUM::getEdge(NBNode* FromNode, NBNode* ToNode) {
    1422             :     EdgeVector::const_iterator i;
    1423           0 :     for (i = FromNode->getOutgoingEdges().begin(); i != FromNode->getOutgoingEdges().end(); i++) {
    1424           0 :         if (ToNode == (*i)->getToNode()) {
    1425             :             return (*i);
    1426             :         }
    1427             :     }
    1428             :     //!!!
    1429             :     return nullptr;
    1430             : }
    1431             : 
    1432             : 
    1433             : double
    1434        2474 : NIImporter_VISUM::getNamedFloat(const std::string& fieldName) {
    1435        2474 :     std::string value = myLineParser.get(fieldName);
    1436        4948 :     if (StringUtils::endsWith(myLineParser.get(fieldName), "km/h")) {
    1437           0 :         value = value.substr(0, value.length() - 4);
    1438             :     }
    1439        4948 :     return StringUtils::toDouble(value);
    1440             : }
    1441             : 
    1442             : 
    1443             : double
    1444           0 : NIImporter_VISUM::getNamedFloat(const std::string& fieldName, double defaultValue) {
    1445             :     try {
    1446           0 :         return StringUtils::toDouble(myLineParser.get(fieldName));
    1447           0 :     } catch (...) {
    1448             :         return defaultValue;
    1449           0 :     }
    1450             : }
    1451             : 
    1452             : 
    1453             : double
    1454        1088 : NIImporter_VISUM::getNamedFloat(const std::string& fieldName1, const std::string& fieldName2) {
    1455        1088 :     if (myLineParser.know(fieldName1)) {
    1456           0 :         return getNamedFloat(fieldName1);
    1457             :     } else {
    1458        1088 :         return getNamedFloat(fieldName2);
    1459             :     }
    1460             : }
    1461             : 
    1462             : 
    1463             : double
    1464           0 : NIImporter_VISUM::getNamedFloat(const std::string& fieldName1, const std::string& fieldName2,
    1465             :                                 double defaultValue) {
    1466           0 :     if (myLineParser.know(fieldName1)) {
    1467           0 :         return getNamedFloat(fieldName1, defaultValue);
    1468             :     } else {
    1469           0 :         return getNamedFloat(fieldName2, defaultValue);
    1470             :     }
    1471             : }
    1472             : 
    1473             : 
    1474             : std::string
    1475         546 : NIImporter_VISUM::getNamedString(const std::string& fieldName) {
    1476        1092 :     return NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1477             : }
    1478             : 
    1479             : 
    1480             : std::string
    1481         362 : NIImporter_VISUM::getNamedString(const std::string& fieldName1,
    1482             :                                  const std::string& fieldName2) {
    1483         362 :     if (myLineParser.know(fieldName1)) {
    1484         178 :         return getNamedString(fieldName1);
    1485             :     } else {
    1486         184 :         return getNamedString(fieldName2);
    1487             :     }
    1488             : }
    1489             : 
    1490             : 
    1491             : 
    1492             : 
    1493             : 
    1494             : 
    1495             : NBNode*
    1496           0 : NIImporter_VISUM::buildDistrictNode(const std::string& id, NBNode* dest,
    1497             :                                     bool isSource) {
    1498             :     // get the district
    1499           0 :     NBDistrict* dist = myNetBuilder.getDistrictCont().retrieve(id);
    1500           0 :     if (dist == nullptr) {
    1501             :         return nullptr;
    1502             :     }
    1503             :     // build the id
    1504             :     std::string nid;
    1505           0 :     nid = id + "-" + dest->getID();
    1506           0 :     if (!isSource) {
    1507           0 :         nid = "-" + nid;
    1508             :     }
    1509             :     // insert the node
    1510           0 :     if (!myNetBuilder.getNodeCont().insert(nid, dist->getPosition())) {
    1511           0 :         WRITE_ERRORF(TL("Could not build connector node '%'."), nid);
    1512             :     }
    1513             :     // return the node
    1514           0 :     return myNetBuilder.getNodeCont().retrieve(nid);
    1515             : }
    1516             : 
    1517             : 
    1518             : bool
    1519         813 : NIImporter_VISUM::checkNodes(NBNode* from, NBNode* to)  {
    1520         813 :     if (from == nullptr) {
    1521           0 :         WRITE_ERROR(TL(" The from-node was not found within the net"));
    1522             :     }
    1523         813 :     if (to == nullptr) {
    1524           0 :         WRITE_ERROR(TL(" The to-node was not found within the net"));
    1525             :     }
    1526         813 :     if (from == to) {
    1527           0 :         WRITE_ERROR(TL(" Both nodes are the same"));
    1528             :     }
    1529         813 :     return from != nullptr && to != nullptr && from != to;
    1530             : }
    1531             : 
    1532             : bool
    1533           0 : NIImporter_VISUM::isSplitEdge(NBEdge* edge, NBNode* node) {
    1534           0 :     return (edge->getID().length() > node->getID().length() + 1
    1535           0 :             && (edge->getID().substr(edge->getID().length() - node->getID().length() - 1) == "_" + node->getID()));
    1536             : }
    1537             : 
    1538             : void
    1539           0 : NIImporter_VISUM::loadLanguage(const std::string& file) {
    1540           0 :     std::ifstream strm(file.c_str());
    1541           0 :     if (!strm.good()) {
    1542           0 :         throw ProcessError(TLF("Could not load VISUM language map from '%'.", file));
    1543             :     }
    1544           0 :     while (strm.good()) {
    1545             :         std::string keyDE;
    1546             :         std::string keyNew;
    1547           0 :         strm >> keyDE;
    1548           0 :         strm >> keyNew;
    1549           0 :         if (KEYS.hasString(keyDE)) {
    1550           0 :             VISUM_KEY key = KEYS.get(keyDE);
    1551           0 :             KEYS.remove(keyDE, key);
    1552           0 :             KEYS.insert(keyNew, key);
    1553           0 :         } else if (keyDE != "") {
    1554           0 :             WRITE_WARNINGF(TL("Unknown entry '%' in VISUM language map"), keyDE);
    1555             :         }
    1556             :     }
    1557             : 
    1558           0 : }
    1559             : 
    1560             : 
    1561             : /****************************************************************************/

Generated by: LCOV version 1.14