View Javadoc
1   package nl.tudelft.simulation.dsol.animation.gis.osm;
2   
3   import java.awt.Color;
4   import java.io.IOException;
5   import java.io.InputStreamReader;
6   import java.io.Reader;
7   import java.net.URL;
8   import java.util.ArrayList;
9   import java.util.Iterator;
10  import java.util.List;
11  import java.util.Set;
12  
13  import org.djutils.exceptions.Throw;
14  
15  import de.siegmar.fastcsv.reader.NamedCsvReader;
16  import de.siegmar.fastcsv.reader.NamedCsvRow;
17  import nl.tudelft.simulation.dsol.animation.gis.FeatureInterface;
18  import nl.tudelft.simulation.dsol.animation.gis.GisMapInterface;
19  import nl.tudelft.simulation.dsol.animation.gis.LayerInterface;
20  import nl.tudelft.simulation.dsol.animation.gis.map.Feature;
21  import nl.tudelft.simulation.dsol.animation.gis.map.GisMap;
22  import nl.tudelft.simulation.dsol.animation.gis.map.Layer;
23  import nl.tudelft.simulation.dsol.animation.gis.parser.ColorParser;
24  import nl.tudelft.simulation.dsol.animation.gis.transform.CoordinateTransform;
25  
26  /**
27   * This class parses a CSV file that defines which elements of an OpenSTreetMap file need to be drawn and what format to use.
28   * <p>
29   * Copyright (c) 2020-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
30   * for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The DSOL
31   * project is distributed under a three-clause BSD-style license, which can be found at
32   * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
33   * </p>
34   * <p>
35   * The dsol-animation-gis project is based on the gisbeans project that has been part of DSOL since 2002, originally by Peter
36   * Jacobs and Paul Jacobs.
37   * </p>
38   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
39   */
40  public final class OsmFileCsvParser
41  {
42      /** Utility class, no constructor. */
43      private OsmFileCsvParser()
44      {
45          // Utility class
46      }
47  
48      /**
49       * Parses a CSV file with information about the map and layers.
50       * @param csvUrl URL; the url of the CSV file.
51       * @param osmUrl URL; the OpenStreetMap file in pbf, osm.gz or osm.bz2 format
52       * @param mapName String; the human readable name of the map
53       * @return MapInterface the parsed map file.
54       * @throws IOException on failure
55       */
56      public static GisMapInterface parseMapFile(final URL csvUrl, final URL osmUrl, final String mapName) throws IOException
57      {
58          return parseMapFile(csvUrl, osmUrl, mapName, new CoordinateTransform.NoTransform());
59      }
60  
61      /**
62       * Parses a CSV file with information about the map and layers.
63       * @param csvUrl URL; the url of the CSV file.
64       * @param osmUrl URL; the OpenStreetMap file in pbf, osm.gz or osm.bz2 format
65       * @param mapName String; the human readable name of the map
66       * @param coordinateTransform CoordinateTransform; the transformation of (x, y) coordinates to (x', y') coordinates.
67       * @return MapInterface the parsed map file.
68       * @throws IOException on failure
69       */
70      public static GisMapInterface parseMapFile(final URL csvUrl, final URL osmUrl, final String mapName,
71              final CoordinateTransform coordinateTransform) throws IOException
72      {
73          return parseMapFile(csvUrl, osmUrl, mapName, coordinateTransform, ',', '"');
74      }
75  
76      /**
77       * Parses a CSV file with information about the map and layers. FieldSeparateor can be, for instance \t for a tab character,
78       * and the quote character can be the double quote, the single quote, or something else.
79       * @param csvUrl URL; the url of the CSV file.
80       * @param osmUrl URL; the OpenStreetMap file in pbf, osm.gz or osm.bz2 format
81       * @param mapName String; the human readable name of the map
82       * @param coordinateTransform CoordinateTransform; the transformation of (x, y) coordinates to (x', y') coordinates.
83       * @param fieldSeparator char; field separator, e.g., comma for csv files and tab for tsv files
84       * @param quoteCharacter char; e.g., single or double quote
85       * @return MapInterface the parsed map file.
86       * @throws IOException on failure reading the CSV file, the shape files, or making the layers
87       * @throws IllegalArgumentException when one of the outline or fill colors can not be parsed
88       * @throws NumberFormatException when one of colors contains an illegal number
89       */
90      public static GisMapInterface parseMapFile(final URL csvUrl, final URL osmUrl, final String mapName,
91              final CoordinateTransform coordinateTransform, final char fieldSeparator, final char quoteCharacter)
92              throws IOException
93      {
94          GisMapInterface map = new GisMap();
95          map.setName(mapName);
96          List<String> layerNames = new ArrayList<>(); // to get index # in case layers are not sorted in the file
97          List<LayerInterface> layerList = new ArrayList<>(); // to pass to Map
98          List<FeatureInterface> featuresToRead = new ArrayList<>();
99  
100         Reader reader = new InputStreamReader(csvUrl.openStream());
101         Throw.when(reader == null, IOException.class, "Cannot find CSV file with OSM shape file information at " + csvUrl);
102         NamedCsvReader csvReader =
103                 NamedCsvReader.builder().fieldSeparator(fieldSeparator).quoteCharacter(quoteCharacter).build(reader);
104         Set<String> header = csvReader.getHeader();
105         if (!header.contains("layerName") || !header.contains("key") || !header.contains("value")
106                 || !header.contains("outlineColor") || !header.contains("fillColor") || !header.contains("display")
107                 || !header.contains("transform"))
108         {
109             throw new IOException("OSM GIS map csv-file header row did not contain all column headers\n" + header.toString());
110         }
111 
112         Iterator<NamedCsvRow> it = csvReader.iterator();
113         while (it.hasNext())
114         {
115             NamedCsvRow row = it.next();
116 
117             String layerName = row.getField("layerName");
118             String key = row.getField("key");
119             String value = row.getField("value");
120             Color outlineColor = ColorParser.parse(row.getField("outlineColor"));
121             Color fillColor = ColorParser.parse(row.getField("fillColor"));
122             boolean display = row.getField("display").toLowerCase().startsWith("t");
123             boolean transform = row.getField("transform").toLowerCase().startsWith("t");
124 
125             LayerInterface layer = null;
126             if (layerNames.contains(layerName))
127             {
128                 layer = layerList.get(layerNames.indexOf(layerName));
129             }
130             else
131             {
132                 layer = new Layer();
133                 layerList.add(layer);
134                 layer.setName(layerName);
135                 layerNames.add(layerName);
136             }
137 
138             Feature feature = new Feature();
139             feature.setKey(key);
140             feature.setValue(value);
141             feature.setOutlineColor(outlineColor);
142             feature.setFillColor(fillColor);
143             layer.addFeature(feature);
144             featuresToRead.add(feature);
145             layer.setDisplay(display);
146             layer.setTransform(transform);
147         }
148         reader.close();
149         csvReader.close();
150 
151         map.setLayers(layerList);
152         OsmFileReader osmReader = new OsmFileReader(osmUrl, coordinateTransform, featuresToRead);
153         osmReader.populateShapes();
154         return map;
155     }
156 
157 }