/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file NIImporter_VISUM.h14/// @author Daniel Krajzewicz15/// @author Michael Behrisch16/// @date Fri, 19 Jul 200217///18// A VISUM network importer19/****************************************************************************/20#pragma once21#include <config.h>2223#include <string>24#include <map>25#include <vector>26#include <netbuild/NBCapacity2Lanes.h>27#include <utils/importio/LineHandler.h>28#include <utils/importio/LineReader.h>29#include <utils/importio/NamedColumnsParser.h>30#include "NIVisumTL.h"313233// ===========================================================================34// class declaration35// ===========================================================================36class OptionsCont;37class NBNetBuilder;38class NBNodeCont;39class NBEdgeCont;40class NBNode;41class NBEdge;424344// ===========================================================================45// class declaration46// ===========================================================================47/**48* @class NIImporter_VISUM49* @brief A VISUM network importer50*51* This class build an internal list of those VISUM-db entries which are52* supported, first. This list is sorted in a way that the parsed dbs can53* build upon each other as their related structures within the XML-input.54* So, nodes are loaded first, then edges, etc.55*56* Because these structures may have a different order within the VISUM-file57* than we need, at first the file is scanned and any occurrence of one of the58* searched dbs is saved. That's where the "Found $XXX at YYY" are printed.59* "YYY" is the character position within the file.60*61* In a second step, the dbs are parsed in the order we need. It is asked for62* each subsequently whether it was found and if so, the proper parse_XXX()63* method is called.64*/65class NIImporter_VISUM {66public:67/** @brief Loads network definition from the assigned option and stores it in the given network builder68*69* If the option "visum" is set, the file stored therein is read and70* the network definition stored therein is stored within the given network71* builder.72*73* If the option "visum" is not set, this method simply returns.74*75* @param[in] oc The options to use76* @param[in] nb The network builder to fill77*/78static void loadNetwork(const OptionsCont& oc, NBNetBuilder& nb);798081protected:82/** @brief constructor83*84* Builds the list of typed db parsers ("TypeParser") and stores them in85* mySingleDataParsers in the order the according db values must be parsed.86*87* @param[in,out] nb the network builder (storage) to fill with parsed values88* @param[in] file The name of the file to parse89* @param[in] capacity2Lanes The converter from flow to lanes90* @param[in] useVisumPrio Information whether the VISUM type's priority shall be used91*/92NIImporter_VISUM(NBNetBuilder& nb, const std::string& file,93NBCapacity2Lanes capacity2Lanes, bool useVisumPrio,94const std::string& languageFile);959697/// @brief destructor98~NIImporter_VISUM();99100101/** @brief Parses the VISUM-network file storing the parsed structures within myNetBuilder102*103* At first, it is checked whether the file can be opened. A ProcessError is thrown104* if not. Otherwise, the file is scanned for occurrences of db table begins. For each found105* db, its position within the file, and the column names are stored in the according106* TypeParser. After this, the sorted list of type parsers is one through and each107* found is used to parse the entries at the found positions using the found column names.108*109* @exception ProcessError If the file could not be opened110*/111void load();112113private:114/** @brief Returns the value from the named column as a float115*116* @param[in] fieldName Name of the column to extract the float from117* @return The parsed real118* @exception OutOfBoundsException If the current data line has less entries than the float's position119* @exception NumberFormatException If the float is not numeric120* @exception UnknownElement If the named data field is not in the line121*/122double getNamedFloat(const std::string& fieldName);123124/** @brief The same, but two different names for the field are allowed125*126* @param[in] fieldName1 Name of the first column to extract the float from127* @param[in] fieldName2 Name of the second column to extract the efloat from128* @return The parsed real129* @exception OutOfBoundsException If the current data line has less entries than the float's position130* @exception NumberFormatException If the float is not numeric131* @exception UnknownElement If the named data field is not in the line132*/133double getNamedFloat(const std::string& fieldName1, const std::string& fieldName2);134135136/** @brief Returns the value from the named column as a float or the default value if an error occurs137*138* @param[in] fieldName Name of the column to extract the float from139* @param[in] defaultValue The default to return in the case of an error140* @return The parsed real or the default value if an error while parsing occurred141*/142double getNamedFloat(const std::string& fieldName, double defaultValue);143144/** @brief The same, but two different names for the field are allowed145*146* @param[in] fieldName1 Name of the first column to extract the float from147* @param[in] fieldName2 Name of the second column to extract the efloat from148* @param[in] defaultValue The default to return in the case of an error149* @return The parsed real or the default value if an error while parsing occurred150*/151double getNamedFloat(const std::string& fieldName1, const std::string& fieldName2,152double defaultValue);153154155/** @brief Returns the value from the named column as a normalised string156*157* "Normalised" means herein that the leading '0' (zeros) are prunned.158*159* @param[in] fieldName Name of the column to extract the string from160* @return The parsed, normalised string161* @exception OutOfBoundsException If the current data line has less entries than the string's position162* @exception NumberFormatException If the string is not numeric163* @exception UnknownElement If the named data field is not in the line164*/165std::string getNamedString(const std::string& fieldName);166167/** @brief The same, but two different names for the field are allowed168*169* @param[in] fieldName1 Name of the first column to extract the string from170* @param[in] fieldName2 Name of the second column to extract the string from171* @return The parsed, normalised string172* @exception OutOfBoundsException If the current data line has less entries than the string's position173* @exception NumberFormatException If the string is not numeric174* @exception UnknownElement If the named data field is not in the line175*/176std::string getNamedString(const std::string& fieldName1, const std::string& fieldName2);177178179/** @brief tries to get a double which is possibly assigned to a certain modality180*181* When the double cannot be extracted using the given name, "(IV)" is182* appended to the begin of the name. Note that this function does not183* yet support public traffic.184*185* @param[in] name Name of the column to extract the real from186* @return The real stored under the named column, or if not found the one from name + suffix, or if not found -1187*/188double getWeightedFloat(const std::string& name, const std::string& suffix);189190/// @brief as above but with two alternative names191double getWeightedFloat2(const std::string& name, const std::string& name2, const std::string& suffix);192193/// @brief parse permissions194SVCPermissions getPermissions(const std::string& name, bool warn = false, SVCPermissions unknown = SVCAll);195196/** @brief tries to get a bool which is possibly assigned to a certain modality197*198* When the bool cannot be extracted using the given name, "IV" is199* appended to the begin of the name. Note that this function does not200* yet support public traffic.201*202* @param[in] name Name of the column to extract the bool from203* @return The bool stored under the named column, or if not found the one from "(IV)"+name, or if not found false204*/205bool getWeightedBool(const std::string& name);206207208/** @brief Tries to get the node which name is stored in the given field209*210* If the field can not be parsed, an exception is thrown. Prints an error if the211* node could not be found, returning 0. Otherwise, if the field could be parsed212* and the node was found, this node is returned.213*214* @param[in] fieldName Name of the column to extract the node's name from215* @return An already known node with the found name216* @exception OutOfBoundsException If the current data line has less entries than the node id's position217* @exception NumberFormatException If the node id is not numeric218* @exception UnknownElement If the named data field is not in the line219*/220NBNode* getNamedNode(const std::string& fieldName);221NBNode* getNamedNodeSecure(const std::string& fieldName, NBNode* fallback = 0);222223/** @brief The same, but two different names for the field are allowed224*225* @param[in] fieldName1 Name of the first column to extract the node's name from226* @param[in] fieldName2 Name of the second column to extract the node's name from227* @return An already known node with the found name228* @exception OutOfBoundsException If the current data line has less entries than the node id's position229* @exception NumberFormatException If the node id is not numeric230* @exception UnknownElement If the named data field is not in the line231*/232NBNode* getNamedNode(const std::string& fieldName1, const std::string& fieldName2);233234235/** @brief Tries to get the edge which name is stored in the given field236*237* If the field can not be parsed, an exception is thrown. Prints an error if the238* edge could not be found, returning 0. Otherwise, if the field could be parsed239* and the edge was found, this edge is returned.240*241* @param[in] fieldName Name of the column to extract the edge's name from242* @return An already known edge with the found name243* @exception OutOfBoundsException If the current data line has less entries than the edge id's position244* @exception NumberFormatException If the edge id is not numeric245* @exception UnknownElement If the named data field is not in the line246*/247NBEdge* getNamedEdge(const std::string& fieldName);248249/** @brief The same, but two different names for the field are allowed250*251* @param[in] fieldName1 Name of the first column to extract the edge's name from252* @param[in] fieldName2 Name of the second column to extract the edge's name from253* @return An already known edge with the found name254* @exception OutOfBoundsException If the current data line has less entries than the edge id's position255* @exception NumberFormatException If the edge id is not numeric256* @exception UnknownElement If the named data field is not in the line257*/258NBEdge* getNamedEdge(const std::string& fieldName1, const std::string& fieldName2);259260261/** @brief Tries to get the edge which name is stored in the given field262* continuating the search for a subedge that ends at the given node263*264* If the field can not be parsed, an exception is thrown. Prints an error if the265* edge could not be found, returning 0. Otherwise, if the field could be parsed266* and the edge was found, this edge is returned.267*268* @param[in] fieldName Name of the column to extract the edge's name from269* @param[in] node The node the consecutive edge must end at in order to be returned270* @return The edge's continuation up to the given node, 0 if not found271* @exception OutOfBoundsException If the current data line has less entries than the edge id's position272* @exception NumberFormatException If the edge id is not numeric273* @exception UnknownElement If the named data field is not in the line274*/275NBEdge* getNamedEdgeContinuating(const std::string& fieldName, NBNode* node);276277/** @brief The same, but two different names for the field are allowed278*279* @param[in] fieldName1 Name of the first column to extract the edge's name from280* @param[in] fieldName2 Name of the second column to extract the edge's name from281* @param[in] node The node the consecutive edge must end at in order to be returned282* @return The edge's continuation up to the given node, 0 if not found283* @exception OutOfBoundsException If the current data line has less entries than the edge id's position284* @exception NumberFormatException If the edge id is not numeric285* @exception UnknownElement If the named data field is not in the line286*/287NBEdge* getNamedEdgeContinuating(const std::string& fieldName1, const std::string& fieldName2,288NBNode* node);289290/** @brief The same, but for an already given edge291*292* @param[in] begin The edge to get the continuation of293* @param[in] node The node the consecutive edge must end at in order to be returned294* @return The edge's continuation up to the given node, 0 if not found295*/296NBEdge* getNamedEdgeContinuating(NBEdge* begin, NBNode* node);297298299/** @brief Returns the edge that connects both nodes300*301* @param[in] FromNode Name of the node the edge shall start at302* @param[in] ToNode Name of the node the edge shall end at303* @return The edge connecting both nodes, 0 if no such edge exists304*/305NBEdge* getEdge(NBNode* FromNode, NBNode* ToNode);306307308/** @brief Returns the opposite direction of the given edge309*310* Because the opposite direction edge may be split, not the plain opposite311* edge, the one which name is obtained by adding/removing the leading '-', is returned,312* but its continuation until the named node.313*314* @param[in] edge Name of the edge to find the opposite of315* @param[in] node Name of the node the opposite edge's continuation must end at316* @return The found opposite edge's continuation, 0 if not found317*/318NBEdge* getReversedContinuating(NBEdge* edge, NBNode* node);319320321/** @brief Builds a node for the given district and returns it322*323* If the district does not exist, an error is generated and 0 returned. Otherwise324* a position for the new node is computed and the new node is built using a combination325* of the district name and the node name as id. If Inserting this node into326* the net builder fails, zero is returned.327*328* @param[in] id Name of the district329* @param[in] dest Name of the according network node330* @param[in] isSource Information whether this node will be used as a source331* @return The built node, zero if an error occurred332*/333NBNode* buildDistrictNode(const std::string& id, NBNode* dest, bool isSource);334335336/** @brief Returns whether both nodes are a valid combination of from/to-nodes337*338* They are valid if both are !=0 and differ.339*340* @param[in] from The from-node341* @param[in] from The to-node342* @return Whether the nodes may be used343*/344bool checkNodes(NBNode* from, NBNode* to);345346347private:348/**349* @brief Definition of a function for parsing a single line from a certain db350*351* This function may assume that both the LineParser is initialised352* with the current line.353*/354typedef void (NIImporter_VISUM::*ParsingFunction)();355356/**357* @struct TypeParser358* @brief A complete call description for parsing a single db.359*/360struct TypeParser {361/** @brief The name of the db362*363* Initialised in the constructor */364std::string name;365366/** @brief Pointer to the function used for parsing367*368* Initialised in the constructor */369ParsingFunction function;370371/** @brief Position of the according db within the file372*373* Set to -1 in the constructor, and reset to the position while374* scanning the file if the according db was found */375long position;376377/** @brief The column names378*379* Set while scanning the file if the according db was found */380std::string pattern;381382};383384385386/// @brief Parses VSYS387void parse_VSysTypes();388389/// @brief Parses STRECKENTYP390void parse_Types();391392/// @brief Parses KNOTEN393void parse_Nodes();394395/// @brief Parses BEZIRK396void parse_Districts();397398/// @brief Parses PUNKT399void parse_Point();400401402/// @brief Parses STRECKE/STRECKEN403void parse_Edges();404405/// @brief Parses FLAECHENELEMENT406void parse_PartOfArea();407408/// @brief Parses FLAECHENELEMENT409void parse_Kante();410411412/// @brief Parses ANBINDUNG413void parse_Connectors();414void parse_Connectors_legacy();415416/// @brief Parses ABBIEGEBEZIEHUNG/ABBIEGER417void parse_Turns();418419/// @brief Parses STRECKENPOLY420void parse_EdgePolys();421422/// @brief Parses FAHRSTREIFEN423void parse_Lanes();424425/// @brief Parses LSA/SIGNALANLAGE426void parse_TrafficLights();427428/// @brief Parses KNOTENZULSA/SIGNALANLAGEZUKNOTEN429void parse_NodesToTrafficLights();430431/// @brief Parses LSASIGNALGRUPPE/SIGNALGRUPPE432void parse_SignalGroups();433434/// @brief Parses ABBZULSASIGNALGRUPPE/SIGNALGRUPPEZUABBIEGER435void parse_TurnsToSignalGroups();436437/// @brief Parses ABBZULSASIGNALGRUPPE/SIGNALGRUPPEZUABBIEGER438void parse_AreaSubPartElement();439440/// @brief Parses LSAPHASE/PHASE441void parse_Phases();442443/// @brief Parses LSASIGNALGRUPPEZULSAPHASE444void parse_SignalGroupsToPhases();445446/// @brief Parses FAHRSTREIFENABBIEGER447void parse_LanesConnections();448449/// @brief Parses HALTEPUNKT (public transport stop locations)450void parse_stopPoints();451452/** @brief Adds a parser into the sorted list of parsers to use453*454* @param[in] name db name to assign the parser to455* @param[in] function The function to use for parsing the named db456*/457void addParser(const std::string& name, ParsingFunction function);458459private:460461/// @brief whether the edge id ends with _nodeID462static bool isSplitEdge(NBEdge* edge, NBNode* node);463464465private:466/// @brief The network builder to fill with loaded values467NBNetBuilder& myNetBuilder;468469/// @brief The name of the parsed file, for error reporting470std::string myFileName;471472/// @brief The line reader to use to read from the file473LineReader myLineReader;474475/** @brief the parser to parse the information from the data lines476*477* the order of columns within the visum format seems to vary, so a named parser is needed */478NamedColumnsParser myLineParser;479480/// @brief The converter to compute the lane number of edges from their capacity481NBCapacity2Lanes myCapacity2Lanes;482483/// @brief Definition of a storage for vsystypes484typedef std::map<std::string, std::string> VSysTypeNames;485/// @brief The used vsystypes486VSysTypeNames myVSysTypes;487488/// @brief Definition of the list of known parsers489typedef std::vector<TypeParser> ParserVector;490/// @brief List of known parsers491ParserVector mySingleDataParsers;492493/// @brief Definition of a map for loaded traffic lights (id->tls)494typedef std::map<std::string, NIVisumTL*> NIVisumTL_Map;495/// @brief List of visum traffic lights496NIVisumTL_Map myTLS;497498/// @brief Already read edges499std::vector<std::string > myTouchedEdges;500501/// @brief Information whether VISUM priority information shall be used502bool myUseVisumPrio;503504/// @brief The name of the currently parsed item used for error reporting505std::string myCurrentID;506507508/// @brief A map of point ids to positions509std::map<long long int, Position> myPoints;510511/// @brief A map of edge (not road, but "edge" in this case) ids to from/to-points512std::map<long long int, std::pair<long long int, long long int> > myEdges;513514/// @brief A map from district shape definition name to the district515std::map<long long int, NBDistrict*> myShapeDistrictMap;516517/// @brief A map from area parts to area ids518std::map<long long int, std::vector<long long int> > mySubPartsAreas;519520/// @brief A temporary storage for district shapes as they are filled incrementally521std::map<NBDistrict*, PositionVector> myDistrictShapes;522523protected:524/**525* @enum VISUM keys526* @brief Numbers representing VISUM keywords527*/528enum VISUM_KEY {529VISUM_SYS,530VISUM_LINKTYPE,531VISUM_NODE,532VISUM_DISTRICT,533VISUM_POINT,534VISUM_LINK,535VISUM_V0,536VISUM_TYPES,537VISUM_RANK,538VISUM_CAPACITY,539VISUM_XCOORD,540VISUM_YCOORD,541VISUM_FROMNODE,542VISUM_TONODE,543VISUM_TYPE,544VISUM_TYP,545VISUM_ID,546VISUM_CODE,547VISUM_DISTRICT_CONNECTION,548VISUM_SOURCE_DISTRICT,549VISUM_FROMNODENO,550VISUM_DIRECTION,551VISUM_SURFACEID,552VISUM_FACEID,553VISUM_FROMPOINTID,554VISUM_TOPOINTID,555VISUM_EDGE,556VISUM_VIANODENO,557VISUM_NUMLANES,558VISUM_TURN,559VISUM_INDEX,560VISUM_LINKPOLY,561VISUM_SURFACEITEM,562VISUM_FACEITEM,563VISUM_EDGEID,564VISUM_ORIGIN,565VISUM_DESTINATION,566VISUM_STOPPOINT,567VISUM_NAME,568VISUM_LINKNO,569VISUM_RELPOS,570// polyconvert keys added to avoid warnings571VISUM_CATID,572VISUM_EDGEITEM,573VISUM_POICATEGORY,574VISUM_NO // must be the last one575};576577/// Strings for the keywords578static StringBijection<VISUM_KEY>::Entry KEYS_DE[];579580/// @brief link directions581static StringBijection<VISUM_KEY> KEYS;582583void loadLanguage(const std::string& file);584};585586587