OsmFileReader.java

package nl.tudelft.simulation.dsol.animation.gis.osm;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;

import org.openstreetmap.osmosis.core.task.v0_6.RunnableSource;
import org.openstreetmap.osmosis.xml.common.CompressionMethod;

import crosby.binary.osmosis.OsmosisReader;
import nl.tudelft.simulation.dsol.animation.gis.DataSourceInterface;
import nl.tudelft.simulation.dsol.animation.gis.FeatureInterface;
import nl.tudelft.simulation.dsol.animation.gis.transform.CoordinateTransform;

/**
 * OsmFileReader reads one layer from an OpenStreetMap file based on the given specifications. The supported formats are pbf,
 * osm, osm.gz, and osm.bz2.
 * <p>
 * Copyright (c) 2021-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
 * for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The DSOL
 * project is distributed under a three-clause BSD-style license, which can be found at
 * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
 * </p>
 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
 */
public class OsmFileReader implements DataSourceInterface
{
    /** */
    private static final long serialVersionUID = 20220130L;

    /** the URL for the osm file to be read. */
    private URL osmURL = null;

    /** an optional transformation of the lat/lon (or other) coordinates. */
    private final CoordinateTransform coordinateTransform;

    /** the features to read by this OpenStreeetMap reader. */
    private final List<FeatureInterface> featuresToRead;

    /**
     * Constructs a new reader for a layer in an OSM shape file.
     * @param osmURL URL; URL can have several valid extensions: .pbf, .osm, .osm.gz, and .osm.bz2
     * @param coordinateTransform CoordinateTransform; the transformation of (x, y) coordinates to (x', y') coordinates.
     * @param featuresToRead the features to read
     * @throws IOException throws an IOException if the url is not accessible
     */
    public OsmFileReader(final URL osmURL, final CoordinateTransform coordinateTransform,
            final List<FeatureInterface> featuresToRead) throws IOException
    {
        this.osmURL = osmURL;
        this.coordinateTransform = coordinateTransform;
        this.featuresToRead = featuresToRead;
    }
    
    /** {@inheritDoc} */
    @Override
    public List<FeatureInterface> getFeatures()
    {
        return this.featuresToRead;
    }

    /** {@inheritDoc} */
    @Override
    public void populateShapes() throws IOException
    {
        String filename = this.osmURL.toString().toLowerCase();
        File inputFile = new File(this.osmURL.getPath());

        OsmLayerSink sinkImplementation = new OsmLayerSink(this.featuresToRead, this.coordinateTransform);
        CompressionMethod compression = CompressionMethod.None;
        boolean pbf = false;
        RunnableSource reader = null;

        if (filename.endsWith(".pbf"))
        {
            pbf = true;
        }
        else if (filename.endsWith(".gz"))
        {
            compression = CompressionMethod.GZip;
        }
        else if (filename.endsWith(".bz2"))
        {
            compression = CompressionMethod.BZip2;
        }

        if (pbf)
        {
            try
            {
                reader = new OsmosisReader(inputFile);
                System.out.println("osm pbf map to read: " + filename);
            }
            catch (Exception exception)
            {
                sinkImplementation.close();
                throw new IOException("Error during reading of OSM file " + filename, exception);
            }
        }
        else
        {
            InputStream fis = this.osmURL.openStream();
            reader = new XmlStreamReader(fis, false, compression);
            System.out.println("osm xml map to read: " + filename);
        }

        reader.setSink(sinkImplementation);
        Thread readerThread = new Thread(reader);
        readerThread.start();

        while (readerThread.isAlive())
        {
            try
            {
                readerThread.join();
            }
            catch (InterruptedException e)
            {
                System.err.println("The map reader thread got a problem!");
                throw new IOException(e);
            }
        }

        System.out.println("OSM layer has been read");
    }

    /** {@inheritDoc} */
    @Override
    public URL getURL()
    {
        return this.osmURL;
    }

    /** {@inheritDoc} */
    @Override
    public boolean isDynamic()
    {
        return false; // OSM data is static
    }

}