Converter Network examples

Examples on how PLANit network converter reader/writer implementations

Here we provide you with a number of examples to convert networks from one format to another by leveraging the PLANit memory model as an intermediary.

All converters adopt the same approach in setting up a network converter. It requires a NetworkReader implementation, a NetworkWriter implementation, and a NetworkConverter instance. PLANit provides factory classes for each converter type, e.g., the NetworkConverterFactory can be used create a NetworkConverter. Then each implementation of a reader and/or writer also provides their respective factory class for the creation of instances, e.g., the PLANit native format reader/writers can be created via the PlanitNetworkReaderFactory.create() and PlanitNetworkWriterFactory.create() methods, respectively. Other supported formats (should) follow the same approach. And if desired, the user can create their own reader/writer imlpementation as well.

Further, each network reader and writer must provide access to user configurable settings in the same way, namely via a .getSettings() method. This allows the user to configure the reader and writer before conducting any conversion. Some settings must be configured otherwise the reader/writer might fail. If this is the case, the factory will provide a .create() method that allows you to immediately provide the mandatory inputs upon creation (or alternatively they can be manually set afterwards).

Prerequisites:

  • It is assumed you are familiar with the data formats of the converters discussed here, otherwise see Data formats

Note that the required Java imports are not listed in these examples as it is expected that the user has access to an IDE (like Eclipse), where this is auto-suggested upon usage.

Example From To Name Description
1 PLANit PLANit Minimum example Most basic example of parsing and writing both in PLANit format
2 PLANit MATSim Matsim writer example Example of persisting network in MATSim format
3 PLANit SHAPE SHAPE (gis) writer example Example of persisting network in Shape (gis) format
4 OSM PLANit OSM reader base example Example of reading a (car-only) network from Open Street Map format
5 OSM PLANit OSM reader rail example Example of reading a rail-only network from Open Street Map format
6 OSM PLANit OSM reader waterways example Example of reading a ferry-only network from Open Street Map format
7 TNTP PLANit TNTP reader example Example of reading a TNTP network and converting it to PLANit format

Minimum example

In this example we simply parse a network in the PLANit XML format and then persist it again in the same format, with the absolute minimum of configuration. See also Data formats/Input/Default section for more information on the PLANit XML network data format.

Compulsory settings

the PLANit reader/writer has the following compulsory settings that must be configured, either by providing them to the factory method, or by configuring them after the instance is created:

reader:

  • Input directory, to look for the network file

writer:

  • Output directory, to store the result network in

PLANit example

// imports here...

public class MinimumExample {

    public void converterExample(String inputDir, String outputDir) {

        /* reader */
        PlanitNetworkReader planitReader = PlanitNetworkReaderFactory.create(inputDir);

        /* writer */
        PlanitNetworkWriter planitWriter = PlanitNetworkWriterFactory.create(outputDir);

        /* convert */
        NetworkConverterFactory.create(planitReader, planitWriter).convert();
    }
}

MATSim writer example

Here, we parse PLANit network in the native XML format and then persist it as a MATSim network. To enhance the quality of the network when viewing it in VIA, we configure the writer such that it produces an additional geometry file that contains the shapes of each link beyond the two extreme nodes. See also Data formats/Input/MATSim section for more information on the MATSim network data format.

Also, when creating the MATSim writer you can explicitly provide the name of the country the network resides in. This is useful in case you do not wish to use the coordinate reference system (crs) of the network created by the reader, but want PLANit to determine a crs based on the country name provided. If the provided country is not supported, PLANit will revert to the network’s crs. Alternatively, the user can set the desired crs explicitly by creating one and providing it to the writer via .getSettings().setDestinationCoordinateReferenceSystem(). Whenever the destination crs differs from the network’s crs all geometries are transformed in the desired projection when persisting.

Currently, the MATSim network only supports PLANit networks with predefined modes via its default mapping, custom PLANit modes have to be manually added to the mapping if they are to be preserved.

The default mode mapping in the MATSim writer maps all public transport modes to a single MATSim mode “pt”. If this is not desired, the user needs to override this mapping manually via the settings.

Compulsory settings

The MATSim writer has the following compulsory settings that must be configured, either by providing them to the factory method, or by configuring them after the instance is created:

  • Output directory to store the result network in

MATSim Example

// imports here...

public class PlanitToMatsimExample {

    public void australianConverterExample(String inputDir, String outputDir) {
        
        /* reader */
        PlanitNetworkReader planitReader = PlanitNetworkReaderFactory.create(inputDir);

        /* writer with hint on input Crs to expect*/
        MatsimNetworkWriter matsimWriter = MatsimNetworkWriterFactory.create(outputDir, CountryNames.AUSTRALIA);
        /* settings -> detailed geometry */
        matsimWriter.getSettings().setGenerateDetailedLinkGeometryFile(true);
        /* settings -> set destination crs */
        final CoordinateReferenceSystem crs = PlanitCrsUtils.createCoordinateReferenceSystem("<srsName>");
        matsimWriter.getSettings().setDestinationCoordinateReferenceSystem(crs);

        /* convert */
        NetworkConverterFactory.create(planitReader, matsimWriter).convert();
    }
}

At this stage only writer implementations are available for MATSim, a reader might be added in future versions.

Shape writer example

Here, we parse a PLANit network in the native XML format and then persist it in the form of Shape files that can beloaded into a GIS application such as Qgis, or ArcGis. Since Shape files only support a single geometry entitity, i.e., just points, or just edges, etc. The shape writer will produce mroe than a single file for the network conversion. Each of these files (layers) can be named and/or switched on/off via the settings individually.

Compulsory settings

The Geometry shape writer has the following compulsory settings that must be configured, either by providing them to the factory method, or by configuring them after the instance is created:

  • Output directory to store the resulting shape files in

Shape geometry Example

// imports here...

public class PlanitToShapeExample {

    public void australianConverterExample(String inputDir, String outputDir) {
        
        /* reader */
        PlanitNetworkReader planitReader = PlanitNetworkReaderFactory.create();
        planitReader.getSettings().setInputDirectory(inputDir);

        /* geometry writer with hint on input Crs to expect, default geometry used is shape file */
        GeometryNetworkWriter geometryWriter = GeometryNetworkWriterFactory.create(outputDir, CountryNames.AUSTRALIA);
        
        /* convert */
        NetworkConverterFactory.create(planitReader, geometryWriter).convert();
    }
}

At this stage only writer implementations are available for geometries/shapes, a reader might be added in future versions.

Open Street Map reader simple example

The Open Street Map reader is more than just a reader for Open Street Map (OSM). Because OSM is not specifically meant for creating topological networks and/or traffic assignment, the reader not only parses networks but also adapts them to construct a topologically meaningful network that is compatible the with PLANit memory model and is suitable for assignments. See also Data formats/Input/OSM section for more information on the OSM data format.

To be able to parse OSM networks, a large number of additional configuration options are made available to the user, from the option to exclude specific roads, to the (de)activation of road (highway) types, rail (railway) types, modes, etc. To aid the user in navigating these options, the settings (accessible via .settings() comprises the following specific configuration categories:

  • OSM general settings via .getSettings().<method_name>
  • OSM highway specific settings via .getSettings().getHighwaySettings().<method_name>
  • OSM railway specific settings via .getSettings().getRailwaySettings().<method_name>
  • OSM waterway specific settings via .getSettings().getWaterwaySettings().<method_name>
  • OSM lane configuration settings via .getSettings().getLaneconfiguration().<method_name>

We cannot show every option in this example, please consult the JavaDoc for detailed documentation on each separate option available

Logging is extensive for this reader. This is because based on warnings/info messages generated, the user is expected to adjust the settings to manually configure/override tagging errors and/or issues the automated conversion/salvaging procedures in the parser flagged. It is therefore recommended to first conduct a trial run with default settings and then gradually update the configuration based on the feedback by the reader.

Compulsory settings

The OSM reader has the following compulsory settings that must be configured, either by providing them to the factory method, or by configuring them after the instance is created:

  • Input file/source , containing directory and file name (file based) or URL (URL source based) to extract network from
  • Country name, to discern what driving direction the roads have and what defaults to apply

The country name determines the defaults used by the OSM reader, e.g., what driving direction roundabouts have, what default speed limits to apply to given OSM way types, etc. These defaults are detailed in the Data formats/Input/OSM section. In case the country name is not provided, the Global defaults (right-hand driving) will be applied, but it is discouraged to use as it likely requires overriding the default speed limits for all used road types.

Country specific defaults

As mentioned default settings that are adopted might depend on the chosen country and the user can provide custom settings for a country very easily. Currently, country specific settings exist for

  • Speed limits defaults
  • Mode access per OSM way type defaults

PLANit will attempt to parse the country specific defaults from its resources. If a user specifies a country for which no dedicated resources exist, PLANit will revert to the global defaults. A user can also provide its own country specific resource, by simply placing a CSV file with the appropriate structure under the correct resource dir, where the file name reflects the ISO3166-2 name, e.g. AU for Australia. See also the JavaDoc.

OSM File based example

// imports here...

public class OsmToPlanitExample {

    public void australianConverterExample(String inputDirAndFile, String outputDir) {

      /* reader */
      OsmNetworkReader osmReader = OsmNetworkReaderFactory.create(inputDirAndFile, CountryNames.AUSTRALIA);

      /* exclude particular OSM ways */
      osmReader.getSettings().excludeOsmWaysFromParsing(1234, 5678, 910210);
      /* only retain private motor vehicles as activated mode to consider */ 
      osmReader.getSettings().getHighwaySettings().deactivateAllOsmRoadModesExcept(OsmRoadModeTags.MOTOR_CAR);
      osmReader.getSettings().activateRailwayParser(false);
      osmReader.getSettings().activateWaterwayParser(false);
      
      /* remove all dangling networks after parsing that are below 40 vertices (nodes) */
      osmReader.getSettings().setRemoveDanglingSubnetworks(true);
      osmReader.getSettings().setDiscardDanglingNetworksBelow(40);
    
      /* deactivate all OSM highway types except the main roads down to secondary roads */
      osmReader.getSettings().deactivateAllOsmWayTypesExcept(
              OsmHighwayTags.MOTORWAY, OsmHighwayTags.MOTORWAY_LINK,
              OsmHighwayTags.TRUNK, OsmHighwayTags.TRUNK_LINK,
              OsmHighwayTags.PRIMARY, OsmHighwayTags.PRIMARY_LINK,
              OsmHighwayTags.SECONDARY, OsmHighwayTags.SECONDARY_LINK);
  
      /* writer */
      PlanitNetworkWriter planitWriter = PlanitNetworkWriterFactory.create(outputDir);
  
      /* convert */
      NetworkConverterFactory.create(osmReader, planitWriter).convert();
    }
}

OSM URL Streaming based example

Below a basic example on how to directly parse from an OSM api stream.

// imports here...

public class OsmToPlanitExample {

    public void streamingConverterExample(String outputDir) {

      /* OSM reader based on URL */
      OsmNetworkReader osmReader = OsmNetworkReaderFactory.create(exampleUrl, CountryNames.GERMANY);
      osmReader.getSettings().setInputSource("https://api.openstreetmap.org/api/0.6/map?bbox=13.465661,52.504055,13.469817,52.506204");
  
      /* only extract footways */
      osmReader.getSettings().getHighwaySettings().deactivateAllOsmHighwayTypesExcept(OsmHighwayTags.FOOTWAY);
      osmReader.getSettings().getHighwaySettings().deactivateAllRoadModesExcept(OsmRoadModeTags.FOOT);
  
      /* writer */
      PlanitNetworkWriter planitWriter = PlanitNetworkWriterFactory.create(outputDir);
  
      /* convert */
      NetworkConverterFactory.create(osmReader, planitWriter).convert();
    }
}

At this stage only reader implementations are available for OSM, a writer is unlikely to be added in future versions.

Open Street Map reader rail example

See OSM Simple Example as a starting point. This example demonstrates how to extract a rail only network by disabling the highway parser, and enabling the railway parser. We also limit the parsing to a smaller bounding box than present in the OSM file.

Logging is extensive for this reader. This is because based on warnings/info messages generated, the user is expected to adjust the settings to manually configure/override tagging errors and/or issues the automated conversion/salvaging procedures in the parser flagged. It is therefore recommended to first conduct a trial run with default settings and then gradually update the configuration based on the feedback by the reader.

OSM rail example

// imports here...

public class OsmToPlanitExample {

    public void railConverterExample(string inputFilePath, String outputDir) {
        
        /* reader */
        OsmNetworkReader osmReader = OsmNetworkReaderFactory.create(inputFilePath, CountyNames.AUSTRALIA);

        /* Only parse a subset of the OSM file by setting a smaller bounding box (or polygon)*/
        osmReader.getSettings().setBoundingBox(144.948083, 144.975849, -37.823582, -37.808292);

        /* activate parsing of track/rail based infrastructure */
        osmReader.getSettings().activateRailwayParser(true);

        /* extract tram and light-rail rail network only */
        osmReader.getSettings().getRailwaySettings().deactivateAllRailModesExcept("tram", "light_rail");

        /* switch off highway parser (or deactivate all its modes) to not parse road network */
        osmReader.getSettings().activateHighwayParser(false);
        // osmReader.getSettings().getHighwaySettings().removeAllRoadModes  // alternatively this has the same effect

        /* deactivate removal of dangling networks, so we keep all rail even on small networks */
        osmReader.getSettings().setRemoveDanglingSubnetworks(false);

        /* writer */
        PlanitNetworkWriter planitWriter = PlanitNetworkWriterFactory.create(outputDir);

        /* convert */
        NetworkConverterFactory.create(osmReader, planitWriter).convert();
    }
}

OSM ferry example

As with rail, but now focus on ferries. This is a special feature as there exist no “roads” for waterways, instead we parse all the ferry routes/connections and treat them as waterways.

It is recommended to switch of the removal of dangling networks if ferries are activated by themselves because ferry crossings might just represent a few links that are disconnected from other ferry routes.

Note that we also support the tags ferry=, e.g., ferry=primary, this will be parsed as a ferry link as well. This typically represents ferry crossings that take cars on the ferry to move them from one bank of a river to the other.

// imports here...

public class OsmToPlanitExample {

    public void ferryConverterExample(string inputFilePath, String outputDir) {
        
        /* reader */
        OsmNetworkReader osmReader = OsmNetworkReaderFactory.create(inputFilePath, CountyNames.AUSTRALIA);

        /* deactivate all non waterway infrastructure */
        osmReader.getSettings().activateHighwayParser(false);
        osmReader.getSettings().activateRailwayParser(false);

      /* deactivate removal of dangling networks, so we keep all ferry connections */
        osmReader.getSettings().setRemoveDanglingSubnetworks(false);

        /* activate parsing of waterways (ferry connections) */
        osmReader.getSettings().activateWaterwayParser(true);
        
        /* writer */
        PlanitNetworkWriter planitWriter = PlanitNetworkWriterFactory.create(outputDir);

        /* convert */
        NetworkConverterFactory.create(osmReader, planitWriter).convert();
    }
}

TNTP reader example

This example demonstrates how to parse a TNTP formatted network. TNTP networks often lack structure in the definition of what the csv file columns mean and what units are used. Therefore this has to be provided explicitly as part of the converter configuration as is demonstrated below for Sioux Falls (see TNTP github page for details on this network)

Example

// imports here...

public class TntpToPlanitExample {

    public void SiouxFallsConverterExample(Path networkFilePath, Path nodeFilePath) {
        /* reader */
        var tntpReader = TntpNetworkReaderFactory.create(
              networkFileLocation.toAbsolutePath().toString(), nodeFileLocation.toAbsolutePath().toString());
        
        // The following arrangement of columns is correct for SiouxFalls
        final Map<NetworkFileColumnType, Integer> networkFileColumns = new HashMap<>();
        networkFileColumns.put(NetworkFileColumnType.UPSTREAM_NODE_ID, 0);
        networkFileColumns.put(NetworkFileColumnType.DOWNSTREAM_NODE_ID, 1);
        networkFileColumns.put(NetworkFileColumnType.CAPACITY_PER_LANE, 2);
        networkFileColumns.put(NetworkFileColumnType.LENGTH, 3);
        networkFileColumns.put(NetworkFileColumnType.FREE_FLOW_TRAVEL_TIME, 4);
        networkFileColumns.put(NetworkFileColumnType.B, 5);
        networkFileColumns.put(NetworkFileColumnType.POWER, 6);
        networkFileColumns.put(NetworkFileColumnType.MAXIMUM_SPEED, 7);
        networkFileColumns.put(NetworkFileColumnType.TOLL, 8);
        networkFileColumns.put(NetworkFileColumnType.LINK_TYPE, 9);
        tntpReader.getSettings().setNetworkFileColumns(networkFileColumns);

        /* unit configuration */
        tntpReader.getSettings().setNetworkFileColumns(networkFileColumns);
        tntpReader.getSettings().setSpeedUnits(SpeedUnits.MILES_H);
        tntpReader.getSettings().setLengthUnits(LengthUnits.MILES);
        tntpReader.getSettings().setCapacityPeriod(1, TimeUnits.HOURS);
        tntpReader.getSettings().setFreeFlowTravelTimeUnits(TimeUnits.MINUTES);
        tntpReader.getSettings().setDefaultMaximumSpeed(defaultMaxSpeedMpH);

        /* writer */
        PlanitNetworkWriter planitWriter = PlanitNetworkWriterFactory.create(outputDir);

        /* convert */
        NetworkConverterFactory.create(osmReader, planitWriter).convert();
    }
}