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

Generated by: LCOV version 2.0-1