LCOV - code coverage report
Current view: top level - src/netimport - NIImporter_VISUM.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 59.7 % 766 457
Test Date: 2026-03-02 16:00:03 Functions: 75.0 % 52 39

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

Generated by: LCOV version 2.0-1