LCOV - code coverage report
Current view: top level - src/netimport - NIImporter_VISUM.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 58.6 % 754 442
Test Date: 2025-11-13 15:38:19 Functions: 76.5 % 51 39

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    NIImporter_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         2003 : NIImporter_VISUM::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
      99              :     // check whether the option is set (properly)
     100         4006 :     if (!oc.isSet("visum-file")) {
     101         1995 :         return;
     102              :     }
     103              :     // build the handler
     104           16 :     NIImporter_VISUM loader(nb, oc.getString("visum-file"),
     105           16 :                             NBCapacity2Lanes(oc.getFloat("lanes-from-capacity.norm")),
     106           16 :                             oc.getBool("visum.use-type-priority"),
     107           24 :                             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        27753 :                 if (line.substr(0, dataName.length()) == dataName) {
     215          159 :                     (*i).position = myLineReader.getPosition();
     216          159 :                     (*i).pattern = line.substr(dataName.length());
     217          477 :                     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          800 :     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          232 :     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            0 :         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           50 :     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              :         long long int flaecheID;
     356              :         try {
     357           50 :             flaecheID = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_SURFACEID)));
     358            0 :         } catch (EmptyData&) {
     359            0 :             flaecheID = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_NO)));
     360            0 :         }
     361           50 :         myShapeDistrictMap[flaecheID] = district;
     362              :     }
     363              : }
     364              : 
     365              : 
     366              : void
     367           25 : NIImporter_VISUM::parse_Point() {
     368           25 :     long long int id = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_ID)));
     369           25 :     double x = StringUtils::toDouble(myLineParser.get(KEYS.getString(VISUM_XCOORD)));
     370           50 :     double y = StringUtils::toDouble(myLineParser.get(KEYS.getString(VISUM_YCOORD)));
     371              :     Position pos(x, y);
     372           25 :     if (!NBNetBuilder::transformCoordinate(pos, false)) {
     373            0 :         WRITE_ERRORF(TL("Unable to project coordinates for point %."), toString(id));
     374            0 :         return;
     375              :     }
     376           25 :     myPoints[id] = pos;
     377              : }
     378              : 
     379              : 
     380              : void
     381          462 : NIImporter_VISUM::parse_Edges() {
     382          924 :     if (myLineParser.know(KEYS.getString(VISUM_TYPES)) && myLineParser.get(KEYS.getString(VISUM_TYPES)) == "") {
     383              :         // no vehicle allowed; don't add
     384          462 :         return;
     385              :     }
     386              :     // get the id
     387          462 :     myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
     388              :     // get the from- & to-node and validate them
     389          462 :     NBNode* from = getNamedNode("VonKnot", KEYS.getString(VISUM_FROMNODE));
     390          462 :     NBNode* to = getNamedNode("NachKnot", KEYS.getString(VISUM_TONODE));
     391          462 :     if (!checkNodes(from, to)) {
     392              :         return;
     393              :     }
     394              :     // get the type
     395          462 :     std::string type = myLineParser.know(KEYS.getString(VISUM_TYP)) ? myLineParser.get(KEYS.getString(VISUM_TYP)) : myLineParser.get(KEYS.getString(VISUM_TYPE));
     396              :     // get the speed
     397          462 :     double speed = myNetBuilder.getTypeCont().getEdgeTypeSpeed(type);
     398          924 :     if (!OptionsCont::getOptions().getBool("visum.use-type-speed")) {
     399              :         try {
     400          462 :             std::string speedS = myLineParser.know("v0-IV") ? myLineParser.get("v0-IV") : myLineParser.get(KEYS.getString(VISUM_V0));
     401          462 :             if (speedS.find("km/h") != std::string::npos) {
     402          104 :                 speedS = speedS.substr(0, speedS.find("km/h"));
     403              :             }
     404          462 :             speed = StringUtils::toDouble(speedS) / 3.6;
     405            0 :         } catch (OutOfBoundsException&) {}
     406              :     }
     407          462 :     if (speed <= 0) {
     408            0 :         speed = myNetBuilder.getTypeCont().getEdgeTypeSpeed(type);
     409              :     }
     410              : 
     411              :     // get the information whether the edge is a one-way
     412          462 :     bool oneway = myLineParser.know("Einbahn")
     413          462 :                   ? StringUtils::toBool(myLineParser.get("Einbahn"))
     414              :                   : true;
     415              :     // get the number of lanes
     416          462 :     int nolanes = myNetBuilder.getTypeCont().getEdgeTypeNumLanes(type);
     417          924 :     if (!OptionsCont::getOptions().getBool("visum.recompute-lane-number")) {
     418          924 :         if (!OptionsCont::getOptions().getBool("visum.use-type-laneno")) {
     419          924 :             if (myLineParser.know("Fahrstreifen")) {
     420            0 :                 nolanes = StringUtils::toInt(myLineParser.get("Fahrstreifen"));
     421          462 :             } else if (myLineParser.know(KEYS.getString(VISUM_NUMLANES))) {
     422          924 :                 nolanes = StringUtils::toInt(myLineParser.get(KEYS.getString(VISUM_NUMLANES)));
     423              :             }
     424              :         }
     425              :     } else {
     426            0 :         if (myLineParser.know(KEYS.getString(VISUM_CAPACITY))) {
     427            0 :             nolanes = myCapacity2Lanes.get(StringUtils::toDouble(myLineParser.get(KEYS.getString(VISUM_CAPACITY))));
     428            0 :         } else if (myLineParser.know("KAP-IV")) {
     429            0 :             nolanes = myCapacity2Lanes.get(StringUtils::toDouble(myLineParser.get("KAP-IV")));
     430              :         }
     431              :     }
     432              :     // check whether the id is already used
     433              :     //  (should be the opposite direction)
     434              :     bool oneway_checked = oneway;
     435          462 :     NBEdge* previous = myNetBuilder.getEdgeCont().retrieve(myCurrentID);
     436          462 :     if (previous != nullptr) {
     437          225 :         myCurrentID = '-' + myCurrentID;
     438          225 :         previous->setLaneSpreadFunction(LaneSpreadFunction::RIGHT);
     439              :         oneway_checked = false;
     440              :     }
     441          462 :     if (find(myTouchedEdges.begin(), myTouchedEdges.end(), myCurrentID) != myTouchedEdges.end()) {
     442              :         oneway_checked = false;
     443              :     }
     444          462 :     std::string tmpid = '-' + myCurrentID;
     445          462 :     if (find(myTouchedEdges.begin(), myTouchedEdges.end(), tmpid) != myTouchedEdges.end()) {
     446            0 :         previous = myNetBuilder.getEdgeCont().retrieve(tmpid);
     447            0 :         if (previous != nullptr) {
     448            0 :             previous->setLaneSpreadFunction(LaneSpreadFunction::RIGHT);
     449              :         }
     450              :         oneway_checked = false;
     451              :     }
     452          462 :     std::string name = StringUtils::latin1_to_utf8(myLineParser.get(KEYS.getString(VISUM_NAME)));
     453              :     // add the edge
     454          462 :     const SVCPermissions permissions = getPermissions(KEYS.getString(VISUM_TYPES), false, myNetBuilder.getTypeCont().getEdgeTypePermissions(type));
     455          462 :     int prio = myUseVisumPrio ? myNetBuilder.getTypeCont().getEdgeTypePriority(type) : -1;
     456          462 :     if (nolanes != 0 && speed != 0) {
     457          450 :         LaneSpreadFunction lsf = oneway_checked ? LaneSpreadFunction::CENTER : LaneSpreadFunction::RIGHT;
     458              :         NBEdge* e = new NBEdge(myCurrentID, from, to, type, speed, NBEdge::UNSPECIFIED_FRICTION, nolanes, prio,
     459          900 :                                NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, lsf, name);
     460          450 :         e->setPermissions(permissions);
     461          450 :         if (!myNetBuilder.getEdgeCont().insert(e)) {
     462            0 :             delete e;
     463            0 :             WRITE_ERRORF(TL("Duplicate edge occurred ('%')."), myCurrentID);
     464              :         }
     465              :     }
     466          462 :     myTouchedEdges.push_back(myCurrentID);
     467              :     // nothing more to do, when the edge is a one-way street
     468          462 :     if (oneway) {
     469              :         return;
     470              :     }
     471              :     // add the opposite edge
     472            0 :     myCurrentID = '-' + myCurrentID;
     473            0 :     if (nolanes != 0 && speed != 0) {
     474            0 :         LaneSpreadFunction lsf = oneway_checked ? LaneSpreadFunction::CENTER : LaneSpreadFunction::RIGHT;
     475              :         NBEdge* e = new NBEdge(myCurrentID, from, to, type, speed, NBEdge::UNSPECIFIED_FRICTION, nolanes, prio,
     476            0 :                                NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, lsf, name);
     477            0 :         e->setPermissions(permissions);
     478            0 :         if (!myNetBuilder.getEdgeCont().insert(e)) {
     479            0 :             delete e;
     480            0 :             WRITE_ERRORF(TL("Duplicate edge occurred ('%')."), myCurrentID);
     481              :         }
     482              :     }
     483            0 :     myTouchedEdges.push_back(myCurrentID);
     484              : }
     485              : 
     486              : 
     487              : void
     488           30 : NIImporter_VISUM::parse_Kante() {
     489           30 :     long long int id = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_ID)));
     490           30 :     long long int from = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_FROMPOINTID)));
     491           30 :     long long int to = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_TOPOINTID)));
     492           30 :     myEdges[id] = std::make_pair(from, to);
     493           30 : }
     494              : 
     495              : 
     496              : void
     497           30 : NIImporter_VISUM::parse_PartOfArea() {
     498           30 :     long long int flaecheID = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_SURFACEID)));
     499           30 :     long long int flaechePartID = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_FACEID)));
     500           30 :     if (mySubPartsAreas.find(flaechePartID) == mySubPartsAreas.end()) {
     501           30 :         mySubPartsAreas[flaechePartID] = std::vector<long long int>();
     502              :     }
     503           30 :     mySubPartsAreas[flaechePartID].push_back(flaecheID);
     504           30 : }
     505              : 
     506              : 
     507              : void
     508            0 : NIImporter_VISUM::parse_Connectors() {
     509              :     // get the source district
     510            0 :     std::string bez = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_SOURCE_DISTRICT)));
     511              :     // get the destination node
     512            0 :     NBNode* dest = getNamedNode(KEYS.getString(VISUM_FROMNODENO));
     513            0 :     if (dest == nullptr) {
     514              :         return;
     515              :     }
     516              :     // get the weight of the connection
     517              :     double proz = 1;
     518            0 :     if (myLineParser.know("Proz") || myLineParser.know("Proz(IV)")) {
     519            0 :         proz = getNamedFloat("Proz", "Proz(IV)") / 100;
     520              :     }
     521              :     // get the information whether this is a sink or a source
     522            0 :     std::string dir = myLineParser.get(KEYS.getString(VISUM_DIRECTION));
     523            0 :     if (dir.length() == 0) {
     524            0 :         dir = KEYS.getString(VISUM_ORIGIN) + KEYS.getString(VISUM_DESTINATION);
     525              :     }
     526              :     // build the source when needed
     527            0 :     if (dir.find(KEYS.getString(VISUM_ORIGIN)) != std::string::npos) {
     528            0 :         for (NBEdge* edge : dest->getOutgoingEdges()) {
     529            0 :             myNetBuilder.getDistrictCont().addSource(bez, edge, proz);
     530              :         }
     531              :     }
     532              :     // build the sink when needed
     533            0 :     if (dir.find(KEYS.getString(VISUM_DESTINATION)) != std::string::npos) {
     534            0 :         for (NBEdge* edge : dest->getIncomingEdges()) {
     535            0 :             myNetBuilder.getDistrictCont().addSink(bez, edge, proz);
     536              :         }
     537              :     }
     538              : }
     539              : 
     540              : 
     541              : 
     542              : void
     543            0 : NIImporter_VISUM::parse_Connectors_legacy() {
     544              :     // get the source district
     545            0 :     std::string bez = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_SOURCE_DISTRICT)));
     546              :     // get the destination node
     547            0 :     NBNode* dest = getNamedNode(KEYS.getString(VISUM_FROMNODENO));
     548            0 :     if (dest == nullptr) {
     549              :         return;
     550              :     }
     551              :     // get the weight of the connection
     552              :     double proz = 1;
     553            0 :     if (myLineParser.know("Proz") || myLineParser.know("Proz(IV)")) {
     554            0 :         proz = getNamedFloat("Proz", "Proz(IV)") / 100;
     555              :     }
     556              :     // get the duration to wait (unused)
     557              : //     double retard = -1;
     558              : //     if (myLineParser.know("t0-IV")) {
     559              : //         retard = getNamedFloat("t0-IV", -1);
     560              : //     }
     561              :     // get the type;
     562              :     //  use a standard type with a large speed when a type is not given
     563              : 
     564            0 :     std::string type = myLineParser.know(KEYS.getString(VISUM_TYP))
     565            0 :                        ? NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_TYP)))
     566            0 :                        : "";
     567              :     // add the connectors as an edge
     568            0 :     std::string id = bez + "-" + dest->getID();
     569              :     // get the information whether this is a sink or a source
     570            0 :     std::string dir = myLineParser.get(KEYS.getString(VISUM_DIRECTION));
     571            0 :     if (dir.length() == 0) {
     572            0 :         dir = KEYS.getString(VISUM_ORIGIN) + KEYS.getString(VISUM_DESTINATION);
     573              :     }
     574              :     // build the source when needed
     575            0 :     if (dir.find(KEYS.getString(VISUM_ORIGIN)) != std::string::npos) {
     576              :         const EdgeVector& edges = dest->getOutgoingEdges();
     577              :         bool hasContinuation = false;
     578            0 :         for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
     579            0 :             if (!(*i)->isMacroscopicConnector()) {
     580              :                 hasContinuation = true;
     581              :             }
     582              :         }
     583            0 :         if (!hasContinuation) {
     584              :             // obviously, there is no continuation on the net
     585            0 :             WRITE_WARNINGF(TL("Incoming connector '%' will not be build - would be not connected to network."), id);
     586              :         } else {
     587            0 :             NBNode* src = buildDistrictNode(bez, dest, true);
     588            0 :             if (src == nullptr) {
     589            0 :                 WRITE_ERRORF(TL("The district '%' could not be built."), bez);
     590            0 :                 return;
     591              :             }
     592              :             NBEdge* edge = new NBEdge(id, src, dest, "VisumConnector",
     593            0 :                                       OptionsCont::getOptions().getFloat("visum.connector-speeds"), NBEdge::UNSPECIFIED_FRICTION,
     594            0 :                                       OptionsCont::getOptions().getInt("visum.connectors-lane-number"),
     595              :                                       -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET,
     596            0 :                                       LaneSpreadFunction::RIGHT, "");
     597              :             edge->setAsMacroscopicConnector();
     598            0 :             if (!myNetBuilder.getEdgeCont().insert(edge)) {
     599            0 :                 WRITE_ERRORF(TL("A duplicate edge id occurred (ID='%')."), id);
     600            0 :                 return;
     601              :             }
     602            0 :             edge = myNetBuilder.getEdgeCont().retrieve(id);
     603            0 :             if (edge != nullptr) {
     604            0 :                 myNetBuilder.getDistrictCont().addSource(bez, edge, proz);
     605              :             }
     606              :         }
     607              :     }
     608              :     // build the sink when needed
     609            0 :     if (dir.find(KEYS.getString(VISUM_DESTINATION)) != std::string::npos) {
     610              :         const EdgeVector& edges = dest->getIncomingEdges();
     611              :         bool hasPredeccessor = false;
     612            0 :         for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
     613            0 :             if (!(*i)->isMacroscopicConnector()) {
     614              :                 hasPredeccessor = true;
     615              :             }
     616              :         }
     617            0 :         if (!hasPredeccessor) {
     618              :             // obviously, the network is not connected to this node
     619            0 :             WRITE_WARNINGF(TL("Outgoing connector '%' will not be build - would be not connected to network."), id);
     620              :         } else {
     621            0 :             NBNode* src = buildDistrictNode(bez, dest, false);
     622            0 :             if (src == nullptr) {
     623            0 :                 WRITE_ERRORF(TL("The district '%' could not be built."), bez);
     624            0 :                 return;
     625              :             }
     626            0 :             id = "-" + id;
     627              :             NBEdge* edge = new NBEdge(id, dest, src, "VisumConnector",
     628            0 :                                       OptionsCont::getOptions().getFloat("visum.connector-speeds"), NBEdge::UNSPECIFIED_FRICTION,
     629            0 :                                       OptionsCont::getOptions().getInt("visum.connectors-lane-number"),
     630              :                                       -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET,
     631            0 :                                       LaneSpreadFunction::RIGHT, "");
     632              :             edge->setAsMacroscopicConnector();
     633            0 :             if (!myNetBuilder.getEdgeCont().insert(edge)) {
     634            0 :                 WRITE_ERRORF(TL("A duplicate edge id occurred (ID='%')."), id);
     635            0 :                 return;
     636              :             }
     637            0 :             edge = myNetBuilder.getEdgeCont().retrieve(id);
     638            0 :             if (edge != nullptr) {
     639            0 :                 myNetBuilder.getDistrictCont().addSink(bez, edge, proz);
     640              :             }
     641              :         }
     642              :     }
     643              : }
     644              : 
     645              : 
     646              : void
     647          804 : NIImporter_VISUM::parse_Turns() {
     648         1608 :     if (myLineParser.know(KEYS.getString(VISUM_TYPES)) && myLineParser.get(KEYS.getString(VISUM_TYPES)) == "") {
     649              :         // no vehicle allowed; don't add
     650           96 :         return;
     651              :     }
     652              :     // retrieve the nodes
     653          756 :     NBNode* from = getNamedNode("VonKnot", KEYS.getString(VISUM_FROMNODE));
     654          756 :     NBNode* via = getNamedNode("UeberKnot", KEYS.getString(VISUM_VIANODENO));
     655          756 :     NBNode* to = getNamedNode("NachKnot", KEYS.getString(VISUM_TONODE));
     656          756 :     if (from == nullptr || via == nullptr || to == nullptr) {
     657              :         return;
     658              :     }
     659              :     // all nodes are known
     660         1512 :     std::string type = myLineParser.know("VSysCode")
     661          756 :                        ? myLineParser.get("VSysCode")
     662          756 :                        : myLineParser.get(KEYS.getString(VISUM_TYPES));
     663          756 :     if (myVSysTypes.find(type) != myVSysTypes.end() && myVSysTypes.find(type)->second == "IV") {
     664              :         // try to set the turning definition
     665          416 :         NBEdge* src = from->getConnectionTo(via);
     666          416 :         NBEdge* dest = via->getConnectionTo(to);
     667              :         // check both
     668          416 :         if (src == nullptr) {
     669           48 :             if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) {
     670            0 :                 WRITE_WARNINGF(TL("There is no edge from node '%' to node '%'."), from->getID(), via->getID());
     671              :             }
     672           24 :             return;
     673              :         }
     674          392 :         if (dest == nullptr) {
     675           48 :             if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) {
     676            0 :                 WRITE_WARNINGF(TL("There is no edge from node '%' to node '%'."), via->getID(), to->getID());
     677              :             }
     678           24 :             return;
     679              :         }
     680              :         // both edges found
     681              :         //  set them into the edge
     682          368 :         src->addEdge2EdgeConnection(dest);
     683              :     }
     684              : }
     685              : 
     686              : 
     687              : void
     688          351 : NIImporter_VISUM::parse_EdgePolys() {
     689              :     // get the from- & to-node and validate them
     690          351 :     NBNode* from = getNamedNode("VonKnot", KEYS.getString(VISUM_FROMNODE));
     691          351 :     NBNode* to = getNamedNode("NachKnot", KEYS.getString(VISUM_TONODE));
     692          351 :     if (!checkNodes(from, to)) {
     693            0 :         return;
     694              :     }
     695              :     bool failed = false;
     696              :     int index;
     697              :     double x, y;
     698              :     try {
     699          351 :         index = StringUtils::toInt(myLineParser.get(KEYS.getString(VISUM_INDEX)));
     700          351 :         x = getNamedFloat(KEYS.getString(VISUM_XCOORD));
     701          351 :         y = getNamedFloat(KEYS.getString(VISUM_YCOORD));
     702            0 :     } catch (NumberFormatException&) {
     703            0 :         WRITE_ERRORF(TL("Error in geometry description from node '%' to node '%'."), from->getID(), to->getID());
     704              :         return;
     705            0 :     }
     706              :     Position pos(x, y);
     707          351 :     if (!NBNetBuilder::transformCoordinate(pos)) {
     708            0 :         WRITE_ERRORF(TL("Unable to project coordinates for node '%'."), from->getID());
     709            0 :         return;
     710              :     }
     711          351 :     NBEdge* e = from->getConnectionTo(to);
     712          351 :     if (e != nullptr) {
     713          351 :         e->addGeometryPoint(index, pos);
     714              :     } else {
     715              :         failed = true;
     716              :     }
     717          351 :     e = to->getConnectionTo(from);
     718          351 :     if (e != nullptr) {
     719          351 :         e->addGeometryPoint(-index, pos);
     720              :         failed = false;
     721              :     }
     722              :     // check whether the operation has failed
     723            0 :     if (failed) {
     724            0 :         if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) {
     725            0 :             WRITE_WARNINGF(TL("There is no edge from node '%' to node '%'."), from->getID(), to->getID());
     726              :         }
     727              :     }
     728              : }
     729              : 
     730              : 
     731              : void
     732          228 : NIImporter_VISUM::parse_Lanes() {
     733              :     // The base number of lanes for the edge was already defined in STRECKE
     734              :     // this refines lane specific attribute (width) and optionally introduces splits for additional lanes
     735              :     // It is permitted for KNOTNR to be 0
     736              :     //
     737              :     // get the edge
     738          228 :     NBEdge* baseEdge = getNamedEdge(KEYS.getString(VISUM_LINKNO));
     739          228 :     if (baseEdge == nullptr) {
     740          220 :         return;
     741              :     }
     742              :     NBEdge* edge = baseEdge;
     743              :     // get the node
     744          228 :     NBNode* node = getNamedNodeSecure("KNOTNR");
     745          228 :     if (node == nullptr) {
     746              :         node = edge->getToNode();
     747              :     } else {
     748          228 :         edge = getNamedEdgeContinuating(KEYS.getString(VISUM_LINKNO), node);
     749              :     }
     750              :     // check
     751          228 :     if (edge == nullptr) {
     752              :         return;
     753              :     }
     754              :     // get the lane
     755          228 :     std::string laneS = myLineParser.know("FSNR")
     756          489 :                         ? NBHelpers::normalIDRepresentation(myLineParser.get("FSNR"))
     757          618 :                         : NBHelpers::normalIDRepresentation(myLineParser.get("NR"));
     758              :     int lane = -1;
     759              :     try {
     760          228 :         lane = StringUtils::toInt(laneS);
     761            0 :     } catch (NumberFormatException&) {
     762            0 :         WRITE_ERRORF(TL("A lane number for edge '%' is not numeric (%)."), edge->getID(), laneS);
     763              :         return;
     764            0 :     }
     765          228 :     lane -= 1;
     766          228 :     if (lane < 0) {
     767            0 :         WRITE_ERRORF(TL("A lane number for edge '%' is not positive (%)."), edge->getID(), laneS);
     768            0 :         return;
     769              :     }
     770              :     // get the direction
     771          456 :     std::string dirS = NBHelpers::normalIDRepresentation(myLineParser.get("RICHTTYP"));
     772              :     int prevLaneNo = baseEdge->getNumLanes();
     773          228 :     if ((dirS == "1" && !(node->hasIncoming(edge))) || (dirS == "0" && !(node->hasOutgoing(edge)))) {
     774              :         // get the last part of the turnaround direction
     775          134 :         NBEdge* cand = getReversedContinuating(edge, node);
     776          134 :         if (cand) {
     777              :             edge = cand;
     778              :         }
     779              :     }
     780              :     // get the length
     781          228 :     std::string lengthS = NBHelpers::normalIDRepresentation(myLineParser.get("LAENGE"));
     782          228 :     double length = -1;
     783              :     try {
     784          228 :         length = StringUtils::toDouble(lengthS);
     785            0 :     } catch (NumberFormatException&) {
     786            0 :         WRITE_ERRORF(TL("A lane length for edge '%' is not numeric (%)."), edge->getID(), lengthS);
     787              :         return;
     788            0 :     }
     789          228 :     if (length < 0) {
     790            0 :         WRITE_ERRORF(TL("A lane length for edge '%' is not positive (%)."), edge->getID(), lengthS);
     791            0 :         return;
     792              :     }
     793              :     //
     794          228 :     if (dirS == "1") {
     795          136 :         lane -= prevLaneNo;
     796              :     }
     797              :     //
     798          228 :     if (length == 0) {
     799          228 :         if ((int) edge->getNumLanes() > lane) {
     800              :             // ok, we know this already...
     801              :             return;
     802              :         }
     803              :         // increment by one
     804            8 :         edge->incLaneNo(1);
     805              :     } else {
     806              :         // check whether this edge already has been created
     807            0 :         if (isSplitEdge(edge, node)) {
     808            0 :             if (edge->getID().substr(edge->getID().find('_')) == "_" + toString(length) + "_" + node->getID()) {
     809            0 :                 if ((int) edge->getNumLanes() > lane) {
     810              :                     // ok, we know this already...
     811            0 :                     return;
     812              :                 }
     813              :                 // increment by one
     814            0 :                 edge->incLaneNo(1);
     815              :                 return;
     816              :             }
     817              :         }
     818              :         // nope, we have to split the edge...
     819              :         //  maybe it is not the proper edge to split - VISUM seems not to sort the splits...
     820              :         bool mustRecheck = true;
     821              :         double seenLength = 0;
     822            0 :         while (mustRecheck) {
     823            0 :             if (isSplitEdge(edge, node)) {
     824              :                 // ok, we have a previously created edge here
     825            0 :                 std::string sub = edge->getID();
     826            0 :                 sub = sub.substr(sub.rfind('_', sub.rfind('_') - 1));
     827            0 :                 sub = sub.substr(1, sub.find('_', 1) - 1);
     828            0 :                 double dist = StringUtils::toDouble(sub);
     829            0 :                 if (dist < length) {
     830            0 :                     seenLength += edge->getLength();
     831            0 :                     if (dirS == "1") {
     832              :                         // incoming -> move back
     833            0 :                         edge = edge->getFromNode()->getIncomingEdges()[0];
     834              :                     } else {
     835              :                         // outgoing -> move forward
     836            0 :                         edge = edge->getToNode()->getOutgoingEdges()[0];
     837              :                     }
     838              :                 } else {
     839              :                     mustRecheck = false;
     840              :                 }
     841              :             } else {
     842              :                 // we have the center edge - do not continue...
     843              :                 mustRecheck = false;
     844              :             }
     845              :         }
     846              :         // compute position
     847              :         Position p;
     848            0 :         double useLength = length - seenLength;
     849            0 :         useLength = edge->getLength() - useLength;
     850            0 :         if (useLength < 0 || useLength > edge->getLength()) {
     851            0 :             WRITE_WARNINGF(TL("Could not find split position for edge '%'."), edge->getID());
     852            0 :             return;
     853              :         }
     854            0 :         std::string edgeID = edge->getID();
     855            0 :         p = edge->getGeometry().positionAtOffset(useLength);
     856            0 :         if (isSplitEdge(edge, node)) {
     857            0 :             edgeID = edgeID.substr(0, edgeID.find('_'));
     858              :         }
     859            0 :         NBNode* rn = new NBNode(edgeID + "_" +  toString((int) length) + "_" + node->getID(), p);
     860            0 :         if (!myNetBuilder.getNodeCont().insert(rn)) {
     861            0 :             throw ProcessError(TL("Ups - could not insert node!"));
     862              :         }
     863            0 :         std::string nid = edgeID + "_" +  toString((int) length) + "_" + node->getID();
     864            0 :         myNetBuilder.getEdgeCont().splitAt(myNetBuilder.getDistrictCont(), edge, useLength, rn,
     865            0 :                                            edge->getID(), nid, edge->getNumLanes() + 0, edge->getNumLanes() + 1);
     866              :         // old edge is deleted and a new edge with the same name created
     867            0 :         edge = myNetBuilder.getEdgeCont().retrieve(edgeID);
     868            0 :         NBEdge* nedge = myNetBuilder.getEdgeCont().retrieve(nid);
     869            0 :         nedge = nedge->getToNode()->getOutgoingEdges()[0];
     870            0 :         while (isSplitEdge(edge, node)) {
     871              :             assert(nedge->getToNode()->getOutgoingEdges().size() > 0);
     872            0 :             nedge->incLaneNo(1);
     873            0 :             nedge = nedge->getToNode()->getOutgoingEdges()[0];
     874              :         }
     875              :     }
     876              : }
     877              : 
     878              : 
     879              : void
     880           17 : NIImporter_VISUM::parse_TrafficLights() {
     881           17 :     myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
     882           17 :     const SUMOTime cycleTime = TIME2STEPS(getWeightedFloat2("Umlaufzeit", "UMLZEIT", "s"));
     883           17 :     const SUMOTime intermediateTime = TIME2STEPS(getWeightedFloat2("StdZwischenzeit", "STDZWZEIT", "s"));
     884           17 :     bool phaseBased = myLineParser.know("PhasenBasiert")
     885           17 :                       ? StringUtils::toBool(myLineParser.get("PhasenBasiert"))
     886              :                       : false;
     887           85 :     const SUMOTime offset = myLineParser.know("ZEITVERSATZ") ? TIME2STEPS(getWeightedFloat("ZEITVERSATZ", "s")) : 0;
     888              :     // add to the list
     889           17 :     myTLS[myCurrentID] = new NIVisumTL(myCurrentID, cycleTime, offset, intermediateTime, phaseBased);
     890           17 : }
     891              : 
     892              : 
     893              : void
     894           17 : NIImporter_VISUM::parse_NodesToTrafficLights() {
     895           17 :     std::string node = myLineParser.get("KnotNr").c_str();
     896           17 :     if (node == "0") {
     897              :         // this is a dummy value which cannot be assigned to
     898              :         return;
     899              :     }
     900           17 :     std::string trafficLight = myLineParser.get("LsaNr").c_str();
     901              :     // add to the list
     902           17 :     NBNode* n = myNetBuilder.getNodeCont().retrieve(node);
     903              :     auto tlIt = myTLS.find(trafficLight);
     904           17 :     if (n != nullptr && tlIt != myTLS.end()) {
     905           34 :         tlIt->second->addNode(n);
     906              :     } else {
     907            0 :         WRITE_ERROR("Could not assign" + std::string(n == nullptr ? " missing" : "") + " node '" + node
     908              :                     + "' to" + std::string(tlIt == myTLS.end() ? " missing" : "") + " traffic light '" + trafficLight + "'");
     909              :     }
     910              : }
     911              : 
     912              : 
     913              : void
     914           72 : NIImporter_VISUM::parse_SignalGroups() {
     915           72 :     myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
     916           72 :     std::string LSAid = NBHelpers::normalIDRepresentation(myLineParser.get("LsaNr"));
     917           72 :     const SUMOTime startTime = TIME2STEPS(getNamedFloat("GzStart", "GRUENANF"));
     918           72 :     const SUMOTime endTime = TIME2STEPS(getNamedFloat("GzEnd", "GRUENENDE"));
     919          192 :     const SUMOTime yellowTime = myLineParser.know("GELB") ? TIME2STEPS(getNamedFloat("GELB")) : -1;
     920              :     // add to the list
     921           72 :     if (myTLS.find(LSAid) == myTLS.end()) {
     922            0 :         WRITE_ERRORF(TL("Could not find TLS '%' for setting the signal group."), LSAid);
     923              :         return;
     924              :     }
     925           72 :     myTLS.find(LSAid)->second->addSignalGroup(myCurrentID, startTime, endTime, yellowTime);
     926              : }
     927              : 
     928              : 
     929              : void
     930          184 : NIImporter_VISUM::parse_TurnsToSignalGroups() {
     931              :     // get the id
     932          368 :     std::string SGid = getNamedString("SGNR", "SIGNALGRUPPENNR");
     933          368 :     if (!myLineParser.know("LsaNr")) {
     934              :         /// XXX could be retrieved from context
     935            0 :         WRITE_WARNING(TL("Ignoring SIGNALGRUPPEZUFSABBIEGER because LsaNr is not known"));
     936              :         return;
     937              :     }
     938          184 :     std::string LSAid = getNamedString("LsaNr");
     939              :     // nodes
     940          184 :     NBNode* from = myLineParser.know("VonKnot") ? getNamedNode("VonKnot") : nullptr;
     941          184 :     NBNode* via = myLineParser.know("KNOTNR")
     942          368 :                   ? getNamedNode("KNOTNR")
     943          232 :                   : getNamedNode("UeberKnot", "UeberKnotNr");
     944          184 :     NBNode* to = myLineParser.know("NachKnot") ? getNamedNode("NachKnot") : nullptr;
     945              :     // edges
     946              :     NBEdge* edg1 = nullptr;
     947              :     NBEdge* edg2 = nullptr;
     948          184 :     if (from == nullptr && to == nullptr) {
     949          184 :         edg1 = getNamedEdgeContinuating("VONSTRNR", via);
     950          368 :         edg2 = getNamedEdgeContinuating("NACHSTRNR", via);
     951              :     } else {
     952            0 :         edg1 = getEdge(from, via);
     953            0 :         edg2 = getEdge(via, to);
     954              :     }
     955              :     // add to the list
     956          184 :     NIVisumTL::SignalGroup& SG = myTLS.find(LSAid)->second->getSignalGroup(SGid);
     957          184 :     if (edg1 != nullptr && edg2 != nullptr) {
     958          184 :         if (!via->hasIncoming(edg1)) {
     959              :             std::string sid;
     960          163 :             if (edg1->getID()[0] == '-') {
     961            0 :                 sid = edg1->getID().substr(1);
     962              :             } else {
     963          326 :                 sid = "-" + edg1->getID();
     964              :             }
     965          163 :             if (sid.find('_') != std::string::npos) {
     966            0 :                 sid = sid.substr(0, sid.find('_'));
     967              :             }
     968          163 :             edg1 = getNamedEdgeContinuating(myNetBuilder.getEdgeCont().retrieve(sid),  via);
     969              :         }
     970          184 :         if (!via->hasOutgoing(edg2)) {
     971              :             std::string sid;
     972           21 :             if (edg2->getID()[0] == '-') {
     973            0 :                 sid = edg2->getID().substr(1);
     974              :             } else {
     975           42 :                 sid = "-" + edg2->getID();
     976              :             }
     977           21 :             if (sid.find('_') != std::string::npos) {
     978            0 :                 sid = sid.substr(0, sid.find('_'));
     979              :             }
     980           21 :             edg2 = getNamedEdgeContinuating(myNetBuilder.getEdgeCont().retrieve(sid),  via);
     981              :         }
     982          368 :         SG.connections().push_back(NBConnection(edg1, edg2));
     983              :     }
     984              : }
     985              : 
     986              : 
     987              : void
     988           30 : NIImporter_VISUM::parse_AreaSubPartElement() {
     989           30 :     long long int id = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_FACEID)));
     990           30 :     long long int edgeid = StringUtils::toLong(myLineParser.get(KEYS.getString(VISUM_EDGEID)));
     991           30 :     if (myEdges.find(edgeid) == myEdges.end()) {
     992            0 :         WRITE_ERROR(TL("Unknown edge in TEILFLAECHENELEMENT"));
     993            0 :         return;
     994              :     }
     995           30 :     std::string dir = myLineParser.get(KEYS.getString(VISUM_DIRECTION));
     996              : // get index (unused)
     997              : //     std::string indexS = NBHelpers::normalIDRepresentation(myLineParser.get("INDEX"));
     998              : //     int index = -1;
     999              : //     try {
    1000              : //         index = StringUtils::toInt(indexS) - 1;
    1001              : //     } catch (NumberFormatException&) {
    1002              : //         WRITE_ERRORF(TL("An index for a TEILFLAECHENELEMENT is not numeric (id='%')."), toString(id));
    1003              : //         return;
    1004              : //     }
    1005           30 :     PositionVector shape;
    1006           30 :     shape.push_back(myPoints[myEdges[edgeid].first]);
    1007           30 :     shape.push_back(myPoints[myEdges[edgeid].second]);
    1008           30 :     if (dir.length() > 0 && dir[0] == '1') {
    1009            0 :         shape = shape.reverse();
    1010              :     }
    1011           30 :     if (mySubPartsAreas.find(id) == mySubPartsAreas.end()) {
    1012            0 :         WRITE_ERRORF(TL("Unknown are for area part '%'."), myCurrentID);
    1013              :         return;
    1014              :     }
    1015              : 
    1016              :     const std::vector<long long int>& areas = mySubPartsAreas.find(id)->second;
    1017           60 :     for (std::vector<long long int>::const_iterator i = areas.begin(); i != areas.end(); ++i) {
    1018           30 :         NBDistrict* d = myShapeDistrictMap[*i];
    1019           30 :         if (d == nullptr) {
    1020            0 :             continue;
    1021              :         }
    1022           30 :         if (myDistrictShapes.find(d) == myDistrictShapes.end()) {
    1023           60 :             myDistrictShapes[d] = PositionVector();
    1024              :         }
    1025           30 :         if (dir.length() > 0 && dir[0] == '1') {
    1026            0 :             myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].second]);
    1027            0 :             myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].first]);
    1028              :         } else {
    1029           30 :             myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].first]);
    1030           30 :             myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].second]);
    1031              :         }
    1032              :     }
    1033           30 : }
    1034              : 
    1035              : 
    1036              : void
    1037            0 : NIImporter_VISUM::parse_Phases() {
    1038              :     // get the id
    1039            0 :     const std::string phaseid = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
    1040            0 :     const std::string LSAid = NBHelpers::normalIDRepresentation(myLineParser.get("LsaNr"));
    1041            0 :     const SUMOTime startTime = TIME2STEPS(getNamedFloat("GzStart", "GRUENANF"));
    1042            0 :     const SUMOTime endTime = TIME2STEPS(getNamedFloat("GzEnd", "GRUENENDE"));
    1043            0 :     const SUMOTime yellowTime = myLineParser.know("GELB") ? TIME2STEPS(getNamedFloat("GELB")) : -1;
    1044            0 :     myTLS.find(LSAid)->second->addPhase(phaseid, startTime, endTime, yellowTime);
    1045            0 : }
    1046              : 
    1047              : 
    1048            0 : void NIImporter_VISUM::parse_SignalGroupsToPhases() {
    1049              :     // get the id
    1050            0 :     std::string Phaseid = NBHelpers::normalIDRepresentation(myLineParser.get("PsNr"));
    1051            0 :     std::string LSAid = NBHelpers::normalIDRepresentation(myLineParser.get("LsaNr"));
    1052            0 :     std::string SGid = NBHelpers::normalIDRepresentation(myLineParser.get("SGNR"));
    1053              :     // insert
    1054            0 :     NIVisumTL* LSA = myTLS.find(LSAid)->second;
    1055            0 :     NIVisumTL::SignalGroup& SG = LSA->getSignalGroup(SGid);
    1056            0 :     NIVisumTL::Phase* PH = LSA->getPhases().find(Phaseid)->second;
    1057            0 :     SG.phases()[Phaseid] = PH;
    1058            0 : }
    1059              : 
    1060              : 
    1061          178 : void NIImporter_VISUM::parse_LanesConnections() {
    1062              :     NBNode* node = nullptr;
    1063              :     NBEdge* fromEdge = nullptr;
    1064              :     NBEdge* toEdge = nullptr;
    1065              :     // get the node and edges depending on network format
    1066          356 :     const std::string nodeID = getNamedString("KNOTNR", "KNOT");
    1067          178 :     if (nodeID == "0") {
    1068            0 :         fromEdge = getNamedEdge("VONSTRNR", "VONSTR");
    1069            0 :         toEdge = getNamedEdge("NACHSTRNR", "NACHSTR");
    1070            0 :         if (fromEdge == nullptr) {
    1071              :             return;
    1072              :         }
    1073              :         node = fromEdge->getToNode();
    1074            0 :         WRITE_WARNING(TL("Ignoring lane-to-lane connection (not yet implemented for this format version)"));
    1075            0 :         return;
    1076              :     } else {
    1077          356 :         node = getNamedNode("KNOTNR", "KNOT");
    1078          178 :         if (node  == nullptr) {
    1079              :             return;
    1080              :         }
    1081          356 :         fromEdge = getNamedEdgeContinuating("VONSTRNR", "VONSTR", node);
    1082          356 :         toEdge = getNamedEdgeContinuating("NACHSTRNR", "NACHSTR", node);
    1083              :     }
    1084          178 :     if (fromEdge == nullptr || toEdge == nullptr) {
    1085              :         return;
    1086              :     }
    1087              : 
    1088              :     int fromLaneOffset = 0;
    1089          178 :     if (!node->hasIncoming(fromEdge)) {
    1090              :         fromLaneOffset = fromEdge->getNumLanes();
    1091          156 :         fromEdge = getReversedContinuating(fromEdge, node);
    1092              :     } else {
    1093           22 :         fromEdge = getReversedContinuating(fromEdge, node);
    1094           44 :         NBEdge* tmp = myNetBuilder.getEdgeCont().retrieve(fromEdge->getID().substr(0, fromEdge->getID().find('_')));
    1095              :         fromLaneOffset = tmp->getNumLanes();
    1096              :     }
    1097              : 
    1098              :     int toLaneOffset = 0;
    1099          178 :     if (!node->hasOutgoing(toEdge)) {
    1100              :         toLaneOffset = toEdge->getNumLanes();
    1101           22 :         toEdge = getReversedContinuating(toEdge, node);
    1102              :     } else {
    1103          312 :         NBEdge* tmp = myNetBuilder.getEdgeCont().retrieve(toEdge->getID().substr(0, toEdge->getID().find('_')));
    1104              :         toLaneOffset = tmp->getNumLanes();
    1105              :     }
    1106              :     // get the from-lane
    1107          178 :     std::string fromLaneS = NBHelpers::normalIDRepresentation(myLineParser.get("VONFSNR"));
    1108              :     int fromLane = -1;
    1109              :     try {
    1110          178 :         fromLane = StringUtils::toInt(fromLaneS);
    1111            0 :     } catch (NumberFormatException&) {
    1112            0 :         WRITE_ERRORF(TL("A from-lane number for edge '%' is not numeric (%)."), fromEdge->getID(), fromLaneS);
    1113              :         return;
    1114            0 :     }
    1115          178 :     fromLane -= 1;
    1116          178 :     if (fromLane < 0) {
    1117            0 :         WRITE_ERRORF(TL("A from-lane number for edge '%' is not positive (%)."), fromEdge->getID(), fromLaneS);
    1118            0 :         return;
    1119              :     }
    1120              :     // get the from-lane
    1121          178 :     std::string toLaneS = NBHelpers::normalIDRepresentation(myLineParser.get("NACHFSNR"));
    1122              :     int toLane = -1;
    1123              :     try {
    1124          178 :         toLane = StringUtils::toInt(toLaneS);
    1125            0 :     } catch (NumberFormatException&) {
    1126            0 :         WRITE_ERRORF(TL("A to-lane number for edge '%' is not numeric (%)."), toEdge->getID(), toLaneS);
    1127              :         return;
    1128            0 :     }
    1129          178 :     toLane -= 1;
    1130          178 :     if (toLane < 0) {
    1131            0 :         WRITE_ERRORF(TL("A to-lane number for edge '%' is not positive (%)."), toEdge->getID(), toLaneS);
    1132            0 :         return;
    1133              :     }
    1134              :     // !!! the next is probably a hack
    1135          178 :     if (fromLane - fromLaneOffset < 0) {
    1136              :         //fromLaneOffset = 0;
    1137              :     } else {
    1138          178 :         fromLane = (int)fromEdge->getNumLanes() - (fromLane - fromLaneOffset) - 1;
    1139              :     }
    1140          178 :     if (toLane - toLaneOffset < 0) {
    1141              :         //toLaneOffset = 0;
    1142              :     } else {
    1143            0 :         toLane = (int)toEdge->getNumLanes() - (toLane - toLaneOffset) - 1;
    1144              :     }
    1145              :     //
    1146          178 :     if ((int) fromEdge->getNumLanes() <= fromLane) {
    1147            0 :         WRITE_ERRORF(TL("A from-lane number for edge '%' is larger than the edge's lane number (%)."), fromEdge->getID(), fromLaneS);
    1148            0 :         return;
    1149              :     }
    1150          178 :     if ((int) toEdge->getNumLanes() <= toLane) {
    1151            0 :         WRITE_ERRORF(TL("A to-lane number for edge '%' is larger than the edge's lane number (%)."), toEdge->getID(), toLaneS);
    1152            0 :         return;
    1153              :     }
    1154              :     //
    1155          356 :     fromEdge->addLane2LaneConnection(fromLane, toEdge, toLane, NBEdge::Lane2LaneInfoType::VALIDATED);
    1156              : }
    1157              : 
    1158              : 
    1159           47 : void NIImporter_VISUM::parse_stopPoints() {
    1160           47 :     std::string id = NBHelpers::normalIDRepresentation(myLineParser.get(KEYS.getString(VISUM_NO)));
    1161           47 :     std::string name = StringUtils::latin1_to_utf8(myLineParser.get(KEYS.getString(VISUM_NAME)));
    1162           47 :     SVCPermissions permissions = getPermissions(KEYS.getString(VISUM_TYPES), true);
    1163           47 :     NBNode* from = getNamedNodeSecure(KEYS.getString(VISUM_FROMNODE));
    1164           47 :     NBNode* to = getNamedNodeSecure(KEYS.getString(VISUM_FROMNODENO));
    1165           47 :     const std::string edgeID = myLineParser.get(KEYS.getString(VISUM_LINKNO));
    1166           47 :     if (edgeID == "") {
    1167          141 :         WRITE_WARNINGF(TL("Ignoring stopping place '%' without edge id"), id);
    1168            0 :     } else if (from == nullptr && to == nullptr) {
    1169            0 :         WRITE_WARNINGF(TL("Ignoring stopping place '%' without node information"), id);
    1170              :     } else {
    1171            0 :         NBEdge* edge = getNamedEdge(KEYS.getString(VISUM_LINKNO));
    1172            0 :         if (edge == nullptr) {
    1173            0 :             WRITE_WARNINGF(TL("Ignoring stopping place '%' with invalid edge reference '%'"), id, edgeID);
    1174            0 :             return;
    1175            0 :         } else if (from != nullptr) {
    1176            0 :             if (edge->getToNode() == from) {
    1177            0 :                 NBEdge* edge2 = myNetBuilder.getEdgeCont().retrieve("-" + edge->getID());
    1178            0 :                 if (edge2 == nullptr) {
    1179            0 :                     WRITE_WARNINGF(TL("Could not find edge with from-node '%' and base id '%' for stopping place '%'"), from->getID(), edge->getID(), id);
    1180              :                 } else {
    1181              :                     edge = edge2;
    1182              :                 }
    1183            0 :             } else if (edge->getFromNode() != from) {
    1184            0 :                 WRITE_WARNINGF(TL("Unexpected from-node '%' for edge '%' of stopping place '%'"), from->getID(), edge->getID(), id);
    1185              :             }
    1186              :         } else {
    1187            0 :             if (edge->getFromNode() == to) {
    1188            0 :                 NBEdge* edge2 = myNetBuilder.getEdgeCont().retrieve("-" + edge->getID());
    1189            0 :                 if (edge2 == nullptr) {
    1190            0 :                     WRITE_WARNINGF(TL("Could not find edge with to-node '%' and base id '%' for stopping place '%'"), to->getID(), edge->getID(), id);
    1191              :                 } else {
    1192              :                     edge = edge2;
    1193              :                 }
    1194            0 :             } else if (edge->getToNode() != to) {
    1195            0 :                 WRITE_WARNINGF(TL("Unexpected to-node '%' for edge '%' of stopping place '%'"), to->getID(), edge->getID(), id);
    1196              :             }
    1197              :         }
    1198            0 :         double relPos = StringUtils::toDouble(myLineParser.get(KEYS.getString(VISUM_RELPOS)));
    1199              :         /// @note could also retrieve Xkoord, ykoord from $HALTESTELLE
    1200            0 :         Position pos = edge->getGeometry().positionAtOffset(edge->getLength() * relPos);
    1201              : 
    1202            0 :         const double length = OptionsCont::getOptions().getFloat("osm.stop-output.length");
    1203            0 :         std::shared_ptr<NBPTStop> ptStop = std::make_shared<NBPTStop>(id, pos, edge->getID(), edge->getID(), length, name, permissions);
    1204            0 :         myNetBuilder.getPTStopCont().insert(ptStop);
    1205              :     }
    1206              : }
    1207              : 
    1208              : 
    1209              : double
    1210         1770 : NIImporter_VISUM::getWeightedFloat(const std::string& name, const std::string& suffix) {
    1211              :     try {
    1212         1770 :         std::string val = myLineParser.get(name);
    1213          902 :         if (val.find(suffix) != std::string::npos) {
    1214            0 :             val = val.substr(0, val.find(suffix));
    1215              :         }
    1216          902 :         return StringUtils::toDouble(val);
    1217          868 :     } catch (...) {}
    1218          868 :     return -1;
    1219              : }
    1220              : 
    1221              : 
    1222              : double
    1223          868 : NIImporter_VISUM::getWeightedFloat2(const std::string& name, const std::string& name2, const std::string& suffix) {
    1224          868 :     double result = getWeightedFloat(name, suffix);
    1225          868 :     if (result != -1) {
    1226              :         return result;
    1227              :     } else {
    1228          868 :         return getWeightedFloat(name2, suffix);
    1229              :     }
    1230              : }
    1231              : 
    1232              : bool
    1233            0 : NIImporter_VISUM::getWeightedBool(const std::string& name) {
    1234              :     try {
    1235            0 :         return StringUtils::toBool(myLineParser.get(name));
    1236            0 :     } catch (...) {}
    1237              :     try {
    1238            0 :         return StringUtils::toBool(myLineParser.get((name + "(IV)")));
    1239            0 :     } catch (...) {}
    1240            0 :     return false;
    1241              : }
    1242              : 
    1243              : SVCPermissions
    1244         1309 : NIImporter_VISUM::getPermissions(const std::string& name, bool warn, SVCPermissions unknown) {
    1245              :     SVCPermissions result = 0;
    1246         6477 :     for (std::string v : StringTokenizer(myLineParser.get(name), ",").getVector()) {
    1247              :         // common values in english and german
    1248              :         // || v == "funiculaire-telecabine" ---> no matching
    1249         3859 :         v = StringUtils::to_lower_case(v);
    1250         3859 :         if (v == "bus" || v == "tcsp" || v == "acces tc" || v == "Accès tc" || v == "accès tc") {
    1251            0 :             result |= SVC_BUS;
    1252         3859 :         } else if (v == "walk" || v == "w" || v == "f" || v == "ped" || v == "map") {
    1253          944 :             result |= SVC_PEDESTRIAN;
    1254         2915 :         } else if (v == "l" || v == "lkw" || v == "h" || v == "hgv" || v == "lw" || v == "truck" || v == "tru" || v == "pl") {
    1255          327 :             result |= SVC_TRUCK;
    1256         2588 :         } else if (v == "b" || v == "bike" || v == "velo") {
    1257          201 :             result |= SVC_BICYCLE;
    1258         2387 :         } else if (v == "train" || v == "rail") {
    1259            0 :             result |= SVC_RAIL;
    1260         2387 :         } else if (v == "tram") {
    1261            0 :             result |= SVC_TRAM;
    1262         2387 :         } else if (v == "p" || v == "pkw" || v == "car" || v == "c" || v == "vp" || v == "2rm") {
    1263         1367 :             result |= SVC_PASSENGER;
    1264              :         } else {
    1265         1020 :             if (warn) {
    1266         1140 :                 WRITE_WARNINGF("Encountered unknown vehicle category '" + v + "' in type '%'", myLineParser.get(KEYS.getString(VISUM_NO)));
    1267              :             }
    1268         1020 :             result |= unknown;
    1269              :         }
    1270         1309 :     }
    1271         1309 :     return result;
    1272              : }
    1273              : 
    1274              : NBNode*
    1275         4256 : NIImporter_VISUM::getNamedNode(const std::string& fieldName) {
    1276         4256 :     std::string nodeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1277         4256 :     NBNode* node = myNetBuilder.getNodeCont().retrieve(nodeS);
    1278         4256 :     if (node == nullptr) {
    1279            0 :         WRITE_ERRORF(TL("The node '%' is not known."), nodeS);
    1280              :     }
    1281         4256 :     return node;
    1282              : }
    1283              : 
    1284              : NBNode*
    1285          322 : NIImporter_VISUM::getNamedNodeSecure(const std::string& fieldName, NBNode* fallback) {
    1286          322 :     std::string nodeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1287          322 :     NBNode* node = myNetBuilder.getNodeCont().retrieve(nodeS);
    1288          322 :     if (node == nullptr) {
    1289           47 :         return fallback;
    1290              :     }
    1291              :     return node;
    1292              : }
    1293              : 
    1294              : 
    1295              : NBNode*
    1296         4096 : NIImporter_VISUM::getNamedNode(const std::string& fieldName1, const std::string& fieldName2) {
    1297         4096 :     if (myLineParser.know(fieldName1)) {
    1298          178 :         return getNamedNode(fieldName1);
    1299              :     } else {
    1300         3918 :         return getNamedNode(fieldName2);
    1301              :     }
    1302              : }
    1303              : 
    1304              : 
    1305              : NBEdge*
    1306          228 : NIImporter_VISUM::getNamedEdge(const std::string& fieldName) {
    1307          228 :     std::string edgeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1308          228 :     NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeS);
    1309          228 :     if (edge == nullptr) {
    1310            0 :         WRITE_ERRORF(TL("The edge '%' is not known."), edgeS);
    1311              :     }
    1312          228 :     return edge;
    1313              : }
    1314              : 
    1315              : 
    1316              : NBEdge*
    1317            0 : NIImporter_VISUM::getNamedEdge(const std::string& fieldName1, const std::string& fieldName2) {
    1318            0 :     if (myLineParser.know(fieldName1)) {
    1319            0 :         return getNamedEdge(fieldName1);
    1320              :     } else {
    1321            0 :         return getNamedEdge(fieldName2);
    1322              :     }
    1323              : }
    1324              : 
    1325              : 
    1326              : 
    1327              : NBEdge*
    1328          334 : NIImporter_VISUM::getReversedContinuating(NBEdge* edge, NBNode* node) {
    1329              :     std::string sid;
    1330          334 :     if (edge->getID()[0] == '-') {
    1331            0 :         sid = edge->getID().substr(1);
    1332              :     } else {
    1333          668 :         sid = "-" + edge->getID();
    1334              :     }
    1335          334 :     if (sid.find('_') != std::string::npos) {
    1336            0 :         sid = sid.substr(0, sid.find('_'));
    1337              :     }
    1338          668 :     return getNamedEdgeContinuating(myNetBuilder.getEdgeCont().retrieve(sid),  node);
    1339              : }
    1340              : 
    1341              : 
    1342              : NBEdge*
    1343         1470 : NIImporter_VISUM::getNamedEdgeContinuating(NBEdge* begin, NBNode* node) {
    1344         1470 :     if (begin == nullptr) {
    1345              :         return nullptr;
    1346              :     }
    1347              :     NBEdge* ret = begin;
    1348         1470 :     std::string edgeID = ret->getID();
    1349              :     // hangle forward
    1350         2386 :     while (ret != nullptr) {
    1351              :         // ok, this is the edge we are looking for
    1352         1470 :         if (ret->getToNode() == node) {
    1353          554 :             return ret;
    1354              :         }
    1355              :         const EdgeVector& nedges = ret->getToNode()->getOutgoingEdges();
    1356          916 :         if (nedges.size() != 1) {
    1357              :             // too many edges follow
    1358              :             ret = nullptr;
    1359          721 :             continue;
    1360              :         }
    1361          195 :         NBEdge* next = nedges[0];
    1362          390 :         if (ret->getID().substr(0, edgeID.length()) != next->getID().substr(0, edgeID.length())) {
    1363              :             // ok, another edge is next...
    1364              :             ret = nullptr;
    1365          195 :             continue;
    1366              :         }
    1367            0 :         if (next->getID().substr(next->getID().length() - node->getID().length()) != node->getID()) {
    1368              :             ret = nullptr;
    1369            0 :             continue;
    1370              :         }
    1371              :         ret = next;
    1372              :     }
    1373              : 
    1374              :     ret = begin;
    1375              :     // hangle backward
    1376          916 :     while (ret != nullptr) {
    1377              :         // ok, this is the edge we are looking for
    1378          916 :         if (ret->getFromNode() == node) {
    1379          916 :             return ret;
    1380              :         }
    1381              :         const EdgeVector& nedges = ret->getFromNode()->getIncomingEdges();
    1382            0 :         if (nedges.size() != 1) {
    1383              :             // too many edges follow
    1384              :             ret = nullptr;
    1385              :             continue;
    1386              :         }
    1387            0 :         NBEdge* next = nedges[0];
    1388            0 :         if (ret->getID().substr(0, edgeID.length()) != next->getID().substr(0, edgeID.length())) {
    1389              :             // ok, another edge is next...
    1390              :             ret = nullptr;
    1391              :             continue;
    1392              :         }
    1393            0 :         if (next->getID().substr(next->getID().length() - node->getID().length()) != node->getID()) {
    1394              :             ret = nullptr;
    1395              :             continue;
    1396              :         }
    1397              :         ret = next;
    1398              :     }
    1399              :     return nullptr;
    1400              : }
    1401              : 
    1402              : 
    1403              : NBEdge*
    1404          952 : NIImporter_VISUM::getNamedEdgeContinuating(const std::string& fieldName, NBNode* node) {
    1405          952 :     std::string edgeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1406          952 :     NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeS);
    1407          952 :     if (edge == nullptr) {
    1408            0 :         WRITE_ERRORF(TL("The edge '%' is not known."), edgeS);
    1409              :     }
    1410         1904 :     return getNamedEdgeContinuating(edge, node);
    1411              : }
    1412              : 
    1413              : 
    1414              : NBEdge*
    1415          356 : NIImporter_VISUM::getNamedEdgeContinuating(const std::string& fieldName1, const std::string& fieldName2,
    1416              :         NBNode* node) {
    1417          356 :     if (myLineParser.know(fieldName1)) {
    1418          356 :         return getNamedEdgeContinuating(fieldName1, node);
    1419              :     } else {
    1420            0 :         return getNamedEdgeContinuating(fieldName2, node);
    1421              :     }
    1422              : }
    1423              : 
    1424              : 
    1425              : NBEdge*
    1426            0 : NIImporter_VISUM::getEdge(NBNode* FromNode, NBNode* ToNode) {
    1427              :     EdgeVector::const_iterator i;
    1428            0 :     for (i = FromNode->getOutgoingEdges().begin(); i != FromNode->getOutgoingEdges().end(); i++) {
    1429            0 :         if (ToNode == (*i)->getToNode()) {
    1430              :             return (*i);
    1431              :         }
    1432              :     }
    1433              :     //!!!
    1434              :     return nullptr;
    1435              : }
    1436              : 
    1437              : 
    1438              : double
    1439         2474 : NIImporter_VISUM::getNamedFloat(const std::string& fieldName) {
    1440         2474 :     std::string value = myLineParser.get(fieldName);
    1441         4948 :     if (StringUtils::endsWith(myLineParser.get(fieldName), "km/h")) {
    1442            0 :         value = value.substr(0, value.length() - 4);
    1443              :     }
    1444         4948 :     return StringUtils::toDouble(value);
    1445              : }
    1446              : 
    1447              : 
    1448              : double
    1449            0 : NIImporter_VISUM::getNamedFloat(const std::string& fieldName, double defaultValue) {
    1450              :     try {
    1451            0 :         return StringUtils::toDouble(myLineParser.get(fieldName));
    1452            0 :     } catch (...) {
    1453              :         return defaultValue;
    1454            0 :     }
    1455              : }
    1456              : 
    1457              : 
    1458              : double
    1459         1088 : NIImporter_VISUM::getNamedFloat(const std::string& fieldName1, const std::string& fieldName2) {
    1460         1088 :     if (myLineParser.know(fieldName1)) {
    1461            0 :         return getNamedFloat(fieldName1);
    1462              :     } else {
    1463         1088 :         return getNamedFloat(fieldName2);
    1464              :     }
    1465              : }
    1466              : 
    1467              : 
    1468              : double
    1469            0 : NIImporter_VISUM::getNamedFloat(const std::string& fieldName1, const std::string& fieldName2,
    1470              :                                 double defaultValue) {
    1471            0 :     if (myLineParser.know(fieldName1)) {
    1472            0 :         return getNamedFloat(fieldName1, defaultValue);
    1473              :     } else {
    1474            0 :         return getNamedFloat(fieldName2, defaultValue);
    1475              :     }
    1476              : }
    1477              : 
    1478              : 
    1479              : std::string
    1480          546 : NIImporter_VISUM::getNamedString(const std::string& fieldName) {
    1481         1092 :     return NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
    1482              : }
    1483              : 
    1484              : 
    1485              : std::string
    1486          362 : NIImporter_VISUM::getNamedString(const std::string& fieldName1,
    1487              :                                  const std::string& fieldName2) {
    1488          362 :     if (myLineParser.know(fieldName1)) {
    1489          178 :         return getNamedString(fieldName1);
    1490              :     } else {
    1491          184 :         return getNamedString(fieldName2);
    1492              :     }
    1493              : }
    1494              : 
    1495              : 
    1496              : 
    1497              : 
    1498              : 
    1499              : 
    1500              : NBNode*
    1501            0 : NIImporter_VISUM::buildDistrictNode(const std::string& id, NBNode* dest,
    1502              :                                     bool isSource) {
    1503              :     // get the district
    1504            0 :     NBDistrict* dist = myNetBuilder.getDistrictCont().retrieve(id);
    1505            0 :     if (dist == nullptr) {
    1506              :         return nullptr;
    1507              :     }
    1508              :     // build the id
    1509              :     std::string nid;
    1510            0 :     nid = id + "-" + dest->getID();
    1511            0 :     if (!isSource) {
    1512            0 :         nid = "-" + nid;
    1513              :     }
    1514              :     // insert the node
    1515            0 :     if (!myNetBuilder.getNodeCont().insert(nid, dist->getPosition())) {
    1516            0 :         WRITE_ERRORF(TL("Could not build connector node '%'."), nid);
    1517              :     }
    1518              :     // return the node
    1519            0 :     return myNetBuilder.getNodeCont().retrieve(nid);
    1520              : }
    1521              : 
    1522              : 
    1523              : bool
    1524          813 : NIImporter_VISUM::checkNodes(NBNode* from, NBNode* to)  {
    1525          813 :     if (from == nullptr) {
    1526            0 :         WRITE_ERROR(TL(" The from-node was not found within the net"));
    1527              :     }
    1528          813 :     if (to == nullptr) {
    1529            0 :         WRITE_ERROR(TL(" The to-node was not found within the net"));
    1530              :     }
    1531          813 :     if (from == to) {
    1532            0 :         WRITE_ERROR(TL(" Both nodes are the same"));
    1533              :     }
    1534          813 :     return from != nullptr && to != nullptr && from != to;
    1535              : }
    1536              : 
    1537              : bool
    1538            0 : NIImporter_VISUM::isSplitEdge(NBEdge* edge, NBNode* node) {
    1539            0 :     return (edge->getID().length() > node->getID().length() + 1
    1540            0 :             && (edge->getID().substr(edge->getID().length() - node->getID().length() - 1) == "_" + node->getID()));
    1541              : }
    1542              : 
    1543              : void
    1544            0 : NIImporter_VISUM::loadLanguage(const std::string& file) {
    1545            0 :     std::ifstream strm(file.c_str());
    1546            0 :     if (!strm.good()) {
    1547            0 :         throw ProcessError(TLF("Could not load VISUM language map from '%'.", file));
    1548              :     }
    1549            0 :     while (strm.good()) {
    1550              :         std::string keyDE;
    1551              :         std::string keyNew;
    1552            0 :         strm >> keyDE;
    1553            0 :         strm >> keyNew;
    1554              :         if (KEYS.hasString(keyDE)) {
    1555            0 :             VISUM_KEY key = KEYS.get(keyDE);
    1556            0 :             KEYS.remove(keyDE, key);
    1557            0 :             KEYS.insert(keyNew, key);
    1558            0 :         } else if (keyDE != "") {
    1559            0 :             WRITE_WARNINGF(TL("Unknown entry '%' in VISUM language map"), keyDE);
    1560              :         }
    1561              :     }
    1562              : 
    1563            0 : }
    1564              : 
    1565              : 
    1566              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1