Developer/How To/Net Importer
In the following, advices on implementing a new network importer are given-
Implementing an own network import module is very easy. The following steps are necessary:
- write methods which read and parse the information from the original file
- insert parsed values into the netbuilding containers
- make the network importer know and use your code
- submit your code
Yes, that's all. Still, the three steps are described more detailed in the following sections.
Building a Reader
There are some conventions on network importers we try to follow. They are not mandatory, but they are assumed to assure the code's extendibility and to force a higher quality of the code.
When starting to write your own importer, you should consider to base it on an existing one. NIImporter_OpenStreetMap.*, NIXML...Handler.* are examples of reading network descriptions form XML files. NIImporter_VISUM.* and NIImporter_DlrNavteq.* read plain text files, formatted in different ways. All these modules are located in <SUMO_HOME>/src/netimport and of course, your import should be placed here, too.
Calling the Reader
Before adding a call to the init-function of your network importer, you have to add according options; otherwise the first call will end with an error due to accessing an unknown option. The options have to be added to void NIFrame::fillOptions().
Then, you can make the importing facility know your parser by including the .h-file of your parser to NILoader.cpp and add a call to his loadNetwork-method within void NILoader::load(OptionsCont &oc).
In most cases, edges, nodes, traffic lights, connections between edges, and other road network attributes are given explicitly and separated. The information must be imported in the correct order. The following order is right:
- edges (need references to origin and to destination nodes)
- connections between edges (need usually references to edges)
- traffic lights (need references to nodes)
Some more outrageous programmers may try to optimise the order a bit if the original data is aligned different. This may be possible in some cases.
In the case nodes, edges, and other information are parsed from several files, the import order must be considered. Of course, it is also possible to store data in temporary containers. Still, this should be avoided as it increases memory consumption, and yes, memory consumption is one of the major problems for the network building process. In the case temporary containers are used, they must of course be cleared before returning from importing.
Starting to Parse
All importers have a static method named "loadNetwork" which starts the parsing. This method is responsible for starting the import if the according options are set and to assure the read values are stored for further processing within the according netbuilding containers. For this purpose, it is necessary to have the options and the netbuilding structure be given to the importer, making the call have the following fingerprint:
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb);
At first, this method asks whether the option which makes NETCONVERT read a file of the according format is set and whether the set value is right. By now, this means only that a check whether the given file(s) really exist(s) is made, not whether it is well formatted or valid in any means. The method FileHelpers::exists(<FILE>) returns whether a given file is existing.
After the file has been checked for being existent, a parser is built and started.
You may have noticed, that some of the import parsers allow to give more than one file, divided by ','. This is of a great help sometimes, still it is not mandatory. It is up to you to decide whether your importer should be able to handle several files or not.
Different formats have different sources for being errornous. In some cases, heuristics may have to be applied during the parsing. In all cases something is strange - and it is not strange each time a network from the given format is imported - a warning should be generated. This is done by calling the macro
If the odd behaviour completely disallows further processing of the imported file, or in the case a read value is not in the right format (a string is read, though a floating point number was awaited, for example), a ProcessError should be thrown. The exception must have an information about the error, for example:
throw ProcessError("Number of lanes is <0");
Yes, the decision whether a strange value is an error or a warning is sometimes difficult.
Adding read Values to the netbuilding Containers
After the definition of a node, an edge, or anything else has been parsed, the according structure must be built and inserted into the according netbuilding container.
|NBNode||A node (intersection, junction)|
|NBEdge||An edge (road, street)|
The following table shows which definitions are stored into which containers:
In most cases, these methods return whether the addition was successful. If it was not, there probably is already an object with the same name. Normally, the imported networks we have dealt with so far did not contain duplicates - with the exception of edges which may bidirectional. In the case the object could not been added, you have to delete it explicitly. In the case your format is known to contain duplicates, you should ask whether a duplicate was already built and only if not, build the instance.
Submitting the Code
In the case you do not have a write access to the repository, we would be very happy if you could issue a pull request or send a patch against a recent version to the sumo-devel mailing list.